Author: Carl Friedrich Bolz <[email protected]>
Branch: 
Changeset: r88581:97648f46bf4e
Date: 2016-11-23 16:18 +0100
http://bitbucket.org/pypy/pypy/changeset/97648f46bf4e/

Log:    issue 2435 testing: make sure to ignore the overridden __getitem__
        method on subclasses pass as **kwargs. This is bug-to-bug
        compatibility with CPython.

diff --git a/pypy/interpreter/argument.py b/pypy/interpreter/argument.py
--- a/pypy/interpreter/argument.py
+++ b/pypy/interpreter/argument.py
@@ -111,7 +111,9 @@
                 self.keywords = self.keywords + keywords
                 self.keywords_w = self.keywords_w + values_w
             return
+        is_dict = False
         if space.isinstance_w(w_starstararg, space.w_dict):
+            is_dict = True
             keys_w = space.unpackiterable(w_starstararg)
         else:
             try:
@@ -125,7 +127,9 @@
             keys_w = space.unpackiterable(w_keys)
         keywords_w = [None] * len(keys_w)
         keywords = [None] * len(keys_w)
-        _do_combine_starstarargs_wrapped(space, keys_w, w_starstararg, 
keywords, keywords_w, self.keywords)
+        _do_combine_starstarargs_wrapped(
+            space, keys_w, w_starstararg, keywords, keywords_w, self.keywords,
+            is_dict)
         self.keyword_names_w = keys_w
         if self.keywords is None:
             self.keywords = keywords
@@ -355,7 +359,7 @@
                             key)
 
 def _do_combine_starstarargs_wrapped(space, keys_w, w_starstararg, keywords,
-        keywords_w, existingkeywords):
+        keywords_w, existingkeywords, is_dict):
     i = 0
     for w_key in keys_w:
         try:
@@ -374,7 +378,16 @@
                             "got multiple values for keyword argument '%s'",
                             key)
         keywords[i] = key
-        keywords_w[i] = space.getitem(w_starstararg, w_key)
+        if is_dict:
+            # issue 2435: bug-to-bug compatibility with cpython. for a 
subclass of
+            # dict, just ignore the __getitem__ and access the underlying dict
+            # directly
+            from pypy.objspace.descroperation import dict_getitem
+            w_descr = dict_getitem(space)
+            w_value = space.get_and_call_function(w_descr, w_starstararg, 
w_key)
+        else:
+            w_value = space.getitem(w_starstararg, w_key)
+        keywords_w[i] = w_value
         i += 1
 
 @jit.look_inside_iff(
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
@@ -120,6 +120,12 @@
             raise OperationError(AttributeError, name)
         return method(*args)
 
+    def lookup_in_type_where(self, cls, name):
+        return 'hopefully not needed', getattr(cls, name)
+
+    def get_and_call_function(self, w_descr, w_obj, *args):
+        return w_descr.__get__(w_obj)(*args)
+
     def type(self, obj):
         class Type:
             def getname(self, space):
@@ -805,3 +811,19 @@
             assert str(e) == "myerror"
         else:
             assert False, "Expected TypeError"
+
+    def test_dict_subclass_with_weird_getitem(self):
+        # issue 2435: bug-to-bug compatibility with cpython. for a subclass of
+        # dict, just ignore the __getitem__ and behave like ext_do_call in 
ceval.c
+        # which just uses the underlying dict
+        class d(dict):
+            def __getitem__(self, key):
+                return key
+
+        for key in ["foo", u"foo"]:
+            q = d()
+            q[key] = "bar"
+
+            def test(**kwargs):
+                return kwargs
+            assert test(**q) == {"foo": "bar"}
diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py
--- a/pypy/objspace/descroperation.py
+++ b/pypy/objspace/descroperation.py
@@ -61,16 +61,24 @@
 @specialize.memo()
 def str_getitem(space):
     "Utility that returns the app-level descriptor str.__getitem__."
-    w_src, w_iter = space.lookup_in_type_where(space.w_str,
-                                               '__getitem__')
-    return w_iter
+    w_src, w_getitem = space.lookup_in_type_where(space.w_str,
+                                                  '__getitem__')
+    return w_getitem
 
 @specialize.memo()
 def unicode_getitem(space):
     "Utility that returns the app-level descriptor unicode.__getitem__."
-    w_src, w_iter = space.lookup_in_type_where(space.w_unicode,
-                                               '__getitem__')
-    return w_iter
+    w_src, w_getitem = space.lookup_in_type_where(space.w_unicode,
+                                                  '__getitem__')
+    return w_getitem
+
[email protected]()
+def dict_getitem(space):
+    "Utility that returns the app-level descriptor dict.__getitem__."
+    w_src, w_getitem = space.lookup_in_type_where(space.w_dict,
+                                                  '__getitem__')
+    return w_getitem
+
 
 def raiseattrerror(space, w_obj, name, w_descr=None):
     if w_descr is None:
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to