Skip to content

_formula

Attributes

_FORMULA_FUNCTION_WHITELIST = Literal['bf', 'lf', 'nlf', 'acformula', 'set_rescor', 'set_mecor', 'set_nl'] module-attribute

Classes

FormulaPart dataclass

A single formula helper invocation.

Instances of this type represent a call like bf("y ~ x") or set_rescor(True) without executing anything. They are primarily used as nodes inside a FormulaConstruct.

Parameters:

Name Type Description Default
_fun Literal[...]

Whitelisted formula helper name.

required
_args Sequence[Primitive]

Positional arguments for the helper.

required
_kwargs Mapping[str, Primitive]

Keyword arguments for the helper.

required
Notes

This is a low-level type. Most users should construct these via the public helper functions in brmspy.brms.

Source code in brmspy/types/formula_dsl.py
@dataclass
class FormulaPart:
    """
    A single formula helper invocation.

    Instances of this type represent a call like `bf("y ~ x")` or `set_rescor(True)`
    without executing anything. They are primarily used as nodes inside a
    [`FormulaConstruct`][brmspy.types.formula_dsl.FormulaConstruct].

    Parameters
    ----------
    _fun : Literal[...]
        Whitelisted formula helper name.
    _args : Sequence[Primitive]
        Positional arguments for the helper.
    _kwargs : Mapping[str, Primitive]
        Keyword arguments for the helper.

    Notes
    -----
    This is a low-level type. Most users should construct these via the public
    helper functions in [`brmspy.brms`][brmspy.brms].
    """

    _fun: _FORMULA_FUNCTION_WHITELIST
    _args: Sequence[Primitive]
    _kwargs: Mapping[str, Primitive]

    def __post_init__(self):
        """Validate `_fun`, `_args`, and `_kwargs` types after construction."""
        # Validate function name first
        if self._fun not in get_args(_FORMULA_FUNCTION_WHITELIST):
            raise ValueError(
                f"FormulaPart._fun must be one of {_FORMULA_FUNCTION_WHITELIST!r}, "
                f"got {self._fun!r}"
            )

        # Enforce _args is a list
        if not isinstance(self._args, Sequence):
            raise TypeError(
                f"FormulaPart._args must be a Sequence, got {type(self._args).__name__}"
            )

        # Enforce _kwargs is a dict
        if not isinstance(self._kwargs, Mapping):
            raise TypeError(
                f"FormulaPart._kwargs must be a Mapping, got {type(self._kwargs).__name__}"
            )

    def __str__(self) -> str:
        """Render a readable `fun(arg1, ..., kw=...)` representation."""
        args = ", ".join(repr(a) for a in self._args)
        kwargs = ", ".join(f"{k}={v!r}" for k, v in self._kwargs.items())
        inner = ", ".join(x for x in (args, kwargs) if x)
        return f"{self._fun}({inner})"

    def __repr__(self) -> str:
        return self.__str__()

Attributes

_fun instance-attribute
_args instance-attribute
_kwargs instance-attribute

Functions

__post_init__()

Validate _fun, _args, and _kwargs types after construction.

Source code in brmspy/types/formula_dsl.py
def __post_init__(self):
    """Validate `_fun`, `_args`, and `_kwargs` types after construction."""
    # Validate function name first
    if self._fun not in get_args(_FORMULA_FUNCTION_WHITELIST):
        raise ValueError(
            f"FormulaPart._fun must be one of {_FORMULA_FUNCTION_WHITELIST!r}, "
            f"got {self._fun!r}"
        )

    # Enforce _args is a list
    if not isinstance(self._args, Sequence):
        raise TypeError(
            f"FormulaPart._args must be a Sequence, got {type(self._args).__name__}"
        )

    # Enforce _kwargs is a dict
    if not isinstance(self._kwargs, Mapping):
        raise TypeError(
            f"FormulaPart._kwargs must be a Mapping, got {type(self._kwargs).__name__}"
        )
__str__()

Render a readable fun(arg1, ..., kw=...) representation.

Source code in brmspy/types/formula_dsl.py
def __str__(self) -> str:
    """Render a readable `fun(arg1, ..., kw=...)` representation."""
    args = ", ".join(repr(a) for a in self._args)
    kwargs = ", ".join(f"{k}={v!r}" for k, v in self._kwargs.items())
    inner = ", ".join(x for x in (args, kwargs) if x)
    return f"{self._fun}({inner})"
__repr__()
Source code in brmspy/types/formula_dsl.py
def __repr__(self) -> str:
    return self.__str__()
__init__(_fun, _args, _kwargs)

Functions

py_to_r(obj)

Convert arbitrary Python objects to R objects via rpy2.

Comprehensive converter that handles nested structures (dicts, lists), DataFrames, arrays, and scalars. Uses rpy2's converters with special handling for dictionaries (→ R named lists) and lists of dicts.

Parameters:

Name Type Description Default
obj any

Python object to convert. Supported types: - None → R NULL - dict → R named list (ListVector), recursively - list/tuple of dicts → R list of named lists - list/tuple (other) → R vector or list - pd.DataFrame → R data.frame - np.ndarray → R vector/matrix - scalars (int, float, str, bool) → R atomic types

required

Returns:

Type Description
rpy2 R object

R representation of the Python object

Notes

