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

Add new resource attributes and increase performance #30

Merged
merged 10 commits into from
Sep 1, 2023
13 changes: 8 additions & 5 deletions pyorthanc/__init__.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
from . import errors, util
from ._filtering import build_patient_forest, find, trim_patients
from ._find import find_instances, find_patients, find_series, find_studies, query_orthanc
from ._modality import Modality, RemoteModality
from ._resources import Instance, Patient, Series, Study
from .async_client import AsyncOrthanc
from .client import Orthanc
from .filtering import build_patient_forest, find, trim_patients
from .find import find_instances, find_patients, find_series, find_studies, query_orthanc
from .remote import RemoteModality
from .resources import Instance, Patient, Series, Study
from .retrieve import retrieve_and_write_instance, retrieve_and_write_patient, retrieve_and_write_patients, \
retrieve_and_write_series, retrieve_and_write_study


__all__ = [
'AsyncOrthanc',
'Orthanc',
'Modality',
'RemoteModality',
'Patient',
'Study',
Expand All @@ -29,4 +30,6 @@
'retrieve_and_write_study',
'retrieve_and_write_series',
'retrieve_and_write_instance',
'util',
'errors',
]
8 changes: 4 additions & 4 deletions pyorthanc/filtering.py → pyorthanc/_filtering.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@

from .async_client import AsyncOrthanc
from .client import Orthanc
from .resources.instance import Instance
from .resources.patient import Patient
from .resources.series import Series
from .resources.study import Study
from ._resources.instance import Instance
from ._resources.patient import Patient
from ._resources.series import Series
from ._resources.study import Study
from .util import async_to_sync


Expand Down
10 changes: 5 additions & 5 deletions pyorthanc/find.py → pyorthanc/_find.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from typing import Dict, List, Union

from .client import Orthanc
from .resources.instance import Instance
from .resources.patient import Patient
from .resources.resource import Resource
from .resources.series import Series
from .resources.study import Study
from ._resources.instance import Instance
from ._resources.patient import Patient
from ._resources.resource import Resource
from ._resources.series import Series
from ._resources.study import Study

DEFAULT_RESOURCES_LIMIT = 1_000

Expand Down
20 changes: 10 additions & 10 deletions pyorthanc/remote.py → pyorthanc/_modality.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@
from .client import Orthanc


class RemoteModality:
"""Wrapper around Orthanc API when dealing with a (remote) modality.
"""
class Modality:
"""Wrapper around Orthanc API when dealing with a modality."""

def __init__(self, client: Orthanc, modality: str) -> None:
"""Constructor
Expand All @@ -23,7 +22,7 @@ def __init__(self, client: Orthanc, modality: str) -> None:
self.modality = modality

def echo(self) -> bool:
"""C-Echo to remote modality
"""C-Echo to modality

Returns
-------
Expand Down Expand Up @@ -60,12 +59,12 @@ def query(self, data: Dict) -> Dict:
... }
... }

>>> remote_modality = RemoteModality(
>>> modality = Modality(
... client=Orthanc('http://localhost:8042'),
... modality='sample'
... )

>>> remote_modality.query(data)
>>> modality.query(data)
"""
return dict(self.client.post_modalities_id_query(self.modality, json=data))

Expand All @@ -88,13 +87,13 @@ def move(self, query_identifier: str, cmove_data: Dict) -> Dict:

