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
10 changes: 8 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,23 @@ default_language_version:

repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.8.6
rev: v0.14.14
hooks:
# Run the linter
- id: ruff
args: [ --fix ]
# Run the formatter
- id: ruff-format
- repo: https://github.com/codespell-project/codespell
rev: v2.3.0
rev: v2.4.1
hooks:
- id: codespell
args: [--skip, "pyproject.toml,docs/_build/*,*.egg-info"]
additional_dependencies:
- tomli
- repo: https://github.com/numpy/numpydoc
rev: v1.10.0
hooks:
- id: numpydoc-validation
name: numpydoc validate
description: Run numpydoc validation across trx package
2 changes: 1 addition & 1 deletion .spin/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
# Spin commands package
"""Spin commands package."""
55 changes: 41 additions & 14 deletions .spin/cmds.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,22 @@


def run(cmd, check=True, capture=True):
"""Run a shell command."""
"""Run a shell command.

Parameters
----------
cmd : list of str
Command and arguments to execute.
check : bool, optional
If True, check the return code and report errors.
capture : bool, optional
If True, capture stdout and stderr.

Returns
-------
str or int or None
Captured stdout string, return code, or None on error.
"""
result = subprocess.run(cmd, capture_output=capture, text=True, check=False)
if check and result.returncode != 0:
if capture:
Expand All @@ -24,7 +39,13 @@ def run(cmd, check=True, capture=True):


def get_remotes():
"""Get dict of remote names to URLs."""
"""Get dict of remote names to URLs.

Returns
-------
dict
Mapping of remote names to their fetch URLs.
"""
output = run(["git", "remote", "-v"])
if not output:
return {}
Expand Down Expand Up @@ -110,11 +131,14 @@ def test(pattern, verbose, pytest_args):

Additional arguments are passed directly to pytest.

Examples:
spin test # Run all tests
spin test -m memmap # Run tests matching 'memmap'
spin test -v # Verbose output
spin test -- -x --tb=short # Pass args to pytest
Parameters
----------
pattern : str or None
Only run tests matching this pattern (passed to pytest -k).
verbose : bool
If True, enable verbose output.
pytest_args : tuple
Additional arguments passed directly to pytest.
"""
cmd = ["pytest", "trx/tests"]

Expand All @@ -138,9 +162,10 @@ def test(pattern, verbose, pytest_args):
def lint(fix):
"""Run linting checks using ruff and codespell.

Examples:
spin lint # Run ruff and codespell checks
spin lint --fix # Run ruff and auto-fix issues
Parameters
----------
fix : bool
If True, automatically fix issues where possible.
"""
click.echo("Running ruff linter...")
cmd = ["ruff", "check", "."]
Expand Down Expand Up @@ -191,10 +216,12 @@ def lint(fix):
def docs(clean, open_browser):
"""Build documentation using Sphinx.

Examples:
spin docs # Build docs
spin docs --clean # Clean and rebuild
spin docs --open # Build and open in browser
Parameters
----------
clean : bool
If True, clean build directory before building.
open_browser : bool
If True, open documentation in browser after building.
"""
import os

Expand Down
1 change: 1 addition & 0 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
"""Sphinx configuration for trx-python documentation."""
# Configuration file for the Sphinx documentation builder.
#
# This file only contains a selection of the most common options. For a full
Expand Down
35 changes: 35 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,38 @@ package = "trx"
"Test" = [".spin/cmds.py:test", ".spin/cmds.py:lint"]
"Docs" = [".spin/cmds.py:docs"]
"Clean" = [".spin/cmds.py:clean"]

[tool.numpydoc_validation]
checks = [
"all", # report on all checks, except the below
# These we we ignore:
"GL01", # Docstring should start in the line immediately after the quotes
"GL02", # Closing quotes on own line (doesn't work on Python 3.13 anyway)
"EX01",
"EX02", # examples failed (we test them separately)
"ES01", # no extended summary
"SA01", # no see also
"YD01", # no yields section
"SA04", # no description in See Also
"PR04", # Parameter "shape (n_channels" has no type
"RT02", # The first line of the Returns section should
]
# remember to use single quotes for regex in TOML
exclude = [ # don't report on objects that match any of these regex
'\.undocumented_method$',
'\.__repr__$',
'\.__str__$',
'\.__len__$',
'\.__getitem__$',
'\.__deepcopy__$',
]
exclude_files = [ # don't process filepaths that match these regex
'^trx/tests/.*',
'^module/gui.*',
'^examples/.*',
]
override_SS05 = [ # override SS05 to allow docstrings starting with these words
'^Process ',
'^Assess ',
'^Access ',
]
57 changes: 52 additions & 5 deletions tools/update_switcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,18 @@


def load_switcher(path):
"""Load existing switcher.json or return empty list."""
"""Load existing switcher.json or return empty list.

Parameters
----------
path : str or Path
Path to the switcher.json file.

Returns
-------
list
List of version entries from the switcher file.
"""
try:
with open(path, "r") as f:
return json.load(f)
Expand All @@ -24,22 +35,52 @@ def load_switcher(path):


def save_switcher(path, versions):
"""Save switcher.json with proper formatting."""
"""Save switcher.json with proper formatting.

Parameters
----------
path : str or Path
Path to the switcher.json file.
versions : list
List of version entries to write.
"""
with open(path, "w") as f:
json.dump(versions, f, indent=4)
f.write("\n")


def ensure_dev_entry(versions):
"""Ensure dev entry exists in versions list."""
"""Ensure dev entry exists in versions list.

Parameters
----------
versions : list
List of version entries.

Returns
-------
list
Updated versions list with dev entry.
"""
dev_exists = any(v.get("version") == "dev" for v in versions)
if not dev_exists:
versions.insert(0, {"name": "dev", "version": "dev", "url": f"{BASE_URL}/dev/"})
return versions


def ensure_stable_entry(versions):
"""Ensure stable entry exists with preferred flag."""
"""Ensure stable entry exists with preferred flag.

Parameters
----------
versions : list
List of version entries.

Returns
-------
list
Updated versions list with stable entry.
"""
stable_idx = next(
(i for i, v in enumerate(versions) if v.get("version") == "stable"), None
)
Expand Down Expand Up @@ -98,7 +139,13 @@ def add_version(versions, version):


def main():
"""Main entry point."""
"""Run the switcher update workflow.

Returns
-------
int
Exit code (0 for success).
"""
parser = argparse.ArgumentParser(
description="Update switcher.json for documentation version switching"
)
Expand Down
1 change: 1 addition & 0 deletions trx/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""TRX file format for brain tractography data."""
Loading