-
-
Notifications
You must be signed in to change notification settings - Fork 110
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
Add typing_extensions.get_annotations #423
Conversation
src/_inspect_stock_annotations.py
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In #151, the consensus seemed to be that we shouldn't add new "data files" to the src directory for usage in tests, because these will end up in the site-packages directory for people who've installed typing_extensions. Should we just store these as strings in test_typing_extensions.py, like we did for the data files in that PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might also be time to split the test file, as it's approaching 10k lines.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we could have an src/test_typing_extensons
directory: then it's only a single importable module in site-packages
, but we'd be able to split it up so that it doesn't get too huge.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the idea of making a test directory. I'll send a separate PR for that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried this and I think it's not worth it. I like to simply run python test_typing_extensions.py
to run the test suite; that would no longer work with a package. I'll move the test files from this PR into exec()
calls instead.
return_value = {key: | ||
value if not isinstance(value, str) else eval(value, globals, locals) | ||
for key, value in ann.items() } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, this isn't going to work for type parameters, which exist in neither the global nor local namespaces. Possibly the fix I made to the typing.py
internals in python/cpython@1e3e7ce should also have been applied to inspect.py
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. In my PEP 649 implementation branch (python/cpython#119891) I handle this by getting obj's __type_params__
, but this may also be worth backporting separately.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Filed python/cpython#120270
while True: | ||
if hasattr(unwrap, '__wrapped__'): | ||
unwrap = unwrap.__wrapped__ | ||
continue | ||
if isinstance(unwrap, functools.partial): | ||
unwrap = unwrap.func | ||
continue | ||
break |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
any idea why inspect.get_annotations
doesn't use inspect.unwrap()
here? Though I suppose we won't be able to use inspect.unwrap
in the CPython version anyway after moving the implementation out of inspect.py
, since we won't want the new annotations
module to depend on inspect
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure. Looks like unwrap() doesn't handle functools.partial specially, though unlike this code it deals with cycles.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's pretty odd; no CPython tests fail if I make this change:
diff --git a/Lib/inspect.py b/Lib/inspect.py
index 2b7f8bec482..4f9c43d9fc7 100644
--- a/Lib/inspect.py
+++ b/Lib/inspect.py
@@ -235,13 +235,11 @@ def get_annotations(obj, *, globals=None, locals=None, eval_str=False):
if module:
obj_globals = getattr(module, '__dict__', None)
obj_locals = dict(vars(obj))
- unwrap = obj
elif isinstance(obj, types.ModuleType):
# module
ann = getattr(obj, '__annotations__', None)
obj_globals = getattr(obj, '__dict__')
obj_locals = None
- unwrap = None
elif callable(obj):
# this includes types.Function, types.BuiltinFunctionType,
# types.BuiltinMethodType, functools.partial, functools.singledispatch,
@@ -249,7 +247,6 @@ def get_annotations(obj, *, globals=None, locals=None, eval_str=False):
ann = getattr(obj, '__annotations__', None)
obj_globals = getattr(obj, '__globals__', None)
obj_locals = None
- unwrap = obj
else:
raise TypeError(f"{obj!r} is not a module, class, or callable.")
@@ -265,17 +262,8 @@ def get_annotations(obj, *, globals=None, locals=None, eval_str=False):
if not eval_str:
return dict(ann)
- if unwrap is not None:
- while True:
- if hasattr(unwrap, '__wrapped__'):
- unwrap = unwrap.__wrapped__
- continue
- if isinstance(unwrap, functools.partial):
- unwrap = unwrap.func
- continue
- break
- if hasattr(unwrap, "__globals__"):
- obj_globals = unwrap.__globals__
+ if not isinstance(obj, types.ModuleType):
+ obj_globals = getattr(unwrap(obj), "__globals__", None) or obj_globals
You could consider that simplification here since we already import inspect
in typing_extensions
, though it obviously can't be applied to CPython
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That sounds like we're missing test coverage for functools.partial
. I think we should mirror the CPython implementation as much as possible.
Co-authored-by: Alex Waygood <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Co-authored-by: Alex Waygood <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. #423 (comment) can be fixed in a followup once we've sorted it out at cpython
Fixes #409
This is based on the implementation in python/cpython#119891. The version that eventually lands in CPython may look a bit different, but should be compatible with what's in this PR.