From 6cf696233e4d777cda88c6ee06053bf71f73a445 Mon Sep 17 00:00:00 2001 From: Sanjay Santhanam <51058514+Sanjays2402@users.noreply.github.com> Date: Sun, 12 Jul 2026 11:38:30 -0700 Subject: [PATCH] Make bytes() on a proxy match bytes() on the wrapped object The C extension implementation of ObjectProxy.__bytes__() called PyObject_Bytes() on the wrapped object, which only honours the __bytes__() protocol. As the proxy always defines __bytes__(), bytes() on a proxy routed through it, so bytes() on a proxy wrapping an object without __bytes__() (e.g. an int) raised TypeError even though bytes() on the wrapped object works. The pure Python implementation already used the bytes() constructor and behaved correctly. Use the bytes() constructor in the C extension too so both implementations return the same result as calling bytes() on the wrapped object directly. --- docs/changes.rst | 13 +++++++++++++ src/wrapt/_wrappers.c | 3 ++- tests/core/test_object_proxy.py | 10 ++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/docs/changes.rst b/docs/changes.rst index 6980c18a..e82dd29f 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -70,6 +70,19 @@ Version 2.3.0 argument form works, and the argument to ``__class_getitem__()`` is now positional only. +**Bugs Fixed** + +* Calling ``bytes()`` on an object proxy did not match calling ``bytes()`` + on the wrapped object directly when the wrapped object did not implement + ``__bytes__()``. The C extension implementation of ``__bytes__()`` used + ``PyObject_Bytes()``, which only honours the ``__bytes__()`` protocol, so + ``bytes(wrapt.ObjectProxy(3))`` raised ``TypeError`` even though + ``bytes(3)`` returns a zero filled buffer. The pure Python implementation + already used the ``bytes()`` constructor and was unaffected. The C + extension now uses the ``bytes()`` constructor as well, so both + implementations yield the same result as using the wrapped object + directly. + Version 2.2.2 ------------- diff --git a/src/wrapt/_wrappers.c b/src/wrapt/_wrappers.c index 9ea1001d..16955b6c 100644 --- a/src/wrapt/_wrappers.c +++ b/src/wrapt/_wrappers.c @@ -2450,7 +2450,8 @@ static PyObject *WraptObjectProxy_bytes(WraptObjectProxyObject *self, return NULL; } - return PyObject_Bytes(self->wrapped); + return PyObject_CallFunctionObjArgs((PyObject *)&PyBytes_Type, + self->wrapped, NULL); } /* ------------------------------------------------------------------------- */ diff --git a/tests/core/test_object_proxy.py b/tests/core/test_object_proxy.py index afb5db83..142185bd 100644 --- a/tests/core/test_object_proxy.py +++ b/tests/core/test_object_proxy.py @@ -1932,6 +1932,16 @@ def __bytes__(self): self.assertEqual(bytes(instance), bytes(proxy)) + def test_int_bytes(self): + # bytes(proxy) should behave like bytes() on the wrapped object even + # when it has no __bytes__ (e.g. an int, where bytes(n) yields a + # zero-filled buffer of length n). + instance = 3 + + proxy = wrapt.ObjectProxy(instance) + + self.assertEqual(bytes(instance), bytes(proxy)) + def test_str_format(self): instance = "abcd"