Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
PYTHON_SOURCES = msgpack test setup.py

.PHONY: all
all: cython
python setup.py build_ext -i -f

.PHONY: black
black:
black -S msgpack/ test/ setup.py
black $(PYTHON_SOURCES)

.PHONY: pyupgrade
pyupgrade:
@find $(PYTHON_SOURCES) -name '*.py' -type f -exec pyupgrade --py37-plus '{}' \;

.PHONY: cython
cython:
Expand Down
1 change: 0 additions & 1 deletion msgpack/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# coding: utf-8
from .exceptions import *
from .ext import ExtType, Timestamp

Expand Down
21 changes: 6 additions & 15 deletions msgpack/ext.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# coding: utf-8
from collections import namedtuple
import datetime
import sys
Expand All @@ -15,10 +14,10 @@ def __new__(cls, code, data):
raise TypeError("data must be bytes")
if not 0 <= code <= 127:
raise ValueError("code must be 0~127")
return super(ExtType, cls).__new__(cls, code, data)
return super().__new__(cls, code, data)


class Timestamp(object):
class Timestamp:
"""Timestamp represents the Timestamp extension type in msgpack.

When built with Cython, msgpack uses C methods to pack and unpack `Timestamp`. When using pure-Python
Expand Down Expand Up @@ -47,24 +46,18 @@ def __init__(self, seconds, nanoseconds=0):
if not isinstance(nanoseconds, int):
raise TypeError("nanoseconds must be an integer")
if not (0 <= nanoseconds < 10**9):
raise ValueError(
"nanoseconds must be a non-negative integer less than 999999999."
)
raise ValueError("nanoseconds must be a non-negative integer less than 999999999.")
self.seconds = seconds
self.nanoseconds = nanoseconds

def __repr__(self):
"""String representation of Timestamp."""
return "Timestamp(seconds={0}, nanoseconds={1})".format(
self.seconds, self.nanoseconds
)
return f"Timestamp(seconds={self.seconds}, nanoseconds={self.nanoseconds})"

def __eq__(self, other):
"""Check for equality with another Timestamp object"""
if type(other) is self.__class__:
return (
self.seconds == other.seconds and self.nanoseconds == other.nanoseconds
)
return self.seconds == other.seconds and self.nanoseconds == other.nanoseconds
return False

def __ne__(self, other):
Expand Down Expand Up @@ -164,9 +157,7 @@ def to_datetime(self):
:rtype: datetime.
"""
utc = datetime.timezone.utc
return datetime.datetime.fromtimestamp(0, utc) + datetime.timedelta(
seconds=self.to_unix()
)
return datetime.datetime.fromtimestamp(0, utc) + datetime.timedelta(seconds=self.to_unix())

@staticmethod
def from_datetime(dt):
Expand Down
70 changes: 20 additions & 50 deletions msgpack/fallback.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,6 @@
import struct


if sys.version_info < (3, 5):
# Ugly hack...
RecursionError = RuntimeError

def _is_recursionerror(e):
return (
len(e.args) == 1
and isinstance(e.args[0], str)
and e.args[0].startswith("maximum recursion depth exceeded")
)

else:

def _is_recursionerror(e):
return True


if hasattr(sys, "pypy_version_info"):
# StringIO is slow on PyPy, StringIO is faster. However: PyPy's own
# StringBuilder is fastest.
Expand All @@ -32,7 +15,7 @@ def _is_recursionerror(e):
from __pypy__.builders import StringBuilder
USING_STRINGBUILDER = True

class StringIO(object):
class StringIO:
def __init__(self, s=b""):
if s:
self.builder = StringBuilder(len(s))
Expand Down Expand Up @@ -109,10 +92,8 @@ def unpackb(packed, **kwargs):
ret = unpacker._unpack()
except OutOfData:
raise ValueError("Unpack failed: incomplete input")
except RecursionError as e:
if _is_recursionerror(e):
raise StackError
raise
except RecursionError:
raise StackError
if unpacker._got_extradata():
raise ExtraData(ret, unpacker._get_extradata())
return ret
Expand Down Expand Up @@ -151,7 +132,7 @@ def unpackb(packed, **kwargs):
}


class Unpacker(object):
class Unpacker:
"""Streaming unpacker.

Arguments:
Expand Down Expand Up @@ -334,9 +315,7 @@ def __init__(
if object_pairs_hook is not None and not callable(object_pairs_hook):
raise TypeError("`object_pairs_hook` is not callable")
if object_hook is not None and object_pairs_hook is not None:
raise TypeError(
"object_pairs_hook and object_hook are mutually " "exclusive"
)
raise TypeError("object_pairs_hook and object_hook are mutually " "exclusive")
if not callable(ext_hook):
raise TypeError("`ext_hook` is not callable")

Expand Down Expand Up @@ -428,20 +407,18 @@ def _read_header(self):
n = b & 0b00011111
typ = TYPE_RAW
if n > self._max_str_len:
raise ValueError("%s exceeds max_str_len(%s)" % (n, self._max_str_len))
raise ValueError(f"{n} exceeds max_str_len({self._max_str_len})")
obj = self._read(n)
elif b & 0b11110000 == 0b10010000:
n = b & 0b00001111
typ = TYPE_ARRAY
if n > self._max_array_len:
raise ValueError(
"%s exceeds max_array_len(%s)" % (n, self._max_array_len)
)
raise ValueError(f"{n} exceeds max_array_len({self._max_array_len})")
elif b & 0b11110000 == 0b10000000:
n = b & 0b00001111
typ = TYPE_MAP
if n > self._max_map_len:
raise ValueError("%s exceeds max_map_len(%s)" % (n, self._max_map_len))
raise ValueError(f"{n} exceeds max_map_len({self._max_map_len})")
elif b == 0xC0:
obj = None
elif b == 0xC2:
Expand All @@ -457,15 +434,15 @@ def _read_header(self):
n = self._buffer[self._buff_i]
self._buff_i += size
if n > self._max_bin_len:
raise ValueError("%s exceeds max_bin_len(%s)" % (n, self._max_bin_len))
raise ValueError(f"{n} exceeds max_bin_len({self._max_bin_len})")
obj = self._read(n)
elif 0xC7 <= b <= 0xC9:
size, fmt, typ = _MSGPACK_HEADERS[b]
self._reserve(size)
L, n = struct.unpack_from(fmt, self._buffer, self._buff_i)
self._buff_i += size
if L > self._max_ext_len:
raise ValueError("%s exceeds max_ext_len(%s)" % (L, self._max_ext_len))
raise ValueError(f"{L} exceeds max_ext_len({self._max_ext_len})")
obj = self._read(L)
elif 0xCA <= b <= 0xD3:
size, fmt = _MSGPACK_HEADERS[b]
Expand All @@ -478,9 +455,7 @@ def _read_header(self):
elif 0xD4 <= b <= 0xD8:
size, fmt, typ = _MSGPACK_HEADERS[b]
if self._max_ext_len < size:
raise ValueError(
"%s exceeds max_ext_len(%s)" % (size, self._max_ext_len)
)
raise ValueError(f"{size} exceeds max_ext_len({self._max_ext_len})")
self._reserve(size + 1)
n, obj = struct.unpack_from(fmt, self._buffer, self._buff_i)
self._buff_i += size + 1
Expand All @@ -493,24 +468,22 @@ def _read_header(self):
n = self._buffer[self._buff_i]
self._buff_i += size
if n > self._max_str_len:
raise ValueError("%s exceeds max_str_len(%s)" % (n, self._max_str_len))
raise ValueError(f"{n} exceeds max_str_len({self._max_str_len})")
obj = self._read(n)
elif 0xDC <= b <= 0xDD:
size, fmt, typ = _MSGPACK_HEADERS[b]
self._reserve(size)
(n,) = struct.unpack_from(fmt, self._buffer, self._buff_i)
self._buff_i += size
if n > self._max_array_len:
raise ValueError(
"%s exceeds max_array_len(%s)" % (n, self._max_array_len)
)
raise ValueError(f"{n} exceeds max_array_len({self._max_array_len})")
elif 0xDE <= b <= 0xDF:
size, fmt, typ = _MSGPACK_HEADERS[b]
self._reserve(size)
(n,) = struct.unpack_from(fmt, self._buffer, self._buff_i)
self._buff_i += size
if n > self._max_map_len:
raise ValueError("%s exceeds max_map_len(%s)" % (n, self._max_map_len))
raise ValueError(f"{n} exceeds max_map_len({self._max_map_len})")
else:
raise FormatError("Unknown header: 0x%x" % b)
return typ, n, obj
Expand Down Expand Up @@ -549,17 +522,14 @@ def _unpack(self, execute=EX_CONSTRUCT):
return
if self._object_pairs_hook is not None:
ret = self._object_pairs_hook(
(self._unpack(EX_CONSTRUCT), self._unpack(EX_CONSTRUCT))
for _ in range(n)
(self._unpack(EX_CONSTRUCT), self._unpack(EX_CONSTRUCT)) for _ in range(n)
)
else:
ret = {}
for _ in range(n):
key = self._unpack(EX_CONSTRUCT)
if self._strict_map_key and type(key) not in (str, bytes):
raise ValueError(
"%s is not allowed for map key" % str(type(key))
)
raise ValueError("%s is not allowed for map key" % str(type(key)))
if type(key) is str:
key = sys.intern(key)
ret[key] = self._unpack(EX_CONSTRUCT)
Expand Down Expand Up @@ -634,7 +604,7 @@ def tell(self):
return self._stream_offset


class Packer(object):
class Packer:
"""
MessagePack Packer

