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
24 changes: 24 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ jobs:
run: |
pip install -e .[test]

- name: Minimal test of command-line
run: |
bids2openminds --help

- name: Test installed package
run: |
pytest -v --cov=bids2openminds --cov-report=lcov
Expand All @@ -46,3 +50,23 @@ jobs:
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
path-to-lcov: coverage.lcov

docs:
runs-on: ubuntu-latest
steps:

- name: Checkout Repository
uses: actions/checkout@v4

- name: Set up Python 3.11
uses: actions/setup-python@v5
with:
python-version: 3.11

- name: Install Sphinx dependencies
run: |
pip install sphinx sphinx-rtd-theme

- name: Build documentation
run: |
sphinx-build -W docs/source docs/_build/html
46 changes: 46 additions & 0 deletions CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Code of Conduct

Contributing to bids2openminds should be a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.

## Our Pledge

In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.

## Our Standards

Examples of behavior that contributes to creating a positive environment include:

- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

- Use of sexualized language or imagery
- Unwelcome sexual attention or advances
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information (e.g. email address) without explicit permission
- Other conduct which could reasonably be considered inappropriate in a professional setting

## Our Responsibilities

Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.

Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.

## Scope

This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or its community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the openMINDS team at `support@openmetadatainitiative.org`. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The openMINDS team is obligated to maintain confidentiality with regard to the reporter of an incident.

Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), [version 1.4](http://contributor-covenant.org/version/1/4/).
19 changes: 19 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Contributing to bids2openminds

Full contribution guidelines are in the [documentation](https://bids2openminds.readthedocs.io/en/latest/contributing.html).

## Quick start

```bash
git clone --recurse-submodules https://github.com/openMetadataInitiative/bids2openminds.git
cd bids2openminds
pip install -e ".[test]"
pytest
```

## Key points

- Feature branches off `main`; PR required to merge; CI must pass
- Google-style docstrings for all public functions
- Deprecations get a `DeprecationWarning` for one release before removal
- Contributors are expected to abide by the [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)
29 changes: 29 additions & 0 deletions bids2openminds/utility.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,16 @@ def table_filter(dataframe: pd.DataFrame, filter_str: str, column: str = "suffix


def pd_table_value(data_frame, column_name, not_list: bool = True):
"""Extract a value from a single-row DataFrame column.

Parameters:
- data_frame (pd.DataFrame): A DataFrame expected to contain a single row.
- column_name (str): The column to read.
- not_list (bool, optional): If True (default), return the scalar value; if False, return a list.

Returns:
- The column value as a scalar (not_list=True) or list (not_list=False), or None if the column is absent.
"""
try:
if column_name in data_frame.columns:
value = data_frame[column_name].to_list()
Expand Down Expand Up @@ -111,14 +121,33 @@ def file_hash(file_path: str, algorithm: str = "MD5"):


def file_storage_size(file_path: str):
"""Return the storage size of a file as an openMINDS QuantitativeValue and a raw byte count.

Parameters:
- file_path (str): The path to the file.

Returns:
- tuple: A (QuantitativeValue, int) pair where the QuantitativeValue expresses the size in bytes
as an openMINDS object and the int is the raw byte count.
"""
file_stats = os.stat(file_path)
file_size = QuantitativeValue(
value=file_stats.st_size, unit=UnitOfMeasurement.by_name("byte"))
return file_size, file_stats.st_size


def detect_nifti_version(file_name, extension, file_size):
"""Detect the NIfTI format version of a file by inspecting its header bytes.

Parameters:
- file_name (str): Path to the NIfTI file.
- extension (str): File extension, either ``".nii"`` or ``".nii.gz"``.
- file_size (int): Size of the file in bytes (unused; reserved for future use).

Returns:
- ContentType or None: The openMINDS ContentType for NIfTI-1 or NIfTI-2, or None if the
header cannot be read or the format is unrecognised.
"""
nii1_sizeof_hdr = 348
nii2_sizeof_hdr = 540

Expand Down
99 changes: 99 additions & 0 deletions docs/source/architecture.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
Architecture
============

bids2openminds converts `BIDS <https://bids.neuroimaging.io/>`_ neuroimaging datasets into
`openMINDS <https://openminds-documentation.readthedocs.io/>`_ metadata collections
serialised as JSON-LD.

Conversion pipeline
-------------------

The top-level entry point is :func:`bids2openminds.converter.convert`.
It orchestrates the following steps:

1. Validate that the input path is a directory and load a BIDS layout via
`ancpBIDS <https://github.com/ANCPLabOldenburg/ancp-bids>`_.
2. Flatten the layout into a Pandas ``DataFrame`` (one row per file) via the
``layout_to_df()`` shim in ``converter.py``.
3. Call functions in ``main.py`` to create typed openMINDS objects:

* Subjects and their biological states
* Persons (authors / contributors)
* Behavioural protocols (tasks)
* File bundles and individual files
* A ``DatasetVersion`` and its parent ``Dataset``

4. Validate the resulting ``openminds.Collection`` against the openMINDS schema.
5. Optionally serialise to JSON-LD (single file or one file per object).
6. Print a human-readable conversion report.

Module descriptions
-------------------

``converter.py``
~~~~~~~~~~~~~~~~

CLI entry point (Click command) and the ``convert()`` function that orchestrates
the pipeline. Also contains ``layout_to_df()``, a shim that translates the
ancpBIDS object model into a flat Pandas DataFrame so the rest of the code can
query files without depending directly on the ancpBIDS API.

``main.py``
~~~~~~~~~~~

All object-creation functions that map BIDS concepts to openMINDS schema objects:
``create_subjects()``, ``create_persons()``, ``create_behavioral_protocol()``,
``create_file()``, ``create_dataset_version()``, and ``create_dataset()``.

``mapping.py``
~~~~~~~~~~~~~~

Controlled-vocabulary dictionaries that translate BIDS terms (file suffixes,
acquisition labels, species identifiers, sex codes, handedness codes) into
openMINDS ``ControlledTerm`` instances. Entries that do not yet have a
corresponding openMINDS instance are marked ``None`` with a ``# TODO`` comment.

``utility.py``
~~~~~~~~~~~~~~

Helper functions: JSON reading, Pandas DataFrame filtering and value extraction,
file hashing (returns an openMINDS ``Hash`` object), file size (returns an
openMINDS ``QuantitativeValue`` object), and NIfTI version detection.

``report.py``
~~~~~~~~~~~~~

Generates a human-readable conversion summary printed after a successful run,
showing counts of subjects, files, persons, and protocols.

openMINDS object model
----------------------

All metadata objects are instances from the ``openminds.v4`` package:

* ``openminds.v4.core`` — ``Dataset``, ``DatasetVersion``, ``SubjectGroup``,
``Subject``, ``SubjectState``, ``Person``, ``File``, ``FileBundle``, etc.
* ``openminds.v4.controlled_terms`` — ``Species``, ``BiologicalSex``,
``Handedness``, ``Technique``, ``ExperimentalApproach``, ``UnitOfMeasurement``, etc.

Objects are added to an ``openminds.Collection``, which enforces the schema and
handles JSON-LD serialisation.

Test structure
--------------

``test/test_bids_examples.py``
End-to-end conversion of datasets from the `bids-examples
<https://github.com/bids-standard/bids-examples>`_ corpus (checked out as a
git submodule at ``bids-examples/``). Each test asserts on the counts of
openMINDS objects produced.

``test/test_thorough_bids_example.py``
Deep validation on a more complex BIDS dataset.

``test_dataset_version.py``, ``test_example_datasets_click.py``, ``test/test_person.py``, ``test/test_task.py``, ``test/test_subject_age.py``, ``test/test_file_bundle.py``, ``test/test_mapping_completeness.py``
Unit tests for individual mapping and utility functions.

The ``bids-examples`` submodule must be initialised before running the full test suite::

git submodule update --init
95 changes: 95 additions & 0 deletions docs/source/contributing.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
Contributing
============

This document describes how to set up a development environment, our workflow conventions, and the standards we follow.

Development setup
-----------------

Clone the repository **with its submodules** (the BIDS example test corpus
lives in a submodule)::

git clone --recurse-submodules https://github.com/openMetadataInitiative/bids2openminds.git
cd bids2openminds
pip install -e ".[test]"

Run the full test suite::

pytest

If you cloned without ``--recurse-submodules``, initialise the submodule afterwards::

git submodule update --init

Branching model
---------------

- All development happens on feature branches created from ``main``.
- Do not push commits directly to ``main``.
- Open a pull request to merge your branch into ``main``.
- At least one maintainer approval is required.
- CI must pass (tests on Linux/Windows/macOS, codespell, docs build) before merging.

Review process
--------------

- Keep pull requests focused; one logical change per PR makes review easier.
- Add an entry to ``CHANGES.rst`` in the *Unreleased* section (or under the next version)
describing the change.
- Respond to review comments; squash fixup commits before the PR is merged if requested.

Versioning
----------

We follow `Semantic Versioning <https://semver.org/>`_ (``MAJOR.MINOR.PATCH``).
While the project is at ``0.x``, minor version bumps may introduce breaking API changes.
Once we reach ``1.0``, breaking changes will only occur in major releases.

Releasing a new version
-----------------------

See :doc:`maintenance` for the full release procedure.

Docstring standard
------------------

Use `Google-style docstrings
<https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings>`_
for all public functions and classes. A minimal example:

.. code-block:: python

def my_function(param: str) -> dict:
"""One-line summary ending with a period.

Parameters:
param (str): Description of the parameter.

Returns:
dict: Description of the return value.

Raises:
ValueError: If param is empty.
"""

Communication
-------------

- **Bugs and feature requests**: `GitHub Issues <https://github.com/openMetadataInitiative/bids2openminds/issues>`_
- **Questions and general discussion**: `GitHub Discussions <https://github.com/openMetadataInitiative/bids2openminds/discussions>`_

Deprecation policy
------------------

When a feature is to be removed:

1. Add a ``DeprecationWarning`` in the current release pointing to the replacement.
2. Document the deprecation in ``CHANGES.rst``.
3. Remove the feature in the next minor (or major) release.

Code of Conduct
---------------

This project follows the `openMINDS Code of Conduct
<https://github.com/openMetadataInitiative/bids2openminds/blob/main/CODE_OF_CONDUCT.md>`_.
All participants are expected to uphold its standards.
3 changes: 3 additions & 0 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,7 @@ We are currently supporting Linux, Windows and Mac OS.
.. toctree::
installation
usage
architecture
contributing
maintenance
changelog
6 changes: 4 additions & 2 deletions docs/source/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ Installation
Dependencies
############

- `pybids` : Python tools for querying and manipulating BIDS datasets.
- `openminds` : Python package for the openMINDS metadata models. The package contains all openMINDS schemas as Python classes in addition to schema base classes and utility methods.
- `ancpbids` : Python tools for querying BIDS datasets.
- `openminds` : Python package for the openMINDS metadata models. The package contains all openMINDS schemas as Python classes in addition to schema base classes, utility methods, and the library of openMINDS terminologies.
- `nameparser` : A simple Python module for parsing human names into their individual components.
- `pandas` : Flexible and powerful data analysis / manipulation library for Python, providing labeled data structures similar to R data.frame objects, statistical functions, and much more
Comment thread
apdavison marked this conversation as resolved.
Resolved
- `PyYAML` : PyYAML is a YAML parser and emitter for Python.
- `click` : Used to create a command-line interface for this function.
- `nameparser` : A simple Python module for parsing human names into their individual components.

Expand Down
Loading
Loading