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"
Metadata
Release files for async-object 3.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| async_object-3.0.0.tar.gz | 103.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| async_object-3.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 111.4 kB
Release files / async_object-3.0.0.tar.gz
| Download URL | async_object-3.0.0.tar.gz |
|---|---|
| Size | 103.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c98c25cc08a84c054aa02cc66d7e1a332224637bf3cb0a40365b1163b782f011
|
|
BLAKE2b-256 checksum How to use checksums |
3d6c9eb1b3f304b653b5ca224bb6c14e07b0892f2465a8c0632d1071dd630efc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.15
|
Release files / async_object-3.0.0-py3-none-any.whl
| Download URL | async_object-3.0.0-py3-none-any.whl |
|---|---|
| Size | 8.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8b8258f3b61973c6ff20270754d4075e9e299b8db3b13feb5cffe27b3839af76
|
|
BLAKE2b-256 checksum How to use checksums |
aee288af38f2f4404eef7fdbbee1b41c32bbaa0e76963c8289205149379c5a10
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.15
|