diff --git a/docs/api.rst b/docs/api.rst index d78d06b..3374348 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -33,6 +33,3 @@ Bundled Transcoders .. autoclass:: MsgPackTranscoder :members: - -.. autoclass:: BinaryWrapper - :members: diff --git a/setup.py b/setup.py index f132b85..a1e115e 100755 --- a/setup.py +++ b/setup.py @@ -51,7 +51,11 @@ setuptools.setup( 'Topic :: Software Development :: Libraries', 'Topic :: Software Development :: Libraries :: Python Modules' ], - packages=setuptools.find_packages(), + packages=[ + 'sprockets', + 'sprockets.mixins', + 'sprockets.mixins.mediatype' + ], install_requires=install_requires, tests_require=tests_require, extras_require={ diff --git a/sprockets/__init__.py b/sprockets/__init__.py deleted file mode 100644 index de40ea7..0000000 --- a/sprockets/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__import__('pkg_resources').declare_namespace(__name__) diff --git a/sprockets/mixins/__init__.py b/sprockets/mixins/__init__.py deleted file mode 100644 index de40ea7..0000000 --- a/sprockets/mixins/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__import__('pkg_resources').declare_namespace(__name__) diff --git a/sprockets/mixins/mediatype/__init__.py b/sprockets/mixins/mediatype/__init__.py index 2acc914..d5d6913 100644 --- a/sprockets/mixins/mediatype/__init__.py +++ b/sprockets/mixins/mediatype/__init__.py @@ -12,7 +12,7 @@ except ImportError as error: # pragma no cover def _error_closure(*args, **kwargs): raise error - class ErrorClosureClass(object): + class ErrorClosureClass: def __init__(self, *args, **kwargs): raise error diff --git a/sprockets/mixins/mediatype/content.py b/sprockets/mixins/mediatype/content.py index d836132..e3d636c 100644 --- a/sprockets/mixins/mediatype/content.py +++ b/sprockets/mixins/mediatype/content.py @@ -43,7 +43,7 @@ SETTINGS_KEY = 'sprockets.mixins.mediatype.ContentSettings' _warning_issued = False -class ContentSettings(object): +class ContentSettings: """ Content selection settings. @@ -276,7 +276,7 @@ def set_default_content_type(application, content_type, encoding=None): settings.default_encoding = encoding -class ContentMixin(object): +class ContentMixin: """ Mix this in to add some content handling methods. @@ -298,7 +298,7 @@ class ContentMixin(object): """ def initialize(self): - super(ContentMixin, self).initialize() + super().initialize() self._request_body = None self._best_response_match = None self._logger = getattr(self, 'logger', logger) diff --git a/sprockets/mixins/mediatype/handlers.py b/sprockets/mixins/mediatype/handlers.py index a4708ef..ba1dee0 100644 --- a/sprockets/mixins/mediatype/handlers.py +++ b/sprockets/mixins/mediatype/handlers.py @@ -10,7 +10,7 @@ Basic content handlers. from tornado import escape -class BinaryContentHandler(object): +class BinaryContentHandler: """ Pack and unpack binary types. @@ -58,7 +58,7 @@ class BinaryContentHandler(object): return self._unpack(data_bytes) -class TextContentHandler(object): +class TextContentHandler: """ Transcodes between textual and object representations. diff --git a/sprockets/mixins/mediatype/transcoders.py b/sprockets/mixins/mediatype/transcoders.py index 98291b6..63e46e3 100644 --- a/sprockets/mixins/mediatype/transcoders.py +++ b/sprockets/mixins/mediatype/transcoders.py @@ -7,7 +7,6 @@ Bundled media type transcoders. """ import base64 import json -import sys import uuid import collections @@ -20,28 +19,6 @@ except ImportError: from sprockets.mixins.mediatype import handlers -class BinaryWrapper(bytes): - """ - Ensures that a Python 2 ``str`` is treated as binary. - - Since :class:`bytes` is a synonym for :class:`str` in Python 2, - you cannot distinguish between something that should be binary - and something that should be encoded as a string. This is a - problem in formats `such as msgpack`_ where binary data and - strings are encoded differently. The :class:`MsgPackTranscoder` - accomodates this by trying to UTF-8 encode a :class:`str` instance - and falling back to binary encoding if the transcode fails. - - You can avoid this by wrapping binary content in an instance of - this class. The transcoder will then treat it as a binary payload - instead of trying to detect whether it is a string or not. - - .. _such as msgpack: http://msgpack.org - - """ - pass - - class JSONTranscoder(handlers.TextContentHandler): """ JSON transcoder instance. @@ -73,7 +50,7 @@ class JSONTranscoder(handlers.TextContentHandler): def __init__(self, content_type='application/json', default_encoding='utf-8'): - super(JSONTranscoder, self).__init__(content_type, self.dumps, + super().__init__(content_type, self.dumps, self.loads, default_encoding) self.dump_options = { 'default': self.dump_object, @@ -128,13 +105,6 @@ class JSONTranscoder(handlers.TextContentHandler): | :class:`uuid.UUID` | Same as ``str(value)`` | +----------------------------+---------------------------------------+ - .. warning:: - - :class:`bytes` instances are treated as character strings by the - standard JSON module in Python 2.7 so the *default* object hook - is never called. In other words, :class:`bytes` values will not - be serialized as Base64 strings in Python 2.7. - """ if isinstance(obj, uuid.UUID): return str(obj) @@ -160,17 +130,14 @@ class MsgPackTranscoder(handlers.BinaryContentHandler): .. _msgpack format: http://msgpack.org/index.html """ - if sys.version_info[0] < 3: - PACKABLE_TYPES = (bool, int, float, long) - else: - PACKABLE_TYPES = (bool, int, float) + PACKABLE_TYPES = (bool, int, float) def __init__(self, content_type='application/msgpack'): if umsgpack is None: raise RuntimeError('Cannot import MsgPackTranscoder, ' 'umsgpack is not available') - super(MsgPackTranscoder, self).__init__(content_type, self.packb, + super().__init__(content_type, self.packb, self.unpackb) def packb(self, data): @@ -214,8 +181,6 @@ class MsgPackTranscoder(handlers.BinaryContentHandler): +-------------------------------+-------------------------------+ | :class:`memoryview` | `bin family`_ | +-------------------------------+-------------------------------+ - | :class:`.BinaryWrapper` | `bin family`_ | - +-------------------------------+-------------------------------+ | :class:`collections.Sequence` | `array family`_ | +-------------------------------+-------------------------------+ | :class:`collections.Set` | `array family`_ | @@ -227,17 +192,6 @@ class MsgPackTranscoder(handlers.BinaryContentHandler): .. note:: - :class:`str` and :class:`bytes` are the same before Python 3. - If you want a value to be treated as a binary value, then you - should wrap it in :class:`.BinaryWrapper` if there is any - chance of running under Python 2.7. - - The processing of :class:`str` in Python 2.x attempts to - encode the string as a UTF-8 stream. If the ``encode`` succeeds, - then the string is encoded according to the `str family`_. - If ``encode`` fails, then the string is encoded according to - the `bin family`_ . - .. _nil byte: https://github.com/msgpack/msgpack/blob/ 0b8f5ac67cdd130f4d4d4fe6afb839b989fdb86a/spec.md#formats-nil .. _true byte: https://github.com/msgpack/msgpack/blob/ @@ -277,16 +231,6 @@ class MsgPackTranscoder(handlers.BinaryContentHandler): if hasattr(datum, 'isoformat'): datum = datum.isoformat() - if sys.version_info[0] < 3 and isinstance(datum, (str, unicode)): - if isinstance(datum, str) and not isinstance(datum, BinaryWrapper): - # try to decode this into a string to make the common - # case work. If we fail, then send along the bytes. - try: - datum = datum.decode('utf-8') - except UnicodeDecodeError: - pass - return datum - if isinstance(datum, (bytes, str)): return datum diff --git a/tests.py b/tests.py index aaae490..732c013 100644 --- a/tests.py +++ b/tests.py @@ -4,7 +4,6 @@ import json import os import pickle import struct -import sys import unittest import uuid @@ -28,7 +27,7 @@ class UTC(datetime.tzinfo): return 'UTC' -class Context(object): +class Context: """Super simple class to call setattr on""" def __init__(self): self.settings = {} @@ -111,16 +110,16 @@ class GetRequestBodyTests(testing.AsyncHTTPTestCase): def test_that_request_with_unhandled_type_results_in_415(self): response = self.fetch( '/', method='POST', headers={'Content-Type': 'application/xml'}, - body=(u'value' - u'\u2731' - u'').encode('utf-8')) + body=('value' + '\u2731' + '').encode('utf-8')) self.assertEqual(response.code, 415) def test_that_msgpack_request_returns_default_type(self): body = { 'name': 'value', 'embedded': { - 'utf8': u'\u2731' + 'utf8': '\u2731' } } response = self.fetch('/', method='POST', body=umsgpack.packb(body), @@ -140,7 +139,7 @@ class GetRequestBodyTests(testing.AsyncHTTPTestCase): class JSONTranscoderTests(unittest.TestCase): def setUp(self): - super(JSONTranscoderTests, self).setUp() + super().setUp() self.transcoder = transcoders.JSONTranscoder() def test_that_uuids_are_dumped_as_strings(self): @@ -161,13 +160,6 @@ class JSONTranscoderTests(unittest.TestCase): self.assertEqual(dumped.replace(' ', ''), '{"now":"%s"}' % obj['now'].isoformat()) - @unittest.skipIf(sys.version_info[0] == 2, 'bytes unsupported on python 2') - def test_that_bytes_are_base64_encoded(self): - bin = bytes(os.urandom(127)) - dumped = self.transcoder.dumps({'bin': bin}) - self.assertEqual( - dumped, '{"bin":"%s"}' % base64.b64encode(bin).decode('ASCII')) - def test_that_bytearrays_are_base64_encoded(self): bin = bytearray(os.urandom(127)) dumped = self.transcoder.dumps({'bin': bin}) @@ -226,7 +218,7 @@ class ContentSettingsTests(unittest.TestCase): class ContentFunctionTests(unittest.TestCase): def setUp(self): - super(ContentFunctionTests, self).setUp() + super().setUp() self.context = Context() def test_that_add_binary_content_type_creates_binary_handler(self): @@ -281,11 +273,11 @@ class ContentFunctionTests(unittest.TestCase): class MsgPackTranscoderTests(unittest.TestCase): def setUp(self): - super(MsgPackTranscoderTests, self).setUp() + super().setUp() self.transcoder = transcoders.MsgPackTranscoder() def test_that_strings_are_dumped_as_strings(self): - dumped = self.transcoder.packb(u'foo') + dumped = self.transcoder.packb('foo') self.assertEqual(self.transcoder.unpackb(dumped), 'foo') self.assertEqual(dumped, pack_string('foo')) @@ -373,6 +365,6 @@ class MsgPackTranscoderTests(unittest.TestCase): def test_that_utf8_values_can_be_forced_to_bytes(self): data = b'a ascii value' - dumped = self.transcoder.packb(transcoders.BinaryWrapper(data)) + dumped = self.transcoder.packb(data) self.assertEqual(self.transcoder.unpackb(dumped), data) self.assertEqual(dumped, pack_bytes(data))