MCPcopy Create free account
hub / github.com/python/mypy / unwrap_final

Method unwrap_final

mypy/semanal.py:3743–3806  ·  view source on GitHub ↗

Strip Final[...] if present in an assignment. This is done to invoke type inference during type checking phase for this assignment. Also, Final[...] doesn't affect type in any way -- it is rather an access qualifier for given `Var`. Also perform various consistency

(self, s: AssignmentStmt)

Source from the content-addressed store, hash-verified

3741 hook(DynamicClassDefContext(call, lval.name, self))
3742
3743 def unwrap_final(self, s: AssignmentStmt) -> bool:
3744 """Strip Final[...] if present in an assignment.
3745
3746 This is done to invoke type inference during type checking phase for this
3747 assignment. Also, Final[...] doesn't affect type in any way -- it is rather an
3748 access qualifier for given `Var`.
3749
3750 Also perform various consistency checks.
3751
3752 Returns True if Final[...] was present.
3753 """
3754 if not s.unanalyzed_type or not self.is_final_type(s.unanalyzed_type):
3755 return False
3756 assert isinstance(s.unanalyzed_type, UnboundType)
3757 if len(s.unanalyzed_type.args) > 1:
3758 self.fail("Final[...] takes at most one type argument", s.unanalyzed_type)
3759 invalid_bare_final = False
3760 if not s.unanalyzed_type.args:
3761 s.type = None
3762 if (
3763 isinstance(s.rvalue, TempNode)
3764 and s.rvalue.no_rhs
3765 # Filter duplicate errors, we already reported this:
3766 and not (self.type and self.type.is_named_tuple)
3767 ):
3768 invalid_bare_final = True
3769 self.fail("Type in Final[...] can only be omitted if there is an initializer", s)
3770 else:
3771 s.type = s.unanalyzed_type.args[0]
3772
3773 if (
3774 s.type is not None
3775 and self.options.python_version < (3, 13)
3776 and self.is_classvar(s.type)
3777 ):
3778 self.fail("Variable should not be annotated with both ClassVar and Final", s)
3779 return False
3780
3781 if len(s.lvalues) != 1 or not isinstance(s.lvalues[0], RefExpr):
3782 self.fail("Invalid final declaration", s)
3783 return False
3784 lval = s.lvalues[0]
3785 assert isinstance(lval, RefExpr)
3786
3787 # Reset inferred status if it was set due to simple literal rvalue on previous iteration.
3788 # TODO: this is a best-effort quick fix, we should avoid the need to manually sync this,
3789 # see https://github.com/python/mypy/issues/6458.
3790 if lval.is_new_def:
3791 lval.is_inferred_def = s.type is None
3792
3793 if self.loop_depth[-1] > 0:
3794 self.fail("Cannot use Final inside a loop", s)
3795 if self.type and self.type.is_protocol:
3796 if self.is_class_scope():
3797 self.msg.protocol_members_cant_be_final(s)
3798 if (
3799 isinstance(s.rvalue, TempNode)
3800 and s.rvalue.no_rhs

Callers 1

visit_assignment_stmtMethod · 0.95

Calls 8

is_final_typeMethod · 0.95
failMethod · 0.95
is_classvarMethod · 0.95
is_class_scopeMethod · 0.95
isinstanceFunction · 0.85
lenFunction · 0.85
final_without_valueMethod · 0.80

Tested by

no test coverage detected