diff -r 8c1438c15ed0 Include/modsupport.h --- a/Include/modsupport.h Mon Jul 28 00:19:36 2014 +0200 +++ b/Include/modsupport.h Thu Jul 31 00:08:20 2014 +1000 @@ -41,7 +41,31 @@ PyAPI_FUNC(int) PyArg_VaParse(PyObject *, const char *, va_list); PyAPI_FUNC(int) PyArg_VaParseTupleAndKeywords(PyObject *, PyObject *, const char *, char **, va_list); + +/* Converters used by Argument Clinic */ +typedef struct nullable_int_t +{ + int i; + int is_null; +} nullable_int_t; + +#define NULLABLE_INT_INITIALIZE(i, is_null) \ + { i, is_null} + +PyAPI_FUNC(int) PyLong_NullableIntConverter(PyObject *arg, void *p); + +typedef struct nullable_Py_ssize_t +{ + Py_ssize_t i; + int is_null; +} nullable_Py_ssize_t; + +#define NULLABLE_PY_SSIZE_T_INITIALIZE(i, is_null) \ + { i, is_null } + +PyAPI_FUNC(int) PyLong_NullablePy_ssize_tConverter(PyObject *arg, void *p); #endif + PyAPI_FUNC(PyObject *) Py_VaBuildValue(const char *, va_list); PyAPI_FUNC(int) PyModule_AddObject(PyObject *, const char *, PyObject *); diff -r 8c1438c15ed0 Modules/itertoolsmodule.c --- a/Modules/itertoolsmodule.c Mon Jul 28 00:19:36 2014 +0200 +++ b/Modules/itertoolsmodule.c Thu Jul 31 00:08:20 2014 +1000 @@ -4104,30 +4104,63 @@ static PyTypeObject repeat_type; +/*[clinic input] +class repeat "repeatobject *" "&repeat_type" + +@classmethod +repeat.__new__ as repeat_new + object: object + times: Py_ssize_t(nullable=True) = None + +Returns an iterator which returns the object the specified number of times. + +If times is None, returns the object endlessly. +[clinic start generated code]*/ + +PyDoc_STRVAR(repeat_new__doc__, +"repeat(object, times=None)\n" +"--\n" +"\n" +"Returns an iterator which returns the object the specified number of times.\n" +"\n" +"If times is None, returns the object endlessly."); + static PyObject * -repeat_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +repeat_new_impl(PyTypeObject *type, PyObject *object, nullable_Py_ssize_t *times); + +static PyObject * +repeat_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) { - repeatobject *ro; - PyObject *element; - Py_ssize_t cnt = -1, n_kwds = 0; - static char *kwargs[] = {"object", "times", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|n:repeat", kwargs, - &element, &cnt)) - return NULL; - - if (kwds != NULL) - n_kwds = PyDict_Size(kwds); - /* Does user supply times argument? */ - if ((PyTuple_Size(args) + n_kwds == 2) && cnt < 0) - cnt = 0; - - ro = (repeatobject *)type->tp_alloc(type, 0); + PyObject *return_value = NULL; + static char *_keywords[] = {"object", "times", NULL}; + PyObject *object; + nullable_Py_ssize_t times = NULLABLE_PY_SSIZE_T_INITIALIZE(0, 1); + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "O|O&:repeat", _keywords, + &object, PyLong_NullablePy_ssize_tConverter, ×)) + goto exit; + return_value = repeat_new_impl(type, object, ×); + +exit: + return return_value; +} + +static PyObject * +repeat_new_impl(PyTypeObject *type, PyObject *object, nullable_Py_ssize_t *times) +/*[clinic end generated code: output=987ae8ef452045f0 input=b63e69de81743e8a]*/ +{ + repeatobject *ro = (repeatobject *)type->tp_alloc(type, 0); if (ro == NULL) return NULL; - Py_INCREF(element); - ro->element = element; - ro->cnt = cnt; + Py_INCREF(object); + ro->element = object; + if (times->is_null) + ro->cnt = -1; + else if (times->i <= 0) + ro->cnt = 0; + else + ro->cnt = times->i; return (PyObject *)ro; } @@ -4196,11 +4229,6 @@ {NULL, NULL} /* sentinel */ }; -PyDoc_STRVAR(repeat_doc, -"repeat(object [,times]) -> create an iterator which returns the object\n\ -for the specified number of times. If not specified, returns the object\n\ -endlessly."); - static PyTypeObject repeat_type = { PyVarObject_HEAD_INIT(NULL, 0) "itertools.repeat", /* tp_name */ @@ -4224,7 +4252,7 @@ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, /* tp_flags */ - repeat_doc, /* tp_doc */ + repeat_new__doc__, /* tp_doc */ (traverseproc)repeat_traverse, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ diff -r 8c1438c15ed0 Python/getargs.c --- a/Python/getargs.c Mon Jul 28 00:19:36 2014 +0200 +++ b/Python/getargs.c Thu Jul 31 00:08:20 2014 +1000 @@ -1851,6 +1851,73 @@ return 0; } + +int +PyLong_NullableIntConverter(PyObject *arg, void *p) +{ + nullable_int_t *ni = (nullable_int_t *)p; + long i; + + if (arg == Py_None) { + ni->is_null = 1; + return 1; + } + + if (float_argument_error(arg)) + return 0; + i = PyLong_AsLong(arg); + if (i == -1 && PyErr_Occurred()) + return 0; + if (i > INT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "signed integer is greater than maximum"); + return 0; + } + if (i < INT_MIN) { + PyErr_SetString(PyExc_OverflowError, + "signed integer is less than minimum"); + return 0; + } + + /* success */ + ni->i = (int)i; + ni->is_null = 0; + return 1; +} + + +int +PyLong_NullablePy_ssize_tConverter(PyObject *arg, void *p) +{ + nullable_Py_ssize_t *ni = (nullable_Py_ssize_t *)p; + PyObject *index; + Py_ssize_t i; + + if (arg == Py_None) { + ni->is_null = 1; + return 1; + } + + if (float_argument_error(arg)) + return 0; + + index = PyNumber_Index(arg); + if (index == NULL) + return 0; + + i = PyLong_AsSsize_t(index); + Py_DECREF(index); + + if (i == -1 && PyErr_Occurred()) + return 0; + + /* success */ + ni->is_null = 0; + ni->i = i; + return 1; +} + + #ifdef __cplusplus }; #endif diff -r 8c1438c15ed0 Tools/clinic/clinic.py --- a/Tools/clinic/clinic.py Mon Jul 28 00:19:36 2014 +0200 +++ b/Tools/clinic/clinic.py Thu Jul 31 00:08:20 2014 +1000 @@ -2175,7 +2175,12 @@ self.py_name = py_name if default is not unspecified: - if self.default_type and not isinstance(default, (self.default_type, Unknown)): + default_type = self.default_type + if not isinstance(self.default_type, tuple): + default_type = (default_type,) + default_type += (Unknown,) + + if self.default_type and not isinstance(default, default_type): if isinstance(self.default_type, type): types_str = self.default_type.__name__ else: @@ -2419,18 +2424,55 @@ if not bitwise: fail("Unsigned shorts must be bitwise (for now).") +class Py_ssize_t_converter(CConverter): + type = 'Py_ssize_t' + default_type = (int, NoneType) + format_unit = 'n' + c_ignored_default = "0" + + def nullable(self, nullable, name): + if not nullable: + if self.default is None: + fail(name + "_converter: unsupported default of None when nullable=False") + return + + type = name + if not type.endswith("_t"): + type += '_t' + type = 'nullable_' + type + + self.type = type + self.format_unit = 'O&' + # can't use str.capitalize(), we want to preserve case + capitalized = name[0].upper() + name[1:] + self.converter = 'PyLong_Nullable' + capitalized + 'Converter' + self.impl_by_reference = self.parse_by_reference = True + + c_default = c_nullable = 0 + if self.default is None: + c_nullable = 1 + elif self.default is not unspecified: + c_default = self.default + self.c_default = "{}_INITIALIZE({}, {})".format( + type.upper(), c_default, c_nullable) + + def converter_init(self, *, nullable=False): + self.nullable(nullable, "Py_ssize_t") + @add_legacy_c_converter('C', types='str') -class int_converter(CConverter): +class int_converter(Py_ssize_t_converter): type = 'int' - default_type = int format_unit = 'i' - c_ignored_default = "0" - - def converter_init(self, *, types='int'): + + def converter_init(self, *, types='int', nullable=False): + self.nullable(nullable, "int") if types == 'str': self.format_unit = 'C' - elif types != 'int': - fail("int_converter: illegal 'types' argument") + if nullable: + fail("int_converter: 'types' must be 'int' when nullable=True") + else: + if types != 'int': + fail("int_converter: illegal 'types' argument") class unsigned_int_converter(CConverter): type = 'unsigned int' @@ -2474,12 +2516,6 @@ if not bitwise: fail("Unsigned PY_LONG_LONGs must be bitwise (for now).") -class Py_ssize_t_converter(CConverter): - type = 'Py_ssize_t' - default_type = int - format_unit = 'n' - c_ignored_default = "0" - class float_converter(CConverter): type = 'float'