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

Callback protocol with other attributes #10976

Closed
erictraut opened this issue Aug 13, 2021 · 2 comments · Fixed by #14084
Closed

Callback protocol with other attributes #10976

erictraut opened this issue Aug 13, 2021 · 2 comments · Fixed by #14084

Comments

@erictraut
Copy link

I'm not sure if this is a mypy bug or intended behavior. I'm looking for advice.

PEP 544 introduced the concept of a callback protocol. In particular, it says:

[Callback protocols] can be defined as protocols with a call member

It is not clear to me whether a protocol that defines members other than __call__ is considered a callback protocol. PEP 544 says:

Callback protocols and Callable[...] types can be used interchangeably.

This could imply that a protocol class that includes attributes other than __call__ is not a callback protocol, but maybe I'm reading too much into it. I thought I remembered reading somewhere (perhaps on a typing-sig thread?) that if a protocol class included attributes other than __call__, it would not be considered a callback protocol, but I can't seem to find that thread.

A pyright user (@kennipj) recently filed this bug report. Currently, the behavior of pyright matches mypy in this case. I'm wondering if mypy's behavior is intended or whether it's a bug.

Here's another mypy bug that is related to this issue: #10403.

@JelleZijlstra
Copy link
Member

I'm not sure "callback protocol" should be defined as a concept by itself: it's just an emergent property of the type system that a Protocol with a __call__ method will match a callable.

For the bug report you link to, I feel the issue is that the type checker doesn't understand that a function is a FunctionType instance with a __name__.

@erictraut
Copy link
Author

It sounds like there's no definitive answer. After much discussion, we've decided to interpret "callback protocol" in a more lax manner, consistent with what @JelleZijlstra said above.

We've made this change in pyright, which now deviates from mypy in the following sample. If you agree with our conclusion, please consider this a request for a change in mypy.

from typing import Protocol

class SomeFunc(Protocol):
    __name__: str
    other_attribute: int

    def __call__(self) -> str:
        ...

def other_func(f: SomeFunc):
    print(f.__name__)
    f.other_attribute = 1

    f.other_attribute = "str"  # pyright and mypy emit an error
    f.missing_attribute = 3  # pyright and mypy emit an error

@other_func  # pyright does not emit an error, but mypy does
def some_func() -> str:
    ...

ilevkivskyi added a commit that referenced this issue Nov 13, 2022
Fixes #10976
Fixes #10403

This is quite straightforward. Note that we will not allow _arbitrary_
attributes on functions, only those that are defined in
`types.FunctionType` (or more precisely `builtins.function` that is
identical). We have a separate issue for arbitrary attributes
#2087
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants