fastlifeweb 0.11.0__py3-none-any.whl → 0.12.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.
- fastlife/config/configurator.py +194 -26
- fastlife/config/settings.py +6 -0
- {fastlifeweb-0.11.0.dist-info → fastlifeweb-0.12.0.dist-info}/METADATA +3 -3
- {fastlifeweb-0.11.0.dist-info → fastlifeweb-0.12.0.dist-info}/RECORD +6 -6
- {fastlifeweb-0.11.0.dist-info → fastlifeweb-0.12.0.dist-info}/LICENSE +0 -0
- {fastlifeweb-0.11.0.dist-info → fastlifeweb-0.12.0.dist-info}/WHEEL +0 -0
fastlife/config/configurator.py
CHANGED
@@ -17,17 +17,30 @@ import logging
|
|
17
17
|
from enum import Enum
|
18
18
|
from pathlib import Path
|
19
19
|
from types import ModuleType
|
20
|
-
from typing import
|
20
|
+
from typing import (
|
21
|
+
TYPE_CHECKING,
|
22
|
+
Any,
|
23
|
+
Callable,
|
24
|
+
List,
|
25
|
+
Optional,
|
26
|
+
Self,
|
27
|
+
Tuple,
|
28
|
+
Type,
|
29
|
+
Union,
|
30
|
+
cast,
|
31
|
+
)
|
21
32
|
|
22
33
|
import venusian
|
23
34
|
from fastapi import Depends, FastAPI
|
24
35
|
from fastapi import Request as BaseRequest
|
25
36
|
from fastapi.params import Depends as DependsType
|
26
37
|
from fastapi.staticfiles import StaticFiles
|
38
|
+
from fastapi.types import IncEx
|
27
39
|
|
28
40
|
from fastlife.middlewares.base import AbstractMiddleware
|
29
41
|
from fastlife.request.request import Request
|
30
42
|
from fastlife.routing.route import Route
|
43
|
+
from fastlife.routing.router import Router
|
31
44
|
from fastlife.security.csrf import check_csrf
|
32
45
|
from fastlife.shared_utils.resolver import resolve
|
33
46
|
|
@@ -55,13 +68,16 @@ class Configurator:
|
|
55
68
|
"""
|
56
69
|
registry_cls = resolve(settings.registry_class)
|
57
70
|
self.registry = registry_cls(settings)
|
58
|
-
self._app = FastAPI(
|
59
|
-
dependencies=[Depends(check_csrf())],
|
60
|
-
docs_url=None,
|
61
|
-
redoc_url=None,
|
62
|
-
)
|
63
71
|
Route._registry = self.registry # type: ignore
|
64
|
-
|
72
|
+
|
73
|
+
self.middlewares: list[Tuple[Type[AbstractMiddleware], Any]] = []
|
74
|
+
self.exception_handlers: list[Tuple[int | Type[Exception], Any]] = []
|
75
|
+
self.mounts: list[Tuple[str, Path, str]] = []
|
76
|
+
|
77
|
+
self.api_title = "FastAPI"
|
78
|
+
self.api_version = "1"
|
79
|
+
|
80
|
+
self.router = Router()
|
65
81
|
self.scanner = venusian.Scanner(fastlife=self)
|
66
82
|
self.include("fastlife.views")
|
67
83
|
self.include("fastlife.middlewares")
|
@@ -72,7 +88,49 @@ class Configurator:
|
|
72
88
|
|
73
89
|
:return: FastAPI application.
|
74
90
|
"""
|
75
|
-
|
91
|
+
_app = FastAPI(
|
92
|
+
title=self.api_title,
|
93
|
+
version=self.api_version,
|
94
|
+
dependencies=[Depends(check_csrf())],
|
95
|
+
docs_url=self.registry.settings.api_swagger_ui_url,
|
96
|
+
redoc_url=self.registry.settings.api_redocs_url,
|
97
|
+
)
|
98
|
+
_app.router.route_class = Route
|
99
|
+
for _route in self.router.routes:
|
100
|
+
route = cast(Route, _route)
|
101
|
+
_app.router.add_api_route(
|
102
|
+
path=route.path,
|
103
|
+
endpoint=route.endpoint,
|
104
|
+
response_model=route.response_model,
|
105
|
+
status_code=route.status_code,
|
106
|
+
tags=route.tags,
|
107
|
+
dependencies=route.dependencies,
|
108
|
+
summary=route.summary,
|
109
|
+
description=route.description,
|
110
|
+
response_description=route.response_description,
|
111
|
+
deprecated=route.deprecated,
|
112
|
+
methods=route.methods,
|
113
|
+
operation_id=route.operation_id,
|
114
|
+
response_model_include=route.response_model_include,
|
115
|
+
response_model_exclude=route.response_model_exclude,
|
116
|
+
response_model_by_alias=route.response_model_by_alias,
|
117
|
+
response_model_exclude_unset=route.response_model_exclude_unset,
|
118
|
+
response_model_exclude_defaults=route.response_model_exclude_defaults,
|
119
|
+
response_model_exclude_none=route.response_model_exclude_none,
|
120
|
+
include_in_schema=route.include_in_schema,
|
121
|
+
name=route.name,
|
122
|
+
openapi_extra=route.openapi_extra,
|
123
|
+
)
|
124
|
+
|
125
|
+
for middleware_class, options in self.middlewares:
|
126
|
+
_app.add_middleware(middleware_class, **options) # type: ignore
|
127
|
+
|
128
|
+
for status_code_or_exc, exception_handler in self.exception_handlers:
|
129
|
+
_app.add_exception_handler(status_code_or_exc, exception_handler)
|
130
|
+
|
131
|
+
for route_path, directory, name in self.mounts:
|
132
|
+
_app.mount(route_path, StaticFiles(directory=directory), name=name)
|
133
|
+
return _app
|
76
134
|
|
77
135
|
def include(self, module: str | ModuleType) -> "Configurator":
|
78
136
|
"""
|
@@ -105,16 +163,21 @@ class Configurator:
|
|
105
163
|
self.scanner.scan(module, categories=[VENUSIAN_CATEGORY]) # type: ignore
|
106
164
|
return self
|
107
165
|
|
166
|
+
def set_api_documentation_info(self, title: str, version: str) -> Self:
|
167
|
+
self.api_title = title
|
168
|
+
self.api_version = version
|
169
|
+
return self
|
170
|
+
|
108
171
|
def add_middleware(
|
109
172
|
self, middleware_class: Type[AbstractMiddleware], **options: Any
|
110
173
|
) -> Self:
|
111
174
|
"""
|
112
175
|
Add a starlette middleware to the FastAPI app.
|
113
176
|
"""
|
114
|
-
self.
|
177
|
+
self.middlewares.append((middleware_class, options))
|
115
178
|
return self
|
116
179
|
|
117
|
-
def
|
180
|
+
def add_api_route(
|
118
181
|
self,
|
119
182
|
name: str,
|
120
183
|
path: str,
|
@@ -123,12 +186,119 @@ class Configurator:
|
|
123
186
|
permission: str | None = None,
|
124
187
|
status_code: int | None = None,
|
125
188
|
tags: List[Union[str, Enum]] | None = None,
|
126
|
-
summary:
|
127
|
-
description:
|
189
|
+
summary: str | None = None,
|
190
|
+
description: str | None = None,
|
128
191
|
response_description: str = "Successful Response",
|
192
|
+
# responses: Dict[Union[int, str], Dict[str, Any]] | None = None,
|
193
|
+
deprecated: bool | None = None,
|
194
|
+
methods: List[str] | None = None,
|
195
|
+
operation_id: Optional[str] = None,
|
196
|
+
# response_model: Any = Default(None),
|
197
|
+
response_model_include: IncEx | None = None,
|
198
|
+
response_model_exclude: IncEx | None = None,
|
199
|
+
response_model_by_alias: bool = True,
|
200
|
+
response_model_exclude_unset: bool = False,
|
201
|
+
response_model_exclude_defaults: bool = False,
|
202
|
+
response_model_exclude_none: bool = False,
|
203
|
+
include_in_schema: bool = True,
|
204
|
+
# response_class: Union[Type[Response], DefaultPlaceholder] = Default(
|
205
|
+
# HTMLResponse
|
206
|
+
# ),
|
207
|
+
openapi_extra: dict[str, Any] | None = None,
|
208
|
+
# generate_unique_id_function: Callable[[APIRoute], str] = Default(
|
209
|
+
# generate_unique_id
|
210
|
+
# ),
|
211
|
+
) -> "Configurator":
|
212
|
+
"""
|
213
|
+
Add an API route to the app.
|
214
|
+
|
215
|
+
Fastlife does not use a decorator to attach routes, instead the decorator
|
216
|
+
:func:`fastlife.config.configurator.configure` has to be used to
|
217
|
+
inject routes inside a method and call the add_route method.
|
218
|
+
|
219
|
+
This route has to be used to add API Route, by API, to expose it in the
|
220
|
+
documentation.
|
221
|
+
|
222
|
+
To add a route that serve HTML user the method {meth}`Configurator.add_route`
|
223
|
+
|
224
|
+
:param name: name of the route, used to build route from the helper
|
225
|
+
:meth:`fastlife.request.request.Request.url_for` in order to create links.
|
226
|
+
:param path: path of the route, use `{curly_brace}` to inject FastAPI Path
|
227
|
+
parameters.
|
228
|
+
:param endpoint: the function that will reveive the request.
|
229
|
+
:param permission: a permission to validate by the
|
230
|
+
:attr:`fastlife.config.settings.Settings.check_permission` function.
|
231
|
+
|
232
|
+
:param methods: restrict route to a list of http methods.
|
233
|
+
:param description: description for the route.
|
234
|
+
:param summary: summary for the route.
|
235
|
+
:param response_description: description for the response.
|
236
|
+
:param operation_id: OpenAPI optional unique string used to identify an
|
237
|
+
operation.
|
238
|
+
:param tags: openapi tags for the route.
|
239
|
+
:param deprecated: mark the route as deprecated.
|
240
|
+
|
241
|
+
:param response_model_include: customize fields list to include in repsonse.
|
242
|
+
:param response_model_exclude: customize fields list to exclude in repsonse.
|
243
|
+
:param response_model_by_alias: serialize fields by alias or by name if False.
|
244
|
+
:param response_model_exclude_unset: exclude fields that are not explicitly
|
245
|
+
set in response.
|
246
|
+
:param response_model_exclude_defaults: exclude default value of response
|
247
|
+
fields.
|
248
|
+
:param response_model_exclude_none: exclude fields instead of serialize to
|
249
|
+
null value.
|
250
|
+
:param include_in_schema: expose or not the route in the doc.
|
251
|
+
:param openapi_extra: open api documentation extra fields.
|
252
|
+
|
253
|
+
:return: the configurator.
|
254
|
+
"""
|
255
|
+
dependencies: List[DependsType] = []
|
256
|
+
if permission:
|
257
|
+
dependencies.append(Depends(self.registry.check_permission(permission)))
|
258
|
+
|
259
|
+
self.router.add_api_route(
|
260
|
+
path,
|
261
|
+
endpoint,
|
262
|
+
# response_model=response_model,
|
263
|
+
status_code=status_code,
|
264
|
+
tags=tags,
|
265
|
+
dependencies=dependencies,
|
266
|
+
summary=summary,
|
267
|
+
description=description,
|
268
|
+
response_description=response_description,
|
269
|
+
# responses=responses,
|
270
|
+
deprecated=deprecated,
|
271
|
+
methods=methods,
|
272
|
+
operation_id=operation_id or name,
|
273
|
+
response_model_include=response_model_include,
|
274
|
+
response_model_exclude=response_model_exclude,
|
275
|
+
response_model_by_alias=response_model_by_alias,
|
276
|
+
response_model_exclude_unset=response_model_exclude_unset,
|
277
|
+
response_model_exclude_defaults=response_model_exclude_defaults,
|
278
|
+
response_model_exclude_none=response_model_exclude_none,
|
279
|
+
include_in_schema=include_in_schema,
|
280
|
+
# response_class=response_class,
|
281
|
+
name=name,
|
282
|
+
openapi_extra=openapi_extra,
|
283
|
+
# generate_unique_id_function=generate_unique_id_function,
|
284
|
+
)
|
285
|
+
return self
|
286
|
+
|
287
|
+
def add_route(
|
288
|
+
self,
|
289
|
+
name: str,
|
290
|
+
path: str,
|
291
|
+
endpoint: Callable[..., Any],
|
292
|
+
*,
|
293
|
+
permission: str | None = None,
|
294
|
+
status_code: int | None = None,
|
295
|
+
# tags: List[Union[str, Enum]] | None = None,
|
296
|
+
# summary: Optional[str] = None,
|
297
|
+
# description: Optional[str] = None,
|
298
|
+
# response_description: str = "Successful Response",
|
129
299
|
# responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
|
130
|
-
deprecated: Optional[bool] = None,
|
131
|
-
methods:
|
300
|
+
# deprecated: Optional[bool] = None,
|
301
|
+
methods: List[str] | None = None,
|
132
302
|
# operation_id: Optional[str] = None,
|
133
303
|
# response_model: Any = Default(None),
|
134
304
|
# response_model_include: Optional[IncEx] = None,
|
@@ -162,26 +332,24 @@ class Configurator:
|
|
162
332
|
:attr:`fastlife.config.settings.Settings.check_permission` function.
|
163
333
|
|
164
334
|
:param methods: restrict route to a list of http methods.
|
165
|
-
:param response_description: description for the response.
|
166
|
-
:param deprecated: mark the route as deprecated.
|
167
335
|
:return: the configurator.
|
168
336
|
"""
|
169
337
|
dependencies: List[DependsType] = []
|
170
338
|
if permission:
|
171
339
|
dependencies.append(Depends(self.registry.check_permission(permission)))
|
172
340
|
|
173
|
-
self.
|
341
|
+
self.router.add_api_route(
|
174
342
|
path,
|
175
343
|
endpoint,
|
176
344
|
# response_model=response_model,
|
177
345
|
status_code=status_code,
|
178
|
-
tags=tags,
|
346
|
+
# tags=tags,
|
179
347
|
dependencies=dependencies,
|
180
|
-
summary=summary,
|
181
|
-
description=description,
|
182
|
-
response_description=response_description,
|
348
|
+
# summary=summary,
|
349
|
+
# description=description,
|
350
|
+
# response_description=response_description,
|
183
351
|
# responses=responses,
|
184
|
-
deprecated=deprecated,
|
352
|
+
# deprecated=deprecated,
|
185
353
|
methods=methods,
|
186
354
|
# operation_id=operation_id,
|
187
355
|
# response_model_include=response_model_include,
|
@@ -190,7 +358,7 @@ class Configurator:
|
|
190
358
|
# response_model_exclude_unset=response_model_exclude_unset,
|
191
359
|
# response_model_exclude_defaults=response_model_exclude_defaults,
|
192
360
|
# response_model_exclude_none=response_model_exclude_none,
|
193
|
-
|
361
|
+
include_in_schema=False,
|
194
362
|
# response_class=response_class,
|
195
363
|
name=name,
|
196
364
|
# openapi_extra=openapi_extra,
|
@@ -210,7 +378,7 @@ class Configurator:
|
|
210
378
|
:return: the configurator
|
211
379
|
|
212
380
|
"""
|
213
|
-
self.
|
381
|
+
self.mounts.append((route_path, directory, name))
|
214
382
|
return self
|
215
383
|
|
216
384
|
def add_exception_handler(
|
@@ -222,12 +390,12 @@ class Configurator:
|
|
222
390
|
req = Request(self.registry, request)
|
223
391
|
return handler(req, exc)
|
224
392
|
|
225
|
-
self.
|
393
|
+
self.exception_handlers.append((status_code_or_exc, exception_handler))
|
226
394
|
return self
|
227
395
|
|
228
396
|
|
229
397
|
def configure(
|
230
|
-
wrapped: Callable[[Configurator], None]
|
398
|
+
wrapped: Callable[[Configurator], None],
|
231
399
|
) -> Callable[[Configurator], None]:
|
232
400
|
"""
|
233
401
|
Decorator used to attach route in a submodule while using the configurator.include.
|
fastlife/config/settings.py
CHANGED
@@ -100,3 +100,9 @@ class Settings(BaseSettings):
|
|
100
100
|
|
101
101
|
decode_reverse_proxy_headers: bool = Field(default=True)
|
102
102
|
"""Ensure that the request object has information based on http proxy headers."""
|
103
|
+
|
104
|
+
api_swagger_ui_url: str | None = Field(default=None)
|
105
|
+
"""Path to the automatic API documentation using Swagger UI."""
|
106
|
+
|
107
|
+
api_redocs_url: str | None = Field(default=None)
|
108
|
+
"""Path to the automatic API documentation using ReDoc."""
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: fastlifeweb
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.12.0
|
4
4
|
Summary: High-level web framework
|
5
5
|
Home-page: https://github.com/mardiros/fastlife
|
6
6
|
License: BSD-derived
|
@@ -18,14 +18,14 @@ Classifier: Programming Language :: Python :: 3.12
|
|
18
18
|
Classifier: Topic :: Internet :: WWW/HTTP
|
19
19
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
20
20
|
Requires-Dist: beautifulsoup4[testing] (>=4.12.2,<5.0.0)
|
21
|
-
Requires-Dist: fastapi (>=0.
|
21
|
+
Requires-Dist: fastapi[standard] (>=0.115.0,<0.116.0)
|
22
22
|
Requires-Dist: itsdangerous (>=2.1.2,<3.0.0)
|
23
23
|
Requires-Dist: jinjax (>=0.44,<0.45)
|
24
24
|
Requires-Dist: markupsafe (>=2.1.3,<3.0.0)
|
25
25
|
Requires-Dist: multidict (>=6.0.5,<7.0.0)
|
26
26
|
Requires-Dist: pydantic (>=2.5.3,<3.0.0)
|
27
27
|
Requires-Dist: pydantic-settings (>=2.0.3,<3.0.0)
|
28
|
-
Requires-Dist: python-multipart (>=0.0.
|
28
|
+
Requires-Dist: python-multipart (>=0.0.9,<0.0.10)
|
29
29
|
Requires-Dist: venusian (>=3.0.0,<4.0.0)
|
30
30
|
Project-URL: Repository, https://github.com/mardiros/fastlife
|
31
31
|
Description-Content-Type: text/markdown
|
@@ -1,8 +1,8 @@
|
|
1
1
|
fastlife/__init__.py,sha256=4tACh9tKuAaMZ-qK0GWJN-WLqaou8H7ZPE9sXfs_NlI,303
|
2
2
|
fastlife/config/__init__.py,sha256=3AoTQ5ojTCYDU3i1vDUCDC5pbBOeSWZ0w1Xo6A1qDrY,284
|
3
|
-
fastlife/config/configurator.py,sha256=
|
3
|
+
fastlife/config/configurator.py,sha256=NaIs6avsnIwc5URd5c4EkIN_DUVtX5XLcpswzxJ0Qd8,15674
|
4
4
|
fastlife/config/registry.py,sha256=v1IKPWKyPaG4TbCzrkC4uU51vRoSdpLWXEvAh_mbtjE,1246
|
5
|
-
fastlife/config/settings.py,sha256=
|
5
|
+
fastlife/config/settings.py,sha256=hjp4-EAAg03SKwlxaZrwXQFMnK9aeI2ICeAX58Y17H8,4003
|
6
6
|
fastlife/middlewares/__init__.py,sha256=C3DUOzR5EhlAv5Zq7h-Abyvkd7bUsJohTRSB2wpRYQE,220
|
7
7
|
fastlife/middlewares/base.py,sha256=9OYqByRuVoIrLt353NOedPQTLdr7LSmxhb2BZcp20qk,638
|
8
8
|
fastlife/middlewares/reverse_proxy/__init__.py,sha256=XTG9_Djw92wlyYh1dUDq8kkO8Oq61kBMqd_jNCsLfaQ,845
|
@@ -1697,7 +1697,7 @@ fastlife/testing/__init__.py,sha256=vuqwoNUd3BuIp3fm7nkvmYkIGjIimf5zUGhDkeWrg2s,
|
|
1697
1697
|
fastlife/testing/testclient.py,sha256=BC7lLQ_jc59UmknAKzgRtW9a3cpX_V_QLp9Mg2ScLA8,20546
|
1698
1698
|
fastlife/views/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1699
1699
|
fastlife/views/pydantic_form.py,sha256=WjRqtwc30g3W_4vqkVj0zzaK-vEWX4ZbtBV5vMpT9Xo,1267
|
1700
|
-
fastlifeweb-0.
|
1701
|
-
fastlifeweb-0.
|
1702
|
-
fastlifeweb-0.
|
1703
|
-
fastlifeweb-0.
|
1700
|
+
fastlifeweb-0.12.0.dist-info/LICENSE,sha256=F75xSseSKMwqzFj8rswYU6NWS3VoWOc_gY3fJYf9_LI,1504
|
1701
|
+
fastlifeweb-0.12.0.dist-info/METADATA,sha256=wFUWg2SoSvF2jb55yI35k73ByKoQRg80Yf1sPu_HkDU,2017
|
1702
|
+
fastlifeweb-0.12.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
1703
|
+
fastlifeweb-0.12.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|