Standard predicates

This section describes the predicates that are included in py-predicate.

Set predicates

A collection of predicates that act on sets.

in_p

Return True if the values are included in the container, otherwise False.

from predicate import in_p

in_123 = in_p([1, 2, 3])

assert not in_123(0)
assert in_123(1)

intersects_p

Return True if the value shares at least one element with the given set, otherwise False.

from predicate import intersects_p

intersects_123 = intersects_p({1, 2, 3})

assert not intersects_123([4, 5, 6])
assert intersects_123([2, 4, 6])

is_subset_p

Return True if the value is a subset, otherwise False.

from predicate import is_subset_p

sub_123 = is_subset_p({1, 2, 3})

assert not sub_123({0, 1})
assert sub_123({1, 2})

is_superset_p

Return True if the value is a superset, otherwise False.

from predicate import is_superset_p

super_123 = is_superset_p({1, 2, 3})

assert not super_123({1, 2, 4})
assert super_123({1, 2, 3, 4})

is_real_subset_p

Return True if the value is a real subset, otherwise False.

from predicate import is_real_subset_p

sub_123 = is_real_subset_p({1, 2, 3})

assert not sub_123({1, 2, 3})
assert sub_123({1, 2})

is_real_superset_p

Return True if the value is a real superset, otherwise False.

from predicate import is_real_superset_p

super_123 = is_real_superset_p({1, 2, 3})

assert not super_123({1, 2, 3})
assert super_123({1, 2, 3, 4})

not_in_p

Return True if the values are not in the container, otherwise False.

from predicate import not_in_p

not_in_123 = not_in_p([1, 2, 3])

assert not_in_123(0)
assert not not_in_123(1)

String predicates

A collection of predicates that act on strings.

ends_with_p

Return True if the string ends with the given suffix, otherwise False.

from predicate import ends_with_p

ends_with_ing = ends_with_p("ing")

assert ends_with_ing("running")
assert not ends_with_ing("run")

is_alnum_p

Return True if all characters in the string are alphanumeric and there is at least one character, False otherwise.

from predicate import is_alnum_p

assert is_alnum_p("abc123")
assert not is_alnum_p("abc 123")
assert not is_alnum_p("")

is_alpha_p

Return True if all characters in the string are alphabetic and there is at least one character, False otherwise.

from predicate import is_alpha_p

assert is_alpha_p("abc")
assert not is_alpha_p("abc123")

is_ascii_p

Return True if the string is empty or all characters in the string are ASCII, False otherwise.

from predicate import is_ascii_p

assert is_ascii_p("hello")
assert is_ascii_p("")
assert not is_ascii_p("héllo")

is_decimal_p

Return True if all characters in the string are decimal characters and there is at least one character, False otherwise.

from predicate import is_decimal_p

assert is_decimal_p("123")
assert not is_decimal_p("12.3")
assert not is_decimal_p("")

is_digit_p

Return True if all characters in the string are digits and there is at least one character, False otherwise.

from predicate import is_digit_p

assert is_digit_p("123")
assert not is_digit_p("12.3")

is_identifier_p

Return True if the string is a valid Python identifier, False otherwise.

from predicate import is_identifier_p

assert is_identifier_p("my_var")
assert is_identifier_p("_private")
assert not is_identifier_p("123abc")
assert not is_identifier_p("my-var")

is_lower_p

Return True if all cased characters in the string are lowercase and there is at least one cased character, False otherwise.

from predicate import is_lower_p

assert is_lower_p("hello")
assert not is_lower_p("Hello")

is_numeric_p

Return True if all characters in the string are numeric characters and there is at least one character, False otherwise.

from predicate import is_numeric_p

assert is_numeric_p("123")
assert not is_numeric_p("12.3")

is_printable_p

Return True if all characters in the string are printable or the string is empty, False otherwise.

from predicate import is_printable_p

assert is_printable_p("hello")
assert is_printable_p("")
assert not is_printable_p("hello\x00")

is_space_p

Return True if there are only whitespace characters in the string and there is at least one character, False otherwise.

from predicate import is_space_p

assert is_space_p("   ")
assert is_space_p("\t\n")
assert not is_space_p("")
assert not is_space_p("hello")

is_title_p

Return True if the string is titlecased (each word starts with an uppercase letter) and there is at least one character, False otherwise.

from predicate import is_title_p

assert is_title_p("Hello World")
assert not is_title_p("hello world")
assert not is_title_p("HELLO WORLD")

is_upper_p

