Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
b677be5
Feat: 1st mkdocs pages
ylemarechal Aug 17, 2023
14dfb3a
Feat: 1st mkdocs pages
ylemarechal Aug 17, 2023
10439b5
Feat: change mkdocs pages
ylemarechal Aug 17, 2023
72ea88a
Feat: change mkdocs pages
ylemarechal Aug 17, 2023
6bcbed3
Feat: change mkdocs pages
ylemarechal Aug 17, 2023
da2e8c2
Feat: add ci
ylemarechal Aug 17, 2023
482737b
Feat: add examples
ylemarechal Aug 17, 2023
f085e10
Feat: add examples
ylemarechal Aug 17, 2023
ce521ee
Feat: add examples
ylemarechal Aug 18, 2023
7c06f8c
Feat: add examples
ylemarechal Aug 18, 2023
5ab2226
Feat: add examples
ylemarechal Aug 18, 2023
687446f
Feat: add examples
ylemarechal Aug 18, 2023
a7ecb17
Feat: add examples
ylemarechal Aug 18, 2023
60c22b1
Feat: add examples
ylemarechal Aug 18, 2023
65a7aff
Feat: add examples
ylemarechal Aug 18, 2023
51d4e7d
Feat: add api ref
ylemarechal Aug 22, 2023
cfad689
Feat: add api ref
ylemarechal Aug 22, 2023
811f86e
Feat: add api ref
ylemarechal Aug 22, 2023
2657239
Feat: add api ref
ylemarechal Aug 22, 2023
d767ced
Feat: add api ref
ylemarechal Aug 22, 2023
e6dc045
Feat: add citation
ylemarechal Aug 24, 2023
d339a6b
Feat: update with latest pyorthanc version
ylemarechal Aug 30, 2023
f8f34a5
Feat: update with latest pyorthanc version
ylemarechal Aug 30, 2023
cea5f81
Feat: Add 1st example
ylemarechal Aug 30, 2023
f34bb93
Feat: Add retrieve patient example
ylemarechal Aug 30, 2023
8c7b86b
Feat: Add badges
ylemarechal Aug 30, 2023
469d29f
Feat: Add badges
ylemarechal Aug 30, 2023
2abd1a8
Feat: Add badges
ylemarechal Aug 30, 2023
7a1c7d0
Feat: changes some doc files
ylemarechal Aug 30, 2023
9651f2b
Feat: changes some doc files
ylemarechal Aug 30, 2023
0bd386e
short modification for index
gacou54 Sep 5, 2023
44983fb
Stop instanciating an client at each example
gacou54 Sep 5, 2023
07c29e7
Fix build due to lib refactor
gacou54 Sep 5, 2023
9697e99
Minor improvements in quickstart
gacou54 Sep 5, 2023
4134b3e
Find resources with complex filters or filter on many resource levels
gacou54 Sep 5, 2023
3b0c012
Merge branch 'gacou54:main' into main
ylemarechal Sep 5, 2023
ccd093f
Merge branch 'gacou54:main' into main
ylemarechal Oct 23, 2023
ea66b4b
Merge branch 'gacou54:main' into main
ylemarechal Feb 16, 2024
2042066
Merge branch 'gacou54:main' into main
ylemarechal Jun 14, 2024
75ba662
Merge branch 'gacou54:main' into main
ylemarechal Jul 31, 2025
a471cd3
✨ download nifti files
ylemarechal Aug 4, 2025
347976c
add line
ylemarechal Aug 4, 2025
7165332
add comments
ylemarechal Aug 4, 2025
f5fd2a6
fix param
ylemarechal Aug 4, 2025
4151107
add dcm file option
ylemarechal Aug 4, 2025
9d9356c
fix for studies and patients
ylemarechal Aug 4, 2025
7b4a1ab
test fix
ylemarechal Aug 4, 2025
626d5dc
add else condition
ylemarechal Aug 4, 2025
13a18c0
comment typo
ylemarechal Aug 4, 2025
64912cd
change to in condition
ylemarechal Aug 4, 2025
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
16 changes: 14 additions & 2 deletions pyorthanc/_resources/instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,15 @@ def get_dicom_file_content(self) -> bytes:
"""
return self.client.get_instances_id_file(self.id_)

def download(self, filepath: Union[str, BinaryIO], with_progres: bool = False) -> None:
def download(self, filepath: Union[str, BinaryIO], with_progres: bool = False, file_format: str = 'dcm') -> None:
"""Download the DICOM file to a target path or buffer

This method is an alternative to the `.get_dicom_file_content()` method for large files.
The `.get_dicom_file_content()` method will pull all the data in a single GET call,
while `.download()` stream the data to a file or a buffer.
Favor the `.download()` method to avoid timeout and memory issues.
file_format option accepts 'dcm', 'nii', 'nii.gz'


Examples
--------
Expand All @@ -68,9 +70,19 @@ def download(self, filepath: Union[str, BinaryIO], with_progres: bool = False) -
# Now do whatever you want to do
buffer.seek(0)
dicom_bytes = buffer.read()

# download instance in nii.gz format
instance.download('instance.nii.gz', file_format='nii.gz')

