Skip to content

SOURCE CODE liquid.filters.wild DOCS

"""Provides some wild filters"""

try:
    from jinja2 import pass_environment
except ImportError:
    from jinja2 import environmentfilter as pass_environment

from typing import TYPE_CHECKING, Any, Callable
from .manager import FilterManager

if TYPE_CHECKING:
    from jinja2.environment import Environment

wild_filter_manager = FilterManager()


@wild_filter_manager.register("ifelse, if_else")DOCS
@pass_environment
def ifelse(
    env: "Environment",
    value: Any,
    test: Any,
    test_args: Any = (),
    true: Any = None,
    true_args: Any = (),
    false: Any = None,
    false_args: Any = (),
) -> Any:
    """An if-else filter, implementing a tenary-like filter.

    Use `ifelse` or `if_else`.

    Examples:
        >>> {{ a | ifelse: isinstance, (int, ),
        >>>                "plus", (1, ),
        >>>                "append", (".html", ) }}
        >>> # 2 when a = 1
        >>> # "a.html" when a = "a"

    Args:
        value: The base value
        test: The test callable or filter name
        test_args: Other args (value as the first arg) for the test
        true: The callable or filter name when test is True
        true_args: Other args (value as the first arg) for the true
            When this is None, return the true callable itself or the name
            of the filter it self
        false: The callable or filter name when test is False
        false_args: Other args (value as the first arg) for the false
            When this is None, return the false callable itself or the name
            of the filter it self
    Returns:
        The result of true of test result is True otherwise result of false.
    """

    def compile_out(func: Any, args: Any) -> Any:
        if args is None:
            return func
        if not isinstance(args, tuple):
            args = (args,)
        if callable(func):
            return func(value, *args)
        expr = env.compile_expression(f"value | {func}(*args)")
        return expr(value=value, args=args)

    test_out = compile_out(test, test_args)
    if test_out:
        return compile_out(true, true_args)
    return compile_out(false, false_args)


@wild_filter_manager.registerDOCS
def call(fn: Callable, *args, **kwargs) -> Any:
    """Call a function with passed arguments

    Examples:
        >>> {{ int | call: "1" | plus: 1 }}
        >>> # 2

    Args:
        fn: The callable
        *args: and
        **kwargs: The arguments for the callable

    Returns:
        The result of calling the function
    """
    return fn(*args, **kwargs)


@wild_filter_manager.registerDOCS
def each(array: Any, fn: Callable, *args: Any, **kwargs: Any) -> Any:
    """Call a function for each item in an array.

    With wild mode, you can use the 'map' filter to apply a function to each
    item in an array. However, this filter is different from the 'map' filter
    in that it takes the array as the first argument and additional arguments
    passed to the function are allowed.

    Examples:
        >>> {{ floor | map: [1.1, 2.1, 3.1] | list }}
        >>> # [1, 2, 3]

        >>> {{ [1.1, 2.1, 3.1] | each: floor }}
        >>> # [1, 2, 3]
        >>> {{ [1.1, 2.1, 3.1] | each: plus, 1 }}
        >>> # [2.2, 3.2, 4.2]

    Args:
        array: The array
        fn: The callable

    Returns:
        The result of calling the function for each item in the array
    """
    return [fn(item, *args, **kwargs) for item in array]