starmallow 0.7.0__tar.gz → 0.8.0__tar.gz

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.
Files changed (118) hide show
  1. {starmallow-0.7.0 → starmallow-0.8.0}/PKG-INFO +4 -4
  2. {starmallow-0.7.0 → starmallow-0.8.0}/README.md +2 -2
  3. {starmallow-0.7.0 → starmallow-0.8.0}/examples/cache_server.py +1 -1
  4. {starmallow-0.7.0 → starmallow-0.8.0}/examples/flask_server.py +1 -1
  5. {starmallow-0.7.0 → starmallow-0.8.0}/examples/goals.ipynb +2 -2
  6. {starmallow-0.7.0 → starmallow-0.8.0}/examples/sample_server.py +1 -1
  7. {starmallow-0.7.0 → starmallow-0.8.0}/pyproject.toml +1 -1
  8. {starmallow-0.7.0 → starmallow-0.8.0}/starmallow/__init__.py +1 -1
  9. {starmallow-0.7.0 → starmallow-0.8.0}/starmallow/endpoint.py +4 -0
  10. {starmallow-0.7.0 → starmallow-0.8.0}/starmallow/ext/marshmallow/openapi.py +2 -2
  11. {starmallow-0.7.0 → starmallow-0.8.0}/starmallow/security/api_key.py +1 -1
  12. {starmallow-0.7.0 → starmallow-0.8.0}/starmallow/security/base.py +1 -1
  13. {starmallow-0.7.0 → starmallow-0.8.0}/starmallow/security/http.py +1 -1
  14. {starmallow-0.7.0 → starmallow-0.8.0}/starmallow/security/oauth2.py +1 -1
  15. {starmallow-0.7.0 → starmallow-0.8.0}/starmallow/security/open_id_connect_url.py +1 -1
  16. {starmallow-0.7.0 → starmallow-0.8.0}/starmallow/types.py +1 -1
  17. {starmallow-0.7.0 → starmallow-0.8.0}/starmallow/utils.py +6 -2
  18. {starmallow-0.7.0 → starmallow-0.8.0}/tests/basic_api.py +1 -1
  19. {starmallow-0.7.0 → starmallow-0.8.0}/tests/security/api_key/test_api_key_cookie.py +1 -1
  20. {starmallow-0.7.0 → starmallow-0.8.0}/tests/security/api_key/test_api_key_cookie_description.py +1 -1
  21. {starmallow-0.7.0 → starmallow-0.8.0}/tests/security/api_key/test_api_key_cookie_optional.py +1 -1
  22. {starmallow-0.7.0 → starmallow-0.8.0}/tests/security/api_key/test_api_key_header.py +1 -1
  23. {starmallow-0.7.0 → starmallow-0.8.0}/tests/security/api_key/test_api_key_header_description.py +1 -1
  24. {starmallow-0.7.0 → starmallow-0.8.0}/tests/security/api_key/test_api_key_header_optional.py +1 -1
  25. {starmallow-0.7.0 → starmallow-0.8.0}/tests/security/api_key/test_api_key_query.py +1 -1
  26. {starmallow-0.7.0 → starmallow-0.8.0}/tests/security/api_key/test_api_key_query_description.py +1 -1
  27. {starmallow-0.7.0 → starmallow-0.8.0}/tests/security/api_key/test_api_key_query_optional.py +1 -1
  28. {starmallow-0.7.0 → starmallow-0.8.0}/tests/security/oauth2/test_oauth2.py +1 -1
  29. {starmallow-0.7.0 → starmallow-0.8.0}/tests/security/oauth2/test_oauth2_optional.py +1 -1
  30. {starmallow-0.7.0 → starmallow-0.8.0}/tests/security/oauth2/test_oauth2_optional_description.py +1 -1
  31. {starmallow-0.7.0 → starmallow-0.8.0}/tests/security/openid_connect/test_openid_connect.py +1 -1
  32. {starmallow-0.7.0 → starmallow-0.8.0}/tests/security/openid_connect/test_openid_connect_description.py +1 -1
  33. {starmallow-0.7.0 → starmallow-0.8.0}/tests/security/openid_connect/test_openid_connect_optional.py +1 -1
  34. {starmallow-0.7.0 → starmallow-0.8.0}/tests/test_additional_properties.py +1 -1
  35. {starmallow-0.7.0 → starmallow-0.8.0}/tests/test_additional_responses_custom_model_in_callback.py +1 -1
  36. {starmallow-0.7.0 → starmallow-0.8.0}/tests/test_additional_responses_custom_validationerror.py +1 -1
  37. {starmallow-0.7.0 → starmallow-0.8.0}/tests/test_additional_responses_response_class.py +1 -1
  38. {starmallow-0.7.0 → starmallow-0.8.0}/tests/test_additional_responses_router.py +1 -1
  39. {starmallow-0.7.0 → starmallow-0.8.0}/tests/test_annotated.py +1 -1
  40. {starmallow-0.7.0 → starmallow-0.8.0}/tests/test_dataclass_fields.py +1 -1
  41. starmallow-0.8.0/tests/test_generics.py +149 -0
  42. {starmallow-0.7.0 → starmallow-0.8.0}/tests/test_input.py +1 -1
  43. {starmallow-0.7.0 → starmallow-0.8.0}/tests/test_requests_orjson.py +1 -1
  44. {starmallow-0.7.0 → starmallow-0.8.0}/tests/test_requests_ujson.py +1 -1
  45. {starmallow-0.7.0 → starmallow-0.8.0}/tests/test_responses.py +1 -1
  46. {starmallow-0.7.0 → starmallow-0.8.0}/tests/test_responses_orjson.py +1 -1
  47. {starmallow-0.7.0 → starmallow-0.8.0}/tests/test_responses_ujson.py +1 -1
  48. {starmallow-0.7.0 → starmallow-0.8.0}/tests/test_ws_router.py +1 -1
  49. starmallow-0.7.0/starmallow/union_field.py +0 -86
  50. {starmallow-0.7.0 → starmallow-0.8.0}/.editorconfig +0 -0
  51. {starmallow-0.7.0 → starmallow-0.8.0}/.gitignore +0 -0
  52. {starmallow-0.7.0 → starmallow-0.8.0}/.pre-commit-config.yaml +0 -0
  53. {starmallow-0.7.0 → starmallow-0.8.0}/Dockerfile +0 -0
  54. {starmallow-0.7.0 → starmallow-0.8.0}/LICENSE.md +0 -0
  55. {starmallow-0.7.0 → starmallow-0.8.0}/docker-compose.yml +0 -0
  56. {starmallow-0.7.0 → starmallow-0.8.0}/docs/design_ideas.md +0 -0
  57. {starmallow-0.7.0 → starmallow-0.8.0}/examples/__init__.py +0 -0
  58. {starmallow-0.7.0 → starmallow-0.8.0}/examples/gunicorn.py +0 -0
  59. {starmallow-0.7.0 → starmallow-0.8.0}/examples/recommended_server.py +0 -0
  60. {starmallow-0.7.0 → starmallow-0.8.0}/starmallow/applications.py +0 -0
  61. {starmallow-0.7.0 → starmallow-0.8.0}/starmallow/background.py +0 -0
  62. {starmallow-0.7.0 → starmallow-0.8.0}/starmallow/concurrency.py +0 -0
  63. {starmallow-0.7.0 → starmallow-0.8.0}/starmallow/constants.py +0 -0
  64. {starmallow-0.7.0 → starmallow-0.8.0}/starmallow/dataclasses.py +0 -0
  65. {starmallow-0.7.0 → starmallow-0.8.0}/starmallow/datastructures.py +0 -0
  66. {starmallow-0.7.0 → starmallow-0.8.0}/starmallow/decorators.py +0 -0
  67. {starmallow-0.7.0 → starmallow-0.8.0}/starmallow/delimited_field.py +0 -0
  68. {starmallow-0.7.0 → starmallow-0.8.0}/starmallow/docs.py +0 -0
  69. {starmallow-0.7.0 → starmallow-0.8.0}/starmallow/endpoints.py +0 -0
  70. {starmallow-0.7.0 → starmallow-0.8.0}/starmallow/exception_handlers.py +0 -0
  71. {starmallow-0.7.0 → starmallow-0.8.0}/starmallow/exceptions.py +0 -0
  72. {starmallow-0.7.0 → starmallow-0.8.0}/starmallow/ext/__init__.py +0 -0
  73. {starmallow-0.7.0 → starmallow-0.8.0}/starmallow/ext/marshmallow/__init__.py +0 -0
  74. {starmallow-0.7.0 → starmallow-0.8.0}/starmallow/fields.py +0 -0
  75. {starmallow-0.7.0 → starmallow-0.8.0}/starmallow/middleware/__init__.py +0 -0
  76. {starmallow-0.7.0 → starmallow-0.8.0}/starmallow/middleware/asyncexitstack.py +0 -0
  77. {starmallow-0.7.0 → starmallow-0.8.0}/starmallow/params.py +0 -0
  78. {starmallow-0.7.0 → starmallow-0.8.0}/starmallow/request_resolver.py +0 -0
  79. {starmallow-0.7.0 → starmallow-0.8.0}/starmallow/requests.py +0 -0
  80. {starmallow-0.7.0 → starmallow-0.8.0}/starmallow/responses.py +0 -0
  81. {starmallow-0.7.0 → starmallow-0.8.0}/starmallow/routing.py +0 -0
  82. {starmallow-0.7.0 → starmallow-0.8.0}/starmallow/schema_generator.py +0 -0
  83. {starmallow-0.7.0 → starmallow-0.8.0}/starmallow/security/__init__.py +0 -0
  84. {starmallow-0.7.0 → starmallow-0.8.0}/starmallow/security/utils.py +0 -0
  85. {starmallow-0.7.0 → starmallow-0.8.0}/starmallow/serializers.py +0 -0
  86. {starmallow-0.7.0 → starmallow-0.8.0}/starmallow/websockets.py +0 -0
  87. {starmallow-0.7.0 → starmallow-0.8.0}/tests/__init__.py +0 -0
  88. {starmallow-0.7.0 → starmallow-0.8.0}/tests/security/__init__.py +0 -0
  89. {starmallow-0.7.0 → starmallow-0.8.0}/tests/security/api_key/__init__.py +0 -0
  90. {starmallow-0.7.0 → starmallow-0.8.0}/tests/security/http/__init__.py +0 -0
  91. {starmallow-0.7.0 → starmallow-0.8.0}/tests/security/http/test_http_base.py +0 -0
  92. {starmallow-0.7.0 → starmallow-0.8.0}/tests/security/http/test_http_base_description.py +0 -0
  93. {starmallow-0.7.0 → starmallow-0.8.0}/tests/security/http/test_http_base_optional.py +0 -0
  94. {starmallow-0.7.0 → starmallow-0.8.0}/tests/security/http/test_http_basic.py +0 -0
  95. {starmallow-0.7.0 → starmallow-0.8.0}/tests/security/http/test_http_basic_realm.py +0 -0
  96. {starmallow-0.7.0 → starmallow-0.8.0}/tests/security/http/test_http_basic_realm_description.py +0 -0
  97. {starmallow-0.7.0 → starmallow-0.8.0}/tests/security/http/test_http_bearer.py +0 -0
  98. {starmallow-0.7.0 → starmallow-0.8.0}/tests/security/http/test_http_bearer_description.py +0 -0
  99. {starmallow-0.7.0 → starmallow-0.8.0}/tests/security/http/test_http_bearer_optional.py +0 -0
  100. {starmallow-0.7.0 → starmallow-0.8.0}/tests/security/http/test_http_digest.py +0 -0
  101. {starmallow-0.7.0 → starmallow-0.8.0}/tests/security/http/test_http_digest_description.py +0 -0
  102. {starmallow-0.7.0 → starmallow-0.8.0}/tests/security/http/test_http_digest_optional.py +0 -0
  103. {starmallow-0.7.0 → starmallow-0.8.0}/tests/security/oauth2/__init__.py +0 -0
  104. {starmallow-0.7.0 → starmallow-0.8.0}/tests/security/oauth2/test_oauth2_authorization_code_bearer.py +0 -0
  105. {starmallow-0.7.0 → starmallow-0.8.0}/tests/security/oauth2/test_oauth2_authorization_code_bearer_description.py +0 -0
  106. {starmallow-0.7.0 → starmallow-0.8.0}/tests/security/oauth2/test_oauth2_password_bearer_optional.py +0 -0
  107. {starmallow-0.7.0 → starmallow-0.8.0}/tests/security/oauth2/test_oauth2_password_bearer_optional_description.py +0 -0
  108. {starmallow-0.7.0 → starmallow-0.8.0}/tests/security/openid_connect/__init__.py +0 -0
  109. {starmallow-0.7.0 → starmallow-0.8.0}/tests/test_additional_response_extra.py +0 -0
  110. {starmallow-0.7.0 → starmallow-0.8.0}/tests/test_additional_responses_bad.py +0 -0
  111. {starmallow-0.7.0 → starmallow-0.8.0}/tests/test_additional_responses_default_validationerror.py +0 -0
  112. {starmallow-0.7.0 → starmallow-0.8.0}/tests/test_basic_api.py +0 -0
  113. {starmallow-0.7.0 → starmallow-0.8.0}/tests/test_delimited_params.py +0 -0
  114. {starmallow-0.7.0 → starmallow-0.8.0}/tests/test_http_endpoints.py +0 -0
  115. {starmallow-0.7.0 → starmallow-0.8.0}/tests/test_middleware.py +0 -0
  116. {starmallow-0.7.0 → starmallow-0.8.0}/tests/test_resolved_param_contextmanagers.py +0 -0
  117. {starmallow-0.7.0 → starmallow-0.8.0}/tests/test_resolved_params.py +0 -0
  118. {starmallow-0.7.0 → starmallow-0.8.0}/tests/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: starmallow
3
- Version: 0.7.0
3
+ Version: 0.8.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>
@@ -28,7 +28,7 @@ Classifier: Typing :: Typed
28
28
  Requires-Python: >=3.10
29
29
  Requires-Dist: apispec[marshmallow]<7,>=6
30
30
  Requires-Dist: dpath<3,>=2.1.0
31
- Requires-Dist: marshmallow-dataclass<9,>=8.5.1
31
+ Requires-Dist: marshmallow-dataclass2<9,>=8.8.1
32
32
  Requires-Dist: marshmallow<4,>=3.18.0
33
33
  Requires-Dist: python-multipart<0.0.7,>=0.0.5
34
34
  Requires-Dist: pyyaml>=5.4.1
@@ -68,7 +68,7 @@ Create a file `main.py` with:
68
68
 
69
69
  ```python
70
70
  from typing import Annotated
71
- from marshmallow_dataclass import dataclass
71
+ from marshmallow_dataclass2 import dataclass
72
72
  from starmallow import Body, Path, StarMallow
73
73
 
74
74
  app = StarMallow()
@@ -131,7 +131,7 @@ INFO: Application startup complete.
131
131
  You can also use class-based views. This can make it easier to organize your code and gives you an easy migration path if you use [flask-smorest](https://flask-smorest.readthedocs.io/)
132
132
 
133
133
  ```python
