Active-learning-driven adaptive experimentation in psychophysics
Contributing to psyphy¶
We welcome contributions from both experienced developers and researchers who may be newer to collaborative software workflows. This guide provides both a quick workflow and a more detailed, step-by-step path.
Quick Start (TL;DR)¶
If you’re already familiar with GitHub workflows, this is the minimal path. For a detailed version scroll down to "Standard Workflow (Step-by-Step)".
Development Tools¶
We use Ruff for linting and formatting, mypy for type checking, and pre-commit to automate both. See LINTING_SETUP.md for the full configuration.
Pre-commit hooks (automatic)¶
Install once during setup:
Running checks manually¶
Before pushing (what CI runs)¶
¶
Code Standards¶
- Keep PRs focused and reasonably small (ideally < 300 lines)
- Write clear commit messages
- Add tests when appropriate
- Update documentation if APIs change
Pull Request Guidelines¶
A good PR should:
- Clearly describe what changed and why
- Reference related issues if applicable
- Be easy to review (avoid large unrelated changes)
Issues¶
Use GitHub issues to report bugs or suggest features.
Include:
- clear description and acceptance criteria
- steps to reproduce (for bugs)
Documentation¶
Build docs locally:
Build static site —--strict is what CI runs, so use it locally too:
hong2025_reproduction.py --mode full,
full_wppm_fit_example.py) are GPU jobs. On an NVIDIA machine, including the
Flatiron cluster, add the cuda extra:
module load cuda cudnn on the cluster, since the system libraries then take
precedence on LD_LIBRARY_PATH and break GPU detection; module load python
is enough. Apple Silicon GPUs are not supported: JAX's Metal backend
cannot do float64, which these examples require for their
published-precision comparisons, so Mac users should expect CPU-only
execution (or --mode quick-style smoke tests only).
Deploy:
Code snippets in docs: the --8<-- markers¶
Tutorial pages do not retype code. They quote it out of the runnable script
next to them, so the page and the script cannot drift apart. Mark a region in
the .py:
and pull it into the .md by path and tag:
This is pymdownx.snippets
from PyMdown Extensions, configured in mkdocs.yml. The 8< is a pair of
scissors — the old "cut here" convention — not something we invented.
Two things to know:
- We set
check_paths: true, so a renamed or deleted tag fails the build rather than silently rendering nothing.mkdocs build --strictcatches it. - Prefer a snippet over pasting code into the Markdown. Pasted code has no such protection and will go stale.
License¶
By contributing, you agree that your contributions will be licensed under the project’s LICENSE.md .
Standard Workflow (Step-by-Step)¶
This section explains the full workflow in detail.
1. Fork and clone¶
On GitHub:
- Fork
flatironinstitute/psyphyto your account
Then locally:
Summary:¶
2. Development setup¶
Install the package and enable pre-commit hooks:
This project uses automated checks (formatting, linting, type checking) via pre-commit . These run automatically when you commit.Alternatively, uv installs from the committed uv.lock, giving you the exact versions everyone else resolved rather than whatever the loose ranges in pyproject.toml allow on the day you install:
uv run <command> instead of manually activating the venv (e.g. uv run pytest), or source .venv/bin/activate once uv sync has created it. Any time you add or bump a dependency in pyproject.toml, run uv lock and commit the updated uv.lock alongside it.
3. Sync with upstream before starting work¶
¶
4. Create a feature branch¶
¶
5. Work and commit¶
¶
6. Push to your fork¶
¶
7. Open a Pull Request¶
On GitHub:
- Base repo: flatironinstitute/psyphy (upstream)
- Compare: your branch on your fork (origin)
8. Iterate on feedback¶
¶
9. After merge¶
¶
Keeping Your Branch Up-to-Date¶
If you’re working on a branch over time, upstream main will change.
⚠️ It’s important to regularly update your branch to avoid large conflicts later.
Recommended approach: rebase¶
When Things Diverge (Merge Conflicts)¶
If your branch and upstream modify the same code, Git will report a conflict.
This is normal.
What a conflict looks like
How to resolve:- Open the file
- Decide how to combine the changes (your IDE, like VSCode will visualize each merge conflict making it straight forward whether to keep the upstream version of your local one)
- Remove the conflict markers
Then:
If conflicts are complex
Don’t try to resolve line-by-line blindly. Instead:
- Understand what upstream changed
- Understand your intended behavior
- Update your code accordingly