hack-house/.venv/lib/python3.12/site-packages/sanic_routing/utils.py
leetcrypt bb1d662ee1 chore: rename project coven → hack-house ⛧
Rebrand the Rust client crate (coven/ → hh/, package+binary "hack-house"),
README, CLI strings, and branch (coven → hack-house). Gitea repo renamed
cmd-chat → hack-house to match. Crypto/server logic unchanged; selftest +
golden-vector test still green, binary is now `hack-house`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 13:29:14 -07:00

98 lines
3.3 KiB
Python

import re
from urllib.parse import quote, unquote
from sanic_routing.exceptions import InvalidUsage
from .patterns import REGEX_PARAM_NAME, REGEX_PARAM_NAME_EXT
class Immutable(dict):
def __setitem__(self, *args):
raise TypeError("Cannot change immutable dict")
def __delitem__(self, *args):
raise TypeError("Cannot change immutable dict")
def parse_parameter_basket(route, basket, raw_path=None):
params = {}
if basket:
for idx, value in basket.items():
for p in route.params[idx]:
if not raw_path or p.raw_path == raw_path:
if not p.regex:
raw_path = p.raw_path
params[p.name] = p.cast(value)
break
elif p.pattern.search(value):
raw_path = p.raw_path
if "(" in p.pattern:
groups = p.pattern.match(value)
value = groups.group(1)
params[p.name] = p.cast(value)
break
if raw_path:
raise ValueError("Invalid parameter")
if raw_path and not params[p.name]:
raise ValueError("Invalid parameter")
if route.unquote:
for p in route.params[idx]:
if isinstance(params[p.name], str):
params[p.name] = unquote(params[p.name])
if raw_path is None:
raise ValueError("Invalid parameter")
return params, raw_path
def path_to_parts(path, delimiter="/"):
r"""
OK > /foo/<id:int>/bar/<name:[A-z]+>
OK > /foo/<unhashable:[A-Za-z0-9/]+>
OK > /foo/<ext:file\.(?P<ext>txt)>/<ext:[a-z]>
OK > /foo/<user>/<user:str>
OK > /foo/<ext:[a-z]>/<ext:file\.(?P<ext>txt)d>
NOT OK > /foo/<ext:file\.(?P<ext>txt)d>/<ext:[a-z]>
"""
path = unquote(path.lstrip(delimiter))
delimiter = re.escape(delimiter)
return tuple(
part if part.startswith("<") else quote(part)
for part in re.split(rf"{delimiter}(?=[^>]*(?:<(?<!\?<)|$))", path)
)
def parts_to_path(parts, delimiter="/"):
path = []
for part in parts:
if part.startswith("<"):
try:
match = REGEX_PARAM_NAME.match(part)
param_type = ""
if match.group(2):
param_type = f":{match.group(2)}"
path.append(f"<{match.group(1)}{param_type}>")
except AttributeError:
try:
match = REGEX_PARAM_NAME_EXT.match(part)
filename_type = ""
extension_type = ""
if match.group(2):
filename_type = f"={match.group(2)}"
if match.group(3):
extension_type = f"={match.group(3)}"
segment = (
f"<{match.group(1)}{filename_type}:"
f"ext{extension_type}>"
)
path.append(segment)
except AttributeError:
raise InvalidUsage(f"Invalid declaration: {part}")
else:
path.append(part)
return delimiter.join(path)