[Python-checkins] bpo-20260: Implement non-bitwise unsigned int converters for Argument Clinic. (GH-8434)

Serhiy Storchaka webhook-mailer at python.org
Thu Jul 26 06:22:19 EDT 2018


https://github.com/python/cpython/commit/7cb7bcff20a386bba59cbc51e2419542de358bd2
commit: 7cb7bcff20a386bba59cbc51e2419542de358bd2
branch: master
author: Serhiy Storchaka <storchaka at gmail.com>
committer: GitHub <noreply at github.com>
date: 2018-07-26T13:22:16+03:00
summary:

bpo-20260: Implement non-bitwise unsigned int converters for Argument Clinic. (GH-8434)

files:
A Misc/NEWS.d/next/Tools-Demos/2018-07-24-00-11-44.bpo-20260.klmmqI.rst
M Doc/howto/clinic.rst
M Include/longobject.h
M Lib/test/test_hashlib.py
M Lib/test/test_poll.py
M Modules/_blake2/blake2b_impl.c
M Modules/_blake2/blake2s_impl.c
M Modules/_blake2/clinic/blake2b_impl.c.h
M Modules/_blake2/clinic/blake2s_impl.c.h
M Modules/clinic/selectmodule.c.h
M Modules/selectmodule.c
M Objects/longobject.c
M Tools/clinic/clinic.py

diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst
index 695fbb1be192..c75c31c98319 100644
--- a/Doc/howto/clinic.rst
+++ b/Doc/howto/clinic.rst
@@ -878,6 +878,12 @@ converter::
     Write a pickled representation of obj to the open file.
     [clinic start generated code]*/
 
+One advantage of real converters is that they're more flexible than legacy
+converters.  For example, the ``unsigned_int`` converter (and all the
+``unsigned_`` converters) can be specified without ``bitwise=True``.  Their
+default behavior performs range checking on the value, and they won't accept
+negative numbers.  You just can't do that with a legacy converter!
+
 Argument Clinic will show you all the converters it has
 available.  For each converter it'll show you all the parameters
 it accepts, along with the default value for each parameter.
diff --git a/Include/longobject.h b/Include/longobject.h
index 7bdd0472baaa..82c06c92a638 100644
--- a/Include/longobject.h
+++ b/Include/longobject.h
@@ -65,6 +65,14 @@ PyAPI_FUNC(PyObject *) PyLong_GetInfo(void);
 #  error "void* different in size from int, long and long long"
 #endif /* SIZEOF_VOID_P */
 
+#ifndef Py_LIMITED_API
+PyAPI_FUNC(int) _PyLong_UnsignedShort_Converter(PyObject *, void *);
+PyAPI_FUNC(int) _PyLong_UnsignedInt_Converter(PyObject *, void *);
+PyAPI_FUNC(int) _PyLong_UnsignedLong_Converter(PyObject *, void *);
+PyAPI_FUNC(int) _PyLong_UnsignedLongLong_Converter(PyObject *, void *);
+PyAPI_FUNC(int) _PyLong_Size_t_Converter(PyObject *, void *);
+#endif
+
 /* Used by Python/mystrtoul.c, _PyBytes_FromHex(),
    _PyBytes_DecodeEscapeRecode(), etc. */
 #ifndef Py_LIMITED_API
diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py
index 5b0218b08567..0f76b24cbb0f 100644
--- a/Lib/test/test_hashlib.py
+++ b/Lib/test/test_hashlib.py
@@ -560,12 +560,12 @@ def check_blake2(self, constructor, salt_size, person_size, key_size,
 
         constructor(leaf_size=0)
         constructor(leaf_size=(1<<32)-1)
-        self.assertRaises(OverflowError, constructor, leaf_size=-1)
+        self.assertRaises(ValueError, constructor, leaf_size=-1)
         self.assertRaises(OverflowError, constructor, leaf_size=1<<32)
 
         constructor(node_offset=0)
         constructor(node_offset=max_offset)
-        self.assertRaises(OverflowError, constructor, node_offset=-1)
+        self.assertRaises(ValueError, constructor, node_offset=-1)
         self.assertRaises(OverflowError, constructor, node_offset=max_offset+1)
 
         constructor(
diff --git a/Lib/test/test_poll.py b/Lib/test/test_poll.py
index d593495a999f..445032dfb841 100644
--- a/Lib/test/test_poll.py
+++ b/Lib/test/test_poll.py
@@ -159,9 +159,9 @@ def test_poll3(self):
             self.fail('Overflow must have occurred')
 
         # Issues #15989, #17919
-        self.assertRaises(OverflowError, pollster.register, 0, -1)
+        self.assertRaises(ValueError, pollster.register, 0, -1)
         self.assertRaises(OverflowError, pollster.register, 0, 1 << 64)
-        self.assertRaises(OverflowError, pollster.modify, 1, -1)
+        self.assertRaises(ValueError, pollster.modify, 1, -1)
         self.assertRaises(OverflowError, pollster.modify, 1, 1 << 64)
 
     @cpython_only
diff --git a/Misc/NEWS.d/next/Tools-Demos/2018-07-24-00-11-44.bpo-20260.klmmqI.rst b/Misc/NEWS.d/next/Tools-Demos/2018-07-24-00-11-44.bpo-20260.klmmqI.rst
new file mode 100644
index 000000000000..f8d0df0ca585
--- /dev/null
+++ b/Misc/NEWS.d/next/Tools-Demos/2018-07-24-00-11-44.bpo-20260.klmmqI.rst
@@ -0,0 +1 @@
+Argument Clinic now has non-bitwise unsigned int converters.
diff --git a/Modules/_blake2/blake2b_impl.c b/Modules/_blake2/blake2b_impl.c
index 822b9f285caf..92d7c5c3a2da 100644
--- a/Modules/_blake2/blake2b_impl.c
+++ b/Modules/_blake2/blake2b_impl.c
@@ -75,8 +75,8 @@ _blake2b.blake2b.__new__ as py_blake2b_new
     person: Py_buffer = None
     fanout: int = 1
     depth: int = 1
-    leaf_size as leaf_size_obj: object = NULL
-    node_offset as node_offset_obj: object = NULL
+    leaf_size: unsigned_long = 0
+    node_offset: unsigned_long_long = 0
     node_depth: int = 0
     inner_size: int = 0
     last_node: bool = False
@@ -87,17 +87,14 @@ Return a new BLAKE2b hash object.
 static PyObject *
 py_blake2b_new_impl(PyTypeObject *type, PyObject *data, int digest_size,
                     Py_buffer *key, Py_buffer *salt, Py_buffer *person,
-                    int fanout, int depth, PyObject *leaf_size_obj,
-                    PyObject *node_offset_obj, int node_depth,
+                    int fanout, int depth, unsigned long leaf_size,
+                    unsigned long long node_offset, int node_depth,
                     int inner_size, int last_node)
-/*[clinic end generated code: output=7506d8d890e5f13b input=e41548dfa0866031]*/
+/*[clinic end generated code: output=65e732c66c2297a0 input=75ab5196b695adee]*/
 {
     BLAKE2bObject *self = NULL;
     Py_buffer buf;
 
-    unsigned long leaf_size = 0;
-    unsigned long long node_offset = 0;
-
     self = new_BLAKE2bObject(type);
     if (self == NULL) {
         goto error;
@@ -152,25 +149,13 @@ py_blake2b_new_impl(PyTypeObject *type, PyObject *data, int digest_size,
     }
     self->param.depth = (uint8_t)depth;
 
-    if (leaf_size_obj != NULL) {
-        leaf_size = PyLong_AsUnsignedLong(leaf_size_obj);
-        if (leaf_size == (unsigned long) -1 && PyErr_Occurred()) {
-            goto error;
-        }
-        if (leaf_size > 0xFFFFFFFFU) {
-            PyErr_SetString(PyExc_OverflowError, "leaf_size is too large");
-            goto error;
-        }
+    if (leaf_size > 0xFFFFFFFFU) {
+        PyErr_SetString(PyExc_OverflowError, "leaf_size is too large");
+        goto error;
     }
     // NB: Simple assignment here would be incorrect on big endian platforms.
     store32(&(self->param.leaf_length), leaf_size);
 
-    if (node_offset_obj != NULL) {
-        node_offset = PyLong_AsUnsignedLongLong(node_offset_obj);
-        if (node_offset == (unsigned long long) -1 && PyErr_Occurred()) {
-            goto error;
-        }
-    }
 #ifdef HAVE_BLAKE2S
     if (node_offset > 0xFFFFFFFFFFFFULL) {
         /* maximum 2**48 - 1 */
diff --git a/Modules/_blake2/blake2s_impl.c b/Modules/_blake2/blake2s_impl.c
index 3b76c9cd89d7..8c49082377f4 100644
--- a/Modules/_blake2/blake2s_impl.c
+++ b/Modules/_blake2/blake2s_impl.c
@@ -75,8 +75,8 @@ _blake2s.blake2s.__new__ as py_blake2s_new
     person: Py_buffer = None
     fanout: int = 1
     depth: int = 1
-    leaf_size as leaf_size_obj: object = NULL
-    node_offset as node_offset_obj: object = NULL
+    leaf_size: unsigned_long = 0
+    node_offset: unsigned_long_long = 0
     node_depth: int = 0
     inner_size: int = 0
     last_node: bool = False
@@ -87,17 +87,14 @@ Return a new BLAKE2s hash object.
 static PyObject *
 py_blake2s_new_impl(PyTypeObject *type, PyObject *data, int digest_size,
                     Py_buffer *key, Py_buffer *salt, Py_buffer *person,
-                    int fanout, int depth, PyObject *leaf_size_obj,
-                    PyObject *node_offset_obj, int node_depth,
+                    int fanout, int depth, unsigned long leaf_size,
+                    unsigned long long node_offset, int node_depth,
                     int inner_size, int last_node)
-/*[clinic end generated code: output=fe060b258a8cbfc6 input=458cfdcb3d0d47ff]*/
+/*[clinic end generated code: output=b95806be0514dcf7 input=f18d6efd9b9a1271]*/
 {
     BLAKE2sObject *self = NULL;
     Py_buffer buf;
 
-    unsigned long leaf_size = 0;
-    unsigned long long node_offset = 0;
-
     self = new_BLAKE2sObject(type);
     if (self == NULL) {
         goto error;
@@ -152,25 +149,13 @@ py_blake2s_new_impl(PyTypeObject *type, PyObject *data, int digest_size,
     }
     self->param.depth = (uint8_t)depth;
 
-    if (leaf_size_obj != NULL) {
-        leaf_size = PyLong_AsUnsignedLong(leaf_size_obj);
-        if (leaf_size == (unsigned long) -1 && PyErr_Occurred()) {
-            goto error;
-        }
-        if (leaf_size > 0xFFFFFFFFU) {
-            PyErr_SetString(PyExc_OverflowError, "leaf_size is too large");
-            goto error;
-        }
+    if (leaf_size > 0xFFFFFFFFU) {
+        PyErr_SetString(PyExc_OverflowError, "leaf_size is too large");
+        goto error;
     }
     // NB: Simple assignment here would be incorrect on big endian platforms.
     store32(&(self->param.leaf_length), leaf_size);
 
-    if (node_offset_obj != NULL) {
-        node_offset = PyLong_AsUnsignedLongLong(node_offset_obj);
-        if (node_offset == (unsigned long long) -1 && PyErr_Occurred()) {
-            goto error;
-        }
-    }
 #ifdef HAVE_BLAKE2S
     if (node_offset > 0xFFFFFFFFFFFFULL) {
         /* maximum 2**48 - 1 */
diff --git a/Modules/_blake2/clinic/blake2b_impl.c.h b/Modules/_blake2/clinic/blake2b_impl.c.h
index 71c073aa36c6..3cb70fb18f5f 100644
--- a/Modules/_blake2/clinic/blake2b_impl.c.h
+++ b/Modules/_blake2/clinic/blake2b_impl.c.h
@@ -5,7 +5,7 @@ preserve
 PyDoc_STRVAR(py_blake2b_new__doc__,
 "blake2b(string=None, *, digest_size=_blake2b.blake2b.MAX_DIGEST_SIZE,\n"
 "        key=None, salt=None, person=None, fanout=1, depth=1,\n"
-"        leaf_size=None, node_offset=None, node_depth=0, inner_size=0,\n"
+"        leaf_size=0, node_offset=0, node_depth=0, inner_size=0,\n"
 "        last_node=False)\n"
 "--\n"
 "\n"
@@ -14,8 +14,8 @@ PyDoc_STRVAR(py_blake2b_new__doc__,
 static PyObject *
 py_blake2b_new_impl(PyTypeObject *type, PyObject *data, int digest_size,
                     Py_buffer *key, Py_buffer *salt, Py_buffer *person,
-                    int fanout, int depth, PyObject *leaf_size_obj,
-                    PyObject *node_offset_obj, int node_depth,
+                    int fanout, int depth, unsigned long leaf_size,
+                    unsigned long long node_offset, int node_depth,
                     int inner_size, int last_node);
 
 static PyObject *
@@ -23,7 +23,7 @@ py_blake2b_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
 {
     PyObject *return_value = NULL;
     static const char * const _keywords[] = {"string", "digest_size", "key", "salt", "person", "fanout", "depth", "leaf_size", "node_offset", "node_depth", "inner_size", "last_node", NULL};
-    static _PyArg_Parser _parser = {"|O$iy*y*y*iiOOiip:blake2b", _keywords, 0};
+    static _PyArg_Parser _parser = {"|O$iy*y*y*iiO&O&iip:blake2b", _keywords, 0};
     PyObject *data = NULL;
     int digest_size = BLAKE2B_OUTBYTES;
     Py_buffer key = {NULL, NULL};
@@ -31,17 +31,17 @@ py_blake2b_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
     Py_buffer person = {NULL, NULL};
     int fanout = 1;
     int depth = 1;
-    PyObject *leaf_size_obj = NULL;
-    PyObject *node_offset_obj = NULL;
+    unsigned long leaf_size = 0;
+    unsigned long long node_offset = 0;
     int node_depth = 0;
     int inner_size = 0;
     int last_node = 0;
 
     if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser,
-        &data, &digest_size, &key, &salt, &person, &fanout, &depth, &leaf_size_obj, &node_offset_obj, &node_depth, &inner_size, &last_node)) {
+        &data, &digest_size, &key, &salt, &person, &fanout, &depth, _PyLong_UnsignedLong_Converter, &leaf_size, _PyLong_UnsignedLongLong_Converter, &node_offset, &node_depth, &inner_size, &last_node)) {
         goto exit;
     }
-    return_value = py_blake2b_new_impl(type, data, digest_size, &key, &salt, &person, fanout, depth, leaf_size_obj, node_offset_obj, node_depth, inner_size, last_node);
+    return_value = py_blake2b_new_impl(type, data, digest_size, &key, &salt, &person, fanout, depth, leaf_size, node_offset, node_depth, inner_size, last_node);
 
 exit:
     /* Cleanup for key */
@@ -122,4 +122,4 @@ _blake2b_blake2b_hexdigest(BLAKE2bObject *self, PyObject *Py_UNUSED(ignored))
 {
     return _blake2b_blake2b_hexdigest_impl(self);
 }
-/*[clinic end generated code: output=535a54852c98e51c input=a9049054013a1b77]*/
+/*[clinic end generated code: output=afc5c45dff0a24f9 input=a9049054013a1b77]*/
diff --git a/Modules/_blake2/clinic/blake2s_impl.c.h b/Modules/_blake2/clinic/blake2s_impl.c.h
index ca908d393b5b..b444f7bb0d92 100644
--- a/Modules/_blake2/clinic/blake2s_impl.c.h
+++ b/Modules/_blake2/clinic/blake2s_impl.c.h
@@ -5,7 +5,7 @@ preserve
 PyDoc_STRVAR(py_blake2s_new__doc__,
 "blake2s(string=None, *, digest_size=_blake2s.blake2s.MAX_DIGEST_SIZE,\n"
 "        key=None, salt=None, person=None, fanout=1, depth=1,\n"
-"        leaf_size=None, node_offset=None, node_depth=0, inner_size=0,\n"
+"        leaf_size=0, node_offset=0, node_depth=0, inner_size=0,\n"
 "        last_node=False)\n"
 "--\n"
 "\n"
@@ -14,8 +14,8 @@ PyDoc_STRVAR(py_blake2s_new__doc__,
 static PyObject *
 py_blake2s_new_impl(PyTypeObject *type, PyObject *data, int digest_size,
                     Py_buffer *key, Py_buffer *salt, Py_buffer *person,
-                    int fanout, int depth, PyObject *leaf_size_obj,
-                    PyObject *node_offset_obj, int node_depth,
+                    int fanout, int depth, unsigned long leaf_size,
+                    unsigned long long node_offset, int node_depth,
                     int inner_size, int last_node);
 
 static PyObject *
@@ -23,7 +23,7 @@ py_blake2s_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
 {
     PyObject *return_value = NULL;
     static const char * const _keywords[] = {"string", "digest_size", "key", "salt", "person", "fanout", "depth", "leaf_size", "node_offset", "node_depth", "inner_size", "last_node", NULL};
-    static _PyArg_Parser _parser = {"|O$iy*y*y*iiOOiip:blake2s", _keywords, 0};
+    static _PyArg_Parser _parser = {"|O$iy*y*y*iiO&O&iip:blake2s", _keywords, 0};
     PyObject *data = NULL;
     int digest_size = BLAKE2S_OUTBYTES;
     Py_buffer key = {NULL, NULL};
@@ -31,17 +31,17 @@ py_blake2s_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
     Py_buffer person = {NULL, NULL};
     int fanout = 1;
     int depth = 1;
-    PyObject *leaf_size_obj = NULL;
-    PyObject *node_offset_obj = NULL;
+    unsigned long leaf_size = 0;
+    unsigned long long node_offset = 0;
     int node_depth = 0;
     int inner_size = 0;
     int last_node = 0;
 
     if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser,
-        &data, &digest_size, &key, &salt, &person, &fanout, &depth, &leaf_size_obj, &node_offset_obj, &node_depth, &inner_size, &last_node)) {
+        &data, &digest_size, &key, &salt, &person, &fanout, &depth, _PyLong_UnsignedLong_Converter, &leaf_size, _PyLong_UnsignedLongLong_Converter, &node_offset, &node_depth, &inner_size, &last_node)) {
         goto exit;
     }
-    return_value = py_blake2s_new_impl(type, data, digest_size, &key, &salt, &person, fanout, depth, leaf_size_obj, node_offset_obj, node_depth, inner_size, last_node);
+    return_value = py_blake2s_new_impl(type, data, digest_size, &key, &salt, &person, fanout, depth, leaf_size, node_offset, node_depth, inner_size, last_node);
 
 exit:
     /* Cleanup for key */
@@ -122,4 +122,4 @@ _blake2s_blake2s_hexdigest(BLAKE2sObject *self, PyObject *Py_UNUSED(ignored))
 {
     return _blake2s_blake2s_hexdigest_impl(self);
 }
-/*[clinic end generated code: output=535ea7903f9ccf76 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=b705723d16f21f57 input=a9049054013a1b77]*/
diff --git a/Modules/clinic/selectmodule.c.h b/Modules/clinic/selectmodule.c.h
index f66ceaab3ccb..b87b3906f116 100644
--- a/Modules/clinic/selectmodule.c.h
+++ b/Modules/clinic/selectmodule.c.h
@@ -83,7 +83,7 @@ select_poll_register(pollObject *self, PyObject *const *args, Py_ssize_t nargs)
     unsigned short eventmask = POLLIN | POLLPRI | POLLOUT;
 
     if (!_PyArg_ParseStack(args, nargs, "O&|O&:register",
-        fildes_converter, &fd, ushort_converter, &eventmask)) {
+        fildes_converter, &fd, _PyLong_UnsignedShort_Converter, &eventmask)) {
         goto exit;
     }
     return_value = select_poll_register_impl(self, fd, eventmask);
@@ -122,7 +122,7 @@ select_poll_modify(pollObject *self, PyObject *const *args, Py_ssize_t nargs)
     unsigned short eventmask;
 
     if (!_PyArg_ParseStack(args, nargs, "O&O&:modify",
-        fildes_converter, &fd, ushort_converter, &eventmask)) {
+        fildes_converter, &fd, _PyLong_UnsignedShort_Converter, &eventmask)) {
         goto exit;
     }
     return_value = select_poll_modify_impl(self, fd, eventmask);
@@ -229,7 +229,7 @@ select_devpoll_register(devpollObject *self, PyObject *const *args, Py_ssize_t n
     unsigned short eventmask = POLLIN | POLLPRI | POLLOUT;
 
     if (!_PyArg_ParseStack(args, nargs, "O&|O&:register",
-        fildes_converter, &fd, ushort_converter, &eventmask)) {
+        fildes_converter, &fd, _PyLong_UnsignedShort_Converter, &eventmask)) {
         goto exit;
     }
     return_value = select_devpoll_register_impl(self, fd, eventmask);
@@ -269,7 +269,7 @@ select_devpoll_modify(devpollObject *self, PyObject *const *args, Py_ssize_t nar
     unsigned short eventmask = POLLIN | POLLPRI | POLLOUT;
 
     if (!_PyArg_ParseStack(args, nargs, "O&|O&:modify",
-        fildes_converter, &fd, ushort_converter, &eventmask)) {
+        fildes_converter, &fd, _PyLong_UnsignedShort_Converter, &eventmask)) {
         goto exit;
     }
     return_value = select_devpoll_modify_impl(self, fd, eventmask);
@@ -1047,4 +1047,4 @@ select_kqueue_control(kqueue_queue_Object *self, PyObject *const *args, Py_ssize
 #ifndef SELECT_KQUEUE_CONTROL_METHODDEF
     #define SELECT_KQUEUE_CONTROL_METHODDEF
 #endif /* !defined(SELECT_KQUEUE_CONTROL_METHODDEF) */
-/*[clinic end generated code: output=3e425445d49c49e2 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=561bec8bcb0e00c5 input=a9049054013a1b77]*/
diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c
index 9ad6f8bdb7ae..15aca2724a2c 100644
--- a/Modules/selectmodule.c
+++ b/Modules/selectmodule.c
@@ -430,30 +430,12 @@ update_ufd_array(pollObject *self)
     return 1;
 }
 
-static int
-ushort_converter(PyObject *obj, void *ptr)
-{
-    unsigned long uval;
-
-    uval = PyLong_AsUnsignedLong(obj);
-    if (uval == (unsigned long)-1 && PyErr_Occurred())
-        return 0;
-    if (uval > USHRT_MAX) {
-        PyErr_SetString(PyExc_OverflowError,
-                        "Python int too large for C unsigned short");
-        return 0;
-    }
-
-    *(unsigned short *)ptr = Py_SAFE_DOWNCAST(uval, unsigned long, unsigned short);
-    return 1;
-}
-
 /*[clinic input]
 select.poll.register
 
     fd: fildes
       either an integer, or an object with a fileno() method returning an int
-    eventmask: object(converter="ushort_converter", type="unsigned short", c_default="POLLIN | POLLPRI | POLLOUT") = POLLIN | POLLPRI | POLLOUT
+    eventmask: unsigned_short(c_default="POLLIN | POLLPRI | POLLOUT") = POLLIN | POLLPRI | POLLOUT
       an optional bitmask describing the type of events to check for
     /
 
@@ -462,7 +444,7 @@ Register a file descriptor with the polling object.
 
 static PyObject *
 select_poll_register_impl(pollObject *self, int fd, unsigned short eventmask)
-/*[clinic end generated code: output=0dc7173c800a4a65 input=499d96a2836217f5]*/
+/*[clinic end generated code: output=0dc7173c800a4a65 input=f18711d9bb021e25]*/
 {
     PyObject *key, *value;
     int err;
@@ -495,7 +477,7 @@ select.poll.modify
     fd: fildes
       either an integer, or an object with a fileno() method returning
       an int
-    eventmask: object(converter="ushort_converter", type="unsigned short")
+    eventmask: unsigned_short
       a bitmask describing the type of events to check for
     /
 
@@ -504,7 +486,7 @@ Modify an already registered file descriptor.
 
 static PyObject *
 select_poll_modify_impl(pollObject *self, int fd, unsigned short eventmask)
-/*[clinic end generated code: output=1a7b88bf079eff17 input=b8e0e04a1264b78f]*/
+/*[clinic end generated code: output=1a7b88bf079eff17 input=a8e383df075c32cf]*/
 {
     PyObject *key, *value;
     int err;
@@ -832,7 +814,7 @@ select.devpoll.register
     fd: fildes
         either an integer, or an object with a fileno() method returning
         an int
-    eventmask: object(converter="ushort_converter", type="unsigned short", c_default="POLLIN | POLLPRI | POLLOUT") = POLLIN | POLLPRI | POLLOUT
+    eventmask: unsigned_short(c_default="POLLIN | POLLPRI | POLLOUT") = POLLIN | POLLPRI | POLLOUT
         an optional bitmask describing the type of events to check for
     /
 
@@ -842,7 +824,7 @@ Register a file descriptor with the polling object.
 static PyObject *
 select_devpoll_register_impl(devpollObject *self, int fd,
                              unsigned short eventmask)
-/*[clinic end generated code: output=6e07fe8b74abba0c input=389a0785bb8feb57]*/
+/*[clinic end generated code: output=6e07fe8b74abba0c input=5bd7cacc47a8ee46]*/
 {
     return internal_devpoll_register(self, fd, eventmask, 0);
 }
@@ -853,7 +835,7 @@ select.devpoll.modify
     fd: fildes
         either an integer, or an object with a fileno() method returning
         an int
-    eventmask: object(converter="ushort_converter", type="unsigned short", c_default="POLLIN | POLLPRI | POLLOUT") = POLLIN | POLLPRI | POLLOUT
+    eventmask: unsigned_short(c_default="POLLIN | POLLPRI | POLLOUT") = POLLIN | POLLPRI | POLLOUT
         an optional bitmask describing the type of events to check for
     /
 
@@ -863,7 +845,7 @@ Modify a possible already registered file descriptor.
 static PyObject *
 select_devpoll_modify_impl(devpollObject *self, int fd,
                            unsigned short eventmask)
-/*[clinic end generated code: output=bc2e6d23aaff98b4 input=f0d7de3889cc55fb]*/
+/*[clinic end generated code: output=bc2e6d23aaff98b4 input=48a820fc5967165d]*/
 static PyObject *
 devpoll_modify(devpollObject *self, PyObject *args)
 {
diff --git a/Objects/longobject.c b/Objects/longobject.c
index ebf87a55b54b..399d35427099 100644
--- a/Objects/longobject.c
+++ b/Objects/longobject.c
@@ -1439,6 +1439,102 @@ PyLong_AsLongLongAndOverflow(PyObject *vv, int *overflow)
     return res;
 }
 
+int
+_PyLong_UnsignedShort_Converter(PyObject *obj, void *ptr)
+{
+    unsigned long uval;
+
+    if (PyLong_Check(obj) && _PyLong_Sign(obj) < 0) {
+        PyErr_SetString(PyExc_ValueError, "value must be positive");
+        return 0;
+    }
+    uval = PyLong_AsUnsignedLong(obj);
+    if (uval == (unsigned long)-1 && PyErr_Occurred())
+        return 0;
+    if (uval > USHRT_MAX) {
+        PyErr_SetString(PyExc_OverflowError,
+                        "Python int too large for C unsigned short");
+        return 0;
+    }
+
+    *(unsigned short *)ptr = Py_SAFE_DOWNCAST(uval, unsigned long, unsigned short);
+    return 1;
+}
+
+int
+_PyLong_UnsignedInt_Converter(PyObject *obj, void *ptr)
+{
+    unsigned long uval;
+
+    if (PyLong_Check(obj) && _PyLong_Sign(obj) < 0) {
+        PyErr_SetString(PyExc_ValueError, "value must be positive");
+        return 0;
+    }
+    uval = PyLong_AsUnsignedLong(obj);
+    if (uval == (unsigned long)-1 && PyErr_Occurred())
+        return 0;
+    if (uval > UINT_MAX) {
+        PyErr_SetString(PyExc_OverflowError,
+                        "Python int too large for C unsigned int");
+        return 0;
+    }
+
+    *(unsigned int *)ptr = Py_SAFE_DOWNCAST(uval, unsigned long, unsigned int);
+    return 1;
+}
+
+int
+_PyLong_UnsignedLong_Converter(PyObject *obj, void *ptr)
+{
+    unsigned long uval;
+
+    if (PyLong_Check(obj) && _PyLong_Sign(obj) < 0) {
+        PyErr_SetString(PyExc_ValueError, "value must be positive");
+        return 0;
+    }
+    uval = PyLong_AsUnsignedLong(obj);
+    if (uval == (unsigned long)-1 && PyErr_Occurred())
+        return 0;
+
+    *(unsigned long *)ptr = uval;
+    return 1;
+}
+
+int
+_PyLong_UnsignedLongLong_Converter(PyObject *obj, void *ptr)
+{
+    unsigned long long uval;
+
+    if (PyLong_Check(obj) && _PyLong_Sign(obj) < 0) {
+        PyErr_SetString(PyExc_ValueError, "value must be positive");
+        return 0;
+    }
+    uval = PyLong_AsUnsignedLongLong(obj);
+    if (uval == (unsigned long long)-1 && PyErr_Occurred())
+        return 0;
+
+    *(unsigned long long *)ptr = uval;
+    return 1;
+}
+
+int
+_PyLong_Size_t_Converter(PyObject *obj, void *ptr)
+{
+    size_t uval;
+
+    if (PyLong_Check(obj) && _PyLong_Sign(obj) < 0) {
+        PyErr_SetString(PyExc_ValueError, "value must be positive");
+        return 0;
+    }
+    uval = PyLong_AsSize_t(obj);
+    if (uval == (size_t)-1 && PyErr_Occurred())
+        return 0;
+
+    *(size_t *)ptr = uval;
+    return 1;
+}
+
+
 #define CHECK_BINOP(v,w)                                \
     do {                                                \
         if (!PyLong_Check(v) || !PyLong_Check(w))       \
diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py
index e7c7eb47e818..653afbea5fc9 100755
--- a/Tools/clinic/clinic.py
+++ b/Tools/clinic/clinic.py
@@ -2603,12 +2603,13 @@ class short_converter(CConverter):
 class unsigned_short_converter(CConverter):
     type = 'unsigned short'
     default_type = int
-    format_unit = 'H'
     c_ignored_default = "0"
 
     def converter_init(self, *, bitwise=False):
-        if not bitwise:
-            fail("Unsigned shorts must be bitwise (for now).")
+        if bitwise:
+            self.format_unit = 'H'
+        else:
+            self.converter = '_PyLong_UnsignedShort_Converter'
 
 @add_legacy_c_converter('C', accept={str})
 class int_converter(CConverter):
@@ -2628,12 +2629,13 @@ def converter_init(self, *, accept={int}, type=None):
 class unsigned_int_converter(CConverter):
     type = 'unsigned int'
     default_type = int
-    format_unit = 'I'
     c_ignored_default = "0"
 
     def converter_init(self, *, bitwise=False):
-        if not bitwise:
-            fail("Unsigned ints must be bitwise (for now).")
+        if bitwise:
+            self.format_unit = 'I'
+        else:
+            self.converter = '_PyLong_UnsignedInt_Converter'
 
 class long_converter(CConverter):
     type = 'long'
@@ -2644,12 +2646,13 @@ class long_converter(CConverter):
 class unsigned_long_converter(CConverter):
     type = 'unsigned long'
     default_type = int
-    format_unit = 'k'
     c_ignored_default = "0"
 
     def converter_init(self, *, bitwise=False):
-        if not bitwise:
-            fail("Unsigned longs must be bitwise (for now).")
+        if bitwise:
+            self.format_unit = 'k'
+        else:
+            self.converter = '_PyLong_UnsignedLong_Converter'
 
 class long_long_converter(CConverter):
     type = 'long long'
@@ -2660,13 +2663,13 @@ class long_long_converter(CConverter):
 class unsigned_long_long_converter(CConverter):
     type = 'unsigned long long'
     default_type = int
-    format_unit = 'K'
     c_ignored_default = "0"
 
     def converter_init(self, *, bitwise=False):
-        if not bitwise:
-            fail("Unsigned long long must be bitwise (for now).")
-
+        if bitwise:
+            self.format_unit = 'K'
+        else:
+            self.converter = '_PyLong_UnsignedLongLong_Converter'
 
 class Py_ssize_t_converter(CConverter):
     type = 'Py_ssize_t'
@@ -2693,6 +2696,11 @@ def converter_init(self, *, accept={int, NoneType}):
         else:
             fail("slice_index_converter: illegal 'accept' argument " + repr(accept))
 
+class size_t_converter(CConverter):
+    type = 'size_t'
+    converter = '_PyLong_Size_t_Converter'
+    c_ignored_default = "0"
+
 
 class float_converter(CConverter):
     type = 'float'



More information about the Python-checkins mailing list