mypy icon indicating copy to clipboard operation
mypy copied to clipboard

Prohibit assignment to __class__ (Fixes #7724)

Open lsrafael13 opened this issue 7 months ago • 6 comments

Adds a type check that disallows assignments to class, which can lead to unsafe runtime behavior.

Includes tests for class assignments and verifies that other dunder and regular attributes remain assignable.

Fixes #7724

lsrafael13 avatar May 30 '25 23:05 lsrafael13

Diff from mypy_primer, showing the effect of this PR on open source code:

nox (https://github.com/wntrblm/nox): 1.10x slower (44.3s -> 48.8s in single noisy sample)

antidote (https://github.com/Finistere/antidote): 1.35x slower (69.7s -> 94.3s in single noisy sample)

materialize (https://github.com/MaterializeInc/materialize): 1.10x slower (143.3s -> 157.5s in single noisy sample)

mypy (https://github.com/python/mypy): 1.07x faster (119.3s -> 111.7s in single noisy sample)

spack (https://github.com/spack/spack): 1.42x faster (118.0s -> 83.1s in single noisy sample)
+ ...:142: error: INTERNAL ERROR -- Please try using mypy master on GitHub:
+ https://mypy.readthedocs.io/en/stable/common_issues.html#using-a-development-mypy-build
+ Please report a bug at https://github.com/python/mypy/issues
+ version: 1.17.0+dev.ff3a89edb6e8750bfd9a87734167d8dba0b308a6
+ ...:142: : note: use --pdb to drop into pdb
- lib/spack/spack/config.py:452: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/config.py:475: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/spec.py:3489: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/patch.py:196: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/fetch_strategy.py:521: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/install_test.py:264: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/install_test.py:412: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/install_test.py:515: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/install_test.py:517: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/install_test.py:528: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/install_test.py:622: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/install_test.py:642: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/install_test.py:842: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/installer.py:223: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/installer.py:2368: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/build_environment.py:380: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/build_environment.py:543: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/binary_distribution.py:2280: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/solver/asp.py:1482: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/solver/asp.py:3842: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/solver/asp.py:3845: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/solver/asp.py:3848: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/test/versions.py:673: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/test/sbang.py:58: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/test/repo.py:117: error: Unused "type: ignore" comment, use narrower [import-not-found] instead of [import] code  [unused-ignore]
- lib/spack/spack/test/repo.py:212: error: Unused "type: ignore" comment, use narrower [import-not-found] instead of [import] code  [unused-ignore]
- lib/spack/spack/test/repo.py:215: error: Unused "type: ignore" comment, use narrower [import-not-found] instead of [import] code  [unused-ignore]
- lib/spack/spack/test/entry_points.py:105: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/graph.py:448: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/graph.py:449: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/graph.py:509: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/unit_test.py:17: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/cmd/create.py:754: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/test/spec_semantics.py:1925: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/test/concretization/core.py:175: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/test/cmd/versions.py:39: error: Unused "type: ignore" comment, use narrower [import-not-found] instead of [import] code  [unused-ignore]
- lib/spack/spack/test/bindist.py:726: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/test/bindist.py:1395: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/ci/common.py:251: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/ci/common.py:269: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/cmd/repo.py:125: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/repo.py:139: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/repo.py:156: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/repo.py:157: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/external.py:145: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/config.py:443: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/checksum.py:92: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/checksum.py:102: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/checksum.py:115: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/buildcache.py:415: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/env.py:373: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
+ Traceback (most recent call last):
+   File "", line 8, in <module>
+     sys.exit(console_entry())
+   File "/__main__.py", line 15, in console_entry
+     main()
+   File "/main.py", line 127, in main
+     res, messages, blockers = run_build(sources, options, fscache, t0, stdout, stderr)
+   File "/main.py", line 211, in run_build
+     res = build.build(sources, options, None, flush_errors, fscache, stdout, stderr)
+   File "/build.py", line 191, in build
+     result = _build(
+   File "/build.py", line 267, in _build
+     graph = dispatch(sources, manager, stdout)
+   File "/build.py", line 2939, in dispatch
+     process_graph(graph, manager)
+   File "/build.py", line 3337, in process_graph
+     process_stale_scc(graph, scc, manager)
+   File "/build.py", line 3438, in process_stale_scc
+     graph[id].type_check_first_pass()
+   File "/build.py", line 2311, in type_check_first_pass
+     self.type_checker().check_first_pass()
+   File "/checker.py", line 471, in check_first_pass
+     self.accept(d)
+   File "/checker.py", line 578, in accept
+     stmt.accept(self)
+   File "/nodes.py", line 829, in accept
+     return visitor.visit_func_def(self)
+   File "/checker.py", line 1131, in visit_func_def
+     self._visit_func_def(defn)
+   File "/checker.py", line 1135, in _visit_func_def
+     self.check_func_item(defn, name=defn.name)
+   File "/checker.py", line 1170, in check_func_item
+     self.check_func_def(defn, typ, name, allow_empty)
+   File "/checker.py", line 1457, in check_func_def
+     self.accept(item.body)
+   File "/checker.py", line 578, in accept
+     stmt.accept(self)
+   File "/nodes.py", line 1297, in accept
+     return visitor.visit_block(self)
+   File "/checker.py", line 3031, in visit_block
+     self.accept(s)
+   File "/checker.py", line 578, in accept
+     stmt.accept(self)
+     ~~~~~~~~~~~^^^^^^
+   File "/nodes.py", line 829, in accept
+     return visitor.visit_func_def(self)
+            ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
+   File "/checker.py", line 1131, in visit_func_def
+     self._visit_func_def(defn)
+     ~~~~~~~~~~~~~~~~~~~~^^^^^^
+   File "/checker.py", line 1135, in _visit_func_def
+     self.check_func_item(defn, name=defn.name)
+     ~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
+   File "/checker.py", line 1170, in check_func_item
+     self.check_func_def(defn, typ, name, allow_empty)
+     ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   File "/checker.py", line 1425, in check_func_def
+     if key_var is not None and not self.is_var_redefined_in_outer_context(
+                                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
+         key_var, defn.line
+         ^^^^^^^^^^^^^^^^^^
+     ):
+     ^
+   File "/checker.py", line 1570, in is_var_redefined_in_outer_context
+     if find_last_var_assignment_line(outer.body, v) >= after_line:
+        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^
+   File "/checker.py", line 8870, in find_last_var_assignment_line
+     n.accept(visitor)
+     ~~~~~~~~^^^^^^^^^
+   File "/nodes.py", line 1297, in accept
+     return visitor.visit_block(self)
+            ~~~~~~~~~~~~~~~~~~~^^^^^^
+   File "/traverser.py", line 123, in visit_block
+     s.accept(self)
+     ~~~~~~~~^^^^^^
+   File "/nodes.py", line 1216, in accept
+     return visitor.visit_class_def(self)
+            ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
+   File "/traverser.py", line 155, in visit_class_def
+     o.defs.accept(self)
+     ~~~~~~~~~~~~~^^^^^^
+   File "/nodes.py", line 1297, in accept
+     return visitor.visit_block(self)
+            ~~~~~~~~~~~~~~~~~~~^^^^^^
+   File "/traverser.py", line 123, in visit_block
+     s.accept(self)
+     ~~~~~~~~^^^^^^
+   File "/nodes.py", line 829, in accept
+     return visitor.visit_func_def(self)
+            ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
+   File "/traverser.py", line 138, in visit_func_def
+     self.visit_func(o)
+     ~~~~~~~~~~~~~~~^^^
+   File "/traverser.py", line 135, in visit_func
+     o.body.accept(self)
+     ~~~~~~~~~~~~~^^^^^^
+   File "/nodes.py", line 1297, in accept
+     return visitor.visit_block(self)
+            ~~~~~~~~~~~~~~~~~~~^^^^^^
+   File "/traverser.py", line 123, in visit_block
+     s.accept(self)
+     ~~~~~~~~^^^^^^
+   File "/nodes.py", line 1384, in accept
+     return visitor.visit_assignment_stmt(self)
+            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
+   File "/checker.py", line 8886, in visit_assignment_stmt
+     self.fail("Assignment to '__class__' is unsafe and not allowed", lv)
+     ^^^^^^^^^
+ AttributeError: 'VarAssignVisitor' object has no attribute 'fail'

github-actions[bot] avatar May 31 '25 00:05 github-actions[bot]

Diff from mypy_primer, showing the effect of this PR on open source code:

colour (https://github.com/colour-science/colour): 1.07x slower (1640.6s -> 1760.3s in single noisy sample)

CPython (cases_generator) (https://github.com/python/cpython): 1.47x faster (23.2s -> 15.7s in single noisy sample)

bokeh (https://github.com/bokeh/bokeh): 1.05x slower (81.4s -> 85.5s in single noisy sample)

imagehash (https://github.com/JohannesBuchner/imagehash): 1.11x slower (76.0s -> 84.2s in single noisy sample)

spack (https://github.com/spack/spack): 1.42x faster (120.9s -> 85.2s in single noisy sample)
+ ...:142: error: INTERNAL ERROR -- Please try using mypy master on GitHub:
+ https://mypy.readthedocs.io/en/stable/common_issues.html#using-a-development-mypy-build
+ Please report a bug at https://github.com/python/mypy/issues
+ version: 1.17.0+dev.13b6bd802c4b97c419312d2c45413685c910e0ad
+ ...:142: : note: use --pdb to drop into pdb
- lib/spack/spack/config.py:452: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/config.py:475: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/spec.py:3489: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/patch.py:196: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/fetch_strategy.py:521: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/install_test.py:264: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/install_test.py:412: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/install_test.py:515: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/install_test.py:517: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/install_test.py:528: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/install_test.py:622: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/install_test.py:642: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/install_test.py:842: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/installer.py:223: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/installer.py:2368: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/build_environment.py:380: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/build_environment.py:543: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/binary_distribution.py:2280: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/solver/asp.py:1482: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/solver/asp.py:3842: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/solver/asp.py:3845: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/solver/asp.py:3848: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/test/versions.py:673: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/test/sbang.py:58: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/test/repo.py:117: error: Unused "type: ignore" comment, use narrower [import-not-found] instead of [import] code  [unused-ignore]
- lib/spack/spack/test/repo.py:212: error: Unused "type: ignore" comment, use narrower [import-not-found] instead of [import] code  [unused-ignore]
- lib/spack/spack/test/repo.py:215: error: Unused "type: ignore" comment, use narrower [import-not-found] instead of [import] code  [unused-ignore]
- lib/spack/spack/test/entry_points.py:105: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/graph.py:448: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/graph.py:449: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/graph.py:509: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/unit_test.py:17: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/cmd/create.py:754: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/test/spec_semantics.py:1925: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/test/concretization/core.py:175: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/test/cmd/versions.py:39: error: Unused "type: ignore" comment, use narrower [import-not-found] instead of [import] code  [unused-ignore]
- lib/spack/spack/test/bindist.py:726: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/test/bindist.py:1395: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/ci/common.py:251: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/ci/common.py:269: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/cmd/repo.py:125: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/repo.py:139: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/repo.py:156: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/repo.py:157: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/external.py:145: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/config.py:443: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/checksum.py:92: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/checksum.py:102: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/checksum.py:115: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/buildcache.py:415: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/env.py:373: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
+ Traceback (most recent call last):
+   File "", line 8, in <module>
+     sys.exit(console_entry())
+   File "/__main__.py", line 15, in console_entry
+     main()
+   File "/main.py", line 127, in main
+     res, messages, blockers = run_build(sources, options, fscache, t0, stdout, stderr)
+   File "/main.py", line 211, in run_build
+     res = build.build(sources, options, None, flush_errors, fscache, stdout, stderr)
+   File "/build.py", line 191, in build
+     result = _build(
+   File "/build.py", line 267, in _build
+     graph = dispatch(sources, manager, stdout)
+   File "/build.py", line 2939, in dispatch
+     process_graph(graph, manager)
+   File "/build.py", line 3337, in process_graph
+     process_stale_scc(graph, scc, manager)
+   File "/build.py", line 3438, in process_stale_scc
+     graph[id].type_check_first_pass()
+   File "/build.py", line 2311, in type_check_first_pass
+     self.type_checker().check_first_pass()
+   File "/checker.py", line 471, in check_first_pass
+     self.accept(d)
+   File "/checker.py", line 578, in accept
+     stmt.accept(self)
+   File "/nodes.py", line 829, in accept
+     return visitor.visit_func_def(self)
+   File "/checker.py", line 1131, in visit_func_def
+     self._visit_func_def(defn)
+   File "/checker.py", line 1135, in _visit_func_def
+     self.check_func_item(defn, name=defn.name)
+   File "/checker.py", line 1170, in check_func_item
+     self.check_func_def(defn, typ, name, allow_empty)
+   File "/checker.py", line 1457, in check_func_def
+     self.accept(item.body)
+   File "/checker.py", line 578, in accept
+     stmt.accept(self)
+   File "/nodes.py", line 1297, in accept
+     return visitor.visit_block(self)
+   File "/checker.py", line 3031, in visit_block
+     self.accept(s)
+   File "/checker.py", line 578, in accept
+     stmt.accept(self)
+     ~~~~~~~~~~~^^^^^^
+   File "/nodes.py", line 829, in accept
+     return visitor.visit_func_def(self)
+            ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
+   File "/checker.py", line 1131, in visit_func_def
+     self._visit_func_def(defn)
+     ~~~~~~~~~~~~~~~~~~~~^^^^^^
+   File "/checker.py", line 1135, in _visit_func_def
+     self.check_func_item(defn, name=defn.name)
+     ~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
+   File "/checker.py", line 1170, in check_func_item
+     self.check_func_def(defn, typ, name, allow_empty)
+     ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   File "/checker.py", line 1425, in check_func_def
+     if key_var is not None and not self.is_var_redefined_in_outer_context(
+                                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
+         key_var, defn.line
+         ^^^^^^^^^^^^^^^^^^
+     ):
+     ^
+   File "/checker.py", line 1570, in is_var_redefined_in_outer_context
+     if find_last_var_assignment_line(outer.body, v) >= after_line:
+        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^
+   File "/checker.py", line 8889, in find_last_var_assignment_line
+     n.accept(visitor)
+     ~~~~~~~~^^^^^^^^^
+   File "/nodes.py", line 1297, in accept
+     return visitor.visit_block(self)
+            ~~~~~~~~~~~~~~~~~~~^^^^^^
+   File "/traverser.py", line 123, in visit_block
+     s.accept(self)
+     ~~~~~~~~^^^^^^
+   File "/nodes.py", line 1216, in accept
+     return visitor.visit_class_def(self)
+            ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
+   File "/traverser.py", line 155, in visit_class_def
+     o.defs.accept(self)
+     ~~~~~~~~~~~~~^^^^^^
+   File "/nodes.py", line 1297, in accept
+     return visitor.visit_block(self)
+            ~~~~~~~~~~~~~~~~~~~^^^^^^
+   File "/traverser.py", line 123, in visit_block
+     s.accept(self)
+     ~~~~~~~~^^^^^^
+   File "/nodes.py", line 829, in accept
+     return visitor.visit_func_def(self)
+            ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
+   File "/traverser.py", line 138, in visit_func_def
+     self.visit_func(o)
+     ~~~~~~~~~~~~~~~^^^
+   File "/traverser.py", line 135, in visit_func
+     o.body.accept(self)
+     ~~~~~~~~~~~~~^^^^^^
+   File "/nodes.py", line 1297, in accept
+     return visitor.visit_block(self)
+            ~~~~~~~~~~~~~~~~~~~^^^^^^
+   File "/traverser.py", line 123, in visit_block
+     s.accept(self)
+     ~~~~~~~~^^^^^^
+   File "/nodes.py", line 1384, in accept
+     return visitor.visit_assignment_stmt(self)
+            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
+   File "/checker.py", line 8905, in visit_assignment_stmt
+     self.chk.fail("Assignment to '__class__' is unsafe and not allowed", lv)
+     ^^^^^^^^
+ AttributeError: 'VarAssignVisitor' object has no attribute 'chk'

discord.py (https://github.com/Rapptz/discord.py): 1.07x faster (311.3s -> 291.7s in single noisy sample)

github-actions[bot] avatar Jun 01 '25 19:06 github-actions[bot]

Diff from mypy_primer, showing the effect of this PR on open source code:

typeshed-stats (https://github.com/AlexWaygood/typeshed-stats): 1.14x slower (84.2s -> 96.4s in single noisy sample)

prefect (https://github.com/PrefectHQ/prefect): 1.14x slower (66.1s -> 75.7s in single noisy sample)

bokeh (https://github.com/bokeh/bokeh): 1.06x slower (79.3s -> 84.3s in single noisy sample)

imagehash (https://github.com/JohannesBuchner/imagehash): 1.06x slower (77.0s -> 81.3s in single noisy sample)

spack (https://github.com/spack/spack): 1.40x faster (118.1s -> 84.3s in single noisy sample)
+ ...:142: error: INTERNAL ERROR -- Please try using mypy master on GitHub:
+ https://mypy.readthedocs.io/en/stable/common_issues.html#using-a-development-mypy-build
+ Please report a bug at https://github.com/python/mypy/issues
+ version: 1.17.0+dev.e728f572af4f60a6cef34ae32c62f02a39aa64f6
+ ...:142: : note: use --pdb to drop into pdb
- lib/spack/spack/config.py:452: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/config.py:475: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/spec.py:3489: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/patch.py:196: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/fetch_strategy.py:521: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/install_test.py:264: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/install_test.py:412: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/install_test.py:515: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/install_test.py:517: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/install_test.py:528: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/install_test.py:622: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/install_test.py:642: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/install_test.py:842: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/installer.py:223: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/installer.py:2368: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/build_environment.py:380: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/build_environment.py:543: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/binary_distribution.py:2280: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/solver/asp.py:1482: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/solver/asp.py:3842: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/solver/asp.py:3845: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/solver/asp.py:3848: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/test/versions.py:673: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/test/sbang.py:58: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/test/repo.py:117: error: Unused "type: ignore" comment, use narrower [import-not-found] instead of [import] code  [unused-ignore]
- lib/spack/spack/test/repo.py:212: error: Unused "type: ignore" comment, use narrower [import-not-found] instead of [import] code  [unused-ignore]
- lib/spack/spack/test/repo.py:215: error: Unused "type: ignore" comment, use narrower [import-not-found] instead of [import] code  [unused-ignore]
- lib/spack/spack/test/entry_points.py:105: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/graph.py:448: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/graph.py:449: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/graph.py:509: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/unit_test.py:17: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/cmd/create.py:754: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/test/spec_semantics.py:1925: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/test/concretization/core.py:175: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/test/cmd/versions.py:39: error: Unused "type: ignore" comment, use narrower [import-not-found] instead of [import] code  [unused-ignore]
- lib/spack/spack/test/bindist.py:726: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/test/bindist.py:1395: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/ci/common.py:251: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/ci/common.py:269: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/cmd/repo.py:125: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/repo.py:139: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/repo.py:156: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/repo.py:157: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/external.py:145: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/config.py:443: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/checksum.py:92: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/checksum.py:102: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/checksum.py:115: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/buildcache.py:415: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/env.py:373: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
+ Traceback (most recent call last):
+   File "", line 8, in <module>
+     sys.exit(console_entry())
+   File "/__main__.py", line 15, in console_entry
+     main()
+   File "/main.py", line 127, in main
+     res, messages, blockers = run_build(sources, options, fscache, t0, stdout, stderr)
+   File "/main.py", line 211, in run_build
+     res = build.build(sources, options, None, flush_errors, fscache, stdout, stderr)
+   File "/build.py", line 191, in build
+     result = _build(
+   File "/build.py", line 267, in _build
+     graph = dispatch(sources, manager, stdout)
+   File "/build.py", line 2939, in dispatch
+     process_graph(graph, manager)
+   File "/build.py", line 3337, in process_graph
+     process_stale_scc(graph, scc, manager)
+   File "/build.py", line 3438, in process_stale_scc
+     graph[id].type_check_first_pass()
+   File "/build.py", line 2311, in type_check_first_pass
+     self.type_checker().check_first_pass()
+   File "/checker.py", line 471, in check_first_pass
+     self.accept(d)
+   File "/checker.py", line 578, in accept
+     stmt.accept(self)
+   File "/nodes.py", line 829, in accept
+     return visitor.visit_func_def(self)
+   File "/checker.py", line 1131, in visit_func_def
+     self._visit_func_def(defn)
+   File "/checker.py", line 1135, in _visit_func_def
+     self.check_func_item(defn, name=defn.name)
+   File "/checker.py", line 1170, in check_func_item
+     self.check_func_def(defn, typ, name, allow_empty)
+   File "/checker.py", line 1457, in check_func_def
+     self.accept(item.body)
+   File "/checker.py", line 578, in accept
+     stmt.accept(self)
+   File "/nodes.py", line 1297, in accept
+     return visitor.visit_block(self)
+   File "/checker.py", line 3031, in visit_block
+     self.accept(s)
+   File "/checker.py", line 578, in accept
+     stmt.accept(self)
+     ~~~~~~~~~~~^^^^^^
+   File "/nodes.py", line 829, in accept
+     return visitor.visit_func_def(self)
+            ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
+   File "/checker.py", line 1131, in visit_func_def
+     self._visit_func_def(defn)
+     ~~~~~~~~~~~~~~~~~~~~^^^^^^
+   File "/checker.py", line 1135, in _visit_func_def
+     self.check_func_item(defn, name=defn.name)
+     ~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
+   File "/checker.py", line 1170, in check_func_item
+     self.check_func_def(defn, typ, name, allow_empty)
+     ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   File "/checker.py", line 1425, in check_func_def
+     if key_var is not None and not self.is_var_redefined_in_outer_context(
+                                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
+         key_var, defn.line
+         ^^^^^^^^^^^^^^^^^^
+     ):
+     ^
+   File "/checker.py", line 1570, in is_var_redefined_in_outer_context
+     if find_last_var_assignment_line(outer.body, v) >= after_line:
+        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^
+   File "/checker.py", line 8889, in find_last_var_assignment_line
+     n.accept(visitor)
+     ~~~~~~~~^^^^^^^^^
+   File "/nodes.py", line 1297, in accept
+     return visitor.visit_block(self)
+            ~~~~~~~~~~~~~~~~~~~^^^^^^
+   File "/traverser.py", line 123, in visit_block
+     s.accept(self)
+     ~~~~~~~~^^^^^^
+   File "/nodes.py", line 1216, in accept
+     return visitor.visit_class_def(self)
+            ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
+   File "/traverser.py", line 155, in visit_class_def
+     o.defs.accept(self)
+     ~~~~~~~~~~~~~^^^^^^
+   File "/nodes.py", line 1297, in accept
+     return visitor.visit_block(self)
+            ~~~~~~~~~~~~~~~~~~~^^^^^^
+   File "/traverser.py", line 123, in visit_block
+     s.accept(self)
+     ~~~~~~~~^^^^^^
+   File "/nodes.py", line 829, in accept
+     return visitor.visit_func_def(self)
+            ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
+   File "/traverser.py", line 138, in visit_func_def
+     self.visit_func(o)
+     ~~~~~~~~~~~~~~~^^^
+   File "/traverser.py", line 135, in visit_func
+     o.body.accept(self)
+     ~~~~~~~~~~~~~^^^^^^
+   File "/nodes.py", line 1297, in accept
+     return visitor.visit_block(self)
+            ~~~~~~~~~~~~~~~~~~~^^^^^^
+   File "/traverser.py", line 123, in visit_block
+     s.accept(self)
+     ~~~~~~~~^^^^^^
+   File "/nodes.py", line 1384, in accept
+     return visitor.visit_assignment_stmt(self)
+            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
+   File "/checker.py", line 8905, in visit_assignment_stmt
+     self.errors.report(
+     ^^^^^^^^^^^
+ AttributeError: 'VarAssignVisitor' object has no attribute 'errors'

discord.py (https://github.com/Rapptz/discord.py): 1.08x slower (289.3s -> 313.5s in single noisy sample)

github-actions[bot] avatar Jun 01 '25 21:06 github-actions[bot]

Diff from mypy_primer, showing the effect of this PR on open source code:

mypy (https://github.com/python/mypy): 1.07x slower (92.3s -> 98.5s in single noisy sample)

spack (https://github.com/spack/spack): 1.41x faster (119.2s -> 84.6s in single noisy sample)
+ ...:142: error: INTERNAL ERROR -- Please try using mypy master on GitHub:
+ https://mypy.readthedocs.io/en/stable/common_issues.html#using-a-development-mypy-build
+ Please report a bug at https://github.com/python/mypy/issues
+ version: 1.17.0+dev.12c0973d8c952e091749cf9f537b1c9852fafc0d
+ ...:142: : note: use --pdb to drop into pdb
- lib/spack/spack/config.py:452: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/config.py:475: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/spec.py:3489: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/patch.py:196: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/fetch_strategy.py:521: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/install_test.py:264: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/install_test.py:412: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/install_test.py:515: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/install_test.py:517: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/install_test.py:528: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/install_test.py:622: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/install_test.py:642: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/install_test.py:842: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/installer.py:223: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/installer.py:2368: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/build_environment.py:380: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/build_environment.py:543: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/binary_distribution.py:2280: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/solver/asp.py:1482: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/solver/asp.py:3842: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/solver/asp.py:3845: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/solver/asp.py:3848: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/test/versions.py:673: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/test/sbang.py:58: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/test/repo.py:117: error: Unused "type: ignore" comment, use narrower [import-not-found] instead of [import] code  [unused-ignore]
- lib/spack/spack/test/repo.py:212: error: Unused "type: ignore" comment, use narrower [import-not-found] instead of [import] code  [unused-ignore]
- lib/spack/spack/test/repo.py:215: error: Unused "type: ignore" comment, use narrower [import-not-found] instead of [import] code  [unused-ignore]
- lib/spack/spack/test/entry_points.py:105: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/graph.py:448: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/graph.py:449: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/graph.py:509: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/unit_test.py:17: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/cmd/create.py:754: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/test/spec_semantics.py:1925: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/test/concretization/core.py:175: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/test/cmd/versions.py:39: error: Unused "type: ignore" comment, use narrower [import-not-found] instead of [import] code  [unused-ignore]
- lib/spack/spack/test/bindist.py:726: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/test/bindist.py:1395: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/ci/common.py:251: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/ci/common.py:269: error: Unused "type: ignore" comment  [unused-ignore]
- lib/spack/spack/cmd/repo.py:125: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/repo.py:139: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/repo.py:156: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/repo.py:157: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/external.py:145: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/config.py:443: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/checksum.py:92: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/checksum.py:102: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/checksum.py:115: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/buildcache.py:415: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
- lib/spack/spack/cmd/env.py:373: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
+ Traceback (most recent call last):
+   File "", line 8, in <module>
+     sys.exit(console_entry())
+   File "/__main__.py", line 15, in console_entry
+     main()
+   File "/main.py", line 127, in main
+     res, messages, blockers = run_build(sources, options, fscache, t0, stdout, stderr)
+   File "/main.py", line 211, in run_build
+     res = build.build(sources, options, None, flush_errors, fscache, stdout, stderr)
+   File "/build.py", line 191, in build
+     result = _build(
+   File "/build.py", line 267, in _build
+     graph = dispatch(sources, manager, stdout)
+   File "/build.py", line 2939, in dispatch
+     process_graph(graph, manager)
+   File "/build.py", line 3337, in process_graph
+     process_stale_scc(graph, scc, manager)
+   File "/build.py", line 3438, in process_stale_scc
+     graph[id].type_check_first_pass()
+   File "/build.py", line 2311, in type_check_first_pass
+     self.type_checker().check_first_pass()
+   File "/checker.py", line 471, in check_first_pass
+     self.accept(d)
+   File "/checker.py", line 578, in accept
+     stmt.accept(self)
+   File "/nodes.py", line 829, in accept
+     return visitor.visit_func_def(self)
+   File "/checker.py", line 1131, in visit_func_def
+     self._visit_func_def(defn)
+   File "/checker.py", line 1135, in _visit_func_def
+     self.check_func_item(defn, name=defn.name)
+   File "/checker.py", line 1170, in check_func_item
+     self.check_func_def(defn, typ, name, allow_empty)
+   File "/checker.py", line 1457, in check_func_def
+     self.accept(item.body)
+   File "/checker.py", line 578, in accept
+     stmt.accept(self)
+   File "/nodes.py", line 1297, in accept
+     return visitor.visit_block(self)
+   File "/checker.py", line 3031, in visit_block
+     self.accept(s)
+   File "/checker.py", line 578, in accept
+     stmt.accept(self)
+     ~~~~~~~~~~~^^^^^^
+   File "/nodes.py", line 829, in accept
+     return visitor.visit_func_def(self)
+            ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
+   File "/checker.py", line 1131, in visit_func_def
+     self._visit_func_def(defn)
+     ~~~~~~~~~~~~~~~~~~~~^^^^^^
+   File "/checker.py", line 1135, in _visit_func_def
+     self.check_func_item(defn, name=defn.name)
+     ~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
+   File "/checker.py", line 1170, in check_func_item
+     self.check_func_def(defn, typ, name, allow_empty)
+     ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   File "/checker.py", line 1425, in check_func_def
+     if key_var is not None and not self.is_var_redefined_in_outer_context(
+                                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
+         key_var, defn.line
+         ^^^^^^^^^^^^^^^^^^
+     ):
+     ^
+   File "/checker.py", line 1570, in is_var_redefined_in_outer_context
+     if find_last_var_assignment_line(outer.body, v) >= after_line:
+        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^
+   File "/checker.py", line 8889, in find_last_var_assignment_line
+     n.accept(visitor)
+     ~~~~~~~~^^^^^^^^^
+   File "/nodes.py", line 1297, in accept
+     return visitor.visit_block(self)
+            ~~~~~~~~~~~~~~~~~~~^^^^^^
+   File "/traverser.py", line 123, in visit_block
+     s.accept(self)
+     ~~~~~~~~^^^^^^
+   File "/nodes.py", line 1216, in accept
+     return visitor.visit_class_def(self)
+            ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
+   File "/traverser.py", line 155, in visit_class_def
+     o.defs.accept(self)
+     ~~~~~~~~~~~~~^^^^^^
+   File "/nodes.py", line 1297, in accept
+     return visitor.visit_block(self)
+            ~~~~~~~~~~~~~~~~~~~^^^^^^
+   File "/traverser.py", line 123, in visit_block
+     s.accept(self)
+     ~~~~~~~~^^^^^^
+   File "/nodes.py", line 829, in accept
+     return visitor.visit_func_def(self)
+            ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
+   File "/traverser.py", line 138, in visit_func_def
+     self.visit_func(o)
+     ~~~~~~~~~~~~~~~^^^
+   File "/traverser.py", line 135, in visit_func
+     o.body.accept(self)
+     ~~~~~~~~~~~~~^^^^^^
+   File "/nodes.py", line 1297, in accept
+     return visitor.visit_block(self)
+            ~~~~~~~~~~~~~~~~~~~^^^^^^
+   File "/traverser.py", line 123, in visit_block
+     s.accept(self)
+     ~~~~~~~~^^^^^^
+   File "/nodes.py", line 1384, in accept
+     return visitor.visit_assignment_stmt(self)
+            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
+   File "/checker.py", line 8905, in visit_assignment_stmt
+     self.fail("Assignment to '__class__' is unsafe and not allowed", lv)
+     ^^^^^^^^^
+ AttributeError: 'VarAssignVisitor' object has no attribute 'fail'

github-actions[bot] avatar Jun 02 '25 20:06 github-actions[bot]

Diff from mypy_primer, showing the effect of this PR on open source code:

zipp (https://github.com/jaraco/zipp)
+ zipp/__init__.py:163: error: Assignment to '__class__' is unsafe and not allowed  [misc]

prefect (https://github.com/PrefectHQ/prefect)
+ src/prefect/_internal/_logging.py:30: error: Assignment to '__class__' is unsafe and not allowed  [misc]
+ src/prefect/_internal/_logging.py:38: error: Assignment to '__class__' is unsafe and not allowed  [misc]
+ src/prefect/client/base.py:174: error: Assignment to '__class__' is unsafe and not allowed  [misc]

porcupine (https://github.com/Akuli/porcupine)
+ porcupine/utils.py:475: error: Assignment to '__class__' is unsafe and not allowed  [misc]

hydpy (https://github.com/hydpy-dev/hydpy)
+ hydpy/docs/sphinx/conf.py:166: error: Assignment to '__class__' is unsafe and not allowed  [misc]

scipy (https://github.com/scipy/scipy)
+ scipy/interpolate/_fitpack2.py:326: error: Assignment to '__class__' is unsafe and not allowed  [misc]

alerta (https://github.com/alerta/alerta)
+ alerta/models/alarms/__init__.py:34: error: Assignment to '__class__' is unsafe and not allowed  [misc]
+ alerta/database/base.py:56: error: Assignment to '__class__' is unsafe and not allowed  [misc]

werkzeug (https://github.com/pallets/werkzeug)
+ src/werkzeug/wrappers/response.py:239: error: Assignment to '__class__' is unsafe and not allowed  [misc]

spack (https://github.com/spack/spack)
+ lib/spack/llnl/util/lang.py:745: error: Assignment to '__class__' is unsafe and not allowed  [misc]
+ lib/spack/llnl/util/lang.py:747: error: Assignment to '__class__' is unsafe and not allowed  [misc]
+ lib/spack/spack/builder.py:133: error: Assignment to '__class__' is unsafe and not allowed  [misc]

discord.py (https://github.com/Rapptz/discord.py): 1.06x faster (297.0s -> 279.3s in single noisy sample)

steam.py (https://github.com/Gobot1234/steam.py)
+ steam/protobufs/msg.py:161: error: Assignment to '__class__' is unsafe and not allowed  [misc]
+ steam/protobufs/msg.py:212: error: Assignment to '__class__' is unsafe and not allowed  [misc]
+ steam/protobufs/msg.py:297: error: Assignment to '__class__' is unsafe and not allowed  [misc]
+ steam/protobufs/msg.py:322: error: Assignment to '__class__' is unsafe and not allowed  [misc]

sphinx (https://github.com/sphinx-doc/sphinx)
+ sphinx/util/logging.py: note: In member "filter" of class "SphinxLogRecordTranslator":
+ sphinx/util/logging.py:505:13: error: Assignment to '__class__' is unsafe and not allowed  [misc]
+ sphinx/util/logging.py:505:13: note: Error code "misc" not covered by "type: ignore" comment

github-actions[bot] avatar Jun 02 '25 23:06 github-actions[bot]

And why on earth is this PR listed as fixing #7724? That one is much broader and doesn't seem to concern __class__ assignments at all?

sterliakov avatar Jun 03 '25 19:06 sterliakov