Skip to content

Commit

Permalink
Fixed NameError when a decorated method references an imported name
Browse files Browse the repository at this point in the history
Fixes #362.
  • Loading branch information
agronholm committed Jun 12, 2023
1 parent 8260f3c commit 845fcbc
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 6 deletions.
7 changes: 5 additions & 2 deletions docs/versionhistory.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ This library adheres to `Semantic Versioning 2.0 <https://semver.org/#semantic-v

**UNRELEASED**

- Fix handling of ``typing_extensions.Literal`` on Python 3.8 and 3.9
when ``typing_extensions>=4.6.0`` is installed.
- Fixed handling of ``typing_extensions.Literal`` on Python 3.8 and 3.9 when
``typing_extensions>=4.6.0`` is installed
(`#363 <https://github.com/agronholm/typeguard/issues/363>`_; PR by Alex Waygood)
- Fixed ``NameError`` when generated type checking code references an imported name from
a method (`#362 <https://github.com/agronholm/typeguard/issues/362>`_)

**4.0.0** (2023-05-12)

Expand Down
18 changes: 14 additions & 4 deletions src/typeguard/_transformer.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import ast
import builtins
import sys
import typing
from ast import (
AST,
Add,
Expand Down Expand Up @@ -395,14 +396,23 @@ def visit_Subscript(self, node: Subscript) -> Any:
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:]
items = cast(
typing.List[expr],
[self.generic_visit(slice_value.elts[0])]
+ slice_value.elts[1:],
)
else:
items = [self.visit(item) for item in slice_value.elts]
items = cast(
typing.List[expr],
[self.generic_visit(item) for item in slice_value.elts],
)

# If this is a Union and any of the items is None, erase the entire
# If this is a Union and any of the items is Any, erase the entire
# annotation
if self._memo.name_matches(node.value, "typing.Union") and any(
item is None for item in items
isinstance(item, expr)
and self._memo.name_matches(item, *anytype_names)
for item in items
):
return None

Expand Down
11 changes: 11 additions & 0 deletions tests/test_typechecked.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
AsyncGenerator,
AsyncIterable,
AsyncIterator,
Dict,
Generator,
Iterable,
Iterator,
Expand Down Expand Up @@ -622,3 +623,13 @@ def foo(x: int) -> None:
b'typeguard.TypeCheckError: argument "x" (str) is not an instance of '
b"int\n"
)


def test_reference_imported_name_from_method() -> None:
# Regression test for #362
@typechecked
class A:
def foo(self) -> Dict[str, Any]:
return {}

A().foo()

0 comments on commit 845fcbc

Please sign in to comment.