Skip to content

Reference

Core types

Bases: Generic[T]

Holds a successfully computed / present value.

Methods mirror those on _Nothing, but actually apply the provided transformations. Failures during mapping or binding gracefully degrade to Nothing.

Parameters

value : T The wrapped payload.

Truthiness

Evaluates to True in boolean context:

>>> bool(just(0))
True

Transformations

fmap(fn): Apply a pure function, catching exceptions -> Maybe bind(fn): Chain a Maybe-returning function, validating return type

Source code in src/talvez/core.py
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
@dataclass(frozen=True)
class Just(Generic[T]):
    """
    Holds a successfully computed / present value.

    Methods mirror those on `_Nothing`, but actually apply the provided
    transformations. Failures during mapping or binding gracefully degrade
    to `Nothing`.

    Parameters
    ----------
    value : T
        The wrapped payload.

    Truthiness
    ----------
    Evaluates to True in boolean context:
    ```pycon
    >>> bool(just(0))
    True
    ```

    Transformations
    ---------------
    fmap(fn): Apply a pure function, catching exceptions -> Maybe
    bind(fn): Chain a Maybe-returning function, validating return type
    """

    value: T

    def __repr__(self) -> str:  # pragma: no cover - trivial
        return f"Just({self.value!r})"

    def __bool__(self) -> bool:
        return True

    # Transformations -------------------------------------------------

    def fmap(self, fn: Callable[[T], U]) -> "Maybe[U]":
        """
        Apply a pure function to the contained value.

        Exceptions raised by `fn` cause the result to become `Nothing`.

        Parameters
        ----------
        fn : Callable[[T], U]
            Pure transformation function.

        Returns
        -------
        Maybe[U]
            Just of transformed value, or Nothing on exception.
        """
        try:
            return just(fn(self.value))
        except Exception:
            return Nothing

    def bind(self, fn: Callable[[T], "Maybe[U]"]) -> "Maybe[U]":
        """
        Chain a function returning another Maybe (monadic bind).

        Enforces that `fn` returns either a `Just` or `Nothing`; any
        other return type results in `Nothing`.

        Parameters
        ----------
        fn : Callable[[T], Maybe[U]]
            Function returning a Maybe.

        Returns
        -------
        Maybe[U]
            Result of `fn(self.value)` or Nothing on error / type mismatch.

        Raises
        ------
        (internally caught)
            Any exception from `fn` results in Nothing.
        """
        try:
            result = fn(self.value)
            if not isinstance(result, (Just, _Nothing)):
                raise TypeError("bind function must return a Maybe")
            return result
        except Exception:
            return Nothing

    # Extraction ------------------------------------------------------

    def get_or(self, default: U) -> Union[T, U]:
        """
        Return the wrapped value (ignoring the default).

        Provided for API symmetry with `_Nothing.get_or`.

        Parameters
        ----------
        default : U
            (Unused) placeholder for symmetry.

        Returns
        -------
        T
            The contained value.
        """
        return self.value

    def to_optional(self) -> Optional[T]:
        """
        Convert to a standard Optional (always the underlying value here).

        Returns
        -------
        Optional[T]
            The contained value (never None unless it was explicitly None).
        """
        return self.value

    # Introspection ---------------------------------------------------

    @property
    def is_nothing(self) -> bool:
        """Return False (this is a Just)."""
        return False

    @property
    def is_just(self) -> bool:
        """Return True (this is a Just)."""
        return True

is_just property

Return True (this is a Just).

is_nothing property

Return False (this is a Just).

bind(fn)

Chain a function returning another Maybe (monadic bind).

Enforces that fn returns either a Just or Nothing; any other return type results in Nothing.

Parameters

fn : Callable[[T], Maybe[U]] Function returning a Maybe.

Returns

Maybe[U] Result of fn(self.value) or Nothing on error / type mismatch.

Raises

(internally caught) Any exception from fn results in Nothing.

Source code in src/talvez/core.py
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
def bind(self, fn: Callable[[T], "Maybe[U]"]) -> "Maybe[U]":
    """
    Chain a function returning another Maybe (monadic bind).

    Enforces that `fn` returns either a `Just` or `Nothing`; any
    other return type results in `Nothing`.

    Parameters
    ----------
    fn : Callable[[T], Maybe[U]]
        Function returning a Maybe.

    Returns
    -------
    Maybe[U]
        Result of `fn(self.value)` or Nothing on error / type mismatch.

    Raises
    ------
    (internally caught)
        Any exception from `fn` results in Nothing.
    """
    try:
        result = fn(self.value)
        if not isinstance(result, (Just, _Nothing)):
            raise TypeError("bind function must return a Maybe")
        return result
    except Exception:
        return Nothing

fmap(fn)

Apply a pure function to the contained value.

