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
28 changes: 28 additions & 0 deletions python/lib/db/decorators/string_path.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from pathlib import Path

from sqlalchemy import String
from sqlalchemy.engine import Dialect
from sqlalchemy.types import TypeDecorator


class StringPath(TypeDecorator[Path]):
"""
Decorator for a database path type.
In SQL, the type will appear as a string.
In Python, the type will appear as a path object.
"""

impl = String
cache_ok = True

def process_bind_param(self, value: Path | None, dialect: Dialect) -> str | None:
if value is None:
return None

return str(value)

def process_result_value(self, value: str | None, dialect: Dialect) -> Path | None:
if value is None:
return None

return Path(value)
6 changes: 4 additions & 2 deletions python/lib/db/models/dicom_archive.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from datetime import date, datetime
from pathlib import Path
from typing import Optional

from sqlalchemy import ForeignKey
Expand All @@ -12,6 +13,7 @@
import lib.db.models.session as db_session
from lib.db.base import Base
from lib.db.decorators.int_bool import IntBool
from lib.db.decorators.string_path import StringPath


class DbDicomArchive(Base):
Expand All @@ -37,8 +39,8 @@ class DbDicomArchive(Base):
creating_user : Mapped[str] = mapped_column('CreatingUser')
sum_type_version : Mapped[int] = mapped_column('sumTypeVersion')
tar_type_version : Mapped[int | None] = mapped_column('tarTypeVersion')
source_location : Mapped[str] = mapped_column('SourceLocation')
archive_location : Mapped[str | None] = mapped_column('ArchiveLocation')
source_path : Mapped[Path] = mapped_column('SourceLocation', StringPath)
archive_path : Mapped[Path | None] = mapped_column('ArchiveLocation', StringPath)
scanner_manufacturer : Mapped[str] = mapped_column('ScannerManufacturer')
scanner_model : Mapped[str] = mapped_column('ScannerModel')
scanner_serial_number : Mapped[str] = mapped_column('ScannerSerialNumber')
Expand Down
4 changes: 3 additions & 1 deletion python/lib/db/models/file.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from datetime import date, datetime
from pathlib import Path

from sqlalchemy import ForeignKey
from sqlalchemy.orm import Mapped, mapped_column, relationship
Expand All @@ -8,14 +9,15 @@
from lib.db.base import Base
from lib.db.decorators.int_bool import IntBool
from lib.db.decorators.int_datetime import IntDatetime
from lib.db.decorators.string_path import StringPath


class DbFile(Base):
__tablename__ = 'files'

id : Mapped[int] = mapped_column('FileID', primary_key=True)
session_id : Mapped[int] = mapped_column('SessionID', ForeignKey('session.ID'))
rel_path : Mapped[str] = mapped_column('File')
path : Mapped[Path] = mapped_column('File', StringPath)
series_uid : Mapped[str | None] = mapped_column('SeriesUID')
echo_time : Mapped[float | None] = mapped_column('EchoTime')
phase_encoding_direction : Mapped[str | None] = mapped_column('PhaseEncodingDirection')
Expand Down
4 changes: 3 additions & 1 deletion python/lib/db/models/mri_protocol_violated_scan.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from datetime import datetime
from pathlib import Path
from typing import Optional

from sqlalchemy import ForeignKey
Expand All @@ -8,6 +9,7 @@
import lib.db.models.dicom_archive as db_dicom_archive
import lib.db.models.mri_protocol_group as db_mri_protocol_group
from lib.db.base import Base
from lib.db.decorators.string_path import StringPath


class DbMriProtocolViolatedScan(Base):
Expand All @@ -19,7 +21,7 @@ class DbMriProtocolViolatedScan(Base):
dicom_archive_id : Mapped[int | None] = mapped_column('TarchiveID', ForeignKey('tarchive.TarchiveID'))
time_run : Mapped[datetime | None] = mapped_column('time_run')
series_description : Mapped[str | None] = mapped_column('series_description')
file_rel_path : Mapped[str | None] = mapped_column('minc_location')
file_path : Mapped[Path | None] = mapped_column('minc_location', StringPath)
patient_name : Mapped[str | None] = mapped_column('PatientName')
tr_range : Mapped[str | None] = mapped_column('TR_range')
te_range : Mapped[str | None] = mapped_column('TE_range')
Expand Down
6 changes: 4 additions & 2 deletions python/lib/db/models/mri_upload.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from datetime import datetime
from pathlib import Path
from typing import Optional

from sqlalchemy import ForeignKey
Expand All @@ -8,6 +9,7 @@
import lib.db.models.session as db_session
from lib.db.base import Base
from lib.db.decorators.int_bool import IntBool
from lib.db.decorators.string_path import StringPath
from lib.db.decorators.y_n_bool import YNBool


Expand All @@ -17,8 +19,8 @@ class DbMriUpload(Base):
id : Mapped[int] = mapped_column('UploadID', primary_key=True)
uploaded_by : Mapped[str] = mapped_column('UploadedBy')
upload_date : Mapped[datetime | None] = mapped_column('UploadDate')
upload_location : Mapped[str] = mapped_column('UploadLocation')
decompressed_location : Mapped[str] = mapped_column('DecompressedLocation')
upload_path : Mapped[Path] = mapped_column('UploadLocation', StringPath)
decompressed_path : Mapped[Path] = mapped_column('DecompressedLocation', StringPath)
insertion_complete : Mapped[bool] = mapped_column('InsertionComplete', IntBool)
inserting : Mapped[bool | None] = mapped_column('Inserting', IntBool)
patient_name : Mapped[str] = mapped_column('PatientName')
Expand Down
4 changes: 3 additions & 1 deletion python/lib/db/models/mri_violation_log.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from datetime import datetime
from pathlib import Path
from typing import Optional

from sqlalchemy import ForeignKey
Expand All @@ -9,6 +10,7 @@
import lib.db.models.mri_protocol_check_group as db_mri_protocol_check_group
import lib.db.models.mri_scan_type as db_mri_scan_type
from lib.db.base import Base
from lib.db.decorators.string_path import StringPath


class DbMriViolationLog(Base):
Expand All @@ -19,7 +21,7 @@ class DbMriViolationLog(Base):
series_uid : Mapped[str | None] = mapped_column('SeriesUID')
dicom_archive_id : Mapped[int | None] \
= mapped_column('TarchiveID', ForeignKey('tarchive.TarchiveID'))
file_rel_path : Mapped[str | None] = mapped_column('MincFile')
file_path : Mapped[Path | None] = mapped_column('MincFile', StringPath)
patient_name : Mapped[str | None] = mapped_column('PatientName')
candidate_id : Mapped[int | None] = mapped_column('CandidateID', ForeignKey('candidate.ID'))
visit_label : Mapped[str | None] = mapped_column('Visit_label')
Expand Down
4 changes: 3 additions & 1 deletion python/lib/db/models/physio_channel.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from datetime import datetime
from decimal import Decimal
from pathlib import Path

from sqlalchemy import ForeignKey
from sqlalchemy.orm import Mapped, mapped_column, relationship
Expand All @@ -8,6 +9,7 @@
import lib.db.models.physio_file as db_physio_file
import lib.db.models.physio_status_type as db_physio_status_type
from lib.db.base import Base
from lib.db.decorators.string_path import StringPath


class DbPhysioChannel(Base):
Expand All @@ -28,7 +30,7 @@ class DbPhysioChannel(Base):
reference : Mapped[str | None] = mapped_column('Reference')
status_description : Mapped[str | None] = mapped_column('StatusDescription')
unit : Mapped[str | None] = mapped_column('Unit')
file_path : Mapped[str | None] = mapped_column('FilePath')
file_path : Mapped[Path | None] = mapped_column('FilePath', StringPath)

