From d97819f76f50abd3525022a5160f6a979f932277 Mon Sep 17 00:00:00 2001 From: Xuehai Pan Date: Thu, 22 May 2025 16:15:58 +0800 Subject: [PATCH 1/9] refactor: use CPython macros to construct `PYBIND11_VERSION_HEX` --- include/pybind11/detail/common.h | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index 93489c7a84..c6c6f5886f 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -14,13 +14,30 @@ # error "PYTHON < 3.8 IS UNSUPPORTED. pybind11 v2.13 was the last to support Python 3.7." #endif +// Similar to Python's convention: https://docs.python.org/3/c-api/apiabiversion.html +// See also: https://github.com/python/cpython/blob/HEAD/Include/patchlevel.h #define PYBIND11_VERSION_MAJOR 3 #define PYBIND11_VERSION_MINOR 0 +#define PYBIND11_VERSION_MICRO 0 +// The release level is set to "alpha" for development versions. +// Use 0xA0 (LEVEL=0xA, SERIAL=0) for development versions. +// ALPHA = 0xA, BETA = 0xB, GAMMA = 0xC (release candidate), FINAL = 0xF (stable release) +#define PYBIND11_VERSION_RELEASE_LEVEL PY_RELEASE_LEVEL_GAMMA +#define PYBIND11_VERSION_RELEASE_SERIAL 1 #define PYBIND11_VERSION_PATCH 0rc1 -// Similar to Python's convention: https://docs.python.org/3/c-api/apiabiversion.html -// Use 0xA0 for dev -#define PYBIND11_VERSION_HEX 0x030000C1 +#if !defined(Py_PACK_FULL_VERSION) +// Stable API since Python 3.14.0a4 +# define Py_PACK_FULL_VERSION(X, Y, Z, LEVEL, SERIAL) \ + ((((X) & 0xff) << 24) | (((Y) & 0xff) << 16) | (((Z) & 0xff) << 8) \ + | (((LEVEL) & 0xf) << 4) | (((SERIAL) & 0xf) << 0)) +#endif +#define PYBIND11_VERSION_HEX \ + Py_PACK_FULL_VERSION(PYBIND11_VERSION_MAJOR, \ + PYBIND11_VERSION_MINOR, \ + PYBIND11_VERSION_MICRO, \ + PYBIND11_VERSION_RELEASE_LEVEL, \ + PYBIND11_VERSION_RELEASE_SERIAL) #include "pybind11_namespace_macros.h" From dd0aa39ed1cab99ba2b4701efa824ca57148cf43 Mon Sep 17 00:00:00 2001 From: Xuehai Pan Date: Thu, 22 May 2025 16:38:51 +0800 Subject: [PATCH 2/9] docs: update release guide --- docs/release.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/release.rst b/docs/release.rst index 0d37771022..42bd63cc36 100644 --- a/docs/release.rst +++ b/docs/release.rst @@ -10,11 +10,13 @@ For example: #define PYBIND11_VERSION_MAJOR X #define PYBIND11_VERSION_MINOR Y + #define PYBIND11_VERSION_MICRO Z + #define PYBIND11_VERSION_RELEASE_LEVEL PY_RELEASE_LEVEL_ALPHA + #define PYBIND11_VERSION_RELEASE_SERIAL 0 #define PYBIND11_VERSION_PATCH Za0 For beta, ``PYBIND11_VERSION_PATCH`` should be ``Zb1``. RC's can be ``Zrc1``. -For a final release, this must be a simple integer. There is also -``PYBIND11_VERSION_HEX`` just below that needs to be updated. +For a final release, this must be a simple integer. To release a new version of pybind11: @@ -28,8 +30,6 @@ If you don't have nox, you should either use ``pipx run nox`` instead, or use - Update ``PYBIND11_VERSION_MAJOR`` etc. in ``include/pybind11/detail/common.h``. PATCH should be a simple integer. - - Update ``PYBIND11_VERSION_HEX`` just below as well. - - Run ``nox -s tests_packaging`` to ensure this was done correctly. - Ensure that all the information in ``pyproject.toml`` is up-to-date, like From 53ec11e00c2590b54c75b7312be8e0d73d60bc09 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Thu, 22 May 2025 15:51:42 -0400 Subject: [PATCH 3/9] tests: add test to keep version values in sync Signed-off-by: Henry Schreiner --- tests/extra_python_package/test_files.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/extra_python_package/test_files.py b/tests/extra_python_package/test_files.py index 9725bedae1..162b918b66 100644 --- a/tests/extra_python_package/test_files.py +++ b/tests/extra_python_package/test_files.py @@ -347,3 +347,27 @@ def tests_build_global_wheel(monkeypatch, tmpdir): pkgconfig_expected = PKGCONFIG.format(VERSION=simple_version) assert pkgconfig_expected == pkgconfig + + +def test_version_matches(): + header = MAIN_DIR / "include/pybind11/detail/common.h" + text = header.read_text() + + # Extract the relevant macro values + micro = re.search(r'#define\s+PYBIND11_VERSION_MICRO\s+(\d+)', text).group(1) + release_level = re.search(r'#define\s+PYBIND11_VERSION_RELEASE_LEVEL\s+([A-Za-z0-9_]+)', text).group(1) + release_serial = re.search(r'#define\s+PYBIND11_VERSION_RELEASE_SERIAL\s+(\d+)', text).group(1) + patch = re.search(r'#define\s+PYBIND11_VERSION_PATCH\s+([^\s]+)', text).group(1) + + # Map release level macro to string + level_map = { + "PY_RELEASE_LEVEL_ALPHA": "a", + "PY_RELEASE_LEVEL_BETA": "b", + "PY_RELEASE_LEVEL_GAMMA": "rc", + "PY_RELEASE_LEVEL_FINAL": "", + } + level_str = level_map.get(release_level, release_level.lower()) + + expected_patch = f"{micro}{level_str}{release_serial}" + + assert patch == expected_patch From f58d34ce23c2981cd01352030ba691a30b5a9f03 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 22 May 2025 19:52:23 +0000 Subject: [PATCH 4/9] style: pre-commit fixes --- tests/extra_python_package/test_files.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/extra_python_package/test_files.py b/tests/extra_python_package/test_files.py index 162b918b66..fb8a8da0f0 100644 --- a/tests/extra_python_package/test_files.py +++ b/tests/extra_python_package/test_files.py @@ -354,10 +354,14 @@ def test_version_matches(): text = header.read_text() # Extract the relevant macro values - micro = re.search(r'#define\s+PYBIND11_VERSION_MICRO\s+(\d+)', text).group(1) - release_level = re.search(r'#define\s+PYBIND11_VERSION_RELEASE_LEVEL\s+([A-Za-z0-9_]+)', text).group(1) - release_serial = re.search(r'#define\s+PYBIND11_VERSION_RELEASE_SERIAL\s+(\d+)', text).group(1) - patch = re.search(r'#define\s+PYBIND11_VERSION_PATCH\s+([^\s]+)', text).group(1) + micro = re.search(r"#define\s+PYBIND11_VERSION_MICRO\s+(\d+)", text).group(1) + release_level = re.search( + r"#define\s+PYBIND11_VERSION_RELEASE_LEVEL\s+([A-Za-z0-9_]+)", text + ).group(1) + release_serial = re.search( + r"#define\s+PYBIND11_VERSION_RELEASE_SERIAL\s+(\d+)", text + ).group(1) + patch = re.search(r"#define\s+PYBIND11_VERSION_PATCH\s+([^\s]+)", text).group(1) # Map release level macro to string level_map = { From 1bd9248aa8a75630af5547a4e7053da7c77bf021 Mon Sep 17 00:00:00 2001 From: Xuehai Pan Date: Fri, 23 May 2025 14:56:02 +0800 Subject: [PATCH 5/9] test: update version test --- tests/extra_python_package/test_files.py | 29 ++++++++++++------------ 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/tests/extra_python_package/test_files.py b/tests/extra_python_package/test_files.py index fb8a8da0f0..01d2b4fdb3 100644 --- a/tests/extra_python_package/test_files.py +++ b/tests/extra_python_package/test_files.py @@ -354,24 +354,23 @@ def test_version_matches(): text = header.read_text() # Extract the relevant macro values - micro = re.search(r"#define\s+PYBIND11_VERSION_MICRO\s+(\d+)", text).group(1) + prefix = r"^\s*#\s*define\s+PYBIND11_VERSION_" + micro = re.search(rf"{prefix}MICRO\s+(\d+)", text).group(1) release_level = re.search( - r"#define\s+PYBIND11_VERSION_RELEASE_LEVEL\s+([A-Za-z0-9_]+)", text + rf"{prefix}RELEASE_LEVEL\s+PY_RELEASE_LEVEL_(\w+)", text ).group(1) - release_serial = re.search( - r"#define\s+PYBIND11_VERSION_RELEASE_SERIAL\s+(\d+)", text - ).group(1) - patch = re.search(r"#define\s+PYBIND11_VERSION_PATCH\s+([^\s]+)", text).group(1) + release_serial = re.search(rf"{prefix}RELEASE_SERIAL\s+(\d+)", text).group(1) + patch = re.search(rf"{prefix}PATCH\s+([^\s]+)", text).group(1) # Map release level macro to string - level_map = { - "PY_RELEASE_LEVEL_ALPHA": "a", - "PY_RELEASE_LEVEL_BETA": "b", - "PY_RELEASE_LEVEL_GAMMA": "rc", - "PY_RELEASE_LEVEL_FINAL": "", - } - level_str = level_map.get(release_level, release_level.lower()) - - expected_patch = f"{micro}{level_str}{release_serial}" + level_map = {"ALPHA": "a", "BETA": "b", "GAMMA": "rc", "FINAL": ""} + level_str = level_map[release_level] + + if release_level == "FINAL": + assert level_str == "" + assert release_serial == "0" + expected_patch = micro + else: + expected_patch = f"{micro}{level_str}{release_serial}" assert patch == expected_patch From ac8340222c3370c33660f0053ec9aff289ac0d0a Mon Sep 17 00:00:00 2001 From: Xuehai Pan Date: Fri, 23 May 2025 15:00:10 +0800 Subject: [PATCH 6/9] test: update version test --- tests/extra_python_package/test_files.py | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/tests/extra_python_package/test_files.py b/tests/extra_python_package/test_files.py index 01d2b4fdb3..28d59f5df8 100644 --- a/tests/extra_python_package/test_files.py +++ b/tests/extra_python_package/test_files.py @@ -354,19 +354,25 @@ def test_version_matches(): text = header.read_text() # Extract the relevant macro values - prefix = r"^\s*#\s*define\s+PYBIND11_VERSION_" - micro = re.search(rf"{prefix}MICRO\s+(\d+)", text).group(1) - release_level = re.search( - rf"{prefix}RELEASE_LEVEL\s+PY_RELEASE_LEVEL_(\w+)", text + regex_prefix = r"^\s*#\s*define\s+PYBIND11_VERSION_" + micro = re.search(rf"{regex_prefix}MICRO\s+(\d+)\b", text).group(1) + release_level = re.search(rf"{regex_prefix}RELEASE_LEVEL\s+(\w+)\b", text).group(1) + release_serial = re.search( + rf"{regex_prefix}RELEASE_SERIAL\s+(\d+)\b", + text, ).group(1) - release_serial = re.search(rf"{prefix}RELEASE_SERIAL\s+(\d+)", text).group(1) - patch = re.search(rf"{prefix}PATCH\s+([^\s]+)", text).group(1) + patch = re.search(rf"{regex_prefix}PATCH\s+([\w.-]+)\b", text).group(1) # Map release level macro to string - level_map = {"ALPHA": "a", "BETA": "b", "GAMMA": "rc", "FINAL": ""} + level_map = { + "PY_RELEASE_LEVEL_ALPHA": "a", + "PY_RELEASE_LEVEL_BETA": "b", + "PY_RELEASE_LEVEL_GAMMA": "rc", + "PY_RELEASE_LEVEL_FINAL": "", + } level_str = level_map[release_level] - if release_level == "FINAL": + if release_level == "PY_RELEASE_LEVEL_FINAL": assert level_str == "" assert release_serial == "0" expected_patch = micro From 9b75c1d6b51d03ae48fb28407f1f97285cb511ea Mon Sep 17 00:00:00 2001 From: Xuehai Pan Date: Fri, 23 May 2025 15:11:06 +0800 Subject: [PATCH 7/9] test: update version test --- tests/extra_python_package/test_files.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/extra_python_package/test_files.py b/tests/extra_python_package/test_files.py index 28d59f5df8..154c31bc56 100644 --- a/tests/extra_python_package/test_files.py +++ b/tests/extra_python_package/test_files.py @@ -354,7 +354,7 @@ def test_version_matches(): text = header.read_text() # Extract the relevant macro values - regex_prefix = r"^\s*#\s*define\s+PYBIND11_VERSION_" + regex_prefix = r"#\s*define\s+PYBIND11_VERSION_" micro = re.search(rf"{regex_prefix}MICRO\s+(\d+)\b", text).group(1) release_level = re.search(rf"{regex_prefix}RELEASE_LEVEL\s+(\w+)\b", text).group(1) release_serial = re.search( From c132aa91d481954f7dbe67948dd6e6369f604751 Mon Sep 17 00:00:00 2001 From: Xuehai Pan Date: Fri, 23 May 2025 16:14:24 +0800 Subject: [PATCH 8/9] chore: update code comments --- include/pybind11/detail/common.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index ad04445ac7..6a9440b60d 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -16,15 +16,19 @@ // Similar to Python's convention: https://docs.python.org/3/c-api/apiabiversion.html // See also: https://github.com/python/cpython/blob/HEAD/Include/patchlevel.h +/* -- start version constants -- */ #define PYBIND11_VERSION_MAJOR 3 #define PYBIND11_VERSION_MINOR 0 #define PYBIND11_VERSION_MICRO 0 -// The release level is set to "alpha" for development versions. -// Use 0xA0 (LEVEL=0xA, SERIAL=0) for development versions. // ALPHA = 0xA, BETA = 0xB, GAMMA = 0xC (release candidate), FINAL = 0xF (stable release) +// - The release level is set to "alpha" for development versions. +// Use 0xA0 (LEVEL=0xA, SERIAL=0) for development versions. +// - For stable releases, set the serial to 0. #define PYBIND11_VERSION_RELEASE_LEVEL PY_RELEASE_LEVEL_GAMMA #define PYBIND11_VERSION_RELEASE_SERIAL 1 +// String version of (micro, release level, release serial), e.g.: 0a0, 0b1, 0rc1, 0 #define PYBIND11_VERSION_PATCH 0rc1 +/* -- end version constants -- */ #if !defined(Py_PACK_FULL_VERSION) // Stable API since Python 3.14.0a4 @@ -32,6 +36,7 @@ ((((X) & 0xff) << 24) | (((Y) & 0xff) << 16) | (((Z) & 0xff) << 8) \ | (((LEVEL) & 0xf) << 4) | (((SERIAL) & 0xf) << 0)) #endif +// Version as a single 4-byte hex number, e.g. 0x030C04B5 == 3.12.4b5. #define PYBIND11_VERSION_HEX \ Py_PACK_FULL_VERSION(PYBIND11_VERSION_MAJOR, \ PYBIND11_VERSION_MINOR, \ From b307c2f16fe01934bb776444ebc3249e86c9cc1a Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Fri, 23 May 2025 15:28:18 -0400 Subject: [PATCH 9/9] Update docs/release.rst --- docs/release.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/release.rst b/docs/release.rst index 42bd63cc36..437b690301 100644 --- a/docs/release.rst +++ b/docs/release.rst @@ -28,7 +28,7 @@ If you don't have nox, you should either use ``pipx run nox`` instead, or use - Update the version number - Update ``PYBIND11_VERSION_MAJOR`` etc. in - ``include/pybind11/detail/common.h``. PATCH should be a simple integer. + ``include/pybind11/detail/common.h``. MICRO should be a simple integer. - Run ``nox -s tests_packaging`` to ensure this was done correctly.