diff --git a/sanic/app.py b/sanic/app.py index b0041507..1d67dcf2 100644 --- a/sanic/app.py +++ b/sanic/app.py @@ -16,7 +16,7 @@ from urllib.parse import urlencode, urlunparse from sanic_routing.route import Route -from sanic import reloader_helpers, websocket +from sanic import reloader_helpers from sanic.asgi import ASGIApp from sanic.base import BaseSanic from sanic.blueprint_group import BlueprintGroup @@ -114,6 +114,8 @@ class Sanic(BaseSanic): if self.config.REGISTER: self.__class__.register_app(self) + self.router.ctx.app = self + @property def loop(self): """Synonymous with asyncio.get_event_loop(). @@ -230,7 +232,6 @@ class Sanic(BaseSanic): websocket = params.pop("websocket", False) subprotocols = params.pop("subprotocols", None) - if websocket: self.enable_websocket() websocket_handler = partial( @@ -294,6 +295,12 @@ class Sanic(BaseSanic): else: self.blueprints[blueprint.name] = blueprint self._blueprint_order.append(blueprint) + + if ( + self.strict_slashes is not None + and blueprint.strict_slashes is None + ): + blueprint.strict_slashes = self.strict_slashes blueprint.register(self, options) def url_for(self, view_name: str, **kwargs): @@ -319,30 +326,28 @@ class Sanic(BaseSanic): # find the route by the supplied view name kw: Dict[str, str] = {} # special static files url_for - if view_name == "static": - kw.update(name=kwargs.pop("name", "static")) - elif view_name.endswith(".static"): # blueprint.static - kwargs.pop("name", None) + + if "." not in view_name: + view_name = f"{self.name}.{view_name}" + + if view_name.endswith(".static"): + name = kwargs.pop("name", None) + if name: + view_name = view_name.replace("static", name) kw.update(name=view_name) - uri, route = self.router.find_route_by_view_name(view_name, **kw) - if not (uri and route): + route = self.router.find_route_by_view_name(view_name, **kw) + if not route: raise URLBuildError( f"Endpoint with name `{view_name}` was not found" ) - # If the route has host defined, split that off - # TODO: Retain netloc and path separately in Route objects - host = uri.find("/") - if host > 0: - host, uri = uri[:host], uri[host:] - else: - host = None + uri = route.path - if view_name == "static" or view_name.endswith(".static"): - filename = kwargs.pop("filename", None) + if getattr(route.ctx, "static", None): + filename = kwargs.pop("filename", "") # it's static folder - if " 1: + raise ValueError( + f"Host is ambiguous: {', '.join(route.ctx.hosts)}" + ) + elif host and host not in route.ctx.hosts: + raise ValueError( + f"Requested host ({host}) is not available for this " + f"route: {route.ctx.hosts}" + ) + elif not host: + host = list(route.ctx.hosts)[0] + if scheme and not external: raise ValueError("When specifying _scheme, _external must be True") @@ -383,45 +402,49 @@ class Sanic(BaseSanic): if "://" in netloc[:8]: netloc = netloc.split("://", 1)[-1] - # for match in matched_params: - # name, _type, pattern = self.router.parse_parameter_string(match) - # # we only want to match against each individual parameter - # specific_pattern = f"^{pattern}$" - # supplied_param = None + # find all the parameters we will need to build in the URL + # matched_params = re.findall(self.router.parameter_pattern, uri) + route.finalize_params() + for params in route.params.values(): + # name, _type, pattern = self.router.parse_parameter_string(match) + # we only want to match against each individual parameter - # if name in kwargs: - # supplied_param = kwargs.get(name) - # del kwargs[name] - # else: - # raise URLBuildError( - # f"Required parameter `{name}` was not passed to url_for" - # ) + for idx, param_info in enumerate(params): + try: + supplied_param = str(kwargs.pop(param_info.name)) + except KeyError: + raise URLBuildError( + f"Required parameter `{param_info.name}` was not " + "passed to url_for" + ) - # supplied_param = str(supplied_param) - # # determine if the parameter supplied by the caller passes the test - # # in the URL - # passes_pattern = re.match(specific_pattern, supplied_param) + # determine if the parameter supplied by the caller + # passes the test in the URL + if param_info.pattern: + passes_pattern = param_info.pattern.match(supplied_param) + if not passes_pattern: + if idx + 1 == len(params): + if param_info.cast != str: + msg = ( + f'Value "{supplied_param}" ' + f"for parameter `{param_info.name}` does " + "not match pattern for type " + f"`{param_info.cast.__name__}`: " + f"{param_info.pattern.pattern}" + ) + else: + msg = ( + f'Value "{supplied_param}" for parameter ' + f"`{param_info.name}` does not satisfy " + f"pattern {param_info.pattern.pattern}" + ) + raise URLBuildError(msg) + else: + continue - # if not passes_pattern: - # if _type != str: - # type_name = _type.__name__ - - # msg = ( - # f'Value "{supplied_param}" ' - # f"for parameter `{name}` does not " - # f"match pattern for type `{type_name}`: {pattern}" - # ) - # else: - # msg = ( - # f'Value "{supplied_param}" for parameter `{name}` ' - # f"does not satisfy pattern {pattern}" - # ) - # raise URLBuildError(msg) - - # # replace the parameter in the URL with the supplied value - # replacement_regex = f"(<{name}.*?>)" - - # out = re.sub(replacement_regex, supplied_param, out) + # replace the parameter in the URL with the supplied value + replacement_regex = f"(<{param_info.name}.*?>)" + out = re.sub(replacement_regex, supplied_param, out) # parse the remainder of the keyword arguments into a querystring query_string = urlencode(kwargs, doseq=True) if kwargs else "" @@ -845,9 +868,6 @@ class Sanic(BaseSanic): await result async def _run_request_middleware(self, request, request_name=None): - print(self.request_middleware) - print(self.named_request_middleware) - print(request_name) # The if improves speed. I don't know why named_middleware = self.named_request_middleware.get( request_name, deque() diff --git a/sanic/blueprints.py b/sanic/blueprints.py index ba1b1951..e8b33410 100644 --- a/sanic/blueprints.py +++ b/sanic/blueprints.py @@ -109,22 +109,35 @@ class Blueprint(BaseSanic): # Prepend the blueprint URI prefix if available uri = url_prefix + future.uri if url_prefix else future.uri + strict_slashes = ( + self.strict_slashes + if future.strict_slashes is None + and self.strict_slashes is not None + else future.strict_slashes + ) + + print(uri, strict_slashes) + apply_route = FutureRoute( future.handler, uri[1:] if uri.startswith("//") else uri, future.methods, future.host or self.host, - future.strict_slashes, + strict_slashes, future.stream, future.version or self.version, future.name, future.ignore_body, future.websocket, future.subprotocols, + future.unquote, + future.static, ) route = app._apply_route(apply_route) - operation = routes.extend if isinstance(route, list) else routes.append + operation = ( + routes.extend if isinstance(route, list) else routes.append + ) operation(route) # Static Files @@ -149,6 +162,3 @@ class Blueprint(BaseSanic): # Event listeners for listener in self._future_listeners: app._apply_listener(listener) - - def _generate_name(self, handler, name: str) -> str: - return f"{self.name}.{name or handler.__name__}" diff --git a/sanic/mixins/routes.py b/sanic/mixins/routes.py index e8a09a53..8fc08707 100644 --- a/sanic/mixins/routes.py +++ b/sanic/mixins/routes.py @@ -36,6 +36,8 @@ class RouteMixin: apply=True, subprotocols=None, websocket=False, + unquote=False, + static=False, ): """Create a blueprint route from a decorated function. @@ -74,21 +76,28 @@ class RouteMixin: nonlocal ignore_body nonlocal subprotocols nonlocal websocket + nonlocal static if isinstance(handler, tuple): # if a handler fn is already wrapped in a route, the handler # variable will be a tuple of (existing routes, handler fn) _, handler = handler - # TODO: - # - THink this thru.... do we want all routes namespaced? - # - - name = self._generate_name(handler, name) + name = self._generate_name(name, handler) if isinstance(host, str): host = frozenset([host]) elif host and not isinstance(host, frozenset): - host = frozenset(host) + try: + host = frozenset(host) + except TypeError: + raise ValueError( + "Expected either string or Iterable of host strings, " + "not %s" % host + ) + + if isinstance(subprotocols, (list, tuple, set)): + subprotocols = frozenset(subprotocols) route = FutureRoute( handler, @@ -102,6 +111,8 @@ class RouteMixin: ignore_body, websocket, subprotocols, + unquote, + static, ) self._future_routes.add(route) @@ -499,12 +510,16 @@ class RouteMixin: :rtype: List[sanic.router.Route] """ - if not name.startswith(self.name + "."): - name = f"{self.name}.{name}" + name = self._generate_name(name) if strict_slashes is None and self.strict_slashes is not None: strict_slashes = self.strict_slashes + if not isinstance(file_or_directory, (str, bytes, PurePath)): + raise ValueError( + f"Static route must be a valid path, not {file_or_directory}" + ) + static = FutureStatic( uri, file_or_directory, @@ -522,5 +537,25 @@ class RouteMixin: if apply: self._apply_static(static) - def _generate_name(self, handler, name: str) -> str: - return name or handler.__name__ + def _generate_name(self, *objects) -> str: + name = None + for obj in objects: + if obj: + if isinstance(obj, str): + name = obj + break + + try: + name = obj.__name__ + except AttributeError: + continue + else: + break + + if not name: + raise Exception("...") + + if not name.startswith(f"{self.name}."): + name = f"{self.name}.{name}" + + return name diff --git a/sanic/models/futures.py b/sanic/models/futures.py index dc48d0db..4ffa13bb 100644 --- a/sanic/models/futures.py +++ b/sanic/models/futures.py @@ -15,6 +15,8 @@ FutureRoute = namedtuple( "ignore_body", "websocket", "subprotocols", + "unquote", + "static", ], ) FutureListener = namedtuple("FutureListener", ["listener", "event"]) diff --git a/sanic/router.py b/sanic/router.py index e56727c5..910b0bfd 100644 --- a/sanic/router.py +++ b/sanic/router.py @@ -1,7 +1,7 @@ from functools import lru_cache from typing import FrozenSet, Iterable, List, Optional, Union -from sanic_routing import BaseRouter, route +from sanic_routing import BaseRouter from sanic_routing.exceptions import NoMethod from sanic_routing.exceptions import NotFound as RoutingNotFound from sanic_routing.route import Route @@ -37,7 +37,7 @@ class Router(BaseRouter): route, handler, params = self.resolve( path=request.path, method=request.method, - extra={"host": request.headers.get("host")} + extra={"host": request.headers.get("host")}, ) except RoutingNotFound as e: raise NotFound("Requested URL {} not found".format(e.path)) @@ -75,6 +75,8 @@ class Router(BaseRouter): ignore_body: bool = False, version: Union[str, float, int] = None, name: Optional[str] = None, + unquote: bool = False, + static: bool = False, ) -> Union[Route, List[Route]]: """ Add a handler to the router @@ -118,6 +120,7 @@ class Router(BaseRouter): methods=methods, name=name, strict=strict_slashes, + unquote=unquote, ) if isinstance(host, str): @@ -134,6 +137,8 @@ class Router(BaseRouter): route = super().add(**params) route.ctx.ignore_body = ignore_body route.ctx.stream = stream + route.ctx.hosts = hosts + route.ctx.static = static routes.append(route) @@ -168,15 +173,19 @@ class Router(BaseRouter): :return: tuple containing (uri, Route) """ if not view_name: - return None, None + return None - if view_name == "static" or view_name.endswith(".static"): - looking_for = f"_static_{name}" - route = self.name_index.get(looking_for) - else: - route = self.name_index.get(view_name) + name = self.ctx.app._generate_name(view_name) + route = self.name_index.get(name) if not route: - return None, None + return None - return route.path, route + return route + + @property + def routes_all(self): + return { + **self.static_routes, + **self.dynamic_routes, + } diff --git a/sanic/static.py b/sanic/static.py index 52db9c1c..6396c26a 100644 --- a/sanic/static.py +++ b/sanic/static.py @@ -6,6 +6,8 @@ from re import sub from time import gmtime, strftime from urllib.parse import unquote +from sanic_routing.patterns import REGEX_TYPES + from sanic.compat import stat_async from sanic.exceptions import ( ContentRangeError, @@ -157,11 +159,11 @@ def register( # If we're not trying to match a file directly, # serve from the folder if not path.isfile(file_or_directory): - uri += "" + uri += "/" # special prefix for static files - if not static.name.startswith("_static_"): - name = f"_static_{static.name}" + # if not static.name.startswith("_static_"): + # name = f"_static_{static.name}" _handler = wraps(_static_request_handler)( partial( @@ -174,11 +176,13 @@ def register( ) ) - _routes, _ = app.route( + route, _ = app.route( uri=uri, methods=["GET", "HEAD"], name=name, host=static.host, strict_slashes=static.strict_slashes, + static=True, )(_handler) - return _routes + + return route diff --git a/tests/test_asgi.py b/tests/test_asgi.py index 74073b4a..6a019e9b 100644 --- a/tests/test_asgi.py +++ b/tests/test_asgi.py @@ -304,24 +304,18 @@ async def test_cookie_customization(app): _, response = await app.asgi_client.get("/cookie") CookieDef = namedtuple("CookieDef", ("value", "httponly")) - Cookie = namedtuple("Cookie", ("domain", "path", "value", "httponly")) cookie_map = { "test": CookieDef("Cookie1", True), "c2": CookieDef("Cookie2", False), } - cookies = { - c.name: Cookie(c.domain, c.path, c.value, "HttpOnly" in c._rest.keys()) - for c in response.cookies.jar - } - for name, definition in cookie_map.items(): - cookie = cookies.get(name) + cookie = response.cookies.get(name) assert cookie assert cookie.value == definition.value - assert cookie.domain == "mockserver.local" - assert cookie.path == "/" - assert cookie.httponly == definition.httponly + assert cookie.get("domain") == "mockserver.local" + assert cookie.get("path") == "/" + assert cookie.get("httponly", False) == definition.httponly @pytest.mark.asyncio diff --git a/tests/test_blueprints.py b/tests/test_blueprints.py index 0ec821bf..f9a01b3b 100644 --- a/tests/test_blueprints.py +++ b/tests/test_blueprints.py @@ -197,7 +197,12 @@ def test_several_bp_with_url_prefix(app): def test_bp_with_host(app): - bp = Blueprint("test_bp_host", url_prefix="/test1", host="example.com") + bp = Blueprint( + "test_bp_host", + url_prefix="/test1", + host="example.com", + strict_slashes=True, + ) @bp.route("/") def handler1(request): @@ -209,18 +214,29 @@ def test_bp_with_host(app): app.blueprint(bp) headers = {"Host": "example.com"} + app.router.finalize() + request, response = app.test_client.get("/test1/", headers=headers) assert response.body == b"Hello" headers = {"Host": "sub.example.com"} request, response = app.test_client.get("/test1/", headers=headers) - print(app.router.find_route_src) assert response.body == b"Hello subdomain!" def test_several_bp_with_host(app): - bp = Blueprint("test_text", url_prefix="/test", host="example.com") - bp2 = Blueprint("test_text2", url_prefix="/test", host="sub.example.com") + bp = Blueprint( + "test_text", + url_prefix="/test", + host="example.com", + strict_slashes=True, + ) + bp2 = Blueprint( + "test_text2", + url_prefix="/test", + host="sub.example.com", + strict_slashes=True, + ) @bp.route("/") def handler(request): @@ -449,6 +465,7 @@ def test_bp_exception_handler(app): def test_bp_listeners(app): + app.route("/")(lambda x: x) blueprint = Blueprint("test_middleware") order = [] @@ -723,7 +740,8 @@ def test_blueprint_middleware_with_args(app: Sanic): @pytest.mark.parametrize("file_name", ["test.file"]) -def test_static_blueprint_name(app: Sanic, static_file_directory, file_name): +def test_static_blueprint_name(static_file_directory, file_name): + app = Sanic("app") current_file = inspect.getfile(inspect.currentframe()) with open(current_file, "rb") as file: file.read() @@ -738,9 +756,6 @@ def test_static_blueprint_name(app: Sanic, static_file_directory, file_name): ) app.blueprint(bp) - print(app.router.name_index) - print(app.router.static_routes) - print(app.router.dynamic_routes) uri = app.url_for("static", name="static.testing") assert uri == "/static/test.file" @@ -841,18 +856,19 @@ def test_duplicate_blueprint(app): ) -def test_strict_slashes_behavior_adoption(app): +def test_strict_slashes_behavior_adoption(): + app = Sanic("app") app.strict_slashes = True + bp = Blueprint("bp") + bp2 = Blueprint("bp2", strict_slashes=False) @app.get("/test") def handler_test(request): return text("Test") - assert app.test_client.get("/test")[1].status == 200 - assert app.test_client.get("/test/")[1].status == 404 - - app.router.finalized = False - bp = Blueprint("bp") + @app.get("/f1", strict_slashes=False) + def f1(request): + return text("f1") @bp.get("/one", strict_slashes=False) def one(request): @@ -862,7 +878,15 @@ def test_strict_slashes_behavior_adoption(app): def second(request): return text("second") + @bp2.get("/third") + def third(request): + return text("third") + app.blueprint(bp) + app.blueprint(bp2) + + assert app.test_client.get("/test")[1].status == 200 + assert app.test_client.get("/test/")[1].status == 404 assert app.test_client.get("/one")[1].status == 200 assert app.test_client.get("/one/")[1].status == 200 @@ -870,19 +894,8 @@ def test_strict_slashes_behavior_adoption(app): assert app.test_client.get("/second")[1].status == 200 assert app.test_client.get("/second/")[1].status == 404 - bp2 = Blueprint("bp2", strict_slashes=False) - - @bp2.get("/third") - def third(request): - return text("third") - - app.blueprint(bp2) assert app.test_client.get("/third")[1].status == 200 assert app.test_client.get("/third/")[1].status == 200 - @app.get("/f1", strict_slashes=False) - def f1(request): - return text("f1") - assert app.test_client.get("/f1")[1].status == 200 assert app.test_client.get("/f1/")[1].status == 200 diff --git a/tests/test_routes.py b/tests/test_routes.py index e514bcd9..4ddbf62f 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -1,19 +1,176 @@ -# import asyncio +import asyncio -# import pytest +from unittest.mock import Mock +import pytest + +from sanic_routing.exceptions import ParameterNameConflicts, RouteExists from sanic_testing.testing import SanicTestClient -from sanic import Sanic +from sanic import Blueprint, Sanic from sanic.constants import HTTP_METHODS +from sanic.exceptions import NotFound +from sanic.request import Request from sanic.response import json, text -from sanic.router import ParameterNameConflicts, RouteDoesNotExist, RouteExists -# from sanic import Sanic -# from sanic.constants import HTTP_METHODS -# from sanic.response import json, text -# from sanic.router import ParameterNameConflicts, RouteDoesNotExist, RouteExists +@pytest.mark.parametrize( + "path,headers,expected", + ( + # app base + (b"/", {}, 200), + (b"/", {"host": "maybe.com"}, 200), + (b"/host", {"host": "matching.com"}, 200), + (b"/host", {"host": "wrong.com"}, 404), + # app strict_slashes default + (b"/without", {}, 200), + (b"/without/", {}, 200), + (b"/with", {}, 200), + (b"/with/", {}, 200), + # app strict_slashes off - expressly + (b"/expwithout", {}, 200), + (b"/expwithout/", {}, 200), + (b"/expwith", {}, 200), + (b"/expwith/", {}, 200), + # app strict_slashes on + (b"/without/strict", {}, 200), + (b"/without/strict/", {}, 404), + (b"/with/strict", {}, 404), + (b"/with/strict/", {}, 200), + # bp1 base + (b"/bp1", {}, 200), + (b"/bp1", {"host": "maybe.com"}, 200), + (b"/bp1/host", {"host": "matching.com"}, 200), # BROKEN ON MASTER + (b"/bp1/host", {"host": "wrong.com"}, 404), + # bp1 strict_slashes default + (b"/bp1/without", {}, 200), + (b"/bp1/without/", {}, 200), + (b"/bp1/with", {}, 200), + (b"/bp1/with/", {}, 200), + # bp1 strict_slashes off - expressly + (b"/bp1/expwithout", {}, 200), + (b"/bp1/expwithout/", {}, 200), + (b"/bp1/expwith", {}, 200), + (b"/bp1/expwith/", {}, 200), + # bp1 strict_slashes on + (b"/bp1/without/strict", {}, 200), + (b"/bp1/without/strict/", {}, 404), + (b"/bp1/with/strict", {}, 404), + (b"/bp1/with/strict/", {}, 200), + # bp2 base + (b"/bp2/", {}, 200), + (b"/bp2/", {"host": "maybe.com"}, 200), + (b"/bp2/host", {"host": "matching.com"}, 200), # BROKEN ON MASTER + (b"/bp2/host", {"host": "wrong.com"}, 404), + # bp2 strict_slashes default + (b"/bp2/without", {}, 200), + (b"/bp2/without/", {}, 404), + (b"/bp2/with", {}, 404), + (b"/bp2/with/", {}, 200), + # # bp2 strict_slashes off - expressly + (b"/bp2/expwithout", {}, 200), + (b"/bp2/expwithout/", {}, 200), + (b"/bp2/expwith", {}, 200), + (b"/bp2/expwith/", {}, 200), + # # bp2 strict_slashes on + (b"/bp2/without/strict", {}, 200), + (b"/bp2/without/strict/", {}, 404), + (b"/bp2/with/strict", {}, 404), + (b"/bp2/with/strict/", {}, 200), + # bp3 base + (b"/bp3", {}, 200), + (b"/bp3", {"host": "maybe.com"}, 200), + (b"/bp3/host", {"host": "matching.com"}, 200), # BROKEN ON MASTER + (b"/bp3/host", {"host": "wrong.com"}, 404), + # bp3 strict_slashes default + (b"/bp3/without", {}, 200), + (b"/bp3/without/", {}, 200), + (b"/bp3/with", {}, 200), + (b"/bp3/with/", {}, 200), + # bp3 strict_slashes off - expressly + (b"/bp3/expwithout", {}, 200), + (b"/bp3/expwithout/", {}, 200), + (b"/bp3/expwith", {}, 200), + (b"/bp3/expwith/", {}, 200), + # bp3 strict_slashes on + (b"/bp3/without/strict", {}, 200), + (b"/bp3/without/strict/", {}, 404), + (b"/bp3/with/strict", {}, 404), + (b"/bp3/with/strict/", {}, 200), + # bp4 base + (b"/bp4", {}, 404), + (b"/bp4", {"host": "maybe.com"}, 200), + (b"/bp4/host", {"host": "matching.com"}, 200), # BROKEN ON MASTER + (b"/bp4/host", {"host": "wrong.com"}, 404), + # bp4 strict_slashes default + (b"/bp4/without", {}, 404), + (b"/bp4/without/", {}, 404), + (b"/bp4/with", {}, 404), + (b"/bp4/with/", {}, 404), + # bp4 strict_slashes off - expressly + (b"/bp4/expwithout", {}, 404), + (b"/bp4/expwithout/", {}, 404), + (b"/bp4/expwith", {}, 404), + (b"/bp4/expwith/", {}, 404), + # bp4 strict_slashes on + (b"/bp4/without/strict", {}, 404), + (b"/bp4/without/strict/", {}, 404), + (b"/bp4/with/strict", {}, 404), + (b"/bp4/with/strict/", {}, 404), + ), +) +def test_matching(path, headers, expected): + app = Sanic("dev") + bp1 = Blueprint("bp1", url_prefix="/bp1") + bp2 = Blueprint("bp2", url_prefix="/bp2", strict_slashes=True) + bp3 = Blueprint("bp3", url_prefix="/bp3", strict_slashes=False) + bp4 = Blueprint("bp4", url_prefix="/bp4", host="maybe.com") + + def handler(request): + return text("Hello!") + + defs = ( + ("/", None, None), + ("/host", None, "matching.com"), + ("/without", None, None), + ("/with/", None, None), + ("/expwithout", False, None), + ("/expwith/", False, None), + ("/without/strict", True, None), + ("/with/strict/", True, None), + ) + for uri, strict_slashes, host in defs: + params = {"uri": uri} + if strict_slashes is not None: + params["strict_slashes"] = strict_slashes + if host is not None: + params["host"] = host + app.route(**params)(handler) + bp1.route(**params)(handler) + bp2.route(**params)(handler) + bp3.route(**params)(handler) + bp4.route(**params)(handler) + + app.blueprint(bp1) + app.blueprint(bp2) + app.blueprint(bp3) + app.blueprint(bp4) + + app.router.finalize() + print(app.router.static_routes) + + request = Request(path, headers, None, "GET", None, app) + + try: + print(app.router.get(request=request)) + except NotFound: + response = 404 + except Exception as e: + response = 500 + else: + response = 200 + + assert response == expected # # ------------------------------------------------------------ # @@ -21,393 +178,400 @@ from sanic.router import ParameterNameConflicts, RouteDoesNotExist, RouteExists # # ------------------------------------------------------------ # -# @pytest.mark.parametrize("method", HTTP_METHODS) -# def test_versioned_routes_get(app, method): -# method = method.lower() +@pytest.mark.parametrize("method", HTTP_METHODS) +def test_versioned_routes_get(app, method): + method = method.lower() -# func = getattr(app, method) -# if callable(func): + func = getattr(app, method) + if callable(func): -# @func(f"/{method}", version=1) -# def handler(request): -# return text("OK") + @func(f"/{method}", version=1) + def handler(request): + return text("OK") -# else: -# print(func) -# raise Exception(f"Method: {method} is not callable") + else: + print(func) + raise Exception(f"Method: {method} is not callable") -# client_method = getattr(app.test_client, method) + client_method = getattr(app.test_client, method) -# request, response = client_method(f"/v1/{method}") -# assert response.status == 200 + request, response = client_method(f"/v1/{method}") + assert response.status == 200 -# def test_shorthand_routes_get(app): -# @app.get("/get") -# def handler(request): -# return text("OK") +def test_shorthand_routes_get(app): + @app.get("/get") + def handler(request): + return text("OK") -# request, response = app.test_client.get("/get") -# assert response.text == "OK" + request, response = app.test_client.get("/get") + assert response.text == "OK" -# request, response = app.test_client.post("/get") -# assert response.status == 405 + request, response = app.test_client.post("/get") + assert response.status == 405 -# def test_shorthand_routes_multiple(app): -# @app.get("/get") -# def get_handler(request): -# return text("OK") +def test_shorthand_routes_multiple(app): + @app.get("/get") + def get_handler(request): + return text("OK") -# @app.options("/get") -# def options_handler(request): -# return text("") + @app.options("/get") + def options_handler(request): + return text("") -# request, response = app.test_client.get("/get/") -# assert response.status == 200 -# assert response.text == "OK" + request, response = app.test_client.get("/get/") + assert response.status == 200 + assert response.text == "OK" -# request, response = app.test_client.options("/get/") -# assert response.status == 200 + request, response = app.test_client.options("/get/") + assert response.status == 200 -# def test_route_strict_slash(app): -# @app.get("/get", strict_slashes=True) -# def handler1(request): -# return text("OK") +def test_route_strict_slash(app): + @app.get("/get", strict_slashes=True) + def handler1(request): + return text("OK") -# @app.post("/post/", strict_slashes=True) -# def handler2(request): -# return text("OK") + @app.post("/post/", strict_slashes=True) + def handler2(request): + return text("OK") -# request, response = app.test_client.get("/get") -# assert response.text == "OK" + request, response = app.test_client.get("/get") + assert response.text == "OK" -# request, response = app.test_client.get("/get/") -# assert response.status == 404 + request, response = app.test_client.get("/get/") + assert response.status == 404 -# request, response = app.test_client.post("/post/") -# assert response.text == "OK" + request, response = app.test_client.post("/post/") + assert response.text == "OK" -# request, response = app.test_client.post("/post") -# assert response.status == 404 + request, response = app.test_client.post("/post") + assert response.status == 404 -# def test_route_invalid_parameter_syntax(app): -# with pytest.raises(ValueError): +def test_route_invalid_parameter_syntax(app): + with pytest.raises(ValueError): -# @app.get("/get/<:string>", strict_slashes=True) -# def handler(request): -# return text("OK") + @app.get("/get/<:string>", strict_slashes=True) + def handler(request): + return text("OK") -# request, response = app.test_client.get("/get") + request, response = app.test_client.get("/get") -# def test_route_strict_slash_default_value(): -# app = Sanic("test_route_strict_slash", strict_slashes=True) +def test_route_strict_slash_default_value(): + app = Sanic("test_route_strict_slash", strict_slashes=True) -# @app.get("/get") -# def handler(request): -# return text("OK") + @app.get("/get") + def handler(request): + return text("OK") -# request, response = app.test_client.get("/get/") -# assert response.status == 404 + request, response = app.test_client.get("/get/") + assert response.status == 404 -# def test_route_strict_slash_without_passing_default_value(app): -# @app.get("/get") -# def handler(request): -# return text("OK") +def test_route_strict_slash_without_passing_default_value(app): + @app.get("/get") + def handler(request): + return text("OK") -# request, response = app.test_client.get("/get/") -# assert response.text == "OK" + request, response = app.test_client.get("/get/") + assert response.text == "OK" -# def test_route_strict_slash_default_value_can_be_overwritten(): -# app = Sanic("test_route_strict_slash", strict_slashes=True) +def test_route_strict_slash_default_value_can_be_overwritten(): + app = Sanic("test_route_strict_slash", strict_slashes=True) -# @app.get("/get", strict_slashes=False) -# def handler(request): -# return text("OK") + @app.get("/get", strict_slashes=False) + def handler(request): + return text("OK") -# request, response = app.test_client.get("/get/") -# assert response.text == "OK" + request, response = app.test_client.get("/get/") + assert response.text == "OK" -# def test_route_slashes_overload(app): -# @app.get("/hello/") -# def handler_get(request): -# return text("OK") +def test_route_slashes_overload(app): + @app.get("/hello/") + def handler_get(request): + return text("OK") -# @app.post("/hello/") -# def handler_post(request): -# return text("OK") + @app.post("/hello/") + def handler_post(request): + return text("OK") -# request, response = app.test_client.get("/hello") -# assert response.text == "OK" + request, response = app.test_client.get("/hello") + assert response.text == "OK" -# request, response = app.test_client.get("/hello/") -# assert response.text == "OK" + request, response = app.test_client.get("/hello/") + assert response.text == "OK" -# request, response = app.test_client.post("/hello") -# assert response.text == "OK" + request, response = app.test_client.post("/hello") + assert response.text == "OK" -# request, response = app.test_client.post("/hello/") -# assert response.text == "OK" + request, response = app.test_client.post("/hello/") + assert response.text == "OK" -# def test_route_optional_slash(app): -# @app.get("/get") -# def handler(request): -# return text("OK") +def test_route_optional_slash(app): + @app.get("/get") + def handler(request): + return text("OK") -# request, response = app.test_client.get("/get") -# assert response.text == "OK" + request, response = app.test_client.get("/get") + assert response.text == "OK" -# request, response = app.test_client.get("/get/") -# assert response.text == "OK" + request, response = app.test_client.get("/get/") + assert response.text == "OK" -# def test_route_strict_slashes_set_to_false_and_host_is_a_list(app): -# # Part of regression test for issue #1120 +def test_route_strict_slashes_set_to_false_and_host_is_a_list(app): + # Part of regression test for issue #1120 + test_client = SanicTestClient(app, port=42101) + site1 = f"127.0.0.1:{test_client.port}" -# test_client = SanicTestClient(app, port=42101) -# site1 = f"127.0.0.1:{test_client.port}" + # before fix, this raises a RouteExists error + @app.get("/get", host=[site1, "site2.com"], strict_slashes=False) + def get_handler(request): + return text("OK") -# # before fix, this raises a RouteExists error -# @app.get("/get", host=[site1, "site2.com"], strict_slashes=False) -# def get_handler(request): -# return text("OK") + request, response = test_client.get("http://" + site1 + "/get") + assert response.text == "OK" -# request, response = test_client.get("http://" + site1 + "/get") -# assert response.text == "OK" + app.router.finalized = False -# @app.post("/post", host=[site1, "site2.com"], strict_slashes=False) -# def post_handler(request): -# return text("OK") + @app.post("/post", host=[site1, "site2.com"], strict_slashes=False) + def post_handler(request): + return text("OK") -# request, response = test_client.post("http://" + site1 + "/post") -# assert response.text == "OK" + request, response = test_client.post("http://" + site1 + "/post") + assert response.text == "OK" -# @app.put("/put", host=[site1, "site2.com"], strict_slashes=False) -# def put_handler(request): -# return text("OK") + app.router.finalized = False -# request, response = test_client.put("http://" + site1 + "/put") -# assert response.text == "OK" + @app.put("/put", host=[site1, "site2.com"], strict_slashes=False) + def put_handler(request): + return text("OK") -# @app.delete("/delete", host=[site1, "site2.com"], strict_slashes=False) -# def delete_handler(request): -# return text("OK") + request, response = test_client.put("http://" + site1 + "/put") + assert response.text == "OK" -# request, response = test_client.delete("http://" + site1 + "/delete") -# assert response.text == "OK" + app.router.finalized = False + @app.delete("/delete", host=[site1, "site2.com"], strict_slashes=False) + def delete_handler(request): + return text("OK") -# def test_shorthand_routes_post(app): -# @app.post("/post") -# def handler(request): -# return text("OK") + request, response = test_client.delete("http://" + site1 + "/delete") + assert response.text == "OK" -# request, response = app.test_client.post("/post") -# assert response.text == "OK" -# request, response = app.test_client.get("/post") -# assert response.status == 405 +def test_shorthand_routes_post(app): + @app.post("/post") + def handler(request): + return text("OK") + request, response = app.test_client.post("/post") + assert response.text == "OK" -# def test_shorthand_routes_put(app): -# @app.put("/put") -# def handler(request): -# return text("OK") + request, response = app.test_client.get("/post") + assert response.status == 405 -# request, response = app.test_client.put("/put") -# assert response.text == "OK" -# request, response = app.test_client.get("/put") -# assert response.status == 405 +def test_shorthand_routes_put(app): + @app.put("/put") + def handler(request): + return text("OK") + request, response = app.test_client.put("/put") + assert response.text == "OK" -# def test_shorthand_routes_delete(app): -# @app.delete("/delete") -# def handler(request): -# return text("OK") + request, response = app.test_client.get("/put") + assert response.status == 405 -# request, response = app.test_client.delete("/delete") -# assert response.text == "OK" -# request, response = app.test_client.get("/delete") -# assert response.status == 405 +def test_shorthand_routes_delete(app): + @app.delete("/delete") + def handler(request): + return text("OK") + request, response = app.test_client.delete("/delete") + assert response.text == "OK" -# def test_shorthand_routes_patch(app): -# @app.patch("/patch") -# def handler(request): -# return text("OK") + request, response = app.test_client.get("/delete") + assert response.status == 405 -# request, response = app.test_client.patch("/patch") -# assert response.text == "OK" -# request, response = app.test_client.get("/patch") -# assert response.status == 405 +def test_shorthand_routes_patch(app): + @app.patch("/patch") + def handler(request): + return text("OK") + request, response = app.test_client.patch("/patch") + assert response.text == "OK" -# def test_shorthand_routes_head(app): -# @app.head("/head") -# def handler(request): -# return text("OK") + request, response = app.test_client.get("/patch") + assert response.status == 405 -# request, response = app.test_client.head("/head") -# assert response.status == 200 -# request, response = app.test_client.get("/head") -# assert response.status == 405 +def test_shorthand_routes_head(app): + @app.head("/head") + def handler(request): + return text("OK") + request, response = app.test_client.head("/head") + assert response.status == 200 -# def test_shorthand_routes_options(app): -# @app.options("/options") -# def handler(request): -# return text("OK") + request, response = app.test_client.get("/head") + assert response.status == 405 -# request, response = app.test_client.options("/options") -# assert response.status == 200 -# request, response = app.test_client.get("/options") -# assert response.status == 405 +def test_shorthand_routes_options(app): + @app.options("/options") + def handler(request): + return text("OK") + request, response = app.test_client.options("/options") + assert response.status == 200 -# def test_static_routes(app): -# @app.route("/test") -# async def handler1(request): -# return text("OK1") + request, response = app.test_client.get("/options") + assert response.status == 405 -# @app.route("/pizazz") -# async def handler2(request): -# return text("OK2") -# request, response = app.test_client.get("/test") -# assert response.text == "OK1" +def test_static_routes(app): + @app.route("/test") + async def handler1(request): + return text("OK1") -# request, response = app.test_client.get("/pizazz") -# assert response.text == "OK2" + @app.route("/pizazz") + async def handler2(request): + return text("OK2") + request, response = app.test_client.get("/test") + assert response.text == "OK1" -# def test_dynamic_route(app): -# results = [] + request, response = app.test_client.get("/pizazz") + assert response.text == "OK2" -# @app.route("/folder/") -# async def handler(request, name): -# results.append(name) -# return text("OK") -# request, response = app.test_client.get("/folder/test123") +def test_dynamic_route(app): + results = [] -# assert response.text == "OK" -# assert results[0] == "test123" + @app.route("/folder/") + async def handler(request, name): + results.append(name) + return text("OK") + app.router.finalize(False) -# def test_dynamic_route_string(app): -# results = [] + request, response = app.test_client.get("/folder/test123") -# @app.route("/folder/") -# async def handler(request, name): -# results.append(name) -# return text("OK") + assert response.text == "OK" + assert results[0] == "test123" -# request, response = app.test_client.get("/folder/test123") -# assert response.text == "OK" -# assert results[0] == "test123" +def test_dynamic_route_string(app): + results = [] -# request, response = app.test_client.get("/folder/favicon.ico") + @app.route("/folder/") + async def handler(request, name): + results.append(name) + return text("OK") -# assert response.text == "OK" -# assert results[1] == "favicon.ico" + request, response = app.test_client.get("/folder/test123") + assert response.text == "OK" + assert results[0] == "test123" -# def test_dynamic_route_int(app): -# results = [] + request, response = app.test_client.get("/folder/favicon.ico") -# @app.route("/folder/") -# async def handler(request, folder_id): -# results.append(folder_id) -# return text("OK") + assert response.text == "OK" + assert results[1] == "favicon.ico" -# request, response = app.test_client.get("/folder/12345") -# assert response.text == "OK" -# assert type(results[0]) is int -# request, response = app.test_client.get("/folder/asdf") -# assert response.status == 404 +def test_dynamic_route_int(app): + results = [] + @app.route("/folder/") + async def handler(request, folder_id): + results.append(folder_id) + return text("OK") -# def test_dynamic_route_number(app): -# results = [] + request, response = app.test_client.get("/folder/12345") + assert response.text == "OK" + assert type(results[0]) is int -# @app.route("/weight/") -# async def handler(request, weight): -# results.append(weight) -# return text("OK") + request, response = app.test_client.get("/folder/asdf") + assert response.status == 404 -# request, response = app.test_client.get("/weight/12345") -# assert response.text == "OK" -# assert type(results[0]) is float -# request, response = app.test_client.get("/weight/1234.56") -# assert response.status == 200 +def test_dynamic_route_number(app): + results = [] -# request, response = app.test_client.get("/weight/.12") -# assert response.status == 200 + @app.route("/weight/") + async def handler(request, weight): + results.append(weight) + return text("OK") -# request, response = app.test_client.get("/weight/12.") -# assert response.status == 200 + request, response = app.test_client.get("/weight/12345") + assert response.text == "OK" + assert type(results[0]) is float -# request, response = app.test_client.get("/weight/1234-56") -# assert response.status == 404 + request, response = app.test_client.get("/weight/1234.56") + assert response.status == 200 -# request, response = app.test_client.get("/weight/12.34.56") -# assert response.status == 404 + request, response = app.test_client.get("/weight/.12") + assert response.status == 200 + request, response = app.test_client.get("/weight/12.") + assert response.status == 200 -# def test_dynamic_route_regex(app): -# @app.route("/folder/") -# async def handler(request, folder_id): -# return text("OK") + request, response = app.test_client.get("/weight/1234-56") + assert response.status == 404 -# request, response = app.test_client.get("/folder/test") -# assert response.status == 200 + request, response = app.test_client.get("/weight/12.34.56") + assert response.status == 404 -# request, response = app.test_client.get("/folder/test1") -# assert response.status == 404 -# request, response = app.test_client.get("/folder/test-123") -# assert response.status == 404 +def test_dynamic_route_regex(app): + @app.route("/folder/") + async def handler(request, folder_id): + return text("OK") -# request, response = app.test_client.get("/folder/") -# assert response.status == 200 + request, response = app.test_client.get("/folder/test") + assert response.status == 200 + request, response = app.test_client.get("/folder/test1") + assert response.status == 404 -# def test_dynamic_route_uuid(app): -# import uuid + request, response = app.test_client.get("/folder/test-123") + assert response.status == 404 -# results = [] + request, response = app.test_client.get("/folder/") + assert response.status == 200 -# @app.route("/quirky/") -# async def handler(request, unique_id): -# results.append(unique_id) -# return text("OK") -# url = "/quirky/123e4567-e89b-12d3-a456-426655440000" -# request, response = app.test_client.get(url) -# assert response.text == "OK" -# assert type(results[0]) is uuid.UUID +def test_dynamic_route_uuid(app): + import uuid -# generated_uuid = uuid.uuid4() -# request, response = app.test_client.get(f"/quirky/{generated_uuid}") -# assert response.status == 200 + results = [] -# request, response = app.test_client.get("/quirky/non-existing") -# assert response.status == 404 + @app.route("/quirky/") + async def handler(request, unique_id): + results.append(unique_id) + return text("OK") + + url = "/quirky/123e4567-e89b-12d3-a456-426655440000" + request, response = app.test_client.get(url) + assert response.text == "OK" + assert type(results[0]) is uuid.UUID + + generated_uuid = uuid.uuid4() + request, response = app.test_client.get(f"/quirky/{generated_uuid}") + assert response.status == 200 + + request, response = app.test_client.get("/quirky/non-existing") + assert response.status == 404 # def test_dynamic_route_path(app): @@ -450,19 +614,19 @@ from sanic.router import ParameterNameConflicts, RouteDoesNotExist, RouteExists # assert response.status == 404 -# @pytest.mark.parametrize("url", ["/ws", "ws"]) -# def test_websocket_route(app, url): -# ev = asyncio.Event() +@pytest.mark.parametrize("url", ["/ws", "ws"]) +def test_websocket_route(app, url): + ev = asyncio.Event() -# @app.websocket(url) -# async def handler(request, ws): -# assert request.scheme == "ws" -# assert ws.subprotocol is None -# ev.set() + @app.websocket(url) + async def handler(request, ws): + assert request.scheme == "ws" + assert ws.subprotocol is None + ev.set() -# request, response = app.test_client.websocket(url) -# assert response.opened is True -# assert ev.is_set() + request, response = app.test_client.websocket(url) + assert response.opened is True + assert ev.is_set() # @pytest.mark.asyncio @@ -478,239 +642,240 @@ from sanic.router import ParameterNameConflicts, RouteDoesNotExist, RouteExists # assert ev.is_set() -# def test_websocket_route_with_subprotocols(app): -# results = [] +def test_websocket_route_with_subprotocols(app): + results = [] -# _, response = SanicTestClient(app).websocket("/ws", subprotocols=["bar"]) -# assert response.opened is True -# assert results == ["bar"] + @app.websocket("/ws", subprotocols=["foo", "bar"]) + async def handler(request, ws): + results.append(ws.subprotocol) + assert ws.subprotocol is not None -# _, response = SanicTestClient(app).websocket( -# "/ws", subprotocols=["bar", "foo"] -# ) -# assert response.opened is True -# assert results == ["bar", "bar"] + _, response = SanicTestClient(app).websocket("/ws", subprotocols=["bar"]) + assert response.opened is True + assert results == ["bar"] -# _, response = SanicTestClient(app).websocket("/ws", subprotocols=["baz"]) -# assert response.opened is True -# assert results == ["bar", "bar", None] + _, response = SanicTestClient(app).websocket( + "/ws", subprotocols=["bar", "foo"] + ) + assert response.opened is True + assert results == ["bar", "bar"] -# _, response = SanicTestClient(app).websocket("/ws") -# assert response.opened is True -# assert results == ["bar", "bar", None, None] + _, response = SanicTestClient(app).websocket("/ws", subprotocols=["baz"]) + assert response.opened is True + assert results == ["bar", "bar", None] -# _, response = SanicTestClient(app).websocket("/ws") -# assert response.opened is True -# assert results == ["bar", "bar", None, None] + _, response = SanicTestClient(app).websocket("/ws") + assert response.opened is True + assert results == ["bar", "bar", None, None] -# @pytest.mark.parametrize("strict_slashes", [True, False, None]) -# def test_add_webscoket_route(app, strict_slashes): -# ev = asyncio.Event() +@pytest.mark.parametrize("strict_slashes", [True, False, None]) +def test_add_webscoket_route(app, strict_slashes): + ev = asyncio.Event() -# async def handler(request, ws): -# assert ws.subprotocol is None -# ev.set() + async def handler(request, ws): + assert ws.subprotocol is None + ev.set() -# app.add_websocket_route(handler, "/ws", strict_slashes=strict_slashes) -# request, response = app.test_client.websocket("/ws") -# assert response.opened is True -# assert ev.is_set() + app.add_websocket_route(handler, "/ws", strict_slashes=strict_slashes) + request, response = app.test_client.websocket("/ws") + assert response.opened is True + assert ev.is_set() -# def test_add_webscoket_route_with_version(app): -# ev = asyncio.Event() +def test_add_webscoket_route_with_version(app): + ev = asyncio.Event() -# async def handler(request, ws): -# assert ws.subprotocol is None -# ev.set() + async def handler(request, ws): + assert ws.subprotocol is None + ev.set() -# app.add_websocket_route(handler, "/ws", version=1) -# request, response = app.test_client.websocket("/v1/ws") -# assert response.opened is True -# assert ev.is_set() + app.add_websocket_route(handler, "/ws", version=1) + request, response = app.test_client.websocket("/v1/ws") + assert response.opened is True + assert ev.is_set() -# def test_route_duplicate(app): +def test_route_duplicate(app): -# with pytest.raises(RouteExists): + with pytest.raises(RouteExists): -# @app.route("/test") -# async def handler1(request): -# pass + @app.route("/test") + async def handler1(request): + pass -# @app.route("/test") -# async def handler2(request): -# pass + @app.route("/test") + async def handler2(request): + pass -# with pytest.raises(RouteExists): + with pytest.raises(RouteExists): -# @app.route("/test//") -# async def handler3(request, dynamic): -# pass + @app.route("/test//") + async def handler3(request, dynamic): + pass -# @app.route("/test//") -# async def handler4(request, dynamic): -# pass + @app.route("/test//") + async def handler4(request, dynamic): + pass -# def test_double_stack_route(app): -# @app.route("/test/1") -# @app.route("/test/2") -# async def handler1(request): -# return text("OK") +def test_double_stack_route(app): + @app.route("/test/1") + @app.route("/test/2") + async def handler1(request): + return text("OK") -# request, response = app.test_client.get("/test/1") -# assert response.status == 200 -# request, response = app.test_client.get("/test/2") -# assert response.status == 200 + request, response = app.test_client.get("/test/1") + assert response.status == 200 + request, response = app.test_client.get("/test/2") + assert response.status == 200 -# @pytest.mark.asyncio -# async def test_websocket_route_asgi(app): -# ev = asyncio.Event() +@pytest.mark.asyncio +async def test_websocket_route_asgi(app): + ev = asyncio.Event() -# @app.websocket("/test/1") -# @app.websocket("/test/2") -# async def handler(request, ws): -# ev.set() + @app.websocket("/test/1") + @app.websocket("/test/2") + async def handler(request, ws): + ev.set() -# request, response = await app.asgi_client.websocket("/test/1") -# first_set = ev.is_set() -# ev.clear() -# request, response = await app.asgi_client.websocket("/test/1") -# second_set = ev.is_set() -# assert first_set and second_set + request, response = await app.asgi_client.websocket("/test/1") + first_set = ev.is_set() + ev.clear() + request, response = await app.asgi_client.websocket("/test/1") + second_set = ev.is_set() + assert first_set and second_set -# def test_method_not_allowed(app): -# @app.route("/test", methods=["GET"]) -# async def handler(request): -# return text("OK") +def test_method_not_allowed(app): + @app.route("/test", methods=["GET"]) + async def handler(request): + return text("OK") -# request, response = app.test_client.get("/test") -# assert response.status == 200 + request, response = app.test_client.get("/test") + assert response.status == 200 -# request, response = app.test_client.post("/test") -# assert response.status == 405 + request, response = app.test_client.post("/test") + assert response.status == 405 -# @pytest.mark.parametrize("strict_slashes", [True, False, None]) -# def test_static_add_route(app, strict_slashes): -# async def handler1(request): -# return text("OK1") +@pytest.mark.parametrize("strict_slashes", [True, False, None]) +def test_static_add_route(app, strict_slashes): + async def handler1(request): + return text("OK1") -# async def handler2(request): -# return text("OK2") + async def handler2(request): + return text("OK2") -# app.add_route(handler1, "/test", strict_slashes=strict_slashes) -# app.add_route(handler2, "/test2", strict_slashes=strict_slashes) + app.add_route(handler1, "/test", strict_slashes=strict_slashes) + app.add_route(handler2, "/test2", strict_slashes=strict_slashes) -# request, response = app.test_client.get("/test") -# assert response.text == "OK1" + request, response = app.test_client.get("/test") + assert response.text == "OK1" -# request, response = app.test_client.get("/test2") -# assert response.text == "OK2" + request, response = app.test_client.get("/test2") + assert response.text == "OK2" -# def test_dynamic_add_route(app): +def test_dynamic_add_route(app): -# results = [] + results = [] -# async def handler(request, name): -# results.append(name) -# return text("OK") + async def handler(request, name): + results.append(name) + return text("OK") -# app.add_route(handler, "/folder/") -# request, response = app.test_client.get("/folder/test123") + app.add_route(handler, "/folder/") + request, response = app.test_client.get("/folder/test123") -# assert response.text == "OK" -# assert results[0] == "test123" + assert response.text == "OK" + assert results[0] == "test123" -# def test_dynamic_add_route_string(app): +def test_dynamic_add_route_string(app): -# results = [] + results = [] -# async def handler(request, name): -# results.append(name) -# return text("OK") + async def handler(request, name): + results.append(name) + return text("OK") -# app.add_route(handler, "/folder/") -# request, response = app.test_client.get("/folder/test123") + app.add_route(handler, "/folder/") + request, response = app.test_client.get("/folder/test123") -# assert response.text == "OK" -# assert results[0] == "test123" + assert response.text == "OK" + assert results[0] == "test123" -# request, response = app.test_client.get("/folder/favicon.ico") + request, response = app.test_client.get("/folder/favicon.ico") -# assert response.text == "OK" -# assert results[1] == "favicon.ico" + assert response.text == "OK" + assert results[1] == "favicon.ico" -# def test_dynamic_add_route_int(app): -# results = [] +def test_dynamic_add_route_int(app): + results = [] -# async def handler(request, folder_id): -# results.append(folder_id) -# return text("OK") + async def handler(request, folder_id): + results.append(folder_id) + return text("OK") -# app.add_route(handler, "/folder/") + app.add_route(handler, "/folder/") -# request, response = app.test_client.get("/folder/12345") -# assert response.text == "OK" -# assert type(results[0]) is int + request, response = app.test_client.get("/folder/12345") + assert response.text == "OK" + assert type(results[0]) is int -# request, response = app.test_client.get("/folder/asdf") -# assert response.status == 404 + request, response = app.test_client.get("/folder/asdf") + assert response.status == 404 -# def test_dynamic_add_route_number(app): -# results = [] +def test_dynamic_add_route_number(app): + results = [] -# async def handler(request, weight): -# results.append(weight) -# return text("OK") + async def handler(request, weight): + results.append(weight) + return text("OK") -# app.add_route(handler, "/weight/") + app.add_route(handler, "/weight/") -# request, response = app.test_client.get("/weight/12345") -# assert response.text == "OK" -# assert type(results[0]) is float + request, response = app.test_client.get("/weight/12345") + assert response.text == "OK" + assert type(results[0]) is float -# request, response = app.test_client.get("/weight/1234.56") -# assert response.status == 200 + request, response = app.test_client.get("/weight/1234.56") + assert response.status == 200 -# request, response = app.test_client.get("/weight/.12") -# assert response.status == 200 + request, response = app.test_client.get("/weight/.12") + assert response.status == 200 -# request, response = app.test_client.get("/weight/12.") -# assert response.status == 200 + request, response = app.test_client.get("/weight/12.") + assert response.status == 200 -# request, response = app.test_client.get("/weight/1234-56") -# assert response.status == 404 + request, response = app.test_client.get("/weight/1234-56") + assert response.status == 404 -# request, response = app.test_client.get("/weight/12.34.56") -# assert response.status == 404 + request, response = app.test_client.get("/weight/12.34.56") + assert response.status == 404 -# def test_dynamic_add_route_regex(app): -# async def handler(request, folder_id): -# return text("OK") +def test_dynamic_add_route_regex(app): + async def handler(request, folder_id): + return text("OK") -# app.add_route(handler, "/folder/") + app.add_route(handler, "/folder/") -# request, response = app.test_client.get("/folder/test") -# assert response.status == 200 + request, response = app.test_client.get("/folder/test") + assert response.status == 200 -# request, response = app.test_client.get("/folder/test1") -# assert response.status == 404 + request, response = app.test_client.get("/folder/test1") + assert response.status == 404 -# request, response = app.test_client.get("/folder/test-123") -# assert response.status == 404 + request, response = app.test_client.get("/folder/test-123") + assert response.status == 404 -# request, response = app.test_client.get("/folder/") -# assert response.status == 200 + request, response = app.test_client.get("/folder/") + assert response.status == 200 # def test_dynamic_add_route_unhashable(app): @@ -732,169 +897,202 @@ from sanic.router import ParameterNameConflicts, RouteDoesNotExist, RouteExists # assert response.status == 404 -# def test_add_route_duplicate(app): +def test_add_route_duplicate(app): -# with pytest.raises(RouteExists): + with pytest.raises(RouteExists): -# async def handler1(request): -# pass + async def handler1(request): + pass -# async def handler2(request): -# pass + async def handler2(request): + pass -# app.add_route(handler1, "/test") -# app.add_route(handler2, "/test") + app.add_route(handler1, "/test") + app.add_route(handler2, "/test") -# with pytest.raises(RouteExists): + with pytest.raises(RouteExists): -# async def handler1(request, dynamic): -# pass + async def handler1(request, dynamic): + pass -# async def handler2(request, dynamic): -# pass + async def handler2(request, dynamic): + pass -# app.add_route(handler1, "/test//") -# app.add_route(handler2, "/test//") + app.add_route(handler1, "/test//") + app.add_route(handler2, "/test//") -# def test_add_route_method_not_allowed(app): -# async def handler(request): -# return text("OK") +def test_add_route_method_not_allowed(app): + async def handler(request): + return text("OK") -# app.add_route(handler, "/test", methods=["GET"]) + app.add_route(handler, "/test", methods=["GET"]) -# request, response = app.test_client.get("/test") -# assert response.status == 200 + request, response = app.test_client.get("/test") + assert response.status == 200 -# request, response = app.test_client.post("/test") -# assert response.status == 405 + request, response = app.test_client.post("/test") + assert response.status == 405 -# def test_removing_slash(app): -# @app.get("/rest/") -# def get(_): -# pass +def test_removing_slash(app): + @app.get("/rest/") + def get(_): + pass -# @app.post("/rest/") -# def post(_): -# pass + @app.post("/rest/") + def post(_): + pass -# assert len(app.router.routes_all.keys()) == 2 + assert len(app.router.routes_all.keys()) == 1 -# def test_overload_routes(app): -# @app.route("/overload", methods=["GET"]) -# async def handler1(request): -# return text("OK1") +def test_overload_routes(app): + @app.route("/overload", methods=["GET"]) + async def handler1(request): + return text("OK1") -# @app.route("/overload", methods=["POST", "PUT"]) -# async def handler2(request): -# return text("OK2") + @app.route("/overload", methods=["POST", "PUT"]) + async def handler2(request): + return text("OK2") -# request, response = app.test_client.get("/overload") -# assert response.text == "OK1" + request, response = app.test_client.get("/overload") + assert response.text == "OK1" -# request, response = app.test_client.post("/overload") -# assert response.text == "OK2" + request, response = app.test_client.post("/overload") + assert response.text == "OK2" -# request, response = app.test_client.put("/overload") -# assert response.text == "OK2" + request, response = app.test_client.put("/overload") + assert response.text == "OK2" -# request, response = app.test_client.delete("/overload") -# assert response.status == 405 + request, response = app.test_client.delete("/overload") + assert response.status == 405 -# with pytest.raises(RouteExists): + app.router.reset() + with pytest.raises(RouteExists): -# @app.route("/overload", methods=["PUT", "DELETE"]) -# async def handler3(request): -# return text("Duplicated") + @app.route("/overload", methods=["PUT", "DELETE"]) + async def handler3(request): + return text("Duplicated") -# def test_unmergeable_overload_routes(app): -# @app.route("/overload_whole", methods=None) -# async def handler1(request): -# return text("OK1") +def test_unmergeable_overload_routes(app): + @app.route("/overload_whole", methods=None) + async def handler1(request): + return text("OK1") -# with pytest.raises(RouteExists): + @app.route("/overload_whole", methods=["POST", "PUT"]) + async def handler2(request): + return text("OK1") -# @app.route("/overload_whole", methods=["POST", "PUT"]) -# async def handler2(request): -# return text("Duplicated") + assert ( + len( + dict(list(app.router.static_routes.values())[0].handlers)[ + "overload_whole" + ] + ) + == 3 + ) -# request, response = app.test_client.get("/overload_whole") -# assert response.text == "OK1" + request, response = app.test_client.get("/overload_whole") + assert response.text == "OK1" -# request, response = app.test_client.post("/overload_whole") -# assert response.text == "OK1" + request, response = app.test_client.post("/overload_whole") + assert response.text == "OK1" -# @app.route("/overload_part", methods=["GET"]) -# async def handler3(request): -# return text("OK1") + request, response = app.test_client.put("/overload_whole") + assert response.text == "OK1" -# with pytest.raises(RouteExists): + app.router.reset() -# @app.route("/overload_part") -# async def handler4(request): -# return text("Duplicated") + @app.route("/overload_part", methods=["GET"]) + async def handler3(request): + return text("OK1") -# request, response = app.test_client.get("/overload_part") -# assert response.text == "OK1" + with pytest.raises(RouteExists): -# request, response = app.test_client.post("/overload_part") -# assert response.status == 405 + @app.route("/overload_part") + async def handler4(request): + return text("Duplicated") + + request, response = app.test_client.get("/overload_part") + assert response.text == "OK1" + + request, response = app.test_client.post("/overload_part") + assert response.status == 405 -# def test_unicode_routes(app): -# @app.get("/你好") -# def handler1(request): -# return text("OK1") +def test_unicode_routes(app): + @app.get("/你好") + def handler1(request): + return text("OK1") -# request, response = app.test_client.get("/你好") -# assert response.text == "OK1" + request, response = app.test_client.get("/你好") + assert response.text == "OK1" -# @app.route("/overload/", methods=["GET"]) -# async def handler2(request, param): -# return text("OK2 " + param) + app.router.reset() -# request, response = app.test_client.get("/overload/你好") -# assert response.text == "OK2 你好" + @app.route("/overload/", methods=["GET"], unquote=True) + async def handler2(request, param): + return text("OK2 " + param) + + request, response = app.test_client.get("/overload/你好") + assert response.text == "OK2 你好" -# def test_uri_with_different_method_and_different_params(app): -# @app.route("/ads/", methods=["GET"]) -# async def ad_get(request, ad_id): -# return json({"ad_id": ad_id}) +def test_uri_with_different_method_and_different_params(app): + @app.route("/ads/", methods=["GET"]) + async def ad_get(request, ad_id): + return json({"ad_id": ad_id}) -# @app.route("/ads/", methods=["POST"]) -# async def ad_post(request, action): -# return json({"action": action}) + @app.route("/ads/", methods=["POST"]) + async def ad_post(request, action): + return json({"action": action}) -# request, response = app.test_client.get("/ads/1234") -# assert response.status == 200 -# assert response.json == {"ad_id": "1234"} + request, response = app.test_client.get("/ads/1234") + assert response.status == 405 -# request, response = app.test_client.post("/ads/post") -# assert response.status == 200 -# assert response.json == {"action": "post"} + request, response = app.test_client.post("/ads/post") + assert response.status == 200 + assert response.json == {"action": "post"} -# def test_route_raise_ParameterNameConflicts(app): -# with pytest.raises(ParameterNameConflicts): +def test_uri_with_different_method_and_same_params(app): + @app.route("/ads/", methods=["GET"]) + async def ad_get(request, ad_id): + return json({"ad_id": ad_id}) -# @app.get("/api/v1///") -# def handler(request, user): -# return text("OK") + @app.route("/ads/", methods=["POST"]) + async def ad_post(request, ad_id): + return json({"ad_id": ad_id}) + + request, response = app.test_client.get("/ads/1234") + assert response.status == 200 + assert response.json == {"ad_id": "1234"} + + request, response = app.test_client.post("/ads/post") + assert response.status == 200 + assert response.json == {"ad_id": "post"} -# def test_route_invalid_host(app): +def test_route_raise_ParameterNameConflicts(app): + @app.get("/api/v1///") + def handler(request, user): + return text("OK") -# host = 321 -# with pytest.raises(ValueError) as excinfo: + with pytest.raises(ParameterNameConflicts): + app.router.finalize() -# @app.get("/test", host=host) -# def handler(request): -# return text("pass") -# assert str(excinfo.value) == ( -# "Expected either string or Iterable of " "host strings, not {!r}" -# ).format(host) +def test_route_invalid_host(app): + + host = 321 + with pytest.raises(ValueError) as excinfo: + + @app.get("/test", host=host) + def handler(request): + return text("pass") + + assert str(excinfo.value) == ( + "Expected either string or Iterable of " "host strings, not {!r}" + ).format(host) diff --git a/tests/test_static.py b/tests/test_static.py index 78c114b9..d116c7b9 100644 --- a/tests/test_static.py +++ b/tests/test_static.py @@ -106,6 +106,7 @@ def test_static_file_bytes(app, static_file_directory, file_name): [dict(), list(), object()], ) def test_static_file_invalid_path(app, static_file_directory, file_name): + app.route("/")(lambda x: x) with pytest.raises(ValueError): app.static("/testing.file", file_name) request, response = app.test_client.get("/testing.file") diff --git a/tests/test_url_building.py b/tests/test_url_building.py index de93015e..6b90fe7e 100644 --- a/tests/test_url_building.py +++ b/tests/test_url_building.py @@ -112,22 +112,21 @@ def test_fails_if_endpoint_not_found(app): def test_fails_url_build_if_param_not_passed(app): url = "/" - for letter in string.ascii_letters: + for letter in string.ascii_lowercase: url += f"<{letter}>/" @app.route(url) def fail(request): return text("this should fail") - fail_args = list(string.ascii_letters) + fail_args = list(string.ascii_lowercase) fail_args.pop() fail_kwargs = {l: l for l in fail_args} with pytest.raises(URLBuildError) as e: app.url_for("fail", **fail_kwargs) - - assert "Required parameter `Z` was not passed to url_for" in str(e.value) + assert e.match("Required parameter `z` was not passed to url_for") def test_fails_url_build_if_params_not_passed(app): @@ -137,8 +136,7 @@ def test_fails_url_build_if_params_not_passed(app): with pytest.raises(ValueError) as e: app.url_for("fail", _scheme="http") - - assert str(e.value) == "When specifying _scheme, _external must be True" + assert e.match("When specifying _scheme, _external must be True") COMPLEX_PARAM_URL = ( @@ -168,7 +166,7 @@ def test_fails_with_int_message(app): expected_error = ( r'Value "not_int" for parameter `foo` ' - r"does not match pattern for type `int`: -?\d+" + r"does not match pattern for type `int`: ^-?\d+" ) assert str(e.value) == expected_error @@ -199,13 +197,10 @@ def test_fails_with_two_letter_string_message(app): with pytest.raises(URLBuildError) as e: app.url_for("fail", **failing_kwargs) - - expected_error = ( - 'Value "foobar" for parameter `two_letter_string` ' - "does not satisfy pattern [A-z]{2}" - ) - - assert str(e.value) == expected_error + e.match( + 'Value "foobar" for parameter `two_letter_string` ' + "does not satisfy pattern ^[A-z]{2}$" + ) def test_fails_with_number_message(app): @@ -218,13 +213,10 @@ def test_fails_with_number_message(app): with pytest.raises(URLBuildError) as e: app.url_for("fail", **failing_kwargs) - - expected_error = ( - 'Value "foo" for parameter `some_number` ' - r"does not match pattern for type `float`: -?(?:\d+(?:\.\d*)?|\.\d+)" - ) - - assert str(e.value) == expected_error + e.match( + 'Value "foo" for parameter `some_number` ' + r"does not match pattern for type `float`: ^-?(?:\d+(?:\.\d*)?|\.\d+)$" + ) @pytest.mark.parametrize("number", [3, -3, 13.123, -13.123]) @@ -273,11 +265,11 @@ def blueprint_app(app): return text(f"foo from first : {param}") @second_print.route("/foo") # noqa - def foo(request): + def bar(request): return text("foo from second") @second_print.route("/foo/") # noqa - def foo_with_param(request, param): + def bar_with_param(request, param): return text(f"foo from second : {param}") app.blueprint(first_print) @@ -290,7 +282,7 @@ def test_blueprints_are_named_correctly(blueprint_app): first_url = blueprint_app.url_for("first.foo") assert first_url == "/first/foo" - second_url = blueprint_app.url_for("second.foo") + second_url = blueprint_app.url_for("second.bar") assert second_url == "/second/foo" @@ -298,7 +290,7 @@ def test_blueprints_work_with_params(blueprint_app): first_url = blueprint_app.url_for("first.foo_with_param", param="bar") assert first_url == "/first/foo/bar" - second_url = blueprint_app.url_for("second.foo_with_param", param="bar") + second_url = blueprint_app.url_for("second.bar_with_param", param="bar") assert second_url == "/second/foo/bar" diff --git a/tests/test_url_for.py b/tests/test_url_for.py index 9ebe979a..bf9a4722 100644 --- a/tests/test_url_for.py +++ b/tests/test_url_for.py @@ -1,18 +1,18 @@ import asyncio +import pytest + from sanic_testing.testing import SanicTestClient from sanic.blueprints import Blueprint def test_routes_with_host(app): - @app.route("/") @app.route("/", name="hostindex", host="example.com") @app.route("/path", name="hostpath", host="path.example.com") def index(request): pass - assert app.url_for("index") == "/" assert app.url_for("hostindex") == "/" assert app.url_for("hostpath") == "/path" assert app.url_for("hostindex", _external=True) == "http://example.com/" @@ -22,6 +22,27 @@ def test_routes_with_host(app): ) +def test_routes_with_multiple_hosts(app): + @app.route("/", name="hostindex", host=["example.com", "path.example.com"]) + def index(request): + pass + + assert app.url_for("hostindex") == "/" + assert ( + app.url_for("hostindex", _host="example.com") == "http://example.com/" + ) + + with pytest.raises(ValueError) as e: + assert app.url_for("hostindex", _external=True) + assert str(e.value).startswith("Host is ambiguous") + + with pytest.raises(ValueError) as e: + assert app.url_for("hostindex", _host="unknown.com") + assert str(e.value).startswith( + "Requested host (unknown.com) is not available for this route" + ) + + def test_websocket_bp_route_name(app): """Tests that blueprint websocket route is named.""" event = asyncio.Event() @@ -63,3 +84,7 @@ def test_websocket_bp_route_name(app): uri = app.url_for("test_bp.foobar_3") assert uri == "/bp/route3" + + +# TODO: add test with a route with multiple hosts +# TODO: add test with a route with _host in url_for diff --git a/tests/test_url_for_static.py b/tests/test_url_for_static.py index 971155ce..6c12c023 100644 --- a/tests/test_url_for_static.py +++ b/tests/test_url_for_static.py @@ -3,6 +3,7 @@ import os import pytest +from sanic import Sanic from sanic.blueprints import Blueprint @@ -26,9 +27,15 @@ def get_file_content(static_file_directory, file_name): @pytest.mark.parametrize( - "file_name", ["test.file", "decode me.txt", "python.png"] + "file_name", + [ + "test.file", + "decode me.txt", + "python.png", + ], ) -def test_static_file(app, static_file_directory, file_name): +def test_static_file(static_file_directory, file_name): + app = Sanic("qq") app.static( "/testing.file", get_file_path(static_file_directory, file_name) ) @@ -38,6 +45,8 @@ def test_static_file(app, static_file_directory, file_name): name="testing_file", ) + app.router.finalize() + uri = app.url_for("static") uri2 = app.url_for("static", filename="any") uri3 = app.url_for("static", name="static", filename="any") @@ -46,10 +55,14 @@ def test_static_file(app, static_file_directory, file_name): assert uri == uri2 assert uri2 == uri3 + app.router.reset() + request, response = app.test_client.get(uri) assert response.status == 200 assert response.body == get_file_content(static_file_directory, file_name) + app.router.reset() + bp = Blueprint("test_bp_static", url_prefix="/bp") bp.static("/testing.file", get_file_path(static_file_directory, file_name)) @@ -61,19 +74,14 @@ def test_static_file(app, static_file_directory, file_name): app.blueprint(bp) - uri = app.url_for("static", name="test_bp_static.static") - uri2 = app.url_for("static", name="test_bp_static.static", filename="any") - uri3 = app.url_for("test_bp_static.static") - uri4 = app.url_for("test_bp_static.static", name="any") - uri5 = app.url_for("test_bp_static.static", filename="any") - uri6 = app.url_for("test_bp_static.static", name="any", filename="any") + uris = [ + app.url_for("static", name="test_bp_static.static"), + app.url_for("static", name="test_bp_static.static", filename="any"), + app.url_for("test_bp_static.static"), + app.url_for("test_bp_static.static", filename="any"), + ] - assert uri == "/bp/testing.file" - assert uri == uri2 - assert uri2 == uri3 - assert uri3 == uri4 - assert uri4 == uri5 - assert uri5 == uri6 + assert all(uri == "/bp/testing.file" for uri in uris) request, response = app.test_client.get(uri) assert response.status == 200 @@ -112,7 +120,9 @@ def test_static_file(app, static_file_directory, file_name): @pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"]) @pytest.mark.parametrize("base_uri", ["/static", "", "/dir"]) -def test_static_directory(app, file_name, base_uri, static_file_directory): +def test_static_directory(file_name, base_uri, static_file_directory): + app = Sanic("base") + app.static(base_uri, static_file_directory) base_uri2 = base_uri + "/2" app.static(base_uri2, static_file_directory, name="uploads") @@ -141,6 +151,8 @@ def test_static_directory(app, file_name, base_uri, static_file_directory): bp.static(base_uri, static_file_directory) bp.static(base_uri2, static_file_directory, name="uploads") + + app.router.reset() app.blueprint(bp) uri = app.url_for( @@ -169,7 +181,8 @@ def test_static_directory(app, file_name, base_uri, static_file_directory): @pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"]) -def test_static_head_request(app, file_name, static_file_directory): +def test_static_head_request(file_name, static_file_directory): + app = Sanic("base") app.static( "/testing.file", get_file_path(static_file_directory, file_name), @@ -214,7 +227,8 @@ def test_static_head_request(app, file_name, static_file_directory): @pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"]) -def test_static_content_range_correct(app, file_name, static_file_directory): +def test_static_content_range_correct(file_name, static_file_directory): + app = Sanic("base") app.static( "/testing.file", get_file_path(static_file_directory, file_name), @@ -252,11 +266,6 @@ def test_static_content_range_correct(app, file_name, static_file_directory): "static", name="test_bp_static.static", filename="any" ) assert uri == app.url_for("test_bp_static.static") - assert uri == app.url_for("test_bp_static.static", name="any") - assert uri == app.url_for("test_bp_static.static", filename="any") - assert uri == app.url_for( - "test_bp_static.static", name="any", filename="any" - ) request, response = app.test_client.get(uri, headers=headers) assert response.status == 206 @@ -270,7 +279,8 @@ def test_static_content_range_correct(app, file_name, static_file_directory): @pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"]) -def test_static_content_range_front(app, file_name, static_file_directory): +def test_static_content_range_front(file_name, static_file_directory): + app = Sanic("base") app.static( "/testing.file", get_file_path(static_file_directory, file_name), @@ -308,11 +318,7 @@ def test_static_content_range_front(app, file_name, static_file_directory): "static", name="test_bp_static.static", filename="any" ) assert uri == app.url_for("test_bp_static.static") - assert uri == app.url_for("test_bp_static.static", name="any") assert uri == app.url_for("test_bp_static.static", filename="any") - assert uri == app.url_for( - "test_bp_static.static", name="any", filename="any" - ) request, response = app.test_client.get(uri, headers=headers) assert response.status == 206 @@ -326,7 +332,8 @@ def test_static_content_range_front(app, file_name, static_file_directory): @pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"]) -def test_static_content_range_back(app, file_name, static_file_directory): +def test_static_content_range_back(file_name, static_file_directory): + app = Sanic("base") app.static( "/testing.file", get_file_path(static_file_directory, file_name), @@ -364,11 +371,7 @@ def test_static_content_range_back(app, file_name, static_file_directory): "static", name="test_bp_static.static", filename="any" ) assert uri == app.url_for("test_bp_static.static") - assert uri == app.url_for("test_bp_static.static", name="any") assert uri == app.url_for("test_bp_static.static", filename="any") - assert uri == app.url_for( - "test_bp_static.static", name="any", filename="any" - ) request, response = app.test_client.get(uri, headers=headers) assert response.status == 206 @@ -382,7 +385,8 @@ def test_static_content_range_back(app, file_name, static_file_directory): @pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"]) -def test_static_content_range_empty(app, file_name, static_file_directory): +def test_static_content_range_empty(file_name, static_file_directory): + app = Sanic("base") app.static( "/testing.file", get_file_path(static_file_directory, file_name), @@ -420,11 +424,7 @@ def test_static_content_range_empty(app, file_name, static_file_directory): "static", name="test_bp_static.static", filename="any" ) assert uri == app.url_for("test_bp_static.static") - assert uri == app.url_for("test_bp_static.static", name="any") assert uri == app.url_for("test_bp_static.static", filename="any") - assert uri == app.url_for( - "test_bp_static.static", name="any", filename="any" - ) request, response = app.test_client.get(uri) assert response.status == 200 @@ -440,6 +440,7 @@ def test_static_content_range_empty(app, file_name, static_file_directory): @pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"]) def test_static_content_range_error(app, file_name, static_file_directory): + app = Sanic("base") app.static( "/testing.file", get_file_path(static_file_directory, file_name), @@ -475,11 +476,7 @@ def test_static_content_range_error(app, file_name, static_file_directory): "static", name="test_bp_static.static", filename="any" ) assert uri == app.url_for("test_bp_static.static") - assert uri == app.url_for("test_bp_static.static", name="any") assert uri == app.url_for("test_bp_static.static", filename="any") - assert uri == app.url_for( - "test_bp_static.static", name="any", filename="any" - ) request, response = app.test_client.get(uri, headers=headers) assert response.status == 416 diff --git a/tests/test_vhosts.py b/tests/test_vhosts.py index 8b060584..92969a76 100644 --- a/tests/test_vhosts.py +++ b/tests/test_vhosts.py @@ -1,3 +1,7 @@ +import pytest + +from sanic_routing.exceptions import RouteExists + from sanic.response import text @@ -38,13 +42,12 @@ def test_vhosts_with_defaults(app): async def handler1(request): return text("Hello, world!") - @app.route("/") - async def handler2(request): - return text("default") + with pytest.raises(RouteExists): + + @app.route("/") + async def handler2(request): + return text("default") headers = {"Host": "hello.com"} request, response = app.test_client.get("/", headers=headers) assert response.text == "Hello, world!" - - request, response = app.test_client.get("/") - assert response.text == "default"