diff options
Diffstat (limited to 'src/zope/interface/_zope_interface_coptimizations.c')
| -rw-r--r-- | src/zope/interface/_zope_interface_coptimizations.c | 91 |
1 files changed, 61 insertions, 30 deletions
diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c index f4f9cce..3a2ecec 100644 --- a/src/zope/interface/_zope_interface_coptimizations.c +++ b/src/zope/interface/_zope_interface_coptimizations.c @@ -43,6 +43,11 @@ 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 PyObject *str__get__; +static PyObject *str__self__; +static PyObject *str__thisclass__; +static PyObject *str__self_class__; +static PyObject *str__mro__; static PyTypeObject *Implements; @@ -91,6 +96,7 @@ import_declarations(void) return 0; } + static PyTypeObject SpecType; /* Forward */ static PyObject * @@ -111,6 +117,12 @@ implementedBy(PyObject *ignored, PyObject *cls) PyObject *dict = NULL, *spec; + if (PyObject_TypeCheck(cls, &PySuper_Type)) + { + // Let merging be handled by Python. + return implementedByFallback(cls); + } + if (PyType_Check(cls)) { dict = TYPE(cls)->tp_dict; @@ -168,6 +180,7 @@ getObjectSpecification(PyObject *ignored, PyObject *ob) if (result != NULL && PyObject_TypeCheck(result, &SpecType)) return result; + PyErr_Clear(); /* We do a getattr here so as not to be defeated by proxies */ @@ -176,11 +189,11 @@ getObjectSpecification(PyObject *ignored, PyObject *ob) { PyErr_Clear(); if (imported_declarations == 0 && import_declarations() < 0) - return NULL; + return NULL; + Py_INCREF(empty); return empty; } - result = implementedBy(NULL, cls); Py_DECREF(cls); @@ -192,7 +205,15 @@ providedBy(PyObject *ignored, PyObject *ob) { PyObject *result, *cls, *cp; + result = NULL; + + if (PyObject_TypeCheck(ob, &PySuper_Type)) + { + return implementedBy(NULL, ob); + } + result = PyObject_GetAttr(ob, str__providedBy__); + if (result == NULL) { PyErr_Clear(); @@ -947,27 +968,14 @@ _getcache(lookup *self, PyObject *provided, PyObject *name) 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; - + result = key = cache = NULL; #ifdef PY3K if ( name && !PyUnicode_Check(name) ) #else @@ -978,14 +986,19 @@ _lookup(lookup *self, "name is not a string or unicode"); return NULL; } - cache = _getcache(self, provided, name); - if (cache == NULL) - return NULL; - required = tuplefy(required); + /* If `required` is a lazy sequence, it could have arbitrary side-effects, + such as clearing our caches. So we must not retreive the cache until + after resolving it. */ + required = PySequence_Tuple(required); if (required == NULL) return NULL; + + cache = _getcache(self, provided, name); + if (cache == NULL) + return NULL; + if (PyTuple_GET_SIZE(required) == 1) key = PyTuple_GET_ITEM(required, 0); else @@ -1154,12 +1167,23 @@ _adapter_hook(lookup *self, return NULL; if (factory != Py_None) - { + { + if (PyObject_TypeCheck(object, &PySuper_Type)) { + PyObject* self = PyObject_GetAttr(object, str__self__); + if (self == NULL) + { + Py_DECREF(factory); + return NULL; + } + // Borrow the reference to self + Py_DECREF(self); + object = self; + } result = PyObject_CallFunctionObjArgs(factory, object, NULL); Py_DECREF(factory); if (result == NULL || result != Py_None) return result; - } + } else result = factory; /* None */ @@ -1217,15 +1241,16 @@ _lookupAll(lookup *self, PyObject *required, PyObject *provided) { PyObject *cache, *result; + /* resolve before getting cache. See note in _lookup. */ + required = PySequence_Tuple(required); + if (required == NULL) + return NULL; + 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) { @@ -1287,15 +1312,16 @@ _subscriptions(lookup *self, PyObject *required, PyObject *provided) { PyObject *cache, *result; + /* resolve before getting cache. See note in _lookup. */ + required = PySequence_Tuple(required); + if (required == NULL) + return NULL; + 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) { @@ -1736,6 +1762,11 @@ init(void) DEFINE_STRING(_generation); DEFINE_STRING(ro); DEFINE_STRING(changed); + DEFINE_STRING(__self__); + DEFINE_STRING(__get__); + DEFINE_STRING(__thisclass__); + DEFINE_STRING(__self_class__); + DEFINE_STRING(__mro__); #undef DEFINE_STRING adapter_hooks = PyList_New(0); if (adapter_hooks == NULL) |
