diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index 2af85ce..4827ae9 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -23,6 +23,9 @@ jobs: - name: Flake8 run: | flake8 sprockets tests.py + - name: Formatting + run: | + yapf -pqr docs setup.py sprockets tests.py test: runs-on: ubuntu-latest diff --git a/CONTRIBUTING b/CONTRIBUTING index c937ef9..0d6e09c 100644 --- a/CONTRIBUTING +++ b/CONTRIBUTING @@ -48,6 +48,10 @@ tool chest. It provides the following commands: **flake8 sprockets tests.py** Run flake8 over the code and report style violations. +**yapf -ri sprockets tests.py** + Inline format the code. You might want to configure your editor to + do this for you every time you save. + If any of the preceding commands give you problems, then you will have to fix them **before** your pull request will be accepted. diff --git a/docs/conf.py b/docs/conf.py index f75a38b..cfd255e 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -3,11 +3,10 @@ import os import pkg_resources needs_sphinx = '4.0' -extensions = ['sphinx.ext.autodoc', - 'sphinx.ext.viewcode', - 'sphinx.ext.intersphinx', - 'sphinx.ext.extlinks', - 'sphinxcontrib.httpdomain'] +extensions = [ + 'sphinx.ext.autodoc', 'sphinx.ext.viewcode', 'sphinx.ext.intersphinx', + 'sphinx.ext.extlinks', 'sphinxcontrib.httpdomain' +] master_doc = 'index' project = 'sprockets.mixins.mediatype' copyright = '2015-2021, AWeber Communications' diff --git a/setup.cfg b/setup.cfg index 5cd258d..474237d 100644 --- a/setup.cfg +++ b/setup.cfg @@ -43,6 +43,7 @@ msgpack = ci = coverage==5.5 flake8==3.9.2 + yapf==0.31.0 dev = coverage==5.5 flake8==3.9.2 @@ -50,6 +51,7 @@ dev = sphinx-rtd-theme==1.0.0 sphinxcontrib-httpdomain==1.7.0 tox==3.24.3 + yapf==0.31.0 docs = sphinx==4.2.0 sphinx-rtd-theme==1.0.0 diff --git a/sprockets/mixins/mediatype/__init__.py b/sprockets/mixins/mediatype/__init__.py index 2d54e3a..45c2d4c 100644 --- a/sprockets/mixins/mediatype/__init__.py +++ b/sprockets/mixins/mediatype/__init__.py @@ -1,15 +1,14 @@ """sprockets.mixins.mediatype""" try: - from .content import (ContentMixin, ContentSettings, # noqa: F401 - add_binary_content_type, add_text_content_type, - set_default_content_type) + from .content import ( # noqa: F401 + ContentMixin, ContentSettings, add_binary_content_type, + add_text_content_type, set_default_content_type) except ImportError: # pragma: no cover import warnings warnings.warn( 'Missing runtime requirements for sprockets.mixins.mediatype', UserWarning) - version_info = (3, 0, 4) version = '.'.join(str(x) for x in version_info) __version__ = version # compatibility diff --git a/sprockets/mixins/mediatype/content.py b/sprockets/mixins/mediatype/content.py index 7552791..7b39b0d 100644 --- a/sprockets/mixins/mediatype/content.py +++ b/sprockets/mixins/mediatype/content.py @@ -34,7 +34,6 @@ from tornado import web from . import handlers - logger = logging.getLogger(__name__) SETTINGS_KEY = 'sprockets.mixins.mediatype.ContentSettings' """Key in application.settings to store the ContentSettings instance.""" @@ -87,7 +86,6 @@ class ContentSettings: instead. """ - def __init__(self): self._handlers = {} self._available_types = [] @@ -102,8 +100,8 @@ class ContentSettings: parsed = headers.parse_content_type(content_type) content_type = str(parsed) if content_type in self._handlers: - logger.warning('handler for %s already set to %r', - content_type, self._handlers[content_type]) + logger.warning('handler for %s already set to %r', content_type, + self._handlers[content_type]) return self._available_types.append(parsed) @@ -182,8 +180,8 @@ def add_binary_content_type(application, content_type, pack, unpack): handlers.BinaryContentHandler(content_type, pack, unpack)) -def add_text_content_type(application, content_type, default_encoding, - dumps, loads): +def add_text_content_type(application, content_type, default_encoding, dumps, + loads): """ Add handler for a text content type. @@ -202,9 +200,10 @@ def add_text_content_type(application, content_type, default_encoding, parsed = headers.parse_content_type(content_type) parsed.parameters.pop('charset', None) normalized = str(parsed) - add_transcoder(application, - handlers.TextContentHandler(normalized, dumps, loads, - default_encoding)) + add_transcoder( + application, + handlers.TextContentHandler(normalized, dumps, loads, + default_encoding)) def add_transcoder(application, transcoder, content_type=None): @@ -277,7 +276,6 @@ class ContentMixin: using ``self.write()``. """ - def initialize(self): super().initialize() self._request_body = None @@ -290,8 +288,7 @@ class ContentMixin: settings = get_settings(self.application, force_instance=True) acceptable = headers.parse_accept( self.request.headers.get( - 'Accept', - settings.default_content_type + 'Accept', settings.default_content_type if settings.default_content_type else '*/*')) try: selected, _ = algorithms.select_content_type( @@ -327,11 +324,13 @@ class ContentMixin: except ValueError: raise web.HTTPError(400, 'failed to parse content type %s', content_type) - content_type = '/'.join([content_type_header.content_type, - content_type_header.content_subtype]) + content_type = '/'.join([ + content_type_header.content_type, + content_type_header.content_subtype + ]) if content_type_header.content_suffix is not None: - content_type = '+'.join([content_type, - content_type_header.content_suffix]) + content_type = '+'.join( + [content_type, content_type_header.content_suffix]) try: handler = settings[content_type] except KeyError: diff --git a/sprockets/mixins/mediatype/handlers.py b/sprockets/mixins/mediatype/handlers.py index ba1dee0..dd14d86 100644 --- a/sprockets/mixins/mediatype/handlers.py +++ b/sprockets/mixins/mediatype/handlers.py @@ -24,7 +24,6 @@ class BinaryContentHandler: and unpacking functions. """ - def __init__(self, content_type, pack, unpack): self._pack = pack self._unpack = unpack @@ -77,7 +76,6 @@ class TextContentHandler: that tornado expects. """ - def __init__(self, content_type, dumps, loads, default_encoding): self._dumps = dumps self._loads = loads diff --git a/sprockets/mixins/mediatype/transcoders.py b/sprockets/mixins/mediatype/transcoders.py index bc201b9..2ee87d0 100644 --- a/sprockets/mixins/mediatype/transcoders.py +++ b/sprockets/mixins/mediatype/transcoders.py @@ -47,8 +47,8 @@ class JSONTranscoder(handlers.TextContentHandler): :meth:`.loads` is called. """ - - def __init__(self, content_type='application/json', + def __init__(self, + content_type='application/json', default_encoding='utf-8'): super().__init__(content_type, self.dumps, self.loads, default_encoding) @@ -240,5 +240,5 @@ class MsgPackTranscoder(handlers.BinaryContentHandler): out[k] = self.normalize_datum(v) return out - raise TypeError( - '{} is not msgpackable'.format(datum.__class__.__name__)) + raise TypeError('{} is not msgpackable'.format( + datum.__class__.__name__)) diff --git a/tests.py b/tests.py index 5331448..1ad15eb 100644 --- a/tests.py +++ b/tests.py @@ -37,11 +37,11 @@ def pack_string(obj): """Optimally pack a string according to msgpack format""" payload = str(obj).encode('ASCII') pl = len(payload) - if pl < (2 ** 5): + if pl < (2**5): prefix = struct.pack('B', 0b10100000 | pl) - elif pl < (2 ** 8): + elif pl < (2**8): prefix = struct.pack('BB', 0xD9, pl) - elif pl < (2 ** 16): + elif pl < (2**16): prefix = struct.pack('>BH', 0xDA, pl) else: prefix = struct.pack('>BI', 0xDB, pl) @@ -51,9 +51,9 @@ def pack_string(obj): def pack_bytes(payload): """Optimally pack a byte string according to msgpack format""" pl = len(payload) - if pl < (2 ** 8): + if pl < (2**8): prefix = struct.pack('BB', 0xC4, pl) - elif pl < (2 ** 16): + elif pl < (2**16): prefix = struct.pack('>BH', 0xC5, pl) else: prefix = struct.pack('>BI', 0xC6, pl) @@ -61,42 +61,55 @@ def pack_bytes(payload): class SendResponseTests(testing.AsyncHTTPTestCase): - def get_app(self): return examples.make_application() def test_that_content_type_default_works(self): - response = self.fetch('/', method='POST', body='{}', + response = self.fetch('/', + method='POST', + body='{}', headers={'Content-Type': 'application/json'}) self.assertEqual(response.code, 200) self.assertEqual(response.headers['Content-Type'], 'application/json; charset="utf-8"') def test_that_missing_content_type_uses_default(self): - response = self.fetch('/', method='POST', body='{}', - headers={'Accept': 'application/xml', - 'Content-Type': 'application/json'}) + response = self.fetch('/', + method='POST', + body='{}', + headers={ + 'Accept': 'application/xml', + 'Content-Type': 'application/json' + }) self.assertEqual(response.code, 200) self.assertEqual(response.headers['Content-Type'], 'application/json; charset="utf-8"') def test_that_accept_header_is_obeyed(self): - response = self.fetch('/', method='POST', body='{}', - headers={'Accept': 'application/msgpack', - 'Content-Type': 'application/json'}) + response = self.fetch('/', + method='POST', + body='{}', + headers={ + 'Accept': 'application/msgpack', + 'Content-Type': 'application/json' + }) self.assertEqual(response.code, 200) self.assertEqual(response.headers['Content-Type'], 'application/msgpack') def test_that_default_content_type_is_set_on_response(self): - response = self.fetch('/', method='POST', body=umsgpack.packb({}), + response = self.fetch('/', + method='POST', + body=umsgpack.packb({}), headers={'Content-Type': 'application/msgpack'}) self.assertEqual(response.code, 200) self.assertEqual(response.headers['Content-Type'], 'application/json; charset="utf-8"') def test_that_vary_header_is_set(self): - response = self.fetch('/', method='POST', body=umsgpack.packb({}), + response = self.fetch('/', + method='POST', + body=umsgpack.packb({}), headers={'Content-Type': 'application/msgpack'}) self.assertEqual(response.code, 200) self.assertEqual(response.headers['Vary'], 'Accept') @@ -106,9 +119,13 @@ class SendResponseTests(testing.AsyncHTTPTestCase): self._app, transcoders.MsgPackTranscoder(content_type='expected/content'), 'application/vendor+msgpack') - response = self.fetch('/', method='POST', body='{}', - headers={'Accept': 'application/vendor+msgpack', - 'Content-Type': 'application/json'}) + response = self.fetch('/', + method='POST', + body='{}', + headers={ + 'Accept': 'application/vendor+msgpack', + 'Content-Type': 'application/json' + }) self.assertEqual(response.code, 200) self.assertEqual(response.headers['Content-Type'], 'expected/content') @@ -123,54 +140,55 @@ class GetRequestBodyTests(testing.AsyncHTTPTestCase): return self.app def test_that_request_with_unhandled_type_results_in_415(self): - response = self.fetch( - '/', method='POST', headers={'Content-Type': 'application/xml'}, - body=('value' - '\u2731' - '').encode('utf-8')) + response = self.fetch('/', + method='POST', + headers={'Content-Type': 'application/xml'}, + 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': '\u2731' - } - } - response = self.fetch('/', method='POST', body=umsgpack.packb(body), + body = {'name': 'value', 'embedded': {'utf8': '\u2731'}} + response = self.fetch('/', + method='POST', + body=umsgpack.packb(body), headers={'Content-Type': 'application/msgpack'}) self.assertEqual(response.code, 200) self.assertEqual(json.loads(response.body.decode('utf-8')), body) def test_that_invalid_data_returns_400(self): response = self.fetch( - '/', method='POST', headers={'Content-Type': 'application/json'}, + '/', + method='POST', + headers={'Content-Type': 'application/json'}, body=('echo' 'Hi' '').encode('utf-8')) self.assertEqual(response.code, 400) def test_that_content_type_suffix_is_handled(self): - content.add_transcoder( - self._app, transcoders.JSONTranscoder(), - 'application/vendor+json') + content.add_transcoder(self._app, transcoders.JSONTranscoder(), + 'application/vendor+json') body = {'hello': 'world'} response = self.fetch( - '/', method='POST', body=json.dumps(body), + '/', + method='POST', + body=json.dumps(body), headers={'Content-Type': 'application/vendor+json'}) self.assertEqual(response.code, 200) self.assertEqual(json.loads(response.body.decode()), body) def test_that_invalid_content_types_result_in_bad_request(self): content.set_default_content_type(self.app, None, None) - response = self.fetch( - '/', method='POST', body='{"hi":"there"}', - headers={'Content-Type': 'application-json'}) + response = self.fetch('/', + method='POST', + body='{"hi":"there"}', + headers={'Content-Type': 'application-json'}) self.assertEqual(response.code, 400) class JSONTranscoderTests(unittest.TestCase): - def setUp(self): super().setUp() self.transcoder = transcoders.JSONTranscoder() @@ -211,7 +229,6 @@ class JSONTranscoderTests(unittest.TestCase): class ContentSettingsTests(unittest.TestCase): - def test_that_handler_listed_in_available_content_types(self): settings = content.ContentSettings() settings['application/json'] = object() @@ -249,14 +266,12 @@ class ContentSettingsTests(unittest.TestCase): class ContentFunctionTests(unittest.TestCase): - def setUp(self): super().setUp() self.context = Context() def test_that_add_binary_content_type_creates_binary_handler(self): - settings = content.install(self.context, - 'application/octet-stream') + settings = content.install(self.context, 'application/octet-stream') content.add_binary_content_type(self.context, 'application/vnd.python.pickle', pickle.dumps, pickle.loads) @@ -304,7 +319,6 @@ class ContentFunctionTests(unittest.TestCase): class MsgPackTranscoderTests(unittest.TestCase): - def setUp(self): super().setUp() self.transcoder = transcoders.MsgPackTranscoder() @@ -322,22 +336,21 @@ class MsgPackTranscoderTests(unittest.TestCase): self.assertEqual(self.transcoder.packb(True), b'\xC3') def test_that_ints_are_packed_appropriately(self): - self.assertEqual(self.transcoder.packb((2 ** 7) - 1), b'\x7F') - self.assertEqual(self.transcoder.packb(2 ** 7), b'\xCC\x80') - self.assertEqual(self.transcoder.packb(2 ** 8), b'\xCD\x01\x00') - self.assertEqual(self.transcoder.packb(2 ** 16), - b'\xCE\x00\x01\x00\x00') - self.assertEqual(self.transcoder.packb(2 ** 32), + self.assertEqual(self.transcoder.packb((2**7) - 1), b'\x7F') + self.assertEqual(self.transcoder.packb(2**7), b'\xCC\x80') + self.assertEqual(self.transcoder.packb(2**8), b'\xCD\x01\x00') + self.assertEqual(self.transcoder.packb(2**16), b'\xCE\x00\x01\x00\x00') + self.assertEqual(self.transcoder.packb(2**32), b'\xCF\x00\x00\x00\x01\x00\x00\x00\x00') def test_that_negative_ints_are_packed_accordingly(self): - self.assertEqual(self.transcoder.packb(-(2 ** 0)), b'\xFF') - self.assertEqual(self.transcoder.packb(-(2 ** 5)), b'\xE0') - self.assertEqual(self.transcoder.packb(-(2 ** 7)), b'\xD0\x80') - self.assertEqual(self.transcoder.packb(-(2 ** 15)), b'\xD1\x80\x00') - self.assertEqual(self.transcoder.packb(-(2 ** 31)), + self.assertEqual(self.transcoder.packb(-(2**0)), b'\xFF') + self.assertEqual(self.transcoder.packb(-(2**5)), b'\xE0') + self.assertEqual(self.transcoder.packb(-(2**7)), b'\xD0\x80') + self.assertEqual(self.transcoder.packb(-(2**15)), b'\xD1\x80\x00') + self.assertEqual(self.transcoder.packb(-(2**31)), b'\xD2\x80\x00\x00\x00') - self.assertEqual(self.transcoder.packb(-(2 ** 63)), + self.assertEqual(self.transcoder.packb(-(2**63)), b'\xD3\x80\x00\x00\x00\x00\x00\x00\x00') def test_that_lists_are_treated_as_arrays(self): diff --git a/tox.ini b/tox.ini index 4c7af88..ce7931d 100644 --- a/tox.ini +++ b/tox.ini @@ -25,3 +25,4 @@ commands = [testenv:lint] commands = flake8 sprockets tests.py + yapf -dr docs setup.py sprockets tests.py