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]