bocadilloproject/aiodine

Consumer API and signature modification

Closed this issue · 0 comments

Current status

In the current v1.x API, @consumer returns an object whose call signature is different from the consumer function:

import aiodine

@aiodine.provider(name="value")
async def provide_value():
    return 42

@aiodine.consumer
async def app(value):
    return value

async def main():
    print(await app())  # 42

Editors and linters tend to complain about the missing arguments, which makes for a poor user experience. Even then, it seems plain odd to be able to call app without value, as value is apparently a required parameter. The implicit Consumer conversion hides too much magic.

Proposed solution

Remove the @consumer API (and the notion of consumers altogether) and introduce aiodine.call():

import aiodine

@aiodine.provider(name="value")
async def provide_value():
    return 42

async def app(value):
    print("Value:", value)

async def main():
    await aiodine.call(app)  # Value: 42

This has a number of benefits:

  • Simplicity:
    • The only high-level concept remaining would be that of "provider".
    • .call() is responsible for injecting providers and managing their lifecycle, whereas that logic was previously scattered across, Store, Provider and Consumer.
  • Transparency: the provider function remains unmodified, which means it can be used just as if it wasn't decorated, which gives us good editor and type checking support:
await app()  # TypeError: missing required argument "value"
await app(21)  # Value: 21
await app(value=21)  # Value: 21
await app(value="21")  # mypy throws an error