Core Utilities
TI-Toolbox provides opinionated, BIDS-compliant infrastructure for path resolution, logging, constants, and config serialization. These modules enforce a strict project structure so that all pipeline stages produce consistent, discoverable outputs.
graph LR
IMPORT(["import tit"]) --> LOG[Logger]
IMPORT --> PM[PathManager]
IMPORT --> CONFIG[Config IO]
PM --> PATHS([BIDS Paths])
LOG --> FILE([File Logs])
CONFIG --> JSON([JSON Files])
JSON --> CLI[CLI Subprocesses]
style IMPORT fill:#1a3a5c,stroke:#48a,color:#fff
style LOG fill:#2d5a27,stroke:#4a8,color:#fff
style PM fill:#2d5a27,stroke:#4a8,color:#fff
style CONFIG fill:#2d5a27,stroke:#4a8,color:#fff
style CLI fill:#2d5a27,stroke:#4a8,color:#fff
style PATHS fill:#1a5c4a,stroke:#4a8,color:#fff
style FILE fill:#1a5c4a,stroke:#4a8,color:#fff
style JSON fill:#1a5c4a,stroke:#4a8,color:#fff
Initialization
Just import — logging and path resolution are automatic:
from tit.sim import SimulationConfig, run_simulation
Importing any tit module configures the tit logger hierarchy and attaches a stdout handler at INFO level. PathManager auto-detects the project directory from the PROJECT_DIR or PROJECT_DIR_NAME environment variables inside Docker containers. No explicit initialization calls are needed.
PathManager
PathManager is a singleton that enforces the BIDS directory layout. All modules use it instead of constructing paths manually.
Project-Level Paths
These methods take no arguments and return top-level directories or files:
| Method |
Returns |
pm.derivatives() |
<project>/derivatives |
pm.sourcedata() |
<project>/sourcedata |
pm.simnibs() |
<project>/derivatives/SimNIBS |
pm.freesurfer() |
<project>/derivatives/freesurfer |
pm.ti_toolbox() |
<project>/derivatives/ti-toolbox |
pm.config_dir() |
<project>/code/ti-toolbox/config |
pm.montage_config() |
<project>/code/ti-toolbox/config/montage_list.json |
pm.project_status() |
<project>/code/ti-toolbox/config/project_status.json |
pm.reports() |
<project>/derivatives/ti-toolbox/reports |
pm.stats_data() |
<project>/derivatives/ti-toolbox/stats/data |
pm.qsiprep() |
<project>/derivatives/qsiprep |
pm.qsirecon() |
<project>/derivatives/qsirecon |
Subject-Level Paths
Methods that accept a subject ID (sid) string without the sub- prefix:
| Method |
Returns |
pm.sub("001") |
<simnibs>/sub-001 |
pm.m2m("001") |
<simnibs>/sub-001/m2m_001 |
pm.t1("001") |
.../m2m_001/T1.nii.gz |
pm.segmentation("001") |
.../m2m_001/segmentation |
pm.tissue_labeling("001") |
.../segmentation/labeling.nii.gz |
pm.eeg_positions("001") |
.../m2m_001/eeg_positions |
pm.rois("001") |
.../m2m_001/ROIs |
pm.simulations("001") |
<simnibs>/sub-001/Simulations |
pm.leadfields("001") |
<simnibs>/sub-001/leadfields |
pm.ex_search("001") |
<simnibs>/sub-001/ex-search |
pm.flex_search("001") |
<simnibs>/sub-001/flex-search |
pm.logs("001") |
<ti-toolbox>/logs/sub-001 |
pm.tissue_analysis_output("001") |
<ti-toolbox>/tissue_analysis/sub-001 |
pm.bids_subject("001") |
<project>/sub-001 |
pm.bids_anat("001") |
<project>/sub-001/anat |
pm.bids_dwi("001") |
<project>/sub-001/dwi |
pm.freesurfer_subject("001") |
<freesurfer>/sub-001 |
pm.freesurfer_mri("001") |
<freesurfer>/sub-001/mri |
pm.sourcedata_subject("001") |
<sourcedata>/sub-001 |
pm.qsiprep_subject("001") |
<qsiprep>/sub-001 |
pm.qsirecon_subject("001") |
<qsirecon>/sub-001 |
Simulation-Level Paths
Methods that accept a subject ID and simulation name:
| Method |
Returns |
pm.simulation("001", "motor") |
.../Simulations/motor |
pm.ti_mesh("001", "motor") |
.../TI/mesh/motor_TI.msh |
pm.ti_mesh_dir("001", "motor") |
.../TI/mesh |
pm.ti_central_surface("001", "motor") |
.../TI/mesh/surfaces/motor_TI_central.msh |
pm.mti_mesh_dir("001", "motor") |
.../mTI/mesh |
pm.analysis_dir("001", "motor", "mesh") |
.../Analyses/Mesh |
pm.analysis_dir("001", "motor", "voxel") |
.../Analyses/Voxel |
Additional paths for optimization runs and statistics:
| Method |
Returns |
pm.flex_search_run("001", "run_01") |
.../flex-search/run_01 |
pm.flex_manifest("001", "run_01") |
.../flex-search/run_01/flex_meta.json |
pm.flex_electrode_positions("001", "run_01") |
.../flex-search/run_01/electrode_positions.json |
pm.ex_search_run("001", "run_01") |
.../ex-search/run_01 |
pm.sourcedata_dicom("001", "anat") |
<sourcedata>/sub-001/anat/dicom |
pm.stats_output("group_comparison", "motor_study") |
<ti-toolbox>/stats/group_comparison/motor_study |
pm.logs_group() |
<ti-toolbox>/logs/group_analysis |
Listing Methods
pm.list_simnibs_subjects() # ["001", "002"] — subjects with m2m folders
pm.list_simulations("001") # ["motor_cortex", "frontal"]
pm.list_eeg_caps("001") # ["GSN-HydroCel-185.csv"]
pm.list_flex_search_runs("001") # ["run_01"] — runs with metadata files
Utility
pm.ensure("/some/path") # creates directory (with parents) and returns the path
Logging
TI-Toolbox logging is file-first. The tit logger hierarchy has propagate=False, so nothing reaches the terminal unless you explicitly opt in.
| Function |
Purpose |
setup_logging(level) |
Configure the tit logger level; adds NO handlers |
add_file_handler(log_file, level, logger_name) |
Attach a FileHandler (append mode); creates parent dirs |
add_stream_handler(logger_name, level) |
Attach a StreamHandler (stdout) |
get_file_only_logger(name, log_file, level) |
Return a logger that writes ONLY to the given file |
Typical Patterns
Terminal output (automatic on import — nothing to do):
import tit # auto-initializes: setup_logging("INFO") + add_stream_handler("tit", "INFO")
File logging (opt-in, used by pipeline modules):
from tit import add_file_handler
fh = add_file_handler("/data/logs/run.log", level="DEBUG")
Isolated file logger (used per-analysis):
from tit.logger import get_file_only_logger
log = get_file_only_logger("roi_analysis", "/data/logs/roi.log")
log.info("Analyzing ROI...")
File handlers:
2025-01-15 14:30:00 | INFO | tit.sim.simulator | Simulation started
Stream handlers use minimal format: %(message)s.
Constants
All hardcoded values live in tit.constants. Key categories:
| Category |
Examples |
| Directory names |
DIR_DERIVATIVES, DIR_SIMNIBS, DIR_FLEX_SEARCH, DIR_ANALYSIS |
| File names |
FILE_MONTAGE_LIST, FILE_T1, FILE_EGI_TEMPLATE |
| File extensions |
EXT_NIFTI (.nii.gz), EXT_MESH (.msh), EXT_CSV |
| BIDS prefixes |
PREFIX_SUBJECT (sub-), PREFIX_SESSION (ses-) |
| Field names |
FIELD_TI_MAX (TI_max), FIELD_MTI_MAX (TI_Max), FIELD_TI_NORMAL (TI_normal) |
| Tissue tags |
GM_TISSUE_TAG (2), WM_TISSUE_TAG (1), BRAIN_TISSUE_TAG_RANGES |
| Conductivities |
CONDUCTIVITY_GRAY_MATTER (0.275 S/m), CONDUCTIVITY_WHITE_MATTER (0.126 S/m), 12 tissues total |
| Tissue properties |
TISSUE_PROPERTIES — list of dicts with number, name, conductivity, and reference |
| Atlas names |
ATLAS_DK40, ATLAS_A2009S, ATLAS_ASEG, ATLAS_APARC_ASEG |
| Analysis defaults |
DEFAULT_PERCENTILES ([95, 99, 99.9]), DEFAULT_FOCALITY_CUTOFFS ([50, 75, 90, 95]), DEFAULT_RADIUS_MM (5.0) |
| Simulation |
SIM_TYPE_TI, SIM_TYPE_MTI, ELECTRODE_SHAPE_ELLIPSE, DEFAULT_INTENSITY (1.0) |
| EEG nets |
EEG_NETS — list of dicts with value, label, electrode_count |
| Validation bounds |
VALIDATION_BOUNDS — min/max for radius, current, iterations, etc. |
| Plot settings |
PLOT_DPI (600), PLOT_FIGSIZE_DEFAULT ((10, 8)) |
| Timestamps |
TIMESTAMP_FORMAT_DEFAULT (%Y%m%d_%H%M%S), TIMESTAMP_FORMAT_READABLE |
| QSI integration |
QSI_RECON_SPECS, QSI_ATLASES, QSI_DEFAULT_CPUS (8) |
from tit import constants as const
const.FIELD_TI_MAX # "TI_max"
const.GM_TISSUE_TAG # 2
const.DEFAULT_RADIUS_MM # 5.0
const.TISSUE_PROPERTIES # [{"number": 1, "name": "White Matter", ...}, ...]
Config IO
The tit.config_io module serializes typed config dataclasses to JSON for CLI subprocesses. This is the mechanism the GUI uses to pass configurations to optimizer and analyzer processes.
from tit.config_io import write_config_json, read_config_json
# Write: dataclass -> temp JSON file, returns path
path = write_config_json(my_flex_config, prefix="flex")
# Read: JSON file -> plain dict
data = read_config_json(path)
Union-typed fields (ROI specs, electrode specs) get a _type discriminator so the subprocess can reconstruct the correct type:
| Class |
_type value |
FlexConfig.SphericalROI |
"SphericalROI" |
FlexConfig.AtlasROI |
"AtlasROI" |
FlexConfig.SubcorticalROI |
"SubcorticalROI" |
ExConfig.PoolElectrodes |
"PoolElectrodes" |
ExConfig.BucketElectrodes |
"BucketElectrodes" |
Montage |
"Montage" |
Error Handling
Custom exceptions are defined in domain-specific modules:
| Exception |
Module |
Base Class |
When Raised |
PreprocessError |
tit.pre.utils |
RuntimeError |
A preprocessing step fails |
PreprocessCancelled |
tit.pre.utils |
RuntimeError |
User cancels a preprocessing run |
DockerBuildError |
tit.pre.qsi.docker_builder |
Exception |
Docker command construction fails |
from tit.pre.utils import PreprocessError, PreprocessCancelled
try:
run_pipeline(config)
except PreprocessCancelled:
print("Pipeline was cancelled")
except PreprocessError as e:
print(f"Pipeline failed: {e}")
API Reference
Path Management
tit.paths.PathManager
PathManager(project_dir: str | None = None)
BIDS-compliant path resolution for TI-Toolbox projects.
Provides methods to resolve file and directory paths within a
BIDS-structured project, including subject anatomical data, SimNIBS
derivatives, FreeSurfer outputs, optimization runs, and analysis results.
The project directory can be set explicitly or auto-detected from the
PROJECT_DIR / PROJECT_DIR_NAME environment variables (useful
inside Docker containers).
Parameters
project_dir : str or None, optional
Root directory of the BIDS project. If None, the directory is
auto-detected from environment variables on first access.
Attributes
project_dir : str or None
Resolved project root, or None if not yet set / detected.
project_dir_name : str or None
Basename of :attr:project_dir.
See Also
get_path_manager : Obtain the global singleton instance.
reset_path_manager : Destroy the singleton for testing or re-init.
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 root directory, auto-detected from environment if unset.
project_dir_name
property
project_dir_name: str | None
Basename of :attr:project_dir, or the PROJECT_DIR_NAME env var.
derivatives
Path to <project>/derivatives/.
Source code in tit/paths.py
| def derivatives(self) -> str:
"""Path to ``<project>/derivatives/``."""
return os.path.join(self._root(), "derivatives")
|
sourcedata
Path to <project>/sourcedata/.
Source code in tit/paths.py
| def sourcedata(self) -> str:
"""Path to ``<project>/sourcedata/``."""
return os.path.join(self._root(), "sourcedata")
|
simnibs
Path to <project>/derivatives/SimNIBS/.
Source code in tit/paths.py
| def simnibs(self) -> str:
"""Path to ``<project>/derivatives/SimNIBS/``."""
return os.path.join(self._root(), "derivatives", "SimNIBS")
|
freesurfer
Path to <project>/derivatives/freesurfer/.
Source code in tit/paths.py
| def freesurfer(self) -> str:
"""Path to ``<project>/derivatives/freesurfer/``."""
return os.path.join(self._root(), "derivatives", "freesurfer")
|
Path to <project>/derivatives/ti-toolbox/.
Source code in tit/paths.py
| def ti_toolbox(self) -> str:
"""Path to ``<project>/derivatives/ti-toolbox/``."""
return os.path.join(self._root(), "derivatives", "ti-toolbox")
|
config_dir
Path to <project>/code/ti-toolbox/config/.
Source code in tit/paths.py
| def config_dir(self) -> str:
"""Path to ``<project>/code/ti-toolbox/config/``."""
return os.path.join(self._root(), "code", "ti-toolbox", "config")
|
montage_config
Path to the montage_list.json configuration file.
Source code in tit/paths.py
| def montage_config(self) -> str:
"""Path to the ``montage_list.json`` configuration file."""
return os.path.join(self.config_dir(), "montage_list.json")
|
project_status
Path to the project_status.json file.
Source code in tit/paths.py
| def project_status(self) -> str:
"""Path to the ``project_status.json`` file."""
return os.path.join(self.config_dir(), "project_status.json")
|
extensions_config
extensions_config() -> str
Path to the extensions.json configuration file.
Uses the user-level config directory so that extension
preferences persist across projects and container restarts.
Source code in tit/paths.py
| def extensions_config(self) -> str:
"""Path to the ``extensions.json`` configuration file.
Uses the user-level config directory so that extension
preferences persist across projects and container restarts.
"""
return os.path.join(self.user_config_dir(), "extensions.json")
|
user_config_dir
staticmethod
Path to the user-level config directory.
Returns the directory that persists across projects and container
restarts. Inside Docker this is /root/.config/ti-toolbox
(mounted from the host by the Electron launcher). Outside Docker
the platform-native config directory is used:
- macOS:
~/.config/ti-toolbox
- Linux:
$XDG_CONFIG_HOME/ti-toolbox (default ~/.config)
- Windows:
%APPDATA%/ti-toolbox
The directory is created if it does not exist.
Returns
str
Absolute path to the user config directory.
Source code in tit/paths.py
| @staticmethod
def user_config_dir() -> str:
"""Path to the user-level config directory.
Returns the directory that persists across projects and container
restarts. Inside Docker this is ``/root/.config/ti-toolbox``
(mounted from the host by the Electron launcher). Outside Docker
the platform-native config directory is used:
- **macOS**: ``~/.config/ti-toolbox``
- **Linux**: ``$XDG_CONFIG_HOME/ti-toolbox`` (default ``~/.config``)
- **Windows**: ``%APPDATA%/ti-toolbox``
The directory is created if it does not exist.
Returns
-------
str
Absolute path to the user config directory.
"""
import platform as _platform
import sys as _sys
# Inside Docker the Electron launcher mounts the host config here.
docker_path = os.path.join("/root", ".config", "ti-toolbox")
if os.path.isdir(docker_path):
return docker_path
# Outside Docker: platform-native paths
system = _platform.system()
if system == "Darwin":
# Use ~/.config (NOT ~/Library/Application Support which is
# Electron's userData dir). Matches env.js getUserConfigDir().
base = os.path.join(os.path.expanduser("~"), ".config")
elif system == "Windows":
base = os.environ.get(
"APPDATA", os.path.join(os.path.expanduser("~"), "AppData", "Roaming")
)
else: # Linux / other
base = os.environ.get(
"XDG_CONFIG_HOME", os.path.join(os.path.expanduser("~"), ".config")
)
config_dir = os.path.join(base, "ti-toolbox")
os.makedirs(config_dir, exist_ok=True)
return config_dir
|
reports
Path to <project>/derivatives/ti-toolbox/reports/.
Source code in tit/paths.py
| def reports(self) -> str:
"""Path to ``<project>/derivatives/ti-toolbox/reports/``."""
return os.path.join(self.ti_toolbox(), "reports")
|
stats_data
Path to <project>/derivatives/ti-toolbox/stats/data/.
Source code in tit/paths.py
| def stats_data(self) -> str:
"""Path to ``<project>/derivatives/ti-toolbox/stats/data/``."""
return os.path.join(self.ti_toolbox(), "stats", "data")
|
stats_output
stats_output(analysis_type: str, analysis_name: str) -> str
Path to a specific statistics output directory.
Parameters
analysis_type : str
Type of statistical analysis (e.g., "permutation").
analysis_name : str
Name of the analysis run.
Returns
str
Absolute path to the output directory.
Source code in tit/paths.py
| def stats_output(self, analysis_type: str, analysis_name: str) -> str:
"""Path to a specific statistics output directory.
Parameters
----------
analysis_type : str
Type of statistical analysis (e.g., ``"permutation"``).
analysis_name : str
Name of the analysis run.
Returns
-------
str
Absolute path to the output directory.
"""
return os.path.join(self.ti_toolbox(), "stats", analysis_type, analysis_name)
|
logs_group
Path to group-analysis log directory.
Source code in tit/paths.py
| def logs_group(self) -> str:
"""Path to group-analysis log directory."""
return os.path.join(self.ti_toolbox(), "logs", "group_analysis")
|
qsiprep
Path to <project>/derivatives/qsiprep/.
Source code in tit/paths.py
| def qsiprep(self) -> str:
"""Path to ``<project>/derivatives/qsiprep/``."""
return os.path.join(self._root(), "derivatives", "qsiprep")
|
qsirecon
Path to <project>/derivatives/qsirecon/.
Source code in tit/paths.py
| def qsirecon(self) -> str:
"""Path to ``<project>/derivatives/qsirecon/``."""
return os.path.join(self._root(), "derivatives", "qsirecon")
|
sub
Path to derivatives/SimNIBS/sub-{sid}/.
Parameters
sid : str
Subject identifier (without sub- prefix).
Returns
str
Absolute path to the subject's SimNIBS directory.
Source code in tit/paths.py
| def sub(self, sid: str) -> str:
"""Path to ``derivatives/SimNIBS/sub-{sid}/``.
Parameters
----------
sid : str
Subject identifier (without ``sub-`` prefix).
Returns
-------
str
Absolute path to the subject's SimNIBS directory.
"""
return os.path.join(self._root(), "derivatives", "SimNIBS", f"sub-{sid}")
|
m2m
Path to the m2m_{sid} head-model directory for sid.
Source code in tit/paths.py
| def m2m(self, sid: str) -> str:
"""Path to the ``m2m_{sid}`` head-model directory for *sid*."""
return os.path.join(self.sub(sid), f"m2m_{sid}")
|
eeg_positions
eeg_positions(sid: str) -> str
Path to the EEG electrode-position directory for sid.
Source code in tit/paths.py
| def eeg_positions(self, sid: str) -> str:
"""Path to the EEG electrode-position directory for *sid*."""
return os.path.join(self.m2m(sid), "eeg_positions")
|
rois
Path to the ROI directory for sid.
Source code in tit/paths.py
| def rois(self, sid: str) -> str:
"""Path to the ROI directory for *sid*."""
return os.path.join(self.m2m(sid), "ROIs")
|
t1
Path to the T1-weighted NIfTI image for sid.
Source code in tit/paths.py
| def t1(self, sid: str) -> str:
"""Path to the T1-weighted NIfTI image for *sid*."""
return os.path.join(self.m2m(sid), "T1.nii.gz")
|
segmentation
Path to the segmentation directory for sid.
Source code in tit/paths.py
| def segmentation(self, sid: str) -> str:
"""Path to the segmentation directory for *sid*."""
return os.path.join(self.m2m(sid), "segmentation")
|
tissue_labeling
tissue_labeling(sid: str) -> str
Path to the tissue labeling NIfTI for sid.
Source code in tit/paths.py
| def tissue_labeling(self, sid: str) -> str:
"""Path to the tissue labeling NIfTI for *sid*."""
return os.path.join(self.segmentation(sid), "labeling.nii.gz")
|
leadfields
Path to the leadfields directory for sid.
Source code in tit/paths.py
| def leadfields(self, sid: str) -> str:
"""Path to the leadfields directory for *sid*."""
return os.path.join(self.sub(sid), "leadfields")
|
simulations
Path to Simulations/ for sid.
Source code in tit/paths.py
| def simulations(self, sid: str) -> str:
"""Path to ``Simulations/`` for *sid*."""
return os.path.join(self.sub(sid), "Simulations")
|
logs
Path to per-subject log directory for sid.
Source code in tit/paths.py
| def logs(self, sid: str) -> str:
"""Path to per-subject log directory for *sid*."""
return os.path.join(self.ti_toolbox(), "logs", f"sub-{sid}")
|
tissue_analysis_output
tissue_analysis_output(sid: str) -> str
Path to tissue-analysis output directory for sid.
Source code in tit/paths.py
| def tissue_analysis_output(self, sid: str) -> str:
"""Path to tissue-analysis output directory for *sid*."""
return os.path.join(self.ti_toolbox(), "tissue_analysis", f"sub-{sid}")
|
bids_subject
Path to <project>/sub-{sid}/ (raw BIDS subject root).
Source code in tit/paths.py
| def bids_subject(self, sid: str) -> str:
"""Path to ``<project>/sub-{sid}/`` (raw BIDS subject root)."""
return os.path.join(self._root(), f"sub-{sid}")
|
bids_anat
Path to <project>/sub-{sid}/anat/.
Source code in tit/paths.py
| def bids_anat(self, sid: str) -> str:
"""Path to ``<project>/sub-{sid}/anat/``."""
return os.path.join(self.bids_subject(sid), "anat")
|
bids_dwi
Path to <project>/sub-{sid}/dwi/.
Source code in tit/paths.py
| def bids_dwi(self, sid: str) -> str:
"""Path to ``<project>/sub-{sid}/dwi/``."""
return os.path.join(self.bids_subject(sid), "dwi")
|
sourcedata_subject
sourcedata_subject(sid: str) -> str
Path to sourcedata/sub-{sid}/.
Source code in tit/paths.py
| def sourcedata_subject(self, sid: str) -> str:
"""Path to ``sourcedata/sub-{sid}/``."""
return os.path.join(self.sourcedata(), f"sub-{sid}")
|
freesurfer_subject
freesurfer_subject(sid: str) -> str
Path to derivatives/freesurfer/sub-{sid}/.
Source code in tit/paths.py
| def freesurfer_subject(self, sid: str) -> str:
"""Path to ``derivatives/freesurfer/sub-{sid}/``."""
return os.path.join(self.freesurfer(), f"sub-{sid}")
|
freesurfer_mri
freesurfer_mri(sid: str) -> str
Path to derivatives/freesurfer/sub-{sid}/mri/.
Source code in tit/paths.py
| def freesurfer_mri(self, sid: str) -> str:
"""Path to ``derivatives/freesurfer/sub-{sid}/mri/``."""
return os.path.join(self.freesurfer_subject(sid), "mri")
|
qsiprep_subject
qsiprep_subject(sid: str) -> str
Path to derivatives/qsiprep/sub-{sid}/.
Source code in tit/paths.py
| def qsiprep_subject(self, sid: str) -> str:
"""Path to ``derivatives/qsiprep/sub-{sid}/``."""
return os.path.join(self.qsiprep(), f"sub-{sid}")
|
qsirecon_subject
qsirecon_subject(sid: str) -> str
Path to derivatives/qsirecon/sub-{sid}/.
Source code in tit/paths.py
| def qsirecon_subject(self, sid: str) -> str:
"""Path to ``derivatives/qsirecon/sub-{sid}/``."""
return os.path.join(self.qsirecon(), f"sub-{sid}")
|
ex_search
Path to exhaustive-search results for sid.
Source code in tit/paths.py
| def ex_search(self, sid: str) -> str:
"""Path to exhaustive-search results for *sid*."""
return os.path.join(self.sub(sid), "ex-search")
|
flex_search
Path to flex-search results for sid.
Source code in tit/paths.py
| def flex_search(self, sid: str) -> str:
"""Path to flex-search results for *sid*."""
return os.path.join(self.sub(sid), "flex-search")
|
simulation
Path to a named simulation directory for sid.
Source code in tit/paths.py
| def simulation(self, sid: str, sim: str) -> str:
"""Path to a named simulation directory for *sid*."""
return os.path.join(self.simulations(sid), sim)
|
ti_mesh
Path to the TI mesh file ({sim}_TI.msh).
Source code in tit/paths.py
| def ti_mesh(self, sid: str, sim: str) -> str:
"""Path to the TI mesh file (``{sim}_TI.msh``)."""
return os.path.join(self.simulation(sid, sim), "TI", "mesh", f"{sim}_TI.msh")
|
ti_mesh_dir
Path to the TI mesh directory.
Source code in tit/paths.py
| def ti_mesh_dir(self, sid: str, sim: str) -> str:
"""Path to the TI mesh directory."""
return os.path.join(self.simulation(sid, sim), "TI", "mesh")
|
ti_central_surface
ti_central_surface(sid: str, sim: str) -> str
Path to the TI central cortical surface mesh.
Source code in tit/paths.py
| def ti_central_surface(self, sid: str, sim: str) -> str:
"""Path to the TI central cortical surface mesh."""
return os.path.join(
self.simulation(sid, sim), "TI", "mesh", "surfaces", f"{sim}_TI_central.msh"
)
|
mti_mesh_dir
Path to the mTI mesh directory.
Source code in tit/paths.py
| def mti_mesh_dir(self, sid: str, sim: str) -> str:
"""Path to the mTI mesh directory."""
return os.path.join(self.simulation(sid, sim), "mTI", "mesh")
|
analysis_dir
Path to the analysis directory for a given analysis space.
Parameters
sid : str
Subject identifier.
sim : str
Simulation name.
space : str
Analysis space — "mesh" or "voxel".
Returns
str
Absolute path to Analyses/Mesh/ or Analyses/Voxel/.
Source code in tit/paths.py
| def analysis_dir(self, sid: str, sim: str, space: str) -> str:
"""Path to the analysis directory for a given analysis space.
Parameters
----------
sid : str
Subject identifier.
sim : str
Simulation name.
space : str
Analysis space — ``"mesh"`` or ``"voxel"``.
Returns
-------
str
Absolute path to ``Analyses/Mesh/`` or ``Analyses/Voxel/``.
"""
folder = "Mesh" if space.lower() == "mesh" else "Voxel"
return os.path.join(self.simulation(sid, sim), "Analyses", folder)
|
sourcedata_dicom
sourcedata_dicom(sid: str, modality: str) -> str
Path to DICOM source data for sid and modality.
Source code in tit/paths.py
| def sourcedata_dicom(self, sid: str, modality: str) -> str:
"""Path to DICOM source data for *sid* and *modality*."""
return os.path.join(self.sourcedata_subject(sid), modality, "dicom")
|
ex_search_run
Path to a specific exhaustive-search run directory.
Source code in tit/paths.py
| def ex_search_run(self, sid: str, run: str) -> str:
"""Path to a specific exhaustive-search run directory."""
return os.path.join(self.ex_search(sid), run)
|
flex_search_run
Path to a specific flex-search run directory.
Source code in tit/paths.py
| def flex_search_run(self, sid: str, name: str) -> str:
"""Path to a specific flex-search run directory."""
return os.path.join(self.flex_search(sid), name)
|
flex_electrode_positions
flex_electrode_positions(sid: str, name: str) -> str
Path to electrode_positions.json for a flex-search run.
Source code in tit/paths.py
| def flex_electrode_positions(self, sid: str, name: str) -> str:
"""Path to ``electrode_positions.json`` for a flex-search run."""
return os.path.join(self.flex_search_run(sid, name), "electrode_positions.json")
|
flex_manifest
Path to flex_meta.json for a flex-search run.
Source code in tit/paths.py
| def flex_manifest(self, sid: str, name: str) -> str:
"""Path to ``flex_meta.json`` for a flex-search run."""
return os.path.join(self.flex_search_run(sid, name), "flex_meta.json")
|
ensure
Create a directory (with parents) if it does not exist.
Parameters
path : str
Directory path to create.
Returns
str
The same path, for convenient chaining.
Source code in tit/paths.py
| def ensure(self, path: str) -> str:
"""Create a directory (with parents) if it does not exist.
Parameters
----------
path : str
Directory path to create.
Returns
-------
str
The same *path*, for convenient chaining.
"""
os.makedirs(path, exist_ok=True)
return path
|
list_simnibs_subjects
list_simnibs_subjects() -> list[str]
List subject IDs that have a SimNIBS head-model (m2m) folder.
Returns
list of str
Naturally sorted subject identifiers (without the sub- prefix).
Returns an empty list if the SimNIBS directory does not exist.
Source code in tit/paths.py
| def list_simnibs_subjects(self) -> list[str]:
"""List subject IDs that have a SimNIBS head-model (m2m) folder.
Returns
-------
list of str
Naturally sorted subject identifiers (without the ``sub-`` prefix).
Returns an empty list if the SimNIBS directory does not exist.
"""
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 simulation folder names for a subject.
Parameters
sid : str
Subject identifier.
Returns
list of str
Alphabetically sorted simulation directory names. Returns an
empty list if the Simulations/ directory does not exist.
Source code in tit/paths.py
| def list_simulations(self, sid: str) -> list[str]:
"""List simulation folder names for a subject.
Parameters
----------
sid : str
Subject identifier.
Returns
-------
list of str
Alphabetically sorted simulation directory names. Returns an
empty list if the ``Simulations/`` directory does not exist.
"""
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 cap CSV filenames for a subject.
Parameters
sid : str
Subject identifier.
Returns
list of str
Sorted CSV filenames found in the eeg_positions/ directory.
Source code in tit/paths.py
| def list_eeg_caps(self, sid: str) -> list[str]:
"""List EEG cap CSV filenames for a subject.
Parameters
----------
sid : str
Subject identifier.
Returns
-------
list of str
Sorted CSV filenames found in the ``eeg_positions/`` directory.
"""
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 run directories containing result metadata.
Only directories that contain flex_meta.json or
electrode_positions.json are included.
Parameters
sid : str
Subject identifier.
Returns
list of str
Sorted run directory names.
Source code in tit/paths.py
| def list_flex_search_runs(self, sid: str) -> list[str]:
"""List flex-search run directories containing result metadata.
Only directories that contain ``flex_meta.json`` or
``electrode_positions.json`` are included.
Parameters
----------
sid : str
Subject identifier.
Returns
-------
list of str
Sorted run directory names.
"""
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
Build a canonical folder name for a spherical ROI analysis.
Parameters
x, y, z : float
Centre coordinates of the sphere (mm).
radius : float
Sphere radius (mm).
coordinate_space : str
"MNI" or "subject".
Returns
str
Folder name, e.g. "sphere_x0.00_y0.00_z0.00_r5.0_MNI".
Source code in tit/paths.py
| @staticmethod
def spherical_analysis_name(
x: float, y: float, z: float, radius: float, coordinate_space: str
) -> str:
"""Build a canonical folder name for a spherical ROI analysis.
Parameters
----------
x, y, z : float
Centre coordinates of the sphere (mm).
radius : float
Sphere radius (mm).
coordinate_space : str
``"MNI"`` or ``"subject"``.
Returns
-------
str
Folder name, e.g. ``"sphere_x0.00_y0.00_z0.00_r5.0_MNI"``.
"""
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
Build a canonical folder name for a cortical/atlas analysis.
Parameters
whole_head : bool
If True, the analysis covers the whole head (no region filter).
region : str or None
Atlas region label(s). Multiple regions are +-separated.
atlas_name : str or None, optional
Human-readable atlas name.
atlas_path : str or None, optional
Filesystem path to the atlas file (used as fallback for naming).
Returns
str
Folder name, e.g. "cortical_precentral_DK40" or
"whole_head_DK40".
Raises
ValueError
If whole_head is False and region is empty or None.
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:
"""Build a canonical folder name for a cortical/atlas analysis.
Parameters
----------
whole_head : bool
If *True*, the analysis covers the whole head (no region filter).
region : str or None
Atlas region label(s). Multiple regions are ``+``-separated.
atlas_name : str or None, optional
Human-readable atlas name.
atlas_path : str or None, optional
Filesystem path to the atlas file (used as fallback for naming).
Returns
-------
str
Folder name, e.g. ``"cortical_precentral_DK40"`` or
``"whole_head_DK40"``.
Raises
------
ValueError
If *whole_head* is *False* and *region* is empty or *None*.
"""
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"
)
if "+" in region_val:
n = len(region_val.split("+"))
h = hashlib.md5(region_val.encode()).hexdigest()[:8]
return f"cortical_{n}regions_{atlas_clean}_{h}"
return f"cortical_{region_val}_{atlas_clean}"
|
analysis_output_dir
analysis_output_dir(*, sid: str, sim: str, space: str, analysis_type: str, 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 the analysis output directory path (does not create it).
Delegates to :meth:spherical_analysis_name or
:meth:cortical_analysis_name depending on analysis_type.
Parameters
sid : str
Subject identifier.
sim : str
Simulation name.
space : str
Analysis space ("mesh" or "voxel").
analysis_type : str
"spherical" or "cortical".
coordinates : sequence of float or None, optional
(x, y, z) centre for spherical analysis.
radius : float or None, optional
Sphere radius in mm (required when analysis_type is
"spherical").
coordinate_space : str, optional
"MNI" or "subject". Default is "subject".
whole_head : bool, optional
Whether cortical analysis covers the whole head.
region : str or None, optional
Atlas region label(s) for cortical analysis.
atlas_name : str or None, optional
Atlas name for cortical analysis.
atlas_path : str or None, optional
Atlas file path for cortical analysis.
Returns
str
Absolute path to the analysis output directory.
Raises
ValueError
If required parameters for the chosen analysis_type are
missing or invalid.
See Also
spherical_analysis_name : Naming convention for spherical ROIs.
cortical_analysis_name : Naming convention for cortical/atlas ROIs.
Source code in tit/paths.py
| def analysis_output_dir(
self,
*,
sid: str,
sim: str,
space: str,
analysis_type: str,
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 the analysis output directory path (does not create it).
Delegates to :meth:`spherical_analysis_name` or
:meth:`cortical_analysis_name` depending on *analysis_type*.
Parameters
----------
sid : str
Subject identifier.
sim : str
Simulation name.
space : str
Analysis space (``"mesh"`` or ``"voxel"``).
analysis_type : str
``"spherical"`` or ``"cortical"``.
coordinates : sequence of float or None, optional
``(x, y, z)`` centre for spherical analysis.
radius : float or None, optional
Sphere radius in mm (required when *analysis_type* is
``"spherical"``).
coordinate_space : str, optional
``"MNI"`` or ``"subject"``. Default is ``"subject"``.
whole_head : bool, optional
Whether cortical analysis covers the whole head.
region : str or None, optional
Atlas region label(s) for cortical analysis.
atlas_name : str or None, optional
Atlas name for cortical analysis.
atlas_path : str or None, optional
Atlas file path for cortical analysis.
Returns
-------
str
Absolute path to the analysis output directory.
Raises
------
ValueError
If required parameters for the chosen *analysis_type* are
missing or invalid.
See Also
--------
spherical_analysis_name : Naming convention for spherical ROIs.
cortical_analysis_name : Naming convention for cortical/atlas ROIs.
"""
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,
)
return os.path.join(base, name)
|
tit.paths.get_path_manager
Return the global :class:PathManager singleton.
Creates a new instance on the first call. If project_dir is provided,
the singleton's :attr:~PathManager.project_dir is (re)set.
Parameters
project_dir : str or None, optional
Project root directory. When None, the existing value (or
environment auto-detection) is used.
Returns
PathManager
The shared singleton instance.
See Also
reset_path_manager : Destroy the singleton for testing or re-init.
Source code in tit/paths.py
| def get_path_manager(project_dir: str | None = None) -> PathManager:
"""Return the global :class:`PathManager` singleton.
Creates a new instance on the first call. If *project_dir* is provided,
the singleton's :attr:`~PathManager.project_dir` is (re)set.
Parameters
----------
project_dir : str or None, optional
Project root directory. When *None*, the existing value (or
environment auto-detection) is used.
Returns
-------
PathManager
The shared singleton instance.
See Also
--------
reset_path_manager : Destroy the singleton for testing or re-init.
"""
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
|
tit.paths.reset_path_manager
reset_path_manager() -> None
Destroy the singleton so the next call creates a fresh instance.
Primarily used in test fixtures to prevent cross-test contamination.
See Also
get_path_manager : Obtain the singleton instance.
Source code in tit/paths.py
| def reset_path_manager() -> None:
"""Destroy the singleton so the next call creates a fresh instance.
Primarily used in test fixtures to prevent cross-test contamination.
See Also
--------
get_path_manager : Obtain the singleton instance.
"""
global _path_manager_instance
_path_manager_instance = None
|
Logging
tit.logger.setup_logging
setup_logging(level: str = 'INFO') -> None
Configure the tit logger hierarchy.
Sets the log level but adds no handlers — file handlers are attached
later via :func:add_file_handler and GUI handlers via Qt signal bridges.
Parameters
level : str, optional
Logging level name (e.g., "DEBUG", "INFO"). Default is
"INFO".
See Also
add_file_handler : Attach a file handler to a named logger.
add_stream_handler : Attach a console handler to a named logger.
Source code in tit/logger.py
| def setup_logging(level: str = "INFO") -> None:
"""Configure the ``tit`` logger hierarchy.
Sets the log level but adds **no** handlers — file handlers are attached
later via :func:`add_file_handler` and GUI handlers via Qt signal bridges.
Parameters
----------
level : str, optional
Logging level name (e.g., ``"DEBUG"``, ``"INFO"``). Default is
``"INFO"``.
See Also
--------
add_file_handler : Attach a file handler to a named logger.
add_stream_handler : Attach a console handler to a named logger.
"""
logger = logging.getLogger("tit")
logger.handlers.clear()
logger.setLevel(getattr(logging, level.upper(), logging.INFO))
logger.propagate = False # never bubble to root/terminal
# Quiet noisy third-party loggers
for name in ("matplotlib", "matplotlib.font_manager", "PIL"):
logging.getLogger(name).setLevel(logging.ERROR)
|
tit.logger.add_file_handler
Attach a file handler to a named logger.
Creates the parent directory if it does not exist. Returns the handler
so callers can remove it when the run completes.
Parameters
log_file : str or pathlib.Path
Path to the log file (opened in append mode).
level : str, optional
Minimum log level for this handler. Default is "DEBUG" so the
file captures everything.
logger_name : str, optional
Logger to attach to. Default is "tit" (the package root).
Returns
logging.FileHandler
The newly created handler.
See Also
setup_logging : Set the package-wide log level.
add_stream_handler : Attach a console (stdout) handler.
get_file_only_logger : Create an isolated file-only logger.
Source code in tit/logger.py
| def add_file_handler(
log_file: str | Path,
level: str = "DEBUG",
logger_name: str = "tit",
) -> logging.FileHandler:
"""Attach a file handler to a named logger.
Creates the parent directory if it does not exist. Returns the handler
so callers can remove it when the run completes.
Parameters
----------
log_file : str or pathlib.Path
Path to the log file (opened in append mode).
level : str, optional
Minimum log level for this handler. Default is ``"DEBUG"`` so the
file captures everything.
logger_name : str, optional
Logger to attach to. Default is ``"tit"`` (the package root).
Returns
-------
logging.FileHandler
The newly created handler.
See Also
--------
setup_logging : Set the package-wide log level.
add_stream_handler : Attach a console (stdout) handler.
get_file_only_logger : Create an isolated file-only logger.
"""
log_file = Path(log_file)
log_file.parent.mkdir(parents=True, exist_ok=True)
fh = logging.FileHandler(str(log_file), mode="a")
fh.setLevel(getattr(logging, level.upper(), logging.DEBUG))
fh.setFormatter(logging.Formatter(LOG_FORMAT, datefmt=DATE_FORMAT))
logging.getLogger(logger_name).addHandler(fh)
return fh
|
tit.logger.add_stream_handler
Attach a stdout handler to a named logger.
Used by scripts for terminal output and by __main__ entry points
so that BaseProcessThread can capture subprocess stdout for the GUI.
Parameters
logger_name : str, optional
Logger to attach to. Default is "tit".
level : str, optional
Minimum log level. Default is "INFO".
Returns
logging.StreamHandler
The newly created handler.
See Also
setup_logging : Set the package-wide log level.
add_file_handler : Attach a file handler.
Source code in tit/logger.py
| def add_stream_handler(
logger_name: str = "tit",
level: str = "INFO",
) -> logging.StreamHandler:
"""Attach a stdout handler to a named logger.
Used by scripts for terminal output and by ``__main__`` entry points
so that ``BaseProcessThread`` can capture subprocess stdout for the GUI.
Parameters
----------
logger_name : str, optional
Logger to attach to. Default is ``"tit"``.
level : str, optional
Minimum log level. Default is ``"INFO"``.
Returns
-------
logging.StreamHandler
The newly created handler.
See Also
--------
setup_logging : Set the package-wide log level.
add_file_handler : Attach a file handler.
"""
import sys
handler = logging.StreamHandler(sys.stdout)
handler.setLevel(getattr(logging, level.upper(), logging.INFO))
handler.setFormatter(logging.Formatter("%(message)s"))
logger = logging.getLogger(logger_name)
logger.addHandler(handler)
return handler
|
tit.logger.get_file_only_logger
Return a logger that writes only to log_file — no console output.
If a logger with name already exists its handlers are replaced so that
repeated calls (e.g., across ROIs) always point at the correct file.
Parameters
name : str
Logger name (should be unique per use-case).
log_file : str or pathlib.Path
Path to the log file.
level : str, optional
Minimum log level. Default is "DEBUG".
Returns
logging.Logger
A configured logger with a single file handler and
propagate=False.
See Also
add_file_handler : Lower-level helper used internally.
Source code in tit/logger.py
| def get_file_only_logger(
name: str,
log_file: str | Path,
level: str = "DEBUG",
) -> logging.Logger:
"""Return a logger that writes **only** to *log_file* — no console output.
If a logger with *name* already exists its handlers are replaced so that
repeated calls (e.g., across ROIs) always point at the correct file.
Parameters
----------
name : str
Logger name (should be unique per use-case).
log_file : str or pathlib.Path
Path to the log file.
level : str, optional
Minimum log level. Default is ``"DEBUG"``.
Returns
-------
logging.Logger
A configured logger with a single file handler and
``propagate=False``.
See Also
--------
add_file_handler : Lower-level helper used internally.
"""
logger = logging.getLogger(name)
logger.handlers.clear()
logger.setLevel(getattr(logging, level.upper(), logging.DEBUG))
logger.propagate = False # never bubble to root/terminal
add_file_handler(log_file, level=level, logger_name=name)
return logger
|
Config IO
tit.config_io.serialize_config
Convert a config dataclass to a JSON-serialisable dict.
Handles Enum fields (via .value), nested dataclasses (recursed),
union-typed ROI / electrode specs (injects a _type discriminator),
and None values (preserved as JSON null).
Also injects project_dir from the active :class:~tit.paths.PathManager
so that subprocess entry points can initialise their own singleton.
Parameters
config : dataclass instance
Any config dataclass (e.g., FlexConfig, ExConfig).
Returns
dict
JSON-serialisable dictionary representation of config.
See Also
write_config_json : Serialise and write to a temp file in one step.
read_config_json : Read a JSON config back into a dict.
Source code in tit/config_io.py
| def serialize_config(config: Any) -> dict[str, Any]:
"""Convert a config dataclass to a JSON-serialisable dict.
Handles Enum fields (via ``.value``), nested dataclasses (recursed),
union-typed ROI / electrode specs (injects a ``_type`` discriminator),
and *None* values (preserved as JSON ``null``).
Also injects ``project_dir`` from the active :class:`~tit.paths.PathManager`
so that subprocess entry points can initialise their own singleton.
Parameters
----------
config : dataclass instance
Any config dataclass (e.g., ``FlexConfig``, ``ExConfig``).
Returns
-------
dict
JSON-serialisable dictionary representation of *config*.
See Also
--------
write_config_json : Serialise and write to a temp file in one step.
read_config_json : Read a JSON config back into a dict.
"""
data = _serialize(config)
# Inject project_dir for subprocess entry points
from tit.paths import get_path_manager
data["project_dir"] = get_path_manager().project_dir
return data
|
tit.config_io.write_config_json
write_config_json(config: Any, prefix: str = 'config') -> str
Serialise a config dataclass to a temporary JSON file.
Parameters
config : dataclass instance
Config object to serialise.
prefix : str, optional
Filename prefix for the temp file. Default is "config".
Returns
str
Absolute path to the created JSON file.
See Also
serialize_config : Convert to dict without writing to disk.
read_config_json : Read a JSON config file.
Source code in tit/config_io.py
| def write_config_json(config: Any, prefix: str = "config") -> str:
"""Serialise a config dataclass to a temporary JSON file.
Parameters
----------
config : dataclass instance
Config object to serialise.
prefix : str, optional
Filename prefix for the temp file. Default is ``"config"``.
Returns
-------
str
Absolute path to the created JSON file.
See Also
--------
serialize_config : Convert to dict without writing to disk.
read_config_json : Read a JSON config file.
"""
data = serialize_config(config)
fd, path = tempfile.mkstemp(prefix=f"{prefix}_", suffix=".json")
with os.fdopen(fd, "w") as f:
json.dump(data, f, indent=2)
return path
|
tit.config_io.read_config_json
Read a JSON config file and return the parsed dict.
Parameters
path : str
Path to the JSON file.
Returns
dict
Parsed JSON contents.
See Also
write_config_json : Create a config JSON file from a dataclass.
Source code in tit/config_io.py
| def read_config_json(path: str) -> dict[str, Any]:
"""Read a JSON config file and return the parsed dict.
Parameters
----------
path : str
Path to the JSON file.
Returns
-------
dict
Parsed JSON contents.
See Also
--------
write_config_json : Create a config JSON file from a dataclass.
"""
with open(path) as f:
return json.load(f)
|
Exceptions
tit.pre.utils.PreprocessError
Bases: RuntimeError
Raised when a preprocessing step fails.
See Also
PreprocessCancelled : Raised specifically when cancelled by a stop event.
tit.pre.utils.PreprocessCancelled
Bases: RuntimeError
Raised when a preprocessing run is cancelled via a stop event.
See Also
PreprocessError : General preprocessing failure.
tit.pre.qsi.docker_builder.DockerBuildError
Bases: Exception
Raised when Docker command construction fails.