Skip to content

Commit

Permalink
Review feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
JelleZijlstra committed Jun 13, 2024
1 parent 6e078fd commit c8510ea
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 56 deletions.
4 changes: 2 additions & 2 deletions Doc/howto/descriptor.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1373,8 +1373,8 @@ Using the non-data descriptor protocol, a pure Python version of
The :func:`functools.update_wrapper` call adds a ``__wrapped__`` attribute
that refers to the underlying function. Also it carries forward
the attributes necessary to make the wrapper look like the wrapped
function: :attr:`~function.__name__`, :attr:`~function.__qualname__`,
:attr:`~function.__doc__`, and :attr:`~function.__annotations__`.
function, including :attr:`~function.__name__`, :attr:`~function.__qualname__`,
and :attr:`~function.__doc__`.

.. testcode::
:hide:
Expand Down
107 changes: 53 additions & 54 deletions Lib/annotationlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import sys
import types

__all__ = ["Format", "ForwardRef", "call_annotate_function", "get_annotations"]


class Format(enum.IntEnum):
VALUE = 1
Expand All @@ -19,7 +21,7 @@ class Format(enum.IntEnum):
# Slots shared by ForwardRef and _Stringifier. The __forward__ names must be
# preserved for compatibility with the old typing.ForwardRef class. The remaining
# names are private.
_slots = (
_SLOTS = (
"__forward_evaluated__",
"__forward_value__",
"__forward_is_argument__",
Expand All @@ -36,9 +38,9 @@ class Format(enum.IntEnum):


class ForwardRef:
"""Internal wrapper to hold a forward reference."""
"""Wrapper that holds a forward reference."""

__slots__ = _slots
__slots__ = _SLOTS

def __init__(
self,
Expand Down Expand Up @@ -87,8 +89,8 @@ def evaluate(self, *, globals=None, locals=None, type_params=None, owner=None):
return value
if owner is None:
owner = self.__owner__
if owner is None and type_params is None:
raise TypeError("Either 'owner' or 'type_params' must be provided")
if type_params is None and owner is None:
raise TypeError("Either 'type_params' or 'owner' must be provided")

if globals is None:
globals = self.__globals__
Expand Down Expand Up @@ -218,7 +220,7 @@ def __repr__(self):
class _Stringifier:
# Must match the slots on ForwardRef, so we can turn an instance of one into an
# instance of the other in place.
__slots__ = _slots
__slots__ = _SLOTS

def __init__(self, node, globals=None, owner=None, is_class=False, cell=None):
assert isinstance(node, ast.AST)
Expand Down Expand Up @@ -251,6 +253,51 @@ def __make_new(self, node):
node, self.__globals__, self.__owner__, self.__forward_is_class__
)

# Must implement this since we set __eq__. We hash by identity so that
# stringifiers in dict keys are kept separate.
def __hash__(self):
return id(self)

def __getitem__(self, other):
# Special case, to avoid stringifying references to class-scoped variables
# as '__classdict__["x"]'.
if (
isinstance(self.__ast_node__, ast.Name)
and self.__ast_node__.id == "__classdict__"
):
raise KeyError
if isinstance(other, tuple):
elts = [self.__convert(elt) for elt in other]
other = ast.Tuple(elts)
else:
other = self.__convert(other)
assert isinstance(other, ast.AST), repr(other)
return self.__make_new(ast.Subscript(self.__ast_node__, other))

def __getattr__(self, attr):
return self.__make_new(ast.Attribute(self.__ast_node__, attr))

def __call__(self, *args, **kwargs):
return self.__make_new(
ast.Call(
self.__ast_node__,
[self.__convert(arg) for arg in args],
[
ast.keyword(key, self.__convert(value))
for key, value in kwargs.items()
],
)
)

def __iter__(self):
yield self.__make_new(ast.Starred(self.__ast_node__))

def __repr__(self):
return ast.unparse(self.__ast_node__)

def __format__(self, format_spec):
raise TypeError("Cannot stringify annotation containing string formatting")

def _make_binop(op: ast.AST):
def binop(self, other):
return self.__make_new(
Expand Down Expand Up @@ -320,14 +367,6 @@ def compare(self, other):

del _make_compare

# Doesn't work because the return type is always coerced to a bool
# __contains__ = _make_compare(ast.In())

# Must implement this since we set __eq__. We hash by identity so that
# stringifiers in dict keys are kept separate.
def __hash__(self):
return id(self)

def _make_unary_op(op):
def unary_op(self):
return self.__make_new(ast.UnaryOp(op, self.__ast_node__))
Expand All @@ -340,46 +379,6 @@ def unary_op(self):

del _make_unary_op

def __getitem__(self, other):
# Special case, to avoid stringifying references to class-scoped variables
# as '__classdict__["x"]'.
if (
isinstance(self.__ast_node__, ast.Name)
and self.__ast_node__.id == "__classdict__"
):
raise KeyError
if isinstance(other, tuple):
elts = [self.__convert(elt) for elt in other]
other = ast.Tuple(elts)
else:
other = self.__convert(other)
assert isinstance(other, ast.AST), repr(other)
return self.__make_new(ast.Subscript(self.__ast_node__, other))

def __getattr__(self, attr):
return self.__make_new(ast.Attribute(self.__ast_node__, attr))

def __call__(self, *args, **kwargs):
return self.__make_new(
ast.Call(
self.__ast_node__,
[self.__convert(arg) for arg in args],
[
ast.keyword(key, self.__convert(value))
for key, value in kwargs.items()
],
)
)

def __iter__(self):
yield self.__make_new(ast.Starred(self.__ast_node__))

def __repr__(self):
return ast.unparse(self.__ast_node__)

def __format__(self, format_spec):
raise TypeError("Cannot stringify annotation containing string formatting")


class _StringifierDict(dict):
def __init__(self, namespace, globals=None, owner=None, is_class=False):
Expand Down
1 change: 1 addition & 0 deletions Lib/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -1039,6 +1039,7 @@ def evaluate_forward_ref(
This is similar to calling the ForwardRef.evaluate() method,
but unlike that method, evaluate_forward_ref() also:
* Recursively evaluates forward references nested within the type hint.
* Rejects certain objects that are not valid type hints.
* Replaces type hints that evaluate to None with types.NoneType.
Expand Down

0 comments on commit c8510ea

Please sign in to comment.