[Zope-Checkins] CVS: Zope/lib/python/Acquisition -
Acquisition.h:1.2 _Acquisition.c:1.2 __init__.py:1.2
setup.py:1.2 tests.py:1.2
Jim Fulton
cvs-admin at zope.org
Fri Nov 28 11:44:15 EST 2003
Update of /cvs-repository/Zope/lib/python/Acquisition
In directory cvs.zope.org:/tmp/cvs-serv3721/lib/python/Acquisition
Added Files:
Acquisition.h _Acquisition.c __init__.py setup.py tests.py
Log Message:
New implementation of Acquisition using new-style extension classes.
=== Zope/lib/python/Acquisition/Acquisition.h 1.1 => 1.2 ===
--- /dev/null Fri Nov 28 11:44:15 2003
+++ Zope/lib/python/Acquisition/Acquisition.h Fri Nov 28 11:44:14 2003
@@ -0,0 +1,60 @@
+/*****************************************************************************
+
+ 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
+
+ ****************************************************************************/
+
+#ifndef __ACQUISITION_H_
+#define __ACQUISITION_H_
+
+typedef struct {
+ PyObject *(*AQ_Acquire) (PyObject *obj, PyObject *name, PyObject *filter,
+ PyObject *extra, int explicit, PyObject *deflt,
+ int containment);
+ PyObject *(*AQ_Get) (PyObject *obj, PyObject *name, PyObject *deflt,
+ int containment);
+ int (*AQ_IsWrapper) (PyObject *obj);
+ PyObject *(*AQ_Base) (PyObject *obj);
+ PyObject *(*AQ_Parent) (PyObject *obj);
+ PyObject *(*AQ_Self) (PyObject *obj);
+ PyObject *(*AQ_Inner) (PyObject *obj);
+ PyObject *(*AQ_Chain) (PyObject *obj, int containment);
+} ACQUISITIONCAPI;
+
+#ifndef _IN_ACQUISITION_C
+
+#define aq_Acquire(obj, name, filter, extra, explicit, deflt, containment ) (AcquisitionCAPI == NULL ? NULL : (AcquisitionCAPI->AQ_Acquire(obj, name, filter, extra, explicit, deflt, containment)))
+#define aq_acquire(obj, name) (AcquisitionCAPI == NULL ? NULL : (AcquisitionCAPI->AQ_Acquire(obj, name, NULL, NULL, 1, NULL, 0)))
+#define aq_get(obj, name, deflt, containment) (AcquistionCAPI == NULL ? NULL : (AcquisitionCAPI->AQ_Get(obj, name, deflt, containment)))
+#define aq_isWrapper(obj) (AcquisitionCAPI == NULL ? -1 : (AcquisitionCAPI->AQ_IsWrapper(obj)))
+#define aq_base(obj) (AcquisitionCAPI == NULL ? NULL : (AcquisitionCAPI->AQ_Base(obj)))
+#define aq_parent(obj) (AcquisitionCAPI == NULL ? NULL : (AcquisitionCAPI->AQ_Parent(obj)))
+#define aq_self(obj) (AcquisitionCAPI == NULL ? NULL : (AcquisitionCAPI->AQ_Self(obj)))
+#define aq_inner(obj) (AcquisitionCAPI == NULL ? NULL : (AcquisitionCAPI->AQ_Inner(obj)))
+#define aq_chain(obj, containment) (AcquisitionCAPI == NULL ? NULL : (AcquisitionCAPI->AQ_CHain(obj, containment)))
+
+static ACQUISITIONCAPI *AcquisitionCAPI = NULL;
+
+#define aq_init() { \
+ PyObject *module; \
+ PyObject *api; \
+ if (! (module = PyImport_ImportModule("Acquisition"))) return; \
+ if (! (api = PyObject_GetAttrString(module,"AcquisitionCAPI"))) return; \
+ Py_DECREF(module); \
+ AcquisitionCAPI = PyCObject_AsVoidPtr(api); \
+ Py_DECREF(api); \
+}
+
+
+
+#endif
+
+#endif
=== Zope/lib/python/Acquisition/_Acquisition.c 1.1 => 1.2 === (1176/1576 lines abridged)
--- /dev/null Fri Nov 28 11:44:15 2003
+++ Zope/lib/python/Acquisition/_Acquisition.c Fri Nov 28 11:44:14 2003
@@ -0,0 +1,1573 @@
+/*****************************************************************************
+
+ Copyright (c) 1996-2003 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
+
+ ****************************************************************************/
+
+#include "ExtensionClass.h"
+
+#define _IN_ACQUISITION_C
+#include "Acquisition.h"
+
+static ACQUISITIONCAPI AcquisitionCAPI;
+
+static void
+PyVar_Assign(PyObject **v, PyObject *e)
+{
+ Py_XDECREF(*v);
+ *v=e;
+}
+
+#define ASSIGN(V,E) PyVar_Assign(&(V),(E))
+#define UNLESS(E) if (!(E))
+#define UNLESS_ASSIGN(V,E) ASSIGN(V,E); UNLESS(V)
+#define OBJECT(O) ((PyObject*)(O))
+
+static PyObject *py__add__, *py__sub__, *py__mul__, *py__div__,
+ *py__mod__, *py__pow__, *py__divmod__, *py__lshift__, *py__rshift__,
+ *py__and__, *py__or__, *py__xor__, *py__coerce__, *py__neg__,
+ *py__pos__, *py__abs__, *py__nonzero__, *py__invert__, *py__int__,
+ *py__long__, *py__float__, *py__oct__, *py__hex__,
+ *py__getitem__, *py__setitem__, *py__delitem__,
+ *py__getslice__, *py__setslice__, *py__delslice__,
+ *py__len__, *py__of__, *py__call__, *py__repr__, *py__str__, *py__cmp__;
+
+static PyObject *Acquired=0;
+
+static void
+init_py_names(void)
+{
+#define INIT_PY_NAME(N) py ## N = PyString_FromString(#N)
+ INIT_PY_NAME(__add__);
+ INIT_PY_NAME(__sub__);
+ INIT_PY_NAME(__mul__);
+ INIT_PY_NAME(__div__);
+ INIT_PY_NAME(__mod__);
+ INIT_PY_NAME(__pow__);
+ INIT_PY_NAME(__divmod__);
+ INIT_PY_NAME(__lshift__);
+ INIT_PY_NAME(__rshift__);
+ INIT_PY_NAME(__and__);
+ INIT_PY_NAME(__or__);
+ INIT_PY_NAME(__xor__);
+ INIT_PY_NAME(__coerce__);
+ INIT_PY_NAME(__neg__);
+ INIT_PY_NAME(__pos__);
+ INIT_PY_NAME(__abs__);
+ INIT_PY_NAME(__nonzero__);
+ INIT_PY_NAME(__invert__);
+ INIT_PY_NAME(__int__);
+ INIT_PY_NAME(__long__);
+ INIT_PY_NAME(__float__);
+ INIT_PY_NAME(__oct__);
+ INIT_PY_NAME(__hex__);
+ INIT_PY_NAME(__getitem__);
+ INIT_PY_NAME(__setitem__);
+ INIT_PY_NAME(__delitem__);
+ INIT_PY_NAME(__getslice__);
+ INIT_PY_NAME(__setslice__);
+ INIT_PY_NAME(__delslice__);
+ INIT_PY_NAME(__len__);
+ INIT_PY_NAME(__of__);
+ INIT_PY_NAME(__call__);
+ INIT_PY_NAME(__repr__);
+ INIT_PY_NAME(__str__);
+ INIT_PY_NAME(__cmp__);
+
+#undef INIT_PY_NAME
+}
+
+static PyObject *
+CallMethodO(PyObject *self, PyObject *name,
+ PyObject *args, PyObject *kw)
+{
+ if (! args && PyErr_Occurred()) return NULL;
+ UNLESS(name=PyObject_GetAttr(self,name)) {
+ if (args) { Py_DECREF(args); }
+ return NULL;
+ }
+ ASSIGN(name,PyEval_CallObjectWithKeywords(name,args,kw));
+ if (args) { Py_DECREF(args); }
+ return name;
+}
+
+#define Build Py_BuildValue
+
+/* Declarations for objects of type Wrapper */
+
+typedef struct {
+ PyObject_HEAD
+ PyObject *obj;
+ PyObject *container;
+} Wrapper;
+
+staticforward PyExtensionClass Wrappertype, XaqWrappertype;
+
+#define isWrapper(O) ((O)->ob_type==(PyTypeObject*)&Wrappertype || \
+ (O)->ob_type==(PyTypeObject*)&XaqWrappertype)
+#define WRAPPER(O) ((Wrapper*)(O))
+
+static PyObject *
+Wrapper__init__(Wrapper *self, PyObject *args)
+{
+ PyObject *obj, *container;
+
+ UNLESS(PyArg_Parse(args,"(OO)",&obj,&container)) return NULL;
+
+ if (self == WRAPPER(obj)) {
+ PyErr_SetString(PyExc_ValueError,
+ "Cannot wrap acquisition wrapper in itself (Wrapper__init__)");
+ return NULL;
+ }
+
+ Py_INCREF(obj);
+ Py_INCREF(container);
+ self->obj=obj;
+ self->container=container;
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* ---------------------------------------------------------------- */
+
+static PyObject *
+__of__(PyObject *inst, PyObject *parent)
+{
+ PyObject *r, *t;
+
+ UNLESS(r=PyObject_GetAttr(inst, py__of__)) return NULL;
+ UNLESS(t=PyTuple_New(1)) goto err;
+ PyTuple_SET_ITEM(t,0,parent);
+ ASSIGN(r,PyObject_CallObject(r,t));
+ PyTuple_SET_ITEM(t,0,NULL);
+ Py_DECREF(t);
+
+ if (r
+ && r->ob_refcnt==1
+ && isWrapper(r)
+ && WRAPPER(r)->container && isWrapper(WRAPPER(r)->container)
+ )
+ while (WRAPPER(r)->obj && isWrapper(WRAPPER(r)->obj)
+ && (WRAPPER(WRAPPER(r)->obj)->container ==
+ WRAPPER(WRAPPER(r)->container)->obj)
+ )
+ {
+ /* Simplify wrapper */
+ Py_XINCREF(WRAPPER(WRAPPER(r)->obj)->obj);
+ ASSIGN(WRAPPER(r)->obj, WRAPPER(WRAPPER(r)->obj)->obj);
+ }
+
+ return r;
+err:
+ Py_DECREF(r);
+ return NULL;
+}
+
+static Wrapper *freeWrappers=0;
+static int nWrappers=0;
+#define MAX_CACHED_WRAPPERS 200
+
+static PyObject *
+newWrapper(PyObject *obj, PyObject *container, PyTypeObject *Wrappertype)
+{
+ Wrapper *self;
+
+ if (freeWrappers)
+ {
+ self=freeWrappers;
+ freeWrappers=(Wrapper*)self->obj;
+ _Py_NewReference((PyObject *)self);
+ assert(self->ob_refcnt == 1);
+ self->ob_type=Wrappertype;
+ nWrappers--;
+ }
+ else
+ {
+ UNLESS(self = PyObject_NEW(Wrapper, Wrappertype)) return NULL;
+ }
+
+ if (self == WRAPPER(obj)) {
[-=- -=- -=- 1176 lines omitted -=- -=- -=-]
+ Py_INCREF(result);
+ return result;
+}
+
+static PyObject *
+module_aq_parent(PyObject *ignored, PyObject *args)
+{
+ PyObject *self;
+
+ UNLESS (PyArg_ParseTuple(args, "O", &self)) return NULL;
+
+ return capi_aq_parent(self);
+}
+
+static PyObject *
+capi_aq_self(PyObject *self)
+{
+ PyObject *result;
+ if (! isWrapper(self))
+ {
+ Py_INCREF(self);
+ return self;
+ }
+
+ if (WRAPPER(self)->obj) result=WRAPPER(self)->obj;
+ else result=Py_None;
+
+ Py_INCREF(result);
+ return result;
+}
+
+static PyObject *
+module_aq_self(PyObject *ignored, PyObject *args)
+{
+ PyObject *self;
+ UNLESS (PyArg_ParseTuple(args, "O", &self)) return NULL;
+ return capi_aq_self(self);
+}
+
+static PyObject *
+capi_aq_inner(PyObject *self)
+{
+ PyObject *result;
+ if (! isWrapper(self))
+ {
+ Py_INCREF(self);
+ return self;
+ }
+
+ if (WRAPPER(self)->obj)
+ {
+ result=WRAPPER(self)->obj;
+ while (isWrapper(result) && WRAPPER(result)->obj)
+ {
+ self=result;
+ result=WRAPPER(result)->obj;
+ }
+ result=self;
+ }
+ else result=Py_None;
+
+ Py_INCREF(result);
+ return result;
+}
+
+static PyObject *
+module_aq_inner(PyObject *ignored, PyObject *args)
+{
+ PyObject *self;
+
+ UNLESS (PyArg_ParseTuple(args, "O", &self)) return NULL;
+ return capi_aq_inner(self);
+}
+
+static PyObject *
+capi_aq_chain(PyObject *self, int containment)
+{
+ PyObject *result;
+
+ UNLESS (result=PyList_New(0)) return NULL;
+
+ while (1)
+ {
+ if (isWrapper(self))
+ {
+ if (WRAPPER(self)->obj)
+ {
+ if (containment)
+ while (WRAPPER(self)->obj && isWrapper(WRAPPER(self)->obj))
+ self=WRAPPER(self)->obj;
+ if (PyList_Append(result,OBJECT(self)) < 0)
+ goto err;
+ }
+ if (WRAPPER(self)->container)
+ {
+ self=WRAPPER(self)->container;
+ continue;
+ }
+ }
+ else
+ if (PyList_Append(result, self) < 0)
+ goto err;
+
+ break;
+ }
+
+ return result;
+err:
+ Py_DECREF(result);
+ return result;
+}
+
+static PyObject *
+module_aq_chain(PyObject *ignored, PyObject *args)
+{
+ PyObject *self;
+ int containment=0;
+
+ UNLESS (PyArg_ParseTuple(args, "O|i", &self, &containment))
+ return NULL;
+
+ return capi_aq_chain(self, containment);
+}
+
+static struct PyMethodDef methods[] = {
+ {"aq_acquire", (PyCFunction)module_aq_acquire, METH_VARARGS|METH_KEYWORDS,
+ "aq_acquire(ob, name [, filter, extra, explicit]) -- "
+ "Get an attribute, acquiring it if necessary"
+ },
+ {"aq_get", (PyCFunction)module_aq_get, METH_VARARGS,
+ "aq_get(ob, name [, default]) -- "
+ "Get an attribute, acquiring it if necessary."
+ },
+ {"aq_base", (PyCFunction)module_aq_base, METH_VARARGS,
+ "aq_base(ob) -- Get the object unwrapped"},
+ {"aq_parent", (PyCFunction)module_aq_parent, METH_VARARGS,
+ "aq_parent(ob) -- Get the parent of an object"},
+ {"aq_self", (PyCFunction)module_aq_self, METH_VARARGS,
+ "aq_self(ob) -- Get the object with the outermost wrapper removed"},
+ {"aq_inner", (PyCFunction)module_aq_inner, METH_VARARGS,
+ "aq_inner(ob) -- "
+ "Get the object with alll but the innermost wrapper removed"},
+ {"aq_chain", (PyCFunction)module_aq_chain, METH_VARARGS,
+ "aq_chain(ob [, containment]) -- "
+ "Get a list of objects in the acquisition environment"},
+ {NULL, NULL}
+};
+
+void
+init_Acquisition(void)
+{
+ PyObject *m, *d;
+ PyObject *api;
+
+ PURE_MIXIN_CLASS(Acquirer,
+ "Base class for objects that implicitly"
+ " acquire attributes from containers\n"
+ , Acquirer_methods);
+ PURE_MIXIN_CLASS(ExplicitAcquirer,
+ "Base class for objects that explicitly"
+ " acquire attributes from containers\n"
+ , Xaq_methods);
+
+ UNLESS(ExtensionClassImported) return;
+
+ UNLESS(Acquired=PyString_FromStringAndSize(NULL,42)) return;
+ strcpy(PyString_AsString(Acquired),
+ "<Special Object Used to Force Acquisition>");
+
+ /* Create the module and add the functions */
+ m = Py_InitModule4("_Acquisition", methods,
+ "Provide base classes for acquiring objects\n\n"
+ "$Id$\n",
+ OBJECT(NULL),PYTHON_API_VERSION);
+
+ d = PyModule_GetDict(m);
+ init_py_names();
+ PyExtensionClass_Export(d,"Acquirer",AcquirerType);
+ PyExtensionClass_Export(d,"ImplicitAcquisitionWrapper",Wrappertype);
+ PyExtensionClass_Export(d,"ExplicitAcquirer",ExplicitAcquirerType);
+ PyExtensionClass_Export(d,"ExplicitAcquisitionWrapper",XaqWrappertype);
+
+ /* Create aliases */
+ PyDict_SetItemString(d,"Implicit",OBJECT(&AcquirerType));
+ PyDict_SetItemString(d,"Explicit",OBJECT(&ExplicitAcquirerType));
+ PyDict_SetItemString(d,"Acquired",Acquired);
+
+ AcquisitionCAPI.AQ_Acquire = capi_aq_acquire;
+ AcquisitionCAPI.AQ_Get = capi_aq_get;
+ AcquisitionCAPI.AQ_IsWrapper = capi_aq_iswrapper;
+ AcquisitionCAPI.AQ_Base = capi_aq_base;
+ AcquisitionCAPI.AQ_Parent = capi_aq_parent;
+ AcquisitionCAPI.AQ_Self = capi_aq_self;
+ AcquisitionCAPI.AQ_Inner = capi_aq_inner;
+ AcquisitionCAPI.AQ_Chain = capi_aq_chain;
+
+ api = PyCObject_FromVoidPtr(&AcquisitionCAPI, NULL);
+ PyDict_SetItemString(d, "AcquisitionCAPI", api);
+ Py_DECREF(api);
+}
=== Zope/lib/python/Acquisition/__init__.py 1.1 => 1.2 ===
--- /dev/null Fri Nov 28 11:44:15 2003
+++ Zope/lib/python/Acquisition/__init__.py Fri Nov 28 11:44:14 2003
@@ -0,0 +1 @@
+from _Acquisition import *
=== Zope/lib/python/Acquisition/setup.py 1.1 => 1.2 ===
--- /dev/null Fri Nov 28 11:44:15 2003
+++ Zope/lib/python/Acquisition/setup.py Fri Nov 28 11:44:14 2003
@@ -0,0 +1,23 @@
+##############################################################################
+#
+# Copyright (c) 2003 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 distutils.core import setup, Extension
+setup(name="_Acquisition", version="2.0",
+ ext_modules=[
+ Extension("_Acquisition", ["_Acquisition.c"],
+ include_dirs = ['.', '../ExtensionClass'],
+ depends = ["Acquisition.h",
+ '../ExtensionClass/ExtensionClass.h']),
+ ])
+
=== Zope/lib/python/Acquisition/tests.py 1.1 => 1.2 === (1113/1513 lines abridged)
--- /dev/null Fri Nov 28 11:44:15 2003
+++ Zope/lib/python/Acquisition/tests.py Fri Nov 28 11:44:14 2003
@@ -0,0 +1,1510 @@
+##############################################################################
+#
+# Copyright (c) 2003 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.
+#
+##############################################################################
+"""Acquisition test cases (and useful examples)
+
+ Acquisition [1] is a mechanism that allows objects to obtain
+ attributes from their environment. It is similar to inheritence,
+ except that, rather than traversing an inheritence hierarchy
+ to obtain attributes, a containment hierarchy is traversed.
+
+ The "ExtensionClass":ExtensionClass.html. release includes mix-in
+ extension base classes that can be used to add acquisition as a
+ feature to extension subclasses. These mix-in classes use the
+ context-wrapping feature of ExtensionClasses to implement
+ acquisition. Consider the following example::
+
+ >>> import ExtensionClass, Acquisition
+
+ >>> class C(ExtensionClass.Base):
+ ... color='red'
+
+ >>> class A(Acquisition.Implicit):
+ ... def report(self):
+ ... print self.color
+
+ >>> a = A()
+ >>> c = C()
+ >>> c.a = a
+
+ >>> c.a.report()
+ red
+
+ >>> d = C()
+ >>> d.color = 'green'
+ >>> d.a = a
+
+ >>> d.a.report()
+ green
+
+ >>> a.report() # raises an attribute error
+ Traceback (most recent call last):
+ ...
+ AttributeError: color
+
+ The class 'A' inherits acquisition behavior from
+ 'Acquisition.Implicit'. The object, 'a', "has" the color of
+ objects 'c' and 'd' when it is accessed through them, but it
+ has no color by itself. The object 'a' obtains attributes
+ from it's environment, where it's environment is defined by
+ the access path used to reach 'a'.
+
+ Acquisition wrappers
+
+ When an object that supports acquisition is accessed through
+ an extension class instance, a special object, called an
+ acquisition wrapper, is returned. In the example above, the
+ expression 'c.a' returns an acquisition wrapper that
+ contains references to both 'c' and 'a'. It is this wrapper
+ that performs attribute lookup in 'c' when an attribute
+ cannot be found in 'a'.
+
+ Aquisition wrappers provide access to the wrapped objects
+ through the attributes 'aq_parent', 'aq_self', 'aq_base'.
+ In the example above, the expressions::
+
+ >>> c.a.aq_parent is c
+ 1
+
+ and::
+
+ >>> c.a.aq_self is a
+ 1
+
+ both evaluate to true, but the expression::
+
+ >>> c.a is a
+ 0
+
+ evaluates to false, because the expression 'c.a' evaluates
+ to an acquisition wrapper around 'c' and 'a', not 'a' itself.
+
+ The attribute 'aq_base' is similar to 'aq_self'. Wrappers may be
+ nested and 'aq_self' may be a wrapped object. The 'aq_base'
+ attribute is the underlying object with all wrappers removed.
+
+ Acquisition Control
+
+ Two styles of acquisition are supported in the current
+ ExtensionClass release, implicit and explicit aquisition.
+
+ Implicit acquisition
+
+ Implicit acquisition is so named because it searches for
+ attributes from the environment automatically whenever an
+ attribute cannot be obtained directly from an object or
+ through inheritence.
+
+ An attribute may be implicitly acquired if it's name does
+ not begin with an underscore, '_'.
+
+ To support implicit acquisition, an object should inherit
+ from the mix-in class 'Acquisition.Implicit'.
+
+ Explicit Acquisition
+
+ When explicit acquisition is used, attributes are not
+ automatically obtained from the environment. Instead, the
+ method 'aq_aquire' must be used, as in::
+
+ print c.a.aq_acquire('color')
+
+ To support explicit acquisition, an object should inherit
+ from the mix-in class 'Acquisition.Explicit'.
+
+ Controlled Acquisition
+
+ A class (or instance) can provide attribute by attribute control
+ over acquisition. This is done by:
+
+ - subclassing from 'Acquisition.Explicit', and
+
+ - setting all attributes that should be acquired to the special
+ value: 'Acquisition.Acquired'. Setting an attribute to this
+ value also allows inherited attributes to be overridden with
+ acquired ones.
+
+ For example, in::
+
+ >>> class E(Acquisition.Explicit):
+ ... id = 1
+ ... secret = 2
+ ... color = Acquisition.Acquired
+ ... __roles__ = Acquisition.Acquired
+
+ The *only* attributes that are automatically acquired from
+ containing objects are 'color', and '__roles__'.
+
+ >>> c = C()
+ >>> c.foo = 'foo'
+ >>> c.e = E()
+ >>> c.e.color
+ 'red'
+ >>> c.e.foo
+ Traceback (most recent call last):
+ ...
+ AttributeError: foo
+
+ Note also that the '__roles__' attribute is acquired even
+ though it's name begins with an underscore:
+
+ >>> c.__roles__ = 'Manager', 'Member'
+ >>> c.e.__roles__
+ ('Manager', 'Member')
+
+ In fact, the special 'Acquisition.Acquired' value can be used
+ in 'Acquisition.Implicit' objects to implicitly acquire
+ selected objects that smell like private objects.
+
+ >>> class I(Acquisition.Implicit):
+ ... __roles__ = Acquisition.Acquired
+
+ >>> c.x = C()
+ >>> c.x.__roles__
+ Traceback (most recent call last):
+ ...
+ AttributeError: __roles__
+
+ >>> c.x = I()
+ >>> c.x.__roles__
+ ('Manager', 'Member')
+
+ Filtered Acquisition
+
+ The acquisition method, 'aq_acquire', accepts two optional
+ arguments. The first of the additional arguments is a
+ "filtering" function that is used when considering whether to
+ acquire an object. The second of the additional arguments is an
+ object that is passed as extra data when calling the filtering
+ function and which defaults to 'None'.
+
+ The filter function is called with five arguments:
+
+ - The object that the 'aq_acquire' method was called on,
+
+ - The object where an object was found,
+
+ - The name of the object, as passed to 'aq_acquire',
[-=- -=- -=- 1113 lines omitted -=- -=- -=-]
+ >>> Acquisition.aq_get(A.B.C.D, "color", None, 1)
+
+ """
+
+def test_explicit_acquisition():
+ """
+ >>> from ExtensionClass import Base
+ >>> import Acquisition
+
+ >>> class B(Base):
+ ... color='red'
+
+ >>> class A(Acquisition.Explicit):
+ ... def hi(self):
+ ... print self.__class__.__name__, self.acquire('color')
+
+ >>> b=B()
+ >>> b.a=A()
+ >>> b.a.hi()
+ A red
+ >>> b.a.color='green'
+ >>> b.a.hi()
+ A green
+
+ >>> try:
+ ... A().hi()
+ ... raise 'Program error', 'spam'
+ ... except AttributeError: pass
+ A
+
+ """
+
+def test_creating_wrappers_directly():
+ """
+ >>> from ExtensionClass import Base
+ >>> from Acquisition import ImplicitAcquisitionWrapper
+
+ >>> class B(Base):
+ ... pass
+
+
+ >>> a = B()
+ >>> a.color = 'red'
+ >>> a.b = B()
+ >>> w = ImplicitAcquisitionWrapper(a.b, a)
+ >>> w.color
+ 'red'
+
+ >>> w = ImplicitAcquisitionWrapper(a.b)
+ Traceback (most recent call last):
+ ...
+ TypeError: argument must be 2-item sequence, not B
+
+ We can reassign aq_parent
+
+ >>> x = B()
+ >>> x.color = 'green'
+ >>> w.aq_parent = x
+ >>> w.color
+ 'green'
+
+ >>> w = ImplicitAcquisitionWrapper()
+ Traceback (most recent call last):
+ ...
+ TypeError: function takes at least one argument
+
+ """
+
+def test_cant_pickle_acquisition_wrappers_classic():
+ """
+ >>> import pickle
+
+ >>> class X:
+ ... def __getstate__(self):
+ ... return 1
+
+ We shouldn't be able to pickle wrappers:
+
+ >>> from Acquisition import ImplicitAcquisitionWrapper
+ >>> w = ImplicitAcquisitionWrapper(X(), X())
+ >>> pickle.dumps(w)
+ Traceback (most recent call last):
+ ...
+ TypeError: Can't pickle objects in acquisition wrappers.
+
+ But that's not enough. We need to defeat persistence as well. :)
+ This is tricky. We want to generate the error in __getstate__, not
+ in the attr access, as attribute errors are too-often hidden:
+
+ >>> getstate = w.__getstate__
+ >>> getstate()
+ Traceback (most recent call last):
+ ...
+ TypeError: Can't pickle objects in acquisition wrappers.
+
+ We shouldn't be able to pickle wrappers:
+
+ >>> from Acquisition import ExplicitAcquisitionWrapper
+ >>> w = ExplicitAcquisitionWrapper(X(), X())
+ >>> pickle.dumps(w)
+ Traceback (most recent call last):
+ ...
+ TypeError: Can't pickle objects in acquisition wrappers.
+
+ But that's not enough. We need to defeat persistence as well. :)
+ This is tricky. We want to generate the error in __getstate__, not
+ in the attr access, as attribute errors are too-often hidden:
+
+ >>> getstate = w.__getstate__
+ >>> getstate()
+ Traceback (most recent call last):
+ ...
+ TypeError: Can't pickle objects in acquisition wrappers.
+ """
+
+def test_cant_pickle_acquisition_wrappers_newstyle():
+ """
+ >>> import pickle
+
+ >>> class X(object):
+ ... def __getstate__(self):
+ ... return 1
+
+ We shouldn't be able to pickle wrappers:
+
+ >>> from Acquisition import ImplicitAcquisitionWrapper
+ >>> w = ImplicitAcquisitionWrapper(X(), X())
+ >>> pickle.dumps(w)
+ Traceback (most recent call last):
+ ...
+ TypeError: Can't pickle objects in acquisition wrappers.
+
+ But that's not enough. We need to defeat persistence as well. :)
+ This is tricky. We want to generate the error in __getstate__, not
+ in the attr access, as attribute errors are too-often hidden:
+
+ >>> getstate = w.__getstate__
+ >>> getstate()
+ Traceback (most recent call last):
+ ...
+ TypeError: Can't pickle objects in acquisition wrappers.
+
+ We shouldn't be able to pickle wrappers:
+
+ >>> from Acquisition import ExplicitAcquisitionWrapper
+ >>> w = ExplicitAcquisitionWrapper(X(), X())
+ >>> pickle.dumps(w)
+ Traceback (most recent call last):
+ ...
+ TypeError: Can't pickle objects in acquisition wrappers.
+
+ But that's not enough. We need to defeat persistence as well. :)
+ This is tricky. We want to generate the error in __getstate__, not
+ in the attr access, as attribute errors are too-often hidden:
+
+ >>> getstate = w.__getstate__
+ >>> getstate()
+ Traceback (most recent call last):
+ ...
+ TypeError: Can't pickle objects in acquisition wrappers.
+ """
+
+def show(x):
+ print showaq(x).strip()
+
+def showaq(m_self, indent=''):
+ rval = ''
+ obj = m_self
+ base = getattr(obj, 'aq_base', obj)
+ try: id = base.id
+ except: id = str(base)
+ try: id = id()
+ except: pass
+
+ if hasattr(obj, 'aq_self'):
+ if hasattr(obj.aq_self, 'aq_self'):
+ rval = rval + indent + "(" + id + ")\n"
+ rval = rval + indent + "| \\\n"
+ rval = rval + showaq(obj.aq_self, '| ' + indent)
+ rval = rval + indent + "|\n"
+ rval = rval + showaq(obj.aq_parent, indent)
+ elif hasattr(obj, 'aq_parent'):
+ rval = rval + indent + id + "\n"
+ rval = rval + indent + "|\n"
+ rval = rval + showaq(obj.aq_parent, indent)
+ else:
+ rval = rval + indent + id + "\n"
+ return rval
+
+
+
+import unittest
+from doctest import DocTestSuite
+
+def test_suite():
+ return unittest.TestSuite((
+ DocTestSuite(),
+ ))
+
+if __name__ == '__main__': unittest.main()
More information about the Zope-Checkins
mailing list