Overview
silo-client is a small Python client for the Data API. One class, one method per endpoint, PostgREST underneath.
It exists to make the two things that bite hand-written callers impossible to miss: a capped response raises instead of returning a short series, and views page while functions do not.
It lives in the repository and is not on PyPI, deliberately, while the API’s surface is still moving.
Install
sdk/silo_client/ into your project.
Configure
url= / key= or set SILO_URL / SILO_ANON_KEY to override the built-in project and key. To move to the signed-in tier, pass a user JWT as token= (or set SILO_TOKEN); silo.tier says which ceiling you are under.
First calls
panel validates metric names against the live catalog, so a typo raises ValueError client-side instead of returning an empty panel. Missing observations stay NaN — never filled.
ids and metrics each accept one bare string or any sequence of them. The single-string case is handled explicitly, not left to Python’s sequence semantics: str is a Sequence[str], so an unguarded list("PETR4") would ask for five one-character ids and the server’s empty answer would read as “no data for PETR4”.
Every method
One per published endpoint. Dates acceptdate objects or ISO strings; None means the server’s default, which for fund windows is the honest one.
The three rules the client enforces
A capped response raises
PostgREST stops every response at 1,000 rows and answers200 with the oldest page. The client asks for a true count (Prefer: count=exact) and raises rather than hand you the short answer:
SiloOverCap), and each pages with its own cursor:
option_history, termo_history, financials, company_financials, anbima_classes, inflation, inflation_items, fidc_tranches, fidc_aging, fund_documents, fund_restatements, fund_restatement_diff, company_events, macro_series, ptax, future_curve, future_series, curve, curve_history and the screen_* functions there is no cursor: SiloOverCap means narrow the window.
panel(wide=True) refuses to pivot a CNPJ that files under two families in the same month — pass entity_type=, or take wide=False and keep asset_class in your own key.
Views page; functions do not
view_all / iter_view require an order — offset paging without a total order can duplicate a row at one boundary and drop one at the next. A view() with no limit that lands on the cap still raises: that is the silent cut, not a page.
The client tells you when it is out of date
catalog() compares the server’s catalog version against the one the client was written for and warns SiloCatalogDrift on a mismatch. It never refuses — everything read off the catalog keeps working. silo.limits() is the tier table straight from the server.
Errors
The client never retries a 4xx into a different answer, and connection retries are safe only because every endpoint is read-only.
Source
sdk/silo_client/client.py is short enough to read in one sitting, and tests/test_sdk_client.py is the contract: offline, via httpx.MockTransport, no network.