fastlifeweb 0.15.1__py3-none-any.whl → 0.16.1__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/__init__.py +8 -4
- fastlife/adapters/jinjax/renderer.py +1 -1
- fastlife/config/__init__.py +4 -4
- fastlife/config/configurator.py +33 -12
- fastlife/config/registry.py +5 -22
- fastlife/config/settings.py +1 -7
- fastlife/middlewares/reverse_proxy/__init__.py +1 -0
- fastlife/request/__init__.py +2 -2
- fastlife/request/form.py +1 -1
- fastlife/request/form_data.py +9 -12
- fastlife/request/request.py +30 -6
- fastlife/routing/route.py +2 -2
- fastlife/security/policy.py +12 -7
- fastlife/services/locale_negociator.py +25 -0
- fastlife/views/pydantic_form.py +1 -3
- {fastlifeweb-0.15.1.dist-info → fastlifeweb-0.16.1.dist-info}/METADATA +1 -1
- {fastlifeweb-0.15.1.dist-info → fastlifeweb-0.16.1.dist-info}/RECORD +19 -18
- {fastlifeweb-0.15.1.dist-info → fastlifeweb-0.16.1.dist-info}/LICENSE +0 -0
- {fastlifeweb-0.15.1.dist-info → fastlifeweb-0.16.1.dist-info}/WHEEL +0 -0
fastlife/__init__.py
CHANGED
@@ -2,14 +2,15 @@ from fastapi import Response
|
|
2
2
|
|
3
3
|
from .config import (
|
4
4
|
Configurator,
|
5
|
-
|
5
|
+
DefaultRegistry,
|
6
|
+
GenericConfigurator,
|
6
7
|
Settings,
|
7
8
|
configure,
|
8
9
|
resource,
|
9
10
|
resource_view,
|
10
11
|
view_config,
|
11
12
|
)
|
12
|
-
from .request import Request
|
13
|
+
from .request import GenericRequest, Registry, Request, get_request
|
13
14
|
|
14
15
|
# from .request.form_data import model
|
15
16
|
from .services.templates import TemplateParams
|
@@ -17,16 +18,19 @@ from .services.templates import TemplateParams
|
|
17
18
|
__all__ = [
|
18
19
|
# Config
|
19
20
|
"configure",
|
21
|
+
"GenericConfigurator",
|
20
22
|
"Configurator",
|
23
|
+
"DefaultRegistry",
|
21
24
|
"TemplateParams",
|
22
|
-
"Registry",
|
23
25
|
"Settings",
|
24
26
|
"view_config",
|
25
27
|
"resource",
|
26
28
|
"resource_view",
|
27
29
|
# Model
|
28
30
|
# "model",
|
29
|
-
# Fast API reexport
|
30
31
|
"Request",
|
32
|
+
"GenericRequest",
|
33
|
+
"get_request",
|
34
|
+
"Registry",
|
31
35
|
"Response",
|
32
36
|
]
|
@@ -62,7 +62,7 @@ def generate_docstring(
|
|
62
62
|
docstring = (ast.get_docstring(func_def, clean=True) or "").strip()
|
63
63
|
if docstring:
|
64
64
|
docstring = textwrap.dedent(docstring)
|
65
|
-
docstring_lines = [
|
65
|
+
docstring_lines = [line for line in docstring.split("\n")]
|
66
66
|
# Add a newline for separation after the function docstring
|
67
67
|
docstring_lines.append("")
|
68
68
|
else:
|
fastlife/config/__init__.py
CHANGED
@@ -1,18 +1,18 @@
|
|
1
1
|
"""Configure fastlife app for dependency injection."""
|
2
2
|
|
3
|
-
from .configurator import Configurator, configure
|
4
|
-
from .registry import
|
3
|
+
from .configurator import Configurator, GenericConfigurator, configure
|
4
|
+
from .registry import DefaultRegistry
|
5
5
|
from .resources import resource, resource_view
|
6
6
|
from .settings import Settings
|
7
7
|
from .views import view_config
|
8
8
|
|
9
9
|
__all__ = [
|
10
10
|
"Configurator",
|
11
|
+
"GenericConfigurator",
|
11
12
|
"configure",
|
12
13
|
"view_config",
|
13
14
|
"resource",
|
14
15
|
"resource_view",
|
15
|
-
"
|
16
|
-
"AppRegistry",
|
16
|
+
"DefaultRegistry",
|
17
17
|
"Settings",
|
18
18
|
]
|
fastlife/config/configurator.py
CHANGED
@@ -19,7 +19,7 @@ from collections.abc import Mapping, Sequence
|
|
19
19
|
from enum import Enum
|
20
20
|
from pathlib import Path
|
21
21
|
from types import ModuleType
|
22
|
-
from typing import TYPE_CHECKING, Annotated, Any, Callable, Self, Tuple, Type
|
22
|
+
from typing import TYPE_CHECKING, Annotated, Any, Callable, Generic, Self, Tuple, Type
|
23
23
|
|
24
24
|
import venusian
|
25
25
|
from fastapi import Depends, FastAPI
|
@@ -38,6 +38,7 @@ from fastlife.security.csrf import check_csrf
|
|
38
38
|
from fastlife.services.policy import check_permission
|
39
39
|
from fastlife.shared_utils.resolver import resolve
|
40
40
|
|
41
|
+
from .registry import DefaultRegistry, TRegistry
|
41
42
|
from .settings import Settings
|
42
43
|
|
43
44
|
if TYPE_CHECKING:
|
@@ -46,7 +47,7 @@ if TYPE_CHECKING:
|
|
46
47
|
AbstractTemplateRendererFactory, # coverage: ignore
|
47
48
|
)
|
48
49
|
|
49
|
-
|
50
|
+
from fastlife.services.locale_negociator import LocaleNegociator
|
50
51
|
|
51
52
|
log = logging.getLogger(__name__)
|
52
53
|
VENUSIAN_CATEGORY = "fastlife"
|
@@ -109,14 +110,14 @@ def rebuild_router(router: Router) -> Router:
|
|
109
110
|
return _router
|
110
111
|
|
111
112
|
|
112
|
-
class
|
113
|
+
class GenericConfigurator(Generic[TRegistry]):
|
113
114
|
"""
|
114
115
|
Configure and build an application.
|
115
116
|
|
116
117
|
Initialize the app from the settings.
|
117
118
|
"""
|
118
119
|
|
119
|
-
registry:
|
120
|
+
registry: TRegistry
|
120
121
|
|
121
122
|
def __init__(self, settings: Settings) -> None:
|
122
123
|
"""
|
@@ -135,10 +136,14 @@ class Configurator:
|
|
135
136
|
self.api_version = "v1"
|
136
137
|
self.api_description: str = ""
|
137
138
|
self.api_summary: str | None = None
|
139
|
+
self.api_swagger_ui_url: str | None = None
|
140
|
+
self.api_redoc_url: str | None = None
|
138
141
|
|
139
142
|
self._route_prefix: str = ""
|
140
143
|
self._routers: dict[str, Router] = defaultdict(Router)
|
141
|
-
self._security_policies: dict[
|
144
|
+
self._security_policies: dict[
|
145
|
+
str, "type[AbstractSecurityPolicy[Any, TRegistry]]"
|
146
|
+
] = {}
|
142
147
|
|
143
148
|
self.scanner = venusian.Scanner(fastlife=self)
|
144
149
|
self.include("fastlife.views")
|
@@ -170,8 +175,8 @@ class Configurator:
|
|
170
175
|
description=self.api_description,
|
171
176
|
summary=self.api_summary,
|
172
177
|
dependencies=[Depends(check_csrf())],
|
173
|
-
docs_url=self.
|
174
|
-
redoc_url=self.
|
178
|
+
docs_url=self.api_swagger_ui_url,
|
179
|
+
redoc_url=self.api_redoc_url,
|
175
180
|
openapi_tags=[tag.model_dump(by_alias=True) for tag in self.tags.values()]
|
176
181
|
if self.tags
|
177
182
|
else None,
|
@@ -241,7 +246,7 @@ class Configurator:
|
|
241
246
|
self._route_prefix = old
|
242
247
|
return self
|
243
248
|
|
244
|
-
def set_locale_negociator(self, locale_negociator:
|
249
|
+
def set_locale_negociator(self, locale_negociator: LocaleNegociator) -> Self:
|
245
250
|
"""Install a locale negociator for the app."""
|
246
251
|
self.registry.locale_negociator = locale_negociator
|
247
252
|
return self
|
@@ -263,20 +268,28 @@ class Configurator:
|
|
263
268
|
title: str,
|
264
269
|
version: str,
|
265
270
|
description: str,
|
271
|
+
*,
|
266
272
|
summary: str | None = None,
|
273
|
+
swagger_ui_url: str | None = None,
|
274
|
+
redoc_url: str | None = None,
|
267
275
|
) -> Self:
|
268
276
|
"""
|
269
277
|
Set your api documentation title for application that expose an API.
|
270
278
|
|
271
279
|
:param title: OpenAPI documentation title
|
272
280
|
:param version: OpenAPI api version
|
273
|
-
:param description: OpenAPI documentation description
|
274
|
-
:param summary: OpenAPI documentation summary
|
281
|
+
:param description: OpenAPI documentation description. Use markdown here.
|
282
|
+
:param summary: OpenAPI documentation summary.
|
283
|
+
A short description: text only.
|
284
|
+
:param swagger_ui_url: Endpoint for {term}`Swagger UI` served by FastAPI
|
285
|
+
:param redoc_url: Endpoint for {term}`Redoc` served by FastAPI
|
275
286
|
"""
|
276
287
|
self.api_title = title
|
277
288
|
self.api_version = version
|
278
289
|
self.api_description = description
|
279
290
|
self.api_summary = summary
|
291
|
+
self.api_swagger_ui_url = swagger_ui_url
|
292
|
+
self.api_redoc_url = redoc_url
|
280
293
|
return self
|
281
294
|
|
282
295
|
def add_open_tag(self, tag: OpenApiTag) -> Self:
|
@@ -296,7 +309,7 @@ class Configurator:
|
|
296
309
|
return self
|
297
310
|
|
298
311
|
def set_security_policy(
|
299
|
-
self, security_policy: "type[AbstractSecurityPolicy[Any]]"
|
312
|
+
self, security_policy: "type[AbstractSecurityPolicy[Any, TRegistry]]"
|
300
313
|
) -> Self:
|
301
314
|
"""
|
302
315
|
Set a security policy for the application.
|
@@ -561,9 +574,17 @@ class Configurator:
|
|
561
574
|
return self
|
562
575
|
|
563
576
|
|
577
|
+
class Configurator(GenericConfigurator[DefaultRegistry]):
|
578
|
+
"""
|
579
|
+
Configure and build an application.
|
580
|
+
|
581
|
+
Initialize the app from the settings.
|
582
|
+
"""
|
583
|
+
|
584
|
+
|
564
585
|
def configure(
|
565
586
|
wrapped: Callable[[Configurator], None],
|
566
|
-
) -> Callable[[
|
587
|
+
) -> Callable[[Any], None]:
|
567
588
|
"""
|
568
589
|
Decorator used to attach route in a submodule while using the configurator.include.
|
569
590
|
"""
|
fastlife/config/registry.py
CHANGED
@@ -1,10 +1,7 @@
|
|
1
1
|
from collections.abc import Mapping
|
2
|
-
from typing import TYPE_CHECKING,
|
2
|
+
from typing import TYPE_CHECKING, TypeVar
|
3
3
|
|
4
|
-
from
|
5
|
-
from fastapi import Request as FastAPIRequest
|
6
|
-
|
7
|
-
from fastlife.request.request import Request
|
4
|
+
from fastlife.services.locale_negociator import LocaleNegociator, default_negociator
|
8
5
|
from fastlife.services.translations import LocalizerFactory
|
9
6
|
|
10
7
|
if TYPE_CHECKING:
|
@@ -14,17 +11,8 @@ if TYPE_CHECKING:
|
|
14
11
|
|
15
12
|
from .settings import Settings
|
16
13
|
|
17
|
-
LocaleNegociator = Callable[[Request], str]
|
18
|
-
|
19
|
-
|
20
|
-
def _default_negociator(settings: Settings) -> LocaleNegociator:
|
21
|
-
def locale_negociator(request: FastAPIRequest) -> str:
|
22
|
-
return settings.default_locale
|
23
|
-
|
24
|
-
return locale_negociator
|
25
14
|
|
26
|
-
|
27
|
-
class AppRegistry:
|
15
|
+
class DefaultRegistry:
|
28
16
|
"""
|
29
17
|
The application registry got fastlife dependency injection.
|
30
18
|
It is initialized by the configurator and accessed by the `fastlife.Registry`.
|
@@ -37,7 +25,7 @@ class AppRegistry:
|
|
37
25
|
|
38
26
|
def __init__(self, settings: Settings) -> None:
|
39
27
|
self.settings = settings
|
40
|
-
self.locale_negociator =
|
28
|
+
self.locale_negociator = default_negociator(self.settings)
|
41
29
|
self.renderers = {}
|
42
30
|
self.localizer = LocalizerFactory()
|
43
31
|
|
@@ -48,9 +36,4 @@ class AppRegistry:
|
|
48
36
|
raise RuntimeError(f"No renderer registered for template {template}")
|
49
37
|
|
50
38
|
|
51
|
-
|
52
|
-
return request.registry
|
53
|
-
|
54
|
-
|
55
|
-
Registry = Annotated[AppRegistry, Depends(get_registry)]
|
56
|
-
"""FastAPI dependency to access to the registry."""
|
39
|
+
TRegistry = TypeVar("TRegistry", bound=DefaultRegistry, covariant=True)
|
fastlife/config/settings.py
CHANGED
@@ -29,7 +29,7 @@ class Settings(BaseSettings):
|
|
29
29
|
a python module name. for instance `fastlife:components` is the directory components
|
30
30
|
found in the fastlife package.
|
31
31
|
"""
|
32
|
-
registry_class: str = Field(default="fastlife.config.registry:
|
32
|
+
registry_class: str = Field(default="fastlife.config.registry:DefaultRegistry")
|
33
33
|
"""Implementation class for the application regitry."""
|
34
34
|
template_renderer_class: str = Field(
|
35
35
|
default="fastlife.templates.renderer:JinjaxTemplateRenderer"
|
@@ -108,9 +108,3 @@ class Settings(BaseSettings):
|
|
108
108
|
|
109
109
|
decode_reverse_proxy_headers: bool = Field(default=True)
|
110
110
|
"""Ensure that the request object has information based on http proxy headers."""
|
111
|
-
|
112
|
-
api_swagger_ui_url: str | None = Field(default=None)
|
113
|
-
"""Path to the automatic API documentation using Swagger UI."""
|
114
|
-
|
115
|
-
api_redocs_url: str | None = Field(default=None)
|
116
|
-
"""Path to the automatic API documentation using ReDoc."""
|
fastlife/request/__init__.py
CHANGED
fastlife/request/form.py
CHANGED
@@ -5,7 +5,7 @@ from typing import Any, Callable, Generic, Mapping, Type, TypeVar, get_origin
|
|
5
5
|
from fastapi import Depends
|
6
6
|
from pydantic import BaseModel, ValidationError
|
7
7
|
|
8
|
-
from fastlife
|
8
|
+
from fastlife import Registry
|
9
9
|
from fastlife.request.form_data import MappingFormData
|
10
10
|
from fastlife.shared_utils.infer import is_union
|
11
11
|
|
fastlife/request/form_data.py
CHANGED
@@ -12,9 +12,9 @@ from typing import (
|
|
12
12
|
Sequence,
|
13
13
|
)
|
14
14
|
|
15
|
-
from fastapi import Depends
|
15
|
+
from fastapi import Depends
|
16
16
|
|
17
|
-
from fastlife
|
17
|
+
from fastlife import Request
|
18
18
|
|
19
19
|
|
20
20
|
def unflatten_struct(
|
@@ -80,13 +80,11 @@ def unflatten_struct(
|
|
80
80
|
return unflattened_output
|
81
81
|
|
82
82
|
|
83
|
-
async def unflatten_mapping_form_data(
|
84
|
-
request: Request, registry: Registry
|
85
|
-
) -> Mapping[str, Any]:
|
83
|
+
async def unflatten_mapping_form_data(request: Request) -> Mapping[str, Any]:
|
86
84
|
"""
|
87
85
|
Parse the {meth}`fastlife.request.request.form` and build a nested structure.
|
88
86
|
"""
|
89
|
-
|
87
|
+
registry = request.registry
|
90
88
|
form_data = await request.form()
|
91
89
|
form_data_decode_list: MutableMapping[str, Any] = {}
|
92
90
|
for key, val in form_data.multi_items():
|
@@ -109,17 +107,16 @@ async def unflatten_mapping_form_data(
|
|
109
107
|
return ret # type: ignore
|
110
108
|
|
111
109
|
|
112
|
-
async def unflatten_sequence_form_data(
|
113
|
-
request: Request, reg: Registry
|
114
|
-
) -> Sequence[str]:
|
110
|
+
async def unflatten_sequence_form_data(request: Request) -> Sequence[str]:
|
115
111
|
"""
|
116
112
|
Parse the {meth}`fastlife.request.request.form` and build a list of structure.
|
117
113
|
"""
|
114
|
+
registry = request.registry
|
118
115
|
form_data = await request.form()
|
119
116
|
# Could raise a value error !
|
120
|
-
return unflatten_struct(
|
121
|
-
form_data, [], csrf_token_name=
|
122
|
-
)
|
117
|
+
return unflatten_struct( # type: ignore
|
118
|
+
form_data, [], csrf_token_name=registry.settings.csrf_token_name
|
119
|
+
)
|
123
120
|
|
124
121
|
|
125
122
|
MappingFormData = Annotated[Mapping[str, Any], Depends(unflatten_mapping_form_data)]
|
fastlife/request/request.py
CHANGED
@@ -1,29 +1,31 @@
|
|
1
1
|
"""HTTP Request representation in a python object."""
|
2
2
|
|
3
|
-
from typing import TYPE_CHECKING, Any
|
3
|
+
from typing import TYPE_CHECKING, Annotated, Any, Generic
|
4
4
|
|
5
5
|
from fastapi import Request as FastAPIRequest
|
6
|
+
from fastapi.params import Depends
|
7
|
+
|
8
|
+
from fastlife.config.registry import DefaultRegistry, TRegistry
|
6
9
|
|
7
10
|
if TYPE_CHECKING:
|
8
|
-
from fastlife.config.registry import AppRegistry # coverage: ignore
|
9
11
|
from fastlife.security.policy import ( # coverage: ignore
|
10
12
|
AbstractSecurityPolicy,
|
11
13
|
HasPermission,
|
12
14
|
)
|
13
15
|
|
14
16
|
|
15
|
-
class
|
17
|
+
class GenericRequest(FastAPIRequest, Generic[TRegistry]):
|
16
18
|
"""HTTP Request representation."""
|
17
19
|
|
18
|
-
registry:
|
20
|
+
registry: TRegistry
|
19
21
|
"""Direct access to the application registry."""
|
20
22
|
locale_name: str
|
21
23
|
"""Request locale used for the i18n of the response."""
|
22
24
|
|
23
|
-
security_policy: "AbstractSecurityPolicy[Any] | None"
|
25
|
+
security_policy: "AbstractSecurityPolicy[Any, TRegistry] | None"
|
24
26
|
"""Request locale used for the i18n of the response."""
|
25
27
|
|
26
|
-
def __init__(self, registry:
|
28
|
+
def __init__(self, registry: TRegistry, request: FastAPIRequest) -> None:
|
27
29
|
super().__init__(request.scope, request.receive)
|
28
30
|
self.registry = registry
|
29
31
|
self.locale_name = registry.locale_negociator(self)
|
@@ -47,3 +49,25 @@ class Request(FastAPIRequest):
|
|
47
49
|
)
|
48
50
|
|
49
51
|
return await self.security_policy.has_permission(permission)
|
52
|
+
|
53
|
+
|
54
|
+
def get_request(request: FastAPIRequest) -> GenericRequest[Any]:
|
55
|
+
return request # type: ignore
|
56
|
+
|
57
|
+
|
58
|
+
Request = Annotated[GenericRequest[DefaultRegistry], Depends(get_request)]
|
59
|
+
"""A request that is associated to the default registry."""
|
60
|
+
# FastAPI handle its Request objects using a lenient_issubclass,
|
61
|
+
# basically a issubclass(Request), doe to the Generic[T], it does not work.
|
62
|
+
|
63
|
+
|
64
|
+
AnyRequest = Annotated[GenericRequest[Any], Depends(get_request)]
|
65
|
+
"""A request version that is associated to the any registry."""
|
66
|
+
|
67
|
+
|
68
|
+
def get_registry(request: Request) -> DefaultRegistry:
|
69
|
+
return request.registry
|
70
|
+
|
71
|
+
|
72
|
+
Registry = Annotated[DefaultRegistry, Depends(get_registry)]
|
73
|
+
"""FastAPI dependency to access to the registry."""
|
fastlife/routing/route.py
CHANGED
@@ -8,7 +8,7 @@ from starlette.responses import Response
|
|
8
8
|
from fastlife.request.request import Request
|
9
9
|
|
10
10
|
if TYPE_CHECKING:
|
11
|
-
from fastlife.config.registry import
|
11
|
+
from fastlife.config.registry import DefaultRegistry # coverage: ignore
|
12
12
|
|
13
13
|
|
14
14
|
class Route(APIRoute):
|
@@ -19,7 +19,7 @@ class Route(APIRoute):
|
|
19
19
|
have the registry property available in every received request.
|
20
20
|
"""
|
21
21
|
|
22
|
-
_registry: "
|
22
|
+
_registry: "DefaultRegistry"
|
23
23
|
"""
|
24
24
|
The application registry.
|
25
25
|
|
fastlife/security/policy.py
CHANGED
@@ -2,14 +2,14 @@
|
|
2
2
|
|
3
3
|
import abc
|
4
4
|
import logging
|
5
|
-
from typing import Any, Callable, Coroutine, Literal, TypeVar
|
5
|
+
from typing import Annotated, Any, Callable, Coroutine, Generic, Literal, TypeVar
|
6
6
|
from uuid import UUID
|
7
7
|
|
8
|
-
from fastapi import HTTPException
|
8
|
+
from fastapi import Depends, HTTPException
|
9
9
|
from starlette.status import HTTP_401_UNAUTHORIZED, HTTP_403_FORBIDDEN
|
10
|
-
from typing_extensions import Generic
|
11
10
|
|
12
|
-
from fastlife import
|
11
|
+
from fastlife import GenericRequest, get_request
|
12
|
+
from fastlife.config.registry import TRegistry
|
13
13
|
|
14
14
|
CheckPermissionHook = Callable[..., Coroutine[Any, Any, None]] | Callable[..., None]
|
15
15
|
CheckPermission = Callable[[str], CheckPermissionHook]
|
@@ -93,7 +93,7 @@ class Denied(HasPermission):
|
|
93
93
|
reason = "Access denied to this resource"
|
94
94
|
|
95
95
|
|
96
|
-
class AbstractSecurityPolicy(abc.ABC, Generic[TUser]):
|
96
|
+
class AbstractSecurityPolicy(abc.ABC, Generic[TUser, TRegistry]):
|
97
97
|
"""Security policy base classe."""
|
98
98
|
|
99
99
|
Forbidden = Forbidden
|
@@ -101,7 +101,12 @@ class AbstractSecurityPolicy(abc.ABC, Generic[TUser]):
|
|
101
101
|
Unauthorized = Unauthorized
|
102
102
|
"""The exception raised if no user has been identified."""
|
103
103
|
|
104
|
-
|
104
|
+
request: GenericRequest[TRegistry]
|
105
|
+
"""Request where the security policy is applied."""
|
106
|
+
|
107
|
+
def __init__(
|
108
|
+
self, request: Annotated[GenericRequest[TRegistry], Depends(get_request)]
|
109
|
+
):
|
105
110
|
"""
|
106
111
|
Build the security policy.
|
107
112
|
|
@@ -141,7 +146,7 @@ class AbstractSecurityPolicy(abc.ABC, Generic[TUser]):
|
|
141
146
|
"""Destroy the request session."""
|
142
147
|
|
143
148
|
|
144
|
-
class InsecurePolicy(AbstractSecurityPolicy[None]):
|
149
|
+
class InsecurePolicy(AbstractSecurityPolicy[None, Any]):
|
145
150
|
"""
|
146
151
|
An implementation of the security policy made for explicit unsecured access.
|
147
152
|
|
@@ -0,0 +1,25 @@
|
|
1
|
+
"""Find the localization gor the given request."""
|
2
|
+
|
3
|
+
from typing import TYPE_CHECKING, Any, Callable
|
4
|
+
|
5
|
+
from fastlife.config.settings import Settings
|
6
|
+
|
7
|
+
LocaleName = str
|
8
|
+
"""The LocaleName is a locale such as en, fr that will be consume for translations."""
|
9
|
+
|
10
|
+
if TYPE_CHECKING:
|
11
|
+
from fastlife.request.request import GenericRequest # coverage: ignore
|
12
|
+
|
13
|
+
LocaleNegociator = Callable[[GenericRequest[Any]], LocaleName] # coverage: ignore
|
14
|
+
"""Interface to implement to negociate a locale""" # coverage: ignore
|
15
|
+
else:
|
16
|
+
LocaleNegociator = Any
|
17
|
+
|
18
|
+
|
19
|
+
def default_negociator(settings: Settings) -> LocaleNegociator:
|
20
|
+
"""The default local negociator return the locale set in the conf."""
|
21
|
+
|
22
|
+
def locale_negociator(request: "GenericRequest[Any]") -> str:
|
23
|
+
return settings.default_locale
|
24
|
+
|
25
|
+
return locale_negociator
|
fastlife/views/pydantic_form.py
CHANGED
@@ -5,13 +5,11 @@ from pydantic.fields import FieldInfo
|
|
5
5
|
|
6
6
|
from fastlife import Configurator, Request, Response, configure
|
7
7
|
from fastlife.adapters.jinjax.renderer import JinjaxRenderer
|
8
|
-
from fastlife.config.registry import Registry
|
9
8
|
from fastlife.shared_utils.resolver import resolve_extended
|
10
9
|
|
11
10
|
|
12
11
|
async def show_widget(
|
13
12
|
typ: str,
|
14
|
-
reg: Registry,
|
15
13
|
request: Request,
|
16
14
|
title: Optional[str] = Query(None),
|
17
15
|
name: Optional[str] = Query(None),
|
@@ -26,7 +24,7 @@ async def show_widget(
|
|
26
24
|
if title:
|
27
25
|
field = FieldInfo(title=title)
|
28
26
|
# FIXME: .jinja should not be hardcoded
|
29
|
-
renderer = cast(JinjaxRenderer,
|
27
|
+
renderer = cast(JinjaxRenderer, request.registry.get_renderer(".jinja")(request))
|
30
28
|
data = renderer.pydantic_form_field(
|
31
29
|
model=model_cls, # type: ignore
|
32
30
|
name=name,
|
@@ -1,7 +1,7 @@
|
|
1
|
-
fastlife/__init__.py,sha256=
|
1
|
+
fastlife/__init__.py,sha256=fokakuhI0fdAjHP5w6GWi-YfCx7iTnrVzjSyZ11Cdgg,676
|
2
2
|
fastlife/adapters/__init__.py,sha256=WYjEN8gp4r7LCHqmIO5VzzvsT8QGRE3w4G47UwYDtAo,94
|
3
3
|
fastlife/adapters/jinjax/__init__.py,sha256=jy88zyqk7nFlaY-0lmgAoe0HyO5r_NKckQb3faQiUv4,137
|
4
|
-
fastlife/adapters/jinjax/renderer.py,sha256=
|
4
|
+
fastlife/adapters/jinjax/renderer.py,sha256=rj2KI4GB8tZstJwImdDYHuswxjdbGri2f8H6YuByaLo,13046
|
5
5
|
fastlife/adapters/jinjax/widgets/__init__.py,sha256=HERnX9xiXUbTDz3XtlnHWABTBjhIq_kkBgWs5E6ZIMY,42
|
6
6
|
fastlife/adapters/jinjax/widgets/base.py,sha256=JoB1bLI97ZW2ycfBcHgrPxiOszE9t_SFFK5L1bR-cSo,4015
|
7
7
|
fastlife/adapters/jinjax/widgets/boolean.py,sha256=w4hZMo_8xDoThStlIUR4eVfLm8JwUp0-TaGCjGSyCbA,1145
|
@@ -1665,34 +1665,35 @@ fastlife/components/pydantic_form/Text.jinja,sha256=2f_3Q32GySHTLFt-YO8gEJNCY-3X
|
|
1665
1665
|
fastlife/components/pydantic_form/Textarea.jinja,sha256=NzfCi5agRUSVcb5RXw0QamM8P1lZ-CdNI6P30zb2948,1155
|
1666
1666
|
fastlife/components/pydantic_form/Union.jinja,sha256=czTska54z9KCZKu-FaycLmOvtH6y6CGUFQ8DHnkjrJk,1461
|
1667
1667
|
fastlife/components/pydantic_form/Widget.jinja,sha256=EXskDqt22D5grpGVwlZA3ndve2Wr_6yQH4qVE9c31Og,397
|
1668
|
-
fastlife/config/__init__.py,sha256=
|
1669
|
-
fastlife/config/configurator.py,sha256=
|
1668
|
+
fastlife/config/__init__.py,sha256=ThosRIPZ_fpD0exZu-kUC_f8ZNa5KyDlleWMmEHkjEo,448
|
1669
|
+
fastlife/config/configurator.py,sha256=5In_ciAxqORR47gKIbZKTd1IOkkMO0a0iB4q5x7ltaI,21955
|
1670
1670
|
fastlife/config/exceptions.py,sha256=2MS2MFgb3mDbtdHEwnC-QYubob3Rl0v8O8y615LY0ds,1180
|
1671
1671
|
fastlife/config/openapiextra.py,sha256=_9rBYeTqB7nVuzvUHMwZU387bTfYFHYLlP05NP0vEDs,513
|
1672
|
-
fastlife/config/registry.py,sha256=
|
1672
|
+
fastlife/config/registry.py,sha256=dGcNm7E6WY0x5HZNzo1gBFvGFCWeJj6JFXsJtLax5NU,1347
|
1673
1673
|
fastlife/config/resources.py,sha256=pM0j5VKVbVak4Z5mFRHBjAjUqORP4TAtCnZM3res5o8,8776
|
1674
|
-
fastlife/config/settings.py,sha256=
|
1674
|
+
fastlife/config/settings.py,sha256=7oggPOucyJwQYI97q8vs3kPXjFIVpQu1q6BK25h-uFs,3789
|
1675
1675
|
fastlife/config/views.py,sha256=Dxi6lO4gFs6GriAW7Rh5GDvebwbrpS2HzYhf30pXJiE,2058
|
1676
1676
|
fastlife/middlewares/__init__.py,sha256=C3DUOzR5EhlAv5Zq7h-Abyvkd7bUsJohTRSB2wpRYQE,220
|
1677
1677
|
fastlife/middlewares/base.py,sha256=9OYqByRuVoIrLt353NOedPQTLdr7LSmxhb2BZcp20qk,638
|
1678
|
-
fastlife/middlewares/reverse_proxy/__init__.py,sha256=
|
1678
|
+
fastlife/middlewares/reverse_proxy/__init__.py,sha256=g1SoVDmenKzpAAPYHTEsWgdBByOxtLg9fGx6RV3i0ok,846
|
1679
1679
|
fastlife/middlewares/reverse_proxy/x_forwarded.py,sha256=WC4xV3i6_Ogqsf_Zgt1ESml8zfnPbJJJkPlC2gTEqW8,1095
|
1680
1680
|
fastlife/middlewares/session/__init__.py,sha256=3XgXcIO6yQls5G7x8K2T8b7a_enA_7rQptWZcp3j2Ak,1400
|
1681
1681
|
fastlife/middlewares/session/middleware.py,sha256=AlRIFXfn3JesKJzMAFUHDOo22mfuwDHkyecDHo9jCdA,3172
|
1682
1682
|
fastlife/middlewares/session/serializer.py,sha256=fTdZCop0y4VkCMyOIo6GEbo5fVWrwsBXaSWfConPL8E,2144
|
1683
1683
|
fastlife/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1684
|
-
fastlife/request/__init__.py,sha256
|
1685
|
-
fastlife/request/form.py,sha256=
|
1686
|
-
fastlife/request/form_data.py,sha256=
|
1684
|
+
fastlife/request/__init__.py,sha256=-wrh12uWM7ysmIUE6FszBit2H6iI5LWVEnHxQJ_23ZE,157
|
1685
|
+
fastlife/request/form.py,sha256=Ln9TySvAccYhFY9zc49P6YGE9cQSi_o3mByxvcuCIKY,3516
|
1686
|
+
fastlife/request/form_data.py,sha256=DNKpXUxeDMYb43zSBnSPTBjAB8OhsYlNjERSsLgFdvI,4454
|
1687
1687
|
fastlife/request/localizer.py,sha256=9MXAcsod-Po5qeg4lttD3dyumiI0y5vGHCwSSmt9or8,349
|
1688
|
-
fastlife/request/request.py,sha256=
|
1688
|
+
fastlife/request/request.py,sha256=h4Ji0GElWJ3W2hHgOwjSKHQcxUjjPuOk09v-oyfjEd0,2568
|
1689
1689
|
fastlife/routing/__init__.py,sha256=8EMnQE5n8oA4J9_c3nxzwKDVt3tefZ6fGH0d2owE8mo,195
|
1690
|
-
fastlife/routing/route.py,sha256=
|
1690
|
+
fastlife/routing/route.py,sha256=O0gwPtP7ur2EHRf76kBASgoLMQciGHXcrJkW8zEPFJA,1413
|
1691
1691
|
fastlife/routing/router.py,sha256=bLZ4k2aDs4L423znwGnw-X2LnM36O8fjhDWc8q1WewI,481
|
1692
1692
|
fastlife/security/__init__.py,sha256=QYDcJ3oXQzqXQxoDD_6biGAtercFrtePttoifiL1j34,25
|
1693
1693
|
fastlife/security/csrf.py,sha256=PvC9Fqdb6c0IzzsnaMx2quQdjjKrb-nOPoAHfcwoAe8,2141
|
1694
|
-
fastlife/security/policy.py,sha256=
|
1694
|
+
fastlife/security/policy.py,sha256=8FWtjcOjkK5UvnjKluVkJIZdec2bfXbkKx7ouiiyjBs,5115
|
1695
1695
|
fastlife/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1696
|
+
fastlife/services/locale_negociator.py,sha256=b1Fsx-r_zIZe0GD8WH1gmslMb0mNrvxuacxD4LNX63o,819
|
1696
1697
|
fastlife/services/policy.py,sha256=ZK4K3fVGT1fUeBdo5sSWnEcJg49CZuaI3z2gyg3KguQ,1653
|
1697
1698
|
fastlife/services/templates.py,sha256=7gPJxGWD-XqputbZpy_Icsz3WHKJaWg2JgkVOeKrjfA,3840
|
1698
1699
|
fastlife/services/translations.py,sha256=Bo5CIjdbQ3g_ihbv4Bz60hzd8VOtqEEPOyhJEbGcvP4,4363
|
@@ -1705,8 +1706,8 @@ fastlife/templates/constants.py,sha256=MGdUjkF9hsPMN8rOS49eWbAApcb8FL-FAeFvJU8k9
|
|
1705
1706
|
fastlife/testing/__init__.py,sha256=vuqwoNUd3BuIp3fm7nkvmYkIGjIimf5zUGhDkeWrg2s,98
|
1706
1707
|
fastlife/testing/testclient.py,sha256=BC7lLQ_jc59UmknAKzgRtW9a3cpX_V_QLp9Mg2ScLA8,20546
|
1707
1708
|
fastlife/views/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1708
|
-
fastlife/views/pydantic_form.py,sha256=
|
1709
|
-
fastlifeweb-0.
|
1710
|
-
fastlifeweb-0.
|
1711
|
-
fastlifeweb-0.
|
1712
|
-
fastlifeweb-0.
|
1709
|
+
fastlife/views/pydantic_form.py,sha256=ZYOXKudmSqtRvFn5ZY75DOXZVunGXJBKpjh9FJcqu6k,1386
|
1710
|
+
fastlifeweb-0.16.1.dist-info/LICENSE,sha256=F75xSseSKMwqzFj8rswYU6NWS3VoWOc_gY3fJYf9_LI,1504
|
1711
|
+
fastlifeweb-0.16.1.dist-info/METADATA,sha256=La4IIIjXXg0eXH5pyshmlUCJdW4InYOusZ-h6oSYtiU,3345
|
1712
|
+
fastlifeweb-0.16.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
1713
|
+
fastlifeweb-0.16.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|