summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Madden <jamadden@gmail.com>2015-05-27 12:26:19 -0500
committerJason Madden <jamadden@gmail.com>2015-05-27 12:26:19 -0500
commit25241e111c15b6e75343ccdac912882ebff0cfd2 (patch)
treecd5f2ccbf737b36d668083b26831aa1178b38f61
parent8f859a0c3ad345a7e427f07651264e1585c3fe9e (diff)
downloadzope-security-25241e111c15b6e75343ccdac912882ebff0cfd2.tar.gz
Let z.s.checker.Global objects be pickled when security-proxied under PyPy with zope.proxy 4.1.5
-rw-r--r--CHANGES.rst2
-rw-r--r--src/zope/security/proxy.py29
2 files changed, 27 insertions, 4 deletions
diff --git a/CHANGES.rst b/CHANGES.rst
index 76a6154..cfe3bb9 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -4,7 +4,7 @@ Changes
4.0.2 (unreleased)
------------------
-- TBD
+- Compatibility with ``zope.proxy`` 4.1.5 under PyPy.
4.0.1 (2014-03-19)
------------------
diff --git a/src/zope/security/proxy.py b/src/zope/security/proxy.py
index 16bb95f..87b3f22 100644
--- a/src/zope/security/proxy.py
+++ b/src/zope/security/proxy.py
@@ -84,11 +84,34 @@ class ProxyPy(PyProxyBase):
checker = super(PyProxyBase, self).__getattribute__('_checker')
if name == '_checker':
return checker
- if name not in ['__cmp__', '__hash__', '__bool__', '__nonzero__',
+ if name not in ('__cmp__', '__hash__', '__bool__', '__nonzero__',
'__lt__', '__le__', '__eq__', '__ne__', '__ge__',
- '__gt__']:
+ '__gt__'):
checker.check_getattr(wrapped, name)
- return checker.proxy(super(ProxyPy, self).__getattribute__(name))
+ if name in ('__reduce__', '__reduce_ex__'):
+ # The superclass specifically denies access to __reduce__
+ # and __reduce__ex__, not letting proxies be pickled. But
+ # for backwards compatibility, we need to be able to
+ # pickle proxies. See checker:Global for an example.
+ val = getattr(wrapped, name)
+ elif name == '__module__':
+ # The superclass deals with descriptors found in the type
+ # of this object just like the Python language spec states, letting
+ # them have precedence over things found in the instance. This
+ # normally makes us a better proxy implementation. However, the
+ # C version of this code in _proxy doesn't take that same care and instead
+ # uses the generic object attribute access methods directly on
+ # the wrapped object. This is a behaviour difference; so far, it's
+ # only been noticed for the __module__ attribute, which checker:Global
+ # wants to override but couldn't because this object's type's __module__ would
+ # get in the way. That broke pickling, and checker:Global can't return
+ # anything more sophisticated than a str (a tuple) because it gets proxied
+ # and breaks pickling again. Our solution is to match the C version for this
+ # one attribute.
+ val = getattr(wrapped, name)
+ else:
+ val = super(ProxyPy, self).__getattribute__(name)
+ return checker.proxy(val)
def __getattr__(self, name):
wrapped = super(PyProxyBase, self).__getattribute__('_wrapped')