starmallow 0.1.0__py3-none-any.whl → 0.2.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.
- starmallow/__init__.py +1 -1
- starmallow/applications.py +6 -3
- starmallow/endpoint.py +93 -43
- starmallow/exceptions.py +8 -1
- starmallow/ext/marshmallow/openapi.py +1 -1
- starmallow/routing.py +1 -1
- starmallow/schema_generator.py +11 -7
- starmallow/security/oauth2.py +2 -2
- starmallow/utils.py +4 -3
- {starmallow-0.1.0.dist-info → starmallow-0.2.1.dist-info}/METADATA +10 -2
- {starmallow-0.1.0.dist-info → starmallow-0.2.1.dist-info}/RECORD +13 -13
- {starmallow-0.1.0.dist-info → starmallow-0.2.1.dist-info}/WHEEL +0 -0
- {starmallow-0.1.0.dist-info → starmallow-0.2.1.dist-info}/licenses/LICENSE.md +0 -0
starmallow/__init__.py
CHANGED
starmallow/applications.py
CHANGED
@@ -35,7 +35,7 @@ from starmallow.exception_handlers import (
|
|
35
35
|
http_exception_handler,
|
36
36
|
request_validation_exception_handler,
|
37
37
|
)
|
38
|
-
from starmallow.exceptions import RequestValidationError
|
38
|
+
from starmallow.exceptions import RequestValidationError, SchemaGenerationError
|
39
39
|
from starmallow.middleware import AsyncExitStackMiddleware
|
40
40
|
from starmallow.responses import JSONResponse
|
41
41
|
from starmallow.routing import APIRoute, APIRouter
|
@@ -122,7 +122,7 @@ class StarMallow(Starlette):
|
|
122
122
|
)
|
123
123
|
|
124
124
|
self.user_middleware = [] if middleware is None else list(middleware)
|
125
|
-
self.middleware_stack =
|
125
|
+
self.middleware_stack: Union[ASGIApp, None] = None
|
126
126
|
self.init_openapi()
|
127
127
|
|
128
128
|
def build_middleware_stack(self) -> ASGIApp:
|
@@ -168,7 +168,10 @@ class StarMallow(Starlette):
|
|
168
168
|
def init_openapi(self):
|
169
169
|
if self.openapi_url:
|
170
170
|
async def openapi(req: Request) -> JSONResponse:
|
171
|
-
|
171
|
+
try:
|
172
|
+
return JSONResponse(self.openapi())
|
173
|
+
except Exception as e:
|
174
|
+
raise SchemaGenerationError() from e
|
172
175
|
|
173
176
|
self.add_route(self.openapi_url, openapi, include_in_schema=False)
|
174
177
|
|
starmallow/endpoint.py
CHANGED
@@ -13,6 +13,7 @@ from typing import (
|
|
13
13
|
Optional,
|
14
14
|
Type,
|
15
15
|
Union,
|
16
|
+
get_origin,
|
16
17
|
)
|
17
18
|
|
18
19
|
import marshmallow as ma
|
@@ -22,6 +23,7 @@ from starlette.background import BackgroundTasks
|
|
22
23
|
from starlette.requests import HTTPConnection, Request
|
23
24
|
from starlette.responses import Response
|
24
25
|
from starlette.websockets import WebSocket
|
26
|
+
from typing_extensions import Annotated
|
25
27
|
|
26
28
|
from starmallow.params import (
|
27
29
|
Body,
|
@@ -37,6 +39,7 @@ from starmallow.params import (
|
|
37
39
|
Security,
|
38
40
|
)
|
39
41
|
from starmallow.responses import JSONResponse
|
42
|
+
from starmallow.security.base import SecurityBaseResolver
|
40
43
|
from starmallow.utils import (
|
41
44
|
create_response_model,
|
42
45
|
get_args,
|
@@ -54,6 +57,13 @@ if TYPE_CHECKING:
|
|
54
57
|
|
55
58
|
logger = logging.getLogger(__name__)
|
56
59
|
|
60
|
+
STARMALLOW_PARAM_TYPES = (
|
61
|
+
Param,
|
62
|
+
NoParam,
|
63
|
+
ResolvedParam,
|
64
|
+
mf.Field,
|
65
|
+
)
|
66
|
+
|
57
67
|
|
58
68
|
@dataclass
|
59
69
|
class EndpointModel:
|
@@ -164,25 +174,31 @@ class SchemaModel(ma.Schema):
|
|
164
174
|
|
165
175
|
class EndpointMixin:
|
166
176
|
|
167
|
-
def _get_param_model(
|
168
|
-
|
177
|
+
def _get_param_model(
|
178
|
+
self,
|
179
|
+
type_annotation: Any,
|
180
|
+
parameter: Param,
|
181
|
+
parameter_name: str,
|
182
|
+
default_value: Any,
|
183
|
+
) -> Union[ma.Schema, mf.Field]:
|
184
|
+
model = type_annotation
|
169
185
|
|
170
186
|
kwargs = {
|
171
187
|
'required': True,
|
172
188
|
'metadata': {
|
173
189
|
'title': (
|
174
|
-
parameter.
|
175
|
-
if (isinstance(parameter
|
176
|
-
else
|
190
|
+
parameter.title
|
191
|
+
if (isinstance(parameter, Param) and parameter.title)
|
192
|
+
else parameter_name.title().replace('_', ' ')
|
177
193
|
),
|
178
194
|
},
|
179
195
|
}
|
180
196
|
# Ensure we pass parameter fields into the marshmallow field
|
181
|
-
if isinstance(parameter
|
182
|
-
if parameter.
|
183
|
-
kwargs['validate'] = parameter.
|
184
|
-
if parameter.
|
185
|
-
kwargs['metadata']['deprecated'] = parameter.
|
197
|
+
if isinstance(parameter, Param):
|
198
|
+
if parameter.validators:
|
199
|
+
kwargs['validate'] = parameter.validators
|
200
|
+
if parameter.deprecated:
|
201
|
+
kwargs['metadata']['deprecated'] = parameter.deprecated
|
186
202
|
|
187
203
|
if is_optional(model):
|
188
204
|
kwargs.update({
|
@@ -190,25 +206,25 @@ class EndpointMixin:
|
|
190
206
|
'required': False,
|
191
207
|
})
|
192
208
|
# This does not support Union[A,B,C,None]. Only Union[A,None] and Optional[A]
|
193
|
-
model = next((a for a in get_args(
|
209
|
+
model = next((a for a in get_args(type_annotation) if a is not None), None)
|
194
210
|
|
195
|
-
if isinstance(parameter
|
211
|
+
if isinstance(parameter, Param):
|
196
212
|
# If default is not Ellipsis, then it's optional regardless of the typehint.
|
197
213
|
# Although it's best practice to also mark the typehint as Optional
|
198
|
-
if
|
214
|
+
if default_value != Ellipsis:
|
199
215
|
kwargs.update({
|
200
|
-
'load_default':
|
216
|
+
'load_default': default_value,
|
201
217
|
'required': False,
|
202
218
|
})
|
203
219
|
|
204
220
|
# Ignore type hint. Use provided model instead.
|
205
|
-
if parameter.
|
206
|
-
model = parameter.
|
207
|
-
elif
|
221
|
+
if parameter.model is not None:
|
222
|
+
model = parameter.model
|
223
|
+
elif default_value != inspect._empty:
|
208
224
|
# If default is not a Param but is defined, then it's optional regardless of the typehint.
|
209
225
|
# Although it's best practice to also mark the typehint as Optional
|
210
226
|
kwargs.update({
|
211
|
-
'load_default':
|
227
|
+
'load_default': default_value,
|
212
228
|
'required': False,
|
213
229
|
})
|
214
230
|
|
@@ -226,7 +242,7 @@ class EndpointMixin:
|
|
226
242
|
elif is_marshmallow_field(model):
|
227
243
|
if model.load_default is not None and model.load_default != kwargs.get('load_default', ma.missing):
|
228
244
|
logger.warning(
|
229
|
-
f"'{
|
245
|
+
f"'{parameter_name}' model and annotation have different 'load_default' values."
|
230
246
|
+ f" {model.load_default} <> {kwargs.get('load_default', ma.missing)}",
|
231
247
|
)
|
232
248
|
|
@@ -239,15 +255,13 @@ class EndpointMixin:
|
|
239
255
|
try:
|
240
256
|
return get_model_field(model, **kwargs)
|
241
257
|
except Exception as e:
|
242
|
-
raise Exception(f'Unknown model type for parameter {
|
243
|
-
|
244
|
-
def get_resolved_param(self, parameter: inspect.Parameter, path: str) -> ResolvedParam:
|
245
|
-
resolved_param: ResolvedParam = parameter.default
|
258
|
+
raise Exception(f'Unknown model type for parameter {parameter_name}, model is {model}') from e
|
246
259
|
|
260
|
+
def get_resolved_param(self, resolved_param: ResolvedParam, annotation: Any, path: str) -> ResolvedParam:
|
247
261
|
# Supports `field = ResolvedParam(resolver_callable)
|
248
262
|
# and field: resolver_callable = ResolvedParam()
|
249
263
|
if resolved_param.resolver is None:
|
250
|
-
resolved_param.resolver =
|
264
|
+
resolved_param.resolver = annotation
|
251
265
|
|
252
266
|
resolved_param.resolver_params = self._get_params(resolved_param.resolver, path=path)
|
253
267
|
|
@@ -261,24 +275,60 @@ class EndpointMixin:
|
|
261
275
|
path_param_names = get_path_param_names(path)
|
262
276
|
params = {param_type: {} for param_type in ParamType}
|
263
277
|
for name, parameter in inspect.signature(func).parameters.items():
|
278
|
+
default_value = parameter.default
|
279
|
+
|
280
|
+
# The type annotation. i.e.: 'str' in these `value: str`. Or `value: [str, Query(gt=3)]`
|
281
|
+
type_annotation: Any = inspect._empty
|
282
|
+
# The param to use when looking for Param details.
|
283
|
+
# i.e.: 'Query(gt=3)' in these `value: Query(gt=3)`. Or `value: [str, Query(gt=3)]`
|
284
|
+
starmallow_param: Any = inspect._empty
|
285
|
+
if parameter.annotation is not inspect.Signature.empty:
|
286
|
+
type_annotation = parameter.annotation
|
287
|
+
if isinstance(parameter.default, STARMALLOW_PARAM_TYPES):
|
288
|
+
starmallow_param = parameter.default
|
289
|
+
default_value = getattr(starmallow_param, 'default', None)
|
290
|
+
|
291
|
+
if get_origin(parameter.annotation) is Annotated:
|
292
|
+
annotated_args = get_args(parameter.annotation)
|
293
|
+
type_annotation = annotated_args[0]
|
294
|
+
starmallow_annotations = [
|
295
|
+
arg
|
296
|
+
for arg in annotated_args[1:]
|
297
|
+
if isinstance(arg, STARMALLOW_PARAM_TYPES)
|
298
|
+
]
|
299
|
+
if starmallow_annotations:
|
300
|
+
assert starmallow_param is inspect._empty, (
|
301
|
+
"Cannot specify `Param` in `Annotated` and default value"
|
302
|
+
f" together for {name!r}"
|
303
|
+
)
|
304
|
+
|
305
|
+
starmallow_param = starmallow_annotations[-1]
|
306
|
+
if (
|
307
|
+
isinstance(starmallow_param, Param)
|
308
|
+
and starmallow_param.default is not inspect.Signature.empty
|
309
|
+
and default_value is inspect.Signature.empty
|
310
|
+
):
|
311
|
+
default_value = starmallow_param.default
|
312
|
+
|
264
313
|
if (
|
265
314
|
# Skip 'self' in APIHTTPEndpoint functions
|
266
315
|
(name == 'self' and '.' in func.__qualname__)
|
267
|
-
or isinstance(
|
316
|
+
or isinstance(starmallow_param, NoParam)
|
268
317
|
):
|
269
318
|
continue
|
270
|
-
elif isinstance(
|
271
|
-
|
272
|
-
params[ParamType.security][name] = security_param
|
273
|
-
# add to resolved so we can properly order them based which to execute first
|
274
|
-
params[ParamType.resolved][name] = security_param
|
275
|
-
continue
|
276
|
-
elif isinstance(parameter.default, ResolvedParam):
|
277
|
-
resolved_param: ResolvedParam = self.get_resolved_param(parameter, path=path)
|
319
|
+
elif isinstance(starmallow_param, ResolvedParam):
|
320
|
+
resolved_param: ResolvedParam = self.get_resolved_param(starmallow_param, type_annotation, path=path)
|
278
321
|
params[ParamType.resolved][name] = resolved_param
|
322
|
+
|
323
|
+
if isinstance(starmallow_param, Security):
|
324
|
+
params[ParamType.security][name] = resolved_param
|
325
|
+
# Allow `ResolvedParam(HTTPBearer())`
|
326
|
+
elif isinstance(resolved_param.resolver, SecurityBaseResolver):
|
327
|
+
params[ParamType.security][name] = resolved_param
|
328
|
+
|
279
329
|
continue
|
280
330
|
elif lenient_issubclass(
|
281
|
-
|
331
|
+
type_annotation,
|
282
332
|
(
|
283
333
|
Request,
|
284
334
|
WebSocket,
|
@@ -287,18 +337,18 @@ class EndpointMixin:
|
|
287
337
|
BackgroundTasks,
|
288
338
|
),
|
289
339
|
):
|
290
|
-
params[ParamType.noparam][name] =
|
340
|
+
params[ParamType.noparam][name] = type_annotation
|
291
341
|
continue
|
292
342
|
|
293
|
-
model = self._get_param_model(
|
343
|
+
model = self._get_param_model(type_annotation, starmallow_param, name, default_value)
|
294
344
|
model.name = name
|
295
345
|
|
296
|
-
if isinstance(
|
346
|
+
if isinstance(starmallow_param, Param):
|
297
347
|
# Create new field_info with processed model
|
298
|
-
field_info =
|
299
|
-
|
300
|
-
deprecated=
|
301
|
-
include_in_schema=
|
348
|
+
field_info = starmallow_param.__class__(
|
349
|
+
starmallow_param.default,
|
350
|
+
deprecated=starmallow_param.deprecated,
|
351
|
+
include_in_schema=starmallow_param.include_in_schema,
|
302
352
|
model=model,
|
303
353
|
)
|
304
354
|
elif isinstance(model, mf.Field):
|
@@ -308,7 +358,7 @@ class EndpointMixin:
|
|
308
358
|
if name in path_param_names:
|
309
359
|
field_info = Path(
|
310
360
|
# If a default was provided, honor it.
|
311
|
-
... if
|
361
|
+
... if default_value == inspect._empty else default_value,
|
312
362
|
deprecated=False,
|
313
363
|
include_in_schema=True,
|
314
364
|
model=model,
|
@@ -317,7 +367,7 @@ class EndpointMixin:
|
|
317
367
|
# Default it to QueryParameter
|
318
368
|
field_info = Query(
|
319
369
|
# If a default was provided, honor it.
|
320
|
-
... if
|
370
|
+
... if default_value == inspect._empty else default_value,
|
321
371
|
deprecated=False,
|
322
372
|
include_in_schema=True,
|
323
373
|
model=model,
|
starmallow/exceptions.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
from typing import Any, Dict, List, Union
|
2
2
|
|
3
3
|
from starlette.exceptions import HTTPException
|
4
|
-
from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY
|
4
|
+
from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY, HTTP_500_INTERNAL_SERVER_ERROR
|
5
5
|
|
6
6
|
|
7
7
|
class RequestValidationError(HTTPException):
|
@@ -20,3 +20,10 @@ class WebSocketRequestValidationError(HTTPException):
|
|
20
20
|
) -> None:
|
21
21
|
super().__init__(status_code=HTTP_422_UNPROCESSABLE_ENTITY)
|
22
22
|
self.errors = errors
|
23
|
+
|
24
|
+
|
25
|
+
class SchemaGenerationError(HTTPException):
|
26
|
+
def __init__(
|
27
|
+
self,
|
28
|
+
) -> None:
|
29
|
+
super().__init__(status_code=HTTP_500_INTERNAL_SERVER_ERROR, detail="Failed to generate schema")
|
@@ -240,7 +240,7 @@ class OpenAPIConverter(ApiSpecOpenAPIConverter):
|
|
240
240
|
ret["explode"] = True
|
241
241
|
ret["style"] = "form"
|
242
242
|
if prop.get("description", None):
|
243
|
-
ret["description"] = prop.pop("description")
|
243
|
+
ret["description"] = prop.pop("description", None)
|
244
244
|
ret["schema"] = prop
|
245
245
|
|
246
246
|
if 'deprecated' in field.metadata:
|
starmallow/routing.py
CHANGED
starmallow/schema_generator.py
CHANGED
@@ -4,6 +4,7 @@ import itertools
|
|
4
4
|
import re
|
5
5
|
import warnings
|
6
6
|
from collections import defaultdict
|
7
|
+
from logging import getLogger
|
7
8
|
from typing import Any, Dict, List, Optional, Sequence, Set, Tuple, Type
|
8
9
|
|
9
10
|
import marshmallow as ma
|
@@ -29,6 +30,7 @@ from starmallow.utils import (
|
|
29
30
|
status_code_ranges,
|
30
31
|
)
|
31
32
|
|
33
|
+
logger = getLogger(__name__)
|
32
34
|
|
33
35
|
class SchemaRegistry(dict):
|
34
36
|
'''
|
@@ -410,10 +412,8 @@ class SchemaGenerator(BaseSchemaGenerator):
|
|
410
412
|
|
411
413
|
# Add default error response
|
412
414
|
if (any_params or endpoint.body_params or endpoint.form_params) and not any(
|
413
|
-
[
|
414
|
-
status in schema['responses']
|
415
|
+
status in schema['responses']
|
415
416
|
for status in ["422", "4XX", "default"]
|
416
|
-
],
|
417
417
|
):
|
418
418
|
self._add_default_error_response(schema)
|
419
419
|
|
@@ -449,9 +449,13 @@ class SchemaGenerator(BaseSchemaGenerator):
|
|
449
449
|
endpoints_info = self.get_endpoints(routes)
|
450
450
|
|
451
451
|
for path, endpoints in endpoints_info.items():
|
452
|
-
|
453
|
-
path
|
454
|
-
|
455
|
-
|
452
|
+
try:
|
453
|
+
self.spec.path(
|
454
|
+
path=path,
|
455
|
+
operations=self.get_operations(endpoints),
|
456
|
+
)
|
457
|
+
except Exception:
|
458
|
+
logger.error(f'Failed to generate schema for path {path}')
|
459
|
+
raise
|
456
460
|
|
457
461
|
return self.spec.to_dict()
|
starmallow/security/oauth2.py
CHANGED
@@ -84,7 +84,7 @@ class OAuth2PasswordRequestForm:
|
|
84
84
|
This is a dependency class, use it like:
|
85
85
|
|
86
86
|
@app.post("/login")
|
87
|
-
def login(form_data: OAuth2PasswordRequestForm =
|
87
|
+
def login(form_data: OAuth2PasswordRequestForm = ResolvedParam()):
|
88
88
|
data = form_data.parse()
|
89
89
|
print(data.username)
|
90
90
|
print(data.password)
|
@@ -134,7 +134,7 @@ class OAuth2PasswordRequestFormStrict(OAuth2PasswordRequestForm):
|
|
134
134
|
This is a dependency class, use it like:
|
135
135
|
|
136
136
|
@app.post("/login")
|
137
|
-
def login(form_data: OAuth2PasswordRequestFormStrict =
|
137
|
+
def login(form_data: OAuth2PasswordRequestFormStrict = ResolvedParam()):
|
138
138
|
data = form_data.parse()
|
139
139
|
print(data.username)
|
140
140
|
print(data.password)
|
starmallow/utils.py
CHANGED
@@ -32,6 +32,7 @@ import marshmallow as ma
|
|
32
32
|
import marshmallow.fields as mf
|
33
33
|
import marshmallow_dataclass.collection_field as collection_field
|
34
34
|
from marshmallow.validate import Equal, OneOf
|
35
|
+
from starlette.responses import Response
|
35
36
|
from typing_inspect import is_final_type, is_generic_type, is_literal_type
|
36
37
|
|
37
38
|
from starmallow.concurrency import contextmanager_in_threadpool
|
@@ -257,9 +258,9 @@ def eq_marshmallow_fields(left: mf.Field, right: mf.Field) -> bool:
|
|
257
258
|
This compares them instead.
|
258
259
|
'''
|
259
260
|
left_dict = left.__dict__.copy()
|
260
|
-
left_dict.pop('_creation_index')
|
261
|
+
left_dict.pop('_creation_index', None)
|
261
262
|
right_dict = right.__dict__.copy()
|
262
|
-
right_dict.pop('_creation_index')
|
263
|
+
right_dict.pop('_creation_index', None)
|
263
264
|
|
264
265
|
return left_dict == right_dict
|
265
266
|
|
@@ -302,7 +303,7 @@ def deep_dict_update(main_dict: Dict[Any, Any], update_dict: Dict[Any, Any]) ->
|
|
302
303
|
|
303
304
|
|
304
305
|
def create_response_model(type_: Type[Any]) -> ma.Schema | mf.Field | None:
|
305
|
-
if type_
|
306
|
+
if type_ in [inspect._empty, None] or issubclass(type_, Response):
|
306
307
|
return None
|
307
308
|
|
308
309
|
field = get_model_field(type_)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: starmallow
|
3
|
-
Version: 0.1
|
3
|
+
Version: 0.2.1
|
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>
|
@@ -68,6 +68,7 @@ An example of Pydantic's limitations can be found in [Issue 2277](https://github
|
|
68
68
|
Create a file `main.py` with:
|
69
69
|
|
70
70
|
```python
|
71
|
+
from typing import Annotated
|
71
72
|
from marshmallow_dataclass import dataclass
|
72
73
|
from starmallow import Body, Path, StarMallow
|
73
74
|
|
@@ -88,7 +89,7 @@ class MyBody:
|
|
88
89
|
|
89
90
|
@app.get("/body")
|
90
91
|
async def get_body(body: MyBody = Body()) -> int:
|
91
|
-
return
|
92
|
+
return body.item_id
|
92
93
|
|
93
94
|
|
94
95
|
# Example with explicit marshmallow schema
|
@@ -98,6 +99,13 @@ class MyBodySchema(ma.Schema):
|
|
98
99
|
@app.get("/path/body_schema")
|
99
100
|
def get_body_from_schema(body: Dict[str, int] = Body(model=MyBodySchema)) -> int:
|
100
101
|
return body['item_id']
|
102
|
+
|
103
|
+
|
104
|
+
# Example with Annotated
|
105
|
+
|
106
|
+
@app.get("/body_annotated")
|
107
|
+
async def get_body_annotated(body: Annotated[MyBody, Body()]) -> int:
|
108
|
+
return body.item_id
|
101
109
|
```
|
102
110
|
|
103
111
|
### Run it
|
@@ -1,5 +1,5 @@
|
|
1
|
-
starmallow/__init__.py,sha256=
|
2
|
-
starmallow/applications.py,sha256=
|
1
|
+
starmallow/__init__.py,sha256=Z9SbracH7YsHAB1n1L9nHMbxRCARFs22aHL9Nq8F9oU,312
|
2
|
+
starmallow/applications.py,sha256=2lgblSsk9vbVI9t-r0RcvfFuvLB_vFw2OebSDiVO_TM,29311
|
3
3
|
starmallow/concurrency.py,sha256=MVRjo4Vqss_yqhaoeVt3xb7rLaSuAq_q9uYgTwbsojE,1375
|
4
4
|
starmallow/constants.py,sha256=u0h8cJKhJY0oIZqzr7wpEZG2bPLrw5FroMnn3d8KBNQ,129
|
5
5
|
starmallow/dataclasses.py,sha256=ap9DInvQjH2AyI4MAAnbDEuNnbPb94PigaNmEb7AQU8,2658
|
@@ -7,32 +7,32 @@ starmallow/datastructures.py,sha256=iH_KJuJ6kBCWEsnHFLdA3iyb6ZxhfdMHYrJlhiEZtDU,
|
|
7
7
|
starmallow/decorators.py,sha256=SBrzmKxzF2q7hNCW_V7j0UV461QERSh9OTtTdTFi6Kg,3597
|
8
8
|
starmallow/delimited_field.py,sha256=gonWgYg6G5xH2yXAyfDgkePmQ8dUaRSp2hdJ3mCfOBw,3466
|
9
9
|
starmallow/docs.py,sha256=eA39LunVMEoPU5ge4qxm2eiJbrFTUSUu5EhG1L_LKxk,6268
|
10
|
-
starmallow/endpoint.py,sha256=
|
10
|
+
starmallow/endpoint.py,sha256=5oHoWu2dSG_nnctRM60ZPkB1R9Mh4cJv5yxRbYEZHec,15593
|
11
11
|
starmallow/endpoints.py,sha256=UrwVZCxbmWI20iNtJ0oXxo4d3-y12TjsOGs_jnStTiU,939
|
12
12
|
starmallow/exception_handlers.py,sha256=gr2qLYWEtsIEH28n7OreEiiLVz6Y7b6osRyS9esJbBk,891
|
13
|
-
starmallow/exceptions.py,sha256=
|
13
|
+
starmallow/exceptions.py,sha256=vabtPJkTmtCdC8_2OPBE8Osz0v0KxaSOX6IWf1jgNkc,872
|
14
14
|
starmallow/fields.py,sha256=arrTabCYoJFZcoY69EZTBH3YUg7CUSr3-zYLiAjYLTM,1238
|
15
15
|
starmallow/params.py,sha256=XRWIFLm2H5jQUIo4gm5Oi4xVqGNosaQSSi7QYqjJyxQ,7000
|
16
16
|
starmallow/responses.py,sha256=k2pf_m21ykf_FECdODUz400pMucMJJf_Zm8TXFujvaU,2012
|
17
|
-
starmallow/routing.py,sha256=
|
18
|
-
starmallow/schema_generator.py,sha256=
|
17
|
+
starmallow/routing.py,sha256=UaqP4NLw7g3-gBFO85x83NDpsbFCZJMIjxQPT31BCS4,47257
|
18
|
+
starmallow/schema_generator.py,sha256=6cMXlovR9xiA3g3Aryt6XFlzC74VVE-s_Ltsfl0nm-M,16815
|
19
19
|
starmallow/serializers.py,sha256=rBEKMNgONgz_bai12uDvAEMCI_aEFGsqMSeIoWtlrOI,12514
|
20
20
|
starmallow/types.py,sha256=8GXWjvzXQhF5NMHf14fbid6uErxVd1Xk_w2I4FoUgZ4,717
|
21
|
-
starmallow/utils.py,sha256=
|
21
|
+
starmallow/utils.py,sha256=MS44NCYDpKA3JRCvJ7lRhrBK57wT5T8QlylZxlcZLEU,9484
|
22
22
|
starmallow/websockets.py,sha256=yIz3LzTBMNclpEoG7oTMbQwxbcdKNU6M8XcqZMyBTuA,2223
|
23
23
|
starmallow/ext/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
24
24
|
starmallow/ext/marshmallow/__init__.py,sha256=33jENGdfPq4-CDG0LOmN3KOGW1pXTy7a2oMwy4hrYzM,208
|
25
|
-
starmallow/ext/marshmallow/openapi.py,sha256=
|
25
|
+
starmallow/ext/marshmallow/openapi.py,sha256=5aGvbwLGVucsVhXExpYeyt8n5dQTzazrf-nuh6mVhmA,9017
|
26
26
|
starmallow/middleware/__init__.py,sha256=vtNm85Z9pUPjJd-9giJGg3YL1wO7Jm5ooXBm31pDOK8,53
|
27
27
|
starmallow/middleware/asyncexitstack.py,sha256=0GPhQSxqSVmAiVIqBIN5slueWYZ8bwh9f2bBPy7AbP0,1191
|
28
28
|
starmallow/security/__init__.py,sha256=1rQFBIGnEbE51XDZSSi9NgPjXLScFq3RoLu4vk0KVYw,191
|
29
29
|
starmallow/security/api_key.py,sha256=v2a3FHv1c--F2guiJ3wxKQi5k0nIcl40d4tqMPFyb44,3131
|
30
30
|
starmallow/security/base.py,sha256=6ybCCf22t8GNR4RZXIzOfFEGws28S-KVqri-gHHXVCU,1131
|
31
31
|
starmallow/security/http.py,sha256=rMwBYQQRil5iVjM87b0gsCENSFQXiqsdAfy0g6Qmvt8,6597
|
32
|
-
starmallow/security/oauth2.py,sha256=
|
32
|
+
starmallow/security/oauth2.py,sha256=PWdrgqUeijxzRAQilXMXRb9DnA-U2-xMQ5LKL4S66t8,9914
|
33
33
|
starmallow/security/open_id_connect_url.py,sha256=ykokB7mJYu4pFsHW4Ro1y71h-5H11mt90jyv64EIQBM,1386
|
34
34
|
starmallow/security/utils.py,sha256=bd8T0YM7UQD5ATKucr1bNtAvz_Y3__dVNAv5UebiPvc,293
|
35
|
-
starmallow-0.1.
|
36
|
-
starmallow-0.1.
|
37
|
-
starmallow-0.1.
|
38
|
-
starmallow-0.1.
|
35
|
+
starmallow-0.2.1.dist-info/METADATA,sha256=a-W6lFF1CHbt1bMQxz-VBT-flN3cZh_5FHB-WF0MBDA,5651
|
36
|
+
starmallow-0.2.1.dist-info/WHEEL,sha256=y1bSCq4r5i4nMmpXeUJMqs3ipKvkZObrIXSvJHm1qCI,87
|
37
|
+
starmallow-0.2.1.dist-info/licenses/LICENSE.md,sha256=QelyGgOzch8CXzy6HrYwHh7nmj0rlWkDA0YzmZ3CPaY,1084
|
38
|
+
starmallow-0.2.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|