Return True if all cased characters in the string are uppercase and there is at least one cased character, False otherwise.

from predicate import is_upper_p

assert is_upper_p("HELLO")
assert not is_upper_p("Hello")

starts_with_p

Return True if the string starts with the given prefix, otherwise False.

from predicate import starts_with_p

starts_with_py = starts_with_p("py")

assert starts_with_py("python")
assert not starts_with_py("java")

all_p

This predicate tests if for all elements in an Iterable, the enclosed predicate is True:

from predicate import all_p, is_int_p

# Predicate to test if all items in an iterable are of type int
all_int = all_p(is_int_p)

assert all_int([1, 2, 3])
assert not all_int([None, 2, 3])

The equivalent code without using predicates could be something like:

def all_int(iter: Iterable) -> bool:
    return all(isinstance(ele, int) for ele in iter)

always_false_p

This predicate ignores any arguments and always returns False:

from predicate import always_false_p

assert not always_false_p(13)

This might be the result of an optimization.

always_p

Synonym for always_true_p.

always_true_p

This predicate ignores any arguments and always returns True:

from predicate import always_true_p

assert always_true_p(13)

This might be the result of an optimization.

any_p

This predicate tests if for any element in an Iterable, the enclosed predicate is True:

from predicate import any_p, is_int_p

# Predicate to test if any of the items in an iterable is of type int
any_int = any_p(is_int_p)

assert not any_int(())
assert any_int((1, 2, 3))
assert any_int([1, 2, 3])
assert any_int([None, 2, 3])

comp_p

This predicate transforms the input with a function and then tests the result against a predicate.

from predicate import comp_p, ge_p

# True if the length of the list is >= 3
long_enough = comp_p(len, ge_p(3))

assert long_enough([1, 2, 3])
assert not long_enough([1, 2])

count_p

The count_p accepts two paramters. The predicate is evaluated and adds 1 to the count if True, otherwise 0. The length_p evaluates the final count and is returned as the value of the count_p itself.

In the next example we define a predicate that returns True if the number of elements in the iterable that are greater or equal 1, is exactly 1.

from predicate import count_p, ge_p, eq_p

predicate = count_p(predicate=ge_p(1), length_p=eq_p(1))

assert predicate([1])
assert not predicate([1, 3])

eq_false_p

This predicates tests if the argument is False.

from predicate import eq_false_p

assert eq_false_p(False)
assert not eq_false_p(True)

Note that this tests for the exact boolean value False. If you want to test for falsy values, see: is_falsy_p.

eq_p

This predicates tests for equality.

from predicate import eq_p

eq_2 = eq_p(2)

assert eq_2(2)
assert not eq_2(3)

eq_true_p

This predicates tests if the argument is True.

from predicate import eq_true_p

assert not eq_true_p(False)
assert eq_true_p(True)

Note that this tests for the exact boolean value True. If you want to test for falsy values, see: is_truthy_p.

fn_p

This predicate can be used to wrap any (lambda) function:

from predicate import fn_p

square_ge_2 = fn_p(lambda x: x * x >= 2)

assert not square_ge_2(1)
assert square_ge_2(2)

Both synchronous and async callables are supported.

from predicate import fn_p

async def is_positive(x: int) -> bool:
    return x > 0

assert fn_p(is_positive)(5)
assert not fn_p(is_positive)(-1)

ge_le_p

This predicate tests if a value satisfies lower <= x <= upper.

from predicate import ge_le_p

between_2_and_5 = ge_le_p(2, 5)

assert between_2_and_5(2)
assert between_2_and_5(5)
assert not between_2_and_5(1)
assert not between_2_and_5(6)

ge_lt_p

This predicate tests if a value satisfies lower <= x < upper.

from predicate import ge_lt_p

predicate = ge_lt_p(2, 5)

assert predicate(2)
assert predicate(4)
assert not predicate(5)

ge_p

This predicates tests for greater or equal a value.

from predicate import ge_p

ge_2 = ge_p(2)

assert ge_2(2)
assert not ge_2(1)

gt_le_p

This predicate tests if a value satisfies lower < x <= upper.

from predicate import gt_le_p

predicate = gt_le_p(2, 5)

assert predicate(3)
assert predicate(5)
assert not predicate(2)

gt_lt_p

This predicate tests if a value satisfies lower < x < upper.

from predicate import gt_lt_p

predicate = gt_lt_p(2, 5)

assert predicate(3)
assert not predicate(2)
assert not predicate(5)

gt_p

