Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check async function ? #15

Open
touilleMan opened this issue Apr 19, 2018 · 3 comments
Open

Check async function ? #15

touilleMan opened this issue Apr 19, 2018 · 3 comments

Comments

@touilleMan
Copy link

It seems the module currently don't make difference between sync and async functions:

>>> import interface
>>> class IFoo(interface.Interface):
...   async def do_async(self):
...     pass
... 
>>> class BadFoo(interface.implements(IFoo)):
...   def do_async(self):
...     pass
... 
>>> # No error has been raised !
@ssanderson
Copy link
Owner

Hmm. I think it's an interesting question whether interface should reject BadFoo in your example.

The contract that you probably care about as a consumer of IFoo is that do_async returns an awaitable, but it's perfectly possible to write a non-async function that returns an awaitable.

For example, this would be probably be a valid implementation of IFoo that doesn't use an async def:

class MyAwaitable:

    def __init__(self, value):
        self.value = value

    def __await__(self):
        return self.value
        yield


class ValidFoo(interface.implements(IFoo)):

    def do_async(self):
        return MyAwaitable(5)

@touilleMan
Copy link
Author

The contract that you probably care about as a consumer of IFoo is that do_async returns an awaitable, but it's perfectly possible to write a non-async function that returns an awaitable.

I agree, however this is a pretty unorthodox way of writting async function... well orthodoxy about async function have changed a lot since Python 3.4, but now async/await have landed and are supported by all major frameworks (asyncio, twisted, tornado, curio, trio etc.)

So considering your example, I would expect it to be implemented like:

class ValidFoo(interface.implements(IFoo)):

    async def do_async(self):
        return await MyAwaitable(5)

This way we respect the async interface requirement, even if we use a custom awaitable.

On a more theoretical point of view, async/await has been designed to easily recognize asynchronous blocks and synchronization points (otherwise generator with yield would have done the job fine ^^). I would say defining interface share a similar goal as another way of making Python code more explicit (as opposed to just have something that runs).

@ssanderson
Copy link
Owner

On a more theoretical point of view, async/await has been designed to easily recognize asynchronous blocks and synchronization points (otherwise generator with yield would have done the job fine ^^). I would say defining interface share a similar goal as another way of making Python code more explicit (as opposed to just have something that runs).

@touilleMan I buy that argument (sorry for the long delay on replying). I took a crack at implementing this in #17 if you want to take a look.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants