[Zope] [ANN] Zope 2.2 patch for cDocumentTemplate/Acquisition bug
Dieter Maurer
dieter@handshake.de
Sun, 5 Nov 2000 19:08:04 +0100 (CET)
Appended is a patch for the cDocumentTemplate/Acquisition bug.
Usually, this bug manifests itself by an "AttributeError: __call__"
for a folder object. The usual context is:
DTML Document:
.....
<dtml-with folder> <!-- here is the Attribute Error -->
....
</dtml-with>
.....
The patch modifies "C" code. This means you need a Zope source
distribution to apply it and then you must regenerate Zope.
Almost surely, the patch is not yet complete:
The code in "cDocumentTemplate.c" looks like (Python emulating
"C" code):
if callable(o):
if hasattr('isDocTemp') and o.isDocTemp:
o= o(None,md)
else: o= o()
The remaining problem is that 'isDocTemp' might be acquired
and does not belong to "o.__call__". In this case, "o"
might be called with the wrong number of parameters.
I would expect, that the problem disappears, when the "isDocTemp"
test is performed with "o.aq_base" rather than "o". But
I am not sure.
Maybe, an acquisition expert can look into this remaining
issue.
Dieter
------------------------------------------------------------------------
--- lib/Components/ExtensionClass/:Acquisition.c Sat Oct 7 20:40:53 2000
+++ lib/Components/ExtensionClass/Acquisition.c Sat Nov 4 21:10:04 2000
@@ -1391,6 +1391,31 @@
return r;
}
+
+/* DM: adding "AqCallable_Check" */
+static int
+aqCallable(PyObject *o) {
+ if (isWrapper(o)) {
+ PyObject *call;
+
+ UNLESS(call=PyObject_GetAttr(o,py__call__)) {
+ PyErr_Clear();
+ return 0;
+ }
+ Py_DECREF(call); return 1;
+ } else
+ return PyCallable_Check(o);
+}
+
+static PyObject *
+AqCallable_Check(PyObject *ignored, PyObject *args)
+{
+ PyObject *o;
+
+ UNLESS (PyArg_ParseTuple(args, "O", &o)) return NULL;
+ return PyInt_FromLong((long) aqCallable(o));
+}
+
static struct PyMethodDef methods[] = {
{"aq_acquire", (PyCFunction)module_aq_acquire, METH_VARARGS|METH_KEYWORDS,
"aq_acquire(ob, name [, filter, extra, explicit]) -- "
@@ -1412,6 +1437,10 @@
{"aq_chain", (PyCFunction)module_aq_chain, METH_VARARGS,
"aq_chain(ob [, containment]) -- "
"Get a list of objects in the acquisition environment"},
+ /* DM */
+ {"callable", (PyCFunction)AqCallable_Check, METH_VARARGS,
+ "callable(ob) -- "
+ "return true iff the object is callable"},
{NULL, NULL}
};
--- lib/python/DocumentTemplate/:cDocumentTemplate.c Sat Jul 29 11:24:34 2000
+++ lib/python/DocumentTemplate/cDocumentTemplate.c Sat Nov 4 21:11:11 2000
@@ -95,14 +95,35 @@
static PyObject *py_Unauthorized_fmt, *py_validate;
static PyObject *py__push, *py__pop, *py_aq_base;
-/* ----------------------------------------------------- */
-
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))
+/* ----------------------------------------------------- */
+/* DM: callable */
+static int (*callable)(PyObject *o);
+
+static PyObject *aq_callable;
+
+static int aq_callable_check(PyObject *o) {
+ PyObject *result= PyObject_CallFunction(aq_callable,"O",o);
+ int callable= PyInt_AsLong(result);
+ Py_DECREF(result);
+ return callable;
+}
+
+static void init_callable() {
+ PyObject *aq= PyImport_ImportModule("Acquisition");
+ if(aq &&
+ (aq_callable= PyObject_GetAttrString(aq,"callable")))
+ callable= aq_callable_check;
+ else callable= PyCallable_Check;
+}
+
+/* ----------------------------------------------------- */
+
typedef struct {
PyObject_HEAD
PyObject *inst;
@@ -370,7 +391,7 @@
{
dt=0;
- if (PyCallable_Check(e))
+ if ((*callable)(e))
{
/* Decide whether we have a document template */
if (rr=PyObject_GetAttr(e,py_isDocTemp))
@@ -917,6 +938,9 @@
PyDict_SetItemString(d, "__version__",
PyString_FromStringAndSize(rev+11,strlen(rev+11)-2));
+
+ /* DM */
+ init_callable();
if (PyErr_Occurred())
Py_FatalError("can't initialize module cDocumentTemplate");