This predicates tests for greater than a value.

from predicate import gt_p

gt_2 = gt_p(2)

assert not gt_2(2)
assert gt_2(3)

has_key_p

This predicate tests if a mapping contains at least one key satisfying a predicate. See has_key_p for full documentation and examples.

from predicate import eq_p, has_key_p

has_name = has_key_p(eq_p("name"))

assert has_name({"name": "Alice"})
assert not has_name({"age": 30})

has_length_p

This predicate tests the length of an iterable against another predicate.

from predicate import has_length_p, lt_p

has_length_lt_2 = has_length_p(lt_p(2))

assert not has_length_lt_2([1, 2, 3])
assert has_length_lt_2({1})

has_path_p

This predicate tests if a nested mapping contains a path where each step’s key satisfies the corresponding predicate.

from predicate import eq_p, has_path_p

# True if the dict has key "user" whose value has key "name"
has_user_name = has_path_p(eq_p("user"), eq_p("name"))

assert has_user_name({"user": {"name": "Alice"}})
assert not has_user_name({"user": {"age": 30}})
assert not has_user_name({"name": "Alice"})

implies_p

This predicate tests if one predicate implies another one.

from predicate import implies_p, ge_p

p = ge_p(2)
q = ge_p(3)

assert not implies(p, q)
assert implies(q, p)

is_bool_p

This predicate tests if the value is of type bool. Only True if the value is either False or True.

from predicate import is_bool_p

assert is_bool_p(False)
assert is_bool_p(True)

is_bytes_p

This predicate tests if the value is of type bytes.

from predicate import is_bytes_p

assert not is_bytes_p("hello")
assert not is_bytes_p(bytearray(b"hello"))
assert is_bytes_p(b"hello")
assert is_bytes_p(b"")

is_callable_p

This predicate tests if the value is of type Callable.

from predicate import is_callable_p

assert is_callable(is_callable)
assert is_callable(lambda x: x)
assert is_callable(str.upper)

is_close_p

This predicate tests if a float value is approximately equal to a target, accounting for floating-point rounding errors. It wraps math.isclose() with configurable rel_tol and abs_tol parameters.

from predicate import is_close_p

predicate = is_close_p(1.0)

assert predicate(1.0)
assert predicate(1.0 + 1e-10)   # within default relative tolerance
assert not predicate(1.1)

Use abs_tol when comparing values near zero:

from predicate import is_close_p

near_zero = is_close_p(0.0, abs_tol=1e-6)

assert near_zero(1e-7)
assert not near_zero(1e-5)

is_complex_p

This predicate tests if the value is of type complex.

from predicate import is_complex_p

assert not is_complex(1)
assert is_complex(complex(1, 1))
assert is_complex(1 + 1j)

is_container_p

This predicate tests if the value is of type Container.

from predicate import is_container_p

assert is_container_p((1, 2, 3))
assert is_container_p([1, 2, 3])
assert is_container_p({1, 2, 3})
assert is_container_p({"one": 1, "two": 2, "three": 3})
assert is_container_p("one")  # a string is also a container!

is_date_p

This predicate tests if the value is of type date.

Note that datetime is a subclass of date, so datetime values also match. If you need to distinguish, combine with ~is_datetime_p.

from datetime import date, datetime
from predicate import is_date_p

assert is_date_p(date.today())
assert is_date_p(datetime.now())  # datetime is a subclass of date
assert not is_date_p("2024-01-01")

is_datetime_p

This predicate tests if the value is of type datetime.

from datetime import datetime
from predicate import is_datetime_p

assert is_datetime_p(datetime.now())

is_dict_p

This predicate tests if the value is of type dict.

from predicate import is_dict_p

assert is_dict_p({"one": 1, "two": 2, "three": 3})

is_dict_of_p

This predicate tests if the value is of type dict and the key and values match the predicates.

from predicate import is_dict_of_p, is_int_p, eq_p

# test for dictionaries that have keys x and y. The values should be integers
predicate = is_dict_of_p((eq_p("x"), is_int_p), (eq_p("y"), is_int_p))

assert predicate({"x": 1, "y": 7})

is_empty_p

This predicate tests if an iterable is empty.

from predicate import is_empty_p

assert is_empty_p(())
assert is_empty_p({})
assert is_empty_p([])
assert is_empty_p("")

is_even_p

This predicate tests if an integer is even.

from predicate import is_even_p

assert is_even_p(0)
assert is_even_p(4)
assert not is_even_p(3)

is_falsy_p

