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

Update to match neurodatascience/nipoppy:main #96

Merged
merged 1 commit into from
May 23, 2024
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
2 changes: 1 addition & 1 deletion .flake8
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ exclude =
venv,
per-file-ignores =
# - docstrings rules that should not be applied to tests
**/test_*: D100, D103, D104
**/test_*: D100, D101, D103, D104
__init__.py:F401
# allow "weird indentation"
tests/test_workflow_*.py: D100, D103, D104, E131, E127, E501
Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/run_tests_new.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ jobs:

runs-on: ubuntu-latest

strategy:
matrix:
python-version: ["3.9", "3.10", "3.11", "3.12"]

# only trigger on upstream repo
if: github.repository_owner == 'neurodatascience' && github.event.repository.name == 'nipoppy'

Expand All @@ -29,7 +33,7 @@ jobs:

- uses: actions/setup-python@v4
with:
python-version: '3.11'
python-version: ${{ matrix.python-version }}

- name: Install package
run: |
Expand Down
3 changes: 3 additions & 0 deletions nipoppy_cli/docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@
("py:class", "argparse.HelpFormatter"),
("py:class", "argparse._SubParsersAction"),
("py:class", "argparse._ActionsContainer"),
("py:class", "StrOrPathLike"),
("py:class", "nipoppy.utils.StrOrPathLike"),
("py:class", "typing_extensions.Self"),
]

# -- Copybutton configuration -------------------------------------------------
Expand Down
13 changes: 7 additions & 6 deletions nipoppy_cli/nipoppy/config/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from pydantic import BaseModel, ConfigDict, Field

from nipoppy.logger import get_logger
from nipoppy.utils import StrOrPathLike

# Apptainer
APPTAINER_BIND_FLAG = "--bind"
Expand Down Expand Up @@ -53,8 +54,8 @@ class ContainerConfig(BaseModel):

def add_bind_path(
self,
path_local: str | Path,
path_inside_container: Optional[str | Path] = None,
path_local: StrOrPathLike,
path_inside_container: Optional[StrOrPathLike] = None,
mode: str = "rw",
):
"""Add a bind path."""
Expand Down Expand Up @@ -100,8 +101,8 @@ def get_container_config(self) -> ContainerConfig:

def add_bind_path_to_args(
args: list[str],
path_local: str | Path,
path_inside_container: Optional[str | Path] = None,
path_local: StrOrPathLike,
path_inside_container: Optional[StrOrPathLike] = None,
mode: Optional[str] = "rw",
):
"""Add a bind path to the container arguments.
Expand All @@ -110,10 +111,10 @@ def add_bind_path_to_args(
----------
args : list[str]
Existing arguments
path_local : str | Path
path_local : nipoppy.utils.StrOrPathLike
Path on disk. If this is a relative path or contains symlinks,
it will be resolved
path_inside_container : Optional[str | Path], optional
path_inside_container : Optional[nipoppy.utils.StrOrPathLike], optional
Path inside the container (if None, will be the same as the local path),
by default None
mode : str, optional
Expand Down
13 changes: 8 additions & 5 deletions nipoppy_cli/nipoppy/config/main.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
"""Dataset configuration."""

from __future__ import annotations

from pathlib import Path
from typing import Any, Optional, Self
from typing import Any, Optional

from pydantic import ConfigDict, Field, model_validator
from typing_extensions import Self

from nipoppy.config.container import ModelWithContainerConfig
from nipoppy.config.pipeline import PipelineConfig
from nipoppy.utils import check_session, load_json
from nipoppy.utils import StrOrPathLike, check_session, load_json


class Config(ModelWithContainerConfig):
Expand Down Expand Up @@ -106,12 +109,12 @@ def get_bids_pipeline_config(
f"{pipeline_name} {pipeline_version} {pipeline_step}"
)

def save(self, fpath: str | Path, **kwargs):
def save(self, fpath: StrOrPathLike, **kwargs):
"""Save the config to a JSON file.

Parameters
----------
fpath : str | Path
fpath : nipoppy.utils.StrOrPathLike
Path to the JSON file to write
"""
fpath = Path(fpath)
Expand All @@ -122,6 +125,6 @@ def save(self, fpath: str | Path, **kwargs):
file.write(self.model_dump_json(**kwargs))

@classmethod
def load(cls, path: str | Path) -> Self:
def load(cls, path: StrOrPathLike) -> Self:
"""Load a dataset configuration."""
return cls(**load_json(path))
2 changes: 2 additions & 0 deletions nipoppy_cli/nipoppy/config/pipeline.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"""Pipeline configuration."""

from __future__ import annotations

import re
from pathlib import Path
from typing import Optional, Sequence
Expand Down
24 changes: 18 additions & 6 deletions nipoppy_cli/nipoppy/layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@
from pydantic import BaseModel, ConfigDict, Field

from nipoppy.base import Base
from nipoppy.utils import FPATH_DEFAULT_LAYOUT, get_pipeline_tag, load_json
from nipoppy.utils import (
FPATH_DEFAULT_LAYOUT,
StrOrPathLike,
get_pipeline_tag,
load_json,
)


class PathInfo(BaseModel):
Expand Down Expand Up @@ -129,17 +134,24 @@ class DatasetLayout(Base):
"""File/directory structure for a specific dataset."""

def __init__(
self, dpath_root: Path | str, fpath_config: Optional[Path | str] = None
self,
dpath_root: StrOrPathLike,
fpath_config: Optional[StrOrPathLike] = None,
):
"""Initialize the object.

