Skip to content

PEP 649: class __annotate__ is shadowed by compiler-generated one #133037

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

Closed
luigig44 opened this issue Apr 27, 2025 · 3 comments
Closed

PEP 649: class __annotate__ is shadowed by compiler-generated one #133037

luigig44 opened this issue Apr 27, 2025 · 3 comments
Labels
3.14 bugs and security fixes interpreter-core (Objects, Python, Grammar, and Parser dirs) topic-typing type-bug An unexpected behavior, bug, or error

Comments

@luigig44
Copy link

luigig44 commented Apr 27, 2025

Bug report

Bug description:

I'm playing around with PEP 649, PEP 749 annotations and I found this surprising behaviour:

class C:
    x: str
    def __annotate__(format):
        if format != 1:
            raise NotImplementedError()
        return {'x': int}

assert C.__annotate__(1) == {'x': int} # This returns {'x': str} and fails

I'm not yet sure why I would write code with annotations and then also write an explicit __annotate__, but I would expect the explicit method to prevail over the compiler-generated one. If I explicitly set C.__annotate__ = some_func afterwards it works as I would expect.

Calling dis on the provided example shows both __annotate__s getting compiled, and one overwriting the other in the class.

Related to #119180.

CPython versions tested on:

3.14, CPython main branch

Operating systems tested on:

Linux

Linked PRs

@luigig44 luigig44 added the type-bug An unexpected behavior, bug, or error label Apr 27, 2025
@sobolevn
Copy link
Member

sobolevn commented Apr 27, 2025

See related #122285

@picnixz picnixz added interpreter-core (Objects, Python, Grammar, and Parser dirs) 3.14 bugs and security fixes labels Apr 27, 2025
@JelleZijlstra
Copy link
Member

This behavior is pretty inconsistent for other attributes set in the class namespace:

>>> class X:
...     __name__ = 42
...     __module__ = 42
...     __qualname__ = "42"
...     __firstlineno__ = 42
...     __static_attributes__ = 42
...     
>>> X.__name__
'X'
>>> X.__module__
42
>>> X.__qualname__
'42'
>>> X.__firstlineno__
42
>>> X.__static_attributes__
()

Still, it's probably nicer to make this work the way this issue asks for. This can be fixed with the approach in #131550 if we do the same thing in class namespaces as we already do there for modules (assign __annotate__ early in class body execution). I'd wait for that one to be merged first and then apply the same change to class bodies.

@JelleZijlstra
Copy link
Member

This was actually already fixed by #132345, because now the compiler-generated __annotate__ function gets stored at a different key in the class dict. I will send a PR with a test case.

(You'll still get your name overwritten if you use the name __annotate_func__ in user code. Don't do that.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3.14 bugs and security fixes interpreter-core (Objects, Python, Grammar, and Parser dirs) topic-typing type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

5 participants