Skip to main content

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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

lc_flask_routes-0.1.0-2.tar.gz (8.1 kB view details)

Uploaded Source

Built Distribution

lc_flask_routes-0.1.0-2-py3-none-any.whl (10.1 kB view details)

Uploaded Python 3

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

Hashes for lc_flask_routes-0.1.0-2.tar.gz
Algorithm Hash digest
SHA256 5a98e57fbbfb418402328355819946a03eaccf27c7a8bf5679581d2d8d32d645
MD5 06e565f4d7f4e5b92632219a339d4179
BLAKE2b-256 8da6a42d8ab7453cb3251545656aa9cbb11fabed5b467bbfa7899ac3a8845e8e

See more details on using hashes here.

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

Hashes for lc_flask_routes-0.1.0-2-py3-none-any.whl
Algorithm Hash digest
SHA256 79203151f9aef7a4130aae8de3d9c3489a1ba8cff9e2107f9a5f41cb3c6e3663
MD5 94c8195412ec42bf2c102f95684cdfc0
BLAKE2b-256 16b879e946309d5f42904ab0ce6b8230c8081b4295a32091ea2b879d3992378b

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page