diff --git a/docs/example.ipynb b/docs/example.ipynb index a6f46e5..b239f65 100644 --- a/docs/example.ipynb +++ b/docs/example.ipynb @@ -25,15 +25,26 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 1, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "23-12-02 13:19 | NBIAClient | DEBUG | Setting up OAuth2 client... with username nbia_guest\n" + ] + } + ], "source": [ + "%load_ext autoreload\n", + "%autoreload 2\n", + "\n", "from nbiatoolkit import NBIAClient\n", "from pprint import pprint\n", "\n", "# Instantiate the client. \n", - "client = NBIAClient()" + "client = NBIAClient(log_level='debug')" ] }, { @@ -63,9 +74,16 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 2, "metadata": {}, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "23-12-02 13:07 | NBIAClient | DEBUG | Querying API endpoint: https://services.cancerimagingarchive.net/nbia-api/services/v2/getCollectionValues\n" + ] + }, { "name": "stdout", "output_type": "stream", @@ -93,9 +111,16 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 3, "metadata": {}, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "23-12-02 13:08 | NBIAClient | DEBUG | Querying API endpoint: https://services.cancerimagingarchive.net/nbia-api/services/getCollectionValuesAndCounts\n" + ] + }, { "name": "stdout", "output_type": "stream", @@ -123,9 +148,16 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 4, "metadata": {}, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "23-12-02 13:08 | NBIAClient | DEBUG | Querying API endpoint: https://services.cancerimagingarchive.net/nbia-api/services/getBodyPartValuesAndCounts\n" + ] + }, { "name": "stdout", "output_type": "stream", @@ -165,9 +197,17 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 11, "metadata": {}, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "23-12-02 13:28 | NBIAClient | DEBUG | Parsing params: {'self': , 'Collection': '4D-Lung', 'Modality': 'CT'}\n", + "23-12-02 13:28 | NBIAClient | DEBUG | Querying API endpoint: https://services.cancerimagingarchive.net/nbia-api/services/v2/getPatientByCollectionAndModality\n" + ] + }, { "name": "stdout", "output_type": "stream", @@ -177,7 +217,7 @@ } ], "source": [ - "patients = client.getPatients(collection=\"4D-Lung\", modality=\"CT\")\n", + "patients = client.getPatients(Collection=\"4D-Lung\", Modality=\"CT\")\n", "pprint(patients[0:5])" ] }, @@ -209,9 +249,16 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 12, "metadata": {}, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "23-12-02 13:34 | NBIAClient | DEBUG | Querying API endpoint: https://services.cancerimagingarchive.net/nbia-api/services/v2/getSeries\n" + ] + }, { "name": "stdout", "output_type": "stream", diff --git a/src/nbiatoolkit/nbia.py b/src/nbiatoolkit/nbia.py index bc5942e..862d206 100644 --- a/src/nbiatoolkit/nbia.py +++ b/src/nbiatoolkit/nbia.py @@ -18,15 +18,17 @@ class NBIAClient: """ def __init__(self, - username: str = "nbia_guest", - password: str = "", - log_level: str = "INFO" - ) -> None: + username: str = "nbia_guest", + password: str = "", + log_level: str = "INFO" + ) -> None: # Setup logger self.logger = setup_logger( - name="NBIAClient", console_logging=True, - log_level=log_level, log_file=None) + name="NBIAClient", + log_level=log_level, + console_logging=True, + log_file=None) # Setup OAuth2 client self.logger.debug( @@ -35,6 +37,31 @@ def __init__(self, self._oauth2_client = OAuth2(username=username, password=password) self.api_headers = self._oauth2_client.getToken() + # setter method to update logger with a new instance of setup_logger + def setLogger( + self, + log_level: str = "INFO", + console_logging: bool = False, + log_file: str = None, + log_dir: str = None, + log_format: str = '%(asctime)s | %(name)s | %(levelname)s | %(message)s', + datefmt: str = '%y-%m-%d %H:%M' + ) -> bool: + try: + self.logger = setup_logger( + name="NBIAClient", + log_level=log_level, + console_logging=console_logging, + log_file=log_file, + log_dir=log_dir, + log_format=log_format, + datefmt=datefmt + ) + return True + except Exception as e: + self.logger.error("Error setting up logger: %s", e) + return False + def query_api(self, endpoint: NBIA_ENDPOINTS, params: dict = {}) -> dict: query_url = NBIA_ENDPOINTS.BASE_URL.value + endpoint.value @@ -81,13 +108,10 @@ def getCollectionPatientCount(self) -> list: return patientCount def getBodyPartCounts( - self, collection: str = "", modality: str = "") -> list: + self, Collection: str = "", Modality: str = "") -> list: + + PARAMS = self.parsePARAMS(locals()) - PARAMS = {} - if collection: - PARAMS["Collection"] = collection - if modality: - PARAMS["Modality"] = modality response = self.query_api( endpoint=NBIA_ENDPOINTS.GET_BODY_PART_PATIENT_COUNT, params=PARAMS) @@ -99,11 +123,13 @@ def getBodyPartCounts( "Count": bodypart["count"]}) return bodyparts - def getPatients(self, collection: str, modality: str) -> list: - assert collection is not None - assert modality is not None + def getPatients(self, Collection: str, Modality: str) -> list: + assert Collection is not None + assert Modality is not None + + + PARAMS = self.parsePARAMS(locals()) - PARAMS = {"Collection": collection, "Modality": modality} response = self.query_api( endpoint=NBIA_ENDPOINTS.GET_PATIENT_BY_COLLECTION_AND_MODALITY, params=PARAMS) @@ -122,22 +148,24 @@ def getSeries(self, Manufacturer: str = "", ) -> list: - params = dict() + PARAMS = dict() for key, value in locals().items(): if (value != "") and (key != "self"): - params[key] = value + PARAMS[key] = value response = self.query_api( endpoint = NBIA_ENDPOINTS.GET_SERIES, - params = params) + params = PARAMS) return response def downloadSeries( - self, SeriesInstanceUID: str, downloadDir: str, + self, + SeriesInstanceUID: str, + downloadDir: str = "./NBIA-Download", filePattern: str = '%PatientName/%StudyDescription-%StudyDate/%SeriesNumber-%SeriesDescription-%SeriesInstanceUID/%InstanceNumber.dcm', overwrite: bool = False ) -> bool: @@ -175,9 +203,17 @@ def downloadSeries( ) sorter.sortDICOMFiles(option="move", overwrite=overwrite) - - return True + return True + # 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.logger.debug("Parsing params: %s", params) + PARAMS = dict() + for key, value in params.items(): + if (value != "") and (key != "self"): + PARAMS[key] = value + return PARAMS diff --git a/src/nbiatoolkit/utils/logger.py b/src/nbiatoolkit/utils/logger.py index 36843ed..3ddf5f3 100644 --- a/src/nbiatoolkit/utils/logger.py +++ b/src/nbiatoolkit/utils/logger.py @@ -4,51 +4,48 @@ def setup_logger( name: str, - debug: bool = False, - console_logging: bool = False, log_level: str = 'INFO', - log_format: str = '%(asctime)s | %(name)s | %(levelname)s | %(message)s', + console_logging: bool = False, log_file: str = None, - log_dir: str = None + log_dir: str = None, + log_format: str = '%(asctime)s | %(name)s | %(levelname)s | %(message)s', + datefmt: str = '%y-%m-%d %H:%M' ) -> logging.Logger: """ Set up a logger object that can be used to log messages to a file and/or console with daily log file rotation. Args: - name (str): The name of the logger. Defaults to 'root'. - debug (bool): Whether to enable debug logging. Defaults to False. - console_logging (bool): Whether to enable console logging. Defaults to False. - log_file (str): The name of the log file if logging to a file. - log_level (str): The logging level for the logger. Defaults to 'INFO'. - log_format (str): The format of the log messages. Defaults to '%(asctime)s | %(name)s | %(levelname)s | %(message)s'. - log_dir (str): The directory where the log file will be saved. + name (str): The name of the logger. + log_level (str, optional): The log level. Defaults to 'INFO'. + console_logging (bool, optional): Whether to log to console. Defaults to False. + log_file (str, optional): The log file name. Defaults to None. + log_dir (str, optional): The log directory. Defaults to None. + log_format (str, optional): The log format. Defaults to '%(asctime)s | %(name)s | %(levelname)s | %(message)s'. + datefmt (str, optional): The date format. Defaults to '%y-%m-%d %H:%M'. Returns: logger (logging.Logger): The logger object. """ - # Convert log_level string to logging level object + # Validate log level level = getattr(logging, log_level.upper(), None) if not isinstance(level, int): raise ValueError(f'Invalid log level: {log_level}') + # Create logger logger = logging.getLogger(name) logger.setLevel(level) # Formatters - formatter = logging.Formatter(log_format) + formatter = logging.Formatter(fmt=log_format, datefmt=datefmt) - # Adding file handler with TimedRotatingFileHandler for daily rotation +# Set up file handler with TimedRotatingFileHandler for daily rotation if log_file: - if log_dir: + try: # Ensure log directory exists - try: + if log_dir: os.makedirs(log_dir, exist_ok=True) - except Exception as e: - raise IOError(f"Error creating log directory: {log_dir}") from e - - log_file = os.path.join(log_dir, log_file) + log_file = os.path.join(log_dir, log_file) - try: file_handler = TimedRotatingFileHandler(log_file, when='midnight', interval=1) file_handler.setFormatter(formatter) file_handler.setLevel(level) @@ -56,9 +53,9 @@ def setup_logger( except Exception as e: raise IOError(f"Error setting up file handler for logger: {e}") from e + # Set up console handler if console_logging is True if console_logging: try: - # Setup console handler with the same formatter and level console_handler = logging.StreamHandler() console_handler.setFormatter(formatter) console_handler.setLevel(level) diff --git a/tests/test_nbia.py b/tests/test_nbia.py index a5bfa54..128f481 100644 --- a/tests/test_nbia.py +++ b/tests/test_nbia.py @@ -22,7 +22,7 @@ def nbia_collections(nbia_client): @pytest.fixture(scope="session") def nbia_patients(nbia_client, nbia_collections): patients = nbia_client.getPatients( - collection=nbia_collections[0], modality = "CT") + Collection=nbia_collections[0], Modality = "CT") return patients def test_nbiaclient_access_token(nbia_client): @@ -41,7 +41,7 @@ def test_getBodyPartCounts_all(nbia_client): assert int(bodyparts[0]["Count"]) > 0 def test_getBodyPartCounts_4DLung(nbia_client): - bodyparts = nbia_client.getBodyPartCounts(collection="4D-Lung") + bodyparts = nbia_client.getBodyPartCounts(Collection="4D-Lung") assert isinstance(bodyparts, list) assert len(bodyparts) > 0 assert isinstance(bodyparts[0], dict)