https://github.com/python/cpython/commit/38ad651b678da098400a8df8c133ebf5ced12965
commit: 38ad651b678da098400a8df8c133ebf5ced12965
branch: main
author: Hugo van Kemenade <[email protected]>
committer: hugovk <[email protected]>
date: 2025-12-15T13:30:23+02:00
summary:
gh-76007: Deprecate `__version__` attribute in `ctypes` (#142679)
files:
A Misc/NEWS.d/next/Library/2025-12-13-21-19-28.gh-issue-76007.6fs_gT.rst
M Doc/deprecations/pending-removal-in-3.20.rst
M Doc/whatsnew/3.15.rst
M Lib/ctypes/__init__.py
M Lib/test/test_ctypes/__init__.py
M Modules/_ctypes/_ctypes.c
M Modules/_ctypes/callproc.c
diff --git a/Doc/deprecations/pending-removal-in-3.20.rst
b/Doc/deprecations/pending-removal-in-3.20.rst
index 1e517531c953e9..4a6a6c3c43a722 100644
--- a/Doc/deprecations/pending-removal-in-3.20.rst
+++ b/Doc/deprecations/pending-removal-in-3.20.rst
@@ -7,6 +7,7 @@ Pending removal in Python 3.20
- :mod:`argparse`
- :mod:`csv`
+ - :mod:`ctypes`
- :mod:`!ctypes.macholib`
- :mod:`decimal` (use :data:`decimal.SPEC_VERSION` instead)
- :mod:`http.server`
diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst
index d9a34fe920d10d..ccf6c76f1e0fa5 100644
--- a/Doc/whatsnew/3.15.rst
+++ b/Doc/whatsnew/3.15.rst
@@ -1032,6 +1032,7 @@ New deprecations
- :mod:`argparse`
- :mod:`csv`
+ - :mod:`ctypes`
- :mod:`!ctypes.macholib`
- :mod:`decimal` (use :data:`decimal.SPEC_VERSION` instead)
- :mod:`http.server`
diff --git a/Lib/ctypes/__init__.py b/Lib/ctypes/__init__.py
index ab5b656e6e5d6c..aec92f3aee2472 100644
--- a/Lib/ctypes/__init__.py
+++ b/Lib/ctypes/__init__.py
@@ -5,12 +5,9 @@
import sysconfig as _sysconfig
import types as _types
-__version__ = "1.1.0"
-
from _ctypes import Union, Structure, Array
from _ctypes import _Pointer
from _ctypes import CFuncPtr as _CFuncPtr
-from _ctypes import __version__ as _ctypes_version
from _ctypes import RTLD_LOCAL, RTLD_GLOBAL
from _ctypes import ArgumentError
from _ctypes import SIZEOF_TIME_T
@@ -18,9 +15,6 @@
from struct import calcsize as _calcsize
-if __version__ != _ctypes_version:
- raise Exception("Version number mismatch", __version__, _ctypes_version)
-
if _os.name == "nt":
from _ctypes import COMError, CopyComPointer, FormatError
@@ -673,3 +667,12 @@ def DllCanUnloadNow():
raise SystemError(f"Unexpected sizeof(time_t): {SIZEOF_TIME_T=}")
_reset_cache()
+
+
+def __getattr__(name):
+ if name == "__version__":
+ from warnings import _deprecated
+
+ _deprecated("__version__", remove=(3, 20))
+ return "1.1.0" # Do not change
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
diff --git a/Lib/test/test_ctypes/__init__.py b/Lib/test/test_ctypes/__init__.py
index eb9126cbe18081..d848beb1ff1857 100644
--- a/Lib/test/test_ctypes/__init__.py
+++ b/Lib/test/test_ctypes/__init__.py
@@ -1,4 +1,5 @@
import os
+import unittest
from test import support
from test.support import import_helper
@@ -6,5 +7,21 @@
# skip tests if the _ctypes extension was not built
import_helper.import_module('ctypes')
+
+class TestModule(unittest.TestCase):
+ def test_deprecated__version__(self):
+ import ctypes
+ import _ctypes
+
+ for mod in (ctypes, _ctypes):
+ with self.subTest(mod=mod):
+ with self.assertWarnsRegex(
+ DeprecationWarning,
+ "'__version__' is deprecated and slated for removal in
Python 3.20",
+ ) as cm:
+ getattr(mod, "__version__")
+ self.assertEqual(cm.filename, __file__)
+
+
def load_tests(*args):
return support.load_package_tests(os.path.dirname(__file__), *args)
diff --git
a/Misc/NEWS.d/next/Library/2025-12-13-21-19-28.gh-issue-76007.6fs_gT.rst
b/Misc/NEWS.d/next/Library/2025-12-13-21-19-28.gh-issue-76007.6fs_gT.rst
new file mode 100644
index 00000000000000..99f73bb094c620
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-12-13-21-19-28.gh-issue-76007.6fs_gT.rst
@@ -0,0 +1 @@
+Deprecate ``__version__`` from :mod:`ctypes`. Patch by Hugo van Kemenade.
diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c
index 91fd23d413de21..774ac71ce9ec56 100644
--- a/Modules/_ctypes/_ctypes.c
+++ b/Modules/_ctypes/_ctypes.c
@@ -6334,7 +6334,6 @@ _ctypes_add_objects(PyObject *mod)
MOD_ADD("FUNCFLAG_USE_ERRNO", PyLong_FromLong(FUNCFLAG_USE_ERRNO));
MOD_ADD("FUNCFLAG_USE_LASTERROR", PyLong_FromLong(FUNCFLAG_USE_LASTERROR));
MOD_ADD("FUNCFLAG_PYTHONAPI", PyLong_FromLong(FUNCFLAG_PYTHONAPI));
- MOD_ADD("__version__", PyUnicode_FromString("1.1.0"));
MOD_ADD("_memmove_addr", PyLong_FromVoidPtr(memmove));
MOD_ADD("_memset_addr", PyLong_FromVoidPtr(memset));
diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c
index a8c16547e4b217..9a1c1ff8bb9cda 100644
--- a/Modules/_ctypes/callproc.c
+++ b/Modules/_ctypes/callproc.c
@@ -1990,8 +1990,32 @@ buffer_info(PyObject *self, PyObject *arg)
}
+static PyObject *
+_ctypes_getattr(PyObject *Py_UNUSED(self), PyObject *args)
+{
+ PyObject *name;
+ if (!PyArg_UnpackTuple(args, "__getattr__", 1, 1, &name)) {
+ return NULL;
+ }
+
+ if (PyUnicode_Check(name) && PyUnicode_EqualToUTF8(name, "__version__")) {
+ if (PyErr_WarnEx(PyExc_DeprecationWarning,
+ "'__version__' is deprecated and slated for "
+ "removal in Python 3.20",
+ 1) < 0) {
+ return NULL;
+ }
+ return PyUnicode_FromString("1.1.0"); // Do not change
+ }
+
+ PyErr_Format(PyExc_AttributeError,
+ "module '_ctypes' has no attribute %R", name);
+ return NULL;
+}
+
PyMethodDef _ctypes_module_methods[] = {
+ {"__getattr__", _ctypes_getattr, METH_VARARGS},
{"get_errno", get_errno, METH_NOARGS},
{"set_errno", set_errno, METH_VARARGS},
{"_unpickle", unpickle, METH_VARARGS },
_______________________________________________
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]