Skip to content

Commit 88791ca

Browse files
ilevkivskyiAlexWaygood
authored andcommitted
Exclude private attributes from override checks (#16464)
Fixes #9910 Fixes #16452 We already exclude private names from override type compatibility checks etc., but it looks like some override checks were still performed, we need to skip them, since private name is actually a different name in subclass. --------- Co-authored-by: Alex Waygood <[email protected]>
1 parent 4b5b316 commit 88791ca

File tree

6 files changed

+48
-4
lines changed

6 files changed

+48
-4
lines changed

mypy/checker.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1879,6 +1879,7 @@ def check_explicit_override_decorator(
18791879
found_method_base_classes
18801880
and not defn.is_explicit_override
18811881
and defn.name not in ("__init__", "__new__")
1882+
and not is_private(defn.name)
18821883
):
18831884
self.msg.explicit_override_decorator_missing(
18841885
defn.name, found_method_base_classes[0].fullname, context or defn
@@ -1921,7 +1922,7 @@ def check_method_or_accessor_override_for_base(
19211922
base_attr = base.names.get(name)
19221923
if base_attr:
19231924
# First, check if we override a final (always an error, even with Any types).
1924-
if is_final_node(base_attr.node):
1925+
if is_final_node(base_attr.node) and not is_private(name):
19251926
self.msg.cant_override_final(name, base.name, defn)
19261927
# Second, final can't override anything writeable independently of types.
19271928
if defn.is_final:
@@ -2679,7 +2680,7 @@ class C(B, A[int]): ... # this is unsafe because...
26792680
ok = True
26802681
# Final attributes can never be overridden, but can override
26812682
# non-final read-only attributes.
2682-
if is_final_node(second.node):
2683+
if is_final_node(second.node) and not is_private(name):
26832684
self.msg.cant_override_final(name, base2.name, ctx)
26842685
if is_final_node(first.node):
26852686
self.check_if_final_var_override_writable(name, second.node, ctx)
@@ -3293,6 +3294,8 @@ def check_compatibility_final_super(
32933294
"""
32943295
if not isinstance(base_node, (Var, FuncBase, Decorator)):
32953296
return True
3297+
if is_private(node.name):
3298+
return True
32963299
if base_node.is_final and (node.is_final or not isinstance(base_node, Var)):
32973300
# Give this error only for explicit override attempt with `Final`, or
32983301
# if we are overriding a final method with variable.

test-data/unit/check-dataclasses.test

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2531,3 +2531,16 @@ class Foo:
25312531

25322532
c: int # E: Name "c" already defined on line 5
25332533
[builtins fixtures/dataclasses.pyi]
2534+
2535+
[case testDataclassInheritanceWorksWithExplicitOverrides]
2536+
# flags: --enable-error-code explicit-override
2537+
from dataclasses import dataclass
2538+
2539+
@dataclass
2540+
class Base:
2541+
x: int
2542+
2543+
@dataclass
2544+
class Child(Base):
2545+
y: int
2546+
[builtins fixtures/dataclasses.pyi]

test-data/unit/check-final.test

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1117,3 +1117,16 @@ from typing import Final
11171117
class MyClass:
11181118
a: None
11191119
a: Final[int] = 1 # E: Cannot redefine an existing name as final # E: Name "a" already defined on line 5
1120+
1121+
[case testFinalOverrideAllowedForPrivate]
1122+
from typing import Final, final
1123+
1124+
class Parent:
1125+
__foo: Final[int] = 0
1126+
@final
1127+
def __bar(self) -> None: ...
1128+
1129+
class Child(Parent):
1130+
__foo: Final[int] = 1
1131+
@final
1132+
def __bar(self) -> None: ...

test-data/unit/check-functions.test

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3159,6 +3159,16 @@ class D(A, B):
31593159
def f(self, z: int) -> str: pass # E: Method "f" is not using @override but is overriding a method in class "__main__.A"
31603160
[typing fixtures/typing-override.pyi]
31613161

3162+
[case testExplicitOverrideAllowedForPrivate]
3163+
# flags: --enable-error-code explicit-override --python-version 3.12
3164+
3165+
class B:
3166+
def __f(self, y: int) -> str: pass
3167+
3168+
class C(B):
3169+
def __f(self, y: int) -> str: pass # OK
3170+
[typing fixtures/typing-override.pyi]
3171+
31623172
[case testCallableProperty]
31633173
from typing import Callable
31643174

test-data/unit/fine-grained-dataclass-transform.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,9 @@ class A(Dataclass):
8686

8787
[out]
8888
main:7: error: Unexpected keyword argument "x" for "B"
89-
builtins.pyi:13: note: "B" defined here
89+
builtins.pyi:14: note: "B" defined here
9090
main:7: error: Unexpected keyword argument "y" for "B"
91-
builtins.pyi:13: note: "B" defined here
91+
builtins.pyi:14: note: "B" defined here
9292
==
9393

9494
[case frozenInheritanceViaDefault]

test-data/unit/fixtures/dataclasses.pyi

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ from typing import (
33
Generic, Iterator, Iterable, Mapping, Optional, Sequence, Tuple,
44
TypeVar, Union, overload,
55
)
6+
from typing_extensions import override
67

78
_T = TypeVar('_T')
89
_U = TypeVar('_U')
@@ -29,8 +30,10 @@ class dict(Mapping[KT, VT]):
2930
def __init__(self, **kwargs: VT) -> None: pass
3031
@overload
3132
def __init__(self, arg: Iterable[Tuple[KT, VT]], **kwargs: VT) -> None: pass
33+
@override
3234
def __getitem__(self, key: KT) -> VT: pass
3335
def __setitem__(self, k: KT, v: VT) -> None: pass
36+
@override
3437
def __iter__(self) -> Iterator[KT]: pass
3538
def __contains__(self, item: object) -> int: pass
3639
def update(self, a: Mapping[KT, VT]) -> None: pass
@@ -42,7 +45,9 @@ class dict(Mapping[KT, VT]):
4245

4346
class list(Generic[_T], Sequence[_T]):
4447
def __contains__(self, item: object) -> int: pass
48+
@override
4549
def __getitem__(self, key: int) -> _T: pass
50+
@override
4651
def __iter__(self) -> Iterator[_T]: pass
4752

4853
class function: pass

0 commit comments

Comments
 (0)