This commit is contained in:
Ask Solem 2013-12-16 16:53:54 +00:00
parent 48853b14bb
commit 620e2b62f5
5 changed files with 54 additions and 33 deletions

View File

@ -8,9 +8,15 @@
3.0.8
=====
:release-date: 2013-12-16 16:00 P.M UTC
:release-date: 2013-12-16 17:00 P.M UTC
:release-by: Ask Solem
- Serializer: loads and dumps now wraps exceptions raised into
:exc:`~kombu.exceptions.DecodeError` and
:exc:`kombu.exceptions.EncodeError` respectively.
Contributed by Ionel Cristian Maries
- Redis: Would attempt to read from the wrong connection if a select/epoll/kqueue
exception event happened.

View File

@ -24,13 +24,19 @@ class KombuError(Exception):
"""Common subclass for all Kombu exceptions."""
pass
class SerializationError(KombuError):
"""Failed to encode a message."""
"""Failed to serialize/deserialize content."""
class EncodeError(SerializationError):
"""Cannot encode object."""
pass
class DeserializationError(KombuError):
"""Failed to decode a message."""
pass
class DecodeError(SerializationError):
"""Cannot decode object."""
class NotBoundError(KombuError):
"""Trying to call channel dependent method on unbound entity."""

View File

@ -18,10 +18,13 @@ except ImportError: # pragma: no cover
cpickle = None # noqa
from collections import namedtuple
from contextlib import contextmanager
from .exceptions import SerializerNotInstalled, ContentDisallowed, SerializationError, DeserializationError
from .five import BytesIO, text_t
from .utils import entrypoints, wrap_exceptions
from .exceptions import (
ContentDisallowed, DecodeError, EncodeError, SerializerNotInstalled
)
from .five import BytesIO, reraise, text_t
from .utils import entrypoints
from .utils.encoding import str_to_bytes, bytes_t
__all__ = ['pickle', 'loads', 'dumps', 'register', 'unregister']
@ -44,6 +47,17 @@ pickle_protocol = int(os.environ.get('PICKLE_PROTOCOL', 2))
codec = namedtuple('codec', ('content_type', 'content_encoding', 'encoder'))
@contextmanager
def _reraise_errors(wrapper,
include=(Exception, ), exclude=(SerializerNotInstalled, )):
try:
yield
except exclude:
raise
except include as exc:
reraise(wrapper, wrapper(exc), sys.exc_info()[2])
def pickle_loads(s, load=pickle_load):
# used to support buffer objects
return load(BytesIO(s))
@ -116,7 +130,6 @@ class SerializerRegistry(object):
raise SerializerNotInstalled(
'No encoder installed for {0}'.format(name))
@wrap_exceptions(SerializationError)
def dumps(self, data, serializer=None):
if serializer == 'raw':
return raw_encode(data)
@ -134,6 +147,7 @@ class SerializerRegistry(object):
# For Unicode objects, force it into a string
if not serializer and isinstance(data, text_t):
with _reraise_errors(EncodeError, exclude=()):
payload = data.encode('utf-8')
return 'text/plain', 'utf-8', payload
@ -145,11 +159,11 @@ class SerializerRegistry(object):
content_type = self._default_content_type
content_encoding = self._default_content_encoding
with _reraise_errors(EncodeError):
payload = encoder(data)
return content_type, content_encoding, payload
encode = dumps # XXX compat
@wrap_exceptions(DeserializationError)
def loads(self, data, content_type, content_encoding,
accept=None, force=False):
if accept is not None:
@ -164,9 +178,11 @@ class SerializerRegistry(object):
if data:
decode = self._decoders.get(content_type)
if decode:
with _reraise_errors(DecodeError):
return decode(data)
if content_encoding not in SKIP_DECODE and \
not isinstance(data, text_t):
with _reraise_errors(DecodeError):
return _decode(data, content_encoding)
return data
decode = loads # XXX compat
@ -280,6 +296,7 @@ def raw_encode(data):
payload = data
if isinstance(payload, text_t):
content_encoding = 'utf-8'
with _reraise_errors(EncodeError, exclude=()):
payload = payload.encode(content_encoding)
else:
content_encoding = 'binary'

View File

@ -7,7 +7,7 @@ import sys
from base64 import b64decode
from kombu.exceptions import ContentDisallowed
from kombu.exceptions import ContentDisallowed, EncodeError, DecodeError
from kombu.five import text_t, bytes_t
from kombu.serialization import (
registry, register, SerializerNotInstalled,
@ -186,6 +186,15 @@ class test_Serialization(Case):
call('pickle'), call('yaml'), call('doomsday')
])
def test_reraises_EncodeError(self):
with self.assertRaises(EncodeError):
dumps([object()], serializer='json')
def test_reraises_DecodeError(self):
with self.assertRaises(DecodeError):
loads(object(), content_type='application/json',
content_encoding='utf-8')
def test_json_loads(self):
self.assertEqual(
py_data,

View File

@ -429,20 +429,3 @@ def maybe_fileno(f):
return fileno(f)
except FILENO_ERRORS:
pass
def wrap_exceptions(exception, catch=Exception):
"""
Catch the exception specified by ``catch`` and raise ``exception`` instead with
the old exception as the value.
"""
def decorator(func):
@wraps(func)
def wrap_exceptions_wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except catch as exc:
raise exception(exc)
return wrap_exceptions_wrapper
return decorator