From e74a63e64dca1052bb44a604eb61f4716bb8041a Mon Sep 17 00:00:00 2001 From: Atsushi Odagiri Date: Mon, 11 Feb 2019 16:20:42 +0000 Subject: [PATCH 1/7] blacken --- webdispatch/base.py | 23 +++-- webdispatch/dummyapps.py | 12 +-- webdispatch/methoddispatcher.py | 28 +++--- webdispatch/mixins.py | 3 +- webdispatch/paster.py | 4 +- webdispatch/testing.py | 7 +- webdispatch/tests/test_base.py | 9 +- webdispatch/tests/test_methoddispatcher.py | 46 +++++---- webdispatch/tests/test_mixins.py | 14 +-- webdispatch/tests/test_paster.py | 8 +- webdispatch/tests/test_uritemplate.py | 18 ++-- webdispatch/tests/test_urldispatcher.py | 112 ++++++++++++--------- webdispatch/uritemplate.py | 52 +++++----- webdispatch/urldispatcher.py | 63 ++++++------ 14 files changed, 202 insertions(+), 197 deletions(-) diff --git a/webdispatch/base.py b/webdispatch/base.py index 437fbd2..aed0182 100644 --- a/webdispatch/base.py +++ b/webdispatch/base.py @@ -7,9 +7,10 @@ class DispatchBase(object): """ Base class for dispatcher application""" def __init__( - self, - applications: Dict[str, Callable] = None, - extra_environ: Dict[str, Any] = None) -> None: + self, + applications: Dict[str, Callable] = None, + extra_environ: Dict[str, Any] = None, + ) -> None: if applications is None: self.applications = {} # type: Dict[str, Callable] @@ -23,11 +24,13 @@ def __init__( def register_app(self, name: str, app: Callable = None) -> Callable: """ register dispatchable wsgi application""" if app is None: + def dec(app): """ inner decorator for register app """ assert app is not None self.register_app(name, app) return app + return dec self.applications[name] = app return None @@ -36,21 +39,19 @@ def get_extra_environ(self) -> Dict[str, Any]: """ returns for environ values for wsgi environ""" return self.extra_environ - def detect_view_name( - self, environ: Dict[str, Any]) -> str: # pragma: nocover + def detect_view_name(self, environ: Dict[str, Any]) -> str: # pragma: nocover """ must returns view name for request """ raise NotImplementedError() def on_view_not_found( - self, - environ: Dict[str, Any], - start_response: Callable) -> Iterable[bytes]: # pragma: nocover + self, environ: Dict[str, Any], start_response: Callable + ) -> Iterable[bytes]: # pragma: nocover """ called when view is not found""" raise NotImplementedError() - def __call__(self, - environ: Dict[str, Any], - start_response: Callable) -> Iterable[bytes]: + def __call__( + self, environ: Dict[str, Any], start_response: Callable + ) -> Iterable[bytes]: extra_environ = self.get_extra_environ() environ.update(extra_environ) view_name = self.detect_view_name(environ) diff --git a/webdispatch/dummyapps.py b/webdispatch/dummyapps.py index 6d68e63..109bc72 100644 --- a/webdispatch/dummyapps.py +++ b/webdispatch/dummyapps.py @@ -3,15 +3,11 @@ def greeting(_, start_response): """ dummy application returns Hello simply""" - start_response( - '200 OK', - [('Content-type', 'text/plain')]) - return [b'Hello'] + start_response("200 OK", [("Content-type", "text/plain")]) + return [b"Hello"] def bye(_, start_response): """ dummy application returns by simply""" - start_response( - '200 OK', - [('Content-type', 'text/plain')]) - return [b'bye'] + start_response("200 OK", [("Content-type", "text/plain")]) + return [b"bye"] diff --git a/webdispatch/methoddispatcher.py b/webdispatch/methoddispatcher.py index 6215387..d52e165 100644 --- a/webdispatch/methoddispatcher.py +++ b/webdispatch/methoddispatcher.py @@ -9,6 +9,7 @@ class MethodDispatcher(DispatchBase): """ dispatch applications with request method. """ + def __init__(self, **kwargs) -> None: super(MethodDispatcher, self).__init__() for name, app in kwargs.items(): @@ -16,17 +17,14 @@ def __init__(self, **kwargs) -> None: def detect_view_name(self, environ: Dict[str, Any]) -> str: """ convert request method to view name """ - return environ['REQUEST_METHOD'].lower() + return environ["REQUEST_METHOD"].lower() def on_view_not_found( - self, _, - start_response: Callable[[str, List[Tuple[str, str]]], None], + self, _, start_response: Callable[[str, List[Tuple[str, str]]], None] ) -> Iterable[bytes]: """ called when valid view is not found """ - start_response( - "405 Method Not Allowed", - [('Content-type', 'text/plain')]) + start_response("405 Method Not Allowed", [("Content-type", "text/plain")]) return [b"Method Not Allowed"] @@ -41,35 +39,35 @@ def wsgiapp(environ, start_response): """ inner app """ handler = handler_cls() return getattr(handler, action_name)(environ, start_response) + return wsgiapp class ActionDispatcher(DispatchBase): """ wsgi application dispatching actions to registered classes""" - def __init__(self, action_var_name: str = 'action') -> None: + def __init__(self, action_var_name: str = "action") -> None: super(ActionDispatcher, self).__init__() self.action_var_name = action_var_name def register_actionhandler(self, action_handler: type) -> None: """ register class as action handler """ for k in action_handler.__dict__: - if k.startswith('_'): + if k.startswith("_"): continue app = action_handler_adapter(action_handler, k) self.register_app(k, app) def detect_view_name(self, environ: Dict[str, Any]) -> str: """ get view name from routing args """ - urlvars = environ.get('wsgiorg.routing_args', [(), {}])[1] + urlvars = environ.get("wsgiorg.routing_args", [(), {}])[1] return urlvars.get(self.action_var_name) def on_view_not_found( - self, environ: Dict[str, Any], - start_response: Callable[[str, List[Tuple[str, str]]], None], + self, + environ: Dict[str, Any], + start_response: Callable[[str, List[Tuple[str, str]]], None], ) -> Iterable[bytes]: """ called when action is not found """ - start_response( - "404 Not Found", - [('Content-type', 'text/plain')]) - return [b"Not Found ", application_uri(environ).encode('utf-8')] + start_response("404 Not Found", [("Content-type", "text/plain")]) + return [b"Not Found ", application_uri(environ).encode("utf-8")] diff --git a/webdispatch/mixins.py b/webdispatch/mixins.py index de103be..7636e9d 100644 --- a/webdispatch/mixins.py +++ b/webdispatch/mixins.py @@ -7,6 +7,7 @@ class URLMapperMixin(object): """ mixin to add :meth:`generate_url` method. """ + environ = {} # type: Dict[str, Any] def generate_url(self, name: str, **kwargs) -> str: @@ -16,4 +17,4 @@ def generate_url(self, name: str, **kwargs) -> str: @property def urlmapper(self) -> URLGenerator: """ get urlmapper object from wsgi environ """ - return self.environ['webdispatch.urlgenerator'] + return self.environ["webdispatch.urlgenerator"] diff --git a/webdispatch/paster.py b/webdispatch/paster.py index cf0ddbc..6c6158b 100644 --- a/webdispatch/paster.py +++ b/webdispatch/paster.py @@ -6,9 +6,7 @@ def make_urldispatch_application(_, **settings): """ paste.app_factory interface for URLDispatcher""" - patterns = [p.split("=", 1) - for p in settings['patterns'].split('\n') - if p] + patterns = [p.split("=", 1) for p in settings["patterns"].split("\n") if p] application = URLDispatcher() for pattern, app in patterns: diff --git a/webdispatch/testing.py b/webdispatch/testing.py index 85cab0d..2dfd63c 100644 --- a/webdispatch/testing.py +++ b/webdispatch/testing.py @@ -6,6 +6,7 @@ def setup_environ(**kwargs): """ setup basic wsgi environ""" environ = {} from wsgiref.util import setup_testing_defaults + setup_testing_defaults(environ) environ.update(kwargs) return environ @@ -15,9 +16,7 @@ def make_env(path_info, script_name): """ set up basic wsgi environ""" from wsgiref.util import setup_testing_defaults - environ = { - "PATH_INFO": path_info, - "SCRIPT_NAME": script_name, - } + + environ = {"PATH_INFO": path_info, "SCRIPT_NAME": script_name} setup_testing_defaults(environ) return environ diff --git a/webdispatch/tests/test_base.py b/webdispatch/tests/test_base.py index eb0aa19..f6581d2 100644 --- a/webdispatch/tests/test_base.py +++ b/webdispatch/tests/test_base.py @@ -10,6 +10,7 @@ class TestDispatchBase(object): def _get_target(): """ get class under test """ from webdispatch.base import DispatchBase + return DispatchBase def _make_one(self, *args, **kwargs): @@ -28,19 +29,19 @@ def test_init_apps(self): """ init with app and no environ""" testing_app = object() - result = self._make_one(applications={'testing': testing_app}) + result = self._make_one(applications={"testing": testing_app}) - compare(result.applications, {'testing': testing_app}) + compare(result.applications, {"testing": testing_app}) compare(result.extra_environ, {}) def test_init_env(self): """ init with app and no environ""" - environ = {'test_value': 1} + environ = {"test_value": 1} result = self._make_one(extra_environ=environ) compare(result.applications, {}) - compare(result.extra_environ, {'test_value': 1}) + compare(result.extra_environ, {"test_value": 1}) def test_not_found(self): """ init with app and no environ""" diff --git a/webdispatch/tests/test_methoddispatcher.py b/webdispatch/tests/test_methoddispatcher.py index b054825..cec324b 100644 --- a/webdispatch/tests/test_methoddispatcher.py +++ b/webdispatch/tests/test_methoddispatcher.py @@ -11,10 +11,12 @@ def dummy_get_app(*dummy): class TestMethodDispatcher(object): """ test for webdispatch.methoddispatcher.MethodDispatcher""" + @staticmethod def _get_target(): """ get class under test """ from webdispatch.methoddispatcher import MethodDispatcher + return MethodDispatcher def _make_one(self, *args, **kwargs): @@ -32,12 +34,13 @@ def test_it(self): def test_not_allowed(self): """ test not found views""" app = self._make_one(get=dummy_get_app) - environ = setup_environ(REQUEST_METHOD='POST') + environ = setup_environ(REQUEST_METHOD="POST") start_response = mock.Mock() result = app(environ, start_response) compare(result, [b"Method Not Allowed"]) start_response.assert_called_with( - '405 Method Not Allowed', [('Content-type', 'text/plain')]) + "405 Method Not Allowed", [("Content-type", "text/plain")] + ) def test_register_app(self): """ test registering app""" @@ -63,10 +66,12 @@ def test_register_app_decorator(self): class TestActionHandlerAdapter(object): """ test for webdispatch.methoddispatcher.action_handler_adapter""" + @staticmethod def _call_fut(*args, **kwargs): """ call function under test """ from webdispatch.methoddispatcher import action_handler_adapter + return action_handler_adapter(*args, **kwargs) def test_call(self): @@ -74,6 +79,7 @@ def test_call(self): class DummyAction(object): """ dummy action class""" + def __init__(self): self.message = b"Hello" @@ -83,17 +89,15 @@ def get_message(self): def action(self, _, start_response): """ dummy action """ - start_response("200 OK", - [("Content-type", "text/plain")]) + start_response("200 OK", [("Content-type", "text/plain")]) return [self.get_message()] target = self._call_fut(DummyAction, "action") - environ = setup_environ(REQUEST_METHOD='POST') + environ = setup_environ(REQUEST_METHOD="POST") start_response = mock.Mock() result = target(environ, start_response) compare(result, [b"Hello"]) - start_response.assert_called_with( - '200 OK', [('Content-type', 'text/plain')]) + start_response.assert_called_with("200 OK", [("Content-type", "text/plain")]) def test_invalid_name(self): """ test using invalid attr name """ @@ -104,10 +108,12 @@ def test_invalid_name(self): class TestActionDispatcher(object): """ test for webdispatch.methoddispatcher.ActionDispatcher""" + @staticmethod def _get_target(): """ get class under test""" from webdispatch.methoddispatcher import ActionDispatcher + return ActionDispatcher def _make_one(self, *args, **kwargs): @@ -120,12 +126,12 @@ def test_it(self): def test_app(*_): """ dummy app""" - return [b'got action'] + return [b"got action"] - app.register_app('test_app', test_app) - routing_args = [(), {'action': 'test_app'}] + app.register_app("test_app", test_app) + routing_args = [(), {"action": "test_app"}] environ = setup_environ() - environ.update({'wsgiorg.routing_args': routing_args}) + environ.update({"wsgiorg.routing_args": routing_args}) start_response = mock.Mock() result = app(environ, start_response) compare(result, [b"got action"]) @@ -147,9 +153,9 @@ def test_action(self, *_): return self.get_body() app.register_actionhandler(DummyHandler) - routing_args = [(), {'action': 'test_action'}] + routing_args = [(), {"action": "test_action"}] environ = setup_environ() - environ.update({'wsgiorg.routing_args': routing_args}) + environ.update({"wsgiorg.routing_args": routing_args}) start_response = mock.Mock() result = app(environ, start_response) compare(result, [b"test action"]) @@ -158,17 +164,15 @@ def test_not_found(self): """ test called not registered action """ app = self._make_one() - app.register_app('test_app', - None) - routing_args = [(), {'action': 'no_app'}] - env = {'wsgiorg.routing_args': routing_args} + app.register_app("test_app", None) + routing_args = [(), {"action": "no_app"}] + env = {"wsgiorg.routing_args": routing_args} environ = setup_environ() environ.update(env) start_response = mock.Mock() result = app(environ, start_response) start_response.assert_called_with( - '404 Not Found', [('Content-type', 'text/plain')]) + "404 Not Found", [("Content-type", "text/plain")] + ) - compare(result, - [b"Not Found ", - b"http://127.0.0.1/"]) + compare(result, [b"Not Found ", b"http://127.0.0.1/"]) diff --git a/webdispatch/tests/test_mixins.py b/webdispatch/tests/test_mixins.py index 445fe2a..d66a223 100644 --- a/webdispatch/tests/test_mixins.py +++ b/webdispatch/tests/test_mixins.py @@ -10,6 +10,7 @@ class TestURLMapperMixin(object): def _get_target(): """ get class under test """ from webdispatch.mixins import URLMapperMixin + return URLMapperMixin def _make_one(self, *args, **kwargs): @@ -20,19 +21,18 @@ def test_generate_url(self): """ test generate_url """ target = self._make_one() dummy_generator = mock.Mock() - dummy_generator.generate.return_value = 'generated' - target.environ = {'webdispatch.urlgenerator': dummy_generator} - result = target.generate_url('a', v1='1', v2='2') + dummy_generator.generate.return_value = "generated" + target.environ = {"webdispatch.urlgenerator": dummy_generator} + result = target.generate_url("a", v1="1", v2="2") - compare(result, 'generated') - dummy_generator.generate.assert_called_with( - 'a', v1='1', v2='2') + compare(result, "generated") + dummy_generator.generate.assert_called_with("a", v1="1", v2="2") def test_urlmapper(self): """ test urlmapper property """ target = self._make_one() dummy_generator = object() - target.environ = {'webdispatch.urlgenerator': dummy_generator} + target.environ = {"webdispatch.urlgenerator": dummy_generator} result = target.urlmapper compare(result, dummy_generator) diff --git a/webdispatch/tests/test_paster.py b/webdispatch/tests/test_paster.py index c3306ff..6d03d8b 100644 --- a/webdispatch/tests/test_paster.py +++ b/webdispatch/tests/test_paster.py @@ -6,6 +6,7 @@ class TestPaste(object): """ test for webdispatch.paster.make_urldispatch_application """ + @staticmethod def _make_env(path_info, script_name): """ make basic wsgi environ """ @@ -15,11 +16,12 @@ def _make_env(path_info, script_name): def _call_fut(*args, **kwargs): """ call function under test """ from webdispatch.paster import make_urldispatch_application + return make_urldispatch_application(*args, **kwargs) def assert_response_body(self, app, path, expected): """ assert body created app on path equals expected""" - environ = self._make_env(path, '') + environ = self._make_env(path, "") start_response = mock.Mock() result = app(environ, start_response) compare(result, expected) @@ -32,5 +34,5 @@ def test_it(self): /bye = webdispatch.dummyapps:bye""" application = self._call_fut(global_conf, patterns=patterns) - self.assert_response_body(application, '/', [b'Hello']) - self.assert_response_body(application, '/bye', [b'bye']) + self.assert_response_body(application, "/", [b"Hello"]) + self.assert_response_body(application, "/bye", [b"bye"]) diff --git a/webdispatch/tests/test_uritemplate.py b/webdispatch/tests/test_uritemplate.py index 59f4381..603ea04 100644 --- a/webdispatch/tests/test_uritemplate.py +++ b/webdispatch/tests/test_uritemplate.py @@ -10,6 +10,7 @@ class TestPatternToRegex(object): def _call_fut(*args, **kwargs): """ call function under test """ from webdispatch.uritemplate import pattern_to_regex + return pattern_to_regex(*args, **kwargs) def test_empty(self): @@ -76,6 +77,7 @@ class TestDetectConverters(object): def _call_fut(*args, **kwargs): """ call function under test """ from webdispatch.uritemplate import detect_converters + return detect_converters(*args, **kwargs) def test_empty(self): @@ -90,14 +92,14 @@ def test_no_type(self): pattern = "{a}" result = self._call_fut(pattern, {}) - compare(result, {'a': str}) + compare(result, {"a": str}) def test_type(self): """ test with specified converter """ pattern = "{a:int}" - result = self._call_fut(pattern, {'int': int}) + result = self._call_fut(pattern, {"int": int}) - compare(result, {'a': int}) + compare(result, {"a": int}) class TestURITemplate(object): @@ -107,6 +109,7 @@ class TestURITemplate(object): def _get_target(): """ get class under test""" from webdispatch.uritemplate import URITemplate + return URITemplate def _make_one(self, *args, **kwargs): @@ -116,6 +119,7 @@ def _make_one(self, *args, **kwargs): def test_bad_format(self): """ test bad format template""" from webdispatch.uritemplate import URITemplateFormatException + path = "a*" with ShouldRaise(URITemplateFormatException): self._make_one(path) @@ -191,15 +195,13 @@ def test_match_conveter_error(self): def test_match_custom_conveter(self): """ test using custom converter """ from datetime import datetime - converters = { - "testing": lambda s: datetime.strptime(s, '%Y%m%d') - } + + converters = {"testing": lambda s: datetime.strptime(s, "%Y%m%d")} path = "{var1}/users/{var2:testing}" target = self._make_one(path, converters=converters) result = target.match("1/users/20140420") - compare(result.matchdict, - dict(var1="1", var2=datetime(2014, 4, 20))) + compare(result.matchdict, dict(var1="1", var2=datetime(2014, 4, 20))) def test_substitue(self): """ test subtituting vars to pattern """ diff --git a/webdispatch/tests/test_urldispatcher.py b/webdispatch/tests/test_urldispatcher.py index 5eac2be..5a3e0c0 100644 --- a/webdispatch/tests/test_urldispatcher.py +++ b/webdispatch/tests/test_urldispatcher.py @@ -9,10 +9,12 @@ class TestURLMapper(object): """ tests for webdispatch.urldispatcher.URLMapper """ + @staticmethod def _get_target(): """ get class under test """ from webdispatch.urldispatcher import URLMapper + return URLMapper def _make_one(self, *args, **kwargs): @@ -21,69 +23,74 @@ def _make_one(self, *args, **kwargs): def test_init(self): """ test create object """ - converters = { - 'int': int, - 'str': str, - 'float': float, - } + converters = {"int": int, "str": str, "float": float} target = self._make_one(converters) - compare(target, C(self._get_target(), - patterns=collections.OrderedDict(), - converters=converters)) + compare( + target, + C( + self._get_target(), + patterns=collections.OrderedDict(), + converters=converters, + ), + ) def test_add(self): """ test add url """ from webdispatch.uritemplate import URITemplate - converters = { - 'int': int, - 'str': str, - 'float': float, - } - pattern = '/{v1}/{v2:int}' - target = self._make_one(converters) - target.add('testing-route', pattern) + converters = {"int": int, "str": str, "float": float} + pattern = "/{v1}/{v2:int}" - compare(target.patterns, - {'testing-route': C(URITemplate, - converters={'v1': str, - 'v2': int}, - pattern=pattern, - strict=False)}) + target = self._make_one(converters) + target.add("testing-route", pattern) + + compare( + target.patterns, + { + "testing-route": C( + URITemplate, + converters={"v1": str, "v2": int}, + pattern=pattern, + strict=False, + ) + }, + ) def test_lookup_none(self): """ test looking up route no registered routes""" target = self._make_one() - result = target.lookup('a') + result = target.lookup("a") compare(result, None) def test_lookup(self): """ test looking up basic usage """ from webdispatch.uritemplate import MatchResult + target = self._make_one() - target.add('testing-route', 'a') - result = target.lookup('a') - compare(result, C(MatchResult, - name='testing-route', - matchdict={}, - matchlength=1)) + target.add("testing-route", "a") + result = target.lookup("a") + compare( + result, C(MatchResult, name="testing-route", matchdict={}, matchlength=1) + ) def test_generate(self): """ test generating url """ target = self._make_one() - target.add('testing-route', 'a/{v1}') + target.add("testing-route", "a/{v1}") - result = target.generate('testing-route', v1='b') - compare(result, 'a/b') + result = target.generate("testing-route", v1="b") + compare(result, "a/b") class TestURLGenerator(object): """ test for webdispatch.urldispatcher.URLGenerator """ + @staticmethod def _get_target(): """ get class under test """ from webdispatch.urldispatcher import URLGenerator + return URLGenerator def _make_one(self, *args, **kwargs): @@ -98,26 +105,28 @@ def test_init(self): compare(target.environ, environ) compare(target.urlmapper, urlmapper) - compare(target.application_uri, 'http://127.0.0.1/') + compare(target.application_uri, "http://127.0.0.1/") def test_generate(self): """ test generating url """ environ = setup_environ() urlmapper = mock.Mock() - urlmapper.generate.return_value = 'testing-route-url' + urlmapper.generate.return_value = "testing-route-url" target = self._make_one(environ, urlmapper) - result = target.generate('testing-route', v1="a") + result = target.generate("testing-route", v1="a") - compare(result, 'http://127.0.0.1/testing-route-url') + compare(result, "http://127.0.0.1/testing-route-url") class TestURLDispatcher(object): """ tests for webdispatch.urldispatcher.URLDispatcher """ + @staticmethod def _get_target(): """ get class under test """ from webdispatch.urldispatcher import URLDispatcher + return URLDispatcher def _make_one(self, *args, **kwargs): @@ -141,22 +150,26 @@ def test_add_url(self): mapper = mock.Mock() target = self._make_one(urlmapper=mapper) app = object() - target.add_url('testing-route', 'a/b', app) + target.add_url("testing-route", "a/b", app) - mapper.add.assert_called_with('testing-route', 'a/b') + mapper.add.assert_called_with("testing-route", "a/b") def test_subroute(self): """ test subroute """ mapper = object() - target = self._make_one(urlmapper=mapper, - extra_environ={'testing': 'e'}) - result = target.add_subroute('prefix/a/b') - - compare(result, C(self._get_target(), - urlmapper=mapper, - prefix='prefix/a/b', - applications={}, - extra_environ={'testing': 'e'})) + target = self._make_one(urlmapper=mapper, extra_environ={"testing": "e"}) + result = target.add_subroute("prefix/a/b") + + compare( + result, + C( + self._get_target(), + urlmapper=mapper, + prefix="prefix/a/b", + applications={}, + extra_environ={"testing": "e"}, + ), + ) def test_detect_view_name(self): """ test detect_view_name """ @@ -173,6 +186,7 @@ def test_on_view_not_found(self): start_response = mock.Mock() result = target(environ, start_response) - compare(result, [b'Not found']) + compare(result, [b"Not found"]) start_response.assert_called_with( - '404 Not Found', [('Content-type', 'text/plain')]) + "404 Not Found", [("Content-type", "text/plain")] + ) diff --git a/webdispatch/uritemplate.py b/webdispatch/uritemplate.py index 1f1c3bf..c46dd06 100644 --- a/webdispatch/uritemplate.py +++ b/webdispatch/uritemplate.py @@ -5,16 +5,11 @@ from datetime import datetime import re import string -from typing import ( # noqa pylint: disable=unused-import - Any, - Dict, - Callable, - Tuple, -) +from typing import Any, Dict, Callable, Tuple # noqa pylint: disable=unused-import -VARS_PT = re.compile(r"{(?P[a-zA-Z0-9_]+)" - r"(:(?P[a-zA-Z0-9_]+))?}", - re.X) +VARS_PT = re.compile( + r"{(?P[a-zA-Z0-9_]+)" r"(:(?P[a-zA-Z0-9_]+))?}", re.X +) META_CHARS = ( "\\", ".", @@ -27,25 +22,26 @@ "(", ")", "[", - "]") # type: Tuple[str, ...] + "]", +) # type: Tuple[str, ...] DEFAULT_CONVERTERS = { - 'int': int, - 'date': lambda s: datetime.strptime(s, '%Y-%m-%d'), - 'date_ym': lambda s: datetime.strptime(s, '%Y-%m'), + "int": int, + "date": lambda s: datetime.strptime(s, "%Y-%m-%d"), + "date_ym": lambda s: datetime.strptime(s, "%Y-%m"), } # type: Dict[str, Callable] def regex_replacer(matched) -> str: """ replace url placeholder to regex pattern""" values = matched.groupdict() - return "(?P<" + values['varname'] + r">[\w-]+)" + return "(?P<" + values["varname"] + r">[\w-]+)" def template_replacer(matched) -> str: """ replace url placeholder to template interpolation""" values = matched.groupdict() - return "${" + values['varname'] + "}" + return "${" + values["varname"] + "}" def pattern_to_regex(pattern: str) -> str: @@ -66,15 +62,15 @@ def pattern_to_template(pattern: str) -> str: return VARS_PT.sub(template_replacer, pattern) -def detect_converters(pattern: str, - converter_dict: Dict[str, Callable], - default: Callable = str): +def detect_converters( + pattern: str, converter_dict: Dict[str, Callable], default: Callable = str +): """ detect pairs of varname and converter from pattern""" converters = {} for matched in VARS_PT.finditer(pattern): matchdict = matched.groupdict() - varname = matchdict['varname'] - converter = matchdict['converter'] + varname = matchdict["varname"] + converter = matchdict["converter"] converters[varname] = converter_dict.get(converter, default) return converters @@ -85,6 +81,7 @@ class URITemplateFormatException(Exception): class MatchResult: """ result of parsing url """ + def __init__(self, matchdict: Dict[str, Any], matchlength: int) -> None: self.name = None # type: str self.matchdict = matchdict @@ -98,24 +95,22 @@ def new_named_args(self, cur_named_args: Dict[str, Any]) -> Dict[str, Any]: def split_path_info(self, path_info: str) -> Tuple[str, str]: """ split path_info to new script_name and new path_info""" - return path_info[:self.matchlength], path_info[self.matchlength:] + return path_info[: self.matchlength], path_info[self.matchlength :] class URITemplate(object): """ parsing and generating url with patterned """ - def __init__(self, tmpl_pattern: str, - converters=None) -> None: - if tmpl_pattern.endswith('*') and not tmpl_pattern.endswith('/*'): - raise URITemplateFormatException('wildcard must be after slash.') + def __init__(self, tmpl_pattern: str, converters=None) -> None: + if tmpl_pattern.endswith("*") and not tmpl_pattern.endswith("/*"): + raise URITemplateFormatException("wildcard must be after slash.") self.pattern = tmpl_pattern self.regex = re.compile(pattern_to_regex(tmpl_pattern)) self.template = string.Template(pattern_to_template(tmpl_pattern)) if converters is None: converters = DEFAULT_CONVERTERS - self.converters = detect_converters( - tmpl_pattern, converters) + self.converters = detect_converters(tmpl_pattern, converters) def match(self, path_info: str) -> MatchResult: """ parse path_info and detect urlvars of url pattern """ @@ -130,8 +125,7 @@ def match(self, path_info: str) -> MatchResult: except ValueError: return None - return MatchResult(matchdict, - matchlength) + return MatchResult(matchdict, matchlength) def convert_values(self, matchdict: Dict[str, str]) -> Dict[str, Any]: """ convert values of ``matchdict`` diff --git a/webdispatch/urldispatcher.py b/webdispatch/urldispatcher.py index 5eda492..9634950 100644 --- a/webdispatch/urldispatcher.py +++ b/webdispatch/urldispatcher.py @@ -3,14 +3,7 @@ """ from collections import OrderedDict from wsgiref.util import application_uri -from typing import ( # noqa - Any, - Callable, - Dict, - List, - Tuple, - Iterable, -) +from typing import Any, Callable, Dict, List, Tuple, Iterable # noqa from .uritemplate import URITemplate, MatchResult from .base import DispatchBase @@ -26,8 +19,7 @@ def __init__(self, converters: Dict[str, Callable] = None) -> None: def add(self, name: str, pattern: str) -> None: """ add url pattern for name """ - self.patterns[name] = URITemplate( - pattern, converters=self.converters) + self.patterns[name] = URITemplate(pattern, converters=self.converters) def lookup(self, path_info: str) -> MatchResult: """ lookup url match for path_info @@ -64,23 +56,25 @@ def generate(self, name: str, **kwargs): def make_full_qualified_url(self, path: str) -> str: """ append application url to path""" - return self.application_uri.rstrip('/') + '/' + path.lstrip('/') + return self.application_uri.rstrip("/") + "/" + path.lstrip("/") class URLDispatcher(DispatchBase): """ dispatch applications with url patterns. """ - def __init__(self, - *, - applications: Dict[str, Callable] = None, - extra_environ: Dict[str, Any] = None, - converters: Dict[str, Callable] = None, - urlmapper: URLMapper = None, - prefix: str = "") -> None: + def __init__( + self, + *, + applications: Dict[str, Callable] = None, + extra_environ: Dict[str, Any] = None, + converters: Dict[str, Callable] = None, + urlmapper: URLMapper = None, + prefix: str = "" + ) -> None: super(URLDispatcher, self).__init__( - applications=applications, - extra_environ=extra_environ) + applications=applications, extra_environ=extra_environ + ) if urlmapper: self.urlmapper = urlmapper else: @@ -98,12 +92,13 @@ def add_subroute(self, pattern: str) -> "URLDispatcher": urlmapper=self.urlmapper, prefix=self.prefix + pattern, applications=self.applications, - extra_environ=self.extra_environ) + extra_environ=self.extra_environ, + ) def detect_view_name(self, environ: Dict[str, Any]) -> str: """ detect view name from environ """ - script_name = environ.get('SCRIPT_NAME', '') - path_info = environ.get('PATH_INFO', '') + script_name = environ.get("SCRIPT_NAME", "") + path_info = environ.get("PATH_INFO", "") match = self.urlmapper.lookup(path_info) if match is None: return None @@ -112,24 +107,24 @@ def detect_view_name(self, environ: Dict[str, Any]) -> str: extra_path_info = splited[1] pos_args = [] # type: List[str] - routing_args = environ.get('wsgiorg.routing_args', ((), {})) + routing_args = environ.get("wsgiorg.routing_args", ((), {})) (cur_pos, cur_named) = routing_args new_pos = list(cur_pos) + list(pos_args) new_named = match.new_named_args(cur_named) - environ['wsgiorg.routing_args'] = (new_pos, new_named) - environ['webdispatch.urlmapper'] = self.urlmapper + environ["wsgiorg.routing_args"] = (new_pos, new_named) + environ["webdispatch.urlmapper"] = self.urlmapper urlgenerator = URLGenerator(environ, self.urlmapper) - environ['webdispatch.urlgenerator'] = urlgenerator - environ['SCRIPT_NAME'] = script_name + splited[0] - environ['PATH_INFO'] = extra_path_info + environ["webdispatch.urlgenerator"] = urlgenerator + environ["SCRIPT_NAME"] = script_name + splited[0] + environ["PATH_INFO"] = extra_path_info return match.name def on_view_not_found( - self, - environ: Dict[str, Any], - start_response: Callable[[str, List[Tuple[str, str]]], None], + self, + environ: Dict[str, Any], + start_response: Callable[[str, List[Tuple[str, str]]], None], ) -> Iterable[bytes]: """ called when views not found""" - start_response('404 Not Found', [('Content-type', 'text/plain')]) - return [b'Not found'] + start_response("404 Not Found", [("Content-type", "text/plain")]) + return [b"Not found"] From f37a21304e18f470175f72c7f7b9d5be35b9ce5d Mon Sep 17 00:00:00 2001 From: Atsushi Odagiri Date: Mon, 11 Feb 2019 16:24:45 +0000 Subject: [PATCH 2/7] upgrade libs --- constraints.txt | 61 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 20 deletions(-) diff --git a/constraints.txt b/constraints.txt index 67f9d92..e4f6ab5 100644 --- a/constraints.txt +++ b/constraints.txt @@ -1,20 +1,41 @@ -beautifulsoup4==4.6.0 -certifi==2017.4.17 -chardet==3.0.4 -colorama==0.3.9 -coverage==4.4.1 -idna==2.5 -mock==2.0.0 -pbr==3.1.1 -py==1.4.34 -pytest==3.1.3 -pytest-cov==2.5.1 -python-coveralls==2.9.1 -PyYAML==3.12 -requests==2.18.1 -six==1.10.0 -testfixtures==5.1.1 -urllib3==1.21.1 -waitress==1.0.2 -WebOb==1.7.3 -WebTest==2.0.27 +appdirs==1.4.3 +astroid==2.1.0 +atomicwrites==1.3.0 +attrs==18.2.0 +beautifulsoup4==4.7.1 +black==18.9b0 +certifi==2018.11.29 +chardet==3.0.4 +Click==7.0 +coverage==4.0.3 +entrypoints==0.3 +flake8==3.7.5 +idna==2.8 +isort==4.3.4 +lazy-object-proxy==1.3.1 +mccabe==0.6.1 +mock==2.0.0 +more-itertools==5.0.0 +mypy==0.670 +mypy-extensions==0.4.1 +pbr==5.1.2 +pluggy==0.8.1 +py==1.7.0 +pycodestyle==2.5.0 +pyflakes==2.1.0 +pylint==2.2.2 +pytest==4.2.0 +pytest-cov==2.6.1 +python-coveralls==2.9.1 +PyYAML==3.13 +requests==2.21.0 +six==1.12.0 +soupsieve==1.7.3 +testfixtures==6.5.0 +toml==0.10.0 +typed-ast==1.3.1 +urllib3==1.24.1 +waitress==1.2.1 +WebOb==1.8.5 +WebTest==2.0.33 +wrapt==1.11.1 From 3f4250f57dbd6459df5e1b7b093b660936019d54 Mon Sep 17 00:00:00 2001 From: Atsushi Odagiri Date: Mon, 11 Feb 2019 16:26:29 +0000 Subject: [PATCH 3/7] configure max line --- setup.cfg | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 0adf19f..53231e7 100644 --- a/setup.cfg +++ b/setup.cfg @@ -10,4 +10,7 @@ with-doctest = 1 universal = 1 [metadata] -version = attr:webdispatch.__version__ \ No newline at end of file +version = attr:webdispatch.__version__ + +[flake8] +max-line-length = 88 From 67c8894bc202a128c173a67530d9392625d3e965 Mon Sep 17 00:00:00 2001 From: Atsushi Odagiri Date: Mon, 11 Feb 2019 16:28:13 +0000 Subject: [PATCH 4/7] flake8 --- webdispatch/uritemplate.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/webdispatch/uritemplate.py b/webdispatch/uritemplate.py index c46dd06..5e10225 100644 --- a/webdispatch/uritemplate.py +++ b/webdispatch/uritemplate.py @@ -95,7 +95,8 @@ def new_named_args(self, cur_named_args: Dict[str, Any]) -> Dict[str, Any]: def split_path_info(self, path_info: str) -> Tuple[str, str]: """ split path_info to new script_name and new path_info""" - return path_info[: self.matchlength], path_info[self.matchlength :] + matchlength = self.matchlength + return path_info[:matchlength], path_info[matchlength:] class URITemplate(object): From 52844227029fbdb50cbc360979b0b3653aaa3bbb Mon Sep 17 00:00:00 2001 From: Atsushi Odagiri Date: Mon, 11 Feb 2019 16:32:55 +0000 Subject: [PATCH 5/7] upgrade --- constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/constraints.txt b/constraints.txt index e4f6ab5..bf1f8ab 100644 --- a/constraints.txt +++ b/constraints.txt @@ -7,7 +7,7 @@ black==18.9b0 certifi==2018.11.29 chardet==3.0.4 Click==7.0 -coverage==4.0.3 +coverage==4.5.2 entrypoints==0.3 flake8==3.7.5 idna==2.8 From 4611b2ffcbc099ef6550c64c6502c5fbd2d3db87 Mon Sep 17 00:00:00 2001 From: Atsushi Odagiri Date: Mon, 11 Feb 2019 16:46:43 +0000 Subject: [PATCH 6/7] mypy --- webdispatch/base.py | 8 +++++--- webdispatch/uritemplate.py | 12 +++++++++--- webdispatch/urldispatcher.py | 6 +++--- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/webdispatch/base.py b/webdispatch/base.py index aed0182..94527a5 100644 --- a/webdispatch/base.py +++ b/webdispatch/base.py @@ -1,6 +1,6 @@ """ base dispatchers """ -from typing import Dict, Any, Callable, Iterable +from typing import Dict, Any, Callable, Iterable, Optional class DispatchBase(object): @@ -33,13 +33,15 @@ def dec(app): return dec self.applications[name] = app - return None + return app def get_extra_environ(self) -> Dict[str, Any]: """ returns for environ values for wsgi environ""" return self.extra_environ - def detect_view_name(self, environ: Dict[str, Any]) -> str: # pragma: nocover + def detect_view_name( + self, environ: Dict[str, Any] + ) -> Optional[str]: # pragma: nocover """ must returns view name for request """ raise NotImplementedError() diff --git a/webdispatch/uritemplate.py b/webdispatch/uritemplate.py index 5e10225..c5fc95d 100644 --- a/webdispatch/uritemplate.py +++ b/webdispatch/uritemplate.py @@ -5,7 +5,13 @@ from datetime import datetime import re import string -from typing import Any, Dict, Callable, Tuple # noqa pylint: disable=unused-import +from typing import ( + Any, + Dict, + Callable, + Optional, + Tuple, +) # noqa pylint: disable=unused-import VARS_PT = re.compile( r"{(?P[a-zA-Z0-9_]+)" r"(:(?P[a-zA-Z0-9_]+))?}", re.X @@ -83,7 +89,7 @@ class MatchResult: """ result of parsing url """ def __init__(self, matchdict: Dict[str, Any], matchlength: int) -> None: - self.name = None # type: str + self.name = None # type: Optional[str] self.matchdict = matchdict self.matchlength = matchlength @@ -113,7 +119,7 @@ def __init__(self, tmpl_pattern: str, converters=None) -> None: converters = DEFAULT_CONVERTERS self.converters = detect_converters(tmpl_pattern, converters) - def match(self, path_info: str) -> MatchResult: + def match(self, path_info: str) -> Optional[MatchResult]: """ parse path_info and detect urlvars of url pattern """ matched = self.regex.match(path_info) if matched is None: diff --git a/webdispatch/urldispatcher.py b/webdispatch/urldispatcher.py index 9634950..9b6dcba 100644 --- a/webdispatch/urldispatcher.py +++ b/webdispatch/urldispatcher.py @@ -3,7 +3,7 @@ """ from collections import OrderedDict from wsgiref.util import application_uri -from typing import Any, Callable, Dict, List, Tuple, Iterable # noqa +from typing import Any, Callable, Dict, List, Optional, Tuple, Iterable # noqa from .uritemplate import URITemplate, MatchResult from .base import DispatchBase @@ -21,7 +21,7 @@ def add(self, name: str, pattern: str) -> None: """ self.patterns[name] = URITemplate(pattern, converters=self.converters) - def lookup(self, path_info: str) -> MatchResult: + def lookup(self, path_info: str) -> Optional[MatchResult]: """ lookup url match for path_info """ for name, pattern in self.patterns.items(): @@ -95,7 +95,7 @@ def add_subroute(self, pattern: str) -> "URLDispatcher": extra_environ=self.extra_environ, ) - def detect_view_name(self, environ: Dict[str, Any]) -> str: + def detect_view_name(self, environ: Dict[str, Any]) -> Optional[str]: """ detect view name from environ """ script_name = environ.get("SCRIPT_NAME", "") path_info = environ.get("PATH_INFO", "") From e6f1b4da0a33f98457ca83587e3348c819f67265 Mon Sep 17 00:00:00 2001 From: Atsushi Odagiri Date: Mon, 11 Feb 2019 17:01:37 +0000 Subject: [PATCH 7/7] setup cache on ci --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 24ecec3..f38d1c6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,6 @@ sudo: false language: python +cache: pip python: - 3.4 - 3.5