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/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
- FrozenSet,
20
- List,
21
- Mapping,
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.util
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: Dict[str, str] = {
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: Tuple[mf.Field] = (
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
- List,
87
+ list,
87
88
  collections.abc.Sequence,
88
89
  Sequence,
89
90
  tuple,
90
- Tuple,
91
+ tuple,
92
+ set,
91
93
  set,
92
- Set,
93
94
  frozenset,
94
- FrozenSet,
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 is_marshmallow_field(model):
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", None)
149
+ kwargs["dump_default"] = kwargs.get("dump_default")
150
150
  if not kwargs.get("required"):
151
- kwargs["load_default"] = kwargs.get("load_default", None)
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
- return UnionField(
160
- [(subtyp, get_model_field(subtyp, required=True)) for subtyp in subtypes],
161
- **kwargs
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, 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, 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, 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, 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, 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, Dict, collections.abc.Mapping, Mapping):
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) -> Set[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
- def is_marshmallow_schema(obj):
237
- return (inspect.isclass(obj) and issubclass(obj, ma.Schema)) or isinstance(obj, ma.Schema)
239
+ class MaDataclassProtocol(Protocol):
240
+ Schema: NotRequired[type[ma.Schema]]
238
241
 
239
242
 
240
- def is_marshmallow_field(obj):
241
- return (inspect.isclass(obj) and issubclass(obj, mf.Field)) or isinstance(obj, mf.Field)
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 is_marshmallow_dataclass(obj):
245
- return is_dataclass(obj) and hasattr(obj, 'Schema') and is_marshmallow_schema(obj.Schema)
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: Dict[str, Any],
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: Union[Type[Any], Tuple[Type[Any], ...], None]) -> bool:
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) # type: ignore[arg-type]
313
+ return isinstance(cls, type) and issubclass(cls, class_or_tuple)
278
314
  except TypeError:
279
- if isinstance(cls, _GenericAlias):
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 __dict_creator__(current, segments, i, hints=()):
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: Dict, path: str, value: Any):
313
- dpath.new(d, path, value, separator='.', creator=__dict_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: Dict[Any, Any], update_dict: Dict[Any, Any]) -> None:
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_: Type[Any]) -> ma.Schema | mf.Field | None:
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
- ) -> DefaultPlaceholder | DefaultType:
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,) + extra_items
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: Dict[str, Any]) -> Any:
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[..., Any]) -> Any:
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.3
1
+ Metadata-Version: 2.4
2
2
  Name: starmallow
3
- Version: 0.8.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<4,>=3.18.0
33
- Requires-Dist: python-multipart<0.0.7,>=0.0.5
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<1,>=0.35
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: isort<6.0.0,>=5.0.6; extra == 'dev'
42
- Requires-Dist: pre-commit<4,>=3.2.0; extra == 'dev'
43
- Requires-Dist: ruff==0.0.260; extra == 'dev'
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<8.0.0,>=7.1.3; extra == 'test'
53
- Requires-Dist: ruff==0.0.260; extra == 'test'
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,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.26.3
2
+ Generator: hatchling 1.27.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -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,,