Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/attr/converters.py: 29%
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"""
8import typing
10from ._compat import _AnnotationExtractor
11from ._make import NOTHING, Factory, pipe
14__all__ = [
15 "default_if_none",
16 "optional",
17 "pipe",
18 "to_bool",
19]
22def optional(converter):
23 """
24 A converter that allows an attribute to be optional. An optional attribute
25 is one which can be set to `None`.
27 Type annotations will be inferred from the wrapped converter's, if it has
28 any.
30 Args:
31 converter (typing.Callable):
32 the converter that is used for non-`None` values.
34 .. versionadded:: 17.1.0
35 """
37 def optional_converter(val):
38 if val is None:
39 return None
40 return converter(val)
42 xtr = _AnnotationExtractor(converter)
44 t = xtr.get_first_param_type()
45 if t:
46 optional_converter.__annotations__["val"] = typing.Optional[t]
48 rt = xtr.get_return_type()
49 if rt:
50 optional_converter.__annotations__["return"] = typing.Optional[rt]
52 return optional_converter
55def default_if_none(default=NOTHING, factory=None):
56 """
57 A converter that allows to replace `None` values by *default* or the result
58 of *factory*.
60 Args:
61 default:
62 Value to be used if `None` is passed. Passing an instance of
63 `attrs.Factory` is supported, however the ``takes_self`` option is
64 *not*.
66 factory (typing.Callable):
67 A callable that takes no parameters whose result is used if `None`
68 is passed.
70 Raises:
71 TypeError: If **neither** *default* or *factory* is passed.
73 TypeError: If **both** *default* and *factory* are passed.
75 ValueError:
76 If an instance of `attrs.Factory` is passed with
77 ``takes_self=True``.
79 .. versionadded:: 18.2.0
80 """
81 if default is NOTHING and factory is None:
82 msg = "Must pass either `default` or `factory`."
83 raise TypeError(msg)
85 if default is not NOTHING and factory is not None:
86 msg = "Must pass either `default` or `factory` but not both."
87 raise TypeError(msg)
89 if factory is not None:
90 default = Factory(factory)
92 if isinstance(default, Factory):
93 if default.takes_self:
94 msg = "`takes_self` is not supported by default_if_none."
95 raise ValueError(msg)
97 def default_if_none_converter(val):
98 if val is not None:
99 return val
101 return default.factory()
103 else:
105 def default_if_none_converter(val):
106 if val is not None:
107 return val
109 return default
111 return default_if_none_converter
114def to_bool(val):
115 """
116 Convert "boolean" strings (for example, from environment variables) to real
117 booleans.
119 Values mapping to `True`:
121 - ``True``
122 - ``"true"`` / ``"t"``
123 - ``"yes"`` / ``"y"``
124 - ``"on"``
125 - ``"1"``
126 - ``1``
128 Values mapping to `False`:
130 - ``False``
131 - ``"false"`` / ``"f"``
132 - ``"no"`` / ``"n"``
133 - ``"off"``
134 - ``"0"``
135 - ``0``
137 Raises:
138 ValueError: For any other value.
140 .. versionadded:: 21.3.0
141 """
142 if isinstance(val, str):
143 val = val.lower()
145 if val in (True, "true", "t", "yes", "y", "on", "1", 1):
146 return True
147 if val in (False, "false", "f", "no", "n", "off", "0", 0):
148 return False
150 msg = f"Cannot convert value to bool: {val!r}"
151 raise ValueError(msg)