Exceptions raised by fn cause the result to become Nothing.

Parameters

fn : Callable[[T], U] Pure transformation function.

Returns

Maybe[U] Just of transformed value, or Nothing on exception.

Source code in src/talvez/core.py
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
def fmap(self, fn: Callable[[T], U]) -> "Maybe[U]":
    """
    Apply a pure function to the contained value.

    Exceptions raised by `fn` cause the result to become `Nothing`.

    Parameters
    ----------
    fn : Callable[[T], U]
        Pure transformation function.

    Returns
    -------
    Maybe[U]
        Just of transformed value, or Nothing on exception.
    """
    try:
        return just(fn(self.value))
    except Exception:
        return Nothing

get_or(default)

Return the wrapped value (ignoring the default).

Provided for API symmetry with _Nothing.get_or.

Parameters

default : U (Unused) placeholder for symmetry.

Returns

T The contained value.

Source code in src/talvez/core.py
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
def get_or(self, default: U) -> Union[T, U]:
    """
    Return the wrapped value (ignoring the default).

    Provided for API symmetry with `_Nothing.get_or`.

    Parameters
    ----------
    default : U
        (Unused) placeholder for symmetry.

    Returns
    -------
    T
        The contained value.
    """
    return self.value

to_optional()

Convert to a standard Optional (always the underlying value here).

Returns

Optional[T] The contained value (never None unless it was explicitly None).

Source code in src/talvez/core.py
250
251
252
253
254
255
256
257
258
259
def to_optional(self) -> Optional[T]:
    """
    Convert to a standard Optional (always the underlying value here).

    Returns
    -------
    Optional[T]
        The contained value (never None unless it was explicitly None).
    """
    return self.value

Wrap a raw value into a Just.

Parameters

a : T Value to wrap.

Returns

Just[T] A Maybe representing presence.

Source code in src/talvez/core.py
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
def just(a: T) -> Just[T]:
    """
    Wrap a raw value into a `Just`.

    Parameters
    ----------
    a : T
        Value to wrap.

    Returns
    -------
    Just[T]
        A Maybe representing presence.
    """
    return Just(a)

Obtain the Nothing sentinel.

Returns

_Nothing The shared singleton representing absence.

Source code in src/talvez/core.py
297
298
299
300
301
302
303
304
305
306
def nothing() -> _Nothing:
    """
    Obtain the `Nothing` sentinel.

    Returns
    -------
    _Nothing
        The shared singleton representing absence.
    """
    return Nothing

Convert a standard Optional into a Maybe.

Parameters

opt : Optional[T] An optional value (None indicates absence).

Returns

Maybe[T] Just(opt) if not None, else Nothing.

Source code in src/talvez/core.py
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
def from_optional(opt: Optional[T]) -> Maybe[T]:
    """
    Convert a standard Optional into a Maybe.

    Parameters
    ----------
    opt : Optional[T]
        An optional value (None indicates absence).

    Returns
    -------
    Maybe[T]
        `Just(opt)` if not None, else `Nothing`.
    """
    return nothing() if opt is None else just(opt)

Turn an iterator of Maybe values into a Maybe of a list.

Short-circuits to Nothing if any element is Nothing; otherwise collects unwrapped values into a list.

Parameters

maybes : Iterator[Maybe[T]] Iterator yielding Maybe values.

Returns

Maybe[list[T]] Just of collected values if all succeed, else Nothing.

Examples

>>> sequence(iter([just(1), just(2)])).get_or([])
[1, 2]
>>> sequence(iter([just(1), nothing(), just(3)])).is_nothing
True
Source code in src/talvez/core.py
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
def sequence(maybes: Iterator[Maybe[T]]) -> Maybe[list[T]]:
    """
    Turn an iterator of Maybe values into a Maybe of a list.

    Short-circuits to `Nothing` if any element is `Nothing`; otherwise
    collects unwrapped values into a list.

    Parameters
    ----------
    maybes : Iterator[Maybe[T]]
        Iterator yielding Maybe values.

    Returns
    -------
    Maybe[list[T]]
        Just of collected values if all succeed, else Nothing.

    Examples
    --------
    ```pycon
    >>> sequence(iter([just(1), just(2)])).get_or([])
    [1, 2]
    >>> sequence(iter([just(1), nothing(), just(3)])).is_nothing
    True
    ```
    """
    out: list[T] = []
    for m in maybes:
        if isinstance(m, _Nothing):
            return Nothing
        out.append(m.value)  # type: ignore[attr-defined]
    return just(out)

Decorators

Decorator factory: wrap a function so it returns a Maybe (Just / Nothing).