physio_file : Mapped['db_physio_file.DbPhysioFile'] = relationship('DbPhysioFile', back_populates='channels')
channel_type : Mapped['db_physio_channel_type.DbPhysioChannelType'] = relationship('DbPhysioChannelType')
Expand Down
15 changes: 9 additions & 6 deletions python/lib/db/models/physio_coord_system.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from pathlib import Path

from sqlalchemy import ForeignKey
from sqlalchemy.orm import Mapped, mapped_column, relationship

Expand All @@ -6,17 +8,18 @@
import lib.db.models.physio_coord_system_unit as db_physio_coord_system_unit
import lib.db.models.physio_modality as db_physio_modality
from lib.db.base import Base
from lib.db.decorators.string_path import StringPath


class DbPhysioCoordSystem(Base):
__tablename__ = 'physiological_coord_system'

id : Mapped[int] = mapped_column('PhysiologicalCoordSystemID', primary_key=True)
name_id : Mapped[int] = mapped_column('NameID', ForeignKey('physiological_coord_system_name.PhysiologicalCoordSystemNameID'))
type_id : Mapped[int] = mapped_column('TypeID', ForeignKey('physiological_coord_system_type.PhysiologicalCoordSystemTypeID'))
unit_id : Mapped[int] = mapped_column('UnitID', ForeignKey('physiological_coord_system_unit.PhysiologicalCoordSystemUnitID'))
modality_id : Mapped[int] = mapped_column('ModalityID', ForeignKey('physiological_modality.PhysiologicalModalityID'))
file_path : Mapped[str | None] = mapped_column('FilePath')
id : Mapped[int] = mapped_column('PhysiologicalCoordSystemID', primary_key=True)
name_id : Mapped[int] = mapped_column('NameID', ForeignKey('physiological_coord_system_name.PhysiologicalCoordSystemNameID'))
type_id : Mapped[int] = mapped_column('TypeID', ForeignKey('physiological_coord_system_type.PhysiologicalCoordSystemTypeID'))
unit_id : Mapped[int] = mapped_column('UnitID', ForeignKey('physiological_coord_system_unit.PhysiologicalCoordSystemUnitID'))
modality_id : Mapped[int] = mapped_column('ModalityID', ForeignKey('physiological_modality.PhysiologicalModalityID'))
file_path : Mapped[Path | None] = mapped_column('FilePath', StringPath)

name : Mapped['db_physio_coord_system_name.DbPhysioCoordSystemName'] = relationship('DbPhysioCoordSystemName')
type : Mapped['db_physio_coord_system_type.DbPhysioCoordSystemType'] = relationship('DbPhysioCoordSystemType')
Expand Down
16 changes: 9 additions & 7 deletions python/lib/db/models/physio_event_file.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from datetime import datetime
from pathlib import Path

from sqlalchemy import ForeignKey
from sqlalchemy.orm import Mapped, mapped_column, relationship
Expand All @@ -9,18 +10,19 @@
import lib.db.models.physio_task_event as db_physio_task_event
import lib.db.models.project as db_project
from lib.db.base import Base
from lib.db.decorators.string_path import StringPath


class DbPhysioEventFile(Base):
__tablename__ = 'physiological_event_file'

id : Mapped[int] = mapped_column('EventFileID', primary_key=True)
physio_file_id : Mapped[int | None] = mapped_column('PhysiologicalFileID', ForeignKey('physiological_file.PhysiologicalFileID'))
project_id : Mapped[int | None] = mapped_column('ProjectID', ForeignKey('Project.ProjectID'))
file_type : Mapped[str] = mapped_column('FileType', ForeignKey('ImagingFileTypes.type'))
file_path : Mapped[str | None] = mapped_column('FilePath')
last_update : Mapped[datetime] = mapped_column('LastUpdate')
last_written : Mapped[datetime] = mapped_column('LastWritten')
id : Mapped[int] = mapped_column('EventFileID', primary_key=True)
physio_file_id : Mapped[int | None] = mapped_column('PhysiologicalFileID', ForeignKey('physiological_file.PhysiologicalFileID'))
project_id : Mapped[int | None] = mapped_column('ProjectID', ForeignKey('Project.ProjectID'))
file_type : Mapped[str] = mapped_column('FileType', ForeignKey('ImagingFileTypes.type'))
file_path : Mapped[Path | None] = mapped_column('FilePath', StringPath)
last_update : Mapped[datetime] = mapped_column('LastUpdate')
last_written : Mapped[datetime] = mapped_column('LastWritten')

