Skip to content

NotImplementedType behaves incorrectly in unions with classes #11457

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
robertschweizer opened this issue Feb 21, 2024 · 2 comments
Closed

NotImplementedType behaves incorrectly in unions with classes #11457

robertschweizer opened this issue Feb 21, 2024 · 2 comments

Comments

@robertschweizer
Copy link
Contributor

robertschweizer commented Feb 21, 2024

from collections.abc import Callable
from types import NotImplementedType


class MyClass:
    pass


callable_union: Callable | NotImplementedType
reveal_type(callable_union)
if not isinstance(callable_union, NotImplementedType):
    reveal_type(callable_union)  # Gets narrowed correctly

class_union: MyClass | NotImplementedType
reveal_type(class_union)
if not isinstance(class_union, NotImplementedType):
    reveal_type(class_union)  # Mypy does not narrow the type

Leads to the following output:

test.py:10: note: Revealed type is "Union[def (*Any, **Any) -> Any, builtins._NotImplementedType]"
test.py:12: note: Revealed type is "def (*Any, **Any) -> Any"
test.py:15: note: Revealed type is "Union[test.MyClass, builtins._NotImplementedType]"
test.py:17: note: Revealed type is "Union[test.MyClass, builtins._NotImplementedType]"

_NotImplementedType in stdlib/builtins.pyi currently inherits from Any. Removing that inheritance as in the below example fixes the issue for me:

from typing import final


@final
class _NotImplementedType:
    # A little weird, but typing the __call__ as NotImplemented makes the error message
    # for NotImplemented() much better
    __call__: NotImplemented  # type: ignore[valid-type]  # pyright: ignore[reportGeneralTypeIssues]


fixed_type: MyClass | _NotImplementedType
reveal_type(fixed_type)
if not isinstance(fixed_type, _NotImplementedType):
    reveal_type(fixed_type)  # Gets narrowed correctly

Edit: The inheritance from Any is actually by design: python/mypy#4791 (comment)

@srittau
Copy link
Collaborator

srittau commented Mar 15, 2024

Working as intended.

@srittau srittau closed this as not planned Won't fix, can't repro, duplicate, stale Mar 15, 2024
@robertschweizer
Copy link
Contributor Author

NotImplementedType is meant to inherit from Any.

The original issue is not handled correctly by mypy though I would say.

I support closing this ticket though. If, for mypy, NotImplementedType inherits from Any, it doesn't make sense to use it in isinstance checks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants