MCPcopy Index your code
hub / github.com/python/mypy / check_final

Method check_final

mypy/checker.py:3921–3973  ·  view source on GitHub ↗

Check if this assignment does not assign to a final attribute. This function performs the check only for name assignments at module and class scope. The assignments to `obj.attr` and `Cls.attr` are checked in checkmember.py.

(self, s: AssignmentStmt | OperatorAssignmentStmt | AssignmentExpr)

Source from the content-addressed store, hash-verified

3919 self._is_final_def = old_ctx
3920
3921 def check_final(self, s: AssignmentStmt | OperatorAssignmentStmt | AssignmentExpr) -> None:
3922 """Check if this assignment does not assign to a final attribute.
3923
3924 This function performs the check only for name assignments at module
3925 and class scope. The assignments to `obj.attr` and `Cls.attr` are checked
3926 in checkmember.py.
3927 """
3928 if isinstance(s, AssignmentStmt):
3929 lvs = self.flatten_lvalues(s.lvalues)
3930 elif isinstance(s, AssignmentExpr):
3931 lvs = [s.target]
3932 else:
3933 lvs = [s.lvalue]
3934 is_final_decl = s.is_final_def if isinstance(s, AssignmentStmt) else False
3935 if is_final_decl and (active_class := self.scope.active_class()):
3936 lv = lvs[0]
3937 assert isinstance(lv, RefExpr)
3938 if lv.node is not None:
3939 assert isinstance(lv.node, Var)
3940 if (
3941 lv.node.final_unset_in_class
3942 and not lv.node.final_set_in_init
3943 and not self.is_stub # It is OK to skip initializer in stub files.
3944 and
3945 # Avoid extra error messages, if there is no type in Final[...],
3946 # then we already reported the error about missing r.h.s.
3947 isinstance(s, AssignmentStmt)
3948 and s.type is not None
3949 # Avoid extra error message for NamedTuples,
3950 # they were reported during semanal
3951 and not active_class.is_named_tuple
3952 ):
3953 self.msg.final_without_value(s)
3954 for lv in lvs:
3955 if isinstance(lv, RefExpr) and isinstance(lv.node, Var):
3956 name = lv.node.name
3957 cls = self.scope.active_class()
3958 if cls is not None:
3959 # These additional checks exist to give more error messages
3960 # even if the final attribute was overridden with a new symbol
3961 # (which is itself an error)...
3962 for base in cls.mro[1:]:
3963 sym = base.names.get(name)
3964 # We only give this error if base node is variable,
3965 # overriding final method will be caught in
3966 # `check_compatibility_final_super()`.
3967 if sym and isinstance(sym.node, Var):
3968 if sym.node.is_final and not is_final_decl:
3969 self.msg.cant_assign_to_final(name, sym.node.info is None, s)
3970 # ...but only once
3971 break
3972 if lv.node.is_final and not is_final_decl:
3973 self.msg.cant_assign_to_final(name, lv.node.info is None, s)
3974
3975 def check_assignment_to_slots(self, lvalue: Lvalue) -> None:
3976 if not isinstance(lvalue, MemberExpr):

Callers 3

visit_assignment_stmtMethod · 0.95
visit_assignment_exprMethod · 0.80

Calls 6

flatten_lvaluesMethod · 0.95
isinstanceFunction · 0.85
active_classMethod · 0.80
final_without_valueMethod · 0.80
cant_assign_to_finalMethod · 0.80
getMethod · 0.45

Tested by

no test coverage detected