Parameters
----------
dataset_root: Path | str
dpath_root : nipoppy.utils.StrOrPathLike
Path to the root directory of the dataset.
fpath_config: Path | str | None
Path to layout config to use, by default None.
fpath_config : Optional[nipoppy.utils.StrOrPathLike], optional
Path to the layout config to use, by default None.
If None, the default layout will be used.

Raises
------
FileNotFoundError
If ``fpath_config`` does not exist.
"""
# use the default layout if none is specified
if fpath_config is None:
Expand Down Expand Up @@ -187,7 +199,7 @@ def __init__(
self.dname_pipeline_work = "work"
self.dname_pipeline_output = "output"

def get_full_path(self, path: str | Path) -> Path:
def get_full_path(self, path: StrOrPathLike) -> Path:
"""Build a full path from a relative path."""
return self.dpath_root / path

Expand Down
4 changes: 3 additions & 1 deletion nipoppy_cli/nipoppy/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

from rich.logging import RichHandler

from nipoppy.utils import StrOrPathLike

DATE_FORMAT = "[%Y-%m-%d %X]"
FORMAT_RICH = "%(message)s"
FORMAT_FILE = "%(asctime)s %(levelname)-7s %(message)s"
Expand All @@ -23,7 +25,7 @@ def get_logger(name: Optional[str] = None, level: int = logging.INFO) -> logging
return logging.getLogger(name=name)


def add_logfile(logger: logging.Logger, fpath_log: Path | str) -> None:
def add_logfile(logger: logging.Logger, fpath_log: StrOrPathLike) -> None:
"""Add a file handler to the logger."""
fpath_log = Path(fpath_log)

Expand Down
11 changes: 7 additions & 4 deletions nipoppy_cli/nipoppy/tabular/base.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
"""Generic class for tabular data."""

from __future__ import annotations

import contextlib
from abc import ABC, abstractmethod
from pathlib import Path
from typing import Any, Optional, Self, Sequence
from typing import Any, Optional, Sequence

import pandas as pd
from pydantic import BaseModel, ValidationError, model_validator
from typing_extensions import Self

from nipoppy.utils import save_df_with_backup
from nipoppy.utils import StrOrPathLike, save_df_with_backup


class BaseTabularModel(BaseModel):
Expand Down Expand Up @@ -77,7 +80,7 @@ def model(self) -> type[BaseTabularModel]:
raise NotImplementedError("model must be assigned in subclass")

@classmethod
def load(cls, fpath: str | Path, validate=True, **kwargs) -> Self:
def load(cls, fpath: StrOrPathLike, validate=True, **kwargs) -> Self:
"""Load (and optionally validate) a tabular data file."""
if "dtype" in kwargs:
raise ValueError(
Expand Down Expand Up @@ -190,7 +193,7 @@ def concatenate(self, other: Self, validate=True) -> Self:

def save_with_backup(
self,
fpath_symlink: str | Path,
fpath_symlink: StrOrPathLike,
dname_backups: Optional[str] = None,
use_relative_path=True,
sort=True,
Expand Down
20 changes: 12 additions & 8 deletions nipoppy_cli/nipoppy/tabular/doughnut.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
"""Class for the doughnut file."""

from __future__ import annotations

import logging
from pathlib import Path
from typing import Optional, Self
from typing import Optional

from pydantic import Field
from typing_extensions import Self

from nipoppy.logger import get_logger
from nipoppy.tabular.manifest import Manifest, ManifestModel
from nipoppy.utils import (
FIELD_DESCRIPTION_MAP,
StrOrPathLike,
participant_id_to_bids_id,
participant_id_to_dicom_id,
)
Expand Down Expand Up @@ -145,17 +149,17 @@ def get_bidsified_participants_sessions(

def generate_doughnut(
manifest: Manifest,
dpath_downloaded: Optional[str | Path] = None,
dpath_organized: Optional[str | Path] = None,
dpath_bidsified: Optional[str | Path] = None,
dpath_downloaded: Optional[StrOrPathLike] = None,
dpath_organized: Optional[StrOrPathLike] = None,
dpath_bidsified: Optional[StrOrPathLike] = None,
empty=False,
logger: Optional[logging.Logger] = None,
# TODO allow custom map from participant_id to participant_dicom_dir
) -> Doughnut:
"""Generate a doughnut object."""

def check_status(
dpath: Optional[str | Path],
dpath: Optional[StrOrPathLike],
participant_dname: str,
session: str,
session_first=False,
Expand Down Expand Up @@ -242,9 +246,9 @@ def check_status(
def update_doughnut(
doughnut: Doughnut,
manifest: Manifest,
dpath_downloaded: Optional[str | Path] = None,
dpath_organized: Optional[str | Path] = None,
dpath_bidsified: Optional[str | Path] = None,
dpath_downloaded: Optional[StrOrPathLike] = None,
dpath_organized: Optional[StrOrPathLike] = None,
dpath_bidsified: Optional[StrOrPathLike] = None,
empty=False,
logger: Optional[logging.Logger] = None,
) -> Doughnut:
Expand Down
5 changes: 4 additions & 1 deletion nipoppy_cli/nipoppy/tabular/manifest.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
"""Class for the dataset manifest."""

from typing import Optional, Self
from __future__ import annotations

from typing import Optional

import pandas as pd
from pydantic import ConfigDict, Field
from typing_extensions import Self

from nipoppy.tabular.base import BaseTabular, BaseTabularModel
from nipoppy.utils import FIELD_DESCRIPTION_MAP
Expand Down
Loading
Loading