Skip to content

Commit 38ad651

Browse files
authored
gh-76007: Deprecate __version__ attribute in ctypes (#142679)
1 parent fb554ad commit 38ad651

File tree

7 files changed

+53
-7
lines changed

7 files changed

+53
-7
lines changed

Doc/deprecations/pending-removal-in-3.20.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Pending removal in Python 3.20
77

88
- :mod:`argparse`
99
- :mod:`csv`
10+
- :mod:`ctypes`
1011
- :mod:`!ctypes.macholib`
1112
- :mod:`decimal` (use :data:`decimal.SPEC_VERSION` instead)
1213
- :mod:`http.server`

Doc/whatsnew/3.15.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,6 +1032,7 @@ New deprecations
10321032

10331033
- :mod:`argparse`
10341034
- :mod:`csv`
1035+
- :mod:`ctypes`
10351036
- :mod:`!ctypes.macholib`
10361037
- :mod:`decimal` (use :data:`decimal.SPEC_VERSION` instead)
10371038
- :mod:`http.server`

Lib/ctypes/__init__.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,16 @@
55
import sysconfig as _sysconfig
66
import types as _types
77

8-
__version__ = "1.1.0"
9-
108
from _ctypes import Union, Structure, Array
119
from _ctypes import _Pointer
1210
from _ctypes import CFuncPtr as _CFuncPtr
13-
from _ctypes import __version__ as _ctypes_version
1411
from _ctypes import RTLD_LOCAL, RTLD_GLOBAL
1512
from _ctypes import ArgumentError
1613
from _ctypes import SIZEOF_TIME_T
1714
from _ctypes import CField
1815

1916
from struct import calcsize as _calcsize
2017

21-
if __version__ != _ctypes_version:
22-
raise Exception("Version number mismatch", __version__, _ctypes_version)
23-
2418
if _os.name == "nt":
2519
from _ctypes import COMError, CopyComPointer, FormatError
2620

@@ -673,3 +667,12 @@ def DllCanUnloadNow():
673667
raise SystemError(f"Unexpected sizeof(time_t): {SIZEOF_TIME_T=}")
674668

675669
_reset_cache()
670+
671+
672+
def __getattr__(name):
673+
if name == "__version__":
674+
from warnings import _deprecated
675+
676+
_deprecated("__version__", remove=(3, 20))
677+
return "1.1.0" # Do not change
678+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")

Lib/test/test_ctypes/__init__.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,27 @@
11
import os
2+
import unittest
23
from test import support
34
from test.support import import_helper
45

56

67
# skip tests if the _ctypes extension was not built
78
import_helper.import_module('ctypes')
89

10+
11+
class TestModule(unittest.TestCase):
12+
def test_deprecated__version__(self):
13+
import ctypes
14+
import _ctypes
15+
16+
for mod in (ctypes, _ctypes):
17+
with self.subTest(mod=mod):
18+
with self.assertWarnsRegex(
19+
DeprecationWarning,
20+
"'__version__' is deprecated and slated for removal in Python 3.20",
21+
) as cm:
22+
getattr(mod, "__version__")
23+
self.assertEqual(cm.filename, __file__)
24+
25+
926
def load_tests(*args):
1027
return support.load_package_tests(os.path.dirname(__file__), *args)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Deprecate ``__version__`` from :mod:`ctypes`. Patch by Hugo van Kemenade.

Modules/_ctypes/_ctypes.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6334,7 +6334,6 @@ _ctypes_add_objects(PyObject *mod)
63346334
MOD_ADD("FUNCFLAG_USE_ERRNO", PyLong_FromLong(FUNCFLAG_USE_ERRNO));
63356335
MOD_ADD("FUNCFLAG_USE_LASTERROR", PyLong_FromLong(FUNCFLAG_USE_LASTERROR));
63366336
MOD_ADD("FUNCFLAG_PYTHONAPI", PyLong_FromLong(FUNCFLAG_PYTHONAPI));
6337-
MOD_ADD("__version__", PyUnicode_FromString("1.1.0"));
63386337

63396338
MOD_ADD("_memmove_addr", PyLong_FromVoidPtr(memmove));
63406339
MOD_ADD("_memset_addr", PyLong_FromVoidPtr(memset));

Modules/_ctypes/callproc.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1990,8 +1990,32 @@ buffer_info(PyObject *self, PyObject *arg)
19901990
}
19911991

19921992

1993+
static PyObject *
1994+
_ctypes_getattr(PyObject *Py_UNUSED(self), PyObject *args)
1995+
{
1996+
PyObject *name;
1997+
if (!PyArg_UnpackTuple(args, "__getattr__", 1, 1, &name)) {
1998+
return NULL;
1999+
}
2000+
2001+
if (PyUnicode_Check(name) && PyUnicode_EqualToUTF8(name, "__version__")) {
2002+
if (PyErr_WarnEx(PyExc_DeprecationWarning,
2003+
"'__version__' is deprecated and slated for "
2004+
"removal in Python 3.20",
2005+
1) < 0) {
2006+
return NULL;
2007+
}
2008+
return PyUnicode_FromString("1.1.0"); // Do not change
2009+
}
2010+
2011+
PyErr_Format(PyExc_AttributeError,
2012+
"module '_ctypes' has no attribute %R", name);
2013+
return NULL;
2014+
}
2015+
19932016

19942017
PyMethodDef _ctypes_module_methods[] = {
2018+
{"__getattr__", _ctypes_getattr, METH_VARARGS},
19952019
{"get_errno", get_errno, METH_NOARGS},
19962020
{"set_errno", set_errno, METH_VARARGS},
19972021
{"_unpickle", unpickle, METH_VARARGS },

0 commit comments

Comments
 (0)