File: //usr/local/CyberCP/lib/python3.10/site-packages/attr/converters.py
# SPDX-License-Identifier: MIT
"""
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)