134
- from marshmallow_dataclass import dataclass
134
+ from marshmallow_dataclass2 import dataclass
135
135
  from starmallow import StarMallow
136
136
  from starmallow.decorators import route
137
137
  from starmallow.endpoints import APIHTTPEndpoint
@@ -13,7 +13,7 @@ Create a file `main.py` with:
13
13
 
14
14
  ```python
15
15
  from typing import Annotated
16
- from marshmallow_dataclass import dataclass
16
+ from marshmallow_dataclass2 import dataclass
17
17
  from starmallow import Body, Path, StarMallow
18
18
 
19
19
  app = StarMallow()
@@ -76,7 +76,7 @@ INFO: Application startup complete.
76
76
  You can also use class-based views. This can make it easier to organize your code and gives you an easy migration path if you use [flask-smorest](https://flask-smorest.readthedocs.io/)
77
77
 
78
78
  ```python
79
- from marshmallow_dataclass import dataclass
79
+ from marshmallow_dataclass2 import dataclass
80
80
  from starmallow import StarMallow
81
81
  from starmallow.decorators import route
82
82
  from starmallow.endpoints import APIHTTPEndpoint
@@ -5,7 +5,7 @@ import hashlib
5
5
  import marshmallow.fields as mf
6
6
  from brotli_asgi import BrotliMiddleware
