Skip to content

Commit 05571b1

Browse files
authored
Fixes #5705 (#8866)
Added notes as suggested in the issue description after error from incompatible arguments in subtype is raised.
1 parent 41927cf commit 05571b1

9 files changed

+80
-19
lines changed

mypy/messages.py

+8
Original file line numberDiff line numberDiff line change
@@ -772,6 +772,14 @@ def argument_incompatible_with_supertype(
772772
.format(arg_num, name, target, arg_type_in_supertype_f),
773773
context,
774774
code=codes.OVERRIDE)
775+
self.note(
776+
'This violates the Liskov substitution principle',
777+
context,
778+
code=codes.OVERRIDE)
779+
self.note(
780+
'See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides',
781+
context,
782+
code=codes.OVERRIDE)
775783

776784
if name == "__eq__" and type_name:
777785
multiline_msg = self.comparison_method_example_msg(class_name=type_name)

test-data/unit/check-abstract.test

+14-4
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,9 @@ class A(metaclass=ABCMeta):
311311
def g(self, x: int) -> int: pass
312312
class B(A):
313313
def f(self, x: str) -> int: \
314-
# E: Argument 1 of "f" is incompatible with supertype "A"; supertype defines the argument type as "int"
314+
# E: Argument 1 of "f" is incompatible with supertype "A"; supertype defines the argument type as "int" \
315+
# N: This violates the Liskov substitution principle \
316+
# N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
315317
pass
316318
def g(self, x: int) -> int: pass
317319
[out]
@@ -327,7 +329,9 @@ class J(metaclass=ABCMeta):
327329
def g(self, x: str) -> str: pass
328330
class A(I, J):
329331
def f(self, x: str) -> int: pass \
330-
# E: Argument 1 of "f" is incompatible with supertype "I"; supertype defines the argument type as "int"
332+
# E: Argument 1 of "f" is incompatible with supertype "I"; supertype defines the argument type as "int" \
333+
# N: This violates the Liskov substitution principle \
334+
# N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
331335
def g(self, x: str) -> int: pass \
332336
# E: Return type "int" of "g" incompatible with return type "str" in supertype "J"
333337
def h(self) -> int: pass # Not related to any base class
@@ -342,7 +346,9 @@ class J(metaclass=ABCMeta):
342346
class I(J): pass
343347
class A(I):
344348
def f(self, x: str) -> int: pass \
345-
# E: Argument 1 of "f" is incompatible with supertype "J"; supertype defines the argument type as "int"
349+
# E: Argument 1 of "f" is incompatible with supertype "J"; supertype defines the argument type as "int" \
350+
# N: This violates the Liskov substitution principle \
351+
# N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
346352
[out]
347353

348354
[case testInvalidOverridingAbstractMethod]
@@ -353,7 +359,9 @@ class J(metaclass=ABCMeta):
353359
def f(self, x: 'J') -> None: pass
354360
class I(J):
355361
@abstractmethod
356-
def f(self, x: 'I') -> None: pass # E: Argument 1 of "f" is incompatible with supertype "J"; supertype defines the argument type as "J"
362+
def f(self, x: 'I') -> None: pass # E: Argument 1 of "f" is incompatible with supertype "J"; supertype defines the argument type as "J" \
363+
# N: This violates the Liskov substitution principle \
364+
# N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
357365
[out]
358366

359367
[case testAbstractClassCoAndContraVariance]
@@ -375,6 +383,8 @@ class A(I):
375383
pass
376384
[out]
377385
main:11: error: Argument 1 of "h" is incompatible with supertype "I"; supertype defines the argument type as "I"
386+
main:11: note: This violates the Liskov substitution principle
387+
main:11: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
378388
main:11: error: Return type "I" of "h" incompatible with return type "A" in supertype "I"
379389

380390

test-data/unit/check-classes.test

+20-4
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,8 @@ class B(A):
282282
def h(self, x: A, y: 'B') -> object: pass # Fail
283283
[out]
284284
main:7: error: Argument 1 of "f" is incompatible with supertype "A"; supertype defines the argument type as "A"
285+
main:7: note: This violates the Liskov substitution principle
286+
main:7: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
285287
main:9: error: Return type "object" of "h" incompatible with return type "A" in supertype "A"
286288

287289
[case testEqMethodsOverridingWithNonObjects]
@@ -290,6 +292,8 @@ class A:
290292
[builtins fixtures/attr.pyi]
291293
[out]
292294
main:2: error: Argument 1 of "__eq__" is incompatible with supertype "object"; supertype defines the argument type as "object"
295+
main:2: note: This violates the Liskov substitution principle
296+
main:2: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
293297
main:2: note: It is recommended for "__eq__" to work with arbitrary objects, for example:
294298
main:2: note: def __eq__(self, other: object) -> bool:
295299
main:2: note: if not isinstance(other, A):
@@ -318,6 +322,8 @@ class C(B): # with gap in implementations
318322
pass
319323
[out]
320324
main:6: error: Argument 1 of "f" is incompatible with supertype "A"; supertype defines the argument type as "B"
325+
main:6: note: This violates the Liskov substitution principle
326+
main:6: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
321327

322328
[case testMethodOverridingAcrossDeepInheritanceHierarchy2]
323329
import typing
@@ -459,7 +465,9 @@ class B(A):
459465
@staticmethod
460466
def f(x: int, y: str) -> None: pass
461467
@staticmethod
462-
def g(x: str, y: str) -> None: pass # E: Argument 1 of "g" is incompatible with supertype "A"; supertype defines the argument type as "int"
468+
def g(x: str, y: str) -> None: pass # E: Argument 1 of "g" is incompatible with supertype "A"; supertype defines the argument type as "int" \
469+
# N: This violates the Liskov substitution principle \
470+
# N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
463471
[builtins fixtures/classmethod.pyi]
464472

465473
[case testOverrideClassMethodWithClassMethod]
@@ -473,7 +481,9 @@ class B(A):
473481
@classmethod
474482
def f(cls, x: int, y: str) -> None: pass
475483
@classmethod
476-
def g(cls, x: str, y: str) -> None: pass # E: Argument 1 of "g" is incompatible with supertype "A"; supertype defines the argument type as "int"
484+
def g(cls, x: str, y: str) -> None: pass # E: Argument 1 of "g" is incompatible with supertype "A"; supertype defines the argument type as "int" \
485+
# N: This violates the Liskov substitution principle \
486+
# N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
477487
[builtins fixtures/classmethod.pyi]
478488

479489
[case testOverrideClassMethodWithStaticMethod]
@@ -489,7 +499,9 @@ class B(A):
489499
@staticmethod
490500
def f(x: int) -> None: pass
491501
@staticmethod
492-
def g(x: str) -> int: pass # E: Argument 1 of "g" is incompatible with supertype "A"; supertype defines the argument type as "int"
502+
def g(x: str) -> int: pass # E: Argument 1 of "g" is incompatible with supertype "A"; supertype defines the argument type as "int" \
503+
# N: This violates the Liskov substitution principle \
504+
# N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
493505
@staticmethod
494506
def h() -> int: pass
495507
[builtins fixtures/classmethod.pyi]
@@ -507,7 +519,9 @@ class B(A):
507519
@classmethod
508520
def f(cls, x: int) -> None: pass
509521
@classmethod
510-
def g(cls, x: int) -> int: pass # E: Argument 1 of "g" is incompatible with supertype "A"; supertype defines the argument type as "str"
522+
def g(cls, x: int) -> int: pass # E: Argument 1 of "g" is incompatible with supertype "A"; supertype defines the argument type as "str" \
523+
# N: This violates the Liskov substitution principle \
524+
# N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
511525
@classmethod
512526
def h(cls) -> int: pass
513527
[builtins fixtures/classmethod.pyi]
@@ -2478,6 +2492,8 @@ class D(A):
24782492
[out]
24792493
main:6: error: Return type "A" of "__iadd__" incompatible with return type "B" in "__add__" of supertype "A"
24802494
main:8: error: Argument 1 of "__iadd__" is incompatible with "__add__" of supertype "A"; supertype defines the argument type as "A"
2495+
main:8: note: This violates the Liskov substitution principle
2496+
main:8: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
24812497
main:8: error: Signatures of "__iadd__" and "__add__" are incompatible
24822498