The wrapped function is executed inside a protective layer that
  1. Captures exceptions -> returns Nothing
  2. Optionally treats warnings as failures (allow_warning=False)
  3. Applies an ensure predicate to the result; non-True -> Nothing
  4. Returns Just(result) on success

IMPORTANT: The ensure predicate must return the literal boolean True for acceptance. Returning any other truthy object (e.g., 1, non-empty list) will be considered failure because talvez.predicates.not_true checks for identity with True. This enforces discipline and avoids accidental truthiness bugs.

Parameters

ensure : Optional[Callable[[Any], bool]], default=None Predicate applied to the successful raw result. If omitted, all results are accepted. If the predicate raises an exception or returns anything other than the literal True, the outcome becomes Nothing. allow_warning : bool, default=False If False, any warning raised during execution causes the decorator to return Nothing. If True, warnings are ignored.

Returns

Callable[[Callable[..., T]], Callable[..., Maybe[T]]] A decorator that transforms a function returning T into one returning Maybe[T].

Examples

>>> from talvez import just, nothing
>>> @maybe()
... def parse_int(s: str) -> int:
...     return int(s)
...
>>> parse_int("10").get_or(None)
10
>>> parse_int("x").is_nothing
True

With an ensure predicate:

>>> @maybe(ensure=lambda v: v > 0)
... def delta(x): return x - 1
...
>>> delta(5).is_just
True
>>> delta(0).is_nothing   # ensure failed (returns -1)
True

Handling warnings:

>>> import warnings
>>> @maybe(allow_warning=False)
... def risky():
...     warnings.warn("deprecated")
...     return 42
...
>>> risky().is_nothing
True
>>> @maybe(allow_warning=True)
... def tolerant():
...     warnings.warn("deprecated")
...     return 42
...
>>> tolerant().get_or(None)
42

Edge Cases

  • Exception in function: returns Nothing
  • Exception in ensure predicate: returns Nothing
  • Warning + allow_warning=False: returns Nothing
  • Function returns None and ensure not provided: wraps as Just(None) (use ensure to reject None if undesired).
Source code in src/talvez/wrappers.py
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
def maybe(
    ensure: Optional[Callable[[Any], bool]] = None,
    allow_warning: bool = False
):
    """
    Decorator factory: wrap a function so it returns a Maybe (Just / Nothing).

    The wrapped function is executed inside a protective layer that:
      1. Captures exceptions -> returns `Nothing`
      2. Optionally treats warnings as failures (`allow_warning=False`)
      3. Applies an `ensure` predicate to the result; non-True -> `Nothing`
      4. Returns `Just(result)` on success

    IMPORTANT: The `ensure` predicate must return the literal boolean `True`
    for acceptance. Returning any other truthy object (e.g., 1, non-empty list)
    will be considered failure because `talvez.predicates.not_true` checks for
    identity with `True`. This enforces discipline and avoids accidental
    truthiness bugs.

    Parameters
    ----------
    ensure : Optional[Callable[[Any], bool]], default=None
        Predicate applied to the successful raw result. If omitted, all results
        are accepted. If the predicate raises an exception or returns anything
        other than the literal `True`, the outcome becomes `Nothing`.
    allow_warning : bool, default=False
        If False, any warning raised during execution causes the decorator to
        return `Nothing`. If True, warnings are ignored.

    Returns
    -------
    Callable[[Callable[..., T]], Callable[..., Maybe[T]]]
        A decorator that transforms a function returning T into one returning
        `Maybe[T]`.

    Examples
    --------
    ```pycon
    >>> from talvez import just, nothing
    >>> @maybe()
    ... def parse_int(s: str) -> int:
    ...     return int(s)
    ...
    >>> parse_int("10").get_or(None)
    10
    >>> parse_int("x").is_nothing
    True
    ```

    With an ensure predicate:

    ```pycon
    >>> @maybe(ensure=lambda v: v > 0)
    ... def delta(x): return x - 1
    ...
    >>> delta(5).is_just
    True
    >>> delta(0).is_nothing   # ensure failed (returns -1)
    True
    ```

    Handling warnings:

    ```pycon
    >>> import warnings
    >>> @maybe(allow_warning=False)
    ... def risky():
    ...     warnings.warn("deprecated")
    ...     return 42
    ...
    >>> risky().is_nothing
    True
    >>> @maybe(allow_warning=True)
    ... def tolerant():
    ...     warnings.warn("deprecated")
    ...     return 42
    ...
    >>> tolerant().get_or(None)
    42
    ```

    Edge Cases
    ----------
    - Exception in function: returns `Nothing`
    - Exception in ensure predicate: returns `Nothing`
    - Warning + allow_warning=False: returns `Nothing`
    - Function returns None and ensure not provided: wraps as Just(None)
      (use ensure to reject None if undesired).
    """
    ensure_fn = ensure if ensure is not None else (lambda a: True)

    def deco(f: Callable[..., T]):
        @wraps(f)
        def wrapped(*args, **kwargs) -> Maybe[T]:
            try:
                result = _with_warning_capture(lambda: f(*args, **kwargs), allow_warning)
            except Exception:
                return nothing()
            try:
                if not_true(ensure_fn(result)):
                    return nothing()
            except Exception:
                return nothing()
            return just(result)
        return wrapped
    return deco