7
7
  from marshmallow.validate import Range
8
- from marshmallow_dataclass import dataclass as ma_dataclass
8
+ from marshmallow_dataclass2 import dataclass as ma_dataclass
9
9
  from starlette.middleware import Middleware
10
10
  from starlette_context import middleware, plugins
11
11
 
@@ -9,7 +9,7 @@ from flask import json as flask_json
9
9
  from flask.views import MethodView
10
10
  # from flask_compress import Compress
11
11
  from flask_smorest import Api, Blueprint
12
- from marshmallow_dataclass import dataclass as ma_dataclass
12
+ from marshmallow_dataclass2 import dataclass as ma_dataclass
13
13
 
14
14
  default_flask_config = {
15
15
  'OPENAPI_VERSION': '3.0.3',
@@ -23,7 +23,7 @@
23
23
  "outputs": [],
24
24
  "source": [
25
25
  "import marshmallow.fields as mf\n",
26
- "from marshmallow_dataclass import dataclass as ma_dataclass\n",
26
+ "from marshmallow_dataclass2 import dataclass as ma_dataclass\n",
27
27
  "from starmallow import APIRouter\n",
28
28
  "from starmallow.params import (\n",
29
29
  " Header, \n",
@@ -150,7 +150,7 @@
150
150
  "from typing import Any, Callable, TypeVar, Generic, Optional, _SpecialForm\n",
151
151
  "\n",
152
152
  "import marshmallow.fields as mf\n",
153
- "from marshmallow_dataclass import dataclass as ma_dataclass\n",
153
+ "from marshmallow_dataclass2 import dataclass as ma_dataclass\n",
154
154
  "\n",
155
155
  "@ma_dataclass\n",
156
156
  "class CreateRequest:\n",
@@ -5,7 +5,7 @@ import aiofiles.tempfile
5
5
  import marshmallow.fields as mf
6
6
  import orjson
7
7
  from marshmallow.validate import Range
8
- from marshmallow_dataclass import dataclass as ma_dataclass
8
+ from marshmallow_dataclass2 import dataclass as ma_dataclass
9
9
  from starlette.middleware import Middleware
10
10
  from starlette.middleware.gzip import GZipMiddleware
11
11
  from starlette_context import middleware, plugins
@@ -38,7 +38,7 @@ dependencies = [
38
38
  "apispec[marshmallow] >=6,<7",
39
39
  "dpath >=2.1.0,<3",
40
40
  "marshmallow >=3.18.0,<4",
41
- "marshmallow-dataclass >=8.5.1,<9",
41
+ "marshmallow-dataclass2 >=8.8.1,<9",
42
42
  "python-multipart >=0.0.5,<0.0.7",
43
43
  "pyyaml >=5.4.1",
44
44
  "starlette >=0.35,<1",
@@ -1,4 +1,4 @@
1
- __version__ = "0.7.0"
1
+ __version__ = "0.8.0"
2
2
 
3
3
  from .applications import StarMallow
4
4
  from .exceptions import RequestValidationError
@@ -20,6 +20,7 @@ from typing import (
20
20
  import marshmallow as ma
21
21
  import marshmallow.fields as mf
22
22
  from marshmallow.utils import missing as missing_
23
+ from marshmallow_dataclass2 import class_schema, is_generic_alias_of_dataclass
23
24
  from starlette.background import BackgroundTasks
24
25
  from starlette.requests import HTTPConnection, Request
25
26
  from starlette.responses import Response
@@ -243,6 +244,9 @@ class EndpointMixin:
243
244
  if is_marshmallow_dataclass(model):
244
245
  model = model.Schema
245
246
 
247
+ if is_generic_alias_of_dataclass(model):
248
+ model = class_schema(model)
249
+
246
250
  if isinstance(model, NewType) and getattr(model, '_marshmallow_field', None):
247
251
  return model._marshmallow_field(**kwargs)
248
252
  elif is_marshmallow_schema(model):
@@ -2,7 +2,7 @@ from typing import Any
2
2
 
3
3
  import marshmallow as ma
4
4
  import marshmallow.fields as mf
5
- import marshmallow_dataclass.collection_field as collection_field
5
+ import marshmallow_dataclass2.collection_field as collection_field
6
6
  from apispec import APISpec
7
7
  from apispec.ext.marshmallow.common import get_fields
8
8
  from apispec.ext.marshmallow.field_converter import (
@@ -12,9 +12,9 @@ from apispec.ext.marshmallow.field_converter import (
12
12
  )
13
13
  from apispec.ext.marshmallow.openapi import OpenAPIConverter as ApiSpecOpenAPIConverter
14
14
  from marshmallow.utils import is_collection
15
+ from marshmallow_dataclass2.union_field import Union as UnionField
15
16
  from packaging.version import Version
16
17
 
17
- from starmallow.union_field import Union as UnionField
18
18
  from starmallow.utils import MARSHMALLOW_ITERABLES
19
19
 
20
20
  # marshmallow field => (JSON Schema type, format)
@@ -1,7 +1,7 @@
1
1
  from enum import Enum
2
2
  from typing import ClassVar, Optional
3
3
 
4
- from marshmallow_dataclass import dataclass as ma_dataclass
4
+ from marshmallow_dataclass2 import dataclass as ma_dataclass
5
5
  from starlette.requests import Request
6
6
  from starlette.status import HTTP_403_FORBIDDEN
7
7
 
@@ -2,7 +2,7 @@ from enum import Enum
2
2
  from typing import Any, ClassVar, Dict, Optional
3
3
 
4
4
  import marshmallow as ma
5
- from marshmallow_dataclass import dataclass as ma_dataclass
5
+ from marshmallow_dataclass2 import dataclass as ma_dataclass
6
6
 
7
7
 
8
8
  # Provided by: https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#security-scheme-object
@@ -2,7 +2,7 @@ import binascii
2
2
  from base64 import b64decode
3
3
  from typing import ClassVar, Optional
4
4
 
5
- from marshmallow_dataclass import dataclass as ma_dataclass
5
+ from marshmallow_dataclass2 import dataclass as ma_dataclass
6
6
  from starlette.requests import Request
7
7
  from starlette.status import HTTP_401_UNAUTHORIZED, HTTP_403_FORBIDDEN
8
8
 
@@ -1,7 +1,7 @@
1
1
  from typing import Any, Dict, List, Optional, Union
2
2
 
3
3
  import marshmallow as ma
4
- from marshmallow_dataclass import dataclass as ma_dataclass
4
+ from marshmallow_dataclass2 import dataclass as ma_dataclass
5
5
  from starlette.requests import Request
6
6
  from starlette.status import HTTP_401_UNAUTHORIZED, HTTP_403_FORBIDDEN
7
7
 
@@ -1,6 +1,6 @@
1
1
  from typing import Optional
2
2
 
3
- from marshmallow_dataclass import dataclass as ma_dataclass
3
+ from marshmallow_dataclass2 import dataclass as ma_dataclass
4
4
  from starlette.exceptions import HTTPException
5
5
  from starlette.requests import Request
6
6
  from starlette.status import HTTP_403_FORBIDDEN
@@ -2,7 +2,7 @@ import uuid
2
2
  from typing import Any, Callable, List, TypeVar, Union
3
3
 
4
4
  import marshmallow.fields as mf
5
- from marshmallow_dataclass import NewType
5
+ from marshmallow_dataclass2 import NewType
6
6
 
7
7
  import starmallow.fields as sf
8
8
  from starmallow.endpoints import APIHTTPEndpoint
@@ -33,15 +33,16 @@ from typing import (
33
33
  import dpath.util
34
34
  import marshmallow as ma
35
35
  import marshmallow.fields as mf
36
- import marshmallow_dataclass.collection_field as collection_field
36
+ import marshmallow_dataclass2.collection_field as collection_field
37
37
  import typing_inspect
38
38
  from marshmallow.validate import Equal, OneOf
39
+ from marshmallow_dataclass2 import class_schema, is_generic_alias_of_dataclass
40
+ from marshmallow_dataclass2.union_field import Union as UnionField
39
41
  from starlette.responses import Response
40
42
  from typing_inspect import is_final_type, is_generic_type, is_literal_type
41
43
 
42
44
  from starmallow.concurrency import contextmanager_in_threadpool
43
45
  from starmallow.datastructures import DefaultPlaceholder, DefaultType
44
- from starmallow.union_field import Union as UnionField
45
46
 
46
47
  if TYPE_CHECKING: # pragma: nocover
47
48
  from starmallow.routing import APIRoute
@@ -105,6 +106,9 @@ def get_model_field(model: Any, **kwargs) -> mf.Field:
105
106
  if is_marshmallow_dataclass(model):
106
107
  model = model.Schema
107
108
 
109
+ if is_generic_alias_of_dataclass(model):
110
+ model = class_schema(model)
111
+
108
112
  if is_marshmallow_schema(model):
109
113
  return mf.Nested(model if isinstance(model, ma.Schema) else model())
110
114
 
@@ -6,7 +6,7 @@ from typing import Final, FrozenSet, Literal, Optional, Union
6
6
  from uuid import UUID
7
7
 
8
8
  from marshmallow.validate import Length, Range, Regexp
9
- from marshmallow_dataclass import dataclass as ma_dataclass
9
+ from marshmallow_dataclass2 import dataclass as ma_dataclass
10
10
 
11
11
  from starmallow import Path, Query, StarMallow
12
12
 
@@ -1,4 +1,4 @@
1
- from marshmallow_dataclass import dataclass as ma_dataclass
1
+ from marshmallow_dataclass2 import dataclass as ma_dataclass
2
2
  from starlette.testclient import TestClient
3
3
 
4
4
  from starmallow import StarMallow
@@ -1,4 +1,4 @@
1
- from marshmallow_dataclass import dataclass as ma_dataclass
1
+ from marshmallow_dataclass2 import dataclass as ma_dataclass
2
2
  from starlette.testclient import TestClient
3
3
 
4
4
  from starmallow import StarMallow
@@ -1,6 +1,6 @@
1
1
  from typing import Optional
2
2
 
3
- from marshmallow_dataclass import dataclass as ma_dataclass
3
+ from marshmallow_dataclass2 import dataclass as ma_dataclass
4
4
  from starlette.testclient import TestClient
5
5
 
6
6
  from starmallow import StarMallow
@@ -1,4 +1,4 @@
1
- from marshmallow_dataclass import dataclass as ma_dataclass
1
+ from marshmallow_dataclass2 import dataclass as ma_dataclass
2
2
  from starlette.testclient import TestClient
3
3
 
4
4
  from starmallow import StarMallow
@@ -1,4 +1,4 @@
1
- from marshmallow_dataclass import dataclass as ma_dataclass
1
+ from marshmallow_dataclass2 import dataclass as ma_dataclass
2
2
  from starlette.testclient import TestClient
3
3
 
4
4
  from starmallow import StarMallow
@@ -1,6 +1,6 @@
1
1
  from typing import Optional
2
2
 
3
- from marshmallow_dataclass import dataclass as ma_dataclass
3
+ from marshmallow_dataclass2 import dataclass as ma_dataclass
4
4
  from starlette.testclient import TestClient
5
5
 
6
6
  from starmallow import StarMallow
@@ -1,4 +1,4 @@
1
- from marshmallow_dataclass import dataclass as ma_dataclass
1
+ from marshmallow_dataclass2 import dataclass as ma_dataclass
2
2
  from starlette.testclient import TestClient
3
3
 
4
4
  from starmallow import StarMallow
@@ -1,4 +1,4 @@
1
- from marshmallow_dataclass import dataclass as ma_dataclass
1
+ from marshmallow_dataclass2 import dataclass as ma_dataclass
2
2
  from starlette.testclient import TestClient
3
3
 
4
4
  from starmallow import StarMallow
@@ -1,6 +1,6 @@
1
1
  from typing import Optional
2
2
 
3
- from marshmallow_dataclass import dataclass as ma_dataclass
3
+ from marshmallow_dataclass2 import dataclass as ma_dataclass
4
4
  from starlette.testclient import TestClient
5
5
 
6
6
  from starmallow import StarMallow
@@ -1,5 +1,5 @@
1
1
  import pytest
2
- from marshmallow_dataclass import dataclass as ma_dataclass
2
+ from marshmallow_dataclass2 import dataclass as ma_dataclass
3
3
  from starlette.testclient import TestClient
4
4
 
5
5
  from starmallow import StarMallow
@@ -1,7 +1,7 @@
1
1
  from typing import Optional
2
2
 
3
3
  import pytest
4
- from marshmallow_dataclass import dataclass as ma_dataclass
4
+ from marshmallow_dataclass2 import dataclass as ma_dataclass
5
5
  from starlette.testclient import TestClient
6
6
 
7
7
  from starmallow import StarMallow
@@ -1,7 +1,7 @@
1
1
  from typing import Optional
2
2
 
3
3
  import pytest
4
- from marshmallow_dataclass import dataclass as ma_dataclass
4
+ from marshmallow_dataclass2 import dataclass as ma_dataclass
5
5
  from starlette.testclient import TestClient
6
6
 
7
7
  from starmallow import StarMallow
@@ -1,4 +1,4 @@
1
- from marshmallow_dataclass import dataclass as ma_dataclass
1
+ from marshmallow_dataclass2 import dataclass as ma_dataclass
2
2
  from starlette.testclient import TestClient
3
3
 
4
4
  from starmallow import StarMallow
@@ -1,4 +1,4 @@
1
- from marshmallow_dataclass import dataclass as ma_dataclass
1
+ from marshmallow_dataclass2 import dataclass as ma_dataclass
2
2
  from starlette.testclient import TestClient
3
3
 
4
4
  from starmallow import StarMallow
@@ -1,6 +1,6 @@
1
1
  from typing import Optional
2
2
 
3
- from marshmallow_dataclass import dataclass as ma_dataclass
3
+ from marshmallow_dataclass2 import dataclass as ma_dataclass
4
4
  from starlette.testclient import TestClient
5
5
 
6
6
  from starmallow import StarMallow
@@ -1,6 +1,6 @@
1
1
  from typing import Dict
2
2
 
3
- from marshmallow_dataclass import dataclass as ma_dataclass
3
+ from marshmallow_dataclass2 import dataclass as ma_dataclass
4
4
  from starlette.testclient import TestClient
5
5
 
6
6
  from starmallow import StarMallow
@@ -1,4 +1,4 @@
1
- from marshmallow_dataclass import dataclass as ma_dataclass
1
+ from marshmallow_dataclass2 import dataclass as ma_dataclass
2
2
  from starlette.responses import JSONResponse
3
3
  from starlette.testclient import TestClient
4
4
 
@@ -1,6 +1,6 @@
1
1
  import typing
2
2
 
3
- from marshmallow_dataclass import dataclass as ma_dataclass
3
+ from marshmallow_dataclass2 import dataclass as ma_dataclass
4
4
  from starlette.responses import JSONResponse
5
5
  from starlette.testclient import TestClient
6
6
 
@@ -1,6 +1,6 @@
1
1
  import typing
2
2
 
3
- from marshmallow_dataclass import dataclass as ma_dataclass
3
+ from marshmallow_dataclass2 import dataclass as ma_dataclass
4
4
  from starlette.responses import JSONResponse
5
5
  from starlette.testclient import TestClient
6
6
 
@@ -1,4 +1,4 @@
1
- from marshmallow_dataclass import dataclass as ma_dataclass
1
+ from marshmallow_dataclass2 import dataclass as ma_dataclass
2
2
  from starlette.testclient import TestClient
3
3
 
4
4
  from starmallow import APIRouter, StarMallow
@@ -5,7 +5,7 @@ from typing import Annotated, Literal, Optional, Union
5
5
  import marshmallow as ma
6
6
  import marshmallow.fields as mf
7
7
  import pytest
8
- from marshmallow_dataclass import dataclass as ma_dataclass
8
+ from marshmallow_dataclass2 import dataclass as ma_dataclass
9
9
  from starlette.testclient import TestClient
10
10
 
11
11
  from starmallow import Body, Header, Path, Query, ResolvedParam, StarMallow
@@ -4,7 +4,7 @@
4
4
  from typing import List
5
5
 
6
6
  import pytest
7
- from marshmallow_dataclass import dataclass as ma_dataclass
7
+ from marshmallow_dataclass2 import dataclass as ma_dataclass
8
8
  from starlette.testclient import TestClient
9
9
 
10
10
  from starmallow import Body, StarMallow
@@ -0,0 +1,149 @@
1
+ '''Test Resolved Params'''
2
+ from dataclasses import field
3
+ from typing import Annotated, Generic, TypeVar
4
+
5
+ import pytest
6
+ from marshmallow_dataclass2 import dataclass as ma_dataclass
7
+ from starlette.testclient import TestClient
8
+
9
+ from starmallow import Query, StarMallow
10
+
11
+ from .utils import assert_json
12
+
13
+ app = StarMallow()
14
+
15
+ T = TypeVar("T")
16
+
17
+ ############################################################
18
+ # Models - classes and schemas
19
+ ############################################################
20
+ # region - VS Code folding marker - https://code.visualstudio.com/docs/editor/codebasics#_folding
21
+
22
+
23
+ @ma_dataclass
24
+ class QueryParameters(Generic[T]):
25
+ id: T = None
26
+
27
+
28
+ @ma_dataclass
29
+ class PageableResponse(Generic[T]):
30
+ items: list[T] = field(default_factory=list)
31
+ # endregion
32
+
33
+
34
+ ############################################################
35
+ # Test API
36
+ ############################################################
37
+ # region
38
+ @app.get("/data")
39
+ def get_data(
40
+ params: Annotated[QueryParameters[int], Query()],
41
+ ) -> PageableResponse[str]:
42
+ return {'items': ['foo', 'bar']}
43
+ # endregion
44
+
45
+
46
+ ############################################################
47
+ # Tests
48
+ ############################################################
49
+ # region
50
+ client = TestClient(app)
51
+
52
+ openapi_schema = {
53
+ "openapi": "3.0.2",
54
+ "info": {"title": "StarMallow", "version": "0.1.0"},
55
+ "paths": {
56
+ "/data": {
57
+ "get": {
58
+ "responses": {
59
+ "200": {
60
+ "description": "Successful Response",
61
+ "content": {
62
+ "application/json": {
63
+ "schema": {
64
+ "$ref": "#/components/schemas/PageableResponse",
65
+ },
66
+ },
67
+ },
68
+ },
69
+ "422": {
70
+ "description": "Validation Error",
71
+ "content": {
72
+ "application/json": {
73
+ "schema": {
74
+ "$ref": "#/components/schemas/HTTPValidationError",
75
+ },
76
+ },
77
+ },
78
+ },
79
+ },
80
+ "summary": "Get Data",
81
+ "operationId": "get_data_data_get",
82
+ "parameters": [
83
+ {
84
+ "required": False,
85
+ "schema": {
86
+ "default": None,
87
+ "nullable": True,
88
+ "type": "integer",
89
+ "title": "Id",
90
+ },
91
+ "name": "id",
92
+ "in": "query",
93
+ },
94
+ ],
95
+ },
96
+ },
97
+ },
98
+ "components": {
99
+ "schemas": {
100
+ "HTTPValidationError": {
101
+ 'properties': {
102
+ 'detail': {
103
+ 'description': 'Error detail',
104
+ 'title': 'Detail',
105
+ },
106
+ 'errors': {
107
+ 'description': 'Exception or error type',
108
+ 'title': 'Errors',
109
+ },
110
+ 'status_code': {
111
+ 'description': 'HTTP status code',
112
+ 'title': 'Status Code',
113
+ 'type': 'integer',
114
+ },
115
+ },
116
+ 'required': ['detail', 'status_code'],
117
+ 'title': 'HTTPValidationError',
118
+ 'type': 'object',
119
+ },
120
+ "PageableResponse": {
121
+ "properties": {
122
+ "items": {
123
+ "items": {
124
+ "type": "string",
125
+ },
126
+ "title": "Items",
127
+ "type": "array",
128
+ },
129
+ },
130
+ "title": "PageableResponse",
131
+ "type": "object",
132
+ },
133
+ },
134
+ },
135
+ }
136
+
137
+
138
+ @pytest.mark.parametrize(
139
+ "path,expected_status,expected_response",
140
+ [
141
+ ("/data?id=50", 200, {"items": ["foo", "bar"]}),
142
+ ("/openapi.json", 200, openapi_schema),
143
+ ],
144
+ )
145
+ def test_get_path(path, expected_status, expected_response):
146
+ response = client.get(path)
147
+ assert response.status_code == expected_status
148
+ assert_json(response.json(), expected_response)
149
+ # endregion
@@ -7,7 +7,7 @@ from typing import Any, Dict, Literal, Optional, Union
7
7
  import marshmallow as ma
8
8
  import marshmallow.fields as mf
9
9
  import pytest
10
- from marshmallow_dataclass import dataclass as ma_dataclass
10
+ from marshmallow_dataclass2 import dataclass as ma_dataclass
11
11
  from starlette.background import BackgroundTasks
12
12
  from starlette.requests import HTTPConnection, Request
13
13
  from starlette.responses import Response
@@ -6,7 +6,7 @@ from uuid import UUID
6
6
 
7
7
  import marshmallow.fields as mf
8
8
  import pytest
9
- from marshmallow_dataclass import dataclass as ma_dataclass
9
+ from marshmallow_dataclass2 import dataclass as ma_dataclass
10
10
  from starlette.testclient import TestClient
11
11
 
12
12
  from starmallow import Body, StarMallow
@@ -6,7 +6,7 @@ from uuid import UUID
6
6
 
7
7
  import marshmallow.fields as mf
8
8
  import pytest
9
- from marshmallow_dataclass import dataclass as ma_dataclass
9
+ from marshmallow_dataclass2 import dataclass as ma_dataclass
10
10
  from starlette.testclient import TestClient
11
11
 
12
12
  from starmallow import Body, StarMallow
@@ -6,7 +6,7 @@ from uuid import UUID
6
6
 
7
7
  import marshmallow.fields as mf
8
8
  import pytest
9
- from marshmallow_dataclass import dataclass as ma_dataclass
9
+ from marshmallow_dataclass2 import dataclass as ma_dataclass
10
10
  from starlette.testclient import TestClient
11
11
 
12
12
  from starmallow import StarMallow
@@ -6,7 +6,7 @@ from uuid import UUID
6
6
 
7
7
  import marshmallow.fields as mf
8
8
  import pytest
9
- from marshmallow_dataclass import dataclass as ma_dataclass
9
+ from marshmallow_dataclass2 import dataclass as ma_dataclass
10
10
  from starlette.testclient import TestClient
11
11
 
12
12
  from starmallow import StarMallow
@@ -6,7 +6,7 @@ from uuid import UUID
6
6
 
7
7
  import marshmallow.fields as mf
8
8
  import pytest
9
- from marshmallow_dataclass import dataclass as ma_dataclass
9
+ from marshmallow_dataclass2 import dataclass as ma_dataclass
10
10
  from starlette.testclient import TestClient
11
11
 
12
12
  from starmallow import StarMallow
@@ -1,4 +1,4 @@
1
- from marshmallow_dataclass import dataclass as ma_dataclass
1
+ from marshmallow_dataclass2 import dataclass as ma_dataclass
2
2
  from starlette.testclient import TestClient
3
3
  from starlette.websockets import WebSocket
4
4
 
@@ -1,86 +0,0 @@
1
- '''Copied from marshmallow_dataclass, https://github.com/lovasoa/marshmallow_dataclass/blob/master/marshmallow_dataclass/union_field.py
2
- Didn't want to add the dependency to this project1
3
- '''
4
-
5
- import copy
6
- import inspect
7
- from typing import Any, List, Optional, Tuple
8
-
9
- import typeguard
10
- from marshmallow import Schema, ValidationError, fields
11
-
12
- try:
13
- from typeguard import TypeCheckError # type: ignore[attr-defined]
14
- except ImportError:
15
- # typeguard < 3
16
- TypeCheckError = TypeError # type: ignore[misc, assignment]
17
-
18
- if "argname" not in inspect.signature(typeguard.check_type).parameters:
19
-
20
- def _check_type(value, expected_type, argname: str):
21
- return typeguard.check_type(value=value, expected_type=expected_type)
22
-
23
- else:
24
- # typeguard < 3.0.0rc2
25
- def _check_type(value, expected_type, argname: str):
26
- return typeguard.check_type( # type: ignore[call-overload]
27
- value=value, expected_type=expected_type, argname=argname,
28
- )
29
-
30
-
31
- class Union(fields.Field):
32
- """A union field, composed other `Field` classes or instances.
33
- This field serializes elements based on their type, with one of its child fields.
34
-
35
- Example: ::
36
-
37
- number_or_string = UnionField([
38
- (float, fields.Float()),
39
- (str, fields.Str())
40
- ])
41
-
42
- :param union_fields: A list of types and their associated field instance.
43
- :param kwargs: The same keyword arguments that :class:`Field` receives.
44
- """
45
-
46
- def __init__(self, union_fields: List[Tuple[type, fields.Field]], **kwargs):
47
- super().__init__(**kwargs)
48
- self.union_fields = union_fields
49
-
50
- def _bind_to_schema(self, field_name: str, schema: Schema) -> None:
51
- super()._bind_to_schema(field_name, schema)
52
- new_union_fields = []
53
- for typ, field in self.union_fields:
54
- field = copy.deepcopy(field)
55
- field._bind_to_schema(field_name, self)
56
- new_union_fields.append((typ, field))
57
-
58
- self.union_fields = new_union_fields
59
-
60
- def _serialize(self, value: Any, attr: Optional[str], obj, **kwargs) -> Any:
61
- errors = []
62
- if value is None:
63
- return value
64
- for typ, field in self.union_fields:
65
- try:
66
- _check_type(value=value, expected_type=typ, argname=attr or "anonymous")
67
- return field._serialize(value, attr, obj, **kwargs)
68
- except TypeCheckError as e:
69
- errors.append(e)
70
- raise TypeError(
71
- f"Unable to serialize value with any of the fields in the union: {errors}",
72
- )
73
-
74
- def _deserialize(self, value: Any, attr: Optional[str], data, **kwargs) -> Any:
75
- errors = []
76
- for typ, field in self.union_fields:
77
- try:
78
- result = field.deserialize(value, **kwargs)
79
- _check_type(
80
- value=result, expected_type=typ, argname=attr or "anonymous",
81
- )
82
- return result
83
- except (TypeCheckError, ValidationError) as e:
84
- errors.append(e)
85
-
86
- raise ValidationError(errors)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes