Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-pystache for openSUSE:Leap:16.0 checked in at 2025-07-24 08:31:12 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Leap:16.0/python-pystache (Old) and /work/SRC/openSUSE:Leap:16.0/.python-pystache.new.8875 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-pystache" Thu Jul 24 08:31:12 2025 rev:2 rq:1293734 version:0.6.8 Changes: -------- --- /work/SRC/openSUSE:Leap:16.0/python-pystache/python-pystache.changes 2025-03-19 11:55:42.996355582 +0100 +++ /work/SRC/openSUSE:Leap:16.0/.python-pystache.new.8875/python-pystache.changes 2025-07-24 08:31:34.907255320 +0200 @@ -1,0 +2,27 @@ +Fri Jun 27 14:52:00 UTC 2025 - Markéta Machová <mmach...@suse.com> + +- Convert to libalternatives + +------------------------------------------------------------------- +Thu Jun 26 12:52:01 UTC 2025 - John Paul Adrian Glaubitz <adrian.glaub...@suse.com> + +- Update to 0.6.8 + * pystache has been stable and out of beta a long time, + update config to reflect by @bakert in (#36) + * feat: Supply ParsingError with additional information + by @mykola-mokhnach-parloa in (#37) + +------------------------------------------------------------------- +Fri Jan 10 12:16:29 UTC 2025 - John Paul Adrian Glaubitz <adrian.glaub...@suse.com> + +- Update to 0.6.7 + * fix: Fail on unmatched tags. +- from version 0.6.6 + * Update README to match supported versions. + * Update pre-commit. + * Update pyproject.toml with 3.12 and 3.13 Python versions. + * Update tox config to use Python 3.12 and 3.13 versions. + * Update yml files with Python 3.12 and 3.13. + * Update changelog for v0.6.5 a bit belatedly. + +------------------------------------------------------------------- Old: ---- pystache-0.6.5.tar.gz New: ---- pystache-0.6.8.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-pystache.spec ++++++ --- /var/tmp/diff_new_pack.IV0RFK/_old 2025-07-24 08:31:35.167266130 +0200 +++ /var/tmp/diff_new_pack.IV0RFK/_new 2025-07-24 08:31:35.167266130 +0200 @@ -1,7 +1,7 @@ # # spec file for package python-pystache # -# Copyright (c) 2024 SUSE LLC +# Copyright (c) 2025 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,8 +17,9 @@ %{?sle15_python_module_pythons} +%bcond_without libalternatives Name: python-pystache -Version: 0.6.5 +Version: 0.6.8 Release: 0 Summary: Mustache for Python License: MIT @@ -30,8 +31,10 @@ BuildRequires: %{python_module setuptools_scm} BuildRequires: %{python_module setuptools} BuildRequires: %{python_module wheel} +BuildRequires: alts BuildRequires: fdupes BuildRequires: python-rpm-macros +Requires: alts BuildArch: noarch %description @@ -58,16 +61,14 @@ %pyproject_install %python_clone -a %{buildroot}%{_bindir}/pystache %python_clone -a %{buildroot}%{_bindir}/pystache-test +%python_group_libalternatives pystache pystache-test %{python_expand %fdupes %{buildroot}%$python_sitelib/} %check %pytest -%post -%{python_install_alternative pystache pystache-test} - -%postun -%{python_uninstall_alternative pystache pystache-test} +%pre +%python_libalternatives_reset_alternative pystache %files %{python_files} %license LICENSE ++++++ pystache-0.6.5.tar.gz -> pystache-0.6.8.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pystache-0.6.5/.pre-commit-config.yaml new/pystache-0.6.8/.pre-commit-config.yaml --- old/pystache-0.6.5/.pre-commit-config.yaml 2023-08-26 20:11:34.000000000 +0200 +++ new/pystache-0.6.8/.pre-commit-config.yaml 2024-12-12 15:13:15.000000000 +0100 @@ -9,7 +9,7 @@ - id: check-useless-excludes - id: check-hooks-apply - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v5.0.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer @@ -21,7 +21,7 @@ exclude: '(conda/meta.yaml|.pep8speaks.yml)' - repo: https://github.com/ambv/black - rev: 23.7.0 + rev: 24.10.0 hooks: - id: black name: "Format code" @@ -29,7 +29,7 @@ language_version: python3 - repo: "https://github.com/asottile/blacken-docs" - rev: "1.16.0" + rev: "1.19.1" hooks: - id: "blacken-docs" name: "Format docs (blacken-docs)" @@ -38,7 +38,7 @@ - "black==23.1.0" - repo: https://github.com/PyCQA/doc8 - rev: v1.1.1 + rev: v1.1.2 hooks: - id: doc8 args: @@ -54,7 +54,7 @@ - id: rst-inline-touching-normal - repo: https://github.com/myint/autoflake - rev: v2.2.0 + rev: v2.3.1 hooks: - id: autoflake exclude: '(.*tests/.*|.*test.py$|^setup.py$|^test_.*.py$)' @@ -65,14 +65,14 @@ - --remove-unused-variables - repo: https://github.com/PyCQA/flake8 - rev: 6.1.0 + rev: 7.1.1 hooks: - id: flake8 exclude: '(.*tests/.*|.*test.py$|^setup.py$|^test_.*.py$)' additional_dependencies: ["flake8-bugbear"] - repo: https://github.com/PyCQA/bandit - rev: 1.7.5 + rev: 1.8.0 hooks: - id: bandit args: ["-ll", "-x", "pystache/tests"] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pystache-0.6.5/CHANGELOG.rst new/pystache-0.6.8/CHANGELOG.rst --- old/pystache-0.6.5/CHANGELOG.rst 2023-08-26 20:57:18.000000000 +0200 +++ new/pystache-0.6.8/CHANGELOG.rst 2024-12-24 09:22:39.000000000 +0100 @@ -1,3 +1,21 @@ +v0.6.6 (2024-12-12) +------------------- + +- Update README to match supported versions. [Thomas David Baker] +- Update pre-commit. [Thomas David Baker] +- Update pyproject.toml with 3.12 and 3.13 Python versions. [Alvaro Crespo] +- Update tox config to use Python 3.12 and 3.13 versions. [Alvaro Crespo] +- Update yml files with Python 3.12 and 3.13. [Alvaro Crespo] +- Update changelog for v0.6.5 a bit belatedly. [Thomas David Baker] + +v0.6.5 (2023-08-26) +------------------- + +- Bump the version bits called out in the readme. [Stephen L Arnold] +- Keep changelog up to date manually as I don't know how to + autogenerate. [Thomas David Baker] + + v0.6.4 (2023-08-13) ------------------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pystache-0.6.5/PKG-INFO new/pystache-0.6.8/PKG-INFO --- old/pystache-0.6.5/PKG-INFO 2023-08-26 21:00:16.003826100 +0200 +++ new/pystache-0.6.8/PKG-INFO 2025-03-18 12:54:32.415202600 +0100 @@ -1,6 +1,6 @@ -Metadata-Version: 2.1 +Metadata-Version: 2.2 Name: pystache -Version: 0.6.5 +Version: 0.6.8 Summary: Mustache for Python Author-email: Chris Wanstrath <ch...@ozmm.org> Maintainer-email: Thomas David Baker <bak...@gmail.com> @@ -31,7 +31,7 @@ Project-URL: Documentation, http://mustache.github.io/ Project-URL: Repository, https://github.com/PennyDreadfulMTG/pystache.git Project-URL: Changelog, https://github.com/PennyDreadfulMTG/pystache/blob/master/CHANGELOG.rst -Classifier: Development Status :: 4 - Beta +Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Programming Language :: Python @@ -40,13 +40,25 @@ Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 Classifier: Topic :: Software Development :: Libraries Requires-Python: >=3.8 Description-Content-Type: text/x-rst +License-File: LICENSE +Requires-Dist: importlib-metadata>=4.6; python_version < "3.10" Provides-Extra: cov +Requires-Dist: coverage; extra == "cov" +Requires-Dist: coverage_python_version; extra == "cov" Provides-Extra: doc +Requires-Dist: sphinx; extra == "doc" +Requires-Dist: sphinx_git; extra == "doc" +Requires-Dist: recommonmark; extra == "doc" +Requires-Dist: sphinx_rtd_theme; extra == "doc" +Requires-Dist: sphinxcontrib-apidoc; extra == "doc" Provides-Extra: test -License-File: LICENSE +Requires-Dist: pytest; extra == "test" +Requires-Dist: pytest-cov; extra == "test" Pystache ======== @@ -59,7 +71,7 @@ This updated fork of Pystache is currently tested on Python 3.8+ and in -Conda, on Linux, Macos, and Windows (Python 2.7 is no longer supported). +Conda, on Linux, Macos, and Windows. |logo| @@ -90,6 +102,8 @@ - Python 3.9 - Python 3.10 - Python 3.11 +- Python 3.12 +- Python 3.13 - Conda (py38 and py310) JSON support is needed only for the command-line interface and to run @@ -327,15 +341,6 @@ .. _pre-commit: https://pre-commit.com/ -Mailing List (old) ------------------- - -There is(was) a `mailing list`_. Note that there is a bit of a delay -between posting a message and seeing it appear in the mailing list archive. - - -.. _mailing list: https://librelist.com/browser/pystache/ - Credits ======= diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pystache-0.6.5/README.rst new/pystache-0.6.8/README.rst --- old/pystache-0.6.5/README.rst 2023-08-26 20:11:34.000000000 +0200 +++ new/pystache-0.6.8/README.rst 2024-12-12 15:13:15.000000000 +0100 @@ -9,7 +9,7 @@ This updated fork of Pystache is currently tested on Python 3.8+ and in -Conda, on Linux, Macos, and Windows (Python 2.7 is no longer supported). +Conda, on Linux, Macos, and Windows. |logo| @@ -40,6 +40,8 @@ - Python 3.9 - Python 3.10 - Python 3.11 +- Python 3.12 +- Python 3.13 - Conda (py38 and py310) JSON support is needed only for the command-line interface and to run @@ -277,15 +279,6 @@ .. _pre-commit: https://pre-commit.com/ -Mailing List (old) ------------------- - -There is(was) a `mailing list`_. Note that there is a bit of a delay -between posting a message and seeing it appear in the mailing list archive. - - -.. _mailing list: https://librelist.com/browser/pystache/ - Credits ======= diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pystache-0.6.5/pyproject.toml new/pystache-0.6.8/pyproject.toml --- old/pystache-0.6.5/pyproject.toml 2023-08-26 20:11:34.000000000 +0200 +++ new/pystache-0.6.8/pyproject.toml 2025-03-14 03:33:27.000000000 +0100 @@ -19,7 +19,7 @@ {name = "Thomas David Baker", email = "bak...@gmail.com"}, ] classifiers = [ - "Development Status :: 4 - Beta", + "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python", @@ -28,6 +28,8 @@ "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Topic :: Software Development :: Libraries", ] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pystache-0.6.5/pystache/_version.py new/pystache-0.6.8/pystache/_version.py --- old/pystache-0.6.5/pystache/_version.py 2023-08-26 21:00:15.000000000 +0200 +++ new/pystache-0.6.8/pystache/_version.py 2025-03-18 12:54:32.000000000 +0100 @@ -1,4 +1,21 @@ -# file generated by setuptools_scm +# file generated by setuptools-scm # don't change, don't track in version control -__version__ = version = '0.6.5' -__version_tuple__ = version_tuple = (0, 6, 5) + +__all__ = ["__version__", "__version_tuple__", "version", "version_tuple"] + +TYPE_CHECKING = False +if TYPE_CHECKING: + from typing import Tuple + from typing import Union + + VERSION_TUPLE = Tuple[Union[int, str], ...] +else: + VERSION_TUPLE = object + +version: str +__version__: str +__version_tuple__: VERSION_TUPLE +version_tuple: VERSION_TUPLE + +__version__ = version = '0.6.8' +__version_tuple__ = version_tuple = (0, 6, 8) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pystache-0.6.5/pystache/parser.py new/pystache-0.6.8/pystache/parser.py --- old/pystache-0.6.5/pystache/parser.py 2023-08-26 20:11:34.000000000 +0200 +++ new/pystache-0.6.8/pystache/parser.py 2025-03-18 12:49:51.000000000 +0100 @@ -17,15 +17,14 @@ # TODO: add some unit tests for this. # TODO: add a test case that checks for spurious spaces. # TODO: add test cases for delimiters. -def parse(template, delimiters=None): +def parse(template, delimiters=None, raise_on_mismatch=False): """ Parse a unicode template string and return a ParsedTemplate instance. Arguments: - template: a unicode template string. - delimiters: a 2-tuple of delimiters. Defaults to the package default. + raise_on_mismatch: a boolean indicating whether to raise an exception when parsing fails. Examples: @@ -36,7 +35,7 @@ """ if type(template) is not str: raise Exception('Template is not unicode: %s' % type(template)) - parser = _Parser(delimiters) + parser = _Parser(delimiters, raise_on_mismatch=raise_on_mismatch) return parser.parse(template) @@ -72,8 +71,33 @@ return re.compile(tag, re.VERBOSE) +class ParsingErrorDetails: + def __init__(self, tag_type, position, tag_key): + """ + :param tag_type: the type of the tag being parsed, for example "/" + :type tag_type: str + :param position: the position of the tag being parsed + :type position: int + :param tag_key: the key of the tag being parsed, for example "em" + :type tag_key: str + """ + self.tag_type = tag_type + self.position = position + self.tag_key = tag_key + + class ParsingError(Exception): - pass + def __init__(self, message, info = None): + super().__init__(message) + self._info = info + + @property + def info(self): + """ + :returns: Additional information about the error. + :rtype: ParsingErrorDetails | None + """ + return self._info ## Node types @@ -220,12 +244,14 @@ class _Parser(object): _delimiters = None _template_re = None + _raise_on_mismatch = False - def __init__(self, delimiters=None): + def __init__(self, delimiters=None, raise_on_mismatch=False): if delimiters is None: delimiters = defaults.DELIMITERS self._delimiters = delimiters + self._raise_on_mismatch = raise_on_mismatch def _compile_delimiters(self): self._template_re = _compile_template_re(self._delimiters) @@ -237,17 +263,12 @@ def parse(self, template): """ Parse a template string starting at some index. - This method uses the current tag delimiter. Arguments: - template: a unicode string that is the template to parse. - index: the index at which to start parsing. - Returns: - a ParsedTemplate instance. """ @@ -259,6 +280,7 @@ states = [] + tag_key = "" while True: match = self._template_re.search(template, start_index) @@ -312,7 +334,21 @@ if tag_type == '/': if tag_key != section_key: - raise ParsingError('Section end tag mismatch: %s != %s' % (tag_key, section_key)) + error_details = ParsingErrorDetails( + tag_type, + start_index, + tag_key, + ) + raise ParsingError( + 'Section end tag mismatch at position %d. Found {{%s%s}}, expected {{%s%s}}' % ( + start_index, + tag_type, + tag_key, + tag_type if section_key else '#', + section_key or tag_key, + ), + error_details + ) # Restore previous state with newly found section data. parsed_section = parsed_template @@ -337,6 +373,20 @@ parsed_template.add(node) + # Some open/close tags were mismatched. + if self._raise_on_mismatch and states: + error_details = ParsingErrorDetails( + states[0][0], + states[0][1], + states[0][2] or tag_key, + ) + raise ParsingError( + "Did not find a matching tag for {{%s%s}}. Its section starts at position %d" % ( + error_details.tag_type, error_details.tag_key, error_details.position + ), + error_details + ) + # Avoid adding spurious empty strings to the parse tree. if start_index != len(template): parsed_template.add(template[start_index:]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pystache-0.6.5/pystache/tests/test_parser.py new/pystache-0.6.8/pystache/tests/test_parser.py --- old/pystache-0.6.5/pystache/tests/test_parser.py 2023-03-09 01:44:03.000000000 +0100 +++ new/pystache-0.6.8/pystache/tests/test_parser.py 2025-03-18 12:49:51.000000000 +0100 @@ -8,19 +8,51 @@ import unittest from pystache.defaults import DELIMITERS -from pystache.parser import _compile_template_re as make_re +from pystache.parser import _compile_template_re as make_re, parse, ParsingError class RegularExpressionTestCase(unittest.TestCase): - """Tests the regular expression returned by _compile_template_re().""" def test_re(self): """ Test getting a key from a dictionary. - """ re = make_re(DELIMITERS) match = re.search("b {{test}}") self.assertEqual(match.start(), 1) + + +class ParseTestCase(unittest.TestCase): + """Tests the parse() function.""" + + def test_parse_okay(self): + """ + Test parsing templates in the cases there are no errors. + """ + ts = [ + '<div>{{>A}}</div>', + '{{#A}}<div> some text</div>', + '{{^A}}<div> some text</div>{{/A}}', + '{{#A}} {{^B}} {{/B}} {{/A}}', + '{{#A}} {{^B}} {{/B}} {{/A}} {{#C}} {{/C}}', + ] + for t in ts: + with self.subTest(template=t): + parse(t) + + def test_parse_fail(self): + """ + Test parsing templates in the cases there are errors. + """ + ts = [ + '{{#A}}<div> some text</div>', + '{{#A}}<div> some text</div>{{/A}} <div> TEXT </div> {{/B}}', + '{{#A}} {{#B}} {{/A}} {{/B}}', + ] + for t in ts: + with self.subTest(template=t): + with self.assertRaises(ParsingError) as e: + parse(t, raise_on_mismatch=True) + self.assertTrue('Did not find a matching tag', str(e)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pystache-0.6.5/pystache/tests/test_renderengine.py new/pystache-0.6.8/pystache/tests/test_renderengine.py --- old/pystache-0.6.5/pystache/tests/test_renderengine.py 2023-03-09 01:44:03.000000000 +0100 +++ new/pystache-0.6.8/pystache/tests/test_renderengine.py 2025-03-18 12:49:51.000000000 +0100 @@ -447,7 +447,7 @@ try: self._assert_render(None, template) except ParsingError as err: - self.assertEqual(str(err), "Section end tag mismatch: section != None") + self.assertTrue("Section end tag mismatch" in str(err)) def test_section__end_tag_mismatch(self): """ @@ -458,7 +458,7 @@ try: self._assert_render(None, template) except ParsingError as err: - self.assertEqual(str(err), "Section end tag mismatch: section_end != section_start") + self.assertTrue("Section end tag mismatch" in str(err)) def test_section__context_values(self): """ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pystache-0.6.5/pystache.egg-info/PKG-INFO new/pystache-0.6.8/pystache.egg-info/PKG-INFO --- old/pystache-0.6.5/pystache.egg-info/PKG-INFO 2023-08-26 21:00:15.000000000 +0200 +++ new/pystache-0.6.8/pystache.egg-info/PKG-INFO 2025-03-18 12:54:32.000000000 +0100 @@ -1,6 +1,6 @@ -Metadata-Version: 2.1 +Metadata-Version: 2.2 Name: pystache -Version: 0.6.5 +Version: 0.6.8 Summary: Mustache for Python Author-email: Chris Wanstrath <ch...@ozmm.org> Maintainer-email: Thomas David Baker <bak...@gmail.com> @@ -31,7 +31,7 @@ Project-URL: Documentation, http://mustache.github.io/ Project-URL: Repository, https://github.com/PennyDreadfulMTG/pystache.git Project-URL: Changelog, https://github.com/PennyDreadfulMTG/pystache/blob/master/CHANGELOG.rst -Classifier: Development Status :: 4 - Beta +Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Programming Language :: Python @@ -40,13 +40,25 @@ Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 Classifier: Topic :: Software Development :: Libraries Requires-Python: >=3.8 Description-Content-Type: text/x-rst +License-File: LICENSE +Requires-Dist: importlib-metadata>=4.6; python_version < "3.10" Provides-Extra: cov +Requires-Dist: coverage; extra == "cov" +Requires-Dist: coverage_python_version; extra == "cov" Provides-Extra: doc +Requires-Dist: sphinx; extra == "doc" +Requires-Dist: sphinx_git; extra == "doc" +Requires-Dist: recommonmark; extra == "doc" +Requires-Dist: sphinx_rtd_theme; extra == "doc" +Requires-Dist: sphinxcontrib-apidoc; extra == "doc" Provides-Extra: test -License-File: LICENSE +Requires-Dist: pytest; extra == "test" +Requires-Dist: pytest-cov; extra == "test" Pystache ======== @@ -59,7 +71,7 @@ This updated fork of Pystache is currently tested on Python 3.8+ and in -Conda, on Linux, Macos, and Windows (Python 2.7 is no longer supported). +Conda, on Linux, Macos, and Windows. |logo| @@ -90,6 +102,8 @@ - Python 3.9 - Python 3.10 - Python 3.11 +- Python 3.12 +- Python 3.13 - Conda (py38 and py310) JSON support is needed only for the command-line interface and to run @@ -327,15 +341,6 @@ .. _pre-commit: https://pre-commit.com/ -Mailing List (old) ------------------- - -There is(was) a `mailing list`_. Note that there is a bit of a delay -between posting a message and seeing it appear in the mailing list archive. - - -.. _mailing list: https://librelist.com/browser/pystache/ - Credits ======= diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pystache-0.6.5/tox.ini new/pystache-0.6.8/tox.ini --- old/pystache-0.6.5/tox.ini 2023-08-26 20:11:34.000000000 +0200 +++ new/pystache-0.6.8/tox.ini 2024-12-12 15:13:15.000000000 +0100 @@ -1,5 +1,5 @@ [tox] -envlist = py3{8,9,10,11}-{linux,macos,windows} +envlist = py3{8,9,10,11,12,13}-{linux,macos,windows} skip_missing_interpreters = true isolated_build = true skipsdist = true @@ -10,6 +10,8 @@ 3.9: py39 3.10: py310 3.11: py311 + 3.12: py312 + 3.13: py313 [gh-actions:env] PLATFORM =