Conversion Rules:

  1. None: → R NULL
  2. DataFrames: → R data.frame (via pandas2ri)
  3. Dictionaries: → R named list (ListVector), recursively converting values
  4. Lists of dicts: → R list with 1-based indexed names containing named lists
  5. Other lists/tuples: → R vectors or lists (via rpy2 default)
  6. NumPy arrays: → R vectors/matrices (via numpy2ri)
  7. Scalars: → R atomic values

Recursive Conversion:

Dictionary values are recursively converted, allowing nested structures:

{'a': {'b': [1, 2, 3]}}    list(a = list(b = c(1, 2, 3)))

List of Dicts:

Lists containing only dicts are converted to R lists with 1-based indexing:

[{'x': 1}, {'x': 2}]    list("1" = list(x = 1), "2" = list(x = 2))

Examples:

from brmspy.helpers.conversion import py_to_r
import numpy as np
import pandas as pd

# Scalars
py_to_r(5)        # R: 5
py_to_r("hello")  # R: "hello"
py_to_r(None)     # R: NULL

# Arrays
py_to_r(np.array([1, 2, 3]))  # R: c(1, 2, 3)

# DataFrames
df = pd.DataFrame({'x': [1, 2], 'y': [3, 4]})
py_to_r(df)  # R: data.frame(x = c(1, 2), y = c(3, 4))
See Also

r_to_py : Convert R objects back to Python kwargs_r : Convert keyword arguments dict for R function calls brmspy.brms.fit : Uses this for converting data to R

Source code in brmspy/helpers/_rpy2/_converters/_dispatch.py
def py_to_r(obj: PyObject) -> Sexp:
    """
    Convert arbitrary Python objects to R objects via rpy2.

    Comprehensive converter that handles nested structures (dicts, lists),
    DataFrames, arrays, and scalars. Uses rpy2's converters with special
    handling for dictionaries (→ R named lists) and lists of dicts.

    Parameters
    ----------
    obj : any
        Python object to convert. Supported types:
        - None → R NULL
        - dict → R named list (ListVector), recursively
        - list/tuple of dicts → R list of named lists
        - list/tuple (other) → R vector or list
        - pd.DataFrame → R data.frame
        - np.ndarray → R vector/matrix
        - scalars (int, float, str, bool) → R atomic types

    Returns
    -------
    rpy2 R object
        R representation of the Python object

    Notes
    -----
    **Conversion Rules:**

    1. **None**: → R NULL
    2. **DataFrames**: → R data.frame (via pandas2ri)
    3. **Dictionaries**: → R named list (ListVector), recursively converting values
    4. **Lists of dicts**: → R list with 1-based indexed names containing named lists
    5. **Other lists/tuples**: → R vectors or lists (via rpy2 default)
    6. **NumPy arrays**: → R vectors/matrices (via numpy2ri)
    7. **Scalars**: → R atomic values

    **Recursive Conversion:**

    Dictionary values are recursively converted, allowing nested structures:
    ```python
    {'a': {'b': [1, 2, 3]}}  →  list(a = list(b = c(1, 2, 3)))
    ```

    **List of Dicts:**

    Lists containing only dicts are converted to R lists with 1-based indexing:
    ```python
    [{'x': 1}, {'x': 2}]  →  list("1" = list(x = 1), "2" = list(x = 2))
    ```

    Examples
    --------

    ```python
    from brmspy.helpers.conversion import py_to_r
    import numpy as np
    import pandas as pd

    # Scalars
    py_to_r(5)        # R: 5
    py_to_r("hello")  # R: "hello"
    py_to_r(None)     # R: NULL

    # Arrays
    py_to_r(np.array([1, 2, 3]))  # R: c(1, 2, 3)

    # DataFrames
    df = pd.DataFrame({'x': [1, 2], 'y': [3, 4]})
    py_to_r(df)  # R: data.frame(x = c(1, 2), y = c(3, 4))
    ```

    See Also
    --------
    r_to_py : Convert R objects back to Python
    kwargs_r : Convert keyword arguments dict for R function calls
    brmspy.brms.fit : Uses this for converting data to R
    """
    import rpy2.robjects as ro

    if obj is None:
        return ro.NULL

    if isinstance(obj, ro.Sexp):
        return obj

    if isinstance(obj, RListVectorExtension) and isinstance(obj.r, ro.Sexp):
        return obj.r

    _type = type(obj)
    converter = None

    if _type in _registry._PY2R_CONVERTERS:
        # O(1) lookup first
        converter = _registry._PY2R_CONVERTERS[_type]
    else:
        for _type, _con in _registry._PY2R_CONVERTERS.items():
            if isinstance(obj, _type):
                converter = _con
                break

    assert len(_registry._PY2R_CONVERTERS) > 0, "NO PY2R CONVERTERS"
    assert (
        converter
    ), "object fallback must be in place in __init__.py! This is an issue with the library, not the user!"
    return converter(obj)

_py2r_formula_part(obj)

Source code in brmspy/helpers/_rpy2/_converters/_formula.py
def _py2r_formula_part(obj: FormulaPart) -> Sexp:
    import rpy2.robjects as ro

    args = [py_to_r(o) for o in obj._args]
    kwargs = {k: py_to_r(v) for k, v in obj._kwargs.items()}

    assert obj._fun in get_args(_FORMULA_FUNCTION_WHITELIST)

    fun = cast(Callable, ro.r(f"brms::{obj._fun}"))
    return fun(*args, **kwargs)