File: base.py

package info (click to toggle)
python-async-property 0.2.2-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 288 kB
  • sloc: python: 765; makefile: 87; sh: 6
file content (45 lines) | stat: -rw-r--r-- 1,279 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import asyncio
import functools

from async_property.proxy import AwaitableOnly

is_coroutine = asyncio.iscoroutinefunction


def async_property(func, *args, **kwargs):
    assert is_coroutine(func), 'Can only use with async def'
    return AsyncPropertyDescriptor(func, *args, **kwargs)


class AsyncPropertyDescriptor:
    def __init__(self, _fget, field_name=None):
        self._fget = _fget
        self.field_name = field_name or _fget.__name__
        functools.update_wrapper(self, _fget)

    def __set_name__(self, owner, name):
        self.field_name = name

    def __get__(self, instance, owner):
        if instance is None:
            return self
        return self.awaitable_only(instance)

    def __set__(self, instance, value):
        raise ValueError(INVALID_ACTION.format('set'))

    def __delete__(self, instance):
        raise ValueError(INVALID_ACTION.format('delete'))

    def get_loader(self, instance):
        @functools.wraps(self._fget)
        async def get_value():
            return await self._fget(instance)
        return get_value

    def awaitable_only(self, instance):
        return AwaitableOnly(self.get_loader(instance))


INVALID_ACTION = 'Cannot {} @async_property. ' \
                 'Use @async_cached_property instead.'