Decorator factory: wrap a function so it returns a raw value with fallback.

Unlike maybe, this returns the successful result directly, or a user-specified default on failure. Failure conditions mirror maybe: - Exception raised - Warning emitted (if allow_warning=False) - Ensure predicate not returning literal True - Ensure predicate raising an exception

Parameters

default : Any The value returned when the wrapped function "fails". Should be a sensible sentinel consistent with your domain. ensure : Optional[Callable[[Any], bool]], default=None Predicate validating the raw result. Must return the literal True to accept; any other outcome triggers the fallback. allow_warning : bool, default=False If False, any warning turns the result into default. If True, warnings are ignored.

Returns

Callable[[Callable[..., T]], Callable[..., Any]] A decorator that converts a function returning T into one returning T-or-default.

Examples

>>> @perhaps(default=0)
... def safe_div(a, b): return a / b
...
>>> safe_div(10, 2)
5.0
>>> safe_div(10, 0)
0

With ensure:

>>> @perhaps(default=None, ensure=lambda v: v > 10)
... def compute(x): return x * 3
...
>>> compute(5)
15
>>> compute(3)  # 3*3 = 9 -> ensure fails
None

Warning handling:

>>> import warnings
>>> @perhaps(default=-1, allow_warning=False)
... def noisy():
...     warnings.warn("careful")
...     return 99
...
>>> noisy()
-1

Design Rationale

Use perhaps when you want ergonomic fallback semantics without having to manipulate a Maybe object explicitly, for contexts where sentinel defaults are acceptable and clearly documented.

Edge Cases

  • If the function legitimately returns a value equal to default, you cannot distinguish fallback vs success—choose a unique sentinel if needed.
  • As with maybe, ensure must return literal True (not just truthy).
Source code in src/talvez/wrappers.py
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
def perhaps(
    default: Any,
    ensure: Optional[Callable[[Any], bool]] = None,
    allow_warning: bool = False
):
    """
    Decorator factory: wrap a function so it returns a raw value with fallback.

    Unlike `maybe`, this returns the successful result directly, or a
    user-specified `default` on failure. Failure conditions mirror `maybe`:
      - Exception raised
      - Warning emitted (if `allow_warning=False`)
      - Ensure predicate not returning literal True
      - Ensure predicate raising an exception

    Parameters
    ----------
    default : Any
        The value returned when the wrapped function "fails". Should be a
        sensible sentinel consistent with your domain.
    ensure : Optional[Callable[[Any], bool]], default=None
        Predicate validating the raw result. Must return the literal True to
        accept; any other outcome triggers the fallback.
    allow_warning : bool, default=False
        If False, any warning turns the result into `default`. If True, warnings
        are ignored.

    Returns
    -------
    Callable[[Callable[..., T]], Callable[..., Any]]
        A decorator that converts a function returning T into one returning
        T-or-default.

    Examples
    --------
    ```pycon
    >>> @perhaps(default=0)
    ... def safe_div(a, b): return a / b
    ...
    >>> safe_div(10, 2)
    5.0
    >>> safe_div(10, 0)
    0
    ```

    With ensure:

    ```pycon
    >>> @perhaps(default=None, ensure=lambda v: v > 10)
    ... def compute(x): return x * 3
    ...
    >>> compute(5)
    15
    >>> compute(3)  # 3*3 = 9 -> ensure fails
    None
    ```

    Warning handling:

    ```pycon
    >>> import warnings
    >>> @perhaps(default=-1, allow_warning=False)
    ... def noisy():
    ...     warnings.warn("careful")
    ...     return 99
    ...
    >>> noisy()
    -1
    ```

    Design Rationale
    ----------------
    Use `perhaps` when you want ergonomic fallback semantics without having to
    manipulate a Maybe object explicitly, for contexts where sentinel defaults
    are acceptable and clearly documented.

    Edge Cases
    ----------
    - If the function legitimately returns a value equal to `default`, you
      cannot distinguish fallback vs success—choose a unique sentinel if needed.
    - As with `maybe`, ensure must return literal True (not just truthy).
    """
    ensure_fn = ensure if ensure is not None else (lambda a: True)

    def deco(f: Callable[..., T]):
        @wraps(f)
        def wrapped(*args, **kwargs) -> Any:
            try:
                result = _with_warning_capture(lambda: f(*args, **kwargs), allow_warning)
            except Exception:
                return default
            try:
                if not_true(ensure_fn(result)):
                    return default
            except Exception:
                return default
            return result
        return wrapped
    return deco

