From: Stefan Behnel Date: Thu, 14 Jan 2010 07:36:13 +0000 (+0100) Subject: implement #470: non-dicts as **kwargs X-Git-Tag: 0.12.1~26 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=4a279e633ac3c2f1f3e1f8c19d16efd57b238d1c;p=cython.git implement #470: non-dicts as **kwargs --- diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py index d2789833..5c079987 100644 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -2775,6 +2775,7 @@ class GeneralCallNode(CallNode): def generate_result_code(self, code): if self.type.is_error: return + dict_temp = dict_ref = None if self.keyword_args and self.starstar_arg: code.put_error_if_neg(self.pos, "PyDict_Update(%s, %s)" % ( @@ -2785,6 +2786,23 @@ class GeneralCallNode(CallNode): keyword_code = self.keyword_args.py_result() elif self.starstar_arg: keyword_code = self.starstar_arg.py_result() + if self.starstar_arg.type is not Builtin.dict_type: + # CPython supports calling functions with non-dicts, so do we + dict_temp = code.funcstate.allocate_temp(py_object_type, manage_ref=False) + dict_ref = code.funcstate.allocate_temp(py_object_type, manage_ref=True) + code.putln("if (unlikely(!PyDict_Check(%s))) {" % keyword_code) + code.putln( + "%s = PyObject_CallFunctionObjArgs((PyObject*)&PyDict_Type, %s, NULL); %s" % ( + dict_ref, + keyword_code, + code.error_goto_if_null(dict_ref, self.pos))) + code.put_gotref(dict_ref) + code.putln("%s = %s;" % (dict_temp, dict_ref)) + code.putln("} else {") + code.putln("%s = 0;" % dict_ref) + code.putln("%s = %s;" % (dict_temp, keyword_code)) + code.putln("}") + keyword_code = dict_temp else: keyword_code = None if not keyword_code: @@ -2802,6 +2820,10 @@ class GeneralCallNode(CallNode): call_code, code.error_goto_if_null(self.result(), self.pos))) code.put_gotref(self.py_result()) + if dict_ref is not None: + code.funcstate.release_temp(dict_temp) + code.put_xdecref_clear(dict_ref, py_object_type) + code.funcstate.release_temp(dict_ref) class AsTupleNode(ExprNode): diff --git a/tests/run/non_dict_kwargs_T470.pyx b/tests/run/non_dict_kwargs_T470.pyx new file mode 100644 index 00000000..1a4f17ba --- /dev/null +++ b/tests/run/non_dict_kwargs_T470.pyx @@ -0,0 +1,52 @@ +__doc__ = u""" +>>> func(**{'a' : 7}) +True +>>> func(**SubDict()) +True + +>>> call_non_dict_test() +True +>>> call_non_dict_test_kw() +True + +>>> call_sub_dict_test() +True +>>> call_sub_dict_test_kw() +True +""" + +import sys + +if sys.version_info >= (2,6): + __doc__ += u""" +>>> func(**NonDict()) +True +""" + +def func(**kwargs): + return type(kwargs) is dict and kwargs['a'] == 7 + + +class NonDict(object): + def __getitem__(self, k): + assert k == 'a' + return 7 + def keys(self): + return ['a'] + +def call_non_dict_test(): + return func(**NonDict()) + +def call_non_dict_test_kw(): + return func(a=5, **NonDict()) + + +class SubDict(dict): + def __init__(self): + self['a'] = 7 + +def call_sub_dict_test(): + return func(**SubDict()) + +def call_sub_dict_test_kw(): + return func(a=5, **SubDict())