chile-open-data-sdk 0.1.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.
- chile_open_data_sdk-0.1.0/.pre-commit-config.yaml +33 -0
- chile_open_data_sdk-0.1.0/CHANGELOG.md +63 -0
- chile_open_data_sdk-0.1.0/CODE_OF_CONDUCT.md +12 -0
- chile_open_data_sdk-0.1.0/CONTRIBUTING.md +91 -0
- chile_open_data_sdk-0.1.0/LICENSE.md +9 -0
- chile_open_data_sdk-0.1.0/PKG-INFO +157 -0
- chile_open_data_sdk-0.1.0/README.md +134 -0
- chile_open_data_sdk-0.1.0/SECURITY.md +29 -0
- chile_open_data_sdk-0.1.0/benchmarks/benchcore_cases.py +33 -0
- chile_open_data_sdk-0.1.0/benchmarks/test_responses.py +23 -0
- chile_open_data_sdk-0.1.0/docs/actions.md +70 -0
- chile_open_data_sdk-0.1.0/docs/api.md +16 -0
- chile_open_data_sdk-0.1.0/docs/architecture.md +34 -0
- chile_open_data_sdk-0.1.0/docs/compatibility.md +44 -0
- chile_open_data_sdk-0.1.0/docs/configuration.md +64 -0
- chile_open_data_sdk-0.1.0/docs/development.md +130 -0
- chile_open_data_sdk-0.1.0/docs/errors.md +48 -0
- chile_open_data_sdk-0.1.0/docs/getting-started.md +32 -0
- chile_open_data_sdk-0.1.0/docs/index.md +17 -0
- chile_open_data_sdk-0.1.0/docs/release-notes.md +32 -0
- chile_open_data_sdk-0.1.0/docs/release-validation.md +59 -0
- chile_open_data_sdk-0.1.0/docs/releasing.md +86 -0
- chile_open_data_sdk-0.1.0/docs/roadmap.md +23 -0
- chile_open_data_sdk-0.1.0/examples/quickstart.py +18 -0
- chile_open_data_sdk-0.1.0/mkdocs.yml +33 -0
- chile_open_data_sdk-0.1.0/pyproject.toml +124 -0
- chile_open_data_sdk-0.1.0/pyproject.toml.orig +89 -0
- chile_open_data_sdk-0.1.0/pyrightconfig.json +22 -0
- chile_open_data_sdk-0.1.0/scripts/check_artifacts.py +46 -0
- chile_open_data_sdk-0.1.0/src/chile_open_data_sdk/__init__.py +8 -0
- chile_open_data_sdk-0.1.0/src/chile_open_data_sdk/_internal/__init__.py +1 -0
- chile_open_data_sdk-0.1.0/src/chile_open_data_sdk/_internal/responses.py +111 -0
- chile_open_data_sdk-0.1.0/src/chile_open_data_sdk/client.py +142 -0
- chile_open_data_sdk-0.1.0/src/chile_open_data_sdk/config.py +93 -0
- chile_open_data_sdk-0.1.0/src/chile_open_data_sdk/errors.py +66 -0
- chile_open_data_sdk-0.1.0/src/chile_open_data_sdk/py.typed +0 -0
- chile_open_data_sdk-0.1.0/src/chile_open_data_sdk/types.py +5 -0
- chile_open_data_sdk-0.1.0/tests/integration/test_portal.py +19 -0
- chile_open_data_sdk-0.1.0/tests/unit/test_core.py +319 -0
- chile_open_data_sdk-0.1.0/tests/unit/test_examples.py +25 -0
- chile_open_data_sdk-0.1.0/tests/unit/test_properties.py +45 -0
- chile_open_data_sdk-0.1.0/uv.lock +1923 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
- repo: local
|
|
3
|
+
hooks:
|
|
4
|
+
- id: ruff-check
|
|
5
|
+
name: Ruff lint
|
|
6
|
+
entry: uv run --locked ruff check .
|
|
7
|
+
language: system
|
|
8
|
+
pass_filenames: false
|
|
9
|
+
always_run: true
|
|
10
|
+
- id: ruff-format
|
|
11
|
+
name: Ruff format check
|
|
12
|
+
entry: uv run --locked ruff format --check .
|
|
13
|
+
language: system
|
|
14
|
+
pass_filenames: false
|
|
15
|
+
always_run: true
|
|
16
|
+
- id: mypy
|
|
17
|
+
name: Mypy strict
|
|
18
|
+
entry: uv run --locked mypy src
|
|
19
|
+
language: system
|
|
20
|
+
pass_filenames: false
|
|
21
|
+
always_run: true
|
|
22
|
+
- id: basedpyright
|
|
23
|
+
name: BasedPyright strict
|
|
24
|
+
entry: uv run --locked basedpyright
|
|
25
|
+
language: system
|
|
26
|
+
pass_filenames: false
|
|
27
|
+
always_run: true
|
|
28
|
+
- id: pytest
|
|
29
|
+
name: Offline tests and coverage
|
|
30
|
+
entry: uv run --locked pytest
|
|
31
|
+
language: system
|
|
32
|
+
pass_filenames: false
|
|
33
|
+
always_run: true
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes are documented here. Versions before 1.0 may evolve their
|
|
4
|
+
public API; compatibility changes will be recorded explicitly.
|
|
5
|
+
|
|
6
|
+
## Unreleased
|
|
7
|
+
|
|
8
|
+
### Changed
|
|
9
|
+
|
|
10
|
+
- Rename the import package from `chile_open_data` to `chile_open_data_sdk` before
|
|
11
|
+
publication. Update imports, documentation, CI, coverage, and artifact validation.
|
|
12
|
+
The distribution remains `chile-open-data-sdk`; class names and behavior are unchanged.
|
|
13
|
+
No compatibility alias is provided. The original local v0.1.0 tag is preserved.
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- Optional BenchCore 1.x integration for Python 3.12+, with two explicitly selected
|
|
18
|
+
CPU benchmarks, JSON report persistence, and a manual reports workflow. SDK and
|
|
19
|
+
default development support remain Python 3.11+.
|
|
20
|
+
|
|
21
|
+
- Strict BasedPyright checks shared with Pyright/Pylance, enforced in CI.
|
|
22
|
+
- Local pre-commit hooks for Ruff, formatting, mypy, BasedPyright, and offline tests.
|
|
23
|
+
- Hypothesis property tests for arbitrary JSON results and immutable secret redaction.
|
|
24
|
+
- Optional pytest-benchmark group with network-free response and redaction benchmarks.
|
|
25
|
+
- Additional Ruff rules for security, comprehensions, logging, datetime usage, and debugging.
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
|
|
29
|
+
- Restore PyPI Trusted Publishing on published non-prerelease GitHub Releases and
|
|
30
|
+
manual dispatch with a required existing tag. Verify tag/version/commit identity
|
|
31
|
+
and run uv quality, documentation, and build checks before the isolated OIDC upload.
|
|
32
|
+
|
|
33
|
+
- Remove unnecessary-isinstance diagnostics by separating runtime validation of
|
|
34
|
+
untyped configuration values from the typed configuration model.
|
|
35
|
+
- Make response assignment and quick-start JSON narrowing explicit for static analyzers.
|
|
36
|
+
|
|
37
|
+
These changes follow the local v0.1.0 checkpoint; the existing tag is not moved.
|
|
38
|
+
|
|
39
|
+
## 0.1.0
|
|
40
|
+
|
|
41
|
+
Initial foundation release, prepared locally; publication is a separate step.
|
|
42
|
+
|
|
43
|
+
### Added
|
|
44
|
+
|
|
45
|
+
- Reusable synchronous `CKANClient` and Chile-first `ChileOpenDataClient`.
|
|
46
|
+
- Frozen typed configuration, granular timeouts, connection limits, TLS verification.
|
|
47
|
+
- Generic JSON Action API calls with unwrapped recursive JSON results.
|
|
48
|
+
- Pydantic v2 envelope validation and structured HTTP, CKAN, and transport errors.
|
|
49
|
+
- Explicit Authorization token support and recursive diagnostic redaction.
|
|
50
|
+
- Deterministic contract tests and an opt-in read-only portal test.
|
|
51
|
+
- English usage guides, generated API reference, policies, roadmap, and release notes.
|
|
52
|
+
- uv lockfile, typed package marker, Python 3.11–3.14 CI, build and artifact checks.
|
|
53
|
+
|
|
54
|
+
### Changed
|
|
55
|
+
|
|
56
|
+
- Replace the empty `chile_open_data_sdk` import skeleton with `chile_open_data`.
|
|
57
|
+
- Replace Poetry packaging with uv/uv_build and lower required Python from 3.14 to 3.11.
|
|
58
|
+
- Replace the inherited publishing workflow with manual artifact preparation.
|
|
59
|
+
|
|
60
|
+
### Security
|
|
61
|
+
|
|
62
|
+
- Disable redirects, environment credentials/proxies, and automatic request replay.
|
|
63
|
+
- Exclude configured tokens and raw HTTP response bodies from SDK diagnostics.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Code of conduct
|
|
2
|
+
|
|
3
|
+
We welcome contributors with different backgrounds and experience levels. Be
|
|
4
|
+
respectful, explain technical disagreements constructively, and give others room
|
|
5
|
+
to learn. Harassment, threats, discrimination, unwanted personal attention, and
|
|
6
|
+
publication of private information are not acceptable.
|
|
7
|
+
|
|
8
|
+
These expectations apply to project issues, pull requests, reviews, and other
|
|
9
|
+
project spaces. Report concerns privately to the maintainer at
|
|
10
|
+
ramirez.ruiz.eliezer.reuven@gmail.com. The maintainer may remove harmful content,
|
|
11
|
+
limit participation, or exclude participants to protect the community. Reports
|
|
12
|
+
will be handled with care for the privacy of those involved.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thank you for helping improve this unofficial community SDK. Keep repository
|
|
4
|
+
code, documentation, examples, and commit messages in English. Spanish is allowed
|
|
5
|
+
in upstream data and examples demonstrating Chilean data.
|
|
6
|
+
|
|
7
|
+
## Set up
|
|
8
|
+
|
|
9
|
+
Install Python 3.11+ and uv, clone the repository, then run:
|
|
10
|
+
|
|
11
|
+
```console
|
|
12
|
+
uv sync --locked --group docs
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Use `uv add`, `uv add --dev`, or `uv add --group docs` to change dependencies.
|
|
16
|
+
Never hand-edit `uv.lock`. Runtime dependencies should be justified by features;
|
|
17
|
+
optional integrations must remain optional. No global Python tooling is required.
|
|
18
|
+
|
|
19
|
+
## Validate before each commit
|
|
20
|
+
|
|
21
|
+
```console
|
|
22
|
+
uv run ruff check .
|
|
23
|
+
uv run ruff format --check .
|
|
24
|
+
uv run mypy src
|
|
25
|
+
uv run basedpyright
|
|
26
|
+
uv run pytest
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
For documentation and packaging changes, also run:
|
|
30
|
+
|
|
31
|
+
```console
|
|
32
|
+
uv run --group docs mkdocs build --strict
|
|
33
|
+
uv build
|
|
34
|
+
uv run python scripts/check_artifacts.py
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Tests use HTTPX MockTransport by default and enforce 90% branch-aware coverage.
|
|
38
|
+
Add behavior-focused tests for public changes and credential-sensitive paths.
|
|
39
|
+
Never test writes against production. To explicitly enable public read tests:
|
|
40
|
+
|
|
41
|
+
```powershell
|
|
42
|
+
$env:CHILE_OPEN_DATA_LIVE_TESTS = "1"
|
|
43
|
+
uv run pytest tests/integration --no-cov
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
On POSIX shells use `CHILE_OPEN_DATA_LIVE_TESTS=1 uv run pytest tests/integration --no-cov`.
|
|
47
|
+
Live availability is not a normal pull-request requirement.
|
|
48
|
+
|
|
49
|
+
## Local hooks and extended tests
|
|
50
|
+
|
|
51
|
+
Ruff handles both linting and formatting. Mypy checks the SDK in strict mode;
|
|
52
|
+
BasedPyright also checks SDK code, examples, and packaging scripts, using a shared
|
|
53
|
+
`pyrightconfig.json` understood by Pyright/Pylance. Select the project's `.venv`
|
|
54
|
+
interpreter in your editor. The unnecessary-isinstance diagnostic stays enabled.
|
|
55
|
+
|
|
56
|
+
Install the repository-local hooks after syncing the environment:
|
|
57
|
+
|
|
58
|
+
```console
|
|
59
|
+
uv run pre-commit install
|
|
60
|
+
uv run pre-commit run --all-files
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Hooks run the locked uv tools, including offline tests, before commits. They check
|
|
64
|
+
formatting without modifying files. Format explicitly with `uv run ruff format .`.
|
|
65
|
+
Hypothesis property tests run as part of normal pytest. Benchmarks are opt-in:
|
|
66
|
+
|
|
67
|
+
```console
|
|
68
|
+
uv run --group benchmark pytest benchmarks --no-cov --benchmark-only
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
BenchCore reports are also available on Python 3.12+:
|
|
72
|
+
|
|
73
|
+
```console
|
|
74
|
+
uv run --group benchcore pytest benchmarks/benchcore_cases.py --no-cov --benchcore-save=.benchcore
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
See [Development tools](docs/development.md) for scope, rationale, and commands.
|
|
78
|
+
|
|
79
|
+
## Changes and review
|
|
80
|
+
|
|
81
|
+
Keep changes coherent and follow the roadmap. Describe the problem, resulting
|
|
82
|
+
behavior, compatibility impact, and validation in pull requests. Update docs and
|
|
83
|
+
CHANGELOG for user-visible changes. Use Conventional Commits such as
|
|
84
|
+
`feat(core): ...`, `fix(actions): ...`, and `docs(api): ...`.
|
|
85
|
+
|
|
86
|
+
Do not manufacture release history, rewrite user commits, or force-push. For
|
|
87
|
+
agent-assisted changes, include an approved `Co-authored-by` identity; never
|
|
88
|
+
invent one. Public API stability begins at 1.0, not at this alpha milestone.
|
|
89
|
+
|
|
90
|
+
Report security issues through [SECURITY.md](SECURITY.md). Participation follows
|
|
91
|
+
[CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md).
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Eli-ezer Reuven Ramirez Ruiz
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: chile-open-data-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: An unofficial, typed Python SDK for Chile's datos.gob.cl and CKAN Action API
|
|
5
|
+
Keywords: chile,open-data,ckan,sdk
|
|
6
|
+
Author: Eli-ezer Reuven Ramirez Ruiz
|
|
7
|
+
Author-email: Eli-ezer Reuven Ramirez Ruiz <ramirez.ruiz.eliezer.reuven@gmail.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE.md
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
+
Classifier: Typing :: Typed
|
|
17
|
+
Requires-Dist: httpx>=0.28.1
|
|
18
|
+
Requires-Dist: pydantic>=2.12.0,<3
|
|
19
|
+
Requires-Python: >=3.11
|
|
20
|
+
Project-URL: Repository, https://github.com/ezer-mackenzie/chile-open-data-sdk
|
|
21
|
+
Project-URL: Issues, https://github.com/ezer-mackenzie/chile-open-data-sdk/issues
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
24
|
+
# Chile Open Data SDK
|
|
25
|
+
|
|
26
|
+
An unofficial, typed Python SDK for Chile's **datos.gob.cl**, with a reusable
|
|
27
|
+
CKAN Action API core. This community project is **not an official SDK of the
|
|
28
|
+
Government of Chile or the maintainers of datos.gob.cl**.
|
|
29
|
+
|
|
30
|
+
## v0.1.0 scope
|
|
31
|
+
|
|
32
|
+
This first release provides a synchronous client, validated configuration,
|
|
33
|
+
connection pooling, JSON action calls, token authentication, and structured errors.
|
|
34
|
+
It is an alpha foundation with a deliberately small public API.
|
|
35
|
+
|
|
36
|
+
Typed dataset services, DataStore wrappers, pagination, async clients, downloads,
|
|
37
|
+
and pandas/Polars integrations are planned for later milestones; they are not
|
|
38
|
+
available in v0.1.0. Generic actions can already query catalog and DataStore
|
|
39
|
+
endpoints when the server supports them.
|
|
40
|
+
|
|
41
|
+
## Installation
|
|
42
|
+
|
|
43
|
+
Python 3.11 or later is required. Before publication, install from a local checkout:
|
|
44
|
+
|
|
45
|
+
```console
|
|
46
|
+
uv sync --locked
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Or build and install the wheel with a standard Python installer:
|
|
50
|
+
|
|
51
|
+
```console
|
|
52
|
+
uv build
|
|
53
|
+
python -m pip install dist/chile_open_data_sdk-0.1.0-py3-none-any.whl
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
After v0.1.0 is published, installation will be:
|
|
57
|
+
|
|
58
|
+
```console
|
|
59
|
+
python -m pip install chile-open-data-sdk==0.1.0
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The distribution is `chile-open-data-sdk`; the import is `chile_open_data_sdk`.
|
|
63
|
+
|
|
64
|
+
## Quick start
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
from chile_open_data_sdk import ChileOpenDataClient
|
|
68
|
+
|
|
69
|
+
with ChileOpenDataClient() as client:
|
|
70
|
+
result = client.actions.call("package_search", {"q": "transport", "rows": 5})
|
|
71
|
+
datasets = result.get("results") if isinstance(result, dict) else None
|
|
72
|
+
if isinstance(datasets, list):
|
|
73
|
+
for dataset in datasets:
|
|
74
|
+
if isinstance(dataset, dict):
|
|
75
|
+
print(dataset.get("title"))
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
The default endpoint is `https://datos.gob.cl/api/3/action`. Calls return the
|
|
79
|
+
unwrapped JSON `result`, preserving additional server fields. Availability and
|
|
80
|
+
metadata quality depend on the upstream portal.
|
|
81
|
+
|
|
82
|
+
## Another CKAN site
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
from chile_open_data_sdk import CKANClient
|
|
86
|
+
|
|
87
|
+
with CKANClient(site_url="https://demo.ckan.org") as client:
|
|
88
|
+
print(client.actions.call("package_list", {"limit": 5}))
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Authentication and errors
|
|
92
|
+
|
|
93
|
+
Credentials are explicit and are sent only in the `Authorization` header. The
|
|
94
|
+
constructor does not read environment credentials. Your application can do so:
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
import os
|
|
98
|
+
|
|
99
|
+
from chile_open_data_sdk import ChileOpenDataClient
|
|
100
|
+
from chile_open_data_sdk.errors import CKANError
|
|
101
|
+
|
|
102
|
+
try:
|
|
103
|
+
with ChileOpenDataClient(api_token=os.environ.get("CHILE_OPEN_DATA_API_TOKEN")) as client:
|
|
104
|
+
result = client.actions.call("package_list", {"limit": 5})
|
|
105
|
+
except CKANError as error:
|
|
106
|
+
print(error.action, error.status_code, error.error_type)
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Generic calls use JSON POST and **never retry automatically**, including read
|
|
110
|
+
operations. They can execute writes: the caller chooses the action and the server
|
|
111
|
+
enforces permissions. Redirects are not followed. Configuration and SDK error
|
|
112
|
+
representations exclude the configured token; do not log raw payloads or credentials.
|
|
113
|
+
|
|
114
|
+
## Documentation
|
|
115
|
+
|
|
116
|
+
- [Getting started](docs/getting-started.md)
|
|
117
|
+
- [Generic actions and querying examples](docs/actions.md)
|
|
118
|
+
- [Configuration and authentication](docs/configuration.md)
|
|
119
|
+
- [Error handling](docs/errors.md)
|
|
120
|
+
- [Public API reference](docs/api.md)
|
|
121
|
+
- [Development tools and benchmarks](docs/development.md)
|
|
122
|
+
- [Architecture](docs/architecture.md)
|
|
123
|
+
- [Compatibility and limitations](docs/compatibility.md)
|
|
124
|
+
- [Roadmap](docs/roadmap.md)
|
|
125
|
+
- [Release process](docs/releasing.md)
|
|
126
|
+
- [v0.1.0 release notes](docs/release-notes.md)
|
|
127
|
+
- [Changelog](CHANGELOG.md)
|
|
128
|
+
|
|
129
|
+
Build the documentation locally with `uv run --group docs mkdocs build --strict`,
|
|
130
|
+
or preview with `uv run --group docs mkdocs serve`. No hosted documentation URL
|
|
131
|
+
is claimed until deployment is configured.
|
|
132
|
+
|
|
133
|
+
## Development
|
|
134
|
+
|
|
135
|
+
```console
|
|
136
|
+
uv sync --locked --group docs
|
|
137
|
+
uv run ruff check .
|
|
138
|
+
uv run ruff format --check .
|
|
139
|
+
uv run mypy src
|
|
140
|
+
uv run basedpyright
|
|
141
|
+
uv run pytest
|
|
142
|
+
uv run --group docs mkdocs build --strict
|
|
143
|
+
uv build
|
|
144
|
+
uv run python scripts/check_artifacts.py
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Normal tests use mocked HTTP; live portal tests are opt-in. See
|
|
148
|
+
[Contributing](CONTRIBUTING.md) and [Security](SECURITY.md).
|
|
149
|
+
|
|
150
|
+
Existing CKAN clients such as [ckanapi](https://github.com/ckan/ckanapi) serve the
|
|
151
|
+
community already. This project's direction is Chile-first defaults, modern
|
|
152
|
+
Python typing, and progressively richer sync/async workflows.
|
|
153
|
+
|
|
154
|
+
## License
|
|
155
|
+
|
|
156
|
+
[MIT](LICENSE.md). Portal datasets may have their own licenses; the SDK's license
|
|
157
|
+
does not determine permission to use upstream data.
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# Chile Open Data SDK
|
|
2
|
+
|
|
3
|
+
An unofficial, typed Python SDK for Chile's **datos.gob.cl**, with a reusable
|
|
4
|
+
CKAN Action API core. This community project is **not an official SDK of the
|
|
5
|
+
Government of Chile or the maintainers of datos.gob.cl**.
|
|
6
|
+
|
|
7
|
+
## v0.1.0 scope
|
|
8
|
+
|
|
9
|
+
This first release provides a synchronous client, validated configuration,
|
|
10
|
+
connection pooling, JSON action calls, token authentication, and structured errors.
|
|
11
|
+
It is an alpha foundation with a deliberately small public API.
|
|
12
|
+
|
|
13
|
+
Typed dataset services, DataStore wrappers, pagination, async clients, downloads,
|
|
14
|
+
and pandas/Polars integrations are planned for later milestones; they are not
|
|
15
|
+
available in v0.1.0. Generic actions can already query catalog and DataStore
|
|
16
|
+
endpoints when the server supports them.
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
Python 3.11 or later is required. Before publication, install from a local checkout:
|
|
21
|
+
|
|
22
|
+
```console
|
|
23
|
+
uv sync --locked
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Or build and install the wheel with a standard Python installer:
|
|
27
|
+
|
|
28
|
+
```console
|
|
29
|
+
uv build
|
|
30
|
+
python -m pip install dist/chile_open_data_sdk-0.1.0-py3-none-any.whl
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
After v0.1.0 is published, installation will be:
|
|
34
|
+
|
|
35
|
+
```console
|
|
36
|
+
python -m pip install chile-open-data-sdk==0.1.0
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The distribution is `chile-open-data-sdk`; the import is `chile_open_data_sdk`.
|
|
40
|
+
|
|
41
|
+
## Quick start
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
from chile_open_data_sdk import ChileOpenDataClient
|
|
45
|
+
|
|
46
|
+
with ChileOpenDataClient() as client:
|
|
47
|
+
result = client.actions.call("package_search", {"q": "transport", "rows": 5})
|
|
48
|
+
datasets = result.get("results") if isinstance(result, dict) else None
|
|
49
|
+
if isinstance(datasets, list):
|
|
50
|
+
for dataset in datasets:
|
|
51
|
+
if isinstance(dataset, dict):
|
|
52
|
+
print(dataset.get("title"))
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The default endpoint is `https://datos.gob.cl/api/3/action`. Calls return the
|
|
56
|
+
unwrapped JSON `result`, preserving additional server fields. Availability and
|
|
57
|
+
metadata quality depend on the upstream portal.
|
|
58
|
+
|
|
59
|
+
## Another CKAN site
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
from chile_open_data_sdk import CKANClient
|
|
63
|
+
|
|
64
|
+
with CKANClient(site_url="https://demo.ckan.org") as client:
|
|
65
|
+
print(client.actions.call("package_list", {"limit": 5}))
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Authentication and errors
|
|
69
|
+
|
|
70
|
+
Credentials are explicit and are sent only in the `Authorization` header. The
|
|
71
|
+
constructor does not read environment credentials. Your application can do so:
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
import os
|
|
75
|
+
|
|
76
|
+
from chile_open_data_sdk import ChileOpenDataClient
|
|
77
|
+
from chile_open_data_sdk.errors import CKANError
|
|
78
|
+
|
|
79
|
+
try:
|
|
80
|
+
with ChileOpenDataClient(api_token=os.environ.get("CHILE_OPEN_DATA_API_TOKEN")) as client:
|
|
81
|
+
result = client.actions.call("package_list", {"limit": 5})
|
|
82
|
+
except CKANError as error:
|
|
83
|
+
print(error.action, error.status_code, error.error_type)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Generic calls use JSON POST and **never retry automatically**, including read
|
|
87
|
+
operations. They can execute writes: the caller chooses the action and the server
|
|
88
|
+
enforces permissions. Redirects are not followed. Configuration and SDK error
|
|
89
|
+
representations exclude the configured token; do not log raw payloads or credentials.
|
|
90
|
+
|
|
91
|
+
## Documentation
|
|
92
|
+
|
|
93
|
+
- [Getting started](docs/getting-started.md)
|
|
94
|
+
- [Generic actions and querying examples](docs/actions.md)
|
|
95
|
+
- [Configuration and authentication](docs/configuration.md)
|
|
96
|
+
- [Error handling](docs/errors.md)
|
|
97
|
+
- [Public API reference](docs/api.md)
|
|
98
|
+
- [Development tools and benchmarks](docs/development.md)
|
|
99
|
+
- [Architecture](docs/architecture.md)
|
|
100
|
+
- [Compatibility and limitations](docs/compatibility.md)
|
|
101
|
+
- [Roadmap](docs/roadmap.md)
|
|
102
|
+
- [Release process](docs/releasing.md)
|
|
103
|
+
- [v0.1.0 release notes](docs/release-notes.md)
|
|
104
|
+
- [Changelog](CHANGELOG.md)
|
|
105
|
+
|
|
106
|
+
Build the documentation locally with `uv run --group docs mkdocs build --strict`,
|
|
107
|
+
or preview with `uv run --group docs mkdocs serve`. No hosted documentation URL
|
|
108
|
+
is claimed until deployment is configured.
|
|
109
|
+
|
|
110
|
+
## Development
|
|
111
|
+
|
|
112
|
+
```console
|
|
113
|
+
uv sync --locked --group docs
|
|
114
|
+
uv run ruff check .
|
|
115
|
+
uv run ruff format --check .
|
|
116
|
+
uv run mypy src
|
|
117
|
+
uv run basedpyright
|
|
118
|
+
uv run pytest
|
|
119
|
+
uv run --group docs mkdocs build --strict
|
|
120
|
+
uv build
|
|
121
|
+
uv run python scripts/check_artifacts.py
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Normal tests use mocked HTTP; live portal tests are opt-in. See
|
|
125
|
+
[Contributing](CONTRIBUTING.md) and [Security](SECURITY.md).
|
|
126
|
+
|
|
127
|
+
Existing CKAN clients such as [ckanapi](https://github.com/ckan/ckanapi) serve the
|
|
128
|
+
community already. This project's direction is Chile-first defaults, modern
|
|
129
|
+
Python typing, and progressively richer sync/async workflows.
|
|
130
|
+
|
|
131
|
+
## License
|
|
132
|
+
|
|
133
|
+
[MIT](LICENSE.md). Portal datasets may have their own licenses; the SDK's license
|
|
134
|
+
does not determine permission to use upstream data.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Security policy
|
|
2
|
+
|
|
3
|
+
## Supported versions
|
|
4
|
+
|
|
5
|
+
Security fixes target the latest released version. v0.1.0 is the initial alpha;
|
|
6
|
+
there are no older supported release lines or service-level guarantees.
|
|
7
|
+
|
|
8
|
+
## Reporting a vulnerability
|
|
9
|
+
|
|
10
|
+
Report vulnerabilities privately to the maintainer at
|
|
11
|
+
ramirez.ruiz.eliezer.reuven@gmail.com. Include the affected version, reproduction
|
|
12
|
+
steps, and impact using synthetic credentials. Do not put tokens, private data,
|
|
13
|
+
or exploit details in public issues. Coordinate disclosure with the maintainer;
|
|
14
|
+
no response-time commitment is currently offered.
|
|
15
|
+
|
|
16
|
+
## Credential handling
|
|
17
|
+
|
|
18
|
+
Use HTTPS and explicit CKAN tokens with the minimum necessary permissions.
|
|
19
|
+
Never commit `.env` files or tokens. Revoke and rotate exposed credentials at the
|
|
20
|
+
issuing CKAN site. Removing a token from a later commit does not revoke it.
|
|
21
|
+
|
|
22
|
+
The SDK excludes tokens from configuration repr, redacts SDK error context,
|
|
23
|
+
disables redirects, and does not retry generic actions. It cannot protect tokens
|
|
24
|
+
that applications print directly or sensitive data returned in successful results.
|
|
25
|
+
Custom transports and application logging remain the caller's responsibility.
|
|
26
|
+
|
|
27
|
+
Generic actions can mutate data. A network timeout does not prove that a write
|
|
28
|
+
failed; inspect server state before retrying. Use local/staging CKAN instances for
|
|
29
|
+
write tests. The library does not execute or download resource files in v0.1.0.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""Explicitly selected BenchCore measurements; excluded from normal test discovery."""
|
|
2
|
+
|
|
3
|
+
import httpx
|
|
4
|
+
import pytest
|
|
5
|
+
from benchcore.core.models import BenchmarkConfig
|
|
6
|
+
from benchcore.integrations.pytest import BenchCoreFixture
|
|
7
|
+
|
|
8
|
+
from chile_open_data_sdk._internal.responses import parse_response, redact
|
|
9
|
+
from chile_open_data_sdk.types import JSONValue
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@pytest.mark.benchcore(
|
|
13
|
+
name="parse-datastore-page[rows=1000]",
|
|
14
|
+
config=BenchmarkConfig(rounds=20, warmup_rounds=2, iterations=10),
|
|
15
|
+
)
|
|
16
|
+
def test_parse_datastore_page(benchcore: BenchCoreFixture) -> None:
|
|
17
|
+
records = [{"_id": i, "region": "Metropolitana", "value": i / 10} for i in range(1000)]
|
|
18
|
+
response = httpx.Response(200, json={"success": True, "result": {"records": records}})
|
|
19
|
+
result = benchcore(parse_response, response, "datastore_search", None)
|
|
20
|
+
assert result.value == {"records": records}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@pytest.mark.benchcore(
|
|
24
|
+
name="redact-diagnostics[entries=100]",
|
|
25
|
+
config=BenchmarkConfig(rounds=20, warmup_rounds=2, iterations=10),
|
|
26
|
+
)
|
|
27
|
+
def test_redact_nested_diagnostics(benchcore: BenchCoreFixture) -> None:
|
|
28
|
+
token = "sdk_secret_benchcore_fixture"
|
|
29
|
+
payload: JSONValue = {
|
|
30
|
+
"errors": [{"message": "echo " + token, "api_token": token} for _ in range(100)]
|
|
31
|
+
}
|
|
32
|
+
result = benchcore(redact, payload, token)
|
|
33
|
+
assert token not in repr(result.value)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Opt-in CPU benchmarks; no network calls or timing assertions."""
|
|
2
|
+
|
|
3
|
+
import httpx
|
|
4
|
+
from pytest_benchmark.fixture import BenchmarkFixture
|
|
5
|
+
|
|
6
|
+
from chile_open_data_sdk._internal.responses import parse_response, redact
|
|
7
|
+
from chile_open_data_sdk.types import JSONValue
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def test_parse_datastore_page(benchmark: BenchmarkFixture) -> None:
|
|
11
|
+
records = [{"_id": i, "region": "Metropolitana", "value": i / 10} for i in range(1000)]
|
|
12
|
+
response = httpx.Response(200, json={"success": True, "result": {"records": records}})
|
|
13
|
+
result = benchmark(parse_response, response, "datastore_search", None)
|
|
14
|
+
assert result == {"records": records}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def test_redact_nested_diagnostics(benchmark: BenchmarkFixture) -> None:
|
|
18
|
+
token = "sdk_secret_benchmark_fixture"
|
|
19
|
+
payload: JSONValue = {
|
|
20
|
+
"errors": [{"message": "echo " + token, "api_token": token} for _ in range(100)]
|
|
21
|
+
}
|
|
22
|
+
result = benchmark(redact, payload, token)
|
|
23
|
+
assert token not in repr(result)
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Generic actions
|
|
2
|
+
|
|
3
|
+
`client.actions.call(action, data=None)` sends a JSON object in an HTTP POST to
|
|
4
|
+
`<site_url><action_path>/<action>`. Parameters are not transformed into a custom
|
|
5
|
+
query language. Nested mappings, lists, booleans, and null are encoded as JSON.
|
|
6
|
+
Action names must start with an ASCII letter and contain only ASCII letters,
|
|
7
|
+
digits, and underscores. Files and multipart uploads are not supported.
|
|
8
|
+
|
|
9
|
+
The return type is `JSONValue`: null, boolean, integer, float, string, list, or
|
|
10
|
+
string-keyed dictionary, recursively. Parameters must also be JSON-compatible,
|
|
11
|
+
with finite numeric values. Unknown CKAN result fields are preserved.
|
|
12
|
+
|
|
13
|
+
## Catalog queries available through the generic API
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
from chile_open_data_sdk import ChileOpenDataClient
|
|
17
|
+
|
|
18
|
+
with ChileOpenDataClient() as client:
|
|
19
|
+
names = client.actions.call("package_list", {"limit": 5})
|
|
20
|
+
search = client.actions.call(
|
|
21
|
+
"package_search",
|
|
22
|
+
{
|
|
23
|
+
"q": "transport",
|
|
24
|
+
"fq": "res_format:CSV",
|
|
25
|
+
"rows": 5,
|
|
26
|
+
"start": 0,
|
|
27
|
+
},
|
|
28
|
+
)
|
|
29
|
+
organizations = client.actions.call("organization_list", {"limit": 5})
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
`package_show` and `resource_show` accept an `id` parameter supplied by your
|
|
33
|
+
application. The names and capabilities of actions depend on the CKAN server and
|
|
34
|
+
its plugins. Prefer the planned typed services when they become available.
|
|
35
|
+
|
|
36
|
+
## DataStore examples
|
|
37
|
+
|
|
38
|
+
The following assumes an existing client and a resource ID obtained from dataset
|
|
39
|
+
metadata. These are generic calls, not the future typed DataStore service:
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
result = client.actions.call(
|
|
43
|
+
"datastore_search",
|
|
44
|
+
{
|
|
45
|
+
"resource_id": resource_id,
|
|
46
|
+
"filters": {"region": "Metropolitana"},
|
|
47
|
+
"fields": ["region"],
|
|
48
|
+
"limit": 10,
|
|
49
|
+
"offset": 0,
|
|
50
|
+
},
|
|
51
|
+
)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Field names and filter values must match the resource. `datastore_search_sql` can
|
|
55
|
+
be called with `{"sql": sql}` if enabled upstream. SQL is caller-provided: never
|
|
56
|
+
build it from untrusted input without proper validation. The SDK does not sanitize
|
|
57
|
+
SQL or implement an ORM. DataStore availability is not guaranteed.
|
|
58
|
+
|
|
59
|
+
## Writes, pagination, and retry policy
|
|
60
|
+
|
|
61
|
+
The generic escape hatch can invoke authenticated write actions. There is no
|
|
62
|
+
read-only allowlist or write confirmation in the SDK. CKAN enforces authorization.
|
|
63
|
+
Never use production writes as connectivity tests.
|
|
64
|
+
|
|
65
|
+
Every call makes one attempt. A timeout can occur after a write was applied; do
|
|
66
|
+
not blindly repeat it. Pagination is manual in v0.1.0: set `start`/`rows` or
|
|
67
|
+
`offset`/`limit` as appropriate. No background or unbounded fetching occurs.
|
|
68
|
+
|
|
69
|
+
Protocol references: [CKAN Action API](https://docs.ckan.org/en/2.11/api/) and
|
|
70
|
+
[DataStore API](https://docs.ckan.org/en/2.11/maintaining/datastore.html).
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# API reference
|
|
2
|
+
|
|
3
|
+
The supported top-level exports are `CKANClient`, `ChileOpenDataClient`,
|
|
4
|
+
`ClientConfig`, `JSONValue`, and `__version__`. Exceptions live in
|
|
5
|
+
`chile_open_data_sdk.errors`. `ActionService` is accessed through `client.actions`;
|
|
6
|
+
applications normally do not instantiate it directly. `_internal` is private.
|
|
7
|
+
|
|
8
|
+
::: chile_open_data_sdk.client.CKANClient
|
|
9
|
+
|
|
10
|
+
::: chile_open_data_sdk.client.ChileOpenDataClient
|
|
11
|
+
|
|
12
|
+
::: chile_open_data_sdk.client.ActionService
|
|
13
|
+
|
|
14
|
+
::: chile_open_data_sdk.config.ClientConfig
|
|
15
|
+
|
|
16
|
+
::: chile_open_data_sdk.errors
|