No project description provided
Project description
flask-routes-py
Overview
The Flask web framework provides the decorator @app.route
to define handlers for routes, which is the recommended method for simple web apps. However, using this method requires
that route handlers be tied to a specific app, and can make it difficult to track/unit test routes for larger web apps.
flask-routes-py
provides mixins for defining routes as classes with static (classmethod
) handlers, with optional extras
like integrated request parameter parsing with flask-reqparser-py, and
automated route discovery and registration with lc-registry.
Installation
Install from PyPi (preferred method)
pip install lc-flask-routes
pip install lc-flask-routes[reqparser] # enable support for lc_flask_reqparser
pip install lc-flask-routes[registry] # enable support for lc_registry
pip install lc-flask-routes[all] # enable all options
Install from GitHub with Pip
pip install git+https://github.com/libcommon/flask-routes-py.git@vx.x.x#egg=lc_flask_routes
where x.x.x
is the version you want to download.
Install by Manual Download
To download the source distribution and/or wheel files, navigate to
https://github.com/libcommon/flask-routes-py/tree/releases/vx.x.x/dist
, where x.x.x
is the version you want to install,
and download either via the UI or with a tool like wget. Then to install run:
pip install <downloaded file>
Do not change the name of the file after downloading, as Pip requires a specific naming convention for installation files.
Dependencies
flask-routes-py
depends on, and is designed to work with, the
Flask framework. Optional dependencies also include
flask-reqparser-py for integrated request parameter parsing, and
lc-registry for route auto-discovery. Only Python versions >= 3.6 are
officially supported.
Getting Started
Define a base class that extends either the BaseRouteMixin
or BaseRouteWithParserMixin
class
(if installed with [reqparser]
or [all]
options) that all other route classes will extend. This class could
contain any helper methods or class variables needed by all routes, but should not define the ROUTE_MAP
class
variable.
from typing import Any, Dict, Optional
import flask
from lc_flask_routes import (
BaseRouteMixin,
BaseRouteWithParserMixin,
RouteResponse,
WerkzeugLocalProxy
)
from lc_flask_reqparser import RequestParser
class BaseRoute(BaseRouteMixin):
"""Base route."""
__slots__ = ()
class BaseParserRoute(BaseRouteWithParserMixin):
"""Base route with request parser."""
__slots__ = ()
@classmethod
def gen_request_parser(cls) -> Optional[RequestParser]:
return (RequestParser()
.add_argument("base_argument_for_all_routes"))
class IndexRoute(BaseRoute):
"""Route: /
Endpoint: "index"
Description: Splash page
"""
__slots__ = ()
ROUTE_MAP = {"/": {"endpoint": "index", "methods": ["GET", "POST"]}}
@classmethod
def get(cls,
app: WerkzeugLocalProxy,
request: WerkzeugLocalProxy,
session: WerkzeugLocalProxy,
route_kwargs: Dict[str, Any]) -> RouteResponse:
return "<h1>Splash Page</h1>"
@classmethod
def post(cls,
app: WerkzeugLocalProxy,
request: WerkzeugLocalProxy,
session: WerkzeugLocalProxy,
route_kwargs: Dict[str, Any]) -> RouteResponse:
return flask.redirect(url_for("index"))
if __name__ == "__main__":
app = flask.Flask(__name__)
IndexRoute.register_route(app)
app.run()
The ROUTE_MAP
class variable should only be defined on non-base routes, and its structure mimics the parameters
for Flask's @app.route
decorator, which really calls add_url_rule
under the hood. Each key is a URI, and each corresponding value are the keyword arguments passed to add_url_rule
. See Flask's documentation
for expectations and limitations of that function. BaseRouteMixin
has a register_route
method that accomplishes the same result as @app.route
.
Each route class must be registered individually (unless using RouteRegistryMixin
- see below).
If installed with the [registry]
or [all]
options, flask-routes-py
also exposes a RouteRegistryMixin
class to be used for auto-discovery
of route classes using metaprogramming. Define a Python metaclass
that extends RouteRegistryMixin
, then define a base class that uses this
metaclass
.
from abc import ABCMeta
from typing import Any, Dict
import flask
from lc_flask_routes import (
BaseRouteMixin,
BaseRouteWithParserMixin,
RouteResponse,
WerkzeugLocalProxy
)
class RouteRegistry(RouteRegistryMixin, ABCMeta):
"""Route registry."""
__slots__ = ()
_REGISTRY = dict()
class BaseRoute(BaseRouteMixin, metaclass=RouteRegistry):
"""Base route. Any child class will be registered in
RouteRegistry's _REGISTRY class variable automatically
(as long as it's in scope)."""
class IndexRoute(BaseRoute):
"""Route: /
Endpoint: "index"
Description: Splash page
"""
__slots__ = ()
ROUTE_MAP = {"/": {"endpoint": "index", "methods": ["GET"]}}
@classmethod
def get(cls,
app: WerkzeugLocalProxy,
request: WerkzeugLocalProxy,
session: WerkzeugLocalProxy,
route_kwargs: Dict[str, Any]) -> RouteResponse:
return "<h1>Splash Page</h1>"
class LoginRoute(BaseRoute):
"""Route: /login
Endpoint: "login"
Description: Login workflow
"""
__slots__ = ()
ROUTE_MAP = {"/login": {"endpoint": "login", "methods": ["POST"]}}
@classmethod
def post(cls,
app: WerkzeugLocalProxy,
request: WerkzeugLocalProxy,
session: WerkzeugLocalProxy,
route_kwargs: Dict[str, Any]) -> RouteResponse:
// Do some work to verify identity
return flask.redirect(url_for("index"))
if __name__ == "__main__":
app = flask.Flask(__name__)
# Register IndexRoute and LoginRoute with app
RouteRegistry.register_routes(app)
app.run()
RouteRegistryMixin
exposes two methods for registering routes with an app: register_routes
and register_routes_where
.
As shown above, register_routes
will register all routes in the registry without any filtering, whereas register_routes_where
evaluates a provided predicate on reach route class before registering it. This could be useful, for example, if the same registry is being used
to initialize two different apps based on a class variable.
Contributing/Suggestions
Contributions and suggestions are welcome! To make a feature request, report a bug, or otherwise comment on existing functionality, please file an issue. For contributions please submit a PR, but make sure to lint, type-check, and test your code before doing so. Thanks in advance!
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file lc_flask_routes-0.1.0-2.tar.gz
.
File metadata
- Download URL: lc_flask_routes-0.1.0-2.tar.gz
- Upload date:
- Size: 8.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.23.0 setuptools/41.2.0 requests-toolbelt/0.9.1 tqdm/4.46.1 CPython/3.7.7
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 5a98e57fbbfb418402328355819946a03eaccf27c7a8bf5679581d2d8d32d645 |
|
MD5 | 06e565f4d7f4e5b92632219a339d4179 |
|
BLAKE2b-256 | 8da6a42d8ab7453cb3251545656aa9cbb11fabed5b467bbfa7899ac3a8845e8e |
File details
Details for the file lc_flask_routes-0.1.0-2-py3-none-any.whl
.
File metadata
- Download URL: lc_flask_routes-0.1.0-2-py3-none-any.whl
- Upload date:
- Size: 10.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.23.0 setuptools/41.2.0 requests-toolbelt/0.9.1 tqdm/4.46.1 CPython/3.7.7
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 79203151f9aef7a4130aae8de3d9c3489a1ba8cff9e2107f9a5f41cb3c6e3663 |
|
MD5 | 94c8195412ec42bf2c102f95684cdfc0 |
|
BLAKE2b-256 | 16b879e946309d5f42904ab0ce6b8230c8081b4295a32091ea2b879d3992378b |