| | |
| |
|
| | """ |
| | Commonly useful converters. |
| | """ |
| |
|
| | import typing |
| |
|
| | from ._compat import _AnnotationExtractor |
| | from ._make import NOTHING, Converter, Factory, pipe |
| |
|
| |
|
| | __all__ = [ |
| | "default_if_none", |
| | "optional", |
| | "pipe", |
| | "to_bool", |
| | ] |
| |
|
| |
|
| | def optional(converter): |
| | """ |
| | A converter that allows an attribute to be optional. An optional attribute |
| | is one which can be set to `None`. |
| | |
| | Type annotations will be inferred from the wrapped converter's, if it has |
| | any. |
| | |
| | Args: |
| | converter (typing.Callable): |
| | the converter that is used for non-`None` values. |
| | |
| | .. versionadded:: 17.1.0 |
| | """ |
| |
|
| | if isinstance(converter, Converter): |
| |
|
| | def optional_converter(val, inst, field): |
| | if val is None: |
| | return None |
| | return converter(val, inst, field) |
| |
|
| | else: |
| |
|
| | def optional_converter(val): |
| | if val is None: |
| | return None |
| | return converter(val) |
| |
|
| | xtr = _AnnotationExtractor(converter) |
| |
|
| | t = xtr.get_first_param_type() |
| | if t: |
| | optional_converter.__annotations__["val"] = typing.Optional[t] |
| |
|
| | rt = xtr.get_return_type() |
| | if rt: |
| | optional_converter.__annotations__["return"] = typing.Optional[rt] |
| |
|
| | if isinstance(converter, Converter): |
| | return Converter(optional_converter, takes_self=True, takes_field=True) |
| |
|
| | return optional_converter |
| |
|
| |
|
| | def default_if_none(default=NOTHING, factory=None): |
| | """ |
| | A converter that allows to replace `None` values by *default* or the result |
| | of *factory*. |
| | |
| | Args: |
| | default: |
| | Value to be used if `None` is passed. Passing an instance of |
| | `attrs.Factory` is supported, however the ``takes_self`` option is |
| | *not*. |
| | |
| | factory (typing.Callable): |
| | A callable that takes no parameters whose result is used if `None` |
| | is passed. |
| | |
| | Raises: |
| | TypeError: If **neither** *default* or *factory* is passed. |
| | |
| | TypeError: If **both** *default* and *factory* are passed. |
| | |
| | ValueError: |
| | If an instance of `attrs.Factory` is passed with |
| | ``takes_self=True``. |
| | |
| | .. versionadded:: 18.2.0 |
| | """ |
| | if default is NOTHING and factory is None: |
| | msg = "Must pass either `default` or `factory`." |
| | raise TypeError(msg) |
| |
|
| | if default is not NOTHING and factory is not None: |
| | msg = "Must pass either `default` or `factory` but not both." |
| | raise TypeError(msg) |
| |
|
| | if factory is not None: |
| | default = Factory(factory) |
| |
|
| | if isinstance(default, Factory): |
| | if default.takes_self: |
| | msg = "`takes_self` is not supported by default_if_none." |
| | raise ValueError(msg) |
| |
|
| | def default_if_none_converter(val): |
| | if val is not None: |
| | return val |
| |
|
| | return default.factory() |
| |
|
| | else: |
| |
|
| | def default_if_none_converter(val): |
| | if val is not None: |
| | return val |
| |
|
| | return default |
| |
|
| | return default_if_none_converter |
| |
|
| |
|
| | def to_bool(val): |
| | """ |
| | Convert "boolean" strings (for example, from environment variables) to real |
| | booleans. |
| | |
| | Values mapping to `True`: |
| | |
| | - ``True`` |
| | - ``"true"`` / ``"t"`` |
| | - ``"yes"`` / ``"y"`` |
| | - ``"on"`` |
| | - ``"1"`` |
| | - ``1`` |
| | |
| | Values mapping to `False`: |
| | |
| | - ``False`` |
| | - ``"false"`` / ``"f"`` |
| | - ``"no"`` / ``"n"`` |
| | - ``"off"`` |
| | - ``"0"`` |
| | - ``0`` |
| | |
| | Raises: |
| | ValueError: For any other value. |
| | |
| | .. versionadded:: 21.3.0 |
| | """ |
| | if isinstance(val, str): |
| | val = val.lower() |
| |
|
| | if val in (True, "true", "t", "yes", "y", "on", "1", 1): |
| | return True |
| | if val in (False, "false", "f", "no", "n", "off", "0", 0): |
| | return False |
| |
|
| | msg = f"Cannot convert value to bool: {val!r}" |
| | raise ValueError(msg) |
| |
|