physio_file : Mapped['db_physio_file.DbPhysioFile | None'] = relationship('PhysiologicalFile')
project : Mapped['db_project.DbProject | None'] = relationship('Project')
Expand Down
4 changes: 3 additions & 1 deletion python/lib/db/models/physio_file.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from datetime import datetime
from pathlib import Path

from sqlalchemy import ForeignKey
from sqlalchemy.orm import Mapped, mapped_column, relationship
Expand All @@ -7,6 +8,7 @@
import lib.db.models.physio_modality as db_physio_modality
import lib.db.models.physio_output_type as db_physio_output_type
from lib.db.base import Base
from lib.db.decorators.string_path import StringPath


class DbPhysioFile(Base):
Expand All @@ -20,7 +22,7 @@ class DbPhysioFile(Base):
file_type : Mapped[str | None] = mapped_column('FileType')
acquisition_time : Mapped[datetime | None] = mapped_column('AcquisitionTime')
inserted_by_user : Mapped[str] = mapped_column('InsertedByUser')
path : Mapped[str] = mapped_column('FilePath')
path : Mapped[Path] = mapped_column('FilePath', StringPath)
index : Mapped[int | None] = mapped_column('Index')
parent_id : Mapped[int | None] = mapped_column('ParentID')

Expand Down
8 changes: 5 additions & 3 deletions python/lib/db/queries/dicom_archive.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@

from pathlib import Path

from sqlalchemy import delete, select
from sqlalchemy.orm import Session as Database

Expand Down Expand Up @@ -29,14 +31,14 @@ def try_get_dicom_archive_with_patient_name(db: Database, patient_name: str) ->
).scalar_one_or_none()


def try_get_dicom_archive_with_archive_location(db: Database, archive_location: str) -> DbDicomArchive | None:
def try_get_dicom_archive_with_archive_path(db: Database, archive_path: Path) -> DbDicomArchive | None:
"""
Get a DICOM archive from the database using its archive location, or return `None` if no DICOM
Get a DICOM archive from the database using its archive path, or return `None` if no DICOM
archive is found.
"""

return db.execute(select(DbDicomArchive)
.where(DbDicomArchive.archive_location.like(f'%{archive_location}%'))
.where(DbDicomArchive.archive_path.like(f'%{archive_path}%'))
).scalar_one_or_none()


Expand Down
10 changes: 6 additions & 4 deletions python/lib/db/queries/file.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from pathlib import Path

from sqlalchemy import delete, select
from sqlalchemy.orm import Session as Database

Expand Down Expand Up @@ -26,14 +28,14 @@ def try_get_file_with_unique_combination(
).scalar_one_or_none()


def try_get_file_with_rel_path(db: Database, rel_path: str) -> DbFile | None:
def try_get_file_with_path(db: Database, path: Path) -> DbFile | None:
"""
Get an imaging file from the database using its relative path, or return `None` if no imaging
file is found.
Get an imaging file from the database using its path, or return `None` if no imaging file is
found.
"""

return db.execute(select(DbFile)
.where(DbFile.rel_path == rel_path)
.where(DbFile.path == path)
).scalar_one_or_none()


Expand Down
4 changes: 3 additions & 1 deletion python/lib/db/queries/physio_file.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
from pathlib import Path

from sqlalchemy import select
from sqlalchemy.orm import Session as Database

from lib.db.models.physio_file import DbPhysioFile


