Source code for duck.routes

"""
Module for route-specific actions.
"""
import os
import pathlib

from typing import List

from duck.routes.route_blueprint import Blueprint
from duck.routes.route_registry import RouteRegistry
from duck.exceptions.all import (
    RouteError,
    BlueprintError,
)
from duck.urls import URLPattern
from duck.utils.path import joinpaths, sanitize_path_segment


[docs] class BlueprintJoinPathError(BlueprintError): """ Raised on function `blueprint_joinpath` if blueprint_subdir is not not really a subpath or doesn't belong to blueprint root directory. """
[docs] class BlueprintJoinPathNameNoMatch(BlueprintJoinPathError): """ Raised on function `blueprint_joinpath` If path's root name is not equal to blueprint name. Handle this to avoid unnecessary lookup for unresolvable paths. """
[docs] def register_urlpatterns(urlpatterns: List[URLPattern]): """ Register some application urlpatterns. """ # register route urlpatterns for urlpattern in urlpatterns: try: if urlpattern.regex: # this is a regex urlpattern url, handler, name, methods = ( urlpattern['url'], urlpattern['handler'], urlpattern['name'], urlpattern['methods'] ) RouteRegistry.regex_register( url, handler, name, methods, ) else: # this is a normal urlpattern url, handler, name, methods = ( urlpattern['url'], urlpattern['handler'], urlpattern['name'], urlpattern['methods'] ) RouteRegistry.register( url, handler, name, methods, ) except Exception as e: raise RouteError(f"Error registering URL pattern '{urlpattern}': {e}")
[docs] def register_blueprints(blueprints: List[Blueprint]): """ Register some application blueprints. """ # Register route blueprint.urlpatterns for blueprint in blueprints: try: register_urlpatterns(blueprint.urlpatterns) except Exception as e: raise BlueprintError(f"Error registering urlpatterns for blueprint '{blueprint}' ") from e
[docs] def blueprint_joinpath(blueprint_subdir: str, path: str, blueprint: Blueprint) -> str: """ Joins directory to form a final blueprint resolvable path. This makes it easy to resolve sub blueprint paths/files. Args: blueprint_subdir (str): This is the absolute subdirectory to the blueprint root directory. path (str): The path to join with, will be joined correctly without the path rootname if blueprint name == path rootname. blueprint (Blueprint): The blueprint with the blueprint_subdir. Raises: ValueError: If path is not relative path. BlueprintJoinPathError: If blueprint_subdir is not not really a subpath or doesn't belong to blueprint root directory. BlueprintJoinPathNameNoMatch: If path's root name is not equal to blueprint name. Handle this to avoid unnecessary lookup for unresolvable paths. Example: ```py # The blueprint_subdir can be any absolute blueprint subpath e.g. template_dir/static_dir blueprint_subdir = "/some/absolute/blueprint/subpath" # This is the target blueprint with the base_dir e.g. template dir blueprint = SomeBlueprint(...) # This is a path of a file you wanna resolve inside the blueprint_subdir # For this to be resolvable in blueprint subdir, Blueprint name must be the first path part. path = "blueprint_name/some/file" # This works if the blueprint name == path root name even if the blueprint path is different. print(blueprint_joinpath(base_dir, path, blueprint)) # Outputs: /some/absolute/blueprint/subpath/some/file ``` """ # Normalize path and remove the first backslash so that pathlib can interpret # `parts` correctly. path = sanitize_path_segment(path).lstrip('/') # Now continue. path = pathlib.Path(path) blueprint_subdir = pathlib.Path(blueprint_subdir.replace("\\", "/")) path_root_name = path.parts[0].strip('/') if path.is_absolute(): raise ValueError("The `path` argument must be a relative path.") try: # Find if the blueprint_subdir belongs to the blueprint root directory. _ = blueprint_subdir.relative_to(str(blueprint.root_directory).replace("\\", "/")) except ValueError as e: raise BlueprintJoinPathError(str(e)) if path_root_name != blueprint.name: raise BlueprintJoinPathNameNoMatch( "The path's name doesn't match with blueprint name, " "this may mean this path is not meant to be resolved at this blueprint subpath." ) # Remove the path's root name and join with blueprint subpath. path = str(path).lstrip('/').lstrip(path_root_name) return joinpaths(blueprint_subdir, path)