Skip to content

paths

tit.paths

TI-Toolbox Path Management Centralized path management for the entire TI-Toolbox codebase.

Usage

from tit.paths import PathManager, get_path_manager

pm = get_path_manager() subjects = pm.list_simnibs_subjects() m2m_dir = pm.m2m("001") sim_dir = pm.simulation("001", "montage1")

PathManager

PathManager(project_dir: str | None = None)

Centralized BIDS-compliant path management for TI-Toolbox.

Source code in tit/paths.py
def __init__(self, project_dir: str | None = None):
    self._project_dir: str | None = None
    if project_dir:
        self.project_dir = project_dir

project_dir property writable

project_dir: str | None

Get/set the project directory. Auto-detects from environment if unset.

project_dir_name property

project_dir_name: str | None

Return the basename of project_dir.

ensure

ensure(path: str) -> str

Create directory (with parents) and return path.

Source code in tit/paths.py
def ensure(self, path: str) -> str:
    """Create directory (with parents) and return path."""
    os.makedirs(path, exist_ok=True)
    return path

list_simnibs_subjects

list_simnibs_subjects() -> list[str]

List subject IDs (without 'sub-' prefix) that have an m2m folder.

Source code in tit/paths.py
def list_simnibs_subjects(self) -> list[str]:
    """List subject IDs (without 'sub-' prefix) that have an m2m folder."""
    simnibs_dir = self.simnibs() if self.project_dir else None
    if not simnibs_dir or not os.path.isdir(simnibs_dir):
        return []

    subjects = []
    for item in os.listdir(simnibs_dir):
        if not item.startswith(const.PREFIX_SUBJECT):
            continue
        sid = item.replace(const.PREFIX_SUBJECT, "", 1)
        if os.path.isdir(self.m2m(sid)):
            subjects.append(sid)

    subjects.sort(
        key=lambda x: [
            int(c) if c.isdigit() else c.lower() for c in re.split("([0-9]+)", x)
        ]
    )
    return subjects

list_simulations

list_simulations(sid: str) -> list[str]

List simulation folder names for a subject.

Source code in tit/paths.py
def list_simulations(self, sid: str) -> list[str]:
    """List simulation folder names for a subject."""
    sim_root = self.simulations(sid)

    try:
        simulations: list[str] = []
        with os.scandir(sim_root) as it:
            for entry in it:
                if entry.is_dir() and not entry.name.startswith("."):
                    simulations.append(entry.name)
        simulations.sort()
        return simulations
    except OSError:
        return []

list_eeg_caps

list_eeg_caps(sid: str) -> list[str]

List EEG cap CSV files for a subject.

Source code in tit/paths.py
def list_eeg_caps(self, sid: str) -> list[str]:
    """List EEG cap CSV files for a subject."""
    eeg_pos_dir = self.eeg_positions(sid) if self.project_dir else None
    if not eeg_pos_dir or not os.path.isdir(eeg_pos_dir):
        return []

    caps = [
        f
        for f in os.listdir(eeg_pos_dir)
        if f.endswith(const.EXT_CSV) and not f.startswith(".")
    ]
    caps.sort()
    return caps

list_flex_search_runs

list_flex_search_runs(sid: str) -> list[str]

List flex-search run folders that contain flex_meta.json or electrode_positions.json.

Source code in tit/paths.py
def list_flex_search_runs(self, sid: str) -> list[str]:
    """List flex-search run folders that contain flex_meta.json or electrode_positions.json."""
    root = self.flex_search(sid) if self.project_dir else None
    if not root or not os.path.isdir(root):
        return []

    try:
        out: list[str] = []
        with os.scandir(root) as it:
            for entry in it:
                if not entry.is_dir() or entry.name.startswith("."):
                    continue
                if os.path.isfile(
                    os.path.join(entry.path, "flex_meta.json")
                ) or os.path.isfile(
                    os.path.join(entry.path, "electrode_positions.json")
                ):
                    out.append(entry.name)
        out.sort()
        return out
    except OSError:
        return []

