Commit 771f7677 authored by Jim Fulton's avatar Jim Fulton

New implementation of Acquisition using new-style extension classes.

parent 2ca62e1a
/*****************************************************************************
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
/*****************************************************************************
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)) {
PyErr_SetString(PyExc_ValueError,
"Cannot wrap acquisition wrapper in itself (newWrapper)");
Py_DECREF(self);
return NULL;
}
Py_INCREF(Wrappertype);
Py_XINCREF(obj);
Py_XINCREF(container);
self->obj=obj;
self->container=container;
return OBJECT(self);
}
static void
Wrapper_dealloc(Wrapper *self)
{
Py_XDECREF(self->obj);
Py_XDECREF(self->container);
Py_DECREF(self->ob_type);
if (nWrappers < MAX_CACHED_WRAPPERS)
{
self->obj=OBJECT(freeWrappers);
freeWrappers=self;
nWrappers++;
}
else
{
PyObject_DEL(self);
}
}
static PyObject *
Wrapper_special(Wrapper *self, char *name, PyObject *oname)
{
PyObject *r=0;
switch(*name)
{
case 'b':
if (strcmp(name,"base")==0)
{
if (self->obj)
{
r=self->obj;
while (isWrapper(r) && WRAPPER(r)->obj) r=WRAPPER(r)->obj;
}
else r=Py_None;
Py_INCREF(r);
return r;
}
break;
case 'p':
if (strcmp(name,"parent")==0)
{
if (self->container) r=self->container;
else r=Py_None;
Py_INCREF(r);
return r;
}
break;
case 's':
if (strcmp(name,"self")==0)
{
if (self->obj) r=self->obj;
else r=Py_None;
Py_INCREF(r);
return r;
}
break;
case 'e':
if (strcmp(name,"explicit")==0)
{
if (self->ob_type != (PyTypeObject *)&XaqWrappertype)
return newWrapper(self->obj, self->container,
(PyTypeObject *)&XaqWrappertype);
Py_INCREF(self);
return OBJECT(self);
}
break;
case 'a':
if (strcmp(name,"acquire")==0)
{
return Py_FindAttr(OBJECT(self),oname);
}
break;
case 'c':
if (strcmp(name,"chain")==0)
{
if ((r = PyList_New(0)))
while (1)
{
if (PyList_Append(r,OBJECT(self)) >= 0)
{
if (isWrapper(self) && self->container)
{
self=WRAPPER(self->container);
continue;
}
}
else
{
Py_DECREF(r);
}
break;
}
return r;
}
break;
case 'i':
if (strcmp(name,"inContextOf")==0)
{
return Py_FindAttr(OBJECT(self),oname);
}
if (strcmp(name,"inner")==0)
{
if (self->obj)
{
r=self->obj;
while (isWrapper(r) && WRAPPER(r)->obj)
{
self=WRAPPER(r);
r=WRAPPER(r)->obj;
}
r=OBJECT(self);
}
else r=Py_None;
Py_INCREF(r);
return r;
}
break;
case 'u':
if (strcmp(name,"uncle")==0)
{
return PyString_FromString("Bob");
}
break;
}
return NULL;
}
static int
apply_filter(PyObject *filter, PyObject *inst, PyObject *oname, PyObject *r,
PyObject *extra, PyObject *orig)
{
/* Calls the filter, passing arguments.
Returns 1 if the filter accepts the value, 0 if not, -1 if an
exception occurred.
Note the special reference counting rule: This function decrements
the refcount of 'r' when it returns 0 or -1. When it returns 1, it
leaves the refcount unchanged.
*/
PyObject *fr;
int ir;
UNLESS(fr=PyTuple_New(5)) goto err;
PyTuple_SET_ITEM(fr,0,orig);
Py_INCREF(orig);
PyTuple_SET_ITEM(fr,1,inst);
Py_INCREF(inst);
PyTuple_SET_ITEM(fr,2,oname);
Py_INCREF(oname);
PyTuple_SET_ITEM(fr,3,r);
Py_INCREF(r);
PyTuple_SET_ITEM(fr,4,extra);
Py_INCREF(extra);
UNLESS_ASSIGN(fr,PyObject_CallObject(filter, fr)) goto err;
ir=PyObject_IsTrue(fr);
Py_DECREF(fr);
if (ir) return 1;
Py_DECREF(r);
return 0;
err:
Py_DECREF(r);
return -1;
}
static PyObject *
Wrapper_acquire(Wrapper *self, PyObject *oname,
PyObject *filter, PyObject *extra, PyObject *orig,
int explicit, int containment);
static PyObject *
Wrapper_findattr(Wrapper *self, PyObject *oname,
PyObject *filter, PyObject *extra, PyObject *orig,
int sob, int sco, int explicit, int containment)
{
PyObject *r, *v, *tb;
char *name="";
if (PyString_Check(oname)) name=PyString_AS_STRING(oname);
if (*name=='a' && name[1]=='q' && name[2]=='_')
if ((r=Wrapper_special(self, name+3, oname)))
{
if (filter)
switch(apply_filter(filter,OBJECT(self),oname,r,extra,orig))
{
case -1: return NULL;
case 1: return r;
}
else return r;
}
else PyErr_Clear();
else if (*name=='_' && name[1]=='_' &&
(strcmp(name+2,"reduce__")==0 ||
strcmp(name+2,"reduce_ex__")==0 ||
strcmp(name+2,"getstate__")==0
))
return PyObject_GenericGetAttr(((PyObject*)self), oname);
/* If we are doing a containment search, then replace self with aq_inner */
if (containment)
while (self->obj && isWrapper(self->obj))
self=WRAPPER(self->obj);
if (sob && self->obj)
{
if (isWrapper(self->obj))
{
if (self == WRAPPER(self->obj)) {
PyErr_SetString(PyExc_RuntimeError,
"Recursion detected in acquisition wrapper");
return NULL;
}
if ((r=Wrapper_findattr(WRAPPER(self->obj),
oname, filter, extra, orig, 1,
/* Search object container if explicit,
or object is implicit acquirer */
explicit ||
self->obj->ob_type ==
(PyTypeObject*)&Wrappertype,
explicit, containment)))
{
if (PyECMethod_Check(r) && PyECMethod_Self(r)==self->obj)
ASSIGN(r,PyECMethod_New(r,OBJECT(self)));
else if (has__of__(r)) ASSIGN(r,__of__(r,OBJECT(self)));
return r;
}
PyErr_Fetch(&r,&v,&tb);
if (r && (r != PyExc_AttributeError))
{
PyErr_Restore(r,v,tb);
return NULL;
}
Py_XDECREF(r); Py_XDECREF(v); Py_XDECREF(tb);
r=NULL;
}
else if ((r=PyObject_GetAttr(self->obj,oname)))
{
if (r==Acquired)
{
Py_DECREF(r);
return Wrapper_acquire(self, oname, filter, extra, orig, 1,
containment);
}
if (PyECMethod_Check(r) && PyECMethod_Self(r)==self->obj)
ASSIGN(r,PyECMethod_New(r,OBJECT(self)));
else if (has__of__(r)) ASSIGN(r,__of__(r,OBJECT(self)));
if (filter)
switch(apply_filter(filter,OBJECT(self),oname,r,extra,orig))
{
case -1: return NULL;
case 1: return r;
}
else return r;
}
else {
PyErr_Fetch(&r,&v,&tb);
if (r != PyExc_AttributeError)
{
PyErr_Restore(r,v,tb);
return NULL;
}
Py_XDECREF(r); Py_XDECREF(v); Py_XDECREF(tb);
r=NULL;
}
PyErr_Clear();
}
if (sco && (*name != '_' || explicit))
return Wrapper_acquire(self, oname, filter, extra, orig, explicit,
containment);
PyErr_SetObject(PyExc_AttributeError,oname);
return NULL;
}
static PyObject *
Wrapper_acquire(Wrapper *self, PyObject *oname,
PyObject *filter, PyObject *extra, PyObject *orig,
int explicit, int containment)
{
PyObject *r;
int sob=1, sco=1;
if (self->container)
{
if (isWrapper(self->container))
{
if (self->obj && isWrapper(self->obj))
{
/* Try to optimize search by recognizing repeated obs in path */
if (WRAPPER(self->obj)->container==
WRAPPER(self->container)->container)
sco=0;
else if (WRAPPER(self->obj)->container==
WRAPPER(self->container)->obj)
sob=0;
}
r=Wrapper_findattr((Wrapper*)self->container,
oname, filter, extra, orig, sob, sco, explicit,
containment);
if (r && has__of__(r)) ASSIGN(r,__of__(r,OBJECT(self)));
return r;
}
else
{
if ((r=PyObject_GetAttr(self->container,oname))) {
if (r == Acquired) {
Py_DECREF(r);
}
else {
if (filter) {
switch(apply_filter(filter,self->container,oname,r,
extra,orig))
{
case -1:
return NULL;
case 1:
if (has__of__(r)) ASSIGN(r,__of__(r,OBJECT(self)));
return r;
}
}
else {
if (has__of__(r)) ASSIGN(r,__of__(r,OBJECT(self)));
return r;
}
}
}
else {
/* May be AttributeError or some other kind of error */
return NULL;
}
}
}
PyErr_SetObject(PyExc_AttributeError, oname);
return NULL;
}
static PyObject *
Wrapper_getattro(Wrapper *self, PyObject *oname)
{
if (self->obj || self->container)
return Wrapper_findattr(self, oname, NULL, NULL, NULL, 1, 1, 0, 0);
/* Maybe we are getting initialized? */
return Py_FindAttr(OBJECT(self),oname);
}
static PyObject *
Xaq_getattro(Wrapper *self, PyObject *oname)
{
char *name="";
/* Special case backward-compatible acquire method. */
if (PyString_Check(oname)) name=PyString_AS_STRING(oname);
if (*name=='a' && name[1]=='c' && strcmp(name+2,"quire")==0)
return Py_FindAttr(OBJECT(self),oname);
if (self->obj || self->container)
return Wrapper_findattr(self, oname, NULL, NULL, NULL, 1, 0, 0, 0);
/* Maybe we are getting initialized? */
return Py_FindAttr(OBJECT(self),oname);
}
static int
Wrapper_setattro(Wrapper *self, PyObject *oname, PyObject *v)
{
char *name="";
/* Allow assignment to parent, to change context. */
if (PyString_Check(oname)) name=PyString_AS_STRING(oname);
if (*name=='a' && name[1]=='q' && name[2]=='_'
&& strcmp(name+3,"parent")==0)
{
Py_XINCREF(v);
ASSIGN(self->container, v);
return 0;
}
if (self->obj)
{
/* Unwrap passed in wrappers! */
while (v && isWrapper(v))
v=WRAPPER(v)->obj;
if (v) return PyObject_SetAttr(self->obj, oname, v);
else return PyObject_DelAttr(self->obj, oname);
}
PyErr_SetString(PyExc_AttributeError,
"Attempt to set attribute on empty acquisition wrapper");
return -1;
}
static int
Wrapper_compare(Wrapper *self, PyObject *w)
{
PyObject *obj, *wobj;
PyObject *m;
int r;
if (OBJECT(self) == w) return 0;
UNLESS (m=PyObject_GetAttr(OBJECT(self), py__cmp__))
{
/* Unwrap self completely -> obj. */
while (self->obj && isWrapper(self->obj))
self=WRAPPER(self->obj);
obj = self->obj;
/* Unwrap w completely -> wobj. */
if (isWrapper(w))
{
while (WRAPPER(w)->obj && isWrapper(WRAPPER(w)->obj))
w=WRAPPER(w)->obj;
wobj = WRAPPER(w)->obj;
}
else wobj = w;
PyErr_Clear();
if (obj == wobj) return 0;
return (obj < w) ? -1 : 1;
}
ASSIGN(m, PyObject_CallFunction(m, "O", w));
UNLESS (m) return -1;
r=PyInt_AsLong(m);
Py_DECREF(m);
return r;
}
static PyObject *
Wrapper_repr(Wrapper *self)
{
PyObject *r;
if ((r=PyObject_GetAttr(OBJECT(self),py__repr__)))
{
ASSIGN(r,PyObject_CallFunction(r,NULL,NULL));
return r;
}
else
{
PyErr_Clear();
return PyObject_Repr(self->obj);
}
}
static PyObject *
Wrapper_str(Wrapper *self)
{
PyObject *r;
if ((r=PyObject_GetAttr(OBJECT(self),py__str__)))
{
ASSIGN(r,PyObject_CallFunction(r,NULL,NULL));
return r;
}
else
{
PyErr_Clear();
return PyObject_Str(self->obj);
}
}
static long
Wrapper_hash(Wrapper *self)
{
return PyObject_Hash(self->obj);
}
static PyObject *
Wrapper_call(Wrapper *self, PyObject *args, PyObject *kw)
{
Py_INCREF(args);
return CallMethodO(OBJECT(self),py__call__,args,kw);
}
/* Code to handle accessing Wrapper objects as sequence objects */
static int
Wrapper_length(Wrapper *self)
{
long l;
PyObject *r;
UNLESS(r=PyObject_GetAttr(OBJECT(self), py__len__)) return -1;
UNLESS_ASSIGN(r,PyObject_CallObject(r,NULL)) return -1;
l=PyInt_AsLong(r);
Py_DECREF(r);
return l;
}
static PyObject *
Wrapper_add(Wrapper *self, PyObject *bb)
{
return CallMethodO(OBJECT(self),py__add__,Build("(O)", bb) ,NULL);
}
static PyObject *
Wrapper_mul(Wrapper *self, int n)
{
return CallMethodO(OBJECT(self),py__mul__,Build("(i)", n),NULL);
}
static PyObject *
Wrapper_item(Wrapper *self, int i)
{
return CallMethodO(OBJECT(self),py__getitem__, Build("(i)", i),NULL);
}
static PyObject *
Wrapper_slice(Wrapper *self, int ilow, int ihigh)
{
return CallMethodO(OBJECT(self),py__getslice__,
Build("(ii)", ilow, ihigh),NULL);
}
static int
Wrapper_ass_item(Wrapper *self, int i, PyObject *v)
{
if (v)
{
UNLESS(v=CallMethodO(OBJECT(self),py__setitem__,
Build("(iO)", i, v),NULL))
return -1;
}
else
{
UNLESS(v=CallMethodO(OBJECT(self),py__delitem__,
Build("(i)", i),NULL))
return -1;
}
Py_DECREF(v);
return 0;
}
static int
Wrapper_ass_slice(Wrapper *self, int ilow, int ihigh, PyObject *v)
{
if (v)
{
UNLESS(v=CallMethodO(OBJECT(self),py__setslice__,
Build("(iiO)", ilow, ihigh, v),NULL))
return -1;
}
else
{
UNLESS(v=CallMethodO(OBJECT(self),py__delslice__,
Build("(ii)", ilow, ihigh),NULL))
return -1;
}
Py_DECREF(v);
return 0;
}
static PySequenceMethods Wrapper_as_sequence = {
(inquiry)Wrapper_length, /*sq_length*/
(binaryfunc)Wrapper_add, /*sq_concat*/
(intargfunc)Wrapper_mul, /*sq_repeat*/
(intargfunc)Wrapper_item, /*sq_item*/
(intintargfunc)Wrapper_slice, /*sq_slice*/
(intobjargproc)Wrapper_ass_item, /*sq_ass_item*/
(intintobjargproc)Wrapper_ass_slice, /*sq_ass_slice*/
};
/* -------------------------------------------------------------- */
/* Code to access Wrapper objects as mappings */
static PyObject *
Wrapper_subscript(Wrapper *self, PyObject *key)
{
return CallMethodO(OBJECT(self),py__getitem__,Build("(O)", key),NULL);
}
static int
Wrapper_ass_sub(Wrapper *self, PyObject *key, PyObject *v)
{
if (v)
{
UNLESS(v=CallMethodO(OBJECT(self),py__setitem__,
Build("(OO)", key, v),NULL))
return -1;
}
else
{
UNLESS(v=CallMethodO(OBJECT(self),py__delitem__,
Build("(O)", key),NULL))
return -1;
}
Py_XDECREF(v);
return 0;
}
static PyMappingMethods Wrapper_as_mapping = {
(inquiry)Wrapper_length, /*mp_length*/
(binaryfunc)Wrapper_subscript, /*mp_subscript*/
(objobjargproc)Wrapper_ass_sub, /*mp_ass_subscript*/
};
/* -------------------------------------------------------------- */
/* Code to access Wrapper objects as numbers */
static PyObject *
Wrapper_sub(Wrapper *self, PyObject *o)
{
return CallMethodO(OBJECT(self),py__sub__,Build("(O)", o),NULL);
}
static PyObject *
Wrapper_div(Wrapper *self, PyObject *o)
{
return CallMethodO(OBJECT(self),py__div__,Build("(O)", o),NULL);
}
static PyObject *
Wrapper_mod(Wrapper *self, PyObject *o)
{
return CallMethodO(OBJECT(self),py__mod__,Build("(O)", o),NULL);
}
static PyObject *
Wrapper_divmod(Wrapper *self, PyObject *o)
{
return CallMethodO(OBJECT(self),py__divmod__,Build("(O)", o),NULL);
}
static PyObject *
Wrapper_pow(Wrapper *self, PyObject *o, PyObject *m)
{
return CallMethodO(OBJECT(self),py__pow__,Build("(OO)", o, m),NULL);
}
static PyObject *
Wrapper_neg(Wrapper *self)
{
return CallMethodO(OBJECT(self), py__neg__, NULL, NULL);
}
static PyObject *
Wrapper_pos(Wrapper *self)
{
return CallMethodO(OBJECT(self), py__pos__, NULL, NULL);
}
static PyObject *
Wrapper_abs(Wrapper *self)
{
return CallMethodO(OBJECT(self), py__abs__, NULL, NULL);
}
static PyObject *
Wrapper_invert(Wrapper *self)
{
return CallMethodO(OBJECT(self), py__invert__, NULL, NULL);
}
static PyObject *
Wrapper_lshift(Wrapper *self, PyObject *o)
{
return CallMethodO(OBJECT(self),py__lshift__,Build("(O)", o),NULL);
}
static PyObject *
Wrapper_rshift(Wrapper *self, PyObject *o)
{
return CallMethodO(OBJECT(self),py__rshift__,Build("(O)", o),NULL);
}
static PyObject *
Wrapper_and(Wrapper *self, PyObject *o)
{
return CallMethodO(OBJECT(self),py__and__,Build("(O)", o),NULL);
}
static PyObject *
Wrapper_xor(Wrapper *self, PyObject *o)
{
return CallMethodO(OBJECT(self),py__xor__,Build("(O)", o),NULL);
}
static PyObject *
Wrapper_or(Wrapper *self, PyObject *o)
{
return CallMethodO(OBJECT(self),py__or__,Build("(O)", o),NULL);
}
static int
Wrapper_coerce(Wrapper **self, PyObject **o)
{
PyObject *m;
UNLESS (m=PyObject_GetAttr(OBJECT(*self), py__coerce__))
{
PyErr_Clear();
Py_INCREF(*self);
Py_INCREF(*o);
return 0;
}
ASSIGN(m, PyObject_CallFunction(m, "O", *o));
UNLESS (m) return -1;
UNLESS (PyArg_ParseTuple(m,"OO", self, o)) goto err;
Py_INCREF(*self);
Py_INCREF(*o);
Py_DECREF(m);
return 0;
err:
Py_DECREF(m);
return -1;
}
static PyObject *
Wrapper_int(Wrapper *self)
{
return CallMethodO(OBJECT(self), py__int__, NULL, NULL);
}
static PyObject *
Wrapper_long(Wrapper *self)
{
return CallMethodO(OBJECT(self), py__long__, NULL, NULL);
}
static PyObject *
Wrapper_float(Wrapper *self)
{
return CallMethodO(OBJECT(self), py__float__, NULL, NULL);
}
static PyObject *
Wrapper_oct(Wrapper *self)
{
return CallMethodO(OBJECT(self), py__oct__, NULL, NULL);
}
static PyObject *
Wrapper_hex(Wrapper *self)
{
return CallMethodO(OBJECT(self), py__hex__, NULL, NULL);
}
static int
Wrapper_nonzero(Wrapper *self)
{
long l;
PyObject *r;
UNLESS(r=PyObject_GetAttr(OBJECT(self), py__nonzero__))
{
PyErr_Clear();
/* Try len */
UNLESS(r=PyObject_GetAttr(OBJECT(self), py__len__))
{
/* No len, it's true :-) */
PyErr_Clear();
return 1;
}
}
UNLESS_ASSIGN(r,PyObject_CallObject(r,NULL)) return -1;
l=PyInt_AsLong(r);
Py_DECREF(r);
return l;
}
static PyNumberMethods Wrapper_as_number = {
(binaryfunc)Wrapper_add, /*nb_add*/
(binaryfunc)Wrapper_sub, /*nb_subtract*/
(binaryfunc)Wrapper_mul, /*nb_multiply*/
(binaryfunc)Wrapper_div, /*nb_divide*/
(binaryfunc)Wrapper_mod, /*nb_remainder*/
(binaryfunc)Wrapper_divmod, /*nb_divmod*/
(ternaryfunc)Wrapper_pow, /*nb_power*/
(unaryfunc)Wrapper_neg, /*nb_negative*/
(unaryfunc)Wrapper_pos, /*nb_positive*/
(unaryfunc)Wrapper_abs, /*nb_absolute*/
(inquiry)Wrapper_nonzero, /*nb_nonzero*/
(unaryfunc)Wrapper_invert, /*nb_invert*/
(binaryfunc)Wrapper_lshift, /*nb_lshift*/
(binaryfunc)Wrapper_rshift, /*nb_rshift*/
(binaryfunc)Wrapper_and, /*nb_and*/
(binaryfunc)Wrapper_xor, /*nb_xor*/
(binaryfunc)Wrapper_or, /*nb_or*/
(coercion)Wrapper_coerce, /*nb_coerce*/
(unaryfunc)Wrapper_int, /*nb_int*/
(unaryfunc)Wrapper_long, /*nb_long*/
(unaryfunc)Wrapper_float, /*nb_float*/
(unaryfunc)Wrapper_oct, /*nb_oct*/
(unaryfunc)Wrapper_hex, /*nb_hex*/
};
/* -------------------------------------------------------- */
static char *acquire_args[] = {"object", "name", "filter", "extra", "explicit",
"default", "containment", NULL};
static PyObject *
Wrapper_acquire_method(Wrapper *self, PyObject *args, PyObject *kw)
{
PyObject *name, *filter=0, *extra=Py_None;
PyObject *expl=0, *defalt=0;
int explicit=1;
int containment=0;
UNLESS (PyArg_ParseTupleAndKeywords(
args, kw, "O|OOOOi", acquire_args+1,
&name, &filter, &extra, &explicit, &defalt, &containment
))
return NULL;
if (expl) explicit=PyObject_IsTrue(expl);
if (filter==Py_None) filter=0;
return Wrapper_findattr(self,name,filter,extra,OBJECT(self),1,
explicit ||
self->ob_type==(PyTypeObject*)&Wrappertype,
explicit, containment);
}
static PyObject *
Wrapper_inContextOf(Wrapper *self, PyObject *args)
{
PyObject *subob, *o, *c;
int inner=1;
UNLESS(PyArg_ParseTuple(args,"O|i",&o,&inner)) return NULL;
if (inner) {
/* subob = self */
subob = OBJECT(self);
/* o = aq_base(o) */
while (isWrapper(o) && WRAPPER(o)->obj) o=WRAPPER(o)->obj;
/* while 1: */
while (1) {
/* if aq_base(subob) is o: return 1 */
c = subob;
while (isWrapper(c) && WRAPPER(c)->obj) c = WRAPPER(c)->obj;
if (c == o) return PyInt_FromLong(1);
/* self = aq_inner(subob) */
/* if self is None: break */
if (isWrapper(subob)) {
self = WRAPPER(subob);
while (self->obj && isWrapper(self->obj))
self = WRAPPER(self->obj);
}
else break;
/* subob = aq_parent(self) */
/* if subob is None: break */
if (self->container)
subob = self->container;
else break;
}
}
else {
/* Follow wrappers instead. */
c = OBJECT(self);
while (1) {
if (c==o) return PyInt_FromLong(1);
if (c && isWrapper(c)) c=WRAPPER(c)->container;
else break;
}
}
return PyInt_FromLong(0);
}
PyObject *
Wrappers_are_not_picklable(PyObject *Wrapper, PyObject *args)
{
PyErr_SetString(PyExc_TypeError,
"Can't pickle objects in acquisition wrappers.");
return NULL;
}
static struct PyMethodDef Wrapper_methods[] = {
{"__init__", (PyCFunction)Wrapper__init__, 0,
"Initialize an Acquirer Wrapper"},
{"acquire", (PyCFunction)Wrapper_acquire_method,
METH_VARARGS|METH_KEYWORDS,
"Get an attribute, acquiring it if necessary"},
{"aq_acquire", (PyCFunction)Wrapper_acquire_method,
METH_VARARGS|METH_KEYWORDS,
"Get an attribute, acquiring it if necessary"},
{"aq_inContextOf", (PyCFunction)Wrapper_inContextOf, METH_VARARGS,
"Test whether the object is currently in the context of the argument"},
{"__getstate__", (PyCFunction)Wrappers_are_not_picklable, METH_VARARGS,
"Wrappers are not picklable"},
{"__reduce__", (PyCFunction)Wrappers_are_not_picklable, METH_VARARGS,
"Wrappers are not picklable"},
{"__reduce_ex__", (PyCFunction)Wrappers_are_not_picklable, METH_VARARGS,
"Wrappers are not picklable"},
{NULL, NULL} /* sentinel */
};
static PyExtensionClass Wrappertype = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"ImplicitAcquirerWrapper", /*tp_name*/
sizeof(Wrapper), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)Wrapper_dealloc, /*tp_dealloc*/
(printfunc)0, /*tp_print*/
(getattrfunc)0, /*tp_getattr*/
(setattrfunc)0, /*tp_setattr*/
(cmpfunc)Wrapper_compare, /*tp_compare*/
(reprfunc)Wrapper_repr, /*tp_repr*/
&Wrapper_as_number, /*tp_as_number*/
&Wrapper_as_sequence, /*tp_as_sequence*/
&Wrapper_as_mapping, /*tp_as_mapping*/
(hashfunc)Wrapper_hash, /*tp_hash*/
(ternaryfunc)Wrapper_call, /*tp_call*/
(reprfunc)Wrapper_str, /*tp_str*/
(getattrofunc)Wrapper_getattro, /*tp_getattr with object key*/
(setattrofunc)Wrapper_setattro, /*tp_setattr with object key*/
/* Space for future expansion */
0L,0L,
"Wrapper object for implicit acquisition", /* Documentation string */
METHOD_CHAIN(Wrapper_methods),
(void*)(EXTENSIONCLASS_BINDABLE_FLAG),
};
static PyExtensionClass XaqWrappertype = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"ExplicitAcquirerWrapper", /*tp_name*/
sizeof(Wrapper), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)Wrapper_dealloc, /*tp_dealloc*/
(printfunc)0, /*tp_print*/
(getattrfunc)0, /*tp_getattr*/
(setattrfunc)0, /*tp_setattr*/
(cmpfunc)Wrapper_compare, /*tp_compare*/
(reprfunc)Wrapper_repr, /*tp_repr*/
&Wrapper_as_number, /*tp_as_number*/
&Wrapper_as_sequence, /*tp_as_sequence*/
&Wrapper_as_mapping, /*tp_as_mapping*/
(hashfunc)Wrapper_hash, /*tp_hash*/
(ternaryfunc)Wrapper_call, /*tp_call*/
(reprfunc)Wrapper_str, /*tp_str*/
(getattrofunc)Xaq_getattro, /*tp_getattr with object key*/
(setattrofunc)Wrapper_setattro, /*tp_setattr with object key*/
/* Space for future expansion */
0L,0L,
"Wrapper object for explicit acquisition", /* Documentation string */
METHOD_CHAIN(Wrapper_methods),
(void*)(EXTENSIONCLASS_BINDABLE_FLAG),
};
static PyObject *
acquire_of(PyObject *self, PyObject *args)
{
PyObject *inst;
UNLESS(PyArg_ParseTuple(args, "O", &inst)) return NULL;
UNLESS(PyExtensionInstance_Check(inst))
{
PyErr_SetString(PyExc_TypeError,
"attempt to wrap extension method using an object that\n"
"is not an extension class instance.");
return NULL;
}
return newWrapper(self, inst, (PyTypeObject *)&Wrappertype);
}
static PyObject *
xaq_of(PyObject *self, PyObject *args)
{
PyObject *inst;
UNLESS(PyArg_ParseTuple(args, "O", &inst)) return NULL;
UNLESS(PyExtensionInstance_Check(inst))
{
PyErr_SetString(PyExc_TypeError,
"attempt to wrap extension method using an object that\n"
"is not an extension class instance.");
return NULL;
}
return newWrapper(self, inst, (PyTypeObject *)&XaqWrappertype);
}
static struct PyMethodDef Acquirer_methods[] = {
{"__of__",(PyCFunction)acquire_of, METH_VARARGS,
"__of__(context) -- return the object in a context"},
{NULL, NULL} /* sentinel */
};
static struct PyMethodDef Xaq_methods[] = {
{"__of__",(PyCFunction)xaq_of, METH_VARARGS,""},
{NULL, NULL} /* sentinel */
};
static PyObject *
capi_aq_acquire(PyObject *self, PyObject *name, PyObject *filter,
PyObject *extra, int explicit, PyObject *defalt, int containment)
{
PyObject *result;
if (filter==Py_None) filter=0;
/* We got a wrapped object, so business as usual */
if (isWrapper(self))
return Wrapper_findattr(
WRAPPER(self), name, filter, extra, OBJECT(self),1,
explicit ||
WRAPPER(self)->ob_type==(PyTypeObject*)&Wrappertype,
explicit, containment);
/* Not wrapped and no filter, so just getattr */
if (! filter) return PyObject_GetAttr(self, name);
/* Crap, we've got to construct a wrapper so we can use Wrapper_findattr */
UNLESS (self=newWrapper(self, NULL, (PyTypeObject*)&Wrappertype))
return NULL;
result=Wrapper_findattr(WRAPPER(self), name, filter, extra, OBJECT(self),
1, 1, explicit, containment);
/* get rid of temp wrapper */
Py_DECREF(self);
return result;
}
static PyObject *
module_aq_acquire(PyObject *ignored, PyObject *args, PyObject *kw)
{
PyObject *self;
PyObject *name, *filter=0, *extra=Py_None;
PyObject *expl=0, *defalt=0;
int explicit=1, containment=0;
UNLESS (PyArg_ParseTupleAndKeywords(
args, kw, "OO|OOOOi", acquire_args,
&self, &name, &filter, &extra, &expl, &defalt, &containment
))
return NULL;
if (expl) explicit=PyObject_IsTrue(expl);
return capi_aq_acquire(self, name, filter, extra, explicit, defalt,
containment);
}
static PyObject *
capi_aq_get(PyObject *self, PyObject *name, PyObject *defalt, int containment)
{
PyObject *result = NULL;
/* We got a wrapped object, so business as usual */
if (isWrapper(self))
result=Wrapper_findattr(WRAPPER(self), name, 0, 0, OBJECT(self), 1, 1, 1,
containment);
else
result=PyObject_GetAttr(self, name);
if (! result && defalt)
{
PyErr_Clear();
result=defalt;
Py_INCREF(result);
}
return result;
}
static PyObject *
module_aq_get(PyObject *r, PyObject *args)
{
PyObject *self, *name, *defalt=0;
int containment=0;
UNLESS (PyArg_ParseTuple(args, "OO|Oi",
&self, &name, &defalt, &containment
)) return NULL;
return capi_aq_get(self, name, defalt, containment);
}
static int
capi_aq_iswrapper(PyObject *self) {
return isWrapper(self);
}
static PyObject *
capi_aq_base(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)
result=WRAPPER(result)->obj;
}
else result=Py_None;
Py_INCREF(result);
return result;
}
static PyObject *
module_aq_base(PyObject *ignored, PyObject *args)
{
PyObject *self;
UNLESS (PyArg_ParseTuple(args, "O", &self)) return NULL;
return capi_aq_base(self);
}
static PyObject *
capi_aq_parent(PyObject *self)
{
PyObject *result=Py_None;
if (isWrapper(self) && WRAPPER(self)->container)
result=WRAPPER(self)->container;
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: _Acquisition.c,v 1.2 2003/11/28 16:44:14 jim Exp $\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);
}
from _Acquisition import *
##############################################################################
#
# 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']),
])
##############################################################################
#
# 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',
- The object found, and
- The extra data passed to 'aq_acquire'.
If the filter returns a true object that the object found is
returned, otherwise, the acquisition search continues.
For example, in::
>>> from Acquisition import Explicit
>>> class HandyForTesting:
... def __init__(self, name): self.name=name
... def __str__(self):
... return "%s(%s)" % (self.name, self.__class__.__name__)
... __repr__=__str__
>>> class E(Explicit, HandyForTesting):
... pass
>>> class Nice(HandyForTesting):
... isNice=1
... def __str__(self):
... return HandyForTesting.__str__(self)+' and I am nice!'
... __repr__=__str__
>>> a = E('a')
>>> a.b = E('b')
>>> a.b.c = E('c')
>>> a.p = Nice('spam')
>>> a.b.p = E('p')
>>> def find_nice(self, ancestor, name, object, extra):
... return hasattr(object,'isNice') and object.isNice
>>> print a.b.c.aq_acquire('p', find_nice)
spam(Nice) and I am nice!
The filtered acquisition in the last line skips over the first
attribute it finds with the name 'p', because the attribute
doesn't satisfy the condition given in the filter.
Acquisition and methods
Python methods of objects that support acquisition can use
acquired attributes as in the 'report' method of the first example
above. When a Python method is called on an object that is
wrapped by an acquisition wrapper, the wrapper is passed to the
method as the first argument. This rule also applies to
user-defined method types and to C methods defined in pure mix-in
classes.
Unfortunately, C methods defined in extension base classes that
define their own data structures, cannot use aquired attributes at
this time. This is because wrapper objects do not conform to the
data structures expected by these methods.
Acquiring Acquiring objects
Consider the following example::
>>> from Acquisition import Implicit
>>> class C(Implicit):
... def __init__(self, name): self.name=name
... def __str__(self):
... return "%s(%s)" % (self.name, self.__class__.__name__)
... __repr__=__str__
>>> a = C("a")
>>> a.b = C("b")
>>> a.b.pref = "spam"
>>> a.b.c = C("c")
>>> a.b.c.color = "red"
>>> a.b.c.pref = "eggs"
>>> a.x = C("x")
>>> o = a.b.c.x
The expression 'o.color' might be expected to return '"red"'. In
earlier versions of ExtensionClass, however, this expression
failed. Acquired acquiring objects did not acquire from the
environment they were accessed in, because objects were only
wrapped when they were first found, and were not rewrapped as they
were passed down the acquisition tree.
In the current release of ExtensionClass, the expression "o.color"
does indeed return '"red"'.
>>> o.color
'red'
When searching for an attribute in 'o', objects are searched in
the order 'x', 'a', 'b', 'c'. So, for example, the expression,
'o.pref' returns '"spam"', not '"eggs"'::
>>> o.pref
'spam'
In earlier releases of ExtensionClass, the attempt to get the
'pref' attribute from 'o' would have failed.
If desired, the current rules for looking up attributes in complex
expressions can best be understood through repeated application of
the '__of__' method:
'a.x' -- 'x.__of__(a)'
'a.b' -- 'b.__of__(a)'
'a.b.x' -- 'x.__of__(a).__of__(b.__of__(a))'
'a.b.c' -- 'c.__of__(b.__of__(a))'
'a.b.c.x' --
'x.__of__(a).__of__(b.__of__(a)).__of__(c.__of__(b.__of__(a)))'
and by keeping in mind that attribute lookup in a wrapper
is done by trying to lookup the attribute in the wrapped object
first and then in the parent object. In the expressions above
involving the '__of__' method, lookup proceeds from left to right.
Note that heuristics are used to avoid most of the repeated
lookups. For example, in the expression: 'a.b.c.x.foo', the object
'a' is searched no more than once, even though it is wrapped three
times.
.. [1] Gil, J., Lorenz, D.,
"Environmental Acquisition--A New Inheritance-Like Abstraction Mechanism",
http://www.bell-labs.com/people/cope/oopsla/Oopsla96TechnicalProgramAbstracts.html#GilLorenz,
OOPSLA '96 Proceedings, ACM SIG-PLAN, October, 1996
$Id: tests.py,v 1.2 2003/11/28 16:44:14 jim Exp $
"""
import ExtensionClass
import Acquisition
class I(Acquisition.Implicit):
def __init__(self, id):
self.id = id
def __repr__(self):
return self.id
class E(Acquisition.Explicit):
def __init__(self, id):
self.id = id
def __repr__(self):
return self.id
def test_unwrapped():
"""
>>> c = I('unwrapped')
>>> show(c)
unwrapped
>>> c.aq_parent
Traceback (most recent call last):
...
AttributeError: aq_parent
>>> Acquisition.aq_acquire(c, 'id')
'unwrapped'
>>> Acquisition.aq_acquire(c, 'x')
Traceback (most recent call last):
...
AttributeError: x
>>> Acquisition.aq_acquire(c, 'id',
... lambda searched, parent, name, ob, extra: extra)
Traceback (most recent call last):
...
AttributeError: id
>>> Acquisition.aq_acquire(c, 'id',
... lambda searched, parent, name, ob, extra: extra,
... 1)
'unwrapped'
>>> Acquisition.aq_base(c) is c
1
>>> Acquisition.aq_chain(c)
[unwrapped]
>>> Acquisition.aq_chain(c, 1)
[unwrapped]
>>> Acquisition.aq_get(c, 'id')
'unwrapped'
>>> Acquisition.aq_get(c, 'x')
Traceback (most recent call last):
...
AttributeError: x
>>> Acquisition.aq_get(c, 'x', 'foo')
'foo'
>>> Acquisition.aq_get(c, 'x', 'foo', 1)
'foo'
>>> Acquisition.aq_inner(c) is c
1
>>> Acquisition.aq_parent(c)
>>> Acquisition.aq_self(c) is c
1
"""
def test_simple():
"""
>>> a = I('a')
>>> a.y = 42
>>> a.b = I('b')
>>> a.b.c = I('c')
>>> show(a.b.c)
c
|
b
|
a
>>> show(a.b.c.aq_parent)
b
|
a
>>> show(a.b.c.aq_self)
c
>>> show(a.b.c.aq_base)
c
>>> show(a.b.c.aq_inner)
c
|
b
|
a
>>> a.b.c.y
42
>>> a.b.c.aq_chain
[c, b, a]
>>> a.b.c.aq_inContextOf(a)
1
>>> a.b.c.aq_inContextOf(a.b)
1
>>> a.b.c.aq_inContextOf(a.b.c)
1
>>> a.b.c.aq_acquire('y')
42
>>> a.b.c.aq_acquire('id')
'c'
>>> a.b.c.aq_acquire('x')
Traceback (most recent call last):
...
AttributeError: x
>>> a.b.c.aq_acquire('id',
... lambda searched, parent, name, ob, extra: extra)
Traceback (most recent call last):
...
AttributeError: id
>>> Acquisition.aq_acquire(a.b.c, 'id',
... lambda searched, parent, name, ob, extra: extra,
... 1)
'c'
>>> Acquisition.aq_acquire(a.b.c, 'id')
'c'
>>> Acquisition.aq_acquire(a.b.c, 'x')
Traceback (most recent call last):
...
AttributeError: x
>>> Acquisition.aq_acquire(a.b.c, 'y')
42
>>> Acquisition.aq_acquire(a.b.c, 'id',
... lambda searched, parent, name, ob, extra: extra)
Traceback (most recent call last):
...
AttributeError: id
>>> Acquisition.aq_acquire(a.b.c, 'id',
... lambda searched, parent, name, ob, extra: extra,
... 1)
'c'
>>> show(Acquisition.aq_base(a.b.c))
c
>>> Acquisition.aq_chain(a.b.c)
[c, b, a]
>>> Acquisition.aq_chain(a.b.c, 1)
[c, b, a]
>>> Acquisition.aq_get(a.b.c, 'id')
'c'
>>> Acquisition.aq_get(a.b.c, 'x')
Traceback (most recent call last):
...
AttributeError: x
>>> Acquisition.aq_get(a.b.c, 'x', 'foo')
'foo'
>>> Acquisition.aq_get(a.b.c, 'x', 'foo', 1)
'foo'
>>> show(Acquisition.aq_inner(a.b.c))
c
|
b
|
a
>>> show(Acquisition.aq_parent(a.b.c))
b
|
a
>>> show(Acquisition.aq_self(a.b.c))
c
"""
def test_muliple():
r"""
>>> a = I('a')
>>> a.color = 'red'
>>> a.a1 = I('a1')
>>> a.a1.color = 'green'
>>> a.a1.a11 = I('a11')
>>> a.a2 = I('a2')
>>> a.a2.a21 = I('a21')
>>> show(a.a1.a11.a2.a21)
a21
|
(a2)
| \
| (a2)
| | \
| | a2
| | |
| | a
| |
| a1
| |
| a
|
a11
|
a1
|
a
>>> a.a1.a11.a2.a21.color
'red'
>>> show(a.a1.a11.a2.a21.aq_parent)
(a2)
| \
| (a2)
| | \
| | a2
| | |
| | a
| |
| a1
| |
| a
|
a11
|
a1
|
a
>>> show(a.a1.a11.a2.a21.aq_parent.aq_parent)
a11
|
a1
|
a
>>> show(a.a1.a11.a2.a21.aq_self)
a21
>>> show(a.a1.a11.a2.a21.aq_parent.aq_self)
(a2)
| \
| a2
| |
| a
|
a1
|
a
>>> show(a.a1.a11.a2.a21.aq_base)
a21
>>> show(a.a1.a11.a2.a21.aq_inner)
a21
|
(a2)
| \
| (a2)
| | \
| | a2
| | |
| | a
| |
| a1
| |
| a
|
a11
|
a1
|
a
>>> show(a.a1.a11.a2.a21.aq_inner.aq_parent.aq_inner)
a2
|
a
>>> show(a.a1.a11.a2.a21.aq_inner.aq_parent.aq_inner.aq_parent)
a
>>> a.a1.a11.a2.a21.aq_chain
[a21, a2, a11, a1, a]
>>> a.a1.a11.a2.a21.aq_inContextOf(a)
1
>>> a.a1.a11.a2.a21.aq_inContextOf(a.a2)
1
>>> a.a1.a11.a2.a21.aq_inContextOf(a.a1)
0
>>> a.a1.a11.a2.a21.aq_acquire('color')
'red'
>>> a.a1.a11.a2.a21.aq_acquire('id')
'a21'
>>> a.a1.a11.a2.a21.aq_acquire('color',
... lambda ob, parent, name, v, extra: extra)
Traceback (most recent call last):
...
AttributeError: color
>>> a.a1.a11.a2.a21.aq_acquire('color',
... lambda ob, parent, name, v, extra: extra, 1)
'red'
>>> a.a1.y = 42
>>> a.a1.a11.a2.a21.aq_acquire('y')
42
>>> a.a1.a11.a2.a21.aq_acquire('y', containment=1)
Traceback (most recent call last):
...
AttributeError: y
Much of the same, but with methods:
>>> show(Acquisition.aq_parent(a.a1.a11.a2.a21))
(a2)
| \
| (a2)
| | \
| | a2
| | |
| | a
| |
| a1
| |
| a
|
a11
|
a1
|
a
>>> show(Acquisition.aq_parent(a.a1.a11.a2.a21.aq_parent))
a11
|
a1
|
a
>>> show(Acquisition.aq_self(a.a1.a11.a2.a21))
a21
>>> show(Acquisition.aq_self(a.a1.a11.a2.a21.aq_parent))
(a2)
| \
| a2
| |
| a
|
a1
|
a
>>> show(Acquisition.aq_base(a.a1.a11.a2.a21))
a21
>>> show(Acquisition.aq_inner(a.a1.a11.a2.a21))
a21
|
(a2)
| \
| (a2)
| | \
| | a2
| | |
| | a
| |
| a1
| |
| a
|
a11
|
a1
|
a
>>> show(Acquisition.aq_inner(a.a1.a11.a2.a21.aq_inner.aq_parent))
a2
|
a
>>> show(Acquisition.aq_parent(
... a.a1.a11.a2.a21.aq_inner.aq_parent.aq_inner))
a
>>> Acquisition.aq_chain(a.a1.a11.a2.a21)
[a21, a2, a11, a1, a]
>>> Acquisition.aq_chain(a.a1.a11.a2.a21, 1)
[a21, a2, a]
>>> Acquisition.aq_acquire(a.a1.a11.a2.a21, 'color')
'red'
>>> Acquisition.aq_acquire(a.a1.a11.a2.a21, 'id')
'a21'
>>> Acquisition.aq_acquire(a.a1.a11.a2.a21, 'color',
... lambda ob, parent, name, v, extra: extra)
Traceback (most recent call last):
...
AttributeError: color
>>> Acquisition.aq_acquire(a.a1.a11.a2.a21, 'color',
... lambda ob, parent, name, v, extra: extra, 1)
'red'
>>> a.a1.y = 42
>>> Acquisition.aq_acquire(a.a1.a11.a2.a21, 'y')
42
>>> Acquisition.aq_acquire(a.a1.a11.a2.a21, 'y', containment=1)
Traceback (most recent call last):
...
AttributeError: y
"""
def test_pinball():
r"""
>>> a = I('a')
>>> a.a1 = I('a1')
>>> a.a1.a11 = I('a11')
>>> a.a1.a12 = I('a12')
>>> a.a2 = I('a2')
>>> a.a2.a21 = I('a21')
>>> a.a2.a22 = I('a22')
>>> show(a.a1.a11.a1.a12.a2.a21.a2.a22)
a22
|
(a2)
| \
| (a2)
| | \
| | a2
| | |
| | a
| |
| (a2)
| | \
| | (a2)
| | | \
| | | a2
| | | |
| | | a
| | |
| | (a1)
| | | \
| | | (a1)
| | | | \
| | | | a1
| | | | |
| | | | a
| | | |
| | | a1
| | | |
| | | a
| | |
| | a11
| | |
| | a1
| | |
| | a
| |
| a12
| |
| (a1)
| | \
| | (a1)
| | | \
| | | a1
| | | |
| | | a
| | |
| | a1
| | |
| | a
| |
| a11
| |
| a1
| |
| a
|
a21
|
(a2)
| \
| (a2)
| | \
| | a2
| | |
| | a
| |
| (a1)
| | \
| | (a1)
| | | \
| | | a1
| | | |
| | | a
| | |
| | a1
| | |
| | a
| |
| a11
| |
| a1
| |
| a
|
a12
|
(a1)
| \
| (a1)
| | \
| | a1
| | |
| | a
| |
| a1
| |
| a
|
a11
|
a1
|
a
"""
def test_explicit():
"""
>>> a = E('a')
>>> a.y = 42
>>> a.b = E('b')
>>> a.b.c = E('c')
>>> show(a.b.c)
c
|
b
|
a
>>> show(a.b.c.aq_parent)
b
|
a
>>> show(a.b.c.aq_self)
c
>>> show(a.b.c.aq_base)
c
>>> show(a.b.c.aq_inner)
c
|
b
|
a
>>> a.b.c.y
Traceback (most recent call last):
...
AttributeError: y
>>> a.b.c.aq_chain
[c, b, a]
>>> a.b.c.aq_inContextOf(a)
1
>>> a.b.c.aq_inContextOf(a.b)
1
>>> a.b.c.aq_inContextOf(a.b.c)
1
>>> a.b.c.aq_acquire('y')
42
>>> a.b.c.aq_acquire('id')
'c'
>>> a.b.c.aq_acquire('x')
Traceback (most recent call last):
...
AttributeError: x
>>> a.b.c.aq_acquire('id',
... lambda searched, parent, name, ob, extra: extra)
Traceback (most recent call last):
...
AttributeError: id
>>> Acquisition.aq_acquire(a.b.c, 'id',
... lambda searched, parent, name, ob, extra: extra,
... 1)
'c'
>>> Acquisition.aq_acquire(a.b.c, 'id')
'c'
>>> Acquisition.aq_acquire(a.b.c, 'x')
Traceback (most recent call last):
...
AttributeError: x
>>> Acquisition.aq_acquire(a.b.c, 'y')
42
>>> Acquisition.aq_acquire(a.b.c, 'id',
... lambda searched, parent, name, ob, extra: extra)
Traceback (most recent call last):
...
AttributeError: id
>>> Acquisition.aq_acquire(a.b.c, 'id',
... lambda searched, parent, name, ob, extra: extra,
... 1)
'c'
>>> show(Acquisition.aq_base(a.b.c))
c
>>> Acquisition.aq_chain(a.b.c)
[c, b, a]
>>> Acquisition.aq_chain(a.b.c, 1)
[c, b, a]
>>> Acquisition.aq_get(a.b.c, 'id')
'c'
>>> Acquisition.aq_get(a.b.c, 'x')
Traceback (most recent call last):
...
AttributeError: x
>>> Acquisition.aq_get(a.b.c, 'y')
42
>>> Acquisition.aq_get(a.b.c, 'x', 'foo')
'foo'
>>> Acquisition.aq_get(a.b.c, 'x', 'foo', 1)
'foo'
>>> show(Acquisition.aq_inner(a.b.c))
c
|
b
|
a
>>> show(Acquisition.aq_parent(a.b.c))
b
|
a
>>> show(Acquisition.aq_self(a.b.c))
c
"""
def test_mixed_explicit_and_explicit():
"""
>>> a = I('a')
>>> a.y = 42
>>> a.b = E('b')
>>> a.b.z = 3
>>> a.b.c = I('c')
>>> show(a.b.c)
c
|
b
|
a
>>> show(a.b.c.aq_parent)
b
|
a
>>> show(a.b.c.aq_self)
c
>>> show(a.b.c.aq_base)
c
>>> show(a.b.c.aq_inner)
c
|
b
|
a
>>> a.b.c.y
42
>>> a.b.c.z
3
>>> a.b.c.aq_chain
[c, b, a]
>>> a.b.c.aq_inContextOf(a)
1
>>> a.b.c.aq_inContextOf(a.b)
1
>>> a.b.c.aq_inContextOf(a.b.c)
1
>>> a.b.c.aq_acquire('y')
42
>>> a.b.c.aq_acquire('z')
3
>>> a.b.c.aq_acquire('z', explicit=False)
3
>>> a.b.c.aq_acquire('id')
'c'
>>> a.b.c.aq_acquire('x')
Traceback (most recent call last):
...
AttributeError: x
>>> a.b.c.aq_acquire('id',
... lambda searched, parent, name, ob, extra: extra)
Traceback (most recent call last):
...
AttributeError: id
>>> Acquisition.aq_acquire(a.b.c, 'id',
... lambda searched, parent, name, ob, extra: extra,
... 1)
'c'
>>> Acquisition.aq_acquire(a.b.c, 'id')
'c'
>>> Acquisition.aq_acquire(a.b.c, 'x')
Traceback (most recent call last):
...
AttributeError: x
>>> Acquisition.aq_acquire(a.b.c, 'y')
42
>>> Acquisition.aq_acquire(a.b.c, 'id',
... lambda searched, parent, name, ob, extra: extra)
Traceback (most recent call last):
...
AttributeError: id
>>> Acquisition.aq_acquire(a.b.c, 'id',
... lambda searched, parent, name, ob, extra: extra,
... 1)
'c'
>>> show(Acquisition.aq_base(a.b.c))
c
>>> Acquisition.aq_chain(a.b.c)
[c, b, a]
>>> Acquisition.aq_chain(a.b.c, 1)
[c, b, a]
>>> Acquisition.aq_get(a.b.c, 'id')
'c'
>>> Acquisition.aq_get(a.b.c, 'x')
Traceback (most recent call last):
...
AttributeError: x
>>> Acquisition.aq_get(a.b.c, 'y')
42
>>> Acquisition.aq_get(a.b.c, 'x', 'foo')
'foo'
>>> Acquisition.aq_get(a.b.c, 'x', 'foo', 1)
'foo'
>>> show(Acquisition.aq_inner(a.b.c))
c
|
b
|
a
>>> show(Acquisition.aq_parent(a.b.c))
b
|
a
>>> show(Acquisition.aq_self(a.b.c))
c
"""
def old_tests():
"""
>>> from ExtensionClass import Base
>>> import Acquisition
>>> class B(Base):
... color='red'
>>> class A(Acquisition.Implicit):
... def hi(self):
... print "%s()" % self.__class__.__name__, self.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()
New test for wrapper comparisons.
>>> foo = b.a
>>> bar = b.a
>>> foo == bar
1
>>> c = A()
>>> b.c = c
>>> b.c.d = c
>>> b.c.d == c
1
>>> b.c.d == b.c
1
>>> b.c == c
1
>>> 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 1
... self = aq_inner(subob)
... if self is None: break
... subob = aq_parent(self)
... if subob is None: break
>>> checkContext(b.c, b)
1
>>> not checkContext(b.c, b.a)
1
>>> b.a.aq_inContextOf(b)
1
>>> b.c.aq_inContextOf(b)
1
>>> b.c.d.aq_inContextOf(b)
1
>>> b.c.d.aq_inContextOf(c)
1
>>> b.c.d.aq_inContextOf(b.c)
1
>>> not b.c.aq_inContextOf(foo)
1
>>> not b.c.aq_inContextOf(b.a)
1
>>> not b.a.aq_inContextOf('somestring')
1
"""
def test_AqAlg():
"""
>>> A=I('A')
>>> A.B=I('B')
>>> A.B.color='red'
>>> A.C=I('C')
>>> A.C.D=I('D')
>>> A
A
>>> Acquisition.aq_chain(A)
[A]
>>> Acquisition.aq_chain(A, 1)
[A]
>>> map(Acquisition.aq_base, Acquisition.aq_chain(A, 1))
[A]
>>> A.C
C
>>> Acquisition.aq_chain(A.C)
[C, A]
>>> Acquisition.aq_chain(A.C, 1)
[C, A]
>>> map(Acquisition.aq_base, Acquisition.aq_chain(A.C, 1))
[C, A]
>>> A.C.D
D
>>> Acquisition.aq_chain(A.C.D)
[D, C, A]
>>> Acquisition.aq_chain(A.C.D, 1)
[D, C, A]
>>> map(Acquisition.aq_base, Acquisition.aq_chain(A.C.D, 1))
[D, C, A]
>>> A.B.C
C
>>> Acquisition.aq_chain(A.B.C)
[C, B, A]
>>> Acquisition.aq_chain(A.B.C, 1)
[C, A]
>>> map(Acquisition.aq_base, Acquisition.aq_chain(A.B.C, 1))
[C, A]
>>> A.B.C.D
D
>>> Acquisition.aq_chain(A.B.C.D)
[D, C, B, A]
>>> Acquisition.aq_chain(A.B.C.D, 1)
[D, C, A]
>>> map(Acquisition.aq_base, Acquisition.aq_chain(A.B.C.D, 1))
[D, C, A]
>>> A.B.C.D.color
'red'
>>> Acquisition.aq_get(A.B.C.D, "color", None)
'red'
>>> 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()
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