Skip to content

blackbull.router

blackbull.router

URL routing for BlackBull.

Router maps (path, method, scheme) triples to handler chains. Paths support exact strings, regex patterns, and {name} / {name:converter} parameter syntax; ErrorRouter does the same for HTTPStatus codes and exception classes. _register_chain composes per-route middlewares with functools.partial so each middleware receives call_next bound to the next link.

RouteGroup is defined in :mod:blackbull.app to avoid a circular import; this module re-exports it lazily through __getattr__.

ConfigurationError

Bases: Exception

Raised by Router.validate() when route definitions are inconsistent.

ErrorRouter

Maps HTTP error statuses and exception classes to ASGI error-handler functions.

Keys accepted by setitem / getitem: - HTTPStatus value (e.g. HTTPStatus.NOT_FOUND) - Exception class (e.g. ValueError)

Lookup rules
  • HTTPStatus key: exact match only.
  • Exception class: walks the MRO so a handler registered for a base class (e.g. Exception) catches all unhandled subclasses.
  • Returns None when no handler is found (caller decides the fallback).

Usage::

errors = ErrorRouter()

@errors[HTTPStatus.NOT_FOUND]
async def handle_404(scope, receive, send):
    ...

@errors[ValueError]
async def handle_value_error(scope, receive, send):
    ...

handler = errors[HTTPStatus.NOT_FOUND]   # → handle_404
handler = errors[KeyError()]              # → handle_value_error via MRO (if registered)
handler = errors[KeyError]               # same, accepting the class directly

__call__(key)

Decorator form: @errors[HTTPStatus.NOT_FOUND]

__getitem__(key)

Return the registered handler for key, or None if not found.

Accepts
  • HTTPStatus → exact match
  • exception class → MRO walk
  • exception instance → MRO walk on type(key)

MethodNotApplicable

Bases: Exception

Raised when the path exists but the HTTP method is not allowed.

PathNotRegistered

Bases: KeyError

Raised when no registered path matches the requested path.

Router

Bases: UserDict, BaseRouter

This class has 2 dictionaries: self.data and self.regex_. key: str or re.Pattern value: (function, methods, scheme)

__contains__(item)

Accept either a plain str (path only) or a (path, method, scheme) tuple. Search both self.data and self.regex_.

__getitem__(key)

key: (path: str, method: HTTPMethod, scheme: Scheme)

Uses the routing trie for O(path-depth) lookup of string-path routes, then falls back to a linear scan of raw re.Pattern routes.

Results are cached in _lookup_cache (up to _LOOKUP_CACHE_MAX entries) so repeated requests to the same (path, method, scheme) skip the trie traversal entirely after the first hit.

__setitem__(key, value)

If key[0] is a str: - Store it in self.data under the normalised (path, methods, scheme) key. - Also compile a regex from {param} / {param:converter} placeholders and store it in self.regex_ together with per-param converter functions.

If key[0] is a re.Pattern: - Store it in self.regex_ only.

When scheme is omitted it is stored as _ANY_SCHEME, which matches any scheme at lookup time.

route(methods=[HTTPMethod.GET], path='/', scheme=Scheme.http, functions=[], middlewares=[], name=None)

Register a function or middleware chain in the routing table.

Three calling conventions: 1. Decorator with no extra middlewares (functions and middlewares both empty) — returns a decorator via route_fn. 2. functions=[...] — registers a pre-built chain immediately; returns None (same as before). 3. middlewares=[...] — returns a decorator; the decorated handler is appended to the middleware list before the chain is registered.

name registers the route for use with url_path_for().

url_path_for(name, /, **params)

Return the path for the named route with params substituted.

Raises KeyError if the name is unknown, ValueError if required params are missing.

validate()

Check all route definitions for consistency, then freeze the router.

Checks performed:

  • Every converter spec names a known converter.
  • Every path param appears in the handler signature (simplified handlers).
  • Converter output type matches the handler's annotation.

Raises :class:ConfigurationError listing all violations found. Sets self._frozen = True on success so no further routes can be added. Called once at app boot from :meth:BlackBull.run / :meth:BlackBull.serve — handler bugs that violate the contract surface before the first request is served, not after.