From 34360c8e09f51075fec0c673b2674d20bed33bf5 Mon Sep 17 00:00:00 2001 From: Martin Panter Date: Fri, 29 Jan 2016 10:12:19 +0000 Subject: Issue #19023: Document ctypes array and pointer classes Also add some more tests. Based on patch by Sye van der Veen. --- Doc/library/ctypes.rst | 58 +++++++++++++++++++++++++++++++++++++--- Lib/ctypes/test/test_arrays.py | 12 ++++++--- Lib/ctypes/test/test_pointers.py | 9 +++++-- Misc/ACKS | 1 + 4 files changed, 70 insertions(+), 10 deletions(-) diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index b72bdb4..9abd469 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -716,8 +716,8 @@ Pointer instances are created by calling the :func:`pointer` function on a >>> pi = pointer(i) >>> -Pointer instances have a :attr:`contents` attribute which returns the object to -which the pointer points, the ``i`` object above:: +Pointer instances have a :attr:`~_Pointer.contents` attribute which +returns the object to which the pointer points, the ``i`` object above:: >>> pi.contents c_long(42) @@ -2401,6 +2401,56 @@ other data types containing pointer type fields. Arrays and pointers ^^^^^^^^^^^^^^^^^^^ -Not yet written - please see the sections :ref:`ctypes-pointers` and section -:ref:`ctypes-arrays` in the tutorial. +.. class:: Array(\*args) + + Abstract base class for arrays. + + The recommended way to create concrete array types is by multiplying any + :mod:`ctypes` data type with a positive integer. Alternatively, you can subclass + this type and define :attr:`_length_` and :attr:`_type_` class variables. + Array elements can be read and written using standard + subscript and slice accesses; for slice reads, the resulting object is + *not* itself an :class:`Array`. + + + .. attribute:: _length_ + + A positive integer specifying the number of elements in the array. + Out-of-range subscripts result in an :exc:`IndexError`. Will be + returned by :func:`len`. + + + .. attribute:: _type_ + + Specifies the type of each element in the array. + + + Array subclass constructors accept positional arguments, used to + initialize the elements in order. + + +.. class:: _Pointer + + Private, abstract base class for pointers. + + Concrete pointer types are created by calling :func:`POINTER` with the + type that will be pointed to; this is done automatically by + :func:`pointer`. + + If a pointer points to an array, its elements can be read and + written using standard subscript and slice accesses. Pointer objects + have no size, so :func:`len` will raise :exc:`TypeError`. Negative + subscripts will read from the memory *before* the pointer (as in C), and + out-of-range subscripts will probably crash with an access violation (if + you're lucky). + + + .. attribute:: _type_ + + Specifies the type pointed to. + + .. attribute:: contents + + Returns the object to which to pointer points. Assigning to this + attribute changes the pointer to point to the assigned object. diff --git a/Lib/ctypes/test/test_arrays.py b/Lib/ctypes/test/test_arrays.py index 8ca77e0..4ed566b 100644 --- a/Lib/ctypes/test/test_arrays.py +++ b/Lib/ctypes/test/test_arrays.py @@ -24,20 +24,24 @@ class ArrayTestCase(unittest.TestCase): self.assertEqual(len(ia), alen) # slot values ok? - values = [ia[i] for i in range(len(init))] + values = [ia[i] for i in range(alen)] self.assertEqual(values, init) + # out-of-bounds accesses should be caught + with self.assertRaises(IndexError): ia[alen] + with self.assertRaises(IndexError): ia[-alen-1] + # change the items from operator import setitem new_values = list(range(42, 42+alen)) [setitem(ia, n, new_values[n]) for n in range(alen)] - values = [ia[i] for i in range(len(init))] + values = [ia[i] for i in range(alen)] self.assertEqual(values, new_values) # are the items initialized to 0? ia = int_array() - values = [ia[i] for i in range(len(init))] - self.assertEqual(values, [0] * len(init)) + values = [ia[i] for i in range(alen)] + self.assertEqual(values, [0] * alen) # Too many initializers should be caught self.assertRaises(IndexError, int_array, *range(alen*2)) diff --git a/Lib/ctypes/test/test_pointers.py b/Lib/ctypes/test/test_pointers.py index 225b9d1..751f85f 100644 --- a/Lib/ctypes/test/test_pointers.py +++ b/Lib/ctypes/test/test_pointers.py @@ -56,9 +56,13 @@ class PointersTestCase(unittest.TestCase): # C code: # int x = 12321; # res = &x - res.contents = c_int(12321) + x = c_int(12321) + res.contents = x self.assertEqual(i.value, 54345) + x.value = -99 + self.assertEqual(res.contents.value, -99) + def test_callbacks_with_pointers(self): # a function type receiving a pointer PROTOTYPE = CFUNCTYPE(c_int, POINTER(c_int)) @@ -131,9 +135,10 @@ class PointersTestCase(unittest.TestCase): def test_basic(self): p = pointer(c_int(42)) - # Although a pointer can be indexed, it ha no length + # Although a pointer can be indexed, it has no length self.assertRaises(TypeError, len, p) self.assertEqual(p[0], 42) + self.assertEqual(p[0:1], [42]) self.assertEqual(p.contents.value, 42) def test_charpp(self): diff --git a/Misc/ACKS b/Misc/ACKS index 93a31de..28e45d3 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1497,6 +1497,7 @@ Dmitry Vasiliev Sebastian Ortiz Vasquez Alexandre Vassalotti Nadeem Vawda +Sye van der Veen Frank Vercruesse Mike Verdone Jaap Vermeulen -- cgit v0.12 From 806cb0f2b69bc6663e2c248afeadcea54c99d377 Mon Sep 17 00:00:00 2001 From: Berker Peksag Date: Thu, 28 Jan 2016 12:42:26 +0200 Subject: Add a link to PEP 384 in stable.rst --- Doc/c-api/stable.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/c-api/stable.rst b/Doc/c-api/stable.rst index 063f856..5b771dd 100644 --- a/Doc/c-api/stable.rst +++ b/Doc/c-api/stable.rst @@ -34,5 +34,5 @@ will work on all subsequent Python releases, but fail to load (because of missing symbols) on the older releases. As of Python 3.2, the set of functions available to the limited API is -documented in PEP 384. In the C API documentation, API elements that are not +documented in :pep:`384`. In the C API documentation, API elements that are not part of the limited API are marked as "Not part of the limited API." -- cgit v0.12 From 7240030c52b5b738830c538bf849da8241c569d0 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 28 Jan 2016 15:41:01 +0100 Subject: Windows: Decode hostname from ANSI code page Issue #26227: On Windows, getnameinfo(), gethostbyaddr() and gethostbyname_ex() functions of the socket module now decode the hostname from the ANSI code page rather than UTF-8. --- Misc/NEWS | 4 ++++ Modules/socketmodule.c | 26 ++++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS index 5e461f9..d6f81db 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -66,6 +66,10 @@ Core and Builtins Library ------- +- Issue #26227: On Windows, getnameinfo(), gethostbyaddr() and + gethostbyname_ex() functions of the socket module now decode the hostname + from the ANSI code page rather than UTF-8. + - Issue #26147: xmlrpc now works with strings not encodable with used non-UTF-8 encoding. diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index bae9634..90aa3af 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -4519,6 +4519,19 @@ PyDoc_STRVAR(gethostbyname_doc, Return the IP address (a string of the form '255.255.255.255') for a host."); +static PyObject* +sock_decode_hostname(const char *name) +{ +#ifdef MS_WINDOWS + /* Issue #26227: gethostbyaddr() returns a string encoded + * to the ANSI code page */ + return PyUnicode_DecodeFSDefault(name); +#else + /* Decode from UTF-8 */ + return PyUnicode_FromString(name); +#endif +} + /* Convenience function common to gethostbyname_ex and gethostbyaddr */ static PyObject * @@ -4529,6 +4542,7 @@ gethost_common(struct hostent *h, struct sockaddr *addr, size_t alen, int af) PyObject *name_list = (PyObject *)NULL; PyObject *addr_list = (PyObject *)NULL; PyObject *tmp; + PyObject *name; if (h == NULL) { /* Let's get real error message to return */ @@ -4637,7 +4651,10 @@ gethost_common(struct hostent *h, struct sockaddr *addr, size_t alen, int af) goto err; } - rtn_tuple = Py_BuildValue("sOO", h->h_name, name_list, addr_list); + name = sock_decode_hostname(h->h_name); + if (name == NULL) + goto err; + rtn_tuple = Py_BuildValue("NOO", name, name_list, addr_list); err: Py_XDECREF(name_list); @@ -5623,6 +5640,7 @@ socket_getnameinfo(PyObject *self, PyObject *args) struct addrinfo hints, *res = NULL; int error; PyObject *ret = (PyObject *)NULL; + PyObject *name; flags = flowinfo = scope_id = 0; if (!PyArg_ParseTuple(args, "Oi:getnameinfo", &sa, &flags)) @@ -5686,7 +5704,11 @@ socket_getnameinfo(PyObject *self, PyObject *args) set_gaierror(error); goto fail; } - ret = Py_BuildValue("ss", hbuf, pbuf); + + name = sock_decode_hostname(hbuf); + if (name == NULL) + goto fail; + ret = Py_BuildValue("Ns", name, pbuf); fail: if (res) -- cgit v0.12 From ad13edb6fd590f836b7f5cb6b4b230ed0e27bc76 Mon Sep 17 00:00:00 2001 From: Berker Peksag Date: Thu, 28 Jan 2016 16:58:00 +0200 Subject: Issue #24705: Add a test case for ef84d21f5292 --- Lib/test/test_sysconfig.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py index 0917c3e..a23bf06a 100644 --- a/Lib/test/test_sysconfig.py +++ b/Lib/test/test_sysconfig.py @@ -421,6 +421,8 @@ class MakefileTests(unittest.TestCase): print("var3=42", file=makefile) print("var4=$/invalid", file=makefile) print("var5=dollar$$5", file=makefile) + print("var6=${var3}/lib/python3.5/config-$(VAR2)$(var5)" + "-x86_64-linux-gnu", file=makefile) vars = sysconfig._parse_makefile(TESTFN) self.assertEqual(vars, { 'var1': 'ab42', @@ -428,6 +430,7 @@ class MakefileTests(unittest.TestCase): 'var3': 42, 'var4': '$/invalid', 'var5': 'dollar$5', + 'var6': '42/lib/python3.5/config-b42dollar$5-x86_64-linux-gnu', }) -- cgit v0.12 From 8f475effbc860e84e266923f9c19915914cc780f Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 28 Jan 2016 18:13:45 +0100 Subject: Backport fixes on test_eintr * Issue #25234: Skip test_eintr.test_open() under OS X to avoid hanging * Issue #25868: Try to make test_eintr.test_sigwaitinfo() more reliable especially on slow buildbots. Use a pipe to synchronize the parent and the child processes. --- Lib/test/eintrdata/eintr_tester.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/Lib/test/eintrdata/eintr_tester.py b/Lib/test/eintrdata/eintr_tester.py index e3c36f9..9931a55 100644 --- a/Lib/test/eintrdata/eintr_tester.py +++ b/Lib/test/eintrdata/eintr_tester.py @@ -334,10 +334,12 @@ class SocketEINTRTest(EINTRBaseTest): self._test_open("fp = open(path, 'r')\nfp.close()", self.python_open) + @unittest.skipIf(sys.platform == 'darwin', "hangs under OS X; see issue #25234") def os_open(self, path): fd = os.open(path, os.O_WRONLY) os.close(fd) + @unittest.skipIf(sys.platform == "darwin", "hangs under OS X; see issue #25234") def test_os_open(self): self._test_open("fd = os.open(path, os.O_RDONLY)\nos.close(fd)", self.os_open) @@ -370,10 +372,10 @@ class SignalEINTRTest(EINTRBaseTest): @unittest.skipUnless(hasattr(signal, 'sigwaitinfo'), 'need signal.sigwaitinfo()') def test_sigwaitinfo(self): - # Issue #25277: The sleep is a weak synchronization between the parent - # and the child process. If the sleep is too low, the test hangs on - # slow or highly loaded systems. - self.sleep_time = 2.0 + # Issue #25277, #25868: give a few miliseconds to the parent process + # between os.write() and signal.sigwaitinfo() to works around a race + # condition + self.sleep_time = 0.100 signum = signal.SIGUSR1 pid = os.getpid() @@ -381,18 +383,28 @@ class SignalEINTRTest(EINTRBaseTest): old_handler = signal.signal(signum, lambda *args: None) self.addCleanup(signal.signal, signum, old_handler) + rpipe, wpipe = os.pipe() + code = '\n'.join(( 'import os, time', 'pid = %s' % os.getpid(), 'signum = %s' % int(signum), 'sleep_time = %r' % self.sleep_time, + 'rpipe = %r' % rpipe, + 'os.read(rpipe, 1)', + 'os.close(rpipe)', 'time.sleep(sleep_time)', 'os.kill(pid, signum)', )) t0 = time.monotonic() - proc = self.subprocess(code) + proc = self.subprocess(code, pass_fds=(rpipe,)) + os.close(rpipe) with kill_on_error(proc): + # sync child-parent + os.write(wpipe, b'x') + os.close(wpipe) + # parent signal.sigwaitinfo([signum]) dt = time.monotonic() - t0 -- cgit v0.12