Examples
--------
>>> remote_modality = RemoteModality(Orthanc('http://localhost:8042'), 'modality')
>>> query_id = remote_modality.query(
>>> modality = Modality(Orthanc('http://localhost:8042'), 'modality')
>>> query_id = modality.query(
... data={'Level': 'Series',
... 'Query': {'PatientID': '',
... 'Modality':'SR'}})

>>> remote_modality.move(
>>> modality.move(
... query_identifier=query_id['ID'],
... cmove_data={'TargetAet': 'TARGETAET'}
... )
Expand All @@ -103,7 +102,7 @@ def move(self, query_identifier: str, cmove_data: Dict) -> Dict:
return dict(self.client.post_queries_id_retrieve(query_identifier, json=cmove_data))

def store(self, instance_or_series_id: str) -> Dict:
"""Store series or instance to remote modality.
"""Store series or instance to modality.

Parameters
----------
Expand All @@ -130,3 +129,4 @@ def get_query_answers(self) -> Dict:
return answers


RemoteModality = Modality
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,8 @@ def get_dicom_file_content(self) -> bytes:

@property
def uid(self) -> str:
"""Get SOPInstanceUID

Returns
-------
str
SOPInstanceUID
"""
return self.get_main_information()['MainDicomTags']['SOPInstanceUID']
"""Get SOPInstanceUID"""
return self._get_main_dicom_tag_value('SOPInstanceUID')

def get_main_information(self) -> Dict:
"""Get instance information
Expand Down Expand Up @@ -96,57 +90,72 @@ def creation_date(self) -> datetime:
return util.make_datetime_from_dicom_date(date_string, time_string)

@property
def series_id(self) -> str:
"""Get the parent series identifier

Returns
-------
str
The parent series identifier.
"""
def series_identifier(self) -> str:
"""Get the parent series identifier"""
return self.get_main_information()['ParentSeries']

@property
def acquisition_number(self) -> int:
return int(self._get_main_dicom_tag_value('AcquisitionNumber'))

@property
def image_index(self) -> int:
return int(self._get_main_dicom_tag_value('ImageIndex'))

@property
def first_level_tags(self) -> Any:
"""Get first level tags
def image_orientation_patient(self) -> List[float]:
orientation = self._get_main_dicom_tag_value('ImageOrientationPatient')

Returns
-------
Any
First level tags.
"""
return [float(i) for i in orientation.split('\\')]

@property
def image_position_patient(self) -> List[float]:
position = self._get_main_dicom_tag_value('ImagePositionPatient')

return [float(i) for i in position.split('\\')]

@property
def image_comments(self) -> str:
return self._get_main_dicom_tag_value('ImageComments')

@property
def instance_number(self) -> int:
return int(self._get_main_dicom_tag_value('InstanceNumber'))

@property
def number_of_frames(self) -> int:
return int(self._get_main_dicom_tag_value('NumberOfFrames'))

@property
def temporal_position_identifier(self) -> str:
return self._get_main_dicom_tag_value('TemporalPositionIdentifier')

@property
def first_level_tags(self) -> Any:
"""Get first level tags"""
return self.client.get_instances_id_content_tags_path(self.id_, '')

@property
def tags(self) -> Dict:
"""Get tags

Returns
-------
Dict
Tags in the form of a dictionary.
"""
"""Get tags"""
return dict(self.client.get_instances_id_tags(self.id_))

@property
def simplified_tags(self) -> Dict:
"""Get simplified tags

Returns
-------
Dict
Simplified tags in the form of a dictionary.
"""
"""Get simplified tags"""
return dict(self.client.get_instances_id_tags(self.id_, params={'simplify': True}))

@property
def labels(self) -> List[str]:
"""Get instance labels"""
return self.get_main_information()['Labels']

def add_label(self, label: str) -> None:
"""Add label to resource"""
self.client.put_instances_id_labels_label(self.id_, label)

def remove_label(self, label):
"""Remove label from resource"""
self.client.delete_instances_id_labels_label(self.id_, label)

def get_content_by_tag(self, tag: str) -> Any:
Expand Down
45 changes: 19 additions & 26 deletions pyorthanc/resources/patient.py → pyorthanc/_resources/patient.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,36 +33,29 @@ def get_main_information(self) -> Dict:

@property
def patient_id(self) -> str:
"""Get patient ID

Returns
-------
str
Patient ID
"""
return self.get_main_information()['MainDicomTags']['PatientID']
"""Get patient ID"""
return self._get_main_dicom_tag_value('PatientID')

@property
def name(self) -> str:
"""Get patient name
"""Get patient name"""
return self._get_main_dicom_tag_value('PatientName')

Returns
-------
str
Patient name
"""
return self.get_main_information()['MainDicomTags']['PatientName']
@property
def birth_date(self) -> datetime:
"""Get patient birthdate"""
date = self._get_main_dicom_tag_value('PatientBirthDate')

return util.make_datetime_from_dicom_date(date)

@property
def sex(self) -> str:
"""Get patient sex
"""Get patient sex"""
return self._get_main_dicom_tag_value('PatientSex')

Returns
-------
str
Patient sex
"""
return self.get_main_information()['MainDicomTags']['PatientSex']
@property
def other_patient_ids(self) -> str:
return self._get_main_dicom_tag_value('OtherPatientIDs').split('\\')

@property
def is_stable(self):
Expand Down Expand Up @@ -224,14 +217,14 @@ def studies(self) -> List[Study]:
"""
if self.lock:
if self._child_resources is None:
studies_information = self.client.get_patients_id_studies(self.id_)
self._child_resources = [Study(i['ID'], self.client, self.lock) for i in studies_information]
studies_ids = self.get_main_information()['Studies']
self._child_resources = [Study(i, self.client, self.lock) for i in studies_ids]

return self._child_resources

studies_information = self.client.get_patients_id_studies(self.id_)
studies_ids = self.get_main_information()['Studies']

return [Study(i['ID'], self.client, self.lock) for i in studies_information]
return [Study(i, self.client, self.lock) for i in studies_ids]

def anonymize(self, remove: List = None, replace: Dict = None, keep: List = None, force: bool = False) -> 'Patient':
"""Anonymize patient
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from typing import Dict, List, Optional
from typing import Any, Dict, List, Optional

from .. import errors
from ..client import Orthanc


Expand Down Expand Up @@ -41,6 +42,12 @@ def identifier(self) -> str:
def get_main_information(self):
raise NotImplementedError

def _get_main_dicom_tag_value(self, tag: str) -> Any:
try:
return self.get_main_information()['MainDicomTags'][tag]
except KeyError:
raise errors.TagDoesNotExistError(f'{self} has no {tag} tag.')

def __eq__(self, other: 'Resource') -> bool:
return self.id_ == other.id_

Expand Down
Loading
Loading