eolas-data 1.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,101 @@
1
+ name: Catalog drift detector
2
+
3
+ # Pings when the live eolas.fyi catalog has gained namespaces or grown the
4
+ # dataset count significantly without a corresponding library release. Opens
5
+ # (or updates) a single tracking issue rather than spamming.
6
+
7
+ on:
8
+ schedule:
9
+ - cron: "0 7 * * 1" # Mondays 07:00 UTC
10
+ workflow_dispatch:
11
+
12
+ permissions:
13
+ issues: write
14
+ contents: read
15
+
16
+ jobs:
17
+ check:
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+
22
+ - uses: actions/setup-python@v5
23
+ with:
24
+ python-version: "3.12"
25
+
26
+ - name: Compare live catalog to baseline
27
+ id: drift
28
+ run: |
29
+ python <<'PY'
30
+ import json, os, urllib.request
31
+
32
+ # Baseline = the snapshot we shipped in the last release.
33
+ # Drift = anything that's changed since.
34
+ import importlib.util, pathlib
35
+ spec = importlib.util.spec_from_file_location(
36
+ "_dataset_names",
37
+ pathlib.Path("eolas_data/_dataset_names.py"),
38
+ )
39
+ module = importlib.util.module_from_spec(spec)
40
+ spec.loader.exec_module(module)
41
+ baseline = set(module.ALL_NAMES)
42
+ baseline_date = module.CATALOG_SNAPSHOT_DATE
43
+
44
+ with urllib.request.urlopen("https://api.eolas.fyi/v1/datasets", timeout=30) as r:
45
+ live = json.load(r)
46
+ live_names = {d["name"] for d in live}
47
+ live_namespaces = sorted({d["namespace"] for d in live})
48
+
49
+ baseline_namespaces = sorted({n.split("_", 1)[0] for n in baseline}) # crude — better via release-time metadata
50
+
51
+ added = sorted(live_names - baseline)
52
+ removed = sorted(baseline - live_names)
53
+ new_count = len(live_names)
54
+ base_count = len(baseline)
55
+ delta_pct = (new_count - base_count) / max(base_count, 1) * 100
56
+
57
+ # Threshold for "interesting" drift
58
+ significant = (
59
+ len(added) >= 10
60
+ or len(removed) >= 1
61
+ or abs(delta_pct) >= 5.0
62
+ )
63
+
64
+ summary = (
65
+ f"Baseline (release {baseline_date}): {base_count} datasets\\n"
66
+ f"Live now: {new_count} datasets ({delta_pct:+.1f}%)\\n\\n"
67
+ f"Added ({len(added)}): {', '.join(added[:30])}"
68
+ f"{' ...' if len(added) > 30 else ''}\\n\\n"
69
+ f"Removed ({len(removed)}): {', '.join(removed) or 'none'}"
70
+ )
71
+ print(summary)
72
+
73
+ with open(os.environ["GITHUB_OUTPUT"], "a") as f:
74
+ f.write(f"significant={'true' if significant else 'false'}\n")
75
+ f.write(f"new_count={new_count}\n")
76
+ f.write(f"base_count={base_count}\n")
77
+ f.write("summary<<EOF\n")
78
+ f.write(summary.replace("\\n", "\n"))
79
+ f.write("\nEOF\n")
80
+ PY
81
+
82
+ - name: Open or update drift issue
83
+ if: steps.drift.outputs.significant == 'true'
84
+ env:
85
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
86
+ SUMMARY: ${{ steps.drift.outputs.summary }}
87
+ NEW_COUNT: ${{ steps.drift.outputs.new_count }}
88
+ BASE_COUNT: ${{ steps.drift.outputs.base_count }}
89
+ run: |
90
+ set -euo pipefail
91
+ TITLE="Catalog drift: ${BASE_COUNT} → ${NEW_COUNT} datasets"
92
+ BODY=$(printf 'The live API catalog has drifted from the shipped baseline.\n\n%s\n\n---\n\nIf this delta warrants a release: bump version, run `python -m eolas_data._regen_names`, commit, tag, push.\n' "$SUMMARY")
93
+
94
+ # Find an existing open drift issue (label `catalog-drift`) and update it; else create.
95
+ EXISTING=$(gh issue list --label catalog-drift --state open --json number --jq '.[0].number' || true)
96
+ if [ -n "$EXISTING" ]; then
97
+ gh issue edit "$EXISTING" --title "$TITLE" --body "$BODY"
98
+ else
99
+ gh label create catalog-drift --color BFD4F2 --description "Live catalog has drifted from shipped baseline" 2>/dev/null || true
100
+ gh issue create --title "$TITLE" --body "$BODY" --label catalog-drift
101
+ fi
@@ -0,0 +1,31 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+
8
+ jobs:
9
+ publish:
10
+ runs-on: ubuntu-latest
11
+ environment: pypi
12
+ permissions:
13
+ id-token: write
14
+
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+
18
+ - uses: actions/setup-python@v5
19
+ with:
20
+ python-version: "3.12"
21
+
22
+ - name: Install build tools
23
+ run: pip install hatchling build
24
+
25
+ - name: Build
26
+ run: python -m build
27
+
28
+ - name: Publish to PyPI
29
+ uses: pypa/gh-action-pypi-publish@release/v1
30
+ with:
31
+ password: ${{ secrets.PYPI_API_TOKEN }}
@@ -0,0 +1,27 @@
1
+ # Python bytecode
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # Test caches
7
+ .pytest_cache/
8
+ .coverage
9
+ .coverage.*
10
+ htmlcov/
11
+
12
+ # Build / dist
13
+ build/
14
+ dist/
15
+ *.egg-info/
16
+ .eggs/
17
+
18
+ # Virtual environments
19
+ .venv/
20
+ venv/
21
+ env/
22
+
23
+ # Editors
24
+ .idea/
25
+ .vscode/
26
+ *.swp
27
+ .DS_Store
@@ -0,0 +1,214 @@
1
+ Metadata-Version: 2.4
2
+ Name: eolas-data
3
+ Version: 1.2.0
4
+ Summary: Python client for the eolas.fyi statistical data API (NZ, Australia, OECD)
5
+ Project-URL: Homepage, https://eolas.fyi
6
+ Project-URL: Documentation, https://phildonovan.github.io/vswarehouse-docs/
7
+ Project-URL: Repository, https://github.com/phildonovan/eolas-data
8
+ Project-URL: Bug Tracker, https://github.com/phildonovan/eolas-data/issues
9
+ Author-email: Virtus Solutions <phil@virtus-solutions.io>
10
+ License: MIT
11
+ Keywords: api,australia,economics,eolas,new-zealand,statistics
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Scientific/Engineering
22
+ Requires-Python: >=3.10
23
+ Requires-Dist: pandas>=1.5
24
+ Requires-Dist: requests>=2.28
25
+ Provides-Extra: cli
26
+ Requires-Dist: rich>=13; extra == 'cli'
27
+ Requires-Dist: typer>=0.12; extra == 'cli'
28
+ Provides-Extra: dev
29
+ Requires-Dist: geopandas>=0.14; extra == 'dev'
30
+ Requires-Dist: pandas; extra == 'dev'
31
+ Requires-Dist: pytest; extra == 'dev'
32
+ Requires-Dist: responses; extra == 'dev'
33
+ Requires-Dist: rich>=13; extra == 'dev'
34
+ Requires-Dist: shapely>=2.0; extra == 'dev'
35
+ Requires-Dist: typer>=0.12; extra == 'dev'
36
+ Provides-Extra: geo
37
+ Requires-Dist: geopandas>=0.14; extra == 'geo'
38
+ Requires-Dist: shapely>=2.0; extra == 'geo'
39
+ Provides-Extra: plot
40
+ Requires-Dist: matplotlib>=3.5; extra == 'plot'
41
+ Provides-Extra: polars
42
+ Requires-Dist: polars>=0.20; extra == 'polars'
43
+ Description-Content-Type: text/markdown
44
+
45
+ # eolas-data
46
+
47
+ Python client for the [eolas.fyi](https://eolas.fyi) statistical data API — 717+ datasets across NZ, Australia, OECD, and more, served as tidy `pandas` DataFrames (or `polars` / `geopandas` if you prefer).
48
+
49
+ ```bash
50
+ pip install eolas-data
51
+ ```
52
+
53
+ ## Quickstart
54
+
55
+ ```python
56
+ from eolas_data import Client
57
+
58
+ client = Client("your_api_key") # or set EOLAS_API_KEY in env
59
+
60
+ # Generic
61
+ df = client.get("nz_cpi", start="2020-01-01")
62
+
63
+ # Source-specific (sets the `eolas_source` metadata)
64
+ df = client.statsnz("nz_cpi")
65
+ df = client.oecd("nz_gdp_production_annual")
66
+
67
+ # Discovery
68
+ all_datasets = client.list()
69
+ nz_only = client.list("Stats NZ")
70
+ meta = client.info("nz_cpi")
71
+ ```
72
+
73
+ Get an API key at <https://eolas.fyi/signup>. Free plan is 10 requests/month; Starter is 100; Pro is unlimited.
74
+
75
+ ## Command-line interface
76
+
77
+ `pip install eolas-data[cli]` adds an `eolas` command for browsing, fetching, and
78
+ scheduling — useful for shell scripts, cron jobs, and AI-agent workflows. Output
79
+ auto-detects piping: rich tables in a terminal, newline-delimited JSON when
80
+ stdout is piped.
81
+
82
+ ```bash
83
+ # one-time setup
84
+ eolas auth set-key
85
+ eolas health
86
+
87
+ # discover
88
+ eolas datasets list --source "Stats NZ"
89
+ eolas datasets list --search cpi --json | jq '.[].name'
90
+ eolas datasets info nz_cpi
91
+ eolas datasets preview nz_cpi --limit 5
92
+
93
+ # fetch (verb matches the Python lib's client.get())
94
+ eolas get nz_cpi --format csv > cpi.csv
95
+ eolas get nz_cpi --start 2020-01-01 --format json | jq '.[].value'
96
+ eolas get sa2_2023 --format parquet --out sa2.parquet
97
+ ```
98
+
99
+ ### Scheduling
100
+
101
+ Set up recurring fetches without touching crontab/Task Scheduler syntax. Works
102
+ on Linux, macOS (cron), and Windows (Task Scheduler).
103
+
104
+ ```bash
105
+ eolas schedule add nz_cpi --daily --out ~/data/cpi.csv
106
+ eolas schedule add nz_gdp --weekly --out ~/data/gdp.csv
107
+ eolas schedule add nzd_usd --cron "0 */6 * * *" --out ~/data/fx.csv # POSIX only
108
+
109
+ eolas schedule list
110
+ eolas schedule remove nz_cpi
111
+ ```
112
+
113
+ Daily is the default. Pre-flight check refuses to install a schedule unless
114
+ your API key is configured (otherwise the job would fail silently forever).
115
+
116
+ ### Integrations (Enterprise plan)
117
+
118
+ Generate ready-to-run connector configs for popular data-pipeline tools — eolas
119
+ becomes a one-command source for Meltano, Fivetran, or Azure Data Factory.
120
+
121
+ ```bash
122
+ eolas integrate meltano --datasets nz_cpi,nz_gdp --output ./my-pipeline/
123
+ eolas integrate fivetran --datasets nz_cpi
124
+ eolas integrate azure-data-factory --datasets nz_cpi,nz_gdp
125
+ ```
126
+
127
+ The generated directory has everything needed to plug into your destination
128
+ warehouse: `meltano.yml`, `fivetran.yml`, or ADF JSON resources, plus a `README.md`
129
+ walking through the rest of the setup. Non-Enterprise users see a clear
130
+ upgrade pointer; the gating lives server-side so the capability is bypass-proof.
131
+
132
+ ### Exit codes
133
+
134
+ Distinct exit codes per error class, for shell scripts and agents:
135
+
136
+ | Code | Meaning |
137
+ |---|---|
138
+ | `0` | Success |
139
+ | `1` | Generic error |
140
+ | `2` | Auth (`AuthenticationError`, including Enterprise-gate 403) |
141
+ | `3` | Rate limit hit |
142
+ | `4` | Dataset / resource not found |
143
+ | `5` | Other API error |
144
+ | `64` | Bad usage (mirrors `sysexits.h`) |
145
+
146
+ ## Geospatial
147
+
148
+ Datasets with a `geometry_wkt` column auto-convert to `geopandas.GeoDataFrame` if `geopandas` is installed:
149
+
150
+ ```bash
151
+ pip install eolas-data[geo]
152
+ ```
153
+
154
+ ```python
155
+ gdf = client.get("nz_addresses") # GeoDataFrame
156
+ df = client.get("nz_addresses", as_geo=False) # plain DataFrame, WKT preserved
157
+ ```
158
+
159
+ ## Polars
160
+
161
+ ```bash
162
+ pip install eolas-data[polars]
163
+ ```
164
+
165
+ ```python
166
+ df = client.get("nz_cpi", engine="polars")
167
+ ```
168
+
169
+ ## Plotting
170
+
171
+ ```bash
172
+ pip install eolas-data[plot]
173
+ ```
174
+
175
+ ```python
176
+ df = client.statsnz("nz_cpi")
177
+ df.plot_dataset()
178
+ ```
179
+
180
+ ## Type stubs
181
+
182
+ Dataset names are exposed as a `Literal` so IDEs autocomplete the catalog:
183
+
184
+ ```python
185
+ from eolas_data import Client
186
+
187
+ client = Client()
188
+ client.get("nz_") # autocomplete shows nz_cpi, nz_gdp_production_annual, ...
189
+ ```
190
+
191
+ The list is regenerated from the live API at release time. Passing a name not in the snapshot still works at runtime — the type hint just won't autocomplete it. Catalog snapshot date is exposed as `eolas_data._dataset_names.CATALOG_SNAPSHOT_DATE`.
192
+
193
+ ## Migrating from `vswarehouse`
194
+
195
+ The previous package name was `vswarehouse`. Direct equivalents:
196
+
197
+ | `vswarehouse` | `eolas_data` |
198
+ |---|---|
199
+ | `from vswarehouse import Client, VSeries` | `from eolas_data import Client, Dataset` |
200
+ | `df.vs_name`, `df.vs_source` | `df.eolas_name`, `df.eolas_source` |
201
+ | `df.plot_series()` | `df.plot_dataset()` |
202
+ | `VS_API_KEY` env var | `EOLAS_API_KEY` (legacy `VS_API_KEY` still honoured) |
203
+
204
+ The API surface is otherwise identical. The default base URL is now `https://api.eolas.fyi` (the old `https://api.virtus-solutions.io` still 301-redirects and works fine — but uses the legacy endpoint shape).
205
+
206
+ ## Releasing
207
+
208
+ See [`docs/clients.md`](https://github.com/phildonovan/eolas/blob/master/docs/clients.md) in the eolas data repo for the tagged-release flow and PyPI token rotation.
209
+
210
+ Before each release: `python -m eolas_data._regen_names` to refresh the dataset name stubs from the live API, commit the change, then tag and push.
211
+
212
+ ## License
213
+
214
+ MIT
@@ -0,0 +1,170 @@
1
+ # eolas-data
2
+
3
+ Python client for the [eolas.fyi](https://eolas.fyi) statistical data API — 717+ datasets across NZ, Australia, OECD, and more, served as tidy `pandas` DataFrames (or `polars` / `geopandas` if you prefer).
4
+
5
+ ```bash
6
+ pip install eolas-data
7
+ ```
8
+
9
+ ## Quickstart
10
+
11
+ ```python
12
+ from eolas_data import Client
13
+
14
+ client = Client("your_api_key") # or set EOLAS_API_KEY in env
15
+
16
+ # Generic
17
+ df = client.get("nz_cpi", start="2020-01-01")
18
+
19
+ # Source-specific (sets the `eolas_source` metadata)
20
+ df = client.statsnz("nz_cpi")
21
+ df = client.oecd("nz_gdp_production_annual")
22
+
23
+ # Discovery
24
+ all_datasets = client.list()
25
+ nz_only = client.list("Stats NZ")
26
+ meta = client.info("nz_cpi")
27
+ ```
28
+
29
+ Get an API key at <https://eolas.fyi/signup>. Free plan is 10 requests/month; Starter is 100; Pro is unlimited.
30
+
31
+ ## Command-line interface
32
+
33
+ `pip install eolas-data[cli]` adds an `eolas` command for browsing, fetching, and
34
+ scheduling — useful for shell scripts, cron jobs, and AI-agent workflows. Output
35
+ auto-detects piping: rich tables in a terminal, newline-delimited JSON when
36
+ stdout is piped.
37
+
38
+ ```bash
39
+ # one-time setup
40
+ eolas auth set-key
41
+ eolas health
42
+
43
+ # discover
44
+ eolas datasets list --source "Stats NZ"
45
+ eolas datasets list --search cpi --json | jq '.[].name'
46
+ eolas datasets info nz_cpi
47
+ eolas datasets preview nz_cpi --limit 5
48
+
49
+ # fetch (verb matches the Python lib's client.get())
50
+ eolas get nz_cpi --format csv > cpi.csv
51
+ eolas get nz_cpi --start 2020-01-01 --format json | jq '.[].value'
52
+ eolas get sa2_2023 --format parquet --out sa2.parquet
53
+ ```
54
+
55
+ ### Scheduling
56
+
57
+ Set up recurring fetches without touching crontab/Task Scheduler syntax. Works
58
+ on Linux, macOS (cron), and Windows (Task Scheduler).
59
+
60
+ ```bash
61
+ eolas schedule add nz_cpi --daily --out ~/data/cpi.csv
62
+ eolas schedule add nz_gdp --weekly --out ~/data/gdp.csv
63
+ eolas schedule add nzd_usd --cron "0 */6 * * *" --out ~/data/fx.csv # POSIX only
64
+
65
+ eolas schedule list
66
+ eolas schedule remove nz_cpi
67
+ ```
68
+
69
+ Daily is the default. Pre-flight check refuses to install a schedule unless
70
+ your API key is configured (otherwise the job would fail silently forever).
71
+
72
+ ### Integrations (Enterprise plan)
73
+
74
+ Generate ready-to-run connector configs for popular data-pipeline tools — eolas
75
+ becomes a one-command source for Meltano, Fivetran, or Azure Data Factory.
76
+
77
+ ```bash
78
+ eolas integrate meltano --datasets nz_cpi,nz_gdp --output ./my-pipeline/
79
+ eolas integrate fivetran --datasets nz_cpi
80
+ eolas integrate azure-data-factory --datasets nz_cpi,nz_gdp
81
+ ```
82
+
83
+ The generated directory has everything needed to plug into your destination
84
+ warehouse: `meltano.yml`, `fivetran.yml`, or ADF JSON resources, plus a `README.md`
85
+ walking through the rest of the setup. Non-Enterprise users see a clear
86
+ upgrade pointer; the gating lives server-side so the capability is bypass-proof.
87
+
88
+ ### Exit codes
89
+
90
+ Distinct exit codes per error class, for shell scripts and agents:
91
+
92
+ | Code | Meaning |
93
+ |---|---|
94
+ | `0` | Success |
95
+ | `1` | Generic error |
96
+ | `2` | Auth (`AuthenticationError`, including Enterprise-gate 403) |
97
+ | `3` | Rate limit hit |
98
+ | `4` | Dataset / resource not found |
99
+ | `5` | Other API error |
100
+ | `64` | Bad usage (mirrors `sysexits.h`) |
101
+
102
+ ## Geospatial
103
+
104
+ Datasets with a `geometry_wkt` column auto-convert to `geopandas.GeoDataFrame` if `geopandas` is installed:
105
+
106
+ ```bash
107
+ pip install eolas-data[geo]
108
+ ```
109
+
110
+ ```python
111
+ gdf = client.get("nz_addresses") # GeoDataFrame
112
+ df = client.get("nz_addresses", as_geo=False) # plain DataFrame, WKT preserved
113
+ ```
114
+
115
+ ## Polars
116
+
117
+ ```bash
118
+ pip install eolas-data[polars]
119
+ ```
120
+
121
+ ```python
122
+ df = client.get("nz_cpi", engine="polars")
123
+ ```
124
+
125
+ ## Plotting
126
+
127
+ ```bash
128
+ pip install eolas-data[plot]
129
+ ```
130
+
131
+ ```python
132
+ df = client.statsnz("nz_cpi")
133
+ df.plot_dataset()
134
+ ```
135
+
136
+ ## Type stubs
137
+
138
+ Dataset names are exposed as a `Literal` so IDEs autocomplete the catalog:
139
+
140
+ ```python
141
+ from eolas_data import Client
142
+
143
+ client = Client()
144
+ client.get("nz_") # autocomplete shows nz_cpi, nz_gdp_production_annual, ...
145
+ ```
146
+
147
+ The list is regenerated from the live API at release time. Passing a name not in the snapshot still works at runtime — the type hint just won't autocomplete it. Catalog snapshot date is exposed as `eolas_data._dataset_names.CATALOG_SNAPSHOT_DATE`.
148
+
149
+ ## Migrating from `vswarehouse`
150
+
151
+ The previous package name was `vswarehouse`. Direct equivalents:
152
+
153
+ | `vswarehouse` | `eolas_data` |
154
+ |---|---|
155
+ | `from vswarehouse import Client, VSeries` | `from eolas_data import Client, Dataset` |
156
+ | `df.vs_name`, `df.vs_source` | `df.eolas_name`, `df.eolas_source` |
157
+ | `df.plot_series()` | `df.plot_dataset()` |
158
+ | `VS_API_KEY` env var | `EOLAS_API_KEY` (legacy `VS_API_KEY` still honoured) |
159
+
160
+ The API surface is otherwise identical. The default base URL is now `https://api.eolas.fyi` (the old `https://api.virtus-solutions.io` still 301-redirects and works fine — but uses the legacy endpoint shape).
161
+
162
+ ## Releasing
163
+
164
+ See [`docs/clients.md`](https://github.com/phildonovan/eolas/blob/master/docs/clients.md) in the eolas data repo for the tagged-release flow and PyPI token rotation.
165
+
166
+ Before each release: `python -m eolas_data._regen_names` to refresh the dataset name stubs from the live API, commit the change, then tag and push.
167
+
168
+ ## License
169
+
170
+ MIT
@@ -0,0 +1,16 @@
1
+ """eolas-data — Python client for the eolas.fyi statistical data API."""
2
+ from .client import Client
3
+ from .dataset import Dataset
4
+ from .exceptions import APIError, AuthenticationError, EolasError, NotFoundError, RateLimitError
5
+
6
+ __version__ = "1.2.0"
7
+
8
+ __all__ = [
9
+ "Client",
10
+ "Dataset",
11
+ "EolasError",
12
+ "AuthenticationError",
13
+ "RateLimitError",
14
+ "NotFoundError",
15
+ "APIError",
16
+ ]