1from __future__ import annotations
 2
 3import functools
 4import uuid
 5from typing import Any
 6
 7
 8class IntConverter:
 9    regex = "[0-9]+"
10
11    def to_python(self, value: str) -> int:
12        return int(value)
13
14    def to_url(self, value: int) -> str:
15        return str(value)
16
17
18class StringConverter:
19    regex = "[^/]+"
20
21    def to_python(self, value: str) -> str:
22        return value
23
24    def to_url(self, value: str) -> str:
25        return value
26
27
28class UUIDConverter:
29    regex = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"
30
31    def to_python(self, value: str) -> uuid.UUID:
32        return uuid.UUID(value)
33
34    def to_url(self, value: uuid.UUID) -> str:
35        return str(value)
36
37
38class SlugConverter(StringConverter):
39    regex = "[-a-zA-Z0-9_]+"
40
41
42class PathConverter(StringConverter):
43    regex = ".+"
44
45
46_DEFAULT_CONVERTERS = {
47    "int": IntConverter(),
48    "path": PathConverter(),
49    "slug": SlugConverter(),
50    "str": StringConverter(),
51    "uuid": UUIDConverter(),
52}
53
54
55_REGISTERED_CONVERTERS: dict[str, Any] = {}
56
57
58def register_converter(converter: type, type_name: str) -> None:
59    _REGISTERED_CONVERTERS[type_name] = converter()
60    _get_converters.cache_clear()
61
62
63@functools.cache
64def _get_converters() -> dict[str, Any]:
65    return {**_DEFAULT_CONVERTERS, **_REGISTERED_CONVERTERS}
66
67
68def _get_converter(raw_converter: str) -> Any:
69    return _get_converters()[raw_converter]