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 CHANGED
@@ -1,4 +1,4 @@
1
- __version__ = "0.1.0"
1
+ __version__ = "0.2.1"
2
2
 
3
3
  from .applications import StarMallow
4
4
  from .exceptions import RequestValidationError
@@ -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 = self.build_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
- return JSONResponse(self.openapi())
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(self, parameter: inspect.Parameter) -> Union[ma.Schema, mf.Field]:
168
- model = parameter.annotation
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.default.title
175
- if (isinstance(parameter.default, Param) and parameter.default.title)
176
- else parameter.name.title().replace('_', ' ')
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.default, Param):
182
- if parameter.default.validators:
183
- kwargs['validate'] = parameter.default.validators
184
- if parameter.default.deprecated:
185
- kwargs['metadata']['deprecated'] = parameter.default.deprecated
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(parameter.annotation) if a is not None), None)
209
+ model = next((a for a in get_args(type_annotation) if a is not None), None)
194
210
 
195
- if isinstance(parameter.default, Param):
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 parameter.default.default != Ellipsis:
214
+ if default_value != Ellipsis:
199
215
  kwargs.update({
200
- 'load_default': parameter.default.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.default.model is not None:
206
- model = parameter.default.model
207
- elif parameter.default != inspect._empty:
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': parameter.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"'{parameter.name}' model and annotation have different 'load_default' values."
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 {parameter.name}, model is {model}') from e
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 = parameter.annotation
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(parameter.default, NoParam)
316
+ or isinstance(starmallow_param, NoParam)
268
317
  ):
269
318
  continue
270
- elif isinstance(parameter.default, Security):
271
- security_param: Security = self.get_resolved_param(parameter, path=path)
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
- parameter.annotation,
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] = parameter.annotation
340
+ params[ParamType.noparam][name] = type_annotation
291
341
  continue
292
342
 
293
- model = self._get_param_model(parameter)
343
+ model = self._get_param_model(type_annotation, starmallow_param, name, default_value)
294
344
  model.name = name
295
345
 
296
- if isinstance(parameter.default, Param):
346
+ if isinstance(starmallow_param, Param):
297
347
  # Create new field_info with processed model
298
- field_info = parameter.default.__class__(
299
- parameter.default.default,
300
- deprecated=parameter.default.deprecated,
301
- include_in_schema=parameter.default.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 parameter.default == inspect._empty else parameter.default,
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 parameter.default == inspect._empty else parameter.default,
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
@@ -584,7 +584,7 @@ class APIRouter(routing.Router):
584
584
  method_tags.extend(endpoint_options.tags)
585
585
 
586
586
  route = APIRoute(
587
- path,
587
+ self.prefix + path,
588
588
  endpoint_function,
589
589
  methods=[method],
590
590
  name=endpoint_options.name or name,
@@ -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
- self.spec.path(
453
- path=path,
454
- operations=self.get_operations(endpoints),
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()
@@ -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 = Depends()):
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 = Depends()):
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_ == inspect._empty:
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.0
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 MyBody.item_id
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=ZV96O-3SQhCjRVTbSI_SesM-Kk6hN6isx3x0kPd49b4,312
2
- starmallow/applications.py,sha256=6AEKK3Gih1PrxWLD7k0Sm13snzGE_40kzoi0igJ0ie4,29170
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=MPWF3v-WXL44J3Q7InpPX_5fam251T-7ImdirwojASI,13743
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=AWIsbrqYXnPBQUGtUT0BPDqqljl53UdnIFTKw7BcraQ,642
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=jfEaP7bZm_744w1Q83BfeUHjRb0Jtd2umLc91J3awyA,47243
18
- starmallow/schema_generator.py,sha256=Tn9loWgvORScxt2UjcYW7KUt9zTk00gQwqkA1TOfGdw,16629
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=PmOdXLVCC82Kqq4x_EYSLGVRuoc1WR6NCaMsHddTakg,9392
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=6C-4n8sLPAmVutGVPkgpRJR-gJjJMXgsz0HicpDNcXw,9011
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=Sb90Y8ADFceqJImXZyAAiXQp-AOwXmAeP30-xdKoV14,9902
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.0.dist-info/METADATA,sha256=1cmZHt1fQG2mGO0L9O6w9X-hiZh6e0MUzFZVUb8g3KE,5474
36
- starmallow-0.1.0.dist-info/WHEEL,sha256=y1bSCq4r5i4nMmpXeUJMqs3ipKvkZObrIXSvJHm1qCI,87
37
- starmallow-0.1.0.dist-info/licenses/LICENSE.md,sha256=QelyGgOzch8CXzy6HrYwHh7nmj0rlWkDA0YzmZ3CPaY,1084
38
- starmallow-0.1.0.dist-info/RECORD,,
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,,