Skip to content

Commit

Permalink
Fixed TypeError when checking a class against type[Self]
Browse files Browse the repository at this point in the history
  • Loading branch information
agronholm committed Nov 2, 2024
1 parent 750286e commit 121efd5
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 5 deletions.
2 changes: 2 additions & 0 deletions docs/versionhistory.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ This library adheres to
``typing.no_type_check()`` (PR by @jolaf)
- Fixed checking of variable assignments involving tuple unpacking
(`#486 <https://github.com/agronholm/typeguard/pull/486>`_)
- Fixed ``TypeError`` when checking a class against ``type[Self]``
(`#481 <https://github.com/agronholm/typeguard/pull/481>`_)

**4.4.0** (2024-10-27)

Expand Down
5 changes: 3 additions & 2 deletions src/typeguard/_checkers.py
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,8 @@ def check_class(

if expected_class is Any:
return
elif expected_class is typing_extensions.Self:
check_self(value, get_origin(expected_class), get_args(expected_class), memo)
elif getattr(expected_class, "_is_protocol", False):
check_protocol(value, expected_class, (), memo)
elif isinstance(expected_class, TypeVar):
Expand Down Expand Up @@ -847,8 +849,7 @@ def check_self(
if isclass(value):
if not issubclass(value, memo.self_type):
raise TypeCheckError(
f"is not an instance of the self type "
f"({qualified_name(memo.self_type)})"
f"is not a subclass of the self type ({qualified_name(memo.self_type)})"
)
elif not isinstance(value, memo.self_type):
raise TypeCheckError(
Expand Down
4 changes: 1 addition & 3 deletions tests/test_checkers.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
)

import pytest
from typing_extensions import LiteralString

from typeguard import (
CollectionCheckStrategy,
Expand Down Expand Up @@ -64,12 +65,9 @@
)

if sys.version_info >= (3, 11):
from typing import LiteralString

SubclassableAny = Any
else:
from typing_extensions import Any as SubclassableAny
from typing_extensions import LiteralString

if sys.version_info >= (3, 10):
from typing import Concatenate, ParamSpec, TypeGuard
Expand Down
23 changes: 23 additions & 0 deletions tests/test_typechecked.py
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,29 @@ def method(cls, another: Self) -> None:
rf"test_classmethod_arg_invalid\.<locals>\.Foo\)"
)

def test_self_type_valid(self):
class Foo:
@typechecked
def method(cls, subclass: type[Self]) -> None:
pass

class Bar(Foo):
pass

Foo().method(Bar)

def test_self_type_invalid(self):
class Foo:
@typechecked
def method(cls, subclass: type[Self]) -> None:
pass

pytest.raises(TypeCheckError, Foo().method, int).match(
rf'argument "subclass" \(class int\) is not a subclass of the self type '
rf"\({__name__}\.{self.__class__.__name__}\."
rf"test_self_type_invalid\.<locals>\.Foo\)"
)


class TestMock:
def test_mock_argument(self):
Expand Down

0 comments on commit 121efd5

Please sign in to comment.