Commit 678151d9 authored by Bryton Lacquement's avatar Bryton Lacquement 🚪

ERP5 Py3: patch Acquisition 4.5+SlapOSPatched001

parent f57414af
diff -uNr Acquisition-4.5.orig/src/Acquisition/_Acquisition.c Acquisition-4.5/src/Acquisition/_Acquisition.c
--- Acquisition-4.5.orig/src/Acquisition/_Acquisition.c 2018-12-10 14:50:38.607014475 +0100
+++ Acquisition-4.5/src/Acquisition/_Acquisition.c 2018-12-10 15:11:31.902452836 +0100
@@ -541,6 +541,64 @@
}
static PyObject *
+Wrapper_GetAttr(PyObject *self, PyObject *attr_name, PyObject *orig)
+{
+ /* This function retrieves an attribute from an object by PyObject_GetAttr.
+
+ The main difference between Wrapper_GetAttr and PyObject_GetAttr is that
+ Wrapper_GetAttr calls _aq_dynamic to generate an attribute dynamically, if
+ the attribute is not found.
+ */
+ PyObject *r, *v, *tb;
+ PyObject *d, *m;
+ PyObject *o;
+
+ if (isWrapper(self))
+ o = WRAPPER(self)->obj;
+ else
+ o = self;
+
+ /* Try to get an attribute in the normal way first. */
+ r = PyObject_GetAttr(o, attr_name);
+ if (r)
+ return r;
+
+ /* If an unexpected error happens, return immediately. */
+ PyErr_Fetch(&r, &v, &tb);
+ if (r != PyExc_AttributeError)
+ {
+ PyErr_Restore(r, v, tb);
+ return NULL;
+ }
+
+ /* Try to get _aq_dynamic. */
+ m = PyObject_GetAttrString(o, "_aq_dynamic");
+ if (!m) {
+ PyErr_Restore(r, v, tb);
+ return NULL;
+ }
+
+ /* Call _aq_dynamic in the context of the original acquisition wrapper. */
+ if (PyECMethod_Check(m) && PyECMethod_Self(m) == o)
+ ASSIGN(m, PyECMethod_New(m, OBJECT(self)));
+ else if (has__of__(m)) ASSIGN(m, __of__(m,OBJECT(self)));
+ d = PyObject_CallFunction(m, "O", attr_name);
+ Py_DECREF(m);
+
+ /* In the case of None, assume that the attribute is not found. */
+ if (d == Py_None) {
+ Py_DECREF(d);
+ PyErr_Restore(r, v, tb);
+ return NULL;
+ }
+
+ Py_XDECREF(r);
+ Py_XDECREF(v);
+ Py_XDECREF(tb);
+ return d;
+}
+
+static PyObject *
Wrapper_acquire(Wrapper *self, PyObject *oname,
PyObject *filter, PyObject *extra, PyObject *orig,
int explicit, int containment);
@@ -675,8 +733,8 @@
return NULL;
}
- /* normal attribute lookup */
- else if ((r = PyObject_GetAttr(self->obj, oname))) {
+ /* Give _aq_dynamic a chance, then normal attribute lookup */
+ else if ((r = Wrapper_GetAttr(OBJECT(self), oname, orig))) {
if (r == Acquired) {
Py_DECREF(r);
return Wrapper_acquire(
@@ -804,7 +862,7 @@
return NULL;
}
- if ((r = PyObject_GetAttr(self->container, oname)) == NULL) {
+ if ((r = Wrapper_GetAttr(self->container, oname, orig)) == NULL) {
/* May be AttributeError or some other kind of error */
return NULL;
}
@@ -828,7 +886,7 @@
static PyObject *
Wrapper_getattro(Wrapper *self, PyObject *oname)
{
- return Wrapper_findattr(self, oname, NULL, NULL, NULL, 1, 1, 0, 0);
+ return Wrapper_findattr(self, oname, NULL, NULL, OBJECT(self), 1, 1, 0, 0);
}
static PyObject *
@@ -844,7 +902,7 @@
if (STR_EQ(PyBytes_AS_STRING(tmp), "acquire")) {
result = Py_FindAttr(OBJECT(self), oname);
} else {
- result = Wrapper_findattr(self, oname, NULL, NULL, NULL, 1, 0, 0, 0);
+ result = Wrapper_findattr(self, oname, NULL, NULL, OBJECT(self), 1, 0, 0, 0);
}
Py_DECREF(tmp);
diff -uNr Acquisition-4.5.orig/src/Acquisition/test_dynamic_acquisition.py Acquisition-4.5/src/Acquisition/test_dynamic_acquisition.py
--- Acquisition-4.5.orig/src/Acquisition/test_dynamic_acquisition.py 1970-01-01 01:00:00.000000000 +0100
+++ Acquisition-4.5/src/Acquisition/test_dynamic_acquisition.py 2018-12-10 14:45:01.601164033 +0100
@@ -0,0 +1,161 @@
+##############################################################################
+#
+# Copyright (c) 1996-2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE
+#
+##############################################################################
+from __future__ import print_function
+
+import Acquisition
+
+def checkContext(self, o):
+ # Python equivalent to aq_inContextOf
+ from Acquisition import aq_base, aq_parent, aq_inner
+ subob = self
+ o = aq_base(o)
+ while 1:
+ if aq_base(subob) is o:
+ return True
+ self = aq_inner(subob)
+ if self is None: break
+ subob = aq_parent(self)
+ if subob is None: break
+ return False
+
+class B(Acquisition.Implicit):
+ color='red'
+
+ def __init__(self, name='b'):
+ self.name = name
+
+ def _aq_dynamic(self, attr):
+ if attr == 'bonjour': return None
+
+ def dynmethod():
+ chain = ' <- '.join(repr(obj) for obj in Acquisition.aq_chain(self))
+ print(repr(self) + '.' + attr)
+ print('chain:', chain)
+
+ return dynmethod
+
+ def __repr__(self):
+ return "%s(%r)" % (self.__class__.__name__, self.name)
+
+class A(Acquisition.Implicit):
+
+ def __init__(self, name='a'):
+ self.name = name
+
+ def hi(self):
+ print(self, self.color)
+
+ def _aq_dynamic(self, attr):
+ return None
+
+ def __repr__(self):
+ return "%s(%r)" % (self.__class__.__name__, self.name)
+
+def test_dynamic():
+ r'''
+ The _aq_dynamic functionality allows an object to dynamically provide an
+ attribute.
+
+ If an object doesn't have an attribute, Acquisition checks to see if the
+ object has a _aq_dynamic method, which is then called. It is functionally
+ equivalent to __getattr__, but _aq_dynamic is called with 'self' as the
+ acquisition wrapped object where as __getattr__ is called with self as the
+ unwrapped object.
+
+ Let's see how this works. In the examples below, the A class defines
+ '_aq_dynamic', but returns 'None' for all attempts, which means that no new
+ attributes should be generated dynamically. It also doesn't define 'color'
+ attribute, even though it uses it in the 'hi' method.
+
+ >>> A().hi()
+ Traceback (most recent call last):
+ ...
+ AttributeError:...
+
+ The class B, on the other hand, generates all attributes dynamically,
+ except if it is called 'bonjour'.
+
+ First we need to check that, even if an object provides '_aq_dynamic',
+ "regular" Aquisition attribute access should still work:
+
+ >>> b=B()
+ >>> b.a=A()
+ >>> b.a.hi()
+ A('a') red
+ >>> b.a.color='green'
+ >>> b.a.hi()
+ A('a') green
+
+ Now, let's see some dynamically generated action. B does not define a
+ 'salut' method, but remember that it dynamically generates a method for
+ every attribute access:
+
+ >>> b.a.salut()
+ B('b').salut
+ chain: B('b')
+
+ >>> a=A('a1')
+ >>> a.b=B('b1')
+ >>> a.b.salut()
+ B('b1').salut
+ chain: B('b1') <- A('a1')
+
+ >>> b.a.bonjour()
+ Traceback (most recent call last):
+ ...
+ AttributeError:...
+
+ >>> a.b.bonjour()
+ Traceback (most recent call last):
+ ...
+ AttributeError:...
+
+ '''
+
+def test_wrapper_comparissons():
+ r'''
+
+ Test wrapper comparisons in presence of _aq_dynamic
+
+ >>> b=B()
+ >>> b.a=A()
+ >>> foo = b.a
+ >>> bar = b.a
+ >>> assert( foo == bar )
+ >>> c = A('c')
+ >>> b.c = c
+ >>> b.c.d = c
+ >>> b.c.d == c
+ True
+ >>> b.c.d == b.c
+ True
+ >>> b.c == c
+ True
+
+ Test contextuality in presence of _aq_dynamic
+
+ >>> checkContext(b.c, b)
+ True
+ >>> checkContext(b.c, b.a)
+ False
+
+ >>> assert b.a.aq_inContextOf(b)
+ >>> assert b.c.aq_inContextOf(b)
+ >>> assert b.c.d.aq_inContextOf(b)
+ >>> assert b.c.d.aq_inContextOf(c)
+ >>> assert b.c.d.aq_inContextOf(b.c)
+ >>> assert not b.c.aq_inContextOf(foo)
+ >>> assert not b.c.aq_inContextOf(b.a)
+ >>> assert not b.a.aq_inContextOf('somestring')
+'''
diff -uNr Acquisition-4.5.orig/src/Acquisition/tests.py Acquisition-4.5/src/Acquisition/tests.py
--- Acquisition-4.5.orig/src/Acquisition/tests.py 2018-12-10 14:50:38.607014475 +0100
+++ Acquisition-4.5/src/Acquisition/tests.py 2018-12-10 15:11:31.902452836 +0100
@@ -3338,6 +3338,7 @@
suites = [
DocTestSuite(),
+ DocTestSuite('Acquisition.test_dynamic_acquisition'),
unittest.defaultTestLoader.loadTestsFromName(__name__),
]
diff -uNr Acquisition-4.5.orig/src/Acquisition.egg-info/SOURCES.txt Acquisition-4.5/src/Acquisition.egg-info/SOURCES.txt
--- Acquisition-4.5.orig/src/Acquisition.egg-info/SOURCES.txt 2018-12-10 14:52:53.472554800 +0100
+++ Acquisition-4.5/src/Acquisition.egg-info/SOURCES.txt 2018-12-10 15:02:54.257219665 +0100
@@ -14,6 +14,7 @@
src/Acquisition/_Acquisition.c
src/Acquisition/__init__.py
src/Acquisition/interfaces.py
+src/Acquisition/test_dynamic_acquisition.py
src/Acquisition/tests.py
src/Acquisition.egg-info/PKG-INFO
src/Acquisition.egg-info/SOURCES.txt
......@@ -61,7 +61,12 @@ eggs -=
SOAPpy
fpconst
Acquisition-patches = ${:_profile_base_location_}/../../component/egg-patch/Acquisition/aq_dynamic-4.5.patch#e923ab436d53282df536de3ef7d3e127
[versions]
# patched eggs
Acquisition = 4.5+SlapOSPatched001
# zc.recipe.egg 2.0.7 (in versions.cfg) requires zc.buildout>=2.12.0, so let's
# revert to the version contained in stack/slapos.cfg
zc.recipe.egg = 2.0.3+slapos003
......
......@@ -532,7 +532,7 @@ extra-paths =
patch-binary = ${patch:location}/bin/patch
PyPDF2-patches = ${:_profile_base_location_}/../../component/egg-patch/PyPDF2/0001-Custom-implementation-of-warnings.formatwarning-remo.patch#d25bb0f5dde7f3337a0a50c2f986f5c8
PyPDF2-patch-options = -p1
Acquisition-patches = ${:_profile_base_location_}/../../component/egg-patch/Acquisition/aq_dynamic.patch#1d9a56e9af4371f5b6951ebf217a15d7
Acquisition-patches = ${:_profile_base_location_}/../../component/egg-patch/Acquisition/aq_dynamic-2.13.12.patch#1d9a56e9af4371f5b6951ebf217a15d7
Acquisition-patch-options = -p1
Products.DCWorkflow-patches = ${:_profile_base_location_}/../../component/egg-patch/Products.DCWorkflow/workflow_method.patch#975b49e96bae33ac8563454fe5fa9899
Products.DCWorkflow-patch-options = -p1
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment