[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