fastlifeweb 0.16.2__py3-none-any.whl → 0.16.4__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/adapters/jinjax/renderer.py +5 -10
- fastlife/adapters/jinjax/widgets/base.py +6 -4
- fastlife/adapters/jinjax/widgets/checklist.py +1 -1
- fastlife/adapters/jinjax/widgets/dropdown.py +7 -7
- fastlife/adapters/jinjax/widgets/factory.py +16 -16
- fastlife/adapters/jinjax/widgets/model.py +2 -1
- fastlife/adapters/jinjax/widgets/sequence.py +3 -2
- fastlife/adapters/jinjax/widgets/text.py +9 -10
- fastlife/adapters/jinjax/widgets/union.py +9 -7
- fastlife/config/configurator.py +9 -10
- fastlife/config/exceptions.py +2 -1
- fastlife/config/openapiextra.py +1 -0
- fastlife/config/resources.py +24 -25
- fastlife/config/views.py +3 -1
- fastlife/middlewares/reverse_proxy/x_forwarded.py +25 -3
- fastlife/middlewares/session/middleware.py +2 -2
- fastlife/middlewares/session/serializer.py +6 -5
- fastlife/request/form.py +7 -6
- fastlife/request/form_data.py +2 -6
- fastlife/routing/route.py +3 -1
- fastlife/routing/router.py +1 -0
- fastlife/security/csrf.py +2 -1
- fastlife/security/policy.py +2 -1
- fastlife/services/locale_negociator.py +2 -1
- fastlife/services/policy.py +2 -1
- fastlife/services/templates.py +2 -1
- fastlife/services/translations.py +3 -2
- fastlife/shared_utils/infer.py +4 -3
- fastlife/shared_utils/resolver.py +6 -3
- fastlife/templates/binding.py +2 -1
- fastlife/testing/__init__.py +1 -0
- fastlife/testing/testclient.py +7 -7
- fastlife/views/pydantic_form.py +4 -4
- {fastlifeweb-0.16.2.dist-info → fastlifeweb-0.16.4.dist-info}/METADATA +1 -1
- {fastlifeweb-0.16.2.dist-info → fastlifeweb-0.16.4.dist-info}/RECORD +37 -37
- {fastlifeweb-0.16.2.dist-info → fastlifeweb-0.16.4.dist-info}/LICENSE +0 -0
- {fastlifeweb-0.16.2.dist-info → fastlifeweb-0.16.4.dist-info}/WHEEL +0 -0
@@ -6,16 +6,11 @@ import ast
|
|
6
6
|
import logging
|
7
7
|
import re
|
8
8
|
import textwrap
|
9
|
+
from collections.abc import Iterator, Mapping, MutableMapping, Sequence
|
9
10
|
from pathlib import Path
|
10
11
|
from typing import (
|
11
12
|
TYPE_CHECKING,
|
12
13
|
Any,
|
13
|
-
Iterator,
|
14
|
-
Mapping,
|
15
|
-
MutableMapping,
|
16
|
-
Optional,
|
17
|
-
Sequence,
|
18
|
-
Type,
|
19
14
|
cast,
|
20
15
|
)
|
21
16
|
|
@@ -108,7 +103,7 @@ def generate_docstring(
|
|
108
103
|
kwonlyargs = func_def.args.kwonlyargs
|
109
104
|
kw_defaults = func_def.args.kw_defaults
|
110
105
|
|
111
|
-
for arg, default in zip(kwonlyargs, kw_defaults):
|
106
|
+
for arg, default in zip(kwonlyargs, kw_defaults, strict=False):
|
112
107
|
process_arg(arg, default)
|
113
108
|
|
114
109
|
if add_content:
|
@@ -342,7 +337,7 @@ class JinjaxRenderer(AbstractTemplateRenderer):
|
|
342
337
|
self,
|
343
338
|
template: str,
|
344
339
|
*,
|
345
|
-
globals:
|
340
|
+
globals: Mapping[str, Any] | None = None,
|
346
341
|
**params: Any,
|
347
342
|
) -> str:
|
348
343
|
# Jinja template does accept the file extention while rendering the template
|
@@ -360,13 +355,13 @@ class JinjaxRenderer(AbstractTemplateRenderer):
|
|
360
355
|
)
|
361
356
|
|
362
357
|
def pydantic_form(
|
363
|
-
self, model: FormModel[Any], *, token:
|
358
|
+
self, model: FormModel[Any], *, token: str | None = None
|
364
359
|
) -> Markup:
|
365
360
|
return WidgetFactory(self, token).get_markup(model)
|
366
361
|
|
367
362
|
def pydantic_form_field(
|
368
363
|
self,
|
369
|
-
model:
|
364
|
+
model: type[Any],
|
370
365
|
*,
|
371
366
|
name: str | None,
|
372
367
|
token: str | None,
|
@@ -1,7 +1,9 @@
|
|
1
1
|
"""Widget base class."""
|
2
|
+
|
2
3
|
import abc
|
3
4
|
import secrets
|
4
|
-
from
|
5
|
+
from collections.abc import Mapping
|
6
|
+
from typing import Any, Generic, TypeVar
|
5
7
|
|
6
8
|
from markupsafe import Markup
|
7
9
|
|
@@ -11,7 +13,7 @@ from fastlife.shared_utils.infer import is_union
|
|
11
13
|
T = TypeVar("T")
|
12
14
|
|
13
15
|
|
14
|
-
def get_title(typ:
|
16
|
+
def get_title(typ: type[Any]) -> str:
|
15
17
|
return getattr(
|
16
18
|
getattr(typ, "__meta__", None),
|
17
19
|
"title",
|
@@ -81,7 +83,7 @@ class Widget(abc.ABC, Generic[T]):
|
|
81
83
|
return Markup(renderer.render_template(self.get_template(), widget=self))
|
82
84
|
|
83
85
|
|
84
|
-
def _get_fullname(typ:
|
86
|
+
def _get_fullname(typ: type[Any]) -> str:
|
85
87
|
if is_union(typ):
|
86
88
|
typs = [_get_fullname(t) for t in typ.__args__] # type: ignore
|
87
89
|
return "|".join(typs) # type: ignore
|
@@ -102,7 +104,7 @@ class TypeWrapper:
|
|
102
104
|
|
103
105
|
def __init__(
|
104
106
|
self,
|
105
|
-
typ:
|
107
|
+
typ: type[Any],
|
106
108
|
route_prefix: str,
|
107
109
|
name: str,
|
108
110
|
token: str,
|
@@ -2,7 +2,7 @@
|
|
2
2
|
Widget for field of type Enum or Literal.
|
3
3
|
"""
|
4
4
|
|
5
|
-
from
|
5
|
+
from collections.abc import Sequence
|
6
6
|
|
7
7
|
from .base import Widget
|
8
8
|
|
@@ -26,14 +26,14 @@ class DropDownWidget(Widget[str]):
|
|
26
26
|
self,
|
27
27
|
name: str,
|
28
28
|
*,
|
29
|
-
title:
|
30
|
-
hint:
|
31
|
-
aria_label:
|
32
|
-
value:
|
29
|
+
title: str | None,
|
30
|
+
hint: str | None = None,
|
31
|
+
aria_label: str | None = None,
|
32
|
+
value: str | None = None,
|
33
33
|
error: str | None = None,
|
34
|
-
options: Sequence[
|
34
|
+
options: Sequence[tuple[str, str]] | Sequence[str],
|
35
35
|
removable: bool = False,
|
36
|
-
token:
|
36
|
+
token: str | None = None,
|
37
37
|
) -> None:
|
38
38
|
super().__init__(
|
39
39
|
name,
|
@@ -3,12 +3,12 @@ Transform.
|
|
3
3
|
"""
|
4
4
|
|
5
5
|
import secrets
|
6
|
-
from collections.abc import MutableSequence, Sequence
|
6
|
+
from collections.abc import Mapping, MutableSequence, Sequence
|
7
7
|
from decimal import Decimal
|
8
8
|
from enum import Enum
|
9
9
|
from inspect import isclass
|
10
10
|
from types import NoneType
|
11
|
-
from typing import Any, Literal,
|
11
|
+
from typing import Any, Literal, cast, get_origin
|
12
12
|
from uuid import UUID
|
13
13
|
|
14
14
|
from markupsafe import Markup
|
@@ -59,7 +59,7 @@ class WidgetFactory:
|
|
59
59
|
|
60
60
|
def get_widget(
|
61
61
|
self,
|
62
|
-
base:
|
62
|
+
base: type[Any],
|
63
63
|
form_data: Mapping[str, Any],
|
64
64
|
form_errors: Mapping[str, Any],
|
65
65
|
*,
|
@@ -78,7 +78,7 @@ class WidgetFactory:
|
|
78
78
|
|
79
79
|
def build(
|
80
80
|
self,
|
81
|
-
typ:
|
81
|
+
typ: type[Any],
|
82
82
|
*,
|
83
83
|
name: str = "",
|
84
84
|
value: Any,
|
@@ -152,7 +152,7 @@ class WidgetFactory:
|
|
152
152
|
name, typ, field, value or "", form_errors, removable
|
153
153
|
)
|
154
154
|
|
155
|
-
if issubclass(typ,
|
155
|
+
if issubclass(typ, int | str | float | Decimal | UUID):
|
156
156
|
return self.build_simpletype(
|
157
157
|
name, typ, field, value or "", form_errors, removable
|
158
158
|
)
|
@@ -162,7 +162,7 @@ class WidgetFactory:
|
|
162
162
|
def build_model(
|
163
163
|
self,
|
164
164
|
field_name: str,
|
165
|
-
typ:
|
165
|
+
typ: type[BaseModel],
|
166
166
|
field: FieldInfo | None,
|
167
167
|
value: Mapping[str, Any],
|
168
168
|
form_errors: Mapping[str, Any],
|
@@ -204,13 +204,13 @@ class WidgetFactory:
|
|
204
204
|
def build_union(
|
205
205
|
self,
|
206
206
|
field_name: str,
|
207
|
-
field_type:
|
207
|
+
field_type: type[Any],
|
208
208
|
field: FieldInfo | None,
|
209
209
|
value: Any,
|
210
210
|
form_errors: Mapping[str, Any],
|
211
211
|
removable: bool,
|
212
212
|
) -> Widget[Any]:
|
213
|
-
types: list[
|
213
|
+
types: list[type[Any]] = []
|
214
214
|
# required = True
|
215
215
|
for typ in field_type.__args__: # type: ignore
|
216
216
|
if typ is NoneType:
|
@@ -271,7 +271,7 @@ class WidgetFactory:
|
|
271
271
|
def build_sequence(
|
272
272
|
self,
|
273
273
|
field_name: str,
|
274
|
-
field_type:
|
274
|
+
field_type: type[Any],
|
275
275
|
field: FieldInfo | None,
|
276
276
|
value: Sequence[Any] | None,
|
277
277
|
form_errors: Mapping[str, Any],
|
@@ -309,7 +309,7 @@ class WidgetFactory:
|
|
309
309
|
def build_set(
|
310
310
|
self,
|
311
311
|
field_name: str,
|
312
|
-
field_type:
|
312
|
+
field_type: type[Any],
|
313
313
|
field: FieldInfo | None,
|
314
314
|
value: Sequence[Any] | None,
|
315
315
|
form_errors: Mapping[str, Any],
|
@@ -368,7 +368,7 @@ class WidgetFactory:
|
|
368
368
|
def build_boolean(
|
369
369
|
self,
|
370
370
|
field_name: str,
|
371
|
-
field_type:
|
371
|
+
field_type: type[Any],
|
372
372
|
field: FieldInfo | None,
|
373
373
|
value: bool,
|
374
374
|
form_errors: Mapping[str, Any],
|
@@ -392,7 +392,7 @@ class WidgetFactory:
|
|
392
392
|
def build_emailtype(
|
393
393
|
self,
|
394
394
|
field_name: str,
|
395
|
-
field_type:
|
395
|
+
field_type: type[Any],
|
396
396
|
field: FieldInfo | None,
|
397
397
|
value: str | int | float,
|
398
398
|
form_errors: Mapping[str, Any],
|
@@ -418,7 +418,7 @@ class WidgetFactory:
|
|
418
418
|
def build_secretstr(
|
419
419
|
self,
|
420
420
|
field_name: str,
|
421
|
-
field_type:
|
421
|
+
field_type: type[Any],
|
422
422
|
field: FieldInfo | None,
|
423
423
|
value: SecretStr | str,
|
424
424
|
form_errors: Mapping[str, Any],
|
@@ -444,7 +444,7 @@ class WidgetFactory:
|
|
444
444
|
def build_literal(
|
445
445
|
self,
|
446
446
|
field_name: str,
|
447
|
-
field_type:
|
447
|
+
field_type: type[Any], # a literal actually
|
448
448
|
field: FieldInfo | None,
|
449
449
|
value: str | int | float,
|
450
450
|
form_errors: Mapping[str, Any],
|
@@ -476,7 +476,7 @@ class WidgetFactory:
|
|
476
476
|
def build_enum(
|
477
477
|
self,
|
478
478
|
field_name: str,
|
479
|
-
field_type:
|
479
|
+
field_type: type[Any], # an enum subclass
|
480
480
|
field: FieldInfo | None,
|
481
481
|
value: str | int | float,
|
482
482
|
form_errors: Mapping[str, Any],
|
@@ -502,7 +502,7 @@ class WidgetFactory:
|
|
502
502
|
def build_simpletype(
|
503
503
|
self,
|
504
504
|
field_name: str,
|
505
|
-
field_type:
|
505
|
+
field_type: type[Any],
|
506
506
|
field: FieldInfo | None,
|
507
507
|
value: str | int | float,
|
508
508
|
form_errors: Mapping[str, Any],
|
@@ -1,4 +1,5 @@
|
|
1
|
-
from
|
1
|
+
from collections.abc import Sequence
|
2
|
+
from typing import Any
|
2
3
|
|
3
4
|
from markupsafe import Markup
|
4
5
|
|
@@ -17,7 +18,7 @@ class SequenceWidget(Widget[Sequence[Widget[Any]]]):
|
|
17
18
|
aria_label: str | None = None,
|
18
19
|
value: Sequence[Widget[Any]] | None,
|
19
20
|
error: str | None = None,
|
20
|
-
item_type:
|
21
|
+
item_type: type[Any],
|
21
22
|
token: str,
|
22
23
|
removable: bool,
|
23
24
|
):
|
@@ -1,5 +1,4 @@
|
|
1
1
|
from collections.abc import Sequence
|
2
|
-
from typing import Optional
|
3
2
|
|
4
3
|
from .base import Widget
|
5
4
|
|
@@ -23,10 +22,10 @@ class TextWidget(Widget[str]):
|
|
23
22
|
self,
|
24
23
|
name: str,
|
25
24
|
*,
|
26
|
-
title:
|
27
|
-
hint:
|
28
|
-
aria_label:
|
29
|
-
placeholder:
|
25
|
+
title: str | None,
|
26
|
+
hint: str | None = None,
|
27
|
+
aria_label: str | None = None,
|
28
|
+
placeholder: str | None = None,
|
30
29
|
error: str | None = None,
|
31
30
|
value: str = "",
|
32
31
|
input_type: str = "text",
|
@@ -87,12 +86,12 @@ class TextareaWidget(Widget[Sequence[str]]):
|
|
87
86
|
self,
|
88
87
|
name: str,
|
89
88
|
*,
|
90
|
-
title:
|
91
|
-
hint:
|
92
|
-
aria_label:
|
93
|
-
placeholder:
|
89
|
+
title: str | None,
|
90
|
+
hint: str | None = None,
|
91
|
+
aria_label: str | None = None,
|
92
|
+
placeholder: str | None = None,
|
94
93
|
error: str | None = None,
|
95
|
-
value:
|
94
|
+
value: Sequence[str] | None = None,
|
96
95
|
removable: bool = False,
|
97
96
|
token: str,
|
98
97
|
) -> None:
|
@@ -1,7 +1,9 @@
|
|
1
1
|
"""
|
2
2
|
Widget for field of type Union.
|
3
3
|
"""
|
4
|
-
|
4
|
+
|
5
|
+
from collections.abc import Sequence
|
6
|
+
from typing import Any, Union
|
5
7
|
|
6
8
|
from markupsafe import Markup
|
7
9
|
from pydantic import BaseModel
|
@@ -31,12 +33,12 @@ class UnionWidget(Widget[Widget[Any]]):
|
|
31
33
|
self,
|
32
34
|
name: str,
|
33
35
|
*,
|
34
|
-
title:
|
35
|
-
hint:
|
36
|
-
aria_label:
|
37
|
-
value:
|
36
|
+
title: str | None,
|
37
|
+
hint: str | None = None,
|
38
|
+
aria_label: str | None = None,
|
39
|
+
value: Widget[Any] | None,
|
38
40
|
error: str | None = None,
|
39
|
-
children_types: Sequence[
|
41
|
+
children_types: Sequence[type[BaseModel]],
|
40
42
|
removable: bool = False,
|
41
43
|
token: str,
|
42
44
|
):
|
@@ -72,7 +74,7 @@ class UnionWidget(Widget[Widget[Any]]):
|
|
72
74
|
widget=self,
|
73
75
|
types=self.build_types(renderer.route_prefix),
|
74
76
|
parent_type=TypeWrapper(
|
75
|
-
Union[tuple(self.children_types)], # type: ignore
|
77
|
+
Union[tuple(self.children_types)], # type: ignore # noqa: UP007
|
76
78
|
renderer.route_prefix,
|
77
79
|
self.parent_name,
|
78
80
|
self.token,
|
fastlife/config/configurator.py
CHANGED
@@ -15,16 +15,15 @@ import importlib
|
|
15
15
|
import inspect
|
16
16
|
import logging
|
17
17
|
from collections import defaultdict
|
18
|
-
from collections.abc import Mapping, Sequence
|
18
|
+
from collections.abc import Callable, 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,
|
22
|
+
from typing import TYPE_CHECKING, Annotated, Any, Generic, Self
|
23
23
|
|
24
24
|
import venusian
|
25
|
-
from fastapi import Depends, FastAPI
|
25
|
+
from fastapi import Depends, FastAPI, Response
|
26
26
|
from fastapi import Request as BaseRequest
|
27
|
-
from fastapi import Response
|
28
27
|
from fastapi.params import Depends as DependsType
|
29
28
|
from fastapi.staticfiles import StaticFiles
|
30
29
|
from fastapi.types import IncEx
|
@@ -127,9 +126,9 @@ class GenericConfigurator(Generic[TRegistry]):
|
|
127
126
|
self.registry = registry_cls(settings)
|
128
127
|
Route._registry = self.registry # type: ignore
|
129
128
|
|
130
|
-
self.middlewares: list[
|
131
|
-
self.exception_handlers: list[
|
132
|
-
self.mounts: list[
|
129
|
+
self.middlewares: list[tuple[type[AbstractMiddleware], Any]] = []
|
130
|
+
self.exception_handlers: list[tuple[int | type[Exception], Any]] = []
|
131
|
+
self.mounts: list[tuple[str, Path, str]] = []
|
133
132
|
self.tags: dict[str, OpenApiTag] = {}
|
134
133
|
|
135
134
|
self.api_title = "OpenAPI"
|
@@ -142,7 +141,7 @@ class GenericConfigurator(Generic[TRegistry]):
|
|
142
141
|
self._route_prefix: str = ""
|
143
142
|
self._routers: dict[str, Router] = defaultdict(Router)
|
144
143
|
self._security_policies: dict[
|
145
|
-
str,
|
144
|
+
str, type[AbstractSecurityPolicy[Any, TRegistry]]
|
146
145
|
] = {}
|
147
146
|
|
148
147
|
self._registered_permissions: set[str] = set()
|
@@ -310,7 +309,7 @@ class GenericConfigurator(Generic[TRegistry]):
|
|
310
309
|
return self
|
311
310
|
|
312
311
|
def add_middleware(
|
313
|
-
self, middleware_class:
|
312
|
+
self, middleware_class: type[AbstractMiddleware], **options: Any
|
314
313
|
) -> Self:
|
315
314
|
"""
|
316
315
|
Add a starlette middleware to the FastAPI app.
|
@@ -522,7 +521,7 @@ class GenericConfigurator(Generic[TRegistry]):
|
|
522
521
|
|
523
522
|
def add_exception_handler(
|
524
523
|
self,
|
525
|
-
status_code_or_exc: int |
|
524
|
+
status_code_or_exc: int | type[Exception],
|
526
525
|
handler: Any,
|
527
526
|
*,
|
528
527
|
template: str | None = None,
|
fastlife/config/exceptions.py
CHANGED
fastlife/config/openapiextra.py
CHANGED
fastlife/config/resources.py
CHANGED
@@ -8,7 +8,8 @@ API Resources declaration using a decorator.
|
|
8
8
|
|
9
9
|
"""
|
10
10
|
|
11
|
-
from
|
11
|
+
from collections.abc import Callable
|
12
|
+
from typing import Any
|
12
13
|
|
13
14
|
import venusian
|
14
15
|
from fastapi.types import IncEx
|
@@ -91,29 +92,21 @@ def resource(
|
|
91
92
|
endpoint=endpoint,
|
92
93
|
tags=[tag],
|
93
94
|
methods=[method.split("_").pop()],
|
94
|
-
permission=
|
95
|
-
status_code=
|
96
|
-
summary=
|
97
|
-
description=
|
98
|
-
response_description=
|
99
|
-
deprecated=
|
100
|
-
operation_id=
|
101
|
-
response_model_include=
|
102
|
-
response_model_exclude=
|
103
|
-
response_model_by_alias=
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
response_model_exclude_defaults=getattr(
|
110
|
-
endpoint, "response_model_exclude_defaults"
|
111
|
-
),
|
112
|
-
response_model_exclude_none=getattr(
|
113
|
-
endpoint, "response_model_exclude_none"
|
114
|
-
),
|
115
|
-
include_in_schema=getattr(endpoint, "include_in_schema"),
|
116
|
-
openapi_extra=getattr(endpoint, "openapi_extra"),
|
95
|
+
permission=endpoint.permission,
|
96
|
+
status_code=endpoint.status_code,
|
97
|
+
summary=endpoint.summary,
|
98
|
+
description=endpoint.description,
|
99
|
+
response_description=endpoint.response_description,
|
100
|
+
deprecated=endpoint.deprecated,
|
101
|
+
operation_id=endpoint.operation_id,
|
102
|
+
response_model_include=endpoint.response_model_include,
|
103
|
+
response_model_exclude=endpoint.response_model_exclude,
|
104
|
+
response_model_by_alias=endpoint.response_model_by_alias,
|
105
|
+
response_model_exclude_unset=endpoint.response_model_exclude_unset,
|
106
|
+
response_model_exclude_defaults=endpoint.response_model_exclude_defaults,
|
107
|
+
response_model_exclude_none=endpoint.response_model_exclude_none,
|
108
|
+
include_in_schema=endpoint.include_in_schema,
|
109
|
+
openapi_extra=endpoint.openapi_extra,
|
117
110
|
)
|
118
111
|
|
119
112
|
for method in dir(ob):
|
@@ -131,7 +124,13 @@ def resource(
|
|
131
124
|
config, method, collection_path, getattr(api, method)
|
132
125
|
)
|
133
126
|
case (
|
134
|
-
"get"
|
127
|
+
"get"
|
128
|
+
| "post"
|
129
|
+
| "put"
|
130
|
+
| "patch"
|
131
|
+
| "delete"
|
132
|
+
| "head"
|
133
|
+
| "options"
|
135
134
|
):
|
136
135
|
bind_config(config, method, path, getattr(api, method))
|
137
136
|
case _:
|
fastlife/config/views.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import logging
|
2
|
-
from
|
2
|
+
from collections.abc import Sequence
|
3
3
|
|
4
4
|
from starlette.types import ASGIApp, Receive, Scope, Send
|
5
5
|
|
@@ -8,13 +8,24 @@ from fastlife.middlewares.base import AbstractMiddleware
|
|
8
8
|
log = logging.getLogger(__name__)
|
9
9
|
|
10
10
|
|
11
|
-
def get_header(headers: Sequence[
|
11
|
+
def get_header(headers: Sequence[tuple[bytes, bytes]], key: bytes) -> str | None:
|
12
12
|
for hdr in headers:
|
13
13
|
if hdr[0].lower() == key:
|
14
14
|
return hdr[1].decode("latin1")
|
15
15
|
return None
|
16
16
|
|
17
17
|
|
18
|
+
def get_header_int(headers: Sequence[tuple[bytes, bytes]], key: bytes) -> int | None:
|
19
|
+
for hdr in headers:
|
20
|
+
if hdr[0].lower() == key:
|
21
|
+
ret = hdr[1].decode("latin1")
|
22
|
+
try:
|
23
|
+
return int(ret)
|
24
|
+
except ValueError:
|
25
|
+
pass
|
26
|
+
return None
|
27
|
+
|
28
|
+
|
18
29
|
class XForwardedStar(AbstractMiddleware):
|
19
30
|
def __init__(
|
20
31
|
self,
|
@@ -25,8 +36,19 @@ class XForwardedStar(AbstractMiddleware):
|
|
25
36
|
async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
|
26
37
|
if scope["type"] in ("http", "websocket"):
|
27
38
|
headers = scope["headers"]
|
39
|
+
x_real_ip = get_header(headers, b"x-real-ip")
|
40
|
+
client = (
|
41
|
+
(
|
42
|
+
x_real_ip,
|
43
|
+
get_header_int(headers, b"x-real-port")
|
44
|
+
or get_header_int(headers, b"x-forwarded-port")
|
45
|
+
or 0,
|
46
|
+
)
|
47
|
+
if x_real_ip
|
48
|
+
else None
|
49
|
+
)
|
28
50
|
new_vals = {
|
29
|
-
"client":
|
51
|
+
"client": client,
|
30
52
|
"host": get_header(headers, b"x-forwarded-host"),
|
31
53
|
"scheme": get_header(headers, b"x-forwarded-proto"),
|
32
54
|
}
|
@@ -1,7 +1,7 @@
|
|
1
1
|
"""Deal with http session."""
|
2
2
|
|
3
3
|
from datetime import timedelta
|
4
|
-
from typing import Literal
|
4
|
+
from typing import Literal
|
5
5
|
|
6
6
|
from starlette.datastructures import MutableHeaders
|
7
7
|
from starlette.requests import HTTPConnection
|
@@ -25,7 +25,7 @@ class SessionMiddleware(AbstractMiddleware):
|
|
25
25
|
cookie_same_site: Literal["lax", "strict", "none"] = "lax",
|
26
26
|
cookie_secure: bool = False,
|
27
27
|
cookie_domain: str = "",
|
28
|
-
serializer:
|
28
|
+
serializer: type[AbsractSessionSerializer] = SignedSessionSerializer,
|
29
29
|
) -> None:
|
30
30
|
self.app = app
|
31
31
|
self.max_age = int(duration.total_seconds())
|
@@ -1,8 +1,10 @@
|
|
1
1
|
"""Serialize session."""
|
2
|
+
|
2
3
|
import abc
|
3
4
|
import json
|
4
5
|
from base64 import b64decode, b64encode
|
5
|
-
from
|
6
|
+
from collections.abc import Mapping
|
7
|
+
from typing import Any
|
6
8
|
|
7
9
|
import itsdangerous
|
8
10
|
|
@@ -11,8 +13,7 @@ class AbsractSessionSerializer(abc.ABC):
|
|
11
13
|
"""Session serializer base class"""
|
12
14
|
|
13
15
|
@abc.abstractmethod
|
14
|
-
def __init__(self, secret_key: str, max_age: int) -> None:
|
15
|
-
...
|
16
|
+
def __init__(self, secret_key: str, max_age: int) -> None: ...
|
16
17
|
|
17
18
|
@abc.abstractmethod
|
18
19
|
def serialize(self, data: Mapping[str, Any]) -> bytes:
|
@@ -20,7 +21,7 @@ class AbsractSessionSerializer(abc.ABC):
|
|
20
21
|
...
|
21
22
|
|
22
23
|
@abc.abstractmethod
|
23
|
-
def deserialize(self, data: bytes) ->
|
24
|
+
def deserialize(self, data: bytes) -> tuple[Mapping[str, Any], bool]:
|
24
25
|
"""Derialize the session raw bytes content and return it as a mapping."""
|
25
26
|
...
|
26
27
|
|
@@ -47,7 +48,7 @@ class SignedSessionSerializer(AbsractSessionSerializer):
|
|
47
48
|
signed = self.signer.sign(encoded)
|
48
49
|
return signed
|
49
50
|
|
50
|
-
def deserialize(self, data: bytes) ->
|
51
|
+
def deserialize(self, data: bytes) -> tuple[Mapping[str, Any], bool]:
|
51
52
|
"""Deserialize the session.
|
52
53
|
|
53
54
|
If the signature is incorect, the session restart from the begining.
|
fastlife/request/form.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
"""HTTP Form serialization."""
|
2
2
|
|
3
|
-
from
|
3
|
+
from collections.abc import Callable, Mapping
|
4
|
+
from typing import Any, Generic, TypeVar, get_origin
|
4
5
|
|
5
6
|
from fastapi import Depends
|
6
7
|
from pydantic import BaseModel, ValidationError
|
@@ -28,7 +29,7 @@ class FormModel(Generic[T]):
|
|
28
29
|
self.is_valid = is_valid
|
29
30
|
|
30
31
|
@classmethod
|
31
|
-
def default(cls, prefix: str, pydantic_type:
|
32
|
+
def default(cls, prefix: str, pydantic_type: type[T]) -> "FormModel[T]":
|
32
33
|
return cls(prefix, pydantic_type.model_construct(), {})
|
33
34
|
|
34
35
|
def edit(self, pydantic_type: T) -> None:
|
@@ -47,7 +48,7 @@ class FormModel(Generic[T]):
|
|
47
48
|
|
48
49
|
@classmethod
|
49
50
|
def from_payload(
|
50
|
-
cls, prefix: str, pydantic_type:
|
51
|
+
cls, prefix: str, pydantic_type: type[T], data: Mapping[str, Any]
|
51
52
|
) -> "FormModel[T]":
|
52
53
|
try:
|
53
54
|
return cls(prefix, pydantic_type(**data.get(prefix, {})), {}, True)
|
@@ -68,12 +69,12 @@ class FormModel(Generic[T]):
|
|
68
69
|
continue
|
69
70
|
|
70
71
|
else:
|
71
|
-
raise NotImplementedError
|
72
|
+
raise NotImplementedError from exc # coverage: ignore
|
72
73
|
elif issubclass(typ, BaseModel):
|
73
74
|
typ = typ.model_fields[part].annotation
|
74
75
|
loc = f"{loc}.{part}"
|
75
76
|
else:
|
76
|
-
raise NotImplementedError
|
77
|
+
raise NotImplementedError from exc # coverage: ignore
|
77
78
|
|
78
79
|
else:
|
79
80
|
# it is an integer and it part of the list
|
@@ -88,7 +89,7 @@ class FormModel(Generic[T]):
|
|
88
89
|
|
89
90
|
|
90
91
|
def form_model(
|
91
|
-
cls:
|
92
|
+
cls: type[T], name: str | None = None
|
92
93
|
) -> Callable[[Mapping[str, Any]], FormModel[T]]:
|
93
94
|
"""
|
94
95
|
Build a model, a class of type T based on Pydandic Base Model from a form payload.
|
fastlife/request/form_data.py
CHANGED
@@ -2,14 +2,10 @@
|
|
2
2
|
Set of functions to unserialize www-form-urlencoded format to python simple types.
|
3
3
|
"""
|
4
4
|
|
5
|
+
from collections.abc import Mapping, MutableMapping, MutableSequence, Sequence
|
5
6
|
from typing import (
|
6
7
|
Annotated,
|
7
8
|
Any,
|
8
|
-
Mapping,
|
9
|
-
MutableMapping,
|
10
|
-
MutableSequence,
|
11
|
-
Optional,
|
12
|
-
Sequence,
|
13
9
|
)
|
14
10
|
|
15
11
|
from fastapi import Depends
|
@@ -22,7 +18,7 @@ def unflatten_struct(
|
|
22
18
|
unflattened_output: MutableMapping[str, Any] | MutableSequence[Any],
|
23
19
|
level: int = 0,
|
24
20
|
*,
|
25
|
-
csrf_token_name:
|
21
|
+
csrf_token_name: str | None = None,
|
26
22
|
) -> Mapping[str, Any] | Sequence[Any]:
|
27
23
|
"""
|
28
24
|
Take a flatten_input map, with key segmented by `.` and build a nested dict.
|
fastlife/routing/route.py
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
"""HTTP Route."""
|
2
|
-
|
2
|
+
|
3
|
+
from collections.abc import Callable, Coroutine
|
4
|
+
from typing import TYPE_CHECKING, Any
|
3
5
|
|
4
6
|
from fastapi.routing import APIRoute
|
5
7
|
from starlette.requests import Request as StarletteRequest
|
fastlife/routing/router.py
CHANGED
fastlife/security/csrf.py
CHANGED
fastlife/security/policy.py
CHANGED
@@ -2,7 +2,8 @@
|
|
2
2
|
|
3
3
|
import abc
|
4
4
|
import logging
|
5
|
-
from
|
5
|
+
from collections.abc import Callable, Coroutine
|
6
|
+
from typing import Annotated, Any, Generic, Literal, TypeVar
|
6
7
|
from uuid import UUID
|
7
8
|
|
8
9
|
from fastapi import Depends, HTTPException
|
fastlife/services/policy.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
"""Security policy."""
|
2
2
|
|
3
|
-
from
|
3
|
+
from collections.abc import Callable, Coroutine
|
4
|
+
from typing import Any
|
4
5
|
|
5
6
|
CheckPermissionHook = Callable[..., Coroutine[Any, Any, None]] | Callable[..., None]
|
6
7
|
CheckPermission = Callable[[str], CheckPermissionHook]
|
fastlife/services/templates.py
CHANGED
@@ -10,7 +10,8 @@ In that case, those base classes have to be implemented.
|
|
10
10
|
"""
|
11
11
|
|
12
12
|
import abc
|
13
|
-
from
|
13
|
+
from collections.abc import Callable, Mapping
|
14
|
+
from typing import Any
|
14
15
|
|
15
16
|
from fastlife import Request, Response
|
16
17
|
from fastlife.security.csrf import create_csrf_token
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import pathlib
|
2
|
-
from
|
2
|
+
from collections.abc import Iterator
|
3
|
+
from typing import TYPE_CHECKING
|
3
4
|
|
4
5
|
from babel.support import NullTranslations, Translations
|
5
6
|
|
@@ -11,7 +12,7 @@ if TYPE_CHECKING:
|
|
11
12
|
locale_name = str
|
12
13
|
|
13
14
|
|
14
|
-
def find_mo_files(root_path: str) -> Iterator[
|
15
|
+
def find_mo_files(root_path: str) -> Iterator[tuple[str, str, pathlib.Path]]:
|
15
16
|
root = pathlib.Path(root_path)
|
16
17
|
|
17
18
|
# Walk through the directory structure and match the pattern
|
fastlife/shared_utils/infer.py
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
"""Type inference."""
|
2
|
+
|
2
3
|
from types import UnionType
|
3
|
-
from typing import Any,
|
4
|
+
from typing import Any, Union, get_origin
|
4
5
|
|
5
6
|
from pydantic import BaseModel
|
6
7
|
|
7
8
|
|
8
|
-
def is_complex_type(typ:
|
9
|
+
def is_complex_type(typ: type[Any]) -> bool:
|
9
10
|
"""
|
10
11
|
Used to detect complex type such as Mapping, Sequence and pydantic BaseModel.
|
11
12
|
|
@@ -14,7 +15,7 @@ def is_complex_type(typ: Type[Any]) -> bool:
|
|
14
15
|
return bool(get_origin(typ) or issubclass(typ, BaseModel))
|
15
16
|
|
16
17
|
|
17
|
-
def is_union(typ:
|
18
|
+
def is_union(typ: type[Any]) -> bool:
|
18
19
|
"""Used to detect unions like Optional[T], Union[T, U] or T | U."""
|
19
20
|
type_origin = get_origin(typ)
|
20
21
|
if type_origin:
|
@@ -1,4 +1,5 @@
|
|
1
1
|
"""Resolution of python objects for dependency injection and more."""
|
2
|
+
|
2
3
|
import importlib.util
|
3
4
|
from pathlib import Path
|
4
5
|
from types import UnionType
|
@@ -20,8 +21,10 @@ def resolve(value: str) -> Any:
|
|
20
21
|
|
21
22
|
try:
|
22
23
|
attr = getattr(module, attr_name)
|
23
|
-
except AttributeError:
|
24
|
-
raise ValueError(
|
24
|
+
except AttributeError as exc:
|
25
|
+
raise ValueError(
|
26
|
+
f"Attribute {attr_name} not found in module {module_name}"
|
27
|
+
) from exc
|
25
28
|
|
26
29
|
return attr
|
27
30
|
|
@@ -32,7 +35,7 @@ def resolve_extended(value: str) -> UnionType:
|
|
32
35
|
if len(values) == 1:
|
33
36
|
return resolve(value)
|
34
37
|
types = [resolve(t) for t in values if t != "builtins:NoneType"]
|
35
|
-
return Union[tuple(types)] # type: ignore
|
38
|
+
return Union[tuple(types)] # type: ignore # noqa: UP007
|
36
39
|
|
37
40
|
|
38
41
|
def resolve_path(value: str) -> str:
|
fastlife/templates/binding.py
CHANGED
fastlife/testing/__init__.py
CHANGED
fastlife/testing/testclient.py
CHANGED
@@ -2,9 +2,9 @@
|
|
2
2
|
|
3
3
|
import re
|
4
4
|
import time
|
5
|
-
from collections.abc import MutableMapping
|
5
|
+
from collections.abc import Iterator, Mapping, MutableMapping, Sequence
|
6
6
|
from http.cookiejar import Cookie
|
7
|
-
from typing import Any,
|
7
|
+
from typing import Any, Literal
|
8
8
|
from urllib.parse import urlencode
|
9
9
|
|
10
10
|
import bs4
|
@@ -76,7 +76,7 @@ class Element:
|
|
76
76
|
return Element(self._client, self._tag.form) if self._tag.form else None
|
77
77
|
|
78
78
|
@property
|
79
|
-
def hx_target(self) ->
|
79
|
+
def hx_target(self) -> str | None:
|
80
80
|
"""
|
81
81
|
Return the hx-target of the element.
|
82
82
|
|
@@ -251,7 +251,7 @@ class WebForm:
|
|
251
251
|
raise ValueError(f'"{fieldname}" does not exists')
|
252
252
|
field = self._formfields[fieldname]
|
253
253
|
if field.node_name != "select":
|
254
|
-
raise ValueError(f"{fieldname} is a {
|
254
|
+
raise ValueError(f"{fieldname} is a {field!r}, " "use set() instead")
|
255
255
|
|
256
256
|
for option in field.by_node_name("option"):
|
257
257
|
if option.text == value.strip():
|
@@ -273,7 +273,7 @@ class WebForm:
|
|
273
273
|
|
274
274
|
if field.node_name != "select":
|
275
275
|
raise ValueError(
|
276
|
-
f"{fieldname} is a {
|
276
|
+
f"{fieldname} is a {self._formfields[fieldname]!r}, "
|
277
277
|
"use unset() for checkbox instead"
|
278
278
|
)
|
279
279
|
if "multiple" not in field.attrs:
|
@@ -392,7 +392,7 @@ class WebResponse:
|
|
392
392
|
def html_body(self) -> Element:
|
393
393
|
"""The body element of the html response."""
|
394
394
|
body = self.html.by_node_name("body")
|
395
|
-
assert len(body) == 1
|
395
|
+
assert len(body) == 1, "body element not found or multiple body found"
|
396
396
|
return body[0]
|
397
397
|
|
398
398
|
@property
|
@@ -400,7 +400,7 @@ class WebResponse:
|
|
400
400
|
"""The form element of the html response."""
|
401
401
|
if self._form is None:
|
402
402
|
form = self.html.form
|
403
|
-
assert form is not None
|
403
|
+
assert form is not None, "form element not found"
|
404
404
|
self._form = WebForm(self._client, self._origin, form)
|
405
405
|
return self._form
|
406
406
|
|
fastlife/views/pydantic_form.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
from typing import
|
1
|
+
from typing import cast
|
2
2
|
|
3
3
|
from fastapi import Query
|
4
4
|
from pydantic.fields import FieldInfo
|
@@ -11,9 +11,9 @@ from fastlife.shared_utils.resolver import resolve_extended
|
|
11
11
|
async def show_widget(
|
12
12
|
typ: str,
|
13
13
|
request: Request,
|
14
|
-
title:
|
15
|
-
name:
|
16
|
-
token:
|
14
|
+
title: str | None = Query(None),
|
15
|
+
name: str | None = Query(None),
|
16
|
+
token: str | None = Query(None),
|
17
17
|
removable: bool = Query(False),
|
18
18
|
) -> Response:
|
19
19
|
"""
|
@@ -1,18 +1,18 @@
|
|
1
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=_8k4a4R4ExjJrKiG5m5bFOxYqOFa3_TtmZ7iU1rd-p8,13041
|
5
5
|
fastlife/adapters/jinjax/widgets/__init__.py,sha256=HERnX9xiXUbTDz3XtlnHWABTBjhIq_kkBgWs5E6ZIMY,42
|
6
|
-
fastlife/adapters/jinjax/widgets/base.py,sha256=
|
6
|
+
fastlife/adapters/jinjax/widgets/base.py,sha256=3bBThRMnsdCi6Q_Dm73ep5pNOqgpSXsvAIBbHshfY7I,4037
|
7
7
|
fastlife/adapters/jinjax/widgets/boolean.py,sha256=w4hZMo_8xDoThStlIUR4eVfLm8JwUp0-TaGCjGSyCbA,1145
|
8
|
-
fastlife/adapters/jinjax/widgets/checklist.py,sha256=
|
9
|
-
fastlife/adapters/jinjax/widgets/dropdown.py,sha256=
|
10
|
-
fastlife/adapters/jinjax/widgets/factory.py,sha256=
|
8
|
+
fastlife/adapters/jinjax/widgets/checklist.py,sha256=8fgOrdxy1xpyQ6p3_mbRMd2vx6EU2WT5jI7QF27Y5EQ,1664
|
9
|
+
fastlife/adapters/jinjax/widgets/dropdown.py,sha256=3Kc7i0z-7d6HrQchSHFCO5-xOh3bSEePo_pjXrIkvSE,1599
|
10
|
+
fastlife/adapters/jinjax/widgets/factory.py,sha256=42cadaEzQb5vrwdOJRpv8JATz97EHa6YZo2EIbDx36o,17554
|
11
11
|
fastlife/adapters/jinjax/widgets/hidden.py,sha256=pkMKxKhBKSGNf1Su81Jr-n8BJ45X5Qjsd1xXnJ7prPI,699
|
12
|
-
fastlife/adapters/jinjax/widgets/model.py,sha256=
|
13
|
-
fastlife/adapters/jinjax/widgets/sequence.py,sha256=
|
14
|
-
fastlife/adapters/jinjax/widgets/text.py,sha256=
|
15
|
-
fastlife/adapters/jinjax/widgets/union.py,sha256=
|
12
|
+
fastlife/adapters/jinjax/widgets/model.py,sha256=xdgY--K4GNo5IIWTLjSAnNRDHq2bt81mh9O5J23y0gg,1299
|
13
|
+
fastlife/adapters/jinjax/widgets/sequence.py,sha256=60rgz4LgE_TQQwajiZhn6EhY-s-HXOiIdQiQoKlUCvQ,1533
|
14
|
+
fastlife/adapters/jinjax/widgets/text.py,sha256=KtUieF-q_BigG5AcL-4Sdr6LrIOQdWPwlaVW-2p-KPQ,3205
|
15
|
+
fastlife/adapters/jinjax/widgets/union.py,sha256=CO6Q4_U8DieVsS5NzMp6TAbVXrBljfcjSARycEKYPDY,2540
|
16
16
|
fastlife/components/A.jinja,sha256=rjnOFNpM2SUeJ0P8FDe3jzc_1WlsL65Kv-tb6KMCEpw,1389
|
17
17
|
fastlife/components/Button.jinja,sha256=COtCjDpzGLNqtBUYsHw7gdUay4kff3KdLJFAzrEnMmo,2310
|
18
18
|
fastlife/components/Checkbox.jinja,sha256=47_E9uPdr3QKUvRVhNQA7VE0uh5FVslQM26cdF0WCtY,753
|
@@ -1666,48 +1666,48 @@ fastlife/components/pydantic_form/Textarea.jinja,sha256=NzfCi5agRUSVcb5RXw0QamM8
|
|
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
1668
|
fastlife/config/__init__.py,sha256=ThosRIPZ_fpD0exZu-kUC_f8ZNa5KyDlleWMmEHkjEo,448
|
1669
|
-
fastlife/config/configurator.py,sha256
|
1670
|
-
fastlife/config/exceptions.py,sha256=
|
1671
|
-
fastlife/config/openapiextra.py,sha256=
|
1669
|
+
fastlife/config/configurator.py,sha256=keVPDTiCVko8Ncn1yYAnhG0x9Zp5J9yxMKEeyXZYP1E,22351
|
1670
|
+
fastlife/config/exceptions.py,sha256=M45w7ZNAj4KPPHNYiCtRHulRRb08rkOGtJ2I8WoXNHI,1207
|
1671
|
+
fastlife/config/openapiextra.py,sha256=rYoerrn9sni2XwnO3gIWqaz7M0aDZPhVLjzqhDxue0o,514
|
1672
1672
|
fastlife/config/registry.py,sha256=dGcNm7E6WY0x5HZNzo1gBFvGFCWeJj6JFXsJtLax5NU,1347
|
1673
|
-
fastlife/config/resources.py,sha256=
|
1673
|
+
fastlife/config/resources.py,sha256=XJIJxNtB5DAxXvDOU3xbJFa7_n-rAy9MXXjwekvj6p8,8583
|
1674
1674
|
fastlife/config/settings.py,sha256=7oggPOucyJwQYI97q8vs3kPXjFIVpQu1q6BK25h-uFs,3789
|
1675
|
-
fastlife/config/views.py,sha256=
|
1675
|
+
fastlife/config/views.py,sha256=V-P53GSnvqEPzkvEWNuI4ofcdbFur2Dl-s6BeKXObwI,2086
|
1676
1676
|
fastlife/middlewares/__init__.py,sha256=C3DUOzR5EhlAv5Zq7h-Abyvkd7bUsJohTRSB2wpRYQE,220
|
1677
1677
|
fastlife/middlewares/base.py,sha256=9OYqByRuVoIrLt353NOedPQTLdr7LSmxhb2BZcp20qk,638
|
1678
1678
|
fastlife/middlewares/reverse_proxy/__init__.py,sha256=g1SoVDmenKzpAAPYHTEsWgdBByOxtLg9fGx6RV3i0ok,846
|
1679
|
-
fastlife/middlewares/reverse_proxy/x_forwarded.py,sha256=
|
1679
|
+
fastlife/middlewares/reverse_proxy/x_forwarded.py,sha256=sGX7b4hOAgsG2KmtL3xlrZt61_IpF1exf6x_33F_QXE,1733
|
1680
1680
|
fastlife/middlewares/session/__init__.py,sha256=3XgXcIO6yQls5G7x8K2T8b7a_enA_7rQptWZcp3j2Ak,1400
|
1681
|
-
fastlife/middlewares/session/middleware.py,sha256=
|
1682
|
-
fastlife/middlewares/session/serializer.py,sha256=
|
1681
|
+
fastlife/middlewares/session/middleware.py,sha256=R48x3MJ-tu8siy8G12hDHa83sMcZz6E1eEb0xwk77E4,3166
|
1682
|
+
fastlife/middlewares/session/serializer.py,sha256=wpaktDP5v1spmbD-D3Q68EK9A0KInE4DT8mkogBJ3Fc,2157
|
1683
1683
|
fastlife/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1684
1684
|
fastlife/request/__init__.py,sha256=-wrh12uWM7ysmIUE6FszBit2H6iI5LWVEnHxQJ_23ZE,157
|
1685
|
-
fastlife/request/form.py,sha256=
|
1686
|
-
fastlife/request/form_data.py,sha256=
|
1685
|
+
fastlife/request/form.py,sha256=BiuvbV85NkvnJECSxqabfq3PhMfdKMPVobS35PhxSFA,3595
|
1686
|
+
fastlife/request/form_data.py,sha256=JZmKbKZz8nnspvCHYHQrz-xsFVJFaWHkTilUWk7Fx-M,4448
|
1687
1687
|
fastlife/request/localizer.py,sha256=9MXAcsod-Po5qeg4lttD3dyumiI0y5vGHCwSSmt9or8,349
|
1688
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=
|
1691
|
-
fastlife/routing/router.py,sha256=
|
1690
|
+
fastlife/routing/route.py,sha256=vqjfMsHAVO0l2B8fuB8t19CKMtE7WoBkG4kvi4lUonM,1441
|
1691
|
+
fastlife/routing/router.py,sha256=ho9TvTkX2iUW6GEh99FgclZVFKkCCCxYG4pPHeUtGn8,482
|
1692
1692
|
fastlife/security/__init__.py,sha256=QYDcJ3oXQzqXQxoDD_6biGAtercFrtePttoifiL1j34,25
|
1693
|
-
fastlife/security/csrf.py,sha256=
|
1694
|
-
fastlife/security/policy.py,sha256=
|
1693
|
+
fastlife/security/csrf.py,sha256=PIKG83LPqKz4kDALnZxIyPdYVwbNqsIryi7JPqRPQag,2168
|
1694
|
+
fastlife/security/policy.py,sha256=ECNEyZXjizK2kz61v5eU7xFNd_M6tIlr9JEwcdyjuj8,5142
|
1695
1695
|
fastlife/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1696
|
-
fastlife/services/locale_negociator.py,sha256=
|
1697
|
-
fastlife/services/policy.py,sha256=
|
1698
|
-
fastlife/services/templates.py,sha256
|
1699
|
-
fastlife/services/translations.py,sha256=
|
1696
|
+
fastlife/services/locale_negociator.py,sha256=Np2O8s7xnYTpf5eCG7LvcfFJ2LV7p_k86NNrU9Lju88,846
|
1697
|
+
fastlife/services/policy.py,sha256=bHe49EiD2ExQpFJxOsno6WyjxNrn8pf0wWDixkToHn0,1680
|
1698
|
+
fastlife/services/templates.py,sha256=-dIt8zrgiRsjMblS174Rx_2xRZkQQRIATYhaA2vbIAk,3867
|
1699
|
+
fastlife/services/translations.py,sha256=0MD6R4xCJM40JxvLyCg5laXEPJlyKvzjhVRkjE5l010,4383
|
1700
1700
|
fastlife/shared_utils/__init__.py,sha256=i66ytuf-Ezo7jSiNQHIsBMVIcB-tDX0tg28-pUOlhzE,26
|
1701
|
-
fastlife/shared_utils/infer.py,sha256=
|
1702
|
-
fastlife/shared_utils/resolver.py,sha256=
|
1701
|
+
fastlife/shared_utils/infer.py,sha256=3G_u6q2aWzeiVlAyGaWIlnAcz90m4bFNwpPYd5JIqfE,723
|
1702
|
+
fastlife/shared_utils/resolver.py,sha256=Nnva8D_BM_REFxH1sXZYKUZ5Ryx6o6vjqBSgvA7qWLY,1778
|
1703
1703
|
fastlife/templates/__init__.py,sha256=QrP_5UAOgxqC-jOu5tcjd-l6GOYrS4dka6vmWMxWqfo,184
|
1704
|
-
fastlife/templates/binding.py,sha256=
|
1704
|
+
fastlife/templates/binding.py,sha256=0pE2btOwLf4xOEgBXVOyz_dIX9tBCYCaJ7RhZI3knbs,1464
|
1705
1705
|
fastlife/templates/constants.py,sha256=MGdUjkF9hsPMN8rOS49eWbAApcb8FL-FAeFvJU8k90M,8387
|
1706
|
-
fastlife/testing/__init__.py,sha256=
|
1707
|
-
fastlife/testing/testclient.py,sha256=
|
1706
|
+
fastlife/testing/__init__.py,sha256=VpxkS3Zp3t_hH8dBiLaGFGhsvt511dhBS_8fMoFXdmU,99
|
1707
|
+
fastlife/testing/testclient.py,sha256=3s0CguxV3AePBRQ5XccutS0sMZtUkxvkt3C7z6IJbz0,20600
|
1708
1708
|
fastlife/views/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1709
|
-
fastlife/views/pydantic_form.py,sha256=
|
1710
|
-
fastlifeweb-0.16.
|
1711
|
-
fastlifeweb-0.16.
|
1712
|
-
fastlifeweb-0.16.
|
1713
|
-
fastlifeweb-0.16.
|
1709
|
+
fastlife/views/pydantic_form.py,sha256=4dv37JORLpvkgCgMGZfUN_qy7wme040GLZAzOTFqdnU,1367
|
1710
|
+
fastlifeweb-0.16.4.dist-info/LICENSE,sha256=F75xSseSKMwqzFj8rswYU6NWS3VoWOc_gY3fJYf9_LI,1504
|
1711
|
+
fastlifeweb-0.16.4.dist-info/METADATA,sha256=pFRnHJnvWXf7-ZucfCFAqkdPQ_VPE9u3MdjeH5RQSJo,3345
|
1712
|
+
fastlifeweb-0.16.4.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
1713
|
+
fastlifeweb-0.16.4.dist-info/RECORD,,
|
File without changes
|
File without changes
|