[pypy-commit] pypy kwargsdict-strategy: add a new space method view_as_kwargs which efficiently unwraps a KwargsDict and use it in the argument parser
cfbolz
noreply at buildbot.pypy.org
Sat Apr 7 15:04:21 CEST 2012
Author: Carl Friedrich Bolz <cfbolz at gmx.de>
Branch: kwargsdict-strategy
Changeset: r54229:166c64714bac
Date: 2012-04-06 11:08 +0200
http://bitbucket.org/pypy/pypy/changeset/166c64714bac/
Log: add a new space method view_as_kwargs which efficiently unwraps a
KwargsDict and use it in the argument parser
diff --git a/pypy/interpreter/argument.py b/pypy/interpreter/argument.py
--- a/pypy/interpreter/argument.py
+++ b/pypy/interpreter/argument.py
@@ -169,6 +169,10 @@
def _combine_starstarargs_wrapped(self, w_starstararg):
# unpack the ** arguments
space = self.space
+ keywords, values_w = space.view_as_kwargs(w_starstararg)
+ if keywords is not None:
+ self._add_keywordargs_no_unwrapping(keywords, values_w)
+ return jit.isconstant(len(self.keywords))
if space.isinstance_w(w_starstararg, space.w_dict):
if not space.is_true(w_starstararg):
return False # don't call unpackiterable - it's jit-opaque
@@ -227,6 +231,26 @@
self.keywords_w = self.keywords_w + keywords_w
self.keyword_names_w = keys_w
+ @jit.look_inside_iff(lambda self, keywords, keywords_w:
+ jit.isconstant(len(keywords) and
+ jit.isconstant(self.keywords)))
+ def _add_keywordargs_no_unwrapping(self, keywords, keywords_w):
+ if self.keywords is None:
+ self.keywords = keywords
+ self.keywords_w = keywords_w
+ else:
+ # looks quadratic, but the JIT should remove all of it nicely.
+ # Also, all the lists should be small
+ for key in keywords:
+ for otherkey in self.keywords:
+ if otherkey == key:
+ raise operationerrfmt(self.space.w_TypeError,
+ "got multiple values "
+ "for keyword argument "
+ "'%s'", key)
+ self.keywords = self.keywords + keywords
+ self.keywords_w = self.keywords_w + keywords_w
+
def fixedunpack(self, argcount):
"""The simplest argument parsing: get the 'argcount' arguments,
or raise a real ValueError if the length is wrong."""
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -914,6 +914,12 @@
"""
return None
+ def view_as_kwargs(self, w_dict):
+ """ if w_dict is a kwargs-dict, return two lists, one of unwrapped
+ strings and one of wrapped values. otherwise return (None, None)
+ """
+ return (None, None)
+
def newlist_str(self, list_s):
return self.newlist([self.wrap(s) for s in list_s])
diff --git a/pypy/interpreter/test/test_argument.py b/pypy/interpreter/test/test_argument.py
--- a/pypy/interpreter/test/test_argument.py
+++ b/pypy/interpreter/test/test_argument.py
@@ -75,7 +75,10 @@
def unpackiterable(self, it):
return list(it)
- def newdict(self):
+ def view_as_kwargs(self, x):
+ return None, None
+
+ def newdict(self, kwargs=False):
return {}
def newlist(self, l=[]):
@@ -488,6 +491,57 @@
assert len(l) == 1
assert l[0] == space.wrap(5)
+ def test_starstarargs_special(self):
+ class kwargs(object):
+ def __init__(self, k, v):
+ self.k = k
+ self.v = v
+ class MyDummySpace(DummySpace):
+ def view_as_kwargs(self, kw):
+ if isinstance(kw, kwargs):
+ return kw.k, kw.v
+ return None, None
+ space = MyDummySpace()
+ for i in range(3):
+ kwds = [("c", 3)]
+ kwds_w = dict(kwds[:i])
+ keywords = kwds_w.keys()
+ keywords_w = kwds_w.values()
+ rest = dict(kwds[i:])
+ w_kwds = kwargs(rest.keys(), rest.values())
+ if i == 2:
+ w_kwds = None
+ assert len(keywords) == len(keywords_w)
+ args = Arguments(space, [1, 2], keywords[:], keywords_w[:], w_starstararg=w_kwds)
+ l = [None, None, None]
+ args._match_signature(None, l, Signature(["a", "b", "c"]), defaults_w=[4])
+ assert l == [1, 2, 3]
+ args = Arguments(space, [1, 2], keywords[:], keywords_w[:], w_starstararg=w_kwds)
+ l = [None, None, None, None]
+ args._match_signature(None, l, Signature(["a", "b", "b1", "c"]), defaults_w=[4, 5])
+ assert l == [1, 2, 4, 3]
+ args = Arguments(space, [1, 2], keywords[:], keywords_w[:], w_starstararg=w_kwds)
+ l = [None, None, None, None]
+ args._match_signature(None, l, Signature(["a", "b", "c", "d"]), defaults_w=[4, 5])
+ assert l == [1, 2, 3, 5]
+ args = Arguments(space, [1, 2], keywords[:], keywords_w[:], w_starstararg=w_kwds)
+ l = [None, None, None, None]
+ py.test.raises(ArgErr, args._match_signature, None, l,
+ Signature(["c", "b", "a", "d"]), defaults_w=[4, 5])
+ args = Arguments(space, [1, 2], keywords[:], keywords_w[:], w_starstararg=w_kwds)
+ l = [None, None, None, None]
+ py.test.raises(ArgErr, args._match_signature, None, l,
+ Signature(["a", "b", "c1", "d"]), defaults_w=[4, 5])
+ args = Arguments(space, [1, 2], keywords[:], keywords_w[:], w_starstararg=w_kwds)
+ l = [None, None, None]
+ args._match_signature(None, l, Signature(["a", "b"], None, "**"))
+ assert l == [1, 2, {'c': 3}]
+ excinfo = py.test.raises(OperationError, Arguments, space, [], ["a"],
+ [1], w_starstararg=kwargs(["a"], [2]))
+ assert excinfo.value.w_type is TypeError
+
+
+
class TestErrorHandling(object):
def test_missing_args(self):
# got_nargs, nkwds, expected_nargs, has_vararg, has_kwarg,
diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py
--- a/pypy/objspace/std/dictmultiobject.py
+++ b/pypy/objspace/std/dictmultiobject.py
@@ -95,7 +95,8 @@
getitem_str delitem length \
clear w_keys values \
items iter setdefault \
- popitem listview_str listview_int".split()
+ popitem listview_str listview_int \
+ view_as_kwargs".split()
def make_method(method):
def f(self, *args):
@@ -169,6 +170,9 @@
def listview_int(self, w_dict):
return None
+ def view_as_kwargs(self, w_dict):
+ return (None, None)
+
class EmptyDictStrategy(DictStrategy):
erase, unerase = rerased.new_erasing_pair("empty")
diff --git a/pypy/objspace/std/kwargsdict.py b/pypy/objspace/std/kwargsdict.py
--- a/pypy/objspace/std/kwargsdict.py
+++ b/pypy/objspace/std/kwargsdict.py
@@ -138,6 +138,9 @@
w_dict.strategy = strategy
w_dict.dstorage = storage
+ def view_as_kwargs(self, w_dict):
+ return self.unerase(w_dict.dstorage)
+
class KwargsDictIterator(IteratorImplementation):
def __init__(self, space, strategy, dictimplementation):
diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py
--- a/pypy/objspace/std/objspace.py
+++ b/pypy/objspace/std/objspace.py
@@ -472,6 +472,12 @@
return w_obj.getitems_int()
return None
+ def view_as_kwargs(self, w_dict):
+ return (None, None)
+ if type(w_obj) is W_DictMultiObject:
+ return w_obj.view_as_kwargs()
+ return (None, None)
+
def _uses_list_iter(self, w_obj):
from pypy.objspace.descroperation import list_iter
return self.lookup(w_obj, '__iter__') is list_iter(self)
More information about the pypy-commit
mailing list