mirror of https://github.com/python/cpython
gh-119180: Rename SOURCE format to STRING (#124620)
This commit is contained in:
parent
a4d1fdfb15
commit
2c10832887
|
@ -32,7 +32,7 @@ This module supports retrieving annotations in three main formats
|
||||||
for annotations that cannot be resolved, allowing you to inspect the
|
for annotations that cannot be resolved, allowing you to inspect the
|
||||||
annotations without evaluating them. This is useful when you need to
|
annotations without evaluating them. This is useful when you need to
|
||||||
work with annotations that may contain unresolved forward references.
|
work with annotations that may contain unresolved forward references.
|
||||||
* :attr:`~Format.SOURCE` returns the annotations as a string, similar
|
* :attr:`~Format.STRING` returns the annotations as a string, similar
|
||||||
to how it would appear in the source file. This is useful for documentation
|
to how it would appear in the source file. This is useful for documentation
|
||||||
generators that want to display annotations in a readable way.
|
generators that want to display annotations in a readable way.
|
||||||
|
|
||||||
|
@ -135,7 +135,7 @@ Classes
|
||||||
values. Real objects may contain references to, :class:`ForwardRef`
|
values. Real objects may contain references to, :class:`ForwardRef`
|
||||||
proxy objects.
|
proxy objects.
|
||||||
|
|
||||||
.. attribute:: SOURCE
|
.. attribute:: STRING
|
||||||
:value: 3
|
:value: 3
|
||||||
|
|
||||||
Values are the text string of the annotation as it appears in the
|
Values are the text string of the annotation as it appears in the
|
||||||
|
@ -197,23 +197,23 @@ Classes
|
||||||
Functions
|
Functions
|
||||||
---------
|
---------
|
||||||
|
|
||||||
.. function:: annotations_to_source(annotations)
|
.. function:: annotations_to_string(annotations)
|
||||||
|
|
||||||
Convert an annotations dict containing runtime values to a
|
Convert an annotations dict containing runtime values to a
|
||||||
dict containing only strings. If the values are not already strings,
|
dict containing only strings. If the values are not already strings,
|
||||||
they are converted using :func:`value_to_source`.
|
they are converted using :func:`value_to_string`.
|
||||||
This is meant as a helper for user-provided
|
This is meant as a helper for user-provided
|
||||||
annotate functions that support the :attr:`~Format.SOURCE` format but
|
annotate functions that support the :attr:`~Format.STRING` format but
|
||||||
do not have access to the code creating the annotations.
|
do not have access to the code creating the annotations.
|
||||||
|
|
||||||
For example, this is used to implement the :attr:`~Format.SOURCE` for
|
For example, this is used to implement the :attr:`~Format.STRING` for
|
||||||
:class:`typing.TypedDict` classes created through the functional syntax:
|
:class:`typing.TypedDict` classes created through the functional syntax:
|
||||||
|
|
||||||
.. doctest::
|
.. doctest::
|
||||||
|
|
||||||
>>> from typing import TypedDict
|
>>> from typing import TypedDict
|
||||||
>>> Movie = TypedDict("movie", {"name": str, "year": int})
|
>>> Movie = TypedDict("movie", {"name": str, "year": int})
|
||||||
>>> get_annotations(Movie, format=Format.SOURCE)
|
>>> get_annotations(Movie, format=Format.STRING)
|
||||||
{'name': 'str', 'year': 'int'}
|
{'name': 'str', 'year': 'int'}
|
||||||
|
|
||||||
.. versionadded:: 3.14
|
.. versionadded:: 3.14
|
||||||
|
@ -282,7 +282,7 @@ Functions
|
||||||
NameError: name 'undefined' is not defined
|
NameError: name 'undefined' is not defined
|
||||||
>>> call_evaluate_function(Alias.evaluate_value, Format.FORWARDREF)
|
>>> call_evaluate_function(Alias.evaluate_value, Format.FORWARDREF)
|
||||||
ForwardRef('undefined')
|
ForwardRef('undefined')
|
||||||
>>> call_evaluate_function(Alias.evaluate_value, Format.SOURCE)
|
>>> call_evaluate_function(Alias.evaluate_value, Format.STRING)
|
||||||
'undefined'
|
'undefined'
|
||||||
|
|
||||||
.. versionadded:: 3.14
|
.. versionadded:: 3.14
|
||||||
|
@ -369,14 +369,14 @@ Functions
|
||||||
|
|
||||||
.. versionadded:: 3.14
|
.. versionadded:: 3.14
|
||||||
|
|
||||||
.. function:: value_to_source(value)
|
.. function:: value_to_string(value)
|
||||||
|
|
||||||
Convert an arbitrary Python value to a format suitable for use by the
|
Convert an arbitrary Python value to a format suitable for use by the
|
||||||
:attr:`~Format.SOURCE` format. This calls :func:`repr` for most
|
:attr:`~Format.STRING` format. This calls :func:`repr` for most
|
||||||
objects, but has special handling for some objects, such as type objects.
|
objects, but has special handling for some objects, such as type objects.
|
||||||
|
|
||||||
This is meant as a helper for user-provided
|
This is meant as a helper for user-provided
|
||||||
annotate functions that support the :attr:`~Format.SOURCE` format but
|
annotate functions that support the :attr:`~Format.STRING` format but
|
||||||
do not have access to the code creating the annotations. It can also
|
do not have access to the code creating the annotations. It can also
|
||||||
be used to provide a user-friendly string representation for other
|
be used to provide a user-friendly string representation for other
|
||||||
objects that contain values that are commonly encountered in annotations.
|
objects that contain values that are commonly encountered in annotations.
|
||||||
|
|
|
@ -3427,7 +3427,7 @@ Introspection helpers
|
||||||
* Replaces type hints that evaluate to :const:`!None` with
|
* Replaces type hints that evaluate to :const:`!None` with
|
||||||
:class:`types.NoneType`.
|
:class:`types.NoneType`.
|
||||||
* Supports the :attr:`~annotationlib.Format.FORWARDREF` and
|
* Supports the :attr:`~annotationlib.Format.FORWARDREF` and
|
||||||
:attr:`~annotationlib.Format.SOURCE` formats.
|
:attr:`~annotationlib.Format.STRING` formats.
|
||||||
|
|
||||||
*forward_ref* must be an instance of :class:`~annotationlib.ForwardRef`.
|
*forward_ref* must be an instance of :class:`~annotationlib.ForwardRef`.
|
||||||
*owner*, if given, should be the object that holds the annotations that
|
*owner*, if given, should be the object that holds the annotations that
|
||||||
|
|
|
@ -91,7 +91,7 @@ annotations. Annotations may be evaluated in the :attr:`~annotationlib.Format.VA
|
||||||
format (which evaluates annotations to runtime values, similar to the behavior in
|
format (which evaluates annotations to runtime values, similar to the behavior in
|
||||||
earlier Python versions), the :attr:`~annotationlib.Format.FORWARDREF` format
|
earlier Python versions), the :attr:`~annotationlib.Format.FORWARDREF` format
|
||||||
(which replaces undefined names with special markers), and the
|
(which replaces undefined names with special markers), and the
|
||||||
:attr:`~annotationlib.Format.SOURCE` format (which returns annotations as strings).
|
:attr:`~annotationlib.Format.STRING` format (which returns annotations as strings).
|
||||||
|
|
||||||
This example shows how these formats behave:
|
This example shows how these formats behave:
|
||||||
|
|
||||||
|
@ -106,7 +106,7 @@ This example shows how these formats behave:
|
||||||
NameError: name 'Undefined' is not defined
|
NameError: name 'Undefined' is not defined
|
||||||
>>> get_annotations(func, format=Format.FORWARDREF)
|
>>> get_annotations(func, format=Format.FORWARDREF)
|
||||||
{'arg': ForwardRef('Undefined')}
|
{'arg': ForwardRef('Undefined')}
|
||||||
>>> get_annotations(func, format=Format.SOURCE)
|
>>> get_annotations(func, format=Format.STRING)
|
||||||
{'arg': 'Undefined'}
|
{'arg': 'Undefined'}
|
||||||
|
|
||||||
Implications for annotated code
|
Implications for annotated code
|
||||||
|
|
|
@ -485,10 +485,10 @@ class _CallableGenericAlias(GenericAlias):
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
if len(self.__args__) == 2 and _is_param_expr(self.__args__[0]):
|
if len(self.__args__) == 2 and _is_param_expr(self.__args__[0]):
|
||||||
return super().__repr__()
|
return super().__repr__()
|
||||||
from annotationlib import value_to_source
|
from annotationlib import value_to_string
|
||||||
return (f'collections.abc.Callable'
|
return (f'collections.abc.Callable'
|
||||||
f'[[{", ".join([value_to_source(a) for a in self.__args__[:-1]])}], '
|
f'[[{", ".join([value_to_string(a) for a in self.__args__[:-1]])}], '
|
||||||
f'{value_to_source(self.__args__[-1])}]')
|
f'{value_to_string(self.__args__[-1])}]')
|
||||||
|
|
||||||
def __reduce__(self):
|
def __reduce__(self):
|
||||||
args = self.__args__
|
args = self.__args__
|
||||||
|
|
|
@ -15,15 +15,15 @@ __all__ = [
|
||||||
"call_evaluate_function",
|
"call_evaluate_function",
|
||||||
"get_annotate_function",
|
"get_annotate_function",
|
||||||
"get_annotations",
|
"get_annotations",
|
||||||
"annotations_to_source",
|
"annotations_to_string",
|
||||||
"value_to_source",
|
"value_to_string",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class Format(enum.IntEnum):
|
class Format(enum.IntEnum):
|
||||||
VALUE = 1
|
VALUE = 1
|
||||||
FORWARDREF = 2
|
FORWARDREF = 2
|
||||||
SOURCE = 3
|
STRING = 3
|
||||||
|
|
||||||
|
|
||||||
_Union = None
|
_Union = None
|
||||||
|
@ -291,9 +291,21 @@ class _Stringifier:
|
||||||
return other.__ast_node__
|
return other.__ast_node__
|
||||||
elif isinstance(other, slice):
|
elif isinstance(other, slice):
|
||||||
return ast.Slice(
|
return ast.Slice(
|
||||||
lower=self.__convert_to_ast(other.start) if other.start is not None else None,
|
lower=(
|
||||||
upper=self.__convert_to_ast(other.stop) if other.stop is not None else None,
|
self.__convert_to_ast(other.start)
|
||||||
step=self.__convert_to_ast(other.step) if other.step is not None else None,
|
if other.start is not None
|
||||||
|
else None
|
||||||
|
),
|
||||||
|
upper=(
|
||||||
|
self.__convert_to_ast(other.stop)
|
||||||
|
if other.stop is not None
|
||||||
|
else None
|
||||||
|
),
|
||||||
|
step=(
|
||||||
|
self.__convert_to_ast(other.step)
|
||||||
|
if other.step is not None
|
||||||
|
else None
|
||||||
|
),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
return ast.Constant(value=other)
|
return ast.Constant(value=other)
|
||||||
|
@ -469,7 +481,7 @@ def call_annotate_function(annotate, format, *, owner=None, _is_evaluate=False):
|
||||||
can be called with any of the format arguments in the Format enum, but
|
can be called with any of the format arguments in the Format enum, but
|
||||||
compiler-generated __annotate__ functions only support the VALUE format.
|
compiler-generated __annotate__ functions only support the VALUE format.
|
||||||
This function provides additional functionality to call __annotate__
|
This function provides additional functionality to call __annotate__
|
||||||
functions with the FORWARDREF and SOURCE formats.
|
functions with the FORWARDREF and STRING formats.
|
||||||
|
|
||||||
*annotate* must be an __annotate__ function, which takes a single argument
|
*annotate* must be an __annotate__ function, which takes a single argument
|
||||||
and returns a dict of annotations.
|
and returns a dict of annotations.
|
||||||
|
@ -487,8 +499,8 @@ def call_annotate_function(annotate, format, *, owner=None, _is_evaluate=False):
|
||||||
return annotate(format)
|
return annotate(format)
|
||||||
except NotImplementedError:
|
except NotImplementedError:
|
||||||
pass
|
pass
|
||||||
if format == Format.SOURCE:
|
if format == Format.STRING:
|
||||||
# SOURCE is implemented by calling the annotate function in a special
|
# STRING is implemented by calling the annotate function in a special
|
||||||
# environment where every name lookup results in an instance of _Stringifier.
|
# environment where every name lookup results in an instance of _Stringifier.
|
||||||
# _Stringifier supports every dunder operation and returns a new _Stringifier.
|
# _Stringifier supports every dunder operation and returns a new _Stringifier.
|
||||||
# At the end, we get a dictionary that mostly contains _Stringifier objects (or
|
# At the end, we get a dictionary that mostly contains _Stringifier objects (or
|
||||||
|
@ -524,9 +536,9 @@ def call_annotate_function(annotate, format, *, owner=None, _is_evaluate=False):
|
||||||
for key, val in annos.items()
|
for key, val in annos.items()
|
||||||
}
|
}
|
||||||
elif format == Format.FORWARDREF:
|
elif format == Format.FORWARDREF:
|
||||||
# FORWARDREF is implemented similarly to SOURCE, but there are two changes,
|
# FORWARDREF is implemented similarly to STRING, but there are two changes,
|
||||||
# at the beginning and the end of the process.
|
# at the beginning and the end of the process.
|
||||||
# First, while SOURCE uses an empty dictionary as the namespace, so that all
|
# First, while STRING uses an empty dictionary as the namespace, so that all
|
||||||
# name lookups result in _Stringifier objects, FORWARDREF uses the globals
|
# name lookups result in _Stringifier objects, FORWARDREF uses the globals
|
||||||
# and builtins, so that defined names map to their real values.
|
# and builtins, so that defined names map to their real values.
|
||||||
# Second, instead of returning strings, we want to return either real values
|
# Second, instead of returning strings, we want to return either real values
|
||||||
|
@ -688,14 +700,14 @@ def get_annotations(
|
||||||
# __annotations__ threw NameError and there is no __annotate__. In that case,
|
# __annotations__ threw NameError and there is no __annotate__. In that case,
|
||||||
# we fall back to trying __annotations__ again.
|
# we fall back to trying __annotations__ again.
|
||||||
return dict(_get_dunder_annotations(obj))
|
return dict(_get_dunder_annotations(obj))
|
||||||
case Format.SOURCE:
|
case Format.STRING:
|
||||||
# For SOURCE, we try to call __annotate__
|
# For STRING, we try to call __annotate__
|
||||||
ann = _get_and_call_annotate(obj, format)
|
ann = _get_and_call_annotate(obj, format)
|
||||||
if ann is not None:
|
if ann is not None:
|
||||||
return ann
|
return ann
|
||||||
# But if we didn't get it, we use __annotations__ instead.
|
# But if we didn't get it, we use __annotations__ instead.
|
||||||
ann = _get_dunder_annotations(obj)
|
ann = _get_dunder_annotations(obj)
|
||||||
return annotations_to_source(ann)
|
return annotations_to_string(ann)
|
||||||
case _:
|
case _:
|
||||||
raise ValueError(f"Unsupported format {format!r}")
|
raise ValueError(f"Unsupported format {format!r}")
|
||||||
|
|
||||||
|
@ -764,10 +776,10 @@ def get_annotations(
|
||||||
return return_value
|
return return_value
|
||||||
|
|
||||||
|
|
||||||
def value_to_source(value):
|
def value_to_string(value):
|
||||||
"""Convert a Python value to a format suitable for use with the SOURCE format.
|
"""Convert a Python value to a format suitable for use with the STRING format.
|
||||||
|
|
||||||
This is inteded as a helper for tools that support the SOURCE format but do
|
This is inteded as a helper for tools that support the STRING format but do
|
||||||
not have access to the code that originally produced the annotations. It uses
|
not have access to the code that originally produced the annotations. It uses
|
||||||
repr() for most objects.
|
repr() for most objects.
|
||||||
|
|
||||||
|
@ -783,10 +795,10 @@ def value_to_source(value):
|
||||||
return repr(value)
|
return repr(value)
|
||||||
|
|
||||||
|
|
||||||
def annotations_to_source(annotations):
|
def annotations_to_string(annotations):
|
||||||
"""Convert an annotation dict containing values to approximately the SOURCE format."""
|
"""Convert an annotation dict containing values to approximately the STRING format."""
|
||||||
return {
|
return {
|
||||||
n: t if isinstance(t, str) else value_to_source(t)
|
n: t if isinstance(t, str) else value_to_string(t)
|
||||||
for n, t in annotations.items()
|
for n, t in annotations.items()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,8 @@ from annotationlib import (
|
||||||
ForwardRef,
|
ForwardRef,
|
||||||
get_annotations,
|
get_annotations,
|
||||||
get_annotate_function,
|
get_annotate_function,
|
||||||
annotations_to_source,
|
annotations_to_string,
|
||||||
value_to_source,
|
value_to_string,
|
||||||
)
|
)
|
||||||
from typing import Unpack
|
from typing import Unpack
|
||||||
|
|
||||||
|
@ -39,14 +39,14 @@ class MyClass:
|
||||||
|
|
||||||
class TestFormat(unittest.TestCase):
|
class TestFormat(unittest.TestCase):
|
||||||
def test_enum(self):
|
def test_enum(self):
|
||||||
self.assertEqual(annotationlib.Format.VALUE.value, 1)
|
self.assertEqual(Format.VALUE.value, 1)
|
||||||
self.assertEqual(annotationlib.Format.VALUE, 1)
|
self.assertEqual(Format.VALUE, 1)
|
||||||
|
|
||||||
self.assertEqual(annotationlib.Format.FORWARDREF.value, 2)
|
self.assertEqual(Format.FORWARDREF.value, 2)
|
||||||
self.assertEqual(annotationlib.Format.FORWARDREF, 2)
|
self.assertEqual(Format.FORWARDREF, 2)
|
||||||
|
|
||||||
self.assertEqual(annotationlib.Format.SOURCE.value, 3)
|
self.assertEqual(Format.STRING.value, 3)
|
||||||
self.assertEqual(annotationlib.Format.SOURCE, 3)
|
self.assertEqual(Format.STRING, 3)
|
||||||
|
|
||||||
|
|
||||||
class TestForwardRefFormat(unittest.TestCase):
|
class TestForwardRefFormat(unittest.TestCase):
|
||||||
|
@ -54,9 +54,7 @@ class TestForwardRefFormat(unittest.TestCase):
|
||||||
def inner(arg: x):
|
def inner(arg: x):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
anno = annotationlib.get_annotations(
|
anno = annotationlib.get_annotations(inner, format=Format.FORWARDREF)
|
||||||
inner, format=annotationlib.Format.FORWARDREF
|
|
||||||
)
|
|
||||||
fwdref = anno["arg"]
|
fwdref = anno["arg"]
|
||||||
self.assertIsInstance(fwdref, annotationlib.ForwardRef)
|
self.assertIsInstance(fwdref, annotationlib.ForwardRef)
|
||||||
self.assertEqual(fwdref.__forward_arg__, "x")
|
self.assertEqual(fwdref.__forward_arg__, "x")
|
||||||
|
@ -66,16 +64,14 @@ class TestForwardRefFormat(unittest.TestCase):
|
||||||
x = 1
|
x = 1
|
||||||
self.assertEqual(fwdref.evaluate(), x)
|
self.assertEqual(fwdref.evaluate(), x)
|
||||||
|
|
||||||
anno = annotationlib.get_annotations(
|
anno = annotationlib.get_annotations(inner, format=Format.FORWARDREF)
|
||||||
inner, format=annotationlib.Format.FORWARDREF
|
|
||||||
)
|
|
||||||
self.assertEqual(anno["arg"], x)
|
self.assertEqual(anno["arg"], x)
|
||||||
|
|
||||||
def test_function(self):
|
def test_function(self):
|
||||||
def f(x: int, y: doesntexist):
|
def f(x: int, y: doesntexist):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
anno = annotationlib.get_annotations(f, format=annotationlib.Format.FORWARDREF)
|
anno = annotationlib.get_annotations(f, format=Format.FORWARDREF)
|
||||||
self.assertIs(anno["x"], int)
|
self.assertIs(anno["x"], int)
|
||||||
fwdref = anno["y"]
|
fwdref = anno["y"]
|
||||||
self.assertIsInstance(fwdref, annotationlib.ForwardRef)
|
self.assertIsInstance(fwdref, annotationlib.ForwardRef)
|
||||||
|
@ -92,14 +88,14 @@ class TestSourceFormat(unittest.TestCase):
|
||||||
def inner(arg: x):
|
def inner(arg: x):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
anno = annotationlib.get_annotations(inner, format=annotationlib.Format.SOURCE)
|
anno = annotationlib.get_annotations(inner, format=Format.STRING)
|
||||||
self.assertEqual(anno, {"arg": "x"})
|
self.assertEqual(anno, {"arg": "x"})
|
||||||
|
|
||||||
def test_function(self):
|
def test_function(self):
|
||||||
def f(x: int, y: doesntexist):
|
def f(x: int, y: doesntexist):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
anno = annotationlib.get_annotations(f, format=annotationlib.Format.SOURCE)
|
anno = annotationlib.get_annotations(f, format=Format.STRING)
|
||||||
self.assertEqual(anno, {"x": "int", "y": "doesntexist"})
|
self.assertEqual(anno, {"x": "int", "y": "doesntexist"})
|
||||||
|
|
||||||
def test_expressions(self):
|
def test_expressions(self):
|
||||||
|
@ -133,7 +129,7 @@ class TestSourceFormat(unittest.TestCase):
|
||||||
):
|
):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
anno = annotationlib.get_annotations(f, format=annotationlib.Format.SOURCE)
|
anno = annotationlib.get_annotations(f, format=Format.STRING)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
anno,
|
anno,
|
||||||
{
|
{
|
||||||
|
@ -184,7 +180,7 @@ class TestSourceFormat(unittest.TestCase):
|
||||||
):
|
):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
anno = annotationlib.get_annotations(f, format=annotationlib.Format.SOURCE)
|
anno = annotationlib.get_annotations(f, format=Format.STRING)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
anno,
|
anno,
|
||||||
{
|
{
|
||||||
|
@ -218,7 +214,7 @@ class TestSourceFormat(unittest.TestCase):
|
||||||
):
|
):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
anno = annotationlib.get_annotations(f, format=annotationlib.Format.SOURCE)
|
anno = annotationlib.get_annotations(f, format=Format.STRING)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
anno,
|
anno,
|
||||||
{
|
{
|
||||||
|
@ -241,13 +237,13 @@ class TestSourceFormat(unittest.TestCase):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
with self.assertRaisesRegex(TypeError, format_msg):
|
with self.assertRaisesRegex(TypeError, format_msg):
|
||||||
annotationlib.get_annotations(f, format=annotationlib.Format.SOURCE)
|
annotationlib.get_annotations(f, format=Format.STRING)
|
||||||
|
|
||||||
def f(fstring_format: f"{a:02d}"):
|
def f(fstring_format: f"{a:02d}"):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
with self.assertRaisesRegex(TypeError, format_msg):
|
with self.assertRaisesRegex(TypeError, format_msg):
|
||||||
annotationlib.get_annotations(f, format=annotationlib.Format.SOURCE)
|
annotationlib.get_annotations(f, format=Format.STRING)
|
||||||
|
|
||||||
|
|
||||||
class TestForwardRefClass(unittest.TestCase):
|
class TestForwardRefClass(unittest.TestCase):
|
||||||
|
@ -276,7 +272,7 @@ class TestForwardRefClass(unittest.TestCase):
|
||||||
with self.assertRaises(NameError):
|
with self.assertRaises(NameError):
|
||||||
ForwardRef("T").evaluate(owner=int)
|
ForwardRef("T").evaluate(owner=int)
|
||||||
|
|
||||||
T, = Gen.__type_params__
|
(T,) = Gen.__type_params__
|
||||||
self.assertIs(ForwardRef("T").evaluate(type_params=Gen.__type_params__), T)
|
self.assertIs(ForwardRef("T").evaluate(type_params=Gen.__type_params__), T)
|
||||||
self.assertIs(ForwardRef("T").evaluate(owner=Gen), T)
|
self.assertIs(ForwardRef("T").evaluate(owner=Gen), T)
|
||||||
|
|
||||||
|
@ -294,8 +290,7 @@ class TestForwardRefClass(unittest.TestCase):
|
||||||
def test_fwdref_with_module(self):
|
def test_fwdref_with_module(self):
|
||||||
self.assertIs(ForwardRef("Format", module="annotationlib").evaluate(), Format)
|
self.assertIs(ForwardRef("Format", module="annotationlib").evaluate(), Format)
|
||||||
self.assertIs(
|
self.assertIs(
|
||||||
ForwardRef("Counter", module="collections").evaluate(),
|
ForwardRef("Counter", module="collections").evaluate(), collections.Counter
|
||||||
collections.Counter
|
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
ForwardRef("Counter[int]", module="collections").evaluate(),
|
ForwardRef("Counter[int]", module="collections").evaluate(),
|
||||||
|
@ -383,22 +378,20 @@ class TestGetAnnotations(unittest.TestCase):
|
||||||
|
|
||||||
self.assertEqual(annotationlib.get_annotations(C1), {"a": int})
|
self.assertEqual(annotationlib.get_annotations(C1), {"a": int})
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
annotationlib.get_annotations(C1, format=annotationlib.Format.FORWARDREF),
|
annotationlib.get_annotations(C1, format=Format.FORWARDREF),
|
||||||
{"a": int},
|
{"a": int},
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
annotationlib.get_annotations(C1, format=annotationlib.Format.SOURCE),
|
annotationlib.get_annotations(C1, format=Format.STRING),
|
||||||
{"a": "int"},
|
{"a": "int"},
|
||||||
)
|
)
|
||||||
self.assertEqual(annotationlib.get_annotations(NoDict), {"b": str})
|
self.assertEqual(annotationlib.get_annotations(NoDict), {"b": str})
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
annotationlib.get_annotations(
|
annotationlib.get_annotations(NoDict, format=Format.FORWARDREF),
|
||||||
NoDict, format=annotationlib.Format.FORWARDREF
|
|
||||||
),
|
|
||||||
{"b": str},
|
{"b": str},
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
annotationlib.get_annotations(NoDict, format=annotationlib.Format.SOURCE),
|
annotationlib.get_annotations(NoDict, format=Format.STRING),
|
||||||
{"b": "str"},
|
{"b": "str"},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -410,20 +403,20 @@ class TestGetAnnotations(unittest.TestCase):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
annotationlib.get_annotations(f1, format=annotationlib.Format.VALUE),
|
annotationlib.get_annotations(f1, format=Format.VALUE),
|
||||||
{"a": int},
|
{"a": int},
|
||||||
)
|
)
|
||||||
self.assertEqual(annotationlib.get_annotations(f1, format=1), {"a": int})
|
self.assertEqual(annotationlib.get_annotations(f1, format=1), {"a": int})
|
||||||
|
|
||||||
fwd = annotationlib.ForwardRef("undefined")
|
fwd = annotationlib.ForwardRef("undefined")
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
annotationlib.get_annotations(f2, format=annotationlib.Format.FORWARDREF),
|
annotationlib.get_annotations(f2, format=Format.FORWARDREF),
|
||||||
{"a": fwd},
|
{"a": fwd},
|
||||||
)
|
)
|
||||||
self.assertEqual(annotationlib.get_annotations(f2, format=2), {"a": fwd})
|
self.assertEqual(annotationlib.get_annotations(f2, format=2), {"a": fwd})
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
annotationlib.get_annotations(f1, format=annotationlib.Format.SOURCE),
|
annotationlib.get_annotations(f1, format=Format.STRING),
|
||||||
{"a": "int"},
|
{"a": "int"},
|
||||||
)
|
)
|
||||||
self.assertEqual(annotationlib.get_annotations(f1, format=3), {"a": "int"})
|
self.assertEqual(annotationlib.get_annotations(f1, format=3), {"a": "int"})
|
||||||
|
@ -446,30 +439,26 @@ class TestGetAnnotations(unittest.TestCase):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(ValueError):
|
||||||
annotationlib.get_annotations(
|
annotationlib.get_annotations(foo, format=Format.FORWARDREF, eval_str=True)
|
||||||
foo, format=annotationlib.Format.FORWARDREF, eval_str=True
|
annotationlib.get_annotations(foo, format=Format.STRING, eval_str=True)
|
||||||
)
|
|
||||||
annotationlib.get_annotations(
|
|
||||||
foo, format=annotationlib.Format.SOURCE, eval_str=True
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_stock_annotations(self):
|
def test_stock_annotations(self):
|
||||||
def foo(a: int, b: str):
|
def foo(a: int, b: str):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
for format in (annotationlib.Format.VALUE, annotationlib.Format.FORWARDREF):
|
for format in (Format.VALUE, Format.FORWARDREF):
|
||||||
with self.subTest(format=format):
|
with self.subTest(format=format):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
annotationlib.get_annotations(foo, format=format),
|
annotationlib.get_annotations(foo, format=format),
|
||||||
{"a": int, "b": str},
|
{"a": int, "b": str},
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
annotationlib.get_annotations(foo, format=annotationlib.Format.SOURCE),
|
annotationlib.get_annotations(foo, format=Format.STRING),
|
||||||
{"a": "int", "b": "str"},
|
{"a": "int", "b": "str"},
|
||||||
)
|
)
|
||||||
|
|
||||||
foo.__annotations__ = {"a": "foo", "b": "str"}
|
foo.__annotations__ = {"a": "foo", "b": "str"}
|
||||||
for format in annotationlib.Format:
|
for format in Format:
|
||||||
with self.subTest(format=format):
|
with self.subTest(format=format):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
annotationlib.get_annotations(foo, format=format),
|
annotationlib.get_annotations(foo, format=format),
|
||||||
|
@ -491,10 +480,10 @@ class TestGetAnnotations(unittest.TestCase):
|
||||||
for kwargs in [
|
for kwargs in [
|
||||||
{},
|
{},
|
||||||
{"eval_str": False},
|
{"eval_str": False},
|
||||||
{"format": annotationlib.Format.VALUE},
|
{"format": Format.VALUE},
|
||||||
{"format": annotationlib.Format.FORWARDREF},
|
{"format": Format.FORWARDREF},
|
||||||
{"format": annotationlib.Format.VALUE, "eval_str": False},
|
{"format": Format.VALUE, "eval_str": False},
|
||||||
{"format": annotationlib.Format.FORWARDREF, "eval_str": False},
|
{"format": Format.FORWARDREF, "eval_str": False},
|
||||||
]:
|
]:
|
||||||
with self.subTest(**kwargs):
|
with self.subTest(**kwargs):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
|
@ -529,7 +518,7 @@ class TestGetAnnotations(unittest.TestCase):
|
||||||
|
|
||||||
for kwargs in [
|
for kwargs in [
|
||||||
{"eval_str": True},
|
{"eval_str": True},
|
||||||
{"format": annotationlib.Format.VALUE, "eval_str": True},
|
{"format": Format.VALUE, "eval_str": True},
|
||||||
]:
|
]:
|
||||||
with self.subTest(**kwargs):
|
with self.subTest(**kwargs):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
|
@ -563,48 +552,36 @@ class TestGetAnnotations(unittest.TestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
annotationlib.get_annotations(isa, format=annotationlib.Format.SOURCE),
|
annotationlib.get_annotations(isa, format=Format.STRING),
|
||||||
{"a": "int", "b": "str"},
|
{"a": "int", "b": "str"},
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
annotationlib.get_annotations(
|
annotationlib.get_annotations(isa.MyClass, format=Format.STRING),
|
||||||
isa.MyClass, format=annotationlib.Format.SOURCE
|
|
||||||
),
|
|
||||||
{"a": "int", "b": "str"},
|
{"a": "int", "b": "str"},
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
annotationlib.get_annotations(
|
annotationlib.get_annotations(isa.function, format=Format.STRING),
|
||||||
isa.function, format=annotationlib.Format.SOURCE
|
|
||||||
),
|
|
||||||
{"a": "int", "b": "str", "return": "MyClass"},
|
{"a": "int", "b": "str", "return": "MyClass"},
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
annotationlib.get_annotations(
|
annotationlib.get_annotations(isa.function2, format=Format.STRING),
|
||||||
isa.function2, format=annotationlib.Format.SOURCE
|
|
||||||
),
|
|
||||||
{"a": "int", "b": "str", "c": "MyClass", "return": "MyClass"},
|
{"a": "int", "b": "str", "c": "MyClass", "return": "MyClass"},
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
annotationlib.get_annotations(
|
annotationlib.get_annotations(isa.function3, format=Format.STRING),
|
||||||
isa.function3, format=annotationlib.Format.SOURCE
|
|
||||||
),
|
|
||||||
{"a": "int", "b": "str", "c": "MyClass"},
|
{"a": "int", "b": "str", "c": "MyClass"},
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
annotationlib.get_annotations(
|
annotationlib.get_annotations(annotationlib, format=Format.STRING),
|
||||||
annotationlib, format=annotationlib.Format.SOURCE
|
{},
|
||||||
),
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
annotationlib.get_annotations(isa.UnannotatedClass, format=Format.STRING),
|
||||||
{},
|
{},
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
annotationlib.get_annotations(
|
annotationlib.get_annotations(
|
||||||
isa.UnannotatedClass, format=annotationlib.Format.SOURCE
|
isa.unannotated_function, format=Format.STRING
|
||||||
),
|
|
||||||
{},
|
|
||||||
)
|
|
||||||
self.assertEqual(
|
|
||||||
annotationlib.get_annotations(
|
|
||||||
isa.unannotated_function, format=annotationlib.Format.SOURCE
|
|
||||||
),
|
),
|
||||||
{},
|
{},
|
||||||
)
|
)
|
||||||
|
@ -620,13 +597,11 @@ class TestGetAnnotations(unittest.TestCase):
|
||||||
{"a": int, "b": str, "return": isa.MyClass},
|
{"a": int, "b": str, "return": isa.MyClass},
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
annotationlib.get_annotations(
|
annotationlib.get_annotations(wrapped, format=Format.FORWARDREF),
|
||||||
wrapped, format=annotationlib.Format.FORWARDREF
|
|
||||||
),
|
|
||||||
{"a": int, "b": str, "return": isa.MyClass},
|
{"a": int, "b": str, "return": isa.MyClass},
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
annotationlib.get_annotations(wrapped, format=annotationlib.Format.SOURCE),
|
annotationlib.get_annotations(wrapped, format=Format.STRING),
|
||||||
{"a": "int", "b": "str", "return": "MyClass"},
|
{"a": "int", "b": "str", "return": "MyClass"},
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
|
@ -643,12 +618,12 @@ class TestGetAnnotations(unittest.TestCase):
|
||||||
for kwargs in [
|
for kwargs in [
|
||||||
{},
|
{},
|
||||||
{"eval_str": False},
|
{"eval_str": False},
|
||||||
{"format": annotationlib.Format.VALUE},
|
{"format": Format.VALUE},
|
||||||
{"format": annotationlib.Format.FORWARDREF},
|
{"format": Format.FORWARDREF},
|
||||||
{"format": annotationlib.Format.SOURCE},
|
{"format": Format.STRING},
|
||||||
{"format": annotationlib.Format.VALUE, "eval_str": False},
|
{"format": Format.VALUE, "eval_str": False},
|
||||||
{"format": annotationlib.Format.FORWARDREF, "eval_str": False},
|
{"format": Format.FORWARDREF, "eval_str": False},
|
||||||
{"format": annotationlib.Format.SOURCE, "eval_str": False},
|
{"format": Format.STRING, "eval_str": False},
|
||||||
]:
|
]:
|
||||||
with self.subTest(**kwargs):
|
with self.subTest(**kwargs):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
|
@ -681,7 +656,7 @@ class TestGetAnnotations(unittest.TestCase):
|
||||||
|
|
||||||
for kwargs in [
|
for kwargs in [
|
||||||
{"eval_str": True},
|
{"eval_str": True},
|
||||||
{"format": annotationlib.Format.VALUE, "eval_str": True},
|
{"format": Format.VALUE, "eval_str": True},
|
||||||
]:
|
]:
|
||||||
with self.subTest(**kwargs):
|
with self.subTest(**kwargs):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
|
@ -767,9 +742,9 @@ class TestGetAnnotations(unittest.TestCase):
|
||||||
annotationlib.get_annotations(f, format=Format.FORWARDREF),
|
annotationlib.get_annotations(f, format=Format.FORWARDREF),
|
||||||
{"x": str},
|
{"x": str},
|
||||||
)
|
)
|
||||||
# ... but not in SOURCE which always uses __annotate__
|
# ... but not in STRING which always uses __annotate__
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
annotationlib.get_annotations(f, format=Format.SOURCE),
|
annotationlib.get_annotations(f, format=Format.STRING),
|
||||||
{"x": "int"},
|
{"x": "int"},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -804,7 +779,7 @@ class TestGetAnnotations(unittest.TestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
annotationlib.get_annotations(ha, format=Format.SOURCE), {"x": "int"}
|
annotationlib.get_annotations(ha, format=Format.STRING), {"x": "int"}
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_raising_annotations_on_custom_object(self):
|
def test_raising_annotations_on_custom_object(self):
|
||||||
|
@ -844,7 +819,7 @@ class TestGetAnnotations(unittest.TestCase):
|
||||||
annotationlib.get_annotations(hb, format=Format.FORWARDREF), {"x": int}
|
annotationlib.get_annotations(hb, format=Format.FORWARDREF), {"x": int}
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
annotationlib.get_annotations(hb, format=Format.SOURCE), {"x": str}
|
annotationlib.get_annotations(hb, format=Format.STRING), {"x": str}
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_pep695_generic_class_with_future_annotations(self):
|
def test_pep695_generic_class_with_future_annotations(self):
|
||||||
|
@ -974,15 +949,13 @@ class TestCallEvaluateFunction(unittest.TestCase):
|
||||||
return undefined
|
return undefined
|
||||||
|
|
||||||
with self.assertRaises(NameError):
|
with self.assertRaises(NameError):
|
||||||
annotationlib.call_evaluate_function(evaluate, annotationlib.Format.VALUE)
|
annotationlib.call_evaluate_function(evaluate, Format.VALUE)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
annotationlib.call_evaluate_function(
|
annotationlib.call_evaluate_function(evaluate, Format.FORWARDREF),
|
||||||
evaluate, annotationlib.Format.FORWARDREF
|
|
||||||
),
|
|
||||||
annotationlib.ForwardRef("undefined"),
|
annotationlib.ForwardRef("undefined"),
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
annotationlib.call_evaluate_function(evaluate, annotationlib.Format.SOURCE),
|
annotationlib.call_evaluate_function(evaluate, Format.STRING),
|
||||||
"undefined",
|
"undefined",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1093,25 +1066,25 @@ class TestGetAnnotateFunction(unittest.TestCase):
|
||||||
|
|
||||||
|
|
||||||
class TestToSource(unittest.TestCase):
|
class TestToSource(unittest.TestCase):
|
||||||
def test_value_to_source(self):
|
def test_value_to_string(self):
|
||||||
self.assertEqual(value_to_source(int), "int")
|
self.assertEqual(value_to_string(int), "int")
|
||||||
self.assertEqual(value_to_source(MyClass), "test.test_annotationlib.MyClass")
|
self.assertEqual(value_to_string(MyClass), "test.test_annotationlib.MyClass")
|
||||||
self.assertEqual(value_to_source(len), "len")
|
self.assertEqual(value_to_string(len), "len")
|
||||||
self.assertEqual(value_to_source(value_to_source), "value_to_source")
|
self.assertEqual(value_to_string(value_to_string), "value_to_string")
|
||||||
self.assertEqual(value_to_source(times_three), "times_three")
|
self.assertEqual(value_to_string(times_three), "times_three")
|
||||||
self.assertEqual(value_to_source(...), "...")
|
self.assertEqual(value_to_string(...), "...")
|
||||||
self.assertEqual(value_to_source(None), "None")
|
self.assertEqual(value_to_string(None), "None")
|
||||||
self.assertEqual(value_to_source(1), "1")
|
self.assertEqual(value_to_string(1), "1")
|
||||||
self.assertEqual(value_to_source("1"), "'1'")
|
self.assertEqual(value_to_string("1"), "'1'")
|
||||||
self.assertEqual(value_to_source(Format.VALUE), repr(Format.VALUE))
|
self.assertEqual(value_to_string(Format.VALUE), repr(Format.VALUE))
|
||||||
self.assertEqual(value_to_source(MyClass()), "my repr")
|
self.assertEqual(value_to_string(MyClass()), "my repr")
|
||||||
|
|
||||||
def test_annotations_to_source(self):
|
def test_annotations_to_string(self):
|
||||||
self.assertEqual(annotations_to_source({}), {})
|
self.assertEqual(annotations_to_string({}), {})
|
||||||
self.assertEqual(annotations_to_source({"x": int}), {"x": "int"})
|
self.assertEqual(annotations_to_string({"x": int}), {"x": "int"})
|
||||||
self.assertEqual(annotations_to_source({"x": "int"}), {"x": "int"})
|
self.assertEqual(annotations_to_string({"x": "int"}), {"x": "int"})
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
annotations_to_source({"x": int, "y": str}), {"x": "int", "y": "str"}
|
annotations_to_string({"x": int, "y": str}), {"x": "int", "y": "str"}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -375,7 +375,7 @@ class DeferredEvaluationTests(unittest.TestCase):
|
||||||
with self.assertRaises(NotImplementedError):
|
with self.assertRaises(NotImplementedError):
|
||||||
annotate(annotationlib.Format.FORWARDREF)
|
annotate(annotationlib.Format.FORWARDREF)
|
||||||
with self.assertRaises(NotImplementedError):
|
with self.assertRaises(NotImplementedError):
|
||||||
annotate(annotationlib.Format.SOURCE)
|
annotate(annotationlib.Format.STRING)
|
||||||
with self.assertRaises(NotImplementedError):
|
with self.assertRaises(NotImplementedError):
|
||||||
annotate(None)
|
annotate(None)
|
||||||
self.assertEqual(annotate(annotationlib.Format.VALUE), {"x": int})
|
self.assertEqual(annotate(annotationlib.Format.VALUE), {"x": int})
|
||||||
|
|
|
@ -1440,7 +1440,7 @@ class TestEvaluateFunctions(unittest.TestCase):
|
||||||
self.assertIs(case(1), int)
|
self.assertIs(case(1), int)
|
||||||
self.assertIs(annotationlib.call_evaluate_function(case, annotationlib.Format.VALUE), int)
|
self.assertIs(annotationlib.call_evaluate_function(case, annotationlib.Format.VALUE), int)
|
||||||
self.assertIs(annotationlib.call_evaluate_function(case, annotationlib.Format.FORWARDREF), int)
|
self.assertIs(annotationlib.call_evaluate_function(case, annotationlib.Format.FORWARDREF), int)
|
||||||
self.assertEqual(annotationlib.call_evaluate_function(case, annotationlib.Format.SOURCE), 'int')
|
self.assertEqual(annotationlib.call_evaluate_function(case, annotationlib.Format.STRING), 'int')
|
||||||
|
|
||||||
def test_constraints(self):
|
def test_constraints(self):
|
||||||
def f[T: (int, str)](): pass
|
def f[T: (int, str)](): pass
|
||||||
|
@ -1451,7 +1451,7 @@ class TestEvaluateFunctions(unittest.TestCase):
|
||||||
self.assertEqual(case.evaluate_constraints(1), (int, str))
|
self.assertEqual(case.evaluate_constraints(1), (int, str))
|
||||||
self.assertEqual(annotationlib.call_evaluate_function(case.evaluate_constraints, annotationlib.Format.VALUE), (int, str))
|
self.assertEqual(annotationlib.call_evaluate_function(case.evaluate_constraints, annotationlib.Format.VALUE), (int, str))
|
||||||
self.assertEqual(annotationlib.call_evaluate_function(case.evaluate_constraints, annotationlib.Format.FORWARDREF), (int, str))
|
self.assertEqual(annotationlib.call_evaluate_function(case.evaluate_constraints, annotationlib.Format.FORWARDREF), (int, str))
|
||||||
self.assertEqual(annotationlib.call_evaluate_function(case.evaluate_constraints, annotationlib.Format.SOURCE), '(int, str)')
|
self.assertEqual(annotationlib.call_evaluate_function(case.evaluate_constraints, annotationlib.Format.STRING), '(int, str)')
|
||||||
|
|
||||||
def test_const_evaluator(self):
|
def test_const_evaluator(self):
|
||||||
T = TypeVar("T", bound=int)
|
T = TypeVar("T", bound=int)
|
||||||
|
|
|
@ -7059,7 +7059,7 @@ class GetTypeHintTests(BaseTestCase):
|
||||||
self.assertIsInstance(annos['x'], annotationlib.ForwardRef)
|
self.assertIsInstance(annos['x'], annotationlib.ForwardRef)
|
||||||
self.assertEqual(annos['x'].__arg__, 'undefined')
|
self.assertEqual(annos['x'].__arg__, 'undefined')
|
||||||
|
|
||||||
self.assertEqual(get_type_hints(C, format=annotationlib.Format.SOURCE),
|
self.assertEqual(get_type_hints(C, format=annotationlib.Format.STRING),
|
||||||
{'x': 'undefined'})
|
{'x': 'undefined'})
|
||||||
|
|
||||||
|
|
||||||
|
@ -7898,7 +7898,7 @@ class NamedTupleTests(BaseTestCase):
|
||||||
self.assertEqual(Z.__annotations__, annos)
|
self.assertEqual(Z.__annotations__, annos)
|
||||||
self.assertEqual(Z.__annotate__(annotationlib.Format.VALUE), annos)
|
self.assertEqual(Z.__annotate__(annotationlib.Format.VALUE), annos)
|
||||||
self.assertEqual(Z.__annotate__(annotationlib.Format.FORWARDREF), annos)
|
self.assertEqual(Z.__annotate__(annotationlib.Format.FORWARDREF), annos)
|
||||||
self.assertEqual(Z.__annotate__(annotationlib.Format.SOURCE), {"a": "None", "b": "str"})
|
self.assertEqual(Z.__annotate__(annotationlib.Format.STRING), {"a": "None", "b": "str"})
|
||||||
|
|
||||||
def test_future_annotations(self):
|
def test_future_annotations(self):
|
||||||
code = """
|
code = """
|
||||||
|
@ -8241,7 +8241,7 @@ class TypedDictTests(BaseTestCase):
|
||||||
self.assertEqual(Emp.__annotations__, annos)
|
self.assertEqual(Emp.__annotations__, annos)
|
||||||
self.assertEqual(Emp.__annotate__(annotationlib.Format.VALUE), annos)
|
self.assertEqual(Emp.__annotate__(annotationlib.Format.VALUE), annos)
|
||||||
self.assertEqual(Emp.__annotate__(annotationlib.Format.FORWARDREF), annos)
|
self.assertEqual(Emp.__annotate__(annotationlib.Format.FORWARDREF), annos)
|
||||||
self.assertEqual(Emp.__annotate__(annotationlib.Format.SOURCE), {'name': 'str', 'id': 'int'})
|
self.assertEqual(Emp.__annotate__(annotationlib.Format.STRING), {'name': 'str', 'id': 'int'})
|
||||||
self.assertEqual(Emp.__total__, True)
|
self.assertEqual(Emp.__total__, True)
|
||||||
self.assertEqual(Emp.__required_keys__, {'name', 'id'})
|
self.assertEqual(Emp.__required_keys__, {'name', 'id'})
|
||||||
self.assertIsInstance(Emp.__required_keys__, frozenset)
|
self.assertIsInstance(Emp.__required_keys__, frozenset)
|
||||||
|
@ -8603,7 +8603,7 @@ class TypedDictTests(BaseTestCase):
|
||||||
self.assertEqual(A.__orig_bases__, (TypedDict, Generic[T]))
|
self.assertEqual(A.__orig_bases__, (TypedDict, Generic[T]))
|
||||||
self.assertEqual(A.__mro__, (A, Generic, dict, object))
|
self.assertEqual(A.__mro__, (A, Generic, dict, object))
|
||||||
self.assertEqual(A.__annotations__, {'a': T})
|
self.assertEqual(A.__annotations__, {'a': T})
|
||||||
self.assertEqual(A.__annotate__(annotationlib.Format.SOURCE), {'a': 'T'})
|
self.assertEqual(A.__annotate__(annotationlib.Format.STRING), {'a': 'T'})
|
||||||
self.assertEqual(A.__parameters__, (T,))
|
self.assertEqual(A.__parameters__, (T,))
|
||||||
self.assertEqual(A[str].__parameters__, ())
|
self.assertEqual(A[str].__parameters__, ())
|
||||||
self.assertEqual(A[str].__args__, (str,))
|
self.assertEqual(A[str].__args__, (str,))
|
||||||
|
@ -8616,7 +8616,7 @@ class TypedDictTests(BaseTestCase):
|
||||||
self.assertEqual(A.__orig_bases__, (TypedDict, Generic[T]))
|
self.assertEqual(A.__orig_bases__, (TypedDict, Generic[T]))
|
||||||
self.assertEqual(A.__mro__, (A, Generic, dict, object))
|
self.assertEqual(A.__mro__, (A, Generic, dict, object))
|
||||||
self.assertEqual(A.__annotations__, {'a': T})
|
self.assertEqual(A.__annotations__, {'a': T})
|
||||||
self.assertEqual(A.__annotate__(annotationlib.Format.SOURCE), {'a': 'T'})
|
self.assertEqual(A.__annotate__(annotationlib.Format.STRING), {'a': 'T'})
|
||||||
self.assertEqual(A.__parameters__, (T,))
|
self.assertEqual(A.__parameters__, (T,))
|
||||||
self.assertEqual(A[str].__parameters__, ())
|
self.assertEqual(A[str].__parameters__, ())
|
||||||
self.assertEqual(A[str].__args__, (str,))
|
self.assertEqual(A[str].__args__, (str,))
|
||||||
|
@ -8628,7 +8628,7 @@ class TypedDictTests(BaseTestCase):
|
||||||
self.assertEqual(A2.__orig_bases__, (Generic[T], TypedDict))
|
self.assertEqual(A2.__orig_bases__, (Generic[T], TypedDict))
|
||||||
self.assertEqual(A2.__mro__, (A2, Generic, dict, object))
|
self.assertEqual(A2.__mro__, (A2, Generic, dict, object))
|
||||||
self.assertEqual(A2.__annotations__, {'a': T})
|
self.assertEqual(A2.__annotations__, {'a': T})
|
||||||
self.assertEqual(A2.__annotate__(annotationlib.Format.SOURCE), {'a': 'T'})
|
self.assertEqual(A2.__annotate__(annotationlib.Format.STRING), {'a': 'T'})
|
||||||
self.assertEqual(A2.__parameters__, (T,))
|
self.assertEqual(A2.__parameters__, (T,))
|
||||||
self.assertEqual(A2[str].__parameters__, ())
|
self.assertEqual(A2[str].__parameters__, ())
|
||||||
self.assertEqual(A2[str].__args__, (str,))
|
self.assertEqual(A2[str].__args__, (str,))
|
||||||
|
@ -8640,7 +8640,7 @@ class TypedDictTests(BaseTestCase):
|
||||||
self.assertEqual(B.__orig_bases__, (A[KT],))
|
self.assertEqual(B.__orig_bases__, (A[KT],))
|
||||||
self.assertEqual(B.__mro__, (B, Generic, dict, object))
|
self.assertEqual(B.__mro__, (B, Generic, dict, object))
|
||||||
self.assertEqual(B.__annotations__, {'a': T, 'b': KT})
|
self.assertEqual(B.__annotations__, {'a': T, 'b': KT})
|
||||||
self.assertEqual(B.__annotate__(annotationlib.Format.SOURCE), {'a': 'T', 'b': 'KT'})
|
self.assertEqual(B.__annotate__(annotationlib.Format.STRING), {'a': 'T', 'b': 'KT'})
|
||||||
self.assertEqual(B.__parameters__, (KT,))
|
self.assertEqual(B.__parameters__, (KT,))
|
||||||
self.assertEqual(B.__total__, False)
|
self.assertEqual(B.__total__, False)
|
||||||
self.assertEqual(B.__optional_keys__, frozenset(['b']))
|
self.assertEqual(B.__optional_keys__, frozenset(['b']))
|
||||||
|
@ -8665,7 +8665,7 @@ class TypedDictTests(BaseTestCase):
|
||||||
'b': KT,
|
'b': KT,
|
||||||
'c': int,
|
'c': int,
|
||||||
})
|
})
|
||||||
self.assertEqual(C.__annotate__(annotationlib.Format.SOURCE), {
|
self.assertEqual(C.__annotate__(annotationlib.Format.STRING), {
|
||||||
'a': 'T',
|
'a': 'T',
|
||||||
'b': 'KT',
|
'b': 'KT',
|
||||||
'c': 'int',
|
'c': 'int',
|
||||||
|
@ -8689,7 +8689,7 @@ class TypedDictTests(BaseTestCase):
|
||||||
'b': T,
|
'b': T,
|
||||||
'c': KT,
|
'c': KT,
|
||||||
})
|
})
|
||||||
self.assertEqual(Point3D.__annotate__(annotationlib.Format.SOURCE), {
|
self.assertEqual(Point3D.__annotate__(annotationlib.Format.STRING), {
|
||||||
'a': 'T',
|
'a': 'T',
|
||||||
'b': 'T',
|
'b': 'T',
|
||||||
'c': 'KT',
|
'c': 'KT',
|
||||||
|
@ -8725,7 +8725,7 @@ class TypedDictTests(BaseTestCase):
|
||||||
'b': KT,
|
'b': KT,
|
||||||
'c': int,
|
'c': int,
|
||||||
})
|
})
|
||||||
self.assertEqual(WithImplicitAny.__annotate__(annotationlib.Format.SOURCE), {
|
self.assertEqual(WithImplicitAny.__annotate__(annotationlib.Format.STRING), {
|
||||||
'a': 'T',
|
'a': 'T',
|
||||||
'b': 'KT',
|
'b': 'KT',
|
||||||
'c': 'int',
|
'c': 'int',
|
||||||
|
@ -8929,7 +8929,7 @@ class TypedDictTests(BaseTestCase):
|
||||||
A.__annotations__
|
A.__annotations__
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
A.__annotate__(annotationlib.Format.SOURCE),
|
A.__annotate__(annotationlib.Format.STRING),
|
||||||
{'x': 'NotRequired[undefined]', 'y': 'ReadOnly[undefined]',
|
{'x': 'NotRequired[undefined]', 'y': 'ReadOnly[undefined]',
|
||||||
'z': 'Required[undefined]'},
|
'z': 'Required[undefined]'},
|
||||||
)
|
)
|
||||||
|
|
|
@ -245,7 +245,7 @@ def _type_repr(obj):
|
||||||
if isinstance(obj, tuple):
|
if isinstance(obj, tuple):
|
||||||
# Special case for `repr` of types with `ParamSpec`:
|
# Special case for `repr` of types with `ParamSpec`:
|
||||||
return '[' + ', '.join(_type_repr(t) for t in obj) + ']'
|
return '[' + ', '.join(_type_repr(t) for t in obj) + ']'
|
||||||
return annotationlib.value_to_source(obj)
|
return annotationlib.value_to_string(obj)
|
||||||
|
|
||||||
|
|
||||||
def _collect_type_parameters(args, *, enforce_default_ordering: bool = True):
|
def _collect_type_parameters(args, *, enforce_default_ordering: bool = True):
|
||||||
|
@ -1036,7 +1036,7 @@ def evaluate_forward_ref(
|
||||||
* Recursively evaluates forward references nested within the type hint.
|
* Recursively evaluates forward references nested within the type hint.
|
||||||
* Rejects certain objects that are not valid type hints.
|
* Rejects certain objects that are not valid type hints.
|
||||||
* Replaces type hints that evaluate to None with types.NoneType.
|
* Replaces type hints that evaluate to None with types.NoneType.
|
||||||
* Supports the *FORWARDREF* and *SOURCE* formats.
|
* Supports the *FORWARDREF* and *STRING* formats.
|
||||||
|
|
||||||
*forward_ref* must be an instance of ForwardRef. *owner*, if given,
|
*forward_ref* must be an instance of ForwardRef. *owner*, if given,
|
||||||
should be the object that holds the annotations that the forward reference
|
should be the object that holds the annotations that the forward reference
|
||||||
|
@ -1053,7 +1053,7 @@ def evaluate_forward_ref(
|
||||||
if type_params is _sentinel:
|
if type_params is _sentinel:
|
||||||
_deprecation_warning_for_no_type_params_passed("typing.evaluate_forward_ref")
|
_deprecation_warning_for_no_type_params_passed("typing.evaluate_forward_ref")
|
||||||
type_params = ()
|
type_params = ()
|
||||||
if format == annotationlib.Format.SOURCE:
|
if format == annotationlib.Format.STRING:
|
||||||
return forward_ref.__forward_arg__
|
return forward_ref.__forward_arg__
|
||||||
if forward_ref.__forward_arg__ in _recursive_guard:
|
if forward_ref.__forward_arg__ in _recursive_guard:
|
||||||
return forward_ref
|
return forward_ref
|
||||||
|
@ -2380,7 +2380,7 @@ def get_type_hints(obj, globalns=None, localns=None, include_extras=False,
|
||||||
hints = {}
|
hints = {}
|
||||||
for base in reversed(obj.__mro__):
|
for base in reversed(obj.__mro__):
|
||||||
ann = annotationlib.get_annotations(base, format=format)
|
ann = annotationlib.get_annotations(base, format=format)
|
||||||
if format is annotationlib.Format.SOURCE:
|
if format is annotationlib.Format.STRING:
|
||||||
hints.update(ann)
|
hints.update(ann)
|
||||||
continue
|
continue
|
||||||
if globalns is None:
|
if globalns is None:
|
||||||
|
@ -2404,7 +2404,7 @@ def get_type_hints(obj, globalns=None, localns=None, include_extras=False,
|
||||||
value = _eval_type(value, base_globals, base_locals, base.__type_params__,
|
value = _eval_type(value, base_globals, base_locals, base.__type_params__,
|
||||||
format=format, owner=obj)
|
format=format, owner=obj)
|
||||||
hints[name] = value
|
hints[name] = value
|
||||||
if include_extras or format is annotationlib.Format.SOURCE:
|
if include_extras or format is annotationlib.Format.STRING:
|
||||||
return hints
|
return hints
|
||||||
else:
|
else:
|
||||||
return {k: _strip_annotations(t) for k, t in hints.items()}
|
return {k: _strip_annotations(t) for k, t in hints.items()}
|
||||||
|
@ -2418,7 +2418,7 @@ def get_type_hints(obj, globalns=None, localns=None, include_extras=False,
|
||||||
and not hasattr(obj, '__annotate__')
|
and not hasattr(obj, '__annotate__')
|
||||||
):
|
):
|
||||||
raise TypeError(f"{obj!r} is not a module, class, or callable.")
|
raise TypeError(f"{obj!r} is not a module, class, or callable.")
|
||||||
if format is annotationlib.Format.SOURCE:
|
if format is annotationlib.Format.STRING:
|
||||||
return hints
|
return hints
|
||||||
|
|
||||||
if globalns is None:
|
if globalns is None:
|
||||||
|
@ -2937,7 +2937,7 @@ def _make_eager_annotate(types):
|
||||||
if format in (annotationlib.Format.VALUE, annotationlib.Format.FORWARDREF):
|
if format in (annotationlib.Format.VALUE, annotationlib.Format.FORWARDREF):
|
||||||
return checked_types
|
return checked_types
|
||||||
else:
|
else:
|
||||||
return annotationlib.annotations_to_source(types)
|
return annotationlib.annotations_to_string(types)
|
||||||
return annotate
|
return annotate
|
||||||
|
|
||||||
|
|
||||||
|
@ -2972,7 +2972,7 @@ class NamedTupleMeta(type):
|
||||||
|
|
||||||
def annotate(format):
|
def annotate(format):
|
||||||
annos = annotationlib.call_annotate_function(original_annotate, format)
|
annos = annotationlib.call_annotate_function(original_annotate, format)
|
||||||
if format != annotationlib.Format.SOURCE:
|
if format != annotationlib.Format.STRING:
|
||||||
return {key: _type_check(val, f"field {key} annotation must be a type")
|
return {key: _type_check(val, f"field {key} annotation must be a type")
|
||||||
for key, val in annos.items()}
|
for key, val in annos.items()}
|
||||||
return annos
|
return annos
|
||||||
|
@ -3220,13 +3220,13 @@ class _TypedDictMeta(type):
|
||||||
annos.update(base_annos)
|
annos.update(base_annos)
|
||||||
if own_annotate is not None:
|
if own_annotate is not None:
|
||||||
own = annotationlib.call_annotate_function(own_annotate, format, owner=tp_dict)
|
own = annotationlib.call_annotate_function(own_annotate, format, owner=tp_dict)
|
||||||
if format != annotationlib.Format.SOURCE:
|
if format != annotationlib.Format.STRING:
|
||||||
own = {
|
own = {
|
||||||
n: _type_check(tp, msg, module=tp_dict.__module__)
|
n: _type_check(tp, msg, module=tp_dict.__module__)
|
||||||
for n, tp in own.items()
|
for n, tp in own.items()
|
||||||
}
|
}
|
||||||
elif format == annotationlib.Format.SOURCE:
|
elif format == annotationlib.Format.STRING:
|
||||||
own = annotationlib.annotations_to_source(own_annotations)
|
own = annotationlib.annotations_to_string(own_annotations)
|
||||||
else:
|
else:
|
||||||
own = own_checked_annotations
|
own = own_checked_annotations
|
||||||
annos.update(own)
|
annos.update(own)
|
||||||
|
|
|
@ -168,7 +168,7 @@ constevaluator_call(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
PyObject *value = ((constevaluatorobject *)self)->value;
|
PyObject *value = ((constevaluatorobject *)self)->value;
|
||||||
if (format == 3) { // SOURCE
|
if (format == 3) { // STRING
|
||||||
PyUnicodeWriter *writer = PyUnicodeWriter_Create(5); // cannot be <5
|
PyUnicodeWriter *writer = PyUnicodeWriter_Create(5); // cannot be <5
|
||||||
if (writer == NULL) {
|
if (writer == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
Loading…
Reference in New Issue