Author: Armin Rigo <[email protected]>
Branch: 
Changeset: r77239:0c9627141b68
Date: 2015-05-09 10:01 +0200
http://bitbucket.org/pypy/pypy/changeset/0c9627141b68/

Log:    Issue #2043 fix

        Also fixes an issue with partial(..., self=...)

diff --git a/lib_pypy/_functools.py b/lib_pypy/_functools.py
--- a/lib_pypy/_functools.py
+++ b/lib_pypy/_functools.py
@@ -8,16 +8,16 @@
     partial(func, *args, **keywords) - new function with partial application
     of the given arguments and keywords.
     """
-
-    def __init__(self, *args, **keywords):
-        if not args:
-            raise TypeError('__init__() takes at least 2 arguments (1 given)')
-        func, args = args[0], args[1:]
+    def __init__(*args, **keywords):
+        if len(args) < 2:
+            raise TypeError('__init__() takes at least 2 arguments (%d given)'
+                            % len(args))
+        self, func, args = args[0], args[1], args[2:]
         if not callable(func):
             raise TypeError("the first argument must be callable")
         self._func = func
         self._args = args
-        self._keywords = keywords or None
+        self._keywords = keywords
 
     def __delattr__(self, key):
         if key == '__dict__':
@@ -37,19 +37,22 @@
         return self._keywords
 
     def __call__(self, *fargs, **fkeywords):
-        if self.keywords is not None:
-            fkeywords = dict(self.keywords, **fkeywords)
-        return self.func(*(self.args + fargs), **fkeywords)
+        if self._keywords:
+            fkeywords = dict(self._keywords, **fkeywords)
+        return self._func(*(self._args + fargs), **fkeywords)
 
     def __reduce__(self):
         d = dict((k, v) for k, v in self.__dict__.iteritems() if k not in
                 ('_func', '_args', '_keywords'))
         if len(d) == 0:
             d = None
-        return (type(self), (self.func,),
-                (self.func, self.args, self.keywords, d))
+        return (type(self), (self._func,),
+                (self._func, self._args, self._keywords, d))
 
     def __setstate__(self, state):
-        self._func, self._args, self._keywords, d = state
+        func, args, keywords, d = state
         if d is not None:
             self.__dict__.update(d)
+        self._func = func
+        self._args = args
+        self._keywords = keywords
diff --git a/pypy/module/test_lib_pypy/test_functools.py 
b/pypy/module/test_lib_pypy/test_functools.py
--- a/pypy/module/test_lib_pypy/test_functools.py
+++ b/pypy/module/test_lib_pypy/test_functools.py
@@ -6,8 +6,10 @@
 def test_partial_reduce():
     partial = _functools.partial(test_partial_reduce)
     state = partial.__reduce__()
+    d = state[2][2]
     assert state == (type(partial), (test_partial_reduce,),
-                     (test_partial_reduce, (), None, None))
+                     (test_partial_reduce, (), d, None))
+    assert d is None or d == {}      # both are acceptable
 
 def test_partial_setstate():
     partial = _functools.partial(object)
@@ -30,3 +32,15 @@
     assert str(exc.value) == "a partial object's dictionary may not be deleted"
     with pytest.raises(AttributeError):
         del partial.zzz
+
+def test_self_keyword():
+    partial = _functools.partial(dict, self=42)
+    assert partial(other=43) == {'self': 42, 'other': 43}
+
+def test_no_keywords():
+    kw1 = _functools.partial(dict).keywords
+    kw2 = _functools.partial(dict, **{}).keywords
+    # CPython gives different results for these two cases, which is not
+    # possible to emulate in pure Python; see issue #2043
+    assert kw1 == {} or kw1 is None
+    assert kw2 == {}
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to