Commit 4a279e63 authored by Stefan Behnel's avatar Stefan Behnel

implement #470: non-dicts as **kwargs

parent f81c75f4
...@@ -2775,6 +2775,7 @@ class GeneralCallNode(CallNode): ...@@ -2775,6 +2775,7 @@ class GeneralCallNode(CallNode):
def generate_result_code(self, code): def generate_result_code(self, code):
if self.type.is_error: return if self.type.is_error: return
dict_temp = dict_ref = None
if self.keyword_args and self.starstar_arg: if self.keyword_args and self.starstar_arg:
code.put_error_if_neg(self.pos, code.put_error_if_neg(self.pos,
"PyDict_Update(%s, %s)" % ( "PyDict_Update(%s, %s)" % (
...@@ -2785,6 +2786,23 @@ class GeneralCallNode(CallNode): ...@@ -2785,6 +2786,23 @@ class GeneralCallNode(CallNode):
keyword_code = self.keyword_args.py_result() keyword_code = self.keyword_args.py_result()
elif self.starstar_arg: elif self.starstar_arg:
keyword_code = self.starstar_arg.py_result() 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: else:
keyword_code = None keyword_code = None
if not keyword_code: if not keyword_code:
...@@ -2802,6 +2820,10 @@ class GeneralCallNode(CallNode): ...@@ -2802,6 +2820,10 @@ class GeneralCallNode(CallNode):
call_code, call_code,
code.error_goto_if_null(self.result(), self.pos))) code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result()) 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): class AsTupleNode(ExprNode):
......
__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())
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