# opensdmx tells you to check constraints before you build a query

> ondata's opensdmx is a Python command line tool and library for statistical data exchange APIs, with Eurostat as the default provider and several national and international sources supported. Its central practical rule is that you must ask the API which codes a dataset contains today, because the codes change under a dataset's title.

**ondata/opensdmx** — Python CLI and library for any SDMX 2.1 REST API — Eurostat, ISTAT, OECD, ECB, World Bank and more. AI-ready.

- Repository: https://github.com/ondata/opensdmx
- Stars: 55 · Forks: 7
- Language: Python
- License: MIT
- Published: 2026-08-27 · Updated: 2026-08-27 · Language: en
- Canonical page: https://hysenlabs.com/projects/ondata-opensdmx

## The pitch is that the model writes the query

The argument the README makes is about a specific failure mode. Large language models are good at understanding a question, but they fabricate numerical data, and it cites research suggesting generated answers are inaccurate up to two-thirds of the time. So the pattern it recommends is to use a model to generate structured API queries rather than to generate the numbers, with this tool acting as the execution layer that fetches the exact published figure. That framing is the whole reason the interface is shaped as it is: discrete subcommands for search, info, constraints, get, run and plot, each of which an agent can call in sequence, plus a saved query file so the same call can be repeated. The project is candid that it also works on its own, and that a human analyst runs the same three flows daily.

## Constraints first, because codes expire under a title

The most useful instruction in the README is a rule rather than a command. Check the constraints, not the dataset title. A dataflow's dimensions change over time, with codes appearing and disappearing, so a code that was valid last year may not be valid today. The constraints command asks the API which values a dataset actually contains right now, either across all dimensions with a code sample or in full for one dimension:

```bash
opensdmx constraints UNE_RT_M        # all dimensions, with a code sample
opensdmx constraints UNE_RT_M age    # full list for one dimension
```

Only codes returned there are safe to use as filters. A code taken from the general codelist instead may not exist in that specific dataset, and the API answers with a 400. There is a cheap middle ground when you want to avoid the full download, a flag that fetches one observation per series so you can test a query before committing to it.

## A saved query file turns a download into a recipe

The second mechanism is that any query can be written to a file and re-run later without remembering its parameters:

```bash
opensdmx get TIPSUN20 --sex T --age Y15-74 --start-period 2020 --query-file unemployment.yaml
opensdmx run unemployment.yaml --out results.csv
```

The point of this is not convenience, it is reproducibility, and the README says so explicitly. A month later the same command produces the same request without anyone reconstructing the arguments, and the file doubles as something you can commit and share. It also stores the human-readable descriptions of the filters alongside the codes, so the recipe is legible to the next person rather than being a wall of short strings. Two smaller habits are recommended with equal seriousness: add the dimensions that have only one value rather than assuming a wildcard is free, and pass the labels flag early, because it costs nothing, converts codes into names like a country or an age bracket, and there is no penalty for leaving it on.

## Semantic search is the one command needing a local model

The installation section makes a precise claim: everything except semantic search works with a plain install. The command that searches the catalogue semantically additionally needs a local model server and a one-off index build, so a first-time user who skips that step finds one command failing while the rest work fine. That is a sensible boundary, since local embedding is a heavy thing to make mandatory for a tool whose other operations are plain HTTP. The same section is unusually thorough about the install variants, which matters because there are three: a tool install that puts the command on the system path, an add for use as a library dependency, and a plain pip install. It also gives three separate upgrade commands, one per install method, so you can upgrade without changing how you installed it.

```bash
uv tool install opensdmx
```

## Three cache lifetimes with different rationales

The example environment file is where the engineering judgement shows. Three separate caches exist, each with its own lifetime and a stated reason. The dataflow catalogue, stored as a parquet file, defaults to seven days. The structure dimensions and the codelist descriptions and values, stored in SQLite, default to thirty days, because that metadata changes far more slowly than the catalogue listing does. The available constraints per dataflow default to seven days again. That ordering is the interesting part: the slow-changing layer is cached longest, which is what you would do if you had measured it, and the fact that the defaults differ at all suggests someone did. There is also an output format setting defaulting to a table with JSON and CSV available, and the file is explicit that an explicit flag on the command line always beats the setting.

