From 908f530b7b27c5ddf14a6b9ce0428238fb7c5d1c Mon Sep 17 00:00:00 2001 From: Andrew Rabert Date: Wed, 28 Nov 2018 11:00:08 -0500 Subject: [PATCH 01/16] Drop PyPy and Python < 3.5 --- .travis.yml | 8 +++----- setup.py | 8 +------- tox.ini | 2 +- 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/.travis.yml b/.travis.yml index 70da083..4a9646b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,9 @@ language: python +dist: xenial python: - - 2.7 - - 3.4 - 3.5 - 3.6 - - 3.7-dev - - pypy + - 3.7 install: - pip install codecov - pip install -r requires/installation.txt @@ -17,7 +15,7 @@ deploy: distributions: sdist bdist_wheel provider: pypi on: - python: 2.7 + python: 3.7 tags: true all_branches: true user: sprockets diff --git a/setup.py b/setup.py index 47fa17a..621216d 100755 --- a/setup.py +++ b/setup.py @@ -43,18 +43,11 @@ setuptools.setup( 'License :: OSI Approved :: BSD License', 'Natural Language :: English', 'Operating System :: OS Independent', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.6', - 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.2', - 'Programming Language :: Python :: 3.3', - 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: Implementation :: CPython', - 'Programming Language :: Python :: Implementation :: PyPy', 'Topic :: Software Development :: Libraries', 'Topic :: Software Development :: Libraries :: Python Modules' ], @@ -63,4 +56,5 @@ setuptools.setup( tests_require=tests_require, namespace_packages=['sprockets', 'sprockets.mixins'], test_suite='nose.collector', + python_requires='>=3.5', zip_safe=False) diff --git a/tox.ini b/tox.ini index a8ff895..837cf6e 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py27,py34,py35,pypy +envlist = py35,py36,py37 indexserver = default = https://pypi.python.org/simple toxworkdir = build/tox From b26998a912abcaa32a5d64ad1dfcaf70aed50234 Mon Sep 17 00:00:00 2001 From: Andrew Rabert Date: Wed, 28 Nov 2018 11:03:33 -0500 Subject: [PATCH 02/16] Add msgpack to extras_requires --- requires/development.txt | 1 + requires/testing.txt | 1 - setup.py | 3 +++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/requires/development.txt b/requires/development.txt index d49abfe..db40700 100644 --- a/requires/development.txt +++ b/requires/development.txt @@ -1,4 +1,5 @@ -r testing.txt -r installation.txt +-e .[msgpack] sphinx>=1.2,<2 sphinxcontrib-httpdomain>=1.3,<2 diff --git a/requires/testing.txt b/requires/testing.txt index 9ce02c6..397355d 100644 --- a/requires/testing.txt +++ b/requires/testing.txt @@ -1,4 +1,3 @@ coverage>=3.7,<3.99 # prevent installing 4.0b on ALL pip versions mock>=1.3,<2 -u-msgpack-python>=2,<3 nose>=1.3,<2 diff --git a/setup.py b/setup.py index 621216d..f132b85 100755 --- a/setup.py +++ b/setup.py @@ -54,6 +54,9 @@ setuptools.setup( packages=setuptools.find_packages(), install_requires=install_requires, tests_require=tests_require, + extras_require={ + 'msgpack': ['u-msgpack-python>=2.5.0,<3'] + }, namespace_packages=['sprockets', 'sprockets.mixins'], test_suite='nose.collector', python_requires='>=3.5', From b2e980d04d0ce9713925e2d0e32eb1681adea471 Mon Sep 17 00:00:00 2001 From: Andrew Rabert Date: Wed, 28 Nov 2018 11:28:18 -0500 Subject: [PATCH 03/16] Update docs - Update and isoldate doc dependencies - Simplify sphinx config - Treat warnings as errors - Remove redundant self.finish() from examples --- README.rst | 2 -- docs/conf.py | 5 ----- examples.py | 1 - requires/development.txt | 3 +-- requires/docs.txt | 2 ++ setup.cfg | 4 ++++ sprockets/mixins/mediatype/content.py | 2 -- 7 files changed, 7 insertions(+), 12 deletions(-) create mode 100644 requires/docs.txt diff --git a/README.rst b/README.rst index 4f46851..659c94e 100644 --- a/README.rst +++ b/README.rst @@ -89,13 +89,11 @@ request handlers. class SomeHandler(content.ContentMixin, web.RequestHandler): def get(self): self.send_response({'data': 'value'}) - self.finish() def post(self): body = self.get_request_body() # do whatever self.send_response({'action': 'performed'}) - self.finish() Based on the settings stored in the ``Application`` instance and the HTTP headers, the request and response data will be handled correctly or the diff --git a/docs/conf.py b/docs/conf.py index 391ad79..464519d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,4 +1,3 @@ -import alabaster from sprockets.mixins.mediatype import __version__ needs_sphinx = '1.0' @@ -6,18 +5,14 @@ extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode', 'sphinx.ext.intersphinx', 'sphinxcontrib.autohttp.tornado'] -source_suffix = '.rst' master_doc = 'index' project = 'sprockets.mixins.mediatype' copyright = '2015-2016, AWeber Communications' release = __version__ version = '.'.join(release.split('.')[0:1]) -pygments_style = 'sphinx' -html_theme = 'alabaster' html_style = 'custom.css' html_static_path = ['static'] -html_theme_path = [alabaster.get_path()] html_sidebars = { '**': ['about.html', 'navigation.html'], } diff --git a/examples.py b/examples.py index bef1f27..354b94a 100644 --- a/examples.py +++ b/examples.py @@ -11,7 +11,6 @@ class SimpleHandler(content.ContentMixin, web.RequestHandler): body = self.get_request_body() self.set_status(200) self.send_response(body) - self.finish() def make_application(**settings): diff --git a/requires/development.txt b/requires/development.txt index db40700..362fd92 100644 --- a/requires/development.txt +++ b/requires/development.txt @@ -1,5 +1,4 @@ +-r docs.txt -r testing.txt -r installation.txt -e .[msgpack] -sphinx>=1.2,<2 -sphinxcontrib-httpdomain>=1.3,<2 diff --git a/requires/docs.txt b/requires/docs.txt new file mode 100644 index 0000000..805b414 --- /dev/null +++ b/requires/docs.txt @@ -0,0 +1,2 @@ +sphinx==1.8.2 +sphinxcontrib-httpdomain==1.7.0 diff --git a/setup.cfg b/setup.cfg index 9682f99..e1b5d6f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,10 @@ [bdist_wheel] universal = 1 +[build_sphinx] +fresh-env = 1 +warning-is-error = 1 + [nosetests] cover-branches = 1 cover-erase = 1 diff --git a/sprockets/mixins/mediatype/content.py b/sprockets/mixins/mediatype/content.py index 0b5ec9d..d836132 100644 --- a/sprockets/mixins/mediatype/content.py +++ b/sprockets/mixins/mediatype/content.py @@ -75,7 +75,6 @@ class ContentSettings(object): response_body = settings['application/msgpack'].to_bytes( response_dict, encoding='utf-8') self.write(response_body) - self.finish() def make_application(): app = web.Application([web.url('/', SomeHandler)]) @@ -288,7 +287,6 @@ class ContentMixin(object): body = self.get_request_body() # do stuff --> response_dict self.send_response(response_dict) - self.finish() :meth:`get_request_body` will deserialize the request data into a dictionary based on the :http:header:`Content-Type` request From 07ed4c8dc9d187f92ee59d0634b317e3fd0f5680 Mon Sep 17 00:00:00 2001 From: Andrew Rabert Date: Wed, 28 Nov 2018 11:29:35 -0500 Subject: [PATCH 04/16] Ensure docs build successfully during CI --- .travis.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4a9646b..776ad7a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,10 +5,10 @@ python: - 3.6 - 3.7 install: - - pip install codecov - - pip install -r requires/installation.txt - - pip install -r requires/testing.txt -script: nosetests + - pip install codecov -r requires/development.txt +script: + - nosetests + - python setup.py build_sphinx after_success: - codecov deploy: From e9bbe21d3cf483a207d93deba288d76751dd7483 Mon Sep 17 00:00:00 2001 From: Andrew Rabert Date: Wed, 28 Nov 2018 11:30:49 -0500 Subject: [PATCH 05/16] Update requirements --- requires/development.txt | 3 +-- requires/testing.txt | 5 ++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/requires/development.txt b/requires/development.txt index 362fd92..7c77917 100644 --- a/requires/development.txt +++ b/requires/development.txt @@ -1,4 +1,3 @@ +-e .[msgpack] -r docs.txt -r testing.txt --r installation.txt --e .[msgpack] diff --git a/requires/testing.txt b/requires/testing.txt index 397355d..fb9480e 100644 --- a/requires/testing.txt +++ b/requires/testing.txt @@ -1,3 +1,2 @@ -coverage>=3.7,<3.99 # prevent installing 4.0b on ALL pip versions -mock>=1.3,<2 -nose>=1.3,<2 +coverage==4.5.2 +nose==1.3.7 From fd3f8b30082c5c63ebf870d4f6a043f767a9b7ca Mon Sep 17 00:00:00 2001 From: Andrew Rabert Date: Wed, 28 Nov 2018 11:32:54 -0500 Subject: [PATCH 06/16] Python 3 updates - Simplify super() - Remove object inheritance - Simplify package namespacing - Remove BinaryWrapper - Remove python 2 code paths --- docs/api.rst | 3 -- setup.py | 6 ++- sprockets/__init__.py | 1 - sprockets/mixins/__init__.py | 1 - sprockets/mixins/mediatype/__init__.py | 2 +- sprockets/mixins/mediatype/content.py | 6 +-- sprockets/mixins/mediatype/handlers.py | 4 +- sprockets/mixins/mediatype/transcoders.py | 62 ++--------------------- tests.py | 28 ++++------ 9 files changed, 24 insertions(+), 89 deletions(-) delete mode 100644 sprockets/__init__.py delete mode 100644 sprockets/mixins/__init__.py 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)) From a28633aef58a44fcc6b29ac89b219401f24817ac Mon Sep 17 00:00:00 2001 From: Andrew Rabert Date: Wed, 28 Nov 2018 11:43:53 -0500 Subject: [PATCH 07/16] Address flake8 complaints --- sprockets/mixins/mediatype/transcoders.py | 7 +++--- tests.py | 28 +++++++++++------------ 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/sprockets/mixins/mediatype/transcoders.py b/sprockets/mixins/mediatype/transcoders.py index 63e46e3..4c76053 100644 --- a/sprockets/mixins/mediatype/transcoders.py +++ b/sprockets/mixins/mediatype/transcoders.py @@ -50,8 +50,8 @@ class JSONTranscoder(handlers.TextContentHandler): def __init__(self, content_type='application/json', default_encoding='utf-8'): - super().__init__(content_type, self.dumps, - self.loads, default_encoding) + super().__init__(content_type, self.dumps, self.loads, + default_encoding) self.dump_options = { 'default': self.dump_object, 'separators': (',', ':'), @@ -137,8 +137,7 @@ class MsgPackTranscoder(handlers.BinaryContentHandler): raise RuntimeError('Cannot import MsgPackTranscoder, ' 'umsgpack is not available') - super().__init__(content_type, self.packb, - self.unpackb) + super().__init__(content_type, self.packb, self.unpackb) def packb(self, data): """Pack `data` into a :class:`bytes` instance.""" diff --git a/tests.py b/tests.py index 732c013..6f59077 100644 --- a/tests.py +++ b/tests.py @@ -36,27 +36,27 @@ class Context: def pack_string(obj): """Optimally pack a string according to msgpack format""" payload = str(obj).encode('ASCII') - l = len(payload) - if l < (2 ** 5): - prefix = struct.pack('B', 0b10100000 | l) - elif l < (2 ** 8): - prefix = struct.pack('BB', 0xD9, l) - elif l < (2 ** 16): - prefix = struct.pack('>BH', 0xDA, l) + pl = len(payload) + if pl < (2 ** 5): + prefix = struct.pack('B', 0b10100000 | pl) + elif pl < (2 ** 8): + prefix = struct.pack('BB', 0xD9, pl) + elif pl < (2 ** 16): + prefix = struct.pack('>BH', 0xDA, pl) else: - prefix = struct.pack('>BI', 0xDB, l) + prefix = struct.pack('>BI', 0xDB, pl) return prefix + payload def pack_bytes(payload): """Optimally pack a byte string according to msgpack format""" - l = len(payload) - if l < (2 ** 8): - prefix = struct.pack('BB', 0xC4, l) - elif l < (2 ** 16): - prefix = struct.pack('>BH', 0xC5, l) + pl = len(payload) + if pl < (2 ** 8): + prefix = struct.pack('BB', 0xC4, pl) + elif pl < (2 ** 16): + prefix = struct.pack('>BH', 0xC5, pl) else: - prefix = struct.pack('>BI', 0xC6, l) + prefix = struct.pack('>BI', 0xC6, pl) return prefix + payload From 00b87a43cf35a37a2651597a996320570913bec6 Mon Sep 17 00:00:00 2001 From: Andrew Rabert Date: Wed, 28 Nov 2018 11:46:08 -0500 Subject: [PATCH 08/16] Use setuptools_scm This allows us to remove the ImportError hack from __init__.py. It also simplifies how the package is versioned - deriving it solely from the repository tag. Both version_info and __version__ have been removed with this change. Given how these are a unofficial-standard at best, I've found it safer to always use pkg_resources to determine the version when I need to. --- docs/conf.py | 4 ++-- setup.py | 5 ++--- sprockets/mixins/mediatype/__init__.py | 23 +++-------------------- 3 files changed, 7 insertions(+), 25 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 464519d..3cc8ab5 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,4 +1,4 @@ -from sprockets.mixins.mediatype import __version__ +import pkg_resources needs_sphinx = '1.0' extensions = ['sphinx.ext.autodoc', @@ -8,7 +8,7 @@ extensions = ['sphinx.ext.autodoc', master_doc = 'index' project = 'sprockets.mixins.mediatype' copyright = '2015-2016, AWeber Communications' -release = __version__ +release = pkg_resources.get_distribution('sprockets.mixins.mediatype').version version = '.'.join(release.split('.')[0:1]) html_style = 'custom.css' diff --git a/setup.py b/setup.py index a1e115e..83607e6 100755 --- a/setup.py +++ b/setup.py @@ -4,8 +4,6 @@ import os import setuptools -from sprockets.mixins import mediatype - def read_requirements(file_name): requirements = [] @@ -30,7 +28,6 @@ tests_require = read_requirements('testing.txt') setuptools.setup( name='sprockets.mixins.mediatype', - version=mediatype.__version__, description='A mixin for reporting handling content-type/accept headers', long_description='\n' + open('README.rst').read(), url='https://github.com/sprockets/sprockets.mixins.media_type', @@ -61,6 +58,8 @@ setuptools.setup( extras_require={ 'msgpack': ['u-msgpack-python>=2.5.0,<3'] }, + setup_requires=['setuptools_scm'], + use_scm_version=True, namespace_packages=['sprockets', 'sprockets.mixins'], test_suite='nose.collector', python_requires='>=3.5', diff --git a/sprockets/mixins/mediatype/__init__.py b/sprockets/mixins/mediatype/__init__.py index d5d6913..7b32367 100644 --- a/sprockets/mixins/mediatype/__init__.py +++ b/sprockets/mixins/mediatype/__init__.py @@ -3,28 +3,11 @@ sprockets.mixins.media_type """ -try: - from .content import (ContentMixin, ContentSettings, - add_binary_content_type, add_text_content_type, - set_default_content_type) - -except ImportError as error: # pragma no cover - def _error_closure(*args, **kwargs): - raise error - - class ErrorClosureClass: - def __init__(self, *args, **kwargs): - raise error - - ContentMixin = ErrorClosureClass - ContentSettings = ErrorClosureClass - add_binary_content_type = _error_closure - add_text_content_type = _error_closure - set_default_content_type = _error_closure +from .content import (ContentMixin, ContentSettings, + add_binary_content_type, add_text_content_type, + set_default_content_type) -version_info = (2, 2, 2) -__version__ = '.'.join(str(v) for v in version_info) __all__ = ['ContentMixin', 'ContentSettings', 'add_binary_content_type', 'add_text_content_type', 'set_default_content_type', 'version_info', '__version__'] From 92bde69779a8aad374c37c8ca7ba209b3c5f6aaf Mon Sep 17 00:00:00 2001 From: Andrew Rabert Date: Wed, 28 Nov 2018 11:48:05 -0500 Subject: [PATCH 09/16] Require flake8 compliance in CI --- .travis.yml | 1 + requires/testing.txt | 1 + 2 files changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 776ad7a..ed7dcb1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,7 @@ install: script: - nosetests - python setup.py build_sphinx + - flake8 after_success: - codecov deploy: diff --git a/requires/testing.txt b/requires/testing.txt index fb9480e..266cc8b 100644 --- a/requires/testing.txt +++ b/requires/testing.txt @@ -1,2 +1,3 @@ coverage==4.5.2 +flake8==3.6.0 nose==1.3.7 From 0ddb30508321021375e09ff832eac2597d7caa04 Mon Sep 17 00:00:00 2001 From: Andrew Rabert Date: Wed, 28 Nov 2018 11:49:19 -0500 Subject: [PATCH 10/16] Drop support for Tornado<5 Matches sprockets.http --- requires/installation.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requires/installation.txt b/requires/installation.txt index d450f7f..6dfc681 100644 --- a/requires/installation.txt +++ b/requires/installation.txt @@ -1,2 +1,2 @@ ietfparse>=1.4,<1.5 -tornado>=3.2,<6 +tornado>=5,<6 From 38275440c701b6ff20000212830a933e02d20dd1 Mon Sep 17 00:00:00 2001 From: Andrew Rabert Date: Wed, 28 Nov 2018 11:56:31 -0500 Subject: [PATCH 11/16] Fix tox --- requires/testing.txt | 1 + tox.ini | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/requires/testing.txt b/requires/testing.txt index 266cc8b..4f73836 100644 --- a/requires/testing.txt +++ b/requires/testing.txt @@ -1,3 +1,4 @@ coverage==4.5.2 flake8==3.6.0 nose==1.3.7 +tox==3.5.3 diff --git a/tox.ini b/tox.ini index 837cf6e..884e23c 100644 --- a/tox.ini +++ b/tox.ini @@ -7,6 +7,6 @@ skip_missing_interpreters = true [testenv] deps = - -rrequires/installation.txt - -rrequires/testing.txt + -e .[msgpack] + -r requires/testing.txt commands = nosetests [] From f9098b9af9248b065b4b70ba3b6bb4a6c3c3d5dd Mon Sep 17 00:00:00 2001 From: Andrew Rabert Date: Wed, 28 Nov 2018 11:56:43 -0500 Subject: [PATCH 12/16] Update gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 643fde7..b3b30fe 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ downloads eggs fake-eggs parts +.eggs # Packages # ############ From 1727bb3655af683f0e47296fa857d4bd5037911d Mon Sep 17 00:00:00 2001 From: Andrew Rabert Date: Wed, 28 Nov 2018 13:17:32 -0500 Subject: [PATCH 13/16] Use pathlib in setup.py for relative paths --- setup.py | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/setup.py b/setup.py index 83607e6..1909304 100755 --- a/setup.py +++ b/setup.py @@ -1,35 +1,30 @@ #!/usr/bin/env python # - -import os +import pathlib import setuptools -def read_requirements(file_name): +REPO_DIR = pathlib.Path(__name__).parent + + +def read_requirements(name): requirements = [] - try: - with open(os.path.join('requires', file_name)) as req_file: - for req_line in req_file: - req_line = req_line.strip() - if '#' in req_line: - req_line = req_line[0:req_line.find('#')].strip() - if req_line.startswith('-r'): - req_line = req_line[2:].strip() - requirements.extend(read_requirements(req_line)) - else: - requirements.append(req_line) - except IOError: - pass + for req_line in REPO_DIR.joinpath(name).read_text().split('\n'): + req_line = req_line.strip() + if '#' in req_line: + req_line = req_line[0:req_line.find('#')].strip() + if req_line.startswith('-r'): + req_line = req_line[2:].strip() + requirements.extend(read_requirements(req_line)) + else: + requirements.append(req_line) return requirements -install_requires = read_requirements('installation.txt') -tests_require = read_requirements('testing.txt') - setuptools.setup( name='sprockets.mixins.mediatype', description='A mixin for reporting handling content-type/accept headers', - long_description='\n' + open('README.rst').read(), + long_description=REPO_DIR.joinpath('README.rst').read_text(), url='https://github.com/sprockets/sprockets.mixins.media_type', author='AWeber Communications', author_email='api@aweber.com', @@ -53,8 +48,8 @@ setuptools.setup( 'sprockets.mixins', 'sprockets.mixins.mediatype' ], - install_requires=install_requires, - tests_require=tests_require, + install_requires=read_requirements('requires/installation.txt'), + tests_require=read_requirements('requires/testing.txt'), extras_require={ 'msgpack': ['u-msgpack-python>=2.5.0,<3'] }, From 1a40c2cef2c59f1eca7f2e03d5f9d61c6af5c90b Mon Sep 17 00:00:00 2001 From: Andrew Rabert Date: Wed, 28 Nov 2018 13:18:19 -0500 Subject: [PATCH 14/16] Ensure package is checked during CI --- .travis.yml | 1 + setup.cfg | 3 +++ 2 files changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index ed7dcb1..f2a76aa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,7 @@ install: script: - nosetests - python setup.py build_sphinx + - python setup.py check - flake8 after_success: - codecov diff --git a/setup.cfg b/setup.cfg index e1b5d6f..308548f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -5,6 +5,9 @@ universal = 1 fresh-env = 1 warning-is-error = 1 +[check] +strict = 1 + [nosetests] cover-branches = 1 cover-erase = 1 From 3aca38d60abb6f5359011b97ac58098042ab4c5a Mon Sep 17 00:00:00 2001 From: Andrew Rabert Date: Wed, 28 Nov 2018 16:26:35 -0500 Subject: [PATCH 15/16] Update copyright --- LICENSE | 2 +- docs/conf.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/LICENSE b/LICENSE index 4a0e81a..4fa05e6 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2015-2016 AWeber Communications +Copyright (c) 2015-2018 AWeber Communications All rights reserved. Redistribution and use in source and binary forms, with or without modification, diff --git a/docs/conf.py b/docs/conf.py index 3cc8ab5..38e751e 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -7,7 +7,7 @@ extensions = ['sphinx.ext.autodoc', 'sphinxcontrib.autohttp.tornado'] master_doc = 'index' project = 'sprockets.mixins.mediatype' -copyright = '2015-2016, AWeber Communications' +copyright = '2015-2018, AWeber Communications' release = pkg_resources.get_distribution('sprockets.mixins.mediatype').version version = '.'.join(release.split('.')[0:1]) From 2fe2480dbf7ab835977afe1ad486e3f3f5709a35 Mon Sep 17 00:00:00 2001 From: Andrew Rabert Date: Wed, 28 Nov 2018 18:22:39 -0500 Subject: [PATCH 16/16] Fix docs --- sprockets/mixins/mediatype/transcoders.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sprockets/mixins/mediatype/transcoders.py b/sprockets/mixins/mediatype/transcoders.py index 4c76053..a5123f0 100644 --- a/sprockets/mixins/mediatype/transcoders.py +++ b/sprockets/mixins/mediatype/transcoders.py @@ -172,7 +172,7 @@ class MsgPackTranscoder(handlers.BinaryContentHandler): +-------------------------------+-------------------------------+ | :class:`float` | `float family`_ | +-------------------------------+-------------------------------+ - | String (see note) | `str family`_ | + | String | `str family`_ | +-------------------------------+-------------------------------+ | :class:`bytes` | `bin family`_ | +-------------------------------+-------------------------------+ @@ -189,8 +189,6 @@ class MsgPackTranscoder(handlers.BinaryContentHandler): | :class:`uuid.UUID` | Converted to String | +-------------------------------+-------------------------------+ - .. note:: - .. _nil byte: https://github.com/msgpack/msgpack/blob/ 0b8f5ac67cdd130f4d4d4fe6afb839b989fdb86a/spec.md#formats-nil .. _true byte: https://github.com/msgpack/msgpack/blob/