/*########################################################################### # # 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