spherical_analysis_name staticmethod

spherical_analysis_name(x: float, y: float, z: float, radius: float, coordinate_space: str) -> str

Return folder name for a spherical analysis.

Source code in tit/paths.py
@staticmethod
def spherical_analysis_name(
    x: float, y: float, z: float, radius: float, coordinate_space: str
) -> str:
    """Return folder name for a spherical analysis."""
    coord_space_suffix = (
        "_MNI" if str(coordinate_space).upper() == "MNI" else "_subject"
    )
    return f"sphere_x{x:.2f}_y{y:.2f}_z{z:.2f}_r{float(radius)}{coord_space_suffix}"

cortical_analysis_name classmethod

cortical_analysis_name(*, whole_head: bool, region: str | None, atlas_name: str | None = None, atlas_path: str | None = None) -> str

Return folder name for a cortical analysis.

Source code in tit/paths.py
@classmethod
def cortical_analysis_name(
    cls,
    *,
    whole_head: bool,
    region: str | None,
    atlas_name: str | None = None,
    atlas_path: str | None = None,
) -> str:
    """Return folder name for a cortical analysis."""
    atlas_clean = cls._atlas_name_clean(atlas_name or atlas_path or "unknown_atlas")
    if whole_head:
        return f"whole_head_{atlas_clean}"
    region_val = str(region or "").strip()
    if not region_val:
        raise ValueError(
            "region is required for cortical analysis unless whole_head=True"
        )
    return f"region_{region_val}_{atlas_clean}"

analysis_output_dir

analysis_output_dir(*, sid: str, sim: str, space: str, analysis_type: str, tissue_type: str | None = None, coordinates=None, radius=None, coordinate_space: str = 'subject', whole_head: bool = False, region: str | None = None, atlas_name: str | None = None, atlas_path: str | None = None) -> str

Return analysis output directory path (does not create it).

Source code in tit/paths.py
def analysis_output_dir(
    self,
    *,
    sid: str,
    sim: str,
    space: str,
    analysis_type: str,
    tissue_type: str | None = None,
    coordinates=None,
    radius=None,
    coordinate_space: str = "subject",
    whole_head: bool = False,
    region: str | None = None,
    atlas_name: str | None = None,
    atlas_path: str | None = None,
) -> str:
    """Return analysis output directory path (does not create it)."""
    base = self.analysis_dir(sid, sim, space)
    at = str(analysis_type).lower()
    if at == "spherical":
        if not coordinates or len(coordinates) != 3 or radius is None:
            raise ValueError(
                "coordinates(3) and radius required for spherical analysis"
            )
        name = self.spherical_analysis_name(
            float(coordinates[0]),
            float(coordinates[1]),
            float(coordinates[2]),
            float(radius),
            coordinate_space,
        )
    else:
        name = self.cortical_analysis_name(
            whole_head=bool(whole_head),
            region=region,
            atlas_name=atlas_name,
            atlas_path=atlas_path,
        )
    if str(space).lower() == "voxel":
        tissue = str(tissue_type or "GM").strip().lower()
        if tissue in {"gm", "wm", "both"}:
            name = f"{name}_{tissue}"
    return os.path.join(base, name)

get_path_manager

get_path_manager(project_dir: str | None = None) -> PathManager

Return the global PathManager singleton.

Source code in tit/paths.py
def get_path_manager(project_dir: str | None = None) -> PathManager:
    """Return the global PathManager singleton."""
    global _path_manager_instance
    if _path_manager_instance is None:
        _path_manager_instance = PathManager()
    if project_dir is not None:
        _path_manager_instance.project_dir = project_dir
    return _path_manager_instance

reset_path_manager

reset_path_manager() -> None

Reset the singleton so the next call to get_path_manager creates a fresh instance.

Source code in tit/paths.py
def reset_path_manager() -> None:
    """Reset the singleton so the next call to get_path_manager creates a fresh instance."""
    global _path_manager_instance
    _path_manager_instance = None