-
Notifications
You must be signed in to change notification settings - Fork 3
Improve handling of future annotations. #53
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -21,7 +21,7 @@ | |
| if typing.TYPE_CHECKING: | ||
| from typing import Any | ||
|
|
||
| from . import _apply_generic | ||
| from . import _apply_generic, _typing_inspect | ||
|
|
||
|
|
||
| __all__ = ("eval_typing",) | ||
|
|
@@ -272,8 +272,59 @@ def _eval_func( | |
| return _apply_generic.make_func(func, annos) | ||
|
|
||
|
|
||
| def _get_class_type_hint_namespaces( | ||
| obj: type, | ||
| ) -> tuple[dict[str, typing.Any], dict[str, typing.Any]]: | ||
| globalns: dict[str, typing.Any] = {} | ||
| localns: dict[str, typing.Any] = {} | ||
|
|
||
| # Get module globals | ||
| if obj.__module__ and (module := sys.modules.get(obj.__module__)): | ||
| globalns.update(module.__dict__) | ||
|
|
||
| # Annotations may use typevars defined in the class | ||
| localns.update(obj.__dict__) | ||
|
|
||
| if _typing_inspect.is_generic_alias(obj): | ||
| # We need the origin's type vars | ||
| localns.update(obj.__origin__.__dict__) | ||
|
|
||
| # Extract type parameters from the class | ||
| args = typing.get_args(obj) | ||
| origin = typing.get_origin(obj) | ||
| tps = getattr(obj, '__type_params__', ()) or getattr( | ||
| origin, '__parameters__', () | ||
| ) | ||
| for tp, arg in zip(tps, args, strict=False): | ||
| localns[tp.__name__] = arg | ||
|
|
||
| # Add the class itself for self-references | ||
| localns[obj.__name__] = obj | ||
|
|
||
| return globalns, localns | ||
|
|
||
|
|
||
| @_eval_types_impl.register | ||
| def _eval_type_type(obj: type, ctx: EvalContext): | ||
| # Ensure that any string annotations are resolved | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @dnwpark check if the robot is right about this? |
||
| if ( | ||
| hasattr(obj, '__annotations__') | ||
| and obj.__annotations__ | ||
| and any(isinstance(v, str) for v in obj.__annotations__.values()) | ||
| ): | ||
| # Ensure we don't recurse infinitely | ||
| ctx.seen[obj] = obj | ||
|
|
||
| # Replace string annotations with resolved types | ||
| globalns, localns = _get_class_type_hint_namespaces(obj) | ||
| hints = { | ||
| k: _eval_types(v, ctx) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need to And more generally I suppose, is this where we want to do this?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need something like this to resolve a case like this: class A:
b: B
class B:
c: C
class C:
pass
t = eval_typing(A)
assert t.__annotations__['b'].__annotations__['c'] is CIf we don't recursively eval, the inner annotations will stay as strings.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure that bothers me |
||
| for k, v in typing.get_type_hints( | ||
| obj, globalns=globalns, localns=localns, include_extras=True | ||
| ).items() | ||
| } | ||
| obj.__annotations__.update(hints) | ||
|
|
||
| return obj | ||
|
|
||
|
|
||
|
|
||
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.
We may wish to keep this TODO for the non str case?