24832499
[case testGetattribute]

test-data/unit/check-columns.test

+3-1
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,9 @@ if int():
262262
class A:
263263
def f(self, x: int) -> None: pass
264264
class B(A):
265-
def f(self, x: str) -> None: pass # E:5: Argument 1 of "f" is incompatible with supertype "A"; supertype defines the argument type as "int"
265+
def f(self, x: str) -> None: pass # E:5: Argument 1 of "f" is incompatible with supertype "A"; supertype defines the argument type as "int" \
266+
# N:5: This violates the Liskov substitution principle \
267+
# N:5: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
266268
class C(A):
267269
def f(self, x: int) -> int: pass # E:5: Return type "int" of "f" incompatible with return type "None" in supertype "A"
268270
class D(A):

test-data/unit/check-dynamic-typing.test

+3-1
Original file line numberDiff line numberDiff line change
@@ -704,7 +704,9 @@ class C:
704704
class B(C):
705705
def f(self, a): pass
706706
class A(B):
707-
def f(self, a: 'D') -> None: # E: Argument 1 of "f" is incompatible with supertype "C"; supertype defines the argument type as "A"
707+
def f(self, a: 'D') -> None: # E: Argument 1 of "f" is incompatible with supertype "C"; supertype defines the argument type as "A" \
708+
# N: This violates the Liskov substitution principle \
709+
# N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
708710
pass
709711
class D: pass
710712
[out]

test-data/unit/check-errorcodes.test

+3-1
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,9 @@ class D:
279279
def f(self, x: int) -> int:
280280
return 0
281281
class E(D):
282-
def f(self, x: str) -> int: # E: Argument 1 of "f" is incompatible with supertype "D"; supertype defines the argument type as "int" [override]
282+
def f(self, x: str) -> int: # E: Argument 1 of "f" is incompatible with supertype "D"; supertype defines the argument type as "int" [override] \
283+
# N: This violates the Liskov substitution principle \
284+
# N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
283285
return 0
284286

285287
class O:

test-data/unit/check-functions.test

+4-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,10 @@ class A(object):
4646
def f(self, a: int, b: str) -> None: pass
4747

4848
class B(A):
49-
def f(self, b: str, a: int) -> None: pass # E: Argument 1 of "f" is incompatible with supertype "A"; supertype defines the argument type as "int" # E: Argument 2 of "f" is incompatible with supertype "A"; supertype defines the argument type as "str"
49+
def f(self, b: str, a: int) -> None: pass # E: Argument 1 of "f" is incompatible with supertype "A"; supertype defines the argument type as "int" \
50+
# N: This violates the Liskov substitution principle \
51+
# N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides \
52+
# E: Argument 2 of "f" is incompatible with supertype "A"; supertype defines the argument type as "str"
5053

5154
class C(A):
5255
def f(self, foo: int, bar: str) -> None: pass

test-data/unit/check-generic-subtyping.test

+23-7
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,9 @@ class C: pass
189189
class D: pass
190190
class A(B[C]):
191191
def f(self, a: D) -> None: pass \
192-
# E: Argument 1 of "f" is incompatible with supertype "B"; supertype defines the argument type as "C"
192+
# E: Argument 1 of "f" is incompatible with supertype "B"; supertype defines the argument type as "C" \
193+
# N: This violates the Liskov substitution principle \
194+
# N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
193195
def g(self, a: C) -> None: pass
194196
[out]
195197

@@ -202,7 +204,9 @@ class B:
202204
def g(self, a: C) -> None: pass
203205
class A(B, Generic[T]):
204206
def f(self, a: T) -> None: pass \
205-
# E: Argument 1 of "f" is incompatible with supertype "B"; supertype defines the argument type as "C"
207+
# E: Argument 1 of "f" is incompatible with supertype "B"; supertype defines the argument type as "C" \
208+
# N: This violates the Liskov substitution principle \
209+
# N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
206210
def g(self, a: 'C') -> None: pass
207211
[out]
208212

