commit 58bbae4bf27590785edd9640300bd4aaada11276e38e89ba165792ea10474329 Author: Matej Cepl Date: Thu Oct 16 16:28:40 2025 +0000 - Update to 3.12.12: - Tools/Demos - gh-139330: SBOM generation tool didn’t cross-check the version and checksum values against the Modules/expat/refresh.sh script, leading to the values becoming out-of-date during routine updates. - Security - gh-139700: Check consistency of the zip64 end of central directory record. Support records with “zip64 extensible data” if there are no bytes prepended to the ZIP file. - gh-139400: xml.parsers.expat: Make sure that parent Expat parsers are only garbage-collected once they are no longer referenced by subparsers created by ExternalEntityParserCreate(). Patch by Sebastian Pipping. - gh-135661: Fix parsing start and end tags in html.parser.HTMLParser according to the HTML5 standard. * Whitespaces no longer accepted between does not end the script section. * Vertical tabulation (\v) and non-ASCII whitespaces no longer recognized as whitespaces. The only whitespaces are \t\n\r\f and space. * Null character (U+0000) no longer ends the tag name. * Attributes and slashes after the tag name in end tags are now ignored, instead of terminating after the first > in quoted attribute value. E.g. . * Multiple slashes and whitespaces between the last attribute and closing > are now ignored in both start and end tags. E.g. . * Multiple = between attribute name and value are no longer collapsed. E.g. produces attribute “foo” with OBS-URL: https://build.opensuse.org/package/show/devel:languages:python:Factory/python312?expand=0&rev=162 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..9b03811 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,23 @@ +## Default LFS +*.7z filter=lfs diff=lfs merge=lfs -text +*.bsp filter=lfs diff=lfs merge=lfs -text +*.bz2 filter=lfs diff=lfs merge=lfs -text +*.gem filter=lfs diff=lfs merge=lfs -text +*.gz filter=lfs diff=lfs merge=lfs -text +*.jar filter=lfs diff=lfs merge=lfs -text +*.lz filter=lfs diff=lfs merge=lfs -text +*.lzma filter=lfs diff=lfs merge=lfs -text +*.obscpio filter=lfs diff=lfs merge=lfs -text +*.oxt filter=lfs diff=lfs merge=lfs -text +*.pdf filter=lfs diff=lfs merge=lfs -text +*.png filter=lfs diff=lfs merge=lfs -text +*.rpm filter=lfs diff=lfs merge=lfs -text +*.tbz filter=lfs diff=lfs merge=lfs -text +*.tbz2 filter=lfs diff=lfs merge=lfs -text +*.tgz filter=lfs diff=lfs merge=lfs -text +*.ttf filter=lfs diff=lfs merge=lfs -text +*.txz filter=lfs diff=lfs merge=lfs -text +*.whl filter=lfs diff=lfs merge=lfs -text +*.xz filter=lfs diff=lfs merge=lfs -text +*.zip filter=lfs diff=lfs merge=lfs -text +*.zst filter=lfs diff=lfs merge=lfs -text diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..57affb6 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.osc diff --git a/CVE-2025-6069-quad-complex-HTMLParser.patch b/CVE-2025-6069-quad-complex-HTMLParser.patch new file mode 100644 index 0000000..70eb744 --- /dev/null +++ b/CVE-2025-6069-quad-complex-HTMLParser.patch @@ -0,0 +1,237 @@ +From 1d53c3e7343bddb064182e02c21b13be9b63390f Mon Sep 17 00:00:00 2001 +From: Serhiy Storchaka +Date: Fri, 13 Jun 2025 19:57:48 +0300 +Subject: [PATCH] [3.12] gh-135462: Fix quadratic complexity in processing + special input in HTMLParser (GH-135464) + +End-of-file errors are now handled according to the HTML5 specs -- +comments and declarations are automatically closed, tags are ignored. +(cherry picked from commit 6eb6c5dbfb528bd07d77b60fd71fd05d81d45c41) + +Co-authored-by: Serhiy Storchaka +--- + Lib/html/parser.py | 41 +++- + Lib/test/test_htmlparser.py | 94 ++++++++-- + Misc/NEWS.d/next/Security/2025-06-13-15-55-22.gh-issue-135462.KBeJpc.rst | 4 + 3 files changed, 116 insertions(+), 23 deletions(-) + create mode 100644 Misc/NEWS.d/next/Security/2025-06-13-15-55-22.gh-issue-135462.KBeJpc.rst + +Index: Python-3.12.11/Lib/html/parser.py +=================================================================== +--- Python-3.12.11.orig/Lib/html/parser.py 2025-07-02 17:09:00.904899297 +0200 ++++ Python-3.12.11/Lib/html/parser.py 2025-07-02 17:09:12.496469955 +0200 +@@ -25,6 +25,7 @@ + charref = re.compile('&#(?:[0-9]+|[xX][0-9a-fA-F]+)[^0-9a-fA-F]') + + starttagopen = re.compile('<[a-zA-Z]') ++endtagopen = re.compile('') + commentclose = re.compile(r'--\s*>') + # Note: +@@ -177,7 +178,7 @@ + k = self.parse_pi(i) + elif startswith("', i + 1) +- if k < 0: +- k = rawdata.find('<', i + 1) +- if k < 0: +- k = i + 1 ++ if starttagopen.match(rawdata, i): # < + letter ++ pass ++ elif startswith("'), +- ('comment', '/img'), +- ('endtag', 'html<')]) ++ ('data', '\n')]) + + def test_starttag_junk_chars(self): ++ self._run_check("<", [('data', '<')]) ++ self._run_check("<>", [('data', '<>')]) ++ self._run_check("< >", [('data', '< >')]) ++ self._run_check("< ", [('data', '< ')]) + self._run_check("", []) ++ self._run_check("<$>", [('data', '<$>')]) + self._run_check("", [('comment', '$')]) + self._run_check("", [('endtag', 'a')]) ++ self._run_check("", [('starttag', 'a", [('endtag', 'a'", [('data', "'", []) ++ self._run_check("", [('starttag', 'a$b', [])]) + self._run_check("", [('startendtag', 'a$b', [])]) + self._run_check("", [('starttag', 'a$b', [])]) + self._run_check("", [('startendtag', 'a$b', [])]) ++ self._run_check("", [('endtag', 'a$b')]) + + def test_slashes_in_starttag(self): + self._run_check('', [('startendtag', 'a', [('foo', 'var')])]) +@@ -539,13 +546,56 @@ + for html, expected in data: + self._run_check(html, expected) + +- def test_broken_comments(self): +- html = ('' ++ def test_eof_in_comments(self): ++ data = [ ++ ('', [('comment', '-!>')]), ++ ('' + '' + '' + '') + expected = [ ++ ('comment', 'ELEMENT br EMPTY'), + ('comment', ' not really a comment '), + ('comment', ' not a comment either --'), + ('comment', ' -- close enough --'), +@@ -600,6 +650,26 @@ + ('endtag', 'a'), ('data', ' bar & baz')] + ) + ++ @support.requires_resource('cpu') ++ def test_eof_no_quadratic_complexity(self): ++ # Each of these examples used to take about an hour. ++ # Now they take a fraction of a second. ++ def check(source): ++ parser = html.parser.HTMLParser() ++ parser.feed(source) ++ parser.close() ++ n = 120_000 ++ check(" +Date: Mon, 28 Jul 2025 17:37:26 +0200 +Subject: [PATCH] gh-130577: tarfile now validates archives to ensure member + offsets are non-negative (GH-137027) (cherry picked from commit + 7040aa54f14676938970e10c5f74ea93cd56aa38) + +Co-authored-by: Alexander Urieles +Co-authored-by: Gregory P. Smith +--- + Lib/tarfile.py | 3 + Lib/test/test_tarfile.py | 156 ++++++++++ + Misc/NEWS.d/next/Library/2025-07-23-00-35-29.gh-issue-130577.c7EITy.rst | 3 + 3 files changed, 162 insertions(+) + create mode 100644 Misc/NEWS.d/next/Library/2025-07-23-00-35-29.gh-issue-130577.c7EITy.rst + +Index: Python-3.12.11/Lib/tarfile.py +=================================================================== +--- Python-3.12.11.orig/Lib/tarfile.py 2025-08-01 22:20:38.061933888 +0200 ++++ Python-3.12.11/Lib/tarfile.py 2025-08-01 22:20:42.185990406 +0200 +@@ -1614,6 +1614,9 @@ + """Round up a byte count by BLOCKSIZE and return it, + e.g. _block(834) => 1024. + """ ++ # Only non-negative offsets are allowed ++ if count < 0: ++ raise InvalidHeaderError("invalid offset") + blocks, remainder = divmod(count, BLOCKSIZE) + if remainder: + blocks += 1 +Index: Python-3.12.11/Lib/test/test_tarfile.py +=================================================================== +--- Python-3.12.11.orig/Lib/test/test_tarfile.py 2025-08-01 22:20:39.792514772 +0200 ++++ Python-3.12.11/Lib/test/test_tarfile.py 2025-08-01 22:20:42.187347433 +0200 +@@ -50,6 +50,7 @@ + xzname = os.path.join(TEMPDIR, "testtar.tar.xz") + tmpname = os.path.join(TEMPDIR, "tmp.tar") + dotlessname = os.path.join(TEMPDIR, "testtar") ++SPACE = b" " + + sha256_regtype = ( + "e09e4bc8b3c9d9177e77256353b36c159f5f040531bbd4b024a8f9b9196c71ce" +@@ -4488,6 +4489,161 @@ + ar.extractall(self.testdir, filter='fully_trusted') + + ++class OffsetValidationTests(unittest.TestCase): ++ tarname = tmpname ++ invalid_posix_header = ( ++ # name: 100 bytes ++ tarfile.NUL * tarfile.LENGTH_NAME ++ # mode, space, null terminator: 8 bytes ++ + b"000755" + SPACE + tarfile.NUL ++ # uid, space, null terminator: 8 bytes ++ + b"000001" + SPACE + tarfile.NUL ++ # gid, space, null terminator: 8 bytes ++ + b"000001" + SPACE + tarfile.NUL ++ # size, space: 12 bytes ++ + b"\xff" * 11 + SPACE ++ # mtime, space: 12 bytes ++ + tarfile.NUL * 11 + SPACE ++ # chksum: 8 bytes ++ + b"0011407" + tarfile.NUL ++ # type: 1 byte ++ + tarfile.REGTYPE ++ # linkname: 100 bytes ++ + tarfile.NUL * tarfile.LENGTH_LINK ++ # magic: 6 bytes, version: 2 bytes ++ + tarfile.POSIX_MAGIC ++ # uname: 32 bytes ++ + tarfile.NUL * 32 ++ # gname: 32 bytes ++ + tarfile.NUL * 32 ++ # devmajor, space, null terminator: 8 bytes ++ + tarfile.NUL * 6 + SPACE + tarfile.NUL ++ # devminor, space, null terminator: 8 bytes ++ + tarfile.NUL * 6 + SPACE + tarfile.NUL ++ # prefix: 155 bytes ++ + tarfile.NUL * tarfile.LENGTH_PREFIX ++ # padding: 12 bytes ++ + tarfile.NUL * 12 ++ ) ++ invalid_gnu_header = ( ++ # name: 100 bytes ++ tarfile.NUL * tarfile.LENGTH_NAME ++ # mode, null terminator: 8 bytes ++ + b"0000755" + tarfile.NUL ++ # uid, null terminator: 8 bytes ++ + b"0000001" + tarfile.NUL ++ # gid, space, null terminator: 8 bytes ++ + b"0000001" + tarfile.NUL ++ # size, space: 12 bytes ++ + b"\xff" * 11 + SPACE ++ # mtime, space: 12 bytes ++ + tarfile.NUL * 11 + SPACE ++ # chksum: 8 bytes ++ + b"0011327" + tarfile.NUL ++ # type: 1 byte ++ + tarfile.REGTYPE ++ # linkname: 100 bytes ++ + tarfile.NUL * tarfile.LENGTH_LINK ++ # magic: 8 bytes ++ + tarfile.GNU_MAGIC ++ # uname: 32 bytes ++ + tarfile.NUL * 32 ++ # gname: 32 bytes ++ + tarfile.NUL * 32 ++ # devmajor, null terminator: 8 bytes ++ + tarfile.NUL * 8 ++ # devminor, null terminator: 8 bytes ++ + tarfile.NUL * 8 ++ # padding: 167 bytes ++ + tarfile.NUL * 167 ++ ) ++ invalid_v7_header = ( ++ # name: 100 bytes ++ tarfile.NUL * tarfile.LENGTH_NAME ++ # mode, space, null terminator: 8 bytes ++ + b"000755" + SPACE + tarfile.NUL ++ # uid, space, null terminator: 8 bytes ++ + b"000001" + SPACE + tarfile.NUL ++ # gid, space, null terminator: 8 bytes ++ + b"000001" + SPACE + tarfile.NUL ++ # size, space: 12 bytes ++ + b"\xff" * 11 + SPACE ++ # mtime, space: 12 bytes ++ + tarfile.NUL * 11 + SPACE ++ # chksum: 8 bytes ++ + b"0010070" + tarfile.NUL ++ # type: 1 byte ++ + tarfile.REGTYPE ++ # linkname: 100 bytes ++ + tarfile.NUL * tarfile.LENGTH_LINK ++ # padding: 255 bytes ++ + tarfile.NUL * 255 ++ ) ++ valid_gnu_header = tarfile.TarInfo("filename").tobuf(tarfile.GNU_FORMAT) ++ data_block = b"\xff" * tarfile.BLOCKSIZE ++ ++ def _write_buffer(self, buffer): ++ with open(self.tarname, "wb") as f: ++ f.write(buffer) ++ ++ def _get_members(self, ignore_zeros=None): ++ with open(self.tarname, "rb") as f: ++ with tarfile.open( ++ mode="r", fileobj=f, ignore_zeros=ignore_zeros ++ ) as tar: ++ return tar.getmembers() ++ ++ def _assert_raises_read_error_exception(self): ++ with self.assertRaisesRegex( ++ tarfile.ReadError, "file could not be opened successfully" ++ ): ++ self._get_members() ++ ++ def test_invalid_offset_header_validations(self): ++ for tar_format, invalid_header in ( ++ ("posix", self.invalid_posix_header), ++ ("gnu", self.invalid_gnu_header), ++ ("v7", self.invalid_v7_header), ++ ): ++ with self.subTest(format=tar_format): ++ self._write_buffer(invalid_header) ++ self._assert_raises_read_error_exception() ++ ++ def test_early_stop_at_invalid_offset_header(self): ++ buffer = self.valid_gnu_header + self.invalid_gnu_header + self.valid_gnu_header ++ self._write_buffer(buffer) ++ members = self._get_members() ++ self.assertEqual(len(members), 1) ++ self.assertEqual(members[0].name, "filename") ++ self.assertEqual(members[0].offset, 0) ++ ++ def test_ignore_invalid_archive(self): ++ # 3 invalid headers with their respective data ++ buffer = (self.invalid_gnu_header + self.data_block) * 3 ++ self._write_buffer(buffer) ++ members = self._get_members(ignore_zeros=True) ++ self.assertEqual(len(members), 0) ++ ++ def test_ignore_invalid_offset_headers(self): ++ for first_block, second_block, expected_offset in ( ++ ( ++ (self.valid_gnu_header), ++ (self.invalid_gnu_header + self.data_block), ++ 0, ++ ), ++ ( ++ (self.invalid_gnu_header + self.data_block), ++ (self.valid_gnu_header), ++ 1024, ++ ), ++ ): ++ self._write_buffer(first_block + second_block) ++ members = self._get_members(ignore_zeros=True) ++ self.assertEqual(len(members), 1) ++ self.assertEqual(members[0].name, "filename") ++ self.assertEqual(members[0].offset, expected_offset) ++ ++ + def setUpModule(): + os_helper.unlink(TEMPDIR) + os.makedirs(TEMPDIR) +Index: Python-3.12.11/Misc/NEWS.d/next/Library/2025-07-23-00-35-29.gh-issue-130577.c7EITy.rst +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ Python-3.12.11/Misc/NEWS.d/next/Library/2025-07-23-00-35-29.gh-issue-130577.c7EITy.rst 2025-08-01 22:20:42.187819145 +0200 +@@ -0,0 +1,3 @@ ++:mod:`tarfile` now validates archives to ensure member offsets are ++non-negative. (Contributed by Alexander Enrique Urieles Nieto in ++:gh:`130577`.) diff --git a/F00251-change-user-install-location.patch b/F00251-change-user-install-location.patch new file mode 100644 index 0000000..02973fe --- /dev/null +++ b/F00251-change-user-install-location.patch @@ -0,0 +1,160 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= +Date: Mon, 15 Feb 2021 12:19:27 +0100 +Subject: [PATCH] 00251: Change user install location +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Set values of base and platbase in sysconfig from /usr +to /usr/local when RPM build is not detected +to make pip and similar tools install into separate location. + +Fedora Change: https://fedoraproject.org/wiki/Changes/Making_sudo_pip_safe +Downstream only. + +We've tried to rework in Fedora 36/Python 3.10 to follow https://bugs.python.org/issue43976 +but we have identified serious problems with that approach, +see https://bugzilla.redhat.com/2026979 or https://bugzilla.redhat.com/2097183 + +pypa/distutils integration: https://github.com/pypa/distutils/pull/70 + +Co-authored-by: Petr Viktorin +Co-authored-by: Miro Hrončok +Co-authored-by: Michal Cyprian +Co-authored-by: Lumír Balhar +--- + Lib/sysconfig.py | 51 ++++++++++++++++++++++++++++++++++++++++++++- + Lib/test/test_sysconfig.py | 17 +++++++++++++-- + 2 files changed, 65 insertions(+), 3 deletions(-) + +Index: Python-3.12.10/Lib/sysconfig.py +=================================================================== +--- Python-3.12.10.orig/Lib/sysconfig.py 2025-04-11 21:04:43.494305425 +0200 ++++ Python-3.12.10/Lib/sysconfig.py 2025-04-11 21:04:51.517931810 +0200 +@@ -104,6 +104,11 @@ + else: + _INSTALL_SCHEMES['venv'] = _INSTALL_SCHEMES['posix_venv'] + ++# For a brief period of time in the Fedora 36 life cycle, ++# this installation scheme existed and was documented in the release notes. ++# For backwards compatibility, we keep it here (at least on 3.10 and 3.11). ++_INSTALL_SCHEMES['rpm_prefix'] = _INSTALL_SCHEMES['posix_prefix'] ++ + + # NOTE: site.py has copy of this function. + # Sync it when modify this function. +@@ -163,13 +168,28 @@ + }, + } + ++# This is used by distutils.command.install in the stdlib ++# as well as pypa/distutils (e.g. bundled in setuptools). ++# The self.prefix value is set to sys.prefix + /local/ ++# if neither RPM build nor virtual environment is ++# detected to make distutils install packages ++# into the separate location. ++# https://fedoraproject.org/wiki/Changes/Making_sudo_pip_safe ++if (not (hasattr(sys, 'real_prefix') or ++ sys.prefix != sys.base_prefix) and ++ 'RPM_BUILD_ROOT' not in os.environ): ++ _prefix_addition = '/local' ++ ++ + _SCHEME_KEYS = ('stdlib', 'platstdlib', 'purelib', 'platlib', 'include', + 'scripts', 'data') + + _PY_VERSION = sys.version.split()[0] + _PY_VERSION_SHORT = f'{sys.version_info[0]}.{sys.version_info[1]}' + _PY_VERSION_SHORT_NO_DOT = f'{sys.version_info[0]}{sys.version_info[1]}' ++_PREFIX = os.path.normpath(sys.prefix) + _BASE_PREFIX = os.path.normpath(sys.base_prefix) ++_EXEC_PREFIX = os.path.normpath(sys.exec_prefix) + _BASE_EXEC_PREFIX = os.path.normpath(sys.base_exec_prefix) + # Mutex guarding initialization of _CONFIG_VARS. + _CONFIG_VARS_LOCK = threading.RLock() +@@ -268,11 +288,40 @@ + target_dict[key] = value + + ++_CONFIG_VARS_LOCAL = None ++ ++ ++def _config_vars_local(): ++ # This function returns the config vars with prefixes amended to /usr/local ++ # https://fedoraproject.org/wiki/Changes/Making_sudo_pip_safe ++ global _CONFIG_VARS_LOCAL ++ if _CONFIG_VARS_LOCAL is None: ++ _CONFIG_VARS_LOCAL = dict(get_config_vars()) ++ _CONFIG_VARS_LOCAL['base'] = '/usr/local' ++ _CONFIG_VARS_LOCAL['platbase'] = '/usr/local' ++ return _CONFIG_VARS_LOCAL ++ ++ + def _expand_vars(scheme, vars): + res = {} + if vars is None: + vars = {} +- _extend_dict(vars, get_config_vars()) ++ ++ # when we are not in a virtual environment or an RPM build ++ # we change '/usr' to '/usr/local' ++ # to avoid surprises, we explicitly check for the /usr/ prefix ++ # Python virtual environments have different prefixes ++ # we only do this for posix_prefix, not to mangle the venv scheme ++ # posix_prefix is used by sudo pip install ++ # we only change the defaults here, so explicit --prefix will take precedence ++ # https://fedoraproject.org/wiki/Changes/Making_sudo_pip_safe ++ if (scheme == 'posix_prefix' and ++ _PREFIX == '/usr' and ++ 'RPM_BUILD_ROOT' not in os.environ): ++ _extend_dict(vars, _config_vars_local()) ++ else: ++ _extend_dict(vars, get_config_vars()) ++ + if os.name == 'nt': + # On Windows we want to substitute 'lib' for schemes rather + # than the native value (without modifying vars, in case it +Index: Python-3.12.10/Lib/test/test_sysconfig.py +=================================================================== +--- Python-3.12.10.orig/Lib/test/test_sysconfig.py 2025-04-11 21:04:45.175417431 +0200 ++++ Python-3.12.10/Lib/test/test_sysconfig.py 2025-04-11 21:04:51.518393464 +0200 +@@ -119,8 +119,19 @@ + for scheme in _INSTALL_SCHEMES: + for name in _INSTALL_SCHEMES[scheme]: + expected = _INSTALL_SCHEMES[scheme][name].format(**config_vars) ++ tested = get_path(name, scheme) ++ # https://fedoraproject.org/wiki/Changes/Making_sudo_pip_safe ++ if tested.startswith('/usr/local'): ++ # /usr/local should only be used in posix_prefix ++ self.assertEqual(scheme, 'posix_prefix') ++ # Fedora CI runs tests for venv and virtualenv that check for other prefixes ++ self.assertEqual(sys.prefix, '/usr') ++ # When building the RPM of Python, %check runs this with RPM_BUILD_ROOT set ++ # Fedora CI runs this with RPM_BUILD_ROOT unset ++ self.assertNotIn('RPM_BUILD_ROOT', os.environ) ++ tested = tested.replace('/usr/local', '/usr') + self.assertEqual( +- os.path.normpath(get_path(name, scheme)), ++ os.path.normpath(tested), + os.path.normpath(expected), + ) + +@@ -353,7 +364,7 @@ + self.assertTrue(os.path.isfile(config_h), config_h) + + def test_get_scheme_names(self): +- wanted = ['nt', 'posix_home', 'posix_prefix', 'posix_venv', 'nt_venv', 'venv'] ++ wanted = ['nt', 'posix_home', 'posix_prefix', 'posix_venv', 'nt_venv', 'venv', 'rpm_prefix'] + if HAS_USER_BASE: + wanted.extend(['nt_user', 'osx_framework_user', 'posix_user']) + self.assertEqual(get_scheme_names(), tuple(sorted(wanted))) +@@ -365,6 +376,8 @@ + cmd = "-c", "import sysconfig; print(sysconfig.get_platform())" + self.assertEqual(py.call_real(*cmd), py.call_link(*cmd)) + ++ @unittest.skipIf('RPM_BUILD_ROOT' not in os.environ, ++ "Test doesn't expect Fedora's paths") + def test_user_similar(self): + # Issue #8759: make sure the posix scheme for the users + # is similar to the global posix_prefix one diff --git a/PACKAGING-NOTES b/PACKAGING-NOTES new file mode 100644 index 0000000..e28c88c --- /dev/null +++ b/PACKAGING-NOTES @@ -0,0 +1,26 @@ +Notes for packagers of Python3 +============================== + +0. Faster build turnaround +-------------------------- + +By default, python builds with profile-guided optimization. This needs +an additional run of the test suite and it is generally slow. +PGO build takes around 50 minutes. + +For development, use "--without profileopt" option to disable PGO. This +shortens the build time to ~5 minutes including test suite. + +1. import_failed.map +---------------------- + +This is a mechanism installed as part of python3-base, that places shim modules +on python's path (through a generated zzzz-import-failed-hooks.pth file, so that +it is imported as much at the end as makes sense; and an _import_failed subdir +of /usr/lib/pythonX.Y). Then when the user tries to import a module that is part +of a subpackage, the ImportError will contain a helpful message telling them +which missing subpackage to install. + +This can sometimes cause problems on non-standard configurations, if the pth +gets included too early (for instance if you are using a script to include all +pths by hand in some strange order). Just something to look out for. diff --git a/Python-3.12.11.tar.xz b/Python-3.12.11.tar.xz new file mode 100644 index 0000000..64fb9b5 --- /dev/null +++ b/Python-3.12.11.tar.xz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c30bb24b7f1e9a19b11b55a546434f74e739bb4c271a3e3a80ff4380d49f7adb +size 20525812 diff --git a/Python-3.12.11.tar.xz.asc b/Python-3.12.11.tar.xz.asc new file mode 100644 index 0000000..0c071fe --- /dev/null +++ b/Python-3.12.11.tar.xz.asc @@ -0,0 +1,18 @@ +-----BEGIN PGP SIGNATURE----- + +iQKTBAABCgB9FiEEcWlgX2LHUTVtBUomqCHmgOX6YwUFAmg/MbpfFIAAAAAALgAo +aXNzdWVyLWZwckBub3RhdGlvbnMub3BlbnBncC5maWZ0aGhvcnNlbWFuLm5ldDcx +Njk2MDVGNjJDNzUxMzU2RDA1NEEyNkE4MjFFNjgwRTVGQTYzMDUACgkQqCHmgOX6 +YwXySQ/7Ba9qlnTLmxqTCO8C7Gf545WNMBL2Ep6JZPgjOcgNk9e1QdAnNV5OOtGm +gW5nNPSTNNcIcPn058GuI24D4RpTQCJfMbMLsfYgvio0E7ij1gC19PsJHb6ejtCS +H2kK237Y1kuqRUdbTZssFDoAR4R9+UCaDuo4XdW+UKQk2GgdNQDMWLKmWF/Xk6Ob +/LihMXj27mDU9nXVdWR55sJzTFzfGB015vmORvcpuctkf1lZ4AfVFMgGw1CgjRjF +kjrOkrDErjDUQ8BIhMh90deiTpigfg7cg1HBDI6GRzklFg6cMfIdfvmfM0MfamX3 +Tow08TGBzmYXWgrqjYXW6JknKhBGOrjXMB7/yNDk9bJVLcOJaLbOmbcG0WRQF/Py +DMOCvr09l0yt5KFYpdKrDvyCuKYfpX33B4C60kU9JzmfXGyQ6LDTPXapZooJ+8Fg +GRTUsc0YWXoaDVCcxMIdiG+jEMQkjWVwW7E/nC/d7WT5L9KPoYFA1sZ834kKq3jr +NmZynbBnKH7m7L+u6HP6B+pa84FKEME69osAXZk0HJOIHB+SOX3E6BXRo6IV8Q/K +J6f5Ja26gJ7KXcUxTgkTkYh7tz0bhb+WeL3j6N/BC0eK7ZVsKRZ/3WnntGsG5B2m +FjVOYKolfkF4tf63SjdFuudgaKGCaDK1PvfwIr7k0oozxrB2ZEA= +=SYH/ +-----END PGP SIGNATURE----- diff --git a/Python-3.12.11.tar.xz.sigstore b/Python-3.12.11.tar.xz.sigstore new file mode 100644 index 0000000..793b770 --- /dev/null +++ b/Python-3.12.11.tar.xz.sigstore @@ -0,0 +1 @@ +{"mediaType": "application/vnd.dev.sigstore.bundle.v0.3+json", "verificationMaterial": {"certificate": {"rawBytes": "MIICyzCCAlGgAwIBAgIUYnM19yJLe8BOsB5QSK0ApWs7UFYwCgYIKoZIzj0EAwMwNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRlcm1lZGlhdGUwHhcNMjUwNjAzMTczMzU5WhcNMjUwNjAzMTc0MzU5WjAAMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEorc8E1btqvKxfzhMFNReGMAAH20rdFPI7kk7GPHd6PdKM7voZXQ95LgSzo2plgysqaIgn3em1cFPQ4JDfZj8FqOCAXAwggFsMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUVdDqigJFvvkJ9bwHazqUCUbFWHwwHwYDVR0jBBgwFoAU39Ppz1YkEZb5qNjpKFWixi4YZD8wHwYDVR0RAQH/BBUwE4ERdGhvbWFzQHB5dGhvbi5vcmcwKQYKKwYBBAGDvzABAQQbaHR0cHM6Ly9hY2NvdW50cy5nb29nbGUuY29tMCsGCisGAQQBg78wAQgEHQwbaHR0cHM6Ly9hY2NvdW50cy5nb29nbGUuY29tMIGLBgorBgEEAdZ5AgQCBH0EewB5AHcA3T0wasbHETJjGR4cmWc3AqJKXrjePK3/h4pygC8p7o4AAAGXNttt1QAABAMASDBGAiEAqqQMp3XA3a5TFLhTtiligp2CQqGlqGE/KfJbdVIQnjUCIQDVOfo4//KX7sZMwYpkhdj7xr/H60oTncyTAQjov+3OTTAKBggqhkjOPQQDAwNoADBlAjEA7RpgIF7whv9DvpnOVavPj4kQxM+gIbCvib3ue2STONKO+JnllxtScT+CypbscLT4AjBQFn7rmkKLgY/lT8YTDf9DqvopFJHXCdlbitQ1imoqOhZqJMEI17CMKMdBcc+BmnU="}, "tlogEntries": [{"logIndex": "228874048", "logId": {"keyId": "wNI9atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0="}, "kindVersion": {"kind": "hashedrekord", "version": "0.0.1"}, "integratedTime": "1748972040", "inclusionPromise": {"signedEntryTimestamp": "MEUCIQDC8I5uDgetSuD63qAPtlnnW58xKiSIGEX9AOJ5AnzNEgIgGfb+03Lf8DsOb1NkU5UNmPUeURv4bkQTgiZjtSfGJX0="}, "inclusionProof": {"logIndex": "106969786", "rootHash": "i3vbVg/L11/yzRE1My+dx8hKb/mLlOrFShOkXpDwz/o=", "treeSize": "106969787", "hashes": ["1fUlZVjuybf+gadL7+hmmzV88MK0fLFhuT2TIf4ruWE=", "h2PCG2d55a7VHzNH7amIjA/LgNJZQAVba+vKss3pYCc=", "fx5Vsw4rXULuFJQV5sKe1/WI5XEQGzkWHHyU/B1zfYw=", "iqK8b0KpsJULg7aqHgSStaU4dNbgrth5QDarXmEl3To=", "5S2DqBJZbuLio6e9iBmJWALzYi0hcpXFV3Z8ydE2lrA=", "n5MzQvR+waONXmENXriYi92eiz9pa5whuAyHmzyZa9Q=", "S+DrHAWb67kO9sHsAjIJ89A0RLlbeXy6mUvzoKO3dMI=", "JQ9xTJKo/o9IWVV8l4RTm06tpXUcGCeAh8ciAprOIoE=", "pqCD1LoiP58WZ9AfwL1uMRLqmiQQKDHHSdnl+4lB+/0=", "uEJFtwcGQJMd9kjQhkXb7gl2WD3WMElCc15uDFvFGxs=", "VdOKzpQhJlpXgijzXANf/hNlje1G/N1kUuVnKNskkso=", "mta5fH/gFwxJ/0fT8yGpn3sFCY0G1RY555Iflm0LInM=", "7v8qPHNDLerpduaMx06eb/MwgoQwczTn/cYGKX/9wZ4="], "checkpoint": {"envelope": "rekor.sigstore.dev - 1193050959916656506\n106969787\ni3vbVg/L11/yzRE1My+dx8hKb/mLlOrFShOkXpDwz/o=\n\n\u2014 rekor.sigstore.dev wNI9ajBFAiBibpE+dFaiZHUWTGPDNXeNfevho16eXV6wm1qMxN/m3wIhAN3M8Rs699nSFmZYP9sEHy6sNglaGwzKb+Nv8tJU7G7B\n"}}, "canonicalizedBody": "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiJjMzBiYjI0YjdmMWU5YTE5YjExYjU1YTU0NjQzNGY3NGU3MzliYjRjMjcxYTNlM2E4MGZmNDM4MGQ0OWY3YWRiIn19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FUUNJQ2piY2JONkNNK1FNbFE4dG1MdkhHbXFuakNrMm9tMmp0WlBsaUdJUWJieUFpQi9wNjAxVTN6RUcxSjFVTk1GWHlCekNhcVhVemhnRTVzVXUwUGFhT2IyelE9PSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVTjVla05EUVd4SFowRjNTVUpCWjBsVldXNU5NVGw1U2t4bE9FSlBjMEkxVVZOTE1FRndWM00zVlVaWmQwTm5XVWxMYjFwSmVtb3dSVUYzVFhjS1RucEZWazFDVFVkQk1WVkZRMmhOVFdNeWJHNWpNMUoyWTIxVmRWcEhWakpOVWpSM1NFRlpSRlpSVVVSRmVGWjZZVmRrZW1SSE9YbGFVekZ3WW01U2JBcGpiVEZzV2tkc2FHUkhWWGRJYUdOT1RXcFZkMDVxUVhwTlZHTjZUWHBWTlZkb1kwNU5hbFYzVG1wQmVrMVVZekJOZWxVMVYycEJRVTFHYTNkRmQxbElDa3R2V2tsNmFqQkRRVkZaU1V0dldrbDZhakJFUVZGalJGRm5RVVZ2Y21NNFJURmlkSEYyUzNobWVtaE5SazVTWlVkTlFVRklNakJ5WkVaUVNUZHJhemNLUjFCSVpEWlFaRXROTjNadldsaFJPVFZNWjFONmJ6SndiR2Q1YzNGaFNXZHVNMlZ0TVdOR1VGRTBTa1JtV21vNFJuRlBRMEZZUVhkblowWnpUVUUwUndwQk1WVmtSSGRGUWk5M1VVVkJkMGxJWjBSQlZFSm5UbFpJVTFWRlJFUkJTMEpuWjNKQ1owVkdRbEZqUkVGNlFXUkNaMDVXU0ZFMFJVWm5VVlZXWkVSeENtbG5Ta1oyZG10S09XSjNTR0Y2Y1ZWRFZXSkdWMGgzZDBoM1dVUldVakJxUWtKbmQwWnZRVlV6T1ZCd2VqRlphMFZhWWpWeFRtcHdTMFpYYVhocE5Ga0tXa1E0ZDBoM1dVUldVakJTUVZGSUwwSkNWWGRGTkVWU1pFZG9kbUpYUm5wUlNFSTFaRWRvZG1KcE5YWmpiV04zUzFGWlMwdDNXVUpDUVVkRWRucEJRZ3BCVVZGaVlVaFNNR05JVFRaTWVUbG9XVEpPZG1SWE5UQmplVFZ1WWpJNWJtSkhWWFZaTWpsMFRVTnpSME5wYzBkQlVWRkNaemM0ZDBGUlowVklVWGRpQ21GSVVqQmpTRTAyVEhrNWFGa3lUblprVnpVd1kzazFibUl5T1c1aVIxVjFXVEk1ZEUxSlIweENaMjl5UW1kRlJVRmtXalZCWjFGRFFrZ3dSV1YzUWpVS1FVaGpRVE5VTUhkaGMySklSVlJLYWtkU05HTnRWMk16UVhGS1MxaHlhbVZRU3pNdmFEUndlV2RET0hBM2J6UkJRVUZIV0U1MGRIUXhVVUZCUWtGTlFRcFRSRUpIUVdsRlFYRnhVVTF3TTFoQk0yRTFWRVpNYUZSMGFXeHBaM0F5UTFGeFIyeHhSMFV2UzJaS1ltUldTVkZ1YWxWRFNWRkVWazltYnpRdkwwdFlDamR6V2sxM1dYQnJhR1JxTjNoeUwwZzJNRzlVYm1ONVZFRlJhbTkyS3pOUFZGUkJTMEpuWjNGb2EycFBVRkZSUkVGM1RtOUJSRUpzUVdwRlFUZFNjR2NLU1VZM2QyaDJPVVIyY0c1UFZtRjJVR28wYTFGNFRTdG5TV0pEZG1saU0zVmxNbE5VVDA1TFR5dEtibXhzZUhSVFkxUXJRM2x3WW5OalRGUTBRV3BDVVFwR2JqZHliV3RMVEdkWkwyeFVPRmxVUkdZNVJIRjJiM0JHU2toWVEyUnNZbWwwVVRGcGJXOXhUMmhhY1VwTlJVa3hOME5OUzAxa1FtTmpLMEp0YmxVOUNpMHRMUzB0UlU1RUlFTkZVbFJKUmtsRFFWUkZMUzB0TFMwSyJ9fX19"}], "timestampVerificationData": {}}, "messageSignature": {"messageDigest": {"algorithm": "SHA2_256", "digest": "wwuyS38emhmxG1WlRkNPdOc5u0wnGj46gP9DgNSfets="}, "signature": "MEQCICjbcbN6CM+QMlQ8tmLvHGmqnjCk2om2jtZPliGIQbbyAiB/p601U3zEG1J1UNMFXyBzCaqXUzhgE5sUu0PaaOb2zQ=="}} diff --git a/Python-3.12.12.tar.xz b/Python-3.12.12.tar.xz new file mode 100644 index 0000000..a5676e8 --- /dev/null +++ b/Python-3.12.12.tar.xz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fb85a13414b028c49ba18bbd523c2d055a30b56b18b92ce454ea2c51edc656c4 +size 20798712 diff --git a/Python-3.12.12.tar.xz.asc b/Python-3.12.12.tar.xz.asc new file mode 100644 index 0000000..9e6c514 --- /dev/null +++ b/Python-3.12.12.tar.xz.asc @@ -0,0 +1,18 @@ +-----BEGIN PGP SIGNATURE----- + +iQKTBAABCgB9FiEEcWlgX2LHUTVtBUomqCHmgOX6YwUFAmjnnr1fFIAAAAAALgAo +aXNzdWVyLWZwckBub3RhdGlvbnMub3BlbnBncC5maWZ0aGhvcnNlbWFuLm5ldDcx +Njk2MDVGNjJDNzUxMzU2RDA1NEEyNkE4MjFFNjgwRTVGQTYzMDUACgkQqCHmgOX6 +YwXF3Q//VrreGa+P8lvp9UMjoj/YquKPwLqjzzAWf5vzHipkebdiESsB1HfGu04k +Jw+ctTnXHf/12u0W7ijv+56JtcJFqEzh8yGokWqOzc99rpCeCY9qtuwaVYtZrTNx +wepRaDAHdhP4Z2kLPDiE6pCXu2NIR5wHqHjQ8JGmprhASc07uxEhNN/gucVR2Sbr +cCfC9rHfHkdhoPpZRRbcraAaxPGL3VyBXf7HuYbHhf4GuF9EVDlFg5I0BzHCKJDd +ebPXYHvsoDgrMMqPXiX/YkGNByf3Ze6KZTNSGICy8SDzIzZgpmtOe5rzvlOXJBZZ +SVfX8SqP4Ufml+MfJrGEx30S9reYYvnyTSmttpbDznonROKPEZOuDt08+CG3yR+T +o5RdIneWmGXRf1mBrFKH9Br5tfOd+YeldfxdoQgla2fFHFVRnab1lsZFOC/HZ5z2 +Q3rPfVMDYKO8yoIKqv0BUzlkn9wYphCWoPHq0Y+SGjcP+Zh5qRTMqZYIaGekhWmx +86egHHVqedMI0Q9hvgIEirupVJ1q34FZn2+3sEka9hdOie9aNHXWTmgWCGDm46qj +qC9tT/jkMzWIY2Y4RdVDMdSCb7HkBEl1eAANq511gJ+eSWAXbP1sVrQoiAQY+EkC +Yu2ceZYsl9i6zm7i/QaU/mOGB7xMZhMQLZBnZTHSzAZo/pBN7y8= +=RuLK +-----END PGP SIGNATURE----- diff --git a/Python-3.12.12.tar.xz.sigstore b/Python-3.12.12.tar.xz.sigstore new file mode 100644 index 0000000..bcab32a --- /dev/null +++ b/Python-3.12.12.tar.xz.sigstore @@ -0,0 +1 @@ +{"mediaType": "application/vnd.dev.sigstore.bundle.v0.3+json", "verificationMaterial": {"certificate": {"rawBytes": "MIICyjCCAlCgAwIBAgIUa7XmzWlmoxbdaf7Bd0cb7k2SJX0wCgYIKoZIzj0EAwMwNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRlcm1lZGlhdGUwHhcNMjUxMDA5MTEzOTEwWhcNMjUxMDA5MTE0OTEwWjAAMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEnnBupfHW0kIyKIch4g4bg/VMzmQSN3W+fDXSBXPHKVV01duW4mnJBNAx8dOjaDQJbbGLCL3nHReR6AHY5EzzWKOCAW8wggFrMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUxS1GFV6/403CJB2LIriD0Yxys+kwHwYDVR0jBBgwFoAU39Ppz1YkEZb5qNjpKFWixi4YZD8wHwYDVR0RAQH/BBUwE4ERdGhvbWFzQHB5dGhvbi5vcmcwKQYKKwYBBAGDvzABAQQbaHR0cHM6Ly9hY2NvdW50cy5nb29nbGUuY29tMCsGCisGAQQBg78wAQgEHQwbaHR0cHM6Ly9hY2NvdW50cy5nb29nbGUuY29tMIGKBgorBgEEAdZ5AgQCBHwEegB4AHYA3T0wasbHETJjGR4cmWc3AqJKXrjePK3/h4pygC8p7o4AAAGZyMSWqQAABAMARzBFAiEAgP3Zja0sZ42WlEujGWIbBp+3AemF4BPwFlVMLG/criwCIDSK9BOHosQgvpZnN+hpQrqZdHZ7j1QXaxWfcERObDGrMAoGCCqGSM49BAMDA2gAMGUCMC/Fx5Bbae7C7w5CjzPgAIRB8sAV5THF7EynHjFxBqjwYhiMblyn5lzwpTsSpcGyiQIxAMtPBAMZXbJeY8LL/rTmrqaS+gvUCFZe430pf/7njbi+vMTsnX6lbyDW6+MBPf2w0Q=="}, "tlogEntries": [{"logIndex": "597445409", "logId": {"keyId": "wNI9atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0="}, "kindVersion": {"kind": "hashedrekord", "version": "0.0.1"}, "integratedTime": "1760009951", "inclusionPromise": {"signedEntryTimestamp": "MEQCICmAn/SSLFYafnAtkPRYmvBAv34ZqQsxnCKxA6lvOwtIAiADgWJmj7xnSimwJjyYMND/62BSa6VAn+yiurqa+3sFbg=="}, "inclusionProof": {"logIndex": "475541147", "rootHash": "NtKq0OO26YDo37dp00CxEkih9ardFvhT06bm+f1SQDE=", "treeSize": "475541154", "hashes": ["NslcefFuKuND6JRNbUSPjLrHeL0W18bCD4VhxfCcQKk=", "A0S2uABqcbgE1HPfloLBAk0TlXFJVl7yLEBondSsQ0c=", "6sWxX6Qc03LZeNbyN5W9cj7IZtqLYjkxFKvRS3ynzso=", "sdBvJFo0UwZVcXbz5NwqW/k4wRKwjiBjYIlN9G6hzXc=", "HSc04gOheRI34V7k9W+RDSDZFEf2I9JjEEOdGOMAUCA=", "C0KrXbTnn0FjHCn6Pk8TOEPndNLUliSsS1kLpaoeFho=", "/lb6eJIa9/379KwZZThJl+TJzpB0p9sLsW59J4AkleA=", "60XcwfvS6KRVEutb85dCHmflKO/pCJu3wP/wi71Hjjw=", "T5+n1/blJViw8vobIXjJuar7GB5qkWPWxuPI4TLuIus=", "N/HdEEbPrOhis60vsOpblzzFJ5Gn0VF1X5o/a5zj5ho=", "5iV4XGoB9mnKM5YryHN+GB7tIaTkjbMhbGbF01zhzKU=", "qXhJobQjWl6SO/pue3trUW2uL4jXx24Ip7lpd4hc5bU=", "56ObhlROm9L8Q4JyN+mxEQ5pZD5QdobB1xZFIeL0lVg=", "EGaD/cNavzxGYLx1Gl0uNNWBZvyXlSHSdlIeH7m+63A=", "2Wv4GiithwNukRKV06clevnQQYCzXmSS/+/OJtXgsXQ=", "1mfy94KpcItqshH9+gwqV6jccupcaMpVsF28New8zDY=", "vS7O4ozHIQZJWBiov+mkpI27GE8zAmVCEkRcP3NDyNE="], "checkpoint": {"envelope": "rekor.sigstore.dev - 1193050959916656506\n475541154\nNtKq0OO26YDo37dp00CxEkih9ardFvhT06bm+f1SQDE=\n\n\u2014 rekor.sigstore.dev wNI9ajBFAiBAXkd6xMHjC/fa3mQGVYRGINSGMy5E39T2cwLfMJUCdAIhAJ8pLs5eiFWKL+RH/M/yyicyskpEIjumbkignFyjP+fn\n"}}, "canonicalizedBody": "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiJmYjg1YTEzNDE0YjAyOGM0OWJhMThiYmQ1MjNjMmQwNTVhMzBiNTZiMThiOTJjZTQ1NGVhMmM1MWVkYzY1NmM0In19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FVUNJUUNzSysxcVRmNGZHd2I1eTBuaHpiQXdKa1hucGUydDYzZU96a3VrQ2Q5bFNRSWdDTzNRb3huTFc2b0FyMk0yMFMvL3k4aURVS0VHZTNwaXBMd0MvK3ptTG5BPSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVTjVha05EUVd4RFowRjNTVUpCWjBsVllUZFliWHBYYkcxdmVHSmtZV1kzUW1Rd1kySTNhekpUU2xnd2QwTm5XVWxMYjFwSmVtb3dSVUYzVFhjS1RucEZWazFDVFVkQk1WVkZRMmhOVFdNeWJHNWpNMUoyWTIxVmRWcEhWakpOVWpSM1NFRlpSRlpSVVVSRmVGWjZZVmRrZW1SSE9YbGFVekZ3WW01U2JBcGpiVEZzV2tkc2FHUkhWWGRJYUdOT1RXcFZlRTFFUVRWTlZFVjZUMVJGZDFkb1kwNU5hbFY0VFVSQk5VMVVSVEJQVkVWM1YycEJRVTFHYTNkRmQxbElDa3R2V2tsNmFqQkRRVkZaU1V0dldrbDZhakJFUVZGalJGRm5RVVZ1YmtKMWNHWklWekJyU1hsTFNXTm9OR2MwWW1jdlZrMTZiVkZUVGpOWEsyWkVXRk1LUWxoUVNFdFdWakF4WkhWWE5HMXVTa0pPUVhnNFpFOXFZVVJSU21KaVIweERURE51U0ZKbFVqWkJTRmsxUlhwNlYwdFBRMEZYT0hkblowWnlUVUUwUndwQk1WVmtSSGRGUWk5M1VVVkJkMGxJWjBSQlZFSm5UbFpJVTFWRlJFUkJTMEpuWjNKQ1owVkdRbEZqUkVGNlFXUkNaMDVXU0ZFMFJVWm5VVlY0VXpGSENrWldOaTgwTURORFNrSXlURWx5YVVRd1dYaDVjeXRyZDBoM1dVUldVakJxUWtKbmQwWnZRVlV6T1ZCd2VqRlphMFZhWWpWeFRtcHdTMFpYYVhocE5Ga0tXa1E0ZDBoM1dVUldVakJTUVZGSUwwSkNWWGRGTkVWU1pFZG9kbUpYUm5wUlNFSTFaRWRvZG1KcE5YWmpiV04zUzFGWlMwdDNXVUpDUVVkRWRucEJRZ3BCVVZGaVlVaFNNR05JVFRaTWVUbG9XVEpPZG1SWE5UQmplVFZ1WWpJNWJtSkhWWFZaTWpsMFRVTnpSME5wYzBkQlVWRkNaemM0ZDBGUlowVklVWGRpQ21GSVVqQmpTRTAyVEhrNWFGa3lUblprVnpVd1kzazFibUl5T1c1aVIxVjFXVEk1ZEUxSlIwdENaMjl5UW1kRlJVRmtXalZCWjFGRFFraDNSV1ZuUWpRS1FVaFpRVE5VTUhkaGMySklSVlJLYWtkU05HTnRWMk16UVhGS1MxaHlhbVZRU3pNdmFEUndlV2RET0hBM2J6UkJRVUZIV25sTlUxZHhVVUZCUWtGTlFRcFNla0pHUVdsRlFXZFFNMXBxWVRCeldqUXlWMnhGZFdwSFYwbGlRbkFyTTBGbGJVWTBRbEIzUm14V1RVeEhMMk55YVhkRFNVUlRTemxDVDBodmMxRm5Dblp3V201T0syaHdVWEp4V21SSVdqZHFNVkZZWVhoWFptTkZVazlpUkVkeVRVRnZSME5EY1VkVFRUUTVRa0ZOUkVFeVowRk5SMVZEVFVNdlJuZzFRbUlLWVdVM1F6ZDNOVU5xZWxCblFVbFNRamh6UVZZMVZFaEdOMFY1YmtocVJuaENjV3AzV1docFRXSnNlVzQxYkhwM2NGUnpVM0JqUjNscFVVbDRRVTEwVUFwQ1FVMWFXR0pLWlZrNFRFd3ZjbFJ0Y25GaFV5dG5kbFZEUmxwbE5ETXdjR1l2TjI1cVlta3JkazFVYzI1WU5teGllVVJYTml0TlFsQm1NbmN3VVQwOUNpMHRMUzB0UlU1RUlFTkZVbFJKUmtsRFFWUkZMUzB0TFMwSyJ9fX19"}], "timestampVerificationData": {}}, "messageSignature": {"messageDigest": {"algorithm": "SHA2_256", "digest": "+4WhNBSwKMSboYu9UjwtBVowtWsYuSzkVOosUe3GVsQ="}, "signature": "MEUCIQCsK+1qTf4fGwb5y0nhzbAwJkXnpe2t63eOzkukCd9lSQIgCO3QoxnLW6oAr2M20S//y8iDUKEGe3pipLwC/+zmLnA="}} diff --git a/README.SUSE b/README.SUSE new file mode 100644 index 0000000..0053bcf --- /dev/null +++ b/README.SUSE @@ -0,0 +1,43 @@ +Python 3 in SUSE +============== + +* Subpackages * + +Python 3 is split into several subpackages, based on external dependencies. +The main package 'python3' has soft dependencies on all subpackages needed to +assemble the standard library; however, these might not all be installed by default. + +If you attempt to import a module that is currently not installed, an ImportError is thrown, +with instructions to install the missing subpackage. Installing the subpackage might result +in installing libraries that the subpackage requires to function. + + +* ensurepip * + +The 'ensurepip' module from Python 3 standard library (PEP 453) is supposed to deploy +a bundled copy of the pip installer. This makes no sense in a managed distribution like SUSE. +Instead, you need to install package 'python3-pip'. Usually this will be installed automatically +with 'python3'. + +Using 'ensurepip' when pip is not installed will result in an ImportError with instructions +to install 'python3-pip'. + + +* Documentation * + +You can find documentation in seprarate packages: python3-doc and +python3-doc-pdf. These contan following documents: + + Tutorial, What's New in Python, Global Module Index, Library Reference, + Macintosh Module Reference, Installing Python Modules, Distributing Python + Modules, Language Reference, Extending and Embedding, Python/C API, + Documenting Python + +The python3-doc package constains many text files from source tarball. + + +* Interactive mode * + +Interactive mode is by default enhanced with of history and command completion. +If you don't like these features, you can unset the PYTHONSTARTUP variable +in your .profile or disable it system wide in /etc/profile.d/python.sh. diff --git a/_multibuild b/_multibuild new file mode 100644 index 0000000..1d50bc4 --- /dev/null +++ b/_multibuild @@ -0,0 +1,4 @@ + + base + doc + diff --git a/baselibs.conf b/baselibs.conf new file mode 100644 index 0000000..d7b7b53 --- /dev/null +++ b/baselibs.conf @@ -0,0 +1,3 @@ +python312-base +python312 +libpython3_12-1_0 diff --git a/bluez-devel-vendor.tar.xz b/bluez-devel-vendor.tar.xz new file mode 100644 index 0000000..bb4fd89 --- /dev/null +++ b/bluez-devel-vendor.tar.xz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4624c6ab6543ec4875bdd5c6c58c874d487128e44e54c8ef1924ec1d48e35928 +size 25328 diff --git a/bpo-31046_ensurepip_honours_prefix.patch b/bpo-31046_ensurepip_honours_prefix.patch new file mode 100644 index 0000000..0459cf5 --- /dev/null +++ b/bpo-31046_ensurepip_honours_prefix.patch @@ -0,0 +1,175 @@ +From 5754521af1d51aa8e445cba07a093bbc0c88596d Mon Sep 17 00:00:00 2001 +From: Zackery Spytz +Date: Mon, 16 Dec 2019 18:24:08 -0700 +Subject: [PATCH] bpo-31046: ensurepip does not honour the value of $(prefix) + +Co-Authored-By: Xavier de Gaye +--- + Doc/library/ensurepip.rst | 12 +++++- + Lib/ensurepip/__init__.py | 18 +++++++--- + Lib/test/test_ensurepip.py | 11 ++++++ + Makefile.pre.in | 4 +- + Misc/NEWS.d/next/Build/2019-12-16-17-50-42.bpo-31046.XA-Qfr.rst | 1 + 5 files changed, 37 insertions(+), 9 deletions(-) + create mode 100644 Misc/NEWS.d/next/Build/2019-12-16-17-50-42.bpo-31046.XA-Qfr.rst + +Index: Python-3.12.10/Doc/library/ensurepip.rst +=================================================================== +--- Python-3.12.10.orig/Doc/library/ensurepip.rst 2025-04-08 13:35:47.000000000 +0200 ++++ Python-3.12.10/Doc/library/ensurepip.rst 2025-04-11 21:16:06.140273604 +0200 +@@ -61,7 +61,11 @@ + By default, ``pip`` is installed into the current virtual environment + (if one is active) or into the system site packages (if there is no + active virtual environment). The installation location can be controlled +-through two additional command line options: ++through some additional command line options: ++ ++.. option:: --prefix ++ ++ Installs ``pip`` using the given directory prefix. + + .. option:: --root + +@@ -102,7 +106,7 @@ + Returns a string specifying the available version of pip that will be + installed when bootstrapping an environment. + +-.. function:: bootstrap(root=None, upgrade=False, user=False, \ ++.. function:: bootstrap(root=None, prefix=None, upgrade=False, user=False, \ + altinstall=False, default_pip=False, \ + verbosity=0) + +@@ -112,6 +116,8 @@ + If *root* is ``None``, then installation uses the default install location + for the current environment. + ++ *prefix* specifies the directory prefix to use when installing. ++ + *upgrade* indicates whether or not to upgrade an existing installation + of an earlier version of ``pip`` to the available version. + +@@ -132,6 +138,8 @@ + *verbosity* controls the level of output to :data:`sys.stdout` from the + bootstrapping operation. + ++ .. versionchanged:: 3.9 the *prefix* parameter was added. ++ + .. audit-event:: ensurepip.bootstrap root ensurepip.bootstrap + + .. note:: +Index: Python-3.12.10/Lib/ensurepip/__init__.py +=================================================================== +--- Python-3.12.10.orig/Lib/ensurepip/__init__.py 2025-04-11 21:04:42.789443156 +0200 ++++ Python-3.12.10/Lib/ensurepip/__init__.py 2025-04-11 21:13:01.303399067 +0200 +@@ -120,27 +120,27 @@ + os.environ['PIP_CONFIG_FILE'] = os.devnull + + +-def bootstrap(*, root=None, upgrade=False, user=False, ++def bootstrap(*, root=None, prefix=None, upgrade=False, user=False, + altinstall=False, default_pip=False, + verbosity=0): + """ + Bootstrap pip into the current Python installation (or the given root +- directory). ++ and directory prefix). + + Note that calling this function will alter both sys.path and os.environ. + """ + # Discard the return value +- _bootstrap(root=root, upgrade=upgrade, user=user, ++ _bootstrap(root=root, prefix=prefix, upgrade=upgrade, user=user, + altinstall=altinstall, default_pip=default_pip, + verbosity=verbosity) + + +-def _bootstrap(*, root=None, upgrade=False, user=False, ++def _bootstrap(*, root=None, prefix=None, upgrade=False, user=False, + altinstall=False, default_pip=False, + verbosity=0): + """ + Bootstrap pip into the current Python installation (or the given root +- directory). Returns pip command status code. ++ and directory prefix). Returns pip command status code. + + Note that calling this function will alter both sys.path and os.environ. + """ +@@ -190,6 +190,8 @@ + args = ["install", "--no-cache-dir", "--no-index", "--find-links", tmpdir] + if root: + args += ["--root", root] ++ if prefix: ++ args += ["--prefix", prefix] + if upgrade: + args += ["--upgrade"] + if user: +@@ -265,6 +267,11 @@ + help="Install everything relative to this alternate root directory.", + ) + parser.add_argument( ++ "--prefix", ++ default=None, ++ help="Install everything using this prefix.", ++ ) ++ parser.add_argument( + "--altinstall", + action="store_true", + default=False, +@@ -283,6 +290,7 @@ + + return _bootstrap( + root=args.root, ++ prefix=args.prefix, + upgrade=args.upgrade, + user=args.user, + verbosity=args.verbosity, +Index: Python-3.12.10/Lib/test/test_ensurepip.py +=================================================================== +--- Python-3.12.10.orig/Lib/test/test_ensurepip.py 2025-04-11 21:04:44.274413027 +0200 ++++ Python-3.12.10/Lib/test/test_ensurepip.py 2025-04-11 21:13:01.303691075 +0200 +@@ -105,6 +105,17 @@ + unittest.mock.ANY, + ) + ++ def test_bootstrapping_with_prefix(self): ++ ensurepip.bootstrap(prefix="/foo/bar/") ++ self.run_pip.assert_called_once_with( ++ [ ++ "install", "--no-cache-dir", "--no-index", "--find-links", ++ unittest.mock.ANY, "--prefix", "/foo/bar/", ++ "pip", ++ ], ++ unittest.mock.ANY, ++ ) ++ + def test_bootstrapping_with_user(self): + ensurepip.bootstrap(user=True) + +Index: Python-3.12.10/Makefile.pre.in +=================================================================== +--- Python-3.12.10.orig/Makefile.pre.in 2025-04-11 21:04:58.388346212 +0200 ++++ Python-3.12.10/Makefile.pre.in 2025-04-11 21:13:01.304095180 +0200 +@@ -1914,7 +1914,7 @@ + install|*) ensurepip="" ;; \ + esac; \ + $(RUNSHARED) $(PYTHON_FOR_BUILD) -m ensurepip \ +- $$ensurepip --root=$(DESTDIR)/ ; \ ++ $$ensurepip --root=$(DESTDIR)/ --prefix=$(prefix) ; \ + fi + + .PHONY: altinstall +@@ -1925,7 +1925,7 @@ + install|*) ensurepip="--altinstall" ;; \ + esac; \ + $(RUNSHARED) $(PYTHON_FOR_BUILD) -m ensurepip \ +- $$ensurepip --root=$(DESTDIR)/ ; \ ++ $$ensurepip --root=$(DESTDIR)/ --prefix=$(prefix) ; \ + fi + + .PHONY: commoninstall +Index: Python-3.12.10/Misc/NEWS.d/next/Build/2019-12-16-17-50-42.bpo-31046.XA-Qfr.rst +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ Python-3.12.10/Misc/NEWS.d/next/Build/2019-12-16-17-50-42.bpo-31046.XA-Qfr.rst 2025-04-11 21:13:01.304672632 +0200 +@@ -0,0 +1 @@ ++A directory prefix can now be specified when using :mod:`ensurepip`. diff --git a/bsc1243155-sphinx-non-determinism.patch b/bsc1243155-sphinx-non-determinism.patch new file mode 100644 index 0000000..d5e2f11 --- /dev/null +++ b/bsc1243155-sphinx-non-determinism.patch @@ -0,0 +1,45 @@ +From 906a590df191f66f4f0c4a70e3edb6fd82c156ef Mon Sep 17 00:00:00 2001 +From: Daniel Garcia Moreno +Date: Tue, 1 Jul 2025 12:13:28 +0200 +Subject: [PATCH] Doc: Generate ids for audit_events using docname + +This patch generates ids for audit_events using the docname so the id is +not global but depend on the source file. This make the doc build +reproducible with multiple cores because it doesn't which file is parsed +first, the id for audit_events will always be consistent independently +of what file is parsed first. + +https://github.com/python/cpython/issues/130979 +--- + Doc/tools/extensions/audit_events.py | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +Index: Python-3.12.11/Doc/tools/extensions/audit_events.py +=================================================================== +--- Python-3.12.11.orig/Doc/tools/extensions/audit_events.py 2025-07-02 16:10:55.447792590 +0200 ++++ Python-3.12.11/Doc/tools/extensions/audit_events.py 2025-07-02 16:12:00.124596479 +0200 +@@ -64,8 +64,13 @@ + logger.warning(msg) + return + +- def id_for(self, name) -> str: +- source_count = len(self.sources.get(name, ())) ++ def _source_count(self, name, docname) -> int: ++ """Count the event name in the same source""" ++ sources = self.sources.get(name, set()) ++ return len([s for s, t in sources if s == docname]) ++ ++ def id_for(self, name, docname) -> str: ++ source_count = self._source_count(name, docname) + name_clean = re.sub(r"\W", "_", name) + return f"audit_event_{name_clean}_{source_count}" + +@@ -140,7 +145,7 @@ + except (IndexError, TypeError): + target = None + if not target: +- target = self.env.audit_events.id_for(name) ++ target = self.env.audit_events.id_for(name, self.env.docname) + ids.append(target) + self.env.audit_events.add_event(name, args, (self.env.docname, target)) + diff --git a/doc-py38-to-py36.patch b/doc-py38-to-py36.patch new file mode 100644 index 0000000..1df4894 --- /dev/null +++ b/doc-py38-to-py36.patch @@ -0,0 +1,780 @@ +--- + Doc/Makefile | 8 +-- + Doc/conf.py | 16 ++++++- + Doc/tools/check-warnings.py | 5 +- + Doc/tools/extensions/audit_events.py | 54 +++++++++++++------------- + Doc/tools/extensions/availability.py | 15 +++---- + Doc/tools/extensions/c_annotations.py | 45 +++++++++++++-------- + Doc/tools/extensions/changes.py | 8 +-- + Doc/tools/extensions/glossary_search.py | 10 +--- + Doc/tools/extensions/implementation_detail.py | 22 +++------- + Doc/tools/extensions/issue_role.py | 16 ++----- + Doc/tools/extensions/misc_news.py | 14 ++---- + Doc/tools/extensions/patchlevel.py | 9 ++-- + Doc/tools/extensions/pydoc_topics.py | 22 +++++----- + 13 files changed, 126 insertions(+), 118 deletions(-) + +Index: Python-3.12.10/Doc/Makefile +=================================================================== +--- Python-3.12.10.orig/Doc/Makefile 2025-04-29 22:11:50.013198738 +0200 ++++ Python-3.12.10/Doc/Makefile 2025-04-29 22:11:52.047098026 +0200 +@@ -14,15 +14,15 @@ + SOURCES = + DISTVERSION = $(shell $(PYTHON) tools/extensions/patchlevel.py) + REQUIREMENTS = requirements.txt +-SPHINXERRORHANDLING = --fail-on-warning ++SPHINXERRORHANDLING = -W + + # Internal variables. + PAPEROPT_a4 = --define latex_elements.papersize=a4paper + PAPEROPT_letter = --define latex_elements.papersize=letterpaper + +-ALLSPHINXOPTS = --builder $(BUILDER) \ +- --doctree-dir build/doctrees \ +- --jobs $(JOBS) \ ++ALLSPHINXOPTS = -b $(BUILDER) \ ++ -d build/doctrees \ ++ -j $(JOBS) \ + $(PAPEROPT_$(PAPER)) \ + $(SPHINXOPTS) $(SPHINXERRORHANDLING) \ + . build/$(BUILDER) $(SOURCES) +Index: Python-3.12.10/Doc/conf.py +=================================================================== +--- Python-3.12.10.orig/Doc/conf.py 2025-04-29 22:11:46.161835452 +0200 ++++ Python-3.12.10/Doc/conf.py 2025-04-29 22:11:52.047459667 +0200 +@@ -11,6 +11,8 @@ + from importlib import import_module + from importlib.util import find_spec + ++from sphinx import version_info ++ + # Make our custom extensions available to Sphinx + sys.path.append(os.path.abspath('tools/extensions')) + sys.path.append(os.path.abspath('includes')) +@@ -87,7 +89,7 @@ + + # Minimum version of sphinx required + # Keep this version in sync with ``Doc/requirements.txt``. +-needs_sphinx = '8.2.0' ++needs_sphinx = '4.2.0' + + # Create table of contents entries for domain objects (e.g. functions, classes, + # attributes, etc.). Default is True. +@@ -342,7 +344,7 @@ + # (See .readthedocs.yml and https://docs.readthedocs.io/en/stable/reference/environment-variables.html) + is_deployment_preview = os.getenv("READTHEDOCS_VERSION_TYPE") == "external" + repository_url = os.getenv("READTHEDOCS_GIT_CLONE_URL", "") +-repository_url = repository_url.removesuffix(".git") ++repository_url = repository_url[:-len(".git")] + html_context = { + "is_deployment_preview": is_deployment_preview, + "repository_url": repository_url or None, +@@ -588,6 +590,16 @@ + } + extlinks_detect_hardcoded_links = True + ++if version_info[:2] < (8, 1): ++ # Sphinx 8.1 has in-built CVE and CWE roles. ++ extlinks.update({ ++ "cve": ( ++ "https://www.cve.org/CVERecord?id=CVE-%s", ++ "CVE-%s", ++ ), ++ "cwe": ("https://cwe.mitre.org/data/definitions/%s.html", "CWE-%s"), ++ }) ++ + # Options for c_annotations extension + # ----------------------------------- + +Index: Python-3.12.10/Doc/tools/check-warnings.py +=================================================================== +--- Python-3.12.10.orig/Doc/tools/check-warnings.py 2025-04-08 13:35:47.000000000 +0200 ++++ Python-3.12.10/Doc/tools/check-warnings.py 2025-04-29 22:11:52.047704324 +0200 +@@ -228,7 +228,8 @@ + print(filename) + for warning in warnings: + if filename in warning: +- if match := WARNING_PATTERN.fullmatch(warning): ++ match = WARNING_PATTERN.fullmatch(warning) ++ if match: + print(" {line}: {msg}".format_map(match)) + return -1 + return 0 +@@ -316,7 +317,7 @@ + + cwd = str(Path.cwd()) + os.path.sep + files_with_nits = { +- warning.removeprefix(cwd).split(":")[0] ++ (warning[len(cwd):].split(":")[0] if warning.startswith(cwd) else warning.split(":")[0]) + for warning in warnings + if "Doc/" in warning + } +Index: Python-3.12.10/Doc/tools/extensions/audit_events.py +=================================================================== +--- Python-3.12.10.orig/Doc/tools/extensions/audit_events.py 2025-04-08 13:35:47.000000000 +0200 ++++ Python-3.12.10/Doc/tools/extensions/audit_events.py 2025-04-29 22:11:52.047967558 +0200 +@@ -1,9 +1,6 @@ + """Support for documenting audit events.""" + +-from __future__ import annotations +- + import re +-from typing import TYPE_CHECKING + + from docutils import nodes + from sphinx.errors import NoUri +@@ -12,12 +9,11 @@ + from sphinx.util import logging + from sphinx.util.docutils import SphinxDirective + +-if TYPE_CHECKING: +- from collections.abc import Iterator ++from typing import Any, List, Tuple + +- from sphinx.application import Sphinx +- from sphinx.builders import Builder +- from sphinx.environment import BuildEnvironment ++from sphinx.application import Sphinx ++from sphinx.builders import Builder ++from sphinx.environment import BuildEnvironment + + logger = logging.getLogger(__name__) + +@@ -32,16 +28,16 @@ + + class AuditEvents: + def __init__(self) -> None: +- self.events: dict[str, list[str]] = {} +- self.sources: dict[str, list[tuple[str, str]]] = {} ++ self.events: dict[str, List[str]] = {} ++ self.sources: dict[str, List[Tuple[str, str]]] = {} + +- def __iter__(self) -> Iterator[tuple[str, list[str], tuple[str, str]]]: ++ def __iter__(self) -> Any: + for name, args in self.events.items(): + for source in self.sources[name]: + yield name, args, source + + def add_event( +- self, name, args: list[str], source: tuple[str, str] ++ self, name, args: List[str], source: Tuple[str, str] + ) -> None: + if name in self.events: + self._check_args_match(name, args) +@@ -49,7 +45,7 @@ + self.events[name] = args + self.sources.setdefault(name, []).append(source) + +- def _check_args_match(self, name: str, args: list[str]) -> None: ++ def _check_args_match(self, name: str, args: List[str]) -> None: + current_args = self.events[name] + msg = ( + f"Mismatched arguments for audit-event {name}: " +@@ -60,7 +56,7 @@ + if len(current_args) != len(args): + logger.warning(msg) + return +- for a1, a2 in zip(current_args, args, strict=False): ++ for a1, a2 in zip(current_args, args): + if a1 == a2: + continue + if any(a1 in s and a2 in s for s in _SYNONYMS): +@@ -73,7 +69,7 @@ + name_clean = re.sub(r"\W", "_", name) + return f"audit_event_{name_clean}_{source_count}" + +- def rows(self) -> Iterator[tuple[str, list[str], list[tuple[str, str]]]]: ++ def rows(self) -> Any: + for name in sorted(self.events.keys()): + yield name, self.events[name], self.sources[name] + +@@ -97,7 +93,7 @@ + def audit_events_merge( + app: Sphinx, + env: BuildEnvironment, +- docnames: list[str], ++ docnames: List[str], + other: BuildEnvironment, + ) -> None: + """In Sphinx parallel builds, this merges audit_events from subprocesses.""" +@@ -126,14 +122,16 @@ + ), + ] + +- def run(self) -> list[nodes.paragraph]: ++ def run(self) -> List[nodes.paragraph]: ++ def _no_walrus_op(args): ++ for arg in args.strip("'\"").split(","): ++ aarg = arg.strip() ++ if aarg: ++ yield aarg ++ + name = self.arguments[0] + if len(self.arguments) >= 2 and self.arguments[1]: +- args = [ +- arg +- for argument in self.arguments[1].strip("'\"").split(",") +- if (arg := argument.strip()) +- ] ++ args = list(_no_walrus_op(self.arguments[1])) + else: + args = [] + ids = [] +@@ -169,7 +167,7 @@ + + + class AuditEventListDirective(SphinxDirective): +- def run(self) -> list[audit_event_list]: ++ def run(self) -> List[audit_event_list]: + return [audit_event_list()] + + +@@ -181,7 +179,11 @@ + return + + table = self._make_table(self.app.builder, self.env.docname) +- for node in self.document.findall(audit_event_list): ++ try: ++ findall = self.document.findall ++ except AttributeError: ++ findall = self.document.traverse ++ for node in findall(audit_event_list): + node.replace_self(table) + + def _make_table(self, builder: Builder, docname: str) -> nodes.table: +@@ -217,8 +219,8 @@ + builder: Builder, + docname: str, + name: str, +- args: list[str], +- sources: list[tuple[str, str]], ++ args: List[str], ++ sources: List[Tuple[str, str]], + ) -> nodes.row: + row = nodes.row() + name_node = nodes.paragraph("", nodes.Text(name)) +Index: Python-3.12.10/Doc/tools/extensions/availability.py +=================================================================== +--- Python-3.12.10.orig/Doc/tools/extensions/availability.py 2025-04-08 13:35:47.000000000 +0200 ++++ Python-3.12.10/Doc/tools/extensions/availability.py 2025-04-29 22:11:52.048206976 +0200 +@@ -1,8 +1,6 @@ + """Support for documenting platform availability""" + +-from __future__ import annotations +- +-from typing import TYPE_CHECKING ++from typing import Dict, List, TYPE_CHECKING, Union + + from docutils import nodes + from sphinx import addnodes +@@ -53,7 +51,7 @@ + optional_arguments = 0 + final_argument_whitespace = True + +- def run(self) -> list[nodes.container]: ++ def run(self) -> List[nodes.container]: + title = sphinx_gettext("Availability") + refnode = addnodes.pending_xref( + title, +@@ -77,7 +75,7 @@ + + return [cnode] + +- def parse_platforms(self) -> dict[str, str | bool]: ++ def parse_platforms(self) -> Dict[str, Union[str, bool]]: + """Parse platform information from arguments + + Arguments is a comma-separated string of platforms. A platform may +@@ -96,12 +94,13 @@ + platform, _, version = arg.partition(" >= ") + if platform.startswith("not "): + version = False +- platform = platform.removeprefix("not ") ++ platform = platform[len("not "):] + elif not version: + version = True + platforms[platform] = version + +- if unknown := set(platforms).difference(KNOWN_PLATFORMS): ++ unknown = set(platforms).difference(KNOWN_PLATFORMS) ++ if unknown: + logger.warning( + "Unknown platform%s or syntax '%s' in '.. availability:: %s', " + "see %s:KNOWN_PLATFORMS for a set of known platforms.", +@@ -114,7 +113,7 @@ + return platforms + + +-def setup(app: Sphinx) -> ExtensionMetadata: ++def setup(app): + app.add_directive("availability", Availability) + + return { +Index: Python-3.12.10/Doc/tools/extensions/c_annotations.py +=================================================================== +--- Python-3.12.10.orig/Doc/tools/extensions/c_annotations.py 2025-04-29 22:11:52.033400629 +0200 ++++ Python-3.12.10/Doc/tools/extensions/c_annotations.py 2025-04-29 22:11:52.048411194 +0200 +@@ -9,22 +9,18 @@ + * Set ``stable_abi_file`` to the path to stable ABI list. + """ + +-from __future__ import annotations +- + import csv + import dataclasses + from pathlib import Path +-from typing import TYPE_CHECKING ++from typing import Any, Dict, List, TYPE_CHECKING, Union + + from docutils import nodes + from docutils.statemachine import StringList +-from sphinx import addnodes ++from sphinx import addnodes, version_info + from sphinx.locale import _ as sphinx_gettext + from sphinx.util.docutils import SphinxDirective + +-if TYPE_CHECKING: +- from sphinx.application import Sphinx +- from sphinx.util.typing import ExtensionMetadata ++from sphinx.application import Sphinx + + ROLE_TO_OBJECT_TYPE = { + "func": "function", +@@ -35,20 +31,20 @@ + } + + +-@dataclasses.dataclass(slots=True) ++@dataclasses.dataclass() + class RefCountEntry: + # Name of the function. + name: str + # List of (argument name, type, refcount effect) tuples. + # (Currently not used. If it was, a dataclass might work better.) +- args: list = dataclasses.field(default_factory=list) ++ args: List = dataclasses.field(default_factory=list) + # Return type of the function. + result_type: str = "" + # Reference count effect for the return value. +- result_refs: int | None = None ++ result_refs: Union[int, None] = None + + +-@dataclasses.dataclass(frozen=True, slots=True) ++@dataclasses.dataclass(frozen=True) + class StableABIEntry: + # Role of the object. + # Source: Each [item_kind] in stable_abi.toml is mapped to a C Domain role. +@@ -67,7 +63,7 @@ + struct_abi_kind: str + + +-def read_refcount_data(refcount_filename: Path) -> dict[str, RefCountEntry]: ++def read_refcount_data(refcount_filename: Path) -> Dict[str, RefCountEntry]: + refcount_data = {} + refcounts = refcount_filename.read_text(encoding="utf8") + for line in refcounts.splitlines(): +@@ -103,7 +99,7 @@ + return refcount_data + + +-def read_stable_abi_data(stable_abi_file: Path) -> dict[str, StableABIEntry]: ++def read_stable_abi_data(stable_abi_file: Path) -> Dict[str, StableABIEntry]: + stable_abi_data = {} + with open(stable_abi_file, encoding="utf8") as fp: + for record in csv.DictReader(fp): +@@ -127,11 +123,14 @@ + continue + if not par[0].get("ids", None): + continue +- name = par[0]["ids"][0].removeprefix("c.") ++ name = par[0]["ids"][0] ++ if name.startswith("c."): ++ name = name[len("c."):] + objtype = par["objtype"] + + # Stable ABI annotation. +- if record := stable_abi_data.get(name): ++ record = stable_abi_data.get(name) ++ if record: + if ROLE_TO_OBJECT_TYPE[record.role] != objtype: + msg = ( + f"Object type mismatch in limited API annotation for {name}: " +@@ -238,7 +237,7 @@ + ) + + +-def _return_value_annotation(result_refs: int | None) -> nodes.emphasis: ++def _return_value_annotation(result_refs: Union[int, None]) -> nodes.emphasis: + classes = ["refcount"] + if result_refs is None: + rc = sphinx_gettext("Return value: Always NULL.") +@@ -258,7 +257,7 @@ + optional_arguments = 0 + final_argument_whitespace = True + +- def run(self) -> list[nodes.Node]: ++ def run(self) -> List[nodes.Node]: + state = self.env.domaindata["c_annotations"] + content = [ + f"* :c:{record.role}:`{record.name}`" +@@ -281,13 +280,23 @@ + ) + + +-def setup(app: Sphinx) -> ExtensionMetadata: ++def setup(app: Sphinx) -> Any: + app.add_config_value("refcount_file", "", "env", types={str}) + app.add_config_value("stable_abi_file", "", "env", types={str}) + app.add_directive("limited-api-list", LimitedAPIList) + app.connect("builder-inited", init_annotations) + app.connect("doctree-read", add_annotations) + ++ if version_info[:2] < (7, 2): ++ from docutils.parsers.rst import directives ++ from sphinx.domains.c import CObject ++ ++ # monkey-patch C object... ++ CObject.option_spec.update({ ++ "no-index-entry": directives.flag, ++ "no-contents-entry": directives.flag, ++ }) ++ + return { + "version": "1.0", + "parallel_read_safe": True, +Index: Python-3.12.10/Doc/tools/extensions/changes.py +=================================================================== +--- Python-3.12.10.orig/Doc/tools/extensions/changes.py 2025-04-08 13:35:47.000000000 +0200 ++++ Python-3.12.10/Doc/tools/extensions/changes.py 2025-04-29 22:11:52.048619113 +0200 +@@ -1,7 +1,5 @@ + """Support for documenting version of changes, additions, deprecations.""" + +-from __future__ import annotations +- + from typing import TYPE_CHECKING + + from sphinx.domains.changeset import ( +@@ -25,7 +23,7 @@ + + + class PyVersionChange(VersionChange): +- def run(self) -> list[Node]: ++ def run(self) -> "list[Node]": + # Replace the 'next' special token with the current development version + self.arguments[0] = expand_version_arg( + self.arguments[0], self.config.release +@@ -43,7 +41,7 @@ + "Deprecated since version %s, removed in version %s" + ) + +- def run(self) -> list[Node]: ++ def run(self) -> "list[Node]": + # Replace the first two arguments (deprecated version and removed version) + # with a single tuple of both versions. + version_deprecated = expand_version_arg( +@@ -73,7 +71,7 @@ + versionlabel_classes[self.name] = "" + + +-def setup(app: Sphinx) -> ExtensionMetadata: ++def setup(app: "Sphinx") -> "ExtensionMetadata": + # Override Sphinx's directives with support for 'next' + app.add_directive("versionadded", PyVersionChange, override=True) + app.add_directive("versionchanged", PyVersionChange, override=True) +Index: Python-3.12.10/Doc/tools/extensions/glossary_search.py +=================================================================== +--- Python-3.12.10.orig/Doc/tools/extensions/glossary_search.py 2025-04-29 22:11:52.033722879 +0200 ++++ Python-3.12.10/Doc/tools/extensions/glossary_search.py 2025-04-29 22:11:52.048797629 +0200 +@@ -1,18 +1,14 @@ + """Feature search results for glossary items prominently.""" + +-from __future__ import annotations +- + import json + from pathlib import Path +-from typing import TYPE_CHECKING ++from typing import Any, TYPE_CHECKING + + from docutils import nodes + from sphinx.addnodes import glossary + from sphinx.util import logging + +-if TYPE_CHECKING: +- from sphinx.application import Sphinx +- from sphinx.util.typing import ExtensionMetadata ++from sphinx.application import Sphinx + + logger = logging.getLogger(__name__) + +@@ -60,7 +56,7 @@ + dest.write_text(json.dumps(app.env.glossary_terms), encoding='utf-8') + + +-def setup(app: Sphinx) -> ExtensionMetadata: ++def setup(app: Sphinx) -> Any: + app.connect('doctree-resolved', process_glossary_nodes) + app.connect('build-finished', write_glossary_json) + +Index: Python-3.12.10/Doc/tools/extensions/implementation_detail.py +=================================================================== +--- Python-3.12.10.orig/Doc/tools/extensions/implementation_detail.py 2025-04-08 13:35:47.000000000 +0200 ++++ Python-3.12.10/Doc/tools/extensions/implementation_detail.py 2025-04-29 22:48:23.397548211 +0200 +@@ -1,17 +1,10 @@ + """Support for marking up implementation details.""" + +-from __future__ import annotations +- +-from typing import TYPE_CHECKING +- + from docutils import nodes + from sphinx.locale import _ as sphinx_gettext + from sphinx.util.docutils import SphinxDirective + +-if TYPE_CHECKING: +- from sphinx.application import Sphinx +- from sphinx.util.typing import ExtensionMetadata +- ++from sphinx.application import Sphinx + + class ImplementationDetail(SphinxDirective): + has_content = True +@@ -21,23 +14,24 @@ + label_text = sphinx_gettext("CPython implementation detail:") + + def run(self): +- self.assert_has_content() +- content_nodes = self.parse_content_to_nodes() ++ container_node = nodes.container() ++ container_node.document = self.state.document # Ensure node has document context ++ self.state.nested_parse(self.content, self.content_offset, container_node) ++ parsed_nodes = container_node.children + + # insert our prefix at the start of the first paragraph +- first_node = content_nodes[0] ++ first_node = parsed_nodes[0] + first_node[:0] = [ + nodes.strong(self.label_text, self.label_text), + nodes.Text(" "), + ] + +- # create a new compound container node +- cnode = nodes.compound("", *content_nodes, classes=["impl-detail"]) ++ cnode = nodes.compound("", *parsed_nodes, classes=["impl-detail"]) + self.set_source_info(cnode) + return [cnode] + + +-def setup(app: Sphinx) -> ExtensionMetadata: ++def setup(app: Sphinx): + app.add_directive("impl-detail", ImplementationDetail) + + return { +Index: Python-3.12.10/Doc/tools/extensions/issue_role.py +=================================================================== +--- Python-3.12.10.orig/Doc/tools/extensions/issue_role.py 2025-04-08 13:35:47.000000000 +0200 ++++ Python-3.12.10/Doc/tools/extensions/issue_role.py 2025-04-29 22:21:55.278961032 +0200 +@@ -1,22 +1,18 @@ + """Support for referencing issues in the tracker.""" + +-from __future__ import annotations +- +-from typing import TYPE_CHECKING ++from typing import TYPE_CHECKING, List, Tuple + + from docutils import nodes + from sphinx.util.docutils import SphinxRole + +-if TYPE_CHECKING: +- from docutils.nodes import Element +- from sphinx.application import Sphinx +- from sphinx.util.typing import ExtensionMetadata ++from docutils.nodes import Element ++from sphinx.application import Sphinx + + + class BPOIssue(SphinxRole): + ISSUE_URI = "https://bugs.python.org/issue?@action=redirect&bpo={0}" + +- def run(self) -> tuple[list[Element], list[nodes.system_message]]: ++ def run(self) -> Tuple[List[Element], List[nodes.system_message]]: + issue = self.text + + # sanity check: there are no bpo issues within these two values +@@ -38,7 +34,7 @@ + class GitHubIssue(SphinxRole): + ISSUE_URI = "https://github.com/python/cpython/issues/{0}" + +- def run(self) -> tuple[list[Element], list[nodes.system_message]]: ++ def run(self) -> Tuple[List[Element], List[nodes.system_message]]: + issue = self.text + + # sanity check: all GitHub issues have ID >= 32426 +@@ -58,7 +54,7 @@ + return [refnode], [] + + +-def setup(app: Sphinx) -> ExtensionMetadata: ++def setup(app: Sphinx) -> "ExtensionMetadata": + app.add_role("issue", BPOIssue()) + app.add_role("gh", GitHubIssue()) + +Index: Python-3.12.10/Doc/tools/extensions/misc_news.py +=================================================================== +--- Python-3.12.10.orig/Doc/tools/extensions/misc_news.py 2025-04-08 13:35:47.000000000 +0200 ++++ Python-3.12.10/Doc/tools/extensions/misc_news.py 2025-04-29 22:11:52.049046825 +0200 +@@ -1,7 +1,5 @@ + """Support for including Misc/NEWS.""" + +-from __future__ import annotations +- + import re + from pathlib import Path + from typing import TYPE_CHECKING +@@ -24,13 +22,13 @@ + +++++++++++ + """ + +-bpo_issue_re: Final[re.Pattern[str]] = re.compile( ++bpo_issue_re: "Final[re.Pattern[str]]" = re.compile( + "(?:issue #|bpo-)([0-9]+)", re.ASCII + ) +-gh_issue_re: Final[re.Pattern[str]] = re.compile( ++gh_issue_re: "Final[re.Pattern[str]]" = re.compile( + "gh-(?:issue-)?([0-9]+)", re.ASCII | re.IGNORECASE + ) +-whatsnew_re: Final[re.Pattern[str]] = re.compile( ++whatsnew_re: "Final[re.Pattern[str]]" = re.compile( + r"^what's new in (.*?)\??$", re.ASCII | re.IGNORECASE | re.MULTILINE + ) + +@@ -42,7 +40,7 @@ + final_argument_whitespace = False + option_spec = {} + +- def run(self) -> list[Node]: ++ def run(self) -> "list[Node]": + # Get content of NEWS file + source, _ = self.get_source_info() + news_file = Path(source).resolve().parent / self.arguments[0] +@@ -54,7 +52,7 @@ + return [nodes.strong(text, text)] + + # remove first 3 lines as they are the main heading +- news_text = news_text.removeprefix(BLURB_HEADER) ++ news_text = news_text[len(BLURB_HEADER):] if news_text.startswith(BLURB_HEADER) else news_text + + news_text = bpo_issue_re.sub(r":issue:`\1`", news_text) + # Fallback handling for GitHub issues +@@ -65,7 +63,7 @@ + return [] + + +-def setup(app: Sphinx) -> ExtensionMetadata: ++def setup(app: "Sphinx") -> "ExtensionMetadata": + app.add_directive("miscnews", MiscNews) + + return { +Index: Python-3.12.10/Doc/tools/extensions/patchlevel.py +=================================================================== +--- Python-3.12.10.orig/Doc/tools/extensions/patchlevel.py 2025-04-08 13:35:47.000000000 +0200 ++++ Python-3.12.10/Doc/tools/extensions/patchlevel.py 2025-04-29 22:11:52.049253068 +0200 +@@ -3,7 +3,7 @@ + import re + import sys + from pathlib import Path +-from typing import Literal, NamedTuple ++from typing import NamedTuple, Tuple + + CPYTHON_ROOT = Path( + __file__, # cpython/Doc/tools/extensions/patchlevel.py +@@ -26,7 +26,7 @@ + major: int #: Major release number + minor: int #: Minor release number + micro: int #: Patch release number +- releaselevel: Literal["alpha", "beta", "candidate", "final"] ++ releaselevel: str + serial: int #: Serial release number + + +@@ -37,7 +37,8 @@ + defines = {} + patchlevel_h = PATCHLEVEL_H.read_text(encoding="utf-8") + for line in patchlevel_h.splitlines(): +- if (m := pat.match(line)) is not None: ++ m = pat.match(line) ++ if m is not None: + name, value = m.groups() + defines[name] = value + +@@ -50,7 +51,7 @@ + ) + + +-def format_version_info(info: version_info) -> tuple[str, str]: ++def format_version_info(info: version_info) -> Tuple[str, str]: + version = f"{info.major}.{info.minor}" + release = f"{info.major}.{info.minor}.{info.micro}" + if info.releaselevel != "final": +Index: Python-3.12.10/Doc/tools/extensions/pydoc_topics.py +=================================================================== +--- Python-3.12.10.orig/Doc/tools/extensions/pydoc_topics.py 2025-04-08 13:35:47.000000000 +0200 ++++ Python-3.12.10/Doc/tools/extensions/pydoc_topics.py 2025-04-29 22:33:59.916893510 +0200 +@@ -1,21 +1,23 @@ + """Support for building "topic help" for pydoc.""" + +-from __future__ import annotations +- + from time import asctime +-from typing import TYPE_CHECKING ++from typing import TYPE_CHECKING, Tuple + + from sphinx.builders.text import TextBuilder + from sphinx.util import logging +-from sphinx.util.display import status_iterator ++try: ++ from sphinx.util.display import status_iterator ++except ModuleNotFoundError: ++ from sphinx.util import status_iterator + from sphinx.util.docutils import new_document + from sphinx.writers.text import TextTranslator + +-if TYPE_CHECKING: ++try: ++ from typing import Sequence, Set ++except ModuleNotFoundError: + from collections.abc import Sequence, Set + +- from sphinx.application import Sphinx +- from sphinx.util.typing import ExtensionMetadata ++from sphinx.application import Sphinx + + logger = logging.getLogger(__name__) + +@@ -161,7 +163,7 @@ + self.outdir.joinpath("topics.py").write_text(topics, encoding="utf-8") + + +-def _display_labels(item: tuple[str, Sequence[tuple[str, str]]]) -> str: ++def _display_labels(item: Tuple[str, Sequence[Tuple[str, str]]]) -> str: + _docname, label_ids = item + labels = [name for name, _id in label_ids] + if len(labels) > 4: +@@ -169,7 +171,7 @@ + return ", ".join(labels) + + +-def _repr(text: str, /) -> str: ++def _repr(text: str) -> str: + """Return a triple-single-quoted representation of text.""" + if "'''" not in text: + return f"r'''{text}'''" +@@ -177,7 +179,7 @@ + return f"'''{text}'''" + + +-def setup(app: Sphinx) -> ExtensionMetadata: ++def setup(app: Sphinx) -> "ExtensionMetadata": + app.add_builder(PydocTopicsBuilder) + + return { diff --git a/docs-docutils_014-Sphinx_420.patch b/docs-docutils_014-Sphinx_420.patch new file mode 100644 index 0000000..664d553 --- /dev/null +++ b/docs-docutils_014-Sphinx_420.patch @@ -0,0 +1,45 @@ +--- + Doc/tools/extensions/c_annotations.py | 6 +++++- + Doc/tools/extensions/glossary_search.py | 12 ++++++++++-- + 2 files changed, 15 insertions(+), 3 deletions(-) + +Index: Python-3.12.10/Doc/tools/extensions/c_annotations.py +=================================================================== +--- Python-3.12.10.orig/Doc/tools/extensions/c_annotations.py 2025-04-08 13:35:47.000000000 +0200 ++++ Python-3.12.10/Doc/tools/extensions/c_annotations.py 2025-04-11 21:16:39.007011463 +0200 +@@ -117,7 +117,11 @@ + state = app.env.domaindata["c_annotations"] + refcount_data = state["refcount_data"] + stable_abi_data = state["stable_abi_data"] +- for node in doctree.findall(addnodes.desc_content): ++ try: ++ findall = doctree.findall ++ except AttributeError: ++ findall = doctree.traverse ++ for node in findall(addnodes.desc_content): + par = node.parent + if par["domain"] != "c": + continue +Index: Python-3.12.10/Doc/tools/extensions/glossary_search.py +=================================================================== +--- Python-3.12.10.orig/Doc/tools/extensions/glossary_search.py 2025-04-08 13:35:47.000000000 +0200 ++++ Python-3.12.10/Doc/tools/extensions/glossary_search.py 2025-04-11 21:16:39.007340209 +0200 +@@ -30,8 +30,16 @@ + else: + terms = app.env.glossary_terms = {} + +- for node in doctree.findall(glossary): +- for glossary_item in node.findall(nodes.definition_list_item): ++ try: ++ findall = doctree.findall ++ except AttributeError: ++ findall = doctree.traverse ++ for node in findall(glossary): ++ try: ++ node_findall = node.findall ++ except AttributeError: ++ node_findall = node.traverse ++ for glossary_item in node_findall(nodes.definition_list_item): + term = glossary_item[0].astext() + definition = glossary_item[-1] + diff --git a/externally_managed.in b/externally_managed.in new file mode 100644 index 0000000..54606b6 --- /dev/null +++ b/externally_managed.in @@ -0,0 +1,12 @@ +[externally-managed] +Error=To install Python packages system-wide, try + zypper install __PYTHONPREFIX__-xyz, where xyz is the package + you are trying to install. + + If you wish to install a non-rpm packaged Python package, + create a virtual environment using __PYTHON__ -m venv path/to/venv. + Then use path/to/venv/bin/python and path/to/venv/bin/pip. + + If you wish to install a non-rpm packaged Python application, + it may be easiest to use `pipx install xyz`, which will manage a + virtual environment for you. Install pipx via `zypper install __PYTHONPREFIX__-pipx` . diff --git a/fix-test-recursion-limit-15.6.patch b/fix-test-recursion-limit-15.6.patch new file mode 100644 index 0000000..adcacce --- /dev/null +++ b/fix-test-recursion-limit-15.6.patch @@ -0,0 +1,32 @@ +--- + Lib/test/test_compile.py | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/Lib/test/test_compile.py ++++ b/Lib/test/test_compile.py +@@ -14,6 +14,9 @@ from test.support import (script_helper, + requires_specialization, C_RECURSION_LIMIT) + from test.support.os_helper import FakePath + ++IS_SLE_15_6 = os.environ.get("SLE_VERSION", "") == "0150600" ++IS_32bit = hasattr(os, "uname") and os.uname().machine in ["i386", "i486", "i586", "i686"] ++ + class TestSpecifics(unittest.TestCase): + + def compile_single(self, source): +@@ -110,6 +113,7 @@ class TestSpecifics(unittest.TestCase): + self.assertEqual(d['z'], 12) + + @unittest.skipIf(support.is_wasi, "exhausts limited stack on WASI") ++ @unittest.skipIf(IS_SLE_15_6 and IS_32bit, "fails on 15.6 i586") + def test_extended_arg(self): + repeat = int(C_RECURSION_LIMIT * 0.9) + longexpr = 'x = x or ' + '-x' * repeat +@@ -603,6 +607,7 @@ class TestSpecifics(unittest.TestCase): + + @support.cpython_only + @unittest.skipIf(support.is_wasi, "exhausts limited stack on WASI") ++ @unittest.skipIf(IS_SLE_15_6 and IS_32bit, "fails on 15.6 i586") + def test_compiler_recursion_limit(self): + # Expected limit is C_RECURSION_LIMIT * 2 + # Duplicating the limit here is a little ugly. diff --git a/fix_configure_rst.patch b/fix_configure_rst.patch new file mode 100644 index 0000000..cacfcc3 --- /dev/null +++ b/fix_configure_rst.patch @@ -0,0 +1,32 @@ +--- + Doc/using/configure.rst | 2 -- + Misc/NEWS | 2 +- + 2 files changed, 1 insertion(+), 3 deletions(-) + +--- a/Doc/using/configure.rst ++++ b/Doc/using/configure.rst +@@ -640,13 +640,11 @@ macOS Options + + See ``Mac/README.rst``. + +-.. option:: --enable-universalsdk + .. option:: --enable-universalsdk=SDKDIR + + Create a universal binary build. *SDKDIR* specifies which macOS SDK should + be used to perform the build (default is no). + +-.. option:: --enable-framework + .. option:: --enable-framework=INSTALLDIR + + Create a Python.framework rather than a traditional Unix install. Optional +--- a/Misc/NEWS ++++ b/Misc/NEWS +@@ -15146,7 +15146,7 @@ C API + - bpo-40939: Removed documentation for the removed ``PyParser_*`` C API. + + - bpo-43795: The list in :ref:`limited-api-list` now shows the public name +- :c:struct:`PyFrameObject` rather than ``_frame``. The non-existing entry ++ :c:type:`PyFrameObject` rather than ``_frame``. The non-existing entry + ``_node`` no longer appears in the list. + + - bpo-44378: :c:func:`Py_IS_TYPE` no longer uses :c:func:`Py_TYPE` to avoid diff --git a/gh139257-Support-docutils-0.22.patch b/gh139257-Support-docutils-0.22.patch new file mode 100644 index 0000000..d990cd1 --- /dev/null +++ b/gh139257-Support-docutils-0.22.patch @@ -0,0 +1,36 @@ +From 19b61747df3d62c822285c488753d6fbdf91e3ac Mon Sep 17 00:00:00 2001 +From: Daniel Garcia Moreno +Date: Tue, 23 Sep 2025 10:20:16 +0200 +Subject: [PATCH 1/2] gh-139257: Support docutils >= 0.22 + +--- + Doc/tools/extensions/pyspecific.py | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +Index: Python-3.12.11/Doc/tools/extensions/pyspecific.py +=================================================================== +--- Python-3.12.11.orig/Doc/tools/extensions/pyspecific.py 2025-06-03 17:41:47.000000000 +0200 ++++ Python-3.12.11/Doc/tools/extensions/pyspecific.py 2025-09-30 18:16:55.089412381 +0200 +@@ -25,11 +25,21 @@ + SOURCE_URI = 'https://github.com/python/cpython/tree/3.12/%s' + + # monkey-patch reST parser to disable alphabetic and roman enumerated lists ++def _disable_alphabetic_and_roman(text): ++ try: ++ # docutils >= 0.22 ++ from docutils.parsers.rst.states import InvalidRomanNumeralError ++ raise InvalidRomanNumeralError(text) ++ except ImportError: ++ # docutils < 0.22 ++ return None ++ ++ + from docutils.parsers.rst.states import Body + Body.enum.converters['loweralpha'] = \ + Body.enum.converters['upperalpha'] = \ + Body.enum.converters['lowerroman'] = \ +- Body.enum.converters['upperroman'] = lambda x: None ++ Body.enum.converters['upperroman'] = _disable_alphabetic_and_roman + + + class PyAwaitableMixin(object): diff --git a/idle3.appdata.xml b/idle3.appdata.xml new file mode 100644 index 0000000..b494f1e --- /dev/null +++ b/idle3.appdata.xml @@ -0,0 +1,51 @@ + + + + org.python.IDLE3 + idle3.desktop + + IDLE3 + Python 3 Integrated Development and Learning Environment + + +

