mirror of
https://github.com/msgpack/msgpack-python.git
synced 2025-10-25 14:44:10 +00:00
Add Packer.buffer() (#320)
This commit is contained in:
parent
a8b3e97fe5
commit
9e210bfc1a
8 changed files with 107 additions and 20 deletions
|
|
@ -18,6 +18,8 @@ If you need to handle large data, you need to specify limits manually.
|
||||||
Other changes
|
Other changes
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
|
Add ``Unpacker.getbuffer()`` method.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
0.5.6
|
0.5.6
|
||||||
|
|
|
||||||
|
|
@ -153,7 +153,7 @@ doctest:
|
||||||
"results in $(BUILDDIR)/doctest/output.txt."
|
"results in $(BUILDDIR)/doctest/output.txt."
|
||||||
|
|
||||||
serve: html
|
serve: html
|
||||||
cd _build/html && python3 -m http.server
|
python3 -m http.server -d _build/html
|
||||||
|
|
||||||
zip: html
|
zip: html
|
||||||
cd _build/html && zip -r ../../../msgpack-doc.zip .
|
cd _build/html && zip -r ../../../msgpack-doc.zip .
|
||||||
|
|
|
||||||
32
docs/advanced.rst
Normal file
32
docs/advanced.rst
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
Advanced usage
|
||||||
|
===============
|
||||||
|
|
||||||
|
Packer
|
||||||
|
------
|
||||||
|
|
||||||
|
autoreset
|
||||||
|
~~~~~~~~~
|
||||||
|
|
||||||
|
When you used ``autoreset=False`` option of :class:`~msgpack.Packer`,
|
||||||
|
``pack()`` method doesn't return packed ``bytes``.
|
||||||
|
|
||||||
|
You can use :meth:`~msgpack.Packer.bytes` or :meth:`~msgpack.Packer.getbuffer` to
|
||||||
|
get packed data.
|
||||||
|
|
||||||
|
``bytes()`` returns ``bytes`` object. ``getbuffer()`` returns some bytes-like
|
||||||
|
object. It's concrete type is implement detail and it will be changed in future
|
||||||
|
versions.
|
||||||
|
|
||||||
|
You can reduce temporary bytes object by using ``Unpacker.getbuffer()``.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
packer = Packer(use_bin_type=True, autoreset=False)
|
||||||
|
|
||||||
|
packer.pack([1, 2])
|
||||||
|
packer.pack([3, 4])
|
||||||
|
|
||||||
|
with open('data.bin', 'wb') as f:
|
||||||
|
f.write(packer.getbuffer())
|
||||||
|
|
||||||
|
packer.reset() # reset internal buffer
|
||||||
|
|
@ -8,3 +8,4 @@ language data exchange.
|
||||||
:maxdepth: 1
|
:maxdepth: 1
|
||||||
|
|
||||||
api
|
api
|
||||||
|
advanced
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,9 @@ cdef extern from "pack.h":
|
||||||
int msgpack_pack_ext(msgpack_packer* pk, char typecode, size_t l)
|
int msgpack_pack_ext(msgpack_packer* pk, char typecode, size_t l)
|
||||||
int msgpack_pack_unicode(msgpack_packer* pk, object o, long long limit)
|
int msgpack_pack_unicode(msgpack_packer* pk, object o, long long limit)
|
||||||
|
|
||||||
|
cdef extern from "buff_converter.h":
|
||||||
|
object buff_to_buff(char *, Py_ssize_t)
|
||||||
|
|
||||||
cdef int DEFAULT_RECURSE_LIMIT=511
|
cdef int DEFAULT_RECURSE_LIMIT=511
|
||||||
cdef long long ITEM_LIMIT = (2**32)-1
|
cdef long long ITEM_LIMIT = (2**32)-1
|
||||||
|
|
||||||
|
|
@ -349,9 +352,16 @@ cdef class Packer(object):
|
||||||
return buf
|
return buf
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
"""Clear internal buffer."""
|
"""Reset internal buffer.
|
||||||
|
|
||||||
|
This method is usaful only when autoreset=False.
|
||||||
|
"""
|
||||||
self.pk.length = 0
|
self.pk.length = 0
|
||||||
|
|
||||||
def bytes(self):
|
def bytes(self):
|
||||||
"""Return buffer content."""
|
"""Return internal buffer contents as bytes object"""
|
||||||
return PyBytes_FromStringAndSize(self.pk.buf, self.pk.length)
|
return PyBytes_FromStringAndSize(self.pk.buf, self.pk.length)
|
||||||
|
|
||||||
|
def getbuffer(self):
|
||||||
|
"""Return view of internal buffer."""
|
||||||
|
return buff_to_buff(self.pk.buf, self.pk.length)
|
||||||
|
|
|
||||||
28
msgpack/buff_converter.h
Normal file
28
msgpack/buff_converter.h
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
#include "Python.h"
|
||||||
|
|
||||||
|
/* cython does not support this preprocessor check => write it in raw C */
|
||||||
|
#if PY_MAJOR_VERSION == 2
|
||||||
|
static PyObject *
|
||||||
|
buff_to_buff(char *buff, Py_ssize_t size)
|
||||||
|
{
|
||||||
|
return PyBuffer_FromMemory(buff, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif (PY_MAJOR_VERSION == 3) && (PY_MINOR_VERSION >= 3)
|
||||||
|
static PyObject *
|
||||||
|
buff_to_buff(char *buff, Py_ssize_t size)
|
||||||
|
{
|
||||||
|
return PyMemoryView_FromMemory(buff, size, PyBUF_READ);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static PyObject *
|
||||||
|
buff_to_buff(char *buff, Py_ssize_t size)
|
||||||
|
{
|
||||||
|
Py_buffer pybuf;
|
||||||
|
if (PyBuffer_FillInfo(&pybuf, NULL, buff, size, 1, PyBUF_FULL_RO) == -1) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PyMemoryView_FromBuffer(&pybuf);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -860,42 +860,34 @@ class Packer(object):
|
||||||
except:
|
except:
|
||||||
self._buffer = StringIO() # force reset
|
self._buffer = StringIO() # force reset
|
||||||
raise
|
raise
|
||||||
ret = self._buffer.getvalue()
|
|
||||||
if self._autoreset:
|
if self._autoreset:
|
||||||
|
ret = self._buffer.getvalue()
|
||||||
self._buffer = StringIO()
|
self._buffer = StringIO()
|
||||||
elif USING_STRINGBUILDER:
|
|
||||||
self._buffer = StringIO(ret)
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def pack_map_pairs(self, pairs):
|
def pack_map_pairs(self, pairs):
|
||||||
self._pack_map_pairs(len(pairs), pairs)
|
self._pack_map_pairs(len(pairs), pairs)
|
||||||
ret = self._buffer.getvalue()
|
|
||||||
if self._autoreset:
|
if self._autoreset:
|
||||||
|
ret = self._buffer.getvalue()
|
||||||
self._buffer = StringIO()
|
self._buffer = StringIO()
|
||||||
elif USING_STRINGBUILDER:
|
|
||||||
self._buffer = StringIO(ret)
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def pack_array_header(self, n):
|
def pack_array_header(self, n):
|
||||||
if n >= 2**32:
|
if n >= 2**32:
|
||||||
raise PackValueError
|
raise PackValueError
|
||||||
self._pack_array_header(n)
|
self._pack_array_header(n)
|
||||||
ret = self._buffer.getvalue()
|
|
||||||
if self._autoreset:
|
if self._autoreset:
|
||||||
|
ret = self._buffer.getvalue()
|
||||||
self._buffer = StringIO()
|
self._buffer = StringIO()
|
||||||
elif USING_STRINGBUILDER:
|
|
||||||
self._buffer = StringIO(ret)
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def pack_map_header(self, n):
|
def pack_map_header(self, n):
|
||||||
if n >= 2**32:
|
if n >= 2**32:
|
||||||
raise PackValueError
|
raise PackValueError
|
||||||
self._pack_map_header(n)
|
self._pack_map_header(n)
|
||||||
ret = self._buffer.getvalue()
|
|
||||||
if self._autoreset:
|
if self._autoreset:
|
||||||
|
ret = self._buffer.getvalue()
|
||||||
self._buffer = StringIO()
|
self._buffer = StringIO()
|
||||||
elif USING_STRINGBUILDER:
|
|
||||||
self._buffer = StringIO(ret)
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def pack_ext_type(self, typecode, data):
|
def pack_ext_type(self, typecode, data):
|
||||||
|
|
@ -976,7 +968,19 @@ class Packer(object):
|
||||||
raise PackValueError('Bin is too large')
|
raise PackValueError('Bin is too large')
|
||||||
|
|
||||||
def bytes(self):
|
def bytes(self):
|
||||||
|
"""Return internal buffer contents as bytes object"""
|
||||||
return self._buffer.getvalue()
|
return self._buffer.getvalue()
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
|
"""Reset internal buffer.
|
||||||
|
|
||||||
|
This method is usaful only when autoreset=False.
|
||||||
|
"""
|
||||||
self._buffer = StringIO()
|
self._buffer = StringIO()
|
||||||
|
|
||||||
|
def getbuffer(self):
|
||||||
|
"""Return view of internal buffer."""
|
||||||
|
if USING_STRINGBUILDER or not PY3:
|
||||||
|
return memoryview(self.bytes())
|
||||||
|
else:
|
||||||
|
return self._buffer.getbuffer()
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ from __future__ import absolute_import, division, print_function, unicode_litera
|
||||||
import struct
|
import struct
|
||||||
from pytest import raises, xfail
|
from pytest import raises, xfail
|
||||||
|
|
||||||
from msgpack import packb, unpackb, Unpacker, Packer
|
from msgpack import packb, unpackb, Unpacker, Packer, pack
|
||||||
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
@ -148,3 +148,13 @@ def test_pairlist():
|
||||||
packed = packer.pack_map_pairs(pairlist)
|
packed = packer.pack_map_pairs(pairlist)
|
||||||
unpacked = unpackb(packed, object_pairs_hook=list)
|
unpacked = unpackb(packed, object_pairs_hook=list)
|
||||||
assert pairlist == unpacked
|
assert pairlist == unpacked
|
||||||
|
|
||||||
|
def test_get_buffer():
|
||||||
|
packer = Packer(autoreset=0, use_bin_type=True)
|
||||||
|
packer.pack([1, 2])
|
||||||
|
strm = BytesIO()
|
||||||
|
strm.write(packer.getbuffer())
|
||||||
|
written = strm.getvalue()
|
||||||
|
|
||||||
|
expected = packb([1, 2], use_bin_type=True)
|
||||||
|
assert written == expected
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue