Restructured blueprint class
Blueprints currently queue functions to be called, which are simple, yet hard to inspect. These changes allow tools to be built that analyze blueprints more easily.
This commit is contained in:
parent
a245e54bd3
commit
629524af04
|
@ -1,59 +1,11 @@
|
||||||
from collections import defaultdict
|
from collections import defaultdict, namedtuple
|
||||||
|
|
||||||
|
|
||||||
class BlueprintSetup:
|
FutureRoute = namedtuple('Route', ['handler', 'uri', 'methods', 'host'])
|
||||||
"""
|
FutureListener = namedtuple('Listener', ['handler', 'uri', 'methods', 'host'])
|
||||||
Creates a blueprint state like object.
|
FutureMiddleware = namedtuple('Route', ['middleware', 'args', 'kwargs'])
|
||||||
"""
|
FutureException = namedtuple('Route', ['handler', 'args', 'kwargs'])
|
||||||
|
FutureStatic = namedtuple('Route', ['uri', 'file_or_directory', 'args', 'kwargs'])
|
||||||
def __init__(self, blueprint, app, options):
|
|
||||||
self.app = app
|
|
||||||
self.blueprint = blueprint
|
|
||||||
self.options = options
|
|
||||||
|
|
||||||
url_prefix = self.options.get('url_prefix')
|
|
||||||
if url_prefix is None:
|
|
||||||
url_prefix = self.blueprint.url_prefix
|
|
||||||
|
|
||||||
#: The prefix that should be used for all URLs defined on the
|
|
||||||
#: blueprint.
|
|
||||||
self.url_prefix = url_prefix
|
|
||||||
|
|
||||||
def add_route(self, handler, uri, methods, host=None):
|
|
||||||
"""
|
|
||||||
A helper method to register a handler to the application url routes.
|
|
||||||
"""
|
|
||||||
if self.url_prefix:
|
|
||||||
uri = self.url_prefix + uri
|
|
||||||
|
|
||||||
if host is None:
|
|
||||||
host = self.blueprint.host
|
|
||||||
|
|
||||||
self.app.route(uri=uri, methods=methods, host=host)(handler)
|
|
||||||
|
|
||||||
def add_exception(self, handler, *args, **kwargs):
|
|
||||||
"""
|
|
||||||
Registers exceptions to sanic.
|
|
||||||
"""
|
|
||||||
self.app.exception(*args, **kwargs)(handler)
|
|
||||||
|
|
||||||
def add_static(self, uri, file_or_directory, *args, **kwargs):
|
|
||||||
"""
|
|
||||||
Registers static files to sanic.
|
|
||||||
"""
|
|
||||||
if self.url_prefix:
|
|
||||||
uri = self.url_prefix + uri
|
|
||||||
|
|
||||||
self.app.static(uri, file_or_directory, *args, **kwargs)
|
|
||||||
|
|
||||||
def add_middleware(self, middleware, *args, **kwargs):
|
|
||||||
"""
|
|
||||||
Registers middleware to sanic.
|
|
||||||
"""
|
|
||||||
if args or kwargs:
|
|
||||||
self.app.middleware(*args, **kwargs)(middleware)
|
|
||||||
else:
|
|
||||||
self.app.middleware(middleware)
|
|
||||||
|
|
||||||
|
|
||||||
class Blueprint:
|
class Blueprint:
|
||||||
|
@ -65,30 +17,47 @@ class Blueprint:
|
||||||
"""
|
"""
|
||||||
self.name = name
|
self.name = name
|
||||||
self.url_prefix = url_prefix
|
self.url_prefix = url_prefix
|
||||||
self.deferred_functions = []
|
|
||||||
self.listeners = defaultdict(list)
|
|
||||||
self.host = host
|
self.host = host
|
||||||
|
|
||||||
def record(self, func):
|
self.routes = []
|
||||||
"""
|
self.exceptions = []
|
||||||
Registers a callback function that is invoked when the blueprint is
|
self.listeners = defaultdict(list)
|
||||||
registered on the application.
|
self.middlewares = []
|
||||||
"""
|
self.statics = []
|
||||||
self.deferred_functions.append(func)
|
|
||||||
|
|
||||||
def make_setup_state(self, app, options):
|
|
||||||
"""
|
|
||||||
Returns a new BlueprintSetup object
|
|
||||||
"""
|
|
||||||
return BlueprintSetup(self, app, options)
|
|
||||||
|
|
||||||
def register(self, app, options):
|
def register(self, app, options):
|
||||||
"""
|
"""
|
||||||
Registers the blueprint to the sanic app.
|
Registers the blueprint to the sanic app.
|
||||||
"""
|
"""
|
||||||
state = self.make_setup_state(app, options)
|
|
||||||
for deferred in self.deferred_functions:
|
url_prefix = options.get('url_prefix', self.url_prefix)
|
||||||
deferred(state)
|
|
||||||
|
# Routes
|
||||||
|
for future in self.routes:
|
||||||
|
# Prepend the blueprint URI prefix if available
|
||||||
|
uri = url_prefix + future.uri if url_prefix else future.uri
|
||||||
|
app.route(
|
||||||
|
uri=uri,
|
||||||
|
methods=future.methods,
|
||||||
|
host=future.host or self.host
|
||||||
|
)(future.handler)
|
||||||
|
|
||||||
|
# Middleware
|
||||||
|
for future in self.middlewares:
|
||||||
|
if future.args or future.kwargs:
|
||||||
|
app.middleware(*future.args, **future.kwargs)(future.middleware)
|
||||||
|
else:
|
||||||
|
app.middleware(future.middleware)
|
||||||
|
|
||||||
|
# Exceptions
|
||||||
|
for future in self.exceptions:
|
||||||
|
app.exception(*future.args, **future.kwargs)(future.handler)
|
||||||
|
|
||||||
|
# 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
|
||||||
|
app.static(uri, future.file_or_directory, *future.args, **future.kwargs)
|
||||||
|
|
||||||
def route(self, uri, methods=frozenset({'GET'}), host=None):
|
def route(self, uri, methods=frozenset({'GET'}), host=None):
|
||||||
"""
|
"""
|
||||||
|
@ -97,7 +66,8 @@ class Blueprint:
|
||||||
:param methods: List of acceptable HTTP methods.
|
:param methods: List of acceptable HTTP methods.
|
||||||
"""
|
"""
|
||||||
def decorator(handler):
|
def decorator(handler):
|
||||||
self.record(lambda s: s.add_route(handler, uri, methods, host))
|
route = FutureRoute(handler, uri, methods, host)
|
||||||
|
self.routes.append(route)
|
||||||
return handler
|
return handler
|
||||||
return decorator
|
return decorator
|
||||||
|
|
||||||
|
@ -108,7 +78,8 @@ class Blueprint:
|
||||||
:param uri: Endpoint at which the route will be accessible.
|
:param uri: Endpoint at which the route will be accessible.
|
||||||
:param methods: List of acceptable HTTP methods.
|
:param methods: List of acceptable HTTP methods.
|
||||||
"""
|
"""
|
||||||
self.record(lambda s: s.add_route(handler, uri, methods, host))
|
route = FutureRoute(handler, uri, methods, host)
|
||||||
|
self.routes.append(route)
|
||||||
return handler
|
return handler
|
||||||
|
|
||||||
def listener(self, event):
|
def listener(self, event):
|
||||||
|
@ -125,10 +96,10 @@ class Blueprint:
|
||||||
"""
|
"""
|
||||||
Creates a blueprint middleware from a decorated function.
|
Creates a blueprint middleware from a decorated function.
|
||||||
"""
|
"""
|
||||||
def register_middleware(middleware):
|
def register_middleware(_middleware):
|
||||||
self.record(
|
future_middleware = FutureMiddleware(_middleware, args, kwargs)
|
||||||
lambda s: s.add_middleware(middleware, *args, **kwargs))
|
self.middlewares.append(future_middleware)
|
||||||
return middleware
|
return _middleware
|
||||||
|
|
||||||
# Detect which way this was called, @middleware or @middleware('AT')
|
# Detect which way this was called, @middleware or @middleware('AT')
|
||||||
if len(args) == 1 and len(kwargs) == 0 and callable(args[0]):
|
if len(args) == 1 and len(kwargs) == 0 and callable(args[0]):
|
||||||
|
@ -143,7 +114,8 @@ class Blueprint:
|
||||||
Creates a blueprint exception from a decorated function.
|
Creates a blueprint exception from a decorated function.
|
||||||
"""
|
"""
|
||||||
def decorator(handler):
|
def decorator(handler):
|
||||||
self.record(lambda s: s.add_exception(handler, *args, **kwargs))
|
exception = FutureException(handler, args, kwargs)
|
||||||
|
self.exceptions.append(exception)
|
||||||
return handler
|
return handler
|
||||||
return decorator
|
return decorator
|
||||||
|
|
||||||
|
@ -153,5 +125,5 @@ class Blueprint:
|
||||||
:param uri: Endpoint at which the route will be accessible.
|
:param uri: Endpoint at which the route will be accessible.
|
||||||
:param file_or_directory: Static asset.
|
:param file_or_directory: Static asset.
|
||||||
"""
|
"""
|
||||||
self.record(
|
static = FutureStatic(uri, file_or_directory, args, kwargs)
|
||||||
lambda s: s.add_static(uri, file_or_directory, *args, **kwargs))
|
self.statics.append(static)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user