[med-svn] [Git][python-team/packages/mypy][master] Cherry-pick patch from upstream to fix FTBFS of black using mypy 2.4.0. Closes: #1150524
Michael R. Crusoe (@crusoe)
gitlab at salsa.debian.org
Tue Oct 13 07:48:22 BST 2026
Michael R. Crusoe pushed to branch master at Debian Python Team / packages / mypy
Commits:
e3ef9995 by Michael R. Crusoe at 2026-10-13T08:48:01+02:00
Cherry-pick patch from upstream to fix FTBFS of black using mypy 2.4.0. Closes: #1150524
- - - - -
7 changed files:
- debian/changelog
- + debian/patches/0001-mypyc-Fix-recursive-setup-for-frame-private-helpers.patch
- debian/patches/hint-typeshed-package
- debian/patches/intersphinx
- debian/patches/remove-mypyc-test-run-timeout
- debian/patches/series
- debian/patches/verbose
Changes:
=====================================
debian/changelog
=====================================
@@ -1,3 +1,10 @@
+mypy (2.4.0-2) unstable; urgency=medium
+
+ * Cherry-pick patch from upstream to fix FTBFS of black using mypy
+ 2.4.0. Closes: #1150524
+
+ -- Michael R. Crusoe <crusoe at debian.org> Tue, 13 Oct 2026 08:47:55 +0200
+
mypy (2.4.0-1) unstable; urgency=medium
* New upstream version
=====================================
debian/patches/0001-mypyc-Fix-recursive-setup-for-frame-private-helpers.patch
=====================================
@@ -0,0 +1,279 @@
+From: Piotr Sawicki <sawickipiotr at outlook.com>
+Date: Mon, 12 Oct 2026 14:53:12 +0200
+Subject: [mypyc] Fix recursive setup for frame-private helpers
+
+Origin: upstream, https://github.com/python/mypy/pull/22187/
+Forwared: not-needed
+---
+ mypyc/irbuild/env_class.py | 35 +++++++++++++++++---------
+ mypyc/irbuild/function.py | 8 +++---
+ mypyc/irbuild/generator.py | 4 +--
+ mypyc/irbuild/util.py | 8 ++++++
+ mypyc/test-data/run-generators.test | 32 ++++++++++++++++++++++++
+ mypyc/test/test_generator_spills.py | 50 +++++++++++++++++++++++++++++++++++++
+ 6 files changed, 118 insertions(+), 19 deletions(-)
+
+diff --git a/mypyc/irbuild/env_class.py b/mypyc/irbuild/env_class.py
+index 4e5c581..55d842a 100644
+--- a/mypyc/irbuild/env_class.py
++++ b/mypyc/irbuild/env_class.py
+@@ -31,6 +31,7 @@ from mypyc.ir.rtypes import RInstance, bitmap_rprimitive, object_rprimitive
+ from mypyc.irbuild.builder import IRBuilder, SymbolTarget
+ from mypyc.irbuild.context import FuncInfo, GeneratorClass, ImplicitClass
+ from mypyc.irbuild.targets import AssignmentTargetAttr
++from mypyc.irbuild.util import get_func_target_symbol
+
+
+ def setup_env_class(builder: IRBuilder) -> ClassIR:
+@@ -141,7 +142,7 @@ def load_env_registers(builder: IRBuilder, prefix: str = "") -> None:
+ # If this is a FuncDef, then make sure to load the FuncDef into its own environment
+ # class so that the function can be called recursively.
+ if isinstance(fitem, FuncDef) and fn_info.add_nested_funcs_to_env:
+- setup_func_for_recursive_call(builder, fitem, fn_info.callable_class, prefix=prefix)
++ setup_func_for_recursive_call(builder, fitem, fn_info.callable_class)
+
+
+ def load_outer_env(
+@@ -298,8 +299,13 @@ def add_vars_to_env(builder: IRBuilder, prefix: str = "") -> None:
+ )
+
+ if fn_info.fitem in builder.encapsulating_funcs:
++ added: set[SymbolNode] = set()
+ for nested_fn in builder.encapsulating_funcs[fn_info.fitem]:
+ if isinstance(nested_fn, FuncDef):
++ target_symbol = get_func_target_symbol(nested_fn)
++ if target_symbol in added:
++ continue
++ added.add(target_symbol)
+ # The return type is 'object' instead of an RInstance of the
+ # callable class because differently defined functions with
+ # the same name and signature across conditional blocks
+@@ -308,10 +314,10 @@ def add_vars_to_env(builder: IRBuilder, prefix: str = "") -> None:
+ nested_prefix = prefix
+ if nested_fn.is_generator or nested_fn.is_coroutine:
+ nested_prefix = GENERATOR_ATTRIBUTE_PREFIX
+- keep_alive = is_free_variable(builder, nested_fn)
+- if fn_info.is_generator and not builder.is_captured_by_nested_func(nested_fn):
++ keep_alive = is_free_variable(builder, target_symbol)
++ if fn_info.is_generator and not builder.is_captured_by_nested_func(target_symbol):
+ builder.add_var_to_generator_frame(
+- nested_fn,
++ target_symbol,
+ object_rprimitive,
+ fn_info.generator_class.self_reg,
+ reassign=False,
+@@ -319,7 +325,7 @@ def add_vars_to_env(builder: IRBuilder, prefix: str = "") -> None:
+ )
+ else:
+ builder.add_var_to_env_class(
+- nested_fn,
++ target_symbol,
+ object_rprimitive,
+ env_for_func,
+ reassign=False,
+@@ -328,9 +334,7 @@ def add_vars_to_env(builder: IRBuilder, prefix: str = "") -> None:
+ )
+
+
+-def setup_func_for_recursive_call(
+- builder: IRBuilder, fdef: FuncDef, base: ImplicitClass, prefix: str = ""
+-) -> None:
++def setup_func_for_recursive_call(builder: IRBuilder, fdef: FuncDef, base: ImplicitClass) -> None:
+ """Enable calling a nested function (with a callable class) recursively.
+
+ Adds the instance of the callable class representing the given
+@@ -338,10 +342,17 @@ def setup_func_for_recursive_call(
+ be called recursively. Note that this needs to be done only for
+ nested functions.
+ """
+- # First, set the attribute of the environment class so that GetAttr can be called on it.
+ prev_env = builder.fn_infos[-2].env_class
+- attr_name = prefix + fdef.name
+- prev_env.attributes[attr_name] = builder.type_to_rtype(fdef.type)
++ target_symbol = get_func_target_symbol(fdef)
++ target = builder.symtables[-2].get(target_symbol)
++ if (
++ not isinstance(target, AssignmentTargetAttr)
++ or not isinstance(target.obj.type, RInstance)
++ or target.obj.type.class_ir is not prev_env
++ ):
++ return
++
++ attr_name = target.attr
+ line = fdef.line
+
+ if isinstance(base, GeneratorClass):
+@@ -355,7 +366,7 @@ def setup_func_for_recursive_call(
+ # Obtain the instance of the callable class representing the FuncDef, and add it to the
+ # current environment.
+ val = builder.add(GetAttr(prev_env_reg, attr_name, line))
+- target = builder.add_local_reg(fdef, object_rprimitive)
++ target = builder.add_local_reg(target_symbol, object_rprimitive)
+ builder.assign(target, val, line)
+
+
+diff --git a/mypyc/irbuild/function.py b/mypyc/irbuild/function.py
+index 588e1cd..2b12b25 100644
+--- a/mypyc/irbuild/function.py
++++ b/mypyc/irbuild/function.py
+@@ -77,6 +77,7 @@ from mypyc.irbuild.env_class import (
+ )
+ from mypyc.irbuild.generator import gen_generator_func, gen_generator_func_body
+ from mypyc.irbuild.targets import AssignmentTarget
++from mypyc.irbuild.util import get_func_target_symbol
+ from mypyc.primitives.dict_ops import (
+ dict_get_method_with_none,
+ dict_new_op,
+@@ -925,11 +926,10 @@ def get_func_target(builder: IRBuilder, fdef: FuncDef) -> AssignmentTarget:
+ If the function was not already defined somewhere, then define it
+ and add it to the current environment.
+ """
+- if orig := fdef.original_def:
+- if isinstance(orig, Decorator):
+- orig = orig.func
++ target_symbol = get_func_target_symbol(fdef)
++ if target_symbol is not fdef:
+ # Get the target associated with the previously defined FuncDef.
+- return builder.lookup(orig)
++ return builder.lookup(target_symbol)
+
+ if builder.fn_info.is_generator or builder.fn_info.add_nested_funcs_to_env:
+ return builder.lookup(fdef)
+diff --git a/mypyc/irbuild/generator.py b/mypyc/irbuild/generator.py
+index 7cd4f7d..86d4d40 100644
+--- a/mypyc/irbuild/generator.py
++++ b/mypyc/irbuild/generator.py
+@@ -111,9 +111,7 @@ def gen_generator_func_body(builder: IRBuilder, fn_info: FuncInfo, func_reg: Val
+ and top_level
+ and top_level.add_nested_funcs_to_env
+ ):
+- setup_func_for_recursive_call(
+- builder, fitem, builder.fn_info.generator_class, prefix=GENERATOR_ATTRIBUTE_PREFIX
+- )
++ setup_func_for_recursive_call(builder, fitem, builder.fn_info.generator_class)
+ cleanup_on_error = BasicBlock()
+ builder.builder.push_error_handler(cleanup_on_error)
+ create_switch_for_generator_class(builder)
+diff --git a/mypyc/irbuild/util.py b/mypyc/irbuild/util.py
+index a2378fa..5c53391 100644
+--- a/mypyc/irbuild/util.py
++++ b/mypyc/irbuild/util.py
+@@ -346,6 +346,14 @@ def get_func_def(op: FuncDef | Decorator | OverloadedFuncDef) -> FuncDef:
+ return op
+
+
++def get_func_target_symbol(fdef: FuncDef) -> FuncDef | Var:
++ """Return the symbol used to store a possibly redefined function."""
++ original = fdef.original_def
++ if isinstance(original, Decorator):
++ return original.func
++ return original or fdef
++
++
+ def concrete_arg_kind(kind: ArgKind) -> ArgKind:
+ """Find the concrete version of an arg kind that is being passed."""
+ if kind == ARG_OPT:
+diff --git a/mypyc/test-data/run-generators.test b/mypyc/test-data/run-generators.test
+index b881079..70f3e80 100644
+--- a/mypyc/test-data/run-generators.test
++++ b/mypyc/test-data/run-generators.test
+@@ -825,6 +825,38 @@ def test_nested_generator_private_spill() -> None:
+ assert yields == ("right",)
+ assert value == "capturedleftsent"
+
++[case testNestedGeneratorPrivateHelper]
++from typing import Iterator
++
++def outer() -> Iterator[int]:
++ def captured() -> Iterator[int]:
++ yield 1
++
++ def private() -> Iterator[int]:
++ yield from captured()
++
++ yield from private()
++
++def test_nested_generator_private_helper() -> None:
++ assert list(outer()) == [1]
++
++[case testRedefinedNestedGeneratorHelper]
++from typing import Iterator
++
++def redefined_nested_helper(flag: bool) -> Iterator[int]:
++ if flag:
++ def helper(n: int) -> int:
++ return 1
++ else:
++ def helper(n: int) -> int:
++ return helper(1) if not n else 2
++
++ yield helper(0)
++
++def test_redefined_nested_generator_helper() -> None:
++ assert list(redefined_nested_helper(True)) == [1]
++ assert list(redefined_nested_helper(False)) == [2]
++
+ [case testGeneratorPrivateAndEscapedBindings]
+ from typing import Any, Callable, Generator, Iterator
+
+diff --git a/mypyc/test/test_generator_spills.py b/mypyc/test/test_generator_spills.py
+index a6e0618..462d2a7 100644
+--- a/mypyc/test/test_generator_spills.py
++++ b/mypyc/test/test_generator_spills.py
+@@ -184,6 +184,56 @@ def gen() -> Iterator[Any]:
+ )
+ assert environment is not frame
+
++ def test_nested_generator_private_helper_stays_on_frame(self) -> None:
++ module, _, _, _ = build_ir_for_single_file2("""\
++from typing import Iterator
++
++def outer() -> Iterator[int]:
++ def captured() -> Iterator[int]:
++ yield 1
++ def private() -> Iterator[int]:
++ yield from captured()
++ yield from private()
++""".splitlines())
++ outer_frame = next(cl for cl in module.classes if cl.name == "outer_gen")
++ environment_type = outer_frame.attributes[ENV_ATTR_NAME]
++ assert isinstance(environment_type, RInstance)
++ environment = environment_type.class_ir
++
++ assert GENERATOR_ATTRIBUTE_PREFIX + "captured" in environment.attributes
++ assert "private" in frame_variables(outer_frame)
++ assert GENERATOR_ATTRIBUTE_PREFIX + "private" not in environment.attributes
++
++ private_frame = next(cl for cl in module.classes if cl.name.startswith("private_gen___"))
++ private_helper = private_frame.env_user_function
++ assert private_helper is not None
++ assert not any(
++ isinstance(op, GetAttr) and op.attr == GENERATOR_ATTRIBUTE_PREFIX + "private"
++ for block in private_helper.blocks
++ for op in block.ops
++ )
++
++ def test_redefined_nested_helper_has_single_storage_location(self) -> None:
++ module, _, _, _ = build_ir_for_single_file2("""\
++from typing import Iterator
++
++def outer(flag: bool) -> Iterator[int]:
++ if flag:
++ def helper(n: int) -> int:
++ return 1
++ else:
++ def helper(n: int) -> int:
++ return helper(1) if not n else 2
++ yield helper(0)
++""".splitlines())
++ outer_frame = next(cl for cl in module.classes if cl.name == "outer_gen")
++ environment_type = outer_frame.attributes[ENV_ATTR_NAME]
++ assert isinstance(environment_type, RInstance)
++ environment = environment_type.class_ir
++
++ assert GENERATOR_ATTRIBUTE_PREFIX + "helper" in environment.attributes
++ assert "helper" not in frame_variables(outer_frame)
++
+ def test_nested_finally_promotes_each_saved_exception(self) -> None:
+ cl = generator_class(
+ """\
=====================================
debian/patches/hint-typeshed-package
=====================================
@@ -11,9 +11,11 @@ Forwarded: not-needed
test-data/unit/fine-grained-modules.test | 4 ++--
4 files changed, 7 insertions(+), 5 deletions(-)
---- mypy.orig/mypy/modulefinder.py
-+++ mypy/mypy/modulefinder.py
-@@ -104,7 +104,9 @@
+diff --git a/mypy/modulefinder.py b/mypy/modulefinder.py
+index baa521a..ef7236c 100644
+--- a/mypy/modulefinder.py
++++ b/mypy/modulefinder.py
+@@ -104,7 +104,9 @@ class ModuleNotFoundReason(Enum):
notes = [doc_link]
elif self is ModuleNotFoundReason.APPROVED_STUBS_NOT_INSTALLED:
msg = 'Library stubs not installed for "{module}"'
@@ -24,9 +26,11 @@ Forwarded: not-needed
if not daemon:
notes.append(
'(or run "mypy --install-types" to install all missing stub packages)'
---- mypy.orig/test-data/unit/check-errorcodes.test
-+++ mypy/test-data/unit/check-errorcodes.test
-@@ -652,7 +652,7 @@
+diff --git a/test-data/unit/check-errorcodes.test b/test-data/unit/check-errorcodes.test
+index c82ef61..9fdbb45 100644
+--- a/test-data/unit/check-errorcodes.test
++++ b/test-data/unit/check-errorcodes.test
+@@ -652,7 +652,7 @@ if int() is str(): # E: Non-overlapping identity check (left operand type: "int
[case testErrorCodeMissingModule]
from defusedxml import xyz # E: Library stubs not installed for "defusedxml" [import-untyped] \
@@ -35,9 +39,11 @@ Forwarded: not-needed
# N: (or run "mypy --install-types" to install all missing stub packages)
from nonexistent import foobar # E: Cannot find implementation or library stub for module named "nonexistent" [import-not-found]
import nonexistent2 # E: Cannot find implementation or library stub for module named "nonexistent2" [import-not-found]
---- mypy.orig/test-data/unit/check-modules.test
-+++ mypy/test-data/unit/check-modules.test
-@@ -3123,7 +3123,7 @@
+diff --git a/test-data/unit/check-modules.test b/test-data/unit/check-modules.test
+index 5fba65f..8f3d51b 100644
+--- a/test-data/unit/check-modules.test
++++ b/test-data/unit/check-modules.test
+@@ -3123,7 +3123,7 @@ import google.non_existent # E: Cannot find implementation or library stub for
from google.non_existent import x
import google.cloud.ndb # E: Library stubs not installed for "google.cloud.ndb" \
@@ -46,9 +52,11 @@ Forwarded: not-needed
# N: (or run "mypy --install-types" to install all missing stub packages) \
# N: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports
from google.cloud import ndb
---- mypy.orig/test-data/unit/fine-grained-modules.test
-+++ mypy/test-data/unit/fine-grained-modules.test
-@@ -2201,12 +2201,12 @@
+diff --git a/test-data/unit/fine-grained-modules.test b/test-data/unit/fine-grained-modules.test
+index 53ee178..8a0e55a 100644
+--- a/test-data/unit/fine-grained-modules.test
++++ b/test-data/unit/fine-grained-modules.test
+@@ -2201,12 +2201,12 @@ import requests
import jack
[out]
a.py:1: error: Library stubs not installed for "requests"
=====================================
debian/patches/intersphinx
=====================================
@@ -5,11 +5,14 @@ Subject: link to local documenatin
Forwarded: not-needed
---
docs/source/conf.py | 13 ++++++++-----
- 1 file changed, 8 insertions(+), 5 deletions(-)
+ mypyc/doc/conf.py | 2 +-
+ 2 files changed, 9 insertions(+), 6 deletions(-)
---- mypy.orig/docs/source/conf.py
-+++ mypy/docs/source/conf.py
-@@ -276,11 +276,14 @@
+diff --git a/docs/source/conf.py b/docs/source/conf.py
+index 02caa44..8d2b84e 100644
+--- a/docs/source/conf.py
++++ b/docs/source/conf.py
+@@ -276,11 +276,14 @@ texinfo_documents = [
rst_prolog = ".. |...| unicode:: U+2026 .. ellipsis\n"
intersphinx_mapping = {
@@ -29,9 +32,11 @@ Forwarded: not-needed
}
---- mypy.orig/mypyc/doc/conf.py
-+++ mypy/mypyc/doc/conf.py
-@@ -38,7 +38,7 @@
+diff --git a/mypyc/doc/conf.py b/mypyc/doc/conf.py
+index e6b2bfa..bdc93c2 100644
+--- a/mypyc/doc/conf.py
++++ b/mypyc/doc/conf.py
+@@ -38,7 +38,7 @@ release = mypy_version
# ones.
extensions = ["sphinx.ext.intersphinx"]
=====================================
debian/patches/remove-mypyc-test-run-timeout
=====================================
@@ -1,12 +1,20 @@
-From: Michael R. Crusoe <crusoe at debian.org>
+From: "Michael R. Crusoe" <crusoe at debian.org>
+Date: Tue, 24 Mar 2026 15:14:09 +0200
Subject: remove 30 seconds timeout, due to slower architectures
+Last-Update: 2026-09-15
+
With Python version 3.13.x & 3.14.x we don't see any hangs
But on sparc64 with hit the timeout, so remove it
+---
+ mypyc/test/test_run.py | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
---- mypy.orig/mypyc/test/test_run.py
-+++ mypy/mypyc/test/test_run.py
-@@ -392,7 +392,7 @@
+diff --git a/mypyc/test/test_run.py b/mypyc/test/test_run.py
+index 868f836..4317780 100644
+--- a/mypyc/test/test_run.py
++++ b/mypyc/test/test_run.py
+@@ -392,7 +392,7 @@ class TestRun(MypycDataSuite):
stderr=subprocess.STDOUT,
env=env,
)
=====================================
debian/patches/series
=====================================
@@ -1,3 +1,4 @@
+0001-mypyc-Fix-recursive-setup-for-frame-private-helpers.patch
remove-mypyc-test-run-timeout
hint-typeshed-package
verbose
=====================================
debian/patches/verbose
=====================================
@@ -7,9 +7,11 @@ Forwarded: not-needed
setup.py | 1 +
1 file changed, 1 insertion(+)
---- mypy.orig/setup.py
-+++ mypy/setup.py
-@@ -165,6 +165,7 @@
+diff --git a/setup.py b/setup.py
+index 1879f68..2d3e05b 100644
+--- a/setup.py
++++ b/setup.py
+@@ -165,6 +165,7 @@ if USE_MYPYC:
separate=separate,
# Mypy itself is allowed to use native_internal extension.
depends_on_librt_internal=True,
View it on GitLab: https://salsa.debian.org/python-team/packages/mypy/-/commit/e3ef9995cf761e6ceac64cdfb843ddd2dd08df2b
--
View it on GitLab: https://salsa.debian.org/python-team/packages/mypy/-/commit/e3ef9995cf761e6ceac64cdfb843ddd2dd08df2b
You're receiving this email because of your account on salsa.debian.org. Manage all notifications: https://salsa.debian.org/-/profile/notifications | Help: https://salsa.debian.org/help
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/debian-med-commit/attachments/20261013/d9d0d27d/attachment-0001.htm>
More information about the debian-med-commit
mailing list