Closed therice closed 1 year ago
Workaround appears to declare the field using dataclasses
directly instead of marshmallow_dataclass
...
from dataclasses import dataclass, field
...
@dataclass
class VersionContainer:
version : Version = field(default=None, metadata={'by_value' : True})
I think the issue is in this line:
version : Version = field_for_schema(Version, metadata={'by_value' : True})
Fields are intended to be passed as annotations for the dataclass's fields, not as defaults for them. marshmallow-dataclass sees version : Version
and makes a field called "version" and binds to it a marshmallow field constructed from the Version Enum (i.e. no custom metadata), then sets the default for that marshmallow field to field_for_schema(Version, metadata={'by_value' : True})
. We can see this behaviour by not passing any value for version when loading:
>>> @dataclass
... class VersionContainer:
... version : Version = field_for_schema(Version, metadata={'by_value' : True})
...
>>> class_schema(VersionContainer)().load({})
VersionContainer(version=<fields.Enum(dump_default=<marshmallow.missing>, attribute=None, validate=None, required=True, load_only=False, dump_only=False, load_default=<marshmallow.missing>, allow_none=False, error_messages={'required': 'Missing data for required field.', 'null': 'Field may not be null.', 'validator_failed': 'Invalid value.', 'unknown': 'Must be one of: {choices}.'})>)
The workaround you posted is just the standard/intended way to pass in extra field metadata when using this library (see https://github.com/lovasoa/marshmallow_dataclass#customizing-generated-fields). Another option if you wish to avoid this field syntax could be to use marshmallow_dataclass.NewType
instead, eg:
>>> VersionField = marshmallow_dataclass.NewType("Version", Version, field=marshmallow.fields.Enum, enum=Version, by_value=True)
>>> @dataclass
... class VersionContainer:
... version: VersionField
...
>>> class_schema(VersionContainer)().load({"version": "foo/v1"})
VersionContainer(version=<Version.v1: 'foo/v1'>)
Hope that helps! Let me know if I misunderstood the problem.
Test case which demonstrates the problem
... @dataclass class VersionContainer: version : Version = field_for_schema(Version, metadata={'by_value' : True})
This is incorrect usage of field_for_schema
. (In fact direct use of field_for_schema
is not documented.)
Workaround appears to declare the field using dataclasses directly instead of marshmallow_dataclass
from dataclasses import dataclass, field ... @dataclass class VersionContainer: version : Version = field(default=None, metadata={'by_value' : True})
This is not so much a workaround, as closer to correct usage.
Even more correct, assuming that you do not want to specify a default value for VersionContainer.version would be:
@dataclass
class VersionContainer:
version : Version = field(metadata={'by_value' : True})
I don't think this is a bug. (The immediately preceding example appears to work fine for me.) Closing. Feel free to reopen if the situation warrants.
https://github.com/lovasoa/marshmallow_dataclass/blob/cddce9a4d75003297d8697ca74cb66ab9a6c7be1/marshmallow_dataclass/__init__.py#L720
If an Enum field specifies named parameters in the declaration, these are silently dropped when loading the associated schema.
Test case which demonstrates the problem
Results of execution
Similar to #199, but after the change to replace the usage of
marshmallow-enum
inv8.5.11