candv.ext.ValueConstant.to_primitive()   A
last analyzed

Complexity

Conditions 4

Size

Total Lines 22
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 11
nop 3
dl 0
loc 22
rs 9.85
c 0
b 0
f 0
1
"""
2
Provides extra ready-to-use classes for constructing custom constants.
3
4
"""
5
import operator
6
7
from .core import Constants
8
from .core import SimpleConstant
9
10
from .exceptions import CandvValueNotFoundError
11
12
from ._utils import export
13
14
15
@export
16
class VerboseMixin:
17
  """
18
  Adds ``verbose_name`` and ``help_text`` attributes to constants.
19
20
  Arguments must be passed as kwargs.
21
22
  :argument str verbose_name: optional verbose name
23
  :argument str help_text: optional description
24
25
  **Example**:
26
27
  .. code-block:: python
28
29
    class CustomConstant(object):
30
31
      def __init__(self, arg1, arg2, kwarg1=None):
32
        pass
33
34
35
    class VerboseCustomConstant(VerboseMixin, CustomConstant):
36
37
      def __init__(self, arg1, arg2, kwarg1=None, verbose_name=None, help_text=None):
38
        super().__init__(
39
          arg1,
40
          arg2,
41
          kwarg1=kwarg1,
42
          verbose_name=verbose_name,
43
          help_text=help_text,
44
        )
45
46
  """
47
  def __init__(self, *args, **kwargs):
48
    self.verbose_name = kwargs.pop('verbose_name', None)
49
    self.help_text = kwargs.pop('help_text', None)
50
    super().__init__(*args, **kwargs)
51
52
  def merge_into_group(self, group):
53
    """
54
    Overrides :meth:`~candv.base.Constant.merge_into_group` to add
55
    ``verbose_name`` with ``help_text`` attributes to the target group.
56
57
    """
58
    super().merge_into_group(group)
59
    group.verbose_name = self.verbose_name
60
    group.help_text = self.help_text
61
62
  def to_primitive(self, *args, **kwargs):
63
    """
64
    .. versionchanged:: 1.5.0
65
       The ``context`` param is replaced by ``*args`` and ``**kwargs``.
66
67
    .. versionadded:: 1.3.0
68
69
    """
70
    primitive = super().to_primitive(*args, **kwargs)
71
    primitive.update({
72
      'verbose_name': (
73
        str(self.verbose_name)
74
        if self.verbose_name is not None
75
        else None
76
      ),
77
      'help_text': (
78
        str(self.help_text)
79
        if self.help_text is not None
80
        else None
81
      ),
82
    })
83
    return primitive
84
85
86
@export
87
class VerboseConstant(VerboseMixin, SimpleConstant):
88
  """
89
  A constant with optional verbose name and optional help text.
90
91
  :argument str verbose_name: optional verbose name of the constant
92
  :argument str help_text: optional description of the constant
93
94
  :ivar str verbose_name: verbose name of the constant. Default: ``None``
95
  :ivar str help_text: verbose description of the constant. Default: ``None``
96
97
  """
98
  def __init__(self, verbose_name=None, help_text=None):
99
    super().__init__(verbose_name=verbose_name, help_text=help_text)
100
101
102
@export
103
class ValueConstant(SimpleConstant):
104
  """
105
  A constant with ability to hold arbitrary values.
106
107
  :argument value: a value to attach to constant
108
  :ivar value: constant's value
109
110
  """
111
  def __init__(self, value):
112
    super().__init__()
113
    self.value = value
114
115
  def merge_into_group(self, group):
116
    """
117
    Redefines :meth:`~candv.base.Constant.merge_into_group` and adds ``value``
118
    attribute to the target group.
119
120
    """
121
    super().merge_into_group(group)
122
    group.value = self.value
123
124
  def to_primitive(self, *args, **kwargs):
125
    """
126
    .. versionchanged:: 1.5.0
127
       The ``context`` param is replaced by ``*args`` and ``**kwargs``.
128
129
    .. versionadded:: 1.3.0
130
131
    """
132
    primitive = super().to_primitive(*args, **kwargs)
133
    value = self.value
134
135
    if hasattr(value, "isoformat"):
136
      value = value.isoformat()
137
138
    if hasattr(value, "to_primitive"):
139
      value = value.to_primitive(*args, **kwargs)
140
141
    elif callable(value):
142
      value = value()
143
144
    primitive['value'] = value
145
    return primitive
146
147
148
@export
149
class VerboseValueConstant(VerboseMixin, ValueConstant):
150
  """
151
  A constant which can have both verbose name, help text, and a value.
152
153
  :argument value: a value to attach to the constant
154
  :argument str verbose_name: an optional verbose name of the constant
155
  :argument str help_text: an optional description of the constant
156
157
  :ivar value: constant's value
158
  :ivar str verbose_name: verbose name of the constant. Default: ``None``
159
  :ivar str help_text: verbose description of the constant. Default: ``None``
160
161
  """
162
  def __init__(self, value, verbose_name=None, help_text=None):
163
    super().__init__(value, verbose_name=verbose_name, help_text=help_text)
164
165
166
@export
167
class Values(Constants):
168
  """
169
  A container for :class:`ValueConstant` and its derivatives.
170
171
  Supports getting and filtering constants by their values plus listing values
172
  of all constants in container.
173
174
  """
175
  constant_class = ValueConstant
176
177
  @classmethod
178
  def get_by_value(cls, value):
179
    """
180
    Get a constant by its value.
181
182
    :param value: value of the constant to look for
183
184
    :returns: first found constant with given value
185
186
    :raises CandvValueNotFoundError: if no constant in container has given value
187
188
    """
189
    for constant in cls.iterconstants():
190
      if constant.value == value:
191
        return constant
192
193
    raise CandvValueNotFoundError(
194
      "constant with value \"{0}\" is not present in \"{1}\""
195
      .format(value, cls)
196
    )
197
198
  @classmethod
199
  def filter_by_value(cls, value):
200
    """
201
    Get all constants which have given value.
202
203
    :param value: value of the constants to look for
204
    :returns: list of all found constants with given value
205
206
    """
207
    constants = []
208
209
    for constant in cls.iterconstants():
210
      if constant.value == value:
211
        constants.append(constant)
212
213
    return constants
214
215
  @classmethod
216
  def values(cls):
217
    """
218
    List values of all constants in the order they were defined.
219
220
    :returns: :class:`list` of values
221
222
    **Example**:
223
224
    .. code-block:: python
225
226
      from candv import Values
227
      from candv import ValueConstant
228
229
230
      class FOO(Values):
231
        TWO  = ValueConstant(2)
232
        ONE  = ValueConstant(1)
233
        SOME = ValueConstant("some string")
234
235
    .. code-block:: python
236
237
      >>> FOO.values()
238
      [2, 1, 'some string']
239
240
    .. note::
241
242
      Overrides :meth:`~candv.base.ConstantsContainer.values` since 1.1.2.
243
244
    """
245
    return [
246
      x.value
247
      for x in cls.iterconstants()
248
    ]
249
250
  @classmethod
251
  def itervalues(cls):
252
    """
253
    Get an iterator over values of all constants in the order they were defined.
254
255
    Same as :meth:`values` but returns an interator.
256
257
    .. note::
258
259
      Overrides :meth:`~candv.base.ConstantsContainer.itervalues` since 1.1.2.
260
261
    """
262
    return map(operator.attrgetter("value"), cls.iterconstants())
263