|
|
/*###########################################################################
|
|
|
#
|
|
|
# Copyright (c) 2003 Zope Foundation 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 "Python.h"
|
|
|
#include "structmember.h"
|
|
|
|
|
|
#define TYPE(O) ((PyTypeObject*)(O))
|
|
|
#define OBJECT(O) ((PyObject*)(O))
|
|
|
#define CLASSIC(O) ((PyClassObject*)(O))
|
|
|
#ifndef PyVarObject_HEAD_INIT
|
|
|
#define PyVarObject_HEAD_INIT(a, b) PyObject_HEAD_INIT(a) b,
|
|
|
#endif
|
|
|
#ifndef Py_TYPE
|
|
|
#define Py_TYPE(o) ((o)->ob_type)
|
|
|
#endif
|
|
|
|
|
|
#if PY_MAJOR_VERSION >= 3
|
|
|
#define PY3K
|
|
|
#endif
|
|
|
|
|
|
static PyObject *str__dict__, *str__implemented__, *strextends;
|
|
|
static PyObject *BuiltinImplementationSpecifications, *str__provides__;
|
|
|
static PyObject *str__class__, *str__providedBy__;
|
|
|
static PyObject *empty, *fallback, *str_implied, *str_cls, *str_implements;
|
|
|
static PyObject *str__conform__, *str_call_conform, *adapter_hooks;
|
|
|
static PyObject *str_uncached_lookup, *str_uncached_lookupAll;
|
|
|
static PyObject *str_uncached_subscriptions;
|
|
|
static PyObject *str_registry, *strro, *str_generation, *strchanged;
|
|
|
|
|
|
static PyTypeObject *Implements;
|
|
|
|
|
|
static int imported_declarations = 0;
|
|
|
|
|
|
static int
|
|
|
import_declarations(void)
|
|
|
{
|
|
|
PyObject *declarations, *i;
|
|
|
|
|
|
declarations = PyImport_ImportModule("zope.interface.declarations");
|
|
|
if (declarations == NULL)
|
|
|
return -1;
|
|
|
|
|
|
BuiltinImplementationSpecifications = PyObject_GetAttrString(
|
|
|
declarations, "BuiltinImplementationSpecifications");
|
|
|
if (BuiltinImplementationSpecifications == NULL)
|
|
|
return -1;
|
|
|
|
|
|
empty = PyObject_GetAttrString(declarations, "_empty");
|
|
|
if (empty == NULL)
|
|
|
return -1;
|
|
|
|
|
|
fallback = PyObject_GetAttrString(declarations, "implementedByFallback");
|
|
|
if (fallback == NULL)
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
|
|
i = PyObject_GetAttrString(declarations, "Implements");
|
|
|
if (i == NULL)
|
|
|
return -1;
|
|
|
|
|
|
if (! PyType_Check(i))
|
|
|
{
|
|
|
PyErr_SetString(PyExc_TypeError,
|
|
|
"zope.interface.declarations.Implements is not a type");
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
Implements = (PyTypeObject *)i;
|
|
|
|
|
|
Py_DECREF(declarations);
|
|
|
|
|
|
imported_declarations = 1;
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
static PyTypeObject SpecType; /* Forward */
|
|
|
|
|
|
static PyObject *
|
|
|
implementedByFallback(PyObject *cls)
|
|
|
{
|
|
|
if (imported_declarations == 0 && import_declarations() < 0)
|
|
|
return NULL;
|
|
|
|
|
|
return PyObject_CallFunctionObjArgs(fallback, cls, NULL);
|
|
|
}
|
|
|
|
|
|
static PyObject *
|
|
|
implementedBy(PyObject *ignored, PyObject *cls)
|
|
|
{
|
|
|
/* Fast retrieval of implements spec, if possible, to optimize
|
|
|
common case. Use fallback code if we get stuck.
|
|
|
*/
|
|
|
|
|
|
PyObject *dict = NULL, *spec;
|
|
|
|
|
|
if (PyType_Check(cls))
|
|
|
{
|
|
|
dict = TYPE(cls)->tp_dict;
|
|
|
Py_XINCREF(dict);
|
|
|
}
|
|
|
|
|
|
if (dict == NULL)
|
|
|
dict = PyObject_GetAttr(cls, str__dict__);
|
|
|
|
|
|
if (dict == NULL)
|
|
|
{
|
|
|
/* Probably a security proxied class, use more expensive fallback code */
|
|
|
PyErr_Clear();
|
|
|
return implementedByFallback(cls);
|
|
|
}
|
|
|
|
|
|
spec = PyObject_GetItem(dict, str__implemented__);
|
|
|
Py_DECREF(dict);
|
|
|
if (spec)
|
|
|
{
|
|
|
if (imported_declarations == 0 && import_declarations() < 0)
|
|
|
return NULL;
|
|
|
|
|
|
if (PyObject_TypeCheck(spec, Implements))
|
|
|
return spec;
|
|
|
|
|
|
/* Old-style declaration, use more expensive fallback code */
|
|
|
Py_DECREF(spec);
|
|
|
return implementedByFallback(cls);
|
|
|
}
|
|
|
|
|
|
PyErr_Clear();
|
|
|
|
|
|
/* Maybe we have a builtin */
|
|
|
if (imported_declarations == 0 && import_declarations() < 0)
|
|
|
return NULL;
|
|
|
|
|
|
spec = PyDict_GetItem(BuiltinImplementationSpecifications, cls);
|
|
|
if (spec != NULL)
|
|
|
{
|
|
|
Py_INCREF(spec);
|
|
|
return spec;
|
|
|
}
|
|
|
|
|
|
/* We're stuck, use fallback */
|
|
|
return implementedByFallback(cls);
|
|
|
}
|
|
|
|
|
|
static PyObject *
|
|
|
getObjectSpecification(PyObject *ignored, PyObject *ob)
|
|
|
{
|
|
|
PyObject *cls, *result;
|
|
|
|
|
|
result = PyObject_GetAttr(ob, str__provides__);
|
|
|
if (result != NULL && PyObject_TypeCheck(result, &SpecType))
|
|
|
return result;
|
|
|
|
|
|
PyErr_Clear();
|
|
|
|
|
|
/* We do a getattr here so as not to be defeated by proxies */
|
|
|
cls = PyObject_GetAttr(ob, str__class__);
|
|
|
if (cls == NULL)
|
|
|
{
|
|
|
PyErr_Clear();
|
|
|
if (imported_declarations == 0 && import_declarations() < 0)
|
|
|
return NULL;
|
|
|
Py_INCREF(empty);
|
|
|
return empty;
|
|
|
}
|
|
|
|
|
|
result = implementedBy(NULL, cls);
|
|
|
Py_DECREF(cls);
|
|
|
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
static PyObject *
|
|
|
providedBy(PyObject *ignored, PyObject *ob)
|
|
|
{
|
|
|
PyObject *result, *cls, *cp;
|
|
|
|
|
|
result = PyObject_GetAttr(ob, str__providedBy__);
|
|
|
if (result == NULL)
|
|
|
{
|
|
|
PyErr_Clear();
|
|
|
return getObjectSpecification(NULL, ob);
|
|
|
}
|
|
|
|
|
|
|
|
|
/* We want to make sure we have a spec. We can't do a type check
|
|
|
because we may have a proxy, so we'll just try to get the
|
|
|
only attribute.
|
|
|
*/
|
|
|
if (PyObject_TypeCheck(result, &SpecType)
|
|
|
||
|
|
|
PyObject_HasAttr(result, strextends)
|
|
|
)
|
|
|
return result;
|
|
|
|
|
|
/*
|
|
|
The object's class doesn't understand descriptors.
|
|
|
Sigh. We need to get an object descriptor, but we have to be
|
|
|
careful. We want to use the instance's __provides__,l if
|
|
|
there is one, but only if it didn't come from the class.
|
|
|
*/
|
|
|
Py_DECREF(result);
|
|
|
|
|
|
cls = PyObject_GetAttr(ob, str__class__);
|
|
|
if (cls == NULL)
|
|
|
return NULL;
|
|
|
|
|
|
result = PyObject_GetAttr(ob, str__provides__);
|
|
|
if (result == NULL)
|
|
|
{
|
|
|
/* No __provides__, so just fall back to implementedBy */
|
|
|
PyErr_Clear();
|
|
|
result = implementedBy(NULL, cls);
|
|
|
Py_DECREF(cls);
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
cp = PyObject_GetAttr(cls, str__provides__);
|
|
|
if (cp == NULL)
|
|
|
{
|
|
|
/* The the class has no provides, assume we're done: */
|
|
|
PyErr_Clear();
|
|
|
Py_DECREF(cls);
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
if (cp == result)
|
|
|
{
|
|
|
/*
|
|
|
Oops, we got the provides from the class. This means
|
|
|
the object doesn't have it's own. We should use implementedBy
|
|
|
*/
|
|
|
Py_DECREF(result);
|
|
|
result = implementedBy(NULL, cls);
|
|
|
}
|
|
|
|
|
|
Py_DECREF(cls);
|
|
|
Py_DECREF(cp);
|
|
|
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
Get an attribute from an inst dict. Return a borrowed reference.
|
|
|
|
|
|
This has a number of advantages:
|
|
|
|
|
|
- It avoids layers of Python api
|
|
|
|
|
|
- It doesn't waste time looking for descriptors
|
|
|
|
|
|
- It fails wo raising an exception, although that shouldn't really
|
|
|
matter.
|
|
|
|
|
|
*/
|
|
|
static PyObject *
|
|
|
inst_attr(PyObject *self, PyObject *name)
|
|
|
{
|
|
|
PyObject **dictp, *v;
|
|
|
|
|
|
dictp = _PyObject_GetDictPtr(self);
|
|
|
if (dictp && *dictp && (v = PyDict_GetItem(*dictp, name)))
|
|
|
return v;
|
|
|
PyErr_SetObject(PyExc_AttributeError, name);
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
Spec_extends(PyObject *self, PyObject *other)
|
|
|
{
|
|
|
PyObject *implied;
|
|
|
|
|
|
implied = inst_attr(self, str_implied);
|
|
|
if (implied == NULL)
|
|
|
return NULL;
|
|
|
|
|
|
#ifdef Py_True
|
|
|
if (PyDict_GetItem(implied, other) != NULL)
|
|
|
{
|
|
|
Py_INCREF(Py_True);
|
|
|
return Py_True;
|
|
|
}
|
|
|
Py_INCREF(Py_False);
|
|
|
return Py_False;
|
|
|
#else
|
|
|
return PyInt_FromLong(PyDict_GetItem(implied, other) != NULL);
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
static char Spec_extends__doc__[] =
|
|
|
"Test whether a specification is or extends another"
|
|
|
;
|
|
|
|
|
|
static char Spec_providedBy__doc__[] =
|
|
|
"Test whether an interface is implemented by the specification"
|
|
|
;
|
|
|
|
|
|
static PyObject *
|
|
|
Spec_call(PyObject *self, PyObject *args, PyObject *kw)
|
|
|
{
|
|
|
PyObject *spec;
|
|
|
|
|
|
if (! PyArg_ParseTuple(args, "O", &spec))
|
|
|
return NULL;
|
|
|
return Spec_extends(self, spec);
|
|
|
}
|
|
|
|
|
|
static PyObject *
|
|
|
Spec_providedBy(PyObject *self, PyObject *ob)
|
|
|
{
|
|
|
PyObject *decl, *item;
|
|
|
|
|
|
decl = providedBy(NULL, ob);
|
|
|
if (decl == NULL)
|
|
|
return NULL;
|
|
|
|
|
|
if (PyObject_TypeCheck(decl, &SpecType))
|
|
|
item = Spec_extends(decl, self);
|
|
|
else
|
|
|
/* decl is probably a security proxy. We have to go the long way
|
|
|
around.
|
|
|
*/
|
|
|
item = PyObject_CallFunctionObjArgs(decl, self, NULL);
|
|
|
|
|
|
Py_DECREF(decl);
|
|
|
return item;
|
|
|
}
|
|
|
|
|
|
|
|
|
static char Spec_implementedBy__doc__[] =
|
|
|
"Test whether the specification is implemented by a class or factory.\n"
|
|
|
"Raise TypeError if argument is neither a class nor a callable."
|
|
|
;
|
|
|
|
|
|
static PyObject *
|
|
|
Spec_implementedBy(PyObject *self, PyObject *cls)
|
|
|
{
|
|
|
PyObject *decl, *item;
|
|
|
|
|
|
decl = implementedBy(NULL, cls);
|
|
|
if (decl == NULL)
|
|
|
return NULL;
|
|
|
|
|
|
if (PyObject_TypeCheck(decl, &SpecType))
|
|
|
item = Spec_extends(decl, self);
|
|
|
else
|
|
|
item = PyObject_CallFunctionObjArgs(decl, self, NULL);
|
|
|
|
|
|
Py_DECREF(decl);
|
|
|
return item;
|
|
|
}
|
|
|
|
|
|
static struct PyMethodDef Spec_methods[] = {
|
|
|
{"providedBy",
|
|
|
(PyCFunction)Spec_providedBy, METH_O,
|
|
|
Spec_providedBy__doc__},
|
|
|
{"implementedBy",
|
|
|
(PyCFunction)Spec_implementedBy, METH_O,
|
|
|
Spec_implementedBy__doc__},
|
|
|
{"isOrExtends", (PyCFunction)Spec_extends, METH_O,
|
|
|
Spec_extends__doc__},
|
|
|
|
|
|
{NULL, NULL} /* sentinel */
|
|
|
};
|
|
|
|
|
|
static PyTypeObject SpecType = {
|
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
|
/* tp_name */ "_interface_coptimizations."
|
|
|
"SpecificationBase",
|
|
|
/* tp_basicsize */ 0,
|
|
|
/* tp_itemsize */ 0,
|
|
|
/* tp_dealloc */ (destructor)0,
|
|
|
/* tp_print */ (printfunc)0,
|
|
|
/* tp_getattr */ (getattrfunc)0,
|
|
|
/* tp_setattr */ (setattrfunc)0,
|
|
|
/* tp_compare */ 0,
|
|
|
/* tp_repr */ (reprfunc)0,
|
|
|
/* tp_as_number */ 0,
|
|
|
/* tp_as_sequence */ 0,
|
|
|
/* tp_as_mapping */ 0,
|
|
|
/* tp_hash */ (hashfunc)0,
|
|
|
/* tp_call */ (ternaryfunc)Spec_call,
|
|
|
/* tp_str */ (reprfunc)0,
|
|
|
/* tp_getattro */ (getattrofunc)0,
|
|
|
/* tp_setattro */ (setattrofunc)0,
|
|
|
/* tp_as_buffer */ 0,
|
|
|
/* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
|
|
"Base type for Specification objects",
|
|
|
/* tp_traverse */ (traverseproc)0,
|
|
|
/* tp_clear */ (inquiry)0,
|
|
|
/* tp_richcompare */ (richcmpfunc)0,
|
|
|
/* tp_weaklistoffset */ (long)0,
|
|
|
/* tp_iter */ (getiterfunc)0,
|
|
|
/* tp_iternext */ (iternextfunc)0,
|
|
|
/* tp_methods */ Spec_methods,
|
|
|
};
|
|
|
|
|
|
static PyObject *
|
|
|
OSD_descr_get(PyObject *self, PyObject *inst, PyObject *cls)
|
|
|
{
|
|
|
PyObject *provides;
|
|
|
|
|
|
if (inst == NULL)
|
|
|
return getObjectSpecification(NULL, cls);
|
|
|
|
|
|
provides = PyObject_GetAttr(inst, str__provides__);
|
|
|
if (provides != NULL)
|
|
|
return provides;
|
|
|
PyErr_Clear();
|
|
|
return implementedBy(NULL, cls);
|
|
|
}
|
|
|
|
|
|
static PyTypeObject OSDType = {
|
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
|
/* tp_name */ "_interface_coptimizations."
|
|
|
"ObjectSpecificationDescriptor",
|
|
|
/* tp_basicsize */ 0,
|
|
|
/* tp_itemsize */ 0,
|
|
|
/* tp_dealloc */ (destructor)0,
|
|
|
/* tp_print */ (printfunc)0,
|
|
|
/* tp_getattr */ (getattrfunc)0,
|
|
|
/* tp_setattr */ (setattrfunc)0,
|
|
|
/* tp_compare */ 0,
|
|
|
/* tp_repr */ (reprfunc)0,
|
|
|
/* tp_as_number */ 0,
|
|
|
/* tp_as_sequence */ 0,
|
|
|
/* tp_as_mapping */ 0,
|
|
|
/* tp_hash */ (hashfunc)0,
|
|
|
/* tp_call */ (ternaryfunc)0,
|
|
|
/* tp_str */ (reprfunc)0,
|
|
|
/* tp_getattro */ (getattrofunc)0,
|
|
|
/* tp_setattro */ (setattrofunc)0,
|
|
|
/* tp_as_buffer */ 0,
|
|
|
/* tp_flags */ Py_TPFLAGS_DEFAULT
|
|
|
| Py_TPFLAGS_BASETYPE ,
|
|
|
"Object Specification Descriptor",
|
|
|
/* tp_traverse */ (traverseproc)0,
|
|
|
/* tp_clear */ (inquiry)0,
|
|
|
/* tp_richcompare */ (richcmpfunc)0,
|
|
|
/* tp_weaklistoffset */ (long)0,
|
|
|
/* tp_iter */ (getiterfunc)0,
|
|
|
/* tp_iternext */ (iternextfunc)0,
|
|
|
/* tp_methods */ 0,
|
|
|
/* tp_members */ 0,
|
|
|
/* tp_getset */ 0,
|
|
|
/* tp_base */ 0,
|
|
|
/* tp_dict */ 0, /* internal use */
|
|
|
/* tp_descr_get */ (descrgetfunc)OSD_descr_get,
|
|
|
};
|
|
|
|
|
|
static PyObject *
|
|
|
CPB_descr_get(PyObject *self, PyObject *inst, PyObject *cls)
|
|
|
{
|
|
|
PyObject *mycls, *implements;
|
|
|
|
|
|
mycls = inst_attr(self, str_cls);
|
|
|
if (mycls == NULL)
|
|
|
return NULL;
|
|
|
|
|
|
if (cls == mycls)
|
|
|
{
|
|
|
if (inst == NULL)
|
|
|
{
|
|
|
Py_INCREF(self);
|
|
|
return OBJECT(self);
|
|
|
}
|
|
|
|
|
|
implements = inst_attr(self, str_implements);
|
|
|
Py_XINCREF(implements);
|
|
|
return implements;
|
|
|
}
|
|
|
|
|
|
PyErr_SetObject(PyExc_AttributeError, str__provides__);
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
static PyTypeObject CPBType = {
|
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
|
/* tp_name */ "_interface_coptimizations."
|
|
|
"ClassProvidesBase",
|
|
|
/* tp_basicsize */ 0,
|
|
|
/* tp_itemsize */ 0,
|
|
|
/* tp_dealloc */ (destructor)0,
|
|
|
/* tp_print */ (printfunc)0,
|
|
|
/* tp_getattr */ (getattrfunc)0,
|
|
|
/* tp_setattr */ (setattrfunc)0,
|
|
|
/* tp_compare */ 0,
|
|
|
/* tp_repr */ (reprfunc)0,
|
|
|
/* tp_as_number */ 0,
|
|
|
/* tp_as_sequence */ 0,
|
|
|
/* tp_as_mapping */ 0,
|
|
|
/* tp_hash */ (hashfunc)0,
|
|
|
/* tp_call */ (ternaryfunc)0,
|
|
|
/* tp_str */ (reprfunc)0,
|
|
|
/* tp_getattro */ (getattrofunc)0,
|
|
|
/* tp_setattro */ (setattrofunc)0,
|
|
|
/* tp_as_buffer */ 0,
|
|
|
/* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
|
|
"C Base class for ClassProvides",
|
|
|
/* tp_traverse */ (traverseproc)0,
|
|
|
/* tp_clear */ (inquiry)0,
|
|
|
/* tp_richcompare */ (richcmpfunc)0,
|
|
|
/* tp_weaklistoffset */ (long)0,
|
|
|
/* tp_iter */ (getiterfunc)0,
|
|
|
/* tp_iternext */ (iternextfunc)0,
|
|
|
/* tp_methods */ 0,
|
|
|
/* tp_members */ 0,
|
|
|
/* tp_getset */ 0,
|
|
|
/* tp_base */ &SpecType,
|
|
|
/* tp_dict */ 0, /* internal use */
|
|
|
/* tp_descr_get */ (descrgetfunc)CPB_descr_get,
|
|
|
};
|
|
|
|
|
|
/* ==================================================================== */
|
|
|
/* ========== Begin: __call__ and __adapt__ =========================== */
|
|
|
|
|
|
/*
|
|
|
def __adapt__(self, obj):
|
|
|
"""Adapt an object to the reciever
|
|
|
"""
|
|
|
if self.providedBy(obj):
|
|
|
return obj
|
|
|
|
|
|
for hook in adapter_hooks:
|
|
|
adapter = hook(self, obj)
|
|
|
if adapter is not None:
|
|
|
return adapter
|
|
|
|
|
|
|
|
|
*/
|
|
|
static PyObject *
|
|
|
__adapt__(PyObject *self, PyObject *obj)
|
|
|
{
|
|
|
PyObject *decl, *args, *adapter;
|
|
|
int implements, i, l;
|
|
|
|
|
|
decl = providedBy(NULL, obj);
|
|
|
if (decl == NULL)
|
|
|
return NULL;
|
|
|
|
|
|
if (PyObject_TypeCheck(decl, &SpecType))
|
|
|
{
|
|
|
PyObject *implied;
|
|
|
|
|
|
implied = inst_attr(decl, str_implied);
|
|
|
if (implied == NULL)
|
|
|
{
|
|
|
Py_DECREF(decl);
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
implements = PyDict_GetItem(implied, self) != NULL;
|
|
|
Py_DECREF(decl);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
/* decl is probably a security proxy. We have to go the long way
|
|
|
around.
|
|
|
*/
|
|
|
PyObject *r;
|
|
|
r = PyObject_CallFunctionObjArgs(decl, self, NULL);
|
|
|
Py_DECREF(decl);
|
|
|
if (r == NULL)
|
|
|
return NULL;
|
|
|
implements = PyObject_IsTrue(r);
|
|
|
Py_DECREF(r);
|
|
|
}
|
|
|
|
|
|
if (implements)
|
|
|
{
|
|
|
Py_INCREF(obj);
|
|
|
return obj;
|
|
|
}
|
|
|
|
|
|
l = PyList_GET_SIZE(adapter_hooks);
|
|
|
args = PyTuple_New(2);
|
|
|
if (args == NULL)
|
|
|
return NULL;
|
|
|
Py_INCREF(self);
|
|
|
PyTuple_SET_ITEM(args, 0, self);
|
|
|
Py_INCREF(obj);
|
|
|
PyTuple_SET_ITEM(args, 1, obj);
|
|
|
for (i = 0; i < l; i++)
|
|
|
{
|
|
|
adapter = PyObject_CallObject(PyList_GET_ITEM(adapter_hooks, i), args);
|
|
|
if (adapter == NULL || adapter != Py_None)
|
|
|
{
|
|
|
Py_DECREF(args);
|
|
|
return adapter;
|
|
|
}
|
|
|
Py_DECREF(adapter);
|
|
|
}
|
|
|
|
|
|
Py_DECREF(args);
|
|
|
|
|
|
Py_INCREF(Py_None);
|
|
|
return Py_None;
|
|
|
}
|
|
|
|
|
|
static struct PyMethodDef ib_methods[] = {
|
|
|
{"__adapt__", (PyCFunction)__adapt__, METH_O,
|
|
|
"Adapt an object to the reciever"},
|
|
|
{NULL, NULL} /* sentinel */
|
|
|
};
|
|
|
|
|
|
/*
|
|
|
def __call__(self, obj, alternate=_marker):
|
|
|
conform = getattr(obj, '__conform__', None)
|
|
|
if conform is not None:
|
|
|
adapter = self._call_conform(conform)
|
|
|
if adapter is not None:
|
|
|
return adapter
|
|
|
|
|
|
adapter = self.__adapt__(obj)
|
|
|
|
|
|
if adapter is not None:
|
|
|
return adapter
|
|
|
elif alternate is not _marker:
|
|
|
return alternate
|
|
|
else:
|
|
|
raise TypeError("Could not adapt", obj, self)
|
|
|
*/
|
|
|
static PyObject *
|
|
|
ib_call(PyObject *self, PyObject *args, PyObject *kwargs)
|
|
|
{
|
|
|
PyObject *conform, *obj, *alternate=NULL, *adapter;
|
|
|
|
|
|
static char *kwlist[] = {"obj", "alternate", NULL};
|
|
|
|
|
|
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O", kwlist,
|
|
|
&obj, &alternate))
|
|
|
return NULL;
|
|
|
|
|
|
conform = PyObject_GetAttr(obj, str__conform__);
|
|
|
if (conform != NULL)
|
|
|
{
|
|
|
adapter = PyObject_CallMethodObjArgs(self, str_call_conform,
|
|
|
conform, NULL);
|
|
|
Py_DECREF(conform);
|
|
|
if (adapter == NULL || adapter != Py_None)
|
|
|
return adapter;
|
|
|
Py_DECREF(adapter);
|
|
|
}
|
|
|
else
|
|
|
PyErr_Clear();
|
|
|
|
|
|
adapter = __adapt__(self, obj);
|
|
|
if (adapter == NULL || adapter != Py_None)
|
|
|
return adapter;
|
|
|
Py_DECREF(adapter);
|
|
|
|
|
|
if (alternate != NULL)
|
|
|
{
|
|
|
Py_INCREF(alternate);
|
|
|
return alternate;
|
|
|
}
|
|
|
|
|
|
adapter = Py_BuildValue("sOO", "Could not adapt", obj, self);
|
|
|
if (adapter != NULL)
|
|
|
{
|
|
|
PyErr_SetObject(PyExc_TypeError, adapter);
|
|
|
Py_DECREF(adapter);
|
|
|
}
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
static PyTypeObject InterfaceBase = {
|
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
|
/* tp_name */ "_zope_interface_coptimizations."
|
|
|
"InterfaceBase",
|
|
|
/* tp_basicsize */ 0,
|
|
|
/* tp_itemsize */ 0,
|
|
|
/* tp_dealloc */ (destructor)0,
|
|
|
/* tp_print */ (printfunc)0,
|
|
|
/* tp_getattr */ (getattrfunc)0,
|
|
|
/* tp_setattr */ (setattrfunc)0,
|
|
|
/* tp_compare */ 0,
|
|
|
/* tp_repr */ (reprfunc)0,
|
|
|
/* tp_as_number */ 0,
|
|
|
/* tp_as_sequence */ 0,
|
|
|
/* tp_as_mapping */ 0,
|
|
|
/* tp_hash */ (hashfunc)0,
|
|
|
/* tp_call */ (ternaryfunc)ib_call,
|
|
|
/* tp_str */ (reprfunc)0,
|
|
|
/* tp_getattro */ (getattrofunc)0,
|
|
|
/* tp_setattro */ (setattrofunc)0,
|
|
|
/* tp_as_buffer */ 0,
|
|
|
/* tp_flags */ Py_TPFLAGS_DEFAULT
|
|
|
| Py_TPFLAGS_BASETYPE ,
|
|
|
/* tp_doc */ "Interface base type providing __call__ and __adapt__",
|
|
|
/* tp_traverse */ (traverseproc)0,
|
|
|
/* tp_clear */ (inquiry)0,
|
|
|
/* tp_richcompare */ (richcmpfunc)0,
|
|
|
/* tp_weaklistoffset */ (long)0,
|
|
|
/* tp_iter */ (getiterfunc)0,
|
|
|
/* tp_iternext */ (iternextfunc)0,
|
|
|
/* tp_methods */ ib_methods,
|
|
|
};
|
|
|
|
|
|
/* =================== End: __call__ and __adapt__ ==================== */
|
|
|
/* ==================================================================== */
|
|
|
|
|
|
/* ==================================================================== */
|
|
|
/* ========================== Begin: Lookup Bases ===================== */
|
|
|
|
|
|
typedef struct {
|
|
|
PyObject_HEAD
|
|
|
PyObject *_cache;
|
|
|
PyObject *_mcache;
|
|
|
PyObject *_scache;
|
|
|
} lookup;
|
|
|
|
|
|
typedef struct {
|
|
|
PyObject_HEAD
|
|
|
PyObject *_cache;
|
|
|
PyObject *_mcache;
|
|
|
PyObject *_scache;
|
|
|
PyObject *_verify_ro;
|
|
|
PyObject *_verify_generations;
|
|
|
} verify;
|
|
|
|
|
|
static int
|
|
|
lookup_traverse(lookup *self, visitproc visit, void *arg)
|
|
|
{
|
|
|
int vret;
|
|
|
|
|
|
if (self->_cache) {
|
|
|
vret = visit(self->_cache, arg);
|
|
|
if (vret != 0)
|
|
|
return vret;
|
|
|
}
|
|
|
|
|
|
if (self->_mcache) {
|
|
|
vret = visit(self->_mcache, arg);
|
|
|
if (vret != 0)
|
|
|
return vret;
|
|
|
}
|
|
|
|
|
|
if (self->_scache) {
|
|
|
vret = visit(self->_scache, arg);
|
|
|
if (vret != 0)
|
|
|
return vret;
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
static int
|
|
|
lookup_clear(lookup *self)
|
|
|
{
|
|
|
Py_CLEAR(self->_cache);
|
|
|
Py_CLEAR(self->_mcache);
|
|
|
Py_CLEAR(self->_scache);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
static void
|
|
|
lookup_dealloc(lookup *self)
|
|
|
{
|
|
|
PyObject_GC_UnTrack((PyObject *)self);
|
|
|
lookup_clear(self);
|
|
|
Py_TYPE(self)->tp_free((PyObject*)self);
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
def changed(self, ignored=None):
|
|
|
self._cache.clear()
|
|
|
self._mcache.clear()
|
|
|
self._scache.clear()
|
|
|
*/
|
|
|
static PyObject *
|
|
|
lookup_changed(lookup *self, PyObject *ignored)
|
|
|
{
|
|
|
lookup_clear(self);
|
|
|
Py_INCREF(Py_None);
|
|
|
return Py_None;
|
|
|
}
|
|
|
|
|
|
#define ASSURE_DICT(N) if (N == NULL) { N = PyDict_New(); \
|
|
|
if (N == NULL) return NULL; \
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
def _getcache(self, provided, name):
|
|
|
cache = self._cache.get(provided)
|
|
|
if cache is None:
|
|
|
cache = {}
|
|
|
self._cache[provided] = cache
|
|
|
if name:
|
|
|
c = cache.get(name)
|
|
|
if c is None:
|
|
|
c = {}
|
|
|
cache[name] = c
|
|
|
cache = c
|
|
|
return cache
|
|
|
*/
|
|
|
static PyObject *
|
|
|
_subcache(PyObject *cache, PyObject *key)
|
|
|
{
|
|
|
PyObject *subcache;
|
|
|
|
|
|
subcache = PyDict_GetItem(cache, key);
|
|
|
if (subcache == NULL)
|
|
|
{
|
|
|
int status;
|
|
|
|
|
|
subcache = PyDict_New();
|
|
|
if (subcache == NULL)
|
|
|
return NULL;
|
|
|
status = PyDict_SetItem(cache, key, subcache);
|
|
|
Py_DECREF(subcache);
|
|
|
if (status < 0)
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
return subcache;
|
|
|
}
|
|
|
static PyObject *
|
|
|
_getcache(lookup *self, PyObject *provided, PyObject *name)
|
|
|
{
|
|
|
PyObject *cache;
|
|
|
|
|
|
ASSURE_DICT(self->_cache);
|
|
|
cache = _subcache(self->_cache, provided);
|
|
|
if (cache == NULL)
|
|
|
return NULL;
|
|
|
|
|
|
if (name != NULL && PyObject_IsTrue(name))
|
|
|
cache = _subcache(cache, name);
|
|
|
|
|
|
return cache;
|
|
|
}
|
|
|
|
|
|
|
|
|
/*
|
|
|
def lookup(self, required, provided, name=u'', default=None):
|
|
|
cache = self._getcache(provided, name)
|
|
|
if len(required) == 1:
|
|
|
result = cache.get(required[0], _not_in_mapping)
|
|
|
else:
|
|
|
result = cache.get(tuple(required), _not_in_mapping)
|
|
|
|
|
|
if result is _not_in_mapping:
|
|
|
result = self._uncached_lookup(required, provided, name)
|
|
|
if len(required) == 1:
|
|
|
cache[required[0]] = result
|
|
|
else:
|
|
|
cache[tuple(required)] = result
|
|
|
|
|
|
if result is None:
|
|
|
return default
|
|
|
|
|
|
return result
|
|
|
*/
|
|
|
static PyObject *
|
|
|
tuplefy(PyObject *v)
|
|
|
{
|
|
|
if (! PyTuple_Check(v))
|
|
|
{
|
|
|
v = PyObject_CallFunctionObjArgs(OBJECT(&PyTuple_Type), v, NULL);
|
|
|
if (v == NULL)
|
|
|
return NULL;
|
|
|
}
|
|
|
else
|
|
|
Py_INCREF(v);
|
|
|
|
|
|
return v;
|
|
|
}
|
|
|
static PyObject *
|
|
|
_lookup(lookup *self,
|
|
|
PyObject *required, PyObject *provided, PyObject *name,
|
|
|
PyObject *default_)
|
|
|
{
|
|
|
PyObject *result, *key, *cache;
|
|
|
|
|
|
#ifdef PY3K
|
|
|
if ( name && !PyUnicode_Check(name) )
|
|
|
#else
|
|
|
if ( name && !PyString_Check(name) && !PyUnicode_Check(name) )
|
|
|
#endif
|
|
|
{
|
|
|
PyErr_SetString(PyExc_ValueError,
|
|
|
"name is not a string or unicode");
|
|
|
return NULL;
|
|
|
}
|
|
|
cache = _getcache(self, provided, name);
|
|
|
if (cache == NULL)
|
|
|
return NULL;
|
|
|
|
|
|
required = tuplefy(required);
|
|
|
if (required == NULL)
|
|
|
return NULL;
|
|
|
|
|
|
if (PyTuple_GET_SIZE(required) == 1)
|
|
|
key = PyTuple_GET_ITEM(required, 0);
|
|
|
else
|
|
|
key = required;
|
|
|
|
|
|
result = PyDict_GetItem(cache, key);
|
|
|
if (result == NULL)
|
|
|
{
|
|
|
int status;
|
|
|
|
|
|
result = PyObject_CallMethodObjArgs(OBJECT(self), str_uncached_lookup,
|
|
|
required, provided, name, NULL);
|
|
|
if (result == NULL)
|
|
|
{
|
|
|
Py_DECREF(required);
|
|
|
return NULL;
|
|
|
}
|
|
|
status = PyDict_SetItem(cache, key, result);
|
|
|
Py_DECREF(required);
|
|
|
if (status < 0)
|
|
|
{
|
|
|
Py_DECREF(result);
|
|
|
return NULL;
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
Py_INCREF(result);
|
|
|
Py_DECREF(required);
|
|
|
}
|
|
|
|
|
|
if (result == Py_None && default_ != NULL)
|
|
|
{
|
|
|
Py_DECREF(Py_None);
|
|
|
Py_INCREF(default_);
|
|
|
return default_;
|
|
|
}
|
|
|
|
|
|
return result;
|
|
|
}
|
|
|
static PyObject *
|
|
|
lookup_lookup(lookup *self, PyObject *args, PyObject *kwds)
|
|
|
{
|
|
|
static char *kwlist[] = {"required", "provided", "name", "default", NULL};
|
|
|
PyObject *required, *provided, *name=NULL, *default_=NULL;
|
|
|
|
|
|
if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist,
|
|
|
&required, &provided, &name, &default_))
|
|
|
return NULL;
|
|
|
|
|
|
return _lookup(self, required, provided, name, default_);
|
|
|
}
|
|
|
|
|
|
|
|
|
/*
|
|
|
def lookup1(self, required, provided, name=u'', default=None):
|
|
|
cache = self._getcache(provided, name)
|
|
|
result = cache.get(required, _not_in_mapping)
|
|
|
if result is _not_in_mapping:
|
|
|
return self.lookup((required, ), provided, name, default)
|
|
|
|
|
|
if result is None:
|
|
|
return default
|
|
|
|
|
|
return result
|
|
|
*/
|
|
|
static PyObject *
|
|
|
_lookup1(lookup *self,
|
|
|
PyObject *required, PyObject *provided, PyObject *name,
|
|
|
PyObject *default_)
|
|
|
{
|
|
|
PyObject *result, *cache;
|
|
|
|
|
|
#ifdef PY3K
|
|
|
if ( name && !PyUnicode_Check(name) )
|
|
|
#else
|
|
|
if ( name && !PyString_Check(name) && !PyUnicode_Check(name) )
|
|
|
#endif
|
|
|
{
|
|
|
PyErr_SetString(PyExc_ValueError,
|
|
|
"name is not a string or unicode");
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
cache = _getcache(self, provided, name);
|
|
|
if (cache == NULL)
|
|
|
return NULL;
|
|
|
|
|
|
result = PyDict_GetItem(cache, required);
|
|
|
if (result == NULL)
|
|
|
{
|
|
|
PyObject *tup;
|
|
|
|
|
|
tup = PyTuple_New(1);
|
|
|
if (tup == NULL)
|
|
|
return NULL;
|
|
|
Py_INCREF(required);
|
|
|
PyTuple_SET_ITEM(tup, 0, required);
|
|
|
result = _lookup(self, tup, provided, name, default_);
|
|
|
Py_DECREF(tup);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
if (result == Py_None && default_ != NULL)
|
|
|
{
|
|
|
result = default_;
|
|
|
}
|
|
|
Py_INCREF(result);
|
|
|
}
|
|
|
|
|
|
return result;
|
|
|
}
|
|
|
static PyObject *
|
|
|
lookup_lookup1(lookup *self, PyObject *args, PyObject *kwds)
|
|
|
{
|
|
|
static char *kwlist[] = {"required", "provided", "name", "default", NULL};
|
|
|
PyObject *required, *provided, *name=NULL, *default_=NULL;
|
|
|
|
|
|
if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist,
|
|
|
&required, &provided, &name, &default_))
|
|
|
return NULL;
|
|
|
|
|
|
return _lookup1(self, required, provided, name, default_);
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
def adapter_hook(self, provided, object, name=u'', default=None):
|
|
|
required = providedBy(object)
|
|
|
cache = self._getcache(provided, name)
|
|
|
factory = cache.get(required, _not_in_mapping)
|
|
|
if factory is _not_in_mapping:
|
|
|
factory = self.lookup((required, ), provided, name)
|
|
|
|
|
|
if factory is not None:
|
|
|
result = factory(object)
|
|
|
if result is not None:
|
|
|
return result
|
|
|
|
|
|
return default
|
|
|
*/
|
|
|
static PyObject *
|
|
|
_adapter_hook(lookup *self,
|
|
|
PyObject *provided, PyObject *object, PyObject *name,
|
|
|
PyObject *default_)
|
|
|
{
|
|
|
PyObject *required, *factory, *result;
|
|
|
|
|
|
#ifdef PY3K
|
|
|
if ( name && !PyUnicode_Check(name) )
|
|
|
#else
|
|
|
if ( name && !PyString_Check(name) && !PyUnicode_Check(name) )
|
|
|
#endif
|
|
|
{
|
|
|
PyErr_SetString(PyExc_ValueError,
|
|
|
"name is not a string or unicode");
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
required = providedBy(NULL, object);
|
|
|
if (required == NULL)
|
|
|
return NULL;
|
|
|
|
|
|
factory = _lookup1(self, required, provided, name, Py_None);
|
|
|
Py_DECREF(required);
|
|
|
if (factory == NULL)
|
|
|
return NULL;
|
|
|
|
|
|
if (factory != Py_None)
|
|
|
{
|
|
|
result = PyObject_CallFunctionObjArgs(factory, object, NULL);
|
|
|
Py_DECREF(factory);
|
|
|
if (result == NULL || result != Py_None)
|
|
|
return result;
|
|
|
}
|
|
|
else
|
|
|
result = factory; /* None */
|
|
|
|
|
|
if (default_ == NULL || default_ == result) /* No default specified, */
|
|
|
return result; /* Return None. result is owned None */
|
|
|
|
|
|
Py_DECREF(result);
|
|
|
Py_INCREF(default_);
|
|
|
|
|
|
return default_;
|
|
|
}
|
|
|
static PyObject *
|
|
|
lookup_adapter_hook(lookup *self, PyObject *args, PyObject *kwds)
|
|
|
{
|
|
|
static char *kwlist[] = {"provided", "object", "name", "default", NULL};
|
|
|
PyObject *object, *provided, *name=NULL, *default_=NULL;
|
|
|
|
|
|
if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist,
|
|
|
&provided, &object, &name, &default_))
|
|
|
return NULL;
|
|
|
|
|
|
return _adapter_hook(self, provided, object, name, default_);
|
|
|
}
|
|
|
|
|
|
static PyObject *
|
|
|
lookup_queryAdapter(lookup *self, PyObject *args, PyObject *kwds)
|
|
|
{
|
|
|
static char *kwlist[] = {"object", "provided", "name", "default", NULL};
|
|
|
PyObject *object, *provided, *name=NULL, *default_=NULL;
|
|
|
|
|
|
if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist,
|
|
|
&object, &provided, &name, &default_))
|
|
|
return NULL;
|
|
|
|
|
|
return _adapter_hook(self, provided, object, name, default_);
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
def lookupAll(self, required, provided):
|
|
|
cache = self._mcache.get(provided)
|
|
|
if cache is None:
|
|
|
cache = {}
|
|
|
self._mcache[provided] = cache
|
|
|
|
|
|
required = tuple(required)
|
|
|
result = cache.get(required, _not_in_mapping)
|
|
|
if result is _not_in_mapping:
|
|
|
result = self._uncached_lookupAll(required, provided)
|
|
|
cache[required] = result
|
|
|
|
|
|
return result
|
|
|
*/
|
|
|
static PyObject *
|
|
|
_lookupAll(lookup *self, PyObject *required, PyObject *provided)
|
|
|
{
|
|
|
PyObject *cache, *result;
|
|
|
|
|
|
ASSURE_DICT(self->_mcache);
|
|
|
cache = _subcache(self->_mcache, provided);
|
|
|
if (cache == NULL)
|
|
|
return NULL;
|
|
|
|
|
|
required = tuplefy(required);
|
|
|
if (required == NULL)
|
|
|
return NULL;
|
|
|
|
|
|
result = PyDict_GetItem(cache, required);
|
|
|
if (result == NULL)
|
|
|
{
|
|
|
int status;
|
|
|
|
|
|
result = PyObject_CallMethodObjArgs(OBJECT(self), str_uncached_lookupAll,
|
|
|
required, provided, NULL);
|
|
|
if (result == NULL)
|
|
|
{
|
|
|
Py_DECREF(required);
|
|
|
return NULL;
|
|
|
}
|
|
|
status = PyDict_SetItem(cache, required, result);
|
|
|
Py_DECREF(required);
|
|
|
if (status < 0)
|
|
|
{
|
|
|
Py_DECREF(result);
|
|
|
return NULL;
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
Py_INCREF(result);
|
|
|
Py_DECREF(required);
|
|
|
}
|
|
|
|
|
|
return result;
|
|
|
}
|
|
|
static PyObject *
|
|
|
lookup_lookupAll(lookup *self, PyObject *args, PyObject *kwds)
|
|
|
{
|
|
|
static char *kwlist[] = {"required", "provided", NULL};
|
|
|
PyObject *required, *provided;
|
|
|
|
|
|
if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist,
|
|
|
&required, &provided))
|
|
|
return NULL;
|
|
|
|
|
|
return _lookupAll(self, required, provided);
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
def subscriptions(self, required, provided):
|
|
|
cache = self._scache.get(provided)
|
|
|
if cache is None:
|
|
|
cache = {}
|
|
|
self._scache[provided] = cache
|
|
|
|
|
|
required = tuple(required)
|
|
|
result = cache.get(required, _not_in_mapping)
|
|
|
if result is _not_in_mapping:
|
|
|
result = self._uncached_subscriptions(required, provided)
|
|
|
cache[required] = result
|
|
|
|
|
|
return result
|
|
|
*/
|
|
|
static PyObject *
|
|
|
_subscriptions(lookup *self, PyObject *required, PyObject *provided)
|
|
|
{
|
|
|
PyObject *cache, *result;
|
|
|
|
|
|
ASSURE_DICT(self->_scache);
|
|
|
cache = _subcache(self->_scache, provided);
|
|
|
if (cache == NULL)
|
|
|
return NULL;
|
|
|
|
|
|
required = tuplefy(required);
|
|
|
if (required == NULL)
|
|
|
return NULL;
|
|
|
|
|
|
result = PyDict_GetItem(cache, required);
|
|
|
if (result == NULL)
|
|
|
{
|
|
|
int status;
|
|
|
|
|
|
result = PyObject_CallMethodObjArgs(
|
|
|
OBJECT(self), str_uncached_subscriptions,
|
|
|
required, provided, NULL);
|
|
|
if (result == NULL)
|
|
|
{
|
|
|
Py_DECREF(required);
|
|
|
return NULL;
|
|
|
}
|
|
|
status = PyDict_SetItem(cache, required, result);
|
|
|
Py_DECREF(required);
|
|
|
if (status < 0)
|
|
|
{
|
|
|
Py_DECREF(result);
|
|
|
return NULL;
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
Py_INCREF(result);
|
|
|
Py_DECREF(required);
|
|
|
}
|
|
|
|
|
|
return result;
|
|
|
}
|
|
|
static PyObject *
|
|
|
lookup_subscriptions(lookup *self, PyObject *args, PyObject *kwds)
|
|
|
{
|
|
|
static char *kwlist[] = {"required", "provided", NULL};
|
|
|
PyObject *required, *provided;
|
|
|
|
|
|
if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist,
|
|
|
&required, &provided))
|
|
|
return NULL;
|
|
|
|
|
|
return _subscriptions(self, required, provided);
|
|
|
}
|
|
|
|
|
|
static struct PyMethodDef lookup_methods[] = {
|
|
|
{"changed", (PyCFunction)lookup_changed, METH_O, ""},
|
|
|
{"lookup", (PyCFunction)lookup_lookup, METH_KEYWORDS | METH_VARARGS, ""},
|
|
|
{"lookup1", (PyCFunction)lookup_lookup1, METH_KEYWORDS | METH_VARARGS, ""},
|
|
|
{"queryAdapter", (PyCFunction)lookup_queryAdapter, METH_KEYWORDS | METH_VARARGS, ""},
|
|
|
{"adapter_hook", (PyCFunction)lookup_adapter_hook, METH_KEYWORDS | METH_VARARGS, ""},
|
|
|
{"lookupAll", (PyCFunction)lookup_lookupAll, METH_KEYWORDS | METH_VARARGS, ""},
|
|
|
{"subscriptions", (PyCFunction)lookup_subscriptions, METH_KEYWORDS | METH_VARARGS, ""},
|
|
|
{NULL, NULL} /* sentinel */
|
|
|
};
|
|
|
|
|
|
static PyTypeObject LookupBase = {
|
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
|
/* tp_name */ "_zope_interface_coptimizations."
|
|
|
"LookupBase",
|
|
|
/* tp_basicsize */ sizeof(lookup),
|
|
|
/* tp_itemsize */ 0,
|
|
|
/* tp_dealloc */ (destructor)&lookup_dealloc,
|
|
|
/* tp_print */ (printfunc)0,
|
|
|
/* tp_getattr */ (getattrfunc)0,
|
|
|
/* tp_setattr */ (setattrfunc)0,
|
|
|
/* tp_compare */ 0,
|
|
|
/* tp_repr */ (reprfunc)0,
|
|
|
/* tp_as_number */ 0,
|
|
|
/* tp_as_sequence */ 0,
|
|
|
/* tp_as_mapping */ 0,
|
|
|
/* tp_hash */ (hashfunc)0,
|
|
|
/* tp_call */ (ternaryfunc)0,
|
|
|
/* tp_str */ (reprfunc)0,
|
|
|
/* tp_getattro */ (getattrofunc)0,
|
|
|
/* tp_setattro */ (setattrofunc)0,
|
|
|
/* tp_as_buffer */ 0,
|
|
|
/* tp_flags */ Py_TPFLAGS_DEFAULT
|
|
|
| Py_TPFLAGS_BASETYPE
|
|
|
| Py_TPFLAGS_HAVE_GC,
|
|
|
/* tp_doc */ "",
|
|
|
/* tp_traverse */ (traverseproc)lookup_traverse,
|
|
|
/* tp_clear */ (inquiry)lookup_clear,
|
|
|
/* tp_richcompare */ (richcmpfunc)0,
|
|
|
/* tp_weaklistoffset */ (long)0,
|
|
|
/* tp_iter */ (getiterfunc)0,
|
|
|
/* tp_iternext */ (iternextfunc)0,
|
|
|
/* tp_methods */ lookup_methods,
|
|
|
};
|
|
|
|
|
|
static int
|
|
|
verifying_traverse(verify *self, visitproc visit, void *arg)
|
|
|
{
|
|
|
int vret;
|
|
|
|
|
|
vret = lookup_traverse((lookup *)self, visit, arg);
|
|
|
if (vret != 0)
|
|
|
return vret;
|
|
|
|
|
|
if (self->_verify_ro) {
|
|
|
vret = visit(self->_verify_ro, arg);
|
|
|
if (vret != 0)
|
|
|
return vret;
|
|
|
}
|
|
|
if (self->_verify_generations) {
|
|
|
vret = visit(self->_verify_generations, arg);
|
|
|
if (vret != 0)
|
|
|
return vret;
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
static int
|
|
|
verifying_clear(verify *self)
|
|
|
{
|
|
|
lookup_clear((lookup *)self);
|
|
|
Py_CLEAR(self->_verify_generations);
|
|
|
Py_CLEAR(self->_verify_ro);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
|
|
|
static void
|
|
|
verifying_dealloc(verify *self)
|
|
|
{
|
|
|
PyObject_GC_UnTrack((PyObject *)self);
|
|
|
verifying_clear(self);
|
|
|
Py_TYPE(self)->tp_free((PyObject*)self);
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
def changed(self, originally_changed):
|
|
|
super(VerifyingBasePy, self).changed(originally_changed)
|
|
|
self._verify_ro = self._registry.ro[1:]
|
|
|
self._verify_generations = [r._generation for r in self._verify_ro]
|
|
|
*/
|
|
|
static PyObject *
|
|
|
_generations_tuple(PyObject *ro)
|
|
|
{
|
|
|
int i, l;
|
|
|
PyObject *generations;
|
|
|
|
|
|
l = PyTuple_GET_SIZE(ro);
|
|
|
generations = PyTuple_New(l);
|
|
|
for (i=0; i < l; i++)
|
|
|
{
|
|
|
PyObject *generation;
|
|
|
|
|
|
generation = PyObject_GetAttr(PyTuple_GET_ITEM(ro, i), str_generation);
|
|
|
if (generation == NULL)
|
|
|
{
|
|
|
Py_DECREF(generations);
|
|
|
return NULL;
|
|
|
}
|
|
|
PyTuple_SET_ITEM(generations, i, generation);
|
|
|
}
|
|
|
|
|
|
return generations;
|
|
|
}
|
|
|
static PyObject *
|
|
|
verifying_changed(verify *self, PyObject *ignored)
|
|
|
{
|
|
|
PyObject *t, *ro;
|
|
|
|
|
|
verifying_clear(self);
|
|
|
|
|
|
t = PyObject_GetAttr(OBJECT(self), str_registry);
|
|
|
if (t == NULL)
|
|
|
return NULL;
|
|
|
ro = PyObject_GetAttr(t, strro);
|
|
|
Py_DECREF(t);
|
|
|
if (ro == NULL)
|
|
|
return NULL;
|
|
|
|
|
|
t = PyObject_CallFunctionObjArgs(OBJECT(&PyTuple_Type), ro, NULL);
|
|
|
Py_DECREF(ro);
|
|
|
if (t == NULL)
|
|
|
return NULL;
|
|
|
|
|
|
ro = PyTuple_GetSlice(t, 1, PyTuple_GET_SIZE(t));
|
|
|
Py_DECREF(t);
|
|
|
if (ro == NULL)
|
|
|
return NULL;
|
|
|
|
|
|
self->_verify_generations = _generations_tuple(ro);
|
|
|
if (self->_verify_generations == NULL)
|
|
|
{
|
|
|
Py_DECREF(ro);
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
self->_verify_ro = ro;
|
|
|
|
|
|
Py_INCREF(Py_None);
|
|
|
return Py_None;
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
def _verify(self):
|
|
|
if ([r._generation for r in self._verify_ro]
|
|
|
!= self._verify_generations):
|
|
|
self.changed(None)
|
|
|
*/
|
|
|
static int
|
|
|
_verify(verify *self)
|
|
|
{
|
|
|
PyObject *changed_result;
|
|
|
|
|
|
if (self->_verify_ro != NULL && self->_verify_generations != NULL)
|
|
|
{
|
|
|
PyObject *generations;
|
|
|
int changed;
|
|
|
|
|
|
generations = _generations_tuple(self->_verify_ro);
|
|
|
if (generations == NULL)
|
|
|
return -1;
|
|
|
|
|
|
changed = PyObject_RichCompareBool(self->_verify_generations,
|
|
|
generations, Py_NE);
|
|
|
Py_DECREF(generations);
|
|
|
if (changed == -1)
|
|
|
return -1;
|
|
|
|
|
|
if (changed == 0)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
changed_result = PyObject_CallMethodObjArgs(OBJECT(self), strchanged,
|
|
|
Py_None, NULL);
|
|
|
if (changed_result == NULL)
|
|
|
return -1;
|
|
|
|
|
|
Py_DECREF(changed_result);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
static PyObject *
|
|
|
verifying_lookup(verify *self, PyObject *args, PyObject *kwds)
|
|
|
{
|
|
|
static char *kwlist[] = {"required", "provided", "name", "default", NULL};
|
|
|
PyObject *required, *provided, *name=NULL, *default_=NULL;
|
|
|
|
|
|
if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist,
|
|
|
&required, &provided, &name, &default_))
|
|
|
return NULL;
|
|
|
|
|
|
if (_verify(self) < 0)
|
|
|
return NULL;
|
|
|
|
|
|
return _lookup((lookup *)self, required, provided, name, default_);
|
|
|
}
|
|
|
|
|
|
static PyObject *
|
|
|
verifying_lookup1(verify *self, PyObject *args, PyObject *kwds)
|
|
|
{
|
|
|
static char *kwlist[] = {"required", "provided", "name", "default", NULL};
|
|
|
PyObject *required, *provided, *name=NULL, *default_=NULL;
|
|
|
|
|
|
if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist,
|
|
|
&required, &provided, &name, &default_))
|
|
|
return NULL;
|
|
|
|
|
|
if (_verify(self) < 0)
|
|
|
return NULL;
|
|
|
|
|
|
return _lookup1((lookup *)self, required, provided, name, default_);
|
|
|
}
|
|
|
|
|
|
static PyObject *
|
|
|
verifying_adapter_hook(verify *self, PyObject *args, PyObject *kwds)
|
|
|
{
|
|
|
static char *kwlist[] = {"provided", "object", "name", "default", NULL};
|
|
|
PyObject *object, *provided, *name=NULL, *default_=NULL;
|
|
|
|
|
|
if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist,
|
|
|
&provided, &object, &name, &default_))
|
|
|
return NULL;
|
|
|
|
|
|
if (_verify(self) < 0)
|
|
|
return NULL;
|
|
|
|
|
|
return _adapter_hook((lookup *)self, provided, object, name, default_);
|
|
|
}
|
|
|
|
|
|
static PyObject *
|
|
|
verifying_queryAdapter(verify *self, PyObject *args, PyObject *kwds)
|
|
|
{
|
|
|
static char *kwlist[] = {"object", "provided", "name", "default", NULL};
|
|
|
PyObject *object, *provided, *name=NULL, *default_=NULL;
|
|
|
|
|
|
if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist,
|
|
|
&object, &provided, &name, &default_))
|
|
|
return NULL;
|
|
|
|
|
|
if (_verify(self) < 0)
|
|
|
return NULL;
|
|
|
|
|
|
return _adapter_hook((lookup *)self, provided, object, name, default_);
|
|
|
}
|
|
|
|
|
|
static PyObject *
|
|
|
verifying_lookupAll(verify *self, PyObject *args, PyObject *kwds)
|
|
|
{
|
|
|
static char *kwlist[] = {"required", "provided", NULL};
|
|
|
PyObject *required, *provided;
|
|
|
|
|
|
if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist,
|
|
|
&required, &provided))
|
|
|
return NULL;
|
|
|
|
|
|
if (_verify(self) < 0)
|
|
|
return NULL;
|
|
|
|
|
|
return _lookupAll((lookup *)self, required, provided);
|
|
|
}
|
|
|
|
|
|
static PyObject *
|
|
|
verifying_subscriptions(verify *self, PyObject *args, PyObject *kwds)
|
|
|
{
|
|
|
static char *kwlist[] = {"required", "provided", NULL};
|
|
|
PyObject *required, *provided;
|
|
|
|
|
|
if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist,
|
|
|
&required, &provided))
|
|
|
return NULL;
|
|
|
|
|
|
if (_verify(self) < 0)
|
|
|
return NULL;
|
|
|
|
|
|
return _subscriptions((lookup *)self, required, provided);
|
|
|
}
|
|
|
|
|
|
static struct PyMethodDef verifying_methods[] = {
|
|
|
{"changed", (PyCFunction)verifying_changed, METH_O, ""},
|
|
|
{"lookup", (PyCFunction)verifying_lookup, METH_KEYWORDS | METH_VARARGS, ""},
|
|
|
{"lookup1", (PyCFunction)verifying_lookup1, METH_KEYWORDS | METH_VARARGS, ""},
|
|
|
{"queryAdapter", (PyCFunction)verifying_queryAdapter, METH_KEYWORDS | METH_VARARGS, ""},
|
|
|
{"adapter_hook", (PyCFunction)verifying_adapter_hook, METH_KEYWORDS | METH_VARARGS, ""},
|
|
|
{"lookupAll", (PyCFunction)verifying_lookupAll, METH_KEYWORDS | METH_VARARGS, ""},
|
|
|
{"subscriptions", (PyCFunction)verifying_subscriptions, METH_KEYWORDS | METH_VARARGS, ""},
|
|
|
{NULL, NULL} /* sentinel */
|
|
|
};
|
|
|
|
|
|
static PyTypeObject VerifyingBase = {
|
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
|
/* tp_name */ "_zope_interface_coptimizations."
|
|
|
"VerifyingBase",
|
|
|
/* tp_basicsize */ sizeof(verify),
|
|
|
/* tp_itemsize */ 0,
|
|
|
/* tp_dealloc */ (destructor)&verifying_dealloc,
|
|
|
/* tp_print */ (printfunc)0,
|
|
|
/* tp_getattr */ (getattrfunc)0,
|
|
|
/* tp_setattr */ (setattrfunc)0,
|
|
|
/* tp_compare */ 0,
|
|
|
/* tp_repr */ (reprfunc)0,
|
|
|
/* tp_as_number */ 0,
|
|
|
/* tp_as_sequence */ 0,
|
|
|
/* tp_as_mapping */ 0,
|
|
|
/* tp_hash */ (hashfunc)0,
|
|
|
/* tp_call */ (ternaryfunc)0,
|
|
|
/* tp_str */ (reprfunc)0,
|
|
|
/* tp_getattro */ (getattrofunc)0,
|
|
|
/* tp_setattro */ (setattrofunc)0,
|
|
|
/* tp_as_buffer */ 0,
|
|
|
/* tp_flags */ Py_TPFLAGS_DEFAULT
|
|
|
| Py_TPFLAGS_BASETYPE
|
|
|
| Py_TPFLAGS_HAVE_GC,
|
|
|
/* tp_doc */ "",
|
|
|
/* tp_traverse */ (traverseproc)verifying_traverse,
|
|
|
/* tp_clear */ (inquiry)verifying_clear,
|
|
|
/* tp_richcompare */ (richcmpfunc)0,
|
|
|
/* tp_weaklistoffset */ (long)0,
|
|
|
/* tp_iter */ (getiterfunc)0,
|
|
|
/* tp_iternext */ (iternextfunc)0,
|
|
|
/* tp_methods */ verifying_methods,
|
|
|
/* tp_members */ 0,
|
|
|
/* tp_getset */ 0,
|
|
|
/* tp_base */ &LookupBase,
|
|
|
};
|
|
|
|
|
|
/* ========================== End: Lookup Bases ======================= */
|
|
|
/* ==================================================================== */
|
|
|
|
|
|
|
|
|
|
|
|
static struct PyMethodDef m_methods[] = {
|
|
|
{"implementedBy", (PyCFunction)implementedBy, METH_O,
|
|
|
"Interfaces implemented by a class or factory.\n"
|
|
|
"Raises TypeError if argument is neither a class nor a callable."},
|
|
|
{"getObjectSpecification", (PyCFunction)getObjectSpecification, METH_O,
|
|
|
"Get an object's interfaces (internal api)"},
|
|
|
{"providedBy", (PyCFunction)providedBy, METH_O,
|
|
|
"Get an object's interfaces"},
|
|
|
|
|
|
{NULL, (PyCFunction)NULL, 0, NULL} /* sentinel */
|
|
|
};
|
|
|
|
|
|
#if PY_MAJOR_VERSION >= 3
|
|
|
static char module_doc[] = "C optimizations for zope.interface\n\n";
|
|
|
|
|
|
static struct PyModuleDef _zic_module = {
|
|
|
PyModuleDef_HEAD_INIT,
|
|
|
"_zope_interface_coptimizations",
|
|
|
module_doc,
|
|
|
-1,
|
|
|
m_methods,
|
|
|
NULL,
|
|
|
NULL,
|
|
|
NULL,
|
|
|
NULL
|
|
|
};
|
|
|
#endif
|
|
|
|
|
|
static PyObject *
|
|
|
init(void)
|
|
|
{
|
|
|
PyObject *m;
|
|
|
|
|
|
#if PY_MAJOR_VERSION < 3
|
|
|
#define DEFINE_STRING(S) \
|
|
|
if(! (str ## S = PyString_FromString(# S))) return NULL
|
|
|
#else
|
|
|
#define DEFINE_STRING(S) \
|
|
|
if(! (str ## S = PyUnicode_FromString(# S))) return NULL
|
|
|
#endif
|
|
|
|
|
|
DEFINE_STRING(__dict__);
|
|
|
DEFINE_STRING(__implemented__);
|
|
|
DEFINE_STRING(__provides__);
|
|
|
DEFINE_STRING(__class__);
|
|
|
DEFINE_STRING(__providedBy__);
|
|
|
DEFINE_STRING(extends);
|
|
|
DEFINE_STRING(_implied);
|
|
|
DEFINE_STRING(_implements);
|
|
|
DEFINE_STRING(_cls);
|
|
|
DEFINE_STRING(__conform__);
|
|
|
DEFINE_STRING(_call_conform);
|
|
|
DEFINE_STRING(_uncached_lookup);
|
|
|
DEFINE_STRING(_uncached_lookupAll);
|
|
|
DEFINE_STRING(_uncached_subscriptions);
|
|
|
DEFINE_STRING(_registry);
|
|
|
DEFINE_STRING(_generation);
|
|
|
DEFINE_STRING(ro);
|
|
|
DEFINE_STRING(changed);
|
|
|
#undef DEFINE_STRING
|
|
|
adapter_hooks = PyList_New(0);
|
|
|
if (adapter_hooks == NULL)
|
|
|
return NULL;
|
|
|
|
|
|
/* Initialize types: */
|
|
|
SpecType.tp_new = PyBaseObject_Type.tp_new;
|
|
|
if (PyType_Ready(&SpecType) < 0)
|
|
|
return NULL;
|
|
|
OSDType.tp_new = PyBaseObject_Type.tp_new;
|
|
|
if (PyType_Ready(&OSDType) < 0)
|
|
|
return NULL;
|
|
|
CPBType.tp_new = PyBaseObject_Type.tp_new;
|
|
|
if (PyType_Ready(&CPBType) < 0)
|
|
|
return NULL;
|
|
|
|
|
|
InterfaceBase.tp_new = PyBaseObject_Type.tp_new;
|
|
|
if (PyType_Ready(&InterfaceBase) < 0)
|
|
|
return NULL;
|
|
|
|
|
|
LookupBase.tp_new = PyBaseObject_Type.tp_new;
|
|
|
if (PyType_Ready(&LookupBase) < 0)
|
|
|
return NULL;
|
|
|
|
|
|
VerifyingBase.tp_new = PyBaseObject_Type.tp_new;
|
|
|
if (PyType_Ready(&VerifyingBase) < 0)
|
|
|
return NULL;
|
|
|
|
|
|
#if PY_MAJOR_VERSION < 3
|
|
|
/* Create the module and add the functions */
|
|
|
m = Py_InitModule3("_zope_interface_coptimizations", m_methods,
|
|
|
"C optimizations for zope.interface\n\n");
|
|
|
#else
|
|
|
m = PyModule_Create(&_zic_module);
|
|
|
#endif
|
|
|
if (m == NULL)
|
|
|
return NULL;
|
|
|
|
|
|
/* Add types: */
|
|
|
if (PyModule_AddObject(m, "SpecificationBase", OBJECT(&SpecType)) < 0)
|
|
|
return NULL;
|
|
|
if (PyModule_AddObject(m, "ObjectSpecificationDescriptor",
|
|
|
(PyObject *)&OSDType) < 0)
|
|
|
return NULL;
|
|
|
if (PyModule_AddObject(m, "ClassProvidesBase", OBJECT(&CPBType)) < 0)
|
|
|
return NULL;
|
|
|
if (PyModule_AddObject(m, "InterfaceBase", OBJECT(&InterfaceBase)) < 0)
|
|
|
return NULL;
|
|
|
if (PyModule_AddObject(m, "LookupBase", OBJECT(&LookupBase)) < 0)
|
|
|
return NULL;
|
|
|
if (PyModule_AddObject(m, "VerifyingBase", OBJECT(&VerifyingBase)) < 0)
|
|
|
return NULL;
|
|
|
if (PyModule_AddObject(m, "adapter_hooks", adapter_hooks) < 0)
|
|
|
return NULL;
|
|
|
return m;
|
|
|
}
|
|
|
|
|
|
PyMODINIT_FUNC
|
|
|
#if PY_MAJOR_VERSION < 3
|
|
|
init_zope_interface_coptimizations(void)
|
|
|
{
|
|
|
init();
|
|
|
}
|
|
|
#else
|
|
|
PyInit__zope_interface_coptimizations(void)
|
|
|
{
|
|
|
return init();
|
|
|
}
|
|
|
#endif
|
|
|
|