1"""
2Commonly useful converters.
3"""
4
5from __future__ import absolute_import, division, print_function
6
7from ._make import NOTHING, Factory, pipe
8
9
10__all__ = [
11    "pipe",
12    "optional",
13    "default_if_none",
14]
15
16
17def optional(converter):
18    """
19    A converter that allows an attribute to be optional. An optional attribute
20    is one which can be set to ``None``.
21
22    :param callable converter: the converter that is used for non-``None``
23        values.
24
25    .. versionadded:: 17.1.0
26    """
27
28    def optional_converter(val):
29        if val is None:
30            return None
31        return converter(val)
32
33    return optional_converter
34
35
36def default_if_none(default=NOTHING, factory=None):
37    """
38    A converter that allows to replace ``None`` values by *default* or the
39    result of *factory*.
40
41    :param default: Value to be used if ``None`` is passed. Passing an instance
42       of `attr.Factory` is supported, however the ``takes_self`` option
43       is *not*.
44    :param callable factory: A callable that takes not parameters whose result
45       is used if ``None`` is passed.
46
47    :raises TypeError: If **neither** *default* or *factory* is passed.
48    :raises TypeError: If **both** *default* and *factory* are passed.
49    :raises ValueError: If an instance of `attr.Factory` is passed with
50       ``takes_self=True``.
51
52    .. versionadded:: 18.2.0
53    """
54    if default is NOTHING and factory is None:
55        raise TypeError("Must pass either `default` or `factory`.")
56
57    if default is not NOTHING and factory is not None:
58        raise TypeError(
59            "Must pass either `default` or `factory` but not both."
60        )
61
62    if factory is not None:
63        default = Factory(factory)
64
65    if isinstance(default, Factory):
66        if default.takes_self:
67            raise ValueError(
68                "`takes_self` is not supported by default_if_none."
69            )
70
71        def default_if_none_converter(val):
72            if val is not None:
73                return val
74
75            return default.factory()
76
77    else:
78
79        def default_if_none_converter(val):
80            if val is not None:
81                return val
82
83            return default
84
85    return default_if_none_converter
86