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
771f7677
Commit
771f7677
authored
Nov 28, 2003
by
Jim Fulton
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
New implementation of Acquisition using new-style extension classes.
parent
2ca62e1a
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
3167 additions
and
0 deletions
+3167
-0
lib/python/Acquisition/Acquisition.h
lib/python/Acquisition/Acquisition.h
+60
-0
lib/python/Acquisition/_Acquisition.c
lib/python/Acquisition/_Acquisition.c
+1573
-0
lib/python/Acquisition/__init__.py
lib/python/Acquisition/__init__.py
+1
-0
lib/python/Acquisition/setup.py
lib/python/Acquisition/setup.py
+23
-0
lib/python/Acquisition/tests.py
lib/python/Acquisition/tests.py
+1510
-0
No files found.
lib/python/Acquisition/Acquisition.h
0 → 100644
View file @
771f7677
/*****************************************************************************
Copyright (c) 1996-2002 Zope Corporation and Contributors.
All Rights Reserved.
This software is subject to the provisions of the Zope Public License,
Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
FOR A PARTICULAR PURPOSE
****************************************************************************/
#ifndef __ACQUISITION_H_
#define __ACQUISITION_H_
typedef
struct
{
PyObject
*
(
*
AQ_Acquire
)
(
PyObject
*
obj
,
PyObject
*
name
,
PyObject
*
filter
,
PyObject
*
extra
,
int
explicit
,
PyObject
*
deflt
,
int
containment
);
PyObject
*
(
*
AQ_Get
)
(
PyObject
*
obj
,
PyObject
*
name
,
PyObject
*
deflt
,
int
containment
);
int
(
*
AQ_IsWrapper
)
(
PyObject
*
obj
);
PyObject
*
(
*
AQ_Base
)
(
PyObject
*
obj
);
PyObject
*
(
*
AQ_Parent
)
(
PyObject
*
obj
);
PyObject
*
(
*
AQ_Self
)
(
PyObject
*
obj
);
PyObject
*
(
*
AQ_Inner
)
(
PyObject
*
obj
);
PyObject
*
(
*
AQ_Chain
)
(
PyObject
*
obj
,
int
containment
);
}
ACQUISITIONCAPI
;
#ifndef _IN_ACQUISITION_C
#define aq_Acquire(obj, name, filter, extra, explicit, deflt, containment ) (AcquisitionCAPI == NULL ? NULL : (AcquisitionCAPI->AQ_Acquire(obj, name, filter, extra, explicit, deflt, containment)))
#define aq_acquire(obj, name) (AcquisitionCAPI == NULL ? NULL : (AcquisitionCAPI->AQ_Acquire(obj, name, NULL, NULL, 1, NULL, 0)))
#define aq_get(obj, name, deflt, containment) (AcquistionCAPI == NULL ? NULL : (AcquisitionCAPI->AQ_Get(obj, name, deflt, containment)))
#define aq_isWrapper(obj) (AcquisitionCAPI == NULL ? -1 : (AcquisitionCAPI->AQ_IsWrapper(obj)))
#define aq_base(obj) (AcquisitionCAPI == NULL ? NULL : (AcquisitionCAPI->AQ_Base(obj)))
#define aq_parent(obj) (AcquisitionCAPI == NULL ? NULL : (AcquisitionCAPI->AQ_Parent(obj)))
#define aq_self(obj) (AcquisitionCAPI == NULL ? NULL : (AcquisitionCAPI->AQ_Self(obj)))
#define aq_inner(obj) (AcquisitionCAPI == NULL ? NULL : (AcquisitionCAPI->AQ_Inner(obj)))
#define aq_chain(obj, containment) (AcquisitionCAPI == NULL ? NULL : (AcquisitionCAPI->AQ_CHain(obj, containment)))
static
ACQUISITIONCAPI
*
AcquisitionCAPI
=
NULL
;
#define aq_init() { \
PyObject *module; \
PyObject *api; \
if (! (module = PyImport_ImportModule("Acquisition"))) return; \
if (! (api = PyObject_GetAttrString(module,"AcquisitionCAPI"))) return; \
Py_DECREF(module); \
AcquisitionCAPI = PyCObject_AsVoidPtr(api); \
Py_DECREF(api); \
}
#endif
#endif
lib/python/Acquisition/_Acquisition.c
0 → 100644
View file @
771f7677
/*****************************************************************************
Copyright (c) 1996-2003 Zope Corporation and Contributors.
All Rights Reserved.
This software is subject to the provisions of the Zope Public License,
Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
FOR A PARTICULAR PURPOSE
****************************************************************************/
#include "ExtensionClass.h"
#define _IN_ACQUISITION_C
#include "Acquisition.h"
static
ACQUISITIONCAPI
AcquisitionCAPI
;
static
void
PyVar_Assign
(
PyObject
**
v
,
PyObject
*
e
)
{
Py_XDECREF
(
*
v
);
*
v
=
e
;
}
#define ASSIGN(V,E) PyVar_Assign(&(V),(E))
#define UNLESS(E) if (!(E))
#define UNLESS_ASSIGN(V,E) ASSIGN(V,E); UNLESS(V)
#define OBJECT(O) ((PyObject*)(O))
static
PyObject
*
py__add__
,
*
py__sub__
,
*
py__mul__
,
*
py__div__
,
*
py__mod__
,
*
py__pow__
,
*
py__divmod__
,
*
py__lshift__
,
*
py__rshift__
,
*
py__and__
,
*
py__or__
,
*
py__xor__
,
*
py__coerce__
,
*
py__neg__
,
*
py__pos__
,
*
py__abs__
,
*
py__nonzero__
,
*
py__invert__
,
*
py__int__
,
*
py__long__
,
*
py__float__
,
*
py__oct__
,
*
py__hex__
,
*
py__getitem__
,
*
py__setitem__
,
*
py__delitem__
,
*
py__getslice__
,
*
py__setslice__
,
*
py__delslice__
,
*
py__len__
,
*
py__of__
,
*
py__call__
,
*
py__repr__
,
*
py__str__
,
*
py__cmp__
;
static
PyObject
*
Acquired
=
0
;
static
void
init_py_names
(
void
)
{
#define INIT_PY_NAME(N) py ## N = PyString_FromString(#N)
INIT_PY_NAME
(
__add__
);
INIT_PY_NAME
(
__sub__
);
INIT_PY_NAME
(
__mul__
);
INIT_PY_NAME
(
__div__
);
INIT_PY_NAME
(
__mod__
);
INIT_PY_NAME
(
__pow__
);
INIT_PY_NAME
(
__divmod__
);
INIT_PY_NAME
(
__lshift__
);
INIT_PY_NAME
(
__rshift__
);
INIT_PY_NAME
(
__and__
);
INIT_PY_NAME
(
__or__
);
INIT_PY_NAME
(
__xor__
);
INIT_PY_NAME
(
__coerce__
);
INIT_PY_NAME
(
__neg__
);
INIT_PY_NAME
(
__pos__
);
INIT_PY_NAME
(
__abs__
);
INIT_PY_NAME
(
__nonzero__
);
INIT_PY_NAME
(
__invert__
);
INIT_PY_NAME
(
__int__
);
INIT_PY_NAME
(
__long__
);
INIT_PY_NAME
(
__float__
);
INIT_PY_NAME
(
__oct__
);
INIT_PY_NAME
(
__hex__
);
INIT_PY_NAME
(
__getitem__
);
INIT_PY_NAME
(
__setitem__
);
INIT_PY_NAME
(
__delitem__
);
INIT_PY_NAME
(
__getslice__
);
INIT_PY_NAME
(
__setslice__
);
INIT_PY_NAME
(
__delslice__
);
INIT_PY_NAME
(
__len__
);
INIT_PY_NAME
(
__of__
);
INIT_PY_NAME
(
__call__
);
INIT_PY_NAME
(
__repr__
);
INIT_PY_NAME
(
__str__
);
INIT_PY_NAME
(
__cmp__
);
#undef INIT_PY_NAME
}
static
PyObject
*
CallMethodO
(
PyObject
*
self
,
PyObject
*
name
,
PyObject
*
args
,
PyObject
*
kw
)
{
if
(
!
args
&&
PyErr_Occurred
())
return
NULL
;
UNLESS
(
name
=
PyObject_GetAttr
(
self
,
name
))
{
if
(
args
)
{
Py_DECREF
(
args
);
}
return
NULL
;
}
ASSIGN
(
name
,
PyEval_CallObjectWithKeywords
(
name
,
args
,
kw
));
if
(
args
)
{
Py_DECREF
(
args
);
}
return
name
;
}
#define Build Py_BuildValue
/* Declarations for objects of type Wrapper */
typedef
struct
{
PyObject_HEAD
PyObject
*
obj
;
PyObject
*
container
;
}
Wrapper
;
staticforward
PyExtensionClass
Wrappertype
,
XaqWrappertype
;
#define isWrapper(O) ((O)->ob_type==(PyTypeObject*)&Wrappertype || \
(O)->ob_type==(PyTypeObject*)&XaqWrappertype)
#define WRAPPER(O) ((Wrapper*)(O))
static
PyObject
*
Wrapper__init__
(
Wrapper
*
self
,
PyObject
*
args
)
{
PyObject
*
obj
,
*
container
;
UNLESS
(
PyArg_Parse
(
args
,
"(OO)"
,
&
obj
,
&
container
))
return
NULL
;
if
(
self
==
WRAPPER
(
obj
))
{
PyErr_SetString
(
PyExc_ValueError
,
"Cannot wrap acquisition wrapper in itself (Wrapper__init__)"
);
return
NULL
;
}
Py_INCREF
(
obj
);
Py_INCREF
(
container
);
self
->
obj
=
obj
;
self
->
container
=
container
;
Py_INCREF
(
Py_None
);
return
Py_None
;
}
/* ---------------------------------------------------------------- */
static
PyObject
*
__of__
(
PyObject
*
inst
,
PyObject
*
parent
)
{
PyObject
*
r
,
*
t
;
UNLESS
(
r
=
PyObject_GetAttr
(
inst
,
py__of__
))
return
NULL
;
UNLESS
(
t
=
PyTuple_New
(
1
))
goto
err
;
PyTuple_SET_ITEM
(
t
,
0
,
parent
);
ASSIGN
(
r
,
PyObject_CallObject
(
r
,
t
));
PyTuple_SET_ITEM
(
t
,
0
,
NULL
);
Py_DECREF
(
t
);
if
(
r
&&
r
->
ob_refcnt
==
1
&&
isWrapper
(
r
)
&&
WRAPPER
(
r
)
->
container
&&
isWrapper
(
WRAPPER
(
r
)
->
container
)
)
while
(
WRAPPER
(
r
)
->
obj
&&
isWrapper
(
WRAPPER
(
r
)
->
obj
)
&&
(
WRAPPER
(
WRAPPER
(
r
)
->
obj
)
->
container
==
WRAPPER
(
WRAPPER
(
r
)
->
container
)
->
obj
)
)
{
/* Simplify wrapper */
Py_XINCREF
(
WRAPPER
(
WRAPPER
(
r
)
->
obj
)
->
obj
);
ASSIGN
(
WRAPPER
(
r
)
->
obj
,
WRAPPER
(
WRAPPER
(
r
)
->
obj
)
->
obj
);
}
return
r
;
err:
Py_DECREF
(
r
);
return
NULL
;
}
static
Wrapper
*
freeWrappers
=
0
;
static
int
nWrappers
=
0
;
#define MAX_CACHED_WRAPPERS 200
static
PyObject
*
newWrapper
(
PyObject
*
obj
,
PyObject
*
container
,
PyTypeObject
*
Wrappertype
)
{
Wrapper
*
self
;
if
(
freeWrappers
)
{
self
=
freeWrappers
;
freeWrappers
=
(
Wrapper
*
)
self
->
obj
;
_Py_NewReference
((
PyObject
*
)
self
);
assert
(
self
->
ob_refcnt
==
1
);
self
->
ob_type
=
Wrappertype
;
nWrappers
--
;
}
else
{
UNLESS
(
self
=
PyObject_NEW
(
Wrapper
,
Wrappertype
))
return
NULL
;
}
if
(
self
==
WRAPPER
(
obj
))
{
PyErr_SetString
(
PyExc_ValueError
,
"Cannot wrap acquisition wrapper in itself (newWrapper)"
);
Py_DECREF
(
self
);
return
NULL
;
}
Py_INCREF
(
Wrappertype
);
Py_XINCREF
(
obj
);
Py_XINCREF
(
container
);
self
->
obj
=
obj
;
self
->
container
=
container
;
return
OBJECT
(
self
);
}
static
void
Wrapper_dealloc
(
Wrapper
*
self
)
{
Py_XDECREF
(
self
->
obj
);
Py_XDECREF
(
self
->
container
);
Py_DECREF
(
self
->
ob_type
);
if
(
nWrappers
<
MAX_CACHED_WRAPPERS
)
{
self
->
obj
=
OBJECT
(
freeWrappers
);
freeWrappers
=
self
;
nWrappers
++
;
}
else
{
PyObject_DEL
(
self
);
}
}
static
PyObject
*
Wrapper_special
(
Wrapper
*
self
,
char
*
name
,
PyObject
*
oname
)
{
PyObject
*
r
=
0
;
switch
(
*
name
)
{
case
'b'
:
if
(
strcmp
(
name
,
"base"
)
==
0
)
{
if
(
self
->
obj
)
{
r
=
self
->
obj
;
while
(
isWrapper
(
r
)
&&
WRAPPER
(
r
)
->
obj
)
r
=
WRAPPER
(
r
)
->
obj
;
}
else
r
=
Py_None
;
Py_INCREF
(
r
);
return
r
;
}
break
;
case
'p'
:
if
(
strcmp
(
name
,
"parent"
)
==
0
)
{
if
(
self
->
container
)
r
=
self
->
container
;
else
r
=
Py_None
;
Py_INCREF
(
r
);
return
r
;
}
break
;
case
's'
:
if
(
strcmp
(
name
,
"self"
)
==
0
)
{
if
(
self
->
obj
)
r
=
self
->
obj
;
else
r
=
Py_None
;
Py_INCREF
(
r
);
return
r
;
}
break
;
case
'e'
:
if
(
strcmp
(
name
,
"explicit"
)
==
0
)
{
if
(
self
->
ob_type
!=
(
PyTypeObject
*
)
&
XaqWrappertype
)
return
newWrapper
(
self
->
obj
,
self
->
container
,
(
PyTypeObject
*
)
&
XaqWrappertype
);
Py_INCREF
(
self
);
return
OBJECT
(
self
);
}
break
;
case
'a'
:
if
(
strcmp
(
name
,
"acquire"
)
==
0
)
{
return
Py_FindAttr
(
OBJECT
(
self
),
oname
);
}
break
;
case
'c'
:
if
(
strcmp
(
name
,
"chain"
)
==
0
)
{
if
((
r
=
PyList_New
(
0
)))
while
(
1
)
{
if
(
PyList_Append
(
r
,
OBJECT
(
self
))
>=
0
)
{
if
(
isWrapper
(
self
)
&&
self
->
container
)
{
self
=
WRAPPER
(
self
->
container
);
continue
;
}
}
else
{
Py_DECREF
(
r
);
}
break
;
}
return
r
;
}
break
;
case
'i'
:
if
(
strcmp
(
name
,
"inContextOf"
)
==
0
)
{
return
Py_FindAttr
(
OBJECT
(
self
),
oname
);
}
if
(
strcmp
(
name
,
"inner"
)
==
0
)
{
if
(
self
->
obj
)
{
r
=
self
->
obj
;
while
(
isWrapper
(
r
)
&&
WRAPPER
(
r
)
->
obj
)
{
self
=
WRAPPER
(
r
);
r
=
WRAPPER
(
r
)
->
obj
;
}
r
=
OBJECT
(
self
);
}
else
r
=
Py_None
;
Py_INCREF
(
r
);
return
r
;
}
break
;
case
'u'
:
if
(
strcmp
(
name
,
"uncle"
)
==
0
)
{
return
PyString_FromString
(
"Bob"
);
}
break
;
}
return
NULL
;
}
static
int
apply_filter
(
PyObject
*
filter
,
PyObject
*
inst
,
PyObject
*
oname
,
PyObject
*
r
,
PyObject
*
extra
,
PyObject
*
orig
)
{
/* Calls the filter, passing arguments.
Returns 1 if the filter accepts the value, 0 if not, -1 if an
exception occurred.
Note the special reference counting rule: This function decrements
the refcount of 'r' when it returns 0 or -1. When it returns 1, it
leaves the refcount unchanged.
*/
PyObject
*
fr
;
int
ir
;
UNLESS
(
fr
=
PyTuple_New
(
5
))
goto
err
;
PyTuple_SET_ITEM
(
fr
,
0
,
orig
);
Py_INCREF
(
orig
);
PyTuple_SET_ITEM
(
fr
,
1
,
inst
);
Py_INCREF
(
inst
);
PyTuple_SET_ITEM
(
fr
,
2
,
oname
);
Py_INCREF
(
oname
);
PyTuple_SET_ITEM
(
fr
,
3
,
r
);
Py_INCREF
(
r
);
PyTuple_SET_ITEM
(
fr
,
4
,
extra
);
Py_INCREF
(
extra
);
UNLESS_ASSIGN
(
fr
,
PyObject_CallObject
(
filter
,
fr
))
goto
err
;
ir
=
PyObject_IsTrue
(
fr
);
Py_DECREF
(
fr
);
if
(
ir
)
return
1
;
Py_DECREF
(
r
);
return
0
;
err:
Py_DECREF
(
r
);
return
-
1
;
}
static
PyObject
*
Wrapper_acquire
(
Wrapper
*
self
,
PyObject
*
oname
,
PyObject
*
filter
,
PyObject
*
extra
,
PyObject
*
orig
,
int
explicit
,
int
containment
);
static
PyObject
*
Wrapper_findattr
(
Wrapper
*
self
,
PyObject
*
oname
,
PyObject
*
filter
,
PyObject
*
extra
,
PyObject
*
orig
,
int
sob
,
int
sco
,
int
explicit
,
int
containment
)
{
PyObject
*
r
,
*
v
,
*
tb
;
char
*
name
=
""
;
if
(
PyString_Check
(
oname
))
name
=
PyString_AS_STRING
(
oname
);
if
(
*
name
==
'a'
&&
name
[
1
]
==
'q'
&&
name
[
2
]
==
'_'
)
if
((
r
=
Wrapper_special
(
self
,
name
+
3
,
oname
)))
{
if
(
filter
)
switch
(
apply_filter
(
filter
,
OBJECT
(
self
),
oname
,
r
,
extra
,
orig
))
{
case
-
1
:
return
NULL
;
case
1
:
return
r
;
}
else
return
r
;
}
else
PyErr_Clear
();
else
if
(
*
name
==
'_'
&&
name
[
1
]
==
'_'
&&
(
strcmp
(
name
+
2
,
"reduce__"
)
==
0
||
strcmp
(
name
+
2
,
"reduce_ex__"
)
==
0
||
strcmp
(
name
+
2
,
"getstate__"
)
==
0
))
return
PyObject_GenericGetAttr
(((
PyObject
*
)
self
),
oname
);
/* If we are doing a containment search, then replace self with aq_inner */
if
(
containment
)
while
(
self
->
obj
&&
isWrapper
(
self
->
obj
))
self
=
WRAPPER
(
self
->
obj
);
if
(
sob
&&
self
->
obj
)
{
if
(
isWrapper
(
self
->
obj
))
{
if
(
self
==
WRAPPER
(
self
->
obj
))
{
PyErr_SetString
(
PyExc_RuntimeError
,
"Recursion detected in acquisition wrapper"
);
return
NULL
;
}
if
((
r
=
Wrapper_findattr
(
WRAPPER
(
self
->
obj
),
oname
,
filter
,
extra
,
orig
,
1
,
/* Search object container if explicit,
or object is implicit acquirer */
explicit
||
self
->
obj
->
ob_type
==
(
PyTypeObject
*
)
&
Wrappertype
,
explicit
,
containment
)))
{
if
(
PyECMethod_Check
(
r
)
&&
PyECMethod_Self
(
r
)
==
self
->
obj
)
ASSIGN
(
r
,
PyECMethod_New
(
r
,
OBJECT
(
self
)));
else
if
(
has__of__
(
r
))
ASSIGN
(
r
,
__of__
(
r
,
OBJECT
(
self
)));
return
r
;
}
PyErr_Fetch
(
&
r
,
&
v
,
&
tb
);
if
(
r
&&
(
r
!=
PyExc_AttributeError
))
{
PyErr_Restore
(
r
,
v
,
tb
);
return
NULL
;
}
Py_XDECREF
(
r
);
Py_XDECREF
(
v
);
Py_XDECREF
(
tb
);
r
=
NULL
;
}
else
if
((
r
=
PyObject_GetAttr
(
self
->
obj
,
oname
)))
{
if
(
r
==
Acquired
)
{
Py_DECREF
(
r
);
return
Wrapper_acquire
(
self
,
oname
,
filter
,
extra
,
orig
,
1
,
containment
);
}
if
(
PyECMethod_Check
(
r
)
&&
PyECMethod_Self
(
r
)
==
self
->
obj
)
ASSIGN
(
r
,
PyECMethod_New
(
r
,
OBJECT
(
self
)));
else
if
(
has__of__
(
r
))
ASSIGN
(
r
,
__of__
(
r
,
OBJECT
(
self
)));
if
(
filter
)
switch
(
apply_filter
(
filter
,
OBJECT
(
self
),
oname
,
r
,
extra
,
orig
))
{
case
-
1
:
return
NULL
;
case
1
:
return
r
;
}
else
return
r
;
}
else
{
PyErr_Fetch
(
&
r
,
&
v
,
&
tb
);
if
(
r
!=
PyExc_AttributeError
)
{
PyErr_Restore
(
r
,
v
,
tb
);
return
NULL
;
}
Py_XDECREF
(
r
);
Py_XDECREF
(
v
);
Py_XDECREF
(
tb
);
r
=
NULL
;
}
PyErr_Clear
();
}
if
(
sco
&&
(
*
name
!=
'_'
||
explicit
))
return
Wrapper_acquire
(
self
,
oname
,
filter
,
extra
,
orig
,
explicit
,
containment
);
PyErr_SetObject
(
PyExc_AttributeError
,
oname
);
return
NULL
;
}
static
PyObject
*
Wrapper_acquire
(
Wrapper
*
self
,
PyObject
*
oname
,
PyObject
*
filter
,
PyObject
*
extra
,
PyObject
*
orig
,
int
explicit
,
int
containment
)
{
PyObject
*
r
;
int
sob
=
1
,
sco
=
1
;
if
(
self
->
container
)
{
if
(
isWrapper
(
self
->
container
))
{
if
(
self
->
obj
&&
isWrapper
(
self
->
obj
))
{
/* Try to optimize search by recognizing repeated obs in path */
if
(
WRAPPER
(
self
->
obj
)
->
container
==
WRAPPER
(
self
->
container
)
->
container
)
sco
=
0
;
else
if
(
WRAPPER
(
self
->
obj
)
->
container
==
WRAPPER
(
self
->
container
)
->
obj
)
sob
=
0
;
}
r
=
Wrapper_findattr
((
Wrapper
*
)
self
->
container
,
oname
,
filter
,
extra
,
orig
,
sob
,
sco
,
explicit
,
containment
);
if
(
r
&&
has__of__
(
r
))
ASSIGN
(
r
,
__of__
(
r
,
OBJECT
(
self
)));
return
r
;
}
else
{
if
((
r
=
PyObject_GetAttr
(
self
->
container
,
oname
)))
{
if
(
r
==
Acquired
)
{
Py_DECREF
(
r
);
}
else
{
if
(
filter
)
{
switch
(
apply_filter
(
filter
,
self
->
container
,
oname
,
r
,
extra
,
orig
))
{
case
-
1
:
return
NULL
;
case
1
:
if
(
has__of__
(
r
))
ASSIGN
(
r
,
__of__
(
r
,
OBJECT
(
self
)));
return
r
;
}
}
else
{
if
(
has__of__
(
r
))
ASSIGN
(
r
,
__of__
(
r
,
OBJECT
(
self
)));
return
r
;
}
}
}
else
{
/* May be AttributeError or some other kind of error */
return
NULL
;
}
}
}
PyErr_SetObject
(
PyExc_AttributeError
,
oname
);
return
NULL
;
}
static
PyObject
*
Wrapper_getattro
(
Wrapper
*
self
,
PyObject
*
oname
)
{
if
(
self
->
obj
||
self
->
container
)
return
Wrapper_findattr
(
self
,
oname
,
NULL
,
NULL
,
NULL
,
1
,
1
,
0
,
0
);
/* Maybe we are getting initialized? */
return
Py_FindAttr
(
OBJECT
(
self
),
oname
);
}
static
PyObject
*
Xaq_getattro
(
Wrapper
*
self
,
PyObject
*
oname
)
{
char
*
name
=
""
;
/* Special case backward-compatible acquire method. */
if
(
PyString_Check
(
oname
))
name
=
PyString_AS_STRING
(
oname
);
if
(
*
name
==
'a'
&&
name
[
1
]
==
'c'
&&
strcmp
(
name
+
2
,
"quire"
)
==
0
)
return
Py_FindAttr
(
OBJECT
(
self
),
oname
);
if
(
self
->
obj
||
self
->
container
)
return
Wrapper_findattr
(
self
,
oname
,
NULL
,
NULL
,
NULL
,
1
,
0
,
0
,
0
);
/* Maybe we are getting initialized? */
return
Py_FindAttr
(
OBJECT
(
self
),
oname
);
}
static
int
Wrapper_setattro
(
Wrapper
*
self
,
PyObject
*
oname
,
PyObject
*
v
)
{
char
*
name
=
""
;
/* Allow assignment to parent, to change context. */
if
(
PyString_Check
(
oname
))
name
=
PyString_AS_STRING
(
oname
);
if
(
*
name
==
'a'
&&
name
[
1
]
==
'q'
&&
name
[
2
]
==
'_'
&&
strcmp
(
name
+
3
,
"parent"
)
==
0
)
{
Py_XINCREF
(
v
);
ASSIGN
(
self
->
container
,
v
);
return
0
;
}
if
(
self
->
obj
)
{
/* Unwrap passed in wrappers! */
while
(
v
&&
isWrapper
(
v
))
v
=
WRAPPER
(
v
)
->
obj
;
if
(
v
)
return
PyObject_SetAttr
(
self
->
obj
,
oname
,
v
);
else
return
PyObject_DelAttr
(
self
->
obj
,
oname
);
}
PyErr_SetString
(
PyExc_AttributeError
,
"Attempt to set attribute on empty acquisition wrapper"
);
return
-
1
;
}
static
int
Wrapper_compare
(
Wrapper
*
self
,
PyObject
*
w
)
{
PyObject
*
obj
,
*
wobj
;
PyObject
*
m
;
int
r
;
if
(
OBJECT
(
self
)
==
w
)
return
0
;
UNLESS
(
m
=
PyObject_GetAttr
(
OBJECT
(
self
),
py__cmp__
))
{
/* Unwrap self completely -> obj. */
while
(
self
->
obj
&&
isWrapper
(
self
->
obj
))
self
=
WRAPPER
(
self
->
obj
);
obj
=
self
->
obj
;
/* Unwrap w completely -> wobj. */
if
(
isWrapper
(
w
))
{
while
(
WRAPPER
(
w
)
->
obj
&&
isWrapper
(
WRAPPER
(
w
)
->
obj
))
w
=
WRAPPER
(
w
)
->
obj
;
wobj
=
WRAPPER
(
w
)
->
obj
;
}
else
wobj
=
w
;
PyErr_Clear
();
if
(
obj
==
wobj
)
return
0
;
return
(
obj
<
w
)
?
-
1
:
1
;
}
ASSIGN
(
m
,
PyObject_CallFunction
(
m
,
"O"
,
w
));
UNLESS
(
m
)
return
-
1
;
r
=
PyInt_AsLong
(
m
);
Py_DECREF
(
m
);
return
r
;
}
static
PyObject
*
Wrapper_repr
(
Wrapper
*
self
)
{
PyObject
*
r
;
if
((
r
=
PyObject_GetAttr
(
OBJECT
(
self
),
py__repr__
)))
{
ASSIGN
(
r
,
PyObject_CallFunction
(
r
,
NULL
,
NULL
));
return
r
;
}
else
{
PyErr_Clear
();
return
PyObject_Repr
(
self
->
obj
);
}
}
static
PyObject
*
Wrapper_str
(
Wrapper
*
self
)
{
PyObject
*
r
;
if
((
r
=
PyObject_GetAttr
(
OBJECT
(
self
),
py__str__
)))
{
ASSIGN
(
r
,
PyObject_CallFunction
(
r
,
NULL
,
NULL
));
return
r
;
}
else
{
PyErr_Clear
();
return
PyObject_Str
(
self
->
obj
);
}
}
static
long
Wrapper_hash
(
Wrapper
*
self
)
{
return
PyObject_Hash
(
self
->
obj
);
}
static
PyObject
*
Wrapper_call
(
Wrapper
*
self
,
PyObject
*
args
,
PyObject
*
kw
)
{
Py_INCREF
(
args
);
return
CallMethodO
(
OBJECT
(
self
),
py__call__
,
args
,
kw
);
}
/* Code to handle accessing Wrapper objects as sequence objects */
static
int
Wrapper_length
(
Wrapper
*
self
)
{
long
l
;
PyObject
*
r
;
UNLESS
(
r
=
PyObject_GetAttr
(
OBJECT
(
self
),
py__len__
))
return
-
1
;
UNLESS_ASSIGN
(
r
,
PyObject_CallObject
(
r
,
NULL
))
return
-
1
;
l
=
PyInt_AsLong
(
r
);
Py_DECREF
(
r
);
return
l
;
}
static
PyObject
*
Wrapper_add
(
Wrapper
*
self
,
PyObject
*
bb
)
{
return
CallMethodO
(
OBJECT
(
self
),
py__add__
,
Build
(
"(O)"
,
bb
)
,
NULL
);
}
static
PyObject
*
Wrapper_mul
(
Wrapper
*
self
,
int
n
)
{
return
CallMethodO
(
OBJECT
(
self
),
py__mul__
,
Build
(
"(i)"
,
n
),
NULL
);
}
static
PyObject
*
Wrapper_item
(
Wrapper
*
self
,
int
i
)
{
return
CallMethodO
(
OBJECT
(
self
),
py__getitem__
,
Build
(
"(i)"
,
i
),
NULL
);
}
static
PyObject
*
Wrapper_slice
(
Wrapper
*
self
,
int
ilow
,
int
ihigh
)
{
return
CallMethodO
(
OBJECT
(
self
),
py__getslice__
,
Build
(
"(ii)"
,
ilow
,
ihigh
),
NULL
);
}
static
int
Wrapper_ass_item
(
Wrapper
*
self
,
int
i
,
PyObject
*
v
)
{
if
(
v
)
{
UNLESS
(
v
=
CallMethodO
(
OBJECT
(
self
),
py__setitem__
,
Build
(
"(iO)"
,
i
,
v
),
NULL
))
return
-
1
;
}
else
{
UNLESS
(
v
=
CallMethodO
(
OBJECT
(
self
),
py__delitem__
,
Build
(
"(i)"
,
i
),
NULL
))
return
-
1
;
}
Py_DECREF
(
v
);
return
0
;
}
static
int
Wrapper_ass_slice
(
Wrapper
*
self
,
int
ilow
,
int
ihigh
,
PyObject
*
v
)
{
if
(
v
)
{
UNLESS
(
v
=
CallMethodO
(
OBJECT
(
self
),
py__setslice__
,
Build
(
"(iiO)"
,
ilow
,
ihigh
,
v
),
NULL
))
return
-
1
;
}
else
{
UNLESS
(
v
=
CallMethodO
(
OBJECT
(
self
),
py__delslice__
,
Build
(
"(ii)"
,
ilow
,
ihigh
),
NULL
))
return
-
1
;
}
Py_DECREF
(
v
);
return
0
;
}
static
PySequenceMethods
Wrapper_as_sequence
=
{
(
inquiry
)
Wrapper_length
,
/*sq_length*/
(
binaryfunc
)
Wrapper_add
,
/*sq_concat*/
(
intargfunc
)
Wrapper_mul
,
/*sq_repeat*/
(
intargfunc
)
Wrapper_item
,
/*sq_item*/
(
intintargfunc
)
Wrapper_slice
,
/*sq_slice*/
(
intobjargproc
)
Wrapper_ass_item
,
/*sq_ass_item*/
(
intintobjargproc
)
Wrapper_ass_slice
,
/*sq_ass_slice*/
};
/* -------------------------------------------------------------- */
/* Code to access Wrapper objects as mappings */
static
PyObject
*
Wrapper_subscript
(
Wrapper
*
self
,
PyObject
*
key
)
{
return
CallMethodO
(
OBJECT
(
self
),
py__getitem__
,
Build
(
"(O)"
,
key
),
NULL
);
}
static
int
Wrapper_ass_sub
(
Wrapper
*
self
,
PyObject
*
key
,
PyObject
*
v
)
{
if
(
v
)
{
UNLESS
(
v
=
CallMethodO
(
OBJECT
(
self
),
py__setitem__
,
Build
(
"(OO)"
,
key
,
v
),
NULL
))
return
-
1
;
}
else
{
UNLESS
(
v
=
CallMethodO
(
OBJECT
(
self
),
py__delitem__
,
Build
(
"(O)"
,
key
),
NULL
))
return
-
1
;
}
Py_XDECREF
(
v
);
return
0
;
}
static
PyMappingMethods
Wrapper_as_mapping
=
{
(
inquiry
)
Wrapper_length
,
/*mp_length*/
(
binaryfunc
)
Wrapper_subscript
,
/*mp_subscript*/
(
objobjargproc
)
Wrapper_ass_sub
,
/*mp_ass_subscript*/
};
/* -------------------------------------------------------------- */
/* Code to access Wrapper objects as numbers */
static
PyObject
*
Wrapper_sub
(
Wrapper
*
self
,
PyObject
*
o
)
{
return
CallMethodO
(
OBJECT
(
self
),
py__sub__
,
Build
(
"(O)"
,
o
),
NULL
);
}
static
PyObject
*
Wrapper_div
(
Wrapper
*
self
,
PyObject
*
o
)
{
return
CallMethodO
(
OBJECT
(
self
),
py__div__
,
Build
(
"(O)"
,
o
),
NULL
);
}
static
PyObject
*
Wrapper_mod
(
Wrapper
*
self
,
PyObject
*
o
)
{
return
CallMethodO
(
OBJECT
(
self
),
py__mod__
,
Build
(
"(O)"
,
o
),
NULL
);
}
static
PyObject
*
Wrapper_divmod
(
Wrapper
*
self
,
PyObject
*
o
)
{
return
CallMethodO
(
OBJECT
(
self
),
py__divmod__
,
Build
(
"(O)"
,
o
),
NULL
);
}
static
PyObject
*
Wrapper_pow
(
Wrapper
*
self
,
PyObject
*
o
,
PyObject
*
m
)
{
return
CallMethodO
(
OBJECT
(
self
),
py__pow__
,
Build
(
"(OO)"
,
o
,
m
),
NULL
);
}
static
PyObject
*
Wrapper_neg
(
Wrapper
*
self
)
{
return
CallMethodO
(
OBJECT
(
self
),
py__neg__
,
NULL
,
NULL
);
}
static
PyObject
*
Wrapper_pos
(
Wrapper
*
self
)
{
return
CallMethodO
(
OBJECT
(
self
),
py__pos__
,
NULL
,
NULL
);
}
static
PyObject
*
Wrapper_abs
(
Wrapper
*
self
)
{
return
CallMethodO
(
OBJECT
(
self
),
py__abs__
,
NULL
,
NULL
);
}
static
PyObject
*
Wrapper_invert
(
Wrapper
*
self
)
{
return
CallMethodO
(
OBJECT
(
self
),
py__invert__
,
NULL
,
NULL
);
}
static
PyObject
*
Wrapper_lshift
(
Wrapper
*
self
,
PyObject
*
o
)
{
return
CallMethodO
(
OBJECT
(
self
),
py__lshift__
,
Build
(
"(O)"
,
o
),
NULL
);
}
static
PyObject
*
Wrapper_rshift
(
Wrapper
*
self
,
PyObject
*
o
)
{
return
CallMethodO
(
OBJECT
(
self
),
py__rshift__
,
Build
(
"(O)"
,
o
),
NULL
);
}
static
PyObject
*
Wrapper_and
(
Wrapper
*
self
,
PyObject
*
o
)
{
return
CallMethodO
(
OBJECT
(
self
),
py__and__
,
Build
(
"(O)"
,
o
),
NULL
);
}
static
PyObject
*
Wrapper_xor
(
Wrapper
*
self
,
PyObject
*
o
)
{
return
CallMethodO
(
OBJECT
(
self
),
py__xor__
,
Build
(
"(O)"
,
o
),
NULL
);
}
static
PyObject
*
Wrapper_or
(
Wrapper
*
self
,
PyObject
*
o
)
{
return
CallMethodO
(
OBJECT
(
self
),
py__or__
,
Build
(
"(O)"
,
o
),
NULL
);
}
static
int
Wrapper_coerce
(
Wrapper
**
self
,
PyObject
**
o
)
{
PyObject
*
m
;
UNLESS
(
m
=
PyObject_GetAttr
(
OBJECT
(
*
self
),
py__coerce__
))
{
PyErr_Clear
();
Py_INCREF
(
*
self
);
Py_INCREF
(
*
o
);
return
0
;
}
ASSIGN
(
m
,
PyObject_CallFunction
(
m
,
"O"
,
*
o
));
UNLESS
(
m
)
return
-
1
;
UNLESS
(
PyArg_ParseTuple
(
m
,
"OO"
,
self
,
o
))
goto
err
;
Py_INCREF
(
*
self
);
Py_INCREF
(
*
o
);
Py_DECREF
(
m
);
return
0
;
err:
Py_DECREF
(
m
);
return
-
1
;
}
static
PyObject
*
Wrapper_int
(
Wrapper
*
self
)
{
return
CallMethodO
(
OBJECT
(
self
),
py__int__
,
NULL
,
NULL
);
}
static
PyObject
*
Wrapper_long
(
Wrapper
*
self
)
{
return
CallMethodO
(
OBJECT
(
self
),
py__long__
,
NULL
,
NULL
);
}
static
PyObject
*
Wrapper_float
(
Wrapper
*
self
)
{
return
CallMethodO
(
OBJECT
(
self
),
py__float__
,
NULL
,
NULL
);
}
static
PyObject
*
Wrapper_oct
(
Wrapper
*
self
)
{
return
CallMethodO
(
OBJECT
(
self
),
py__oct__
,
NULL
,
NULL
);
}
static
PyObject
*
Wrapper_hex
(
Wrapper
*
self
)
{
return
CallMethodO
(
OBJECT
(
self
),
py__hex__
,
NULL
,
NULL
);
}
static
int
Wrapper_nonzero
(
Wrapper
*
self
)
{
long
l
;
PyObject
*
r
;
UNLESS
(
r
=
PyObject_GetAttr
(
OBJECT
(
self
),
py__nonzero__
))
{
PyErr_Clear
();
/* Try len */
UNLESS
(
r
=
PyObject_GetAttr
(
OBJECT
(
self
),
py__len__
))
{
/* No len, it's true :-) */
PyErr_Clear
();
return
1
;
}
}
UNLESS_ASSIGN
(
r
,
PyObject_CallObject
(
r
,
NULL
))
return
-
1
;
l
=
PyInt_AsLong
(
r
);
Py_DECREF
(
r
);
return
l
;
}
static
PyNumberMethods
Wrapper_as_number
=
{
(
binaryfunc
)
Wrapper_add
,
/*nb_add*/
(
binaryfunc
)
Wrapper_sub
,
/*nb_subtract*/
(
binaryfunc
)
Wrapper_mul
,
/*nb_multiply*/
(
binaryfunc
)
Wrapper_div
,
/*nb_divide*/
(
binaryfunc
)
Wrapper_mod
,
/*nb_remainder*/
(
binaryfunc
)
Wrapper_divmod
,
/*nb_divmod*/
(
ternaryfunc
)
Wrapper_pow
,
/*nb_power*/
(
unaryfunc
)
Wrapper_neg
,
/*nb_negative*/
(
unaryfunc
)
Wrapper_pos
,
/*nb_positive*/
(
unaryfunc
)
Wrapper_abs
,
/*nb_absolute*/
(
inquiry
)
Wrapper_nonzero
,
/*nb_nonzero*/
(
unaryfunc
)
Wrapper_invert
,
/*nb_invert*/
(
binaryfunc
)
Wrapper_lshift
,
/*nb_lshift*/
(
binaryfunc
)
Wrapper_rshift
,
/*nb_rshift*/
(
binaryfunc
)
Wrapper_and
,
/*nb_and*/
(
binaryfunc
)
Wrapper_xor
,
/*nb_xor*/
(
binaryfunc
)
Wrapper_or
,
/*nb_or*/
(
coercion
)
Wrapper_coerce
,
/*nb_coerce*/
(
unaryfunc
)
Wrapper_int
,
/*nb_int*/
(
unaryfunc
)
Wrapper_long
,
/*nb_long*/
(
unaryfunc
)
Wrapper_float
,
/*nb_float*/
(
unaryfunc
)
Wrapper_oct
,
/*nb_oct*/
(
unaryfunc
)
Wrapper_hex
,
/*nb_hex*/
};
/* -------------------------------------------------------- */
static
char
*
acquire_args
[]
=
{
"object"
,
"name"
,
"filter"
,
"extra"
,
"explicit"
,
"default"
,
"containment"
,
NULL
};
static
PyObject
*
Wrapper_acquire_method
(
Wrapper
*
self
,
PyObject
*
args
,
PyObject
*
kw
)
{
PyObject
*
name
,
*
filter
=
0
,
*
extra
=
Py_None
;
PyObject
*
expl
=
0
,
*
defalt
=
0
;
int
explicit
=
1
;
int
containment
=
0
;
UNLESS
(
PyArg_ParseTupleAndKeywords
(
args
,
kw
,
"O|OOOOi"
,
acquire_args
+
1
,
&
name
,
&
filter
,
&
extra
,
&
explicit
,
&
defalt
,
&
containment
))
return
NULL
;
if
(
expl
)
explicit
=
PyObject_IsTrue
(
expl
);
if
(
filter
==
Py_None
)
filter
=
0
;
return
Wrapper_findattr
(
self
,
name
,
filter
,
extra
,
OBJECT
(
self
),
1
,
explicit
||
self
->
ob_type
==
(
PyTypeObject
*
)
&
Wrappertype
,
explicit
,
containment
);
}
static
PyObject
*
Wrapper_inContextOf
(
Wrapper
*
self
,
PyObject
*
args
)
{
PyObject
*
subob
,
*
o
,
*
c
;
int
inner
=
1
;
UNLESS
(
PyArg_ParseTuple
(
args
,
"O|i"
,
&
o
,
&
inner
))
return
NULL
;
if
(
inner
)
{
/* subob = self */
subob
=
OBJECT
(
self
);
/* o = aq_base(o) */
while
(
isWrapper
(
o
)
&&
WRAPPER
(
o
)
->
obj
)
o
=
WRAPPER
(
o
)
->
obj
;
/* while 1: */
while
(
1
)
{
/* if aq_base(subob) is o: return 1 */
c
=
subob
;
while
(
isWrapper
(
c
)
&&
WRAPPER
(
c
)
->
obj
)
c
=
WRAPPER
(
c
)
->
obj
;
if
(
c
==
o
)
return
PyInt_FromLong
(
1
);
/* self = aq_inner(subob) */
/* if self is None: break */
if
(
isWrapper
(
subob
))
{
self
=
WRAPPER
(
subob
);
while
(
self
->
obj
&&
isWrapper
(
self
->
obj
))
self
=
WRAPPER
(
self
->
obj
);
}
else
break
;
/* subob = aq_parent(self) */
/* if subob is None: break */
if
(
self
->
container
)
subob
=
self
->
container
;
else
break
;
}
}
else
{
/* Follow wrappers instead. */
c
=
OBJECT
(
self
);
while
(
1
)
{
if
(
c
==
o
)
return
PyInt_FromLong
(
1
);
if
(
c
&&
isWrapper
(
c
))
c
=
WRAPPER
(
c
)
->
container
;
else
break
;
}
}
return
PyInt_FromLong
(
0
);
}
PyObject
*
Wrappers_are_not_picklable
(
PyObject
*
Wrapper
,
PyObject
*
args
)
{
PyErr_SetString
(
PyExc_TypeError
,
"Can't pickle objects in acquisition wrappers."
);
return
NULL
;
}
static
struct
PyMethodDef
Wrapper_methods
[]
=
{
{
"__init__"
,
(
PyCFunction
)
Wrapper__init__
,
0
,
"Initialize an Acquirer Wrapper"
},
{
"acquire"
,
(
PyCFunction
)
Wrapper_acquire_method
,
METH_VARARGS
|
METH_KEYWORDS
,
"Get an attribute, acquiring it if necessary"
},
{
"aq_acquire"
,
(
PyCFunction
)
Wrapper_acquire_method
,
METH_VARARGS
|
METH_KEYWORDS
,
"Get an attribute, acquiring it if necessary"
},
{
"aq_inContextOf"
,
(
PyCFunction
)
Wrapper_inContextOf
,
METH_VARARGS
,
"Test whether the object is currently in the context of the argument"
},
{
"__getstate__"
,
(
PyCFunction
)
Wrappers_are_not_picklable
,
METH_VARARGS
,
"Wrappers are not picklable"
},
{
"__reduce__"
,
(
PyCFunction
)
Wrappers_are_not_picklable
,
METH_VARARGS
,
"Wrappers are not picklable"
},
{
"__reduce_ex__"
,
(
PyCFunction
)
Wrappers_are_not_picklable
,
METH_VARARGS
,
"Wrappers are not picklable"
},
{
NULL
,
NULL
}
/* sentinel */
};
static
PyExtensionClass
Wrappertype
=
{
PyObject_HEAD_INIT
(
NULL
)
0
,
/*ob_size*/
"ImplicitAcquirerWrapper"
,
/*tp_name*/
sizeof
(
Wrapper
),
/*tp_basicsize*/
0
,
/*tp_itemsize*/
/* methods */
(
destructor
)
Wrapper_dealloc
,
/*tp_dealloc*/
(
printfunc
)
0
,
/*tp_print*/
(
getattrfunc
)
0
,
/*tp_getattr*/
(
setattrfunc
)
0
,
/*tp_setattr*/
(
cmpfunc
)
Wrapper_compare
,
/*tp_compare*/
(
reprfunc
)
Wrapper_repr
,
/*tp_repr*/
&
Wrapper_as_number
,
/*tp_as_number*/
&
Wrapper_as_sequence
,
/*tp_as_sequence*/
&
Wrapper_as_mapping
,
/*tp_as_mapping*/
(
hashfunc
)
Wrapper_hash
,
/*tp_hash*/
(
ternaryfunc
)
Wrapper_call
,
/*tp_call*/
(
reprfunc
)
Wrapper_str
,
/*tp_str*/
(
getattrofunc
)
Wrapper_getattro
,
/*tp_getattr with object key*/
(
setattrofunc
)
Wrapper_setattro
,
/*tp_setattr with object key*/
/* Space for future expansion */
0L
,
0L
,
"Wrapper object for implicit acquisition"
,
/* Documentation string */
METHOD_CHAIN
(
Wrapper_methods
),
(
void
*
)(
EXTENSIONCLASS_BINDABLE_FLAG
),
};
static
PyExtensionClass
XaqWrappertype
=
{
PyObject_HEAD_INIT
(
NULL
)
0
,
/*ob_size*/
"ExplicitAcquirerWrapper"
,
/*tp_name*/
sizeof
(
Wrapper
),
/*tp_basicsize*/
0
,
/*tp_itemsize*/
/* methods */
(
destructor
)
Wrapper_dealloc
,
/*tp_dealloc*/
(
printfunc
)
0
,
/*tp_print*/
(
getattrfunc
)
0
,
/*tp_getattr*/
(
setattrfunc
)
0
,
/*tp_setattr*/
(
cmpfunc
)
Wrapper_compare
,
/*tp_compare*/
(
reprfunc
)
Wrapper_repr
,
/*tp_repr*/
&
Wrapper_as_number
,
/*tp_as_number*/
&
Wrapper_as_sequence
,
/*tp_as_sequence*/
&
Wrapper_as_mapping
,
/*tp_as_mapping*/
(
hashfunc
)
Wrapper_hash
,
/*tp_hash*/
(
ternaryfunc
)
Wrapper_call
,
/*tp_call*/
(
reprfunc
)
Wrapper_str
,
/*tp_str*/
(
getattrofunc
)
Xaq_getattro
,
/*tp_getattr with object key*/
(
setattrofunc
)
Wrapper_setattro
,
/*tp_setattr with object key*/
/* Space for future expansion */
0L
,
0L
,
"Wrapper object for explicit acquisition"
,
/* Documentation string */
METHOD_CHAIN
(
Wrapper_methods
),
(
void
*
)(
EXTENSIONCLASS_BINDABLE_FLAG
),
};
static
PyObject
*
acquire_of
(
PyObject
*
self
,
PyObject
*
args
)
{
PyObject
*
inst
;
UNLESS
(
PyArg_ParseTuple
(
args
,
"O"
,
&
inst
))
return
NULL
;
UNLESS
(
PyExtensionInstance_Check
(
inst
))
{
PyErr_SetString
(
PyExc_TypeError
,
"attempt to wrap extension method using an object that
\n
"
"is not an extension class instance."
);
return
NULL
;
}
return
newWrapper
(
self
,
inst
,
(
PyTypeObject
*
)
&
Wrappertype
);
}
static
PyObject
*
xaq_of
(
PyObject
*
self
,
PyObject
*
args
)
{
PyObject
*
inst
;
UNLESS
(
PyArg_ParseTuple
(
args
,
"O"
,
&
inst
))
return
NULL
;
UNLESS
(
PyExtensionInstance_Check
(
inst
))
{
PyErr_SetString
(
PyExc_TypeError
,
"attempt to wrap extension method using an object that
\n
"
"is not an extension class instance."
);
return
NULL
;
}
return
newWrapper
(
self
,
inst
,
(
PyTypeObject
*
)
&
XaqWrappertype
);
}
static
struct
PyMethodDef
Acquirer_methods
[]
=
{
{
"__of__"
,(
PyCFunction
)
acquire_of
,
METH_VARARGS
,
"__of__(context) -- return the object in a context"
},
{
NULL
,
NULL
}
/* sentinel */
};
static
struct
PyMethodDef
Xaq_methods
[]
=
{
{
"__of__"
,(
PyCFunction
)
xaq_of
,
METH_VARARGS
,
""
},
{
NULL
,
NULL
}
/* sentinel */
};
static
PyObject
*
capi_aq_acquire
(
PyObject
*
self
,
PyObject
*
name
,
PyObject
*
filter
,
PyObject
*
extra
,
int
explicit
,
PyObject
*
defalt
,
int
containment
)
{
PyObject
*
result
;
if
(
filter
==
Py_None
)
filter
=
0
;
/* We got a wrapped object, so business as usual */
if
(
isWrapper
(
self
))
return
Wrapper_findattr
(
WRAPPER
(
self
),
name
,
filter
,
extra
,
OBJECT
(
self
),
1
,
explicit
||
WRAPPER
(
self
)
->
ob_type
==
(
PyTypeObject
*
)
&
Wrappertype
,
explicit
,
containment
);
/* Not wrapped and no filter, so just getattr */
if
(
!
filter
)
return
PyObject_GetAttr
(
self
,
name
);
/* Crap, we've got to construct a wrapper so we can use Wrapper_findattr */
UNLESS
(
self
=
newWrapper
(
self
,
NULL
,
(
PyTypeObject
*
)
&
Wrappertype
))
return
NULL
;
result
=
Wrapper_findattr
(
WRAPPER
(
self
),
name
,
filter
,
extra
,
OBJECT
(
self
),
1
,
1
,
explicit
,
containment
);
/* get rid of temp wrapper */
Py_DECREF
(
self
);
return
result
;
}
static
PyObject
*
module_aq_acquire
(
PyObject
*
ignored
,
PyObject
*
args
,
PyObject
*
kw
)
{
PyObject
*
self
;
PyObject
*
name
,
*
filter
=
0
,
*
extra
=
Py_None
;
PyObject
*
expl
=
0
,
*
defalt
=
0
;
int
explicit
=
1
,
containment
=
0
;
UNLESS
(
PyArg_ParseTupleAndKeywords
(
args
,
kw
,
"OO|OOOOi"
,
acquire_args
,
&
self
,
&
name
,
&
filter
,
&
extra
,
&
expl
,
&
defalt
,
&
containment
))
return
NULL
;
if
(
expl
)
explicit
=
PyObject_IsTrue
(
expl
);
return
capi_aq_acquire
(
self
,
name
,
filter
,
extra
,
explicit
,
defalt
,
containment
);
}
static
PyObject
*
capi_aq_get
(
PyObject
*
self
,
PyObject
*
name
,
PyObject
*
defalt
,
int
containment
)
{
PyObject
*
result
=
NULL
;
/* We got a wrapped object, so business as usual */
if
(
isWrapper
(
self
))
result
=
Wrapper_findattr
(
WRAPPER
(
self
),
name
,
0
,
0
,
OBJECT
(
self
),
1
,
1
,
1
,
containment
);
else
result
=
PyObject_GetAttr
(
self
,
name
);
if
(
!
result
&&
defalt
)
{
PyErr_Clear
();
result
=
defalt
;
Py_INCREF
(
result
);
}
return
result
;
}
static
PyObject
*
module_aq_get
(
PyObject
*
r
,
PyObject
*
args
)
{
PyObject
*
self
,
*
name
,
*
defalt
=
0
;
int
containment
=
0
;
UNLESS
(
PyArg_ParseTuple
(
args
,
"OO|Oi"
,
&
self
,
&
name
,
&
defalt
,
&
containment
))
return
NULL
;
return
capi_aq_get
(
self
,
name
,
defalt
,
containment
);
}
static
int
capi_aq_iswrapper
(
PyObject
*
self
)
{
return
isWrapper
(
self
);
}
static
PyObject
*
capi_aq_base
(
PyObject
*
self
)
{
PyObject
*
result
;
if
(
!
isWrapper
(
self
))
{
Py_INCREF
(
self
);
return
self
;
}
if
(
WRAPPER
(
self
)
->
obj
)
{
result
=
WRAPPER
(
self
)
->
obj
;
while
(
isWrapper
(
result
)
&&
WRAPPER
(
result
)
->
obj
)
result
=
WRAPPER
(
result
)
->
obj
;
}
else
result
=
Py_None
;
Py_INCREF
(
result
);
return
result
;
}
static
PyObject
*
module_aq_base
(
PyObject
*
ignored
,
PyObject
*
args
)
{
PyObject
*
self
;
UNLESS
(
PyArg_ParseTuple
(
args
,
"O"
,
&
self
))
return
NULL
;
return
capi_aq_base
(
self
);
}
static
PyObject
*
capi_aq_parent
(
PyObject
*
self
)
{
PyObject
*
result
=
Py_None
;
if
(
isWrapper
(
self
)
&&
WRAPPER
(
self
)
->
container
)
result
=
WRAPPER
(
self
)
->
container
;
Py_INCREF
(
result
);
return
result
;
}
static
PyObject
*
module_aq_parent
(
PyObject
*
ignored
,
PyObject
*
args
)
{
PyObject
*
self
;
UNLESS
(
PyArg_ParseTuple
(
args
,
"O"
,
&
self
))
return
NULL
;
return
capi_aq_parent
(
self
);
}
static
PyObject
*
capi_aq_self
(
PyObject
*
self
)
{
PyObject
*
result
;
if
(
!
isWrapper
(
self
))
{
Py_INCREF
(
self
);
return
self
;
}
if
(
WRAPPER
(
self
)
->
obj
)
result
=
WRAPPER
(
self
)
->
obj
;
else
result
=
Py_None
;
Py_INCREF
(
result
);
return
result
;
}
static
PyObject
*
module_aq_self
(
PyObject
*
ignored
,
PyObject
*
args
)
{
PyObject
*
self
;
UNLESS
(
PyArg_ParseTuple
(
args
,
"O"
,
&
self
))
return
NULL
;
return
capi_aq_self
(
self
);
}
static
PyObject
*
capi_aq_inner
(
PyObject
*
self
)
{
PyObject
*
result
;
if
(
!
isWrapper
(
self
))
{
Py_INCREF
(
self
);
return
self
;
}
if
(
WRAPPER
(
self
)
->
obj
)
{
result
=
WRAPPER
(
self
)
->
obj
;
while
(
isWrapper
(
result
)
&&
WRAPPER
(
result
)
->
obj
)
{
self
=
result
;
result
=
WRAPPER
(
result
)
->
obj
;
}
result
=
self
;
}
else
result
=
Py_None
;
Py_INCREF
(
result
);
return
result
;
}
static
PyObject
*
module_aq_inner
(
PyObject
*
ignored
,
PyObject
*
args
)
{
PyObject
*
self
;
UNLESS
(
PyArg_ParseTuple
(
args
,
"O"
,
&
self
))
return
NULL
;
return
capi_aq_inner
(
self
);
}
static
PyObject
*
capi_aq_chain
(
PyObject
*
self
,
int
containment
)
{
PyObject
*
result
;
UNLESS
(
result
=
PyList_New
(
0
))
return
NULL
;
while
(
1
)
{
if
(
isWrapper
(
self
))
{
if
(
WRAPPER
(
self
)
->
obj
)
{
if
(
containment
)
while
(
WRAPPER
(
self
)
->
obj
&&
isWrapper
(
WRAPPER
(
self
)
->
obj
))
self
=
WRAPPER
(
self
)
->
obj
;
if
(
PyList_Append
(
result
,
OBJECT
(
self
))
<
0
)
goto
err
;
}
if
(
WRAPPER
(
self
)
->
container
)
{
self
=
WRAPPER
(
self
)
->
container
;
continue
;
}
}
else
if
(
PyList_Append
(
result
,
self
)
<
0
)
goto
err
;
break
;
}
return
result
;
err:
Py_DECREF
(
result
);
return
result
;
}
static
PyObject
*
module_aq_chain
(
PyObject
*
ignored
,
PyObject
*
args
)
{
PyObject
*
self
;
int
containment
=
0
;
UNLESS
(
PyArg_ParseTuple
(
args
,
"O|i"
,
&
self
,
&
containment
))
return
NULL
;
return
capi_aq_chain
(
self
,
containment
);
}
static
struct
PyMethodDef
methods
[]
=
{
{
"aq_acquire"
,
(
PyCFunction
)
module_aq_acquire
,
METH_VARARGS
|
METH_KEYWORDS
,
"aq_acquire(ob, name [, filter, extra, explicit]) -- "
"Get an attribute, acquiring it if necessary"
},
{
"aq_get"
,
(
PyCFunction
)
module_aq_get
,
METH_VARARGS
,
"aq_get(ob, name [, default]) -- "
"Get an attribute, acquiring it if necessary."
},
{
"aq_base"
,
(
PyCFunction
)
module_aq_base
,
METH_VARARGS
,
"aq_base(ob) -- Get the object unwrapped"
},
{
"aq_parent"
,
(
PyCFunction
)
module_aq_parent
,
METH_VARARGS
,
"aq_parent(ob) -- Get the parent of an object"
},
{
"aq_self"
,
(
PyCFunction
)
module_aq_self
,
METH_VARARGS
,
"aq_self(ob) -- Get the object with the outermost wrapper removed"
},
{
"aq_inner"
,
(
PyCFunction
)
module_aq_inner
,
METH_VARARGS
,
"aq_inner(ob) -- "
"Get the object with alll but the innermost wrapper removed"
},
{
"aq_chain"
,
(
PyCFunction
)
module_aq_chain
,
METH_VARARGS
,
"aq_chain(ob [, containment]) -- "
"Get a list of objects in the acquisition environment"
},
{
NULL
,
NULL
}
};
void
init_Acquisition
(
void
)
{
PyObject
*
m
,
*
d
;
PyObject
*
api
;
PURE_MIXIN_CLASS
(
Acquirer
,
"Base class for objects that implicitly"
" acquire attributes from containers
\n
"
,
Acquirer_methods
);
PURE_MIXIN_CLASS
(
ExplicitAcquirer
,
"Base class for objects that explicitly"
" acquire attributes from containers
\n
"
,
Xaq_methods
);
UNLESS
(
ExtensionClassImported
)
return
;
UNLESS
(
Acquired
=
PyString_FromStringAndSize
(
NULL
,
42
))
return
;
strcpy
(
PyString_AsString
(
Acquired
),
"<Special Object Used to Force Acquisition>"
);
/* Create the module and add the functions */
m
=
Py_InitModule4
(
"_Acquisition"
,
methods
,
"Provide base classes for acquiring objects
\n\n
"
"$Id: _Acquisition.c,v 1.2 2003/11/28 16:44:14 jim Exp $
\n
"
,
OBJECT
(
NULL
),
PYTHON_API_VERSION
);
d
=
PyModule_GetDict
(
m
);
init_py_names
();
PyExtensionClass_Export
(
d
,
"Acquirer"
,
AcquirerType
);
PyExtensionClass_Export
(
d
,
"ImplicitAcquisitionWrapper"
,
Wrappertype
);
PyExtensionClass_Export
(
d
,
"ExplicitAcquirer"
,
ExplicitAcquirerType
);
PyExtensionClass_Export
(
d
,
"ExplicitAcquisitionWrapper"
,
XaqWrappertype
);
/* Create aliases */
PyDict_SetItemString
(
d
,
"Implicit"
,
OBJECT
(
&
AcquirerType
));
PyDict_SetItemString
(
d
,
"Explicit"
,
OBJECT
(
&
ExplicitAcquirerType
));
PyDict_SetItemString
(
d
,
"Acquired"
,
Acquired
);
AcquisitionCAPI
.
AQ_Acquire
=
capi_aq_acquire
;
AcquisitionCAPI
.
AQ_Get
=
capi_aq_get
;
AcquisitionCAPI
.
AQ_IsWrapper
=
capi_aq_iswrapper
;
AcquisitionCAPI
.
AQ_Base
=
capi_aq_base
;
AcquisitionCAPI
.
AQ_Parent
=
capi_aq_parent
;
AcquisitionCAPI
.
AQ_Self
=
capi_aq_self
;
AcquisitionCAPI
.
AQ_Inner
=
capi_aq_inner
;
AcquisitionCAPI
.
AQ_Chain
=
capi_aq_chain
;
api
=
PyCObject_FromVoidPtr
(
&
AcquisitionCAPI
,
NULL
);
PyDict_SetItemString
(
d
,
"AcquisitionCAPI"
,
api
);
Py_DECREF
(
api
);
}
lib/python/Acquisition/__init__.py
0 → 100644
View file @
771f7677
from
_Acquisition
import
*
lib/python/Acquisition/setup.py
0 → 100644
View file @
771f7677
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
from
distutils.core
import
setup
,
Extension
setup
(
name
=
"_Acquisition"
,
version
=
"2.0"
,
ext_modules
=
[
Extension
(
"_Acquisition"
,
[
"_Acquisition.c"
],
include_dirs
=
[
'.'
,
'../ExtensionClass'
],
depends
=
[
"Acquisition.h"
,
'../ExtensionClass/ExtensionClass.h'
]),
])
lib/python/Acquisition/tests.py
0 → 100644
View file @
771f7677
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Acquisition test cases (and useful examples)
Acquisition [1] is a mechanism that allows objects to obtain
attributes from their environment. It is similar to inheritence,
except that, rather than traversing an inheritence hierarchy
to obtain attributes, a containment hierarchy is traversed.
The "ExtensionClass":ExtensionClass.html. release includes mix-in
extension base classes that can be used to add acquisition as a
feature to extension subclasses. These mix-in classes use the
context-wrapping feature of ExtensionClasses to implement
acquisition. Consider the following example::
>>> import ExtensionClass, Acquisition
>>> class C(ExtensionClass.Base):
... color='red'
>>> class A(Acquisition.Implicit):
... def report(self):
... print self.color
>>> a = A()
>>> c = C()
>>> c.a = a
>>> c.a.report()
red
>>> d = C()
>>> d.color = 'green'
>>> d.a = a
>>> d.a.report()
green
>>> a.report() # raises an attribute error
Traceback (most recent call last):
...
AttributeError: color
The class 'A' inherits acquisition behavior from
'Acquisition.Implicit'. The object, 'a', "has" the color of
objects 'c' and 'd' when it is accessed through them, but it
has no color by itself. The object 'a' obtains attributes
from it's environment, where it's environment is defined by
the access path used to reach 'a'.
Acquisition wrappers
When an object that supports acquisition is accessed through
an extension class instance, a special object, called an
acquisition wrapper, is returned. In the example above, the
expression 'c.a' returns an acquisition wrapper that
contains references to both 'c' and 'a'. It is this wrapper
that performs attribute lookup in 'c' when an attribute
cannot be found in 'a'.
Aquisition wrappers provide access to the wrapped objects
through the attributes 'aq_parent', 'aq_self', 'aq_base'.
In the example above, the expressions::
>>> c.a.aq_parent is c
1
and::
>>> c.a.aq_self is a
1
both evaluate to true, but the expression::
>>> c.a is a
0
evaluates to false, because the expression 'c.a' evaluates
to an acquisition wrapper around 'c' and 'a', not 'a' itself.
The attribute 'aq_base' is similar to 'aq_self'. Wrappers may be
nested and 'aq_self' may be a wrapped object. The 'aq_base'
attribute is the underlying object with all wrappers removed.
Acquisition Control
Two styles of acquisition are supported in the current
ExtensionClass release, implicit and explicit aquisition.
Implicit acquisition
Implicit acquisition is so named because it searches for
attributes from the environment automatically whenever an
attribute cannot be obtained directly from an object or
through inheritence.
An attribute may be implicitly acquired if it's name does
not begin with an underscore, '_'.
To support implicit acquisition, an object should inherit
from the mix-in class 'Acquisition.Implicit'.
Explicit Acquisition
When explicit acquisition is used, attributes are not
automatically obtained from the environment. Instead, the
method 'aq_aquire' must be used, as in::
print c.a.aq_acquire('color')
To support explicit acquisition, an object should inherit
from the mix-in class 'Acquisition.Explicit'.
Controlled Acquisition
A class (or instance) can provide attribute by attribute control
over acquisition. This is done by:
- subclassing from 'Acquisition.Explicit', and
- setting all attributes that should be acquired to the special
value: 'Acquisition.Acquired'. Setting an attribute to this
value also allows inherited attributes to be overridden with
acquired ones.
For example, in::
>>> class E(Acquisition.Explicit):
... id = 1
... secret = 2
... color = Acquisition.Acquired
... __roles__ = Acquisition.Acquired
The *only* attributes that are automatically acquired from
containing objects are 'color', and '__roles__'.
>>> c = C()
>>> c.foo = 'foo'
>>> c.e = E()
>>> c.e.color
'red'
>>> c.e.foo
Traceback (most recent call last):
...
AttributeError: foo
Note also that the '__roles__' attribute is acquired even
though it's name begins with an underscore:
>>> c.__roles__ = 'Manager', 'Member'
>>> c.e.__roles__
('Manager', 'Member')
In fact, the special 'Acquisition.Acquired' value can be used
in 'Acquisition.Implicit' objects to implicitly acquire
selected objects that smell like private objects.
>>> class I(Acquisition.Implicit):
... __roles__ = Acquisition.Acquired
>>> c.x = C()
>>> c.x.__roles__
Traceback (most recent call last):
...
AttributeError: __roles__
>>> c.x = I()
>>> c.x.__roles__
('Manager', 'Member')
Filtered Acquisition
The acquisition method, 'aq_acquire', accepts two optional
arguments. The first of the additional arguments is a
"filtering" function that is used when considering whether to
acquire an object. The second of the additional arguments is an
object that is passed as extra data when calling the filtering
function and which defaults to 'None'.
The filter function is called with five arguments:
- The object that the 'aq_acquire' method was called on,
- The object where an object was found,
- The name of the object, as passed to 'aq_acquire',
- The object found, and
- The extra data passed to 'aq_acquire'.
If the filter returns a true object that the object found is
returned, otherwise, the acquisition search continues.
For example, in::
>>> from Acquisition import Explicit
>>> class HandyForTesting:
... def __init__(self, name): self.name=name
... def __str__(self):
... return "%s(%s)" % (self.name, self.__class__.__name__)
... __repr__=__str__
>>> class E(Explicit, HandyForTesting):
... pass
>>> class Nice(HandyForTesting):
... isNice=1
... def __str__(self):
... return HandyForTesting.__str__(self)+' and I am nice!'
... __repr__=__str__
>>> a = E('a')
>>> a.b = E('b')
>>> a.b.c = E('c')
>>> a.p = Nice('spam')
>>> a.b.p = E('p')
>>> def find_nice(self, ancestor, name, object, extra):
... return hasattr(object,'isNice') and object.isNice
>>> print a.b.c.aq_acquire('p', find_nice)
spam(Nice) and I am nice!
The filtered acquisition in the last line skips over the first
attribute it finds with the name 'p', because the attribute
doesn't satisfy the condition given in the filter.
Acquisition and methods
Python methods of objects that support acquisition can use
acquired attributes as in the 'report' method of the first example
above. When a Python method is called on an object that is
wrapped by an acquisition wrapper, the wrapper is passed to the
method as the first argument. This rule also applies to
user-defined method types and to C methods defined in pure mix-in
classes.
Unfortunately, C methods defined in extension base classes that
define their own data structures, cannot use aquired attributes at
this time. This is because wrapper objects do not conform to the
data structures expected by these methods.
Acquiring Acquiring objects
Consider the following example::
>>> from Acquisition import Implicit
>>> class C(Implicit):
... def __init__(self, name): self.name=name
... def __str__(self):
... return "%s(%s)" % (self.name, self.__class__.__name__)
... __repr__=__str__
>>> a = C("a")
>>> a.b = C("b")
>>> a.b.pref = "spam"
>>> a.b.c = C("c")
>>> a.b.c.color = "red"
>>> a.b.c.pref = "eggs"
>>> a.x = C("x")
>>> o = a.b.c.x
The expression 'o.color' might be expected to return '"red"'. In
earlier versions of ExtensionClass, however, this expression
failed. Acquired acquiring objects did not acquire from the
environment they were accessed in, because objects were only
wrapped when they were first found, and were not rewrapped as they
were passed down the acquisition tree.
In the current release of ExtensionClass, the expression "o.color"
does indeed return '"red"'.
>>> o.color
'red'
When searching for an attribute in 'o', objects are searched in
the order 'x', 'a', 'b', 'c'. So, for example, the expression,
'o.pref' returns '"spam"', not '"eggs"'::
>>> o.pref
'spam'
In earlier releases of ExtensionClass, the attempt to get the
'pref' attribute from 'o' would have failed.
If desired, the current rules for looking up attributes in complex
expressions can best be understood through repeated application of
the '__of__' method:
'a.x' -- 'x.__of__(a)'
'a.b' -- 'b.__of__(a)'
'a.b.x' -- 'x.__of__(a).__of__(b.__of__(a))'
'a.b.c' -- 'c.__of__(b.__of__(a))'
'a.b.c.x' --
'x.__of__(a).__of__(b.__of__(a)).__of__(c.__of__(b.__of__(a)))'
and by keeping in mind that attribute lookup in a wrapper
is done by trying to lookup the attribute in the wrapped object
first and then in the parent object. In the expressions above
involving the '__of__' method, lookup proceeds from left to right.
Note that heuristics are used to avoid most of the repeated
lookups. For example, in the expression: 'a.b.c.x.foo', the object
'a' is searched no more than once, even though it is wrapped three
times.
.. [1] Gil, J., Lorenz, D.,
"Environmental Acquisition--A New Inheritance-Like Abstraction Mechanism",
http://www.bell-labs.com/people/cope/oopsla/Oopsla96TechnicalProgramAbstracts.html#GilLorenz,
OOPSLA '96 Proceedings, ACM SIG-PLAN, October, 1996
$Id: tests.py,v 1.2 2003/11/28 16:44:14 jim Exp $
"""
import
ExtensionClass
import
Acquisition
class
I
(
Acquisition
.
Implicit
):
def
__init__
(
self
,
id
):
self
.
id
=
id
def
__repr__
(
self
):
return
self
.
id
class
E
(
Acquisition
.
Explicit
):
def
__init__
(
self
,
id
):
self
.
id
=
id
def
__repr__
(
self
):
return
self
.
id
def
test_unwrapped
():
"""
>>> c = I('unwrapped')
>>> show(c)
unwrapped
>>> c.aq_parent
Traceback (most recent call last):
...
AttributeError: aq_parent
>>> Acquisition.aq_acquire(c, 'id')
'unwrapped'
>>> Acquisition.aq_acquire(c, 'x')
Traceback (most recent call last):
...
AttributeError: x
>>> Acquisition.aq_acquire(c, 'id',
... lambda searched, parent, name, ob, extra: extra)
Traceback (most recent call last):
...
AttributeError: id
>>> Acquisition.aq_acquire(c, 'id',
... lambda searched, parent, name, ob, extra: extra,
... 1)
'unwrapped'
>>> Acquisition.aq_base(c) is c
1
>>> Acquisition.aq_chain(c)
[unwrapped]
>>> Acquisition.aq_chain(c, 1)
[unwrapped]
>>> Acquisition.aq_get(c, 'id')
'unwrapped'
>>> Acquisition.aq_get(c, 'x')
Traceback (most recent call last):
...
AttributeError: x
>>> Acquisition.aq_get(c, 'x', 'foo')
'foo'
>>> Acquisition.aq_get(c, 'x', 'foo', 1)
'foo'
>>> Acquisition.aq_inner(c) is c
1
>>> Acquisition.aq_parent(c)
>>> Acquisition.aq_self(c) is c
1
"""
def
test_simple
():
"""
>>> a = I('a')
>>> a.y = 42
>>> a.b = I('b')
>>> a.b.c = I('c')
>>> show(a.b.c)
c
|
b
|
a
>>> show(a.b.c.aq_parent)
b
|
a
>>> show(a.b.c.aq_self)
c
>>> show(a.b.c.aq_base)
c
>>> show(a.b.c.aq_inner)
c
|
b
|
a
>>> a.b.c.y
42
>>> a.b.c.aq_chain
[c, b, a]
>>> a.b.c.aq_inContextOf(a)
1
>>> a.b.c.aq_inContextOf(a.b)
1
>>> a.b.c.aq_inContextOf(a.b.c)
1
>>> a.b.c.aq_acquire('y')
42
>>> a.b.c.aq_acquire('id')
'c'
>>> a.b.c.aq_acquire('x')
Traceback (most recent call last):
...
AttributeError: x
>>> a.b.c.aq_acquire('id',
... lambda searched, parent, name, ob, extra: extra)
Traceback (most recent call last):
...
AttributeError: id
>>> Acquisition.aq_acquire(a.b.c, 'id',
... lambda searched, parent, name, ob, extra: extra,
... 1)
'c'
>>> Acquisition.aq_acquire(a.b.c, 'id')
'c'
>>> Acquisition.aq_acquire(a.b.c, 'x')
Traceback (most recent call last):
...
AttributeError: x
>>> Acquisition.aq_acquire(a.b.c, 'y')
42
>>> Acquisition.aq_acquire(a.b.c, 'id',
... lambda searched, parent, name, ob, extra: extra)
Traceback (most recent call last):
...
AttributeError: id
>>> Acquisition.aq_acquire(a.b.c, 'id',
... lambda searched, parent, name, ob, extra: extra,
... 1)
'c'
>>> show(Acquisition.aq_base(a.b.c))
c
>>> Acquisition.aq_chain(a.b.c)
[c, b, a]
>>> Acquisition.aq_chain(a.b.c, 1)
[c, b, a]
>>> Acquisition.aq_get(a.b.c, 'id')
'c'
>>> Acquisition.aq_get(a.b.c, 'x')
Traceback (most recent call last):
...
AttributeError: x
>>> Acquisition.aq_get(a.b.c, 'x', 'foo')
'foo'
>>> Acquisition.aq_get(a.b.c, 'x', 'foo', 1)
'foo'
>>> show(Acquisition.aq_inner(a.b.c))
c
|
b
|
a
>>> show(Acquisition.aq_parent(a.b.c))
b
|
a
>>> show(Acquisition.aq_self(a.b.c))
c
"""
def
test_muliple
():
r"""
>>> a = I('a')
>>> a.color = 'red'
>>> a.a1 = I('a1')
>>> a.a1.color = 'green'
>>> a.a1.a11 = I('a11')
>>> a.a2 = I('a2')
>>> a.a2.a21 = I('a21')
>>> show(a.a1.a11.a2.a21)
a21
|
(a2)
| \
| (a2)
| | \
| | a2
| | |
| | a
| |
| a1
| |
| a
|
a11
|
a1
|
a
>>> a.a1.a11.a2.a21.color
'red'
>>> show(a.a1.a11.a2.a21.aq_parent)
(a2)
| \
| (a2)
| | \
| | a2
| | |
| | a
| |
| a1
| |
| a
|
a11
|
a1
|
a
>>> show(a.a1.a11.a2.a21.aq_parent.aq_parent)
a11
|
a1
|
a
>>> show(a.a1.a11.a2.a21.aq_self)
a21
>>> show(a.a1.a11.a2.a21.aq_parent.aq_self)
(a2)
| \
| a2
| |
| a
|
a1
|
a
>>> show(a.a1.a11.a2.a21.aq_base)
a21
>>> show(a.a1.a11.a2.a21.aq_inner)
a21
|
(a2)
| \
| (a2)
| | \
| | a2
| | |
| | a
| |
| a1
| |
| a
|
a11
|
a1
|
a
>>> show(a.a1.a11.a2.a21.aq_inner.aq_parent.aq_inner)
a2
|
a
>>> show(a.a1.a11.a2.a21.aq_inner.aq_parent.aq_inner.aq_parent)
a
>>> a.a1.a11.a2.a21.aq_chain
[a21, a2, a11, a1, a]
>>> a.a1.a11.a2.a21.aq_inContextOf(a)
1
>>> a.a1.a11.a2.a21.aq_inContextOf(a.a2)
1
>>> a.a1.a11.a2.a21.aq_inContextOf(a.a1)
0
>>> a.a1.a11.a2.a21.aq_acquire('color')
'red'
>>> a.a1.a11.a2.a21.aq_acquire('id')
'a21'
>>> a.a1.a11.a2.a21.aq_acquire('color',
... lambda ob, parent, name, v, extra: extra)
Traceback (most recent call last):
...
AttributeError: color
>>> a.a1.a11.a2.a21.aq_acquire('color',
... lambda ob, parent, name, v, extra: extra, 1)
'red'
>>> a.a1.y = 42
>>> a.a1.a11.a2.a21.aq_acquire('y')
42
>>> a.a1.a11.a2.a21.aq_acquire('y', containment=1)
Traceback (most recent call last):
...
AttributeError: y
Much of the same, but with methods:
>>> show(Acquisition.aq_parent(a.a1.a11.a2.a21))
(a2)
| \
| (a2)
| | \
| | a2
| | |
| | a
| |
| a1
| |
| a
|
a11
|
a1
|
a
>>> show(Acquisition.aq_parent(a.a1.a11.a2.a21.aq_parent))
a11
|
a1
|
a
>>> show(Acquisition.aq_self(a.a1.a11.a2.a21))
a21
>>> show(Acquisition.aq_self(a.a1.a11.a2.a21.aq_parent))
(a2)
| \
| a2
| |
| a
|
a1
|
a
>>> show(Acquisition.aq_base(a.a1.a11.a2.a21))
a21
>>> show(Acquisition.aq_inner(a.a1.a11.a2.a21))
a21
|
(a2)
| \
| (a2)
| | \
| | a2
| | |
| | a
| |
| a1
| |
| a
|
a11
|
a1
|
a
>>> show(Acquisition.aq_inner(a.a1.a11.a2.a21.aq_inner.aq_parent))
a2
|
a
>>> show(Acquisition.aq_parent(
... a.a1.a11.a2.a21.aq_inner.aq_parent.aq_inner))
a
>>> Acquisition.aq_chain(a.a1.a11.a2.a21)
[a21, a2, a11, a1, a]
>>> Acquisition.aq_chain(a.a1.a11.a2.a21, 1)
[a21, a2, a]
>>> Acquisition.aq_acquire(a.a1.a11.a2.a21, 'color')
'red'
>>> Acquisition.aq_acquire(a.a1.a11.a2.a21, 'id')
'a21'
>>> Acquisition.aq_acquire(a.a1.a11.a2.a21, 'color',
... lambda ob, parent, name, v, extra: extra)
Traceback (most recent call last):
...
AttributeError: color
>>> Acquisition.aq_acquire(a.a1.a11.a2.a21, 'color',
... lambda ob, parent, name, v, extra: extra, 1)
'red'
>>> a.a1.y = 42
>>> Acquisition.aq_acquire(a.a1.a11.a2.a21, 'y')
42
>>> Acquisition.aq_acquire(a.a1.a11.a2.a21, 'y', containment=1)
Traceback (most recent call last):
...
AttributeError: y
"""
def
test_pinball
():
r"""
>>> a = I('a')
>>> a.a1 = I('a1')
>>> a.a1.a11 = I('a11')
>>> a.a1.a12 = I('a12')
>>> a.a2 = I('a2')
>>> a.a2.a21 = I('a21')
>>> a.a2.a22 = I('a22')
>>> show(a.a1.a11.a1.a12.a2.a21.a2.a22)
a22
|
(a2)
| \
| (a2)
| | \
| | a2
| | |
| | a
| |
| (a2)
| | \
| | (a2)
| | | \
| | | a2
| | | |
| | | a
| | |
| | (a1)
| | | \
| | | (a1)
| | | | \
| | | | a1
| | | | |
| | | | a
| | | |
| | | a1
| | | |
| | | a
| | |
| | a11
| | |
| | a1
| | |
| | a
| |
| a12
| |
| (a1)
| | \
| | (a1)
| | | \
| | | a1
| | | |
| | | a
| | |
| | a1
| | |
| | a
| |
| a11
| |
| a1
| |
| a
|
a21
|
(a2)
| \
| (a2)
| | \
| | a2
| | |
| | a
| |
| (a1)
| | \
| | (a1)
| | | \
| | | a1
| | | |
| | | a
| | |
| | a1
| | |
| | a
| |
| a11
| |
| a1
| |
| a
|
a12
|
(a1)
| \
| (a1)
| | \
| | a1
| | |
| | a
| |
| a1
| |
| a
|
a11
|
a1
|
a
"""
def
test_explicit
():
"""
>>> a = E('a')
>>> a.y = 42
>>> a.b = E('b')
>>> a.b.c = E('c')
>>> show(a.b.c)
c
|
b
|
a
>>> show(a.b.c.aq_parent)
b
|
a
>>> show(a.b.c.aq_self)
c
>>> show(a.b.c.aq_base)
c
>>> show(a.b.c.aq_inner)
c
|
b
|
a
>>> a.b.c.y
Traceback (most recent call last):
...
AttributeError: y
>>> a.b.c.aq_chain
[c, b, a]
>>> a.b.c.aq_inContextOf(a)
1
>>> a.b.c.aq_inContextOf(a.b)
1
>>> a.b.c.aq_inContextOf(a.b.c)
1
>>> a.b.c.aq_acquire('y')
42
>>> a.b.c.aq_acquire('id')
'c'
>>> a.b.c.aq_acquire('x')
Traceback (most recent call last):
...
AttributeError: x
>>> a.b.c.aq_acquire('id',
... lambda searched, parent, name, ob, extra: extra)
Traceback (most recent call last):
...
AttributeError: id
>>> Acquisition.aq_acquire(a.b.c, 'id',
... lambda searched, parent, name, ob, extra: extra,
... 1)
'c'
>>> Acquisition.aq_acquire(a.b.c, 'id')
'c'
>>> Acquisition.aq_acquire(a.b.c, 'x')
Traceback (most recent call last):
...
AttributeError: x
>>> Acquisition.aq_acquire(a.b.c, 'y')
42
>>> Acquisition.aq_acquire(a.b.c, 'id',
... lambda searched, parent, name, ob, extra: extra)
Traceback (most recent call last):
...
AttributeError: id
>>> Acquisition.aq_acquire(a.b.c, 'id',
... lambda searched, parent, name, ob, extra: extra,
... 1)
'c'
>>> show(Acquisition.aq_base(a.b.c))
c
>>> Acquisition.aq_chain(a.b.c)
[c, b, a]
>>> Acquisition.aq_chain(a.b.c, 1)
[c, b, a]
>>> Acquisition.aq_get(a.b.c, 'id')
'c'
>>> Acquisition.aq_get(a.b.c, 'x')
Traceback (most recent call last):
...
AttributeError: x
>>> Acquisition.aq_get(a.b.c, 'y')
42
>>> Acquisition.aq_get(a.b.c, 'x', 'foo')
'foo'
>>> Acquisition.aq_get(a.b.c, 'x', 'foo', 1)
'foo'
>>> show(Acquisition.aq_inner(a.b.c))
c
|
b
|
a
>>> show(Acquisition.aq_parent(a.b.c))
b
|
a
>>> show(Acquisition.aq_self(a.b.c))
c
"""
def
test_mixed_explicit_and_explicit
():
"""
>>> a = I('a')
>>> a.y = 42
>>> a.b = E('b')
>>> a.b.z = 3
>>> a.b.c = I('c')
>>> show(a.b.c)
c
|
b
|
a
>>> show(a.b.c.aq_parent)
b
|
a
>>> show(a.b.c.aq_self)
c
>>> show(a.b.c.aq_base)
c
>>> show(a.b.c.aq_inner)
c
|
b
|
a
>>> a.b.c.y
42
>>> a.b.c.z
3
>>> a.b.c.aq_chain
[c, b, a]
>>> a.b.c.aq_inContextOf(a)
1
>>> a.b.c.aq_inContextOf(a.b)
1
>>> a.b.c.aq_inContextOf(a.b.c)
1
>>> a.b.c.aq_acquire('y')
42
>>> a.b.c.aq_acquire('z')
3
>>> a.b.c.aq_acquire('z', explicit=False)
3
>>> a.b.c.aq_acquire('id')
'c'
>>> a.b.c.aq_acquire('x')
Traceback (most recent call last):
...
AttributeError: x
>>> a.b.c.aq_acquire('id',
... lambda searched, parent, name, ob, extra: extra)
Traceback (most recent call last):
...
AttributeError: id
>>> Acquisition.aq_acquire(a.b.c, 'id',
... lambda searched, parent, name, ob, extra: extra,
... 1)
'c'
>>> Acquisition.aq_acquire(a.b.c, 'id')
'c'
>>> Acquisition.aq_acquire(a.b.c, 'x')
Traceback (most recent call last):
...
AttributeError: x
>>> Acquisition.aq_acquire(a.b.c, 'y')
42
>>> Acquisition.aq_acquire(a.b.c, 'id',
... lambda searched, parent, name, ob, extra: extra)
Traceback (most recent call last):
...
AttributeError: id
>>> Acquisition.aq_acquire(a.b.c, 'id',
... lambda searched, parent, name, ob, extra: extra,
... 1)
'c'
>>> show(Acquisition.aq_base(a.b.c))
c
>>> Acquisition.aq_chain(a.b.c)
[c, b, a]
>>> Acquisition.aq_chain(a.b.c, 1)
[c, b, a]
>>> Acquisition.aq_get(a.b.c, 'id')
'c'
>>> Acquisition.aq_get(a.b.c, 'x')
Traceback (most recent call last):
...
AttributeError: x
>>> Acquisition.aq_get(a.b.c, 'y')
42
>>> Acquisition.aq_get(a.b.c, 'x', 'foo')
'foo'
>>> Acquisition.aq_get(a.b.c, 'x', 'foo', 1)
'foo'
>>> show(Acquisition.aq_inner(a.b.c))
c
|
b
|
a
>>> show(Acquisition.aq_parent(a.b.c))
b
|
a
>>> show(Acquisition.aq_self(a.b.c))
c
"""
def
old_tests
():
"""
>>> from ExtensionClass import Base
>>> import Acquisition
>>> class B(Base):
... color='red'
>>> class A(Acquisition.Implicit):
... def hi(self):
... print "%s()" % self.__class__.__name__, self.color
>>> b=B()
>>> b.a=A()
>>> b.a.hi()
A() red
>>> b.a.color='green'
>>> b.a.hi()
A() green
>>> try:
... A().hi()
... raise 'Program error', 'spam'
... except AttributeError: pass
A()
New test for wrapper comparisons.
>>> foo = b.a
>>> bar = b.a
>>> foo == bar
1
>>> c = A()
>>> b.c = c
>>> b.c.d = c
>>> b.c.d == c
1
>>> b.c.d == b.c
1
>>> b.c == c
1
>>> def checkContext(self, o):
... # Python equivalent to aq_inContextOf
... from Acquisition import aq_base, aq_parent, aq_inner
... subob = self
... o = aq_base(o)
... while 1:
... if aq_base(subob) is o: return 1
... self = aq_inner(subob)
... if self is None: break
... subob = aq_parent(self)
... if subob is None: break
>>> checkContext(b.c, b)
1
>>> not checkContext(b.c, b.a)
1
>>> b.a.aq_inContextOf(b)
1
>>> b.c.aq_inContextOf(b)
1
>>> b.c.d.aq_inContextOf(b)
1
>>> b.c.d.aq_inContextOf(c)
1
>>> b.c.d.aq_inContextOf(b.c)
1
>>> not b.c.aq_inContextOf(foo)
1
>>> not b.c.aq_inContextOf(b.a)
1
>>> not b.a.aq_inContextOf('somestring')
1
"""
def
test_AqAlg
():
"""
>>> A=I('A')
>>> A.B=I('B')
>>> A.B.color='red'
>>> A.C=I('C')
>>> A.C.D=I('D')
>>> A
A
>>> Acquisition.aq_chain(A)
[A]
>>> Acquisition.aq_chain(A, 1)
[A]
>>> map(Acquisition.aq_base, Acquisition.aq_chain(A, 1))
[A]
>>> A.C
C
>>> Acquisition.aq_chain(A.C)
[C, A]
>>> Acquisition.aq_chain(A.C, 1)
[C, A]
>>> map(Acquisition.aq_base, Acquisition.aq_chain(A.C, 1))
[C, A]
>>> A.C.D
D
>>> Acquisition.aq_chain(A.C.D)
[D, C, A]
>>> Acquisition.aq_chain(A.C.D, 1)
[D, C, A]
>>> map(Acquisition.aq_base, Acquisition.aq_chain(A.C.D, 1))
[D, C, A]
>>> A.B.C
C
>>> Acquisition.aq_chain(A.B.C)
[C, B, A]
>>> Acquisition.aq_chain(A.B.C, 1)
[C, A]
>>> map(Acquisition.aq_base, Acquisition.aq_chain(A.B.C, 1))
[C, A]
>>> A.B.C.D
D
>>> Acquisition.aq_chain(A.B.C.D)
[D, C, B, A]
>>> Acquisition.aq_chain(A.B.C.D, 1)
[D, C, A]
>>> map(Acquisition.aq_base, Acquisition.aq_chain(A.B.C.D, 1))
[D, C, A]
>>> A.B.C.D.color
'red'
>>> Acquisition.aq_get(A.B.C.D, "color", None)
'red'
>>> Acquisition.aq_get(A.B.C.D, "color", None, 1)
"""
def
test_explicit_acquisition
():
"""
>>> from ExtensionClass import Base
>>> import Acquisition
>>> class B(Base):
... color='red'
>>> class A(Acquisition.Explicit):
... def hi(self):
... print self.__class__.__name__, self.acquire('color')
>>> b=B()
>>> b.a=A()
>>> b.a.hi()
A red
>>> b.a.color='green'
>>> b.a.hi()
A green
>>> try:
... A().hi()
... raise 'Program error', 'spam'
... except AttributeError: pass
A
"""
def
test_creating_wrappers_directly
():
"""
>>> from ExtensionClass import Base
>>> from Acquisition import ImplicitAcquisitionWrapper
>>> class B(Base):
... pass
>>> a = B()
>>> a.color = 'red'
>>> a.b = B()
>>> w = ImplicitAcquisitionWrapper(a.b, a)
>>> w.color
'red'
>>> w = ImplicitAcquisitionWrapper(a.b)
Traceback (most recent call last):
...
TypeError: argument must be 2-item sequence, not B
We can reassign aq_parent
>>> x = B()
>>> x.color = 'green'
>>> w.aq_parent = x
>>> w.color
'green'
>>> w = ImplicitAcquisitionWrapper()
Traceback (most recent call last):
...
TypeError: function takes at least one argument
"""
def
test_cant_pickle_acquisition_wrappers_classic
():
"""
>>> import pickle
>>> class X:
... def __getstate__(self):
... return 1
We shouldn't be able to pickle wrappers:
>>> from Acquisition import ImplicitAcquisitionWrapper
>>> w = ImplicitAcquisitionWrapper(X(), X())
>>> pickle.dumps(w)
Traceback (most recent call last):
...
TypeError: Can't pickle objects in acquisition wrappers.
But that's not enough. We need to defeat persistence as well. :)
This is tricky. We want to generate the error in __getstate__, not
in the attr access, as attribute errors are too-often hidden:
>>> getstate = w.__getstate__
>>> getstate()
Traceback (most recent call last):
...
TypeError: Can't pickle objects in acquisition wrappers.
We shouldn't be able to pickle wrappers:
>>> from Acquisition import ExplicitAcquisitionWrapper
>>> w = ExplicitAcquisitionWrapper(X(), X())
>>> pickle.dumps(w)
Traceback (most recent call last):
...
TypeError: Can't pickle objects in acquisition wrappers.
But that's not enough. We need to defeat persistence as well. :)
This is tricky. We want to generate the error in __getstate__, not
in the attr access, as attribute errors are too-often hidden:
>>> getstate = w.__getstate__
>>> getstate()
Traceback (most recent call last):
...
TypeError: Can't pickle objects in acquisition wrappers.
"""
def
test_cant_pickle_acquisition_wrappers_newstyle
():
"""
>>> import pickle
>>> class X(object):
... def __getstate__(self):
... return 1
We shouldn't be able to pickle wrappers:
>>> from Acquisition import ImplicitAcquisitionWrapper
>>> w = ImplicitAcquisitionWrapper(X(), X())
>>> pickle.dumps(w)
Traceback (most recent call last):
...
TypeError: Can't pickle objects in acquisition wrappers.
But that's not enough. We need to defeat persistence as well. :)
This is tricky. We want to generate the error in __getstate__, not
in the attr access, as attribute errors are too-often hidden:
>>> getstate = w.__getstate__
>>> getstate()
Traceback (most recent call last):
...
TypeError: Can't pickle objects in acquisition wrappers.
We shouldn't be able to pickle wrappers:
>>> from Acquisition import ExplicitAcquisitionWrapper
>>> w = ExplicitAcquisitionWrapper(X(), X())
>>> pickle.dumps(w)
Traceback (most recent call last):
...
TypeError: Can't pickle objects in acquisition wrappers.
But that's not enough. We need to defeat persistence as well. :)
This is tricky. We want to generate the error in __getstate__, not
in the attr access, as attribute errors are too-often hidden:
>>> getstate = w.__getstate__
>>> getstate()
Traceback (most recent call last):
...
TypeError: Can't pickle objects in acquisition wrappers.
"""
def
show
(
x
):
print
showaq
(
x
).
strip
()
def
showaq
(
m_self
,
indent
=
''
):
rval
=
''
obj
=
m_self
base
=
getattr
(
obj
,
'aq_base'
,
obj
)
try
:
id
=
base
.
id
except
:
id
=
str
(
base
)
try
:
id
=
id
()
except
:
pass
if
hasattr
(
obj
,
'aq_self'
):
if
hasattr
(
obj
.
aq_self
,
'aq_self'
):
rval
=
rval
+
indent
+
"("
+
id
+
")
\
n
"
rval
=
rval
+
indent
+
"|
\
\
\
n
"
rval
=
rval
+
showaq
(
obj
.
aq_self
,
'| '
+
indent
)
rval
=
rval
+
indent
+
"|
\
n
"
rval
=
rval
+
showaq
(
obj
.
aq_parent
,
indent
)
elif
hasattr
(
obj
,
'aq_parent'
):
rval
=
rval
+
indent
+
id
+
"
\
n
"
rval
=
rval
+
indent
+
"|
\
n
"
rval
=
rval
+
showaq
(
obj
.
aq_parent
,
indent
)
else
:
rval
=
rval
+
indent
+
id
+
"
\
n
"
return
rval
import
unittest
from
doctest
import
DocTestSuite
def
test_suite
():
return
unittest
.
TestSuite
((
DocTestSuite
(),
))
if
__name__
==
'__main__'
:
unittest
.
main
()
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