Skip to content

Commit

Permalink
Fixed Optional being removed from the AST if it was located within a …
Browse files Browse the repository at this point in the history
…subscript

Fixes #442.
  • Loading branch information
agronholm committed Mar 21, 2024
1 parent ab9594a commit 4c81a00
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 2 deletions.
2 changes: 2 additions & 0 deletions docs/versionhistory.rst
Expand Up @@ -7,6 +7,8 @@ This library adheres to
**UNRELEASED**

- Avoid creating reference cycles when type checking unions
- Fixed ``Optional[...]`` being removed from the AST if it was located within a
subscript (`#442 <https://github.com/agronholm/typeguard/issues/442>`_)

**4.1.5** (2023-09-11)

Expand Down
6 changes: 4 additions & 2 deletions src/typeguard/_transformer.py
Expand Up @@ -457,9 +457,11 @@ def visit_Subscript(self, node: Subscript) -> Any:
# If the transformer erased the slice entirely, just return the node
# value without the subscript (unless it's Optional, in which case erase
# the node entirely
if self._memo.name_matches(node.value, "typing.Optional"):
if self._memo.name_matches(
node.value, "typing.Optional"
) and not hasattr(node, "slice"):
return None
elif sys.version_info >= (3, 9) and not hasattr(node, "slice"):
if sys.version_info >= (3, 9) and not hasattr(node, "slice"):
return node.value
elif sys.version_info < (3, 9) and not hasattr(node.slice, "value"):
return node.value
Expand Down
27 changes: 27 additions & 0 deletions tests/test_transformer.py
Expand Up @@ -1042,6 +1042,33 @@ def foo(x: Optional[Hashable]) -> Optional[Hashable]:
).strip()
)

def test_optional_nested(self) -> None:
node = parse(
dedent(
"""
from typing import Any, List, Optional
def foo(x: List[Optional[int]]) -> None:
pass
"""
)
)
TypeguardTransformer().visit(node)
assert (
unparse(node)
== dedent(
"""
from typeguard import TypeCheckMemo
from typeguard._functions import check_argument_types
from typing import Any, List, Optional
def foo(x: List[Optional[int]]) -> None:
memo = TypeCheckMemo(globals(), locals())
check_argument_types('foo', {'x': (x, List[Optional[int]])}, memo)
"""
).strip()
)

def test_subscript_within_union(self) -> None:
# Regression test for #397
node = parse(
Expand Down

0 comments on commit 4c81a00

Please sign in to comment.