ensure predicate behavior

The ensure callable MUST return the literal boolean True (not just a truthy value) for a result to be accepted. Anything else (False, 1, [], object()) is treated as failure. This is enforced via the not_true predicate for defensive programming.

Choosing between maybe() and perhaps()

  • Use @maybe() when you want explicit Just / Nothing handling.
  • Use @perhaps(default=...) when a sentinel fallback is more ergonomic.

Composition and chaining

Sequentially apply a series of Maybe-producing functions, short-circuiting on the first failure.

This function implements a left-to-right monadic bind chain. It starts with an initial Maybe m and applies each function in fns to the unwrapped value of the current Just (via bind). If at any point the current value is Nothing, evaluation stops early and Nothing is returned.

Parameters

m : Maybe[Any] The initial Maybe value (typically just(x) or nothing()). *fns : Callable[[Any], Maybe[Any]] A variadic sequence of functions. Each function must accept the unwrapped value from the previous Just and return a new Maybe.

Returns

Maybe[Any] The resulting Maybe after applying all functions, or the first Nothing encountered.

Notes

  • This is analogous to a fold/ reduce over monadic bind operations.
  • Functions are only invoked if the current accumulator is a Just.
  • Any function returning Nothing halts further processing.

Examples

>>> from talvez import just, nothing
>>> def parse_int(s: str):
...     try:
...         return just(int(s))
...     except ValueError:
...         return nothing()
...
>>> def reciprocal(x: int):
...     return nothing() if x == 0 else just(1 / x)
...
>>> chain(just("10"), parse_int, reciprocal).get_or(None)
0.1
>>> chain(just("foo"), parse_int, reciprocal).is_nothing
True

Edge Cases

  • Passing no functions: returns the original m.
  • If m is already Nothing, no functions are executed.
Source code in src/talvez/ops.py
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
def chain(m: Maybe[Any], *fns: Callable[[Any], Maybe[Any]]) -> Maybe[Any]:
    """
    Sequentially apply a series of Maybe-producing functions, short-circuiting on the first failure.

    This function implements a left-to-right monadic bind chain. It starts with an
    initial Maybe `m` and applies each function in `fns` to the unwrapped value
    of the current `Just` (via `bind`). If at any point the current value is
    `Nothing`, evaluation stops early and `Nothing` is returned.

    Parameters
    ----------
    m : Maybe[Any]
        The initial Maybe value (typically `just(x)` or `nothing()`).
    *fns : Callable[[Any], Maybe[Any]]
        A variadic sequence of functions. Each function must accept the unwrapped
        value from the previous `Just` and return a new `Maybe`.

    Returns
    -------
    Maybe[Any]
        The resulting Maybe after applying all functions, or the first `Nothing`
        encountered.

    Notes
    -----
    - This is analogous to a fold/ reduce over monadic bind operations.
    - Functions are only invoked if the current accumulator is a `Just`.
    - Any function returning `Nothing` halts further processing.

    Examples
    --------
    ```pycon
    >>> from talvez import just, nothing
    >>> def parse_int(s: str):
    ...     try:
    ...         return just(int(s))
    ...     except ValueError:
    ...         return nothing()
    ...
    >>> def reciprocal(x: int):
    ...     return nothing() if x == 0 else just(1 / x)
    ...
    >>> chain(just("10"), parse_int, reciprocal).get_or(None)
    0.1
    >>> chain(just("foo"), parse_int, reciprocal).is_nothing
    True
    ```

    Edge Cases
    ----------
    - Passing no functions: returns the original `m`.
    - If `m` is already `Nothing`, no functions are executed.
    """
    current: Maybe[Any] = m
    for fn in fns:
        if current.is_nothing:  # type: ignore[attr-defined]
            break
        current = current.bind(fn)  # type: ignore[arg-type]
    return current

Compose multiple Maybe-producing functions into a reusable pipeline.

Returns a new function that expects an initial Maybe and applies the provided functions in order using chain. This is useful when you want to define a processing pipeline once and reuse it across different starting values.

Parameters

*fns : Callable[[Any], Maybe[Any]] A sequence of functions, each taking a plain (unwrapped) value and returning a Maybe.

Returns

Callable[[Maybe[Any]], Maybe[Any]] A function that, given an initial Maybe, applies the pipeline.

Examples

>>> from talvez import just, nothing
>>> def non_empty(s: str):
...     return just(s) if s else nothing()
...
>>> def to_int(s: str):
...     try:
...         return just(int(s))
...     except ValueError:
...         return nothing()
...
>>> def positive(x: int):
...         return just(x) if x > 0 else nothing()
...
>>> pipeline = compose_maybe(non_empty, to_int, positive)
>>> pipeline(just("42")).get_or(None)
42
>>> pipeline(just("")).is_nothing
True
>>> pipeline(just("-5")).is_nothing
True

