Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/attr/converters.py: 25%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# SPDX-License-Identifier: MIT
3"""
4Commonly useful converters.
5"""
7import typing
9from ._compat import _AnnotationExtractor
10from ._make import NOTHING, Converter, Factory, pipe
13__all__ = [
14 "default_if_none",
15 "optional",
16 "pipe",
17 "to_bool",
18]
21def optional(converter):
22 """
23 A converter that allows an attribute to be optional. An optional attribute
24 is one which can be set to `None`.
26 Type annotations will be inferred from the wrapped converter's, if it has
27 any.
29 Args:
30 converter (typing.Callable):
31 the converter that is used for non-`None` values.
33 .. versionadded:: 17.1.0
34 """
36 if isinstance(converter, Converter):
38 def optional_converter(val, inst, field):
39 if val is None:
40 return None
41 return converter(val, inst, field)
43 else:
45 def optional_converter(val):
46 if val is None:
47 return None
48 return converter(val)
50 xtr = _AnnotationExtractor(converter)
52 t = xtr.get_first_param_type()
53 if t:
54 optional_converter.__annotations__["val"] = typing.Optional[t]
56 rt = xtr.get_return_type()
57 if rt:
58 optional_converter.__annotations__["return"] = typing.Optional[rt]
60 if isinstance(converter, Converter):
61 return Converter(optional_converter, takes_self=True, takes_field=True)
63 return optional_converter
66def default_if_none(default=NOTHING, factory=None):
67 """
68 A converter that allows to replace `None` values by *default* or the result
69 of *factory*.
71 Args:
72 default:
73 Value to be used if `None` is passed. Passing an instance of
74 `attrs.Factory` is supported, however the ``takes_self`` option is
75 *not*.
77 factory (typing.Callable):
78 A callable that takes no parameters whose result is used if `None`
79 is passed.
81 Raises:
82 TypeError: If **neither** *default* or *factory* is passed.
84 TypeError: If **both** *default* and *factory* are passed.
86 ValueError:
87 If an instance of `attrs.Factory` is passed with
88 ``takes_self=True``.
90 .. versionadded:: 18.2.0
91 """
92 if default is NOTHING and factory is None:
93 msg = "Must pass either `default` or `factory`."
94 raise TypeError(msg)
96 if default is not NOTHING and factory is not None:
97 msg = "Must pass either `default` or `factory` but not both."
98 raise TypeError(msg)
100 if factory is not None:
101 default = Factory(factory)
103 if isinstance(default, Factory):
104 if default.takes_self:
105 msg = "`takes_self` is not supported by default_if_none."
106 raise ValueError(msg)
108 def default_if_none_converter(val):
109 if val is not None:
110 return val
112 return default.factory()
114 else:
116 def default_if_none_converter(val):
117 if val is not None:
118 return val
120 return default
122 return default_if_none_converter
125def to_bool(val):
126 """
127 Convert "boolean" strings (for example, from environment variables) to real
128 booleans.
130 Values mapping to `True`:
132 - ``True``
133 - ``"true"`` / ``"t"``
134 - ``"yes"`` / ``"y"``
135 - ``"on"``
136 - ``"1"``
137 - ``1``
139 Values mapping to `False`:
141 - ``False``
142 - ``"false"`` / ``"f"``
143 - ``"no"`` / ``"n"``
144 - ``"off"``
145 - ``"0"``
146 - ``0``
148 Raises:
149 ValueError: For any other value.
151 .. versionadded:: 21.3.0
152 """
153 if isinstance(val, str):
154 val = val.lower()
156 if val in (True, "true", "t", "yes", "y", "on", "1", 1):
157 return True
158 if val in (False, "false", "f", "no", "n", "off", "0", 0):
159 return False
161 msg = f"Cannot convert value to bool: {val!r}"
162 raise ValueError(msg)