https://github.com/python/cpython/commit/1439b81928f1b52c5a0ac7fd81fdd66afd5f72da
commit: 1439b81928f1b52c5a0ac7fd81fdd66afd5f72da
branch: main
author: Petr Viktorin <[email protected]>
committer: encukou <[email protected]>
date: 2025-01-09T11:10:28+01:00
summary:
gh-128629: Add Py_PACK_VERSION and Py_PACK_FULL_VERSION (GH-128630)
files:
A Misc/NEWS.d/next/C_API/2025-01-08-13-13-18.gh-issue-128629.gSmzyl.rst
A Modules/_testlimitedcapi/clinic/version.c.h
A Modules/_testlimitedcapi/version.c
M Doc/c-api/apiabiversion.rst
M Doc/data/stable_abi.dat
M Doc/whatsnew/3.14.rst
M Include/patchlevel.h
M Include/pymacro.h
M Lib/test/test_capi/test_misc.py
M Lib/test/test_stable_abi_ctypes.py
M Misc/stable_abi.toml
M Modules/Setup.stdlib.in
M Modules/_testlimitedcapi.c
M Modules/_testlimitedcapi/parts.h
M PC/python3dll.c
M PCbuild/_testlimitedcapi.vcxproj
M PCbuild/_testlimitedcapi.vcxproj.filters
M Python/modsupport.c
diff --git a/Doc/c-api/apiabiversion.rst b/Doc/c-api/apiabiversion.rst
index f6c8284daeacb0..96050f59bd5250 100644
--- a/Doc/c-api/apiabiversion.rst
+++ b/Doc/c-api/apiabiversion.rst
@@ -6,9 +6,13 @@
API and ABI Versioning
***********************
+
+Build-time version constants
+----------------------------
+
CPython exposes its version number in the following macros.
-Note that these correspond to the version code is **built** with,
-not necessarily the version used at **run time**.
+Note that these correspond to the version code is **built** with.
+See :c:var:`Py_Version` for the version used at **run time**.
See :ref:`stable` for a discussion of API and ABI stability across versions.
@@ -37,37 +41,83 @@ See :ref:`stable` for a discussion of API and ABI stability
across versions.
.. c:macro:: PY_VERSION_HEX
The Python version number encoded in a single integer.
+ See :c:func:`Py_PACK_FULL_VERSION` for the encoding details.
- The underlying version information can be found by treating it as a 32 bit
- number in the following manner:
-
-
+-------+-------------------------+-------------------------+--------------------------+
- | Bytes | Bits (big endian order) | Meaning | Value for
``3.4.1a2`` |
-
+=======+=========================+=========================+==========================+
- | 1 | 1-8 | ``PY_MAJOR_VERSION`` | ``0x03``
|
-
+-------+-------------------------+-------------------------+--------------------------+
- | 2 | 9-16 | ``PY_MINOR_VERSION`` | ``0x04``
|
-
+-------+-------------------------+-------------------------+--------------------------+
- | 3 | 17-24 | ``PY_MICRO_VERSION`` | ``0x01``
|
-
+-------+-------------------------+-------------------------+--------------------------+
- | 4 | 25-28 | ``PY_RELEASE_LEVEL`` | ``0xA``
|
- +
+-------------------------+-------------------------+--------------------------+
- | | 29-32 | ``PY_RELEASE_SERIAL`` | ``0x2``
|
-
+-------+-------------------------+-------------------------+--------------------------+
+ Use this for numeric comparisons, for example,
+ ``#if PY_VERSION_HEX >= ...``.
- Thus ``3.4.1a2`` is hexversion ``0x030401a2`` and ``3.10.0`` is
- hexversion ``0x030a00f0``.
- Use this for numeric comparisons, e.g. ``#if PY_VERSION_HEX >= ...``.
-
- This version is also available via the symbol :c:var:`Py_Version`.
+Run-time version
+----------------
.. c:var:: const unsigned long Py_Version
- The Python runtime version number encoded in a single constant integer, with
- the same format as the :c:macro:`PY_VERSION_HEX` macro.
+ The Python runtime version number encoded in a single constant integer.
+ See :c:func:`Py_PACK_FULL_VERSION` for the encoding details.
This contains the Python version used at run time.
+ Use this for numeric comparisons, for example, ``if (Py_Version >= ...)``.
+
.. versionadded:: 3.11
-All the given macros are defined in :source:`Include/patchlevel.h`.
+
+Bit-packing macros
+------------------
+
+.. c:function:: uint32_t Py_PACK_FULL_VERSION(int major, int minor, int micro,
int release_level, int release_serial)
+
+ Return the given version, encoded as a single 32-bit integer with
+ the following structure:
+
+
+------------------+-------+----------------+-----------+--------------------------+
+ | | No. | | | Example values
|
+ | | of | |
+-------------+------------+
+ | Argument | bits | Bit mask | Bit shift | ``3.4.1a2`` |
``3.10.0`` |
+
+==================+=======+================+===========+=============+============+
+ | *major* | 8 | ``0xFF000000`` | 24 | ``0x03`` |
``0x03`` |
+
+------------------+-------+----------------+-----------+-------------+------------+
+ | *minor* | 8 | ``0x00FF0000`` | 16 | ``0x04`` |
``0x0A`` |
+
+------------------+-------+----------------+-----------+-------------+------------+
+ | *micro* | 8 | ``0x0000FF00`` | 8 | ``0x01`` |
``0x00`` |
+
+------------------+-------+----------------+-----------+-------------+------------+
+ | *release_level* | 4 | ``0x000000F0`` | 4 | ``0xA`` |
``0xF`` |
+
+------------------+-------+----------------+-----------+-------------+------------+
+ | *release_serial* | 4 | ``0x0000000F`` | 0 | ``0x2`` |
``0x0`` |
+
+------------------+-------+----------------+-----------+-------------+------------+
+
+ For example:
+
+ +-------------+------------------------------------+-----------------+
+ | Version | ``Py_PACK_FULL_VERSION`` arguments | Encoded version |
+ +=============+====================================+=================+
+ | ``3.4.1a2`` | ``(3, 4, 1, 0xA, 2)`` | ``0x030401a2`` |
+ +-------------+------------------------------------+-----------------+
+ | ``3.10.0`` | ``(3, 10, 0, 0xF, 0)`` | ``0x030a00f0`` |
+ +-------------+------------------------------------+-----------------+
+
+ Out-of range bits in the arguments are ignored.
+ That is, the macro can be defined as:
+
+ .. code-block:: c
+
+ #ifndef Py_PACK_FULL_VERSION
+ #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
+
+ ``Py_PACK_FULL_VERSION`` is primarily a macro, intended for use in
+ ``#if`` directives, but it is also available as an exported function.
+
+ .. versionadded:: 3.14
+
+.. c:function:: uint32_t Py_PACK_VERSION(int major, int minor)
+
+ Equivalent to ``Py_PACK_FULL_VERSION(major, minor, 0, 0, 0)``.
+ The result does not correspond to any Python release, but is useful
+ in numeric comparisons.
+
+ .. versionadded:: 3.14
diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat
index 6f9d27297e8f65..c15f82603aa944 100644
--- a/Doc/data/stable_abi.dat
+++ b/Doc/data/stable_abi.dat
@@ -883,6 +883,8 @@ func,Py_Main,3.2,,
func,Py_MakePendingCalls,3.2,,
func,Py_NewInterpreter,3.2,,
func,Py_NewRef,3.10,,
+func,Py_PACK_FULL_VERSION,3.14,,
+func,Py_PACK_VERSION,3.14,,
func,Py_REFCNT,3.14,,
func,Py_ReprEnter,3.2,,
func,Py_ReprLeave,3.2,,
diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst
index 16851b4e63ea2c..72abfebd46f2b9 100644
--- a/Doc/whatsnew/3.14.rst
+++ b/Doc/whatsnew/3.14.rst
@@ -1243,6 +1243,10 @@ New features
file.
(Contributed by Victor Stinner in :gh:`127350`.)
+* Add macros :c:func:`Py_PACK_VERSION` and :c:func:`Py_PACK_FULL_VERSION` for
+ bit-packing Python version numbers.
+ (Contributed by Petr Viktorin in :gh:`128629`.)
+
Porting to Python 3.14
----------------------
diff --git a/Include/patchlevel.h b/Include/patchlevel.h
index 6d4f719fcde5a8..eca2ca08a4337c 100644
--- a/Include/patchlevel.h
+++ b/Include/patchlevel.h
@@ -1,4 +1,5 @@
-
+#ifndef _Py_PATCHLEVEL_H
+#define _Py_PATCHLEVEL_H
/* Python version identification scheme.
When the major or minor version changes, the VERSION variable in
@@ -26,10 +27,23 @@
#define PY_VERSION "3.14.0a3+"
/*--end constants--*/
+
+#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))
+
/* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2.
Use this for numeric comparisons, e.g. #if PY_VERSION_HEX >= ... */
-#define PY_VERSION_HEX ((PY_MAJOR_VERSION << 24) | \
- (PY_MINOR_VERSION << 16) | \
- (PY_MICRO_VERSION << 8) | \
- (PY_RELEASE_LEVEL << 4) | \
- (PY_RELEASE_SERIAL << 0))
+#define PY_VERSION_HEX _Py_PACK_FULL_VERSION( \
+ PY_MAJOR_VERSION, \
+ PY_MINOR_VERSION, \
+ PY_MICRO_VERSION, \
+ PY_RELEASE_LEVEL, \
+ PY_RELEASE_SERIAL)
+
+// Public Py_PACK_VERSION is declared in pymacro.h; it needs <inttypes.h>.
+
+#endif //_Py_PATCHLEVEL_H
diff --git a/Include/pymacro.h b/Include/pymacro.h
index e0378f9d27a048..a82f347866e8d0 100644
--- a/Include/pymacro.h
+++ b/Include/pymacro.h
@@ -190,4 +190,13 @@
// "comparison of unsigned expression in '< 0' is always false".
#define _Py_IS_TYPE_SIGNED(type) ((type)(-1) <= 0)
+#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030E0000 // 3.14
+// Version helpers. These are primarily macros, but have exported equivalents.
+PyAPI_FUNC(uint32_t) Py_PACK_FULL_VERSION(int x, int y, int z, int level, int
serial);
+PyAPI_FUNC(uint32_t) Py_PACK_VERSION(int x, int y);
+#define Py_PACK_FULL_VERSION _Py_PACK_FULL_VERSION
+#define Py_PACK_VERSION(X, Y) Py_PACK_FULL_VERSION(X, Y, 0, 0, 0)
+#endif // Py_LIMITED_API < 3.14
+
+
#endif /* Py_PYMACRO_H */
diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py
index ada30181aeeca9..b62bc4c2ecd980 100644
--- a/Lib/test/test_capi/test_misc.py
+++ b/Lib/test/test_capi/test_misc.py
@@ -3335,6 +3335,49 @@ def run(self):
self.assertEqual(len(set(py_thread_ids)), len(py_thread_ids),
py_thread_ids)
+class TestVersions(unittest.TestCase):
+ full_cases = (
+ (3, 4, 1, 0xA, 2, 0x030401a2),
+ (3, 10, 0, 0xF, 0, 0x030a00f0),
+ (0x103, 0x10B, 0xFF00, -1, 0xF0, 0x030b00f0), # test masking
+ )
+ xy_cases = (
+ (3, 4, 0x03040000),
+ (3, 10, 0x030a0000),
+ (0x103, 0x10B, 0x030b0000), # test masking
+ )
+
+ def test_pack_full_version(self):
+ for *args, expected in self.full_cases:
+ with self.subTest(hexversion=hex(expected)):
+ result = _testlimitedcapi.pack_full_version(*args)
+ self.assertEqual(result, expected)
+
+ def test_pack_version(self):
+ for *args, expected in self.xy_cases:
+ with self.subTest(hexversion=hex(expected)):
+ result = _testlimitedcapi.pack_version(*args)
+ self.assertEqual(result, expected)
+
+ def test_pack_full_version_ctypes(self):
+ ctypes = import_helper.import_module('ctypes')
+ ctypes_func = ctypes.pythonapi.Py_PACK_FULL_VERSION
+ ctypes_func.restype = ctypes.c_uint32
+ ctypes_func.argtypes = [ctypes.c_int] * 5
+ for *args, expected in self.full_cases:
+ with self.subTest(hexversion=hex(expected)):
+ result = ctypes_func(*args)
+ self.assertEqual(result, expected)
+
+ def test_pack_version_ctypes(self):
+ ctypes = import_helper.import_module('ctypes')
+ ctypes_func = ctypes.pythonapi.Py_PACK_VERSION
+ ctypes_func.restype = ctypes.c_uint32
+ ctypes_func.argtypes = [ctypes.c_int] * 2
+ for *args, expected in self.xy_cases:
+ with self.subTest(hexversion=hex(expected)):
+ result = ctypes_func(*args)
+ self.assertEqual(result, expected)
if __name__ == "__main__":
unittest.main()
diff --git a/Lib/test/test_stable_abi_ctypes.py
b/Lib/test/test_stable_abi_ctypes.py
index fa08dc6a25b0ea..f3724ce6d4d15a 100644
--- a/Lib/test/test_stable_abi_ctypes.py
+++ b/Lib/test/test_stable_abi_ctypes.py
@@ -901,6 +901,8 @@ def test_windows_feature_macros(self):
"Py_MakePendingCalls",
"Py_NewInterpreter",
"Py_NewRef",
+ "Py_PACK_FULL_VERSION",
+ "Py_PACK_VERSION",
"Py_REFCNT",
"Py_ReprEnter",
"Py_ReprLeave",
diff --git
a/Misc/NEWS.d/next/C_API/2025-01-08-13-13-18.gh-issue-128629.gSmzyl.rst
b/Misc/NEWS.d/next/C_API/2025-01-08-13-13-18.gh-issue-128629.gSmzyl.rst
new file mode 100644
index 00000000000000..cde5bf38f754b6
--- /dev/null
+++ b/Misc/NEWS.d/next/C_API/2025-01-08-13-13-18.gh-issue-128629.gSmzyl.rst
@@ -0,0 +1,2 @@
+Add macros :c:func:`Py_PACK_VERSION` and :c:func:`Py_PACK_FULL_VERSION` for
+bit-packing Python version numbers.
diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml
index f9e51f0683c965..276526a1b6908e 100644
--- a/Misc/stable_abi.toml
+++ b/Misc/stable_abi.toml
@@ -2540,3 +2540,7 @@
added = '3.14'
[function.PyType_Freeze]
added = '3.14'
+[function.Py_PACK_FULL_VERSION]
+ added = '3.14'
+[function.Py_PACK_VERSION]
+ added = '3.14'
diff --git a/Modules/Setup.stdlib.in b/Modules/Setup.stdlib.in
index 52c0f883d383db..b7357f41768a2f 100644
--- a/Modules/Setup.stdlib.in
+++ b/Modules/Setup.stdlib.in
@@ -163,7 +163,7 @@
@MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c
@MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c
_testinternalcapi/test_lock.c _testinternalcapi/pytime.c
_testinternalcapi/set.c _testinternalcapi/test_critical_sections.c
@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c
_testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c
_testcapi/set.c _testcapi/list.c _testcapi/tuple.c _testcapi/getargs.c
_testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c
_testcapi/long.c _testcapi/float.c _testcapi/complex.c _testcapi/numbers.c
_testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c
_testcapi/buffer.c _testcapi/pyatomic.c _testcapi/run.c _testcapi/file.c
_testcapi/codec.c _testcapi/immortal.c _testcapi/gc.c _testcapi/hash.c
_testcapi/time.c _testcapi/bytes.c _testcapi/object.c _testcapi/monitoring.c
_testcapi/config.c
-@MODULE__TESTLIMITEDCAPI_TRUE@_testlimitedcapi _testlimitedcapi.c
_testlimitedcapi/abstract.c _testlimitedcapi/bytearray.c
_testlimitedcapi/bytes.c _testlimitedcapi/codec.c _testlimitedcapi/complex.c
_testlimitedcapi/dict.c _testlimitedcapi/eval.c _testlimitedcapi/float.c
_testlimitedcapi/heaptype_relative.c _testlimitedcapi/list.c
_testlimitedcapi/long.c _testlimitedcapi/object.c _testlimitedcapi/pyos.c
_testlimitedcapi/set.c _testlimitedcapi/sys.c _testlimitedcapi/tuple.c
_testlimitedcapi/unicode.c _testlimitedcapi/vectorcall_limited.c
+@MODULE__TESTLIMITEDCAPI_TRUE@_testlimitedcapi _testlimitedcapi.c
_testlimitedcapi/abstract.c _testlimitedcapi/bytearray.c
_testlimitedcapi/bytes.c _testlimitedcapi/codec.c _testlimitedcapi/complex.c
_testlimitedcapi/dict.c _testlimitedcapi/eval.c _testlimitedcapi/float.c
_testlimitedcapi/heaptype_relative.c _testlimitedcapi/list.c
_testlimitedcapi/long.c _testlimitedcapi/object.c _testlimitedcapi/pyos.c
_testlimitedcapi/set.c _testlimitedcapi/sys.c _testlimitedcapi/tuple.c
_testlimitedcapi/unicode.c _testlimitedcapi/vectorcall_limited.c
_testlimitedcapi/version.c
@MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c
@MODULE__TESTCLINIC_LIMITED_TRUE@_testclinic_limited _testclinic_limited.c
diff --git a/Modules/_testlimitedcapi.c b/Modules/_testlimitedcapi.c
index ba83a23117b2a5..bcc69a339ec5c4 100644
--- a/Modules/_testlimitedcapi.c
+++ b/Modules/_testlimitedcapi.c
@@ -83,5 +83,8 @@ PyInit__testlimitedcapi(void)
if (_PyTestLimitedCAPI_Init_VectorcallLimited(mod) < 0) {
return NULL;
}
+ if (_PyTestLimitedCAPI_Init_Version(mod) < 0) {
+ return NULL;
+ }
return mod;
}
diff --git a/Modules/_testlimitedcapi/clinic/version.c.h
b/Modules/_testlimitedcapi/clinic/version.c.h
new file mode 100644
index 00000000000000..096c7dd528b332
--- /dev/null
+++ b/Modules/_testlimitedcapi/clinic/version.c.h
@@ -0,0 +1,93 @@
+/*[clinic input]
+preserve
+[clinic start generated code]*/
+
+PyDoc_STRVAR(_testlimitedcapi_pack_full_version__doc__,
+"pack_full_version($module, major, minor, micro, level, serial, /)\n"
+"--\n"
+"\n");
+
+#define _TESTLIMITEDCAPI_PACK_FULL_VERSION_METHODDEF \
+ {"pack_full_version",
(PyCFunction)(void(*)(void))_testlimitedcapi_pack_full_version, METH_FASTCALL,
_testlimitedcapi_pack_full_version__doc__},
+
+static PyObject *
+_testlimitedcapi_pack_full_version_impl(PyObject *module, int major,
+ int minor, int micro, int level,
+ int serial);
+
+static PyObject *
+_testlimitedcapi_pack_full_version(PyObject *module, PyObject *const *args,
Py_ssize_t nargs)
+{
+ PyObject *return_value = NULL;
+ int major;
+ int minor;
+ int micro;
+ int level;
+ int serial;
+
+ if (nargs != 5) {
+ PyErr_Format(PyExc_TypeError, "pack_full_version expected 5 arguments,
got %zd", nargs);
+ goto exit;
+ }
+ major = PyLong_AsInt(args[0]);
+ if (major == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ minor = PyLong_AsInt(args[1]);
+ if (minor == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ micro = PyLong_AsInt(args[2]);
+ if (micro == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ level = PyLong_AsInt(args[3]);
+ if (level == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ serial = PyLong_AsInt(args[4]);
+ if (serial == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ return_value = _testlimitedcapi_pack_full_version_impl(module, major,
minor, micro, level, serial);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(_testlimitedcapi_pack_version__doc__,
+"pack_version($module, major, minor, /)\n"
+"--\n"
+"\n");
+
+#define _TESTLIMITEDCAPI_PACK_VERSION_METHODDEF \
+ {"pack_version",
(PyCFunction)(void(*)(void))_testlimitedcapi_pack_version, METH_FASTCALL,
_testlimitedcapi_pack_version__doc__},
+
+static PyObject *
+_testlimitedcapi_pack_version_impl(PyObject *module, int major, int minor);
+
+static PyObject *
+_testlimitedcapi_pack_version(PyObject *module, PyObject *const *args,
Py_ssize_t nargs)
+{
+ PyObject *return_value = NULL;
+ int major;
+ int minor;
+
+ if (nargs != 2) {
+ PyErr_Format(PyExc_TypeError, "pack_version expected 2 arguments, got
%zd", nargs);
+ goto exit;
+ }
+ major = PyLong_AsInt(args[0]);
+ if (major == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ minor = PyLong_AsInt(args[1]);
+ if (minor == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ return_value = _testlimitedcapi_pack_version_impl(module, major, minor);
+
+exit:
+ return return_value;
+}
+/*[clinic end generated code: output=aed3e226da77f2d2 input=a9049054013a1b77]*/
diff --git a/Modules/_testlimitedcapi/parts.h b/Modules/_testlimitedcapi/parts.h
index 4107b150c5b4e0..56d566b66565a3 100644
--- a/Modules/_testlimitedcapi/parts.h
+++ b/Modules/_testlimitedcapi/parts.h
@@ -40,5 +40,6 @@ int _PyTestLimitedCAPI_Init_Sys(PyObject *module);
int _PyTestLimitedCAPI_Init_Tuple(PyObject *module);
int _PyTestLimitedCAPI_Init_Unicode(PyObject *module);
int _PyTestLimitedCAPI_Init_VectorcallLimited(PyObject *module);
+int _PyTestLimitedCAPI_Init_Version(PyObject *module);
#endif // Py_TESTLIMITEDCAPI_PARTS_H
diff --git a/Modules/_testlimitedcapi/version.c
b/Modules/_testlimitedcapi/version.c
new file mode 100644
index 00000000000000..57cd6e4e928ea3
--- /dev/null
+++ b/Modules/_testlimitedcapi/version.c
@@ -0,0 +1,77 @@
+/* Test version macros in the limited API */
+
+#include "pyconfig.h" // Py_GIL_DISABLED
+#ifndef Py_GIL_DISABLED
+# define Py_LIMITED_API 0x030e0000 // Added in 3.14
+#endif
+
+#include "parts.h"
+#include "clinic/version.c.h"
+#include <stdio.h>
+
+/*[clinic input]
+module _testlimitedcapi
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=2700057f9c1135ba]*/
+
+/*[clinic input]
+_testlimitedcapi.pack_full_version
+
+ major: int
+ minor: int
+ micro: int
+ level: int
+ serial: int
+ /
+[clinic start generated code]*/
+
+static PyObject *
+_testlimitedcapi_pack_full_version_impl(PyObject *module, int major,
+ int minor, int micro, int level,
+ int serial)
+/*[clinic end generated code: output=b87a1e9805648861 input=2a304423be61d2ac]*/
+{
+ uint32_t macro_result = Py_PACK_FULL_VERSION(
+ major, minor, micro, level, serial);
+#undef Py_PACK_FULL_VERSION
+ uint32_t func_result = Py_PACK_FULL_VERSION(
+ major, minor, micro, level, serial);
+
+ assert(macro_result == func_result);
+ return PyLong_FromUnsignedLong((unsigned long)func_result);
+}
+
+/*[clinic input]
+_testlimitedcapi.pack_version
+
+ major: int
+ minor: int
+ /
+[clinic start generated code]*/
+
+static PyObject *
+_testlimitedcapi_pack_version_impl(PyObject *module, int major, int minor)
+/*[clinic end generated code: output=771247bbd06e7883 input=3e39e9dcbc09e86a]*/
+{
+ uint32_t macro_result = Py_PACK_VERSION(major, minor);
+#undef Py_PACK_VERSION
+ uint32_t func_result = Py_PACK_VERSION(major, minor);
+
+ assert(macro_result == func_result);
+ return PyLong_FromUnsignedLong((unsigned long)func_result);
+}
+
+static PyMethodDef TestMethods[] = {
+ _TESTLIMITEDCAPI_PACK_FULL_VERSION_METHODDEF
+ _TESTLIMITEDCAPI_PACK_VERSION_METHODDEF
+ {NULL},
+};
+
+int
+_PyTestLimitedCAPI_Init_Version(PyObject *m)
+{
+ if (PyModule_AddFunctions(m, TestMethods) < 0) {
+ return -1;
+ }
+ return 0;
+}
diff --git a/PC/python3dll.c b/PC/python3dll.c
index 8657ddb9fa5155..84b3c735240b73 100755
--- a/PC/python3dll.c
+++ b/PC/python3dll.c
@@ -81,6 +81,8 @@ EXPORT_FUNC(Py_Main)
EXPORT_FUNC(Py_MakePendingCalls)
EXPORT_FUNC(Py_NewInterpreter)
EXPORT_FUNC(Py_NewRef)
+EXPORT_FUNC(Py_PACK_FULL_VERSION)
+EXPORT_FUNC(Py_PACK_VERSION)
EXPORT_FUNC(Py_REFCNT)
EXPORT_FUNC(Py_ReprEnter)
EXPORT_FUNC(Py_ReprLeave)
diff --git a/PCbuild/_testlimitedcapi.vcxproj b/PCbuild/_testlimitedcapi.vcxproj
index 846e027e10c7fa..0ea5edba3aa9a7 100644
--- a/PCbuild/_testlimitedcapi.vcxproj
+++ b/PCbuild/_testlimitedcapi.vcxproj
@@ -112,6 +112,7 @@
<ClCompile Include="..\Modules\_testlimitedcapi\tuple.c" />
<ClCompile Include="..\Modules\_testlimitedcapi\unicode.c" />
<ClCompile Include="..\Modules\_testlimitedcapi\vectorcall_limited.c" />
+ <ClCompile Include="..\Modules\_testlimitedcapi\version.c" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\PC\python_nt.rc" />
diff --git a/PCbuild/_testlimitedcapi.vcxproj.filters
b/PCbuild/_testlimitedcapi.vcxproj.filters
index 57be2e2fc5b950..b379090eb599f5 100644
--- a/PCbuild/_testlimitedcapi.vcxproj.filters
+++ b/PCbuild/_testlimitedcapi.vcxproj.filters
@@ -28,6 +28,7 @@
<ClCompile Include="..\Modules\_testlimitedcapi\tuple.c" />
<ClCompile Include="..\Modules\_testlimitedcapi\unicode.c" />
<ClCompile Include="..\Modules\_testlimitedcapi\vectorcall_limited.c" />
+ <ClCompile Include="..\Modules\_testlimitedcapi\version.c" />
<ClCompile Include="..\Modules\_testlimitedcapi.c" />
</ItemGroup>
<ItemGroup>
diff --git a/Python/modsupport.c b/Python/modsupport.c
index 0fb7783345c78e..517dc971f88c87 100644
--- a/Python/modsupport.c
+++ b/Python/modsupport.c
@@ -648,3 +648,20 @@ PyModule_AddType(PyObject *module, PyTypeObject *type)
return PyModule_AddObjectRef(module, name, (PyObject *)type);
}
+
+
+/* Exported functions for version helper macros */
+
+#undef Py_PACK_FULL_VERSION
+uint32_t
+Py_PACK_FULL_VERSION(int x, int y, int z, int level, int serial)
+{
+ return _Py_PACK_FULL_VERSION(x, y, z, level, serial);
+}
+
+#undef Py_PACK_VERSION
+uint32_t
+Py_PACK_VERSION(int x, int y)
+{
+ return Py_PACK_FULL_VERSION(x, y, 0, 0, 0);
+}
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]