Comparison

This: pipeline = compose_maybe(f1, f2, f3) result = pipeline(just(x)) Is equivalent to: result = chain(just(x), f1, f2, f3)

Edge Cases

  • If no functions are provided, the returned runner is the identity on Maybe.
  • Fail-fast semantics are inherited from chain.
Source code in src/talvez/ops.py
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
def compose_maybe(*fns: Callable[[Any], Maybe[Any]]):
    """
    Compose multiple Maybe-producing functions into a reusable pipeline.

    Returns a new function that expects an initial `Maybe` and applies the
    provided functions in order using `chain`. This is useful when you want to
    define a processing pipeline once and reuse it across different starting
    values.

    Parameters
    ----------
    *fns : Callable[[Any], Maybe[Any]]
        A sequence of functions, each taking a plain (unwrapped) value and
        returning a `Maybe`.

    Returns
    -------
    Callable[[Maybe[Any]], Maybe[Any]]
        A function that, given an initial `Maybe`, applies the pipeline.

    Examples
    --------
    ```pycon
    >>> from talvez import just, nothing
    >>> def non_empty(s: str):
    ...     return just(s) if s else nothing()
    ...
    >>> def to_int(s: str):
    ...     try:
    ...         return just(int(s))
    ...     except ValueError:
    ...         return nothing()
    ...
    >>> def positive(x: int):
    ...         return just(x) if x > 0 else nothing()
    ...
    >>> pipeline = compose_maybe(non_empty, to_int, positive)
    >>> pipeline(just("42")).get_or(None)
    42
    >>> pipeline(just("")).is_nothing
    True
    >>> pipeline(just("-5")).is_nothing
    True
    ```

    Comparison
    ----------
    This:
        pipeline = compose_maybe(f1, f2, f3)
        result = pipeline(just(x))
    Is equivalent to:
        result = chain(just(x), f1, f2, f3)

    Edge Cases
    ----------
    - If no functions are provided, the returned runner is the identity on `Maybe`.
    - Fail-fast semantics are inherited from `chain`.
    """
    def runner(m: Maybe[Any]) -> Maybe[Any]:
        return chain(m, *fns)
    return runner

Predicates

Return True if the argument is NOT the literal boolean True.

This helper is intentionally strict: it only treats the single object True as true-ish for the negation test. Any other truthy value (e.g., 1, "yes", non‑empty containers) returns True because it is not the singleton True.

Parameters

x : Any Value to test for identity with the boolean True.

Returns

bool False only when x is True; True otherwise.

Examples

>>> not_true(True)
False
>>> not_true(False)
True
>>> not_true(1)
True
>>> not_true("anything")
True

Notes

This function is used internally to implement other predicates without conflating general truthiness with strict identity to True.

Source code in src/talvez/predicates.py
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
def not_true(x: Any) -> bool:
    """
    Return True if the argument is NOT the literal boolean True.

    This helper is intentionally strict: it only treats the single object `True`
    as true-ish for the negation test. Any other truthy value (e.g., 1, "yes",
    non‑empty containers) returns True because it is not the singleton `True`.

    Parameters
    ----------
    x : Any
        Value to test for identity with the boolean `True`.

    Returns
    -------
    bool
        False only when `x is True`; True otherwise.

    Examples
    --------
    ```pycon
    >>> not_true(True)
    False
    >>> not_true(False)
    True
    >>> not_true(1)
    True
    >>> not_true("anything")
    True
    ```

    Notes
    -----
    This function is used internally to implement other predicates without
    conflating general truthiness with strict identity to `True`.
    """
    return not (x is True)

Return True if the value is not None.

Parameters

a : Any Value to check.

Returns

bool True if a is not None, False otherwise.

Examples

>>> not_null(None)
False
>>> not_null(0)
True
>>> not_null("")
True
Source code in src/talvez/predicates.py
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
def not_null(a: Any) -> bool:
    """
    Return True if the value is not None.

    Parameters
    ----------
    a : Any
        Value to check.

    Returns
    -------
    bool
        True if `a is not None`, False otherwise.

    Examples
    --------
    ```pycon
    >>> not_null(None)
    False
    >>> not_null(0)
    True
    >>> not_null("")
    True
    ```
    """
    # Intentionally phrased via not_true for internal stylistic consistency.
    return not_true(a is None)

Return True if the value is NOT a floating-point NaN (Not-a-Number).

Parameters

a : Any Value to check. Only floats are considered; other types return True.

Returns

