Reproducibility¶
agrobr enables 100% reproducible analyses.
Deterministic Mode¶
from agrobr import datasets
async with datasets.deterministic(snapshot="2025-12-31"):
df = await datasets.preco_diario("soja")
Also available as a decorator:
from agrobr.datasets.deterministic import deterministic_decorator
@deterministic_decorator("2025-12-31")
async def meu_pipeline():
df = await datasets.preco_diario("soja")
return df
Snapshot Semantics¶
| Aspect | Definition |
|---|---|
| Format | "YYYY-MM-DD" — maximum cutoff date |
| Filter | Datasets with snapshot support (e.g. preco_diario) filter by data <= snapshot |
| Network | Datasets with snapshot support query the local cache only (offline) |
| Scope | Isolated per async context (contextvars) — does not affect other tasks |
| MetaInfo | snapshot field filled automatically in all datasets |
Per-dataset support
The date filter and offline mode are applied by datasets that implement snapshot support (currently preco_diario). The others record the snapshot in MetaInfo for provenance but query the sources normally.
Checking the Mode¶
from agrobr.datasets import is_deterministic, get_snapshot
async with datasets.deterministic("2025-12-31"):
print(is_deterministic()) # True
print(get_snapshot()) # "2025-12-31"
print(is_deterministic()) # False
print(get_snapshot()) # None
Use Cases¶
Academic Papers¶
async with datasets.deterministic("2024-12-31"):
df_precos = await datasets.preco_diario("soja")
df_safra = await datasets.estimativa_safra("soja", safra="2024/25")
Backtests¶
async def backtest(data_corte: str):
async with datasets.deterministic(data_corte):
df = await datasets.preco_diario("soja")
return calcular_estrategia(df)
resultados = [await backtest(f"2024-{m:02d}-01") for m in range(1, 13)]
Auditing¶
df, meta = await datasets.preco_diario("soja", return_meta=True)
audit_log = {
"snapshot": meta.snapshot,
"source": meta.source,
"fetched_at": meta.fetched_at.isoformat(),
"records": meta.records_count,
"contract": meta.contract_version,
}
Thread/Async Safety¶
Deterministic mode uses contextvars, ensuring isolation:
- Each async task has its own context
- Different threads do not interfere
- Nested contexts work correctly
async def task_a():
async with datasets.deterministic("2024-01-01"):
assert get_snapshot() == "2024-01-01"
async def task_b():
async with datasets.deterministic("2025-01-01"):
assert get_snapshot() == "2025-01-01"
await asyncio.gather(task_a(), task_b())
Prerequisites¶
For full reproducibility, the local cache must contain the historical data:
- Run the queries normally first (populates the cache)
- Use deterministic mode to reproduce