]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-76007: Deprecate `__version__` attribute in `ctypes` (#142679)
authorHugo van Kemenade <1324225+hugovk@users.noreply.github.com>
Mon, 15 Dec 2025 11:30:23 +0000 (13:30 +0200)
committerGitHub <noreply@github.com>
Mon, 15 Dec 2025 11:30:23 +0000 (13:30 +0200)
Doc/deprecations/pending-removal-in-3.20.rst
Doc/whatsnew/3.15.rst
Lib/ctypes/__init__.py
Lib/test/test_ctypes/__init__.py
Misc/NEWS.d/next/Library/2025-12-13-21-19-28.gh-issue-76007.6fs_gT.rst [new file with mode: 0644]
Modules/_ctypes/_ctypes.c
Modules/_ctypes/callproc.c

index 1e517531c953e9fff549216db52f50facd1d0c70..4a6a6c3c43a7229923dd91a4e521f9fec3028827 100644 (file)
@@ -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`
index d9a34fe920d10d5a711b2d1800318a6c08e28274..ccf6c76f1e0fa53635ee53184b8541969b013af0 100644 (file)
@@ -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`
index ab5b656e6e5d6cf15e092f01690487deaa69f24e..aec92f3aee247213a426b7c32a4f8b888fcca721 100644 (file)
@@ -5,12 +5,9 @@ import sys as _sys
 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 _ctypes import CField
 
 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 @@ else:
     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}")
index eb9126cbe1808160568fb100b3dc393603a75502..d848beb1ff1857142ee366d055025b1919929a85 100644 (file)
@@ -1,4 +1,5 @@
 import os
+import unittest
 from test import support
 from test.support import import_helper
 
@@ -6,5 +7,21 @@ from test.support import import_helper
 # 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 (file)
index 0000000..99f73bb
--- /dev/null
@@ -0,0 +1 @@
+Deprecate ``__version__`` from :mod:`ctypes`. Patch by Hugo van Kemenade.
index 91fd23d413de21b223b044d1eea04189c5fc450c..774ac71ce9ec5632658580d2a2b4ca67925c88fe 100644 (file)
@@ -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));
index a8c16547e4b217bb6b1c66f0204a9cdb05a0061d..9a1c1ff8bb9cdae7c29e7140ed9d0188d7186912 100644 (file)
@@ -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 },