commovision
The Python client and command line for the CommoVision oil and gas data API.
It wraps the REST contract at api.commovision.com: keyed requests, cursor
pagination, CSV and DataFrame loading, bulk extracts, and the change feed.
The full endpoint reference lives at https://api.commovision.com/docs.
Install
pip install commovision
DataFrame loading is optional: pip install "commovision[polars]" or
pip install "commovision[pandas]".
Quickstart
Three steps from a key to data.
-
Create a key in the portal at
app.commovision.comunder Account & settings, API keys, and put it in theCOMMOVISION_API_KEYenvironment variable. The key is shown once: store it in a secrets manager or an environment variable, never in code. -
Confirm the key works and read what it can access. A result confirms the key;
entitlementslists what your plan grants:import commovision client = commovision.Client() print(client.me()["entitlements"])
-
Make your first data call.
rowswalks pages for you; filters pass through exactly as the reference spells them:for well in client.rows("wells", state_province="Texas", limit=10): print(well["well_id"], well["well_name"])
limit is the most rows you want IN TOTAL, across every page. Leave it unset
and the walk reads the whole selection, which on a wide filter is a large pull:
one request per page, and every row counts against your plan's budget.
page_size sets how many rows one request asks for; leave it unset and the
server chooses.
DataFrames
wells = client.frame(
"wells",
state_province="Texas",
basin="Permian Basin",
trajectory="horizontal",
limit=5000,
) # polars; client.df(...) returns pandas
One well's monthly series, by its opaque well_id:
series = client.frame(f"wells/{wells['well_id'][0]}/production", month="2020-01..")
Treat well_id and every other id as an opaque string.
Whole-selection CSV
Register routes stream your whole filtered selection as one download, without paging. The server refuses up front when the selection does not fit your remaining budget, so a download is never cut short for budget:
client.export_csv("permits", "tx_permits.csv", state_province="Texas")
A download writes a temporary file beside its destination and renames over it,
so the destination is replaced rather than written through. A path that exists
and is not a regular file is refused for that reason: -o /dev/null would
replace the null device rather than discard the bytes. Name a file, or a path
that does not exist yet.
One consequence of that, worth knowing before it surprises you: a destination
that is a symlink to a regular file is replaced by a regular file, so the file
it pointed at is left untouched and stops being updated. If you keep something
like latest.parquet as a link into a shared directory, download to the real
path and update the link yourself. Resolving the link and writing through it
would be the worse behaviour, because a partly written file would then be
visible to everything reading the shared copy.
Bulk extracts and the change feed
For a whole table, download a prebuilt extract, then keep it current from the change feed instead of re-downloading:
catalog = client.extracts()
record = client.download_extract("tx", "well_production", "tx_production.parquet")
feed = client.changes("tx", "well_production", from_version=record["version"])
for page in feed:
apply_upserts_and_deletes(page.rows) # your upsert by key, delete by key
store(feed.cursor) # the resume point
A stored cursor resumes for 60 days. One past that raises
commovision.CursorExpired, whose resync_extract names the extract to
reload before starting the feed again from its version.
Command line
commovision wells --state-province Texas --limit 1000 --csv > tx_wells.csv
commovision wells --state-province Texas --all -o tx_wells.csv
commovision me
commovision extract tx well_production -o tx_production.parquet
commovision changes tx well_production --from-version 3 --state-file tx.cursor
commovision get /oil-gas/v1/freshness
Filter flags pass through as query parameters, so the command line serves
every filter the API serves; an unknown one is refused by the server with the
parameter named. --limit is the most rows in total and --page-size the rows
per request; --all writes the whole selection and takes neither. Pass the key
in COMMOVISION_API_KEY rather than --key, which is visible to every user of
the machine and lands in shell history and CI logs.
Exit codes a script can branch on:
| Code | Means |
|---|---|
| 0 | done |
| 2 | a usage error, or a request the server refused |
| 3 | the change cursor expired: reload the extract named on stderr |
| 4 | over quota |
Pacing and errors
Your plan states a rolling 24-hour row ceiling, and on some plans a monthly
allowance; every data response reports both in its headers. The client sleeps
out a short 429 or 503 wait on its own and retries. A wait longer than
max_retry_wait (120 seconds by default) is not slept: the client raises
instead, so a monthly refusal surfaces as an exception rather than a
weeks-long sleep.
Every failure the API itself reports raises commovision.APIError, carrying
the API's error body:
branch on error.code (a stable identifier such as invalid-parameter), read
error.retry_after where the answer named one, and quote error.request_id
when you write to us at https://commovision.com/contact/. Two subclasses mark
the cases a script usually handles on its own:
| Exception | Raised for |
|---|---|
commovision.QuotaExceeded |
a 429: a row quota, or the per-account in-flight bound |
commovision.CursorExpired |
a 410 on the change feed; resync_extract names the extract to reload |
commovision.ChecksumMismatch |
a downloaded extract that does not match the sha256 its issuance stated: download it again rather than retrying the issuance |
commovision.CommoVisionError |
the client's own refusals: no key, a missing optional extra, a parameter a walk sets itself |
The first two are APIError; all four are commovision.CommoVisionError, so
one except commovision.CommoVisionError catches everything this package
raises.
One name to know when you set page_size: it rides as the request's own
limit, so a value above a route's maximum comes back as a 400 naming
limit. Leaving page_size unset lets the server choose, which is the right
default; set it when you would rather make fewer, larger requests.
Versioning
This package follows the API's own compatibility promise rather than an internal one, because people depend on it from outside:
- Additive change ships freely in minor and patch releases: new methods, new optional parameters, new fields in returned data. Write your code to ignore fields it does not recognize.
- A breaking change to this package ships only as a new major version, announced in the changelog below.
- The API itself versions by namespace: a breaking API change ships as a new namespace and the prior one keeps working for at least six months after the announcement (reference, "Versioning").
License
MIT. Keep the copyright notice with the code and there is nothing else to
observe; the full text ships in the package as LICENSE.
Changelog
- 0.1.0: first release. Keyed requests with pacing, cursor pagination, CSV and DataFrame loading, whole-selection export, bulk extract download with checksum verification, the change feed, and the command line.
Metadata
Release files for commovision 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| commovision-0.1.0.tar.gz | 24.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| commovision-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 47.3 kB
Release files / commovision-0.1.0.tar.gz
| Download URL | commovision-0.1.0.tar.gz |
|---|---|
| Size | 24.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c59cb021a216db0ac43bbedf4e4cb336b65b390b40b001547f78864e14e3186b
|
|
BLAKE2b-256 checksum How to use checksums |
361fb6372f1f57511900b614b11070b351a7c69fd13d444a912bea5bec89a5e4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / commovision-0.1.0-py3-none-any.whl
| Download URL | commovision-0.1.0-py3-none-any.whl |
|---|---|
| Size | 22.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d838ba89878b2e760e122f55a6eb294bdc3e116bab11dc35daa8203d34837922
|
|
BLAKE2b-256 checksum How to use checksums |
82ac1eeb33692287131543ac6b45c3169ccf4b5fb3fd4da04dca54d8e52377d1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|