[Zope-Checkins] CVS: Zope2 - DT_Util.py:1.81 cDocumentTemplate.c:1.39 pDocumentTemplate.py:1.30
shane@digicool.com
shane@digicool.com
Thu, 21 Jun 2001 15:08:59 -0400 (EDT)
Update of /cvs-repository/Zope2/lib/python/DocumentTemplate
In directory korak.digicool.com:/tmp/cvs-serv29498
Modified Files:
DT_Util.py cDocumentTemplate.c pDocumentTemplate.py
Log Message:
The old "AttributeError: __call__" bug resurfaced with Python 2.1, but this
change is intended to solve it once and for all: there's now a "safe_callable"
function, implemented both in cDocumentTemplate and pDocumentTemplate, that
can more reliably check for callability.
A surprising side effect is that DTML is about 15% faster with this change
(according to a rudimentary test).
--- Updated File DT_Util.py in package Zope2 --
--- DT_Util.py 2001/06/21 17:45:12 1.80
+++ DT_Util.py 2001/06/21 19:08:59 1.81
@@ -112,8 +112,10 @@
try:
import ExtensionClass
- from cDocumentTemplate import InstanceDict, TemplateDict, render_blocks
-except: from pDocumentTemplate import InstanceDict, TemplateDict, render_blocks
+ from cDocumentTemplate import InstanceDict, TemplateDict, \
+ render_blocks, safe_callable
+except: from pDocumentTemplate import InstanceDict, TemplateDict, \
+ render_blocks, safe_callable
functype = type(int_param)
@@ -185,15 +187,11 @@
v = v.__render_with_namespace__(self)
else:
vbase = getattr(v, 'aq_base', v)
- if callable(vbase):
- try:
- if getattr(vbase, 'isDocTemp', 0):
- v = v(None, self)
- else:
- v = v()
- except AttributeError, n:
- if n != '__call__':
- raise
+ if safe_callable(vbase):
+ if getattr(vbase, 'isDocTemp', 0):
+ v = v(None, self)
+ else:
+ v = v()
return v
d['render']=render
--- Updated File cDocumentTemplate.c in package Zope2 --
--- cDocumentTemplate.c 2001/06/21 17:45:12 1.38
+++ cDocumentTemplate.c 2001/06/21 19:08:59 1.39
@@ -94,6 +94,7 @@
static PyObject *py_hasRole, *py__proxy_roles, *py_Unauthorized;
static PyObject *py_Unauthorized_fmt, *py_guarded_getattr;
static PyObject *py__push, *py__pop, *py_aq_base, *py_renderNS;
+static PyObject *py___class__;
/* ----------------------------------------------------- */
@@ -322,7 +323,35 @@
return Py_None;
}
+static int
+safe_PyCallable_Check(PyObject *x)
+{
+ PyObject *klass;
+ if (x == NULL)
+ return 0;
+ klass = PyObject_GetAttr(x, py___class__);
+ if (klass) {
+ PyObject *call = PyObject_GetAttr(x, py___call__);
+ if (call) {
+ Py_DECREF(klass);
+ Py_DECREF(call);
+ return 1;
+ }
+ else {
+ PyErr_Clear();
+ Py_DECREF(klass);
+ if (PyClass_Check(x) || PyExtensionClass_Check(x))
+ return 1;
+ else
+ return 0;
+ }
+ }
+ else {
+ PyErr_Clear();
+ return PyCallable_Check(x);
+ }
+}
static int
dtObjectIsCallable(PyObject *ob) {
@@ -332,9 +361,9 @@
/* Ensure that an object is really callable by unwrapping it */
UNLESS(base=PyObject_GetAttr(ob, py_aq_base)) {
PyErr_Clear();
- return PyCallable_Check(ob);
+ return safe_PyCallable_Check(ob);
}
- result=PyCallable_Check(base);
+ result=safe_PyCallable_Check(base);
Py_DECREF(base);
return result;
}
@@ -369,7 +398,7 @@
MM_cget(MM *self, PyObject *key, int call)
{
long i;
- PyObject *e, *t, *rr, *tb;
+ PyObject *e, *rr, *tb;
UNLESS(-1 != (i=PyList_Size(self->data))) return NULL;
while (--i >= 0)
@@ -401,27 +430,10 @@
rr=PyObject_CallObject(e,NULL);
if (rr) ASSIGN(e,rr);
- else
- {
- PyErr_Fetch(&t, &rr, &tb);
- if (t!=PyExc_AttributeError ||
- PyObject_Compare(rr,py___call__) != 0)
- {
- PyErr_Restore(t,rr,tb);
- Py_DECREF(e);
- return NULL;
- }
- /*
- Added by Brian on 08/30/99. We need to be sure
- to DECREF the exception in the event of an
- AttributeError to avoid leaking.
- */
- else {
- Py_XDECREF(t);
- Py_XDECREF(rr);
- Py_XDECREF(tb);
- }
- }
+ else {
+ Py_DECREF(e);
+ return NULL;
+ }
}
return e;
}
@@ -865,9 +877,26 @@
return NULL;
}
+static PyObject *
+safe_callable(PyObject *self, PyObject *args)
+{
+ PyObject *ob;
+ int res;
+
+ UNLESS(PyArg_ParseTuple(args,"O", &ob)) return NULL;
+ res = safe_PyCallable_Check(ob);
+ if (res)
+ return PyInt_FromLong(1);
+ else
+ return PyInt_FromLong(0);
+}
+
static struct PyMethodDef Module_Level__methods[] = {
{"render_blocks", (PyCFunction)render_blocks, METH_VARARGS,
""},
+ {"safe_callable", (PyCFunction)safe_callable, METH_VARARGS,
+ "callable() with a workaround for a problem with ExtensionClasses\n"
+ "and __call__()."},
{NULL, (PyCFunction)NULL, 0, NULL} /* sentinel */
};
@@ -894,6 +923,7 @@
UNLESS(py_Unauthorized=PyString_FromString("Unauthorized")) return;
UNLESS(py_Unauthorized_fmt=PyString_FromString(
"You are not authorized to access <em>%s</em>.")) return;
+ UNLESS(py___class__=PyString_FromString("__class__")) return;
UNLESS(py_AUTHENTICATED_USER=PyString_FromString("AUTHENTICATED_USER"))
return;
--- Updated File pDocumentTemplate.py in package Zope2 --
--- pDocumentTemplate.py 2001/06/21 17:45:12 1.29
+++ pDocumentTemplate.py 2001/06/21 19:08:59 1.30
@@ -91,29 +91,31 @@
import string, sys, types
from string import join
+ClassTypes = [types.ClassType]
+
+try:
+ from ExtensionClass import Base
+except ImportError:
+ pass
+else:
+ class c(Base): pass
+ ClassTypes.append(c.__class__)
+
+
+def safe_callable(ob):
+ # Works with ExtensionClasses and Acquisition.
+ if hasattr(ob, '__class__'):
+ if hasattr(ob, '__call__'):
+ return 1
+ else:
+ return type(ob) in ClassTypes
+ else:
+ return callable(ob)
+
+
StringType=type('')
TupleType=type(())
-isFunctionType={}
-for name in ['BuiltinFunctionType', 'BuiltinMethodType', 'ClassType',
- 'FunctionType', 'LambdaType', 'MethodType', 'UnboundMethodType']:
- try: isFunctionType[getattr(types,name)]=1
- except: pass
-
-try: # Add function and method types from Extension Classes
- import ExtensionClass
- isFunctionType[ExtensionClass.PythonMethodType]=1
- isFunctionType[ExtensionClass.ExtensionMethodType]=1
-except: pass
-
-isFunctionType=isFunctionType.has_key
-
-isSimpleType={}
-for n in dir(types):
- if (n[-4:]=='Type' and n != 'InstanceType' and
- not isFunctionType(getattr(types, n))):
- isSimpleType[getattr(types, n)]=1
-isSimpleType=isSimpleType.has_key
class InstanceDict:
@@ -204,25 +206,18 @@
try: self.keys=m.keys
except: pass
- def __getitem__(self,key,call=1,
- simple=isSimpleType,
- isFunctionType=isFunctionType,
- ):
+ def __getitem__(self,key,call=1):
v = self.dicts[key]
if call:
if hasattr(v, '__render_with_namespace__'):
return v.__render_with_namespace__(self)
vbase = getattr(v, 'aq_base', v)
- if callable(vbase):
- try:
- if getattr(vbase, 'isDocTemp', 0):
- v = v(None, self)
- else:
- v = v()
- except AttributeError, n:
- if n != '__call__':
- raise
+ if safe_callable(vbase):
+ if getattr(vbase, 'isDocTemp', 0):
+ v = v(None, self)
+ else:
+ v = v()
return v
def has_key(self,key):