From ce46869a65f7dd7275688e49509b19944129bf52 Mon Sep 17 00:00:00 2001 From: Constantinos Eleftheriou Date: Tue, 11 Aug 2026 15:04:55 +0100 Subject: [PATCH] Prepare v0.1.0 release Add CHANGELOG.md documenting the initial feature set, and point the README at PyPI now that the package is published there. Fix two faults that would have broken the release: - The report templates match the blanket *.html rule in .gitignore, which hatchling honours when selecting files, so base.html and session.html were silently dropped from both the sdist and the wheel. Since the Jinja2 PackageLoader is constructed at import time, the installed package failed on `import visiomode_analysis` and every CLI command was unusable. Negate the ignore rule and declare the templates as build artifacts. - The release-github job downloaded an artifact named "dist" while the build job uploads "release-dists", so creating the GitHub release would have failed. Also add a twine check and a clean-venv smoke test of the built wheel to the publish workflow. The test suite runs against the source tree, so it cannot catch packaging faults of this kind on its own. Co-Authored-By: Claude Opus 5 --- .github/workflows/python-publish.yml | 31 ++++++++++++----- .gitignore | 6 +++- CHANGELOG.md | 52 ++++++++++++++++++++++++++++ README.md | 8 ++++- pyproject.toml | 6 +++- 5 files changed, 92 insertions(+), 11 deletions(-) create mode 100644 CHANGELOG.md diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 392ed45..d9af372 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -30,10 +30,30 @@ jobs: - name: Build release distributions run: | - # NOTE: put your own distribution build steps here. python -m pip install build python -m build + - name: Check distributions + run: | + python -m pip install twine + python -m twine check dist/* + + # Install the built wheel in a clean venv and exercise it end to end. This + # catches packaging faults that the test suite cannot see, because the + # tests run against the source tree rather than the built distribution + # (e.g. package data missing from the wheel). + - name: Smoke test built wheel + run: | + python -m venv /tmp/smoke + /tmp/smoke/bin/pip install dist/*.whl + /tmp/smoke/bin/visiomode-analysis --version + mkdir -p /tmp/smoke-out + /tmp/smoke/bin/visiomode-analysis session \ + exploratory/test_data/example-gonogo-leverpush.json \ + -o /tmp/smoke-out + test -n "$(find /tmp/smoke-out -name '*report-session.html' -print -quit)" + test -n "$(find /tmp/smoke-out -name '*trials.csv' -print -quit)" + - name: Upload distributions uses: actions/upload-artifact@v4 with: @@ -51,7 +71,7 @@ jobs: - name: Download build artifacts uses: actions/download-artifact@v4 with: - name: dist + name: release-dists path: dist/ - name: Create release @@ -78,12 +98,7 @@ jobs: # For more information, see: https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#deployment-protection-rules environment: name: pypi - # OPTIONAL: uncomment and update to include your PyPI project URL in the deployment status: - # url: https://pypi.org/p/YOURPROJECT - # - # ALTERNATIVE: if your GitHub Release name is the PyPI project version string - # ALTERNATIVE: exactly, uncomment the following line instead: - # url: https://pypi.org/project/YOURPROJECT/${{ github.event.release.name }} + url: https://pypi.org/p/visiomode-analysis steps: - name: Retrieve release distributions diff --git a/.gitignore b/.gitignore index ceb4223..5374379 100644 --- a/.gitignore +++ b/.gitignore @@ -163,10 +163,14 @@ cython_debug/ # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ -# Ignore outputs +# Ignore outputs *.csv *.html +# ...but the report templates are package data, not outputs. Without this the +# build backend honours the *.html rule above and silently ships a broken wheel. +!src/visiomode_analysis/reports/templates/*.html + scratch/ scratch diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..c7e64fd --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,52 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [0.1.0] - 2026-08-11 + +First public release. + +### Added + +- **Session processing** (`visiomode_analysis.session`) — reads a raw Visiomode + session JSON and flattens its nested trial list into a per-trial + `pandas.DataFrame`, reconciling several historical Visiomode JSON schema + versions along the way. +- **Session metadata** — `get_metadata()` derives animal ID, experiment, date, + protocol and stimulus spec, preferring BIDS-like tokens encoded in the + filename (`sub-_exp-_ses-_behaviour-.json`) over + the JSON body. +- **Session summaries** — `summary()` aggregates trials into signal-detection-theory + metrics (hit and false alarm rates, d', criterion), trial counts and reaction + time statistics, with `_wc` ("with corrections") variants computed alongside + the corrections-excluded defaults. +- **Signal detection theory metrics** (`session.metrics`) — `d_prime`, + `criterion` and `perseveration`, including a 2AFC correction for d'. +- **HTML session reports** — `generate_report()` renders a standalone, + self-contained report from a Jinja2 template with embedded Plotly figures. +- **Plotly figure builders** (`session.plots`) — reusable figures for session + reports, each able to return an embeddable HTML `
` via `as_html=True`. +- **GLM regressors** (`session.regressor`) — `generate_regressors()` builds + stimulus, response and reward event regressors aligned to an external + timestamp series such as imaging frame times or an electrophysiology + acquisition clock. Go/No-Go is implemented; other protocols raise + `NotImplementedError`. +- **Subject-level collation** (`visiomode_analysis.subject`) — + `collate_sessions()` globs the `*trials.csv` files produced by the `session` + command for one subject, aggregates them into a single per-subject summary CSV + and assigns per-protocol `task_session` ranks. +- **Command line interface** — a `visiomode-analysis` entry point with `session`, + `regressors`, `subject` and `group` subcommands. Output files follow the same + BIDS-like naming convention as the inputs so downstream steps can find them + automatically. +- **Group-level analysis** — `group` subcommand scaffolded; not yet implemented. +- Test suite covering trial flattening, metrics, plots, regressors, session + summaries, subject collation and the CLI, run against Python 3.11–3.13 in CI. + +[Unreleased]: https://github.com/DuguidLab/visiomode_analysis/compare/v0.1.0...HEAD +[0.1.0]: https://github.com/DuguidLab/visiomode_analysis/releases/tag/v0.1.0 diff --git a/README.md b/README.md index 01ce2f2..51ef351 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,12 @@ Analysis library and CLI for behavioural session data recorded with [Visiomode]( Requires Python 3.11+. +```bash +pip install visiomode-analysis +``` + +Or, to install the latest unreleased code from `main`: + ```bash pip install git+https://github.com/DuguidLab/visiomode_analysis.git ``` @@ -115,7 +121,7 @@ hatch test --cover hatch run types:check ``` -See [CONTRIBUTING.md](CONTRIBUTING.md). +See [CONTRIBUTING.md](CONTRIBUTING.md) for the issue workflow, and [CHANGELOG.md](CHANGELOG.md) for release notes. ## License diff --git a/pyproject.toml b/pyproject.toml index 7b7e3a2..8484f82 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -46,9 +46,13 @@ path = ".venv" # Use uv environment path [tool.hatch.build.targets.wheel] packages = ["src/visiomode_analysis"] +# The report templates match the *.html rule in .gitignore, which the build +# backend honours. Listing them as artifacts forces them into the wheel. +artifacts = ["src/visiomode_analysis/reports/templates/*.html"] [tool.hatch.build.targets.sdist] -exclude = ["/.github", "/docs"] +exclude = ["/.github", "/.claude", "/docs"] +artifacts = ["src/visiomode_analysis/reports/templates/*.html"] [tool.hatch.version] path = "src/visiomode_analysis/__about__.py"