starmallow 0.8.0__py3-none-any.whl → 0.9.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.
- starmallow/__init__.py +1 -1
- starmallow/applications.py +196 -232
- starmallow/background.py +1 -1
- starmallow/concurrency.py +8 -7
- starmallow/dataclasses.py +11 -10
- starmallow/datastructures.py +1 -1
- starmallow/decorators.py +31 -30
- starmallow/delimited_field.py +37 -15
- starmallow/docs.py +5 -5
- starmallow/endpoint.py +103 -81
- starmallow/endpoints.py +3 -2
- starmallow/exceptions.py +3 -3
- starmallow/ext/marshmallow/openapi.py +11 -14
- starmallow/fields.py +3 -3
- starmallow/generics.py +34 -0
- starmallow/middleware/asyncexitstack.py +1 -2
- starmallow/params.py +20 -21
- starmallow/py.typed +0 -0
- starmallow/request_resolver.py +62 -58
- starmallow/responses.py +5 -4
- starmallow/routing.py +231 -239
- starmallow/schema_generator.py +98 -52
- starmallow/security/api_key.py +10 -10
- starmallow/security/base.py +11 -3
- starmallow/security/http.py +30 -25
- starmallow/security/oauth2.py +47 -47
- starmallow/security/open_id_connect_url.py +6 -6
- starmallow/security/utils.py +2 -5
- starmallow/serializers.py +59 -63
- starmallow/types.py +12 -8
- starmallow/utils.py +108 -68
- starmallow/websockets.py +3 -6
- {starmallow-0.8.0.dist-info → starmallow-0.9.0.dist-info}/METADATA +14 -13
- starmallow-0.9.0.dist-info/RECORD +43 -0
- {starmallow-0.8.0.dist-info → starmallow-0.9.0.dist-info}/WHEEL +1 -1
- starmallow-0.8.0.dist-info/RECORD +0 -41
- {starmallow-0.8.0.dist-info → starmallow-0.9.0.dist-info}/licenses/LICENSE.md +0 -0
starmallow/utils.py
CHANGED
@@ -3,8 +3,10 @@ import datetime as dt
|
|
3
3
|
import inspect
|
4
4
|
import logging
|
5
5
|
import re
|
6
|
+
import sys
|
6
7
|
import uuid
|
7
8
|
import warnings
|
9
|
+
from collections.abc import Callable, Mapping, Sequence
|
8
10
|
from contextlib import AsyncExitStack, asynccontextmanager, contextmanager
|
9
11
|
from dataclasses import is_dataclass
|
10
12
|
from decimal import Decimal
|
@@ -13,24 +15,17 @@ from types import NoneType, UnionType
|
|
13
15
|
from typing import (
|
14
16
|
TYPE_CHECKING,
|
15
17
|
Any,
|
16
|
-
Callable,
|
17
|
-
Dict,
|
18
18
|
ForwardRef,
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
Sequence,
|
23
|
-
Set,
|
24
|
-
Tuple,
|
25
|
-
Type,
|
19
|
+
Protocol,
|
20
|
+
TypeGuard,
|
21
|
+
TypeVar,
|
26
22
|
Union,
|
27
|
-
_eval_type,
|
28
|
-
_GenericAlias,
|
23
|
+
_eval_type, # type: ignore
|
29
24
|
get_args,
|
30
25
|
get_origin,
|
31
26
|
)
|
32
27
|
|
33
|
-
import dpath
|
28
|
+
import dpath
|
34
29
|
import marshmallow as ma
|
35
30
|
import marshmallow.fields as mf
|
36
31
|
import marshmallow_dataclass2.collection_field as collection_field
|
@@ -44,12 +39,18 @@ from typing_inspect import is_final_type, is_generic_type, is_literal_type
|
|
44
39
|
from starmallow.concurrency import contextmanager_in_threadpool
|
45
40
|
from starmallow.datastructures import DefaultPlaceholder, DefaultType
|
46
41
|
|
42
|
+
if sys.version_info >= (3, 11):
|
43
|
+
from typing import NotRequired
|
44
|
+
else:
|
45
|
+
# Python 3.10 and below
|
46
|
+
from typing_extensions import NotRequired
|
47
|
+
|
47
48
|
if TYPE_CHECKING: # pragma: nocover
|
48
49
|
from starmallow.routing import APIRoute
|
49
50
|
|
50
51
|
logger = logging.getLogger(__name__)
|
51
52
|
|
52
|
-
status_code_ranges:
|
53
|
+
status_code_ranges: dict[str, str] = {
|
53
54
|
"1XX": "Information",
|
54
55
|
"2XX": "Success",
|
55
56
|
"3XX": "Redirection",
|
@@ -58,7 +59,7 @@ status_code_ranges: Dict[str, str] = {
|
|
58
59
|
"DEFAULT": "Default Response",
|
59
60
|
}
|
60
61
|
|
61
|
-
MARSHMALLOW_ITERABLES:
|
62
|
+
MARSHMALLOW_ITERABLES: tuple[type[mf.Field], ...] = (
|
62
63
|
mf.Dict,
|
63
64
|
mf.List,
|
64
65
|
mf.Mapping,
|
@@ -83,23 +84,25 @@ PY_TO_MF_MAPPING = {
|
|
83
84
|
|
84
85
|
PY_ITERABLES = [
|
85
86
|
list,
|
86
|
-
|
87
|
+
list,
|
87
88
|
collections.abc.Sequence,
|
88
89
|
Sequence,
|
89
90
|
tuple,
|
90
|
-
|
91
|
+
tuple,
|
92
|
+
set,
|
91
93
|
set,
|
92
|
-
Set,
|
93
94
|
frozenset,
|
94
|
-
|
95
|
+
frozenset,
|
96
|
+
dict,
|
95
97
|
dict,
|
96
|
-
Dict,
|
97
98
|
collections.abc.Mapping,
|
98
99
|
Mapping,
|
99
100
|
]
|
100
101
|
|
102
|
+
T = TypeVar("T")
|
103
|
+
|
101
104
|
|
102
|
-
def get_model_field(model: Any, **kwargs) -> mf.Field:
|
105
|
+
def get_model_field(model: Any, **kwargs) -> mf.Field | None:
|
103
106
|
if model == inspect._empty:
|
104
107
|
return None
|
105
108
|
|
@@ -112,7 +115,7 @@ def get_model_field(model: Any, **kwargs) -> mf.Field:
|
|
112
115
|
if is_marshmallow_schema(model):
|
113
116
|
return mf.Nested(model if isinstance(model, ma.Schema) else model())
|
114
117
|
|
115
|
-
if
|
118
|
+
if is_marshmallow_field_or_generic(model):
|
116
119
|
return model if isinstance(model, mf.Field) else model()
|
117
120
|
|
118
121
|
# Native Python handling
|
@@ -132,10 +135,7 @@ def get_model_field(model: Any, **kwargs) -> mf.Field:
|
|
132
135
|
|
133
136
|
if is_final_type(model):
|
134
137
|
arguments = get_args(model)
|
135
|
-
if arguments
|
136
|
-
subtyp = arguments[0]
|
137
|
-
else:
|
138
|
-
subtyp = Any
|
138
|
+
subtyp = arguments[0] if arguments else Any
|
139
139
|
return get_model_field(subtyp, **kwargs)
|
140
140
|
|
141
141
|
# enumerations
|
@@ -146,9 +146,9 @@ def get_model_field(model: Any, **kwargs) -> mf.Field:
|
|
146
146
|
if typing_inspect.is_union_type(model):
|
147
147
|
if typing_inspect.is_optional_type(model):
|
148
148
|
kwargs["allow_none"] = kwargs.get("allow_none", True)
|
149
|
-
kwargs["dump_default"] = kwargs.get("dump_default"
|
149
|
+
kwargs["dump_default"] = kwargs.get("dump_default")
|
150
150
|
if not kwargs.get("required"):
|
151
|
-
kwargs["load_default"] = kwargs.get("load_default"
|
151
|
+
kwargs["load_default"] = kwargs.get("load_default")
|
152
152
|
kwargs.setdefault("required", False)
|
153
153
|
|
154
154
|
arguments = get_args(model)
|
@@ -156,44 +156,47 @@ def get_model_field(model: Any, **kwargs) -> mf.Field:
|
|
156
156
|
if len(subtypes) == 1:
|
157
157
|
return get_model_field(model, **kwargs)
|
158
158
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
159
|
+
union_types = []
|
160
|
+
for subtyp in subtypes:
|
161
|
+
field = get_model_field(subtyp, required=True)
|
162
|
+
if field is not None:
|
163
|
+
union_types.append((subtyp, field))
|
164
|
+
|
165
|
+
return UnionField(union_types, **kwargs)
|
163
166
|
|
164
167
|
origin = get_origin(model)
|
165
168
|
if origin not in PY_ITERABLES:
|
166
169
|
raise Exception(f'Unknown model type, model is {model}')
|
167
170
|
|
168
171
|
arguments = get_args(model)
|
169
|
-
if origin in (list,
|
172
|
+
if origin in (list, list):
|
170
173
|
child_type = get_model_field(arguments[0])
|
171
|
-
return mf.List(child_type, **kwargs)
|
174
|
+
return mf.List(child_type, **kwargs) # type: ignore
|
172
175
|
|
173
176
|
if origin in (collections.abc.Sequence, Sequence) or (
|
174
|
-
origin in (tuple,
|
177
|
+
origin in (tuple, tuple)
|
175
178
|
and len(arguments) == 2
|
176
179
|
and arguments[1] is Ellipsis
|
177
180
|
):
|
178
181
|
child_type = get_model_field(arguments[0])
|
179
|
-
return collection_field.Sequence(child_type, **kwargs)
|
182
|
+
return collection_field.Sequence(child_type, **kwargs) # type: ignore
|
180
183
|
|
181
|
-
if origin in (set,
|
184
|
+
if origin in (set, set):
|
182
185
|
child_type = get_model_field(arguments[0])
|
183
|
-
return collection_field.Set(child_type, frozen=False, **kwargs)
|
186
|
+
return collection_field.Set(child_type, frozen=False, **kwargs) # type: ignore
|
184
187
|
|
185
|
-
if origin in (frozenset,
|
188
|
+
if origin in (frozenset, frozenset):
|
186
189
|
child_type = get_model_field(arguments[0])
|
187
|
-
return collection_field.Set(child_type, frozen=True, **kwargs)
|
190
|
+
return collection_field.Set(child_type, frozen=True, **kwargs) # type: ignore
|
188
191
|
|
189
|
-
if origin in (tuple,
|
190
|
-
child_types = (
|
192
|
+
if origin in (tuple, tuple):
|
193
|
+
child_types = tuple(
|
191
194
|
get_model_field(arg)
|
192
195
|
for arg in arguments
|
193
196
|
)
|
194
|
-
return mf.Tuple(child_types, **kwargs)
|
197
|
+
return mf.Tuple(child_types, **kwargs) # type: ignore
|
195
198
|
|
196
|
-
if origin in (dict,
|
199
|
+
if origin in (dict, dict, collections.abc.Mapping, Mapping):
|
197
200
|
key_type = get_model_field(arguments[0])
|
198
201
|
value_type = get_model_field(arguments[1])
|
199
202
|
return mf.Dict(keys=key_type, values=value_type, **kwargs)
|
@@ -220,7 +223,7 @@ def is_optional(field):
|
|
220
223
|
return get_origin(field) in (Union, UnionType) and type(None) in get_args(field)
|
221
224
|
|
222
225
|
|
223
|
-
def get_path_param_names(path: str) ->
|
226
|
+
def get_path_param_names(path: str) -> set[str]:
|
224
227
|
return set(re.findall("{(.*?)}", path))
|
225
228
|
|
226
229
|
|
@@ -233,16 +236,47 @@ def generate_unique_id(route: "APIRoute") -> str:
|
|
233
236
|
return operation_id
|
234
237
|
|
235
238
|
|
236
|
-
|
237
|
-
|
239
|
+
class MaDataclassProtocol(Protocol):
|
240
|
+
Schema: NotRequired[type[ma.Schema]]
|
238
241
|
|
239
242
|
|
240
|
-
def
|
241
|
-
|
243
|
+
def is_marshmallow_schema(obj: Any) -> TypeGuard[ma.Schema | type[ma.Schema]]:
|
244
|
+
try:
|
245
|
+
return (inspect.isclass(obj) and issubclass(obj, ma.Schema)) or isinstance(obj, ma.Schema)
|
246
|
+
except TypeError:
|
247
|
+
# This is a workaround for the case where obj is a generic type
|
248
|
+
# and issubclass raises a TypeError.
|
249
|
+
return False
|
242
250
|
|
243
251
|
|
244
|
-
def
|
245
|
-
|
252
|
+
def is_marshmallow_field(obj: Any) -> TypeGuard[mf.Field | type[mf.Field]]:
|
253
|
+
try:
|
254
|
+
return (inspect.isclass(obj) and issubclass(obj, mf.Field)) or isinstance(obj, mf.Field)
|
255
|
+
except TypeError:
|
256
|
+
# This is a workaround for the case where obj is a generic type
|
257
|
+
# and issubclass raises a TypeError.
|
258
|
+
return False
|
259
|
+
|
260
|
+
|
261
|
+
def is_marshmallow_field_or_generic(obj: Any) -> TypeGuard[mf.Field | type[mf.Field]]:
|
262
|
+
try:
|
263
|
+
return (
|
264
|
+
(inspect.isclass(obj) and issubclass(obj, mf.Field))
|
265
|
+
or isinstance(obj, mf.Field)
|
266
|
+
or (
|
267
|
+
isinstance(obj, typing_inspect.typingGenericAlias)
|
268
|
+
and lenient_issubclass(get_origin(obj), mf.Field)
|
269
|
+
)
|
270
|
+
)
|
271
|
+
except TypeError:
|
272
|
+
# This is a workaround for the case where obj is a generic type
|
273
|
+
# and issubclass raises a TypeError.
|
274
|
+
return False
|
275
|
+
|
276
|
+
def is_marshmallow_dataclass(obj: MaDataclassProtocol | Any) -> TypeGuard[MaDataclassProtocol]:
|
277
|
+
schema = getattr(obj, 'Schema', None)
|
278
|
+
|
279
|
+
return is_dataclass(obj) and schema is not None and is_marshmallow_schema(schema)
|
246
280
|
|
247
281
|
|
248
282
|
def is_async_gen_callable(call: Callable[..., Any]) -> bool:
|
@@ -263,29 +297,32 @@ async def solve_generator(
|
|
263
297
|
*,
|
264
298
|
call: Callable[..., Any],
|
265
299
|
stack: AsyncExitStack,
|
266
|
-
gen_kwargs:
|
300
|
+
gen_kwargs: dict[str, Any],
|
267
301
|
) -> Any:
|
268
302
|
if is_gen_callable(call):
|
269
303
|
cm = contextmanager_in_threadpool(contextmanager(call)(**gen_kwargs))
|
270
304
|
elif is_async_gen_callable(call):
|
271
305
|
cm = asynccontextmanager(call)(**gen_kwargs)
|
306
|
+
else:
|
307
|
+
raise ValueError(f"Cannot solve generator for {call}")
|
272
308
|
return await stack.enter_async_context(cm)
|
273
309
|
|
274
310
|
|
275
|
-
def lenient_issubclass(cls: Any, class_or_tuple:
|
311
|
+
def lenient_issubclass(cls: Any, class_or_tuple: type[Any] | tuple[type[Any | UnionType], ...] | UnionType) -> bool:
|
276
312
|
try:
|
277
|
-
return isinstance(cls, type) and issubclass(cls, class_or_tuple)
|
313
|
+
return isinstance(cls, type) and issubclass(cls, class_or_tuple)
|
278
314
|
except TypeError:
|
279
|
-
|
280
|
-
return False
|
281
|
-
raise # pragma: no cover
|
315
|
+
return False
|
282
316
|
|
283
317
|
|
284
|
-
def eq_marshmallow_fields(left: mf.Field, right: mf.Field) -> bool:
|
318
|
+
def eq_marshmallow_fields(left: mf.Field | Any, right: mf.Field | Any) -> bool:
|
285
319
|
'''
|
286
320
|
Marshmallow Fields don't have an __eq__ functions.
|
287
321
|
This compares them instead.
|
288
322
|
'''
|
323
|
+
if not (isinstance(left, mf.Field) and isinstance(right, mf.Field)):
|
324
|
+
return False
|
325
|
+
|
289
326
|
left_dict = left.__dict__.copy()
|
290
327
|
left_dict.pop('_creation_index', None)
|
291
328
|
right_dict = right.__dict__.copy()
|
@@ -294,7 +331,7 @@ def eq_marshmallow_fields(left: mf.Field, right: mf.Field) -> bool:
|
|
294
331
|
return left_dict == right_dict
|
295
332
|
|
296
333
|
|
297
|
-
def
|
334
|
+
def _dict_creator(current, segments, i, hints: Sequence | None = None):
|
298
335
|
'''
|
299
336
|
Create missing path components. Always create a dictionary.
|
300
337
|
|
@@ -303,17 +340,17 @@ def __dict_creator__(current, segments, i, hints=()):
|
|
303
340
|
segment = segments[i]
|
304
341
|
|
305
342
|
# Infer the type from the hints provided.
|
306
|
-
if i < len(hints):
|
343
|
+
if hints and i < len(hints):
|
307
344
|
current[segment] = hints[i][1]()
|
308
345
|
else:
|
309
346
|
current[segment] = {}
|
310
347
|
|
311
348
|
|
312
|
-
def dict_safe_add(d:
|
313
|
-
dpath.new(d, path, value, separator='.', creator=
|
349
|
+
def dict_safe_add(d: dict, path: str, value: Any):
|
350
|
+
dpath.new(d, path, value, separator='.', creator=_dict_creator)
|
314
351
|
|
315
352
|
|
316
|
-
def deep_dict_update(main_dict:
|
353
|
+
def deep_dict_update(main_dict: dict[Any, Any], update_dict: dict[Any, Any]) -> None:
|
317
354
|
for key, value in update_dict.items():
|
318
355
|
if (
|
319
356
|
key in main_dict
|
@@ -331,7 +368,7 @@ def deep_dict_update(main_dict: Dict[Any, Any], update_dict: Dict[Any, Any]) ->
|
|
331
368
|
main_dict[key] = value
|
332
369
|
|
333
370
|
|
334
|
-
def create_response_model(type_:
|
371
|
+
def create_response_model(type_: type[Any] | Any | ma.Schema | mf.Field) -> mf.Field | None:
|
335
372
|
if type_ in [inspect._empty, None] or (inspect.isclass(type_) and issubclass(type_, Response)):
|
336
373
|
return None
|
337
374
|
|
@@ -347,7 +384,7 @@ def create_response_model(type_: Type[Any]) -> ma.Schema | mf.Field | None:
|
|
347
384
|
def get_value_or_default(
|
348
385
|
first_item: DefaultPlaceholder | DefaultType,
|
349
386
|
*extra_items: DefaultPlaceholder | DefaultType,
|
350
|
-
) ->
|
387
|
+
) -> Any:
|
351
388
|
"""
|
352
389
|
Pass items or `DefaultPlaceholder`s by descending priority.
|
353
390
|
|
@@ -355,12 +392,15 @@ def get_value_or_default(
|
|
355
392
|
|
356
393
|
Otherwise, the first item (a `DefaultPlaceholder`) will be returned.
|
357
394
|
"""
|
358
|
-
items = (first_item,
|
395
|
+
items = (first_item, *extra_items)
|
359
396
|
for item in items:
|
360
397
|
if not isinstance(item, DefaultPlaceholder):
|
361
398
|
return item
|
362
|
-
return first_item
|
363
399
|
|
400
|
+
if isinstance(first_item, DefaultPlaceholder):
|
401
|
+
return first_item.value
|
402
|
+
else:
|
403
|
+
return first_item
|
364
404
|
|
365
405
|
def get_name(endpoint: Callable) -> str:
|
366
406
|
if inspect.isroutine(endpoint) or inspect.isclass(endpoint):
|
@@ -387,14 +427,14 @@ def get_typed_signature(call: Callable[..., Any]) -> inspect.Signature:
|
|
387
427
|
return typed_signature
|
388
428
|
|
389
429
|
|
390
|
-
def get_typed_annotation(annotation: Any, globalns:
|
430
|
+
def get_typed_annotation(annotation: Any, globalns: dict[str, Any]) -> Any:
|
391
431
|
if isinstance(annotation, str):
|
392
432
|
annotation = ForwardRef(annotation)
|
393
433
|
annotation = evaluate_forwardref(annotation, globalns, globalns)
|
394
434
|
return annotation
|
395
435
|
|
396
436
|
|
397
|
-
def get_typed_return_annotation(call: Callable[...,
|
437
|
+
def get_typed_return_annotation(call: Callable[..., T]) -> T | None:
|
398
438
|
signature = inspect.signature(call)
|
399
439
|
annotation = signature.return_annotation
|
400
440
|
|
starmallow/websockets.py
CHANGED
@@ -13,7 +13,7 @@ class APIWebSocket(WebSocket):
|
|
13
13
|
async def receive_json(
|
14
14
|
self,
|
15
15
|
mode: str = "text",
|
16
|
-
model: ma.Schema = None,
|
16
|
+
model: ma.Schema | type[ma.Schema] | None = None,
|
17
17
|
) -> Any:
|
18
18
|
if mode not in {"text", "binary"}:
|
19
19
|
raise RuntimeError('The "mode" argument should be "text" or "binary".')
|
@@ -24,10 +24,7 @@ class APIWebSocket(WebSocket):
|
|
24
24
|
message = await self.receive()
|
25
25
|
self._raise_on_disconnect(message)
|
26
26
|
|
27
|
-
if mode == "text"
|
28
|
-
text = message["text"]
|
29
|
-
else:
|
30
|
-
text = message["bytes"].decode("utf-8")
|
27
|
+
text = message["text"] if mode == "text" else message["bytes"].decode("utf-8")
|
31
28
|
|
32
29
|
if model:
|
33
30
|
if isinstance(model, ma.Schema):
|
@@ -44,7 +41,7 @@ class APIWebSocket(WebSocket):
|
|
44
41
|
self,
|
45
42
|
data: Any,
|
46
43
|
mode: str = "text",
|
47
|
-
model: ma.Schema = None,
|
44
|
+
model: ma.Schema | type[ma.Schema] | None = None,
|
48
45
|
) -> None:
|
49
46
|
if mode not in {"text", "binary"}:
|
50
47
|
raise RuntimeError('The "mode" argument should be "text" or "binary".')
|
@@ -1,10 +1,11 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: starmallow
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.9.0
|
4
4
|
Summary: StarMallow framework
|
5
5
|
Project-URL: Homepage, https://github.com/mvanderlee/starmallow
|
6
6
|
Author-email: Michiel Vanderlee <jmt.vanderlee@gmail.com>
|
7
|
-
License: MIT
|
7
|
+
License-Expression: MIT
|
8
|
+
License-File: LICENSE.md
|
8
9
|
Classifier: Development Status :: 3 - Alpha
|
9
10
|
Classifier: Environment :: Web Environment
|
10
11
|
Classifier: Framework :: AsyncIO
|
@@ -17,6 +18,8 @@ Classifier: Programming Language :: Python
|
|
17
18
|
Classifier: Programming Language :: Python :: 3 :: Only
|
18
19
|
Classifier: Programming Language :: Python :: 3.10
|
19
20
|
Classifier: Programming Language :: Python :: 3.11
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
20
23
|
Classifier: Topic :: Internet
|
21
24
|
Classifier: Topic :: Internet :: WWW/HTTP
|
22
25
|
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
|
@@ -29,28 +32,26 @@ Requires-Python: >=3.10
|
|
29
32
|
Requires-Dist: apispec[marshmallow]<7,>=6
|
30
33
|
Requires-Dist: dpath<3,>=2.1.0
|
31
34
|
Requires-Dist: marshmallow-dataclass2<9,>=8.8.1
|
32
|
-
Requires-Dist: marshmallow
|
33
|
-
Requires-Dist: python-multipart
|
35
|
+
Requires-Dist: marshmallow>=3.18.0
|
36
|
+
Requires-Dist: python-multipart>=0.0.20
|
34
37
|
Requires-Dist: pyyaml>=5.4.1
|
35
|
-
Requires-Dist: starlette
|
38
|
+
Requires-Dist: starlette>=0.46
|
36
39
|
Provides-Extra: all
|
37
40
|
Requires-Dist: orjson; extra == 'all'
|
38
41
|
Requires-Dist: ujson>=3.2.1; extra == 'all'
|
39
42
|
Requires-Dist: uvicorn[standard]>=0.12.0; extra == 'all'
|
40
43
|
Provides-Extra: dev
|
41
|
-
Requires-Dist:
|
42
|
-
Requires-Dist:
|
43
|
-
Requires-Dist:
|
44
|
-
Requires-Dist: uvicorn[standard]<0.22.0,>=0.17.0; extra == 'dev'
|
44
|
+
Requires-Dist: pre-commit>=4; extra == 'dev'
|
45
|
+
Requires-Dist: ruff==0.11.6; extra == 'dev'
|
46
|
+
Requires-Dist: uvicorn[standard]>=0.34; extra == 'dev'
|
45
47
|
Provides-Extra: publish
|
46
48
|
Requires-Dist: hatch>=1.7.0; extra == 'publish'
|
47
49
|
Provides-Extra: test
|
48
50
|
Requires-Dist: coverage[toml]<8.0,>=6.5.0; extra == 'test'
|
49
51
|
Requires-Dist: httpx>=0.22.0; extra == 'test'
|
50
|
-
Requires-Dist: isort<6.0.0,>=5.0.6; extra == 'test'
|
51
52
|
Requires-Dist: mypy<2,>=1.1.1; extra == 'test'
|
52
|
-
Requires-Dist: pytest
|
53
|
-
Requires-Dist: ruff==0.
|
53
|
+
Requires-Dist: pytest>=8; extra == 'test'
|
54
|
+
Requires-Dist: ruff==0.11.6; extra == 'test'
|
54
55
|
Description-Content-Type: text/markdown
|
55
56
|
|
56
57
|
# StarMallow
|
@@ -0,0 +1,43 @@
|
|
1
|
+
starmallow/__init__.py,sha256=tGlfbHYbodKJlydvWAPia0GpXyB1nRcjV5Quz2iZeUw,322
|
2
|
+
starmallow/applications.py,sha256=wI3mViPAgMAGDUy0PzDLyd6GFQaFY_d1-85LBASATNY,30396
|
3
|
+
starmallow/background.py,sha256=asjTMgO25zqZiKsxcEVBGPKd_Nb7RVZDEmzR4PNy6-k,996
|
4
|
+
starmallow/concurrency.py,sha256=YNIFo8jmHZYXfFkqzL1xFiE5QFwWYnGUsYgAROv041Q,1404
|
5
|
+
starmallow/constants.py,sha256=u0h8cJKhJY0oIZqzr7wpEZG2bPLrw5FroMnn3d8KBNQ,129
|
6
|
+
starmallow/dataclasses.py,sha256=P8Eft25Q5UBhDp-3b0T-n2IOtjrQpxmRUxs3WAwlRFQ,2787
|
7
|
+
starmallow/datastructures.py,sha256=oq2Dz6zcoQx9ctMSSviZMAX_wvNTT9ytkSBtZjcg7bY,853
|
8
|
+
starmallow/decorators.py,sha256=VGzfFYualOcplRK6L3Tu2GrCl3a5yrOgADqWMokqzcQ,4036
|
9
|
+
starmallow/delimited_field.py,sha256=MKQnCp-B8q1R69G6aCgthtWVCISqkKBFpTSnwcfC_8A,4429
|
10
|
+
starmallow/docs.py,sha256=tc077aDFAzHTjpnEpqS8BVMhVolaYFmrqQ2obd1Jsbg,6229
|
11
|
+
starmallow/endpoint.py,sha256=JVJTglAkAydVKIsgKr4dR_X9gzso6OHr_d6xUhq1MNU,17794
|
12
|
+
starmallow/endpoints.py,sha256=2RuKhEX0EpEyWUdlKVfD0WXz_8zNQEduCoZ4UJkybZc,953
|
13
|
+
starmallow/exception_handlers.py,sha256=gr2qLYWEtsIEH28n7OreEiiLVz6Y7b6osRyS9esJbBk,891
|
14
|
+
starmallow/exceptions.py,sha256=arXkENa6dV626t_IDWZKqrh6laeV54PWbVIW0dafT2o,843
|
15
|
+
starmallow/fields.py,sha256=5zXP2JLyTpVnVhl23GYHY9W3Sc5Oc_kRvOWmI7WWNRM,1283
|
16
|
+
starmallow/generics.py,sha256=CE_Wf0vIqkup0mirGa-PL5511DT-avaCkC1Jx4sMe_U,1102
|
17
|
+
starmallow/params.py,sha256=EDnUNVNfRY7uv5D1rzfmIrWKJ85R2ku4l13w1QKG4E8,8720
|
18
|
+
starmallow/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
19
|
+
starmallow/request_resolver.py,sha256=o9OID0wOUCG1iUuvJVT6-ghzG61Pv08QiznFjzZZ8RE,11689
|
20
|
+
starmallow/requests.py,sha256=o_yNhH9WJ35uAGuoXa5_gihevHeaveOvkP525dbwQSU,843
|
21
|
+
starmallow/responses.py,sha256=H6Ze0R5JG9O8eaS4dffiAn3lI6Y9-hz3aDHdWKGk_nw,2023
|
22
|
+
starmallow/routing.py,sha256=dK6ayN_Ruqz3ZGNQ3pFwqnguF7Vl0oIfD7e8OnnED_Y,45364
|
23
|
+
starmallow/schema_generator.py,sha256=Y4o8v5OUgTZA2byTOcUKONimdF8JjiwD8FZLxCVOF0I,19210
|
24
|
+
starmallow/serializers.py,sha256=Z-42L6is9klknpJ3r1DcGjB7t_txPfRvp-Rvj87_n70,12622
|
25
|
+
starmallow/types.py,sha256=uPjoKwKF06n7b2yTtm0WAO1a_SOwRYJG1xzDy_GKAUg,879
|
26
|
+
starmallow/utils.py,sha256=CudZ2x7iWHr6xi7RT848aSIZuAfDUFzWVCxHuyKvk-E,14146
|
27
|
+
starmallow/websockets.py,sha256=54ctFGgA4A3VFwpUFmlu8aVmHOo4R6x3O_-z5r2BsdI,2232
|
28
|
+
starmallow/ext/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
29
|
+
starmallow/ext/marshmallow/__init__.py,sha256=33jENGdfPq4-CDG0LOmN3KOGW1pXTy7a2oMwy4hrYzM,208
|
30
|
+
starmallow/ext/marshmallow/openapi.py,sha256=SkaGp80qvQxDSatxygN3IIKXQ7GTa01rioY_uddTxEs,10164
|
31
|
+
starmallow/middleware/__init__.py,sha256=vtNm85Z9pUPjJd-9giJGg3YL1wO7Jm5ooXBm31pDOK8,53
|
32
|
+
starmallow/middleware/asyncexitstack.py,sha256=wxugZgPg5yxuXxZjPm-_PMG7hAfOeo2lRLR07eaSWS8,1160
|
33
|
+
starmallow/security/__init__.py,sha256=1rQFBIGnEbE51XDZSSi9NgPjXLScFq3RoLu4vk0KVYw,191
|
34
|
+
starmallow/security/api_key.py,sha256=8WH52R4OjLKYSkXj35AgayFsXM7JQVp1Pf0DzpMl4ms,3108
|
35
|
+
starmallow/security/base.py,sha256=d2bMKCbPB8wh4Ce0b5xSYS9ZHeeyVLnyjpwK_NE505M,1404
|
36
|
+
starmallow/security/http.py,sha256=oOG436aohU9uNM40B0LP0Vg8Pcroj5pjzE1NRGiqOOs,6683
|
37
|
+
starmallow/security/oauth2.py,sha256=G72-wJyvrGyHUbg9hbzf44RBN8zFalZYnHKpRC2I1po,10108
|
38
|
+
starmallow/security/open_id_connect_url.py,sha256=9E-Zwnt-IR3jimOMkvIwnGHTuJMlGmjs7LCf1SGtKT8,1415
|
39
|
+
starmallow/security/utils.py,sha256=7tziAa2Cwa7xhwM_NF4DSY3BHoqVaWgJ21VuV8LvhrY,253
|
40
|
+
starmallow-0.9.0.dist-info/METADATA,sha256=ZQ_7tnMWg4IhxxCo3FhmBwa8OGc42qBRdOwBnBeK9y8,5611
|
41
|
+
starmallow-0.9.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
42
|
+
starmallow-0.9.0.dist-info/licenses/LICENSE.md,sha256=QelyGgOzch8CXzy6HrYwHh7nmj0rlWkDA0YzmZ3CPaY,1084
|
43
|
+
starmallow-0.9.0.dist-info/RECORD,,
|
@@ -1,41 +0,0 @@
|
|
1
|
-
starmallow/__init__.py,sha256=_rVQsLfQ3QzRRXvJYKcuR9Ki79d7xvWU1Mhk7E4y2KY,322
|
2
|
-
starmallow/applications.py,sha256=mSL4YDozP8n6v22g4NX7EAMXmGhzzhtjtZd68YHcFvw,31720
|
3
|
-
starmallow/background.py,sha256=qxT6-9SfnkcGZzvecNOpIsCOMW0TPwDtpQ81GHI28P0,995
|
4
|
-
starmallow/concurrency.py,sha256=MVRjo4Vqss_yqhaoeVt3xb7rLaSuAq_q9uYgTwbsojE,1375
|
5
|
-
starmallow/constants.py,sha256=u0h8cJKhJY0oIZqzr7wpEZG2bPLrw5FroMnn3d8KBNQ,129
|
6
|
-
starmallow/dataclasses.py,sha256=ap9DInvQjH2AyI4MAAnbDEuNnbPb94PigaNmEb7AQU8,2658
|
7
|
-
starmallow/datastructures.py,sha256=iH_KJuJ6kBCWEsnHFLdA3iyb6ZxhfdMHYrJlhiEZtDU,839
|
8
|
-
starmallow/decorators.py,sha256=MYk3WEFRSfQTN0Y3JoL3Y_Cz47gatMrVEPtNDw42XwU,4105
|
9
|
-
starmallow/delimited_field.py,sha256=gonWgYg6G5xH2yXAyfDgkePmQ8dUaRSp2hdJ3mCfOBw,3466
|
10
|
-
starmallow/docs.py,sha256=eA39LunVMEoPU5ge4qxm2eiJbrFTUSUu5EhG1L_LKxk,6268
|
11
|
-
starmallow/endpoint.py,sha256=WChgjb47lYUrbyeaQiyUbuyHFCREYPiZJMNLqnz_iuA,16186
|
12
|
-
starmallow/endpoints.py,sha256=UrwVZCxbmWI20iNtJ0oXxo4d3-y12TjsOGs_jnStTiU,939
|
13
|
-
starmallow/exception_handlers.py,sha256=gr2qLYWEtsIEH28n7OreEiiLVz6Y7b6osRyS9esJbBk,891
|
14
|
-
starmallow/exceptions.py,sha256=vabtPJkTmtCdC8_2OPBE8Osz0v0KxaSOX6IWf1jgNkc,872
|
15
|
-
starmallow/fields.py,sha256=arrTabCYoJFZcoY69EZTBH3YUg7CUSr3-zYLiAjYLTM,1238
|
16
|
-
starmallow/params.py,sha256=MJzUzUs6GEyrbpDZ1r8To8vR-QwpopdxDStq802o5Ug,8662
|
17
|
-
starmallow/request_resolver.py,sha256=frOxhQPxhWKnStJDTVrs5wu6Icf3dTbbv9VblegxS3A,11135
|
18
|
-
starmallow/requests.py,sha256=o_yNhH9WJ35uAGuoXa5_gihevHeaveOvkP525dbwQSU,843
|
19
|
-
starmallow/responses.py,sha256=k2pf_m21ykf_FECdODUz400pMucMJJf_Zm8TXFujvaU,2012
|
20
|
-
starmallow/routing.py,sha256=VSotmrEerVzuUfn20mpmSbuRVS4XiHrPtNRvBP8KJ4M,45397
|
21
|
-
starmallow/schema_generator.py,sha256=yi368FwF9B50ZHSNOG0rvYVirVUeMFq2kXkUDeJUz4w,17961
|
22
|
-
starmallow/serializers.py,sha256=rBEKMNgONgz_bai12uDvAEMCI_aEFGsqMSeIoWtlrOI,12514
|
23
|
-
starmallow/types.py,sha256=xp4eitWenXRZCPlsopTfG4aMs86kOrvioDTCVLg-MXU,718
|
24
|
-
starmallow/utils.py,sha256=lI6qWalsBsEaJLSiGsCC_vBN6Sw-r5aDTl9hWuHCW-Q,12459
|
25
|
-
starmallow/websockets.py,sha256=yIz3LzTBMNclpEoG7oTMbQwxbcdKNU6M8XcqZMyBTuA,2223
|
26
|
-
starmallow/ext/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
27
|
-
starmallow/ext/marshmallow/__init__.py,sha256=33jENGdfPq4-CDG0LOmN3KOGW1pXTy7a2oMwy4hrYzM,208
|
28
|
-
starmallow/ext/marshmallow/openapi.py,sha256=LHFcdw8ISpPsS2drefL2h8AiKk_B_I7UffloEH3-xXI,10202
|
29
|
-
starmallow/middleware/__init__.py,sha256=vtNm85Z9pUPjJd-9giJGg3YL1wO7Jm5ooXBm31pDOK8,53
|
30
|
-
starmallow/middleware/asyncexitstack.py,sha256=0GPhQSxqSVmAiVIqBIN5slueWYZ8bwh9f2bBPy7AbP0,1191
|
31
|
-
starmallow/security/__init__.py,sha256=1rQFBIGnEbE51XDZSSi9NgPjXLScFq3RoLu4vk0KVYw,191
|
32
|
-
starmallow/security/api_key.py,sha256=OWogzuwqPC3H0xf4jzx_RQjC8UoM8WDVtOhjq1lQ5ik,3145
|
33
|
-
starmallow/security/base.py,sha256=PtTsBViTUEtNUT9q_zFFydnOqIvGLfKggtgyCYeYRZk,1145
|
34
|
-
starmallow/security/http.py,sha256=O4mUrBHp6JTJNewOvcG_dgsx0IwjMonL8usswOqGdOY,6608
|
35
|
-
starmallow/security/oauth2.py,sha256=wlc5K6rURqOrMLwSYeOcd_2ZtFcvMqG3OwbiAwpft3E,10006
|
36
|
-
starmallow/security/open_id_connect_url.py,sha256=NONotu-uAWJUps06wdyVCJSRrK71Bl23z8gWWi7ymmw,1400
|
37
|
-
starmallow/security/utils.py,sha256=bd8T0YM7UQD5ATKucr1bNtAvz_Y3__dVNAv5UebiPvc,293
|
38
|
-
starmallow-0.8.0.dist-info/METADATA,sha256=w3SFqGhVi71VdQQZBQyQsM0Kk7dPvrGRAte3GpVAH5M,5618
|
39
|
-
starmallow-0.8.0.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
|
40
|
-
starmallow-0.8.0.dist-info/licenses/LICENSE.md,sha256=QelyGgOzch8CXzy6HrYwHh7nmj0rlWkDA0YzmZ3CPaY,1084
|
41
|
-
starmallow-0.8.0.dist-info/RECORD,,
|
File without changes
|