This predicate tests for falsy values, for example False, “”, {}, [], 0, etc.

from predicate import is_falsy_p

assert is_falsy_p(0)
assert is_falsy_p({})

is_finite_p

This predicate tests if the value is a finite number (i.e. not infinite and not NaN).

import math
from predicate import is_finite_p

assert not is_finite_p(math.inf)
assert not is_finite_p(math.nan)
assert is_finite_p(42)

is_float_p

This predicate tests if the value is of type float.

from predicate import is_float_p

assert not is_float_p(3)
assert is_float_p(3.14)

is_frozenset_p

This predicate tests if the value is of type frozenset.

from predicate import is_frozenset_p

assert not is_frozenset_p({1, 2, 3})  # a set, not a frozenset
assert is_frozenset_p(frozenset({1, 2, 3}))
assert is_frozenset_p(frozenset())

is_hashable_p

This predicate tests if the value is hashable.

from predicate import is_hashable_p

assert not is_hashable_p({})
assert is_hashable_p("foo")

is_inf_p

This predicate tests if the value is infinite.

import math
from predicate import is_inf_p

assert not is_inf_p(3)
assert is_inf_p(math.inf)

is_instance_p

This predicate tests if the value is an instance of one or more given classes.

from predicate import is_instance_p

is_int_or_str = is_instance_p(int, str)

assert is_int_or_str(42)
assert is_int_or_str("hello")
assert not is_int_or_str(3.14)

is_int_p

This predicate tests if the value is of type int.

from predicate import is_int_p

assert not is_int_p(3.14)
assert is_int_p(3)

is_iterable_of_p

This predicate tests if the value is an Iterable and all its elements satisfy the given predicate.

from predicate import is_iterable_of_p, is_int_p

all_ints = is_iterable_of_p(is_int_p)

assert all_ints([1, 2, 3])
assert all_ints((1,))
assert not all_ints([1, "two", 3])

is_iterable_p

This predicate tests if the value is of type Iterable.

from predicate import is_iterable_p

assert is_iterable_p([1, 2, 3])
assert is_iterable_p("hello")
assert not is_iterable_p(42)

is_list_of_p

This predicate predicate tests if the value if a list, where all items in the list conform to a given predicate.

from predicate import is_list_of_p, is_str_p

is_list_of_str = is_list_of_p(is_str_p)

assert not is_list_of_str(["one", "two", 3])
assert is_list_of_str(["foo"])

is_list_p

This predicate tests if the value is of type list.

from predicate import is_list_p

assert not is_list_p({1, 2, 3})
assert is_list_p([1, 2, 3])

is_mapping_p

This predicate tests if the value is a Mapping (i.e. any dict-like type).

from collections import OrderedDict
from predicate import is_mapping_p

assert is_mapping_p({"key": "value"})
assert is_mapping_p(OrderedDict())
assert not is_mapping_p([("key", "value")])

is_nan_p

This predicate tests if the value is NaN (not a number).

import math
from predicate import is_nan_p

assert not is_nan_p(1)
assert is_nan_p(math.nan)

is_none_p

This predicate tests if the value is None.

from predicate import is_none_p

assert not is_none_p(13)
assert is_none_p(None)

is_not_none_p

This predicate tests if the value is not None.

from predicate import is_not_none_p

assert not is_not_none_p(None)
assert is_not_none_p(13)

is_not_empty_p

This predicate tests if an iterable is not empty.

from predicate import is_not_empty_p

assert is_not_empty_p([1])
assert is_not_empty_p("hello")
assert not is_not_empty_p([])
assert not is_not_empty_p("")

is_number_p

This predicate tests if the value is a number (int, float, or complex). bool values are excluded, consistent with how is_int_p works.

from predicate import is_number_p

assert is_number_p(42)
assert is_number_p(3.14)
assert is_number_p(1 + 2j)
assert not is_number_p(True)  # bool is excluded
assert not is_number_p("42")

is_odd_p

This predicate tests if an integer is odd.

from predicate import is_odd_p

assert is_odd_p(1)
assert is_odd_p(7)
assert not is_odd_p(4)

is_path_p

This predicate tests if the value is a pathlib path. Matches Path, PurePosixPath, PureWindowsPath, and any other PurePath subclass.

from pathlib import Path, PurePosixPath
from predicate import is_path_p

assert is_path_p(Path("/tmp/file.txt"))
assert is_path_p(PurePosixPath("/etc/hosts"))
assert not is_path_p("/tmp/file.txt")  # a plain string is not a path

is_predicate_p

This predicate tests if the value is of type Predicate.

from predicate import is_predicate_p, eq_p

assert is_predicate_p(eq_p(1))
assert not is_predicate_p(42)

is_range_p

This predicate tests if value is a range.

from predicate import is_range_p

assert not is_range_p(0)
assert is_range_p(range(5))

is_sequence_p

This predicate tests if the value is a Sequence (list, tuple, str, bytes, range, etc.). Note that dict and set are not sequences.

from predicate import is_sequence_p

assert is_sequence_p([1, 2, 3])
assert is_sequence_p((1, 2))
assert is_sequence_p("hello")  # str is a sequence
assert is_sequence_p(range(5))
assert not is_sequence_p({1, 2, 3})
assert not is_sequence_p({"key": "value"})

is_set_of_p

This predicate predicate tests if the value if a set, where all items in the set conform to a given predicate.

from predicate import is_set_of_p, is_str_p

is_set_of_str = is_set_of_p(is_str_p)

assert not is_set_of_str({"one", "two", 3})
assert is_set_of_str({"foo"})

is_set_p

This predicate tests if the value is of type set.

from predicate import is_set_p

assert is_set_p({1, 2, 3})
assert not is_set_p([1, 2, 3])
assert not is_set_p(frozenset({1, 2, 3}))

is_str_p

This predicate tests if the value is of type str.

from predicate import is_str_p

assert not is_str_p(3.14)
assert is_str_p("foo")

is_subclass_p

This predicate tests if a class is a subclass of the given class.

from predicate import is_subclass_p

is_int_subclass = is_subclass_p(int)

assert is_int_subclass(bool)  # bool is a subclass of int
assert not is_int_subclass(str)

is_time_p

This predicate tests if the value is of type datetime.time.

from datetime import time
from predicate import is_time_p

assert is_time_p(time(12, 30))
assert is_time_p(time(0, 0, 0))
assert not is_time_p("12:30")

is_timedelta_p

This predicate tests if the value is of type datetime.timedelta.

from datetime import timedelta
from predicate import is_timedelta_p

assert is_timedelta_p(timedelta(days=1))
assert is_timedelta_p(timedelta(seconds=3600))
assert not is_timedelta_p(3600)

is_truthy_p

This predicate tests for truthy values, for example True, “foo”, {“foo”}, [1], 13, etc.

from predicate import is_truthy_p

assert is_truthy_p(1)
assert is_truthy_p({"foo"})

is_tuple_of_p

This predicate tests if the value is a tuple of a specific structure, where each element matches the corresponding predicate.

from predicate import is_tuple_of_p, is_int_p, is_str_p

is_int_str_pair = is_tuple_of_p(is_int_p, is_str_p)

assert is_int_str_pair((1, "hello"))
assert not is_int_str_pair((1, 2))
assert not is_int_str_pair((1, "hello", "extra"))

is_tuple_p

This predicate tests if the value is of type tuple.

from predicate import is_tuple_p

assert is_tuple_p((1, 2, 3))
assert is_tuple_p(())
assert not is_tuple_p([1, 2, 3])

is_uuid_p

This predicate tests if the value is of type UUID.

from uuid import UUID, uuid4
from predicate import is_uuid_p

assert is_uuid_p(uuid4())
assert is_uuid_p(UUID("12345678-1234-5678-1234-567812345678"))
assert not is_uuid_p("12345678-1234-5678-1234-567812345678")

juxt_p

This predicate applies multiple predicates to the same value, collects the boolean results, and then evaluates those results with an evaluate predicate.

In the simplest case, check if a value satisfies exactly two of four predicates:

from predicate import count_p, eq_p, is_int_p, is_str_p, juxt_p

p1 = is_int_p
p2 = is_str_p
p3 = eq_p(2)
p4 = eq_p("foo")

two_true = count_p(predicate=eq_p(True), length_p=eq_p(2))

predicate = juxt_p(p1, p2, p3, p4, evaluate=two_true)

assert predicate(2)  # is_int_p and eq_p(2) are both True
assert predicate("foo")  # is_str_p and eq_p("foo") are both True
assert not predicate(1)  # only is_int_p is True

juxt_p also works with predicates that themselves accept iterables, enabling compound checks on the same input in a single predicate:

from predicate import all_p, count_p, eq_p, exactly_one_p, is_int_p, juxt_p

all_int = all_p(is_int_p)
three_zeros = count_p(predicate=eq_p(0), length_p=eq_p(3))
one_true = exactly_one_p(predicate=eq_p(True))

