Commit b6b0f9a0 authored by Stefan Behnel's avatar Stefan Behnel

fixed handling of keyword-only arguments

changed more exception messages to what Py3 raises
some cleanup
parent 086f4098
...@@ -1562,7 +1562,7 @@ class DefNode(FuncDefNode): ...@@ -1562,7 +1562,7 @@ class DefNode(FuncDefNode):
if arg.is_generic: if arg.is_generic:
code.put( code.put(
'"%s",' % '"%s",' %
arg.name) arg.name.utf8encode())
if arg.kw_only and not arg.default: if arg.kw_only and not arg.default:
has_reqd_kwds = 1 has_reqd_kwds = 1
flag = "1" flag = "1"
...@@ -1593,20 +1593,19 @@ class DefNode(FuncDefNode): ...@@ -1593,20 +1593,19 @@ class DefNode(FuncDefNode):
has_kwonly_args = self.num_kwonly_args > 0 has_kwonly_args = self.num_kwonly_args > 0
has_star_or_kw_args = self.star_arg is not None \ has_star_or_kw_args = self.star_arg is not None \
or self.starstar_arg is not None or has_kwonly_args or self.starstar_arg is not None or has_kwonly_args
if not self.signature_has_generic_args(): if not self.signature_has_generic_args():
if has_star_or_kw_args: if has_star_or_kw_args:
error(self.pos, "This method cannot have * or keyword arguments") error(self.pos, "This method cannot have * or keyword arguments")
self.generate_argument_conversion_code(code) self.generate_argument_conversion_code(code)
elif not self.signature_has_nongeneric_args(): elif not self.signature_has_nongeneric_args():
# func(*args) or func(**kw) or func(*args, **kw) # func(*args) or func(**kw) or func(*args, **kw)
self.generate_stararg_copy_code(code) self.generate_stararg_copy_code(code)
else: else:
arg_addrs = []
arg_formats = []
positional_args = [] positional_args = []
kw_only_args = []
default_seen = 0 default_seen = 0
for arg in self.args: for arg in self.args:
arg_entry = arg.entry arg_entry = arg.entry
...@@ -1616,37 +1615,30 @@ class DefNode(FuncDefNode): ...@@ -1616,37 +1615,30 @@ class DefNode(FuncDefNode):
"%s = %s;" % ( "%s = %s;" % (
arg_entry.cname, arg_entry.cname,
arg.default_result_code)) arg.default_result_code))
if not default_seen:
arg_formats.append("|")
default_seen = 1 default_seen = 1
if not arg.is_self_arg and not arg.kw_only: if not arg.is_self_arg:
positional_args.append(arg) if arg.kw_only:
kw_only_args.append(arg)
else:
positional_args.append(arg)
elif arg.kw_only: elif arg.kw_only:
if not default_seen: kw_only_args.append(arg)
arg_formats.append("|")
default_seen = 1 default_seen = 1
elif default_seen: elif default_seen:
error(arg.pos, "Non-default argument following default argument") error(arg.pos, "Non-default argument following default argument")
elif not arg.is_self_arg: elif not arg.is_self_arg:
positional_args.append(arg) positional_args.append(arg)
if arg.needs_conversion: if arg.needs_conversion:
arg_addrs.append("&" + arg.hdr_cname)
format = arg.hdr_type.parsetuple_format format = arg.hdr_type.parsetuple_format
else: else:
arg_addrs.append("&" + arg_entry.cname)
format = arg_entry.type.parsetuple_format format = arg_entry.type.parsetuple_format
if format: if not format:
arg_formats.append(format) error(arg.pos,
else: "Cannot convert Python object argument to type '%s' (when parsing input arguments)"
error(arg.pos, % arg.type)
"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)
self.generate_tuple_and_keyword_parsing_code( 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 code.error_label = old_error_label
if code.label_used(our_error_label): if code.label_used(our_error_label):
...@@ -1664,52 +1656,6 @@ class DefNode(FuncDefNode): ...@@ -1664,52 +1656,6 @@ class DefNode(FuncDefNode):
code.putln("return %s;" % self.error_value()) code.putln("return %s;" % self.error_value())
code.put_label(end_label) 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): def generate_arg_assignment(self, arg, item, code):
if arg.type.is_pyobject: if arg.type.is_pyobject:
if arg.is_generic: if arg.is_generic:
...@@ -1748,8 +1694,12 @@ class DefNode(FuncDefNode): ...@@ -1748,8 +1694,12 @@ class DefNode(FuncDefNode):
def generate_stararg_copy_code(self, code): def generate_stararg_copy_code(self, code):
if not self.star_arg: if not self.star_arg:
self.generate_positional_args_check(code, 0) self.generate_positional_args_check(0, code)
self.generate_keyword_args_check(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: if self.starstar_arg:
code.putln("%s = (%s) ? PyDict_Copy(%s) : PyDict_New();" % ( code.putln("%s = (%s) ? PyDict_Copy(%s) : PyDict_New();" % (
...@@ -1769,16 +1719,11 @@ class DefNode(FuncDefNode): ...@@ -1769,16 +1719,11 @@ class DefNode(FuncDefNode):
self.star_arg.entry.xdecref_cleanup = 0 self.star_arg.entry.xdecref_cleanup = 0
self.star_arg = None self.star_arg = None
def generate_stararg_getting_code(self, code): def generate_stararg_getting_code(self, max_positional_args, 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()
if self.star_arg: if self.star_arg:
star_arg_cname = self.star_arg.entry.cname star_arg_cname = self.star_arg.entry.cname
code.putln("if (likely(PyTuple_GET_SIZE(%s) <= %d)) {" % ( 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_incref(Naming.args_cname, py_object_type)
code.put("%s = %s; " % (star_arg_cname, Naming.empty_tuple)) code.put("%s = %s; " % (star_arg_cname, Naming.empty_tuple))
code.put_incref(Naming.empty_tuple, py_object_type) code.put_incref(Naming.empty_tuple, py_object_type)
...@@ -1786,18 +1731,12 @@ class DefNode(FuncDefNode): ...@@ -1786,18 +1731,12 @@ class DefNode(FuncDefNode):
code.putln( code.putln(
"if (unlikely(__Pyx_SplitStarArg(&%s, %d, &%s) < 0)) return %s;" % ( "if (unlikely(__Pyx_SplitStarArg(&%s, %d, &%s) < 0)) return %s;" % (
Naming.args_cname, Naming.args_cname,
nargs, max_positional_args,
star_arg_cname, star_arg_cname,
self.error_value())) self.error_value()))
code.putln("}") code.putln("}")
self.star_arg.entry.xdecref_cleanup = 0 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: if self.starstar_arg:
handle_error = 1 handle_error = 1
code.put( code.put(
...@@ -1809,25 +1748,7 @@ class DefNode(FuncDefNode): ...@@ -1809,25 +1748,7 @@ class DefNode(FuncDefNode):
Naming.args_cname, Naming.args_cname,
self.name.utf8encode())) self.name.utf8encode()))
self.starstar_arg.entry.xdecref_cleanup = 0 self.starstar_arg.entry.xdecref_cleanup = 0
elif self.num_required_kw_args: error_return = "return %s;" % self.error_value()
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:
if self.star_arg: if self.star_arg:
code.putln("{") code.putln("{")
code.put_decref(Naming.args_cname, py_object_type) code.put_decref(Naming.args_cname, py_object_type)
...@@ -1838,29 +1759,28 @@ class DefNode(FuncDefNode): ...@@ -1838,29 +1759,28 @@ class DefNode(FuncDefNode):
code.putln(error_return) code.putln(error_return)
def generate_tuple_and_keyword_parsing_code(self, positional_args, 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 min_positional_args = self.num_required_args - self.num_required_kw_args
if len(self.args) > 0 and self.args[0].is_self_arg: if len(self.args) > 0 and self.args[0].is_self_arg:
min_positional_args -= 1 min_positional_args -= 1
max_positional_args = len(positional_args) 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: if not self.star_arg:
code.putln("if (unlikely(PyTuple_GET_SIZE(%s) > %d)) {" % ( self.generate_positional_args_check(max_positional_args, code)
Naming.args_cname, max_positional_args))
code.put('__Pyx_RaiseArgtupleInvalid("%s", %d, %d, PyTuple_GET_SIZE(%s)); ' % ( if self.star_arg or self.starstar_arg:
self.name.utf8encode(), min_positional_args, self.generate_stararg_getting_code(max_positional_args, code)
max_positional_args, Naming.args_cname))
code.putln(code.error_goto(self.pos))
code.putln("}")
# --- optimised code when we receive keyword arguments # --- optimised code when we receive keyword arguments
code.putln("if (unlikely(%s) && (PyDict_Size(%s) > 0)) {" % ( code.putln("if (unlikely(%s) && (PyDict_Size(%s) > 0)) {" % (
Naming.kwds_cname, Naming.kwds_cname)) Naming.kwds_cname, Naming.kwds_cname))
code.putln("PyObject* values[%d];" % max_positional_args) code.putln("PyObject* values[%d];" % max_args)
code.putln("Py_ssize_t kw_args = PyDict_Size(%s), arg;" % code.putln("Py_ssize_t arg, kw_args = PyDict_Size(%s);" %
Naming.kwds_cname) 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++) {" % code.putln("for (arg=0; arg < PyTuple_GET_SIZE(%s); arg++) {" %
Naming.args_cname) Naming.args_cname)
code.putln("values[arg] = PyTuple_GET_ITEM(%s, arg);" % code.putln("values[arg] = PyTuple_GET_ITEM(%s, arg);" %
...@@ -1873,21 +1793,27 @@ class DefNode(FuncDefNode): ...@@ -1873,21 +1793,27 @@ class DefNode(FuncDefNode):
code.putln('}') code.putln('}')
code.putln('}') code.putln('}')
# parse remaining positional args from the keyword dictionary
code.putln("for (arg=PyTuple_GET_SIZE(%s); arg < %d; arg++) {" % ( 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]);' % ( code.putln('values[arg] = PyDict_GetItemString(%s, %s[arg]);' % (
Naming.kwds_cname, Naming.kwdlist_cname)) Naming.kwds_cname, Naming.kwdlist_cname))
code.putln('if (values[arg]) kw_args--;'); code.putln('if (values[arg]) kw_args--;');
code.putln('}') code.putln('}')
# raise an error if not all keywords were read
code.putln('if (unlikely(kw_args > 0)) {') code.putln('if (unlikely(kw_args > 0)) {')
code.put('if (!__Pyx_CheckKeywords(%s, "%s", %s)) ' % ( code.put('if (!__Pyx_CheckKeywords(%s, "%s", %s)) ' % (
Naming.kwds_cname, self.name.utf8encode(), Naming.kwdlist_cname)) Naming.kwds_cname, self.name.utf8encode(), Naming.kwdlist_cname))
code.putln(code.error_goto(self.pos)) code.putln(code.error_goto(self.pos))
code.putln('}') code.putln('}')
# convert arg values to their final type and assign them
default_seen = False 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: if arg.default:
default_seen = True default_seen = True
if default_seen: if default_seen:
...@@ -1896,60 +1822,62 @@ class DefNode(FuncDefNode): ...@@ -1896,60 +1822,62 @@ class DefNode(FuncDefNode):
if default_seen: if default_seen:
if not arg.default: if not arg.default:
code.putln('} else {') code.putln('} else {')
code.put('__Pyx_RaiseArgtupleInvalid("%s", %d, %d, %d); ' % ( if arg.kw_only:
self.name.utf8encode(), min_positional_args, code.put('PyErr_Format(PyExc_TypeError, "%s() needs keyword-only argument %s"); ' % (
max_positional_args, i)) 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(code.error_goto(self.pos))
code.putln('}') code.putln('}')
i += 1
# --- optimised code when we did not receive any keyword arguments # --- optimised code when we do not receive any keyword arguments
code.putln('} else if (unlikely(PyTuple_GET_SIZE(%s) < %d)) {' % ( if self.num_required_kw_args:
Naming.args_cname, min_positional_args)) # simple case: keywords required but none passed
code.put('__Pyx_RaiseArgtupleInvalid("%s", %d, %d, PyTuple_GET_SIZE(%s)); ' % ( for arg in self.args:
self.name.utf8encode(), min_positional_args, if arg.kw_only and not arg.default:
max_positional_args, Naming.args_cname)) required_arg = arg
code.putln(code.error_goto(self.pos)) code.putln('} else {')
code.put('PyErr_Format(PyExc_TypeError, "%s() needs keyword-only argument %s");' % (
code.putln('} else {') self.name.utf8encode(), required_arg.name.utf8encode()))
closing = 0 code.putln(code.error_goto(self.pos))
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('}')
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('}') # parse all positional arguments from the args tuple
return code.putln('} else {')
closing = 0
argformat = '"%s"' % string.join(arg_formats, "") for i, arg in enumerate(positional_args):
pt_arglist = [Naming.args_cname, Naming.kwds_cname, argformat, Naming.kwdlist_cname] + arg_addrs if arg.default:
pt_argstring = string.join(pt_arglist, ", ") code.putln('if (PyTuple_GET_SIZE(%s) > %s) {' % (Naming.args_cname, i))
code.putln( closing += 1
'if (unlikely(!PyArg_ParseTupleAndKeywords(%s))) %s' % ( item = "PyTuple_GET_ITEM(%s, %s)" % (Naming.args_cname, i)
pt_argstring, self.generate_arg_assignment(arg, item, code)
code.error_goto(self.pos))) for _ in range(closing):
self.generate_argument_conversion_code(code) 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)) {" % ( 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));' % ( 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("return %s;" % self.error_value())
code.putln("}") 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): def generate_argument_conversion_code(self, code):
# Generate code to convert arguments from # Generate code to convert arguments from
# signature type to declared type, if needed. # signature type to declared type, if needed.
...@@ -4612,7 +4540,7 @@ arg_passed_twice: ...@@ -4612,7 +4540,7 @@ arg_passed_twice:
goto bad; goto bad;
missing_kwarg: missing_kwarg:
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"required keyword argument '%s' is missing", *p); "%s() needs keyword-only argument %s", func_name, *p);
bad: bad:
Py_XDECREF(s); Py_XDECREF(s);
Py_XDECREF(kwds1); Py_XDECREF(kwds1);
......
__doc__ = u""" __doc__ = u"""
>>> test() >>> test_pos_args(h)
1 2 3 * 0 0 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 3 * 0 0
1 2 9 * 2 1 1 2 9 * 2 1
1 2 7 * 2 1 1 2 7 * 2 1
1 2 9 * 2 2 1 2 9 * 2 2
1 2 9 * 2 2 1 2 9 * 2 2
1 2 9 * 2 3 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) print a, b, c, u'*', len(args), len(kwargs)
args = (9,8,7) args = (9,8,7)
...@@ -21,11 +73,26 @@ else: ...@@ -21,11 +73,26 @@ else:
kwargs = {"test" : u"toast"} kwargs = {"test" : u"toast"}
def test(): def test_kw_args(f):
f(1,2,3)
f(1,2, c=3) f(1,2, c=3)
f(1,2, d=3, *args) f(1,2, d=3, *args)
f(1,2, d=3, *(7,8,9)) f(1,2, d=3, *(7,8,9))
f(1,2, d=3, *args, **kwargs) f(1,2, d=3, *args, **kwargs)
f(1,2, d=3, *args, e=5) f(1,2, d=3, *args, e=5)
f(1,2, d=3, *args, e=5, **kwargs) 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()
...@@ -40,7 +40,7 @@ __doc__ = u""" ...@@ -40,7 +40,7 @@ __doc__ = u"""
TypeError: f() takes at most 3 positional arguments (4 given) TypeError: f() takes at most 3 positional arguments (4 given)
>>> f(1,2) >>> f(1,2)
Traceback (most recent call last): 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) >>> f(1,2, c=1, e=2)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: 'e' is an invalid keyword argument for this function TypeError: 'e' is an invalid keyword argument for this function
...@@ -54,10 +54,10 @@ __doc__ = u""" ...@@ -54,10 +54,10 @@ __doc__ = u"""
TypeError: g() takes at most 3 positional arguments (4 given) TypeError: g() takes at most 3 positional arguments (4 given)
>>> g(1,2) >>> g(1,2)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'c' is missing TypeError: g() needs keyword-only argument c
>>> g(1,2, c=1) >>> g(1,2, c=1)
Traceback (most recent call last): 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)
>>> h(1,2, c=1, f=2, e=3) >>> h(1,2, c=1, f=2, e=3)
...@@ -66,10 +66,10 @@ __doc__ = u""" ...@@ -66,10 +66,10 @@ __doc__ = u"""
>>> h(1,2,3) >>> h(1,2,3)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'c' is missing TypeError: h() needs keyword-only argument c
>>> h(1,2, d=1) >>> h(1,2, d=1)
Traceback (most recent call last): 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)
>>> k(1,2, c=1, f=2, e=3) >>> k(1,2, c=1, f=2, e=3)
...@@ -78,10 +78,10 @@ __doc__ = u""" ...@@ -78,10 +78,10 @@ __doc__ = u"""
>>> k(1,2,3) >>> k(1,2,3)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'f' is missing TypeError: k() needs keyword-only argument f
>>> k(1,2, d=1) >>> k(1,2, d=1)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'f' is missing TypeError: k() needs keyword-only argument f
""" """
import sys, re import sys, re
......
...@@ -40,7 +40,7 @@ __doc__ = u""" ...@@ -40,7 +40,7 @@ __doc__ = u"""
TypeError: f() takes at most 2 positional arguments (3 given) TypeError: f() takes at most 2 positional arguments (3 given)
>>> f(1,2) >>> f(1,2)
Traceback (most recent call last): 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) >>> f(1,2, c=1, e=2)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: 'e' is an invalid keyword argument for this function TypeError: 'e' is an invalid keyword argument for this function
...@@ -54,10 +54,10 @@ __doc__ = u""" ...@@ -54,10 +54,10 @@ __doc__ = u"""
TypeError: g() takes at most 2 positional arguments (3 given) TypeError: g() takes at most 2 positional arguments (3 given)
>>> g(1,2) >>> g(1,2)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'c' is missing TypeError: g() needs keyword-only argument c
>>> g(1,2, c=1) >>> g(1,2, c=1)
Traceback (most recent call last): 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)
>>> h(1,2, c=1, f=2, e=3) >>> h(1,2, c=1, f=2, e=3)
...@@ -66,10 +66,10 @@ __doc__ = u""" ...@@ -66,10 +66,10 @@ __doc__ = u"""
>>> h(1,2,3) >>> h(1,2,3)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'c' is missing TypeError: h() needs keyword-only argument c
>>> h(1,2, d=1) >>> h(1,2, d=1)
Traceback (most recent call last): 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)
>>> k(1,2, c=1, f=2, e=3) >>> k(1,2, c=1, f=2, e=3)
...@@ -78,10 +78,10 @@ __doc__ = u""" ...@@ -78,10 +78,10 @@ __doc__ = u"""
>>> k(1,2,3) >>> k(1,2,3)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'f' is missing TypeError: k() needs keyword-only argument f
>>> k(1,2, d=1) >>> k(1,2, d=1)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'f' is missing TypeError: k() needs keyword-only argument f
""" """
cdef class Ext: cdef class Ext:
......
...@@ -37,7 +37,7 @@ __doc__ = u""" ...@@ -37,7 +37,7 @@ __doc__ = u"""
TypeError: f() takes at most 2 positional arguments (3 given) TypeError: f() takes at most 2 positional arguments (3 given)
>>> f(1,2) >>> f(1,2)
Traceback (most recent call last): 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) >>> f(1,2, c=1, e=2)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: 'e' is an invalid keyword argument for this function TypeError: 'e' is an invalid keyword argument for this function
...@@ -51,10 +51,10 @@ __doc__ = u""" ...@@ -51,10 +51,10 @@ __doc__ = u"""
TypeError: g() takes at most 2 positional arguments (3 given) TypeError: g() takes at most 2 positional arguments (3 given)
>>> g(1,2) >>> g(1,2)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'c' is missing TypeError: g() needs keyword-only argument c
>>> g(1,2, c=1) >>> g(1,2, c=1)
Traceback (most recent call last): 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)
>>> h(1,2, c=1, f=2, e=3) >>> h(1,2, c=1, f=2, e=3)
...@@ -63,10 +63,10 @@ __doc__ = u""" ...@@ -63,10 +63,10 @@ __doc__ = u"""
>>> h(1,2,3) >>> h(1,2,3)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'c' is missing TypeError: h() needs keyword-only argument c
>>> h(1,2, d=1) >>> h(1,2, d=1)
Traceback (most recent call last): 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)
>>> k(1,2, c=1, f=2, e=3) >>> k(1,2, c=1, f=2, e=3)
...@@ -75,10 +75,10 @@ __doc__ = u""" ...@@ -75,10 +75,10 @@ __doc__ = u"""
>>> k(1,2,3) >>> k(1,2,3)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'f' is missing TypeError: k() needs keyword-only argument f
>>> k(1,2, d=1) >>> k(1,2, d=1)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'f' is missing TypeError: k() needs keyword-only argument f
""" """
def b(a, b, c): def b(a, b, c):
......
__doc__ = u""" __doc__ = u"""
>>> call3(b) >>> call3(b)
1 2 3
>>> call4(b) >>> call4(b)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: b() takes at most 3 positional arguments (4 given) TypeError: b() takes at most 3 positional arguments (4 given)
>>> call2(c) >>> call2(c)
1 2 1
>>> call3(c) >>> call3(c)
1 2 3
>>> call4(c) >>> call4(c)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: c() takes at most 3 positional arguments (4 given) TypeError: c() takes at most 3 positional arguments (4 given)
>>> call2(d) >>> call2(d)
1 2 88
>>> call2c(d) >>> call2c(d)
1 2 1
>>> call3(d) >>> call3(d)
Traceback (most recent call last): Traceback (most recent call last):
...@@ -21,64 +26,82 @@ __doc__ = u""" ...@@ -21,64 +26,82 @@ __doc__ = u"""
TypeError: 'd' is an invalid keyword argument for this function TypeError: 'd' is an invalid keyword argument for this function
>>> call2(e) >>> call2(e)
1 2 88 []
>>> call2c(e) >>> call2c(e)
1 2 1 []
>>> call2d(e) >>> call2d(e)
1 2 88 [('d', 1)]
>>> call2cde(e) >>> call2cde(e)
1 2 1 [('d', 2), ('e', 3)]
>>> call3(e) >>> call3(e)
1 2 3 []
>>> call4(e) >>> call4(e)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: e() takes at most 3 positional arguments (4 given) TypeError: e() takes at most 3 positional arguments (4 given)
>>> call2c(f) >>> call2c(f)
1 2 1 42
>>> call2cd(f) >>> call2cd(f)
1 2 1 2
>>> call3(f) >>> call3(f)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: f() takes at most 2 positional arguments (3 given) TypeError: f() takes at most 2 positional arguments (3 given)
>>> call2(f) >>> call2(f)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'c' is missing TypeError: f() needs keyword-only argument c
>>> call2ce(f) >>> call2ce(f)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: 'e' is an invalid keyword argument for this function TypeError: 'e' is an invalid keyword argument for this function
>>> call2cf(g) >>> call2cf(g)
1 2 1 42 17 2 []
>>> call2cefd(g) >>> call2cefd(g)
1 2 1 11 0 2 []
>>> call2cfex(g) >>> call2cfex(g)
1 2 1 42 0 2 [('x', 25)]
>>> call3(g) >>> call3(g)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: g() takes at most 2 positional arguments (3 given) TypeError: g() takes at most 2 positional arguments (3 given)
>>> call2(g) >>> call2(g)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'c' is missing TypeError: g() needs keyword-only argument c
>>> call2c(g) >>> call2c(g)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'f' is missing TypeError: g() needs keyword-only argument f
>>> call2cf(h) >>> call2cf(h)
1 2 1 42 17 2 () []
>>> call2cfe(h) >>> call2cfe(h)
1 2 1 42 3 2 () []
>>> call6cf(h) >>> call6cf(h)
1 2 1 42 17 2 (3, 4, 5, 6) []
>>> call6cfexy(h) >>> call6cfexy(h)
1 2 1 42 3 2 (3, 4, 5, 6) [('x', 25), ('y', 11)]
>>> call3(h) >>> call3(h)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'c' is missing TypeError: h() needs keyword-only argument c
>>> call3d(h) >>> call3d(h)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'c' is missing TypeError: h() needs keyword-only argument c
>>> call2cf(k) >>> call2cf(k)
1 2 1 42 17 2 () []
>>> call2cfe(k) >>> call2cfe(k)
1 2 1 42 3 2 () []
>>> call6df(k) >>> call6df(k)
1 2 3 1 17 2 (4, 5, 6) []
>>> call6dfexy(k) >>> call6dfexy(k)
1 2 3 1 3 2 (4, 5, 6) [('x', 25), ('y', 11)]
>>> call3(k) >>> call3(k)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'f' is missing TypeError: k() needs keyword-only argument f
>>> call2d(k) >>> call2d(k)
Traceback (most recent call last): Traceback (most recent call last):
TypeError: required keyword argument 'f' is missing TypeError: k() needs keyword-only argument f
""" """
import sys, re import sys, re
...@@ -145,25 +168,33 @@ def call6dfexy(f): ...@@ -145,25 +168,33 @@ def call6dfexy(f):
# the called functions: # the called functions:
def b(a, b, c): def b(a, b, c):
pass print a,b,c
def c(a, b, c=1): def c(a, b, c=1):
pass print a,b,c
def d(a, b, *, c = 88): def d(a, b, *, c = 88):
pass print a,b,c
def e(a, b, c = 88, **kwds): 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): def f(a, b, *, c, d = 42):
pass print a,b,c,d
def g(a, b, *, c, d = 42, e = 17, f, **kwds): 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): 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): 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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment