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¶
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: