-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
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
Check override compatibility for dynamically typed methods #17274
Conversation
This fixes python#9618 in a fairly aggressive way, by turning on all override checks for all methods. This means that with this change, MyPy will complain in cases where just inspecting type signatures involving `Any` is enough to establish that an override is a type error: - This includes the case of overriding `@final` as listed in python#9618 - But it also includes arity mismatches, for example when an untyped subclass method adds a required attribute not in the parent class method. The tests illustrate this, I added a test case to `check-functions.test` (is this a good place for it?) for the `@final` check specifically but also updated a few existing tests of dynamic logic. The resulting code change is very simple (since all override checks happen in the same place), and I think conceptually it is right to enable all these checks because the contract is that MyPy won't generally type check *bodies* of functions, but the function signatures are actually part of the *class* type definition which is (in other cases) sanity-checked even when there are no annotations. If we think that the arity checks are too big a change, I can work on a refactor that would let us validate *only* `@final` but not other properties. Maybe waiting for `mypy_primer` output is the way to go?
323cbd7
to
a463090
Compare
for more information, see https://pre-commit.ci
This comment has been minimized.
This comment has been minimized.
The mypy primer results suggest that there are a lot of packages relying on the ability to unsoundly change arity of function signatures. I'm not completely convinced this is a good reason a type checker should in principle allow incompatible overrides with untyped definitions, since these library authors are going to be stuck anyway if they ever try to add type annotations, but it does look like a big enough backward incompatibility that we might not want it in mypy by default. I'll put up an alternative PR where we only enable override checks when validating untyped defs, and see what the mypy_primer results show in that case. |
Diff from mypy_primer, showing the effect of this PR on open source code: comtypes (https://github.com/enthought/comtypes)
+ comtypes/test/__init__.py:159: error: Signature of "run" incompatible with supertype "TextTestRunner" [override]
+ comtypes/test/__init__.py:159: note: Superclass:
+ comtypes/test/__init__.py:159: note: def run(self, test: TestSuite | TestCase) -> TestResult
+ comtypes/test/__init__.py:159: note: Subclass:
+ comtypes/test/__init__.py:159: note: def run(self, test: Any, skipped: Any) -> Any
+ comtypes/server/localserver.py:37: error: Signature of "IUnknown_AddRef" incompatible with supertype "COMObject" [override]
+ comtypes/server/localserver.py:37: note: Superclass:
+ comtypes/server/localserver.py:37: note: def IUnknown_AddRef(self, this: Any, Any = ..., /, _debug: Any = ...) -> Any
+ comtypes/server/localserver.py:37: note: Subclass:
+ comtypes/server/localserver.py:37: note: def IUnknown_AddRef(self, this: Any) -> Any
+ comtypes/server/localserver.py:40: error: Signature of "IUnknown_Release" incompatible with supertype "COMObject" [override]
+ comtypes/server/localserver.py:40: note: Superclass:
+ comtypes/server/localserver.py:40: note: def IUnknown_Release(self, this: Any, Any = ..., /, _debug: Any = ...) -> Any
+ comtypes/server/localserver.py:40: note: Subclass:
+ comtypes/server/localserver.py:40: note: def IUnknown_Release(self, this: Any) -> Any
sockeye (https://github.com/awslabs/sockeye)
+ sockeye/lexicon.py:260: error: Signature of "get_blocked_trg_ids" incompatible with supertype "RestrictLexicon" [override]
+ sockeye/lexicon.py:260: note: Superclass:
+ sockeye/lexicon.py:260: note: def get_blocked_trg_ids(self, src_ids: Any | None = ...) -> Any
+ sockeye/lexicon.py:260: note: Subclass:
+ sockeye/lexicon.py:260: note: def get_blocked_trg_ids(self, src_ids: Any) -> Any
+ sockeye/lexicon.py:307: error: Signature of "get_allowed_trg_ids" incompatible with supertype "RestrictLexicon" [override]
+ sockeye/lexicon.py:307: note: Superclass:
+ sockeye/lexicon.py:307: note: def get_allowed_trg_ids(self, src_ids: Any | None = ...) -> Any
+ sockeye/lexicon.py:307: note: Subclass:
+ sockeye/lexicon.py:307: note: def get_allowed_trg_ids(self, src_ids: Any) -> Any
pandas (https://github.com/pandas-dev/pandas)
+ pandas/core/arrays/boolean.py:359: error: Signature of "_logical_method" incompatible with supertype "BaseMaskedArray" [override]
+ pandas/core/arrays/boolean.py:359: note: Superclass:
+ pandas/core/arrays/boolean.py:359: note: def _arith_method(self: BaseMaskedArray, other: Any, op: Any) -> Any
+ pandas/core/arrays/boolean.py:359: note: Subclass:
+ pandas/core/arrays/boolean.py:359: note: def _logical_method(self, other: Any, op: Any) -> Any
+ pandas/core/arrays/boolean.py:359: note: Superclass:
+ pandas/core/arrays/boolean.py:359: note: def _arith_method(self: BaseMaskedArray, other: Any, op: Any) -> Any
+ pandas/core/arrays/boolean.py:359: note: Subclass:
+ pandas/core/arrays/boolean.py:359: note: def _logical_method(self, other: Any, op: Any) -> Any
+ pandas/core/indexes/interval.py:993: error: Signature of "_intersection" incompatible with supertype "Index" [override]
+ pandas/core/indexes/interval.py:993: note: Superclass:
+ pandas/core/indexes/interval.py:993: note: def _intersection(self, other: Index, sort: bool = ...) -> Any
+ pandas/core/indexes/interval.py:993: note: Subclass:
+ pandas/core/indexes/interval.py:993: note: def _intersection(self, other: Any, sort: Any) -> Any
+ pandas/core/resample.py:1624: error: Signature of "_downsample" incompatible with supertype "Resampler" [override]
+ pandas/core/resample.py:1624: note: Superclass:
+ pandas/core/resample.py:1624: note: def _downsample(self, f: Any, **kwargs: Any) -> Any
+ pandas/core/resample.py:1624: note: Subclass:
+ pandas/core/resample.py:1624: note: def _downsample(self, how: Any, **kwargs: Any) -> Any
+ pandas/core/resample.py:1783: error: Signature of "_downsample" incompatible with supertype "Resampler" [override]
+ pandas/core/resample.py:1783: note: Superclass:
+ pandas/core/resample.py:1783: note: def _downsample(self, f: Any, **kwargs: Any) -> Any
+ pandas/core/resample.py:1783: note: Subclass:
+ pandas/core/resample.py:1783: note: def _downsample(self, how: Any, **kwargs: Any) -> Any
+ pandas/tests/window/test_win_type.py:159: error: Signature of "get_window_bounds" incompatible with supertype "BaseIndexer" [override]
+ pandas/tests/window/test_win_type.py:159: note: Superclass:
+ pandas/tests/window/test_win_type.py:159: note: def get_window_bounds(self, num_values: int = ..., min_periods: int | None = ..., center: bool | None = ..., closed: str | None = ..., step: int | None = ...) -> tuple[ndarray[Any, Any], ndarray[Any, Any]]
+ pandas/tests/window/test_win_type.py:159: note: Subclass:
+ pandas/tests/window/test_win_type.py:159: note: def get_window_bounds(self, num_values: Any, min_periods: Any, center: Any, closed: Any, step: Any) -> Any
+ pandas/tests/window/test_rolling.py:1293: error: Signature of "get_window_bounds" incompatible with supertype "BaseIndexer" [override]
+ pandas/tests/window/test_rolling.py:1293: note: Superclass:
+ pandas/tests/window/test_rolling.py:1293: note: def get_window_bounds(self, num_values: int = ..., min_periods: int | None = ..., center: bool | None = ..., closed: str | None = ..., step: int | None = ...) -> tuple[ndarray[Any, Any], ndarray[Any, Any]]
+ pandas/tests/window/test_rolling.py:1293: note: Subclass:
+ pandas/tests/window/test_rolling.py:1293: note: def get_window_bounds(self, num_values: Any, min_periods: Any, center: Any, closed: Any, step: Any) -> Any
+ pandas/tests/window/test_base_indexer.py:27: error: Signature of "get_window_bounds" incompatible with supertype "BaseIndexer" [override]
+ pandas/tests/window/test_base_indexer.py:27: note: Superclass:
+ pandas/tests/window/test_base_indexer.py:27: note: def get_window_bounds(self, num_values: int = ..., min_periods: int | None = ..., center: bool | None = ..., closed: str | None = ..., step: int | None = ...) -> tuple[ndarray[Any, Any], ndarray[Any, Any]]
+ pandas/tests/window/test_base_indexer.py:27: note: Subclass:
+ pandas/tests/window/test_base_indexer.py:27: note: def get_window_bounds(self) -> Any
+ pandas/tests/window/test_base_indexer.py:49: error: Signature of "get_window_bounds" incompatible with supertype "BaseIndexer" [override]
+ pandas/tests/window/test_base_indexer.py:49: note: Superclass:
+ pandas/tests/window/test_base_indexer.py:49: note: def get_window_bounds(self, num_values: int = ..., min_periods: int | None = ..., center: bool | None = ..., closed: str | None = ..., step: int | None = ...) -> tuple[ndarray[Any, Any], ndarray[Any, Any]]
+ pandas/tests/window/test_base_indexer.py:49: note: Subclass:
+ pandas/tests/window/test_base_indexer.py:49: note: def get_window_bounds(self, num_values: Any, min_periods: Any, center: Any, closed: Any, step: Any) -> Any
+ pandas/tests/window/test_base_indexer.py:71: error: Signature of "get_window_bounds" incompatible with supertype "BaseIndexer" [override]
+ pandas/tests/window/test_base_indexer.py:71: note: Superclass:
+ pandas/tests/window/test_base_indexer.py:71: note: def get_window_bounds(self, num_values: int = ..., min_periods: int | None = ..., center: bool | None = ..., closed: str | None = ..., step: int | None = ...) -> tuple[ndarray[Any, Any], ndarray[Any, Any]]
+ pandas/tests/window/test_base_indexer.py:71: note: Subclass:
+ pandas/tests/window/test_base_indexer.py:71: note: def get_window_bounds(self, num_values: Any, min_periods: Any, center: Any, closed: Any, step: Any) -> Any
+ pandas/tests/window/test_base_indexer.py:300: error: Signature of "get_window_bounds" incompatible with supertype "BaseIndexer" [override]
+ pandas/tests/window/test_base_indexer.py:300: note: Superclass:
+ pandas/tests/window/test_base_indexer.py:300: note: def get_window_bounds(self, num_values: int = ..., min_periods: int | None = ..., center: bool | None = ..., closed: str | None = ..., step: int | None = ...) -> tuple[ndarray[Any, Any], ndarray[Any, Any]]
+ pandas/tests/window/test_base_indexer.py:300: note: Subclass:
+ pandas/tests/window/test_base_indexer.py:300: note: def get_window_bounds(self, num_values: Any, min_periods: Any, center: Any, closed: Any, step: Any) -> Any
+ pandas/tests/window/test_base_indexer.py:481: error: Signature of "get_window_bounds" incompatible with supertype "BaseIndexer" [override]
+ pandas/tests/window/test_base_indexer.py:481: note: Superclass:
+ pandas/tests/window/test_base_indexer.py:481: note: def get_window_bounds(self, num_values: int = ..., min_periods: int | None = ..., center: bool | None = ..., closed: str | None = ..., step: int | None = ...) -> tuple[ndarray[Any, Any], ndarray[Any, Any]]
+ pandas/tests/window/test_base_indexer.py:481: note: Subclass:
+ pandas/tests/window/test_base_indexer.py:481: note: def get_window_bounds(self, num_values: Any, min_periods: Any, center: Any, closed: Any, step: Any) -> Any
+ pandas/tests/window/test_base_indexer.py:503: error: Signature of "get_window_bounds" incompatible with supertype "BaseIndexer" [override]
+ pandas/tests/window/test_base_indexer.py:503: note: Superclass:
+ pandas/tests/window/test_base_indexer.py:503: note: def get_window_bounds(self, num_values: int = ..., min_periods: int | None = ..., center: bool | None = ..., closed: str | None = ..., step: int | None = ...) -> tuple[ndarray[Any, Any], ndarray[Any, Any]]
+ pandas/tests/window/test_base_indexer.py:503: note: Subclass:
+ pandas/tests/window/test_base_indexer.py:503: note: def get_window_bounds(self, num_values: Any, min_periods: Any, center: Any, closed: Any, step: Any) -> Any
+ pandas/tests/extension/json/array.py:241: error: Signature of "_pad_or_backfill" incompatible with supertype "ExtensionArray" [override]
+ pandas/tests/extension/json/array.py:241: note: Superclass:
+ pandas/tests/extension/json/array.py:241: note: def _pad_or_backfill(self, *, method: Literal['backfill', 'bfill', 'ffill', 'pad'], limit: int | None = ..., limit_area: Literal['inside', 'outside'] | None = ..., copy: bool = ...) -> JSONArray
+ pandas/tests/extension/json/array.py:241: note: Subclass:
+ pandas/tests/extension/json/array.py:241: note: def _pad_or_backfill(self, *, method: Any, limit: Any = ..., copy: Any = ...) -> Any
+ pandas/tests/extension/decimal/array.py:292: error: Signature of "fillna" incompatible with supertype "ExtensionArray" [override]
+ pandas/tests/extension/decimal/array.py:292: note: Superclass:
+ pandas/tests/extension/decimal/array.py:292: note: def fillna(self, value: object, limit: int | None = ..., copy: bool = ...) -> DecimalArray
+ pandas/tests/extension/decimal/array.py:292: note: Subclass:
+ pandas/tests/extension/decimal/array.py:292: note: def fillna(self, value: Any = ..., limit: Any = ...) -> Any
+ pandas/tests/extension/test_string.py:107: error: Signature of "test_view" incompatible with supertype "BaseInterfaceTests" [override]
+ pandas/tests/extension/test_string.py:107: note: Superclass:
+ pandas/tests/extension/test_string.py:107: note: def test_view(self, data: Any) -> Any
+ pandas/tests/extension/test_string.py:107: note: Subclass:
+ pandas/tests/extension/test_string.py:107: note: def test_view(self, data: Any, request: Any, arrow_string_storage: Any) -> Any
+ pandas/tests/extension/test_string.py:116: error: Signature of "test_transpose" incompatible with supertype "BaseReshapingTests" [override]
+ pandas/tests/extension/test_string.py:116: note: Superclass:
+ pandas/tests/extension/test_string.py:116: note: def test_transpose(self, data: Any) -> Any
+ pandas/tests/extension/test_string.py:116: note: Subclass:
... (truncated 146 lines) ...
sympy (https://github.com/sympy/sympy)
+ sympy/core/numbers.py:349: error: Signature of "invert" incompatible with supertype "Expr" [override]
+ sympy/core/numbers.py:349: note: Superclass:
+ sympy/core/numbers.py:349: note: def invert(self, g: Any, *gens: Any, **args: Any) -> Any
+ sympy/core/numbers.py:349: note: Subclass:
+ sympy/core/numbers.py:349: note: def invert(self, other: Any, *gens: Any, **args: Any) -> Any
+ sympy/core/numbers.py:3020: error: Signature of "evalf" incompatible with supertype "EvalfMixin" [override]
+ sympy/core/numbers.py:3020: note: Superclass:
+ sympy/core/numbers.py:3020: note: def evalf(self, n: Any = ..., subs: Any = ..., maxn: Any = ..., chop: Any = ..., strict: Any = ..., quad: Any = ..., verbose: Any = ...) -> Any
+ sympy/core/numbers.py:3020: note: Subclass:
+ sympy/core/numbers.py:3020: note: def evalf(self, prec: Any = ..., **options: Any) -> Any
+ sympy/core/numbers.py:3181: error: Signature of "evalf" incompatible with supertype "EvalfMixin" [override]
+ sympy/core/numbers.py:3181: note: Superclass:
+ sympy/core/numbers.py:3181: note: def evalf(self, n: Any = ..., subs: Any = ..., maxn: Any = ..., chop: Any = ..., strict: Any = ..., quad: Any = ..., verbose: Any = ...) -> Any
+ sympy/core/numbers.py:3181: note: Subclass:
+ sympy/core/numbers.py:3181: note: def evalf(self, prec: Any = ..., **options: Any) -> Any
+ sympy/core/function.py:1775: error: Signature of "_eval_lseries" incompatible with supertype "Expr" [override]
+ sympy/core/function.py:1775: note: Superclass:
+ sympy/core/function.py:1775: note: def _eval_lseries(self, x: Any, logx: Any = ..., cdir: Any = ...) -> Any
+ sympy/core/function.py:1775: note: Subclass:
+ sympy/core/function.py:1775: note: def _eval_lseries(self, x: Any, logx: Any, cdir: Any = ...) -> Any
+ sympy/core/function.py:2281: error: Signature of "evalf" incompatible with supertype "EvalfMixin" [override]
+ sympy/core/function.py:2281: note: Superclass:
+ sympy/core/function.py:2281: note: def evalf(self, n: Any = ..., subs: Any = ..., maxn: Any = ..., chop: Any = ..., strict: Any = ..., quad: Any = ..., verbose: Any = ...) -> Any
+ sympy/core/function.py:2281: note: Subclass:
+ sympy/core/function.py:2281: note: def evalf(self, prec: Any = ..., **options: Any) -> Any
+ sympy/physics/units/prefixes.py:73: error: Signature of "__repr__" incompatible with supertype "Printable" [override]
+ sympy/physics/units/prefixes.py:73: note: Superclass:
+ sympy/physics/units/prefixes.py:73: note: def __str__(Printable, /) -> Any
+ sympy/physics/units/prefixes.py:73: note: Subclass:
+ sympy/physics/units/prefixes.py:73: note: def __repr__(self) -> Any
+ sympy/functions/elementary/miscellaneous.py:649: error: Signature of "evalf" incompatible with supertype "EvalfMixin" [override]
+ sympy/functions/elementary/miscellaneous.py:649: note: Superclass:
+ sympy/functions/elementary/miscellaneous.py:649: note: def evalf(self, n: Any = ..., subs: Any = ..., maxn: Any = ..., chop: Any = ..., strict: Any = ..., quad: Any = ..., verbose: Any = ...) -> Any
+ sympy/functions/elementary/miscellaneous.py:649: note: Subclass:
+ sympy/functions/elementary/miscellaneous.py:649: note: def evalf(self, n: Any = ..., **options: Any) -> Any
+ sympy/functions/elementary/miscellaneous.py:791: error: Signature of "_eval_is_positive" incompatible with supertype "MinMaxBase" [override]
+ sympy/functions/elementary/miscellaneous.py:791: note: Superclass:
+ sympy/functions/elementary/miscellaneous.py:791: note: def (s: Any) -> Any
+ sympy/functions/elementary/miscellaneous.py:791: note: Subclass:
+ sympy/functions/elementary/miscellaneous.py:791: note: def _eval_is_positive(self) -> Any
+ sympy/functions/elementary/miscellaneous.py:794: error: Signature of "_eval_is_nonnegative" incompatible with supertype "MinMaxBase" [override]
+ sympy/functions/elementary/miscellaneous.py:794: note: Superclass:
+ sympy/functions/elementary/miscellaneous.py:794: note: def (s: Any) -> Any
+ sympy/functions/elementary/miscellaneous.py:794: note: Subclass:
+ sympy/functions/elementary/miscellaneous.py:794: note: def _eval_is_nonnegative(self) -> Any
+ sympy/functions/elementary/miscellaneous.py:797: error: Signature of "_eval_is_negative" incompatible with supertype "MinMaxBase" [override]
+ sympy/functions/elementary/miscellaneous.py:797: note: Superclass:
+ sympy/functions/elementary/miscellaneous.py:797: note: def (s: Any) -> Any
+ sympy/functions/elementary/miscellaneous.py:797: note: Subclass:
+ sympy/functions/elementary/miscellaneous.py:797: note: def _eval_is_negative(self) -> Any
+ sympy/functions/elementary/miscellaneous.py:854: error: Signature of "_eval_is_positive" incompatible with supertype "MinMaxBase" [override]
+ sympy/functions/elementary/miscellaneous.py:854: note: Superclass:
+ sympy/functions/elementary/miscellaneous.py:854: note: def (s: Any) -> Any
+ sympy/functions/elementary/miscellaneous.py:854: note: Subclass:
+ sympy/functions/elementary/miscellaneous.py:854: note: def _eval_is_positive(self) -> Any
+ sympy/functions/elementary/miscellaneous.py:857: error: Signature of "_eval_is_nonnegative" incompatible with supertype "MinMaxBase" [override]
+ sympy/functions/elementary/miscellaneous.py:857: note: Superclass:
+ sympy/functions/elementary/miscellaneous.py:857: note: def (s: Any) -> Any
+ sympy/functions/elementary/miscellaneous.py:857: note: Subclass:
+ sympy/functions/elementary/miscellaneous.py:857: note: def _eval_is_nonnegative(self) -> Any
+ sympy/functions/elementary/miscellaneous.py:860: error: Signature of "_eval_is_negative" incompatible with supertype "MinMaxBase" [override]
+ sympy/functions/elementary/miscellaneous.py:860: note: Superclass:
+ sympy/functions/elementary/miscellaneous.py:860: note: def (s: Any) -> Any
+ sympy/functions/elementary/miscellaneous.py:860: note: Subclass:
+ sympy/functions/elementary/miscellaneous.py:860: note: def _eval_is_negative(self) -> Any
+ sympy/combinatorics/free_groups.py:442: error: Signature of "index" incompatible with supertype "tuple" [override]
+ sympy/combinatorics/free_groups.py:442: note: Superclass:
+ sympy/combinatorics/free_groups.py:442: note: def index(self, Any, SupportsIndex = ..., SupportsIndex = ..., /) -> int
+ sympy/combinatorics/free_groups.py:442: note: Subclass:
+ sympy/combinatorics/free_groups.py:442: note: def index(self, gen: Any) -> Any
+ sympy/combinatorics/free_groups.py:442: error: Signature of "index" incompatible with supertype "Sequence" [override]
+ sympy/combinatorics/free_groups.py:442: note: Superclass:
+ sympy/combinatorics/free_groups.py:442: note: def index(self, value: Any, start: int = ..., stop: int = ...) -> int
+ sympy/combinatorics/free_groups.py:442: note: Subclass:
+ sympy/combinatorics/free_groups.py:442: note: def index(self, gen: Any) -> Any
+ sympy/codegen/ast.py:318: error: Signature of "__repr__" incompatible with supertype "Printable" [override]
+ sympy/codegen/ast.py:318: note: Superclass:
+ sympy/codegen/ast.py:318: note: def __str__(Printable, /) -> Any
+ sympy/codegen/ast.py:318: note: Subclass:
+ sympy/codegen/ast.py:318: note: def __repr__(self) -> Any
+ sympy/codegen/ast.py:907: error: Signature of "_sympystr" incompatible with supertype "Token" [override]
+ sympy/codegen/ast.py:907: note: Superclass:
+ sympy/codegen/ast.py:907: note: def _sympyrepr(self: Token, printer: Any, *args: Any, joiner: Any = ..., **kwargs: Any) -> Any
+ sympy/codegen/ast.py:907: note: Subclass:
+ sympy/codegen/ast.py:907: note: def _sympystr(self, printer: Any, *args: Any, **kwargs: Any) -> Any
+ sympy/codegen/ast.py:1023: error: Signature of "_sympystr" incompatible with supertype "Token" [override]
+ sympy/codegen/ast.py:1023: note: Superclass:
+ sympy/codegen/ast.py:1023: note: def _sympyrepr(self: Token, printer: Any, *args: Any, joiner: Any = ..., **kwargs: Any) -> Any
+ sympy/codegen/ast.py:1023: note: Subclass:
+ sympy/codegen/ast.py:1023: note: def _sympystr(self, printer: Any, *args: Any, **kwargs: Any) -> Any
+ sympy/codegen/ast.py:1298: error: Signature of "cast_nocheck" incompatible with supertype "FloatBaseType" [override]
+ sympy/codegen/ast.py:1298: note: Superclass:
+ sympy/codegen/ast.py:1298: note: @staticmethod
+ sympy/codegen/ast.py:1298: note: def __new__(cls, num: Any, dps: Any = ..., precision: Any = ...) -> Float
+ sympy/codegen/ast.py:1298: note: Subclass:
+ sympy/codegen/ast.py:1298: note: def cast_nocheck(self, value: Any) -> Any
+ sympy/codegen/ast.py:1318: error: Signature of "cast_nocheck" incompatible with supertype "FloatBaseType" [override]
+ sympy/codegen/ast.py:1318: note: Superclass:
+ sympy/codegen/ast.py:1318: note: @staticmethod
+ sympy/codegen/ast.py:1318: note: def __new__(cls, num: Any, dps: Any = ..., precision: Any = ...) -> Float
+ sympy/codegen/ast.py:1318: note: Subclass:
+ sympy/codegen/ast.py:1318: note: def cast_nocheck(self, value: Any) -> Any
+ sympy/codegen/ast.py:1399: error: Signature of "_sympystr" incompatible with supertype "Token" [override]
+ sympy/codegen/ast.py:1399: note: Superclass:
+ sympy/codegen/ast.py:1399: note: def _sympyrepr(self: Token, printer: Any, *args: Any, joiner: Any = ..., **kwargs: Any) -> Any
+ sympy/codegen/ast.py:1399: note: Subclass:
+ sympy/codegen/ast.py:1399: note: def _sympystr(self, printer: Any, *args: Any, **kwargs: Any) -> Any
... (truncated 1170 lines) ...
manticore (https://github.com/trailofbits/manticore)
+ manticore/core/smtlib/visitors.py:199: error: Signature of "visit" incompatible with supertype "Visitor" [override]
+ manticore/core/smtlib/visitors.py:199: note: Superclass:
+ manticore/core/smtlib/visitors.py:199: note: def visit(self, node: Any, use_fixed_point: Any = ...) -> Any
+ manticore/core/smtlib/visitors.py:199: note: Subclass:
+ manticore/core/smtlib/visitors.py:199: note: def visit(self, expression: Any) -> Any
+ manticore/core/workspace.py:400: error: Signature of "load_value" incompatible with supertype "Store" [override]
+ manticore/core/workspace.py:400: note: Superclass:
+ manticore/core/workspace.py:400: note: def load_value(self, key: str, binary: bool = ...) -> Any
+ manticore/core/workspace.py:400: note: Subclass:
+ manticore/core/workspace.py:400: note: def load_value(self, key: Any) -> Any
+ manticore/ethereum/manticore.py:1572: error: Signature of "generate_testcase" incompatible with supertype "ManticoreBase" [override]
+ manticore/ethereum/manticore.py:1572: note: Superclass:
+ manticore/ethereum/manticore.py:1572: note: def generate_testcase(self, state: Any, message: str = ..., name: str = ...) -> Testcase
+ manticore/ethereum/manticore.py:1572: note: Subclass:
+ manticore/ethereum/manticore.py:1572: note: def generate_testcase(self, state: Any, message: Any = ..., only_if: Any = ..., name: Any = ...) -> Any
+ tests/native/test_x86.py:73: error: Signature of "assertEqual" incompatible with supertype "TestCase" [override]
+ tests/native/test_x86.py:73: note: Superclass:
+ tests/native/test_x86.py:73: note: def assertEqual(self, first: Any, second: Any, msg: Any = ...) -> None
+ tests/native/test_x86.py:73: note: Subclass:
+ tests/native/test_x86.py:73: note: def assertEqual(self, a: Any, b: Any) -> Any
+ tests/native/test_aarch64cpu.py:14071: error: Signature of "assertEqual" incompatible with supertype "TestCase" [override]
+ tests/native/test_aarch64cpu.py:14071: note: Superclass:
+ tests/native/test_aarch64cpu.py:14071: note: def assertEqual(self, first: Any, second: Any, msg: Any = ...) -> None
+ tests/native/test_aarch64cpu.py:14071: note: Subclass:
+ tests/native/test_aarch64cpu.py:14071: note: def assertEqual(self, actual: Any, expected: Any, *args: Any, **kwargs: Any) -> Any
+ manticore/native/manticore.py:27: error: Signature of "generate_testcase" incompatible with supertype "ManticoreBase" [override]
+ manticore/native/manticore.py:27: note: Superclass:
+ manticore/native/manticore.py:27: note: def generate_testcase(self, state: Any, message: str = ..., name: str = ...) -> Testcase
+ manticore/native/manticore.py:27: note: Subclass:
+ manticore/native/manticore.py:27: note: def generate_testcase(self, state: Any, message: Any = ...) -> Any
cloud-init (https://github.com/canonical/cloud-init)
+ cloudinit/safeyaml.py:165: error: Signature of "construct_mapping" incompatible with supertype "SafeConstructor" [override]
+ cloudinit/safeyaml.py:165: note: Superclass:
+ cloudinit/safeyaml.py:165: note: def construct_mapping(self, node: MappingNode, deep: bool = ...) -> dict[Hashable, Any]
+ cloudinit/safeyaml.py:165: note: Subclass:
+ cloudinit/safeyaml.py:165: note: def construct_mapping(self, node: Any) -> Any
+ cloudinit/safeyaml.py:165: error: Signature of "construct_mapping" incompatible with supertype "BaseConstructor" [override]
+ cloudinit/safeyaml.py:165: note: Superclass:
+ cloudinit/safeyaml.py:165: note: def construct_mapping(self, node: MappingNode, deep: bool = ...) -> dict[Hashable, Any]
+ cloudinit/safeyaml.py:165: note: Subclass:
+ cloudinit/safeyaml.py:165: note: def construct_mapping(self, node: Any) -> Any
+ cloudinit/helpers.py:442: error: Signature of "get" incompatible with supertype "RawConfigParser" [override]
+ cloudinit/helpers.py:442: note: Superclass:
+ cloudinit/helpers.py:442: note: @overload
+ cloudinit/helpers.py:442: note: def get(self, section: str, option: str, *, raw: bool = ..., vars: Mapping[str, str] | None = ...) -> str | Any
+ cloudinit/helpers.py:442: note: @overload
+ cloudinit/helpers.py:442: note: def [_T] get(self, section: str, option: str, *, raw: bool = ..., vars: Mapping[str, str] | None = ..., fallback: _T) -> str | _T | Any
+ cloudinit/helpers.py:442: note: Subclass:
+ cloudinit/helpers.py:442: note: def get(self, section: Any, option: Any) -> Any
+ cloudinit/helpers.py:442: error: Signature of "get" incompatible with supertype "Mapping" [override]
+ cloudinit/helpers.py:442: note: Superclass:
+ cloudinit/helpers.py:442: note: @overload
+ cloudinit/helpers.py:442: note: def get(self, str, /) -> Mapping[str, str] | None
+ cloudinit/helpers.py:442: note: @overload
+ cloudinit/helpers.py:442: note: def [_T] get(self, str, /, default: Mapping[str, str] | _T) -> Mapping[str, str] | _T
+ cloudinit/helpers.py:442: note: Subclass:
+ cloudinit/helpers.py:442: note: def get(self, section: Any, option: Any) -> Any
+ cloudinit/helpers.py:461: error: Signature of "getboolean" incompatible with supertype "RawConfigParser" [override]
+ cloudinit/helpers.py:461: note: Superclass:
+ cloudinit/helpers.py:461: note: @overload
+ cloudinit/helpers.py:461: note: def getboolean(self, section: str, option: str, *, raw: bool = ..., vars: Mapping[str, str] | None = ...) -> bool
+ cloudinit/helpers.py:461: note: @overload
+ cloudinit/helpers.py:461: note: def [_T] getboolean(self, section: str, option: str, *, raw: bool = ..., vars: Mapping[str, str] | None = ..., fallback: _T = ...) -> bool | _T
+ cloudinit/helpers.py:461: note: Subclass:
+ cloudinit/helpers.py:461: note: def getboolean(self, section: Any, option: Any) -> Any
+ cloudinit/helpers.py:466: error: Signature of "getfloat" incompatible with supertype "RawConfigParser" [override]
+ cloudinit/helpers.py:466: note: Superclass:
+ cloudinit/helpers.py:466: note: @overload
+ cloudinit/helpers.py:466: note: def getfloat(self, section: str, option: str, *, raw: bool = ..., vars: Mapping[str, str] | None = ...) -> float
+ cloudinit/helpers.py:466: note: @overload
+ cloudinit/helpers.py:466: note: def [_T] getfloat(self, section: str, option: str, *, raw: bool = ..., vars: Mapping[str, str] | None = ..., fallback: _T = ...) -> float | _T
+ cloudinit/helpers.py:466: note: Subclass:
+ cloudinit/helpers.py:466: note: def getfloat(self, section: Any, option: Any) -> Any
+ cloudinit/helpers.py:471: error: Signature of "getint" incompatible with supertype "RawConfigParser" [override]
+ cloudinit/helpers.py:471: note: Superclass:
+ cloudinit/helpers.py:471: note: @overload
+ cloudinit/helpers.py:471: note: def getint(self, section: str, option: str, *, raw: bool = ..., vars: Mapping[str, str] | None = ...) -> int
+ cloudinit/helpers.py:471: note: @overload
+ cloudinit/helpers.py:471: note: def [_T] getint(self, section: str, option: str, *, raw: bool = ..., vars: Mapping[str, str] | None = ..., fallback: _T = ...) -> int | _T
+ cloudinit/helpers.py:471: note: Subclass:
+ cloudinit/helpers.py:471: note: def getint(self, section: Any, option: Any) -> Any
+ tests/integration_tests/clouds.py:362: error: Signature of "_get_or_set_profile_list" incompatible with supertype "_LxdIntegrationCloud" [override]
... (truncated 771 lines) ...``` |
This commit fixes python#9618 by making MyPy always complain if a method overrides a base class method marked as `@final`. In the process, it also adds a few additional validations: - Always verify the `@override` decorator, which ought to be pretty backward-compatible for most projects assuming that strict override checks aren't enabled by default (and it appears to me that `--enable-error-code explicit-override` is off by default) - Verify that the method signature is compatible (which in practice means only arity and argument name checks) *if* the `--check-untyped-defs` flag is set; it seems unlikely that a user would want mypy to validate the bodies of untyped functions but wouldn't want to be alerted about incompatible overrides. Note: I did also explore enabling the signature compatibility check for all code, which in principle makes sense. But the mypy_primer results indicated that there would be backward compability issues because too many libraries rely on us not validating this: python#17274
The mypy_primer tests suggest this is too noisy. Closing this PR in favor of more relaxed checks in #17276 |
This commit fixes #9618 by making MyPy always complain if a method overrides a base class method marked as `@final`. In the process, it also adds a few additional validations: - Always verify the `@override` decorator, which ought to be pretty backward-compatible for most projects assuming that strict override checks aren't enabled by default (and it appears to me that `--enable-error-code explicit-override` is off by default) - Verify that the method signature is compatible (which in practice means only arity and argument name checks) *if* the `--check-untyped-defs` flag is set; it seems unlikely that a user would want mypy to validate the bodies of untyped functions but wouldn't want to be alerted about incompatible overrides. Note: I did also explore enabling the signature compatibility check for all code, which in principle makes sense. But the mypy_primer results indicated that there would be backward compability issues because too many libraries rely on us not validating this: #17274
This fixes #9618 in a fairly aggressive way, by turning on all override checks for all methods. This means that with this change, MyPy will complain in cases where just inspecting type signatures involving
Any
is enough to establish that an override is a type error:@final
as listed in@final
decorator is not honored on override with --check-untyped-defs #9618The tests illustrate this, I added a test case to
check-functions.test
(is this a good place for it?) for the@final
check specifically but also updated a few existing tests of dynamic logic.The resulting code change is very simple (since all override checks happen in the same place), and I think conceptually it is right to enable all these checks because the contract is that MyPy won't generally type check bodies of functions, but the function signatures are actually part of the class type definition which is (in other cases) sanity-checked even when there are no annotations.
If we think that the arity checks are too big a change, I can work on a refactor that would let us validate only
@final
but not other properties. I think we should give it a shot and see ifmypy_primer
indicates a big blast radius.