I am making a job class by inheriting from asyncio.Future with some custom attributes, and expect the job instance functions like the original Future.
When I call job.set_result inside a coroutine, it raises a Future object is not initialized error, then I tried to get future initialized by call asyncio.ensure_future and the same error appears.
I tried more and find that the future is usually created by loop.create_future(), however, there is no options to create my custom future.
Below is an example, How can I get my custom future initialized?
import asyncio
from dataclasses import dataclass
@dataclass
class Job(asyncio.Future):
job_task: Callable
real_future: asyncio.Future = None
something: str = None
def schedule(self):
async def run():
res = await self.job_task()
self.set_result(res) # raise error, future not initialized
return res
self.real_future = asyncio.ensure_future(run())
async def main():
async def task():
await asyncio.sleep(1)
return 1
job = Job(task)
job.schedule()
await job
asyncio.run(main())
You need to call the superclass constructor yourself, something that dataclass's __init__ can't do because of reasons. But you also shouldn't try to re-implement __init__ yourself, since it is not exactly intuitive and you might mess up.
The Right Way To Do It (given that you want to keep using the @dataclass decorator) is leveraging the __post_init__ hook that dataclasses provide:
@dataclass
class Job(asyncio.Future):
job_task: Callable
real_future: asyncio.Future = None
something: str = None
def __post_init__(self)
super().__init__()
def schedule(self):
async def run():
res = await self.job_task()
self.set_result(res) # works now
return res
self.real_future = asyncio.ensure_future(run())
The problem is that Future is not a dataclass, but your Job class inherits from it and uses the @dataclass decorator. This results in failure to invoke Future.__init__ and consequently failure to initialize the future object.
To fix the issue, don't use the @dataclass decorator in the first
place. Instead, write an explicit __init__ that sets the necessary attributes, and invokes super().__init__() to initialize the Future correctly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With