diff --git a/mypy/checker.py b/mypy/checker.py index 9c389cccd95f..3c132731d809 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -3078,6 +3078,11 @@ def visit_assignment_stmt(self, s: AssignmentStmt) -> None: with self.enter_final_context(s.is_final_def): self.check_assignment(s.lvalues[-1], s.rvalue, s.type is None, s.new_syntax) + for lv in s.lvalues: + if isinstance(lv, MemberExpr): + if lv.name == "__class__": + self.fail("Assignment to '__class__' is unsafe and not allowed", lv) + if s.is_alias_def: self.check_type_alias_rvalue(s) diff --git a/test-data/unit/check-assign-to-class.test b/test-data/unit/check-assign-to-class.test new file mode 100644 index 000000000000..53043c657e12 --- /dev/null +++ b/test-data/unit/check-assign-to-class.test @@ -0,0 +1,22 @@ +[case test_assign_to_dunder_class] +class A: + def foo(self): + self.__class__ = B # E: Assignment to '__class__' is unsafe and not allowed + +class B: + pass + +[case test_assign_to_other_dunder_attributes] +class C: + def bar(self): + self.__name__ = "NewName" # OK + self.__doc__ = "Test doc" # OK + +class D: + pass + +[case test_assign_to_regular_attribute] +class E: + x = 1 + def baz(self): + self.x = 2 # OK