Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Z
Zope
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
Zope
Commits
db20880e
Commit
db20880e
authored
Feb 08, 2009
by
Hanno Schlichting
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Pull in Acquisition from the standalone package
parent
a8ccc89a
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
0 additions
and
4651 deletions
+0
-4651
lib/python/Acquisition/Acquisition.h
lib/python/Acquisition/Acquisition.h
+0
-60
lib/python/Acquisition/README.txt
lib/python/Acquisition/README.txt
+0
-417
lib/python/Acquisition/_Acquisition.c
lib/python/Acquisition/_Acquisition.c
+0
-1874
lib/python/Acquisition/__init__.py
lib/python/Acquisition/__init__.py
+0
-10
lib/python/Acquisition/interfaces.py
lib/python/Acquisition/interfaces.py
+0
-64
lib/python/Acquisition/tests.py
lib/python/Acquisition/tests.py
+0
-2226
No files found.
lib/python/Acquisition/Acquisition.h
deleted
100644 → 0
View file @
a8ccc89a
/*****************************************************************************
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.1 (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
lib/python/Acquisition/README.txt
deleted
100644 → 0
View file @
a8ccc89a
.. contents::
Introductory Example
====================
Zope implements acquisition with "Extension Class" mix-in classes. To
use acquisition your classes must inherit from an acquisition base
class. For 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 its
environment, where its 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``.
Acquisition wrappers provide access to the wrapped objects through the
attributes ``aq_parent``, ``aq_self``, ``aq_base``. Continue the
example from above::
>>> c.a.aq_parent is c
True
>>> c.a.aq_self is a
True
Explicit and Implicit Acquisition
=================================
Two styles of acquisition are supported: implicit and explicit
acquisition.
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 inheritance.
An attribute can be implicitly acquired if its name does not begin
with an underscore.
To support implicit acquisition, your class 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_acquire must be
used. For example::
>>> print c.a.aq_acquire('color')
red
To support explicit acquisition, your class should inherit from the
mix-in class ``Acquisition.Explicit``.
Controlling Acquisition
-----------------------
A class (or instance) can provide attribute by attribute control over
acquisition. Your should subclass from ``Acquisition.Explicit``, and set
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::
>>> class C(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__``. Note that the ``__roles__``
attribute is acquired even though its name begins with an
underscore. In fact, the special ``Acquisition.Acquired`` value can be
used in ``Acquisition.Implicit`` objects to implicitly acquire
selected objects that smell like private objects.
Sometimes, you want to dynamically make an implicitly acquiring object
acquire explicitly. You can do this by getting the object's
aq_explicit attribute. This attribute provides the object with an
explicit wrapper that places the original implicit wrapper.
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.
Here's an example::
>>> 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.
Filtered acquisition is rarely used in Zope.
Acquiring from Context
======================
Normally acquisition allows objects to acquire data from their
containers. However an object can acquire from objects that aren't its
containers.
Most of the examples we've seen so far show establishing of an
acquisition context using getattr semantics. For example, ``a.b`` is a
reference to ``b`` in the context of ``a``.
You can also manually set acquisition context using the ``__of__``
method. For example::
>>> from Acquisition import Implicit
>>> class C(Implicit): pass
...
>>> a = C()
>>> b = C()
>>> a.color = "red"
>>> print b.__of__(a).color
red
In this case, ``a`` does not contain ``b``, but it is put in ``b``'s
context using the ``__of__`` method.
Here's another subtler example that shows how you can construct an
acquisition context that includes non-container objects::
>>> from Acquisition import Implicit
>>> class C(Implicit):
... def __init__(self, name):
... self.name = name
>>> a = C("a")
>>> a.b = C("b")
>>> a.b.color = "red"
>>> a.x = C("x")
>>> print a.b.x.color
red
Even though ``b`` does not contain ``x``, ``x`` can acquire the color
attribute from ``b``. This works because in this case, ``x`` is accessed
in the context of ``b`` even though it is not contained by ``b``.
Here acquisition context is defined by the objects used to access
another object.
Containment Before Context
==========================
If in the example above suppose both a and b have an color attribute::
>>> a = C("a")
>>> a.color = "green"
>>> a.b = C("b")
>>> a.b.color = "red"
>>> a.x = C("x")
>>> print a.b.x.color
green
Why does ``a.b.x.color`` acquire color from ``a`` and not from ``b``?
The answer is that an object acquires from its containers before
non-containers in its context.
To see why consider this example in terms of expressions using the
``__of__`` method::
a.x -> x.__of__(a)
a.b -> b.__of__(a)
a.b.x -> x.__of__(a).__of__(b.__of__(a))
Keep in mind that attribute lookup in a wrapper is done by trying to
look up the attribute in the wrapped object first and then in the
parent object. So in the expressions above proceeds from left to
right.
The upshot of these rules is that attributes are looked up by
containment before context.
This rule holds true also for more complex examples. For example,
``a.b.c.d.e.f.g.attribute`` would search for attribute in ``g`` and
all its containers first. (Containers are searched in order from the
innermost parent to the outermost container.) If the attribute is not
found in ``g`` or any of its containers, then the search moves to
``f`` and all its containers, and so on.
Additional Attributes and Methods
=================================
You can use the special method ``aq_inner`` to access an object
wrapped only by containment. So in the example above,
``a.b.x.aq_inner`` is equivalent to ``a.x``.
You can find out the acquisition context of an object using the
aq_chain method like so:
>>> [obj.name for obj in a.b.x.aq_chain]
['x', 'b', 'a']
You can find out if an object is in the containment context of another
object using the ``aq_inContextOf`` method. For example:
>>> a.b.aq_inContextOf(a)
1
.. Note: as of this writing the aq_inContextOf examples don't work the
way they should be working. According to Jim, this is because
aq_inContextOf works by comparing object pointer addresses, which
(because they are actually different wrapper objects) doesn't give
you the expected results. He acknowledges that this behavior is
controversial, and says that there is a collector entry to change
it so that you would get the answer you expect in the above. (We
just need to get to it).
Acquisition Module Functions
============================
In addition to using acquisition attributes and methods directly on
objects you can use similar functions defined in the ``Acquisition``
module. These functions have the advantage that you don't need to
check to make sure that the object has the method or attribute before
calling it.
``aq_acquire(object, name [, filter, extra, explicit, default, containment])``
Acquires an object with the given name.
This function can be used to explictly acquire when using explicit
acquisition and to acquire names that wouldn't normally be
acquired.
The function accepts a number of optional arguments:
``filter``
A callable filter object that is used to decide if an object
should be acquired.
The filter 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 argument passed to aq_acquire.
If the filter returns a true object that the object found is
returned, otherwise, the acquisition search continues.
``extra``
Extra data to be passed as the last argument to the filter.
``explicit``
A flag (boolean value) indicating whether explicit acquisition
should be used. The default value is true. If the flag is
true, then acquisition will proceed regardless of whether
wrappers encountered in the search of the acquisition
hierarchy are explicit or implicit wrappers. If the flag is
false, then parents of explicit wrappers are not searched.
This argument is useful if you want to apply a filter without
overriding explicit wrappers.
``default``
A default value to return if no value can be acquired.
``containment``
A flag indicating whether the search should be limited to the
containment hierarchy.
In addition, arguments can be provided as keywords.
``aq_base(object)``
Return the object with all wrapping removed.
``aq_chain(object [, containment])``
Return a list containing the object and it's acquisition
parents. The optional argument, containment, controls whether the
containment or access hierarchy is used.
``aq_get(object, name [, default, containment])``
Acquire an attribute, name. A default value can be provided, as
can a flag that limits search to the containment hierarchy.
``aq_inner(object)``
Return the object with all but the innermost layer of wrapping
removed.
``aq_parent(object)``
Return the acquisition parent of the object or None if the object
is unwrapped.
``aq_self(object)``
Return the object with one layer of wrapping removed, unless the
object is unwrapped, in which case the object is returned.
In most cases it is more convenient to use these module functions
instead of the acquisition attributes and methods directly.
Acquisition and Methods
=======================
Python methods of objects that support acquisition can use acquired
attributes. 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. In practice, you will seldom
find this a problem.
Conclusion
==========
Acquisition provides a powerful way to dynamically share information
between objects. Zope 2 uses acquisition for a number of its key
features including security, object publishing, and DTML variable
lookup. Acquisition also provides an elegant solution to the problem
of circular references for many classes of problems. While acquisition
is powerful, you should take care when using acquisition in your
applications. The details can get complex, especially with the
differences between acquiring from context and acquiring from
containment.
lib/python/Acquisition/_Acquisition.c
deleted
100644 → 0
View file @
a8ccc89a
/*****************************************************************************
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.1 (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/ExtensionClass.h"
#define _IN_ACQUISITION_C
#include "Acquisition/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__contains__
,
*
py__len__
,
*
py__of__
,
*
py__call__
,
*
py__repr__
,
*
py__str__
,
*
py__cmp__
,
*
py__parent__
,
*
py__iter__
;
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
(
__contains__
);
INIT_PY_NAME
(
__len__
);
INIT_PY_NAME
(
__of__
);
INIT_PY_NAME
(
__call__
);
INIT_PY_NAME
(
__repr__
);
INIT_PY_NAME
(
__str__
);
INIT_PY_NAME
(
__cmp__
);
INIT_PY_NAME
(
__parent__
);
INIT_PY_NAME
(
__iter__
);
#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
/* For obscure reasons, we need to use tp_richcompare instead of tp_compare.
* The comparisons here all most naturally compute a cmp()-like result.
* This little helper turns that into a bool result for rich comparisons.
*/
static
PyObject
*
diff_to_bool
(
int
diff
,
int
op
)
{
PyObject
*
result
;
int
istrue
;
switch
(
op
)
{
case
Py_EQ
:
istrue
=
diff
==
0
;
break
;
case
Py_NE
:
istrue
=
diff
!=
0
;
break
;
case
Py_LE
:
istrue
=
diff
<=
0
;
break
;
case
Py_GE
:
istrue
=
diff
>=
0
;
break
;
case
Py_LT
:
istrue
=
diff
<
0
;
break
;
case
Py_GT
:
istrue
=
diff
>
0
;
break
;
default:
assert
(
!
"op unknown"
);
istrue
=
0
;
/* To shut up compiler */
}
result
=
istrue
?
Py_True
:
Py_False
;
Py_INCREF
(
result
);
return
result
;
}
/* 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
int
Wrapper__init__
(
Wrapper
*
self
,
PyObject
*
args
,
PyObject
*
kwargs
)
{
PyObject
*
obj
,
*
container
;
if
(
kwargs
&&
PyDict_Size
(
kwargs
)
!=
0
)
{
PyErr_SetString
(
PyExc_TypeError
,
"kwyword arguments not allowed"
);
return
-
1
;
}
UNLESS
(
PyArg_ParseTuple
(
args
,
"OO:__init__"
,
&
obj
,
&
container
))
return
-
1
;
if
(
self
==
WRAPPER
(
obj
))
{
PyErr_SetString
(
PyExc_ValueError
,
"Cannot wrap acquisition wrapper in itself (Wrapper__init__)"
);
return
-
1
;
}
Py_INCREF
(
obj
);
self
->
obj
=
obj
;
if
(
container
!=
Py_None
)
{
Py_INCREF
(
container
);
self
->
container
=
container
;
}
return
0
;
}
/* ---------------------------------------------------------------- */
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
;
Py_INCREF
(
parent
);
PyTuple_SET_ITEM
(
t
,
0
,
parent
);
ASSIGN
(
r
,
PyObject_CallObject
(
r
,
t
));
Py_DECREF
(
t
);
if
(
r
!=
NULL
&&
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
)
)
{
if
(
r
->
ob_refcnt
!=
1
)
{
t
=
PyObject_CallFunctionObjArgs
((
PyObject
*
)(
r
->
ob_type
),
WRAPPER
(
r
)
->
obj
,
WRAPPER
(
r
)
->
container
,
NULL
);
Py_DECREF
(
r
);
if
(
t
==
NULL
)
return
NULL
;
r
=
t
;
}
/* 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
PyObject
*
Wrapper_descrget
(
Wrapper
*
self
,
PyObject
*
inst
,
PyObject
*
cls
)
{
if
(
inst
==
NULL
)
{
Py_INCREF
(
self
);
return
(
PyObject
*
)
self
;
}
return
__of__
((
PyObject
*
)
self
,
inst
);
}
#define newWrapper(obj, container, Wrappertype) \
PyObject_CallFunctionObjArgs(OBJECT(Wrappertype), obj, container, NULL)
static
int
Wrapper_traverse
(
Wrapper
*
self
,
visitproc
visit
,
void
*
arg
)
{
int
vret
;
if
(
self
->
obj
)
{
vret
=
visit
(
self
->
obj
,
arg
);
if
(
vret
!=
0
)
return
vret
;
}
if
(
self
->
container
)
{
vret
=
visit
(
self
->
container
,
arg
);
if
(
vret
!=
0
)
return
vret
;
}
return
0
;
}
static
int
Wrapper_clear
(
Wrapper
*
self
)
{
PyObject
*
tmp
;
tmp
=
self
->
obj
;
self
->
obj
=
NULL
;
Py_XDECREF
(
tmp
);
tmp
=
self
->
container
;
self
->
container
=
NULL
;
Py_XDECREF
(
tmp
);
return
0
;
}
static
void
Wrapper_dealloc
(
Wrapper
*
self
)
{
Wrapper_clear
(
self
);
self
->
ob_type
->
tp_free
((
PyObject
*
)
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
)
/*
Parameters:
sob
Search self->obj for the 'oname' attribute
sco
Search self->container for the 'oname' attribute
explicit
Explicitly acquire 'oname' attribute from container (assumed with
implicit acquisition wrapper)
containment
Use the innermost wrapper ("aq_inner") for looking up the 'oname'
attribute.
*/
{
PyObject
*
r
,
*
v
,
*
tb
;
char
*
name
=
""
;
if
(
PyString_Check
(
oname
))
name
=
PyString_AS_STRING
(
oname
);
if
((
*
name
==
'a'
&&
name
[
1
]
==
'q'
&&
name
[
2
]
==
'_'
)
||
(
strcmp
(
name
,
"__parent__"
)
==
0
))
{
/* __parent__ is an alias to aq_parent */
if
(
strcmp
(
name
,
"__parent__"
)
==
0
)
name
=
"parent"
;
else
name
=
name
+
3
;
if
((
r
=
Wrapper_special
(
self
,
name
,
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
;
}
/* normal attribute lookup */
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
(
r
&&
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
();
}
/* Lookup has failed, acquire it from parent. */
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
,
*
v
,
*
tb
;
int
sob
=
1
,
sco
=
1
;
if
(
self
->
container
)
{
/* If the container has an acquisition wrapper itself, we'll use
Wrapper_findattr to progress further. */
if
(
isWrapper
(
self
->
container
))
{
if
(
self
->
obj
&&
isWrapper
(
self
->
obj
))
{
/* Try to optimize search by recognizing repeated
objects 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
;
}
/* Don't search the container when the container of the
container is the same object as 'self'. */
if
(
WRAPPER
(
self
->
container
)
->
container
==
WRAPPER
(
self
)
->
obj
)
{
sco
=
0
;
containment
=
1
;
}
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
;
}
/* If the container has a __parent__ pointer, we create an
acquisition wrapper for it accordingly. Then we can proceed
with Wrapper_findattr, just as if the container had an
acquisition wrapper in the first place (see above). */
else
if
((
r
=
PyObject_GetAttr
(
self
->
container
,
py__parent__
)))
{
ASSIGN
(
self
->
container
,
newWrapper
(
self
->
container
,
r
,
(
PyTypeObject
*
)
&
Wrappertype
));
/* Don't search the container when the parent of the parent
is the same object as 'self' */
if
(
WRAPPER
(
r
)
->
obj
==
WRAPPER
(
self
)
->
obj
)
sco
=
0
;
Py_DECREF
(
r
);
/* don't need __parent__ anymore */
r
=
Wrapper_findattr
((
Wrapper
*
)
self
->
container
,
oname
,
filter
,
extra
,
orig
,
sob
,
sco
,
explicit
,
containment
);
/* There's no need to DECREF the wrapper here because it's
not stored in self->container, thus 'self' owns its
reference now */
return
r
;
}
/* The container is the end of the acquisition chain; if we
can't look up the attribute here, we can't look it up at
all. */
else
{
/* We need to clean up the AttributeError from the previous
getattr (because it has clearly failed). */
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
;
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
)
||
(
strcmp
(
name
,
"__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_richcompare
(
Wrapper
*
self
,
PyObject
*
w
,
int
op
)
{
int
diff
=
Wrapper_compare
(
self
,
w
);
return
diff_to_bool
(
diff
,
op
);
}
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
int
Wrapper_contains
(
Wrapper
*
self
,
PyObject
*
v
)
{
long
c
;
UNLESS
(
v
=
CallMethodO
(
OBJECT
(
self
),
py__contains__
,
Build
(
"(O)"
,
v
)
,
NULL
))
return
-
1
;
c
=
PyInt_AsLong
(
v
);
Py_DECREF
(
v
);
return
c
;
}
static
PyObject
*
Wrapper_iter
(
Wrapper
*
self
)
{
return
CallMethodO
(
OBJECT
(
self
),
py__iter__
,
NULL
,
NULL
);
}
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*/
(
objobjproc
)
Wrapper_contains
,
/*sq_contains*/
};
/* -------------------------------------------------------------- */
/* 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
;
PyObject
*
result
;
/* DM 2005-08-25: argument "default" ignored */
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
;
/* DM 2005-08-25: argument "default" ignored -- fix it! */
# if 0
return
Wrapper_findattr
(
self
,
name
,
filter
,
extra
,
OBJECT
(
self
),
1
,
explicit
||
self
->
ob_type
==
(
PyTypeObject
*
)
&
Wrappertype
,
explicit
,
containment
);
# else
result
=
Wrapper_findattr
(
self
,
name
,
filter
,
extra
,
OBJECT
(
self
),
1
,
explicit
||
self
->
ob_type
==
(
PyTypeObject
*
)
&
Wrappertype
,
explicit
,
containment
);
if
(
result
==
NULL
&&
defalt
!=
NULL
)
{
/* as "Python/bltinmodule.c:builtin_getattr" turn
only 'AttributeError' into a default value, such
that e.g. "ConflictError" and errors raised by the filter
are not mapped to the default value.
*/
if
(
PyErr_ExceptionMatches
(
PyExc_AttributeError
))
{
PyErr_Clear
();
Py_INCREF
(
defalt
);
result
=
defalt
;
}
}
return
result
;
# endif
}
/* forward declaration so that we can use it in Wrapper_inContextOf */
static
PyObject
*
capi_aq_inContextOf
(
PyObject
*
self
,
PyObject
*
o
,
int
inner
);
static
PyObject
*
Wrapper_inContextOf
(
Wrapper
*
self
,
PyObject
*
args
)
{
PyObject
*
o
;
int
inner
=
1
;
UNLESS
(
PyArg_ParseTuple
(
args
,
"O|i"
,
&
o
,
&
inner
))
return
NULL
;
return
capi_aq_inContextOf
((
PyObject
*
)
self
,
o
,
inner
);
}
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
[]
=
{
{
"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
)
0
,
/*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*/
/* tp_as_buffer */
0
,
/* tp_flags */
Py_TPFLAGS_DEFAULT
|
Py_TPFLAGS_BASETYPE
|
Py_TPFLAGS_HAVE_GC
,
"Wrapper object for implicit acquisition"
,
/* Documentation string */
/* tp_traverse */
(
traverseproc
)
Wrapper_traverse
,
/* tp_clear */
(
inquiry
)
Wrapper_clear
,
/* tp_richcompare */
(
richcmpfunc
)
Wrapper_richcompare
,
/* tp_weaklistoffset */
(
long
)
0
,
(
getiterfunc
)
Wrapper_iter
,
/*tp_iter*/
/* tp_iternext */
(
iternextfunc
)
0
,
/* tp_methods */
Wrapper_methods
,
/* tp_members */
0
,
/* tp_getset */
0
,
/* tp_base */
0
,
/* tp_dict */
0
,
/* tp_descr_get */
(
descrgetfunc
)
Wrapper_descrget
,
/* tp_descr_set */
0
,
/* tp_dictoffset */
0
,
/* tp_init */
(
initproc
)
Wrapper__init__
,
};
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
)
0
,
/*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*/
/* tp_as_buffer */
0
,
/* tp_flags */
Py_TPFLAGS_DEFAULT
|
Py_TPFLAGS_BASETYPE
|
Py_TPFLAGS_HAVE_GC
,
"Wrapper object for implicit acquisition"
,
/* Documentation string */
/* tp_traverse */
(
traverseproc
)
Wrapper_traverse
,
/* tp_clear */
(
inquiry
)
Wrapper_clear
,
/* tp_richcompare */
(
richcmpfunc
)
Wrapper_richcompare
,
/* tp_weaklistoffset */
(
long
)
0
,
(
getiterfunc
)
Wrapper_iter
,
/*tp_iter*/
/* tp_iternext */
(
iternextfunc
)
0
,
/* tp_methods */
Wrapper_methods
,
/* tp_members */
0
,
/* tp_getset */
0
,
/* tp_base */
0
,
/* tp_dict */
0
,
/* tp_descr_get */
(
descrgetfunc
)
Wrapper_descrget
,
/* tp_descr_set */
0
,
/* tp_dictoffset */
0
,
/* tp_init */
(
initproc
)
Wrapper__init__
,
};
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
,
*
v
,
*
tb
;
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; check if we have a __parent__ pointer. If that's
the case, create a wrapper and pretend it's business as usual. */
else
if
((
result
=
PyObject_GetAttr
(
self
,
py__parent__
)))
{
self
=
newWrapper
(
self
,
result
,
(
PyTypeObject
*
)
&
Wrappertype
);
Py_DECREF
(
result
);
/* don't need __parent__ anymore */
result
=
Wrapper_findattr
(
WRAPPER
(
self
),
name
,
filter
,
extra
,
OBJECT
(
self
),
1
,
1
,
explicit
,
containment
);
/* Get rid of temporary wrapper */
Py_DECREF
(
self
);
return
result
;
}
/* No wrapper and no __parent__, so just getattr. */
else
{
/* Clean up the AttributeError from the previous getattr
(because it has clearly failed). */
PyErr_Fetch
(
&
result
,
&
v
,
&
tb
);
if
(
result
&&
(
result
!=
PyExc_AttributeError
))
{
PyErr_Restore
(
result
,
v
,
tb
);
return
NULL
;
}
Py_XDECREF
(
result
);
Py_XDECREF
(
v
);
Py_XDECREF
(
tb
);
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
,
Py_None
,
(
PyTypeObject
*
)
&
Wrappertype
))
return
NULL
;
result
=
Wrapper_findattr
(
WRAPPER
(
self
),
name
,
filter
,
extra
,
OBJECT
(
self
),
1
,
1
,
explicit
,
containment
);
/* Get rid of temporary 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
,
*
v
,
*
tb
;
/* 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
);
/* Not wrapped; check if we have a __parent__ pointer. If that's
the case, create a wrapper and pretend it's business as usual. */
else
if
((
result
=
PyObject_GetAttr
(
self
,
py__parent__
)))
{
self
=
newWrapper
(
self
,
result
,
(
PyTypeObject
*
)
&
Wrappertype
);
Py_DECREF
(
result
);
/* don't need __parent__ anymore */
result
=
Wrapper_findattr
(
WRAPPER
(
self
),
name
,
0
,
0
,
OBJECT
(
self
),
1
,
1
,
1
,
containment
);
Py_DECREF
(
self
);
/* Get rid of temporary wrapper. */
}
else
{
/* Clean up the AttributeError from the previous getattr
(because it has clearly failed). */
PyErr_Fetch
(
&
result
,
&
v
,
&
tb
);
if
(
result
&&
(
result
!=
PyExc_AttributeError
))
{
PyErr_Restore
(
result
,
v
,
tb
);
return
NULL
;
}
Py_XDECREF
(
result
);
Py_XDECREF
(
v
);
Py_XDECREF
(
tb
);
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
,
*
v
,
*
tb
;
if
(
isWrapper
(
self
)
&&
WRAPPER
(
self
)
->
container
)
{
result
=
WRAPPER
(
self
)
->
container
;
Py_INCREF
(
result
);
return
result
;
}
else
if
((
result
=
PyObject_GetAttr
(
self
,
py__parent__
)))
/* We already own the reference to result (PyObject_GetAttr gives
it to us), no need to INCREF here */
return
result
;
else
{
/* We need to clean up the AttributeError from the previous
getattr (because it has clearly failed) */
PyErr_Fetch
(
&
result
,
&
v
,
&
tb
);
if
(
result
&&
(
result
!=
PyExc_AttributeError
))
{
PyErr_Restore
(
result
,
v
,
tb
);
return
NULL
;
}
Py_XDECREF
(
result
);
Py_XDECREF
(
v
);
Py_XDECREF
(
tb
);
result
=
Py_None
;
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
,
*
v
,
*
tb
;
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
;
if
((
self
=
PyObject_GetAttr
(
self
,
py__parent__
)))
{
Py_DECREF
(
self
);
/* We don't need our own reference. */
if
(
self
!=
Py_None
)
continue
;
}
else
{
PyErr_Fetch
(
&
self
,
&
v
,
&
tb
);
if
(
self
&&
(
self
!=
PyExc_AttributeError
))
{
PyErr_Restore
(
self
,
v
,
tb
);
return
NULL
;
}
Py_XDECREF
(
self
);
Py_XDECREF
(
v
);
Py_XDECREF
(
tb
);
}
}
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
PyObject
*
capi_aq_inContextOf
(
PyObject
*
self
,
PyObject
*
o
,
int
inner
)
{
PyObject
*
next
,
*
c
;
/* next = self
o = aq_base(o) */
next
=
self
;
while
(
isWrapper
(
o
)
&&
WRAPPER
(
o
)
->
obj
)
o
=
WRAPPER
(
o
)
->
obj
;
while
(
1
)
{
/* if aq_base(next) is o: return 1 */
c
=
next
;
while
(
isWrapper
(
c
)
&&
WRAPPER
(
c
)
->
obj
)
c
=
WRAPPER
(
c
)
->
obj
;
if
(
c
==
o
)
return
PyInt_FromLong
(
1
);
if
(
inner
)
{
self
=
capi_aq_inner
(
next
);
Py_DECREF
(
self
);
/* We're not holding on to the inner wrapper */
if
(
self
==
Py_None
)
break
;
}
else
self
=
next
;
next
=
capi_aq_parent
(
self
);
Py_DECREF
(
next
);
/* We're not holding on to the parent */
if
(
next
==
Py_None
)
break
;
}
return
PyInt_FromLong
(
0
);
}
static
PyObject
*
module_aq_inContextOf
(
PyObject
*
ignored
,
PyObject
*
args
)
{
PyObject
*
self
,
*
o
;
int
inner
=
1
;
UNLESS
(
PyArg_ParseTuple
(
args
,
"OO|i"
,
&
self
,
&
o
,
&
inner
))
return
NULL
;
return
capi_aq_inContextOf
(
self
,
o
,
inner
);
}
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 all 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"
},
{
"aq_inContextOf"
,
(
PyCFunction
)
module_aq_inContextOf
,
METH_VARARGS
,
"aq_inContextOf(base, ob [, inner]) -- "
"Determine whether the object is in the acquisition context of base."
},
{
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
);
}
lib/python/Acquisition/__init__.py
deleted
100644 → 0
View file @
a8ccc89a
from
zope.interface
import
classImplements
from
_Acquisition
import
*
from
interfaces
import
IAcquirer
from
interfaces
import
IAcquisitionWrapper
classImplements
(
Explicit
,
IAcquirer
)
classImplements
(
ExplicitAcquisitionWrapper
,
IAcquisitionWrapper
)
classImplements
(
Implicit
,
IAcquirer
)
classImplements
(
ImplicitAcquisitionWrapper
,
IAcquisitionWrapper
)
lib/python/Acquisition/interfaces.py
deleted
100644 → 0
View file @
a8ccc89a
##############################################################################
#
# Copyright (c) 2005 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (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 z3 interfaces.
$Id$
"""
from
zope.interface
import
Attribute
from
zope.interface
import
Interface
class
IAcquirer
(
Interface
):
"""Acquire attributes from containers.
"""
def
__of__
(
context
):
"""Get the object in a context.
"""
class
IAcquisitionWrapper
(
Interface
):
"""Wrapper object for acquisition.
"""
def
aq_acquire
(
name
,
filter
=
None
,
extra
=
None
,
explicit
=
True
,
default
=
0
,
containment
=
0
):
"""Get an attribute, acquiring it if necessary.
"""
def
aq_inContextOf
(
obj
,
inner
=
1
):
"""Test whether the object is currently in the context of the argument.
"""
aq_base
=
Attribute
(
"""Get the object unwrapped."""
)
aq_parent
=
Attribute
(
"""Get the parent of an object."""
)
aq_self
=
Attribute
(
"""Get the object with the outermost wrapper removed."""
)
aq_inner
=
Attribute
(
"""Get the object with all but the innermost wrapper removed."""
)
aq_chain
=
Attribute
(
"""Get a list of objects in the acquisition environment."""
)
lib/python/Acquisition/tests.py
deleted
100644 → 0
View file @
a8ccc89a
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (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$
"""
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
>>> c.__parent__
Traceback (most recent call last):
...
AttributeError: __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
>>> Acquisition.aq_inContextOf(a.b.c, a)
1
>>> Acquisition.aq_inContextOf(a.b.c, a.b)
1
>>> Acquisition.aq_inContextOf(a.b.c, 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
A wrapper's __parent__ attribute (which is equivalent to its
aq_parent attribute) points to the Acquisition parent.
>>> a.b.c.__parent__ == a.b.c.aq_parent
True
>>> a.b.c.__parent__ == a.b
True
"""
def
test__of__exception
():
"""
Wrapper_findattr did't check for an exception in a user defined
__of__ method before passing the result to the filter. In this
case the 'value' argument of the filter was NULL, which caused
a segfault when being accessed.
>>> class UserError(Exception):
... pass
...
>>> class X(Acquisition.Implicit):
... def __of__(self, parent):
... if Acquisition.aq_base(parent) is not parent:
... raise UserError, 'ack'
... return X.inheritedAttribute('__of__')(self, parent)
...
>>> a = I('a')
>>> a.b = I('b')
>>> a.b.x = X('x')
>>> Acquisition.aq_acquire(a.b, 'x',
... lambda self, object, name, value, extra: repr(value))
Traceback (most recent call last):
...
UserError: ack
"""
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
test_aq_inContextOf
():
"""
>>> 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
>>> class Location(object):
... __parent__ = None
>>> 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
>>> l = Location()
>>> l.__parent__ = b.c
>>> def checkContext(self, o):
... # Python equivalent to aq_inContextOf
... from Acquisition import aq_base, aq_parent, aq_inner
... next = self
... o = aq_base(o)
... while 1:
... if aq_base(next) is o:
... return 1
... self = aq_inner(next)
... if self is None:
... break
... next = aq_parent(self)
... if next is None:
... break
... return 0
>>> checkContext(b.c, b)
1
>>> not checkContext(b.c, b.a)
1
>>> checkContext(l, b)
1
>>> checkContext(l, b.c)
1
>>> not checkContext(l, b.a)
1
Acquisition.aq_inContextOf works the same way:
>>> Acquisition.aq_inContextOf(b.c, b)
1
>>> Acquisition.aq_inContextOf(b.c, b.a)
0
>>> Acquisition.aq_inContextOf(l, b)
1
>>> Acquisition.aq_inContextOf(l, b.c)
1
>>> Acquisition.aq_inContextOf(l, b.a)
0
>>> 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
>>> b.c.aq_inContextOf(foo)
0
>>> b.c.aq_inContextOf(b.a)
0
>>> b.a.aq_inContextOf('somestring')
0
"""
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: __init__() takes exactly 2 arguments (1 given)
We can reassign aq_parent / __parent__ on a wrapper:
>>> x = B()
>>> x.color = 'green'
>>> w.aq_parent = x
>>> w.color
'green'
>>> y = B()
>>> y.color = 'blue'
>>> w.__parent__ = y
>>> w.color
'blue'
Note that messing with the wrapper won't in any way affect the
wrapped object:
>>> Acquisition.aq_base(w).__parent__
Traceback (most recent call last):
...
AttributeError: __parent__
>>> w = ImplicitAcquisitionWrapper()
Traceback (most recent call last):
...
TypeError: __init__() takes exactly 2 arguments (0 given)
>>> w = ImplicitAcquisitionWrapper(obj=1)
Traceback (most recent call last):
...
TypeError: kwyword arguments not allowed
"""
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
test_z3interfaces
():
"""
>>> from zope.interface.verify import verifyClass
Explicit and Implicit implement IAcquirer:
>>> from Acquisition import Explicit
>>> from Acquisition import Implicit
>>> from Acquisition.interfaces import IAcquirer
>>> verifyClass(IAcquirer, Explicit)
True
>>> verifyClass(IAcquirer, Implicit)
True
ExplicitAcquisitionWrapper and ImplicitAcquisitionWrapper implement
IAcquisitionWrapper:
>>> from Acquisition import ExplicitAcquisitionWrapper
>>> from Acquisition import ImplicitAcquisitionWrapper
>>> from Acquisition.interfaces import IAcquisitionWrapper
>>> verifyClass(IAcquisitionWrapper, ExplicitAcquisitionWrapper)
True
>>> verifyClass(IAcquisitionWrapper, ImplicitAcquisitionWrapper)
True
"""
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
def
test_Basic_gc
():
"""Test to make sure that EC instances participate in GC
>>> from ExtensionClass import Base
>>> import gc
>>> thresholds = gc.get_threshold()
>>> gc.set_threshold(0)
>>> for B in I, E:
... class C1(B):
... pass
...
... class C2(Base):
... def __del__(self):
... print 'removed'
...
... a=C1('a')
... a.b = C1('a.b')
... a.b.a = a
... a.b.c = C2()
... ignore = gc.collect()
... del a
... removed = gc.collect()
... print removed > 0
removed
True
removed
True
>>> gc.set_threshold(*thresholds)
"""
def
test_Wrapper_gc
():
"""Test to make sure that EC instances participate in GC
>>> import gc
>>> thresholds = gc.get_threshold()
>>> gc.set_threshold(0)
>>> for B in I, E:
... class C:
... def __del__(self):
... print 'removed'
...
... a=B('a')
... a.b = B('b')
... a.a_b = a.b # circ ref through wrapper
... a.b.c = C()
... ignored = gc.collect()
... del a
... removed = gc.collect()
... removed > 0
removed
True
removed
True
>>> gc.set_threshold(*thresholds)
"""
def
test_proxying
():
"""Make sure that recent python slots are proxied.
>>> import Acquisition
>>> class Impl(Acquisition.Implicit):
... pass
>>> class C(Acquisition.Implicit):
... def __getitem__(self, key):
... print 'getitem', key
... if key == 4:
... raise IndexError
... return key
... def __contains__(self, key):
... print 'contains', repr(key)
... return key == 5
... def __iter__(self):
... print 'iterating...'
... return iter((42,))
The naked class behaves like this:
>>> c = C()
>>> 3 in c
contains 3
False
>>> 5 in c
contains 5
True
>>> list(c)
iterating...
[42]
Let's put c in the context of i:
>>> i = Impl()
>>> i.c = c
Now check that __contains__ is properly used:
>>> 3 in i.c # c.__of__(i)
contains 3
False
>>> 5 in i.c
contains 5
True
>>> list(i.c)
iterating...
[42]
Let's let's test the same again with an explicit wrapper:
>>> import Acquisition
>>> class Impl(Acquisition.Explicit):
... pass
>>> class C(Acquisition.Explicit):
... def __getitem__(self, key):
... print 'getitem', key
... if key == 4:
... raise IndexError
... return key
... def __contains__(self, key):
... print 'contains', repr(key)
... return key == 5
... def __iter__(self):
... print 'iterating...'
... return iter((42,))
The naked class behaves like this:
>>> c = C()
>>> 3 in c
contains 3
False
>>> 5 in c
contains 5
True
>>> list(c)
iterating...
[42]
Let's put c in the context of i:
>>> i = Impl()
>>> i.c = c
Now check that __contains__ is properly used:
>>> 3 in i.c # c.__of__(i)
contains 3
False
>>> 5 in i.c
contains 5
True
>>> list(i.c)
iterating...
[42]
"""
class
Location
(
object
):
__parent__
=
None
class
ECLocation
(
ExtensionClass
.
Base
):
__parent__
=
None
def
test___parent__no_wrappers
():
"""
Acquisition also works with objects that aren't wrappers, as long
as they have __parent__ pointers. Let's take a hierarchy like
z --isParent--> y --isParent--> x:
>>> x = Location()
>>> y = Location()
>>> z = Location()
>>> x.__parent__ = y
>>> y.__parent__ = z
and some attributes that we want to acquire:
>>> x.hello = 'world'
>>> y.foo = 42
>>> z.foo = 43 # this should not be found
>>> z.bar = 3.145
``aq_acquire`` works as we know it from implicit/acquisition
wrappers:
>>> Acquisition.aq_acquire(x, 'hello')
'world'
>>> Acquisition.aq_acquire(x, 'foo')
42
>>> Acquisition.aq_acquire(x, 'bar')
3.145
as does ``aq_get``:
>>> Acquisition.aq_get(x, 'hello')
'world'
>>> Acquisition.aq_get(x, 'foo')
42
>>> Acquisition.aq_get(x, 'bar')
3.145
and ``aq_parent``:
>>> Acquisition.aq_parent(x) is y
True
>>> Acquisition.aq_parent(y) is z
True
as well as ``aq_chain``:
>>> Acquisition.aq_chain(x) == [x, y, z]
True
"""
def
test_implicit_wrapper_as___parent__
():
"""
Let's do the same test again, only now not all objects are of the
same kind and link to each other via __parent__ pointers. The
root is a stupid ExtensionClass object:
>>> class Root(ExtensionClass.Base):
... bar = 3.145
>>> z = Root()
The intermediate parent is an object that supports implicit
acquisition. We bind it to the root via the __of__ protocol:
>>> class Impl(Acquisition.Implicit):
... foo = 42
>>> y = Impl().__of__(z)
The child object is again a simple object with a simple __parent__
pointer:
>>> x = Location()
>>> x.hello = 'world'
>>> x.__parent__ = y
``aq_acquire`` works as expected from implicit/acquisition
wrappers:
>>> Acquisition.aq_acquire(x, 'hello')
'world'
>>> Acquisition.aq_acquire(x, 'foo')
42
>>> Acquisition.aq_acquire(x, 'bar')
3.145
as does ``aq_get``:
>>> Acquisition.aq_get(x, 'hello')
'world'
>>> Acquisition.aq_get(x, 'foo')
42
>>> Acquisition.aq_get(x, 'bar')
3.145
and ``aq_parent``:
>>> Acquisition.aq_parent(x) is y
True
>>> Acquisition.aq_parent(y) is z
True
as well as ``aq_chain``:
>>> Acquisition.aq_chain(x) == [x, y, z]
True
Note that also the (implicit) acquisition wrapper has a __parent__
pointer, which is automatically computed from the acquisition
container (it's identical to aq_parent):
>>> y.__parent__ is z
True
Just as much as you can assign to aq_parent, you can also assign
to __parent__ to change the acquisition context of the wrapper:
>>> newroot = Root()
>>> y.__parent__ = newroot
>>> y.__parent__ is z
False
>>> y.__parent__ is newroot
True
Note that messing with the wrapper won't in any way affect the
wrapped object:
>>> Acquisition.aq_base(y).__parent__
Traceback (most recent call last):
...
AttributeError: __parent__
"""
def
test_explicit_wrapper_as___parent__
():
"""
Let's do this test yet another time, with an explicit wrapper:
>>> class Root(ExtensionClass.Base):
... bar = 3.145
>>> z = Root()
The intermediate parent is an object that supports implicit
acquisition. We bind it to the root via the __of__ protocol:
>>> class Expl(Acquisition.Explicit):
... foo = 42
>>> y = Expl().__of__(z)
The child object is again a simple object with a simple __parent__
pointer:
>>> x = Location()
>>> x.hello = 'world'
>>> x.__parent__ = y
``aq_acquire`` works as expected from implicit/acquisition
wrappers:
>>> Acquisition.aq_acquire(x, 'hello')
'world'
>>> Acquisition.aq_acquire(x, 'foo')
42
>>> Acquisition.aq_acquire(x, 'bar')
3.145
as does ``aq_get``:
>>> Acquisition.aq_get(x, 'hello')
'world'
>>> Acquisition.aq_get(x, 'foo')
42
>>> Acquisition.aq_get(x, 'bar')
3.145
and ``aq_parent``:
>>> Acquisition.aq_parent(x) is y
True
>>> Acquisition.aq_parent(y) is z
True
as well as ``aq_chain``:
>>> Acquisition.aq_chain(x) == [x, y, z]
True
Note that also the (explicit) acquisition wrapper has a __parent__
pointer, which is automatically computed from the acquisition
container (it's identical to aq_parent):
>>> y.__parent__ is z
True
Just as much as you can assign to aq_parent, you can also assign
to __parent__ to change the acquisition context of the wrapper:
>>> newroot = Root()
>>> y.__parent__ = newroot
>>> y.__parent__ is z
False
>>> y.__parent__ is newroot
True
Note that messing with the wrapper won't in any way affect the
wrapped object:
>>> Acquisition.aq_base(y).__parent__
Traceback (most recent call last):
...
AttributeError: __parent__
"""
def
test_implicit_wrapper_has_nonwrapper_as_aq_parent
():
"""Let's do this the other way around: The root and the
intermediate parent is an object that doesn't support acquisition,
>>> y = ECLocation()
>>> z = Location()
>>> y.__parent__ = z
>>> y.foo = 42
>>> z.foo = 43 # this should not be found
>>> z.bar = 3.145
only the outmost object does:
>>> class Impl(Acquisition.Implicit):
... hello = 'world'
>>> x = Impl().__of__(y)
Again, acquiring objects works as usual:
>>> Acquisition.aq_acquire(x, 'hello')
'world'
>>> Acquisition.aq_acquire(x, 'foo')
42
>>> Acquisition.aq_acquire(x, 'bar')
3.145
as does ``aq_get``:
>>> Acquisition.aq_get(x, 'hello')
'world'
>>> Acquisition.aq_get(x, 'foo')
42
>>> Acquisition.aq_get(x, 'bar')
3.145
and ``aq_parent``:
>>> Acquisition.aq_parent(x) == y
True
>>> x.aq_parent == y
True
>>> x.aq_parent.aq_parent == z
True
>>> Acquisition.aq_parent(y) is z
True
as well as ``aq_chain``:
>>> Acquisition.aq_chain(x) == [x, y, z]
True
>>> x.aq_chain == [x, y, z]
True
Because the outmost object, ``x``, is wrapped in an implicit
acquisition wrapper, we can also use direct attribute access:
>>> x.hello
'world'
>>> x.foo
42
>>> x.bar
3.145
"""
def
test_explicit_wrapper_has_nonwrapper_as_aq_parent
():
"""Let's do this the other way around: The root and the
intermediate parent is an object that doesn't support acquisition,
>>> y = ECLocation()
>>> z = Location()
>>> y.__parent__ = z
>>> y.foo = 42
>>> z.foo = 43 # this should not be found
>>> z.bar = 3.145
only the outmost object does:
>>> class Expl(Acquisition.Explicit):
... hello = 'world'
>>> x = Expl().__of__(y)
Again, acquiring objects works as usual:
>>> Acquisition.aq_acquire(x, 'hello')
'world'
>>> Acquisition.aq_acquire(x, 'foo')
42
>>> Acquisition.aq_acquire(x, 'bar')
3.145
as does ``aq_get``:
>>> Acquisition.aq_get(x, 'hello')
'world'
>>> Acquisition.aq_get(x, 'foo')
42
>>> Acquisition.aq_get(x, 'bar')
3.145
and ``aq_parent``:
>>> Acquisition.aq_parent(x) == y
True
>>> x.aq_parent == y
True
>>> x.aq_parent.aq_parent == z
True
>>> Acquisition.aq_parent(y) is z
True
as well as ``aq_chain``:
>>> Acquisition.aq_chain(x) == [x, y, z]
True
>>> x.aq_chain == [x, y, z]
True
"""
def
test___parent__aq_parent_circles
():
"""
As a general safety belt, Acquisition won't follow a mixture of
circular __parent__ pointers and aq_parent wrappers. These can
occurr when code that uses implicit acquisition wrappers meets
code that uses __parent__ pointers.
>>> class Impl(Acquisition.Implicit):
... hello = 'world'
>>> class Impl2(Acquisition.Implicit):
... hello = 'world2'
... only = 'here'
>>> x = Impl()
>>> y = Impl2().__of__(x)
>>> x.__parent__ = y
>>> x.__parent__.aq_base is y.aq_base
True
>>> x.__parent__.__parent__ is x
True
>>> x.hello
'world'
>>> Acquisition.aq_acquire(x, 'hello')
'world'
>>> x.only
Traceback (most recent call last):
...
AttributeError: only
>>> Acquisition.aq_acquire(x, 'only')
'here'
>>> Acquisition.aq_acquire(x, 'non_existant_attr')
Traceback (most recent call last):
...
AttributeError: non_existant_attr
>>> Acquisition.aq_acquire(y, 'non_existant_attr')
Traceback (most recent call last):
...
AttributeError: non_existant_attr
>>> x.non_existant_attr
Traceback (most recent call last):
...
AttributeError: non_existant_attr
>>> y.non_existant_attr
Traceback (most recent call last):
...
AttributeError: non_existant_attr
"""
def
test___parent__parent__circles
():
"""
Acquisition won't follow circular __parent__ references:
>>> class Impl(Acquisition.Implicit):
... hello = 'world'
>>> class Impl2(Acquisition.Implicit):
... hello = 'world2'
... only = 'here'
>>> x = Impl()
>>> y = Impl2()
>>> x.__parent__ = y
>>> y.__parent__ = x
>>> x.__parent__.__parent__ is x
True
>>> Acquisition.aq_acquire(x, 'hello')
'world'
>>> Acquisition.aq_acquire(x, 'only')
'here'
>>> Acquisition.aq_acquire(x, 'non_existant_attr')
Traceback (most recent call last):
...
AttributeError: non_existant_attr
>>> Acquisition.aq_acquire(y, 'non_existant_attr')
Traceback (most recent call last):
...
AttributeError: non_existant_attr
"""
import
unittest
from
zope.testing.doctest
import
DocTestSuite
,
DocFileSuite
def
test_suite
():
return
unittest
.
TestSuite
((
DocTestSuite
(),
DocFileSuite
(
'README.txt'
,
package
=
'Acquisition'
),
))
if
__name__
==
'__main__'
:
unittest
.
main
(
defaultTest
=
'test_suite'
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment