Skip to content

Commit

Permalink
Fixed subscripts of unimportable types not being handled correctly
Browse files Browse the repository at this point in the history
Fixes #336.
  • Loading branch information
agronholm committed Apr 11, 2023
1 parent 1bbe094 commit dee8c39
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 3 deletions.
5 changes: 5 additions & 0 deletions docs/versionhistory.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ Version history

This library adheres to `Semantic Versioning 2.0 <https://semver.org/#semantic-versioning-200>`_.

**UNRELEASED**

- Fixed imports guarded by ``if TYPE_CHECKING:`` when used with subscripts
(``SomeType[...]``) being replaced with ``Any[...]`` instead of just ``Any``

**4.0.0rc3** (2023-04-10)

- Fixed ``typing.Literal`` subscript contents being evaluated as forward references
Expand Down
6 changes: 6 additions & 0 deletions src/typeguard/_transformer.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,12 @@ def visit_Attribute(self, node: Attribute) -> Any:
return node

def visit_Subscript(self, node: Subscript) -> Any:
if self._memo.is_ignored_name(node.value):
if self.level > 0:
return self.transformer._get_import("typing", "Any")
else:
return None

self.level += 1

# The subscript of typing(_extensions).Literal can be any arbitrary string, so
Expand Down
16 changes: 15 additions & 1 deletion tests/dummymodule.py
Original file line number Diff line number Diff line change
Expand Up @@ -316,11 +316,25 @@ def typed_variable_args(


@typechecked
def guarded_type_hint(x: "Imaginary") -> "Imaginary":
def guarded_type_hint_plain(x: "Imaginary") -> "Imaginary":
y: Imaginary = x
return y


@typechecked
def guarded_type_hint_subscript_toplevel(x: "Imaginary[int]") -> "Imaginary[int]":
y: Imaginary[int] = x
return y


@typechecked
def guarded_type_hint_subscript_nested(
x: List["Imaginary[int]"],
) -> List["Imaginary[int]"]:
y: List[Imaginary[int]] = x
return y


@typechecked
def literal(x: Literal["foo"]) -> Literal["foo"]:
y: Literal["foo"] = x
Expand Down
11 changes: 9 additions & 2 deletions tests/test_instrumentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -332,8 +332,15 @@ def test_kwargs_fail(self, dummymodule):
dummymodule.typed_variable_args("foo", "bar", a="baz")


def test_guarded_type(dummymodule):
assert dummymodule.guarded_type_hint("foo") == "foo"
class TestGuardedType:
def test_plain(self, dummymodule):
assert dummymodule.guarded_type_hint_plain("foo") == "foo"

def test_subscript_toplevel(self, dummymodule):
assert dummymodule.guarded_type_hint_subscript_toplevel("foo") == "foo"

def test_subscript_nested(self, dummymodule):
assert dummymodule.guarded_type_hint_subscript_nested(["foo"]) == ["foo"]


def test_literal(dummymodule):
Expand Down

0 comments on commit dee8c39

Please sign in to comment.