bool False only when a is a float and math.isnan(a) is True.

Examples

>>> not_nan(float("nan"))
False
>>> not_nan(3.14)
True
>>> not_nan("nan")
True
Source code in src/talvez/predicates.py
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
def not_nan(a: Any) -> bool:
    """
    Return True if the value is NOT a floating-point NaN (Not-a-Number).

    Parameters
    ----------
    a : Any
        Value to check. Only floats are considered; other types return True.

    Returns
    -------
    bool
        False only when `a` is a float and `math.isnan(a)` is True.

    Examples
    --------
    ```pycon
    >>> not_nan(float("nan"))
    False
    >>> not_nan(3.14)
    True
    >>> not_nan("nan")
    True
    ```
    """
    return not (isinstance(a, float) and math.isnan(a))

Return True if the value is not positive or negative infinity.

Parameters

a : Any Value to check. Only ints/floats are considered for +/- infinity.

Returns

bool False when a is +inf or -inf (as a numeric); True otherwise.

Examples

>>> not_infinite(float("inf"))
False
>>> not_infinite(float("-inf"))
False
>>> not_infinite(42)
True
>>> not_infinite("inf")
True
Source code in src/talvez/predicates.py
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
def not_infinite(a: Any) -> bool:
    """
    Return True if the value is not positive or negative infinity.

    Parameters
    ----------
    a : Any
        Value to check. Only ints/floats are considered for +/- infinity.

    Returns
    -------
    bool
        False when `a` is +inf or -inf (as a numeric); True otherwise.

    Examples
    --------
    ```pycon
    >>> not_infinite(float("inf"))
    False
    >>> not_infinite(float("-inf"))
    False
    >>> not_infinite(42)
    True
    >>> not_infinite("inf")
    True
    ```
    """
    return not (isinstance(a, (float, int)) and (a == float("inf") or a == float("-inf")))

Composite predicate: value is neither None, NaN, nor infinite.

This is a convenience aggregator combining
  • not_null
  • not_nan
  • not_infinite

Parameters

a : Any Value to test.

Returns

bool True only if all component predicates pass.

Examples

>>> not_undefined(None)
False
>>> not_undefined(float("nan"))
False
>>> not_undefined(float("inf"))
False
>>> not_undefined(0)
True
Source code in src/talvez/predicates.py
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
def not_undefined(a: Any) -> bool:
    """
    Composite predicate: value is neither None, NaN, nor infinite.

    This is a convenience aggregator combining:
      - not_null
      - not_nan
      - not_infinite

    Parameters
    ----------
    a : Any
        Value to test.

    Returns
    -------
    bool
        True only if all component predicates pass.

    Examples
    --------
    ```pycon
    >>> not_undefined(None)
    False
    >>> not_undefined(float("nan"))
    False
    >>> not_undefined(float("inf"))
    False
    >>> not_undefined(0)
    True
    ```
    """
    return all([
        not_null(a),
        not_nan(a),
        not_infinite(a),
    ])

Return True if the object has a length > 0, or if it has no length concept.

Semantics
  • If the object implements len, returns len(a) > 0.
  • If it does not (AttributeError / TypeError), treats it as "not empty" and returns True (optimistic / permissive behavior).

Parameters

a : Any Value or container to check.

Returns

bool False only when a length can be determined AND that length is 0.

Examples

>>> not_empty([])
False
>>> not_empty([1])
True
>>> not_empty("")
False
>>> not_empty("hi")
True
>>> class NoLen: pass
>>> not_empty(NoLen())
True  # no length concept -> considered not empty

Notes

Choosing to treat objects without a length as "not empty" avoids false negatives on scalar values; adjust if your domain requires stricter checks.

Source code in src/talvez/predicates.py
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
def not_empty(a: Any) -> bool:
    """
    Return True if the object has a length > 0, or if it has no length concept.

    Semantics:
      - If the object implements __len__, returns len(a) > 0.
      - If it does not (AttributeError / TypeError), treats it as "not empty"
        and returns True (optimistic / permissive behavior).

    Parameters
    ----------
    a : Any
        Value or container to check.

    Returns
    -------
    bool
        False only when a length can be determined AND that length is 0.

    Examples
    --------
    ```pycon
    >>> not_empty([])
    False
    >>> not_empty([1])
    True
    >>> not_empty("")
    False
    >>> not_empty("hi")
    True
    >>> class NoLen: pass
    >>> not_empty(NoLen())
    True  # no length concept -> considered not empty
    ```

    Notes
    -----
    Choosing to treat objects without a length as "not empty" avoids false
    negatives on scalar values; adjust if your domain requires stricter checks.
    """
    try:
        return len(a) > 0  # type: ignore[arg-type]
    except Exception:
        return True

Logical combinators

Logical AND combinator for predicates.

