Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Implementation of annotated abstractmethod is typed as Any #15669

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
anentropic opened this issue Jul 14, 2023 · 4 comments
Closed

Implementation of annotated abstractmethod is typed as Any #15669

anentropic opened this issue Jul 14, 2023 · 4 comments
Labels
bug mypy got something wrong

Comments

@anentropic
Copy link

anentropic commented Jul 14, 2023

Bug Report

If you add type annotations to an @abstractmethod in an ABC then I would expect that implementations of that method in concrete classes would be type-checked to match the types on the abstract method.

But mypy treats the implemented method as Any -> Any

To Reproduce

I was originally doing this with generics in the base class:

from __future__ import annotations

from abc import ABCMeta, abstractmethod
from datetime import date
from typing import Generic, TypeVar

T = TypeVar("T")


class GenericValidatorABC(Generic[T], metaclass=ABCMeta):
    @abstractmethod
    def validate(self, context, value: T) -> T:
        ...


class DateOfBirthValidator(GenericValidatorABC[date]):
    name = "date_of_birth"

    def validate(self, context, value):
        return value.year > 1900


reveal_type(DateOfBirthValidator.validate)

But it turns out that the problem also occurs in the simpler non-generic case too:

class DateValidatorABC(metaclass=ABCMeta):
    @abstractmethod
    def validate(self, context, value: date) -> date:
        ...


class DateOfBirthValidator2(DateValidatorABC):
    name = "date_of_birth"

    def validate(self, context, value):
        return value.year > 1900


reveal_type(DateOfBirthValidator2.validate)

Expected Behavior

I would expect mypy to infer, and require, the type of the implemented method to match the annotated type of the abstract method.

So there should be a type error from our implementations above as value is date but the method returns bool.

Actual Behavior

Instead, reveal_type shows:

main.py:21: note: Revealed type is "def (self: __main__.DateOfBirthValidator, context: Any, value: Any) -> Any"
main.py:37: note: Revealed type is "def (self: __main__.DateOfBirthValidator2, context: Any, value: Any) -> Any"

https://mypy-play.net/?mypy=latest&python=3.11&gist=9fc2dca490527a088fe7bc81601f1666

Your Environment

  • Mypy version used: 1.4.1
  • Mypy command-line flags:
  • Mypy configuration options from mypy.ini (and other config files):
  • Python version used: 3.11
@anentropic anentropic added the bug mypy got something wrong label Jul 14, 2023
@anentropic
Copy link
Author

A case that does cause mypy to complain is if the concrete implementation is fully annotated:

class DateValidatorABC(metaclass=ABCMeta):
    @abstractmethod
    def validate(self, context, value: date) -> date:
        ...


class DateOfBirthValidator3(DateValidatorABC):
    name = "date_of_birth"

    def validate(self, context, value: date) -> bool:
        return value.year > 1900

this gives:

error: Return type "bool" of "validate" incompatible with return type "date" in supertype "DateValidatorABC"  [override]

...which is exactly what I was hoping for.

I'm just using https://mypy-play.net/ with default options (I assume equivalent to mypy with no cli args), I wondered now if there was an option that would affect this.

Enabling --check-untyped-defs does not help the original examples.

--disallow-untyped-defs does of course error for the untyped method def, but not the incompatible type.

@erictraut
Copy link

Pyright implements type inference for parameters in subclasses based on annotations in parent classes, so it is consistent with the "expected behavior" you've requested above.

Mypy maintainers have previously stated that they think parameter types should always be explicit, even in subclasses. I don't know if their position has changed since then. Perhaps one of them could clarify.

@anentropic
Copy link
Author

@erictraut thanks

I am also in favour of explicit parameter types, but it seems weird to allow a (possibly unintended) implicit Any in subclass to override an explicit typing in the parent 🤔

seems like mypy needs to be run with --strict option or results are likely to be worthless

@Morikko
Copy link

Morikko commented Jan 15, 2025

#15669 (comment) The same example without the abstractmethod decorator is also raising an error.

Maybe the issue could be generalized to any method and not just abstract ones like: Overriding of an annotated method is typed as Any.

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

No branches or pull requests

4 participants