PyGER
Python Generic Extensible Router
PyGER lets you build arbitrary route matchers and nested matching trees. It provides a flexible and powerful routing layer that enables a clean separation between handling request types and request content.
Features
A composable request-matching interface: PyGER lets you build a routing layer to dispatch on any facet of a request. This means you can model any state of the world and match it to your request handler (e.g. HTTP headers, authentication state, the time of day, etc.).
Powerful built-in URI path routing: PyGER ships with a pre-made path router which supports
relative paths (/resource/../actually_another_resource
), regex matched path segments
(/fruits/{fruit_id:\d+}
), and remainder matching (/root/{*the_rest_of_the_segments}
). It
supports valid RFC3986 paths and it aims
to be the fastest pure-Python router with its feature set.
Routing and only routing: By default, PyGER does not invoke any matched handlers, rather it returns the matched handlers and information from the matching process. This is different from the behavior you might expect from a controller where you can input a request and the desired effects are performed. In contrast, PyGER lets you fully isolate choosing a function from executing it resulting in applications that are easier to read, test, and reason about.
Support for Python 3.4+: Official support for Python 3.4 and up, with tests run against both CPython and PyPy (PyPy3.3 until a newer version is stable).
Installation
Installing PyGER is as simple as:
pip install pyger
Preferably inside a virtual environment.
Basic Usage
Here is a simple example of how you would set up the path router:
from pyger.routers import URIPathRouter
def foo_handler(): pass
def bar_handler(): pass
router = URIPathRouter()
router.connect(foo_handler, path="/foo/{foo_id}")
router.connect(bar_handler, path="/bar/{*path_to_specific_bar}")
And here is how you would evaluate paths against it:
>>> router.match(path="/foo/blip")
RouteMatch(target=<function foo_handler>, match_info={'foo_id': 'fizzle'})
>>> router.match(path="/bar/baz/blip/bloop/")
RouteMatch(target=<function bar_handler>, match_info={'*path_to_specific_bar': ('baz', 'blip', 'bloop')})
>>> router.match(path="/unregistered_route")
pyger.base.MatchError
Check out the project examples to see how to build nested routers, or how to integrate PyGER within a web framework.
Contributing
PyGER is a young project and all contributions are welcome! Feel free to open an issue or suggest a change in a pull request.
The project could particularly benefit from new example scripts integrating PyGER with your favorite web frameworks, as well as new examples of using PyGER outside of the HTTP domain.
License
BSD licensed. See the LICENSE file for details.