## The SOCKS proxy story is fixed from one version onward

One note in the installation section is a small piece of engineering history worth keeping. From a particular version, the project bundles the proxy support of its HTTP client, so it works out of the box where all traffic is routed through a SOCKS proxy, which is the situation inside some sandboxed environments. On older versions, network calls fail with an import error rather than anything resembling a network problem, which is a genuinely confusing symptom. The fix given is a one-off patch to the isolated tool environment, and the command that does it is a small lesson in itself: it locates the interpreter inside the tool directory by searching for a matching binary and passing it to the installer explicitly, rather than relying on whichever Python happens to be active in the shell.

```bash
uv pip install \
  --python "$(find ~/.local/share/uv/tools/opensdmx -name 'python3*' -type f | head -1)" \
  socksio "httpx[socks]"
```

## Strict type checking, and a list of libraries that opt out

The project configuration is short enough to read as a statement of intent. The package requires Python 3.12 or newer and is classified as beta, with a single console entry point. The dependency list is deliberately broad in one direction and narrow in another: two dataframe libraries and an arrow library suggest that output format is a real feature rather than an afterthought, a grammar of graphics library explains the plotting command, and a retry library plus a terminal formatting library account for a client that talks to slow remote APIs and prints tables. The tooling section is the interesting part. The type checker runs in strict mode over the source tree, the linter has one suppression rule and it is an import-order rule, and the type checker carries an explicit list of third-party libraries whose stubs are missing and are therefore ignored.

## The readme calls the project experimental

The first note in the README, above the description and above the installation instructions, says this is an experimental tool and asks people to help test it by opening issues or sharing feedback. That framing is worth taking seriously rather than skipping. The releases are numbered in the zero-hundreds, the most recent within days of the last commit, and the version in the manifest matches the newest tag, so the project is moving quickly and releasing often. The package is offered under a permissive licence and its own repository carries the same one. Two structural choices also stand out. The repository ships a directory of agent skills, including a guided explorer that walks the discovery flow conversationally, and a lock file for whatever those skills depend on, which tells you that the tool is being built to be driven by an agent as much as by a person. A separate documentation set includes an architecture page with a design philosophy section, and that is where the reasoning lives.

## Conclusion

opensdmx suits an analyst or agent that has to produce exact published figures from a statistical API without a model inventing the numbers, and it suits a team that wants a saved query file as the unit of reproducibility. It does not suit anyone who needs a semantic search over the catalogue without running a local model first, or who wants a documented stable schema, since the project describes itself as experimental. Before adopting it, check three things: which provider you actually need, since the default is one country's statistics office, whether your network is proxied, which changes your install, and whether the caching defaults suit how fast the upstream catalogues change.

## FAQ

### What is the SDMx format that opensdmx talks to?

It is a standard for exchanging statistical data over a REST interface, and this tool is a client for any implementation of version 2.1 of it. Data is organised as dataflows with dimensions, each dimension has codes, and a query selects codes from the dimensions to fetch the observations.

### Why does opensdmx tell me to check constraints before building a query?

Because a dataflow's dimensions change over time, so codes appear and disappear. The constraints command asks the dataset which values it actually contains now, and only those codes are safe as filters. A code taken from the general codelist may not exist in that dataset and the request comes back with a 400.

### What does semantic search in opensdmx need that other commands do not?

A local model server and a one-off index build. Everything else in the tool works with a plain install, while the semantic search flag on the search command is the one part that needs the local model running first.

### Which settings can I change in opensdmx without editing code?

Three cache lifetimes and an output format. The dataflow catalogue and the per-dataset constraints default to seven days, structure dimensions and codelist descriptions to thirty days, and the output defaults to a table with JSON and CSV available. An explicit output flag on the command line always overrides the setting.

## Sources

- [Official README](https://github.com/ondata/opensdmx#readme)
- [Project repository](https://github.com/ondata/opensdmx)
- [Release notes](https://github.com/ondata/opensdmx/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/ondata-opensdmx
