fastapi-dynamic-route-registration 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fastapi_dynamic_route_registration/__init__.py +14 -0
- fastapi_dynamic_route_registration/py.typed +0 -0
- fastapi_dynamic_route_registration/register_routers.py +109 -0
- fastapi_dynamic_route_registration/router_decorator.py +139 -0
- fastapi_dynamic_route_registration-0.1.0.dist-info/METADATA +149 -0
- fastapi_dynamic_route_registration-0.1.0.dist-info/RECORD +9 -0
- fastapi_dynamic_route_registration-0.1.0.dist-info/WHEEL +5 -0
- fastapi_dynamic_route_registration-0.1.0.dist-info/licenses/LICENSE +21 -0
- fastapi_dynamic_route_registration-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""
|
|
2
|
+
FastAPI Dynamic Route Registration
|
|
3
|
+
------------------------------------
|
|
4
|
+
A library to help dynamically register routes in FastAPI applications.
|
|
5
|
+
|
|
6
|
+
Drop-in spiritual successor to ``flask-dynamic-route-registration``.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from .register_routers import register_router, register_routers
|
|
10
|
+
from .router_decorator import register_route
|
|
11
|
+
|
|
12
|
+
__version__ = "0.1.0"
|
|
13
|
+
|
|
14
|
+
__all__ = ["register_route", "register_router", "register_routers"]
|
|
File without changes
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
from collections.abc import Mapping
|
|
2
|
+
from inspect import getmembers
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from fastapi import APIRouter, FastAPI
|
|
6
|
+
|
|
7
|
+
from .router_decorator import is_register_route
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def register_router(
|
|
11
|
+
container: FastAPI | APIRouter,
|
|
12
|
+
module_name: str,
|
|
13
|
+
routers_data: str | Any | list[str | Any],
|
|
14
|
+
route_kwargs: Mapping[str, Any],
|
|
15
|
+
) -> list[APIRouter]:
|
|
16
|
+
"""Register a single module's routes into *container*.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
container: A ``FastAPI`` app or parent ``APIRouter`` to mount the new
|
|
20
|
+
router(s) into.
|
|
21
|
+
module_name: Dotted import path of the module that contains
|
|
22
|
+
``@register_route``-decorated functions.
|
|
23
|
+
routers_data: Configuration data.
|
|
24
|
+
|
|
25
|
+
- ``str`` — treated as the URL prefix for a single router.
|
|
26
|
+
- ``dict`` — may have keys ``router_name``, ``router_kwargs``
|
|
27
|
+
(passed to ``APIRouter()``) and ``params`` (injected into every
|
|
28
|
+
route as default values, same semantics as the Flask version).
|
|
29
|
+
- ``list`` — list of the above; mounts the module multiple times
|
|
30
|
+
at different prefixes or with different params.
|
|
31
|
+
|
|
32
|
+
route_kwargs: Extra key/value pairs merged into every router's
|
|
33
|
+
``params`` dict and bound as default parameter values in decorated
|
|
34
|
+
route functions. Use this to inject shared dependencies such as
|
|
35
|
+
an application context object.
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
List of the newly created ``APIRouter`` instances (empty list if the
|
|
39
|
+
module contains no ``@register_route``-decorated functions).
|
|
40
|
+
"""
|
|
41
|
+
module_object = __import__(module_name, fromlist=[""])
|
|
42
|
+
functions = getmembers(module_object, is_register_route)
|
|
43
|
+
|
|
44
|
+
if not functions:
|
|
45
|
+
return []
|
|
46
|
+
|
|
47
|
+
if not isinstance(routers_data, list):
|
|
48
|
+
routers_data = [routers_data]
|
|
49
|
+
|
|
50
|
+
new_routers: list[APIRouter] = []
|
|
51
|
+
|
|
52
|
+
for router_data in routers_data:
|
|
53
|
+
if isinstance(router_data, str):
|
|
54
|
+
router_data = {"router_kwargs": {"prefix": router_data}}
|
|
55
|
+
|
|
56
|
+
router_kwargs: dict[str, Any] = router_data.get("router_kwargs", {})
|
|
57
|
+
params: dict[str, Any] = {**router_data.get("params", {}), **route_kwargs}
|
|
58
|
+
|
|
59
|
+
# Normalise Flask-style url_prefix key in router_kwargs
|
|
60
|
+
if "url_prefix" in router_kwargs and "prefix" not in router_kwargs:
|
|
61
|
+
router_kwargs["prefix"] = router_kwargs.pop("url_prefix")
|
|
62
|
+
|
|
63
|
+
new_router = APIRouter(**router_kwargs)
|
|
64
|
+
|
|
65
|
+
for _name, register_fn in functions:
|
|
66
|
+
register_fn(new_router, **params)
|
|
67
|
+
|
|
68
|
+
container.include_router(new_router)
|
|
69
|
+
new_routers.append(new_router)
|
|
70
|
+
|
|
71
|
+
return new_routers
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def register_routers(
|
|
75
|
+
container: FastAPI | APIRouter,
|
|
76
|
+
module_prefix: str,
|
|
77
|
+
routers: Mapping[str, Any],
|
|
78
|
+
route_kwargs: Mapping[str, Any],
|
|
79
|
+
**kwargs: Any,
|
|
80
|
+
) -> APIRouter:
|
|
81
|
+
"""Register multiple modules' routes into *container*.
|
|
82
|
+
|
|
83
|
+
Mirrors ``register_blueprints`` from the Flask version. Each key in
|
|
84
|
+
*routers* is a module suffix (appended to *module_prefix* with a ``.``
|
|
85
|
+
separator) and its value is the *routers_data* accepted by
|
|
86
|
+
:func:`register_router`.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
container: A ``FastAPI`` app or parent ``APIRouter``.
|
|
90
|
+
module_prefix: Common dotted prefix for all modules (e.g.
|
|
91
|
+
``"myapp.api"``).
|
|
92
|
+
routers: Mapping of ``{module_suffix: routers_data}``.
|
|
93
|
+
route_kwargs: Extra key/value pairs merged into every route's params
|
|
94
|
+
and bound as default parameter values (e.g.
|
|
95
|
+
``{"app_context": ctx}``).
|
|
96
|
+
**kwargs: Extra kwargs forwarded to the top-level ``APIRouter``
|
|
97
|
+
constructor (e.g. ``tags``, ``dependencies``).
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
The top-level ``APIRouter`` that wraps all sub-routers.
|
|
101
|
+
"""
|
|
102
|
+
parent_router = APIRouter(**kwargs)
|
|
103
|
+
|
|
104
|
+
for module_suffix, routers_data in routers.items():
|
|
105
|
+
module_name = f"{module_prefix}.{module_suffix}"
|
|
106
|
+
register_router(parent_router, module_name, routers_data, route_kwargs)
|
|
107
|
+
|
|
108
|
+
container.include_router(parent_router)
|
|
109
|
+
return parent_router
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import functools
|
|
2
|
+
import inspect
|
|
3
|
+
import types
|
|
4
|
+
from collections.abc import Callable
|
|
5
|
+
from typing import Any, Protocol
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class EndpointEnabledCallback(Protocol):
|
|
9
|
+
def __call__(self, **params: Any) -> bool: ...
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _bind_params_as_defaults(
|
|
13
|
+
func: Callable[..., Any], params: dict[str, Any]
|
|
14
|
+
) -> Callable[..., Any]:
|
|
15
|
+
"""Return a new callable with *params* injected as parameter defaults.
|
|
16
|
+
|
|
17
|
+
FastAPI introspects ``__signature__`` to build request validation and
|
|
18
|
+
dependency injection. We replace the signature so that any key in
|
|
19
|
+
*params* that matches a parameter name becomes its default value,
|
|
20
|
+
overriding any pre-existing default. This mirrors the
|
|
21
|
+
``defaults=params`` mechanism of Flask blueprints.
|
|
22
|
+
|
|
23
|
+
Only params whose keys appear in the function signature (or the function
|
|
24
|
+
accepts ``**kwargs``) are injected; unrecognized keys are silently dropped
|
|
25
|
+
so that one ``route_kwargs`` dict can be broadcast to all routes without
|
|
26
|
+
causing ``TypeError`` for routes that don't declare every key.
|
|
27
|
+
|
|
28
|
+
``**kwargs`` (VAR_KEYWORD) parameters are stripped from the
|
|
29
|
+
FastAPI-visible signature because FastAPI cannot handle them and would
|
|
30
|
+
attempt to treat them as query parameters.
|
|
31
|
+
"""
|
|
32
|
+
sig = inspect.signature(func)
|
|
33
|
+
accepts_var_keyword = any(
|
|
34
|
+
p.kind is inspect.Parameter.VAR_KEYWORD for p in sig.parameters.values()
|
|
35
|
+
)
|
|
36
|
+
# Params to actually inject: only those accepted by the function.
|
|
37
|
+
injectable = {
|
|
38
|
+
k: v for k, v in params.items() if k in sig.parameters or accepts_var_keyword
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
new_params = []
|
|
42
|
+
for name, param in sig.parameters.items():
|
|
43
|
+
# Drop **kwargs from the FastAPI-visible signature: FastAPI cannot
|
|
44
|
+
# handle VAR_KEYWORD parameters and would try to make them query params.
|
|
45
|
+
if param.kind is inspect.Parameter.VAR_KEYWORD:
|
|
46
|
+
continue
|
|
47
|
+
if name in injectable:
|
|
48
|
+
# Always override the existing default so that injected values
|
|
49
|
+
# from per-router params take precedence over function-level defaults.
|
|
50
|
+
new_params.append(param.replace(default=injectable[name]))
|
|
51
|
+
else:
|
|
52
|
+
new_params.append(param)
|
|
53
|
+
|
|
54
|
+
if inspect.iscoroutinefunction(func):
|
|
55
|
+
|
|
56
|
+
@functools.wraps(func)
|
|
57
|
+
async def async_bound(*args: Any, **kwargs: Any) -> Any:
|
|
58
|
+
for k, v in injectable.items():
|
|
59
|
+
kwargs.setdefault(k, v)
|
|
60
|
+
return await func(*args, **kwargs)
|
|
61
|
+
|
|
62
|
+
async_bound.__signature__ = sig.replace(parameters=new_params) # type: ignore[attr-defined]
|
|
63
|
+
return async_bound
|
|
64
|
+
else:
|
|
65
|
+
|
|
66
|
+
@functools.wraps(func)
|
|
67
|
+
def sync_bound(*args: Any, **kwargs: Any) -> Any:
|
|
68
|
+
for k, v in injectable.items():
|
|
69
|
+
kwargs.setdefault(k, v)
|
|
70
|
+
return func(*args, **kwargs)
|
|
71
|
+
|
|
72
|
+
sync_bound.__signature__ = sig.replace(parameters=new_params) # type: ignore[attr-defined]
|
|
73
|
+
return sync_bound
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def register_route(
|
|
77
|
+
path: str,
|
|
78
|
+
*,
|
|
79
|
+
methods: list[str] | None = None,
|
|
80
|
+
endpoint: str | None = None,
|
|
81
|
+
enabled: bool | EndpointEnabledCallback = True,
|
|
82
|
+
**route_kwargs: Any,
|
|
83
|
+
) -> Callable[..., Any]:
|
|
84
|
+
"""Decorator that marks a function as a FastAPI route to be registered later.
|
|
85
|
+
|
|
86
|
+
Usage is intentionally identical to the Flask ``register_route`` decorator so
|
|
87
|
+
that endpoint modules can be ported with minimal diff.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
path: The URL path relative to the router prefix (e.g. ``""`` or
|
|
91
|
+
``"/{dag_id}"``). Flask ``<param>`` syntax is **not** supported;
|
|
92
|
+
use FastAPI path syntax ``{param}`` directly.
|
|
93
|
+
methods: HTTP methods (default ``["GET"]``).
|
|
94
|
+
endpoint: Override the operation name; defaults to the function name.
|
|
95
|
+
enabled: ``True``, ``False``, or a callable ``(**params) -> bool`` that
|
|
96
|
+
receives the per-router *params* at registration time.
|
|
97
|
+
**route_kwargs: Extra kwargs forwarded to ``router.add_api_route()``.
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
A ``Callable`` wrapper tagged with ``.is_url_rule = True``. When
|
|
101
|
+
called as ``wrapper(router, **params)``, it registers the original
|
|
102
|
+
function on the given ``APIRouter`` with *params* bound as parameter
|
|
103
|
+
defaults via :func:`_bind_params_as_defaults`.
|
|
104
|
+
"""
|
|
105
|
+
_methods = methods or ["GET"]
|
|
106
|
+
|
|
107
|
+
def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
|
|
108
|
+
_endpoint = endpoint or func.__name__
|
|
109
|
+
|
|
110
|
+
def wrapper(router: Any, **params: Any) -> None:
|
|
111
|
+
if callable(enabled):
|
|
112
|
+
endpoint_enabled: bool = enabled(**params)
|
|
113
|
+
else:
|
|
114
|
+
endpoint_enabled = enabled
|
|
115
|
+
|
|
116
|
+
if not endpoint_enabled:
|
|
117
|
+
return
|
|
118
|
+
|
|
119
|
+
# Always run through _bind_params_as_defaults so that **kwargs
|
|
120
|
+
# is stripped from the FastAPI-visible signature even when params
|
|
121
|
+
# is empty.
|
|
122
|
+
bound_func = _bind_params_as_defaults(func, params)
|
|
123
|
+
|
|
124
|
+
router.add_api_route(
|
|
125
|
+
path,
|
|
126
|
+
bound_func,
|
|
127
|
+
methods=_methods,
|
|
128
|
+
name=_endpoint,
|
|
129
|
+
**route_kwargs,
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
wrapper.is_url_rule = True # type: ignore[attr-defined]
|
|
133
|
+
return wrapper
|
|
134
|
+
|
|
135
|
+
return decorator
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def is_register_route(func: Any) -> bool:
|
|
139
|
+
return isinstance(func, types.FunctionType) and getattr(func, "is_url_rule", False)
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: fastapi-dynamic-route-registration
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A library to help dynamically register routes in FastAPI applications.
|
|
5
|
+
Author-email: Jérôme DIAZ <jerome_diaz@me.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/jeromediaz/fastapi-dynamic-route-registration
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/jeromediaz/fastapi-dynamic-route-registration/issues
|
|
9
|
+
Keywords: fastapi,route,dynamic
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Framework :: FastAPI
|
|
14
|
+
Classifier: Typing :: Typed
|
|
15
|
+
Requires-Python: >=3.12
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: fastapi>=0.100.0
|
|
19
|
+
Requires-Dist: typing-extensions>=4.0.0
|
|
20
|
+
Provides-Extra: dev
|
|
21
|
+
Requires-Dist: black; extra == "dev"
|
|
22
|
+
Requires-Dist: pytest; extra == "dev"
|
|
23
|
+
Requires-Dist: ruff; extra == "dev"
|
|
24
|
+
Requires-Dist: mypy; extra == "dev"
|
|
25
|
+
Requires-Dist: httpx; extra == "dev"
|
|
26
|
+
Dynamic: license-file
|
|
27
|
+
|
|
28
|
+
# FastAPI dynamic route registration
|
|
29
|
+
|
|
30
|
+
[](https://pypi.org/project/fastapi-dynamic-route-registration/)
|
|
31
|
+
[](https://pypi.org/project/fastapi-dynamic-route-registration/)
|
|
32
|
+
|
|
33
|
+
A library to help dynamically register routes in FastAPI applications.
|
|
34
|
+
|
|
35
|
+
It is the FastAPI successor to [flask-dynamic-route-registration](https://github.com/jeromediaz/flask-dynamic-route-registration): endpoint modules decorate their functions with `@register_route`, and the application mounts whole modules from a configuration map — with per-router prefixes and shared values injected as parameter defaults.
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pip install fastapi-dynamic-route-registration
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## How to Use
|
|
42
|
+
### Basic Setup
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
from fastapi import FastAPI
|
|
46
|
+
from fastapi_dynamic_route_registration import register_router
|
|
47
|
+
|
|
48
|
+
app = FastAPI()
|
|
49
|
+
|
|
50
|
+
register_router(app, "healthcheck", "", {})
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Inside the `healthcheck/__init__.py` file
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
from fastapi_dynamic_route_registration import register_route
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@register_route("/health")
|
|
60
|
+
def health() -> dict:
|
|
61
|
+
return {"status": "OK"}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Reusing a module with different parameters, conditional routes
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
api_versions = [
|
|
68
|
+
{"router_kwargs": {"prefix": "/api/1"}, "params": {"version": 1}},
|
|
69
|
+
{"router_kwargs": {"prefix": "/api/2"}, "params": {"version": 2}},
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
register_router(app, "api", api_versions, {})
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Inside the `api/__init__.py` file
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
from fastapi_dynamic_route_registration import register_route
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@register_route("/status")
|
|
82
|
+
def status(*, version: int = 1) -> dict:
|
|
83
|
+
return {"status": "OK", "version": version}
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@register_route("/foo", enabled=lambda **params: params.get("version", 1) >= 2)
|
|
87
|
+
def foo_a() -> dict:
|
|
88
|
+
return {"hello": "world"}
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
@register_route("/foo/{subject}", enabled=lambda **params: params.get("version", 1) >= 2)
|
|
92
|
+
def foo_b(subject: str) -> dict:
|
|
93
|
+
return {"hello": subject}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
This registers four routes:
|
|
97
|
+
|
|
98
|
+
| URL | Return value | Function |
|
|
99
|
+
|----------------------|--------------------------------|----------|
|
|
100
|
+
| /api/1/status | {"status": "OK", "version": 1} | status |
|
|
101
|
+
| /api/2/status | {"status": "OK", "version": 2} | status |
|
|
102
|
+
| /api/2/foo | {"hello": "world"} | foo_a |
|
|
103
|
+
| /api/2/foo/{subject} | {"hello": subject} | foo_b |
|
|
104
|
+
|
|
105
|
+
Values from `params` (and from the `route_kwargs` passed to `register_router`) become the **default value** of the parameter with the same name. FastAPI still sees that parameter: a plain `version: int = 1` stays a query parameter, whose default is now the injected value. Keys a function does not declare are dropped — unless it accepts `**kwargs`, in which case they are passed on every call while `**kwargs` itself stays hidden from FastAPI. One shared mapping (e.g. an application context object) can therefore be broadcast to every route.
|
|
106
|
+
|
|
107
|
+
### Other route options
|
|
108
|
+
|
|
109
|
+
`register_route` forwards extra keyword arguments to `APIRouter.add_api_route`:
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
@register_route("/items", methods=["POST"], status_code=201, tags=["items"])
|
|
113
|
+
def create_item(item: Item) -> Item:
|
|
114
|
+
return item
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Registering multiple modules at once
|
|
118
|
+
|
|
119
|
+
`register_routers` (plural) registers several modules under a shared parent router:
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
from fastapi import FastAPI
|
|
123
|
+
from fastapi_dynamic_route_registration import register_routers
|
|
124
|
+
|
|
125
|
+
app = FastAPI()
|
|
126
|
+
|
|
127
|
+
register_routers(
|
|
128
|
+
app,
|
|
129
|
+
"myapp.api",
|
|
130
|
+
{
|
|
131
|
+
"healthcheck": "",
|
|
132
|
+
"users": {"router_kwargs": {"prefix": "/users"}},
|
|
133
|
+
},
|
|
134
|
+
route_kwargs={},
|
|
135
|
+
prefix="/v1",
|
|
136
|
+
)
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Each value accepts the same shapes as `register_router`: a prefix string, a dict with `router_kwargs` (passed to `APIRouter`) and `params`, or a list of those. A configuration map like this is easy to keep in a JSON file per application.
|
|
140
|
+
|
|
141
|
+
### Differences from the Flask version
|
|
142
|
+
|
|
143
|
+
- Path parameters use FastAPI syntax: `{param}`, not `<param>`.
|
|
144
|
+
- `router_kwargs` replaces `blueprint_kwargs`; a Flask-style `url_prefix` key is still accepted and mapped to `prefix`.
|
|
145
|
+
- One function registers one route.
|
|
146
|
+
|
|
147
|
+
## License
|
|
148
|
+
|
|
149
|
+
This project is licensed under the MIT License - see the [LICENSE](https://github.com/jeromediaz/fastapi-dynamic-route-registration/blob/main/LICENSE) file for details.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
fastapi_dynamic_route_registration/__init__.py,sha256=yQnd639AlyfLywnsCg2N4zO0NZCdvT3CcO_TnVB8JLs,423
|
|
2
|
+
fastapi_dynamic_route_registration/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
fastapi_dynamic_route_registration/register_routers.py,sha256=p9Nb1KtZ1wlwks0p-44A1aqBQzduBr1XdmDOdYcvpBg,4055
|
|
4
|
+
fastapi_dynamic_route_registration/router_decorator.py,sha256=mPRpQDLDGftH_DUvHCrZpc0LCWqv5KALaSH0QSzohwA,5340
|
|
5
|
+
fastapi_dynamic_route_registration-0.1.0.dist-info/licenses/LICENSE,sha256=5LFZRGEYJM0yj60bF-rPdi3ANN0-Vb_SOx6PgXS_KLs,1069
|
|
6
|
+
fastapi_dynamic_route_registration-0.1.0.dist-info/METADATA,sha256=_XN1-7efg3kuHP2WuhgjT8ckZrR67IUWqEurnZ55UcU,5419
|
|
7
|
+
fastapi_dynamic_route_registration-0.1.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
8
|
+
fastapi_dynamic_route_registration-0.1.0.dist-info/top_level.txt,sha256=SqDVD53KRr-11bHU-4JdweXVzr8XpZigin5Soa0Qct0,35
|
|
9
|
+
fastapi_dynamic_route_registration-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 DIAZ Jérôme
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
fastapi_dynamic_route_registration
|