Source code for FuPy.utils

"""
Utilities to support functional programming in Python.
For internal use only.

Copyright (c) 2024 - Eindhoven University of Technology, The Netherlands

This software is made available under the terms of the MIT License.
"""
import inspect
from typing import Any, Callable

__all__ = [
    "count_required_args",
    "indent_lines",
    "show_value", "show_args", "force",
]


[docs] def count_required_args(f: Callable[..., Any]) -> int: """Count the minimum number of required non-keyword arguments of f. Does not work for built-in functions (use parameter r of Func to bypass this). """ # N.B. The following does not work, because of a circular import, # triggered by the use of the func decorator in basics, # which executes already during import and calls count_required_args. # from .basics import Func # from .laziness import Lazy # if isinstance(f, (Func, Lazy)): if hasattr(f, '__class__') and f.__class__.__name__ in ('Func', 'Lazy'): return 1 sig = inspect.signature(f) def parameter_is_required(p: inspect.Parameter) -> bool: return p.default is inspect.Parameter.empty and p.kind in ( inspect.Parameter.POSITIONAL_ONLY, inspect.Parameter.POSITIONAL_OR_KEYWORD, ) return sum(parameter_is_required(p) for p in sig.parameters.values())
[docs] def indent_lines(line: str, indentation: str = '', k: int = 0) -> str: """Indent each line by n spaces, except for the first k lines. """ lines = line.split('\n') return '\n'.join([f"{'' if index < k else indentation}{line}" for index, line in enumerate(lines)])
[docs] def show_value(value) -> str: """Show value, quoting strings. Used in tracing; so, avoid evaluation of lazy objects. """ # print(f"show_value(repr={value!r}, str={value!s})") if type(value) is tuple: if len(value) == 1: return f"({show_value(value[0])},)" return f"({', '.join(show_value(v) for v in value)})" elif isinstance(value, str): return repr(value) else: return str(value)
[docs] def show_args(args: tuple[Any, ...]) -> str: """Show tuple as a string, with strings quoted, without trailing comma if singleton. N.B. The singleton case does not occur in case of auto-(un)packing of arguments. Used in tracing; so, avoid evaluation of lazy objects. """ from FuPy.basics import Left, Right, Func from FuPy.fixpoints import Fix if not args: return "_" elif len(args) == 1: arg = args[0] if isinstance(arg, (Left, Right, Fix)): return f"({arg})" elif isinstance(arg, Func): return arg.show('.') else: return show_value(arg) else: return f"({', '.join(show_value(arg) for arg in args)})"
[docs] def force(v: Any) -> Any: """Resume all suspended computations. """ if hasattr(v, '__force__'): return v.__force__() elif isinstance(v, tuple): return tuple(force(item) for item in v) else: return v