cython-devel

changeset 2802:df9b7285ec6a

implement #470: non-dicts as **kwargs
author Stefan Behnel <scoder@users.berlios.de>
date Thu Jan 14 08:36:13 2010 +0100 (2 years ago)
parents b74db1985752
children 5d1ea5364347
files Cython/Compiler/ExprNodes.py tests/run/non_dict_kwargs_T470.pyx
line diff
1.1 --- a/Cython/Compiler/ExprNodes.py Thu Jan 14 08:03:17 2010 +0100 1.2 +++ b/Cython/Compiler/ExprNodes.py Thu Jan 14 08:36:13 2010 +0100 1.3 @@ -2775,6 +2775,7 @@ 1.4 1.5 def generate_result_code(self, code): 1.6 if self.type.is_error: return 1.7 + dict_temp = dict_ref = None 1.8 if self.keyword_args and self.starstar_arg: 1.9 code.put_error_if_neg(self.pos, 1.10 "PyDict_Update(%s, %s)" % ( 1.11 @@ -2785,6 +2786,23 @@ 1.12 keyword_code = self.keyword_args.py_result() 1.13 elif self.starstar_arg: 1.14 keyword_code = self.starstar_arg.py_result() 1.15 + if self.starstar_arg.type is not Builtin.dict_type: 1.16 + # CPython supports calling functions with non-dicts, so do we 1.17 + dict_temp = code.funcstate.allocate_temp(py_object_type, manage_ref=False) 1.18 + dict_ref = code.funcstate.allocate_temp(py_object_type, manage_ref=True) 1.19 + code.putln("if (unlikely(!PyDict_Check(%s))) {" % keyword_code) 1.20 + code.putln( 1.21 + "%s = PyObject_CallFunctionObjArgs((PyObject*)&PyDict_Type, %s, NULL); %s" % ( 1.22 + dict_ref, 1.23 + keyword_code, 1.24 + code.error_goto_if_null(dict_ref, self.pos))) 1.25 + code.put_gotref(dict_ref) 1.26 + code.putln("%s = %s;" % (dict_temp, dict_ref)) 1.27 + code.putln("} else {") 1.28 + code.putln("%s = 0;" % dict_ref) 1.29 + code.putln("%s = %s;" % (dict_temp, keyword_code)) 1.30 + code.putln("}") 1.31 + keyword_code = dict_temp 1.32 else: 1.33 keyword_code = None 1.34 if not keyword_code: 1.35 @@ -2802,6 +2820,10 @@ 1.36 call_code, 1.37 code.error_goto_if_null(self.result(), self.pos))) 1.38 code.put_gotref(self.py_result()) 1.39 + if dict_ref is not None: 1.40 + code.funcstate.release_temp(dict_temp) 1.41 + code.put_xdecref_clear(dict_ref, py_object_type) 1.42 + code.funcstate.release_temp(dict_ref) 1.43 1.44 1.45 class AsTupleNode(ExprNode):
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/tests/run/non_dict_kwargs_T470.pyx Thu Jan 14 08:36:13 2010 +0100 2.3 @@ -0,0 +1,52 @@ 2.4 +__doc__ = u""" 2.5 +>>> func(**{'a' : 7}) 2.6 +True 2.7 +>>> func(**SubDict()) 2.8 +True 2.9 + 2.10 +>>> call_non_dict_test() 2.11 +True 2.12 +>>> call_non_dict_test_kw() 2.13 +True 2.14 + 2.15 +>>> call_sub_dict_test() 2.16 +True 2.17 +>>> call_sub_dict_test_kw() 2.18 +True 2.19 +""" 2.20 + 2.21 +import sys 2.22 + 2.23 +if sys.version_info >= (2,6): 2.24 + __doc__ += u""" 2.25 +>>> func(**NonDict()) 2.26 +True 2.27 +""" 2.28 + 2.29 +def func(**kwargs): 2.30 + return type(kwargs) is dict and kwargs['a'] == 7 2.31 + 2.32 + 2.33 +class NonDict(object): 2.34 + def __getitem__(self, k): 2.35 + assert k == 'a' 2.36 + return 7 2.37 + def keys(self): 2.38 + return ['a'] 2.39 + 2.40 +def call_non_dict_test(): 2.41 + return func(**NonDict()) 2.42 + 2.43 +def call_non_dict_test_kw(): 2.44 + return func(a=5, **NonDict()) 2.45 + 2.46 + 2.47 +class SubDict(dict): 2.48 + def __init__(self): 2.49 + self['a'] = 7 2.50 + 2.51 +def call_sub_dict_test(): 2.52 + return func(**SubDict()) 2.53 + 2.54 +def call_sub_dict_test_kw(): 2.55 + return func(a=5, **SubDict())