Commit 4b58bc3d authored by Kevin Modzelewski's avatar Kevin Modzelewski

Add the slotdef for tp_descr_get and make getattr_hook check it

parent 8f1cfa61
...@@ -142,6 +142,24 @@ static PyObject* wrap_next(PyObject* self, PyObject* args, void* wrapped) { ...@@ -142,6 +142,24 @@ static PyObject* wrap_next(PyObject* self, PyObject* args, void* wrapped) {
return res; return res;
} }
static PyObject* wrap_descr_get(PyObject* self, PyObject* args, void* wrapped) noexcept {
descrgetfunc func = (descrgetfunc)wrapped;
PyObject* obj;
PyObject* type = NULL;
if (!PyArg_UnpackTuple(args, "", 1, 2, &obj, &type))
return NULL;
if (obj == Py_None)
obj = NULL;
if (type == Py_None)
type = NULL;
if (type == NULL && obj == NULL) {
PyErr_SetString(PyExc_TypeError, "__get__(None, None) is invalid");
return NULL;
}
return (*func)(self, obj, type);
}
static PyObject* wrap_coercefunc(PyObject* self, PyObject* args, void* wrapped) noexcept { static PyObject* wrap_coercefunc(PyObject* self, PyObject* args, void* wrapped) noexcept {
coercion func = (coercion)wrapped; coercion func = (coercion)wrapped;
PyObject* other, *res; PyObject* other, *res;
...@@ -676,6 +694,25 @@ static PyObject* slot_tp_iternext(PyObject* self) noexcept { ...@@ -676,6 +694,25 @@ static PyObject* slot_tp_iternext(PyObject* self) noexcept {
return call_method(self, "next", &next_str, "()"); return call_method(self, "next", &next_str, "()");
} }
static PyObject* slot_tp_descr_get(PyObject* self, PyObject* obj, PyObject* type) noexcept {
PyTypeObject* tp = Py_TYPE(self);
PyObject* get;
get = typeLookup(tp, "__get__", NULL);
if (get == NULL) {
/* Avoid further slowdowns */
if (tp->tp_descr_get == slot_tp_descr_get)
tp->tp_descr_get = NULL;
Py_INCREF(self);
return self;
}
if (obj == NULL)
obj = Py_None;
if (type == NULL)
type = Py_None;
return PyObject_CallFunctionObjArgs(get, self, obj, type, NULL);
}
static PyObject* slot_tp_getattro(PyObject* self, PyObject* name) noexcept { static PyObject* slot_tp_getattro(PyObject* self, PyObject* name) noexcept {
static PyObject* getattribute_str = NULL; static PyObject* getattribute_str = NULL;
return call_method(self, "__getattribute__", &getattribute_str, "(O)", name); return call_method(self, "__getattribute__", &getattribute_str, "(O)", name);
...@@ -719,8 +756,6 @@ static PyObject* call_attribute(PyObject* self, PyObject* attr, PyObject* name) ...@@ -719,8 +756,6 @@ static PyObject* call_attribute(PyObject* self, PyObject* attr, PyObject* name)
static PyObject* slot_tp_getattr_hook(PyObject* self, PyObject* name) noexcept { static PyObject* slot_tp_getattr_hook(PyObject* self, PyObject* name) noexcept {
PyObject* getattr, *getattribute, * res = NULL; PyObject* getattr, *getattribute, * res = NULL;
static PyObject* getattribute_str = NULL;
static PyObject* getattr_str = NULL;
/* speed hack: we could use lookup_maybe, but that would resolve the /* speed hack: we could use lookup_maybe, but that would resolve the
method fully for each attribute lookup for classes with method fully for each attribute lookup for classes with
...@@ -746,13 +781,9 @@ static PyObject* slot_tp_getattr_hook(PyObject* self, PyObject* name) noexcept { ...@@ -746,13 +781,9 @@ static PyObject* slot_tp_getattr_hook(PyObject* self, PyObject* name) noexcept {
} else { } else {
res = call_attribute(self, getattribute, name); res = call_attribute(self, getattribute, name);
} }
if (res == NULL) { if (res == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) {
try { PyErr_Clear();
res = runtimeCall(getattr, ArgPassSpec(2, 0, false, false), self, name, NULL, NULL, NULL); res = call_attribute(self, getattr, name);
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
}
} }
return res; return res;
} }
...@@ -1224,6 +1255,7 @@ static slotdef slotdefs[] ...@@ -1224,6 +1255,7 @@ static slotdef slotdefs[]
TPSLOT("__iter__", tp_iter, slot_tp_iter, wrap_unaryfunc, "x.__iter__() <==> iter(x)"), TPSLOT("__iter__", tp_iter, slot_tp_iter, wrap_unaryfunc, "x.__iter__() <==> iter(x)"),
TPSLOT("next", tp_iternext, slot_tp_iternext, wrap_next, "x.next() -> the next value, or raise StopIteration"), TPSLOT("next", tp_iternext, slot_tp_iternext, wrap_next, "x.next() -> the next value, or raise StopIteration"),
TPSLOT("__get__", tp_descr_get, slot_tp_descr_get, wrap_descr_get, "descr.__get__(obj[, type]) -> value"),
FLSLOT("__init__", tp_init, slot_tp_init, (wrapperfunc)wrap_init, "x.__init__(...) initializes x; " FLSLOT("__init__", tp_init, slot_tp_init, (wrapperfunc)wrap_init, "x.__init__(...) initializes x; "
"see help(type(x)) for signature", "see help(type(x)) for signature",
......
# expected: fail
# - object.__getattribute__ doesn't exist
# attr-getting resolution. # attr-getting resolution.
class M(type): class M(type):
......
...@@ -53,8 +53,6 @@ else: ...@@ -53,8 +53,6 @@ else:
print 'False' print 'False'
# __getattr__ and __setattr__ # __getattr__ and __setattr__
# Looks like __getattr__ and __setattr__ should *not* be looked up with
# the descriptor protocol
class DescriptorGetattr(object): class DescriptorGetattr(object):
def __get__(self, obj, type): def __get__(self, obj, type):
print 'getattr __get__ called' print 'getattr __get__ called'
...@@ -68,8 +66,8 @@ class DescriptorSetattr(object): ...@@ -68,8 +66,8 @@ class DescriptorSetattr(object):
def setattr(attr, val): def setattr(attr, val):
print 'setattr called for attr', attr, val print 'setattr called for attr', attr, val
class D(object): class D(object):
__getattr__ = DescriptorGetattr __getattr__ = DescriptorGetattr()
__setattr__ = DescriptorSetattr __setattr__ = DescriptorSetattr()
d = D() d = D()
try: try:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment