Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Transition to versioned bids functions #349

Merged
merged 25 commits into from
Feb 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
735e568
Update docstrings of bids specs
pvandyken Oct 20, 2023
2e19f16
Change TypeAlias from strings to List and Dict
pvandyken Oct 20, 2023
a81a60b
Switch to lazily loaded imports
pvandyken Oct 20, 2023
110b2e6
Split utility containers into seperate file
pvandyken Oct 21, 2023
70ce62e
Transition to versioned bids functions
pvandyken Oct 20, 2023
303a748
Fix bug in placement of unknown entities
pvandyken Oct 21, 2023
292914a
Refactor poe tasks
pvandyken Oct 21, 2023
b9af41d
Add v0.10.1 spec
pvandyken Dec 9, 2023
6dbf0e5
Update documentation
pvandyken Dec 9, 2023
f8d58ce
Switch over to a configured spec system
pvandyken Dec 11, 2023
e8e7815
Updates to documentation
pvandyken Dec 11, 2023
fdded77
Change most path submodules to private
pvandyken Dec 11, 2023
e3a62ed
Add deprecation and dangerous bids usage warnings
pvandyken Dec 11, 2023
d5774d5
Fix whitespace issues in MultSelectDict doctest
pvandyken Dec 11, 2023
8342890
Extend include_subject/session_dir to all builders
pvandyken Dec 11, 2023
ad00225
Try different in_interactive_session rule
pvandyken Dec 12, 2023
6d75150
Increase deadline for pyproject formatting test
pvandyken Dec 12, 2023
efa4922
Apply formatting after mkinit and update-bids
pvandyken Dec 16, 2023
6cebbcc
Add quality check for update-bids
pvandyken Dec 19, 2023
37857cc
Refactor try block in format function
pvandyken Dec 20, 2023
e7b96d8
Add tests for spec docstrings
pvandyken Dec 20, 2023
e9cb07c
Fix typo in docs
pvandyken Jan 22, 2024
e602511
Restrict root dir from test examples
pvandyken Jan 22, 2024
5f1720f
Update mkinit
pvandyken Jan 24, 2024
5210c86
Expand discussion of bids specs in docs
pvandyken Feb 1, 2024
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
9 changes: 9 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@ jobs:
# run python style checks
- name: Poetry Lock Check
run: poetry check --lock
# Check that running update-bids doesn't change any files
- name: update-bids check
run: |
poetry run poe update-bids
git diff --quiet || (
git status
echo 'bids specs out of date, run `poetry run poe update-bids`'
exit 1
)
- name: Formatting
run: poetry run ruff format snakebids --check
- name: Linting
Expand Down
1 change: 1 addition & 0 deletions docs/_static/css/typealiases.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#snakebids\.paths\.utils\.BidsPathSpec,
#snakebids\.types\.InputsConfig,
#snakebids\.types\.ZipList,
#snakebids\.types\.ZipListLike {
Expand Down
6 changes: 6 additions & 0 deletions docs/api/app.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
BIDS App Bootstrapping
======================


.. automodule:: snakebids.app
:members:
6 changes: 6 additions & 0 deletions docs/api/creation.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Dataset Creation
=======================================

.. currentmodule:: snakebids

.. autofunction:: generate_inputs
82 changes: 43 additions & 39 deletions docs/api/main.rst
Original file line number Diff line number Diff line change
@@ -1,67 +1,71 @@
.. _main api:


================
API
================

.. py:currentmodule:: snakebids

snakebids
---------

.. autoclass:: snakebids.BidsComponent
:members:
:exclude-members: input_wildcards, input_lists, input_name, input_path, input_zip_lists
:inherited-members:

.. dropdown:: Legacy ``BidsComponents`` properties
:icon: info
:class-title: sd-outline-info
.. toctree::
:hidden:

The following properties are historical aliases of ``BidsComponents`` properties. There are no current plans to deprecate them, but new code should avoid them.
paths
creation
manipulation
structures
app

.. autoproperty:: snakebids.BidsComponent.input_zip_lists

.. autoproperty:: snakebids.BidsComponent.input_wildcards
Path Building
-------------

.. autoproperty:: snakebids.BidsComponent.input_name
.. Need to manually create this table because bids does not have a proper docstring

.. autoproperty:: snakebids.BidsComponent.input_path
=================================== ================================
:func:`bids <bids>` Generate bids or bids-like paths
:func:`bids_factory <bids_factory>` Create new :func:`bids` functions according to a spec
=================================== ================================

.. autoproperty:: snakebids.BidsComponent.input_lists

Dataset Creation
----------------

.. autoclass:: snakebids.BidsPartialComponent
.. autosummary::
:nosignatures:

.. autoclass:: snakebids.BidsComponentRow
:members:
:exclude-members: zip_lists
generate_inputs

.. autoclass:: snakebids.BidsDataset
:members:
:exclude-members: input_wildcards, input_lists, input_path, input_zip_lists
Dataset Manipulation
--------------------

.. dropdown:: Legacy ``BidsDataset`` properties
:icon: info
:class-title: sd-outline-info
.. autosummary::
:nosignatures:

The following properties are historical aliases of :class:`~snakebids.BidsDataset` properties. There are no current plans to deprecate them, but new code should avoid them.
filter_list
get_filtered_ziplist_index

.. autoproperty:: snakebids.BidsDataset.input_zip_lists
Data Structures
---------------

.. autoproperty:: snakebids.BidsDataset.input_wildcards
.. autosummary::
:nosignatures:

.. autoproperty:: snakebids.BidsDataset.input_path
BidsComponent
BidsPartialComponent
BidsComponentRow
BidsDataset
BidsDatasetDict

.. autoproperty:: snakebids.BidsDataset.input_lists


.. automodule:: snakebids
:exclude-members: from_bids_lists, BidsComponent, BidsPartialComponent, BidsComponentRow, BidsDataset
:members:
BIDS App Booststrapping
-----------------------

.. currentmodule:: snakebids.app

app
---
.. autosummary::
:nosignatures:
:recursive:

.. automodule:: snakebids.app
:members:
SnakeBidsApp
7 changes: 7 additions & 0 deletions docs/api/manipulation.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Dataset Manipulation
=======================================

.. currentmodule:: snakebids

.. automodule:: snakebids
:members: filter_list, get_filtered_ziplist_index
86 changes: 86 additions & 0 deletions docs/api/paths.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
Path Building
=============

.. py:currentmodule:: snakebids

.. autofunction:: snakebids.bids

.. autofunction:: bids_factory(spec)

.. autofunction:: set_bids_spec

.. _specs:

Specs
-----

.. py:currentmodule:: snakebids.paths.specs

BIDS specs control the formatting of paths produced by the :func:`~snakebids.bids` function. They specify the order of recognized entities, placing ``ses-X`` after ``sub-Y``, for instance, no matter what order they are specified in the function. Unrecognized entitites are placed in the order specified in the function call.

Because of this, each addition of entities to the spec presents a potentially breaking change. Suppose an entity called ``foo`` were added to the spec. Calls to :func:`~snakebids.bids` with ``foo`` as an argument would place the entity at the end of the path:

.. code-block:: python

from snakebids import bids

# Before foo is in the spec
bids(
subject="001",
session="1",
label="WM",
foo="bar",
suffix="data.nii.gz",
) == "sub-001_ses-1_label-WM_foo-bar_data.nii.gz"

The addition of ``foo`` to the spec might move the position of the entity forward in the output:

.. code-block:: python

# After foo is in the spec
bids(
subject="001",
session="1",
label="WM",
foo="bar",
suffix="data.nii.gz",
) == "sub-001_ses-1_foo-bar_label-WM_data.nii.gz"

This would change the output paths of workflow using this function call, causing a breaking change in workflow behaviour.

To ensure stable path generation across releases, Snakebids ships with versioned specs that can be explicitly set using :func:`snakebids.set_bids_specs`. These specs are named after the snakebids version they release with. By default, :func:`~snakebids.bids` will always use the latest spec, but production code should generally declare the spec to be used by the workflow:

.. code-block:: python

from snakebids import set_bids_spec
set_bids_spec("v0_0_0")

This is especially true of workflows using custom entities. To emphasize this, a warning is issued in python scripts and apps using such entities without declaring a spec version.


.. automodule:: snakebids.paths.specs
:exclude-members: latest
:members:

.. function:: latest

Points to the most recent spec

Types
-----

.. py:currentmodule:: snakebids

.. autoclass:: BidsFunction
:members:

.. py:currentmodule:: snakebids.paths

.. autoclass:: BidsPathEntitySpec
:members:

.. automodule:: snakebids.paths
:noindex:
:members: BidsPathSpec

.. class:: BidsPathSpec
53 changes: 53 additions & 0 deletions docs/api/structures.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
Data Structures
===============

.. py:currentmodule:: snakebids

.. autoclass:: BidsComponent
:members:
:exclude-members: input_wildcards, input_lists, input_name, input_path, input_zip_lists
:inherited-members:

.. dropdown:: Legacy ``BidsComponents`` properties
:icon: info
:class-title: sd-outline-info

The following properties are historical aliases of ``BidsComponents`` properties. There are no current plans to deprecate them, but new code should avoid them.

.. autoproperty:: BidsComponent.input_zip_lists

.. autoproperty:: BidsComponent.input_wildcards

.. autoproperty:: BidsComponent.input_name

.. autoproperty:: BidsComponent.input_path

.. autoproperty:: BidsComponent.input_lists


.. autoclass:: BidsPartialComponent

.. autoclass:: BidsComponentRow
:members:
:exclude-members: zip_lists

.. autoclass:: BidsDataset
:members:
:exclude-members: input_wildcards, input_lists, input_path, input_zip_lists

.. dropdown:: Legacy ``BidsDataset`` properties
:icon: info
:class-title: sd-outline-info

The following properties are historical aliases of :class:`~snakebids.BidsDataset` properties. There are no current plans to deprecate them, but new code should avoid them.

.. autoproperty:: BidsDataset.input_zip_lists

.. autoproperty:: BidsDataset.input_wildcards

.. autoproperty:: BidsDataset.input_path

.. autoproperty:: BidsDataset.input_lists

.. autoclass:: BidsDatasetDict
:members:
10 changes: 9 additions & 1 deletion docs/bids_app/overview.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
# Overview
# Bids Apps

```{toctree}
:hidden:

config
workflow
plugins
```

Snakebids apps rely on a configuration file (`snakebids.yml`). This file specifies which files from a BIDS dataset should be used as input. The apps also utilize workflow definitions, which are written in one or more Snakefile(s) and determine how the input files are processed.

Expand Down
8 changes: 5 additions & 3 deletions docs/bids_app/plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Plugins are a feature in Snakebids that enables you to add custom functionality
For a full list of plugins distributed with Snakebids, see the [Plugins reference](/api/plugins) page.
```

(using-plugins)=
## Using plugins
To add one or more plugins to your {class}`SnakeBidsApp <snakebids.app.SnakeBidsApp>`, pass them to the {class}`~snakebids.app.SnakeBidsApp` constructor via the {attr}`~snakebids.app.SnakeBidsApp.plugins` parameter. Your plugin will have access to CLI parameters (after they've been parsed) via their names in {attr}`SnakeBidsApp.config <snakebids.app.SnakeBidsApp.config>`. Any modifications to that config dictionary made by the plugin will be carried forward into the workflow.

Expand All @@ -23,13 +24,14 @@ SnakeBidsApp(
).run_snakemake()
```

(creating-plugins)=
## Creating plugins
A plugin is a function or callable class that accepts a {class}`SnakeBidsApp <snakebids.app.SnakeBidsApp>` as input and returns a modified {class}`SnakeBidsApp` or `None`.

As an example, a simplified version of the bids-validator plugin that runs the [BIDS Validator](https://github.com/bids-standard/bids-validator) could be defined as follows:

```py
import subprocess
import subprocess

from snakebids.app import SnakeBidsApp
from snakebids.exceptions import SnakeBidsPluginError
Expand All @@ -55,7 +57,7 @@ class BidsValidator:


class InvalidBidsError(SnakebidsPluginError):
"""Error raised if input BIDS dataset is invalid,
"""Error raised if input BIDS dataset is invalid,
inheriting from SnakebidsPluginError.
"""
```
Expand All @@ -70,4 +72,4 @@ A plugin can be used to implement any logic that can be handled by a Python func

```{note}
When creating a custom error for your Snakebids plugin, it is recommended to inherit from {class}`SnakebidsPluginError <snakebids.exceptions.SnakebidsPluginError>` such that errors will be recognized as a plugin error.
```
```
9 changes: 7 additions & 2 deletions docs/bids_function/overview.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Overview
========
Bids Function
=============

The ``bids`` function generates a BIDS-like filepath corresponding to its keyword arguments. The generated filepath has the form::

Expand Down Expand Up @@ -60,3 +60,8 @@ Now if you want to process all inputs of a given form regardless of how their wi
**inputs.subj_wildcards
),
)

Specs
-----

The structure of the built path is based on the currently active BIDS spec. More information can be found on the :ref:`specs <specs>` page.
4 changes: 3 additions & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"sphinxarg.ext",
"sphinx.ext.intersphinx",
"sphinx.ext.napoleon",
"sphinx.ext.autosummary",
"sphinx.ext.autodoc",
"sphinxcontrib.asciinema",
"myst_parser",
Expand Down Expand Up @@ -69,7 +70,8 @@
"InputsConfig": "snakebids.types.InputsConfig",
}
autodoc_typehints_format = "short"
autosummary_imported_members = True
# autosummary_imported_members = True
autosummary_generate = True


# Add any paths that contain templates here, relative to this directory.
Expand Down
Loading
Loading