Small, dependency-free Python examples for working with the ODR API.
Each script reads its configuration from .env in this directory
(copy env.example if you need a fresh one) and uses nothing outside
the Python standard library.
cp env.example .env # then fill in the values| Setting | Meaning |
|---|---|
ODR_API_BASE_URL |
ODR host, no trailing slash. On WordPress-integrated sites this is the ODR alias, e.g. https://dev.rruff.net/odr_rruff |
ODR_API_USERNAME / ODR_API_PASSWORD |
Account allowed to authenticate at /api/v5/token. Public data needs no special permissions |
ODR_AMCSD_DATASET_UUID |
Dataset (database) uuid; defaults to AMCSD |
ODR_VERIFY_TLS |
0 accepts self-signed certs. Dev only |
Real environment variables take precedence over .env, and
--base-url / --dataset-uuid / --env override both.
.env is gitignored — it holds credentials, so don't commit it.
Finds an AMCSD record by its database_code_amcsd value and downloads
its CIF. The same example is provided in two languages -- they take the
same arguments, print the same output and return the same exit codes, so
pick whichever suits you:
| File | Runtime | Requirements |
|---|---|---|
amcsd_download_cif.py |
Python 3 | standard library only |
amcsd_download_cif.js |
Node.js 18+ | no dependencies |
The examples below show the Python version; swap in ./amcsd_download_cif.js
for Node.
# Minimal CIF for one record
./amcsd_download_cif.py 0000035
# ...and the Original CIF too, when the record has one
./amcsd_download_cif.py 0014553 --original
# Show every field in the AMCSD database with its uuid
./amcsd_download_cif.py --show-template
# Write somewhere other than the current directory
./amcsd_download_cif.py 0000035 --out ./cifsFiles are saved under the name ODR holds for them, e.g.
Abellaite__0014553.cif. Exit status is 0 on success, 1 when nothing
matched or no file was attached, and 2 on an API error.
POST /api/v5/token— exchange the credentials for a JWT.GET /api/v5/template/<dataset_uuid>— the database template, which maps each field to its uuid.POST /api/v5/dataset/<dataset_uuid>/search/<limit>/<offset>— search byfield_uuid, sending the code as a plain value.GET <file href>— each file in the response carries its own download link; the JWT is sent along so restricted files work for an account that may see them.
Every call addresses things by uuid. The numeric field ids at the top of
the script (7191 database_code_amcsd, 7195 Minimal CIF, 8050
Original CIF) are only used to look up those uuids in the template, so
they can be repointed at another database by changing the ids and the
dataset uuid.
Two details worth knowing if you adapt this:
- Don't quote values for an exact match. ODR treats surrounding
quotes as literal characters on these fields, so
"0000035"finds nothing. The script sends the raw value and then confirms the exact match against the results itself, since a text search can return more than one record. - Search responses are paged. They come back as
{"results": N, "offset": N, "limit": N, "records": [...]}, whereresultsis the total. Without a limit the server returns 25 records, and the maximum per request is 100.