Skip to content

Commit

Permalink
Fixed TypeError when trying to check against a naked str forward refe…
Browse files Browse the repository at this point in the history
…rence
  • Loading branch information
agronholm committed Apr 30, 2023
1 parent b1fee6c commit fc673d4
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 2 deletions.
3 changes: 3 additions & 0 deletions docs/versionhistory.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ This library adheres to `Semantic Versioning 2.0 <https://semver.org/#semantic-v
- Added ``InstrumentationWarning`` to the public API
- Fixed instrumentation using ``typing.Optional`` without a subscript when the subscript
value was erased due to being an ignored import
- Fixed ``TypeError: isinstance() arg 2 must be a type or tuple of types`` when
instrumented code tries to check a value against a naked (``str``, not ``ForwardRef``)
forward reference

**4.0.0rc4** (2023-04-15)

Expand Down
12 changes: 10 additions & 2 deletions src/typeguard/_checkers.py
Original file line number Diff line number Diff line change
Expand Up @@ -756,8 +756,16 @@ def check_type_internal(
checker(value, origin_type, args, memo)
return

if not isinstance(value, origin_type):
raise TypeCheckError(f"is not an instance of {qualified_name(origin_type)}")
if isclass(origin_type):
if not isinstance(value, origin_type):
raise TypeCheckError(f"is not an instance of {qualified_name(origin_type)}")
elif type(origin_type) is str:
warnings.warn(
f"Skipping type check against {origin_type!r}; this looks like a "
f"string-form forward reference imported from another module",
TypeHintWarning,
stacklevel=get_stacklevel(),
)


# Equality checks are applied to these
Expand Down
10 changes: 10 additions & 0 deletions tests/test_checkers.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,10 @@
CollectionCheckStrategy,
ForwardRefPolicy,
TypeCheckError,
TypeCheckMemo,
TypeHintWarning,
check_type,
check_type_internal,
suppress_type_checks,
)
from typeguard._utils import qualified_name
Expand Down Expand Up @@ -1037,3 +1039,11 @@ def test_none():
def test_return_checked_value():
value = {"foo": 1}
assert check_type(value, Dict[str, int]) is value


def test_imported_str_forward_ref():
value = {"foo": 1}
memo = TypeCheckMemo(globals(), locals())
pattern = r"Skipping type check against 'Dict\[str, int\]'"
with pytest.warns(TypeHintWarning, match=pattern):
check_type_internal(value, "Dict[str, int]", memo)

0 comments on commit fc673d4

Please sign in to comment.