ausdata-sdk 0.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,30 @@
1
+ # Build artefacts
2
+ dist/
3
+ build/
4
+ *.egg-info/
5
+ *.egg
6
+ __pycache__/
7
+ *.pyc
8
+ *.pyo
9
+
10
+ # Virtual envs
11
+ .venv/
12
+ venv/
13
+ env/
14
+
15
+ # Tooling caches
16
+ .pytest_cache/
17
+ .ruff_cache/
18
+ .mypy_cache/
19
+ .coverage
20
+ htmlcov/
21
+
22
+ # uv lock retained but exclude editor/system files
23
+ .DS_Store
24
+ .idea/
25
+ .vscode/
26
+ *.swp
27
+
28
+ # Local env files
29
+ .env
30
+ .env.local
@@ -0,0 +1,61 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. Versioning follows
4
+ [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
5
+
6
+ ## [0.2.0] — 2026-05-17
7
+
8
+ ### Distribution
9
+
10
+ - **PyPI distribution name changed:** `ausdata` → `ausdata-sdk` (the
11
+ short `ausdata` name was taken by another project on PyPI). The
12
+ **import path stays `from ausdata import Client`** — no code changes
13
+ required for existing users. Install command:
14
+ `pip install ausdata-sdk` (was `pip install ausdata`).
15
+
16
+ ### Added
17
+
18
+ - `client.whoami()` / `AsyncClient.whoami()` — caller introspection.
19
+ - `client.describe(source, dataset_id)` / async equivalent — schema lookup.
20
+ - `client.list_datasets(source)` / async equivalent — enumerate a source's
21
+ curated datasets.
22
+ - `client.get_data(source, dataset_id, **filters)` / async equivalent —
23
+ generic data fetch with kwargs for source-specific dimension filters.
24
+ - `WhoamiResponse` typed model.
25
+ - Drift-detection tests (`tests/test_model_drift.py`) — fail CI when the
26
+ SDK model fields diverge from the live API response shape.
27
+
28
+ ### Changed
29
+
30
+ - Default base URL is now `https://ausdata-api.fly.dev` (was the unconfigured
31
+ `https://api.ausdata.io`). Override via `AUSDATA_BASE_URL` env var or the
32
+ `base_url` constructor arg.
33
+ - `EconomicDashboard` model gained `consumer_spending_yoy_pct`. The old
34
+ `lending_housing_change_qoq_pct` field is kept as a deprecated alias and
35
+ will be removed in v0.2.
36
+
37
+ ## [0.1.0] — 2026-05-16
38
+
39
+ Initial scaffold.
40
+
41
+ ### Added
42
+ - Synchronous `Client` and asynchronous `AsyncClient` over httpx.
43
+ - API-key resolution: constructor arg, then `AUSDATA_API_KEY` env var.
44
+ - Typed response models mirroring the ausdata-api `ApiResponse` envelope
45
+ (`Meta`, `Links`, `SourceCitation`, plus per-endpoint payload shapes).
46
+ - Endpoint methods for the v1 MVP surface:
47
+ - `health()`
48
+ - `account.api_key()` / `account.rotate_key()`
49
+ - `search_datasets(q, source, limit)`
50
+ - `real_wages(start, end, seasonal_adjustment)`
51
+ - `economic_dashboard(period)`
52
+ - Convenience: `ApiResponse.to_dataframe()` (requires `pandas` extra),
53
+ `to_csv(path=None)`, `to_json()`.
54
+ - Typed exception hierarchy (`AusdataError`, `AuthenticationError`,
55
+ `PermissionError`, `RateLimitError`, `ValidationError`, `UpstreamError`,
56
+ `AusdataServerError`) — each carries the API's hint string.
57
+ - Automatic retry policy: 5xx and 429 retried with exponential backoff,
58
+ `Retry-After` header respected up to 60s, configurable via constructor.
59
+ - `py.typed` marker so downstream users get full IDE type completion.
60
+ - Test suite (40+ tests) covering successful parsing, auth, errors, retries,
61
+ pandas integration, and the async surface. All mocked — no live calls.
@@ -0,0 +1,115 @@
1
+ # ausdata-sdk — developer notes
2
+
3
+ The official Python client library for the hosted REST API at
4
+ [ausdata.io](https://ausdata.io). Layer 3's public face — thin HTTP wrapper,
5
+ not a data engine.
6
+
7
+ **One-line value prop:** `pip install ausdata-sdk` (imports as `from ausdata import Client`) and call typed methods against
8
+ the hosted API; no MCP runtime, no SDMX parsing, no upstream credentials.
9
+
10
+ ## License
11
+
12
+ **MIT.** This package is intentionally MIT (not FSL like `ausdata-api`)
13
+ because the SDK is a trivial HTTP wrapper — the moat lives in the API
14
+ backend, not here. Permissive licensing maximises adoption + makes
15
+ enterprise legal teams happy.
16
+
17
+ The upstream FastAPI in `../ausdata-api/` is FSL-1.1-MIT; that's where
18
+ competitors would lift code and the licence does the work.
19
+
20
+ ## Layout
21
+
22
+ ```
23
+ src/ausdata/
24
+ ├── __init__.py Re-exports Client, AsyncClient, models, exceptions
25
+ ├── client.py Synchronous Client (httpx.Client)
26
+ ├── async_client.py AsyncClient (httpx.AsyncClient)
27
+ ├── models.py Pydantic ApiResponse envelope + per-endpoint payloads
28
+ ├── exceptions.py AusdataError + 6 typed subclasses
29
+ ├── py.typed PEP 561 marker — full IDE type completion downstream
30
+ └── _internal/
31
+ ├── http.py API-key resolution, default headers, error mapping
32
+ └── retry.py RetryPolicy (5xx + 429 with Retry-After)
33
+
34
+ tests/
35
+ ├── conftest.py Canned API response fixtures (all mocked via pytest-httpx)
36
+ ├── test_client.py Sync client construction + headers + base_url
37
+ ├── test_async_client.py
38
+ ├── test_endpoints.py Success-path test per public method
39
+ ├── test_exceptions.py 4xx/5xx → typed exception mapping
40
+ ├── test_retry.py Backoff math + end-to-end retry behaviour
41
+ └── test_to_dataframe.py pandas/CSV/JSON conversions
42
+ ```
43
+
44
+ ## Cross-links
45
+
46
+ - **API spec** (private): `../API_DESIGN_V1.md` — every endpoint here mirrors
47
+ what the API exposes. If you add an endpoint method, update both files.
48
+ - **API server** (private): `../ausdata-api/` — when its response shape
49
+ changes, mirror the change in `models.py` here. Add new optional fields
50
+ rather than breaking changes whenever possible so old SDK versions stay
51
+ compatible with new servers.
52
+ - **Portfolio strategy** (private): `../STRATEGY.md` — the SDK is intentionally
53
+ separate from the 9 sister MCP packages on PyPI; don't blur the line.
54
+
55
+ ## Development
56
+
57
+ ```bash
58
+ cd ausdata-sdk
59
+ uv sync --extra dev
60
+ uv run pytest -q
61
+ uv run ruff check src tests
62
+ uv build
63
+ ```
64
+
65
+ All tests use `pytest-httpx` — there are zero live API calls in the suite.
66
+ This is deliberate: SDK tests should run in CI without secrets and in <2s.
67
+
68
+ ## Test patterns
69
+
70
+ - One success-path test per endpoint method (see `test_endpoints.py`)
71
+ - One typed-exception test per HTTP status the API uses (`test_exceptions.py`)
72
+ - Retry behaviour is tested both unit-style (`RetryPolicy` math) and
73
+ integration-style (full `Client.health()` calls with mocked 500s)
74
+ - pandas import failure is tested by patching `builtins.__import__` so the
75
+ test runs even if pandas is installed in the dev environment
76
+
77
+ ## Anti-patterns — don't do these
78
+
79
+ - **Don't auto-publish to PyPI.** The user runs `uv publish` when ready.
80
+ CI here only lints + tests; no Trusted Publishing workflow yet.
81
+ - **Don't push to a public GitHub remote** until the user explicitly creates
82
+ it. Local commits only for now.
83
+ - **Don't add new runtime dependencies beyond `httpx` + `pydantic`** (plus
84
+ `pandas` as an optional extra). The SDK's value is being lightweight.
85
+ - **Don't import from any sister MCP package** (`abs_mcp`, `rba_mcp`, etc.).
86
+ The SDK talks to the hosted API only — that's the whole point of the
87
+ layered architecture.
88
+ - **Don't build a CLI here.** A future `ausdata-cli` package can wrap this
89
+ SDK; keep them separate.
90
+ - **Don't reimplement data parsing.** All shaping happens in `ausdata-api`'s
91
+ composers + the sister MCPs they call.
92
+ - **Don't echo tokens or API keys** in logs, errors, or test output.
93
+
94
+ ## Adding a new endpoint method
95
+
96
+ 1. Confirm the API supports it (`../ausdata-api/src/ausdata_api/routers/`).
97
+ 2. Add the payload shape to `src/ausdata/models.py` if it isn't already
98
+ there. Prefer optional fields so older SDK versions don't break.
99
+ 3. Add a method to both `Client` and `AsyncClient` (parameters mirror
100
+ the API query string, kwarg-only where it improves readability).
101
+ 4. Add at least one success-path test (`test_endpoints.py`) and any
102
+ relevant error-path test (`test_exceptions.py`).
103
+ 5. Update `README.md` (endpoint table) + `CHANGELOG.md` (new entry).
104
+
105
+ ## Releasing (when the user is ready)
106
+
107
+ 1. Bump `version` in `pyproject.toml` + `src/ausdata/__init__.py`.
108
+ 2. Update `CHANGELOG.md`.
109
+ 3. `uv run pytest -q` 10x — zero flakes.
110
+ 4. `uv run ruff check src tests` — clean.
111
+ 5. `uv build` — wheel + sdist build cleanly.
112
+ 6. `uv publish` — **user runs this**, not Claude.
113
+
114
+ PyPI new-project rate limit: 5 per account per 24h. Plan first publish
115
+ accordingly; the user handles this.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Harry Vass
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,193 @@
1
+ Metadata-Version: 2.4
2
+ Name: ausdata-sdk
3
+ Version: 0.2.0
4
+ Summary: Python SDK for the Australian public data API. Free tier available at ausdata.io.
5
+ Project-URL: Homepage, https://ausdata.io
6
+ Project-URL: Documentation, https://docs.ausdata.io
7
+ Project-URL: Repository, https://github.com/Bigred97/ausdata-sdk
8
+ Project-URL: Issues, https://github.com/Bigred97/ausdata-sdk/issues
9
+ Author: Harry Vass
10
+ License: MIT License
11
+
12
+ Copyright (c) 2026 Harry Vass
13
+
14
+ Permission is hereby granted, free of charge, to any person obtaining a copy
15
+ of this software and associated documentation files (the "Software"), to deal
16
+ in the Software without restriction, including without limitation the rights
17
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18
+ copies of the Software, and to permit persons to whom the Software is
19
+ furnished to do so, subject to the following conditions:
20
+
21
+ The above copyright notice and this permission notice shall be included in all
22
+ copies or substantial portions of the Software.
23
+
24
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30
+ SOFTWARE.
31
+ License-File: LICENSE
32
+ Keywords: api,australia,client,mcp,public-data,sdk
33
+ Classifier: Development Status :: 4 - Beta
34
+ Classifier: License :: OSI Approved :: MIT License
35
+ Classifier: Programming Language :: Python :: 3.11
36
+ Classifier: Programming Language :: Python :: 3.12
37
+ Classifier: Programming Language :: Python :: 3.13
38
+ Classifier: Topic :: Internet :: WWW/HTTP
39
+ Classifier: Topic :: Scientific/Engineering :: Information Analysis
40
+ Classifier: Typing :: Typed
41
+ Requires-Python: >=3.11
42
+ Requires-Dist: httpx>=0.27
43
+ Requires-Dist: pydantic>=2.7
44
+ Provides-Extra: dev
45
+ Requires-Dist: pandas>=2.0; extra == 'dev'
46
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
47
+ Requires-Dist: pytest-httpx>=0.30; extra == 'dev'
48
+ Requires-Dist: pytest>=8; extra == 'dev'
49
+ Requires-Dist: ruff>=0.5; extra == 'dev'
50
+ Provides-Extra: pandas
51
+ Requires-Dist: pandas>=2.0; extra == 'pandas'
52
+ Description-Content-Type: text/markdown
53
+
54
+ # ausdata — Python SDK for the Australian public data API
55
+
56
+ The official Python client for [ausdata.io](https://ausdata.io). One auth key,
57
+ one uniform response envelope, every major Australian government data source.
58
+
59
+ ```bash
60
+ pip install ausdata-sdk
61
+ # or, with pandas convenience:
62
+ pip install "ausdata-sdk[pandas]"
63
+ ```
64
+
65
+ ## Why?
66
+
67
+ The chart you spend 90 minutes building in Excel — one HTTP call.
68
+
69
+ ```bash
70
+ # Before — wrangling SDMX XML by hand
71
+ curl 'https://api.data.abs.gov.au/data/WPI/...'
72
+
73
+ # After — typed, normalised, attribution-tagged
74
+ ```
75
+
76
+ ```python
77
+ from ausdata import Client
78
+
79
+ client = Client(api_key="ak_xxx")
80
+ result = client.real_wages(start="2019-Q1", end="2024-Q4")
81
+
82
+ print(result.data[0])
83
+ # RealWageRow(period='2024-Q4', wpi_annual_change_pct=3.2,
84
+ # cpi_annual_change_pct=2.4, real_wages_gap_pct=0.8,
85
+ # real_wages_direction='growing')
86
+
87
+ df = result.to_dataframe() # pandas (optional extra)
88
+ result.to_csv("real_wages.csv") # Datawrapper-friendly
89
+ ```
90
+
91
+ ## Async client
92
+
93
+ ```python
94
+ import asyncio
95
+ from ausdata import AsyncClient
96
+
97
+ async def main():
98
+ async with AsyncClient(api_key="ak_xxx") as client:
99
+ snapshot = await client.economic_dashboard()
100
+ print(snapshot.data.cash_rate_pct, snapshot.data.unemployment_rate_pct)
101
+
102
+ asyncio.run(main())
103
+ ```
104
+
105
+ ## Endpoints
106
+
107
+ | Method | API endpoint | What you get |
108
+ |---|---|---|
109
+ | `client.health()` | `GET /v1/health` | Service status (no quota cost) |
110
+ | `client.whoami()` | `GET /v1/whoami` | Tier + monthly usage (works for API keys or JWTs) |
111
+ | `client.account.api_key()` | `GET /v1/account/api-key` | Your key + tier + monthly usage (JWT-only) |
112
+ | `client.account.rotate_key()` | `POST /v1/account/api-key` | Rotate the key, get new plaintext (JWT-only) |
113
+ | `client.search_datasets(q=...)` | `GET /v1/search-datasets` | Search across all 9 AU sources |
114
+ | `client.list_datasets(source)` | `GET /v1/datasets/{source}` | Enumerate curated datasets for one source |
115
+ | `client.describe(source, id)` | `GET /v1/describe/{source}/{id}` | Schema: dimensions, valid filters, valid values |
116
+ | `client.get_data(source, id, **filters)` | `GET /v1/data/{source}/{id}` | Fetch any dataset with source-specific filters |
117
+ | `client.real_wages(start=...)` | `GET /v1/real-wages` | WPI YoY minus CPI YoY (composed) |
118
+ | `client.economic_dashboard()` | `GET /v1/economic-dashboard` | 5-source headline macro snapshot (composed) |
119
+
120
+ The full discover → introspect → fetch loop is:
121
+
122
+ ```python
123
+ r = client.search_datasets(q="unemployment rate") # find dataset
124
+ schema = client.describe("abs", "LF") # see valid filters
125
+ data = client.get_data("abs", "LF", # fetch with right filters
126
+ measure="unemployment_rate",
127
+ region="nsw", start="2024-01")
128
+ ```
129
+
130
+ Every data response is wrapped in the same `ApiResponse` envelope so you
131
+ always know where to find the payload (`.data`), the attribution (`.meta.sources`),
132
+ and the audit trail (`.meta.retrieved_at`, `.meta.stale`).
133
+
134
+ ## Pricing
135
+
136
+ | Tier | Price | Calls/mo | Notes |
137
+ |---|---|---|---|
138
+ | Free | $0 | 100 | 1y history, attribution required |
139
+ | Analyst | $29 | 10,000 | 10y history, no attribution |
140
+ | Pro | $99 | 100,000 | Webhooks, priority support |
141
+ | Enterprise | custom | unlimited | SLA, white-label, custom queries |
142
+
143
+ Sign up + get a free key at [ausdata.io](https://ausdata.io).
144
+
145
+ ## Configuration
146
+
147
+ ```python
148
+ from ausdata import Client
149
+
150
+ # API key resolution order:
151
+ # 1. explicit api_key= argument
152
+ # 2. AUSDATA_API_KEY environment variable
153
+ client = Client(
154
+ api_key="ak_xxx",
155
+ base_url="https://api.ausdata.io", # override for staging
156
+ timeout=30.0, # per-request timeout (seconds)
157
+ max_retries=3, # 5xx + 429 retry budget
158
+ retry_backoff_factor=2.0, # exponential delay multiplier
159
+ )
160
+ ```
161
+
162
+ ## Errors
163
+
164
+ ```python
165
+ from ausdata import Client
166
+ from ausdata.exceptions import (
167
+ AusdataError, # base
168
+ AuthenticationError, # 401
169
+ PermissionError, # 403, 402 (tier-blocked)
170
+ RateLimitError, # 429 with retry_after
171
+ ValidationError, # 400
172
+ UpstreamError, # 502/503
173
+ AusdataServerError, # 5xx fallback
174
+ )
175
+
176
+ try:
177
+ result = client.real_wages(start="not-a-quarter")
178
+ except ValidationError as e:
179
+ print(e.message, "Hint:", e.hint)
180
+ ```
181
+
182
+ Every error carries the API's message plus the actionable `hint` when
183
+ available (e.g. `"Did you mean 2024-Q1?"`).
184
+
185
+ ## Links
186
+
187
+ - **Docs**: [docs.ausdata.io](https://docs.ausdata.io)
188
+ - **API reference**: [api.ausdata.io/docs](https://api.ausdata.io/docs)
189
+ - **Issues**: [github.com/Bigred97/ausdata-sdk/issues](https://github.com/Bigred97/ausdata-sdk/issues)
190
+
191
+ ## License
192
+
193
+ MIT. See [LICENSE](LICENSE).
@@ -0,0 +1,140 @@
1
+ # ausdata — Python SDK for the Australian public data API
2
+
3
+ The official Python client for [ausdata.io](https://ausdata.io). One auth key,
4
+ one uniform response envelope, every major Australian government data source.
5
+
6
+ ```bash
7
+ pip install ausdata-sdk
8
+ # or, with pandas convenience:
9
+ pip install "ausdata-sdk[pandas]"
10
+ ```
11
+
12
+ ## Why?
13
+
14
+ The chart you spend 90 minutes building in Excel — one HTTP call.
15
+
16
+ ```bash
17
+ # Before — wrangling SDMX XML by hand
18
+ curl 'https://api.data.abs.gov.au/data/WPI/...'
19
+
20
+ # After — typed, normalised, attribution-tagged
21
+ ```
22
+
23
+ ```python
24
+ from ausdata import Client
25
+
26
+ client = Client(api_key="ak_xxx")
27
+ result = client.real_wages(start="2019-Q1", end="2024-Q4")
28
+
29
+ print(result.data[0])
30
+ # RealWageRow(period='2024-Q4', wpi_annual_change_pct=3.2,
31
+ # cpi_annual_change_pct=2.4, real_wages_gap_pct=0.8,
32
+ # real_wages_direction='growing')
33
+
34
+ df = result.to_dataframe() # pandas (optional extra)
35
+ result.to_csv("real_wages.csv") # Datawrapper-friendly
36
+ ```
37
+
38
+ ## Async client
39
+
40
+ ```python
41
+ import asyncio
42
+ from ausdata import AsyncClient
43
+
44
+ async def main():
45
+ async with AsyncClient(api_key="ak_xxx") as client:
46
+ snapshot = await client.economic_dashboard()
47
+ print(snapshot.data.cash_rate_pct, snapshot.data.unemployment_rate_pct)
48
+
49
+ asyncio.run(main())
50
+ ```
51
+
52
+ ## Endpoints
53
+
54
+ | Method | API endpoint | What you get |
55
+ |---|---|---|
56
+ | `client.health()` | `GET /v1/health` | Service status (no quota cost) |
57
+ | `client.whoami()` | `GET /v1/whoami` | Tier + monthly usage (works for API keys or JWTs) |
58
+ | `client.account.api_key()` | `GET /v1/account/api-key` | Your key + tier + monthly usage (JWT-only) |
59
+ | `client.account.rotate_key()` | `POST /v1/account/api-key` | Rotate the key, get new plaintext (JWT-only) |
60
+ | `client.search_datasets(q=...)` | `GET /v1/search-datasets` | Search across all 9 AU sources |
61
+ | `client.list_datasets(source)` | `GET /v1/datasets/{source}` | Enumerate curated datasets for one source |
62
+ | `client.describe(source, id)` | `GET /v1/describe/{source}/{id}` | Schema: dimensions, valid filters, valid values |
63
+ | `client.get_data(source, id, **filters)` | `GET /v1/data/{source}/{id}` | Fetch any dataset with source-specific filters |
64
+ | `client.real_wages(start=...)` | `GET /v1/real-wages` | WPI YoY minus CPI YoY (composed) |
65
+ | `client.economic_dashboard()` | `GET /v1/economic-dashboard` | 5-source headline macro snapshot (composed) |
66
+
67
+ The full discover → introspect → fetch loop is:
68
+
69
+ ```python
70
+ r = client.search_datasets(q="unemployment rate") # find dataset
71
+ schema = client.describe("abs", "LF") # see valid filters
72
+ data = client.get_data("abs", "LF", # fetch with right filters
73
+ measure="unemployment_rate",
74
+ region="nsw", start="2024-01")
75
+ ```
76
+
77
+ Every data response is wrapped in the same `ApiResponse` envelope so you
78
+ always know where to find the payload (`.data`), the attribution (`.meta.sources`),
79
+ and the audit trail (`.meta.retrieved_at`, `.meta.stale`).
80
+
81
+ ## Pricing
82
+
83
+ | Tier | Price | Calls/mo | Notes |
84
+ |---|---|---|---|
85
+ | Free | $0 | 100 | 1y history, attribution required |
86
+ | Analyst | $29 | 10,000 | 10y history, no attribution |
87
+ | Pro | $99 | 100,000 | Webhooks, priority support |
88
+ | Enterprise | custom | unlimited | SLA, white-label, custom queries |
89
+
90
+ Sign up + get a free key at [ausdata.io](https://ausdata.io).
91
+
92
+ ## Configuration
93
+
94
+ ```python
95
+ from ausdata import Client
96
+
97
+ # API key resolution order:
98
+ # 1. explicit api_key= argument
99
+ # 2. AUSDATA_API_KEY environment variable
100
+ client = Client(
101
+ api_key="ak_xxx",
102
+ base_url="https://api.ausdata.io", # override for staging
103
+ timeout=30.0, # per-request timeout (seconds)
104
+ max_retries=3, # 5xx + 429 retry budget
105
+ retry_backoff_factor=2.0, # exponential delay multiplier
106
+ )
107
+ ```
108
+
109
+ ## Errors
110
+
111
+ ```python
112
+ from ausdata import Client
113
+ from ausdata.exceptions import (
114
+ AusdataError, # base
115
+ AuthenticationError, # 401
116
+ PermissionError, # 403, 402 (tier-blocked)
117
+ RateLimitError, # 429 with retry_after
118
+ ValidationError, # 400
119
+ UpstreamError, # 502/503
120
+ AusdataServerError, # 5xx fallback
121
+ )
122
+
123
+ try:
124
+ result = client.real_wages(start="not-a-quarter")
125
+ except ValidationError as e:
126
+ print(e.message, "Hint:", e.hint)
127
+ ```
128
+
129
+ Every error carries the API's message plus the actionable `hint` when
130
+ available (e.g. `"Did you mean 2024-Q1?"`).
131
+
132
+ ## Links
133
+
134
+ - **Docs**: [docs.ausdata.io](https://docs.ausdata.io)
135
+ - **API reference**: [api.ausdata.io/docs](https://api.ausdata.io/docs)
136
+ - **Issues**: [github.com/Bigred97/ausdata-sdk/issues](https://github.com/Bigred97/ausdata-sdk/issues)
137
+
138
+ ## License
139
+
140
+ MIT. See [LICENSE](LICENSE).
@@ -0,0 +1,54 @@
1
+ [project]
2
+ name = "ausdata-sdk"
3
+ version = "0.2.0"
4
+ description = "Python SDK for the Australian public data API. Free tier available at ausdata.io."
5
+ readme = "README.md"
6
+ license = { file = "LICENSE" }
7
+ requires-python = ">=3.11"
8
+ authors = [{ name = "Harry Vass" }]
9
+ keywords = ["mcp", "australia", "public-data", "api", "client", "sdk"]
10
+ classifiers = [
11
+ "Development Status :: 4 - Beta",
12
+ "License :: OSI Approved :: MIT License",
13
+ "Programming Language :: Python :: 3.11",
14
+ "Programming Language :: Python :: 3.12",
15
+ "Programming Language :: Python :: 3.13",
16
+ "Topic :: Internet :: WWW/HTTP",
17
+ "Topic :: Scientific/Engineering :: Information Analysis",
18
+ "Typing :: Typed",
19
+ ]
20
+ dependencies = [
21
+ "httpx>=0.27",
22
+ "pydantic>=2.7",
23
+ ]
24
+
25
+ [project.optional-dependencies]
26
+ pandas = ["pandas>=2.0"]
27
+ dev = [
28
+ "pytest>=8",
29
+ "pytest-asyncio>=0.23",
30
+ "pytest-httpx>=0.30",
31
+ "pandas>=2.0",
32
+ "ruff>=0.5",
33
+ ]
34
+
35
+ [project.urls]
36
+ Homepage = "https://ausdata.io"
37
+ Documentation = "https://docs.ausdata.io"
38
+ Repository = "https://github.com/Bigred97/ausdata-sdk"
39
+ Issues = "https://github.com/Bigred97/ausdata-sdk/issues"
40
+
41
+ [build-system]
42
+ requires = ["hatchling"]
43
+ build-backend = "hatchling.build"
44
+
45
+ [tool.hatch.build.targets.wheel]
46
+ packages = ["src/ausdata"]
47
+
48
+ [tool.pytest.ini_options]
49
+ asyncio_mode = "auto"
50
+ testpaths = ["tests"]
51
+ pythonpath = ["src"]
52
+
53
+ [tool.ruff.lint.per-file-ignores]
54
+ "tests/*" = ["E741", "F841", "F401"]
@@ -0,0 +1,76 @@
1
+ """Python SDK for the Australian public data API at https://ausdata.io.
2
+
3
+ Quick start::
4
+
5
+ from ausdata import Client
6
+
7
+ client = Client(api_key="ak_xxx") # or set AUSDATA_API_KEY
8
+ result = client.real_wages(start="2019-Q1", end="2024-Q4")
9
+ df = result.to_dataframe()
10
+
11
+ Async equivalent::
12
+
13
+ import asyncio
14
+ from ausdata import AsyncClient
15
+
16
+ async def main():
17
+ async with AsyncClient(api_key="ak_xxx") as client:
18
+ return await client.real_wages(start="2019-Q1")
19
+
20
+ asyncio.run(main())
21
+ """
22
+
23
+ from __future__ import annotations
24
+
25
+ from ._version import __version__
26
+ from .async_client import AsyncClient
27
+ from .client import Client
28
+ from .exceptions import (
29
+ AusdataError,
30
+ AusdataServerError,
31
+ AuthenticationError,
32
+ PermissionError,
33
+ RateLimitError,
34
+ UpstreamError,
35
+ ValidationError,
36
+ )
37
+ from .models import (
38
+ AccountResponse,
39
+ ApiResponse,
40
+ DatasetSummary,
41
+ EconomicDashboard,
42
+ HealthResponse,
43
+ Links,
44
+ Meta,
45
+ RealWageRow,
46
+ SearchResponse,
47
+ SourceCitation,
48
+ WhoamiResponse,
49
+ )
50
+
51
+ __all__ = [
52
+ "__version__",
53
+ # clients
54
+ "AsyncClient",
55
+ "Client",
56
+ # exceptions
57
+ "AusdataError",
58
+ "AusdataServerError",
59
+ "AuthenticationError",
60
+ "PermissionError",
61
+ "RateLimitError",
62
+ "UpstreamError",
63
+ "ValidationError",
64
+ # models
65
+ "AccountResponse",
66
+ "ApiResponse",
67
+ "DatasetSummary",
68
+ "EconomicDashboard",
69
+ "HealthResponse",
70
+ "Links",
71
+ "Meta",
72
+ "RealWageRow",
73
+ "SearchResponse",
74
+ "SourceCitation",
75
+ "WhoamiResponse",
76
+ ]