Skip to content

Commit 890959a

Browse files
committed
use stable ABI methods to make buffers
less work when it's time to try stable ABI wheels
1 parent 741a800 commit 890959a

File tree

3 files changed

+40
-26
lines changed

3 files changed

+40
-26
lines changed

tests/test_message.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
import time
1717

18+
import pytest
19+
1820
import zmq
1921
from zmq_test_utils import PYPY, BaseZMQTestCase, SkipTest, skip_cpython_cffi, skip_pypy
2022

@@ -215,11 +217,18 @@ def test_buffer_in(self):
215217
"""test using a buffer as input"""
216218
ins = "§§¶•ªº˜µ¬˚…∆˙åß∂©œ∑´†≈ç√".encode()
217219
zmq.Frame(memoryview(ins))
220+
zmq.Frame(bytearray(5))
218221

219222
def test_bad_buffer_in(self):
220223
"""test using a bad object"""
221-
self.assertRaises(TypeError, zmq.Frame, 5)
222-
self.assertRaises(TypeError, zmq.Frame, object())
224+
with pytest.raises(TypeError):
225+
zmq.Frame(5)
226+
with pytest.raises(TypeError):
227+
zmq.Frame(object())
228+
with pytest.raises(TypeError):
229+
zmq.Frame("str")
230+
with pytest.raises(BufferError):
231+
zmq.Frame(memoryview(bytearray(10))[::2])
223232

224233
def test_buffer_out(self):
225234
"""receiving buffered output"""

tests/test_socket.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -513,11 +513,11 @@ def test_recv_into_bad(self):
513513
b.recv_into(buf, nbytes=-1)
514514
# not contiguous
515515
buf = memoryview(bytearray(10))[::2]
516-
with pytest.raises(ValueError):
516+
with pytest.raises(BufferError):
517517
b.recv_into(buf)
518518
# readonly
519519
buf = memoryview(b"readonly")
520-
with pytest.raises(ValueError):
520+
with pytest.raises(BufferError):
521521
b.recv_into(buf)
522522
# too big
523523
buf = bytearray(10)

zmq/backend/cython/_zmq.py

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,13 @@
6363
PyBytes_Size,
6464
PyErr_CheckSignals,
6565
)
66-
from cython.cimports.cpython.buffer import Py_buffer, PyBuffer_IsContiguous
67-
from cython.cimports.cpython.memoryview import PyMemoryView_GET_BUFFER
66+
from cython.cimports.cpython.buffer import (
67+
Py_buffer,
68+
PyBUF_ANY_CONTIGUOUS,
69+
PyBUF_WRITABLE,
70+
PyBuffer_Release,
71+
PyObject_GetBuffer,
72+
)
6873
from cython.cimports.libc.errno import EAGAIN, EINTR, ENAMETOOLONG, ENOENT, ENOTSOCK
6974

7075
# cimports require Cython 3
@@ -245,14 +250,19 @@ def _copy_zmq_msg_bytes(zmq_msg: pointer(zmq_msg_t)) -> bytes:
245250

246251
@cfunc
247252
@inline
248-
def _asbuffer(buf, data_c: pointer(p_void)) -> size_t:
253+
def _asbuffer(obj, data_c: pointer(p_void), writable: bint = False) -> size_t:
249254
"""Get a C buffer from a memoryview"""
250-
view = memoryview(buf)
251-
pybuf: pointer(Py_buffer) = PyMemoryView_GET_BUFFER(view)
252-
if not PyBuffer_IsContiguous(pybuf, 'A'):
253-
raise BufferError("memoryview: underlying buffer is not contiguous")
255+
pybuf = declare(Py_buffer)
256+
flags: C.int = PyBUF_ANY_CONTIGUOUS
257+
if writable:
258+
flags |= PyBUF_WRITABLE
259+
rc: C.int = PyObject_GetBuffer(obj, address(pybuf), flags)
260+
if rc < 0:
261+
raise ValueError("Couldn't create buffer")
254262
data_c[0] = pybuf.buf
255-
return pybuf.len
263+
data_size: size_t = pybuf.len
264+
PyBuffer_Release(address(pybuf))
265+
return data_size
256266

257267

258268
_gc = None
@@ -1237,31 +1247,26 @@ def recv_into(self, buffer, /, *, nbytes=0, flags=0) -> C.int:
12371247
------
12381248
ZMQError
12391249
for any of the reasons `zmq_recv` might fail.
1240-
ValueError
1241-
for invalid inputs, such as readonly or not contiguous buffers,
1242-
or invalid nbytes.
1250+
BufferError
1251+
for invalid buffers, such as readonly or not contiguous.
12431252
"""
12441253
c_flags: C.int = flags
12451254
_check_closed(self)
1246-
c_nbytes: C.int = nbytes
1255+
c_nbytes: size_t = nbytes
12471256
if c_nbytes < 0:
12481257
raise ValueError(f"{nbytes=} must be non-negative")
12491258
view = memoryview(buffer)
1250-
# get C buffer
1251-
py_buf: pointer(Py_buffer) = PyMemoryView_GET_BUFFER(view)
1252-
if py_buf.readonly:
1253-
raise ValueError("Cannot recv_into readonly buffer")
1254-
if not PyBuffer_IsContiguous(py_buf, 'A'):
1255-
raise ValueError("Can only recv_into contiguous buffer")
1259+
c_data = declare(pointer(C.void))
1260+
view_bytes: C.size_t = _asbuffer(view, address(c_data), True)
12561261
if nbytes == 0:
1257-
c_nbytes = py_buf.len
1258-
elif c_nbytes > py_buf.len:
1259-
raise ValueError(f"{nbytes=} too big for memoryview of {py_buf.len}B")
1262+
c_nbytes = view_bytes
1263+
elif c_nbytes > view_bytes:
1264+
raise ValueError(f"{nbytes=} too big for memoryview of {view_bytes}B")
12601265

12611266
# call zmq_recv, with retries
12621267
while True:
12631268
with nogil:
1264-
rc: C.int = zmq_recv(self.handle, py_buf.buf, c_nbytes, c_flags)
1269+
rc: C.int = zmq_recv(self.handle, c_data, c_nbytes, c_flags)
12651270
try:
12661271
_check_rc(rc)
12671272
except InterruptedSystemCall:

0 commit comments

Comments
 (0)