mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
gh-128629: Add Py_PACK_VERSION and Py_PACK_FULL_VERSION (GH-128630)
This commit is contained in:
parent
4685401845
commit
1439b81928
18 changed files with 358 additions and 33 deletions
|
@ -6,9 +6,13 @@
|
||||||
API and ABI Versioning
|
API and ABI Versioning
|
||||||
***********************
|
***********************
|
||||||
|
|
||||||
|
|
||||||
|
Build-time version constants
|
||||||
|
----------------------------
|
||||||
|
|
||||||
CPython exposes its version number in the following macros.
|
CPython exposes its version number in the following macros.
|
||||||
Note that these correspond to the version code is **built** with,
|
Note that these correspond to the version code is **built** with.
|
||||||
not necessarily the version used at **run time**.
|
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.
|
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
|
.. c:macro:: PY_VERSION_HEX
|
||||||
|
|
||||||
The Python version number encoded in a single integer.
|
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
|
Use this for numeric comparisons, for example,
|
||||||
number in the following manner:
|
``#if PY_VERSION_HEX >= ...``.
|
||||||
|
|
||||||
+-------+-------------------------+-------------------------+--------------------------+
|
|
||||||
| 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`` |
|
|
||||||
+-------+-------------------------+-------------------------+--------------------------+
|
|
||||||
|
|
||||||
Thus ``3.4.1a2`` is hexversion ``0x030401a2`` and ``3.10.0`` is
|
Run-time version
|
||||||
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`.
|
|
||||||
|
|
||||||
.. c:var:: const unsigned long Py_Version
|
.. c:var:: const unsigned long Py_Version
|
||||||
|
|
||||||
The Python runtime version number encoded in a single constant integer, with
|
The Python runtime version number encoded in a single constant integer.
|
||||||
the same format as the :c:macro:`PY_VERSION_HEX` macro.
|
See :c:func:`Py_PACK_FULL_VERSION` for the encoding details.
|
||||||
This contains the Python version used at run time.
|
This contains the Python version used at run time.
|
||||||
|
|
||||||
|
Use this for numeric comparisons, for example, ``if (Py_Version >= ...)``.
|
||||||
|
|
||||||
.. versionadded:: 3.11
|
.. 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
|
||||||
|
|
2
Doc/data/stable_abi.dat
generated
2
Doc/data/stable_abi.dat
generated
|
@ -883,6 +883,8 @@ func,Py_Main,3.2,,
|
||||||
func,Py_MakePendingCalls,3.2,,
|
func,Py_MakePendingCalls,3.2,,
|
||||||
func,Py_NewInterpreter,3.2,,
|
func,Py_NewInterpreter,3.2,,
|
||||||
func,Py_NewRef,3.10,,
|
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_REFCNT,3.14,,
|
||||||
func,Py_ReprEnter,3.2,,
|
func,Py_ReprEnter,3.2,,
|
||||||
func,Py_ReprLeave,3.2,,
|
func,Py_ReprLeave,3.2,,
|
||||||
|
|
|
@ -1243,6 +1243,10 @@ New features
|
||||||
file.
|
file.
|
||||||
(Contributed by Victor Stinner in :gh:`127350`.)
|
(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
|
Porting to Python 3.14
|
||||||
----------------------
|
----------------------
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
|
#ifndef _Py_PATCHLEVEL_H
|
||||||
|
#define _Py_PATCHLEVEL_H
|
||||||
/* Python version identification scheme.
|
/* Python version identification scheme.
|
||||||
|
|
||||||
When the major or minor version changes, the VERSION variable in
|
When the major or minor version changes, the VERSION variable in
|
||||||
|
@ -26,10 +27,23 @@
|
||||||
#define PY_VERSION "3.14.0a3+"
|
#define PY_VERSION "3.14.0a3+"
|
||||||
/*--end constants--*/
|
/*--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.
|
/* 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 >= ... */
|
Use this for numeric comparisons, e.g. #if PY_VERSION_HEX >= ... */
|
||||||
#define PY_VERSION_HEX ((PY_MAJOR_VERSION << 24) | \
|
#define PY_VERSION_HEX _Py_PACK_FULL_VERSION( \
|
||||||
(PY_MINOR_VERSION << 16) | \
|
PY_MAJOR_VERSION, \
|
||||||
(PY_MICRO_VERSION << 8) | \
|
PY_MINOR_VERSION, \
|
||||||
(PY_RELEASE_LEVEL << 4) | \
|
PY_MICRO_VERSION, \
|
||||||
(PY_RELEASE_SERIAL << 0))
|
PY_RELEASE_LEVEL, \
|
||||||
|
PY_RELEASE_SERIAL)
|
||||||
|
|
||||||
|
// Public Py_PACK_VERSION is declared in pymacro.h; it needs <inttypes.h>.
|
||||||
|
|
||||||
|
#endif //_Py_PATCHLEVEL_H
|
||||||
|
|
|
@ -190,4 +190,13 @@
|
||||||
// "comparison of unsigned expression in '< 0' is always false".
|
// "comparison of unsigned expression in '< 0' is always false".
|
||||||
#define _Py_IS_TYPE_SIGNED(type) ((type)(-1) <= 0)
|
#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 */
|
#endif /* Py_PYMACRO_H */
|
||||||
|
|
|
@ -3335,6 +3335,49 @@ class TestPyThreadId(unittest.TestCase):
|
||||||
self.assertEqual(len(set(py_thread_ids)), len(py_thread_ids),
|
self.assertEqual(len(set(py_thread_ids)), len(py_thread_ids),
|
||||||
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__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
2
Lib/test/test_stable_abi_ctypes.py
generated
2
Lib/test/test_stable_abi_ctypes.py
generated
|
@ -901,6 +901,8 @@ SYMBOL_NAMES = (
|
||||||
"Py_MakePendingCalls",
|
"Py_MakePendingCalls",
|
||||||
"Py_NewInterpreter",
|
"Py_NewInterpreter",
|
||||||
"Py_NewRef",
|
"Py_NewRef",
|
||||||
|
"Py_PACK_FULL_VERSION",
|
||||||
|
"Py_PACK_VERSION",
|
||||||
"Py_REFCNT",
|
"Py_REFCNT",
|
||||||
"Py_ReprEnter",
|
"Py_ReprEnter",
|
||||||
"Py_ReprLeave",
|
"Py_ReprLeave",
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Add macros :c:func:`Py_PACK_VERSION` and :c:func:`Py_PACK_FULL_VERSION` for
|
||||||
|
bit-packing Python version numbers.
|
|
@ -2540,3 +2540,7 @@
|
||||||
added = '3.14'
|
added = '3.14'
|
||||||
[function.PyType_Freeze]
|
[function.PyType_Freeze]
|
||||||
added = '3.14'
|
added = '3.14'
|
||||||
|
[function.Py_PACK_FULL_VERSION]
|
||||||
|
added = '3.14'
|
||||||
|
[function.Py_PACK_VERSION]
|
||||||
|
added = '3.14'
|
||||||
|
|
|
@ -163,7 +163,7 @@
|
||||||
@MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c
|
@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__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__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_TRUE@_testclinic _testclinic.c
|
||||||
@MODULE__TESTCLINIC_LIMITED_TRUE@_testclinic_limited _testclinic_limited.c
|
@MODULE__TESTCLINIC_LIMITED_TRUE@_testclinic_limited _testclinic_limited.c
|
||||||
|
|
||||||
|
|
|
@ -83,5 +83,8 @@ PyInit__testlimitedcapi(void)
|
||||||
if (_PyTestLimitedCAPI_Init_VectorcallLimited(mod) < 0) {
|
if (_PyTestLimitedCAPI_Init_VectorcallLimited(mod) < 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
if (_PyTestLimitedCAPI_Init_Version(mod) < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
return mod;
|
return mod;
|
||||||
}
|
}
|
||||||
|
|
93
Modules/_testlimitedcapi/clinic/version.c.h
generated
Normal file
93
Modules/_testlimitedcapi/clinic/version.c.h
generated
Normal file
|
@ -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]*/
|
|
@ -40,5 +40,6 @@ int _PyTestLimitedCAPI_Init_Sys(PyObject *module);
|
||||||
int _PyTestLimitedCAPI_Init_Tuple(PyObject *module);
|
int _PyTestLimitedCAPI_Init_Tuple(PyObject *module);
|
||||||
int _PyTestLimitedCAPI_Init_Unicode(PyObject *module);
|
int _PyTestLimitedCAPI_Init_Unicode(PyObject *module);
|
||||||
int _PyTestLimitedCAPI_Init_VectorcallLimited(PyObject *module);
|
int _PyTestLimitedCAPI_Init_VectorcallLimited(PyObject *module);
|
||||||
|
int _PyTestLimitedCAPI_Init_Version(PyObject *module);
|
||||||
|
|
||||||
#endif // Py_TESTLIMITEDCAPI_PARTS_H
|
#endif // Py_TESTLIMITEDCAPI_PARTS_H
|
||||||
|
|
77
Modules/_testlimitedcapi/version.c
Normal file
77
Modules/_testlimitedcapi/version.c
Normal file
|
@ -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;
|
||||||
|
}
|
2
PC/python3dll.c
generated
2
PC/python3dll.c
generated
|
@ -81,6 +81,8 @@ EXPORT_FUNC(Py_Main)
|
||||||
EXPORT_FUNC(Py_MakePendingCalls)
|
EXPORT_FUNC(Py_MakePendingCalls)
|
||||||
EXPORT_FUNC(Py_NewInterpreter)
|
EXPORT_FUNC(Py_NewInterpreter)
|
||||||
EXPORT_FUNC(Py_NewRef)
|
EXPORT_FUNC(Py_NewRef)
|
||||||
|
EXPORT_FUNC(Py_PACK_FULL_VERSION)
|
||||||
|
EXPORT_FUNC(Py_PACK_VERSION)
|
||||||
EXPORT_FUNC(Py_REFCNT)
|
EXPORT_FUNC(Py_REFCNT)
|
||||||
EXPORT_FUNC(Py_ReprEnter)
|
EXPORT_FUNC(Py_ReprEnter)
|
||||||
EXPORT_FUNC(Py_ReprLeave)
|
EXPORT_FUNC(Py_ReprLeave)
|
||||||
|
|
|
@ -112,6 +112,7 @@
|
||||||
<ClCompile Include="..\Modules\_testlimitedcapi\tuple.c" />
|
<ClCompile Include="..\Modules\_testlimitedcapi\tuple.c" />
|
||||||
<ClCompile Include="..\Modules\_testlimitedcapi\unicode.c" />
|
<ClCompile Include="..\Modules\_testlimitedcapi\unicode.c" />
|
||||||
<ClCompile Include="..\Modules\_testlimitedcapi\vectorcall_limited.c" />
|
<ClCompile Include="..\Modules\_testlimitedcapi\vectorcall_limited.c" />
|
||||||
|
<ClCompile Include="..\Modules\_testlimitedcapi\version.c" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ResourceCompile Include="..\PC\python_nt.rc" />
|
<ResourceCompile Include="..\PC\python_nt.rc" />
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
<ClCompile Include="..\Modules\_testlimitedcapi\tuple.c" />
|
<ClCompile Include="..\Modules\_testlimitedcapi\tuple.c" />
|
||||||
<ClCompile Include="..\Modules\_testlimitedcapi\unicode.c" />
|
<ClCompile Include="..\Modules\_testlimitedcapi\unicode.c" />
|
||||||
<ClCompile Include="..\Modules\_testlimitedcapi\vectorcall_limited.c" />
|
<ClCompile Include="..\Modules\_testlimitedcapi\vectorcall_limited.c" />
|
||||||
|
<ClCompile Include="..\Modules\_testlimitedcapi\version.c" />
|
||||||
<ClCompile Include="..\Modules\_testlimitedcapi.c" />
|
<ClCompile Include="..\Modules\_testlimitedcapi.c" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -648,3 +648,20 @@ PyModule_AddType(PyObject *module, PyTypeObject *type)
|
||||||
|
|
||||||
return PyModule_AddObjectRef(module, name, (PyObject *)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);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue