diff -pruN 6.20250414/autoscripts/prerm-py3clean 6.20251029/autoscripts/prerm-py3clean
--- 6.20250414/autoscripts/prerm-py3clean	2025-04-14 20:39:29.000000000 +0000
+++ 6.20251029/autoscripts/prerm-py3clean	2025-10-29 13:53:03.000000000 +0000
@@ -1,4 +1,4 @@
-if command -v py3clean >/dev/null 2>&1; then
+if command -v py3clean >/dev/null 2>&1 && python3 -c 'pass' 2>/dev/null; then
 	py3clean -p #PACKAGE# #ARGS#
 else
 	dpkg -L #PACKAGE# | sed -En -e '/^(.*)\/(.+)\.py$/s,,rm "\1/__pycache__/\2".*,e'
diff -pruN 6.20250414/debian/changelog 6.20251029/debian/changelog
--- 6.20250414/debian/changelog	2025-04-14 20:39:29.000000000 +0000
+++ 6.20251029/debian/changelog	2025-10-29 13:53:03.000000000 +0000
@@ -1,3 +1,26 @@
+dh-python (6.20251029) unstable; urgency=medium
+
+  [ Colin Watson ]
+  * dh_python3: Suppress generated dependencies that would be satisfied by
+    python3 >= 3.11.
+
+  [ Matthias Klose ]
+  * autoscripts/prerm-py3clean: Check for a working /usr/bin/python3,
+    the same interpreter used for py3clean.  Addresses: #1109501.
+
+  [ Stefano Rivera ]
+  * Update the list of Python versions we test things for.
+  * Rename stable ABI extensions to include a multiarch tuple, allowing
+    co-installation.
+
+  [ Simon Chopin ]
+  * pybuild: add an optional dest arg to testfiles syntax (Closes: #947800)
+
+  [ Niels Thykier ]
+  * dh_python3: Add introspection hints for known configuration files
+
+ -- Stefano Rivera <stefanor@debian.org>  Wed, 29 Oct 2025 15:53:03 +0200
+
 dh-python (6.20250414) unstable; urgency=medium
 
   [ Colin Watson ]
diff -pruN 6.20250414/dh_python3 6.20251029/dh_python3
--- 6.20250414/dh_python3	2025-04-14 20:39:29.000000000 +0000
+++ 6.20251029/dh_python3	2025-10-29 13:53:03.000000000 +0000
@@ -44,6 +44,10 @@ os.umask(0o22)
 DEFAULT = default('cpython3')
 SUPPORTED = supported('cpython3')
 
+# See /usr/share/doc/debhelper/PROGRAMMING.md.gz
+#
+# INTROSPECTABLE: CONFIG-FILES pkgfile(pyinstall) pkgfile(pyremove) pkgfile(pydist) pkgfile(bcep) pkgfile(py3dist-overrides)
+
 
 class Scanner(Scan):
     def handle_ext(self, fpath):
@@ -271,6 +275,7 @@ def main():
         dependencies.export_to(dh)
 
         pydist_file = join('debian', "%s.pydist" % package)
+
         if exists(pydist_file):
             if not validate_pydist(pydist_file):
                 log.warning("%s.pydist file is invalid", package)
diff -pruN 6.20250414/dh_python3.rst 6.20251029/dh_python3.rst
--- 6.20250414/dh_python3.rst	2025-04-14 20:39:29.000000000 +0000
+++ 6.20251029/dh_python3.rst	2025-10-29 13:53:03.000000000 +0000
@@ -30,8 +30,6 @@ QUICK GUIDE FOR MAINTAINERS
  * install files to the *standard* locations, add `--install-layout=deb` to
    setup.py's install command if your package is using distutils,
  * add `python3` to dh's --with option, or:
- * `include /usr/share/cdbs/1/class/python-distutils.mk` in debian/rules and
-   depend on `cdbs (>= 0.4.90)`, or:
  * call ``dh_python3`` in the `binary-*` target,
  * add `${python3:Depends}` to Depends
 
diff -pruN 6.20250414/dhpython/build/base.py 6.20251029/dhpython/build/base.py
--- 6.20250414/dhpython/build/base.py	2025-04-14 20:39:29.000000000 +0000
+++ 6.20251029/dhpython/build/base.py	2025-10-29 13:53:03.000000000 +0000
@@ -21,7 +21,7 @@
 import logging
 from functools import wraps
 from glob import glob1
-from os import remove, walk
+from os import remove, walk, makedirs
 from os.path import exists, isdir, join
 from pathlib import Path
 from shlex import quote
@@ -56,12 +56,18 @@ def copy_test_files(dest='{build_dir}',
                         break
 
             files_to_remove = set()
-            for name in files_to_copy:
+            for entry in files_to_copy:
+                name, *rest = entry.split(maxsplit=1)
+                dest_suffix = rest[0] if rest else ""
+                if not dest_suffix or dest_suffix.endswith('/'):
+                    dest_suffix = join(dest_suffix, name.rsplit('/', 1)[-1])
+
                 src_dpath = join(args['dir'], name)
-                dst_dpath = join(dest.format(**args), name.rsplit('/', 1)[-1])
+                dst_dpath = join(dest.format(**args), dest_suffix)
                 if exists(src_dpath):
                     if not exists(dst_dpath):
                         log.debug("Copying %s to %s for tests", src_dpath, dst_dpath)
+                        makedirs(dst_dpath.rsplit('/', 1)[0], exist_ok=True)
                         if isdir(src_dpath):
                             copytree(src_dpath, dst_dpath)
                         else:
diff -pruN 6.20250414/dhpython/fs.py 6.20251029/dhpython/fs.py
--- 6.20250414/dhpython/fs.py	2025-04-14 20:39:29.000000000 +0000
+++ 6.20251029/dhpython/fs.py	2025-10-29 13:53:03.000000000 +0000
@@ -68,7 +68,6 @@ def fix_locations(package, interpreter,
 
 def share_files(srcdir, dstdir, interpreter, options):
     """Try to move as many files from srcdir to dstdir as possible."""
-    cleanup_actions = []
     for i in os.listdir(srcdir):
         fpath1 = join(srcdir, i)
         if not lexists(fpath1):  # removed in rename_ext
@@ -131,8 +130,6 @@ def share_files(srcdir, dstdir, interpre
                 diff = difflib.unified_diff(fromlines, tolines, fpath1, fpath2)
                 sys.stderr.writelines(diff)
 
-    for action, args in cleanup_actions:
-        action(dstdir, *args)
     try:
         os.removedirs(srcdir)
     except OSError:
@@ -175,7 +172,7 @@ def merge_WHEEL(src, dst):
 
 
 def write_INSTALLER(distdir):
-    """Write 'debain' as the INSTALLER"""
+    """Write 'debian' as the INSTALLER"""
     log.debug("Writing INSTALLER in %s", distdir)
     installer = join(distdir, "INSTALLER")
     with open(installer, "w", encoding="UTF-8") as f:
diff -pruN 6.20250414/dhpython/interpreter.py 6.20251029/dhpython/interpreter.py
--- 6.20250414/dhpython/interpreter.py	2025-04-14 20:39:29.000000000 +0000
+++ 6.20251029/dhpython/interpreter.py	2025-10-29 13:53:03.000000000 +0000
@@ -39,19 +39,20 @@ SHEBANG_RE = re.compile(r'''
 EXTFILE_RE = re.compile(r'''
     (?P<name>.*?)
     (?:\.
-        (?P<stableabi>abi\d+)
-     |(?:\.
-        (?P<soabi>
-            (?P<impl>cpython|pypy)
-            -
-            (?P<ver>\d{2,})
-            (?P<flags>[a-z]*)
-        )?
         (?:
-            (?:(?<!\.)-)?  # minus sign only if soabi is defined
+            (?P<stableabi>abi\d+)
+            |(?P<soabi>
+                (?P<impl>cpython|pypy)
+                -
+                (?P<ver>\d{2,})
+                (?P<flags>[a-z]*)
+            )
+        )
+        (?:
+            -
             (?P<multiarch>[^/]*?)
         )?
-    ))?
+    )?
     (?P<debug>_d)?
     \.so$''', re.VERBOSE)
 log = logging.getLogger('dhpython')
@@ -426,14 +427,15 @@ class Interpreter:
             # version number is set
             version = Version("%s.%s" % (info['ver'][0], info['ver'][1]))
 
-        if info['stableabi']:
-            # files with stable ABI in name don't need changes
+        if info['stableabi'] and version < Version('3.13'):
+            # We added support for stableabi multiarch filenames in 3.13
+            # (GH-122931)
             return
         if info['debug'] and self.debug is False:
             # do not change Python 2.X extensions already marked as debug
             # (the other way around is acceptable)
             return
-        if info['soabi'] and info['multiarch']:
+        if (info['soabi'] or info['stableabi']) and info['multiarch']:
             # already tagged, nothing we can do here
             return
 
@@ -446,7 +448,7 @@ class Interpreter:
         if info['soabi'] and soabi and info['soabi'] != soabi:
             return
 
-        tmp_soabi = info['soabi'] or soabi
+        tmp_soabi = info['stableabi'] or info['soabi'] or soabi
         tmp_multiarch = info['multiarch'] or multiarch
 
         result = info['name']
@@ -456,9 +458,9 @@ class Interpreter:
             result = result[:-6]
 
         if tmp_soabi:
-            result = "{}.{}".format(result, tmp_soabi)
-            if tmp_multiarch and tmp_multiarch not in soabi:
-                result = "{}-{}".format(result, tmp_multiarch)
+            result = f"{result}.{tmp_soabi}"
+        if tmp_multiarch and tmp_multiarch not in result:
+            result = f"{result}-{tmp_multiarch}"
 
         result += '.so'
         if fname == result:
diff -pruN 6.20250414/dhpython/pydist.py 6.20251029/dhpython/pydist.py
--- 6.20250414/dhpython/pydist.py	2025-04-14 20:39:29.000000000 +0000
+++ 6.20251029/dhpython/pydist.py	2025-10-29 13:53:03.000000000 +0000
@@ -108,7 +108,7 @@ DEB_VERS_OPS = {
     '~=': '>=',
 }
 # Optimize away any dependencies on Python less than:
-MIN_PY_VERSION = [3, 9]
+MIN_PY_VERSION = [3, 11]
 
 
 def validate(fpath):
diff -pruN 6.20250414/pybuild 6.20251029/pybuild
--- 6.20250414/pybuild	2025-04-14 20:39:29.000000000 +0000
+++ 6.20251029/pybuild	2025-10-29 13:53:03.000000000 +0000
@@ -602,5 +602,5 @@ if __name__ == '__main__':
     log.debug('version: DEVELV')
     log.debug(sys.argv)
     main(cfg)
-    # let dh/cdbs clean the .pybuild dir
+    # let dh clean the .pybuild dir
     # rmtree(join(cfg.dir, '.pybuild'))
diff -pruN 6.20250414/pybuild.rst 6.20251029/pybuild.rst
--- 6.20250414/pybuild.rst	2025-04-14 20:39:29.000000000 +0000
+++ 6.20251029/pybuild.rst	2025-10-29 13:53:03.000000000 +0000
@@ -123,6 +123,11 @@ testfiles
     If `testfiles` are provided, it overrides these defaults, if
     still required they need to be explicitly specified.
 
+    By default, the test files are copied at the root of the build directory.
+    You can optionally specify a destination as second argument in the
+    `testfiles`. If the destination ends with a `/` it is treated as a target
+    directory into which the file will be copied.
+
 BUILD SYSTEM ARGUMENTS
 ----------------------
   Additional arguments passed to the build system.
diff -pruN 6.20250414/tests/common.mk 6.20251029/tests/common.mk
--- 6.20250414/tests/common.mk	2025-04-14 20:39:29.000000000 +0000
+++ 6.20251029/tests/common.mk	2025-10-29 13:53:03.000000000 +0000
@@ -2,7 +2,7 @@
 
 export DEBPYTHON3_DEFAULT ?= $(shell python3 ../../dhpython/_defaults.py default cpython3)
 export DEBPYTHON3_SUPPORTED ?= $(shell python3 ../../dhpython/_defaults.py supported cpython3)
-export DEB_HOST_MULTIARCH=my_multiarch-triplet
+export DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH)
 export DEB_HOST_ARCH ?= $(shell dpkg-architecture -qDEB_HOST_ARCH)
 export DH_INTERNAL_OPTIONS=
 
diff -pruN 6.20250414/tests/test_interpreter.py 6.20251029/tests/test_interpreter.py
--- 6.20250414/tests/test_interpreter.py	2025-04-14 20:39:29.000000000 +0000
+++ 6.20251029/tests/test_interpreter.py	2025-10-29 13:53:03.000000000 +0000
@@ -16,189 +16,6 @@ class TestInterpreter(unittest.TestCase)
         else:
             del environ['DEB_HOST_MULTIARCH']
 
-    @unittest.skipUnless(exists('/usr/bin/python3.1'), 'python3.1 is not installed')
-    def test_python31(self):
-        i = Interpreter('python3.1')
-        self.assertEqual(i.soabi(), '')
-        self.assertIsNone(i.check_extname('foo.so'))
-        self.assertIsNone(i.check_extname('foo.abi3.so'))
-        self.assertIsNone(i.check_extname('foo/bar/bazmodule.so'))
-
-    @unittest.skipUnless(exists('/usr/bin/python3.1-dbg'), 'python3.1-dbg is not installed')
-    def test_python31dbg(self):
-        i = Interpreter('python3.1-dbg')
-        self.assertEqual(i.soabi(), '')
-        self.assertIsNone(i.check_extname('foo.so'))
-        self.assertIsNone(i.check_extname('foo.abi3.so'))
-        self.assertIsNone(i.check_extname('foo/bar/bazmodule.so'))
-
-    @unittest.skipUnless(exists('/usr/bin/python3.2'), 'python3.2 is not installed')
-    def test_python32(self):
-        i = Interpreter('python3.2')
-        self.assertEqual(i.soabi(), 'cpython-32mu')
-        self.assertEqual(i.check_extname('foo.so'), r'foo.cpython-32mu.so')
-        self.assertIsNone(i.check_extname('foo.cpython-33m.so'))  # different version
-        self.assertIsNone(i.check_extname('foo.cpython-32mu-OTHER.so'))  # different architecture
-        self.assertIsNone(i.check_extname('foo.abi3.so'))
-        self.assertEqual(i.check_extname('foo/bar/bazmodule.so'), r'foo/bar/bazmodule.cpython-32mu.so')
-
-    @unittest.skipUnless(exists('/usr/bin/python3.2-dbg'), 'python3.2-dbg is not installed')
-    def test_python32dbg(self):
-        i = Interpreter('python3.2-dbg')
-        self.assertEqual(i.soabi(), 'cpython-32dmu')
-        self.assertEqual(i.check_extname('foo.so'), r'foo.cpython-32dmu.so')
-        self.assertIsNone(i.check_extname('foo.cpython-33m.so'))  # different version
-        self.assertIsNone(i.check_extname('foo.cpython-32dmu-OTHER.so'))  # different architecture
-        self.assertIsNone(i.check_extname('foo.abi3.so'))
-        self.assertEqual(i.check_extname('foo/bar/bazmodule.so'), r'foo/bar/bazmodule.cpython-32dmu.so')
-
-    @unittest.skipUnless(exists('/usr/bin/python3.4'), 'python3.4 is not installed')
-    def test_python34(self):
-        i = Interpreter('python3.4')
-        self.assertEqual(i.soabi(), 'cpython-34m')
-        self.assertEqual(i.check_extname('foo.so'), r'foo.cpython-34m-MYARCH.so')
-        self.assertIsNone(i.check_extname('foo.cpython-32m.so'))  # different version
-        self.assertIsNone(i.check_extname('foo.cpython-34m-OTHER.so'))  # different architecture
-        self.assertEqual(i.check_extname('foo.cpython-34m.so'), r'foo.cpython-34m-MYARCH.so')
-        self.assertIsNone(i.check_extname('foo.abi3.so'))
-        self.assertEqual(i.check_extname('foo/bar/bazmodule.so'), r'foo/bar/baz.cpython-34m-MYARCH.so')
-
-    @unittest.skipUnless(exists('/usr/bin/python3.4-dbg'), 'python3.4-dbg is not installed')
-    def test_python34dbg(self):
-        i = Interpreter('python3.4-dbg')
-        self.assertEqual(i.soabi(), 'cpython-34dm')
-        self.assertEqual(i.check_extname('foo.so'), r'foo.cpython-34dm-MYARCH.so')
-        self.assertIsNone(i.check_extname('foo.cpython-32m.so'))  # different version
-        self.assertIsNone(i.check_extname('foo.cpython-34m-OTHER.so'))  # different architecture
-        self.assertIsNone(i.check_extname('foo.abi3.so'))
-        self.assertEqual(i.check_extname('foo/bar/bazmodule.so'), r'foo/bar/baz.cpython-34dm-MYARCH.so')
-
-    @unittest.skipUnless(exists('/usr/bin/python3.5'), 'python3.5 is not installed')
-    def test_python35(self):
-        i = Interpreter('python3.5')
-        self.assertEqual(i.soabi(), 'cpython-35m')
-        self.assertEqual(i.check_extname('foo.so'), r'foo.cpython-35m-MYARCH.so')
-        self.assertIsNone(i.check_extname('foo.cpython-32m.so'))  # different version
-        self.assertIsNone(i.check_extname('foo.cpython-35m-OTHER.so'))  # different architecture
-        self.assertEqual(i.check_extname('foo.cpython-35m.so'), r'foo.cpython-35m-MYARCH.so')
-        self.assertIsNone(i.check_extname('foo.abi3.so'))
-        self.assertEqual(i.check_extname('foo/bar/bazmodule.so'), r'foo/bar/baz.cpython-35m-MYARCH.so')
-
-    @unittest.skipUnless(exists('/usr/bin/python3.5-dbg'), 'python3.5-dbg is not installed')
-    def test_python35dbg(self):
-        i = Interpreter('python3.5-dbg')
-        self.assertEqual(i.soabi(), 'cpython-35dm')
-        self.assertEqual(i.check_extname('foo.so'), r'foo.cpython-35dm-MYARCH.so')
-        self.assertIsNone(i.check_extname('foo.cpython-32m.so'))  # different version
-        self.assertIsNone(i.check_extname('foo.cpython-35m-OTHER.so'))  # different architecture
-        self.assertIsNone(i.check_extname('foo.abi3.so'))
-        self.assertEqual(i.check_extname('foo/bar/bazmodule.so'), r'foo/bar/baz.cpython-35dm-MYARCH.so')
-
-    @unittest.skipUnless(exists('/usr/bin/python3.6'), 'python3.6 is not installed')
-    def test_python36(self):
-        i = Interpreter('python3.6')
-        self.assertEqual(i.soabi(), 'cpython-36m')
-        self.assertEqual(i.check_extname('foo.so'), r'foo.cpython-36m-MYARCH.so')
-        self.assertIsNone(i.check_extname('foo.cpython-32m.so'))  # different version
-        self.assertIsNone(i.check_extname('foo.cpython-36m-OTHER.so'))  # different architecture
-        self.assertEqual(i.check_extname('foo.cpython-36m.so'), r'foo.cpython-36m-MYARCH.so')
-        self.assertIsNone(i.check_extname('foo.abi3.so'))
-        self.assertEqual(i.check_extname('foo/bar/bazmodule.so'), r'foo/bar/baz.cpython-36m-MYARCH.so')
-
-    @unittest.skipUnless(exists('/usr/bin/python3.6-dbg'), 'python3.6-dbg is not installed')
-    def test_python36dbg(self):
-        i = Interpreter('python3.6-dbg')
-        self.assertEqual(i.soabi(), 'cpython-36dm')
-        self.assertEqual(i.check_extname('foo.so'), r'foo.cpython-36dm-MYARCH.so')
-        self.assertIsNone(i.check_extname('foo.cpython-32m.so'))  # different version
-        self.assertIsNone(i.check_extname('foo.cpython-36m-OTHER.so'))  # different architecture
-        self.assertIsNone(i.check_extname('foo.abi3.so'))
-        self.assertEqual(i.check_extname('foo/bar/bazmodule.so'), r'foo/bar/baz.cpython-36dm-MYARCH.so')
-
-    @unittest.skipUnless(exists('/usr/bin/python3.7'), 'python3.7 is not installed')
-    def test_python37(self):
-        i = Interpreter('python3.7')
-        self.assertEqual(i.soabi(), 'cpython-37m')
-        self.assertEqual(i.check_extname('foo.so'), r'foo.cpython-37m-MYARCH.so')
-        self.assertIsNone(i.check_extname('foo.cpython-32m.so'))  # different version
-        self.assertIsNone(i.check_extname('foo.cpython-37m-OTHER.so'))  # different architecture
-        self.assertEqual(i.check_extname('foo.cpython-37m.so'), r'foo.cpython-37m-MYARCH.so')
-        self.assertIsNone(i.check_extname('foo.abi3.so'))
-        self.assertEqual(i.check_extname('foo/bar/bazmodule.so'), r'foo/bar/baz.cpython-37m-MYARCH.so')
-
-    @unittest.skipUnless(exists('/usr/bin/python3.7-dbg'), 'python3.7-dbg is not installed')
-    def test_python37dbg(self):
-        i = Interpreter('python3.7-dbg')
-        self.assertEqual(i.soabi(), 'cpython-37dm')
-        self.assertEqual(i.check_extname('foo.so'), r'foo.cpython-37dm-MYARCH.so')
-        self.assertIsNone(i.check_extname('foo.cpython-32m.so'))  # different version
-        self.assertIsNone(i.check_extname('foo.cpython-37m-OTHER.so'))  # different architecture
-        self.assertIsNone(i.check_extname('foo.abi3.so'))
-        self.assertEqual(i.check_extname('foo/bar/bazmodule.so'), r'foo/bar/baz.cpython-37dm-MYARCH.so')
-
-    @unittest.skipUnless(exists('/usr/bin/python3.8'), 'python3.8 is not installed')
-    def test_python38(self):
-        i = Interpreter('python3.8')
-        self.assertEqual(i.soabi(), 'cpython-38')
-        self.assertEqual(i.check_extname('foo.so'), r'foo.cpython-38-MYARCH.so')
-        self.assertIsNone(i.check_extname('foo.cpython-32m.so'))  # different version
-        self.assertIsNone(i.check_extname('foo.cpython-38-OTHER.so'))  # different architecture
-        self.assertEqual(i.check_extname('foo.cpython-38.so'), r'foo.cpython-38-MYARCH.so')
-        self.assertIsNone(i.check_extname('foo.abi3.so'))
-        self.assertEqual(i.check_extname('foo/bar/bazmodule.so'), r'foo/bar/baz.cpython-38-MYARCH.so')
-
-    @unittest.skipUnless(exists('/usr/bin/python3.8-dbg'), 'python3.8-dbg is not installed')
-    def test_python38dbg(self):
-        i = Interpreter('python3.8-dbg')
-        self.assertEqual(i.soabi(), 'cpython-38d')
-        self.assertEqual(i.check_extname('foo.so'), r'foo.cpython-38d-MYARCH.so')
-        self.assertIsNone(i.check_extname('foo.cpython-32m.so'))  # different version
-        self.assertIsNone(i.check_extname('foo.cpython-38-OTHER.so'))  # different architecture
-        self.assertIsNone(i.check_extname('foo.abi3.so'))
-        self.assertEqual(i.check_extname('foo/bar/bazmodule.so'), r'foo/bar/baz.cpython-38d-MYARCH.so')
-
-    @unittest.skipUnless(exists('/usr/bin/python3.9'), 'python3.9 is not installed')
-    def test_python39(self):
-        i = Interpreter('python3.9')
-        self.assertEqual(i.soabi(), 'cpython-39')
-        self.assertEqual(i.check_extname('foo.so'), r'foo.cpython-39-MYARCH.so')
-        self.assertIsNone(i.check_extname('foo.cpython-32m.so'))  # different version
-        self.assertIsNone(i.check_extname('foo.cpython-39-OTHER.so'))  # different architecture
-        self.assertEqual(i.check_extname('foo.cpython-39.so'), r'foo.cpython-39-MYARCH.so')
-        self.assertIsNone(i.check_extname('foo.abi3.so'))
-        self.assertEqual(i.check_extname('foo/bar/bazmodule.so'), r'foo/bar/baz.cpython-39-MYARCH.so')
-
-    @unittest.skipUnless(exists('/usr/bin/python3.9-dbg'), 'python3.9-dbg is not installed')
-    def test_python39dbg(self):
-        i = Interpreter('python3.9-dbg')
-        self.assertEqual(i.soabi(), 'cpython-39d')
-        self.assertEqual(i.check_extname('foo.so'), r'foo.cpython-39d-MYARCH.so')
-        self.assertIsNone(i.check_extname('foo.cpython-32m.so'))  # different version
-        self.assertIsNone(i.check_extname('foo.cpython-39-OTHER.so'))  # different architecture
-        self.assertIsNone(i.check_extname('foo.abi3.so'))
-        self.assertEqual(i.check_extname('foo/bar/bazmodule.so'), r'foo/bar/baz.cpython-39d-MYARCH.so')
-
-    @unittest.skipUnless(exists('/usr/bin/python3.10'), 'python3.10 is not installed')
-    def test_python310(self):
-        i = Interpreter('python3.10')
-        self.assertEqual(i.soabi(), 'cpython-310')
-        self.assertEqual(i.check_extname('foo.so'), r'foo.cpython-310-MYARCH.so')
-        self.assertIsNone(i.check_extname('foo.cpython-32m.so'))  # different version
-        self.assertIsNone(i.check_extname('foo.cpython-310-OTHER.so'))  # different architecture
-        self.assertEqual(i.check_extname('foo.cpython-310.so'), r'foo.cpython-310-MYARCH.so')
-        self.assertIsNone(i.check_extname('foo.abi3.so'))
-        self.assertEqual(i.check_extname('foo/bar/bazmodule.so'), r'foo/bar/baz.cpython-310-MYARCH.so')
-
-    @unittest.skipUnless(exists('/usr/bin/python3.10-dbg'), 'python3.10-dbg is not installed')
-    def test_python310dbg(self):
-        i = Interpreter('python3.10-dbg')
-        self.assertEqual(i.soabi(), 'cpython-310d')
-        self.assertEqual(i.check_extname('foo.so'), r'foo.cpython-310d-MYARCH.so')
-        self.assertIsNone(i.check_extname('foo.cpython-32m.so'))  # different version
-        self.assertIsNone(i.check_extname('foo.cpython-310-OTHER.so'))  # different architecture
-        self.assertIsNone(i.check_extname('foo.abi3.so'))
-        self.assertEqual(i.check_extname('foo/bar/bazmodule.so'), r'foo/bar/baz.cpython-310d-MYARCH.so')
-
     @unittest.skipUnless(exists('/usr/bin/python3.11'), 'python3.11 is not installed')
     def test_python311(self):
         i = Interpreter('python3.11')
@@ -241,6 +58,52 @@ class TestInterpreter(unittest.TestCase)
         self.assertIsNone(i.check_extname('foo.abi3.so'))
         self.assertEqual(i.check_extname('foo/bar/bazmodule.so'), r'foo/bar/baz.cpython-312d-MYARCH.so')
 
+    @unittest.skipUnless(exists('/usr/bin/python3.13'), 'python3.13 is not installed')
+    def test_python313(self):
+        i = Interpreter('python3.13')
+        self.assertEqual(i.soabi(), 'cpython-313')
+        self.assertEqual(i.check_extname('foo.so'), r'foo.cpython-313-MYARCH.so')
+        self.assertIsNone(i.check_extname('foo.cpython-33m.so'))  # different version
+        self.assertIsNone(i.check_extname('foo.cpython-313-OTHER.so'))  # different architecture
+        self.assertEqual(i.check_extname('foo.cpython-313.so'), r'foo.cpython-313-MYARCH.so')
+        self.assertEqual(i.check_extname('foo.abi3.so'), "foo.abi3-MYARCH.so")
+        self.assertIsNone(i.check_extname('foo.abi3-OTHER.so'))
+        self.assertEqual(i.check_extname('foo/bar/bazmodule.so'), r'foo/bar/baz.cpython-313-MYARCH.so')
+
+    @unittest.skipUnless(exists('/usr/bin/python3.13-dbg'), 'python3.13-dbg is not installed')
+    def test_python313dbg(self):
+        i = Interpreter('python3.13-dbg')
+        self.assertEqual(i.soabi(), 'cpython-313d')
+        self.assertEqual(i.check_extname('foo.so'), r'foo.cpython-313d-MYARCH.so')
+        self.assertIsNone(i.check_extname('foo.cpython-33m.so'))  # different version
+        self.assertIsNone(i.check_extname('foo.cpython-313-OTHER.so'))  # different architecture
+        self.assertEqual(i.check_extname('foo.abi3.so'), "foo.abi3-MYARCH.so")
+        self.assertIsNone(i.check_extname('foo.abi3-OTHER.so'))
+        self.assertEqual(i.check_extname('foo/bar/bazmodule.so'), r'foo/bar/baz.cpython-313d-MYARCH.so')
+
+    @unittest.skipUnless(exists('/usr/bin/python3.14'), 'python3.14 is not installed')
+    def test_python314(self):
+        i = Interpreter('python3.14')
+        self.assertEqual(i.soabi(), 'cpython-314')
+        self.assertEqual(i.check_extname('foo.so'), r'foo.cpython-314-MYARCH.so')
+        self.assertIsNone(i.check_extname('foo.cpython-34m.so'))  # different version
+        self.assertIsNone(i.check_extname('foo.cpython-314-OTHER.so'))  # different architecture
+        self.assertEqual(i.check_extname('foo.cpython-314.so'), r'foo.cpython-314-MYARCH.so')
+        self.assertEqual(i.check_extname('foo.abi3.so'), "foo.abi3-MYARCH.so")
+        self.assertIsNone(i.check_extname('foo.abi3-OTHER.so'))
+        self.assertEqual(i.check_extname('foo/bar/bazmodule.so'), r'foo/bar/baz.cpython-314-MYARCH.so')
+
+    @unittest.skipUnless(exists('/usr/bin/python3.14-dbg'), 'python3.14-dbg is not installed')
+    def test_python314dbg(self):
+        i = Interpreter('python3.14-dbg')
+        self.assertEqual(i.soabi(), 'cpython-314d')
+        self.assertEqual(i.check_extname('foo.so'), r'foo.cpython-314d-MYARCH.so')
+        self.assertIsNone(i.check_extname('foo.cpython-34m.so'))  # different version
+        self.assertIsNone(i.check_extname('foo.cpython-314-OTHER.so'))  # different architecture
+        self.assertEqual(i.check_extname('foo.abi3.so'), "foo.abi3-MYARCH.so")
+        self.assertIsNone(i.check_extname('foo.abi3-OTHER.so'))
+        self.assertEqual(i.check_extname('foo/bar/bazmodule.so'), r'foo/bar/baz.cpython-314d-MYARCH.so')
+
     def test_python3(self):
         i = Interpreter('python{}.{}'.format(*sys.version_info[:2]))
         pyver = '{}{}'.format(*sys.version_info[:2])
@@ -249,7 +112,8 @@ class TestInterpreter(unittest.TestCase)
         self.assertIsNone(i.check_extname('foo.cpython-32m.so'))  # different version
         self.assertIsNone(i.check_extname(f'foo.cpython-{pyver}-OTHER.so'))  # different architecture
         self.assertEqual(i.check_extname(f'foo.cpython-{pyver}.so'), rf'foo.cpython-{pyver}-MYARCH.so')
-        self.assertIsNone(i.check_extname('foo.abi3.so'))
+        self.assertEqual(i.check_extname('foo.abi3.so'), "foo.abi3-MYARCH.so")
+        self.assertIsNone(i.check_extname('foo.abi3-OTHER.so'))
         self.assertEqual(i.check_extname('foo/bar/bazmodule.so'), rf'foo/bar/baz.cpython-{pyver}-MYARCH.so')
 
     @unittest.skipUnless(exists('/usr/bin/python3-dbg'), 'python3-dbg is not installed')
@@ -260,7 +124,8 @@ class TestInterpreter(unittest.TestCase)
         self.assertEqual(i.check_extname('foo.so'), rf'foo.cpython-{pyver}d-MYARCH.so')
         self.assertIsNone(i.check_extname('foo.cpython-32m.so'))  # different version
         self.assertIsNone(i.check_extname(f'foo.cpython-{pyver}-OTHER.so'))  # different architecture
-        self.assertIsNone(i.check_extname('foo.abi3.so'))
+        self.assertEqual(i.check_extname('foo.abi3.so'), "foo.abi3-MYARCH.so")
+        self.assertIsNone(i.check_extname('foo.abi3-OTHER.so'))
         self.assertEqual(i.check_extname('foo/bar/bazmodule.so'), rf'foo/bar/baz.cpython-{pyver}d-MYARCH.so')
 
     def test_bare_module(self):
diff -pruN 6.20250414/tests/tpb02/debian/pybuild.testfiles 6.20251029/tests/tpb02/debian/pybuild.testfiles
--- 6.20250414/tests/tpb02/debian/pybuild.testfiles	2025-04-14 20:39:29.000000000 +0000
+++ 6.20251029/tests/tpb02/debian/pybuild.testfiles	2025-10-29 13:53:03.000000000 +0000
@@ -1,3 +1,5 @@
 testfile1.txt
 nested/testfile2.txt
 testdir
+testfile4.txt destination/
+testfile5.txt renamed
diff -pruN 6.20250414/tests/tpb02/foo/test_foo.py 6.20251029/tests/tpb02/foo/test_foo.py
--- 6.20250414/tests/tpb02/foo/test_foo.py	2025-04-14 20:39:29.000000000 +0000
+++ 6.20251029/tests/tpb02/foo/test_foo.py	2025-10-29 13:53:03.000000000 +0000
@@ -9,3 +9,5 @@ class RequiredTest(TestCase):
         open('testfile1.txt').close()
         open('testfile2.txt').close()
         open('testdir/testfile3.txt').close()
+        open('destination/testfile4.txt').close()
+        open('renamed').close()
diff -pruN 6.20250414/tests/tpb04/Makefile 6.20251029/tests/tpb04/Makefile
--- 6.20250414/tests/tpb04/Makefile	2025-04-14 20:39:29.000000000 +0000
+++ 6.20251029/tests/tpb04/Makefile	2025-10-29 13:53:03.000000000 +0000
@@ -3,7 +3,7 @@ include ../common.mk
 
 check:
 	test -f debian/python3-foo/usr/lib/python3/dist-packages/foo.py
-	test -f debian/python3-foo-ext/usr/lib/python3/dist-packages/_foo.abi3.so
+	test -f debian/python3-foo-ext/usr/lib/python3/dist-packages/_foo.abi3-$(DEB_HOST_MULTIARCH).so
 	test -e test-executed
 
 clean:
