|
| 1 | +# Project Guidelines — Planetary Computer Tasks (pctasks) |
| 2 | + |
| 3 | +## Architecture |
| 4 | + |
| 5 | +Monorepo of 12 Python namespace packages under `pctasks/`, each independently installable via `hatchling`. Dependency order: `core → cli → task → client → ingest → ingest_task → dataset → run → notify → router → server → dev`. Additional code in `pctasks_funcs/` (Azure Functions), `datasets/` (~60 dataset definitions), and `deployment/` (Terraform/Helm). |
| 6 | + |
| 7 | +**Core data flow**: blob storage assets → splits (by prefix) → chunks (file listing CSVs) → `Collection.create_item()` produces pystac Items → ingest into PgSTAC via pypgstac. |
| 8 | + |
| 9 | +Key abstractions: |
| 10 | +- **`PCBaseModel`** (`pctasks/core/pctasks/core/models/base.py`): Pydantic v2 base with YAML serde, `by_alias=True`, `exclude_none=True`. |
| 11 | +- **`Task[T, U]`** (`pctasks/task/pctasks/task/task.py`): Generic abstract task, define `_input_model`/`_output_model` and `run(input, context)`. |
| 12 | +- **`Collection`** (`pctasks/dataset/pctasks/dataset/collection.py`): Abstract base for datasets; implement `create_item(cls, asset_uri, storage_factory) -> List[pystac.Item] | WaitTaskResult` as a classmethod. |
| 13 | +- **`StorageFactory`**: Creates `Storage` objects from `blob://<account>/<container>/<path>` URIs. |
| 14 | +- **Settings**: `pydantic-settings` with double-underscore env vars (`PCTASKS__COSMOSDB__URL`, `PCTASKS_RUN__TASK_RUNNER_TYPE`). |
| 15 | + |
| 16 | +## Code Style |
| 17 | + |
| 18 | +- **Formatter**: black (default settings) + isort. Run `scripts/format`. |
| 19 | +- **Linter**: flake8 with `max-line-length = 120`, ignores `E203, W503, E731, E722` (see `.flake8`). |
| 20 | +- **Type checking**: mypy with `disallow_untyped_defs = True` — all functions must have type annotations (see `mypy.ini`). |
| 21 | +- **No docstrings** unless explicitly requested. |
| 22 | +- All models extend `PCBaseModel` (Pydantic v2). Use `model_validate`, `model_dump`, `field_validator`, `model_validator`. |
| 23 | + |
| 24 | +## Build and Test |
| 25 | + |
| 26 | +```bash |
| 27 | +scripts/install # Create venv with uv, install all packages in editable mode |
| 28 | +scripts/server # Start local dev stack (Azurite, PgSTAC, server, STAC API) |
| 29 | +scripts/test # Full lint + test suite (runs in Docker via docker-compose.console.yml) |
| 30 | +scripts/test --subpackage core # Test one package |
| 31 | +scripts/test --test-only # Skip lint |
| 32 | +scripts/test --lint-only # Skip tests |
| 33 | +scripts/format # Auto-format all packages (black + isort) |
| 34 | +``` |
| 35 | + |
| 36 | +Per-package test commands (from within `pctasks/<pkg>/`): |
| 37 | +```bash |
| 38 | +pytest tests/ # Run package tests |
| 39 | +mypy --config-file ../../mypy.ini pctasks # Type-check |
| 40 | +``` |
| 41 | + |
| 42 | +## Project Conventions |
| 43 | + |
| 44 | +### Dataset directory pattern (`datasets/<name>/`) |
| 45 | +``` |
| 46 | +dataset.yaml # Required: dataset definition (id, image, collections, asset_storage, chunks) |
| 47 | +<name>.py # Required: Collection subclass with create_item classmethod |
| 48 | +collection/template.json # STAC collection Jinja2 template |
| 49 | +test_<name>.py # Tests: import collection class, call create_item with blob URIs |
| 50 | +requirements.txt # Optional: extra pip deps |
| 51 | +Dockerfile # Optional: custom image (otherwise uses pctasks-task-base) |
| 52 | +``` |
| 53 | + |
| 54 | +Dataset YAML references code via `${{ local.path(./<file>.py) }}` and class via `<module>:<ClassName>` (no `.py`). |
| 55 | + |
| 56 | +### Templating syntax in YAML |
| 57 | +- `${{ args.<name> }}` — CLI arguments |
| 58 | +- `${{ secrets.<key> }}` — KeyVault/dev-secrets.yaml |
| 59 | +- `${{ local.path(<relative>) }}` — Path relative to YAML file |
| 60 | +- `${{ local.file(<relative>) }}` — Inline file contents |
| 61 | + |
| 62 | +### CLI |
| 63 | +Click-based with plugin discovery via `pctasks.commands` entry point group. Each package registers subcommands in its `pyproject.toml`. |
| 64 | + |
| 65 | +### Testing patterns |
| 66 | +- pytest with `asyncio_mode = auto` (see `pytest.ini`) |
| 67 | +- Dataset tests are co-located: `datasets/<name>/test_<name>.py` |
| 68 | +- Package tests: `pctasks/<pkg>/tests/` |
| 69 | +- Integration tests: `tests/` |
| 70 | +- Use `StorageFactory()` in tests for blob access; `SimpleWorkflowExecutor` for local workflow execution. |
| 71 | + |
| 72 | +## Integration Points |
| 73 | + |
| 74 | +- **Azure Blob Storage**: All asset URIs use `blob://<account>/<container>/<path>` scheme. |
| 75 | +- **Cosmos DB**: Workflow/run state persistence; emulated locally via docker-compose. |
| 76 | +- **PgSTAC**: STAC item storage (PostgreSQL + PostGIS), port 5499 locally. |
| 77 | +- **Azurite**: Local Azure Storage emulator, ports 10000-10002. |
| 78 | +- **Argo Workflows**: Production workflow orchestration on Kubernetes. |
| 79 | +- **Azure Batch**: Production task execution. |
| 80 | +- **Kind cluster**: Local Kubernetes for Argo testing (`scripts/cluster setup`). |
0 commit comments