summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Perl <m@thp.io>2022-07-03 18:58:02 (GMT)
committerGitHub <noreply@github.com>2022-07-03 18:58:02 (GMT)
commitb296c7442be97600dc87819e885e037313883d8e (patch)
tree1bac0d27ad4aa8f047864ead58cb480057e12243
parent39c29f753e6d6f390dce5a36613c1e03f43d28ea (diff)
downloadcpython-b296c7442be97600dc87819e885e037313883d8e.zip
cpython-b296c7442be97600dc87819e885e037313883d8e.tar.gz
cpython-b296c7442be97600dc87819e885e037313883d8e.tar.bz2
gh-92869: ctypes: Add c_time_t (#92870)
Adds `ctypes.c_time_t` to represent the C `time_t` type accurately as its size varies. Primarily-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Co-authored-by: Gregory P. Smith <greg@krypto.org> [Google]
-rw-r--r--Doc/library/ctypes.rst37
-rw-r--r--Lib/ctypes/__init__.py8
-rw-r--r--Lib/test/test_ctypes/test_sizes.py3
-rw-r--r--Misc/NEWS.d/next/Library/2022-05-17-06-27-39.gh-issue-92869.t8oBkw.rst2
-rw-r--r--Modules/_ctypes/_ctypes.c1
5 files changed, 44 insertions, 7 deletions
diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst
index 52950b5..4757371 100644
--- a/Doc/library/ctypes.rst
+++ b/Doc/library/ctypes.rst
@@ -148,15 +148,14 @@ Calling functions
^^^^^^^^^^^^^^^^^
You can call these functions like any other Python callable. This example uses
-the ``time()`` function, which returns system time in seconds since the Unix
-epoch, and the ``GetModuleHandleA()`` function, which returns a win32 module
-handle.
+the ``rand()`` function, which takes no arguments and returns a pseudo-random integer::
-This example calls both functions with a ``NULL`` pointer (``None`` should be used
-as the ``NULL`` pointer)::
+ >>> print(libc.rand()) # doctest: +SKIP
+ 1804289383
+
+On Windows, you can call the ``GetModuleHandleA()`` function, which returns a win32 module
+handle (passing ``None`` as single argument to call it with a ``NULL`` pointer)::
- >>> print(libc.time(None)) # doctest: +SKIP
- 1150640792
>>> print(hex(windll.kernel32.GetModuleHandleA(None))) # doctest: +WINDOWS
0x1d000000
>>>
@@ -247,6 +246,8 @@ Fundamental data types
| :class:`c_ssize_t` | :c:type:`ssize_t` or | int |
| | :c:type:`Py_ssize_t` | |
+----------------------+------------------------------------------+----------------------------+
+| :class:`c_time_t` | :c:type:`time_t` | int |
++----------------------+------------------------------------------+----------------------------+
| :class:`c_float` | :c:type:`float` | float |
+----------------------+------------------------------------------+----------------------------+
| :class:`c_double` | :c:type:`double` | float |
@@ -447,6 +448,21 @@ By default functions are assumed to return the C :c:type:`int` type. Other
return types can be specified by setting the :attr:`restype` attribute of the
function object.
+The C prototype of ``time()`` is ``time_t time(time_t *)``. Because ``time_t``
+might be of a different type than the default return type ``int``, you should
+specify the ``restype``::
+
+ >>> libc.time.restype = c_time_t
+
+The argument types can be specified using ``argtypes``::
+
+ >>> libc.time.argtypes = (POINTER(c_time_t),)
+
+To call the function with a ``NULL`` pointer as first argument, use ``None``::
+
+ >>> print(libc.time(None)) # doctest: +SKIP
+ 1150640792
+
Here is a more advanced example, it uses the ``strchr`` function, which expects
a string pointer and a char, and returns a pointer to a string::
@@ -2275,6 +2291,13 @@ These are the fundamental ctypes data types:
.. versionadded:: 3.2
+.. class:: c_time_t
+
+ Represents the C :c:type:`time_t` datatype.
+
+ .. versionadded:: 3.12
+
+
.. class:: c_ubyte
Represents the C :c:type:`unsigned char` datatype, it interprets the value as
diff --git a/Lib/ctypes/__init__.py b/Lib/ctypes/__init__.py
index 26135ad..b94b337 100644
--- a/Lib/ctypes/__init__.py
+++ b/Lib/ctypes/__init__.py
@@ -11,6 +11,7 @@ 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
from struct import calcsize as _calcsize
@@ -563,4 +564,11 @@ for kind in [c_ushort, c_uint, c_ulong, c_ulonglong]:
elif sizeof(kind) == 8: c_uint64 = kind
del(kind)
+if SIZEOF_TIME_T == 8:
+ c_time_t = c_int64
+elif SIZEOF_TIME_T == 4:
+ c_time_t = c_int32
+else:
+ raise SystemError(f"Unexpected sizeof(time_t): {SIZEOF_TIME_T=}")
+
_reset_cache()
diff --git a/Lib/test/test_ctypes/test_sizes.py b/Lib/test/test_ctypes/test_sizes.py
index 4ceacbc..bf8d6ea 100644
--- a/Lib/test/test_ctypes/test_sizes.py
+++ b/Lib/test/test_ctypes/test_sizes.py
@@ -28,6 +28,9 @@ class SizesTestCase(unittest.TestCase):
def test_ssize_t(self):
self.assertEqual(sizeof(c_void_p), sizeof(c_ssize_t))
+ def test_time_t(self):
+ self.assertEqual(sizeof(c_time_t), SIZEOF_TIME_T)
+
if __name__ == "__main__":
unittest.main()
diff --git a/Misc/NEWS.d/next/Library/2022-05-17-06-27-39.gh-issue-92869.t8oBkw.rst b/Misc/NEWS.d/next/Library/2022-05-17-06-27-39.gh-issue-92869.t8oBkw.rst
new file mode 100644
index 0000000..7787f34
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2022-05-17-06-27-39.gh-issue-92869.t8oBkw.rst
@@ -0,0 +1,2 @@
+Added :class:`~ctypes.c_time_t` to :mod:`ctypes`, which has the same size as
+the :c:type:`time_t` type in C.
diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c
index 2c629d7..a3c7c8c 100644
--- a/Modules/_ctypes/_ctypes.c
+++ b/Modules/_ctypes/_ctypes.c
@@ -5784,6 +5784,7 @@ _ctypes_add_objects(PyObject *mod)
MOD_ADD("RTLD_GLOBAL", PyLong_FromLong(RTLD_GLOBAL));
MOD_ADD("CTYPES_MAX_ARGCOUNT", PyLong_FromLong(CTYPES_MAX_ARGCOUNT));
MOD_ADD("ArgumentError", Py_NewRef(PyExc_ArgError));
+ MOD_ADD("SIZEOF_TIME_T", PyLong_FromSsize_t(SIZEOF_TIME_T));
return 0;
#undef MOD_ADD
}