Passed
Branch master (9e8f7a)
by Oleksandr
01:29
created

candv.ext   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 255
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 21
eloc 81
dl 0
loc 255
rs 10
c 0
b 0
f 0

12 Methods

Rating   Name   Duplication   Size   Complexity  
A VerboseConstant.__init__() 0 2 1
A ValueConstant.__init__() 0 3 1
A Values.get_by_value() 0 19 3
A VerboseMixin.merge_into_group() 0 9 1
A Values.itervalues() 0 13 1
A ValueConstant.merge_into_group() 0 8 1
A VerboseMixin.to_primitive() 0 18 3
A ValueConstant.to_primitive() 0 18 4
A Values.values() 0 33 1
A VerboseMixin.__init__() 0 4 1
A Values.filter_by_value() 0 16 3
A VerboseValueConstant.__init__() 0 2 1
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, context=None):
63
    """
64
    .. versionadded:: 1.3.0
65
    """
66
    primitive = super().to_primitive(context)
67
    primitive.update({
68
      'verbose_name': (
69
        str(self.verbose_name)
70
        if self.verbose_name is not None
71
        else None
72
      ),
73
      'help_text': (
74
        str(self.help_text)
75
        if self.help_text is not None
76
        else None
77
      ),
78
    })
79
    return primitive
80
81
82
@export
83
class VerboseConstant(VerboseMixin, SimpleConstant):
84
  """
85
  A constant with optional verbose name and optional help text.
86
87
  :argument str verbose_name: optional verbose name of the constant
88
  :argument str help_text: optional description of the constant
89
90
  :ivar str verbose_name: verbose name of the constant. Default: ``None``
91
  :ivar str help_text: verbose description of the constant. Default: ``None``
92
93
  """
94
  def __init__(self, verbose_name=None, help_text=None):
95
    super().__init__(verbose_name=verbose_name, help_text=help_text)
96
97
98
@export
99
class ValueConstant(SimpleConstant):
100
  """
101
  A constant with ability to hold arbitrary values.
102
103
  :argument value: a value to attach to constant
104
  :ivar value: constant's value
105
106
  """
107
  def __init__(self, value):
108
    super().__init__()
109
    self.value = value
110
111
  def merge_into_group(self, group):
112
    """
113
    Redefines :meth:`~candv.base.Constant.merge_into_group` and adds ``value``
114
    attribute to the target group.
115
116
    """
117
    super().merge_into_group(group)
118
    group.value = self.value
119
120
  def to_primitive(self, context=None):
121
    """
122
    .. versionadded:: 1.3.0
123
    """
124
    primitive = super().to_primitive(context)
125
    value = self.value
126
127
    if hasattr(value, "isoformat"):
128
      value = value.isoformat()
129
130
    if hasattr(value, "to_primitive"):
131
      value = value.to_primitive(context)
132
133
    elif callable(value):
134
      value = value()
135
136
    primitive['value'] = value
137
    return primitive
138
139
140
@export
141
class VerboseValueConstant(VerboseMixin, ValueConstant):
142
  """
143
  A constant which can have both verbose name, help text, and a value.
144
145
  :argument value: a value to attach to the constant
146
  :argument str verbose_name: an optional verbose name of the constant
147
  :argument str help_text: an optional description of the constant
148
149
  :ivar value: constant's value
150
  :ivar str verbose_name: verbose name of the constant. Default: ``None``
151
  :ivar str help_text: verbose description of the constant. Default: ``None``
152
153
  """
154
  def __init__(self, value, verbose_name=None, help_text=None):
155
    super().__init__(value, verbose_name=verbose_name, help_text=help_text)
156
157
158
@export
159
class Values(Constants):
160
  """
161
  A container for :class:`ValueConstant` and its derivatives.
162
163
  Supports getting and filtering constants by their values plus listing values
164
  of all constants in container.
165
166
  """
167
  constant_class = ValueConstant
168
169
  @classmethod
170
  def get_by_value(cls, value):
171
    """
172
    Get a constant by its value.
173
174
    :param value: value of the constant to look for
175
176
    :returns: first found constant with given value
177
178
    :raises CandvValueNotFoundError: if no constant in container has given value
179
180
    """
181
    for constant in cls.iterconstants():
182
      if constant.value == value:
183
        return constant
184
185
    raise CandvValueNotFoundError(
186
      "constant with value \"{0}\" is not present in \"{1}\""
187
      .format(value, cls)
188
    )
189
190
  @classmethod
191
  def filter_by_value(cls, value):
192
    """
193
    Get all constants which have given value.
194
195
    :param value: value of the constants to look for
196
    :returns: list of all found constants with given value
197
198
    """
199
    constants = []
200
201
    for constant in cls.iterconstants():
202
      if constant.value == value:
203
        constants.append(constant)
204
205
    return constants
206
207
  @classmethod
208
  def values(cls):
209
    """
210
    List values of all constants in the order they were defined.
211
212
    :returns: :class:`list` of values
213
214
    **Example**:
215
216
    .. code-block:: python
217
218
      from candv import Values
219
      from candv import ValueConstant
220
221
222
      class FOO(Values):
223
        TWO  = ValueConstant(2)
224
        ONE  = ValueConstant(1)
225
        SOME = ValueConstant("some string")
226
227
    .. code-block:: python
228
229
      >>> FOO.values()
230
      [2, 1, 'some string']
231
232
    .. note::
233
234
      Overrides :meth:`~candv.base.ConstantsContainer.values` since 1.1.2.
235
236
    """
237
    return [
238
      x.value
239
      for x in cls.iterconstants()
240
    ]
241
242
  @classmethod
243
  def itervalues(cls):
244
    """
245
    Get an iterator over values of all constants in the order they were defined.
246
247
    Same as :meth:`values` but returns an interator.
248
249
    .. note::
250
251
      Overrides :meth:`~candv.base.ConstantsContainer.itervalues` since 1.1.2.
252
253
    """
254
    return map(operator.attrgetter("value"), cls.iterconstants())
255