Returns a new predicate that evaluates each provided predicate in order. Short-circuits and returns False on the first predicate that does NOT strictly return the boolean True (identity check). Any truthy non-True value (e.g. 1) is considered a failure, enforcing discipline in predicate implementations.

Parameters

*preds : Predicate Predicates of signature (Any) -> bool.

Returns

Predicate Composite predicate representing logical conjunction.

Examples

>>> p = and_(not_null, not_nan, not_infinite)
>>> p(10)
True
>>> p(float("nan"))
False
>>> p(None)
False

Edge Cases

  • No predicates: returns a predicate that always returns True.
Source code in src/talvez/predicates.py
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
def and_(*preds: Predicate) -> Predicate:
    """
    Logical AND combinator for predicates.

    Returns a new predicate that evaluates each provided predicate in order.
    Short-circuits and returns False on the first predicate that does NOT
    strictly return the boolean True (identity check). Any truthy non-True
    value (e.g. 1) is considered a failure, enforcing discipline in predicate
    implementations.

    Parameters
    ----------
    *preds : Predicate
        Predicates of signature (Any) -> bool.

    Returns
    -------
    Predicate
        Composite predicate representing logical conjunction.

    Examples
    --------
    ```pycon
    >>> p = and_(not_null, not_nan, not_infinite)
    >>> p(10)
    True
    >>> p(float("nan"))
    False
    >>> p(None)
    False
    ```

    Edge Cases
    ----------
    - No predicates: returns a predicate that always returns True.
    """
    if not preds:
        return lambda a: True

    def _combined(a: Any) -> bool:
        for p in preds:
            if not_true(p(a)):
                return False
        return True
    return _combined

Logical OR combinator for predicates.

Returns a predicate that evaluates each provided predicate in order and short-circuits on the first that returns the literal True. Exceptions inside individual predicates are swallowed (treated as a non-match) to keep the OR robust.

Parameters

*preds : Predicate Predicates of signature (Any) -> bool.

Returns

Predicate Composite predicate representing logical disjunction.

Examples

>>> p = or_(not_null, not_empty)
>>> p(None)
False        # both fail
>>> p("")
False        # not_null OK but empty string -> not_empty False
>>> p("x")
True
>>> p([])    # not_null True but empty -> not_empty False -> overall False
False

Edge Cases

  • No predicates: returns a predicate that always returns False.
  • Non-boolean truthy values returned by individual predicates are ignored unless they are exactly True, encouraging explicit boolean returns.
Source code in src/talvez/predicates.py
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
def or_(*preds: Predicate) -> Predicate:
    """
    Logical OR combinator for predicates.

    Returns a predicate that evaluates each provided predicate in order and
    short-circuits on the first that returns the literal True. Exceptions inside
    individual predicates are swallowed (treated as a non-match) to keep the OR
    robust.

    Parameters
    ----------
    *preds : Predicate
        Predicates of signature (Any) -> bool.

    Returns
    -------
    Predicate
        Composite predicate representing logical disjunction.

    Examples
    --------
    ```pycon
    >>> p = or_(not_null, not_empty)
    >>> p(None)
    False        # both fail
    >>> p("")
    False        # not_null OK but empty string -> not_empty False
    >>> p("x")
    True
    >>> p([])    # not_null True but empty -> not_empty False -> overall False
    False
    ```

    Edge Cases
    ----------
    - No predicates: returns a predicate that always returns False.
    - Non-boolean truthy values returned by individual predicates are ignored
      unless they are exactly True, encouraging explicit boolean returns.
    """
    if not preds:
        return lambda a: False

    def _combined(a: Any) -> bool:
        for p in preds:
            try:
                if p(a) is True:
                    return True
            except Exception:
                continue
        return False
    return _combined

Tip

These are strict: each predicate must return the literal True to be considered a pass. Any other truthy value will fail the conjunction (and_) or be ignored in the disjunction (or_).

Common usage patterns

from talvez import maybe, just, nothing, chain, compose_maybe, not_null, and_

@maybe(ensure=lambda x: x > 0)
def positive_delta(x: int) -> int:
    return x - 1

pipeline = compose_maybe(
    lambda x: just(x * 2),
    lambda y: positive_delta(y)  # returns Maybe[int]
)

result = pipeline(just(10))      # Just(19)
failed = pipeline(just(0))       # Nothing

Error & warning handling

  • maybe(..., allow_warning=False) turns any emitted warning into failure.

  • perhaps(..., allow_warning=True) will ignore warnings and still return the raw value.

Interoperability

Purpose Helper
Convert Optional[T] to Maybe[T] from_optional
Convert Maybe[T] to Optional[T] maybe_val.to_optional()
Batch short-circuit across many Maybes sequence(iter_of_maybes)