async-object let you write classes with async def __init__
Project description
async-object
async-object let you write classes with async def __init__
Installation
From PyPI repository
pip install --user async-object
From source
git clone https://github.com/francis-clairicia/async-object.git
cd async-object
pip install --user .
Usage
It is simple, with async-object you can do this:
from async_object import AsyncObject
class MyObject(AsyncObject):
async def __init__(self) -> None:
await super().__init__()
# Do some async stuff
if __name__ == "__main__":
import asyncio
async def main() -> None:
instance = await MyObject()
assert isinstance(instance, MyObject)
asyncio.run(main())
This example uses asyncio, but it is compatible with all runner libraries, since this package only uses the language syntax.
Description
async-object provides a base class AsyncObject using AsyncObjectMeta metaclass.
AsyncObjectMeta overrides the default type constructor in order to return a coroutine, which must be await-ed to get the instance.
async def main() -> None:
coroutine = MyObject()
print(coroutine)
instance = await coroutine
print(instance)
Replace the main in the Usage example by this one and run it. You should see something like this in your console:
<coroutine object AsyncObjectMeta.__call__ at 0x7ff1f28eb300>
<__main__.MyObject object at 0x7ff1f21a4fd0>
Arguments
Obviously, arguments can be given to __init__ and __new__.
The inheritance logic with "normal" constructors is the same here:
from typing_extensions import Self
class MyObjectOnlyNew(AsyncObject):
def __new__(cls, *args: Any, **kwargs: Any) -> Self:
self = super().__new__(cls)
print(args)
print(kwargs)
return self
class MyObjectOnlyInit(AsyncObject):
async def __init__(self, *args: Any, **kwargs: Any) -> None:
# await super().__init__() # Optional if the base class is only AsyncObject (but useful in multiple inheritance context)
print(args)
print(kwargs)
class MyObjectBothNewAndInit(AsyncObject):
def __new__(cls, *args: Any, **kwargs: Any) -> Self:
self = super().__new__(cls)
print(args)
print(kwargs)
return self
async def __init__(self, *args: Any, **kwargs: Any) -> None:
# await super().__init__()
print(args)
print(kwargs)
Inheritance
Talking about inheritance, there are a few rules to follow:
AsyncObjector a subclass must appear at least once in the base classes declaration.- Non-
AsyncObjectclasses can be used as base classes if they do not override__init__(in order not to break the MRO). - To avoid confusion with awaitable objects, overriding
__await__is forbidden.
Abstract base classes
There is a metaclass AsyncABCMeta deriving from AsyncObjectMeta and abc.ABCMeta which allows you to declare abstract base classes
import abc
from async_object import AsyncObject, AsyncABCMeta
class MyAbstractObject(AsyncObject, metaclass=AsyncABCMeta):
@abc.abstractmethod
def method(self) -> None:
raise NotImplementedError
@abc.abstractmethod
async def async_method(self) -> None:
raise NotImplementedError
class MyObject(MyAbstractObject):
async def __init__(self) -> None:
pass
def method(self) -> None:
pass
async def async_method(self) -> None:
pass
N.B.: There is a shorthand AsyncABC like abc.ABC.
import abc
from async_object import AsyncABC
class MyAbstractObject(AsyncABC):
@abc.abstractmethod
def method(self) -> None:
raise NotImplementedError
@abc.abstractmethod
async def async_method(self) -> None:
raise NotImplementedError
Static type checking: mypy integration
mypy does not like having async def for __init__, and will not understand await AsyncObject().
async-object embeds a plugin which helps mypy to understand asynchronous constructors.
Installation
Firstly, install the needed dependencies:
pip install async-object[mypy]
To register this plugin in your mypy.ini, pyproject.toml, or whatever, you must add async_object.contrib.mypy.plugin to the plugins list.
In mypy.ini:
[mypy]
plugins = async_object.contrib.mypy.plugin
In pyproject.toml:
[tool.mypy]
plugins = ["async_object.contrib.mypy.plugin"]
For more information, see the mypy documentation.
What is permitted then ?
__init__ method returning a coroutine is accepted
The error The return type of "__init__" must be None is discarded.
class MyObject(AsyncObject):
async def __init__(self, param: int) -> None:
await super().__init__()
The class instanciation introspection is fixed
async def main() -> None:
coroutine = MyObject()
reveal_type(coroutine) # Revealed type is "typing.Coroutine[Any, Any, __main__.MyObject]"
instance = await coroutine
reveal_type(instance) # Revealed type is "__main__.MyObject"
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file async_object-2.0.0.tar.gz.
File metadata
- Download URL: async_object-2.0.0.tar.gz
- Upload date:
- Size: 32.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.9.18
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0168dc4489ea3bf6620837d9af1382d36524b435d0ebdea2affcdbc802b5f9f3
|
|
| MD5 |
0cc1ef9b8ac5be5e64e13f449e941534
|
|
| BLAKE2b-256 |
5ee1bf32038dce05cfcf528c5222c227403318a948c6a458dbf0a9ae67f2220e
|
File details
Details for the file async_object-2.0.0-py3-none-any.whl.
File metadata
- Download URL: async_object-2.0.0-py3-none-any.whl
- Upload date:
- Size: 8.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.9.18
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fa527d7af21b274972ee171347370099ae2f3a8353a6f3bbaa4958919ac364c2
|
|
| MD5 |
2fbb90cd561149f8b2d405fc2b733017
|
|
| BLAKE2b-256 |
767ec72fe3e97116b6f6bbbbf517f9777efc62ee113f08d11b2ea3790768a7ad
|