mirror of
https://github.com/msgpack/msgpack-python.git
synced 2025-10-19 12:03:15 +00:00
parent
e1068087e0
commit
e0f0e145f1
2 changed files with 57 additions and 15 deletions
|
@ -106,6 +106,7 @@ cdef class Packer:
|
||||||
cdef object _default
|
cdef object _default
|
||||||
cdef object _berrors
|
cdef object _berrors
|
||||||
cdef const char *unicode_errors
|
cdef const char *unicode_errors
|
||||||
|
cdef size_t exports # number of exported buffers
|
||||||
cdef bint strict_types
|
cdef bint strict_types
|
||||||
cdef bint use_float
|
cdef bint use_float
|
||||||
cdef bint autoreset
|
cdef bint autoreset
|
||||||
|
@ -117,10 +118,16 @@ cdef class Packer:
|
||||||
raise MemoryError("Unable to allocate internal buffer.")
|
raise MemoryError("Unable to allocate internal buffer.")
|
||||||
self.pk.buf_size = buf_size
|
self.pk.buf_size = buf_size
|
||||||
self.pk.length = 0
|
self.pk.length = 0
|
||||||
|
self.exports = 0
|
||||||
|
|
||||||
def __dealloc__(self):
|
def __dealloc__(self):
|
||||||
PyMem_Free(self.pk.buf)
|
PyMem_Free(self.pk.buf)
|
||||||
self.pk.buf = NULL
|
self.pk.buf = NULL
|
||||||
|
assert self.exports == 0
|
||||||
|
|
||||||
|
cdef _check_exports(self):
|
||||||
|
if self.exports > 0:
|
||||||
|
raise BufferError("Existing exports of data: Packer cannot be changed")
|
||||||
|
|
||||||
def __init__(self, *, default=None,
|
def __init__(self, *, default=None,
|
||||||
bint use_single_float=False, bint autoreset=True, bint use_bin_type=True,
|
bint use_single_float=False, bint autoreset=True, bint use_bin_type=True,
|
||||||
|
@ -149,8 +156,8 @@ cdef class Packer:
|
||||||
cdef unsigned long ulval
|
cdef unsigned long ulval
|
||||||
cdef const char* rawval
|
cdef const char* rawval
|
||||||
cdef Py_ssize_t L
|
cdef Py_ssize_t L
|
||||||
cdef bool strict_types = self.strict_types
|
|
||||||
cdef Py_buffer view
|
cdef Py_buffer view
|
||||||
|
cdef bint strict = self.strict_types
|
||||||
|
|
||||||
if o is None:
|
if o is None:
|
||||||
msgpack_pack_nil(&self.pk)
|
msgpack_pack_nil(&self.pk)
|
||||||
|
@ -158,7 +165,7 @@ cdef class Packer:
|
||||||
msgpack_pack_true(&self.pk)
|
msgpack_pack_true(&self.pk)
|
||||||
elif o is False:
|
elif o is False:
|
||||||
msgpack_pack_false(&self.pk)
|
msgpack_pack_false(&self.pk)
|
||||||
elif PyLong_CheckExact(o) if strict_types else PyLong_Check(o):
|
elif PyLong_CheckExact(o) if strict else PyLong_Check(o):
|
||||||
try:
|
try:
|
||||||
if o > 0:
|
if o > 0:
|
||||||
ullval = o
|
ullval = o
|
||||||
|
@ -171,19 +178,19 @@ cdef class Packer:
|
||||||
return -2
|
return -2
|
||||||
else:
|
else:
|
||||||
raise OverflowError("Integer value out of range")
|
raise OverflowError("Integer value out of range")
|
||||||
elif PyFloat_CheckExact(o) if strict_types else PyFloat_Check(o):
|
elif PyFloat_CheckExact(o) if strict else PyFloat_Check(o):
|
||||||
if self.use_float:
|
if self.use_float:
|
||||||
msgpack_pack_float(&self.pk, <float>o)
|
msgpack_pack_float(&self.pk, <float>o)
|
||||||
else:
|
else:
|
||||||
msgpack_pack_double(&self.pk, <double>o)
|
msgpack_pack_double(&self.pk, <double>o)
|
||||||
elif PyBytesLike_CheckExact(o) if strict_types else PyBytesLike_Check(o):
|
elif PyBytesLike_CheckExact(o) if strict else PyBytesLike_Check(o):
|
||||||
L = Py_SIZE(o)
|
L = Py_SIZE(o)
|
||||||
if L > ITEM_LIMIT:
|
if L > ITEM_LIMIT:
|
||||||
PyErr_Format(ValueError, b"%.200s object is too large", Py_TYPE(o).tp_name)
|
PyErr_Format(ValueError, b"%.200s object is too large", Py_TYPE(o).tp_name)
|
||||||
rawval = o
|
rawval = o
|
||||||
msgpack_pack_bin(&self.pk, L)
|
msgpack_pack_bin(&self.pk, L)
|
||||||
msgpack_pack_raw_body(&self.pk, rawval, L)
|
msgpack_pack_raw_body(&self.pk, rawval, L)
|
||||||
elif PyUnicode_CheckExact(o) if strict_types else PyUnicode_Check(o):
|
elif PyUnicode_CheckExact(o) if strict else PyUnicode_Check(o):
|
||||||
if self.unicode_errors == NULL:
|
if self.unicode_errors == NULL:
|
||||||
rawval = PyUnicode_AsUTF8AndSize(o, &L)
|
rawval = PyUnicode_AsUTF8AndSize(o, &L)
|
||||||
if L >ITEM_LIMIT:
|
if L >ITEM_LIMIT:
|
||||||
|
@ -196,7 +203,7 @@ cdef class Packer:
|
||||||
rawval = o
|
rawval = o
|
||||||
msgpack_pack_raw(&self.pk, L)
|
msgpack_pack_raw(&self.pk, L)
|
||||||
msgpack_pack_raw_body(&self.pk, rawval, L)
|
msgpack_pack_raw_body(&self.pk, rawval, L)
|
||||||
elif PyDict_CheckExact(o) if strict_types else PyDict_Check(o):
|
elif PyDict_CheckExact(o) if strict else PyDict_Check(o):
|
||||||
L = len(o)
|
L = len(o)
|
||||||
if L > ITEM_LIMIT:
|
if L > ITEM_LIMIT:
|
||||||
raise ValueError("dict is too large")
|
raise ValueError("dict is too large")
|
||||||
|
@ -204,7 +211,7 @@ cdef class Packer:
|
||||||
for k, v in o.items():
|
for k, v in o.items():
|
||||||
self._pack(k, nest_limit)
|
self._pack(k, nest_limit)
|
||||||
self._pack(v, nest_limit)
|
self._pack(v, nest_limit)
|
||||||
elif type(o) is ExtType if strict_types else isinstance(o, ExtType):
|
elif type(o) is ExtType if strict else isinstance(o, ExtType):
|
||||||
# This should be before Tuple because ExtType is namedtuple.
|
# This should be before Tuple because ExtType is namedtuple.
|
||||||
rawval = o.data
|
rawval = o.data
|
||||||
L = len(o.data)
|
L = len(o.data)
|
||||||
|
@ -216,7 +223,7 @@ cdef class Packer:
|
||||||
llval = o.seconds
|
llval = o.seconds
|
||||||
ulval = o.nanoseconds
|
ulval = o.nanoseconds
|
||||||
msgpack_pack_timestamp(&self.pk, llval, ulval)
|
msgpack_pack_timestamp(&self.pk, llval, ulval)
|
||||||
elif PyList_CheckExact(o) if strict_types else (PyTuple_Check(o) or PyList_Check(o)):
|
elif PyList_CheckExact(o) if strict else (PyTuple_Check(o) or PyList_Check(o)):
|
||||||
L = Py_SIZE(o)
|
L = Py_SIZE(o)
|
||||||
if L > ITEM_LIMIT:
|
if L > ITEM_LIMIT:
|
||||||
raise ValueError("list is too large")
|
raise ValueError("list is too large")
|
||||||
|
@ -264,6 +271,7 @@ cdef class Packer:
|
||||||
|
|
||||||
def pack(self, object obj):
|
def pack(self, object obj):
|
||||||
cdef int ret
|
cdef int ret
|
||||||
|
self._check_exports()
|
||||||
try:
|
try:
|
||||||
ret = self._pack(obj, DEFAULT_RECURSE_LIMIT)
|
ret = self._pack(obj, DEFAULT_RECURSE_LIMIT)
|
||||||
except:
|
except:
|
||||||
|
@ -277,12 +285,16 @@ cdef class Packer:
|
||||||
return buf
|
return buf
|
||||||
|
|
||||||
def pack_ext_type(self, typecode, data):
|
def pack_ext_type(self, typecode, data):
|
||||||
|
self._check_exports()
|
||||||
|
if len(data) > ITEM_LIMIT:
|
||||||
|
raise ValueError("ext data too large")
|
||||||
msgpack_pack_ext(&self.pk, typecode, len(data))
|
msgpack_pack_ext(&self.pk, typecode, len(data))
|
||||||
msgpack_pack_raw_body(&self.pk, data, len(data))
|
msgpack_pack_raw_body(&self.pk, data, len(data))
|
||||||
|
|
||||||
def pack_array_header(self, long long size):
|
def pack_array_header(self, long long size):
|
||||||
|
self._check_exports()
|
||||||
if size > ITEM_LIMIT:
|
if size > ITEM_LIMIT:
|
||||||
raise ValueError
|
raise ValueError("array too large")
|
||||||
msgpack_pack_array(&self.pk, size)
|
msgpack_pack_array(&self.pk, size)
|
||||||
if self.autoreset:
|
if self.autoreset:
|
||||||
buf = PyBytes_FromStringAndSize(self.pk.buf, self.pk.length)
|
buf = PyBytes_FromStringAndSize(self.pk.buf, self.pk.length)
|
||||||
|
@ -290,8 +302,9 @@ cdef class Packer:
|
||||||
return buf
|
return buf
|
||||||
|
|
||||||
def pack_map_header(self, long long size):
|
def pack_map_header(self, long long size):
|
||||||
|
self._check_exports()
|
||||||
if size > ITEM_LIMIT:
|
if size > ITEM_LIMIT:
|
||||||
raise ValueError
|
raise ValueError("map too learge")
|
||||||
msgpack_pack_map(&self.pk, size)
|
msgpack_pack_map(&self.pk, size)
|
||||||
if self.autoreset:
|
if self.autoreset:
|
||||||
buf = PyBytes_FromStringAndSize(self.pk.buf, self.pk.length)
|
buf = PyBytes_FromStringAndSize(self.pk.buf, self.pk.length)
|
||||||
|
@ -305,7 +318,11 @@ cdef class Packer:
|
||||||
*pairs* should be a sequence of pairs.
|
*pairs* should be a sequence of pairs.
|
||||||
(`len(pairs)` and `for k, v in pairs:` should be supported.)
|
(`len(pairs)` and `for k, v in pairs:` should be supported.)
|
||||||
"""
|
"""
|
||||||
msgpack_pack_map(&self.pk, len(pairs))
|
self._check_exports()
|
||||||
|
size = len(pairs)
|
||||||
|
if size > ITEM_LIMIT:
|
||||||
|
raise ValueError("map too large")
|
||||||
|
msgpack_pack_map(&self.pk, size)
|
||||||
for k, v in pairs:
|
for k, v in pairs:
|
||||||
self._pack(k)
|
self._pack(k)
|
||||||
self._pack(v)
|
self._pack(v)
|
||||||
|
@ -319,6 +336,7 @@ cdef class Packer:
|
||||||
|
|
||||||
This method is useful only when autoreset=False.
|
This method is useful only when autoreset=False.
|
||||||
"""
|
"""
|
||||||
|
self._check_exports()
|
||||||
self.pk.length = 0
|
self.pk.length = 0
|
||||||
|
|
||||||
def bytes(self):
|
def bytes(self):
|
||||||
|
@ -326,11 +344,15 @@ cdef class Packer:
|
||||||
return PyBytes_FromStringAndSize(self.pk.buf, self.pk.length)
|
return PyBytes_FromStringAndSize(self.pk.buf, self.pk.length)
|
||||||
|
|
||||||
def getbuffer(self):
|
def getbuffer(self):
|
||||||
"""Return view of internal buffer."""
|
"""Return memoryview of internal buffer.
|
||||||
|
|
||||||
|
Note: Packer now supports buffer protocol. You can use memoryview(packer).
|
||||||
|
"""
|
||||||
return memoryview(self)
|
return memoryview(self)
|
||||||
|
|
||||||
def __getbuffer__(self, Py_buffer *buffer, int flags):
|
def __getbuffer__(self, Py_buffer *buffer, int flags):
|
||||||
PyBuffer_FillInfo(buffer, self, self.pk.buf, self.pk.length, 1, flags)
|
PyBuffer_FillInfo(buffer, self, self.pk.buf, self.pk.length, 1, flags)
|
||||||
|
self.exports += 1
|
||||||
|
|
||||||
def __releasebuffer__(self, Py_buffer *buffer):
|
def __releasebuffer__(self, Py_buffer *buffer):
|
||||||
pass
|
self.exports -= 1
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#!/usr/bin/env python
|
from pytest import raises
|
||||||
|
|
||||||
from msgpack import packb, unpackb
|
from msgpack import packb, unpackb, Packer
|
||||||
|
|
||||||
|
|
||||||
def test_unpack_buffer():
|
def test_unpack_buffer():
|
||||||
|
@ -27,3 +27,23 @@ def test_unpack_memoryview():
|
||||||
assert [b"foo", b"bar"] == obj
|
assert [b"foo", b"bar"] == obj
|
||||||
expected_type = bytes
|
expected_type = bytes
|
||||||
assert all(type(s) == expected_type for s in obj)
|
assert all(type(s) == expected_type for s in obj)
|
||||||
|
|
||||||
|
|
||||||
|
def test_packer_getbuffer():
|
||||||
|
packer = Packer(autoreset=False)
|
||||||
|
packer.pack_array_header(2)
|
||||||
|
packer.pack(42)
|
||||||
|
packer.pack("hello")
|
||||||
|
buffer = packer.getbuffer()
|
||||||
|
assert isinstance(buffer, memoryview)
|
||||||
|
assert bytes(buffer) == b"\x92*\xa5hello"
|
||||||
|
|
||||||
|
if Packer.__module__ == "msgpack._cmsgpack": # only for Cython
|
||||||
|
# cython Packer supports buffer protocol directly
|
||||||
|
assert bytes(packer) == b"\x92*\xa5hello"
|
||||||
|
|
||||||
|
with raises(BufferError):
|
||||||
|
packer.pack(42)
|
||||||
|
buffer.release()
|
||||||
|
packer.pack(42)
|
||||||
|
assert bytes(packer) == b"\x92*\xa5hello*"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue