diff -r 0056aaf42bf7 Doc/howto/clinic.rst --- a/Doc/howto/clinic.rst Wed Jan 15 15:09:43 2014 +0000 +++ b/Doc/howto/clinic.rst Wed Jan 15 20:58:16 2014 +0200 @@ -744,6 +744,12 @@ 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 -r 0056aaf42bf7 Include/longobject.h --- a/Include/longobject.h Wed Jan 15 15:09:43 2014 +0000 +++ b/Include/longobject.h Wed Jan 15 20:58:16 2014 +0200 @@ -65,6 +65,13 @@ # 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_Size_t_Converter(PyObject *, void *); +#endif + /* Used by Python/mystrtoul.c. */ #ifndef Py_LIMITED_API PyAPI_DATA(unsigned char) _PyLong_DigitValue[256]; @@ -91,6 +98,9 @@ PyAPI_FUNC(unsigned PY_LONG_LONG) PyLong_AsUnsignedLongLong(PyObject *); PyAPI_FUNC(unsigned PY_LONG_LONG) PyLong_AsUnsignedLongLongMask(PyObject *); PyAPI_FUNC(PY_LONG_LONG) PyLong_AsLongLongAndOverflow(PyObject *, int *); +#ifndef Py_LIMITED_API +PyAPI_FUNC(int) _PyLong_UnsignedLongLong_Converter(PyObject *, void *); +#endif #endif /* HAVE_LONG_LONG */ PyAPI_FUNC(PyObject *) PyLong_FromString(const char *, char **, int); diff -r 0056aaf42bf7 Misc/NEWS --- a/Misc/NEWS Wed Jan 15 15:09:43 2014 +0000 +++ b/Misc/NEWS Wed Jan 15 20:58:16 2014 +0200 @@ -88,6 +88,8 @@ Tools/Demos ----------- +- Issue #20260: Argument Clinic now has non-bitwise unsigned int converters. + - Issue #20268: Argument Clinic now supports cloning the parameters and return converter of existing functions. diff -r 0056aaf42bf7 Modules/selectmodule.c --- a/Modules/selectmodule.c Wed Jan 15 15:09:43 2014 +0000 +++ b/Modules/selectmodule.c Wed Jan 15 20:58:16 2014 +0200 @@ -361,24 +361,6 @@ 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; -} - PyDoc_STRVAR(poll_register_doc, "register(fd [, eventmask] ) -> None\n\n\ Register a file descriptor with the polling object.\n\ @@ -394,7 +376,8 @@ unsigned short events = POLLIN | POLLPRI | POLLOUT; int err; - if (!PyArg_ParseTuple(args, "O|O&:register", &o, ushort_converter, &events)) + if (!PyArg_ParseTuple(args, "O|O&:register", &o, + _PyLong_UnsignedShort_Converter, &events)) return NULL; fd = PyObject_AsFileDescriptor(o); @@ -437,7 +420,8 @@ unsigned short events; int err; - if (!PyArg_ParseTuple(args, "OO&:modify", &o, ushort_converter, &events)) + if (!PyArg_ParseTuple(args, "OO&:modify", &o, + _PyLong_UnsignedShort_Converter, &events)) return NULL; fd = PyObject_AsFileDescriptor(o); @@ -749,7 +733,8 @@ if (self->fd_devpoll < 0) return devpoll_err_closed(); - if (!PyArg_ParseTuple(args, "O|O&:register", &o, ushort_converter, &events)) + if (!PyArg_ParseTuple(args, "O|O&:register", &o, + _PyLong_UnsignedShort_Converter, &events)) return NULL; fd = PyObject_AsFileDescriptor(o); diff -r 0056aaf42bf7 Modules/zlibmodule.c --- a/Modules/zlibmodule.c Wed Jan 15 15:09:43 2014 +0000 +++ b/Modules/zlibmodule.c Wed Jan 15 20:58:16 2014 +0200 @@ -306,46 +306,6 @@ return ReturnVal; } -/*[python input] - -class uint_converter(CConverter): - type = 'unsigned int' - converter = 'uint_converter' - -[python start generated code]*/ -/*[python end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ - -static int -uint_converter(PyObject *obj, void *ptr) -{ - long val; - unsigned long uval; - - val = PyLong_AsLong(obj); - if (val == -1 && PyErr_Occurred()) { - uval = PyLong_AsUnsignedLong(obj); - if (uval == (unsigned long)-1 && PyErr_Occurred()) - return 0; - } - else { - if (val < 0) { - PyErr_SetString(PyExc_ValueError, - "value must be positive"); - return 0; - } - uval = (unsigned long)val; - } - - 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; -} - PyDoc_STRVAR(decompress__doc__, "decompress(string[, wbits[, bufsize]]) -- Return decompressed string.\n" "\n" @@ -365,7 +325,8 @@ z_stream zst; if (!PyArg_ParseTuple(args, "y*|iO&:decompress", - &pinput, &wsize, uint_converter, &bufsize)) + &pinput, &wsize, + _PyLong_UnsignedInt_Converter, &bufsize)) return NULL; if ((size_t)pinput.len > UINT_MAX) { @@ -751,7 +712,7 @@ data: Py_buffer The binary data to decompress. - max_length: uint = 0 + max_length: unsigned_int = 0 The maximum allowable length of the decompressed data. Unconsumed input data will be stored in the unconsumed_tail attribute. @@ -794,7 +755,7 @@ if (!PyArg_ParseTuple(args, "y*|O&:decompress", - &data, uint_converter, &max_length)) + &data, _PyLong_UnsignedInt_Converter, &max_length)) goto exit; return_value = zlib_Decompress_decompress_impl((compobject *)self, &data, max_length); @@ -808,7 +769,7 @@ static PyObject * zlib_Decompress_decompress_impl(compobject *self, Py_buffer *data, unsigned int max_length) -/*[clinic end generated code: checksum=e0058024c4a97b411d2e2197791b89fde175f76f]*/ +/*[clinic end generated code: checksum=c8a3ecf4a98f8dc047b3fdf7a1db95057850d0be]*/ { int err; unsigned int old_length, length = DEFAULTALLOC; @@ -1178,7 +1139,8 @@ unsigned long start_total_out; Py_ssize_t size; - if (!PyArg_ParseTuple(args, "|O&:flush", uint_converter, &length)) + if (!PyArg_ParseTuple(args, "|O&:flush", + _PyLong_UnsignedInt_Converter, &length)) return NULL; if (length == 0) { PyErr_SetString(PyExc_ValueError, "length must be greater than zero"); diff -r 0056aaf42bf7 Objects/longobject.c --- a/Objects/longobject.c Wed Jan 15 15:09:43 2014 +0000 +++ b/Objects/longobject.c Wed Jan 15 20:58:16 2014 +0200 @@ -1418,6 +1418,106 @@ #endif /* HAVE_LONG_LONG */ +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; +} + +#ifdef HAVE_LONG_LONG + +int +_PyLong_UnsignedLongLong_Converter(PyObject *obj, void *ptr) +{ + unsigned PY_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 PY_LONG_LONG)-1 && PyErr_Occurred()) + return 0; + + *(unsigned PY_LONG_LONG *)ptr = uval; + return 1; +} + +#endif /* HAVE_LONG_LONG */ + +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 -r 0056aaf42bf7 Tools/clinic/clinic.py --- a/Tools/clinic/clinic.py Wed Jan 15 15:09:43 2014 +0000 +++ b/Tools/clinic/clinic.py Wed Jan 15 20:58:16 2014 +0200 @@ -1684,12 +1684,13 @@ 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', types='str') class int_converter(CConverter): @@ -1707,12 +1708,13 @@ 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' @@ -1723,12 +1725,13 @@ 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 PY_LONG_LONG_converter(CConverter): type = 'PY_LONG_LONG' @@ -1739,12 +1742,13 @@ class unsigned_PY_LONG_LONG_converter(CConverter): type = 'unsigned PY_LONG_LONG' default_type = int - format_unit = 'K' c_ignored_default = "0" def converter_init(self, *, bitwise=False): - if not bitwise: - fail("Unsigned PY_LONG_LONGs 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' @@ -1752,6 +1756,11 @@ format_unit = 'n' c_ignored_default = "0" +class size_t_converter(CConverter): + type = 'size_t' + converter = '_PyLong_Size_t_Converter' + c_ignored_default = "0" + class float_converter(CConverter): type = 'float'