diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 0000000..3dac982 --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,32 @@ +{ + "env": { + "AWS_PROFILE": "mavedb-agent-readonly" + }, + "permissions": { + "deny": ["Bash(* --no-verify*)", "Read(~/.aws/**)", "Read(~/.pgpass)", "Read(~/.ssh/**)"], + "ask": [ + "Edit(**/.claude/settings*.json)", + "Bash(git push *--force*)", + "Bash(git push * -f*)", + "Bash(git push * main*)", + "Bash(git push * mavedb-main*)", + "Bash(git push * mavedb-dev*)", + "Bash(git push * release-*)", + "Bash(git -C * push *--force*)", + "Bash(git -C * push * -f*)", + "Bash(git -C * push * main*)", + "Bash(git -C * push * mavedb-main*)", + "Bash(git -C * push * mavedb-dev*)", + "Bash(git -C * push * release-*)", + "Bash(aws *--profile*)", + "Bash(*AWS_PROFILE=*)", + "Bash(eb *)", + "Bash(*MODE=prodapi*)", + "Bash(poetry add *)", + "Bash(poetry -C * add *)", + "Bash(npm install *)", + "Bash(npm --prefix * install *)", + "Bash(*pip install *)" + ] + } +} diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index bacb99e..23d7600 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -27,7 +27,7 @@ jobs: # only run tests known to work in CI run: | mkdir -p coverage - python3 -m pytest tests/test_mavedb_data.py --cov-report=lcov:coverage/lcov.info + bin/t tests/test_mavedb_data.py --cov-report=lcov:coverage/lcov.info - name: Upload coverage to Coveralls uses: coverallsapp/github-action@v2 @@ -46,10 +46,5 @@ jobs: - name: Install dependencies run: python3 -m pip install ".[dev]" - - name: Check style - run: python3 -m ruff check . && ruff format --check . - - - name: Verify schema.json is up to date - run: | - python scripts/generate_schema.py - git diff --exit-code schema.json + - name: Lint, format and schema.json checks + run: bin/check diff --git a/.gitignore b/.gitignore index 439b17c..1aec9a5 100644 --- a/.gitignore +++ b/.gitignore @@ -173,5 +173,6 @@ urn:*.json tmp:*.json *_mapping_*.json -# Agent settings -.claude/ +# Agent settings: personal files stay local; the shared permission rules are committed +.claude/* +!.claude/settings.json diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..4df7852 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,30 @@ +# AGENTS.md — dcd_mapping + +Facts about this repo that you can't work out from the code. Keep this file short. Rules shared with the other MaveDB repos are in the workspace `AGENTS.md` one folder up. Update both in the same change that makes any of it untrue. + +The mapper turns a MaveDB score set's variants into GA4GH VRS objects. MaveDB's worker calls it over HTTP (`POST /api/v1/map/{urn}`, served from `src/api/`); the `dcd-map` CLI does the same job locally. This repo is MaveDB's fork of `ave-dcd/dcd_mapping`: work goes to `VariantEffect/dcd_mapping2`, branched from and merged into `mavedb-dev`, which is released to `mavedb-main`. + +## Setup + +- `python3 -m venv .venv && .venv/bin/pip install -e '.[dev,tests]'`, on Python 3.11. The `bin/` scripts use `.venv` when it exists. +- A real mapping run needs UTA, SeqRepo, the Gene Normalizer database and BLAT. The README's Prerequisites section covers each. + +## Commands + +| Task | Command | +|---|---| +| Lint, format and `schema.json` checks | `bin/check` | +| What CI tests | `bin/t tests/test_mavedb_data.py` | +| Other tests | `bin/t tests/test_variant_projection.py` | +| Regenerate `schema.json` | `.venv/bin/python scripts/generate_schema.py` | + +- Run `bin/check` after every edit, and the tests for what you touched before handing work back. +- Only `tests/test_mavedb_data.py` runs in CI. The align and `vrs_map` tests need BLAT, and others need SeqRepo or UTA, so some fail on a machine without them. Check a failure against `mavedb-dev` before blaming your change, and report it rather than skipping or loosening the test. + +## Rules + +- Open pull requests with `gh pr create -R VariantEffect/dcd_mapping2 --base mavedb-dev`. Without `-R`, `gh` may target the upstream `ave-dcd` repo. +- `schema.json` is the output contract the MaveDB api consumes. A change to `schemas.py` that alters it ships with the regenerated file in the same commit; `bin/check` fails otherwise. +- `ga4gh.vrs` is pinned to 2.0.0a6 and `cool-seq-tool` to 0.4.0.dev3, because upgrading either means moving the whole GA4GH stack (gene-normalizer, seqrepo, cdot) at once. Don't bump any of them as part of other work. +- Never store a RefSeq sequence in SeqRepo from another source, such as cdot's genome-assembled transcript. It changes the refget, and with it every allele digest MaveDB has published. +- Docstrings use the reST `:param:` style the code already has, not Google style. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..43c994c --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/README.md b/README.md index 84c81f0..69adf0b 100644 --- a/README.md +++ b/README.md @@ -165,8 +165,11 @@ Add pre-commit hooks pre-commit install ``` -Run tests with `pytest` +Run the lint, format and `schema.json` checks with `bin/check`, and tests with `bin/t`, which wraps `pytest`: ``` -pytest +bin/check +bin/t tests/test_mavedb_data.py ``` + +Only `tests/test_mavedb_data.py` runs in CI; most other test modules need BLAT, SeqRepo or UTA. Conventions for contributors and coding agents are in [AGENTS.md](AGENTS.md). diff --git a/bin/check b/bin/check new file mode 100755 index 0000000..1f07999 --- /dev/null +++ b/bin/check @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +# Fast static checks: lint, format and the schema.json contract. Tests run through bin/t. +# Runs every check before exiting so one invocation reports all failures. +# Uses .venv when present (local development), otherwise the python3 on PATH (CI). +set -uo pipefail +cd "$(dirname "$0")/.." +PY="${PYTHON:-$([ -x .venv/bin/python ] && echo .venv/bin/python || echo python3)}" + +status=0 +"$PY" -m ruff check . || status=1 +"$PY" -m ruff format --check . || status=1 +"$PY" scripts/generate_schema.py --check || status=1 +exit $status diff --git a/bin/t b/bin/t new file mode 100755 index 0000000..0f83da8 --- /dev/null +++ b/bin/t @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +# Tests: bin/t [test path or node id] [pytest args]. Only tests/test_mavedb_data.py runs in CI; +# most other modules need BLAT, SeqRepo or UTA. MAVEDB_BASE_URL matches CI; requests are mocked. +set -euo pipefail +cd "$(dirname "$0")/.." +PY="${PYTHON:-$([ -x .venv/bin/python ] && echo .venv/bin/python || echo python3)}" + +export MAVEDB_BASE_URL="${MAVEDB_BASE_URL:-https://api.mavedb.org}" +exec "$PY" -m pytest "$@" diff --git a/scripts/generate_schema.py b/scripts/generate_schema.py index 8e9b8b0..ae75725 100644 --- a/scripts/generate_schema.py +++ b/scripts/generate_schema.py @@ -7,13 +7,15 @@ python scripts/generate_schema.py The script writes the JSON Schema for :class:`~dcd_mapping.schemas.ScoresetMapping` -to ``schema.json`` at the repository root, overwriting the previous file. +to ``schema.json`` at the repository root, overwriting the previous file. With +``--check`` it writes nothing and exits 1 if ``schema.json`` is out of date. If you change schemas.py, re-run this script and commit the result. """ import json import pathlib +import sys from dcd_mapping.schemas import ScoresetMapping @@ -22,9 +24,17 @@ def main() -> None: - """Generate JSON Schema for ScoresetMapping and write to file.""" - schema = ScoresetMapping.model_json_schema() - SCHEMA_PATH.write_text(json.dumps(schema, indent=2, sort_keys=True) + "\n") + """Generate JSON Schema for ScoresetMapping and write it, or check it with --check.""" + schema = ( + json.dumps(ScoresetMapping.model_json_schema(), indent=2, sort_keys=True) + "\n" + ) + if "--check" in sys.argv[1:]: + if SCHEMA_PATH.read_text() != schema: + msg = f"{SCHEMA_PATH} is out of date; run python scripts/generate_schema.py" + print(msg) # noqa: T201 + sys.exit(1) + return + SCHEMA_PATH.write_text(schema) print(f"Written: {SCHEMA_PATH}") # noqa: T201