+ IDLE is Python’s Integrated Development and Learning Environment. + The GUI is uniform between Windows, Unix, and macOS. + IDLE provides an easy way to start writing, running, and debugging + Python code. +

+

+ IDLE is written in pure Python, and uses the tkinter GUI toolkit. + It provides: +

+
    +
  • a Python shell window (interactive interpreter) with colorizing of code input, output, and error messages,
  • +
  • a multi-window text editor with multiple undo, Python colorizing, smart indent, call tips, auto completion, and other features,
  • +
  • search within any window, replace within editor windows, and search through multiple files (grep),
  • +
  • a debugger with persistent breakpoints, stepping, and viewing of global and local namespaces.
  • +
+
+ + + Python Software Foundation + + + https://docs.python.org/3/library/idle.html + + + + https://in.waw.pl/~zbyszek/fedora/idle3-appdata/idle3-main-window.png + + + https://in.waw.pl/~zbyszek/fedora/idle3-appdata/idle3-class-browser.png + + + https://in.waw.pl/~zbyszek/fedora/idle3-appdata/idle3-code-viewer.png + + + + Python-2.0 + CC0-1.0 + zbyszek@in.waw.pl +
+ diff --git a/idle3.desktop b/idle3.desktop new file mode 100644 index 0000000..43f5a4c --- /dev/null +++ b/idle3.desktop @@ -0,0 +1,12 @@ +[Desktop Entry] +Version=1.0 +Name=IDLE 3 +GenericName=Python 3 IDE +Comment=Python 3 Integrated Development and Learning Environment +Exec=idle3 %F +TryExec=idle3 +Terminal=false +Type=Application +Icon=idle3 +Categories=Development;IDE; +MimeType=text/x-python; diff --git a/import_failed.map b/import_failed.map new file mode 100644 index 0000000..7cba163 --- /dev/null +++ b/import_failed.map @@ -0,0 +1,7 @@ +python312-curses: curses _curses +python312-dbm: dbm _dbm _gdbm +python312-idle: idlelib +python312-testsuite: test _ctypes_test _testbuffer _testcapi _testclinic _testinternalcapi _testimportmultiple _testmultiphase _testsinglephase _xxinterpchannels _xxtestfuzz +python312-tk: tkinter _tkinter +python312-tools: turtledemo +python312: sqlite3 readline _sqlite3 nis diff --git a/import_failed.py b/import_failed.py new file mode 100644 index 0000000..258b5a5 --- /dev/null +++ b/import_failed.py @@ -0,0 +1,23 @@ +import sys, os +from sysconfig import get_path + +failed_map_path = os.path.join(get_path('stdlib'), '_import_failed', 'import_failed.map') + +if __spec__: + failed_name = __spec__.name +else: + failed_name = __name__ + +with open(failed_map_path) as fd: + for line in fd: + package = line.split(':')[0] + imports = line.split(':')[1] + if failed_name in imports: + raise ImportError(f"""Module '{failed_name}' is not installed. +Use: + sudo zypper install {package} +to install it.""") + +raise ImportError(f"""Module '{failed_name}' is not installed. +It is supposed to be part of python3 distribution, but missing from failed import map. +Please file a bug on the SUSE Bugzilla.""") diff --git a/macros.python3 b/macros.python3 new file mode 100644 index 0000000..2bd193b --- /dev/null +++ b/macros.python3 @@ -0,0 +1,28 @@ +%have_python3 1 + +# commented out legacy macro definitions +#py3_prefix /usr +#py3_incdir /usr/include/python3.5m +#py3_ver 3.5 + +# these should now be provided by macros.python_all +#python3_sitearch /usr/lib64/python3.5/site-packages +#python3_sitelib /usr/lib/python3.5/site-packages +#python3_version 3.5 + +# hard to say if anyone ever used these? +#py3_soflags cpython-35m-x86_64-linux-gnu +#py3_abiflags m +%cpython3_soabi %(python3 -c "import sysconfig; print(sysconfig.get_config_var('SOABI'))") +%py3_soflags %cpython3_soabi + +# compilation macros that might be in use somewhere +%py3_compile(O) \ +find %1 -name '*.pyc' -exec rm -f {} ";"\ +python3 -c "import sys, os, compileall; br='%{buildroot}'; compileall.compile_dir(sys.argv[1], ddir=br and (sys.argv[1][len(os.path.abspath(br)):]+'/') or None)" %1\ +%{-O:\ +find %1 -name '*.pyo' -exec rm -f {} ";"\ +python3 -O -c "import sys, os, compileall; br='%{buildroot}'; compileall.compile_dir(sys.argv[1], ddir=br and (sys.argv[1][len(os.path.abspath(br)):]+'/') or None)" %1\ +} + + diff --git a/no-skipif-doctests.patch b/no-skipif-doctests.patch new file mode 100644 index 0000000..2020707 --- /dev/null +++ b/no-skipif-doctests.patch @@ -0,0 +1,647 @@ +only in patch2: +unchanged: +--- + Doc/library/turtle.rst | 81 ------------------------------------------------- + 1 file changed, 81 deletions(-) + +Index: Python-3.12.2/Doc/library/turtle.rst +=================================================================== +--- Python-3.12.2.orig/Doc/library/turtle.rst ++++ Python-3.12.2/Doc/library/turtle.rst +@@ -441,7 +441,6 @@ Turtle motion + turtle is headed. + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle.position() + (0.00,0.00) +@@ -468,7 +467,6 @@ Turtle motion + >>> turtle.goto(0, 0) + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle.position() + (0.00,0.00) +@@ -487,13 +485,11 @@ Turtle motion + orientation depends on the turtle mode, see :func:`mode`. + + .. doctest:: +- :skipif: _tkinter is None + :hide: + + >>> turtle.setheading(22) + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle.heading() + 22.0 +@@ -512,13 +508,11 @@ Turtle motion + orientation depends on the turtle mode, see :func:`mode`. + + .. doctest:: +- :skipif: _tkinter is None + :hide: + + >>> turtle.setheading(22) + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle.heading() + 22.0 +@@ -541,13 +535,11 @@ Turtle motion + not change the turtle's orientation. + + .. doctest:: +- :skipif: _tkinter is None + :hide: + + >>> turtle.goto(0, 0) + + .. doctest:: +- :skipif: _tkinter is None + + >>> tp = turtle.pos() + >>> tp +@@ -609,13 +601,11 @@ Turtle motion + unchanged. + + .. doctest:: +- :skipif: _tkinter is None + :hide: + + >>> turtle.goto(0, 240) + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle.position() + (0.00,240.00) +@@ -631,13 +621,11 @@ Turtle motion + Set the turtle's second coordinate to *y*, leave first coordinate unchanged. + + .. doctest:: +- :skipif: _tkinter is None + :hide: + + >>> turtle.goto(0, 40) + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle.position() + (0.00,40.00) +@@ -664,7 +652,6 @@ Turtle motion + =================== ==================== + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle.setheading(90) + >>> turtle.heading() +@@ -677,14 +664,12 @@ Turtle motion + its start-orientation (which depends on the mode, see :func:`mode`). + + .. doctest:: +- :skipif: _tkinter is None + :hide: + + >>> turtle.setheading(90) + >>> turtle.goto(0, -10) + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle.heading() + 90.0 +@@ -716,7 +701,6 @@ Turtle motion + calculated automatically. May be used to draw regular polygons. + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle.home() + >>> turtle.position() +@@ -745,7 +729,6 @@ Turtle motion + + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle.home() + >>> turtle.dot() +@@ -763,7 +746,6 @@ Turtle motion + it by calling ``clearstamp(stamp_id)``. + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle.color("blue") + >>> stamp_id = turtle.stamp() +@@ -778,7 +760,6 @@ Turtle motion + Delete stamp with given *stampid*. + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle.position() + (150.00,-0.00) +@@ -816,7 +797,6 @@ Turtle motion + undo actions is determined by the size of the undobuffer. + + .. doctest:: +- :skipif: _tkinter is None + + >>> for i in range(4): + ... turtle.fd(50); turtle.lt(80) +@@ -849,7 +829,6 @@ Turtle motion + turtle turn instantly. + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle.speed() + 3 +@@ -870,7 +849,6 @@ Tell Turtle's state + Return the turtle's current location (x,y) (as a :class:`Vec2D` vector). + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle.pos() + (440.00,-0.00) +@@ -886,7 +864,6 @@ Tell Turtle's state + orientation which depends on the mode - "standard"/"world" or "logo". + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle.goto(10, 10) + >>> turtle.towards(0,0) +@@ -898,7 +875,6 @@ Tell Turtle's state + Return the turtle's x coordinate. + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle.home() + >>> turtle.left(50) +@@ -914,7 +890,6 @@ Tell Turtle's state + Return the turtle's y coordinate. + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle.home() + >>> turtle.left(60) +@@ -931,7 +906,6 @@ Tell Turtle's state + :func:`mode`). + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle.home() + >>> turtle.left(67) +@@ -948,7 +922,6 @@ Tell Turtle's state + other turtle, in turtle step units. + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle.home() + >>> turtle.distance(30,40) +@@ -972,7 +945,6 @@ Settings for measurement + Default value is 360 degrees. + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle.home() + >>> turtle.left(90) +@@ -995,7 +967,6 @@ Settings for measurement + ``degrees(2*math.pi)``. + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle.home() + >>> turtle.left(90) +@@ -1006,7 +977,6 @@ Settings for measurement + 1.5707963267948966 + + .. doctest:: +- :skipif: _tkinter is None + :hide: + + >>> turtle.degrees(360) +@@ -1042,7 +1012,6 @@ Drawing state + thickness. If no argument is given, the current pensize is returned. + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle.pensize() + 1 +@@ -1074,7 +1043,6 @@ Drawing state + attributes in one statement. + + .. doctest:: +- :skipif: _tkinter is None + :options: +NORMALIZE_WHITESPACE + + >>> turtle.pen(fillcolor="black", pencolor="red", pensize=10) +@@ -1097,7 +1065,6 @@ Drawing state + Return ``True`` if pen is down, ``False`` if it's up. + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle.penup() + >>> turtle.isdown() +@@ -1138,7 +1105,6 @@ Color control + newly set pencolor. + + .. doctest:: +- :skipif: _tkinter is None + + >>> colormode() + 1.0 +@@ -1187,7 +1153,6 @@ Color control + with the newly set fillcolor. + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle.fillcolor("violet") + >>> turtle.fillcolor() +@@ -1226,7 +1191,6 @@ Color control + with the newly set colors. + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle.color("red", "green") + >>> turtle.color() +@@ -1243,7 +1207,6 @@ Filling + ~~~~~~~ + + .. doctest:: +- :skipif: _tkinter is None + :hide: + + >>> turtle.home() +@@ -1253,7 +1216,6 @@ Filling + Return fillstate (``True`` if filling, ``False`` else). + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle.begin_fill() + >>> if turtle.filling(): +@@ -1278,7 +1240,6 @@ Filling + above may be either all yellow or have some white regions. + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle.color("black", "red") + >>> turtle.begin_fill() +@@ -1295,7 +1256,6 @@ More drawing control + variables to the default values. + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle.goto(0,-22) + >>> turtle.left(100) +@@ -1346,7 +1306,6 @@ Visibility + drawing observably. + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle.hideturtle() + +@@ -1357,7 +1316,6 @@ Visibility + Make the turtle visible. + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle.showturtle() + +@@ -1388,7 +1346,6 @@ Appearance + deal with shapes see Screen method :func:`register_shape`. + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle.shape() + 'classic' +@@ -1414,7 +1371,6 @@ Appearance + ``resizemode("user")`` is called by :func:`shapesize` when used with arguments. + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle.resizemode() + 'noresize' +@@ -1438,7 +1394,6 @@ Appearance + of the shape's outline. + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle.shapesize() + (1.0, 1.0, 1) +@@ -1463,7 +1418,6 @@ Appearance + heading of the turtle are sheared. + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle.shape("circle") + >>> turtle.shapesize(5,2) +@@ -1480,7 +1434,6 @@ Appearance + change the turtle's heading (direction of movement). + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle.reset() + >>> turtle.shape("circle") +@@ -1526,7 +1479,6 @@ Appearance + turtle (its direction of movement). + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle.reset() + >>> turtle.shape("circle") +@@ -1555,7 +1507,6 @@ Appearance + given matrix. + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle = Turtle() + >>> turtle.shape("square") +@@ -1571,7 +1522,6 @@ Appearance + can be used to define a new shape or components of a compound shape. + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle.shape("square") + >>> turtle.shapetransform(4, -1, 0, 2) +@@ -1596,7 +1546,6 @@ Using events + procedural way: + + .. doctest:: +- :skipif: _tkinter is None + + >>> def turn(x, y): + ... left(180) +@@ -1617,7 +1566,6 @@ Using events + ``None``, existing bindings are removed. + + .. doctest:: +- :skipif: _tkinter is None + + >>> class MyTurtle(Turtle): + ... def glow(self,x,y): +@@ -1645,7 +1593,6 @@ Using events + mouse-click event on that turtle. + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle.ondrag(turtle.goto) + +@@ -1673,7 +1620,6 @@ Special Turtle methods + Return the last recorded polygon. + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle.home() + >>> turtle.begin_poly() +@@ -1693,7 +1639,6 @@ Special Turtle methods + turtle properties. + + .. doctest:: +- :skipif: _tkinter is None + + >>> mick = Turtle() + >>> joe = mick.clone() +@@ -1706,7 +1651,6 @@ Special Turtle methods + return the "anonymous turtle": + + .. doctest:: +- :skipif: _tkinter is None + + >>> pet = getturtle() + >>> pet.fd(50) +@@ -1720,7 +1664,6 @@ Special Turtle methods + TurtleScreen methods can then be called for that object. + + .. doctest:: +- :skipif: _tkinter is None + + >>> ts = turtle.getscreen() + >>> ts +@@ -1738,7 +1681,6 @@ Special Turtle methods + ``None``, the undobuffer is disabled. + + .. doctest:: +- :skipif: _tkinter is None + + >>> turtle.setundobuffer(42) + +@@ -1748,7 +1690,6 @@ Special Turtle methods + Return number of entries in the undobuffer. + + .. doctest:: +- :skipif: _tkinter is None + + >>> while undobufferentries(): + ... undo() +@@ -1771,7 +1712,6 @@ below: + For example: + + .. doctest:: +- :skipif: _tkinter is None + + >>> s = Shape("compound") + >>> poly1 = ((0,0),(10,-5),(0,10),(-10,-5)) +@@ -1782,7 +1722,6 @@ below: + 3. Now add the Shape to the Screen's shapelist and use it: + + .. doctest:: +- :skipif: _tkinter is None + + >>> register_shape("myshape", s) + >>> shape("myshape") +@@ -1802,7 +1741,6 @@ Most of the examples in this section ref + ``screen``. + + .. doctest:: +- :skipif: _tkinter is None + :hide: + + >>> screen = Screen() +@@ -1819,7 +1757,6 @@ Window control + Set or return background color of the TurtleScreen. + + .. doctest:: +- :skipif: _tkinter is None + + >>> screen.bgcolor("orange") + >>> screen.bgcolor() +@@ -1911,7 +1848,6 @@ Window control + distorted. + + .. doctest:: +- :skipif: _tkinter is None + + >>> screen.reset() + >>> screen.setworldcoordinates(-50,-7.5,50,7.5) +@@ -1922,7 +1858,6 @@ Window control + ... left(45); fd(2) # a regular octagon + + .. doctest:: +- :skipif: _tkinter is None + :hide: + + >>> screen.reset() +@@ -1944,7 +1879,6 @@ Animation control + Optional argument: + + .. doctest:: +- :skipif: _tkinter is None + + >>> screen.delay() + 10 +@@ -1966,7 +1900,6 @@ Animation control + :func:`delay`). + + .. doctest:: +- :skipif: _tkinter is None + + >>> screen.tracer(8, 25) + >>> dist = 2 +@@ -2003,7 +1936,6 @@ Using screen events + must have the focus. (See method :func:`listen`.) + + .. doctest:: +- :skipif: _tkinter is None + + >>> def f(): + ... fd(50) +@@ -2024,7 +1956,6 @@ Using screen events + must have focus. (See method :func:`listen`.) + + .. doctest:: +- :skipif: _tkinter is None + + >>> def f(): + ... fd(50) +@@ -2049,7 +1980,6 @@ Using screen events + named ``turtle``: + + .. doctest:: +- :skipif: _tkinter is None + + >>> screen.onclick(turtle.goto) # Subsequently clicking into the TurtleScreen will + >>> # make the turtle move to the clicked point. +@@ -2069,7 +1999,6 @@ Using screen events + Install a timer that calls *fun* after *t* milliseconds. + + .. doctest:: +- :skipif: _tkinter is None + + >>> running = True + >>> def f(): +@@ -2151,7 +2080,6 @@ Settings and special methods + ============ ========================= =================== + + .. doctest:: +- :skipif: _tkinter is None + + >>> mode("logo") # resets turtle heading to north + >>> mode() +@@ -2166,7 +2094,6 @@ Settings and special methods + values of color triples have to be in the range 0..*cmode*. + + .. doctest:: +- :skipif: _tkinter is None + + >>> screen.colormode(1) + >>> turtle.pencolor(240, 160, 80) +@@ -2187,7 +2114,6 @@ Settings and special methods + do with a Tkinter Canvas. + + .. doctest:: +- :skipif: _tkinter is None + + >>> cv = screen.getcanvas() + >>> cv +@@ -2199,7 +2125,6 @@ Settings and special methods + Return a list of names of all currently available turtle shapes. + + .. doctest:: +- :skipif: _tkinter is None + + >>> screen.getshapes() + ['arrow', 'blank', 'circle', ..., 'turtle'] +@@ -2223,7 +2148,6 @@ Settings and special methods + coordinates: Install the corresponding polygon shape. + + .. doctest:: +- :skipif: _tkinter is None + + >>> screen.register_shape("triangle", ((5,-3), (0,5), (-5,-3))) + +@@ -2239,7 +2163,6 @@ Settings and special methods + Return the list of turtles on the screen. + + .. doctest:: +- :skipif: _tkinter is None + + >>> for turtle in screen.turtles(): + ... turtle.color("red") +@@ -2301,7 +2224,6 @@ Methods specific to Screen, not inherite + center window vertically + + .. doctest:: +- :skipif: _tkinter is None + + >>> screen.setup (width=200, height=200, startx=0, starty=0) + >>> # sets window to 200x200 pixels, in upper left of screen +@@ -2317,7 +2239,6 @@ Methods specific to Screen, not inherite + Set title of turtle window to *titlestring*. + + .. doctest:: +- :skipif: _tkinter is None + + >>> screen.title("Welcome to the turtle zoo!") + +@@ -2388,7 +2309,6 @@ Public classes + Example: + + .. doctest:: +- :skipif: _tkinter is None + + >>> poly = ((0,0),(10,-5),(0,10),(-10,-5)) + >>> s = Shape("compound") +@@ -2774,7 +2694,6 @@ Changes since Python 3.0 + + + .. doctest:: +- :skipif: _tkinter is None + :hide: + + >>> for turtle in turtles(): diff --git a/pre_checkin.sh b/pre_checkin.sh new file mode 100644 index 0000000..a2cf992 --- /dev/null +++ b/pre_checkin.sh @@ -0,0 +1,78 @@ +#!/bin/bash + +export LC_ALL=C + +master=python*.spec + +# create import_failed.map from package definitions +pkgname=$(grep python_pkg_name $master |grep define |awk -F' ' '{print $3}') +MAPFILE=import_failed.map +function new_map_line () { + package=$1 + package=$(echo $1 |sed -e "s:%{python_pkg_name}:$pkgname:") + modules=$2 + if [ -z "$package" -o -z "$modules" ]; then + return + fi + if [[ "$package" =~ "-base" ]]; then + return + fi + echo "$package:$modules" >> $MAPFILE.tmp +} + +for spec in *.spec; do + basename=${spec%.spec} + package= + modules= + while read line; do + case $line in + "%files -n "*) + new_map_line $package "$modules" + package=${line#"%files -n "} + modules= + ;; + "%files "*) + new_map_line $package "$modules" + package=$basename-${line#"%files "} + modules= + ;; + "%files") + new_map_line $package "$modules" + package=$basename + modules= + ;; + "%{sitedir}/config-"*) + # ignore + ;; + "%{sitedir}/"*) + word=${line#"%{sitedir}/"} + if ! echo $word | grep -q /; then + modules="$modules $word" + fi + ;; + "%{dynlib "*"}") + word=${line#"%{dynlib "} + word=${word%"}"} + modules="$modules $word" + ;; + esac + done < $spec + new_map_line $package "$modules" +done + +cat $MAPFILE.tmp |sort -u > $MAPFILE +rm $MAPFILE.tmp + +# run test inclusion check +tar xJf Python-*.xz +python3 skipped_tests.py + +# generate baselibs.conf +VERSION=$(grep ^Version $master|awk -F':' '{print $2}' |sed -e 's/ //g') +python_version=${VERSION:0:3} # 3.3 +python_version_abitag=${python_version//./} # 33 +python_version_soname=${python_version//./_} # 3_3 +echo "$pkgname-base" > baselibs.conf +echo "$pkgname" >> baselibs.conf +echo "libpython$python_version_soname-1_0" >> baselibs.conf + diff --git a/python-3.3.0b1-fix_date_time_compiler.patch b/python-3.3.0b1-fix_date_time_compiler.patch new file mode 100644 index 0000000..43bb625 --- /dev/null +++ b/python-3.3.0b1-fix_date_time_compiler.patch @@ -0,0 +1,27 @@ +--- + Makefile.pre.in | 7 +++++++ + 1 file changed, 7 insertions(+) + +Index: Python-3.12.4/Makefile.pre.in +=================================================================== +--- Python-3.12.4.orig/Makefile.pre.in ++++ Python-3.12.4/Makefile.pre.in +@@ -1337,11 +1337,18 @@ Modules/getbuildinfo.o: $(PARSER_OBJS) \ + $(DTRACE_OBJS) \ + $(srcdir)/Modules/getbuildinfo.c + $(CC) -c $(PY_CORE_CFLAGS) \ ++ -DDATE="\"`date -u -r Makefile.pre.in +"%b %d %Y"`\"" \ ++ -DTIME="\"`date -u -r Makefile.pre.in +"%T"`\"" \ + -DGITVERSION="\"`LC_ALL=C $(GITVERSION)`\"" \ + -DGITTAG="\"`LC_ALL=C $(GITTAG)`\"" \ + -DGITBRANCH="\"`LC_ALL=C $(GITBRANCH)`\"" \ + -o $@ $(srcdir)/Modules/getbuildinfo.c + ++Python/getcompiler.o: $(srcdir)/Python/getcompiler.c Makefile ++ $(CC) -c $(PY_CORE_CFLAGS) \ ++ -DCOMPILER='"[GCC]"' \ ++ -o $@ $(srcdir)/Python/getcompiler.c ++ + Modules/getpath.o: $(srcdir)/Modules/getpath.c Python/frozen_modules/getpath.h Makefile $(PYTHON_HEADERS) + $(CC) -c $(PY_CORE_CFLAGS) -DPYTHONPATH='"$(PYTHONPATH)"' \ + -DPREFIX='"$(prefix)"' \ diff --git a/python-3.3.0b1-localpath.patch b/python-3.3.0b1-localpath.patch new file mode 100644 index 0000000..69174fb --- /dev/null +++ b/python-3.3.0b1-localpath.patch @@ -0,0 +1,13 @@ +Index: Python-3.12.2/Lib/site.py +=================================================================== +--- Python-3.12.2.orig/Lib/site.py ++++ Python-3.12.2/Lib/site.py +@@ -77,7 +77,7 @@ import io + import stat + + # Prefixes for site-packages; add additional prefixes like /usr/local here +-PREFIXES = [sys.prefix, sys.exec_prefix] ++PREFIXES = [sys.prefix, sys.exec_prefix, '/usr/local'] + # Enable per user site-packages directory + # set it to False to disable the feature or True to force the feature + ENABLE_USER_SITE = None diff --git a/python.keyring b/python.keyring new file mode 100644 index 0000000..93baed9 --- /dev/null +++ b/python.keyring @@ -0,0 +1,78 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +=J6BY +-----END PGP PUBLIC KEY BLOCK----- diff --git a/python312-rpmlintrc b/python312-rpmlintrc new file mode 100644 index 0000000..5b35f34 --- /dev/null +++ b/python312-rpmlintrc @@ -0,0 +1,3 @@ +addFilter("pem-certificate.*/usr/lib.*/python.*/test/*.pem") +addFilter("devel-file-in-non-devel-package.*/usr/lib.*/python.*/tests/*.c") +addFilter("devel-file-in-non-devel-package.*/usr/lib.*/python.*/test/*.cpp") diff --git a/python312.changes b/python312.changes new file mode 100644 index 0000000..0db2121 --- /dev/null +++ b/python312.changes @@ -0,0 +1,7314 @@ +------------------------------------------------------------------- +Wed Oct 15 09:10:21 UTC 2025 - Daniel Garcia + +- Update to 3.12.12: + - Tools/Demos + - gh-139330: SBOM generation tool didn’t cross-check the version + and checksum values against the Modules/expat/refresh.sh script, + leading to the values becoming out-of-date during routine + updates. + - Security + - gh-139700: Check consistency of the zip64 end of central + directory record. Support records with “zip64 extensible data” + if there are no bytes prepended to the ZIP file. + - gh-139400: xml.parsers.expat: Make sure that parent Expat + parsers are only garbage-collected once they are no longer + referenced by subparsers created by + ExternalEntityParserCreate(). Patch by Sebastian Pipping. + - gh-135661: Fix parsing start and end tags in + html.parser.HTMLParser according to the HTML5 standard. + * Whitespaces no longer accepted between does not end the script section. + * Vertical tabulation (\v) and non-ASCII whitespaces no longer + recognized as whitespaces. The only whitespaces are \t\n\r\f + and space. + * Null character (U+0000) no longer ends the tag name. + * Attributes and slashes after the tag name in end tags are now + ignored, instead of terminating after the first > in quoted + attribute value. E.g. . + * Multiple slashes and whitespaces between the last attribute + and closing > are now ignored in both start and end tags. E.g. +
. + * Multiple = between attribute name and value are no longer + collapsed. E.g. produces attribute “foo” with + value “=bar”. + - gh-135661: Fix CDATA section parsing in html.parser.HTMLParser + according to the HTML5 standard: ] ]> and ]] > no longer end the + CDATA section. Add private method _set_support_cdata() which can + be used to specify how to parse <[CDATA[ — as a CDATA section in + foreign content (SVG or MathML) or as a bogus comment in the + HTML namespace. + - gh-102555: Fix comment parsing in html.parser.HTMLParser + according to the HTML5 standard. --!> now ends the comment. -- > + no longer ends the comment. Support abnormally ended empty + comments <--> and <--->. + - gh-135462: Fix quadratic complexity in processing specially + crafted input in html.parser.HTMLParser. End-of-file errors are + now handled according to the HTML5 specs – comments and + declarations are automatically closed, tags are ignored. + - gh-118350: Fix support of escapable raw text mode (elements + “textarea” and “title”) in html.parser.HTMLParser. + - gh-86155: html.parser.HTMLParser.close() no longer loses data + when the