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

gh-119180: Add annotationlib module to support PEP 649 #119891

Merged
merged 136 commits into from
Jul 23, 2024

Conversation

JelleZijlstra
Copy link
Member

@JelleZijlstra JelleZijlstra commented Jun 1, 2024

This PR implements the annotationlib module proposed by PEP-749, as well as related Python changes for PEP-649 and PEP-749.

Comment on lines 265 to 271
class NoDict(type):
@property
def __dict__(cls):
raise AttributeError

class C1(metaclass=NoDict):
a: int

This comment was marked as resolved.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vars(C1) raises an error here already:

>>> class NoDict(type):
...     @property
...     def __dict__(cls):
...         raise AttributeError
... 
... class C1(metaclass=NoDict):
...     a: int
... 
>>> vars(C1)
Traceback (most recent call last):
  File "<python-input-1>", line 1, in <module>
    vars(C1)
    ~~~~^^^^
TypeError: vars() argument must have __dict__ attribute

However, the tests I added don't yet cover cases where we call vars() on the "owner", I'll work on that later.

This comment was marked as resolved.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh! this behaviour changed between two versions actually! (I incorrectly checked it with 3.12.2 actually and not 3.14!)

Um, that sounds bad. We should try to bisect that and make sure it was deliberate.

Copy link
Contributor

@picnixz picnixz Jun 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh no false alarm. How come I got no error yesterday but I got one today? maybe it's an even older version. Let me verify again.

EDIT: Sorry Alex, what I said on the behaviour was incorrect!

Copy link
Contributor

@picnixz picnixz Jun 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ! I know, actually I was trying to make the error on the type of C1, namely vars(type(C1)) and not on C1 itself. However, it should be possible to have owner = NoDict or is it not possible?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This actually made me find an even more basic bug:

>>> class X(type):
...     a: int
...     
>>> class Y(metaclass=X):
...     b: str
...     
>>> Y.__annotations__
{'a': <class 'int'>}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Posted https://discuss.python.org/t/pep-749-implementing-pep-649/54974/28 about this, I think I'll want to deal with it in a separate PR (since the solution likely involves changes to #119361).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this PR I won't handle the metaclass case yet; still thinking about how to handle that.

@rhettinger rhettinger removed their request for review June 17, 2024 02:18
@JelleZijlstra
Copy link
Member Author

This PR is still ready for review. While we will likely make some change related to metaclasses, that won't materially effect the changes here. I'd like to get this PR landed as a foundation to build the rest of the PEP implementation on, so I'd appreciate any reviews.

Copy link
Member

@carljm carljm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me!

Comment on lines 108 to 111
if self.__forward_module__ is not None:
globals = getattr(
sys.modules.get(self.__forward_module__, None), "__dict__", globals
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this (if set) will override the above heuristics on lines 97-107 anyway, why not move it above line 97 so that if we get a globals from __forward_module__ we don't need to bother with those other lookups?

def test_expressions(self):
def f(
add: a + b,
sub: a + b,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
sub: a + b,
sub: a - b,

anno,
{
"add": "a + b",
"sub": "a + b",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"sub": "a + b",
"sub": "a - b",

self.assertEqual(annotationlib.get_annotations(int), {})
self.assertEqual(annotationlib.get_annotations(object), {})

def test_custom_metaclass(self):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you plan to add tests here for the pathological cases with metaclass annotations, or make that change in a separate PR?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll leave metaclasses to a separate PR (#119180).


def test_custom_object_with_annotations(self):
class C:
def __init__(self, x: int = 0, y: str = ""):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are the arguments and their annotations actually related to the test? If not, I'd remove them for clarity about what behavior the test is actually specifying.

@JelleZijlstra
Copy link
Member Author

Thanks @carljm for the review! I pushed fixes for the issues you identified.

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

Successfully merging this pull request may close these issues.

4 participants