File: __init__.py

package info (click to toggle)
python-marshmallow-enum 1.5.1-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye
  • size: 140 kB
  • sloc: python: 359; sh: 8; makefile: 3
file content (117 lines) | stat: -rw-r--r-- 3,634 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
from __future__ import unicode_literals

import sys
import warnings
from enum import Enum

from marshmallow import ValidationError
from marshmallow.fields import Field

PY2 = sys.version_info.major == 2
# ugh Python 2
if PY2:
    string_types = (str, unicode)  # noqa: F821
    text_type = unicode  # noqa: F821
else:
    string_types = (str, )
    text_type = str


class LoadDumpOptions(Enum):
    value = 1
    name = 0


class EnumField(Field):
    VALUE = LoadDumpOptions.value
    NAME = LoadDumpOptions.name

    default_error_messages = {
        'by_name': 'Invalid enum member {input}',
        'by_value': 'Invalid enum value {input}',
        'must_be_string': 'Enum name must be string'
    }

    def __init__(
            self, enum, by_value=False, load_by=None, dump_by=None, error='', *args, **kwargs
    ):
        self.enum = enum
        self.by_value = by_value

        if error and any(old in error for old in ('name}', 'value}', 'choices}')):
            warnings.warn(
                "'name', 'value', and 'choices' fail inputs are deprecated,"
                "use input, names and values instead",
                DeprecationWarning,
                stacklevel=2
            )

        self.error = error

        if load_by is None:
            load_by = LoadDumpOptions.value if by_value else LoadDumpOptions.name

        if not isinstance(load_by, Enum) or load_by not in LoadDumpOptions:
            raise ValueError(
                'Invalid selection for load_by must be EnumField.VALUE or EnumField.NAME, got {}'.
                format(load_by)
            )

        if dump_by is None:
            dump_by = LoadDumpOptions.value if by_value else LoadDumpOptions.name

        if not isinstance(dump_by, Enum) or dump_by not in LoadDumpOptions:
            raise ValueError(
                'Invalid selection for load_by must be EnumField.VALUE or EnumField.NAME, got {}'.
                format(dump_by)
            )

        self.load_by = load_by
        self.dump_by = dump_by

        super(EnumField, self).__init__(*args, **kwargs)

    def _serialize(self, value, attr, obj):
        if value is None:
            return None
        elif self.dump_by == LoadDumpOptions.value:
            return value.value
        else:
            return value.name

    def _deserialize(self, value, attr, data, **kwargs):
        if value is None:
            return None
        elif self.load_by == LoadDumpOptions.value:
            return self._deserialize_by_value(value, attr, data)
        else:
            return self._deserialize_by_name(value, attr, data)

    def _deserialize_by_value(self, value, attr, data):
        try:
            return self.enum(value)
        except ValueError:
            self.fail('by_value', input=value, value=value)

    def _deserialize_by_name(self, value, attr, data):
        if not isinstance(value, string_types):
            self.fail('must_be_string', input=value, name=value)

        try:
            return getattr(self.enum, value)
        except AttributeError:
            self.fail('by_name', input=value, name=value)

    def fail(self, key, **kwargs):
        kwargs['values'] = ', '.join([text_type(mem.value) for mem in self.enum])
        kwargs['names'] = ', '.join([mem.name for mem in self.enum])

        if self.error:
            if self.by_value:
                kwargs['choices'] = kwargs['values']
            else:
                kwargs['choices'] = kwargs['names']
            msg = self.error.format(**kwargs)
            raise ValidationError(msg)
        else:
            super(EnumField, self).fail(key, **kwargs)