FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

gh-141174: Improve `annotationlib.get_annotations()` test coverage by dr-carlos · Pull Request #141286 · python/cpython · GitHub

/ cpython Public
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension .py  (1) All 1 file type selected
Viewed files
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Unified
Split
Hide whitespace
Diff view
Unified
Split
Hide whitespace
70 changes: 69 additions & 1 deletion Lib/test/test_annotationlib.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import pickle
from string.templatelib import Template, Interpolation
import typing
import sys
import unittest
from annotationlib import (
Format,
Expand Down Expand Up @@ -755,6 +756,8 @@ def test_stringized_annotations_in_module(self):

for kwargs in [
{"eval_str": True},
{"eval_str": True, "globals": isa.__dict__, "locals": {}},
{"eval_str": True, "globals": {}, "locals": isa.__dict__},
{"format": Format.VALUE, "eval_str": True},
]:
with self.subTest(**kwargs):
Expand Down Expand Up @@ -788,7 +791,7 @@ def test_stringized_annotations_in_empty_module(self):
self.assertEqual(get_annotations(isa2, eval_str=False), {})

def test_stringized_annotations_with_star_unpack(self):
def f(*args: *tuple[int, ...]): ...
def f(*args: "*tuple[int, ...]"): ...
self.assertEqual(get_annotations(f, eval_str=True),
{'args': (*tuple[int, ...],)[0]})

Expand All @@ -811,6 +814,44 @@ def test_stringized_annotations_on_wrapper(self):
{"a": "int", "b": "str", "return": "MyClass"},
)

def test_stringized_annotations_on_partial_wrapper(self):
isa = inspect_stringized_annotations

def times_three_str(fn: typing.Callable[[str], isa.MyClass]):
@functools.wraps(fn)
def wrapper(b: "str") -> "MyClass":
return fn(b * 3)

return wrapper

wrapped = times_three_str(functools.partial(isa.function, 1))
self.assertEqual(wrapped("x"), isa.MyClass(1, "xxx"))
self.assertIsNot(wrapped.__globals__, isa.function.__globals__)
self.assertEqual(
get_annotations(wrapped, eval_str=True),
{"b": str, "return": isa.MyClass},
)
self.assertEqual(
get_annotations(wrapped, eval_str=False),
{"b": "str", "return": "MyClass"},
)

# If functools is not loaded, names will be evaluated in the current
# module instead of being unwrapped to the original.
functools_mod = sys.modules["functools"]
del sys.modules["functools"]

self.assertEqual(
get_annotations(wrapped, eval_str=True),
{"b": str, "return": MyClass},
)
self.assertEqual(
get_annotations(wrapped, eval_str=False),
{"b": "str", "return": "MyClass"},
)

sys.modules["functools"] = functools_mod

def test_stringized_annotations_on_class(self):
isa = inspect_stringized_annotations
# test that local namespace lookups work
Expand All @@ -823,6 +864,16 @@ def test_stringized_annotations_on_class(self):
{"x": int},
)

def test_stringized_annotations_on_custom_object(self):
class HasAnnotations:
@property
def __annotations__(self):
return {"x": "int"}

ha = HasAnnotations()
self.assertEqual(get_annotations(ha), {"x": "int"})
self.assertEqual(get_annotations(ha, eval_str=True), {"x": int})

def test_stringized_annotation_permutations(self):
def define_class(name, has_future, has_annos, base_text, extra_names=None):
lines = []
Expand Down Expand Up @@ -990,6 +1041,23 @@ def __annotate__(self):
{"x": "int"},
)

def test_non_dict_annotate(self):
class WeirdAnnotate:
def __annotate__(self, *args, **kwargs):
return "not a dict"

wa = WeirdAnnotate()
for format in Format:
if format == Format.VALUE_WITH_FAKE_GLOBALS:
continue
with (
self.subTest(format=format),
self.assertRaisesRegex(
ValueError, r".*__annotate__ returned a non-dict"
),
):
get_annotations(wa, format=format)

def test_no_annotations(self):
class CustomClass:
pass
Expand Down
Loading

Back | FazBrowse Home | New Git URL