Skip to content

Commit f628aa6

Browse files
committed
chore(serena): update memories
[skip ci]
1 parent 426ee22 commit f628aa6

7 files changed

Lines changed: 431 additions & 320 deletions

.serena/memories/code_style_conventions.md

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ import ckanext.datapusher_plus.cli as cli
3232

3333
## Logging
3434
- Standard `logging` module with custom **TRACE level (5)** defined in `logging_utils.py`.
35-
- Pipeline stages use `ProcessingContext.logger` rather than module-level loggers — keeps per-job context.
35+
- Pipeline stages use `ProcessingContext.logger` rather than module-level
36+
loggers — keeps per-job context.
3637
- Prefer f-string log messages.
3738

3839
## Error handling
@@ -41,13 +42,29 @@ import ckanext.datapusher_plus.cli as cli
4142
- Raise specific exceptions from those classes instead of generic `Exception`.
4243

4344
## Linting
44-
- Flake8, with **E501 disabled** project-wide (the `# flake8: noqa: E501` comment is conventional at the top of many files). Long lines are accepted.
45+
- Flake8, with **E501 disabled** project-wide (the `# flake8: noqa: E501`
46+
comment is conventional at the top of many files). Long lines are accepted.
47+
48+
## Config keys
49+
- All `ckanext.datapusher_plus.*` settings use **lowercase** key strings.
50+
Two recent regressions stemmed from drift: PR #324 fixed
51+
`ckanext.datastore_plus.pii_screening` (typo'd namespace), and PR #326
52+
fixed `ckanext.datapusher_plus.SPATIAL_SIMPLIFICATION_RELATIVE_TOLERANCE`
53+
(uppercase). Add AST drift-guard tests for new settings.
4554

4655
## Architectural patterns
47-
- **Pipeline stage pattern** (v2.0): each stage subclasses `BaseStage` and mutates `ProcessingContext`. Add new behaviour as a new stage, not by extending an existing one. Keep stages single-responsibility.
48-
- Prefer editing the modular `jobs/` package — `jobs_legacy.py` is kept only for reference.
49-
- CKAN plugin interfaces are wired in `plugin.py`; new actions go through `logic/action.py` + `logic/schema.py` + `logic/auth.py`.
56+
- **Pipeline stage pattern**: each stage subclasses `BaseStage` and mutates
57+
`ProcessingContext`. Add new behaviour as a new stage, not by extending
58+
an existing one. Keep stages single-responsibility.
59+
- **Prefect @task wrappers** in `jobs/prefect_flow.py` are thin —
60+
they delegate to `BaseStage.process()` bodies. Don't embed business
61+
logic in the task functions.
62+
- The v2-era `jobs_legacy.py` is gone — there is nothing to "edit the
63+
modular jobs/ package instead of". All work happens under `jobs/`.
64+
- CKAN plugin interfaces are wired in `plugin.py`; new actions go through
65+
`logic/action.py` + `logic/schema.py` + `logic/auth.py`.
5066

5167
## Comments
52-
- Keep comments focused on **why**, not what (per default Claude guidance + project style).
68+
- Keep comments focused on **why**, not what (per default Claude
69+
guidance + project style).
5370
- Do not create new `*.md`/README files unless explicitly asked.

.serena/memories/codebase_structure.md

Lines changed: 124 additions & 73 deletions
Large diffs are not rendered by default.

.serena/memories/dpp_test_container.md

Lines changed: 95 additions & 173 deletions
Large diffs are not rendered by default.
Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,45 @@
11
# DataPusher+ (datapusher-plus)
22

33
## Purpose
4-
DataPusher+ is a **CKAN extension (v2.0.0)** for ultra-fast, robust data ingestion into CKAN's datastore. It replaces the legacy Datapusher webservice and combines the speed/robustness of `ckanext-xloader` with the data-type guessing of Datapusher — supercharged with metadata inference/suggestion via Jinja2 formulas defined in scheming YAML.
4+
DataPusher+ is a **CKAN extension (v3.0.0a0)** for ultra-fast, robust data
5+
ingestion into CKAN's datastore. It replaces the legacy Datapusher webservice
6+
and combines the speed/robustness of `ckanext-xloader` with the data-type
7+
guessing of Datapusher — supercharged with metadata inference/suggestion via
8+
Jinja2 formulas defined in scheming YAML.
59

610
Key differentiators:
7-
- **Guaranteed type inference** — scans the entire file (not first N rows) via [qsv](https://github.com/dathere/qsv), a Rust CSV toolkit.
11+
- **Guaranteed type inference** — scans the entire file (not first N rows) via
12+
[qsv](https://github.com/dathere/qsv), a Rust CSV toolkit.
813
- **PostgreSQL COPY** for direct datastore loading (no API overhead).
9-
- **Jinja2 formula system** for metadata inference/suggestion (`formula` and `suggest_formula` in scheming YAML).
14+
- **Jinja2 formula system** for metadata inference/suggestion (`formula` and
15+
`suggestion_formula` in scheming YAML — NOTE the production key is
16+
`suggestion_formula`, not `suggest_formula`).
1017
- **DRUF** (Dataset Resource Upload First) workflow support.
11-
- Three formula namespaces available: `dpps` (per-field stats), `dppf` (per-field freq tables), `dpp` (inferred metadata: RECORD_COUNT, DATE_FIELDS, LAT_FIELD, LON_FIELD, etc.).
12-
- No longer a separate webservice — it is now a full CKAN extension (`ckan.plugins` entry point: `datapusher_plus = ckanext.datapusher_plus.plugin:DatapusherPlusPlugin`).
18+
- **v3.0**: [Prefect](https://www.prefect.io/) 3.7+-orchestrated ingestion
19+
flow — replaces the v2 in-process `DataProcessingPipeline` loop and the
20+
earlier RQ-based job runner. The one-shot `migrate-from-rq` CLI handles
21+
the upgrade.
22+
- Three formula namespaces available: `dpps` (per-field stats), `dppf`
23+
(per-field freq tables), `dpp` (inferred metadata: RECORD_COUNT,
24+
DATE_FIELDS, LAT_FIELD, LON_FIELD, etc.).
25+
- No longer a separate webservice — it is a full CKAN extension
26+
(`ckan.plugins` entry point: `datapusher_plus =
27+
ckanext.datapusher_plus.plugin:DatapusherPlusPlugin`).
1328

1429
## Repository
1530
- GitHub: https://github.com/dathere/datapusher-plus
1631
- License: AGPL-3.0-or-later
1732
- Maintainer: datHere Engineering <info@dathere.com>
18-
- Current branch defaults: `main`
19-
- This project lives at `/Users/joelnatividad/GitHub/datapusher-plus` on the host (Darwin/macOS).
33+
- Default branch: `main`
34+
- This project lives at `/Users/joelnatividad/GitHub/datapusher-plus` on the
35+
host (Darwin/macOS).
2036

2137
## External runtime dependencies
22-
- **Python 3.10, 3.11, 3.12, 3.13** (`requires-python = ">=3.10"`)
23-
- **qsv v4.0.0+** (path configured via `ckanext.datapusher_plus.qsv_bin`)
24-
- **CKAN 2.10+** with `ckanext-scheming`
25-
- **PostgreSQL** datastore
26-
- **RQ (Redis Queue)** for background job processing
38+
- **Python 3.10, 3.11, 3.12, 3.13** (`requires-python = ">=3.10"`); the
39+
unit-test CI only exercises 3.10 (the only Python in the
40+
`ckan/ckan-dev:2.11` image).
41+
- **qsv v20.1.0+** (path configured via `ckanext.datapusher_plus.qsv_bin`;
42+
`MINIMUM_QSV_VERSION` is enforced at startup).
43+
- **CKAN 2.10+** with `ckanext-scheming`.
44+
- **PostgreSQL** datastore.
45+
- **Prefect 3.7+** for orchestrating the v3.0 ingestion flow.
Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,53 @@
11
# Serena Usage Notes for this Project
22

33
## Activation
4-
Project is named **datapusher-plus** at `/Users/joelnatividad/GitHub/datapusher-plus`. Language: Python only. File encoding: utf-8.
4+
Project is named **datapusher-plus** at `/Users/joelnatividad/GitHub/datapusher-plus`.
5+
Language: Python only. File encoding: utf-8.
56

67
## Preferred entry points for navigation
78
- **Plugin entry**: `ckanext/datapusher_plus/plugin.py``DatapusherPlusPlugin`
8-
- **Pipeline entry**: `ckanext/datapusher_plus/jobs/pipeline.py``datapusher_plus_to_datastore`
9+
- **Flow entry (v3.0)**: `ckanext/datapusher_plus/jobs/prefect_flow.py`
10+
`datapusher_plus_flow` (the @flow) and the per-stage @task functions.
11+
Use this — `jobs/pipeline.py` from the v2 era no longer exists.
912
- **Shared state**: `ckanext/datapusher_plus/jobs/context.py``ProcessingContext`
13+
- **Runtime/flow input**: `ckanext/datapusher_plus/jobs/runtime_context.py`
14+
`JobInput` (frozen, JSON-serializable), the per-stage `*Result` dataclasses,
15+
the `RuntimeContext` ContextVar.
1016
- **Stage base**: `ckanext/datapusher_plus/jobs/stages/base.py``BaseStage`
11-
- **Actions API surface**: `ckanext/datapusher_plus/logic/action.py` (e.g. `datapusher_submit`, `datapusher_hook`, `datapusher_status`)
12-
- **Data models**: `ckanext/datapusher_plus/model/model.py` (`Jobs`, `Metadata`, `Logs`)
17+
- **Actions API surface**: `ckanext/datapusher_plus/logic/action.py`
18+
(`datapusher_submit`, `datapusher_hook`, `datapusher_status`)
19+
- **Data models**: `ckanext/datapusher_plus/model/model.py` (`Jobs`,
20+
`Metadata`, `Logs`)
21+
- **Prefect plumbing**: `prefect_client.py` is the single place CKAN admin
22+
paths touch `prefect.*`; `jobs/__init__.py` uses PEP 562 lazy
23+
`__getattr__` to defer the Prefect import so CKAN CLI commands don't
24+
spin up a Prefect server.
1325

1426
## Workflow recipes
15-
- Understanding a CKAN action handler: `find_symbol` with name_path `datapusher_submit` (or other action) in `logic/action.py`, `include_body=True`.
27+
- Understanding a CKAN action handler: `find_symbol` with name_path
28+
`datapusher_submit` (or other action) in `logic/action.py`,
29+
`include_body=True`.
1630
- Adding a pipeline stage:
1731
1. `get_symbols_overview` on `jobs/stages/base.py`.
1832
2. `find_symbol` on `BaseStage`, `include_body=True`.
19-
3. Create new module under `jobs/stages/` using `replace_symbol_body` on a placeholder, or write a new file with the editor.
20-
4. Hook the new stage into the pipeline by editing `jobs/pipeline.py` with `replace_symbol_body` on the orchestration function.
21-
- Renaming or moving a function: prefer `rename` / `move` Serena tools so all references update. Use `find_referencing_symbols` first to scope blast radius.
22-
- Inspecting how a CKAN interface is wired: `find_symbol` on `DatapusherPlusPlugin` with `depth=1`, then drill into the method that implements the interface hook (`update_config`, `get_actions`, etc.).
33+
3. Create new module under `jobs/stages/` and add the matching
34+
`@task` wrapper in `jobs/prefect_flow.py`.
35+
4. Hook the new task into the flow by editing `datapusher_plus_flow`
36+
in `jobs/prefect_flow.py` (use `replace_symbol_body`).
37+
- Renaming or moving a function: prefer `rename` / `move` Serena tools so
38+
all references update. Use `find_referencing_symbols` first to scope
39+
blast radius.
40+
- Inspecting how a CKAN interface is wired: `find_symbol` on
41+
`DatapusherPlusPlugin` with `depth=1`, then drill into the method that
42+
implements the interface hook (`update_config`, `get_actions`, etc.).
2343

2444
## Known oddities
25-
- `plugin.py` defines `DatastoreException` twice (lines around the top) — likely vestigial; leave alone unless asked to clean up.
26-
- `jobs.py` and `jobs_legacy.py` both exist at the package root in addition to the modular `jobs/` package. The legacy module is kept for reference; do not edit it.
27-
- `# flake8: noqa: E501` is conventional at the top of many modules; preserve when editing.
45+
- `plugin.py` defines `DatastoreException` twice (lines around the top) —
46+
likely vestigial; leave alone unless asked to clean up.
47+
- The v2-era `jobs.py`, `jobs_legacy.py`, and `jobs/pipeline.py` files
48+
have all been removed; if you see references to them in old docs or
49+
memories, they are stale.
50+
- `jobs/__init__.py` re-exports `datapusher_plus_to_datastore` as an
51+
alias for `datapusher_plus_flow` — preserves the v2 import path.
52+
- `# flake8: noqa: E501` is conventional at the top of many modules;
53+
preserve when editing.

.serena/memories/suggested_commands.md

Lines changed: 65 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,39 @@
33
> Host OS: **Darwin (macOS)**. Project root: `/Users/joelnatividad/GitHub/datapusher-plus`.
44
55
## Testing
6+
67
```bash
7-
# Run the full test suite
8-
pytest tests/
8+
# Run the full unit suite (integration tests need the docker-compose stack)
9+
pytest tests/ --ignore=tests/integration
910

1011
# Run one file
11-
pytest tests/test_unit.py
12+
pytest tests/test_qsv_v20_regression.py
1213

13-
# Run with coverage of the extension package
14-
pytest --cov=ckanext/datapusher_plus tests/
14+
# Coverage of the extension package — note `-p pytest_cov`: the unit
15+
# suite needs PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 to avoid CKAN's pytest
16+
# plugin calling make_app() in pytest_sessionstart, which means `--cov`
17+
# is an unrecognized argument unless pytest-cov is loaded explicitly.
18+
PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 QSV_BIN=/path/to/qsvdp \
19+
CKAN_INI=/srv/app/src/ckan/test-core.ini \
20+
pytest -p pytest_cov --cov=ckanext/datapusher_plus tests/ \
21+
--ignore=tests/integration
1522

16-
# Debug a failure with IPython's pdb (configured globally in setup.cfg)
23+
# Debug a failure with IPython's pdb (preset via pyproject.toml addopt)
1724
pytest --pdbcls=IPython.terminal.debugger:TerminalPdb tests/
25+
26+
# Integration tests (require scripts/integration-up beforehand)
27+
INTEGRATION=1 CKAN_URL=http://localhost:5050 pytest tests/integration/ -v
28+
29+
# JavaScript suite (Vitest + jsdom, host-side)
30+
npm install # first time only
31+
npm test # one-shot (alias for npx vitest run)
32+
npm run test:watch # watch mode
1833
```
19-
Pytest defaults (from `setup.cfg`): SQLAlchemy and `DeprecationWarning` warnings are filtered; `--pdbcls=IPython.terminal.debugger:TerminalPdb` is preset.
34+
35+
> **Pytest config lives in `pyproject.toml`** under
36+
> `[tool.pytest.ini_options]` (warning filters + the IPython `--pdbcls`
37+
> addopt). It moved from `setup.cfg` during the v3.0 refactor — comments
38+
> referencing `setup.cfg` for pytest config are stale.
2039
2140
## Installing dependencies
2241
```bash
@@ -28,55 +47,74 @@ pip install -e ".[dev]" # editable + dev extras
2847

2948
## CKAN CLI (run inside the CKAN environment)
3049
```bash
31-
# Resubmit all resources to datapusher
50+
# Resubmit all updated datastore resources
3251
ckan -c /etc/ckan/default/ckan.ini datapusher_plus resubmit -y
3352

3453
# Submit one dataset's resources
3554
ckan -c /etc/ckan/default/ckan.ini datapusher_plus submit {dataset_id}
3655

56+
# Register / update the DP+ flow as a Prefect deployment (idempotent)
57+
ckan -c /etc/ckan/default/ckan.ini datapusher_plus prefect-deploy
58+
59+
# One-shot v2 (RQ) → v3 (Prefect) migration
60+
ckan -c /etc/ckan/default/ckan.ini datapusher_plus migrate-from-rq
61+
3762
# Apply Alembic migrations for this extension
3863
ckan -c /etc/ckan/default/ckan.ini db upgrade -p datapusher_plus
3964
```
4065

4166
## Linting / formatting
42-
No formatter is enforced; flake8 is the implicit linter with `E501` disabled. There is **no** project-level `make lint`, `ruff`, or `black` config — match existing style.
67+
No formatter is enforced; flake8 is the implicit linter with `E501`
68+
disabled. There is **no** project-level `make lint`, `ruff`, or `black`
69+
config — match existing style.
4370

4471
## CI
45-
- Integration workflow: `.github/workflows/main.yml` (manual dispatch; spins up CKAN 2.11 + Solr + Postgres + Redis containers).
46-
- Unit-test workflow: `.github/workflows/test.yml` (note: this file targets older Python versions — read carefully before relying on it).
47-
- CodeQL: `.github/workflows/codeql-analysis.yml`.
48-
- Publish: `.github/workflows/python-publish.yml`.
72+
73+
- `.github/workflows/test.yml`**Unit Tests** (PR #326). Runs the full
74+
unit suite (`pytest tests/ --ignore=tests/integration`) inside
75+
`ckan/ckan-dev:2.11` on push to `main`/`dev` and PR to `main`. Python
76+
3.10 only (the only Python the dev image ships). Mirrors the
77+
`dpp-test` container setup: geo libs, qsv 20.1.0, `PYTEST_DISABLE_PLUGIN_AUTOLOAD`
78+
/ `QSV_BIN` / `CKAN_INI` envs.
79+
- `.github/workflows/ci.yml`**DataPusher+ Integration CI**. Runs the
80+
qsv contract regression (`test_qsv_v20_regression.py`) + the
81+
integration suite on push to `main`/`dev` and PR to `main`. Does NOT
82+
run the full unit suite.
83+
- `.github/workflows/main.yml`**Automated DataPusher+ Testing Run**.
84+
`workflow_dispatch`-only manual end-to-end run.
85+
- `.github/workflows/codeql-analysis.yml` — CodeQL.
86+
- `.github/workflows/python-publish.yml` — package publish.
87+
88+
> The JS suite is **not** in CI; it's a host-side `npm test`.
4989
5090
## Common git operations
5191
```bash
5292
git status
5393
git diff
5494
git log --oneline -20
5595
git checkout -b feature/<name>
56-
gh pr create # GitHub CLI
96+
gh pr create
5797
gh pr view <n>
5898
gh pr checks <n>
5999
```
60100

61101
## macOS-specific system command notes
62102
The system is **Darwin**, so a few BSD-vs-GNU gotchas:
63-
- `sed -i` requires an empty string argument: `sed -i '' 's/foo/bar/' file` (not `sed -i 's/.../'`). Prefer the Edit tool anyway.
64-
- `find` accepts BSD flags; long-form `-iregex` etc. still work, but `-printf` does not — use `-exec` or `xargs`.
65-
- `date` flags differ from GNU coreutils (`date -v-1d` for "yesterday" instead of `date -d 'yesterday'`).
66-
- `readlink -f` is not BSD-native; use `greadlink -f` (from `coreutils`) or `python -c 'import os,sys; print(os.path.realpath(sys.argv[1]))'`.
103+
- `sed -i` requires an empty string argument: `sed -i '' 's/foo/bar/' file`
104+
(not `sed -i 's/.../'`). Prefer the Edit tool anyway.
105+
- `find` accepts BSD flags; long-form `-iregex` etc. still work, but
106+
`-printf` does not — use `-exec` or `xargs`.
107+
- `date` flags differ from GNU coreutils (`date -v-1d` for "yesterday"
108+
instead of `date -d 'yesterday'`).
109+
- `readlink -f` is not BSD-native; use `greadlink -f` (from `coreutils`)
110+
or `python -c 'import os,sys; print(os.path.realpath(sys.argv[1]))'`.
67111
- `ls` colors via `ls -G`, not `--color`.
68112
- Use `pbcopy` / `pbpaste` for clipboard.
69113
- Prefer `rg` (ripgrep) and `fd` if installed; otherwise `grep -R` / `find`.
70114

71-
## Quick exploration aliases (none configured; standard tools)
72-
```bash
73-
ls ckanext/datapusher_plus/
74-
ls ckanext/datapusher_plus/jobs/stages/
75-
rg "datapusher_plus_to_datastore" ckanext/ # if rg available
76-
grep -R "datapusher_plus_to_datastore" ckanext/
77-
```
78-
79115
## qsv (the runtime dependency)
80116
- Binary path configured by `ckanext.datapusher_plus.qsv_bin` in `ckan.ini`.
81-
- Must be **qsv v4.0.0+**. The CI uses `QSV_VER=7.1.0` (set in `main.yml`).
117+
- Must be **qsv v20.1.0+** (`MINIMUM_QSV_VERSION`).
82118
- Local invocation goes through `ckanext/datapusher_plus/qsv_utils.py`.
119+
- CI installs from the dathere/qsv release archive
120+
(`qsv-${QSV_VER}-x86_64-unknown-linux-musl.zip`) to `/usr/local/bin/qsvdp`.

0 commit comments

Comments
 (0)