Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 8 additions & 10 deletions .github/workflows/python-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,28 +24,26 @@ jobs:
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
- name: Install uv
uses: astral-sh/setup-uv@v6
with:
python-version: "3.x"
enable-cache: true
cache-dependency-glob: "uv.lock"

- name: Build release distributions
run: |
python -m pip install build
python -m build
run: make build

- name: Check distributions
run: |
python -m pip install twine
python -m twine check dist/*
run: uvx 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
uv venv /tmp/smoke
uv pip install --python /tmp/smoke/bin/python dist/*.whl
/tmp/smoke/bin/visiomode-analysis --version
mkdir -p /tmp/smoke-out
/tmp/smoke/bin/visiomode-analysis session \
Expand Down
23 changes: 10 additions & 13 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,18 @@ jobs:
- name: Check out repository
uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
- name: Install uv
uses: astral-sh/setup-uv@v6
with:
enable-cache: true
cache-dependency-glob: "uv.lock"
python-version: ${{ matrix.python-version }}

- name: Cache uv
uses: actions/cache@v4
with:
path: ~/.cache/uv
key: uv-${{ runner.os }}-py${{ matrix.python-version }}-${{ hashFiles('pyproject.toml') }}
restore-keys: |
uv-${{ runner.os }}-py${{ matrix.python-version }}-

- name: Install Hatch
run: pip install hatch
# FROZEN=1 makes the run fail if uv.lock is out of step with
# pyproject.toml, rather than silently resolving something different from
# what contributors get locally.
- name: Install dependencies
run: make install FROZEN=1

- name: Run tests with coverage
run: hatch test --python ${{ matrix.python-version }} --cover
run: make test-cov FROZEN=1
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -180,3 +180,4 @@ AGENTS.md
GEMINI.md
.claude/CLAUDE.md

.vscode/
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Changed

- **Tooling** — the project is now managed entirely with [uv](https://docs.astral.sh/uv/);
Hatch is no longer used as a test/environment runner. Tests run with
`uv run pytest --cov`, type checks with `uv run mypy`, and builds with
`uv build`. Development dependencies moved into a `dev` dependency group in
`pyproject.toml` and are now captured in `uv.lock`. Hatchling remains the
build backend, so the built distributions are unchanged.
- **Makefile** — common tasks are wrapped in `make` targets (`test`, `test-cov`,
`types`, `check`, `build`, `install`, `lock`, `clean`), which CI now calls
directly so local and CI invocations cannot drift apart.
- **Versioning** — the version is now declared statically in `pyproject.toml`
and bumped with `uv version --bump <major|minor|patch>`;
`visiomode_analysis.__about__.__version__` reads it back from the installed
distribution metadata.

### Fixed

- The type-check command no longer fails to start. The Hatch `types` environment
inherited `path = ".venv"` from the default environment and tried to
`pip install` into the uv-managed venv, which has no `pip`. Type stubs for
pandas and scipy are now pinned as dev dependencies.

## [0.1.0] - 2026-08-11

First public release.
Expand Down
8 changes: 4 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Contributing to Visiomode-analysis

## Issues workflow using VSCode
## Issues workflow using VSCode

1. Create a new issue on Github <https://github.com/DuguidLab/visiomode_analysis/issues/new>
2. In VSCode, navigate to the Github tab, select your issue and click the arrow button on its right to create a new issue branch.
2. In VSCode, navigate to the Github tab, select your issue and click the arrow button on its right to create a new issue branch.
3. (Optional) Under exploratory, create a new Jupyter notebook with the name `issue-<number>_<initials>_<description>.ipynb`.
4. Work on your issue.
5. Commit and push back to Github.
6. When you're finished, submit a pull request.
5. Commit and push back to Github.
6. When you're finished, submit a pull request.
42 changes: 42 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Thin wrappers around uv, so the commands used locally and in CI are the same.
#
# make test # run the test suite
# make test ARGS="tests/test_metrics.py -k d_prime"
# make check # everything CI checks
#
# Pass FROZEN=1 to fail on a stale uv.lock

FROZEN_FLAG := $(if $(FROZEN),--frozen,)
UV_RUN := uv run $(FROZEN_FLAG)
ARGS ?=

.DEFAULT_GOAL := help
.PHONY: help install test test-cov types check build clean lock

help: ## Show this help
@grep -hE '^[a-z-]+:.*?##' $(MAKEFILE_LIST) \
| sed -e 's/:.*##/:/' \
| awk -F':' '{printf " \033[36m%-10s\033[0m %s\n", $$1, $$2}'

install: ## Sync the virtualenv with pyproject.toml and uv.lock
uv sync $(FROZEN_FLAG)

test: ## Run the test suite
$(UV_RUN) pytest $(ARGS)

test-cov: ## Run the test suite with coverage (what CI runs)
$(UV_RUN) pytest --cov $(ARGS)

types: ## Type check with mypy
$(UV_RUN) mypy $(ARGS)

check: test-cov types ## Run the full test suite with coverage, then type check

build: ## Build the sdist and wheel into dist/
uv build

lock: ## Re-resolve and update uv.lock
uv lock

clean: ## Remove build artefacts and tool caches
rm -rf dist .coverage .coverage.* .pytest_cache .mypy_cache
27 changes: 22 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ cd visiomode_analysis
uv sync
```

This creates a `.venv` with the package and its dependencies installed in editable mode.
This creates a `.venv` with the package, its dependencies and the development tooling installed, with the package itself in editable mode.

## Usage

Expand Down Expand Up @@ -113,15 +113,32 @@ src/visiomode_analysis/

## Development

Common dev tasks are wrapped in a `Makefile`; run `make` on its own to list them.

```bash
# Run the full test suite with coverage
hatch test --cover
# Run the test suite
make test

# Run tests with coverage
make test-cov

# Run a single test file or test
make test ARGS="tests/test_metrics.py"
make test ARGS="tests/test_metrics.py::test_d_prime_afc_correction -v"

# Type checking
hatch run types:check
make types

# Everything CI checks: tests with coverage, then type check
make check

# Build the sdist and wheel
make build
```

See [CONTRIBUTING.md](CONTRIBUTING.md) for the issue workflow, and [CHANGELOG.md](CHANGELOG.md) for release notes.
Each target is a wrapper around the equivalent `uv run` command (`make test` is `uv run pytest`), you can just call uv directly if you so please.

See [CONTRIBUTING.md](CONTRIBUTING.md) for how to contribute and raise issues. See [CHANGELOG.md](CHANGELOG.md) for release notes.

## License

Expand Down
29 changes: 18 additions & 11 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "visiomode-analysis"
dynamic = ["version"]
version = "0.1.0"
description = 'Analysis package for Visiomode sessions'
readme = "README.md"
requires-python = ">=3.11"
Expand Down Expand Up @@ -41,8 +41,15 @@ Source = "https://github.com/DuguidLab/visiomode_analysis"
[project.scripts]
visiomode-analysis = "visiomode_analysis:cli"

[tool.hatch.envs.default]
path = ".venv" # Use uv environment path
[dependency-groups]
dev = [
"pytest",
"pytest-cov",
"coverage[toml]",
"mypy>=1.0.0",
"pandas-stubs",
"scipy-stubs",
]

[tool.hatch.build.targets.wheel]
packages = ["src/visiomode_analysis"]
Expand All @@ -54,15 +61,15 @@ artifacts = ["src/visiomode_analysis/reports/templates/*.html"]
exclude = ["/.github", "/.claude", "/docs"]
artifacts = ["src/visiomode_analysis/reports/templates/*.html"]

[tool.hatch.version]
path = "src/visiomode_analysis/__about__.py"
[tool.mypy]
files = ["src/visiomode_analysis", "tests"]

[tool.hatch.envs.types]
extra-dependencies = [
"mypy>=1.0.0",
]
[tool.hatch.envs.types.scripts]
check = "mypy --install-types --non-interactive {args:src/visiomode_analysis tests}"
# Plotly ships no type information, so every import from it is an error under
# the default settings. Stubs for the remaining third-party deps are pinned in
# the dev dependency group instead of being fetched on the fly.
[[tool.mypy.overrides]]
module = ["plotly.*"]
ignore_missing_imports = true

[tool.pytest.ini_options]
testpaths = ["tests"]
Expand Down
2 changes: 1 addition & 1 deletion release-checklist.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

* Create a new branch called `release/<version>` (e.g. `git branch release/v0.1.0`). Make sure you're doing this from the `main` branch.
* Checkout the new release branch.
* Bump the version using `hatch version <major|minor|micro>`.
* Bump the version using `uv version --bump <major|minor|patch>`. This edits `version` in `pyproject.toml` and refreshes `uv.lock` — commit both.
* Commit the version change.
* Tag the version with git using `git tag <version number>` (e.g. `git tag v0.1.0`).
* Push everything with `git push && git push --tags`.
Expand Down
4 changes: 3 additions & 1 deletion src/visiomode_analysis/__about__.py
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
__version__ = "0.1.0"
from importlib.metadata import version

__version__ = version("visiomode-analysis")
Loading
Loading