```
"""
self._download_file(f'{self.client.url}/instances/{self.id_}/file', filepath, with_progres)
if file_format.lower() not in ['dcm', 'nii', 'nii.gz']:
raise ValueError(
f"format should be one of ['dcm, 'nii', 'nii.gz'], "
f"got '{file_format}' instead."
)

self._download_file(f'{self.client.url}/instances/{self.id_}', filepath, with_progres, file_format)

@property
def uid(self) -> str:
Expand Down
2 changes: 1 addition & 1 deletion pyorthanc/_resources/patient.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ def download(self, filepath: Union[str, BinaryIO], with_progres: bool = False) -
zip_bytes = buffer.read()
```
"""
self._download_file(f'{self.client.url}/patients/{self.id_}/archive', filepath, with_progres)
self._download_file(f'{self.client.url}/patients/{self.id_}', filepath, with_progres, 'zip')

def get_patient_module(self, simplify: bool = False, short: bool = False) -> Dict:
"""Get patient module in a simplified version
Expand Down
29 changes: 29 additions & 0 deletions pyorthanc/_resources/resource.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import abc
from typing import Any, BinaryIO, Dict, List, Optional, Union

from httpx import HTTPError
from httpx._types import QueryParamTypes

from .. import errors, util
from ..client import Orthanc
from ..errors import PluginNotEnabledError


class Resource:
Expand Down Expand Up @@ -76,11 +78,38 @@ def _make_response_format_params(self, simplify: bool = False, short: bool = Fal

return params

def _is_neuro_plugin_installed(self):
try:
_ = self.client.get_plugins_id(id_='neuro')
return True
except HTTPError:
return False

def _download_file(
self, url: str,
filepath: Union[str, BinaryIO],
with_progress: bool = False,
file_format: str = 'zip',
params: Optional[QueryParamTypes] = None):

if file_format.lower() == 'zip':
url = f'{url}/archive'
elif file_format.lower() == 'dcm':
url = f'{url}/file'
elif file_format.lower() in ['nii', 'nii.gz']:
if not self._is_neuro_plugin_installed():
raise PluginNotEnabledError(
'Neuro plugin is not installed or enabled on Orthanc instance. More information on https://orthanc.uclouvain.be/book/plugins/neuro.html'
)
url = f'{url}/nifti'
if file_format.lower() == 'nii.gz':
url += '?compress'
else:
raise ValueError(
f"format should be one of ['dcm, 'zip', 'nii', 'nii.gz'], "
f"got '{file_format}' instead."
)

# Check if filepath is a path or a file object.
if isinstance(filepath, str):
is_file_object = False
Expand Down
13 changes: 11 additions & 2 deletions pyorthanc/_resources/series.py
Original file line number Diff line number Diff line change
Expand Up @@ -584,13 +584,14 @@ def get_zip(self) -> bytes:
"""
return self.client.get_series_id_archive(self.id_)

def download(self, filepath: Union[str, BinaryIO], with_progres: bool = False) -> None:
def download(self, filepath: Union[str, BinaryIO], with_progres: bool = False, file_format: str = 'zip') -> None:
"""Download the zip file to a target path or buffer

This method is an alternative to the `.get_zip()` method for large files.
The `.get_zip()` method will pull all the data in a single GET call,
while `.download()` stream the data to a file or a buffer.
Favor the `.download()` method to avoid timeout and memory issues.
file_format option accepts 'zip', 'nii', 'nii.gz'

Examples
--------
Expand All @@ -610,9 +611,17 @@ def download(self, filepath: Union[str, BinaryIO], with_progres: bool = False) -
# Now do whatever you want to do
buffer.seek(0)
zip_bytes = buffer.read()

# download series in nii.gz format
a_series.download('series.nii.gz', file_format='nii.gz')
```
"""
self._download_file(f'{self.client.url}/series/{self.id_}/archive', filepath, with_progres)
if file_format.lower() not in ['zip', 'nii', 'nii.gz']:
raise ValueError(
f"format should be one of ['zip', 'nii', 'nii.gz'], "
f"got '{file_format}' instead."
)
self._download_file(f'{self.client.url}/series/{self.id_}', filepath, with_progres, file_format)

def get_shared_tags(self, simplify: bool = False, short: bool = False) -> Dict:
"""Retrieve the shared tags of the series"""
Expand Down
2 changes: 1 addition & 1 deletion pyorthanc/_resources/study.py
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,7 @@ def download(self, filepath: Union[str, BinaryIO], with_progres: bool = False) -
zip_bytes = buffer.read()
```
"""
self._download_file(f'{self.client.url}/studies/{self.id_}/archive', filepath, with_progres)
self._download_file(f'{self.client.url}/studies/{self.id_}', filepath, with_progres, 'zip')

def get_shared_tags(self, simplify: bool = False, short: bool = False) -> Dict:
"""Retrieve the shared tags of the study"""
Expand Down
4 changes: 4 additions & 0 deletions pyorthanc/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,7 @@ class ModificationError(Exception):

class NotInInternalEnvironmentError(Exception):
pass


class PluginNotEnabledError(Exception):
pass