def try_get_physio_file_with_path(db: Database, path: str) -> DbPhysioFile | None:
def try_get_physio_file_with_path(db: Database, path: Path) -> DbPhysioFile | None:
"""
Get a physiological file from the database using its path, or return `None` if no file was
found.
Expand Down
7 changes: 4 additions & 3 deletions python/lib/dcm2bids_imaging_pipeline_lib/base_pipeline.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import os
import shutil
from pathlib import Path

import lib.exitcode
from lib.config import get_data_dir_path_config, get_dicom_archive_dir_path_config
from lib.database import Database
from lib.database_lib.config import Config
from lib.db.queries.dicom_archive import try_get_dicom_archive_with_archive_location
from lib.db.queries.dicom_archive import try_get_dicom_archive_with_archive_path
from lib.db.queries.mri_upload import try_get_mri_upload_with_id
from lib.get_session_info import SessionConfigError, get_dicom_archive_session_info
from lib.imaging import Imaging
Expand Down Expand Up @@ -149,7 +150,7 @@ def load_mri_upload_and_dicom_archive(self):
)

self.dicom_archive = self.mri_upload.dicom_archive
if os.path.join(self.data_dir, 'tarchive', self.dicom_archive.archive_location) != tarchive_path:
if os.path.join(self.data_dir, 'tarchive', self.dicom_archive.archive_path) != tarchive_path:
log_error_exit(
self.env,
f"UploadID {upload_id} and ArchiveLocation {tarchive_path} do not refer to the same upload",
Expand Down Expand Up @@ -177,7 +178,7 @@ def load_mri_upload_and_dicom_archive(self):

elif tarchive_path:
archive_location = os.path.relpath(tarchive_path, self.dicom_lib_dir)
dicom_archive = try_get_dicom_archive_with_archive_location(self.env.db, archive_location)
dicom_archive = try_get_dicom_archive_with_archive_path(self.env.db, Path(archive_location))
if dicom_archive is None:
log_error_exit(
self.env,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import re
import subprocess
import sys
from pathlib import Path

import lib.exitcode
from lib.dcm2bids_imaging_pipeline_lib.base_pipeline import BasePipeline
Expand Down Expand Up @@ -35,7 +36,7 @@ def __init__(self, loris_getopt_obj, script_name):
self.init_session_info()
self.series_uid = self.options_dict["series_uid"]["value"]
self.tarchive_path = os.path.join(
self.data_dir, "tarchive", self.dicom_archive.archive_location
self.data_dir, "tarchive", self.dicom_archive.archive_path
)

# ---------------------------------------------------------------------------------------------
Expand All @@ -47,7 +48,7 @@ def __init__(self, loris_getopt_obj, script_name):
# Extract DICOM files from the tarchive
# ---------------------------------------------------------------------------------------------
self.extracted_dicom_dir = self.imaging_obj.extract_files_from_dicom_archive(
os.path.join(self.data_dir, 'tarchive', self.dicom_archive.archive_location),
os.path.join(self.data_dir, 'tarchive', self.dicom_archive.archive_path),
self.tmp_dir
)

Expand Down Expand Up @@ -334,7 +335,7 @@ def _move_and_update_dicom_archive(self):
"""

acq_date = self.dicom_archive.date_acquired
archive_location = self.dicom_archive.archive_location
archive_location = str(self.dicom_archive.archive_path)

pattern = re.compile(r"^[0-9]{4}/")
if acq_date and not pattern.match(archive_location):
Expand All @@ -349,7 +350,7 @@ def _move_and_update_dicom_archive(self):
os.replace(self.tarchive_path, new_tarchive_path)
self.tarchive_path = new_tarchive_path
# add the new archive location to the list of fields to update in the tarchive table
self.dicom_archive.archive_location = new_archive_location
self.dicom_archive.archive_path = Path(new_archive_location)

self.dicom_archive.session = self.session

Expand Down
Loading
Loading