8000 Allow accessing `__init__` on final classes and when `__init__` is fi… · python/mypy@6d860cf · GitHub
[go: up one dir, main page]

Skip to content

Commit 6d860cf

Browse files
authored
Allow accessing __init__ on final classes and when __init__ is final (#19035)
Fixes #19033.
1 parent db752bb commit 6d860cf

File tree

2 files changed

+32
-9
lines changed

2 files changed

+32
-9
lines changed

mypy/checkmember.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -308,18 +308,21 @@ def report_missing_attribute(
308308
def analyze_instance_member_access(
309309
name: str, typ: Instance, mx: MemberContext, override_info: TypeInfo | None
310310
) -> Type:
311-
if name == "__init__" and not mx.is_super:
312-
# Accessing __init__ in statically typed code would compromise
313-
# type safety unless used via super().
314-
mx.fail(message_registry.CANNOT_ACCESS_INIT)
315-
return AnyType(TypeOfAny.from_error)
316-
317-
# The base object has an instance type.
318-
319311
info = typ.type
320312
if override_info:
321313
info = override_info
322314

315+
method = info.get_method(name)
316+
317+
if name == "__init__" and not mx.is_super and not info.is_final:
318+
if not method or not method.is_final:
319+
# Accessing __init__ in statically typed code would compromise
320+
# type safety unless used via super() or the method/class is final.
321+
mx.fail(message_registry.CANNOT_ACCESS_INIT)
322+
return AnyType(TypeOfAny.from_error)
323+
324+
# The base object has an instance type.
325+
323326
if (
324327
state.find_occurrences
325328
and info.name == state.find_occurrences[0]
@@ -329,7 +332,6 @@ def analyze_instance_member_access(
329332
mx.msg.note("Occurrence of '{}.{}'".format(*state.find_occurrences), mx.context)
330333

331334
# Look up the member. First look up the method dictionary.
332-
method = info.get_method(name)
333335
if method and not isinstance(method, Decorator):
334336
if mx.is_super and not mx.suppress_errors:
335337
validate_super_call(method, mx)

test-data/unit/check-final.test

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1229,3 +1229,24 @@ reveal_type(B() and 42) # N: Revealed type is "Literal[42]?"
12291229
reveal_type(C() and 42) # N: Revealed type is "__main__.C"
12301230

12311231
[builtins fixtures/bool.pyi]
1232+
1233+
[case testCanAccessFinalClassInit]
1234+
from typing import final
1235+
1236+
@final
1237+
class FinalClass:
1238+
pass
1239+
1240+
def check_final_class() -> None:
1241+
new_instance = FinalClass()
1242+
new_instance.__init__()
1243+
1244+
class FinalInit:
1245+
@final
1246+
def __init__(self) -> None:
1247+
pass
1248+
1249+
def check_final_init() -> None:
1250+
new_instance = FinalInit()
1251+
new_instance.__init__()
1252+
[builtins fixtures/tuple.pyi]

0 commit comments

Comments
 (0)
0