Expand Down Expand Up @@ -844,9 +814,9 @@ def _pack(
continue

if self._datetime and check(obj, _DateTime):
raise ValueError("Cannot serialize %r where tzinfo=None" % (obj,))
raise ValueError(f"Cannot serialize {obj!r} where tzinfo=None")

raise TypeError("Cannot serialize %r" % (obj,))
raise TypeError(f"Cannot serialize {obj!r}")

def pack(self, obj):
try:
Expand Down Expand Up @@ -933,7 +903,7 @@ def _pack_map_header(self, n):

def _pack_map_pairs(self, n, pairs, nest_limit=DEFAULT_RECURSE_LIMIT):
self._pack_map_header(n)
for (k, v) in pairs:
for k, v in pairs:
self._pack(k, nest_limit - 1)
self._pack(v, nest_limit - 1)

Expand Down
5 changes: 5 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,8 @@ requires = [
"setuptools >= 35.0.2",
]
build-backend = "setuptools.build_meta"

[tool.black]
line-length = 100
target-version = ["py37"]
skip_string_normalization = true
8 changes: 5 additions & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Also declared in pyproject.toml, if updating here please also update there
# Also declared in pyproject.toml, if updating here please also update there.
Cython~=0.29.30

# dev only tools. no need to add pyproject
black==22.3.0
# Tools required only for development. No need to add it to pyproject.toml file.
black==23.3.0
pytest==7.3.1
pyupgrade==3.3.2
1 change: 0 additions & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ project_urls =

classifiers =
Programming Language :: Python :: 3
Programming Language :: Python :: 3.6
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Expand Down
9 changes: 2 additions & 7 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#!/usr/bin/env python
# coding: utf-8
import io
import os
import sys
Expand All @@ -25,7 +24,7 @@ class NoCython(Exception):


def cythonize(src):
sys.stderr.write("cythonize: %r\n" % (src,))
sys.stderr.write(f"cythonize: {src!r}\n")
cython_compiler.compile([src], cplus=True)


Expand All @@ -36,11 +35,7 @@ def ensure_source(src):
if not have_cython:
raise NoCython
cythonize(pyx)
elif (
os.path.exists(pyx)
and os.stat(src).st_mtime < os.stat(pyx).st_mtime
and have_cython
):
elif os.path.exists(pyx) and os.stat(src).st_mtime < os.stat(pyx).st_mtime and have_cython:
cythonize(pyx)
return src

Expand Down
1 change: 0 additions & 1 deletion test/test_buffer.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#!/usr/bin/env python
# coding: utf-8

import sys
import pytest
Expand Down
7 changes: 3 additions & 4 deletions test/test_case.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
#!/usr/bin/env python
# coding: utf-8
from msgpack import packb, unpackb


def check(length, obj, use_bin_type=True):
v = packb(obj, use_bin_type=use_bin_type)
assert len(v) == length, "%r length should be %r but get %r" % (obj, length, len(v))
assert len(v) == length, f"{obj!r} length should be {length!r} but get {len(v)!r}"
assert unpackb(v, use_list=0, raw=not use_bin_type) == obj


Expand Down Expand Up @@ -120,11 +119,11 @@ def test_match():
),
({}, b"\x80"),
(
dict([(x, x) for x in range(15)]),
{x: x for x in range(15)},
b"\x8f\x00\x00\x01\x01\x02\x02\x03\x03\x04\x04\x05\x05\x06\x06\x07\x07\x08\x08\t\t\n\n\x0b\x0b\x0c\x0c\r\r\x0e\x0e",
),
(
dict([(x, x) for x in range(16)]),
{x: x for x in range(16)},
b"\xde\x00\x10\x00\x00\x01\x01\x02\x02\x03\x03\x04\x04\x05\x05\x06\x06\x07\x07\x08\x08\t\t\n\n\x0b\x0b\x0c\x0c\r\r\x0e\x0e\x0f\x0f",
),
]
Expand Down
1 change: 0 additions & 1 deletion test/test_except.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#!/usr/bin/env python
# coding: utf-8

from pytest import raises
from msgpack import packb, unpackb, Unpacker, FormatError, StackError, OutOfData
Expand Down
7 changes: 2 additions & 5 deletions test/test_extension.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from __future__ import print_function
import array
import msgpack
from msgpack import ExtType
Expand All @@ -17,9 +16,7 @@ def p(s):
assert p(b"A" * 16) == b"\xd8\x42" + b"A" * 16 # fixext 16
assert p(b"ABC") == b"\xc7\x03\x42ABC" # ext 8
assert p(b"A" * 0x0123) == b"\xc8\x01\x23\x42" + b"A" * 0x0123 # ext 16
assert (
p(b"A" * 0x00012345) == b"\xc9\x00\x01\x23\x45\x42" + b"A" * 0x00012345
) # ext 32
assert p(b"A" * 0x00012345) == b"\xc9\x00\x01\x23\x45\x42" + b"A" * 0x00012345 # ext 32


def test_unpack_ext_type():
Expand Down Expand Up @@ -49,7 +46,7 @@ def default(obj):
except AttributeError:
data = obj.tostring()
return ExtType(typecode, data)
raise TypeError("Unknown type object %r" % (obj,))
raise TypeError(f"Unknown type object {obj!r}")

def ext_hook(code, data):
print("ext_hook called", code, data)
Expand Down
Loading