Skip to content

Commit

Permalink
Don't try to parse the second argument of Annotated as a forward refe…
Browse files Browse the repository at this point in the history
…rence

Fixes #353.
  • Loading branch information
agronholm committed May 7, 2023
1 parent 3863c0f commit be4dd33
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 1 deletion.
2 changes: 2 additions & 0 deletions docs/versionhistory.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ This library adheres to `Semantic Versioning 2.0 <https://semver.org/#semantic-v
- Fixed ``@typechecked`` optimization causing compilation of instrumented code to fail
when an ``if`` block was left empty by the AST transformer
(`#352 <https://github.com/agronholm/typeguard/issues/352>`_)
- Fixed the AST transformer trying to parse the second argument of ``typing.Annotated``
as a forward reference (`#353 <https://github.com/agronholm/typeguard/issues/353>`_)

**4.0.0rc5** (2023-05-01)

Expand Down
11 changes: 10 additions & 1 deletion src/typeguard/_transformer.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@
"typing.Literal",
"typing_extensions.Literal",
)
annotated_names = (
"typing.Annotated",
"typing_extensions.Annotated",
)
ignore_decorators = (
"typing.no_type_check",
"typeguard.typeguard_ignore",
Expand Down Expand Up @@ -388,7 +392,12 @@ def visit_Subscript(self, node: Subscript) -> Any:
slice_value = node.slice

if isinstance(slice_value, Tuple):
items = [self.visit(item) for item in slice_value.elts]
if self._memo.name_matches(node.value, *annotated_names):
# Only treat the first argument to typing.Annotated as a potential
# forward reference
items = [self.visit(slice_value.elts[0])] + slice_value.elts[1:]
else:
items = [self.visit(item) for item in slice_value.elts]

# If this is a Union and any of the items is None, erase the entire
# annotation
Expand Down
29 changes: 29 additions & 0 deletions tests/test_transformer.py
Original file line number Diff line number Diff line change
Expand Up @@ -1492,3 +1492,32 @@ def foo(x: str) -> None:
"""
).strip()
)


def test_dont_parse_annotated_2nd_arg() -> None:
# Regression test for #352
node = parse(
dedent(
"""
from typing import Annotated
def foo(x: Annotated[str, 'foo bar']) -> None:
pass
"""
)
)
TypeguardTransformer(["foo"]).visit(node)
assert (
unparse(node)
== dedent(
"""
from typing import Annotated
def foo(x: Annotated[str, 'foo bar']) -> None:
from typeguard import TypeCheckMemo
from typeguard._functions import check_argument_types
memo = TypeCheckMemo(globals(), locals())
check_argument_types('foo', {'x': (x, Annotated[str, 'foo bar'])}, memo)
"""
).strip()
)

0 comments on commit be4dd33

Please sign in to comment.