predicate = juxt_p(all_int, three_zeros, evaluate=one_true)

assert predicate([1, 2, 3, 4])  # all ints, not 3 zeros → exactly one True
assert not predicate(
    [1, 0, 2, 0, 3, 0]
)  # all ints and 3 zeros → both True, so one_true fails

le_p

This predicates tests for less than or equal a value.

from predicate import le_p

le_2 = le_p(2)

assert le_2(2)
assert not le_2(3)

lt_p

This predicates tests for less than a value.

from predicate import lt_p

lt_2 = lt_p(2)

assert not lt_2(2)
assert lt_2(1)

match_p

This predicate tests if a sequence matches a series of predicates in order. Each predicate in the series is applied to the corresponding element.

from predicate import is_int_p, is_str_p, match_p

int_then_str = match_p(is_int_p, is_str_p)

assert int_then_str([1, "hello"])
assert not int_then_str([1, 2])
assert not int_then_str(["hello", 1])

ne_p

This predicate tests for non equality

from predicate import ne_p

ne_2 = ne_p(2)

assert not ne_2(2)
assert ne_2(3)

neg_p

This predicate tests if a number is negative (strictly less than zero).

from predicate import neg_p

assert neg_p(-1)
assert not neg_p(0)
assert not neg_p(1)

pos_p

This predicate tests if a number is positive (strictly greater than zero).

from predicate import pos_p

assert pos_p(1)
assert not pos_p(0)
assert not pos_p(-1)

raises_p

This predicate tests if a callable (thunk) raises an exception when called. Returns True if calling the thunk raises any exception, False otherwise. Both synchronous and async callables are supported.

from predicate import raises_p

assert raises_p(lambda: 1 / 0)
assert raises_p(lambda: int("x"))
assert not raises_p(lambda: 1)

Async functions are also supported:

async def fetch():
    raise ConnectionError("unreachable")

async def ok():
    return 42

assert raises_p(fetch)
assert not raises_p(ok)

raises_exception_p

This predicate tests if a callable raises a specific exception type when called. Returns True only if the exact exception type (or a subclass of it) is raised. Both synchronous and async callables are supported.

from predicate import raises_exception_p

assert raises_exception_p(ValueError)(lambda: int("x"))
assert raises_exception_p(Exception)(lambda: 1 / 0)    # ZeroDivisionError is a subclass of Exception
assert not raises_exception_p(ValueError)(lambda: 1 / 0)  # wrong exception type
assert not raises_exception_p(ValueError)(lambda: 1)       # no exception raised

async def async_value_error():
    raise ValueError("bad input")

assert raises_exception_p(ValueError)(async_value_error)

reduce_p

The reduce_p predicate threads an accumulator through an iterable. For each element x, it calls fn(acc, x) which returns a (new_acc, predicate) tuple. The element x must satisfy the returned predicate, and the accumulator advances for the next element. Returns True if all elements pass, or if the iterable is empty.

import sys
from predicate import reduce_p, ge_p

is_sorted_p = reduce_p(fn=lambda acc, x: (x, ge_p(acc)), initial=-sys.maxsize - 1)

assert is_sorted_p([])
assert is_sorted_p([1, 2, 3])
assert not is_sorted_p([1, 3, 2])
from predicate import reduce_p, eq_p, always_true_p

is_interval_3_p = reduce_p(fn=lambda acc, x: (x, eq_p(acc + 3) if acc else always_true_p), initial=None)

assert is_interval_3_p([1, 4, 7])
assert not is_interval_3_p([1, 3])

Both synchronous and async callables are supported.

import sys
from predicate import reduce_p, ge_p

async def sorted_step(acc, x):
    return x, ge_p(acc)

is_sorted_p = reduce_p(fn=sorted_step, initial=-sys.maxsize - 1)

assert is_sorted_p([1, 2, 3])
assert not is_sorted_p([3, 1, 2])

regex_p

This predicate tests if a string matches a regular expression pattern.

from predicate import regex_p

is_phone = regex_p(r"\d{3}-\d{4}")

assert is_phone("555-1234")
assert not is_phone("hello")

tee_p

Predicate that always returns True, but is useful for handling side-effects.

from predicate import all_p, lt_p, tee_p

log = tee_p(print)

all_lt_2 = all_p(log | lt_p(2))

zero_p

Returns True of the value is zero, otherwise False.

from predicate import zero_p

assert zero_p(0)