Skip to content

get_type_hints(): find the right globalns for classes and modules#470

Merged
ambv merged 2 commits into
masterfrom
globalnsForClasses
Sep 14, 2017
Merged

get_type_hints(): find the right globalns for classes and modules#470
ambv merged 2 commits into
masterfrom
globalnsForClasses

Conversation

@ambv

@ambv ambv commented Sep 13, 2017

Copy link
Copy Markdown
Contributor

This makes the default behavior (without specifying globalns manually) more
predictable for users.

Implementation for classes assumes has a __module__ attribute and that module
is present in sys.modules. It does this recursively for all bases in the
MRO. For modules, the implementation just uses their __dict__ directly.

This is backwards compatible, will just raise fewer exceptions in naive user
code.

Comment thread src/typing.py Outdated
if globalns is None:
globalns = getattr(obj, '__globals__', {})
if isinstance(obj, type):
globalns = vars(sys.modules[obj.__module__])

@ilevkivskyi ilevkivskyi Sep 13, 2017

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

While you are at it maybe you can fix same way also the logic below when __mro__ is traversed
(I could imagine that base classes are from different modules). Or will it be too hard? If not, I would add also a test for such scenario.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yeah, I have a few ideas more but it's annoying that we don't ship ann_module.py et al. but always refer to the one in test for Python 3.5+. This makes it hard to iterate on them.

Let me see what I can do.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done!

@ambv
ambv force-pushed the globalnsForClasses branch from 9378f79 to 7ca2449 Compare September 13, 2017 23:05
@ambv ambv changed the title get_type_hints(): find the right globalns for classes get_type_hints(): find the right globalns for classes and modules Sep 13, 2017
Comment thread src/test_typing.py
# don't account for the case where there are multiple types of the same
# name coming from different modules in the same program.
mgc_hints = {'default_a': Optional[mod_generics_cache.A],
'default_b': Optional[mod_generics_cache.B]}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I will fix this bug in a separate PR when this one lands.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I will fix this bug in a separate PR when this one lands.

OK, just don't forget about it (or open an issue if you want to do this later).

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hi, I was looking at a different issue and noticed this test code behaving non-deterministically depending on when mod_generics_cache was loaded (specifically this test would expectedly fail when I just ran the test_typing module, but unexpectedly succeed when I ran ./python -m test.)

Fixing the underlying type hint caching is beyond my scope as a new contributor, but it seems like something like this would make this test behave more reliably, if that seems reasonable to y'all: natgaertner/cpython@0cde103

This makes the default behavior (without specifying `globalns` manually) more
predictable for users.

Implementation for classes assumes has a `__module__` attribute and that module
is present in `sys.modules`.  It does this recursively for all bases in the
MRO.  For modules, the implementation just uses their `__dict__` directly.

This is backwards compatible, will just raise fewer exceptions in naive user
code.
@ambv
ambv force-pushed the globalnsForClasses branch from 7ca2449 to 8581ec2 Compare September 13, 2017 23:16
Comment thread src/mod_generics_cache.py
@@ -1,14 +1,53 @@
"""Module for testing the behavior of generics across different modules."""

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I only added a bunch of variable annotations here but since this wasn't compatible with < 3.5, I had to uglify this module. Now it's actually easier to see what's going on just by looking at the entire file with the "View" button.

Comment thread src/test_typing.py
# don't account for the case where there are multiple types of the same
# name coming from different modules in the same program.
mgc_hints = {'default_a': Optional[mod_generics_cache.A],
'default_b': Optional[mod_generics_cache.B]}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I will fix this bug in a separate PR when this one lands.

OK, just don't forget about it (or open an issue if you want to do this later).

@ambv
ambv merged commit 468b3fe into master Sep 14, 2017
@gvanrossum
gvanrossum deleted the globalnsForClasses branch September 14, 2017 17:44
@gvanrossum

Copy link
Copy Markdown
Member

Also, will this go into 3.6.3?

@ambv

ambv commented Sep 14, 2017

Copy link
Copy Markdown
Contributor Author

Yes, that's the point. I'm working on the backport as you read this.

@ambv

ambv commented Sep 14, 2017

Copy link
Copy Markdown
Contributor Author

Hopefully I'll get to fix the invalid cache of forward refs, too, before 2017-09-18 (PEP 494 3.6.3 RC).

ambv pushed a commit to ambv/cpython that referenced this pull request Sep 14, 2017
…ules

This makes the default behavior (without specifying `globalns` manually) more
predictable for users, finds the right globalns automatically.

Implementation for classes assumes has a `__module__` attribute and that module
is present in `sys.modules`.  It does this recursively for all bases in the
MRO.  For modules, the implementation just uses their `__dict__` directly.

This is backwards compatible, will just raise fewer exceptions in naive user
code.

Originally implemented and reviewed at python/typing#470.
@ilevkivskyi

Copy link
Copy Markdown
Member

Hopefully I'll get to fix the invalid cache of forward refs, too, before 2017-09-18 (PEP 494 3.6.3 RC).

Yes, it would be great if this gets in too.

miss-islington pushed a commit to miss-islington/cpython that referenced this pull request Sep 14, 2017
…nd modules (pythonGH-3582)

This makes the default behavior (without specifying `globalns` manually) more
predictable for users, finds the right globalns automatically.

Implementation for classes assumes has a `__module__` attribute and that module
is present in `sys.modules`.  It does this recursively for all bases in the
MRO.  For modules, the implementation just uses their `__dict__` directly.

This is backwards compatible, will just raise fewer exceptions in naive user
code.

Originally implemented and reviewed at python/typing#470.
(cherry picked from commit f350a26)
ambv added a commit to python/cpython that referenced this pull request Sep 14, 2017
…ules (#3582)

This makes the default behavior (without specifying `globalns` manually) more
predictable for users, finds the right globalns automatically.

Implementation for classes assumes has a `__module__` attribute and that module
is present in `sys.modules`.  It does this recursively for all bases in the
MRO.  For modules, the implementation just uses their `__dict__` directly.

This is backwards compatible, will just raise fewer exceptions in naive user
code.

Originally implemented and reviewed at python/typing#470.
ambv pushed a commit to python/cpython that referenced this pull request Sep 14, 2017
…nd modules (GH-3582) (#3583)

This makes the default behavior (without specifying `globalns` manually) more
predictable for users, finds the right globalns automatically.

Implementation for classes assumes has a `__module__` attribute and that module
is present in `sys.modules`.  It does this recursively for all bases in the
MRO.  For modules, the implementation just uses their `__dict__` directly.

This is backwards compatible, will just raise fewer exceptions in naive user
code.

Originally implemented and reviewed at python/typing#470.
(cherry picked from commit f350a26)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants