[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