Skip to content

Commit

Permalink
feat: added base_url setter if user wants to use NLST. added properti…
Browse files Browse the repository at this point in the history
…es for logger and base_url.
  • Loading branch information
jjjermiah committed Feb 4, 2024
1 parent c1e8f3d commit 5a992df
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 32 deletions.
87 changes: 55 additions & 32 deletions src/nbiatoolkit/nbia.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
from .auth import OAuth2
from .logger.logger import setup_logger
from logging import Logger
from .utils import NBIA_ENDPOINTS, validateMD5, clean_html, convertMillis, convertDateFormat
from .dicomsort import DICOMSorter

import requests
from requests.exceptions import JSONDecodeError as JSONDecodeError
from typing import Union
from typing import Union, LiteralString
import io
import zipfile
from tqdm import tqdm
from pyfiglet import Figlet

import os
from datetime import datetime
# set __version__ variable
Expand All @@ -28,47 +28,70 @@ class NBIAClient:
"""

def __init__(
self, username: str = "nbia_guest", password: str = "", log_level: str = "INFO"
self,
username: str = "nbia_guest",
password: str = "",
log_level: str = "INFO"
) -> None:
# Setup logger
self.log = setup_logger(
self._log: Logger = setup_logger(
name="NBIAClient", log_level=log_level, console_logging=True, log_file=None
)

# Setup OAuth2 client
self.log.debug("Setting up OAuth2 client... with username %s", username)

self._log.debug("Setting up OAuth2 client... with username %s", username)
self._oauth2_client = OAuth2(username=username, password=password)

try:
self._api_headers = self._oauth2_client.getToken()
except Exception as e:
self.log.error("Error retrieving access token: %s", e)
self._log.error("Error retrieving access token: %s", e)

Check warning on line 48 in src/nbiatoolkit/nbia.py

View check run for this annotation

Codecov / codecov/patch

src/nbiatoolkit/nbia.py#L48

Added line #L48 was not covered by tests
self._api_headers = None
raise e

self._base_url : NBIA_ENDPOINTS = NBIA_ENDPOINTS.BASE_URL

@property
def headers(self):
return self._api_headers

# create a setter for the base_url in case user want to use NLST
@property
def base_url(self) -> NBIA_ENDPOINTS:
return self._base_url

Check warning on line 61 in src/nbiatoolkit/nbia.py

View check run for this annotation

Codecov / codecov/patch

src/nbiatoolkit/nbia.py#L61

Added line #L61 was not covered by tests

@base_url.setter
def base_url(self, nbia_url: NBIA_ENDPOINTS) -> None:
self._base_url = nbia_url

Check warning on line 65 in src/nbiatoolkit/nbia.py

View check run for this annotation

Codecov / codecov/patch

src/nbiatoolkit/nbia.py#L65

Added line #L65 was not covered by tests

@property
def logger(self) -> Logger:
return self._log

Check warning on line 69 in src/nbiatoolkit/nbia.py

View check run for this annotation

Codecov / codecov/patch

src/nbiatoolkit/nbia.py#L69

Added line #L69 was not covered by tests

@logger.setter
def logger(self, logger: Logger) -> None:
self._log = logger

Check warning on line 73 in src/nbiatoolkit/nbia.py

View check run for this annotation

Codecov / codecov/patch

src/nbiatoolkit/nbia.py#L73

Added line #L73 was not covered by tests


def query_api(
self, endpoint: NBIA_ENDPOINTS, params: dict = {}
) -> Union[list, dict, bytes]:
query_url = NBIA_ENDPOINTS.BASE_URL.value + endpoint.value

self.log.debug("Querying API endpoint: %s", query_url)
self.log.debug("Query parameters: %s", params)
# query_url = NBIA_ENDPOINTS.BASE_URL.value + endpoint.value
query_url: LiteralString = self._base_url.value + endpoint.value

self._log.debug("Querying API endpoint: %s", query_url)
self._log.debug("Query parameters: %s", params)
response: requests.Response
try:
response = requests.get(url=query_url, headers=self.headers, params=params)
response.raise_for_status() # Raise an HTTPError for bad responses
except requests.exceptions.RequestException as e:
self.log.error("Error querying API: %s", e)
self._log.error("Error querying API: %s", e)

Check warning on line 90 in src/nbiatoolkit/nbia.py

View check run for this annotation

Codecov / codecov/patch

src/nbiatoolkit/nbia.py#L90

Added line #L90 was not covered by tests
raise e

if response.status_code != 200:
self.log.error(
self._log.error(
"Error querying API: %s %s", response.status_code, response.reason
)
raise requests.exceptions.RequestException(
Expand All @@ -85,21 +108,21 @@ def query_api(
response_data: bytes = response.content
return response_data
except JSONDecodeError as j:
self.log.debug("Response: %s", response.text)
self._log.debug("Response: %s", response.text)

Check warning on line 111 in src/nbiatoolkit/nbia.py

View check run for this annotation

Codecov / codecov/patch

src/nbiatoolkit/nbia.py#L111

Added line #L111 was not covered by tests
if response.text == "":
self.log.error("Response text is empty.")
self._log.error("Response text is empty.")

Check warning on line 113 in src/nbiatoolkit/nbia.py

View check run for this annotation

Codecov / codecov/patch

src/nbiatoolkit/nbia.py#L113

Added line #L113 was not covered by tests
else:
self.log.error("Error parsing response as JSON: %s", j)
self._log.error("Error parsing response as JSON: %s", j)

Check warning on line 115 in src/nbiatoolkit/nbia.py

View check run for this annotation

Codecov / codecov/patch

src/nbiatoolkit/nbia.py#L115

Added line #L115 was not covered by tests
raise j
except Exception as e:
self.log.error("Error querying API: %s", e)
self._log.error("Error querying API: %s", e)

Check warning on line 118 in src/nbiatoolkit/nbia.py

View check run for this annotation

Codecov / codecov/patch

src/nbiatoolkit/nbia.py#L118

Added line #L118 was not covered by tests
raise e

def getCollections(self, prefix: str = "") -> Union[list[str], None]:
response = self.query_api(NBIA_ENDPOINTS.GET_COLLECTIONS)

if not isinstance(response, list):
self.log.error("Expected list, but received: %s", type(response))
self._log.error("Expected list, but received: %s", type(response))

Check warning on line 125 in src/nbiatoolkit/nbia.py

View check run for this annotation

Codecov / codecov/patch

src/nbiatoolkit/nbia.py#L125

Added line #L125 was not covered by tests
return None

collections = []
Expand Down Expand Up @@ -140,7 +163,7 @@ def getModalityValues(
)

if not isinstance(response, list):
self.log.error("Expected list, but received: %s", type(response))
self._log.error("Expected list, but received: %s", type(response))

Check warning on line 166 in src/nbiatoolkit/nbia.py

View check run for this annotation

Codecov / codecov/patch

src/nbiatoolkit/nbia.py#L166

Added line #L166 was not covered by tests
return None

modalities = []
Expand All @@ -155,7 +178,7 @@ def getPatients(self, Collection: str = "") -> Union[list[dict[str, str]], None]

response = self.query_api(endpoint=NBIA_ENDPOINTS.GET_PATIENTS, params=PARAMS)
if not isinstance(response, list):
self.log.error("Expected list, but received: %s", type(response))
self._log.error("Expected list, but received: %s", type(response))

Check warning on line 181 in src/nbiatoolkit/nbia.py

View check run for this annotation

Codecov / codecov/patch

src/nbiatoolkit/nbia.py#L181

Added line #L181 was not covered by tests
return None

patientList = []
Expand Down Expand Up @@ -218,7 +241,7 @@ def getPatientsByCollectionAndModality(
params=PARAMS,
)
if not isinstance(response, list):
self.log.error("Expected list, but received: %s", type(response))
self._log.error("Expected list, but received: %s", type(response))

Check warning on line 244 in src/nbiatoolkit/nbia.py

View check run for this annotation

Codecov / codecov/patch

src/nbiatoolkit/nbia.py#L244

Added line #L244 was not covered by tests
return None

patientList = [_["PatientId"] for _ in response]
Expand All @@ -231,7 +254,7 @@ def getCollectionPatientCount(
response = self.query_api(NBIA_ENDPOINTS.GET_COLLECTION_PATIENT_COUNT)

if not isinstance(response, list):
self.log.error("Expected list, but received: %s", type(response))
self._log.error("Expected list, but received: %s", type(response))

Check warning on line 257 in src/nbiatoolkit/nbia.py

View check run for this annotation

Codecov / codecov/patch

src/nbiatoolkit/nbia.py#L257

Added line #L257 was not covered by tests
return None

patientCounts = []
Expand All @@ -256,7 +279,7 @@ def getBodyPartCounts(
)

if not isinstance(response, list):
self.log.error("Expected list, but received: %s", type(response))
self._log.error("Expected list, but received: %s", type(response))

Check warning on line 282 in src/nbiatoolkit/nbia.py

View check run for this annotation

Codecov / codecov/patch

src/nbiatoolkit/nbia.py#L282

Added line #L282 was not covered by tests
return None

bodyparts = []
Expand All @@ -277,7 +300,7 @@ def getStudies(
response = self.query_api(endpoint=NBIA_ENDPOINTS.GET_STUDIES, params=PARAMS)

if not isinstance(response, list):
self.log.error("Expected list, but received: %s", type(response))
self._log.error("Expected list, but received: %s", type(response))

Check warning on line 303 in src/nbiatoolkit/nbia.py

View check run for this annotation

Codecov / codecov/patch

src/nbiatoolkit/nbia.py#L303

Added line #L303 was not covered by tests
return None

return response
Expand All @@ -298,7 +321,7 @@ def getSeries(
response = self.query_api(endpoint=NBIA_ENDPOINTS.GET_SERIES, params=PARAMS)

if not isinstance(response, list):
self.log.error("Expected list, but received: %s", type(response))
self._log.error("Expected list, but received: %s", type(response))
return None

return response
Expand All @@ -321,7 +344,7 @@ def getSeriesMetadata(
)

if not isinstance(response, list):
self.log.error("Expected list, but received: %s", type(response))
self._log.error("Expected list, but received: %s", type(response))

Check warning on line 347 in src/nbiatoolkit/nbia.py

View check run for this annotation

Codecov / codecov/patch

src/nbiatoolkit/nbia.py#L347

Added line #L347 was not covered by tests
return None

metadata.extend(response)
Expand All @@ -343,7 +366,7 @@ def getNewSeries(
response = self.query_api(endpoint=NBIA_ENDPOINTS.GET_UPDATED_SERIES, params=PARAMS)

if not isinstance(response, list):
self.log.error("Expected list, but received: %s", type(response))
self._log.error("Expected list, but received: %s", type(response))

Check warning on line 369 in src/nbiatoolkit/nbia.py

View check run for this annotation

Codecov / codecov/patch

src/nbiatoolkit/nbia.py#L369

Added line #L369 was not covered by tests
return None

return response
Expand Down Expand Up @@ -412,13 +435,13 @@ def _downloadSingleSeries(
params = dict()
params["SeriesInstanceUID"] = SeriesInstanceUID

self.log.debug("Downloading series: %s", SeriesInstanceUID)
self._log.debug("Downloading series: %s", SeriesInstanceUID)
response = self.query_api(
endpoint=NBIA_ENDPOINTS.DOWNLOAD_SERIES, params=params
)

if not isinstance(response, bytes):
self.log.error(f"Expected binary data, but received: {type(response)}")
self._log.error(f"Expected binary data, but received: {type(response)}")

Check warning on line 444 in src/nbiatoolkit/nbia.py

View check run for this annotation

Codecov / codecov/patch

src/nbiatoolkit/nbia.py#L444

Added line #L444 was not covered by tests
return False

file = zipfile.ZipFile(io.BytesIO(response))
Expand All @@ -429,7 +452,7 @@ def _downloadSingleSeries(
try:
validateMD5(seriesDir=tempDir)
except Exception as e:
self.log.error("Error validating MD5 hash: %s", e)
self._log.error("Error validating MD5 hash: %s", e)

Check warning on line 455 in src/nbiatoolkit/nbia.py

View check run for this annotation

Codecov / codecov/patch

src/nbiatoolkit/nbia.py#L455

Added line #L455 was not covered by tests
return False

# Create an instance of DICOMSorter with the desired target pattern
Expand All @@ -442,7 +465,7 @@ def _downloadSingleSeries(
)
# sorter.sortDICOMFiles(option="move", overwrite=overwrite)
if not sorter.sortDICOMFiles(option="move", overwrite=overwrite):
self.log.error(
self._log.error(

Check warning on line 468 in src/nbiatoolkit/nbia.py

View check run for this annotation

Codecov / codecov/patch

src/nbiatoolkit/nbia.py#L468

Added line #L468 was not covered by tests
"Error sorting DICOM files for series %s\n \
failed files located at %s",
SeriesInstanceUID,
Expand All @@ -455,7 +478,7 @@ def _downloadSingleSeries(
# parsePARAMS is a helper function that takes a locals() dict and returns
# a dict with only the non-empty values
def parsePARAMS(self, params: dict) -> dict:
self.log.debug("Parsing params: %s", params)
self._log.debug("Parsing params: %s", params)
PARAMS = dict()
for key, value in params.items():
if (value != "") and (key != "self"):
Expand Down
1 change: 1 addition & 0 deletions src/nbiatoolkit/utils/nbia_endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ class NBIA_ENDPOINTS(Enum):
"""

BASE_URL = "https://services.cancerimagingarchive.net/nbia-api/services/"
NLST_URL = "https://nlst.cancerimagingarchive.net/nbia-api/services/"

GET_COLLECTIONS = "v2/getCollectionValues"
GET_COLLECTION_PATIENT_COUNT = "getCollectionValuesAndCounts"
Expand Down

0 comments on commit 5a992df

Please sign in to comment.