Skip to content

Commit 167ccde

Browse files
author
Benoit Crickboom
committed
enhanced education plugin methods
1 parent 1aedc42 commit 167ccde

6 files changed

Lines changed: 104 additions & 3 deletions

File tree

orthanc_api_client/http_client.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ def _raise_or_retry_on_errors(self, response, url) -> bool:
116116
Will return False if everything was ok (HTTP 200 code).
117117
'''
118118
if response.status_code >= 200 and response.status_code < 300:
119+
self._token_updated = False
119120
return False
120121

121122
if response.status_code == 401:

orthanc_api_client/resources/education_images.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import json
22
import typing
33
from enum import StrEnum
4-
from typing import Dict
4+
from typing import Dict, List
55
import uuid
66
from .resources import Resources
77
from ..education_image import Image
@@ -17,6 +17,18 @@ class Images(Resources):
1717
def __init__(self, api_client: 'OrthancApiClient'):
1818
super().__init__(api_client=api_client, url_segment='/education/api')
1919

20+
def get(self, resource_id) -> Image:
21+
payload = {
22+
"resource_id": resource_id,
23+
"project": "_all-studies"
24+
}
25+
r = self._api_client.post(
26+
endpoint=f"{self._url_segment}/list-images",
27+
json=payload
28+
)
29+
print(r.content)
30+
return Image.from_json(json.loads(r.content))
31+
2032
def get_images_by_project(self, project_id: str) -> typing.List[Image]:
2133
payload = {
2234
"project": project_id
@@ -33,6 +45,18 @@ def get_series_without_a_project(self) -> typing.List[Image]:
3345
def get_studies_without_a_project(self) -> typing.List[Image]:
3446
return self.get_images_by_project(project_id="_unused-studies")
3547

48+
def get_all_images(self) -> typing.List[Image]:
49+
return self.get_images_by_project(project_id="_all-studies")
50+
51+
def delete(self, resource_id):
52+
if self._api_client.studies.get(resource_id) is not None:
53+
self._api_client.studies.delete(resource_id)
54+
elif self._api_client.series.get(resource_id) is not None:
55+
self._api_client.series.delete(resource_id)
56+
57+
def delete_all(self):
58+
self._api_client.delete_all_content()
59+
3660
def link_image_to_project(self, resource_id: str, project_id: str, resource_level: str="Series"):
3761
"""
3862
resource_level: 'Study' or 'Series'

orthanc_api_client/resources/education_projects.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,34 @@ def create(self, name: str, description: str) :
2222
endpoint=f"{self._url_segment}/",
2323
json=payload
2424
)
25+
r.raise_for_status()
26+
2527
return r.json()['id']
2628

29+
def delete(self, project_id: str):
30+
self._api_client.delete(f"{self._url_segment}/{project_id}")
31+
32+
33+
def delete_all(self):
34+
prjs = self.get_all()
35+
for prj in prjs:
36+
self.delete(prj.id)
37+
2738
def get(self, project_id: str) -> Project:
2839
r = self._api_client.get(f"{self._url_segment}/{project_id}")
40+
r.raise_for_status()
41+
2942
return Project.from_json(self._api_client, json.loads(r.content))
3043

3144
def get_all(self) -> typing.List[Project]:
3245
r = self._api_client.get(f"{self._url_segment}/")
46+
r.raise_for_status()
47+
3348
return [Project.from_json(self._api_client, prj_json) for prj_json in json.loads(r.content)]
3449

50+
def set_viewer(self, project_id: str, viewer: str):
51+
if viewer not in [ 'stone', 'volview', 'wsi', 'ohif-basic', 'ohif-volume', 'ohif-tumor', 'ohif-segmentation' ]:
52+
raise Exception(f'viewer {viewer} not supported')
53+
54+
r=self._api_client.put(f"{self._url_segment}/{project_id}/primary-viewer", data=json.dumps(viewer))
55+
r.raise_for_status()

release-notes.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
V 0.25.0
1+
V 0.25.1
22
========
33

44
- Added components for the education plugin.

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
# For a discussion on single-sourcing the version across setup.py and the
2929
# project code, see
3030
# https://packaging.python.org/guides/single-sourcing-package-version/
31-
version='0.25.0', # Required
31+
version='0.25.1', # Required
3232

3333
# This is a one-line description or tagline of what your project does. This
3434
# corresponds to the "Summary" metadata field:

tests/test_api_client.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1896,6 +1896,7 @@ def test_metrics(self):
18961896

18971897
def test_education_create_project(self):
18981898
self.od.delete_all_content()
1899+
self.od.projects.delete_all()
18991900

19001901
# prj creation
19011902
id = self.od.projects.create("prj-name", "prj-desc")
@@ -1909,8 +1910,32 @@ def test_education_create_project(self):
19091910
all = self.od.projects.get_all()
19101911
self.assertEqual(len(all), 1)
19111912

1913+
# check the project deletion
1914+
self.od.projects.delete(id)
1915+
all = self.od.projects.get_all()
1916+
self.assertEqual(len(all), 0)
1917+
1918+
def test_education_delete_all_projects(self):
1919+
self.od.delete_all_content()
1920+
self.od.projects.delete_all()
1921+
1922+
# prj creation
1923+
self.od.projects.create("prj-name", "prj-desc")
1924+
self.od.projects.create("prj-name2", "prj-desc2")
1925+
1926+
# check that there are 2 projects
1927+
all = self.od.projects.get_all()
1928+
self.assertEqual(len(all), 2)
1929+
1930+
# check the project deletion
1931+
self.od.projects.delete_all()
1932+
all = self.od.projects.get_all()
1933+
self.assertEqual(len(all), 0)
1934+
19121935
def test_education_upload(self):
19131936
self.od.delete_all_content()
1937+
self.od.images.delete_all()
1938+
self.od.projects.delete_all()
19141939

19151940
# upload 1 image
19161941
upload_id = self.od.images.upload_and_dicomize(file_path=here / "stimuli/education.jpeg", description="upload-desc")
@@ -1953,6 +1978,36 @@ def test_education_change_title(self):
19531978
images = self.od.images.get_series_without_a_project()
19541979
self.assertEqual(images[0].title, "new-title")
19551980

1981+
def test_education_set_viewer(self):
1982+
self.od.delete_all_content()
1983+
self.od.projects.delete_all()
1984+
1985+
# prj creation
1986+
id = self.od.projects.create("prj-name", "prj-desc")
1987+
prj = self.od.projects.get(id)
1988+
1989+
self.assertEqual(prj.primary_viewer.description, "stone")
1990+
1991+
self.od.projects.set_viewer(id, "volview")
1992+
prj = self.od.projects.get(id)
1993+
self.assertEqual(prj.primary_viewer.description, "volview")
1994+
1995+
def test_token_renewal(self):
1996+
self.od.delete_all_content()
1997+
self.od.projects.delete_all()
1998+
1999+
# put an expired token in the client
2000+
expired_token = "ZeyJhbGciOiJSUzI1NiIsImtpZCI6IjNhMjQzYWRhLTVhM2MtNDA0Mi04NmQ5LWFhZjBjM2ZiNzM3MCIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3ODI0ODYyNDgsImlhdCI6MTc4MjQ4MjY0OCwiaWQiOiJ0ZXN0IiwiaW5zdHJ1Y3Rvcl9vZiI6W10sImxlYXJuZXJfb2YiOltdLCJyb2xlIjoiYWRtaW4ifQ.L2DYuuNtHXnnhb6D7guT9t36b4pK-MTvk74UyoRsfHSqzFaikPEJZz6oM2Y2xkTqqwm_oOcjX_P683-s_MFAVycP-G3Fijfcz-hri-1_ewIMPd2mWGqg-jaXFDJBKD5Wo-Ws8rmWPweCu1VQ89dp6sYvPLKuJXCwaug5VFmGlP86lH6Cj4XuvFH9ncV1ynQzakEUAmoahL9H56QrrpXlD8J9TuoScPLqpxtAydFccL8r10Ysiyr-QWB4123BJUGo9jlpxYS29tpiswLbj94L8RX4vU5kjJu1ehn9jNJzNulPyarpaPHlBULJcQn8jyezqqQUuP1UbF5t09qszIZkEw"
2001+
expired_headers = {
2002+
"Authorization": f"Bearer {expired_token}"
2003+
}
2004+
self.od._http_session.headers.update(expired_headers)
2005+
2006+
id = self.od.projects.create("prj-name", "prj-desc")
2007+
prj = self.od.projects.get(id)
2008+
2009+
# check prj creation
2010+
self.assertEqual(prj.name, "prj-name")
19562011

19572012
def test_pool_maxsize(self):
19582013

0 commit comments

Comments
 (0)