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

[PEP 695] Fix multiple nested classes don't work #17820

Merged
merged 9 commits into from
Oct 11, 2024

Conversation

changhoetyng
Copy link
Contributor

This PR modifies the lookup_fully_qualified_or_none method to support multiple nested classes.

Fixes #17780

This comment has been minimized.

This comment has been minimized.

Copy link
Collaborator

@JukkaL JukkaL left a comment

Choose a reason for hiding this comment

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

Thanks for the PR! The logic looks mostly right, but I don't think it works for packages.

mypy/semanal.py Outdated
return None
# Check if there's nested module A.B.C
splitted = fullname.rsplit(".")
module, names = splitted[0], splitted[1:]
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this logic is not quite right for packages. We should find the longest prefix of fullname that is a module (it could be e.g. a.b for a.b.C.D), and then look up through TypeInfos based on that.

Also add a test case for a case like a.b.C.D where a.b is a package.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry about that! I'll take a look as soon as possible :)

This comment has been minimized.

@changhoetyng
Copy link
Contributor Author

Hi @JukkaL, I have fixed this. Now, the logic identifies the longest prefix of full name that represents a module. I have also added a test case to cover scenarios with nested packages. Let me know if you want me to adjust the implementation further. Thanks!

Copy link
Collaborator

@JukkaL JukkaL left a comment

Choose a reason for hiding this comment

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

Thanks for the updates! I have few comments, mostly stylistic.

mypy/semanal.py Outdated
If the module is not found, pop the last element of the splitted list and append it to the names list.

This is to find the longest prefix of the module name that is in the modules dictionary.
"""
Copy link
Collaborator

Choose a reason for hiding this comment

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

Style nit: We only use docstrings at beginning of a function/module/class, not inside function bodies.

@@ -6408,14 +6408,44 @@ def lookup_fully_qualified_or_none(self, fullname: str) -> SymbolTableNode | Non
# TODO: support nested classes (but consider performance impact,
# we might keep the module level only lookup for thing like 'builtins.int').
assert "." in fullname
module, name = fullname.rsplit(".", maxsplit=1)
if module not in self.modules:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please keep the original "fast path" which we'll be hitting most of the time. This way your new logic, which is a bit more expensive, it not slowing he typical code path. This may be performance critical. In more concrete terms, add your new logic under if module not in self.modules:, and keep the other code as is in the function.

mypy/semanal.py Outdated
module, name = fullname.rsplit(".", maxsplit=1)
if module not in self.modules:

splitted_modules = fullname.rsplit(".")
Copy link
Collaborator

Choose a reason for hiding this comment

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

Minor: Here you can use just fullname.split("."), since it won't make a difference in semantics and split is the more usual variant.

This comment has been minimized.

@changhoetyng
Copy link
Contributor Author

@JukkaL Thanks for the comments. I have made some changes to them. Let me know if you have any extra comments!

Since this change will allow support for nested classes, should I remove the below TODO?

 # TODO: support nested classes (but consider performance impact,
 #       we might keep the module level only lookup for thing like 'builtins.int').

@JukkaL
Copy link
Collaborator

JukkaL commented Oct 10, 2024

Since this change will allow support for nested classes, should I remove the below TODO?

Yes, please!

@changhoetyng
Copy link
Contributor Author

@JukkaL It's done! Is there anything else I need to add?

This comment has been minimized.

Copy link
Collaborator

@JukkaL JukkaL left a comment

Choose a reason for hiding this comment

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

Thanks for the updates! Looks good now.

@changhoetyng
Copy link
Contributor Author

@JukkaL No worries!

Copy link
Contributor

According to mypy_primer, this change doesn't affect type check results on a corpus of open source code. ✅

@JukkaL JukkaL merged commit 54f4954 into python:master Oct 11, 2024
18 checks passed
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.

[PEP 695] Multiple nested classes don't work
2 participants