Skip to content

Commit

Permalink
Merge 2b058db into 1ded4d9
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael Howitz committed Apr 18, 2019
2 parents 1ded4d9 + 2b058db commit 8a54299
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 5 deletions.
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ matrix:
include:
- name: "2.7-pure"
python: "2.7"
env: PURE_PYTHON = 1
env: PURE_PYTHON=1
- python: "3.7"
dist: xenial
- name: "3.7-pure"
python: "3.7"
env: PURE_PYTHON = 1
env: PURE_PYTHON=1
dist: xenial
- python: "3.8-dev"
dist: xenial
Expand Down
4 changes: 4 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ Changelog

- Add support for Python 3.8a3.

- Add support to call ``bytes()`` on an object wrapped by an
``ImplicitAcquisitionWrapper``.
(`#38 <https://github.com/zopefoundation/Acquisition/issues/38>`_)


4.5 (2018-10-05)
----------------
Expand Down
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,7 @@ Conclusion
----------

Acquisition provides a powerful way to dynamically share information
between objects. Zope 2 uses acquisition for a number of its key
between objects. Zope uses acquisition for a number of its key
features including security, object publishing, and DTML variable
lookup. Acquisition also provides an elegant solution to the problem
of circular references for many classes of problems. While acquisition
Expand Down
24 changes: 23 additions & 1 deletion src/Acquisition/_Acquisition.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ static PyObject *py__add__, *py__sub__, *py__mul__, *py__div__,
*py__long__, *py__float__, *py__oct__, *py__hex__,
*py__getitem__, *py__setitem__, *py__delitem__,
*py__getslice__, *py__setslice__, *py__delslice__, *py__contains__,
*py__len__, *py__of__, *py__call__, *py__repr__, *py__str__, *py__unicode__,
*py__len__, *py__of__, *py__call__, *py__repr__,
*py__str__, *py__unicode__, *py__bytes__,
*py__cmp__, *py__parent__, *py__iter__, *py__bool__, *py__index__, *py__iadd__,
*py__isub__, *py__imul__, *py__imod__, *py__ipow__, *py__ilshift__, *py__irshift__,
*py__iand__, *py__ixor__, *py__ior__, *py__floordiv__, *py__truediv__,
Expand Down Expand Up @@ -95,6 +96,7 @@ init_py_names(void)
INIT_PY_NAME(__repr__);
INIT_PY_NAME(__str__);
INIT_PY_NAME(__unicode__);
INIT_PY_NAME(__bytes__);
INIT_PY_NAME(__cmp__);
INIT_PY_NAME(__parent__);
INIT_PY_NAME(__iter__);
Expand Down Expand Up @@ -970,6 +972,24 @@ Wrapper_unicode(Wrapper *self)
}
}

static PyObject *
Wrapper_bytes(Wrapper *self)
{
PyObject *r;

if ((r = PyObject_GetAttr(OBJECT(self), py__bytes__))) {
ASSIGN(r, PyObject_CallFunction(r, NULL, NULL));
return r;
} else {
PyErr_Clear();
#ifdef PY3K
return PyBytes_FromObject(self->obj);
#else
return Wrapper_str(self);
#endif
}
}

static long
Wrapper_hash(Wrapper *self)
{
Expand Down Expand Up @@ -1487,6 +1507,8 @@ static struct PyMethodDef Wrapper_methods[] = {
"Wrappers are not picklable"},
{"__unicode__", (PyCFunction)Wrapper_unicode, METH_NOARGS,
"Unicode"},
{"__bytes__", (PyCFunction)Wrapper_bytes, METH_NOARGS,
"Bytes"},
{NULL, NULL}
};

Expand Down
9 changes: 8 additions & 1 deletion src/Acquisition/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def _apply_filter(predicate, inst, name, result, extra, orig):
return predicate(orig, inst, name, result, extra)


if sys.version_info < (3,):
if sys.version_info < (3,): # pragma: PY2
import copy_reg

def _rebound_method(method, wrapper):
Expand Down Expand Up @@ -566,6 +566,13 @@ def __str__(self):
except (AttributeError, TypeError): # pragma: PY3
return str(aq_self)

def __bytes__(self):
aq_self = self._obj
try:
return _rebound_method(aq_self.__bytes__, self)()
except (AttributeError, TypeError): # pragma: PY3
return bytes(aq_self)

__binary_special_methods__ = [
# general numeric
'__add__',
Expand Down
21 changes: 21 additions & 0 deletions src/Acquisition/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -2449,6 +2449,27 @@ class Impl(Implicit):
# By the time it gets there, it's not wrapped:
self.assertIs(type(child.__dict__['child2']), Impl)

def test__bytes__is_correcty_wrapped(self):
class A(Implicit):

def __bytes__(self):
return b'my bytes'

a = A()
a.b = A()
wrapper = Acquisition.ImplicitAcquisitionWrapper(a.b, a)
self.assertEqual(b'my bytes', bytes(wrapper))

def test_AttributeError_if_object_has_no__bytes__(self):
class A(Implicit):
pass

a = A()
a.b = A()
wrapper = Acquisition.ImplicitAcquisitionWrapper(a.b, a)
with self.assertRaises(TypeError):
bytes(wrapper)


class TestOf(unittest.TestCase):

Expand Down

0 comments on commit 8a54299

Please sign in to comment.