Commit 6fb96530 authored by Tres Seaver's avatar Tres Seaver

Make module-level 'aq_acquire' respect 'default'.

Fixes LP #1387363.

Cherry-pick cdfad147 and
ea7ef69d from master.
parent e5253424
...@@ -4,6 +4,9 @@ Changelog ...@@ -4,6 +4,9 @@ Changelog
2.13.9 (unreleased) 2.13.9 (unreleased)
------------------- -------------------
- Make module-level ``aq_acquire`` API respect the ``default`` parameter.
LP #1387363.
- Don't raise an attribute error for ``__iter__`` if the fallback to - Don't raise an attribute error for ``__iter__`` if the fallback to
``__getitem__`` succeeds. LP #1155760. ``__getitem__`` succeeds. LP #1155760.
......
...@@ -1489,12 +1489,14 @@ capi_aq_acquire(PyObject *self, PyObject *name, PyObject *filter, ...@@ -1489,12 +1489,14 @@ capi_aq_acquire(PyObject *self, PyObject *name, PyObject *filter,
if (filter==Py_None) filter=0; if (filter==Py_None) filter=0;
/* We got a wrapped object, so business as usual */ /* We got a wrapped object, so business as usual */
if (isWrapper(self)) if (isWrapper(self)) {
return Wrapper_findattr( result = Wrapper_findattr(
WRAPPER(self), name, filter, extra, OBJECT(self),1, WRAPPER(self), name, filter, extra, OBJECT(self),1,
explicit || explicit ||
WRAPPER(self)->ob_type==(PyTypeObject*)&Wrappertype, WRAPPER(self)->ob_type==(PyTypeObject*)&Wrappertype,
explicit, containment); explicit, containment);
goto check_default;
}
/* Not wrapped; check if we have a __parent__ pointer. If that's /* Not wrapped; check if we have a __parent__ pointer. If that's
the case, create a wrapper and pretend it's business as usual. */ the case, create a wrapper and pretend it's business as usual. */
else if ((result = PyObject_GetAttr(self, py__parent__))) else if ((result = PyObject_GetAttr(self, py__parent__)))
...@@ -1505,7 +1507,7 @@ capi_aq_acquire(PyObject *self, PyObject *name, PyObject *filter, ...@@ -1505,7 +1507,7 @@ capi_aq_acquire(PyObject *self, PyObject *name, PyObject *filter,
OBJECT(self), 1, 1, explicit, containment); OBJECT(self), 1, 1, explicit, containment);
/* Get rid of temporary wrapper */ /* Get rid of temporary wrapper */
Py_DECREF(self); Py_DECREF(self);
return result; goto check_default;
} }
/* No wrapper and no __parent__, so just getattr. */ /* No wrapper and no __parent__, so just getattr. */
else else
...@@ -1520,7 +1522,10 @@ capi_aq_acquire(PyObject *self, PyObject *name, PyObject *filter, ...@@ -1520,7 +1522,10 @@ capi_aq_acquire(PyObject *self, PyObject *name, PyObject *filter,
} }
Py_XDECREF(result); Py_XDECREF(v); Py_XDECREF(tb); Py_XDECREF(result); Py_XDECREF(v); Py_XDECREF(tb);
if (! filter) return PyObject_GetAttr(self, name); if (! filter) {
result = PyObject_GetAttr(self, name);
goto check_default;
}
/* Crap, we've got to construct a wrapper so we can use /* Crap, we've got to construct a wrapper so we can use
Wrapper_findattr */ Wrapper_findattr */
...@@ -1532,8 +1537,22 @@ capi_aq_acquire(PyObject *self, PyObject *name, PyObject *filter, ...@@ -1532,8 +1537,22 @@ capi_aq_acquire(PyObject *self, PyObject *name, PyObject *filter,
/* Get rid of temporary wrapper */ /* Get rid of temporary wrapper */
Py_DECREF(self); Py_DECREF(self);
return result; goto check_default;
} }
check_default:
if (result == NULL && defalt != NULL) {
/* as "Python/bltinmodule.c:builtin_getattr" turn
only 'AttributeError' into a default value, such
that e.g. "ConflictError" and errors raised by the filter
are not mapped to the default value.
*/
if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
PyErr_Clear();
Py_INCREF(defalt);
result = defalt;
}
}
return result;
} }
static PyObject * static PyObject *
......
...@@ -2515,6 +2515,19 @@ class TestAcquire(unittest.TestCase): ...@@ -2515,6 +2515,19 @@ class TestAcquire(unittest.TestCase):
def test_explicit_wrapper_false(self): def test_explicit_wrapper_false(self):
self.assertEqual(self.a.b.c.aq_acquire('z', explicit=False), 3) self.assertEqual(self.a.b.c.aq_acquire('z', explicit=False), 3)
def test_wrapper_falls_back_to_default(self):
self.assertEqual(self.acquire(self.a.b.c, 'nonesuch', default=4), 4)
def test_no_wrapper_but___parent___falls_back_to_default(self):
class NotWrapped(object):
pass
child = NotWrapped()
parent = child.__parent__ = NotWrapped()
self.assertEqual(self.acquire(child, 'nonesuch', default=4), 4)
def test_unwrapped_falls_back_to_default(self):
self.assertEqual(self.acquire(object(), 'nonesuch', default=4), 4)
class TestUnicode(unittest.TestCase): class TestUnicode(unittest.TestCase):
......
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