[pypy-commit] pypy py3.5: Add validation of __getnewargs__()/__getnewargs_ex__() return values
rlamy
pypy.commits at gmail.com
Mon May 22 11:58:53 EDT 2017
Author: Ronan Lamy <ronan.lamy at gmail.com>
Branch: py3.5
Changeset: r91372:48119cb4c0db
Date: 2017-05-22 16:58 +0100
http://bitbucket.org/pypy/pypy/changeset/48119cb4c0db/
Log: Add validation of __getnewargs__()/__getnewargs_ex__() return values
diff --git a/pypy/objspace/std/objectobject.py b/pypy/objspace/std/objectobject.py
--- a/pypy/objspace/std/objectobject.py
+++ b/pypy/objspace/std/objectobject.py
@@ -173,31 +173,55 @@
return space.get_and_call_function(w_impl, w_obj)
+def _getnewargs(space, w_obj):
+ w_descr = space.lookup(w_obj, '__getnewargs_ex__')
+ hasargs = True
+ if w_descr is not None:
+ w_result = space.get_and_call_function(w_descr, w_obj)
+ if not space.isinstance_w(w_result, space.w_tuple):
+ raise oefmt(space.w_TypeError,
+ "__getnewargs_ex__ should return a tuple, not '%T'", w_result)
+ n = space.len_w(w_result)
+ if n != 2:
+ raise oefmt(space.w_ValueError,
+ "__getnewargs_ex__ should return a tuple of length 2, not %d",
+ n)
+ w_args, w_kwargs = space.fixedview(w_result, 2)
+ if not space.isinstance_w(w_args, space.w_tuple):
+ raise oefmt(space.w_TypeError,
+ "first item of the tuple returned by __getnewargs_ex__ must "
+ "be a tuple, not '%T'", w_args)
+ if not space.isinstance_w(w_kwargs, space.w_dict):
+ raise oefmt(space.w_TypeError,
+ "second item of the tuple returned by __getnewargs_ex__ must "
+ "be a dict, not '%T'", w_kwargs)
+ else:
+ w_descr = space.lookup(w_obj, '__getnewargs__')
+ if w_descr is not None:
+ w_args = space.get_and_call_function(w_descr, w_obj)
+ if not space.isinstance_w(w_args, space.w_tuple):
+ raise oefmt(space.w_TypeError,
+ "__getnewargs__ should return a tuple, not '%T'", w_args)
+ else:
+ hasargs = False
+ w_args = space.newtuple([])
+ w_kwargs = space.w_None
+ return hasargs, w_args, w_kwargs
+
@unwrap_spec(proto=int)
def descr__reduce__(space, w_obj, proto=0):
w_proto = space.newint(proto)
if proto >= 2:
- w_descr = space.lookup(w_obj, '__getnewargs_ex__')
- hasargs = True
- if w_descr is not None:
- w_result = space.get_and_call_function(w_descr, w_obj)
- w_args, w_kwargs = space.fixedview(w_result, 2)
- else:
- w_descr = space.lookup(w_obj, '__getnewargs__')
- if w_descr is not None:
- w_args = space.get_and_call_function(w_descr, w_obj)
- else:
- hasargs = False
- w_args = space.newtuple([])
- w_kwargs = space.w_None
+ hasargs, w_args, w_kwargs = _getnewargs(space, w_obj)
w_getstate = space.lookup(w_obj, '__get_state__')
if w_getstate is None:
- required = not hasargs and \
- not space.isinstance_w(w_obj, space.w_list) and \
- not space.isinstance_w(w_obj, space.w_dict)
+ required = (not hasargs and
+ not space.isinstance_w(w_obj, space.w_list) and
+ not space.isinstance_w(w_obj, space.w_dict))
w_obj_type = space.type(w_obj)
if required and w_obj_type.layout.typedef.variable_sized:
- raise oefmt(space.w_TypeError, "cannot pickle %N objects", w_obj_type)
+ raise oefmt(
+ space.w_TypeError, "cannot pickle %N objects", w_obj_type)
return reduce_2(space, w_obj, w_proto, w_args, w_kwargs)
return reduce_1(space, w_obj, w_proto)
diff --git a/pypy/objspace/std/test/test_obj.py b/pypy/objspace/std/test/test_obj.py
--- a/pypy/objspace/std/test/test_obj.py
+++ b/pypy/objspace/std/test/test_obj.py
@@ -89,6 +89,47 @@
assert '__getnewargs__' not in seen
assert '__getnewargs_ex__' not in seen
+ def test_reduce_ex_errors(self):
+ # cf. lib-python/3/test/test_descr.py::PicklingTests.test_reduce()
+ args = (-101, "spam")
+ kwargs = {'bacon': -201, 'fish': -301}
+
+ class C2:
+ def __getnewargs__(self):
+ return "bad args"
+ excinfo = raises(TypeError, C2().__reduce_ex__, 4)
+ assert str(excinfo.value) == \
+ "__getnewargs__ should return a tuple, not 'str'"
+
+ class C4:
+ def __getnewargs_ex__(self):
+ return (args, "bad dict")
+ excinfo = raises(TypeError, C4().__reduce_ex__, 4)
+ assert str(excinfo.value) == ("second item of the tuple "
+ "returned by __getnewargs_ex__ must be a dict, not 'str'")
+
+ class C5:
+ def __getnewargs_ex__(self):
+ return ("bad tuple", kwargs)
+ excinfo = raises(TypeError, C5().__reduce_ex__, 4)
+ assert str(excinfo.value) == ("first item of the tuple "
+ "returned by __getnewargs_ex__ must be a tuple, not 'str'")
+
+ class C6:
+ def __getnewargs_ex__(self):
+ return ()
+ excinfo = raises(ValueError, C6().__reduce_ex__, 4)
+ assert str(excinfo.value) == \
+ "__getnewargs_ex__ should return a tuple of length 2, not 0"
+
+ class C7:
+ def __getnewargs_ex__(self):
+ return "bad args"
+ excinfo = raises(TypeError, C7().__reduce_ex__, 4)
+ assert str(excinfo.value) == \
+ "__getnewargs_ex__ should return a tuple, not 'str'"
+
+
def test_reduce_state_empty_dict(self):
class X(object):
pass
More information about the pypy-commit
mailing list