water-ogcapi 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.
- water_ogcapi-0.1.0/.agents/skills/live-api/SKILL.md +105 -0
- water_ogcapi-0.1.0/.agents/skills/update-package/SKILL.md +119 -0
- water_ogcapi-0.1.0/.agents/skills/update-package/summarize.py +49 -0
- water_ogcapi-0.1.0/.gemini/settings.json +8 -0
- water_ogcapi-0.1.0/.github/dependabot.yml +7 -0
- water_ogcapi-0.1.0/.github/pull_request_template.md +26 -0
- water_ogcapi-0.1.0/.github/workflows/ci.yml +76 -0
- water_ogcapi-0.1.0/.github/workflows/docs.yml +50 -0
- water_ogcapi-0.1.0/.github/workflows/drift.yml +43 -0
- water_ogcapi-0.1.0/.github/workflows/release.yml +94 -0
- water_ogcapi-0.1.0/.gitignore +83 -0
- water_ogcapi-0.1.0/.pre-commit-config.yaml +104 -0
- water_ogcapi-0.1.0/AGENTS.md +232 -0
- water_ogcapi-0.1.0/CODE_OF_CONDUCT.md +120 -0
- water_ogcapi-0.1.0/LICENSE +21 -0
- water_ogcapi-0.1.0/PKG-INFO +159 -0
- water_ogcapi-0.1.0/README.md +127 -0
- water_ogcapi-0.1.0/REVIEW.md +60 -0
- water_ogcapi-0.1.0/SECURITY.md +19 -0
- water_ogcapi-0.1.0/docs/.nav.yml +13 -0
- water_ogcapi-0.1.0/docs/api.md +68 -0
- water_ogcapi-0.1.0/docs/contributing.md +1 -0
- water_ogcapi-0.1.0/docs/design.md +2857 -0
- water_ogcapi-0.1.0/docs/endpoints.md +82 -0
- water_ogcapi-0.1.0/docs/examples/cache_quota_resume.ipynb +408 -0
- water_ogcapi-0.1.0/docs/examples/cache_quota_resume.py +154 -0
- water_ogcapi-0.1.0/docs/examples/fabricdata.ipynb +482 -0
- water_ogcapi-0.1.0/docs/examples/fabricdata.py +135 -0
- water_ogcapi-0.1.0/docs/examples/geoconnex.ipynb +397 -0
- water_ogcapi-0.1.0/docs/examples/geoconnex.py +126 -0
- water_ogcapi-0.1.0/docs/examples/images/cache_quota_resume.png +0 -0
- water_ogcapi-0.1.0/docs/examples/images/fabricdata.png +0 -0
- water_ogcapi-0.1.0/docs/examples/images/geoconnex.png +0 -0
- water_ogcapi-0.1.0/docs/examples/images/nwis.png +0 -0
- water_ogcapi-0.1.0/docs/examples/images/transport.png +0 -0
- water_ogcapi-0.1.0/docs/examples/index.md +27 -0
- water_ogcapi-0.1.0/docs/examples/nwis.ipynb +472 -0
- water_ogcapi-0.1.0/docs/examples/nwis.py +144 -0
- water_ogcapi-0.1.0/docs/examples/transport.ipynb +435 -0
- water_ogcapi-0.1.0/docs/examples/transport.py +227 -0
- water_ogcapi-0.1.0/docs/guide/.nav.yml +14 -0
- water_ogcapi-0.1.0/docs/guide/dataretrieval.md +122 -0
- water_ogcapi-0.1.0/docs/guide/errors.md +75 -0
- water_ogcapi-0.1.0/docs/guide/index.md +35 -0
- water_ogcapi-0.1.0/docs/guide/logging.md +117 -0
- water_ogcapi-0.1.0/docs/guide/pagination.md +123 -0
- water_ogcapi-0.1.0/docs/guide/performance.md +150 -0
- water_ogcapi-0.1.0/docs/guide/pynhd.md +134 -0
- water_ogcapi-0.1.0/docs/guide/queries.md +146 -0
- water_ogcapi-0.1.0/docs/guide/setup.md +71 -0
- water_ogcapi-0.1.0/docs/guide/sync-and-async.md +115 -0
- water_ogcapi-0.1.0/docs/guide/workers.md +68 -0
- water_ogcapi-0.1.0/docs/index.md +5 -0
- water_ogcapi-0.1.0/docs/license.md +5 -0
- water_ogcapi-0.1.0/pixi.lock +5357 -0
- water_ogcapi-0.1.0/pyproject.toml +379 -0
- water_ogcapi-0.1.0/scripts/audit-requirements.txt +2 -0
- water_ogcapi-0.1.0/scripts/bench.py +538 -0
- water_ogcapi-0.1.0/scripts/convert_notebooks.py +19 -0
- water_ogcapi-0.1.0/scripts/griffe_twins.py +74 -0
- water_ogcapi-0.1.0/scripts/lint_untracked.py +21 -0
- water_ogcapi-0.1.0/scripts/lock_sdists.py +34 -0
- water_ogcapi-0.1.0/scripts/openapi_drift.py +166 -0
- water_ogcapi-0.1.0/scripts/record_fixtures.py +145 -0
- water_ogcapi-0.1.0/scripts/roadmap.py +107 -0
- water_ogcapi-0.1.0/scripts/run_guides.py +59 -0
- water_ogcapi-0.1.0/src/water_ogcapi/__init__.py +70 -0
- water_ogcapi-0.1.0/src/water_ogcapi/_arrow.py +89 -0
- water_ogcapi-0.1.0/src/water_ogcapi/_cache.py +37 -0
- water_ogcapi-0.1.0/src/water_ogcapi/_client.py +1017 -0
- water_ogcapi-0.1.0/src/water_ogcapi/_governor.py +138 -0
- water_ogcapi-0.1.0/src/water_ogcapi/_logging.py +151 -0
- water_ogcapi-0.1.0/src/water_ogcapi/_metadata.py +456 -0
- water_ogcapi-0.1.0/src/water_ogcapi/_paging.py +210 -0
- water_ogcapi-0.1.0/src/water_ogcapi/_query.py +444 -0
- water_ogcapi-0.1.0/src/water_ogcapi/_redact.py +40 -0
- water_ogcapi-0.1.0/src/water_ogcapi/_results.py +538 -0
- water_ogcapi-0.1.0/src/water_ogcapi/_services.py +275 -0
- water_ogcapi-0.1.0/src/water_ogcapi/_sync.py +355 -0
- water_ogcapi-0.1.0/src/water_ogcapi/_transport.py +1446 -0
- water_ogcapi-0.1.0/src/water_ogcapi/aio.py +27 -0
- water_ogcapi-0.1.0/src/water_ogcapi/exceptions.py +199 -0
- water_ogcapi-0.1.0/src/water_ogcapi/py.typed +0 -0
- water_ogcapi-0.1.0/tests/conftest.py +19 -0
- water_ogcapi-0.1.0/tests/fixtures/README.md +60 -0
- water_ogcapi-0.1.0/tests/fixtures/fabricdata/collections.json +4334 -0
- water_ogcapi-0.1.0/tests/fixtures/fabricdata/gagesii/collection.json +161 -0
- water_ogcapi-0.1.0/tests/fixtures/fabricdata/gagesii/items-1.json +236 -0
- water_ogcapi-0.1.0/tests/fixtures/fabricdata/gagesii/items-2.json +170 -0
- water_ogcapi-0.1.0/tests/fixtures/fabricdata/gagesii/queryables.json +108 -0
- water_ogcapi-0.1.0/tests/fixtures/fabricdata/gagesii/schema.json +92 -0
- water_ogcapi-0.1.0/tests/fixtures/fabricdata/landing.json +112 -0
- water_ogcapi-0.1.0/tests/fixtures/fabricdata/openapi.json +17785 -0
- water_ogcapi-0.1.0/tests/fixtures/geoconnex/collections.json +3590 -0
- water_ogcapi-0.1.0/tests/fixtures/geoconnex/gages/collection.json +199 -0
- water_ogcapi-0.1.0/tests/fixtures/geoconnex/gages/queryables.json +120 -0
- water_ogcapi-0.1.0/tests/fixtures/geoconnex/gages/schema.json +100 -0
- water_ogcapi-0.1.0/tests/fixtures/geoconnex/hu02/items-1.json +252 -0
- water_ogcapi-0.1.0/tests/fixtures/geoconnex/hu02/items-2.json +254 -0
- water_ogcapi-0.1.0/tests/fixtures/geoconnex/hu02/items-3.json +136 -0
- water_ogcapi-0.1.0/tests/fixtures/geoconnex/landing.json +101 -0
- water_ogcapi-0.1.0/tests/fixtures/geoconnex/openapi.json +10786 -0
- water_ogcapi-0.1.0/tests/fixtures/nwis/collections.json +4627 -0
- water_ogcapi-0.1.0/tests/fixtures/nwis/daily/collection.json +159 -0
- water_ogcapi-0.1.0/tests/fixtures/nwis/daily/items-1.json +156 -0
- water_ogcapi-0.1.0/tests/fixtures/nwis/daily/items-2.json +150 -0
- water_ogcapi-0.1.0/tests/fixtures/nwis/daily/items-3.json +150 -0
- water_ogcapi-0.1.0/tests/fixtures/nwis/daily/queryables.json +311 -0
- water_ogcapi-0.1.0/tests/fixtures/nwis/daily/schema.json +113 -0
- water_ogcapi-0.1.0/tests/fixtures/nwis/landing.json +110 -0
- water_ogcapi-0.1.0/tests/fixtures/nwis/monitoring-locations/collection.json +158 -0
- water_ogcapi-0.1.0/tests/fixtures/nwis/monitoring-locations/item-USGS-01646500.json +132 -0
- water_ogcapi-0.1.0/tests/fixtures/nwis/monitoring-locations/items-1.json +253 -0
- water_ogcapi-0.1.0/tests/fixtures/nwis/monitoring-locations/items-2.json +249 -0
- water_ogcapi-0.1.0/tests/fixtures/nwis/monitoring-locations/items-3.json +249 -0
- water_ogcapi-0.1.0/tests/fixtures/nwis/monitoring-locations/queryables.json +264 -0
- water_ogcapi-0.1.0/tests/fixtures/nwis/monitoring-locations/schema.json +307 -0
- water_ogcapi-0.1.0/tests/fixtures/nwis/openapi.json +29560 -0
- water_ogcapi-0.1.0/tests/test_arrow.py +409 -0
- water_ogcapi-0.1.0/tests/test_client.py +1729 -0
- water_ogcapi-0.1.0/tests/test_download.py +1025 -0
- water_ogcapi-0.1.0/tests/test_exceptions.py +91 -0
- water_ogcapi-0.1.0/tests/test_fanout.py +657 -0
- water_ogcapi-0.1.0/tests/test_governor.py +398 -0
- water_ogcapi-0.1.0/tests/test_logging.py +143 -0
- water_ogcapi-0.1.0/tests/test_metadata.py +192 -0
- water_ogcapi-0.1.0/tests/test_openapi_drift.py +237 -0
- water_ogcapi-0.1.0/tests/test_pickles.py +131 -0
- water_ogcapi-0.1.0/tests/test_results.py +303 -0
- water_ogcapi-0.1.0/tests/test_roadmap.py +64 -0
- water_ogcapi-0.1.0/tests/test_services.py +379 -0
- water_ogcapi-0.1.0/tests/test_sync.py +552 -0
- water_ogcapi-0.1.0/tests/test_transport.py +1566 -0
- water_ogcapi-0.1.0/tests/test_validation.py +224 -0
- water_ogcapi-0.1.0/zensical.toml +62 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: live-api
|
|
3
|
+
description: Use before sending any request to the live NWIS, FabricData, or GeoConnex endpoints, including recording test fixtures, writing or running network-marked tests, checking rate-limit or auth headers, and writing up API behavior findings. Covers credential handling, quota limits, and what evidence to keep.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Working against the live endpoints
|
|
7
|
+
|
|
8
|
+
These are production services that USGS runs for every user. Base URLs are in
|
|
9
|
+
`README.md`.
|
|
10
|
+
|
|
11
|
+
## Credentials
|
|
12
|
+
|
|
13
|
+
A leaked key ends up in git history, CI logs, or a public issue, where anyone can spend
|
|
14
|
+
its quota. Recorded fixtures and copied URLs are the easy ways for it to reach disk.
|
|
15
|
+
|
|
16
|
+
- Read the key from the `USGS_API_KEY` environment variable. Never print it or write it
|
|
17
|
+
into a file, commit, issue, or chat message. Run an offline probe of code that reads
|
|
18
|
+
the variable as `env -u USGS_API_KEY <probe>` or with a fake value, and print only
|
|
19
|
+
comparisons (`headers["X-Api-Key"] == FAKE`); put `env -u` on the probe command
|
|
20
|
+
only, since the redaction filter below reads the variable.
|
|
21
|
+
- USGS documents two forms: an `X-Api-Key` request header and an `api_key` query
|
|
22
|
+
parameter. Use the header. The query form puts the key in the request URL, and the
|
|
23
|
+
server may echo query parameters into the `next` links of the response body.
|
|
24
|
+
- Scrub at record time, before anything is written to disk. Store no request headers.
|
|
25
|
+
- GeoConnex takes no key. Never send it one.
|
|
26
|
+
- The HTTP/2 encoder logs headers: `hpack` writes every header value, the key included,
|
|
27
|
+
at DEBUG on its own logger, and the package raises that logger to INFO at import
|
|
28
|
+
(D-20). A test that the key never reaches a log captures the root logger at DEBUG
|
|
29
|
+
while the real encoder runs. A mocked transport skips the encoder, so it proves only
|
|
30
|
+
the layers above it.
|
|
31
|
+
- A server can echo the key back: a redirect's `Location` has carried it as a query
|
|
32
|
+
parameter. Pipe every probe's output through a filter that replaces the key's value,
|
|
33
|
+
and request a base URL with its trailing slash, since the bare form redirects.
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
<probe command> 2>&1 | python3 -c 'import os, sys; k = os.environ["USGS_API_KEY"]; sys.stdout.writelines(l.replace(k, "REDACTED") for l in sys.stdin)'
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
- Before finishing, scan for the current key. The command fails loudly when the variable
|
|
40
|
+
is unset or empty, prints file names only, and keeps the key off the command line.
|
|
41
|
+
No output means the current key is not in the working tree; it cannot find old or
|
|
42
|
+
encoded keys.
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
: "${USGS_API_KEY:?}" && command grep -rlF -f <(printenv USGS_API_KEY) . --exclude-dir=.git --exclude-dir=.pixi
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Quota
|
|
49
|
+
|
|
50
|
+
- Keep probes small: a low `limit`, one page unless the question is about paging.
|
|
51
|
+
- When a script derives a committed artifact (a snapshot, a fixture) from a live
|
|
52
|
+
response, save the raw response once, scrubbed as a fixture is, to the scratchpad
|
|
53
|
+
and never the repo, and develop the derivation against that file. Refetch only to
|
|
54
|
+
confirm the final artifact.
|
|
55
|
+
- A test run reaches the live services only with `-m network` (`test-network`) or
|
|
56
|
+
`-m ''` (`test-all`); `addopts` deselects network-marked tests everywhere else, so a
|
|
57
|
+
narrowed run (`pixi r -e test315 pytest tests/test_x.py`) stays offline.
|
|
58
|
+
- Probe through `Transport(max_retries=0)` so one call sends one request. The default
|
|
59
|
+
retries up to three times, and the caller never sees the intermediate responses.
|
|
60
|
+
- Read `X-RateLimit-Remaining` on each response and stop well before zero. It lags a
|
|
61
|
+
burst of requests by a few seconds, so space probes out. If a service sends no
|
|
62
|
+
`X-RateLimit-*` headers, keep to a handful of requests per task.
|
|
63
|
+
- Never provoke a 429. Test rate-limit handling against `httpx2.MockTransport` only.
|
|
64
|
+
- Make network tests for FabricData skip when the backend does not respond.
|
|
65
|
+
|
|
66
|
+
## Stable targets
|
|
67
|
+
|
|
68
|
+
- NWIS: monitoring location `01646500` (Potomac River near Washington, DC), and a small
|
|
69
|
+
bounding box around Washington, DC.
|
|
70
|
+
- GeoConnex: the 22 two-digit HUCs in `hu02`, `01` to `22`.
|
|
71
|
+
|
|
72
|
+
## Fixtures
|
|
73
|
+
|
|
74
|
+
- Record from real responses. Keep the status, the response headers, and the body. Keep
|
|
75
|
+
the request URL and params with credentials removed.
|
|
76
|
+
- A fixture stores the decoded body, so drop the headers that describe the wire bytes,
|
|
77
|
+
`content-encoding` and `content-length`: a mock serving a decoded body under
|
|
78
|
+
`content-encoding: gzip` tries to gunzip plain JSON. Never store `set-cookie`.
|
|
79
|
+
`scripts/record_fixtures.py` drops all three.
|
|
80
|
+
- Record the request date with each fixture. The NWIS API is v1 and USGS may change it.
|
|
81
|
+
- If `tests/fixtures/` does not exist yet, propose a layout before creating one.
|
|
82
|
+
- Note which services send `X-RateLimit-*` headers. The quota logic depends on it.
|
|
83
|
+
|
|
84
|
+
## Checking that the key is honored
|
|
85
|
+
|
|
86
|
+
Send one keyed and one unkeyed request to the same endpoint and compare the
|
|
87
|
+
`X-RateLimit-*` headers. A higher limit on the keyed response shows the key was honored.
|
|
88
|
+
Equal limits or missing headers are inconclusive; record them as such.
|
|
89
|
+
|
|
90
|
+
USGS raises a key's limit on request, and a raised key reports its own limit on every
|
|
91
|
+
endpoint (D-30). A check made with such a key shows that key's limit, so record a
|
|
92
|
+
default limit only from a key that has the default. Ignore `X-RateLimit-*` on a response
|
|
93
|
+
with `x-cache: Hit`: CloudFront serves the headers stored with the cached response.
|
|
94
|
+
|
|
95
|
+
## Writing up findings
|
|
96
|
+
|
|
97
|
+
Write each finding as a neutral, reproducible observation:
|
|
98
|
+
|
|
99
|
+
1. The request: method, URL with credentials removed, and date.
|
|
100
|
+
1. What the response showed: status, the relevant headers, a short body excerpt.
|
|
101
|
+
1. What was expected, citing the OGC API spec or the USGS docs.
|
|
102
|
+
|
|
103
|
+
Keep what you observed apart from what you infer from it. `docs/design.md` Q-07 lists
|
|
104
|
+
claims that are still unverified. Do not state any of them as fact until a live response
|
|
105
|
+
confirms it.
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: update-package
|
|
3
|
+
description: Update this package's locked dependencies and pre-commit hooks, then land the change. `pixi update` refreshes pixi.lock, `pixi r pcupdate` moves the hook revisions, the full gate from AGENTS.md runs with the dependency audit and the network tests, findings the newer tools raise get fixed at their cause, and the change goes in through a PR merged once CI passes. Use when asked to update dependencies, refresh or bump the lock file, update the pre-commit hooks, or run /update-package.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Update dependencies and hooks
|
|
7
|
+
|
|
8
|
+
Asking for this skill is the go-ahead to push the branch, open the PR, and merge it once
|
|
9
|
+
CI passes, for a contributor allowed to merge; anyone else stops at the open PR and asks
|
|
10
|
+
a maintainer. It covers nothing else: no tag, no release, no force-push, no change to
|
|
11
|
+
repository settings, and no merge while a required check is red or pending.
|
|
12
|
+
|
|
13
|
+
`$SCRATCH` below is a scratch directory outside the repository.
|
|
14
|
+
|
|
15
|
+
## 1. Preflight
|
|
16
|
+
|
|
17
|
+
Stop at the first failure and report it. The tree must be clean and match `origin/main`,
|
|
18
|
+
since the PR has to hold the update and nothing else:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
git fetch -q origin
|
|
22
|
+
DEF=$(git symbolic-ref --short refs/remotes/origin/HEAD | sed 's#^origin/##')
|
|
23
|
+
test "$(git branch --show-current)" = "$DEF" &&
|
|
24
|
+
test -z "$(git status --porcelain)" &&
|
|
25
|
+
test "$(git rev-parse HEAD)" = "$(git rev-parse "origin/$DEF")"
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Then branch, following the `<type>/<short-description>` rule in AGENTS.md:
|
|
29
|
+
`B=chore/update-deps-$(date +%F); git switch -c "$B"`, adding `-2` for a second run the
|
|
30
|
+
same day.
|
|
31
|
+
|
|
32
|
+
## 2. Update
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pixi update --json >| "$SCRATCH/pixi-update.json"
|
|
36
|
+
pixi r pcupdate >| "$SCRATCH/pcupdate.log" 2>&1
|
|
37
|
+
python3 .agents/skills/update-package/summarize.py "$SCRATCH/pixi-update.json"
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The script prints one Markdown row per change (package, before, after, environments) and
|
|
41
|
+
the change count on stderr; a report with no changes prints `0 package changes`. A row
|
|
42
|
+
with the same version on both sides is a build-string change. The hook log names each
|
|
43
|
+
hook that moved (`updating v0.16.10 -> v0.17.1`). Mark the changes to the runtime
|
|
44
|
+
dependencies, `[project] dependencies` in `pyproject.toml` (`httpx2` and `h2`), since
|
|
45
|
+
reviewers read those first. When neither `pixi.lock` nor `.pre-commit-config.yaml`
|
|
46
|
+
changed, report that, delete the branch, and stop.
|
|
47
|
+
|
|
48
|
+
## 3. Gate
|
|
49
|
+
|
|
50
|
+
Delete `.coverage` and any `.coverage.*` files first, since coverage accumulates across
|
|
51
|
+
runs (AGENTS.md, Gotchas). Then run, each to a clean exit:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pixi r lint && pixi r typecheck && pixi r -e test313 test && pixi r -e test315 test &&
|
|
55
|
+
pixi r docs && pixi r audit
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
- Lint runs the new hook versions over every file. When a formatter rewrites files, run
|
|
59
|
+
lint once more and keep the rewrite for its own commit.
|
|
60
|
+
- The docs build and the audit belong here even with no change under `docs/`: a new
|
|
61
|
+
zensical or mkdocstrings can break the build, and a new resolution can pull in an
|
|
62
|
+
advisory.
|
|
63
|
+
- When a runtime dependency moved, also run `pixi r -e test315 test-network`, following
|
|
64
|
+
the `live-api` skill. The offline tests mock the wire that `httpx2` drives, so they
|
|
65
|
+
cannot see a change in it.
|
|
66
|
+
|
|
67
|
+
## 4. Fix what the new versions raise
|
|
68
|
+
|
|
69
|
+
Fix each finding at its cause. Never silence one to pass: no new ignore, no lowered
|
|
70
|
+
strictness in `pyproject.toml`, no skipped or loosened test, and no package pinned back
|
|
71
|
+
without the maintainer's yes. A finding that needs a design call, or a package whose new
|
|
72
|
+
version breaks something with no small fix, goes to the maintainer with the failing
|
|
73
|
+
output and the options: fix it, pin an upper bound, or hold the package out by updating
|
|
74
|
+
the others by name (`pixi update <pkg> ...`). A fix that makes or reverses a design
|
|
75
|
+
decision updates `docs/design.md` in the same change.
|
|
76
|
+
|
|
77
|
+
## 5. Commit
|
|
78
|
+
|
|
79
|
+
One commit per concern, staged by path, each chained to the gate with nothing between
|
|
80
|
+
the gate and `&&`:
|
|
81
|
+
|
|
82
|
+
1. `chore: update pixi.lock`, the body giving the change count and the runtime changes;
|
|
83
|
+
1. `chore: update pre-commit hooks`, the body naming each hook's new revision;
|
|
84
|
+
1. a formatter rewrite from the new hooks: `style: apply <tool> <version> formatting`;
|
|
85
|
+
1. each fix, as `fix:` or `refactor:`, naming what the new version changed.
|
|
86
|
+
|
|
87
|
+
Check each with `git show --stat HEAD` before making the next.
|
|
88
|
+
|
|
89
|
+
## 6. Pull request and merge
|
|
90
|
+
|
|
91
|
+
Push the branch and open the PR from `.github/pull_request_template.md`: the runtime
|
|
92
|
+
changes, the hook revisions, the full table in a collapsed `<details>` block, and the
|
|
93
|
+
gate results, network tests and audit included. With no issue to close, say so on the
|
|
94
|
+
body's first line in place of `Closes #`.
|
|
95
|
+
|
|
96
|
+
Wait for CI without a polling loop where your agent's environment forbids one; in a
|
|
97
|
+
plain terminal, `gh pr checks <n> --watch --fail-fast` blocks until the checks finish.
|
|
98
|
+
The ruleset on `main` requires `Test (test313)`, `Test (test315)`, `typecheck`, `lint`,
|
|
99
|
+
and `build`. A red check is fixed on the branch and pushed, back through steps 3 to 5.
|
|
100
|
+
|
|
101
|
+
Merge only when every required check passes and the PR reads CLEAN, with a rebase merge:
|
|
102
|
+
`gh pr merge <n> --rebase`. Record the branch tip first (`TIP=$(git rev-parse "$B")`),
|
|
103
|
+
then:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
git fetch -q origin
|
|
107
|
+
test "$(git rev-parse "origin/$DEF^{tree}")" = "$(git rev-parse "$TIP^{tree}")" &&
|
|
108
|
+
git switch -q "$DEF" && git merge -q --ff-only "origin/$DEF" && git branch -D "$B"
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
A tree mismatch means `main` moved during the merge: report it and keep the local
|
|
112
|
+
branch. Report the PR, the merged commit, and the notable changes in a few lines.
|
|
113
|
+
|
|
114
|
+
## Pre-flight before the merge
|
|
115
|
+
|
|
116
|
+
Answer in writing: the branch holds only the update and its fixes; every gate step
|
|
117
|
+
passed on the final tree, the docs build and the audit included; the network tests ran
|
|
118
|
+
if a runtime dependency moved; no finding was silenced; the runtime changes are named in
|
|
119
|
+
the PR; every required check passed and the PR is CLEAN.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""Print one Markdown table row per package change in a ``pixi update --json`` report.
|
|
2
|
+
|
|
3
|
+
Usage: ``python3 .agents/skills/update-package/summarize.py <report.json>``. The change
|
|
4
|
+
count goes to stderr; a report with no changes prints ``0 package changes``.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
import re
|
|
11
|
+
import sys
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
# A conda entry carries only its URL: name-version-build.conda
|
|
16
|
+
CONDA_VERSION = re.compile(r"/[^/]+?-([^-/]+)-[^-/]+\.(?:conda|tar\.bz2)$")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def version(side: dict[str, Any] | None) -> str:
|
|
20
|
+
"""Return the version on one side of a change, ``-`` when the package is absent."""
|
|
21
|
+
if not side:
|
|
22
|
+
return "-"
|
|
23
|
+
if "version" in side:
|
|
24
|
+
return str(side["version"])
|
|
25
|
+
match = CONDA_VERSION.search(str(side.get("conda", "")))
|
|
26
|
+
return match.group(1) if match else "?"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def main(report: Path) -> None:
|
|
30
|
+
"""Print the rows for ``report``, one per package and version pair."""
|
|
31
|
+
changes: dict[tuple[str, str, str], set[str]] = {}
|
|
32
|
+
environments = json.loads(report.read_text(encoding="utf-8")).get("environment", {})
|
|
33
|
+
for env, platforms in environments.items():
|
|
34
|
+
for packages in platforms.values():
|
|
35
|
+
for package in packages:
|
|
36
|
+
key = (
|
|
37
|
+
package["name"],
|
|
38
|
+
version(package.get("before")),
|
|
39
|
+
version(package.get("after")),
|
|
40
|
+
)
|
|
41
|
+
changes.setdefault(key, set()).add(env)
|
|
42
|
+
out = sys.stdout
|
|
43
|
+
for (name, old, new), envs in sorted(changes.items()):
|
|
44
|
+
out.write(f"| {name} | {old} | {new} | {', '.join(sorted(envs))} |\n")
|
|
45
|
+
sys.stderr.write(f"{len(changes)} package changes\n")
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
if __name__ == "__main__":
|
|
49
|
+
main(Path(sys.argv[1]))
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
Closes #
|
|
2
|
+
|
|
3
|
+
## What changed
|
|
4
|
+
|
|
5
|
+
<!-- What the change does and why, in a few sentences. Name the D-, L-, or Q- entries in
|
|
6
|
+
docs/design.md it touches. -->
|
|
7
|
+
|
|
8
|
+
## How it was checked
|
|
9
|
+
|
|
10
|
+
<!-- Tick what ran. Add any live-API or manual check, with what it showed. -->
|
|
11
|
+
|
|
12
|
+
- [ ] `pixi r lint`
|
|
13
|
+
- [ ] `pixi r typecheck`
|
|
14
|
+
- [ ] `pixi r -e test313 test`
|
|
15
|
+
- [ ] `pixi r -e test315 test`
|
|
16
|
+
- [ ] `pixi r docs` (needed when `docs/`, `README.md`, or `zensical.toml` changed)
|
|
17
|
+
|
|
18
|
+
## Risk and revert
|
|
19
|
+
|
|
20
|
+
<!-- What this could break and for whom, the review depth REVIEW.md asks for, and how to
|
|
21
|
+
undo it: a revert of this PR, or, after a release, a fix release. -->
|
|
22
|
+
|
|
23
|
+
## Design record
|
|
24
|
+
|
|
25
|
+
- [ ] `docs/design.md` is updated, or this change makes, reverses, or answers nothing
|
|
26
|
+
there
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
14
|
+
cancel-in-progress: true
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
test:
|
|
18
|
+
name: Test (${{ matrix.environment }}, ${{ matrix.os }})
|
|
19
|
+
runs-on: ${{ matrix.os }}
|
|
20
|
+
strategy:
|
|
21
|
+
fail-fast: false
|
|
22
|
+
matrix:
|
|
23
|
+
environment: [test313, test315]
|
|
24
|
+
# One runner per pixi platform: linux-64, osx-arm64, win-64.
|
|
25
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
26
|
+
steps:
|
|
27
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
28
|
+
with:
|
|
29
|
+
fetch-depth: 0 # hatch-vcs reads tags for the version
|
|
30
|
+
- uses: prefix-dev/setup-pixi@ad1da6449d9e506fd127fd67ab2d054a769f6a94 # v0.11.2
|
|
31
|
+
with:
|
|
32
|
+
pixi-version: v0.84.0 # Dependabot does not bump this; see D-55
|
|
33
|
+
environments: ${{ matrix.environment }}
|
|
34
|
+
# `test` excludes the network marker, so CI never touches USGS servers.
|
|
35
|
+
- run: pixi run -e ${{ matrix.environment }} test
|
|
36
|
+
|
|
37
|
+
# The install is the check: a dev package locked as an sdist must build here (D-71).
|
|
38
|
+
dev-install:
|
|
39
|
+
name: Install dev (${{ matrix.os }})
|
|
40
|
+
runs-on: ${{ matrix.os }}
|
|
41
|
+
strategy:
|
|
42
|
+
fail-fast: false
|
|
43
|
+
matrix:
|
|
44
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
45
|
+
steps:
|
|
46
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
47
|
+
with:
|
|
48
|
+
fetch-depth: 0 # hatch-vcs reads tags for the version
|
|
49
|
+
- uses: prefix-dev/setup-pixi@ad1da6449d9e506fd127fd67ab2d054a769f6a94 # v0.11.2
|
|
50
|
+
with:
|
|
51
|
+
pixi-version: v0.84.0 # Dependabot does not bump this; see D-55
|
|
52
|
+
environments: dev
|
|
53
|
+
|
|
54
|
+
typecheck:
|
|
55
|
+
runs-on: ubuntu-latest
|
|
56
|
+
steps:
|
|
57
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
58
|
+
with:
|
|
59
|
+
fetch-depth: 0
|
|
60
|
+
- uses: prefix-dev/setup-pixi@ad1da6449d9e506fd127fd67ab2d054a769f6a94 # v0.11.2
|
|
61
|
+
with:
|
|
62
|
+
pixi-version: v0.84.0 # Dependabot does not bump this; see D-55
|
|
63
|
+
environments: typecheck
|
|
64
|
+
- run: pixi run typecheck
|
|
65
|
+
|
|
66
|
+
lint:
|
|
67
|
+
runs-on: ubuntu-latest
|
|
68
|
+
steps:
|
|
69
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
70
|
+
- uses: prefix-dev/setup-pixi@ad1da6449d9e506fd127fd67ab2d054a769f6a94 # v0.11.2
|
|
71
|
+
with:
|
|
72
|
+
pixi-version: v0.84.0 # Dependabot does not bump this; see D-55
|
|
73
|
+
environments: lint
|
|
74
|
+
- run: pixi run lint
|
|
75
|
+
# Needs network: resolves the runtime dependencies from PyPI and checks their advisories.
|
|
76
|
+
- run: pixi run audit
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
name: Docs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
# Refreshes the roadmap page, which is generated from the GitHub milestones.
|
|
8
|
+
schedule:
|
|
9
|
+
- cron: 0 6 * * *
|
|
10
|
+
workflow_dispatch:
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
contents: read
|
|
14
|
+
issues: read
|
|
15
|
+
|
|
16
|
+
# Never cancel a Pages deployment mid-flight; superseded PR builds can go.
|
|
17
|
+
concurrency:
|
|
18
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
19
|
+
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
|
20
|
+
|
|
21
|
+
jobs:
|
|
22
|
+
build:
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
26
|
+
- uses: prefix-dev/setup-pixi@ad1da6449d9e506fd127fd67ab2d054a769f6a94 # v0.11.2
|
|
27
|
+
with:
|
|
28
|
+
pixi-version: v0.84.0 # Dependabot does not bump this; see D-55
|
|
29
|
+
environments: docs
|
|
30
|
+
# --strict fails the build on warnings such as broken links.
|
|
31
|
+
- run: pixi run docs
|
|
32
|
+
env:
|
|
33
|
+
GITHUB_TOKEN: ${{ github.token }}
|
|
34
|
+
- uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
|
|
35
|
+
with:
|
|
36
|
+
path: site
|
|
37
|
+
|
|
38
|
+
deploy:
|
|
39
|
+
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
|
|
40
|
+
needs: build
|
|
41
|
+
runs-on: ubuntu-latest
|
|
42
|
+
permissions:
|
|
43
|
+
pages: write
|
|
44
|
+
id-token: write
|
|
45
|
+
environment:
|
|
46
|
+
name: github-pages
|
|
47
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
48
|
+
steps:
|
|
49
|
+
- uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1
|
|
50
|
+
id: deployment
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
name: Drift
|
|
2
|
+
|
|
3
|
+
# Weekly check that the live services still match the tests and the OpenAPI snapshots
|
|
4
|
+
# (D-63). Never on pull_request, so no fork run sees the key.
|
|
5
|
+
on:
|
|
6
|
+
schedule:
|
|
7
|
+
- cron: 0 7 * * 1
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
permissions:
|
|
11
|
+
contents: read
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
network-tests:
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
timeout-minutes: 20
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
19
|
+
with:
|
|
20
|
+
fetch-depth: 0 # hatch-vcs reads tags for the version
|
|
21
|
+
persist-credentials: false
|
|
22
|
+
- uses: prefix-dev/setup-pixi@ad1da6449d9e506fd127fd67ab2d054a769f6a94 # v0.11.2
|
|
23
|
+
with:
|
|
24
|
+
pixi-version: v0.84.0 # Dependabot does not bump this; see D-55
|
|
25
|
+
environments: test315
|
|
26
|
+
- run: pixi run -e test315 test-network
|
|
27
|
+
env:
|
|
28
|
+
USGS_API_KEY: ${{ secrets.USGS_API_KEY }} # a key used only here
|
|
29
|
+
|
|
30
|
+
openapi:
|
|
31
|
+
runs-on: ubuntu-latest
|
|
32
|
+
timeout-minutes: 20
|
|
33
|
+
steps:
|
|
34
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
35
|
+
with:
|
|
36
|
+
fetch-depth: 0
|
|
37
|
+
persist-credentials: false
|
|
38
|
+
- uses: prefix-dev/setup-pixi@ad1da6449d9e506fd127fd67ab2d054a769f6a94 # v0.11.2
|
|
39
|
+
with:
|
|
40
|
+
pixi-version: v0.84.0 # Dependabot does not bump this; see D-55
|
|
41
|
+
environments: test315
|
|
42
|
+
# Sends no key: the OpenAPI documents are public.
|
|
43
|
+
- run: pixi run -e test315 drift
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
# PEP 440 final and pre-release versions only.
|
|
6
|
+
tags:
|
|
7
|
+
- v[0-9]+.[0-9]+.[0-9]+
|
|
8
|
+
- v[0-9]+.[0-9]+.[0-9]+rc[0-9]+
|
|
9
|
+
- v[0-9]+.[0-9]+.[0-9]+[ab][0-9]+
|
|
10
|
+
|
|
11
|
+
permissions: {}
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
release-notes:
|
|
15
|
+
name: Create release notes
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
permissions:
|
|
18
|
+
contents: write # create the GitHub release
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
21
|
+
with:
|
|
22
|
+
fetch-depth: 0
|
|
23
|
+
persist-credentials: false
|
|
24
|
+
# checkout can leave the tag lightweight (actions/checkout#882), dropping the release summary.
|
|
25
|
+
- run: git fetch --force origin "+refs/tags/${GITHUB_REF_NAME}:refs/tags/${GITHUB_REF_NAME}"
|
|
26
|
+
# tag_pattern matches only vX.Y.Z, so a pre-release such as v0.1.0rc1 gets its tag message as notes.
|
|
27
|
+
- id: kind
|
|
28
|
+
run: |
|
|
29
|
+
if [[ "$GITHUB_REF_NAME" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
|
30
|
+
echo "prerelease=false" >> "$GITHUB_OUTPUT"
|
|
31
|
+
else
|
|
32
|
+
echo "prerelease=true" >> "$GITHUB_OUTPUT"
|
|
33
|
+
git tag -l --format='%(contents)' "$GITHUB_REF_NAME" > release-notes.md
|
|
34
|
+
fi
|
|
35
|
+
- uses: orhun/git-cliff-action@a9a95522b26fe6403f7bb24031f21fb573d0f5ff # v4.9.1
|
|
36
|
+
if: steps.kind.outputs.prerelease == 'false'
|
|
37
|
+
with:
|
|
38
|
+
version: v2.14.2 # same as the dev environment's git-cliff
|
|
39
|
+
config: pyproject.toml
|
|
40
|
+
args: --latest --strip all
|
|
41
|
+
env:
|
|
42
|
+
OUTPUT: release-notes.md
|
|
43
|
+
GITHUB_REPO: ${{ github.repository }}
|
|
44
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
45
|
+
- run: gh release create "$GITHUB_REF_NAME" --repo "$GITHUB_REPOSITORY" --verify-tag --notes-file release-notes.md --prerelease="$PRERELEASE"
|
|
46
|
+
env:
|
|
47
|
+
GH_TOKEN: ${{ github.token }}
|
|
48
|
+
PRERELEASE: ${{ steps.kind.outputs.prerelease }}
|
|
49
|
+
|
|
50
|
+
build:
|
|
51
|
+
name: Build distribution
|
|
52
|
+
runs-on: ubuntu-latest
|
|
53
|
+
permissions:
|
|
54
|
+
contents: read
|
|
55
|
+
steps:
|
|
56
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
57
|
+
with:
|
|
58
|
+
fetch-depth: 0 # hatch-vcs reads tags for the version
|
|
59
|
+
persist-credentials: false
|
|
60
|
+
- uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
|
|
61
|
+
with:
|
|
62
|
+
enable-cache: false # no cache poisoning in a publishing pipeline
|
|
63
|
+
- run: uv build
|
|
64
|
+
# Each distribution installs alone, imports, and carries the tag's version.
|
|
65
|
+
- run: |
|
|
66
|
+
for dist in dist/*.whl dist/*.tar.gz; do
|
|
67
|
+
uv run --isolated --no-project --with "$dist" python -c \
|
|
68
|
+
'import sys, water_ogcapi as w; assert w.__version__ == sys.argv[1], w.__version__' \
|
|
69
|
+
"${GITHUB_REF_NAME#v}"
|
|
70
|
+
done
|
|
71
|
+
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
|
72
|
+
with:
|
|
73
|
+
name: dist
|
|
74
|
+
path: dist/
|
|
75
|
+
|
|
76
|
+
publish:
|
|
77
|
+
name: Publish to PyPI
|
|
78
|
+
needs: [build, release-notes]
|
|
79
|
+
runs-on: ubuntu-latest
|
|
80
|
+
environment:
|
|
81
|
+
name: pypi
|
|
82
|
+
url: https://pypi.org/p/water-ogcapi
|
|
83
|
+
permissions:
|
|
84
|
+
id-token: write # trusted publishing and PEP 740 attestations
|
|
85
|
+
steps:
|
|
86
|
+
- uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
|
|
87
|
+
with:
|
|
88
|
+
enable-cache: false
|
|
89
|
+
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
|
90
|
+
with:
|
|
91
|
+
name: dist
|
|
92
|
+
path: dist/
|
|
93
|
+
- uses: astral-sh/attest-action@39b6ce43875c196a579e31635b11aa2a2036384a # v0.0.7
|
|
94
|
+
- run: uv publish
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
env/
|
|
12
|
+
build/
|
|
13
|
+
develop-eggs/
|
|
14
|
+
dist/
|
|
15
|
+
downloads/
|
|
16
|
+
eggs/
|
|
17
|
+
.eggs/
|
|
18
|
+
lib/
|
|
19
|
+
lib64/
|
|
20
|
+
parts/
|
|
21
|
+
sdist/
|
|
22
|
+
var/
|
|
23
|
+
wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
|
|
28
|
+
# Unit test / coverage reports
|
|
29
|
+
htmlcov/
|
|
30
|
+
.tox/
|
|
31
|
+
.coverage
|
|
32
|
+
.coverage.*
|
|
33
|
+
.cache
|
|
34
|
+
nosetests.xml
|
|
35
|
+
coverage.xml
|
|
36
|
+
*.cover
|
|
37
|
+
.hypothesis/
|
|
38
|
+
.pytest_cache/
|
|
39
|
+
.pytest_tmp/
|
|
40
|
+
|
|
41
|
+
# dotenv
|
|
42
|
+
.env
|
|
43
|
+
|
|
44
|
+
# virtualenv
|
|
45
|
+
.venv
|
|
46
|
+
venv/
|
|
47
|
+
ENV/
|
|
48
|
+
|
|
49
|
+
# mypy
|
|
50
|
+
.mypy_cache/
|
|
51
|
+
|
|
52
|
+
# IDE settings
|
|
53
|
+
.vscode/
|
|
54
|
+
.idea/
|
|
55
|
+
|
|
56
|
+
# Pixi
|
|
57
|
+
.pixi
|
|
58
|
+
.pixi.lock
|
|
59
|
+
|
|
60
|
+
# Zensical build output
|
|
61
|
+
**/site/
|
|
62
|
+
# Pages generated from the notebooks in docs/examples/ by `pixi r docs`
|
|
63
|
+
/docs/examples/*.md
|
|
64
|
+
!/docs/examples/index.md
|
|
65
|
+
/docs/examples/*_files/
|
|
66
|
+
# Generated from the GitHub milestones by `pixi r docs`
|
|
67
|
+
/docs/roadmap.md
|
|
68
|
+
|
|
69
|
+
# Misc
|
|
70
|
+
.DS_Store
|
|
71
|
+
junit.xml
|
|
72
|
+
|
|
73
|
+
# AI agents. AGENTS.md and .agents/skills/ are the shared files; .claude/skills links to
|
|
74
|
+
# the latter. The negations override a global ignore of these directories.
|
|
75
|
+
!/.agents/
|
|
76
|
+
/.agents/*
|
|
77
|
+
!/.agents/skills
|
|
78
|
+
!/.claude/
|
|
79
|
+
/.claude/*
|
|
80
|
+
!/.claude/skills
|
|
81
|
+
# Claude Code skips AGENTS.md when a CLAUDE.md exists, so keep personal ones out.
|
|
82
|
+
CLAUDE.md
|
|
83
|
+
CLAUDE.local.md
|