@@ -215,7 +219,9 @@ class B(Generic[T]):
215219
def g(self, a: T) -> None: pass
216220
class A(B[S], Generic[T, S]):
217221
def f(self, a: T) -> None: pass \
218-
# E: Argument 1 of "f" is incompatible with supertype "B"; supertype defines the argument type as "S"
222+
# E: Argument 1 of "f" is incompatible with supertype "B"; supertype defines the argument type as "S" \
223+
# N: This violates the Liskov substitution principle \
224+
# N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
219225
def g(self, a: S) -> None: pass
220226
[out]
221227

@@ -233,7 +239,9 @@ class C(Generic[T, U, V]):
233239
class B(C[D, D, T], Generic[T]): pass
234240
class A(B[S], Generic[T, S]):
235241
def f(self, a: T) -> None: pass \
236-
# E: Argument 1 of "f" is incompatible with supertype "C"; supertype defines the argument type as "S"
242+
# E: Argument 1 of "f" is incompatible with supertype "C"; supertype defines the argument type as "S" \
243+
# N: This violates the Liskov substitution principle \
244+
# N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
237245
def g(self, a: S) -> None: pass
238246
[out]
239247

@@ -283,6 +291,8 @@ class D(A):
283291
def f(self, x: T1, y: S) -> None: pass # TODO: This error could be more specific.
284292
[out]
285293
main:12: error: Argument 2 of "f" is incompatible with supertype "A"; supertype defines the argument type as "S"
294+
main:12: note: This violates the Liskov substitution principle
295+
main:12: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
286296
main:14: error: Signature of "f" incompatible with supertype "A"
287297

288298

@@ -538,7 +548,9 @@ class I(Generic[T]):
538548
def g(self, a: T) -> None: pass
539549
class A(I[C]):
540550
def f(self, a: 'D') -> None: pass \
541-
# E: Argument 1 of "f" is incompatible with supertype "I"; supertype defines the argument type as "C"
551+
# E: Argument 1 of "f" is incompatible with supertype "I"; supertype defines the argument type as "C" \
552+
# N: This violates the Liskov substitution principle \
553+
# N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
542554
def g(self, a: 'C') -> None: pass
543555
class C: pass
544556
class D: pass
@@ -570,7 +582,9 @@ class B(I[C]):
570582
def g(self, a: 'C', b: Any) -> None: pass
571583
class A(B):
572584
def g(self, a: 'C', b: 'C') -> None: pass \
573-
# E: Argument 2 of "g" is incompatible with supertype "I"; supertype defines the argument type as "D"
585+
# E: Argument 2 of "g" is incompatible with supertype "I"; supertype defines the argument type as "D" \
586+
# N: This violates the Liskov substitution principle \
587+
# N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
574588
def f(self, a: 'C', b: 'C') -> None: pass
575589
class C: pass
576590
class D: pass
@@ -587,7 +601,9 @@ class B(I[C]):
587601
def f(self, a: 'C', b: Any) -> None: pass
588602
class A(B):
589603
def f(self, a: 'C', b: 'D') -> None: pass \
590-
# E: Argument 2 of "f" is incompatible with supertype "I"; supertype defines the argument type as "C"
604+
# E: Argument 2 of "f" is incompatible with supertype "I"; supertype defines the argument type as "C" \
605+
# N: This violates the Liskov substitution principle \
606+
# N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
591607
class C: pass
592608
class D: pass
593609
[out]

test-data/unit/check-multiple-inheritance.test

+2
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,8 @@ class IntFlag(int, Flag):
539539
def __or__(self: _T, other: str) -> _T: ...
540540
[out]
541541
main:8: error: Argument 1 of "__or__" is incompatible with supertype "Flag"; supertype defines the argument type as "IntFlag"
542+
main:8: note: This violates the Liskov substitution principle
543+
main:8: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
542544

543545
[case testMultipleInheritance_MethodDefinitionsCompatibleNoOverride]
544546
from typing import TypeVar, Union

0 commit comments

Comments
 (0)