9
9
from marshmallow .class_registry import get_class
10
10
from marshmallow .decorators import post_dump
11
11
from marshmallow .utils import _Missing
12
-
13
12
from marshmallow import INCLUDE , EXCLUDE , RAISE
13
+ # marshmallow.fields.Enum support has been added in marshmallow v3.18
14
+ # see https://github.com/marshmallow-code/marshmallow/blob/dev/CHANGELOG.rst#3180-2022-09-15
15
+ from marshmallow import __version__ as _MarshmallowVersion
16
+ # the package "packaging" is a requirement of marshmallow itself => we don't need to install it separately
17
+ # see https://github.com/marshmallow-code/marshmallow/blob/ddbe06f923befe754e213e03fb95be54e996403d/setup.py#L61
18
+ from packaging .version import Version
19
+
20
+
21
+ def marshmallow_version_supports_native_enums () -> bool :
22
+ """
23
+ returns true if and only if the version of marshmallow installed supports enums natively
24
+ """
25
+ return Version (_MarshmallowVersion ) >= Version ("3.18" )
26
+
14
27
15
28
try :
16
29
from marshmallow_union import Union
20
33
ALLOW_UNIONS = False
21
34
22
35
try :
23
- from marshmallow_enum import EnumField , LoadDumpOptions
36
+ from marshmallow_enum import EnumField as MarshmallowEnumEnumField , LoadDumpOptions
24
37
25
- ALLOW_ENUMS = True
38
+ ALLOW_MARSHMALLOW_ENUM_ENUMS = True
26
39
except ImportError :
27
- ALLOW_ENUMS = False
40
+ ALLOW_MARSHMALLOW_ENUM_ENUMS = False
41
+
42
+ ALLOW_MARSHMALLOW_NATIVE_ENUMS = marshmallow_version_supports_native_enums ()
43
+ if ALLOW_MARSHMALLOW_NATIVE_ENUMS :
44
+ from marshmallow .fields import Enum as MarshmallowNativeEnumField
28
45
29
46
from .exceptions import UnsupportedValueError
30
47
from .validation import (
92
109
(fields .Nested , dict ),
93
110
]
94
111
95
- if ALLOW_ENUMS :
112
+ if ALLOW_MARSHMALLOW_NATIVE_ENUMS :
113
+ MARSHMALLOW_TO_PY_TYPES_PAIRS .append ((MarshmallowNativeEnumField , Enum ))
114
+ if ALLOW_MARSHMALLOW_ENUM_ENUMS :
96
115
# We currently only support loading enum's from their names. So the possible
97
116
# values will always map to string in the JSONSchema
98
- MARSHMALLOW_TO_PY_TYPES_PAIRS .append ((EnumField , Enum ))
117
+ MARSHMALLOW_TO_PY_TYPES_PAIRS .append ((MarshmallowEnumEnumField , Enum ))
99
118
100
119
101
120
FIELD_VALIDATORS = {
@@ -191,8 +210,10 @@ def _from_python_type(self, obj, field, pytype) -> typing.Dict[str, typing.Any]:
191
210
if field .default is not missing and not callable (field .default ):
192
211
json_schema ["default" ] = field .default
193
212
194
- if ALLOW_ENUMS and isinstance (field , EnumField ):
195
- json_schema ["enum" ] = self ._get_enum_values (field )
213
+ if ALLOW_MARSHMALLOW_NATIVE_ENUMS and isinstance (field , MarshmallowNativeEnumField ):
214
+ json_schema ["enum" ] = self ._get_marshmallow_native_enum_values (field )
215
+ elif ALLOW_MARSHMALLOW_ENUM_ENUMS and isinstance (field , MarshmallowEnumEnumField ):
216
+ json_schema ["enum" ] = self ._get_marshmallow_enum_enum_values (field )
196
217
197
218
if field .allow_none :
198
219
previous_type = json_schema ["type" ]
@@ -218,8 +239,8 @@ def _from_python_type(self, obj, field, pytype) -> typing.Dict[str, typing.Any]:
218
239
)
219
240
return json_schema
220
241
221
- def _get_enum_values (self , field ) -> typing .List [str ]:
222
- assert ALLOW_ENUMS and isinstance (field , EnumField )
242
+ def _get_marshmallow_enum_enum_values (self , field ) -> typing .List [str ]:
243
+ assert ALLOW_MARSHMALLOW_ENUM_ENUMS and isinstance (field , MarshmallowEnumEnumField )
223
244
224
245
if field .load_by == LoadDumpOptions .value :
225
246
# Python allows enum values to be almost anything, so it's easier to just load from the
@@ -229,6 +250,17 @@ def _get_enum_values(self, field) -> typing.List[str]:
229
250
)
230
251
231
252
return [value .name for value in field .enum ]
253
+ def _get_marshmallow_native_enum_values (self , field ) -> typing .List [str ]:
254
+ assert ALLOW_MARSHMALLOW_NATIVE_ENUMS and isinstance (field , MarshmallowNativeEnumField )
255
+
256
+ if field .by_value :
257
+ # Python allows enum values to be almost anything, so it's easier to just load from the
258
+ # names of the enum's which will have to be strings.
259
+ raise NotImplementedError (
260
+ "Currently do not support JSON schema for enums loaded by value"
261
+ )
262
+
263
+ return [value .name for value in field .enum ]
232
264
233
265
def _from_union_schema (
234
266
self , obj , field
0 commit comments