Package: async-object
async-objectasync-objectlet you write classes withasync def __init__InstallationFrom PyPI repositorypipinstall--userasync-objectFrom sourcegitclonehttps://github.com/francis-clairicia/async-object.gitcdasync-object
pipinstall--user.UsageIt is simple, withasync-objectyou can do this:fromasync_objectimportAsyncObjectclassMyObject(AsyncObject):asyncdef__init__(self)->None:awaitsuper().__init__()# Do some async stuffif__name__=="__main__":importasyncioasyncdefmain()->None:instance=awaitMyObject()assertisinstance(instance,MyObject)asyncio.run(main())This example usesasyncio, but it is compatible with all runner libraries, since this package only uses the language syntax.Descriptionasync-objectprovides a base classAsyncObjectusingAsyncObjectMetametaclass.AsyncObjectMetaoverrides the defaulttypeconstructor in order to return a coroutine, which must beawait-ed to get the instance.asyncdefmain()->None:coroutine=MyObject()print(coroutine)instance=awaitcoroutineprint(instance)Replace themainin theUsageexample 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>ArgumentsObviously, arguments can be given to__init__and__new__.
The inheritance logic with "normal" constructors is the same here:fromtyping_extensionsimportSelfclassMyObjectOnlyNew(AsyncObject):def__new__(cls,*args:Any,**kwargs:Any)->Self:self=super().__new__(cls)print(args)print(kwargs)returnselfclassMyObjectOnlyInit(AsyncObject):asyncdef__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)classMyObjectBothNewAndInit(AsyncObject):def__new__(cls,*args:Any,**kwargs:Any)->Self:self=super().__new__(cls)print(args)print(kwargs)returnselfasyncdef__init__(self,*args:Any,**kwargs:Any)->None:# await super().__init__()print(args)print(kwargs)InheritanceTalking 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 theMRO).To avoid confusion withawaitable objects, overriding__await__is forbidden.Abstract base classesThere is a metaclassAsyncABCMetaderiving fromAsyncObjectMetaandabc.ABCMetawhich allows you to declare abstract base classesimportabcfromasync_objectimportAsyncObject,AsyncABCMetaclassMyAbstractObject(AsyncObject,metaclass=AsyncABCMeta):@abc.abstractmethoddefmethod(self)->None:raiseNotImplementedError@abc.abstractmethodasyncdefasync_method(self)->None:raiseNotImplementedErrorclassMyObject(MyAbstractObject):asyncdef__init__(self)->None:passdefmethod(self)->None:passasyncdefasync_method(self)->None:passN.B.: There is a shorthandAsyncABClikeabc.ABC.importabcfromasync_objectimportAsyncABCclassMyAbstractObject(AsyncABC):@abc.abstractmethoddefmethod(self)->None:raiseNotImplementedError@abc.abstractmethodasyncdefasync_method(self)->None:raiseNotImplementedErrorStatic type checking: mypy integrationmypydoes not like havingasync deffor__init__, and will not understandawait AsyncObject().async-objectembeds a plugin which helpsmypyto understand asynchronous constructors.InstallationFirstly, install the needed dependencies:pipinstallasync-object[mypy]To register this plugin in yourmypy.ini,pyproject.toml, or whatever, you must addasync_object.contrib.mypy.pluginto the plugins list.Inmypy.ini:[mypy]plugins=async_object.contrib.mypy.pluginInpyproject.toml:[tool.mypy]plugins=["async_object.contrib.mypy.plugin"]For more information, seethe mypy documentation.What is permitted then ?__init__method returning a coroutine is acceptedThe errorThe return type of "__init__" must be Noneis discarded.classMyObject(AsyncObject):asyncdef__init__(self,param:int)->None:awaitsuper().__init__()The class instanciation introspection is fixedasyncdefmain()->None:coroutine=MyObject()reveal_type(coroutine)# Revealed type is "typing.Coroutine[Any, Any, __main__.MyObject]"instance=awaitcoroutinereveal_type(instance)# Revealed type is "__main__.MyObject"