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.
@@ -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 TYPE_CHECKING, Any, Callable, List, Optional, Self, Type, Union
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
- self._app.router.route_class = Route
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
- return self._app
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._app.add_middleware(middleware_class, **options) # type: ignore
177
+ self.middlewares.append((middleware_class, options))
115
178
  return self
116
179
 
117
- def add_route(
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: Optional[str] = None,
127
- description: Optional[str] = None,
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: Optional[List[str]] = None,
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._app.add_api_route(
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
- # include_in_schema=include_in_schema,
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._app.mount(route_path, StaticFiles(directory=directory), name=name)
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._app.add_exception_handler(status_code_or_exc, exception_handler)
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.
@@ -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.11.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.112.0,<0.113.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.6,<0.0.7)
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=ol8tdOSDk9Q_M1Nkme-3DaAEXkV5j6XXYIFR3V0Xxvw,8640
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=mdM1YlBXFq2HDWCKeMkBeHmW4NlgKEPZyKAxumUsrbo,3760
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.11.0.dist-info/LICENSE,sha256=F75xSseSKMwqzFj8rswYU6NWS3VoWOc_gY3fJYf9_LI,1504
1701
- fastlifeweb-0.11.0.dist-info/METADATA,sha256=wzlejQlx8pvO4_sjNGkntJHTdKEx28RHTk_20h8J9oA,2006
1702
- fastlifeweb-0.11.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
1703
- fastlifeweb-0.11.0.dist-info/RECORD,,
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,,