Move logic into mixins
This commit is contained in:
parent
33d7f4da6b
commit
dadf76ce72
128
sanic/app.py
128
sanic/app.py
|
@ -30,8 +30,10 @@ from sanic.exceptions import (
|
|||
)
|
||||
from sanic.handlers import ErrorHandler, ListenerType, MiddlewareType
|
||||
from sanic.log import LOGGING_CONFIG_DEFAULTS, error_logger, logger
|
||||
from sanic.mixins.base import BaseMixin
|
||||
from sanic.mixins.middleware import MiddlewareMixin
|
||||
from sanic.mixins.routes import RouteMixin
|
||||
from sanic.models.futures import FutureRoute
|
||||
from sanic.models.futures import FutureMiddleware, FutureRoute, FutureStatic
|
||||
from sanic.request import Request
|
||||
from sanic.response import BaseHTTPResponse, HTTPResponse
|
||||
from sanic.router import Router
|
||||
|
@ -47,7 +49,7 @@ from sanic.views import CompositionView
|
|||
from sanic.websocket import ConnectionClosed, WebSocketProtocol
|
||||
|
||||
|
||||
class Sanic(RouteMixin):
|
||||
class Sanic(BaseMixin, RouteMixin, MiddlewareMixin):
|
||||
_app_registry: Dict[str, "Sanic"] = {}
|
||||
test_mode = False
|
||||
|
||||
|
@ -65,7 +67,6 @@ class Sanic(RouteMixin):
|
|||
) -> None:
|
||||
super().__init__()
|
||||
|
||||
# Get name from previous stack frame
|
||||
if name is None:
|
||||
raise SanicException(
|
||||
"Sanic instance cannot be unnamed. "
|
||||
|
@ -169,44 +170,8 @@ class Sanic(RouteMixin):
|
|||
def _apply_route(self, route: FutureRoute) -> Route:
|
||||
return self.router.add(**route._asdict())
|
||||
|
||||
def add_websocket_route(
|
||||
self,
|
||||
handler,
|
||||
uri,
|
||||
host=None,
|
||||
strict_slashes=None,
|
||||
subprotocols=None,
|
||||
version=None,
|
||||
name=None,
|
||||
):
|
||||
"""
|
||||
A helper method to register a function as a websocket route.
|
||||
|
||||
:param handler: a callable function or instance of a class
|
||||
that can handle the websocket request
|
||||
:param host: Host IP or FQDN details
|
||||
:param uri: URL path that will be mapped to the websocket
|
||||
handler
|
||||
handler
|
||||
:param strict_slashes: If the API endpoint needs to terminate
|
||||
with a "/" or not
|
||||
:param subprotocols: Subprotocols to be used with websocket
|
||||
handshake
|
||||
:param name: A unique name assigned to the URL so that it can
|
||||
be used with :func:`url_for`
|
||||
:return: Objected decorated by :func:`websocket`
|
||||
"""
|
||||
if strict_slashes is None:
|
||||
strict_slashes = self.strict_slashes
|
||||
|
||||
return self.websocket(
|
||||
uri,
|
||||
host=host,
|
||||
strict_slashes=strict_slashes,
|
||||
subprotocols=subprotocols,
|
||||
version=version,
|
||||
name=name,
|
||||
)(handler)
|
||||
def _apply_static(self, static: FutureStatic) -> Route:
|
||||
return static_register(self, static)
|
||||
|
||||
def enable_websocket(self, enable=True):
|
||||
"""Enable or disable the support for websocket.
|
||||
|
@ -281,77 +246,20 @@ class Sanic(RouteMixin):
|
|||
self.named_response_middleware[_rn].appendleft(middleware)
|
||||
|
||||
# Decorator
|
||||
def middleware(self, middleware_or_request):
|
||||
"""
|
||||
Decorate and register middleware to be called before a request.
|
||||
Can either be called as *@app.middleware* or
|
||||
*@app.middleware('request')*
|
||||
|
||||
:param: middleware_or_request: Optional parameter to use for
|
||||
identifying which type of middleware is being registered.
|
||||
"""
|
||||
# Detect which way this was called, @middleware or @middleware('AT')
|
||||
if callable(middleware_or_request):
|
||||
return self.register_middleware(middleware_or_request)
|
||||
|
||||
else:
|
||||
return partial(
|
||||
self.register_middleware, attach_to=middleware_or_request
|
||||
)
|
||||
|
||||
# Static Files
|
||||
def static(
|
||||
def _apply_middleware(
|
||||
self,
|
||||
uri,
|
||||
file_or_directory,
|
||||
pattern=r"/?.+",
|
||||
use_modified_since=True,
|
||||
use_content_range=False,
|
||||
stream_large_files=False,
|
||||
name="static",
|
||||
host=None,
|
||||
strict_slashes=None,
|
||||
content_type=None,
|
||||
middleware: FutureMiddleware,
|
||||
route_names: Optional[List[str]] = None,
|
||||
):
|
||||
"""
|
||||
Register a root to serve files from. The input can either be a
|
||||
file or a directory. This method will enable an easy and simple way
|
||||
to setup the :class:`Route` necessary to serve the static files.
|
||||
|
||||
:param uri: URL path to be used for serving static content
|
||||
:param file_or_directory: Path for the Static file/directory with
|
||||
static files
|
||||
:param pattern: Regex Pattern identifying the valid static files
|
||||
:param use_modified_since: If true, send file modified time, and return
|
||||
not modified if the browser's matches the server's
|
||||
:param use_content_range: If true, process header for range requests
|
||||
and sends the file part that is requested
|
||||
:param stream_large_files: If true, use the
|
||||
:func:`StreamingHTTPResponse.file_stream` handler rather
|
||||
than the :func:`HTTPResponse.file` handler to send the file.
|
||||
If this is an integer, this represents the threshold size to
|
||||
switch to :func:`StreamingHTTPResponse.file_stream`
|
||||
:param name: user defined name used for url_for
|
||||
:param host: Host IP or FQDN for the service to use
|
||||
:param strict_slashes: Instruct :class:`Sanic` to check if the request
|
||||
URLs need to terminate with a */*
|
||||
:param content_type: user defined content type for header
|
||||
:return: routes registered on the router
|
||||
:rtype: List[sanic.router.Route]
|
||||
"""
|
||||
return static_register(
|
||||
self,
|
||||
uri,
|
||||
file_or_directory,
|
||||
pattern,
|
||||
use_modified_since,
|
||||
use_content_range,
|
||||
stream_large_files,
|
||||
name,
|
||||
host,
|
||||
strict_slashes,
|
||||
content_type,
|
||||
)
|
||||
print(f"{middleware=}")
|
||||
if route_names:
|
||||
return self.register_named_middleware(
|
||||
middleware.middleware, route_names, middleware.attach_to
|
||||
)
|
||||
else:
|
||||
return self.register_middleware(
|
||||
middleware.middleware, middleware.attach_to
|
||||
)
|
||||
|
||||
def blueprint(self, blueprint, **options):
|
||||
"""Register a blueprint on the application.
|
||||
|
|
|
@ -112,10 +112,13 @@ class BlueprintGroup(MutableSequence):
|
|||
:param kwargs: Optional Keyword arg to use with Middleware
|
||||
:return: Partial function to apply the middleware
|
||||
"""
|
||||
kwargs["bp_group"] = True
|
||||
|
||||
def register_middleware_for_blueprints(fn):
|
||||
for blueprint in self.blueprints:
|
||||
blueprint.middleware(fn, *args, **kwargs)
|
||||
|
||||
if args and callable(args[0]):
|
||||
fn = args[0]
|
||||
args = list(args)[1:]
|
||||
return register_middleware_for_blueprints(fn)
|
||||
return register_middleware_for_blueprints
|
||||
|
|
|
@ -2,6 +2,8 @@ from collections import defaultdict, namedtuple
|
|||
|
||||
from sanic.blueprint_group import BlueprintGroup
|
||||
from sanic.constants import HTTP_METHODS
|
||||
from sanic.mixins.base import BaseMixin
|
||||
from sanic.mixins.middleware import MiddlewareMixin
|
||||
from sanic.mixins.routes import RouteMixin
|
||||
from sanic.models.futures import (
|
||||
FutureException,
|
||||
|
@ -13,7 +15,7 @@ from sanic.models.futures import (
|
|||
from sanic.views import CompositionView
|
||||
|
||||
|
||||
class Blueprint(RouteMixin):
|
||||
class Blueprint(BaseMixin, RouteMixin, MiddlewareMixin):
|
||||
def __init__(
|
||||
self,
|
||||
name,
|
||||
|
@ -34,8 +36,6 @@ class Blueprint(RouteMixin):
|
|||
:param strict_slashes: Enforce the API urls are requested with a
|
||||
training */*
|
||||
"""
|
||||
super().__init__()
|
||||
|
||||
self.name = name
|
||||
self.url_prefix = url_prefix
|
||||
self.host = host
|
||||
|
@ -53,6 +53,14 @@ class Blueprint(RouteMixin):
|
|||
kwargs["apply"] = False
|
||||
return super().route(*args, **kwargs)
|
||||
|
||||
def static(self, *args, **kwargs):
|
||||
kwargs["apply"] = False
|
||||
return super().static(*args, **kwargs)
|
||||
|
||||
def middleware(self, *args, **kwargs):
|
||||
kwargs["apply"] = False
|
||||
return super().middleware(*args, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def group(*blueprints, url_prefix=""):
|
||||
"""
|
||||
|
@ -118,51 +126,26 @@ class Blueprint(RouteMixin):
|
|||
future.ignore_body,
|
||||
)
|
||||
|
||||
_route = app._apply_route(apply_route)
|
||||
route = app._apply_route(apply_route)
|
||||
routes.append(route)
|
||||
|
||||
# TODO:
|
||||
# for future in self.websocket_routes:
|
||||
# # attach the blueprint name to the handler so that it can be
|
||||
# # prefixed properly in the router
|
||||
# future.handler.__blueprintname__ = self.name
|
||||
# # Prepend the blueprint URI prefix if available
|
||||
# uri = url_prefix + future.uri if url_prefix else future.uri
|
||||
# _routes, _ = app.websocket(
|
||||
# uri=uri,
|
||||
# host=future.host or self.host,
|
||||
# strict_slashes=future.strict_slashes,
|
||||
# name=future.name,
|
||||
# )(future.handler)
|
||||
# if _routes:
|
||||
# routes += _routes
|
||||
# Static Files
|
||||
for future in self._future_statics:
|
||||
# Prepend the blueprint URI prefix if available
|
||||
uri = url_prefix + future.uri if url_prefix else future.uri
|
||||
apply_route = FutureStatic(uri, *future[1:])
|
||||
route = app._apply_static(apply_route)
|
||||
routes.append(route)
|
||||
|
||||
# # Static Files
|
||||
# for future in self.statics:
|
||||
# # Prepend the blueprint URI prefix if available
|
||||
# uri = url_prefix + future.uri if url_prefix else future.uri
|
||||
# _routes = app.static(
|
||||
# uri, future.file_or_directory, *future.args, **future.kwargs
|
||||
# )
|
||||
# if _routes:
|
||||
# routes += _routes
|
||||
route_names = [route.name for route in routes if route]
|
||||
|
||||
# route_names = [route.name for route in routes if route]
|
||||
# Middleware
|
||||
for future in self._future_middleware:
|
||||
app._apply_middleware(future, route_names)
|
||||
|
||||
# # Middleware
|
||||
# for future in self.middlewares:
|
||||
# if future.args or future.kwargs:
|
||||
# app.register_named_middleware(
|
||||
# future.middleware,
|
||||
# route_names,
|
||||
# *future.args,
|
||||
# **future.kwargs,
|
||||
# )
|
||||
# else:
|
||||
# app.register_named_middleware(future.middleware, route_names)
|
||||
|
||||
# # Exceptions
|
||||
# for future in self.exceptions:
|
||||
# app.exception(*future.args, **future.kwargs)(future.handler)
|
||||
# Exceptions
|
||||
for future in self.exceptions:
|
||||
app.exception(*future.args, **future.kwargs)(future.handler)
|
||||
|
||||
# Event listeners
|
||||
for event, listeners in self.listeners.items():
|
||||
|
@ -181,35 +164,6 @@ class Blueprint(RouteMixin):
|
|||
|
||||
return decorator
|
||||
|
||||
def middleware(self, *args, **kwargs):
|
||||
"""
|
||||
Create a blueprint middleware from a decorated function.
|
||||
|
||||
:param args: Positional arguments to be used while invoking the
|
||||
middleware
|
||||
:param kwargs: optional keyword args that can be used with the
|
||||
middleware.
|
||||
"""
|
||||
|
||||
def register_middleware(_middleware):
|
||||
future_middleware = FutureMiddleware(_middleware, args, kwargs)
|
||||
self.middlewares.append(future_middleware)
|
||||
return _middleware
|
||||
|
||||
# Detect which way this was called, @middleware or @middleware('AT')
|
||||
if len(args) == 1 and len(kwargs) == 0 and callable(args[0]):
|
||||
middleware = args[0]
|
||||
args = []
|
||||
return register_middleware(middleware)
|
||||
else:
|
||||
if kwargs.get("bp_group") and callable(args[0]):
|
||||
middleware = args[0]
|
||||
args = args[1:]
|
||||
kwargs.pop("bp_group")
|
||||
return register_middleware(middleware)
|
||||
else:
|
||||
return register_middleware
|
||||
|
||||
def exception(self, *args, **kwargs):
|
||||
"""
|
||||
This method enables the process of creating a global exception
|
||||
|
@ -230,20 +184,5 @@ class Blueprint(RouteMixin):
|
|||
|
||||
return decorator
|
||||
|
||||
def static(self, uri, file_or_directory, *args, **kwargs):
|
||||
"""Create a blueprint static route from a decorated function.
|
||||
|
||||
:param uri: endpoint at which the route will be accessible.
|
||||
:param file_or_directory: Static asset.
|
||||
"""
|
||||
name = kwargs.pop("name", "static")
|
||||
if not name.startswith(self.name + "."):
|
||||
name = f"{self.name}.{name}"
|
||||
kwargs.update(name=name)
|
||||
|
||||
strict_slashes = kwargs.get("strict_slashes")
|
||||
if strict_slashes is None and self.strict_slashes is not None:
|
||||
kwargs.update(strict_slashes=self.strict_slashes)
|
||||
|
||||
static = FutureStatic(uri, file_or_directory, args, kwargs)
|
||||
self.statics.append(static)
|
||||
def _generate_name(self, handler, name: str) -> str:
|
||||
return f"{self.name}.{name or handler.__name__}"
|
||||
|
|
19
sanic/mixins/base.py
Normal file
19
sanic/mixins/base.py
Normal file
|
@ -0,0 +1,19 @@
|
|||
class Base(type):
|
||||
def __new__(cls, name, bases, attrs):
|
||||
init = attrs.get("__init__")
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
nonlocal init
|
||||
for base in type(self).__bases__:
|
||||
if base.__name__ != "BaseMixin":
|
||||
base.__init__(self, *args, **kwargs)
|
||||
|
||||
if init:
|
||||
init(self, *args, **kwargs)
|
||||
|
||||
attrs["__init__"] = __init__
|
||||
return type.__new__(cls, name, bases, attrs)
|
||||
|
||||
|
||||
class BaseMixin(metaclass=Base):
|
||||
...
|
41
sanic/mixins/middleware.py
Normal file
41
sanic/mixins/middleware.py
Normal file
|
@ -0,0 +1,41 @@
|
|||
from functools import partial
|
||||
from typing import Set
|
||||
|
||||
from sanic.models.futures import FutureMiddleware
|
||||
|
||||
|
||||
class MiddlewareMixin:
|
||||
def __init__(self, *args, **kwargs) -> None:
|
||||
self._future_middleware: Set[FutureMiddleware] = set()
|
||||
|
||||
def _apply_middleware(self, middleware: FutureMiddleware):
|
||||
raise NotImplementedError
|
||||
|
||||
def middleware(
|
||||
self, middleware_or_request, attach_to="request", apply=True
|
||||
):
|
||||
"""
|
||||
Decorate and register middleware to be called before a request.
|
||||
Can either be called as *@app.middleware* or
|
||||
*@app.middleware('request')*
|
||||
|
||||
:param: middleware_or_request: Optional parameter to use for
|
||||
identifying which type of middleware is being registered.
|
||||
"""
|
||||
|
||||
def register_middleware(_middleware, attach_to="request"):
|
||||
future_middleware = FutureMiddleware(_middleware, attach_to)
|
||||
self._future_middleware.add(future_middleware)
|
||||
if apply:
|
||||
self._apply_middleware(future_middleware)
|
||||
return _middleware
|
||||
|
||||
# Detect which way this was called, @middleware or @middleware('AT')
|
||||
if callable(middleware_or_request):
|
||||
return register_middleware(
|
||||
middleware_or_request, attach_to=attach_to
|
||||
)
|
||||
else:
|
||||
return partial(
|
||||
register_middleware, attach_to=middleware_or_request
|
||||
)
|
|
@ -1,25 +1,31 @@
|
|||
from functools import partial
|
||||
from inspect import signature
|
||||
from typing import List, Set
|
||||
from pathlib import PurePath
|
||||
from typing import List, Set, Union
|
||||
|
||||
import websockets
|
||||
|
||||
from sanic_routing.route import Route
|
||||
|
||||
from sanic.constants import HTTP_METHODS
|
||||
from sanic.models.futures import FutureRoute
|
||||
from sanic.models.futures import FutureRoute, FutureStatic
|
||||
from sanic.views import CompositionView
|
||||
|
||||
|
||||
class RouteMixin:
|
||||
def __init__(self) -> None:
|
||||
self._future_routes: Set[Route] = set()
|
||||
self._future_websocket_routes: Set[Route] = set()
|
||||
def __init__(self, *args, **kwargs) -> None:
|
||||
self._future_routes: Set[FutureRoute] = set()
|
||||
self._future_statics: Set[FutureStatic] = set()
|
||||
self.name = ""
|
||||
self.strict_slashes = False
|
||||
|
||||
def _apply_route(self, route: FutureRoute) -> Route:
|
||||
raise NotImplementedError
|
||||
|
||||
def _route(
|
||||
def _apply_static(self, static: FutureStatic) -> Route:
|
||||
raise NotImplementedError
|
||||
|
||||
def route(
|
||||
self,
|
||||
uri,
|
||||
methods=frozenset({"GET"}),
|
||||
|
@ -133,30 +139,6 @@ class RouteMixin:
|
|||
|
||||
return decorator
|
||||
|
||||
def route(
|
||||
self,
|
||||
uri,
|
||||
methods=frozenset({"GET"}),
|
||||
host=None,
|
||||
strict_slashes=None,
|
||||
stream=False,
|
||||
version=None,
|
||||
name=None,
|
||||
ignore_body=False,
|
||||
apply=True,
|
||||
):
|
||||
return self._route(
|
||||
uri=uri,
|
||||
methods=methods,
|
||||
host=host,
|
||||
strict_slashes=strict_slashes,
|
||||
stream=stream,
|
||||
version=version,
|
||||
name=name,
|
||||
ignore_body=ignore_body,
|
||||
apply=apply,
|
||||
)
|
||||
|
||||
def add_route(
|
||||
self,
|
||||
handler,
|
||||
|
@ -435,7 +417,7 @@ class RouteMixin:
|
|||
:param version: Blueprint Version
|
||||
:param name: Unique name to identify the Websocket Route
|
||||
"""
|
||||
return self._route(
|
||||
return self.route(
|
||||
uri=uri,
|
||||
host=host,
|
||||
methods=None,
|
||||
|
@ -474,11 +456,8 @@ class RouteMixin:
|
|||
be used with :func:`url_for`
|
||||
:return: Objected decorated by :func:`websocket`
|
||||
"""
|
||||
if strict_slashes is None:
|
||||
strict_slashes = self.strict_slashes
|
||||
|
||||
return self.websocket(
|
||||
uri,
|
||||
uri=uri,
|
||||
host=host,
|
||||
strict_slashes=strict_slashes,
|
||||
subprotocols=subprotocols,
|
||||
|
@ -486,5 +465,69 @@ class RouteMixin:
|
|||
name=name,
|
||||
)(handler)
|
||||
|
||||
def static(
|
||||
self,
|
||||
uri,
|
||||
file_or_directory: Union[str, bytes, PurePath],
|
||||
pattern=r"/?.+",
|
||||
use_modified_since=True,
|
||||
use_content_range=False,
|
||||
stream_large_files=False,
|
||||
name="static",
|
||||
host=None,
|
||||
strict_slashes=None,
|
||||
content_type=None,
|
||||
apply=True,
|
||||
):
|
||||
"""
|
||||
Register a root to serve files from. The input can either be a
|
||||
file or a directory. This method will enable an easy and simple way
|
||||
to setup the :class:`Route` necessary to serve the static files.
|
||||
|
||||
:param uri: URL path to be used for serving static content
|
||||
:param file_or_directory: Path for the Static file/directory with
|
||||
static files
|
||||
:param pattern: Regex Pattern identifying the valid static files
|
||||
:param use_modified_since: If true, send file modified time, and return
|
||||
not modified if the browser's matches the server's
|
||||
:param use_content_range: If true, process header for range requests
|
||||
and sends the file part that is requested
|
||||
:param stream_large_files: If true, use the
|
||||
:func:`StreamingHTTPResponse.file_stream` handler rather
|
||||
than the :func:`HTTPResponse.file` handler to send the file.
|
||||
If this is an integer, this represents the threshold size to
|
||||
switch to :func:`StreamingHTTPResponse.file_stream`
|
||||
:param name: user defined name used for url_for
|
||||
:param host: Host IP or FQDN for the service to use
|
||||
:param strict_slashes: Instruct :class:`Sanic` to check if the request
|
||||
URLs need to terminate with a */*
|
||||
:param content_type: user defined content type for header
|
||||
:return: routes registered on the router
|
||||
:rtype: List[sanic.router.Route]
|
||||
"""
|
||||
|
||||
if not name.startswith(self.name + "."):
|
||||
name = f"{self.name}.{name}"
|
||||
|
||||
if strict_slashes is None and self.strict_slashes is not None:
|
||||
strict_slashes = self.strict_slashes
|
||||
|
||||
static = FutureStatic(
|
||||
uri,
|
||||
file_or_directory,
|
||||
pattern,
|
||||
use_modified_since,
|
||||
use_content_range,
|
||||
stream_large_files,
|
||||
name,
|
||||
host,
|
||||
strict_slashes,
|
||||
content_type,
|
||||
)
|
||||
self._future_statics.add(static)
|
||||
|
||||
if apply:
|
||||
self._apply_static(static)
|
||||
|
||||
def _generate_name(self, handler, name: str) -> str:
|
||||
return name or handler.__name__
|
||||
|
|
|
@ -18,10 +18,20 @@ FutureRoute = namedtuple(
|
|||
FutureListener = namedtuple(
|
||||
"FutureListener", ["handler", "uri", "methods", "host"]
|
||||
)
|
||||
FutureMiddleware = namedtuple(
|
||||
"FutureMiddleware", ["middleware", "args", "kwargs"]
|
||||
)
|
||||
FutureMiddleware = namedtuple("FutureMiddleware", ["middleware", "attach_to"])
|
||||
FutureException = namedtuple("FutureException", ["handler", "args", "kwargs"])
|
||||
FutureStatic = namedtuple(
|
||||
"FutureStatic", ["uri", "file_or_directory", "args", "kwargs"]
|
||||
"FutureStatic",
|
||||
[
|
||||
"uri",
|
||||
"file_or_directory",
|
||||
"pattern",
|
||||
"use_modified_since",
|
||||
"use_content_range",
|
||||
"stream_large_files",
|
||||
"name",
|
||||
"host",
|
||||
"strict_slashes",
|
||||
"content_type",
|
||||
],
|
||||
)
|
||||
|
|
|
@ -16,6 +16,7 @@ from sanic.exceptions import (
|
|||
)
|
||||
from sanic.handlers import ContentRangeHandler
|
||||
from sanic.log import error_logger
|
||||
from sanic.models.futures import FutureStatic
|
||||
from sanic.response import HTTPResponse, file, file_stream
|
||||
|
||||
|
||||
|
@ -112,16 +113,7 @@ async def _static_request_handler(
|
|||
|
||||
def register(
|
||||
app,
|
||||
uri: str,
|
||||
file_or_directory: Union[str, bytes, PurePath],
|
||||
pattern,
|
||||
use_modified_since,
|
||||
use_content_range,
|
||||
stream_large_files,
|
||||
name: str = "static",
|
||||
host=None,
|
||||
strict_slashes=None,
|
||||
content_type=None,
|
||||
static: FutureStatic,
|
||||
):
|
||||
# TODO: Though sanic is not a file server, I feel like we should at least
|
||||
# make a good effort here. Modified-since is nice, but we could
|
||||
|
@ -152,38 +144,42 @@ def register(
|
|||
:rtype: List[sanic.router.Route]
|
||||
"""
|
||||
|
||||
if isinstance(file_or_directory, bytes):
|
||||
file_or_directory = file_or_directory.decode("utf-8")
|
||||
elif isinstance(file_or_directory, PurePath):
|
||||
file_or_directory = str(file_or_directory)
|
||||
elif not isinstance(file_or_directory, str):
|
||||
if isinstance(static.file_or_directory, bytes):
|
||||
file_or_directory = static.file_or_directory.decode("utf-8")
|
||||
elif isinstance(static.file_or_directory, PurePath):
|
||||
file_or_directory = str(static.file_or_directory)
|
||||
elif not isinstance(static.file_or_directory, str):
|
||||
raise ValueError("Invalid file path string.")
|
||||
else:
|
||||
file_or_directory = static.file_or_directory
|
||||
|
||||
uri = static.uri
|
||||
name = static.name
|
||||
# If we're not trying to match a file directly,
|
||||
# serve from the folder
|
||||
if not path.isfile(file_or_directory):
|
||||
uri += "<file_uri:" + pattern + ">"
|
||||
uri += "<file_uri:" + static.pattern + ">"
|
||||
|
||||
# special prefix for static files
|
||||
if not name.startswith("_static_"):
|
||||
name = f"_static_{name}"
|
||||
if not static.name.startswith("_static_"):
|
||||
name = f"_static_{static.name}"
|
||||
|
||||
_handler = wraps(_static_request_handler)(
|
||||
partial(
|
||||
_static_request_handler,
|
||||
file_or_directory,
|
||||
use_modified_since,
|
||||
use_content_range,
|
||||
stream_large_files,
|
||||
content_type=content_type,
|
||||
static.use_modified_since,
|
||||
static.use_content_range,
|
||||
static.stream_large_files,
|
||||
content_type=static.content_type,
|
||||
)
|
||||
)
|
||||
|
||||
_routes, _ = app.route(
|
||||
uri,
|
||||
uri=uri,
|
||||
methods=["GET", "HEAD"],
|
||||
name=name,
|
||||
host=host,
|
||||
strict_slashes=strict_slashes,
|
||||
host=static.host,
|
||||
strict_slashes=static.strict_slashes,
|
||||
)(_handler)
|
||||
return _routes
|
||||
|
|
Loading…
Reference in New Issue
Block a user