Skip to content

Advanced

Custom type converters

You can teach r_bridge how to serialise your own types to R and back, without modifying the library.

Serialiser (Python → R)

from r_bridge import register_serializer

class Money:
    def __init__(self, amount: float, currency: str):
        self.amount = amount
        self.currency = currency

register_serializer(
    Money,
    lambda obj: {
        "__type__": "money",
        "amount": obj.amount,
        "currency": obj.currency,
    }
)

R receives a named list with the __type__ field, which you can handle on the R side however you like.

Deserialiser (R → Python)

from r_bridge import register_deserializer

register_deserializer(
    "money",
    lambda d: Money(amount=d["amount"], currency=d["currency"])
)

Now any R value tagged {"__type__": "money", ...} is automatically converted back to a Money instance.


Accessing R libraries

Using a custom library path

with RBridge(r_libs=["/path/to/my/r/libs"]) as r:
    r.eval('library(mypackage)')

The path is prepended to R_LIBS_USER before R starts.

Installing R packages at runtime

with RBridge() as r:
    r.eval('if (!requireNamespace("ggplot2")) install.packages("ggplot2")')
    r.eval('library(ggplot2)')

Concurrent usage

RBridge is thread-safe: a single threading.Lock serialises all calls. Only one request is in flight at a time, so calls from multiple threads are queued rather than interleaved.

import threading
from r_bridge import RBridge

with RBridge() as r:
    def worker(n):
        result = r.call("sqrt", float(n), result_type_hint="scalar")
        print(f"sqrt({n}) = {result}")

    threads = [threading.Thread(target=worker, args=(i,)) for i in range(10)]
    for t in threads:
        t.start()
    for t in threads:
        t.join()

Per-call timeouts

The bridge-wide call_timeout can be overridden for individual slow calls:

with RBridge(call_timeout=5.0) as r:
    # most calls use the 5-second default
    r.mean([1, 2, 3])

    # this specific call is allowed 120 seconds
    r.eval("run_long_simulation()", timeout=120.0)

Logging

r_bridge uses Python's standard logging module under the logger name r_bridge. Set log_level="DEBUG" to see non-protocol R stdout and internal diagnostics:

import logging
logging.basicConfig(level=logging.DEBUG)

with RBridge(log_level="DEBUG") as r:
    r.eval('cat("stray output\n")')
    # logged at DEBUG: R stdout (non-protocol): stray output