From b6b0f9a0ed32f22d084c37246954fb71d7a12e50 Mon Sep 17 00:00:00 2001 From: Stefan Behnel Date: Fri, 22 Aug 2008 12:28:15 +0200 Subject: [PATCH] fixed handling of keyword-only arguments changed more exception messages to what Py3 raises some cleanup --- Cython/Compiler/Nodes.py | 250 ++++++++++++---------------------- tests/run/callargs.pyx | 75 +++++++++- tests/run/classkwonlyargs.pyx | 14 +- tests/run/extkwonlyargs.pyx | 14 +- tests/run/kwonlyargs.pyx | 14 +- tests/run/kwonlyargscall.pyx | 61 +++++++-- 6 files changed, 227 insertions(+), 201 deletions(-) diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index 77fb89cd..2a7b2743 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -1562,7 +1562,7 @@ class DefNode(FuncDefNode): if arg.is_generic: code.put( '"%s",' % - arg.name) + arg.name.utf8encode()) if arg.kw_only and not arg.default: has_reqd_kwds = 1 flag = "1" @@ -1593,20 +1593,19 @@ class DefNode(FuncDefNode): has_kwonly_args = self.num_kwonly_args > 0 has_star_or_kw_args = self.star_arg is not None \ or self.starstar_arg is not None or has_kwonly_args - + if not self.signature_has_generic_args(): if has_star_or_kw_args: error(self.pos, "This method cannot have * or keyword arguments") self.generate_argument_conversion_code(code) - + elif not self.signature_has_nongeneric_args(): # func(*args) or func(**kw) or func(*args, **kw) self.generate_stararg_copy_code(code) - + else: - arg_addrs = [] - arg_formats = [] positional_args = [] + kw_only_args = [] default_seen = 0 for arg in self.args: arg_entry = arg.entry @@ -1616,37 +1615,30 @@ class DefNode(FuncDefNode): "%s = %s;" % ( arg_entry.cname, arg.default_result_code)) - if not default_seen: - arg_formats.append("|") default_seen = 1 - if not arg.is_self_arg and not arg.kw_only: - positional_args.append(arg) + if not arg.is_self_arg: + if arg.kw_only: + kw_only_args.append(arg) + else: + positional_args.append(arg) elif arg.kw_only: - if not default_seen: - arg_formats.append("|") + kw_only_args.append(arg) default_seen = 1 elif default_seen: error(arg.pos, "Non-default argument following default argument") elif not arg.is_self_arg: positional_args.append(arg) if arg.needs_conversion: - arg_addrs.append("&" + arg.hdr_cname) format = arg.hdr_type.parsetuple_format else: - arg_addrs.append("&" + arg_entry.cname) format = arg_entry.type.parsetuple_format - if format: - arg_formats.append(format) - else: - error(arg.pos, - "Cannot convert Python object argument to type '%s' (when parsing input arguments)" - % arg.type) - - if has_star_or_kw_args: - self.generate_stararg_getting_code(code) + if not format: + error(arg.pos, + "Cannot convert Python object argument to type '%s' (when parsing input arguments)" + % arg.type) self.generate_tuple_and_keyword_parsing_code( - positional_args, arg_formats, arg_addrs, code) + positional_args, kw_only_args, code) code.error_label = old_error_label if code.label_used(our_error_label): @@ -1664,52 +1656,6 @@ class DefNode(FuncDefNode): code.putln("return %s;" % self.error_value()) code.put_label(end_label) - def _generate_argument_tuple_parsing_code(self, positional_args, - arg_formats, arg_addrs, code): - # Unpack inplace if it's simple - if not self.num_required_kw_args: - min_positional_args = self.num_required_args - self.num_required_kw_args - max_positional_args = len(positional_args) - if len(self.args) > 0 and self.args[0].is_self_arg: - min_positional_args -= 1 - if max_positional_args == min_positional_args: - count_cond = "likely(PyTuple_GET_SIZE(%s) == %s)" % ( - Naming.args_cname, max_positional_args) - else: - count_cond = "likely(%s <= PyTuple_GET_SIZE(%s)) && likely(PyTuple_GET_SIZE(%s) <= %s)" % ( - min_positional_args, - Naming.args_cname, - Naming.args_cname, - max_positional_args) - code.putln( - 'if (likely(!%s) && %s) {' % (Naming.kwds_cname, count_cond)) - i = 0 - closing = 0 - for arg in positional_args: - if arg.default: - code.putln('if (PyTuple_GET_SIZE(%s) > %s) {' % (Naming.args_cname, i)) - closing += 1 - item = "PyTuple_GET_ITEM(%s, %s)" % (Naming.args_cname, i) - self.generate_arg_assignment(arg, item, code) - i += 1 - for _ in range(closing): - code.putln('}') - code.putln( - '}') - code.putln('else {') - - argformat = '"%s"' % string.join(arg_formats, "") - pt_arglist = [Naming.args_cname, Naming.kwds_cname, argformat, Naming.kwdlist_cname] + arg_addrs - pt_argstring = string.join(pt_arglist, ", ") - code.putln( - 'if (unlikely(!PyArg_ParseTupleAndKeywords(%s))) %s' % ( - pt_argstring, - code.error_goto(self.pos))) - self.generate_argument_conversion_code(code) - - if not self.num_required_kw_args: - code.putln('}') - def generate_arg_assignment(self, arg, item, code): if arg.type.is_pyobject: if arg.is_generic: @@ -1748,8 +1694,12 @@ class DefNode(FuncDefNode): def generate_stararg_copy_code(self, code): if not self.star_arg: - self.generate_positional_args_check(code, 0) - self.generate_keyword_args_check(code) + self.generate_positional_args_check(0, code) + + code.putln( + "if (unlikely(%s) && unlikely(!__Pyx_CheckKeywordStrings(%s, \"%s\", %d))) return %s;" % ( + Naming.kwds_cname, Naming.kwds_cname, self.name, + bool(self.starstar_arg), self.error_value())) if self.starstar_arg: code.putln("%s = (%s) ? PyDict_Copy(%s) : PyDict_New();" % ( @@ -1769,16 +1719,11 @@ class DefNode(FuncDefNode): self.star_arg.entry.xdecref_cleanup = 0 self.star_arg = None - def generate_stararg_getting_code(self, code): - num_kwonly = self.num_kwonly_args - fixed_args = self.entry.signature.num_fixed_args() - nargs = len(self.args) - num_kwonly - fixed_args - error_return = "return %s;" % self.error_value() - + def generate_stararg_getting_code(self, max_positional_args, code): if self.star_arg: star_arg_cname = self.star_arg.entry.cname code.putln("if (likely(PyTuple_GET_SIZE(%s) <= %d)) {" % ( - Naming.args_cname, nargs)) + Naming.args_cname, max_positional_args)) code.put_incref(Naming.args_cname, py_object_type) code.put("%s = %s; " % (star_arg_cname, Naming.empty_tuple)) code.put_incref(Naming.empty_tuple, py_object_type) @@ -1786,18 +1731,12 @@ class DefNode(FuncDefNode): code.putln( "if (unlikely(__Pyx_SplitStarArg(&%s, %d, &%s) < 0)) return %s;" % ( Naming.args_cname, - nargs, + max_positional_args, star_arg_cname, self.error_value())) code.putln("}") self.star_arg.entry.xdecref_cleanup = 0 - else: - # make sure supernumerous positional arguments do not run - # into keyword-only arguments and provide a more helpful - # message than PyArg_ParseTupelAndKeywords() - self.generate_positional_args_check(code, nargs) - handle_error = 0 if self.starstar_arg: handle_error = 1 code.put( @@ -1809,25 +1748,7 @@ class DefNode(FuncDefNode): Naming.args_cname, self.name.utf8encode())) self.starstar_arg.entry.xdecref_cleanup = 0 - elif self.num_required_kw_args: - handle_error = 1 - code.put('if (unlikely(__Pyx_CheckRequiredKeywords(%s, %s, %s, PyTuple_GET_SIZE(%s), "%s") < 0)) ' % ( - Naming.kwds_cname, - Naming.kwdlist_cname, - self.reqd_kw_flags_cname, - Naming.args_cname, - self.name.utf8encode())) - else: - # check that positional arguments are not passed as keywords also - handle_error = 1 - code.put('if (unlikely(%s) && unlikely(__Pyx_CheckDoubleKeywords(%s, %s, PyTuple_GET_SIZE(%s), "%s") < 0)) ' % ( - Naming.kwds_cname, - Naming.kwds_cname, - Naming.kwdlist_cname, - Naming.args_cname, - self.name.utf8encode())) - - if handle_error: + error_return = "return %s;" % self.error_value() if self.star_arg: code.putln("{") code.put_decref(Naming.args_cname, py_object_type) @@ -1838,29 +1759,28 @@ class DefNode(FuncDefNode): code.putln(error_return) def generate_tuple_and_keyword_parsing_code(self, positional_args, - arg_formats, arg_addrs, code): + kw_only_args, code): min_positional_args = self.num_required_args - self.num_required_kw_args if len(self.args) > 0 and self.args[0].is_self_arg: min_positional_args -= 1 max_positional_args = len(positional_args) + max_args = max_positional_args + len(kw_only_args) - # just a quick check to start with if not self.star_arg: - code.putln("if (unlikely(PyTuple_GET_SIZE(%s) > %d)) {" % ( - Naming.args_cname, max_positional_args)) - code.put('__Pyx_RaiseArgtupleInvalid("%s", %d, %d, PyTuple_GET_SIZE(%s)); ' % ( - self.name.utf8encode(), min_positional_args, - max_positional_args, Naming.args_cname)) - code.putln(code.error_goto(self.pos)) - code.putln("}") + self.generate_positional_args_check(max_positional_args, code) + + if self.star_arg or self.starstar_arg: + self.generate_stararg_getting_code(max_positional_args, code) # --- optimised code when we receive keyword arguments code.putln("if (unlikely(%s) && (PyDict_Size(%s) > 0)) {" % ( Naming.kwds_cname, Naming.kwds_cname)) - code.putln("PyObject* values[%d];" % max_positional_args) - code.putln("Py_ssize_t kw_args = PyDict_Size(%s), arg;" % + code.putln("PyObject* values[%d];" % max_args) + code.putln("Py_ssize_t arg, kw_args = PyDict_Size(%s);" % Naming.kwds_cname) + # parse arg tuple and check that positional args are not also + # passed as kw args code.putln("for (arg=0; arg < PyTuple_GET_SIZE(%s); arg++) {" % Naming.args_cname) code.putln("values[arg] = PyTuple_GET_ITEM(%s, arg);" % @@ -1873,21 +1793,27 @@ class DefNode(FuncDefNode): code.putln('}') code.putln('}') + # parse remaining positional args from the keyword dictionary code.putln("for (arg=PyTuple_GET_SIZE(%s); arg < %d; arg++) {" % ( - Naming.args_cname, max_positional_args)) + Naming.args_cname, max_args)) code.putln('values[arg] = PyDict_GetItemString(%s, %s[arg]);' % ( Naming.kwds_cname, Naming.kwdlist_cname)) code.putln('if (values[arg]) kw_args--;'); code.putln('}') + # raise an error if not all keywords were read code.putln('if (unlikely(kw_args > 0)) {') code.put('if (!__Pyx_CheckKeywords(%s, "%s", %s)) ' % ( Naming.kwds_cname, self.name.utf8encode(), Naming.kwdlist_cname)) code.putln(code.error_goto(self.pos)) code.putln('}') + # convert arg values to their final type and assign them default_seen = False - for i, arg in enumerate(positional_args): + i = 0 + for arg in self.args: + if arg.is_self_arg: + continue if arg.default: default_seen = True if default_seen: @@ -1896,60 +1822,62 @@ class DefNode(FuncDefNode): if default_seen: if not arg.default: code.putln('} else {') - code.put('__Pyx_RaiseArgtupleInvalid("%s", %d, %d, %d); ' % ( - self.name.utf8encode(), min_positional_args, - max_positional_args, i)) + if arg.kw_only: + code.put('PyErr_Format(PyExc_TypeError, "%s() needs keyword-only argument %s"); ' % ( + self.name.utf8encode(), arg.name.utf8encode())) + else: + code.put('__Pyx_RaiseArgtupleInvalid("%s", %d, %d, %d); ' % ( + self.name.utf8encode(), min_positional_args, + max_positional_args, i)) code.putln(code.error_goto(self.pos)) code.putln('}') + i += 1 - # --- optimised code when we did not receive any keyword arguments - code.putln('} else if (unlikely(PyTuple_GET_SIZE(%s) < %d)) {' % ( - Naming.args_cname, min_positional_args)) - code.put('__Pyx_RaiseArgtupleInvalid("%s", %d, %d, PyTuple_GET_SIZE(%s)); ' % ( - self.name.utf8encode(), min_positional_args, - max_positional_args, Naming.args_cname)) - code.putln(code.error_goto(self.pos)) - - code.putln('} else {') - closing = 0 - for i, arg in enumerate(positional_args): - if arg.default: - code.putln('if (PyTuple_GET_SIZE(%s) > %s) {' % (Naming.args_cname, i)) - closing += 1 - item = "PyTuple_GET_ITEM(%s, %s)" % (Naming.args_cname, i) - self.generate_arg_assignment(arg, item, code) - for _ in range(closing): + # --- optimised code when we do not receive any keyword arguments + if self.num_required_kw_args: + # simple case: keywords required but none passed + for arg in self.args: + if arg.kw_only and not arg.default: + required_arg = arg + code.putln('} else {') + code.put('PyErr_Format(PyExc_TypeError, "%s() needs keyword-only argument %s");' % ( + self.name.utf8encode(), required_arg.name.utf8encode())) + code.putln(code.error_goto(self.pos)) code.putln('}') + else: + # check if we have all required positional arguments + code.putln('} else if (unlikely(PyTuple_GET_SIZE(%s) < %d)) {' % ( + Naming.args_cname, min_positional_args)) + code.put('__Pyx_RaiseArgtupleInvalid("%s", %d, %d, PyTuple_GET_SIZE(%s)); ' % ( + self.name.utf8encode(), min_positional_args, + max_positional_args, Naming.args_cname)) + code.putln(code.error_goto(self.pos)) - code.putln('}') - return - - argformat = '"%s"' % string.join(arg_formats, "") - pt_arglist = [Naming.args_cname, Naming.kwds_cname, argformat, Naming.kwdlist_cname] + arg_addrs - pt_argstring = string.join(pt_arglist, ", ") - code.putln( - 'if (unlikely(!PyArg_ParseTupleAndKeywords(%s))) %s' % ( - pt_argstring, - code.error_goto(self.pos))) - self.generate_argument_conversion_code(code) + # parse all positional arguments from the args tuple + code.putln('} else {') + closing = 0 + for i, arg in enumerate(positional_args): + if arg.default: + code.putln('if (PyTuple_GET_SIZE(%s) > %s) {' % (Naming.args_cname, i)) + closing += 1 + item = "PyTuple_GET_ITEM(%s, %s)" % (Naming.args_cname, i) + self.generate_arg_assignment(arg, item, code) + for _ in range(closing): + code.putln('}') - code.putln('}') + code.putln('}') + return - def generate_positional_args_check(self, code, nargs): + def generate_positional_args_check(self, max_positional_args, code): + # make sure supernumerous positional arguments do not run + # into keyword-only arguments and provide a helpful message code.putln("if (unlikely(PyTuple_GET_SIZE(%s) > %d)) {" % ( - Naming.args_cname, nargs)) + Naming.args_cname, max_positional_args)) code.putln('__Pyx_RaiseArgtupleInvalid("%s", 0, %d, PyTuple_GET_SIZE(%s));' % ( - self.name.utf8encode(), nargs, Naming.args_cname)) + self.name.utf8encode(), max_positional_args, Naming.args_cname)) code.putln("return %s;" % self.error_value()) code.putln("}") - def generate_keyword_args_check(self, code): - code.putln("if (unlikely(%s)) {" % Naming.kwds_cname) - code.putln("if (unlikely(!__Pyx_CheckKeywordStrings(%s, \"%s\", %d))) return %s;" % ( - Naming.kwds_cname, self.name, - bool(self.starstar_arg), self.error_value())) - code.putln("}") - def generate_argument_conversion_code(self, code): # Generate code to convert arguments from # signature type to declared type, if needed. @@ -4612,7 +4540,7 @@ arg_passed_twice: goto bad; missing_kwarg: PyErr_Format(PyExc_TypeError, - "required keyword argument '%s' is missing", *p); + "%s() needs keyword-only argument %s", func_name, *p); bad: Py_XDECREF(s); Py_XDECREF(kwds1); diff --git a/tests/run/callargs.pyx b/tests/run/callargs.pyx index 27d46cab..6976a993 100644 --- a/tests/run/callargs.pyx +++ b/tests/run/callargs.pyx @@ -1,15 +1,67 @@ __doc__ = u""" - >>> test() + >>> test_pos_args(h) 1 2 3 * 0 0 + 1 2 9 * 2 0 + 1 2 7 * 2 0 + 9 8 7 * 0 0 + 7 8 9 * 0 0 + + >>> test_kw_args(h) 1 2 3 * 0 0 1 2 9 * 2 1 1 2 7 * 2 1 1 2 9 * 2 2 1 2 9 * 2 2 1 2 9 * 2 3 + + >>> test_kw_args(e) + 2 1 + 5 1 + 5 1 + 5 2 + 5 2 + 5 3 + + >>> test_kw(e) + 0 1 + 0 2 + 0 2 + 0 1 + + >>> test_kw(g) + 1 + 2 + 2 + 1 + + >>> test_pos_args(f) + 3 + 5 + 5 + 3 + 3 + + >>> test_noargs(e) + 0 0 + >>> test_noargs(f) + 0 + >>> test_noargs(g) + 0 + >>> test_noargs(h) + Traceback (most recent call last): + TypeError: h() takes at least 3 positional arguments (0 given) """ -def f(a, b, c, *args, **kwargs): +def e(*args, **kwargs): + print len(args), len(kwargs) + +def f(*args): + print len(args) + +def g(**kwargs): + print len(kwargs) + +def h(a, b, c, *args, **kwargs): print a, b, c, u'*', len(args), len(kwargs) args = (9,8,7) @@ -21,11 +73,26 @@ else: kwargs = {"test" : u"toast"} -def test(): - f(1,2,3) +def test_kw_args(f): f(1,2, c=3) f(1,2, d=3, *args) f(1,2, d=3, *(7,8,9)) f(1,2, d=3, *args, **kwargs) f(1,2, d=3, *args, e=5) f(1,2, d=3, *args, e=5, **kwargs) + +def test_pos_args(f): + f(1,2,3) + f(1,2, *args) + f(1,2, *(7,8,9)) + f(*args) + f(*(7,8,9)) + +def test_kw(f): + f(c=3) + f(d=3, e=5) + f(d=3, **kwargs) + f(**kwargs) + +def test_noargs(f): + f() diff --git a/tests/run/classkwonlyargs.pyx b/tests/run/classkwonlyargs.pyx index 2c2b1e2b..5ab9a2da 100644 --- a/tests/run/classkwonlyargs.pyx +++ b/tests/run/classkwonlyargs.pyx @@ -40,7 +40,7 @@ __doc__ = u""" TypeError: f() takes at most 3 positional arguments (4 given) >>> f(1,2) Traceback (most recent call last): - TypeError: required keyword argument 'c' is missing + TypeError: f() needs keyword-only argument c >>> f(1,2, c=1, e=2) Traceback (most recent call last): TypeError: 'e' is an invalid keyword argument for this function @@ -54,10 +54,10 @@ __doc__ = u""" TypeError: g() takes at most 3 positional arguments (4 given) >>> g(1,2) Traceback (most recent call last): - TypeError: required keyword argument 'c' is missing + TypeError: g() needs keyword-only argument c >>> g(1,2, c=1) Traceback (most recent call last): - TypeError: required keyword argument 'f' is missing + TypeError: g() needs keyword-only argument f >>> h(1,2, c=1, f=2) >>> h(1,2, c=1, f=2, e=3) @@ -66,10 +66,10 @@ __doc__ = u""" >>> h(1,2,3) Traceback (most recent call last): - TypeError: required keyword argument 'c' is missing + TypeError: h() needs keyword-only argument c >>> h(1,2, d=1) Traceback (most recent call last): - TypeError: required keyword argument 'c' is missing + TypeError: h() needs keyword-only argument c >>> k(1,2, c=1, f=2) >>> k(1,2, c=1, f=2, e=3) @@ -78,10 +78,10 @@ __doc__ = u""" >>> k(1,2,3) Traceback (most recent call last): - TypeError: required keyword argument 'f' is missing + TypeError: k() needs keyword-only argument f >>> k(1,2, d=1) Traceback (most recent call last): - TypeError: required keyword argument 'f' is missing + TypeError: k() needs keyword-only argument f """ import sys, re diff --git a/tests/run/extkwonlyargs.pyx b/tests/run/extkwonlyargs.pyx index b2d343ee..b819419c 100644 --- a/tests/run/extkwonlyargs.pyx +++ b/tests/run/extkwonlyargs.pyx @@ -40,7 +40,7 @@ __doc__ = u""" TypeError: f() takes at most 2 positional arguments (3 given) >>> f(1,2) Traceback (most recent call last): - TypeError: required keyword argument 'c' is missing + TypeError: f() needs keyword-only argument c >>> f(1,2, c=1, e=2) Traceback (most recent call last): TypeError: 'e' is an invalid keyword argument for this function @@ -54,10 +54,10 @@ __doc__ = u""" TypeError: g() takes at most 2 positional arguments (3 given) >>> g(1,2) Traceback (most recent call last): - TypeError: required keyword argument 'c' is missing + TypeError: g() needs keyword-only argument c >>> g(1,2, c=1) Traceback (most recent call last): - TypeError: required keyword argument 'f' is missing + TypeError: g() needs keyword-only argument f >>> h(1,2, c=1, f=2) >>> h(1,2, c=1, f=2, e=3) @@ -66,10 +66,10 @@ __doc__ = u""" >>> h(1,2,3) Traceback (most recent call last): - TypeError: required keyword argument 'c' is missing + TypeError: h() needs keyword-only argument c >>> h(1,2, d=1) Traceback (most recent call last): - TypeError: required keyword argument 'c' is missing + TypeError: h() needs keyword-only argument c >>> k(1,2, c=1, f=2) >>> k(1,2, c=1, f=2, e=3) @@ -78,10 +78,10 @@ __doc__ = u""" >>> k(1,2,3) Traceback (most recent call last): - TypeError: required keyword argument 'f' is missing + TypeError: k() needs keyword-only argument f >>> k(1,2, d=1) Traceback (most recent call last): - TypeError: required keyword argument 'f' is missing + TypeError: k() needs keyword-only argument f """ cdef class Ext: diff --git a/tests/run/kwonlyargs.pyx b/tests/run/kwonlyargs.pyx index 710dc476..b60ac4d5 100644 --- a/tests/run/kwonlyargs.pyx +++ b/tests/run/kwonlyargs.pyx @@ -37,7 +37,7 @@ __doc__ = u""" TypeError: f() takes at most 2 positional arguments (3 given) >>> f(1,2) Traceback (most recent call last): - TypeError: required keyword argument 'c' is missing + TypeError: f() needs keyword-only argument c >>> f(1,2, c=1, e=2) Traceback (most recent call last): TypeError: 'e' is an invalid keyword argument for this function @@ -51,10 +51,10 @@ __doc__ = u""" TypeError: g() takes at most 2 positional arguments (3 given) >>> g(1,2) Traceback (most recent call last): - TypeError: required keyword argument 'c' is missing + TypeError: g() needs keyword-only argument c >>> g(1,2, c=1) Traceback (most recent call last): - TypeError: required keyword argument 'f' is missing + TypeError: g() needs keyword-only argument f >>> h(1,2, c=1, f=2) >>> h(1,2, c=1, f=2, e=3) @@ -63,10 +63,10 @@ __doc__ = u""" >>> h(1,2,3) Traceback (most recent call last): - TypeError: required keyword argument 'c' is missing + TypeError: h() needs keyword-only argument c >>> h(1,2, d=1) Traceback (most recent call last): - TypeError: required keyword argument 'c' is missing + TypeError: h() needs keyword-only argument c >>> k(1,2, c=1, f=2) >>> k(1,2, c=1, f=2, e=3) @@ -75,10 +75,10 @@ __doc__ = u""" >>> k(1,2,3) Traceback (most recent call last): - TypeError: required keyword argument 'f' is missing + TypeError: k() needs keyword-only argument f >>> k(1,2, d=1) Traceback (most recent call last): - TypeError: required keyword argument 'f' is missing + TypeError: k() needs keyword-only argument f """ def b(a, b, c): diff --git a/tests/run/kwonlyargscall.pyx b/tests/run/kwonlyargscall.pyx index 415ee88a..296e512e 100644 --- a/tests/run/kwonlyargscall.pyx +++ b/tests/run/kwonlyargscall.pyx @@ -1,17 +1,22 @@ __doc__ = u""" >>> call3(b) + 1 2 3 >>> call4(b) Traceback (most recent call last): TypeError: b() takes at most 3 positional arguments (4 given) >>> call2(c) + 1 2 1 >>> call3(c) + 1 2 3 >>> call4(c) Traceback (most recent call last): TypeError: c() takes at most 3 positional arguments (4 given) >>> call2(d) + 1 2 88 >>> call2c(d) + 1 2 1 >>> call3(d) Traceback (most recent call last): @@ -21,64 +26,82 @@ __doc__ = u""" TypeError: 'd' is an invalid keyword argument for this function >>> call2(e) + 1 2 88 [] >>> call2c(e) + 1 2 1 [] >>> call2d(e) + 1 2 88 [('d', 1)] >>> call2cde(e) + 1 2 1 [('d', 2), ('e', 3)] >>> call3(e) + 1 2 3 [] >>> call4(e) Traceback (most recent call last): TypeError: e() takes at most 3 positional arguments (4 given) >>> call2c(f) + 1 2 1 42 >>> call2cd(f) + 1 2 1 2 >>> call3(f) Traceback (most recent call last): TypeError: f() takes at most 2 positional arguments (3 given) >>> call2(f) Traceback (most recent call last): - TypeError: required keyword argument 'c' is missing + TypeError: f() needs keyword-only argument c >>> call2ce(f) Traceback (most recent call last): TypeError: 'e' is an invalid keyword argument for this function >>> call2cf(g) + 1 2 1 42 17 2 [] >>> call2cefd(g) + 1 2 1 11 0 2 [] >>> call2cfex(g) + 1 2 1 42 0 2 [('x', 25)] >>> call3(g) Traceback (most recent call last): TypeError: g() takes at most 2 positional arguments (3 given) >>> call2(g) Traceback (most recent call last): - TypeError: required keyword argument 'c' is missing + TypeError: g() needs keyword-only argument c >>> call2c(g) Traceback (most recent call last): - TypeError: required keyword argument 'f' is missing + TypeError: g() needs keyword-only argument f >>> call2cf(h) + 1 2 1 42 17 2 () [] >>> call2cfe(h) + 1 2 1 42 3 2 () [] >>> call6cf(h) + 1 2 1 42 17 2 (3, 4, 5, 6) [] >>> call6cfexy(h) + 1 2 1 42 3 2 (3, 4, 5, 6) [('x', 25), ('y', 11)] >>> call3(h) Traceback (most recent call last): - TypeError: required keyword argument 'c' is missing + TypeError: h() needs keyword-only argument c >>> call3d(h) Traceback (most recent call last): - TypeError: required keyword argument 'c' is missing + TypeError: h() needs keyword-only argument c >>> call2cf(k) + 1 2 1 42 17 2 () [] >>> call2cfe(k) + 1 2 1 42 3 2 () [] >>> call6df(k) + 1 2 3 1 17 2 (4, 5, 6) [] >>> call6dfexy(k) + 1 2 3 1 3 2 (4, 5, 6) [('x', 25), ('y', 11)] >>> call3(k) Traceback (most recent call last): - TypeError: required keyword argument 'f' is missing + TypeError: k() needs keyword-only argument f >>> call2d(k) Traceback (most recent call last): - TypeError: required keyword argument 'f' is missing + TypeError: k() needs keyword-only argument f """ import sys, re @@ -145,25 +168,33 @@ def call6dfexy(f): # the called functions: def b(a, b, c): - pass + print a,b,c def c(a, b, c=1): - pass + print a,b,c def d(a, b, *, c = 88): - pass + print a,b,c def e(a, b, c = 88, **kwds): - pass + kwlist = list(kwds.items()) + kwlist.sort() + print a,b,c, kwlist def f(a, b, *, c, d = 42): - pass + print a,b,c,d def g(a, b, *, c, d = 42, e = 17, f, **kwds): - pass + kwlist = list(kwds.items()) + kwlist.sort() + print a,b,c,d,e,f, kwlist def h(a, b, *args, c, d = 42, e = 17, f, **kwds): - pass + kwlist = list(kwds.items()) + kwlist.sort() + print a,b,c,d,e,f, args, kwlist def k(a, b, c=1, *args, d = 42, e = 17, f, **kwds): - pass + kwlist = list(kwds.items()) + kwlist.sort() + print a,b,c,d,e,f, args, kwlist -- 2.26.2