Purpose: core Python library for HED (Hierarchical Event Descriptors) validation, summary, and analysis of event annotations in neuroscience datasets (BIDS compatible). Distributed on PyPI as hedtools. Not in scope: the online tools server (repo hed-server, package hedweb), the browser-based tools (repo hed-web, JavaScript), and the schema vocabularies themselves (repo hed-schemas).
Test framework: unittest. Never convert the suite to pytest style as a side effect of other work, and never mix the two.
- Install dev env:
pip install -e ".[dev,test,docs,examples]"(uv works:uv venv .venvthenuv pip install ...) - Fetch test data:
git submodule update --init --recursive - Run tests:
python -m unittest discover tests -v - Spec tests (need submodules):
python -m unittest discover spec_tests -v - Single test:
python -m unittest tests.models.test_hed_string.TestHedString.test_constructor - Lint and fix:
ruff check --fix --unsafe-fixes hed/ tests/ - Format:
ruff format hed/ tests/ - Spelling:
typos - Docs:
sphinx-build -b html docs docs/_build/html - CLI:
hedpy --help(andhedpy COMMAND --helpfor exact syntax)
CI runs ruff check, ruff format --check, typos, the unittest suite, and the spec tests; replicate those locally before asking for a push. Workflow details: .rules/ci_cd.md.
hed/- the package:models/(HedString, HedTag, Sidecar, TabularInput),validator/,schema/(loading, caching, I/O),tools/(BIDS, analysis, remodeling),errors/,cli/(hedpyentry point)tests/- unit tests mirroringhed/; test data intests/data/spec_tests/- HED specification compliance tests; data via git submodulesdocs/- Sphinx sources.rules/- detailed conventions:python.md,testing.md,git.md,ci_cd.md,code_review.md.status/- working notes. Gitignored; local to each machine.
- ASCII only in prose, code, comments, docstrings, and filenames:
-not em or en dashes,->not arrows,...not an ellipsis character, straight quotes, no emoji. Applies to new and edited content; never sweep existing files for it as a side effect of other work. Exception: genuine data (author names, dataset titles, recorded API responses) keeps whatever characters it actually contains. - Line length 120; ruff rules live in
pyproject.tomlunder[tool.ruff]. - Google-style docstrings for public APIs, with
Parameters:notArgs:. - Markdown headers in sentence case: first word, proper nouns, and acronyms.
- No mocks in tests: real schemas, real HED strings, real files (
.rules/testing.md). - Commits: atomic, subject under 50 chars, no emoji, no AI attribution. PRs target
main(.rules/git.md).
hed/_version.pyis auto-generated by setuptools-scm - never edit it.- Schemas are cached in
~/.hedtools/and shared across processes - never modify a loaded schema in place; cache locking usesportalocker. - Validation returns structured issue lists and never raises for validation failures; collect issues with
ErrorHandler. - HED strings are comma-separated path strings (e.g.
Event, Sensory-event);HedSchemahandles a single schema,HedSchemaGroupmultiple libraries. - Use absolute imports from
hed, never relative imports. - If spec tests cannot find data, run
git submodule update --init --recursive. - BIDS sidecar inheritance is resolved by
BidsFileGroup- never resolve it by hand.
Hosted at https://github.com/hed-standard/hed-python. Keep local main a clean mirror of the hed-standard main - never commit or merge to it locally. Do all work on a branch based on that main and get it into hed-standard through a pull request, typically pushed to your own fork first. Remote names (origin, upstream, ...) vary by checkout, so commands here never assume them; your own remote layout is a machine fact for .status/local-environment.md.
hed-schemas- the HED vocabularies (XML/MediaWiki/OWL); also a submodule underspec_tests/hed-specification- the formal spec; error codes here reference ithed-examples- example datasets; submodule used byspec_tests/hed-server- the online tools at hedtools.org (Python packagehedweb), the main consumer of this packagehed-web- the browser-based tools at hedtags.org/hed-web (JavaScript; does not use this package)
.status/ is gitignored, so it exists only on the machine that wrote it and never in a fresh clone or worktree.
.status/README.md- the index. Read this first; it lists what is active..status/decisions.md- why things are the way they are. Read before proposing structural changes. Append entries; never rewrite one..status/plans/*.md- active plans. Check theStatus:header and the[ ]/[x]markers before starting work..status/local-environment.md- this machine's paths, interpreter, and quirks. Tool-agnostic. Never copy its contents into a committed file.- IMPORTANT: do not read
.status/archive/unless a file is named for you. Nothing new is created at the.status/root.
- IMPORTANT: every file written to
.status/opens with aFor humans:summary - three or four sentences, at the very top: what the file is and what a person needs to take from it. The same applies to a long answer in a session: lead with the conclusion. - IMPORTANT: temporary scripts, experiments, and one-off test files go in
.status/scratch/- never the repository root. Anything inscratch/may be deleted unread. - IMPORTANT: never delete or rewrite a file under
.status/without asking first. Appending is fine. - For a change spanning more than three files, write a plan to
.status/plans/and stop for review before editing. - When you are guessing about an external API or data format, say so explicitly rather than assuming.
- Show evidence, not assertions: the command you ran and its actual output.
- Do not commit, push, or create branches unless asked. Never push - the owner does the pushes.