From d447aaa695024917351b2e7535ae6f8e1065cfe1 Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Mon, 27 Jul 2026 16:52:10 +0000 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=93=9D=20Add=20docstrings=20to=20`fea?= =?UTF-8?q?ture/lightweight-reviewer`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Docstrings generation was requested by @chezhia. * https://github.com/Project-MONAI/MONAILabel/pull/1907#issuecomment-5094062326 The following files were modified: * `monailabel/datastore/local.py` * `monailabel/endpoints/datastore_review.py` * `plugins/slicer/MONAILabelReviewer/MONAILabelReviewer.py` * `plugins/slicer/MONAILabelReviewer/MONAILabelReviewerLib/ImageDataController.py` * `plugins/slicer/MONAILabelReviewer/MONAILabelReviewerLib/MonaiServerREST.py` * `sample-apps/reviewer/app.py` * `sample-apps/reviewer/client.py` * `sample-apps/reviewer/lib/config.py` --- monailabel/datastore/local.py | 35 ++++ monailabel/endpoints/datastore_review.py | 147 +++++++++++++++++ .../MONAILabelReviewer/MONAILabelReviewer.py | 56 ++++++- .../ImageDataController.py | 26 +++ .../MONAILabelReviewerLib/MonaiServerREST.py | 38 +++++ sample-apps/reviewer/app.py | 47 ++++-- sample-apps/reviewer/client.py | 150 ++++++++---------- sample-apps/reviewer/lib/config.py | 30 ++-- 8 files changed, 417 insertions(+), 112 deletions(-) diff --git a/monailabel/datastore/local.py b/monailabel/datastore/local.py index 41e42fbfb..bff92019b 100644 --- a/monailabel/datastore/local.py +++ b/monailabel/datastore/local.py @@ -217,6 +217,15 @@ def set_description(self, description: str): self._update_datastore_file() def _to_id(self, file: str) -> Tuple[str, str]: + """ + Derive an identifier and extension from a filename using the configured file extensions. + + Parameters: + file (str): Filename to parse. + + Returns: + Tuple[str, str]: The identifier and matched extension. + """ ext = file_ext(file) extensions = [e.replace("*", "") for e in self._extensions] for e in extensions: @@ -226,11 +235,28 @@ def _to_id(self, file: str) -> Tuple[str, str]: return id, ext def _to_label_id(self, file: str) -> Tuple[str, str]: + """Convert a label filename to its identifier and extension. + + Parameters: + file (str): Label filename to parse. + + Returns: + Tuple[str, str]: The label identifier and file extension. + """ if file.lower().endswith(".seg.nrrd"): return file[: -len(".seg.nrrd")], ".seg.nrrd" return self._to_id(file) def _filename(self, id: str, ext: str) -> str: + """Construct a filename by concatenating an identifier with its extension. + + Parameters: + id (str): The file identifier. + ext (str): The file extension. + + Returns: + str: The resulting filename. + """ return id + ext def _to_bytes(self, file): @@ -611,6 +637,15 @@ def _add_non_existing_images(self) -> int: return invalidate def _add_non_existing_labels(self, tag) -> int: + """ + Add label metadata for label files that exist on disk but are missing from the datastore. + + Parameters: + tag (str): Label tag identifying the directory containing the label files. + + Returns: + int: Number of labels added to the datastore. + """ invalidate = 0 self._init_from_datastore_file() diff --git a/monailabel/endpoints/datastore_review.py b/monailabel/endpoints/datastore_review.py index 2bec22ab7..84d49289c 100644 --- a/monailabel/endpoints/datastore_review.py +++ b/monailabel/endpoints/datastore_review.py @@ -38,6 +38,16 @@ def _safe_label_info(datastore, image_id: str, tag: str) -> Dict[str, Any]: + """ + Retrieve label metadata for an image and tag. + + Parameters: + image_id (str): Identifier of the image. + tag (str): Label tag used to locate the metadata. + + Returns: + Dict[str, Any]: The label metadata when it is a dictionary; otherwise, an empty dictionary. + """ try: info = datastore.get_label_info(image_id, tag) return info if isinstance(info, dict) else {} @@ -49,6 +59,18 @@ def _safe_label_info(datastore, image_id: str, tag: str) -> Dict[str, Any]: def _parse_date_range(date_range: Optional[str]) -> Optional[Tuple[datetime, datetime]]: + """ + Parse an optional comma-separated ISO timestamp range. + + Parameters: + date_range (Optional[str]): Range in the form ``start,end``. + + Returns: + Optional[Tuple[datetime, datetime]]: The parsed start and end timestamps, or ``None`` when no range is provided. + + Raises: + HTTPException: If the range is incomplete or contains invalid ISO timestamps. + """ if not date_range: return None @@ -63,6 +85,16 @@ def _parse_date_range(date_range: Optional[str]) -> Optional[Tuple[datetime, dat def _matches_date_range(value: Optional[str], parsed: Optional[Tuple[datetime, datetime]]) -> bool: + """ + Determine whether a timestamp falls within an optional inclusive date range. + + Parameters: + value (Optional[str]): ISO-formatted timestamp to evaluate. + parsed (Optional[Tuple[datetime, datetime]]): Inclusive start and end timestamps, or `None` to disable filtering. + + Returns: + bool: `true` if filtering is disabled or the timestamp falls within the range, `false` otherwise. + """ if not parsed: return True if not value: @@ -78,6 +110,17 @@ def _matches_date_range(value: Optional[str], parsed: Optional[Tuple[datetime, d def _review_case(datastore, image_id: str, tag: str) -> Dict[str, Any]: + """ + Build a review record containing image metadata, review details, and label status. + + Parameters: + datastore: Datastore used to retrieve image, label, and review information. + image_id (str): Identifier of the image. + tag (str): Label tag associated with the review. + + Returns: + Dict[str, Any]: Review record with derived status, reviewer information, and label presence. + """ image_info = datastore.get_image_info(image_id) or {} label_info = _safe_label_info(datastore, image_id, tag) labels = datastore.get_labels_by_image_id(image_id) or {} @@ -108,6 +151,22 @@ def _list_review_cases( date_range: Optional[str], tag: str, ) -> List[Dict[str, Any]]: + """ + Collect review cases that match the specified status, image, reviewer, date, and label tag filters. + + Parameters: + status_filter (Optional[str]): Review status to match. + search (Optional[str]): Comma-separated image IDs to include. + reviewer (Optional[str]): Reviewer name to match. + date_range (Optional[str]): ISO timestamp range in the format ``start,end``. + tag (str): Label tag used to build each review case. + + Returns: + List[Dict[str, Any]]: Review cases that satisfy all provided filters. + + Raises: + HTTPException: If ``date_range`` is not a valid ISO timestamp range. + """ datastore = app_instance().datastore() image_ids = datastore.list_images() parsed_range = _parse_date_range(date_range) @@ -134,6 +193,15 @@ def _list_review_cases( def _summary(items: List[Dict[str, Any]]) -> Dict[str, int]: + """ + Count review cases by overall total and status. + + Parameters: + items (List[Dict[str, Any]]): Review case records containing a status field. + + Returns: + Dict[str, int]: Counts for total, approved, flagged, pending, and unlabeled cases. + """ return { "total": len(items), "approved": sum(1 for item in items if item.get("status") == "approved"), @@ -144,6 +212,15 @@ def _summary(items: List[Dict[str, Any]]) -> Dict[str, int]: def _report_stats(items: List[Dict[str, Any]]) -> Dict[str, Any]: + """ + Summarize review cases by status and difficulty level. + + Parameters: + items (List[Dict[str, Any]]): Review case records to summarize. + + Returns: + Dict[str, Any]: Status and difficulty counts with the current recording timestamp. + """ return { **_summary(items), "easy": sum(1 for item in items if item.get("level") == "easy"), @@ -154,6 +231,15 @@ def _report_stats(items: List[Dict[str, Any]]) -> Dict[str, Any]: def _render_csv(items: List[Dict[str, Any]]) -> str: + """ + Render review case records as CSV text. + + Parameters: + items (List[Dict[str, Any]]): Review case records to include in the CSV output. + + Returns: + str: CSV text containing a header row and one row for each review case. + """ handle = io.StringIO() writer = csv.writer(handle) writer.writerow(["image_id", "status", "level", "reviewer", "comment", "last_reviewed", "tag"]) @@ -173,9 +259,27 @@ def _render_csv(items: List[Dict[str, Any]]) -> str: def _render_html(stats: Dict[str, Any]) -> str: + """ + Render review statistics as an HTML report. + + Parameters: + stats (Dict[str, Any]): Statistics and generation timestamp to include in the report. + + Returns: + str: An HTML document containing review status and difficulty counts with percentages. + """ total = stats["total"] or 1 def row(name: str, value: int) -> str: + """Render an HTML table row containing a label, count, and percentage of the total. + + Parameters: + name (str): The label displayed in the row. + value (int): The count used to calculate the percentage. + + Returns: + str: An escaped HTML table row with the label, count, and percentage. + """ return f"{escape(name)}{value}" f"{(100.0 * value / total):.1f}%" return ( @@ -207,6 +311,21 @@ async def api_review_cases( tag: str = DefaultLabelTag.FINAL.value, user: User = Depends(RBAC(settings.MONAI_LABEL_AUTH_ROLE_USER)), ): + """ + List filtered review cases with pagination and aggregate status counts. + + Parameters: + offset (int): Number of matching cases to skip. + limit (int): Maximum number of cases to include in the results. + status_filter (Optional[str]): Status used to filter cases. + search (Optional[str]): Comma-separated image identifiers used to filter cases. + reviewer (Optional[str]): Reviewer name used to filter cases. + date_range (Optional[str]): ISO timestamp range in the format ``start,end``. + tag (str): Label tag used to build the review cases. + + Returns: + Dict[str, Any]: A response containing summary counts, paginated results, and filter metadata. + """ items = _list_review_cases(status_filter, search, reviewer, date_range, tag) results = items[offset : offset + limit] @@ -228,6 +347,18 @@ async def api_review_versions( image: str, user: User = Depends(RBAC(settings.MONAI_LABEL_AUTH_ROLE_USER)), ): + """ + Retrieve the available label versions for an image. + + Parameters: + image (str): Identifier of the image whose label versions are requested. + + Returns: + dict: A success response containing the image identifier and version metadata. + + Raises: + HTTPException: If no labels are found for the image. + """ datastore = app_instance().datastore() labels = datastore.get_labels_by_image_id(image) if not labels: @@ -258,6 +389,22 @@ async def api_review_report( tag: str = DefaultLabelTag.FINAL.value, user: User = Depends(RBAC(settings.MONAI_LABEL_AUTH_ROLE_USER)), ): + """ + Generate a review report in JSON, CSV, or HTML format. + + Parameters: + fmt (str): Output format: `"json"`, `"csv"`, or `"html"`. + reviewer (Optional[str]): Limits results to a specific reviewer. + date_range (Optional[str]): ISO timestamp range in `start,end` format. + tag (str): Label tag used to select review cases. + + Returns: + dict: A formatted report containing review statistics and, for JSON output, + the applied filters and matching review cases. + + Raises: + HTTPException: If `fmt` is not `"json"`, `"csv"`, or `"html"`. + """ items = _list_review_cases(None, None, reviewer, date_range, tag) stats = _report_stats(items) fmt = fmt.lower() diff --git a/plugins/slicer/MONAILabelReviewer/MONAILabelReviewer.py b/plugins/slicer/MONAILabelReviewer/MONAILabelReviewer.py index 66e7d75b0..2b9586517 100644 --- a/plugins/slicer/MONAILabelReviewer/MONAILabelReviewer.py +++ b/plugins/slicer/MONAILabelReviewer/MONAILabelReviewer.py @@ -426,6 +426,9 @@ def cleanCache(self): # Section: Server def loadServerSelection(self): + """ + Populate the server URL selector with normalized addresses stored in application settings. + """ settings = qt.QSettings() serverUrlHistory = settings.value("MONAILabel/serverUrlHistory") @@ -437,14 +440,25 @@ def loadServerSelection(self): self.ui.comboBox_server_url.addItems(server_urls) def normalizeServerUrl(self, serverUrl: str) -> str: + """ + Normalize a server URL for consistent use by removing surrounding whitespace and trailing slashes. + + Parameters: + serverUrl (str): The server URL to normalize. + + Returns: + str: The normalized server URL, or an empty string when no URL is provided. + """ if not serverUrl: return "" return serverUrl.strip().rstrip("/") def init_dicom_stream(self): """ - initiates connection to monai server - Default: client listens on "http://127.0.0.1:8000" + Connect to the configured MONAI Label server and initialize the reviewer interface. + + The selected server URL is normalized before connection. Displays a warning and leaves + the interface uninitialized when the connection fails. """ # Check Connection self.cleanCache() @@ -1497,6 +1511,11 @@ def updateAfterEditingSegmentation(self): self.setVersionTagInComboBox(versionTag=newLabelNameCreated) def reloadImageAfterEditingLabel(self): + """ + Reload the current image using its latest label version after an edit. + + The image display and label version selector are refreshed to reflect the updated segmentation. + """ imageId = self.currentImageData.getFileName() latestVersion = self.currentImageData.getLatestVersionTag() logging.info(f"{self.getCurrentTime()}: Loading image (id='{imageId}') with version tag = '{latestVersion}'") @@ -1504,6 +1523,11 @@ def reloadImageAfterEditingLabel(self): self.fillComboBoxLabelVersions(self.currentImageData) def processDataStoreRecords(self): + """ + Process datastore records and display a warning when processing fails. + + The selected server address is normalized for inclusion in failure messages. + """ serverUrl: str = self.normalizeServerUrl(self.ui.comboBox_server_url.currentText) result: bool = self.logic.initMetaDataProcessing() if result is False: @@ -1668,11 +1692,11 @@ def updateLabelInfo( def loadDicomAndSegmentation(self, imageData: ImageData, tag: str): """ - Loads original Dicom image and Segmentation into slicer window + Load an image and, when available, its segmentation into the Slicer scene. + Parameters: - imageData (ImageData): Contains meta data (of dicom and segmenation) - which is required for rest request to monai server - in order to get dicom and segmenation (.nrrd). + imageData (ImageData): Image metadata used to retrieve the DICOM image and segmentation. + tag (str): Version tag identifying the segmentation to load. """ # Request dicom image_name = imageData.getFileName() @@ -1717,11 +1741,25 @@ def getPathToStore(self, segmentationFileName: str, tempDirectory: str) -> str: def displaySegmention(self, destination: str): """ - Displays the segmentation in slicer window + Display a segmentation file in the Slicer window. + + Parameters: + destination (str): Path to the segmentation file. """ segmentation = slicer.util.loadSegmentation(destination) def requestDicomImage(self, image_id: str, image_name: str, node_name: str): + """ + Download an image from the MONAI Label server and load it into Slicer. + + Parameters: + image_id (str): Identifier of the image to download. + image_name (str): File name used for temporary storage. + node_name (str): Name associated with the image node. + + Raises: + RuntimeError: If the server does not return the image. + """ response = self.imageDataController.requestImage(image_id) if response is None: raise RuntimeError(f"Failed to download image '{image_id}' from MONAI Label server") @@ -1735,7 +1773,9 @@ def requestDicomImage(self, image_id: str, image_name: str, node_name: str): def setTempFolderDir(self): """ - Create temporary dirctory to store the downloaded segmentation (.nrrd) + Create the temporary directory used to store downloaded segmentation files. + + The directory is created only once and its path is logged. """ if self.temp_dir is None: self.temp_dir = tempfile.TemporaryDirectory() diff --git a/plugins/slicer/MONAILabelReviewer/MONAILabelReviewerLib/ImageDataController.py b/plugins/slicer/MONAILabelReviewer/MONAILabelReviewerLib/ImageDataController.py index 670beb303..01fc67a86 100644 --- a/plugins/slicer/MONAILabelReviewer/MONAILabelReviewerLib/ImageDataController.py +++ b/plugins/slicer/MONAILabelReviewer/MONAILabelReviewerLib/ImageDataController.py @@ -235,9 +235,26 @@ def reuqestSegmentation(self, image_id: str, tag: str) -> requests.models.Respon return img_blob def getDicomDownloadUri(self, image_id: str) -> str: + """Return the download URI for an image's DICOM data. + + Parameters: + image_id (str): Identifier of the image. + + Returns: + str: DICOM download URI. + """ return self.monaiServerREST.getDicomDownloadUri(image_id) def requestImage(self, image_id: str) -> requests.models.Response: + """ + Request an image from the MONAI server. + + Parameters: + image_id (str): Identifier of the image to request. + + Returns: + requests.models.Response: The image response, or `None` if the request did not return data. + """ img_blob = self.monaiServerREST.requestImage(image_id) if img_blob is not None: logging.info( @@ -248,6 +265,15 @@ def requestImage(self, image_id: str) -> requests.models.Response: return img_blob def saveLabelInMonaiServer(self, image_in: str, label_in: str, tag: str, params: Dict): + """ + Save a label and its metadata to the MONAI server. + + Parameters: + image_in (str): Identifier or path of the source image. + label_in (str): Identifier or path of the label. + tag (str): Version tag for the label. + params (Dict): Label metadata and update parameters. + """ self.monaiServerREST.saveLabel(image_in, label_in, tag, params) def deleteLabelByVersionTag(self, imageId: str, versionTag: str) -> bool: diff --git a/plugins/slicer/MONAILabelReviewer/MONAILabelReviewerLib/MonaiServerREST.py b/plugins/slicer/MONAILabelReviewer/MONAILabelReviewerLib/MonaiServerREST.py index 42c3ceb01..56e5efd6a 100644 --- a/plugins/slicer/MONAILabelReviewer/MONAILabelReviewerLib/MonaiServerREST.py +++ b/plugins/slicer/MONAILabelReviewer/MONAILabelReviewerLib/MonaiServerREST.py @@ -25,10 +25,21 @@ class MonaiServerREST: def __init__(self, serverUrl: str): + """ + Initialize the REST client with a normalized server URL. + + Parameters: + serverUrl (str): Base URL of the MONAI server. Trailing slashes are removed when provided. + """ self.PARAMS_PREFIX_REST_REQUEST = "params" self.serverUrl = serverUrl.rstrip("/") if serverUrl else serverUrl def getServerUrl(self) -> str: + """Return the configured MONAI server URL. + + Returns: + str: The server URL. + """ return self.serverUrl def getCurrentTime(self) -> datetime: @@ -53,11 +64,28 @@ def requestDataStoreInfo(self) -> dict: return response.json() def getDicomDownloadUri(self, image_id: str) -> str: + """Build the download URI for a DICOM image. + + Parameters: + image_id (str): Identifier of the image to retrieve. + + Returns: + str: The encoded DICOM image download URI. + """ download_uri = f"{self.serverUrl}/datastore/image?image={quote_plus(image_id)}" logging.info(f"{self.getCurrentTime()}: REST: request dicom image '{download_uri}'") return download_uri def requestImage(self, image_id: str) -> requests.models.Response: + """ + Request an image from the MONAI server. + + Parameters: + image_id (str): Identifier of the image to request. + + Returns: + requests.models.Response: The successful image response, or None if the request fails or returns a non-200 status. + """ download_uri = self.getDicomDownloadUri(image_id) try: @@ -81,6 +109,16 @@ def requestImage(self, image_id: str) -> requests.models.Response: return response def requestSegmentation(self, image_id: str, tag: str) -> requests.models.Response: + """ + Request a segmentation for an image using the specified version tag. + + Parameters: + image_id (str): Identifier of the image whose segmentation is requested. + tag (str): Segmentation version tag; an empty string uses the ``final`` tag. + + Returns: + requests.models.Response: The successful HTTP response, or ``None`` if the request fails or returns a non-200 status code. + """ if tag == "": tag = "final" download_uri = f"{self.serverUrl}/datastore/label?label={quote_plus(image_id)}&tag={quote_plus(tag)}" diff --git a/sample-apps/reviewer/app.py b/sample-apps/reviewer/app.py index fb2572255..df9a2c830 100644 --- a/sample-apps/reviewer/app.py +++ b/sample-apps/reviewer/app.py @@ -65,7 +65,17 @@ def __init__(self, app_dir: str, studies: str, conf: Dict): logger.info(f"Studies: {self.review_config['studies']}") def _load_review_config(self, studies: str, conf: Dict) -> Dict[str, Any]: - """Load review-specific configuration.""" + """ + Load review configuration from supplied values and environment variables. + + Parameters: + studies (str): Path or identifier for the studies datastore. + conf (Dict): Optional configuration values. + + Returns: + Dict[str, Any]: Resolved review configuration, including server, datastore, + reviewer, and mode settings. + """ conf_dict = conf or {} config = { @@ -86,29 +96,46 @@ def _load_review_config(self, studies: str, conf: Dict) -> Dict[str, Any]: return config def init_infers(self) -> Dict[str, Any]: + """Indicate that this application provides no inference components. + + Returns: + Dict[str, Any]: An empty dictionary. + """ return {} def init_trainers(self) -> Dict[str, Any]: + """ + Indicate that the application has no training components. + + Returns: + Dict[str, Any]: An empty dictionary. + """ return {} def init_strategies(self) -> Dict[str, Any]: + """ + Indicate that the application provides no strategy components. + + Returns: + Dict[str, Any]: An empty dictionary. + """ return {} def init_scoring_methods(self) -> Dict[str, Any]: + """Indicate that no scoring methods are configured. + + Returns: + Dict[str, Any]: An empty dictionary. + """ return {} def info(self) -> Dict[str, Any]: """ - Get application information. - + Provide application metadata and review workflow capabilities. + Returns: - { - "name": "MONAILabel Reviewer", - "description": "Lightweight review app", - "version": "1.0.0", - "studies": "/path/to/images", - "config": {...} - } + Dict[str, Any]: Application metadata including the resolved studies path, + review configuration, supported features, and review-only mode. """ meta = super().info() meta.update( diff --git a/sample-apps/reviewer/client.py b/sample-apps/reviewer/client.py index bd44f7d19..4506f8a40 100644 --- a/sample-apps/reviewer/client.py +++ b/sample-apps/reviewer/client.py @@ -48,11 +48,11 @@ class LightweightReviewClient: def __init__(self, server_url: str = "http://localhost:8000", timeout: int = 30): """ - Initialize lightweight review client. - + Initialize a review client for the specified MONAI Label server. + Parameters: - - server_url: MONAI Label server URL - - timeout: Request timeout in seconds + server_url (str): MONAI Label server URL. + timeout (int): Request timeout in seconds. """ self.server_url = server_url.rstrip("/") self.timeout = timeout @@ -64,7 +64,12 @@ def __init__(self, server_url: str = "http://localhost:8000", timeout: int = 30) logger.info(f"ReviewClient initialized: {self.server_url}") def ping(self) -> bool: - """Check if server is reachable.""" + """ + Check whether the server responds successfully. + + Returns: + bool: `True` if the server responds with HTTP status 200, `False` otherwise. + """ try: response = requests.get(f"{self.server_url}", timeout=5) status = response.status_code == 200 @@ -79,24 +84,15 @@ def ping(self) -> bool: def list_images(self, offset: int = 0, limit: int = 100, status_filter: Optional[str] = None) -> Dict[str, Any]: """ - List all images available for review. - - Query Parameters: - - offset: Pagination offset (default: 0) - - limit: Pagination limit (default: 100) - - status_filter: Filter by status (approved/flagged/unapproved) - + List reviewable images with optional pagination and status filtering. + + Parameters: + offset (int): Number of images to skip. + limit (int): Maximum number of images to return. + status_filter (Optional[str]): Status by which to filter images. + Returns: - { - "summary": { - "total": 100, - "approved": 45, - "flagged": 5, - "pending": 50 - }, - "results": [...list of image metadata...], - "metadata": {...} - } + Dict[str, Any]: Review case data on success, or an error dictionary if the request fails. """ try: params = {"limit": str(limit), "offset": str(offset)} @@ -121,13 +117,13 @@ def list_images(self, offset: int = 0, limit: int = 100, status_filter: Optional def download_image(self, image_id: str) -> bytes: """ - Download DICOM image data. - + Download the image data identified by `image_id`. + Parameters: - - image_id: Unique identifier for the image - + image_id (str): Unique identifier of the image. + Returns: - Image file bytes in original format + bytes: Image data in its original format, or `None` if the download fails. """ try: response = requests.get( @@ -148,20 +144,14 @@ def download_image(self, image_id: str) -> bytes: def download_label(self, label_id: str, tag: str = "final") -> Dict[str, Any]: """ - Download segmentation label or mask. - + Download a segmentation label for the specified version. + Parameters: - - label_id: Label/segmentation ID - - tag: Label version/tag (default: final) - + label_id (str): Identifier of the label to download. + tag (str): Version or tag of the label. + Returns: - { - "status": "success", - "label_id": "label_001", - "tag": "final", - "data": {binary representation}, - "metadata": {...} - } + Dict[str, Any] or None: The decoded label data, or None if the request fails. """ try: response = requests.get( @@ -182,17 +172,13 @@ def download_label(self, label_id: str, tag: str = "final") -> Dict[str, Any]: def download_labelinfo(self, label_id: str) -> Dict[str, Any]: """ - Download label metadata. - + Download metadata for a label using its final version. + Parameters: - - label_id: Label/segmentation ID - + label_id (str): Identifier of the label whose metadata to retrieve. + Returns: - { - "status": "success", - "label_id": "label_001", - "info": {...metadata...} - } + Dict[str, Any] | None: The label metadata, or None if the request fails. """ try: response = requests.get( @@ -223,19 +209,19 @@ def update_labelinfo( workflow_id: Optional[str] = None, ) -> bool: """ - Update label metadata for review. - + Update review metadata for a label. + Parameters: - - label_id: Label/segmentation ID - - status: "approved" | "flagged" | "unapproved" - - level: "easy" | "medium" | "hard" - - comment: Review comment text - - reviewer_name: Name of reviewer - - reviewer_email: Email of reviewer - - workflow_id: Optional workflow identifier - + label_id (str): Label or segmentation identifier. + status (str): Review status to assign. + level (Optional[str]): Review difficulty level. + comment (Optional[str]): Review comment. + reviewer_name (Optional[str]): Name of the reviewer. + reviewer_email (Optional[str]): Email address of the reviewer. + workflow_id (Optional[str]): Workflow identifier. + Returns: - True on success, False on failure + bool: True if the metadata update succeeds; False otherwise. """ try: review_info = {"status": status, "reviewer_name": reviewer_name, "workflow_id": workflow_id} @@ -279,18 +265,18 @@ def save_label( version_note: Optional[str] = None, ) -> bool: """ - Save a new or updated segmentation label. - + Upload a segmentation label for an image. + Parameters: - - image_id: Image ID - - label_file: Path to segmentation file - - tag: Label version/tag - - reviewer_name: Name of reviewer/saver - - comment: Optional comment about this version - - version_note: Reason for this version - + image_id (str): Identifier of the image associated with the label. + label_file (Path): Path to the label file to upload. + tag (str): Version tag for the label. + reviewer_name (str): Name of the reviewer submitting the label. + comment (Optional[str]): Comment associated with the label. + version_note (Optional[str]): Note describing the label version. + Returns: - True on success, False on failure + bool: True if the label is saved successfully, False otherwise. """ try: # Prepare approvals data @@ -326,17 +312,13 @@ def save_label( def get_versions(self, image_id: str) -> Dict[str, Any]: """ - List all available versions for an image. - + List the available label versions for an image. + Parameters: - - image_id: Image ID - + image_id (str): Identifier of the image whose label versions to retrieve. + Returns: - { - "status": "success", - "image_id": "CT_abdomen_001", - "versions": [...] - } + Dict[str, Any]: Version information on success, or an error dictionary if the request fails. """ try: response = requests.get( @@ -357,14 +339,14 @@ def get_versions(self, image_id: str) -> Dict[str, Any]: def generate_report(self, fmt: str = "json", reviewer: str = None) -> Dict[str, Any]: """ - Generate a review summary report. - + Generate a review summary report, optionally filtered by reviewer. + Parameters: - - fmt: Report format ("json", "csv", "html") - - reviewer: Optional reviewer filter - + fmt (str): Requested report format, such as "json", "csv", or "html". + reviewer (str): Optional reviewer name used to filter the report. + Returns: - Report data + Dict[str, Any]: Report data on success, or an error dictionary when the request fails. """ try: response = requests.get( diff --git a/sample-apps/reviewer/lib/config.py b/sample-apps/reviewer/lib/config.py index 8fa98271e..399295d12 100644 --- a/sample-apps/reviewer/lib/config.py +++ b/sample-apps/reviewer/lib/config.py @@ -33,15 +33,14 @@ def __init__( mode: str = "review", ): """ - Initialize reviewer configuration. - + Initialize reviewer configuration from arguments and environment variables. + Parameters: - - server_url: MONAI Label server URL (e.g., http://localhost:8000) - If None, runs in standalone mode using local cache - - cache_dir: Directory for cache storage - - reviewer_name: Name of the reviewer - - reviewer_email: Email of the reviewer - - mode: Operating mode - "review" (requires server) or "standalone" (local cache only) + server_url (Optional[str]): URL of the MONAI Label server. + cache_dir (Optional[str]): Directory used for review data caching. + reviewer_name (Optional[str]): Display name of the reviewer. + reviewer_email (Optional[str]): Email address of the reviewer. + mode (str): Operating mode, such as ``"review"`` or ``"standalone"``. """ # Resolve server URL self.server_url = server_url @@ -92,14 +91,25 @@ def anaconda_channel(self) -> str: @property def server_mode(self) -> str: - """Return the server mode description.""" + """Describe whether the reviewer operates in standalone or server-synchronized mode. + + Returns: + str: The current review mode description. + """ if self.review_only: return "Lightweight Review Mode (Standalone)" else: return "Full Review Mode with Server Sync" def dict(self) -> dict: - """Return configuration as dictionary.""" + """ + Export the review configuration and its derived operating settings. + + Returns: + dict: Configuration values including server details, reviewer identity, + review mode, workspace settings, history and cache limits, server mode, + and synchronization status. + """ return { "server_url": self.server_url, "cache_dir": self.cache_dir, From 53aef15aac0cf242ddff1eac03657a26d87c41f5 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 27 Jul 2026 16:52:41 +0000 Subject: [PATCH 2/2] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- monailabel/datastore/local.py | 16 +-- monailabel/endpoints/datastore_review.py | 100 +++++++++--------- .../MONAILabelReviewer/MONAILabelReviewer.py | 36 +++---- .../ImageDataController.py | 10 +- .../MONAILabelReviewerLib/MonaiServerREST.py | 18 ++-- sample-apps/reviewer/app.py | 14 +-- sample-apps/reviewer/client.py | 40 +++---- sample-apps/reviewer/lib/config.py | 6 +- 8 files changed, 120 insertions(+), 120 deletions(-) diff --git a/monailabel/datastore/local.py b/monailabel/datastore/local.py index bff92019b..2a9dc8499 100644 --- a/monailabel/datastore/local.py +++ b/monailabel/datastore/local.py @@ -219,10 +219,10 @@ def set_description(self, description: str): def _to_id(self, file: str) -> Tuple[str, str]: """ Derive an identifier and extension from a filename using the configured file extensions. - + Parameters: file (str): Filename to parse. - + Returns: Tuple[str, str]: The identifier and matched extension. """ @@ -236,10 +236,10 @@ def _to_id(self, file: str) -> Tuple[str, str]: def _to_label_id(self, file: str) -> Tuple[str, str]: """Convert a label filename to its identifier and extension. - + Parameters: file (str): Label filename to parse. - + Returns: Tuple[str, str]: The label identifier and file extension. """ @@ -249,11 +249,11 @@ def _to_label_id(self, file: str) -> Tuple[str, str]: def _filename(self, id: str, ext: str) -> str: """Construct a filename by concatenating an identifier with its extension. - + Parameters: id (str): The file identifier. ext (str): The file extension. - + Returns: str: The resulting filename. """ @@ -639,10 +639,10 @@ def _add_non_existing_images(self) -> int: def _add_non_existing_labels(self, tag) -> int: """ Add label metadata for label files that exist on disk but are missing from the datastore. - + Parameters: tag (str): Label tag identifying the directory containing the label files. - + Returns: int: Number of labels added to the datastore. """ diff --git a/monailabel/endpoints/datastore_review.py b/monailabel/endpoints/datastore_review.py index 84d49289c..5cb180a7f 100644 --- a/monailabel/endpoints/datastore_review.py +++ b/monailabel/endpoints/datastore_review.py @@ -40,11 +40,11 @@ def _safe_label_info(datastore, image_id: str, tag: str) -> Dict[str, Any]: """ Retrieve label metadata for an image and tag. - + Parameters: image_id (str): Identifier of the image. tag (str): Label tag used to locate the metadata. - + Returns: Dict[str, Any]: The label metadata when it is a dictionary; otherwise, an empty dictionary. """ @@ -61,15 +61,15 @@ def _safe_label_info(datastore, image_id: str, tag: str) -> Dict[str, Any]: def _parse_date_range(date_range: Optional[str]) -> Optional[Tuple[datetime, datetime]]: """ Parse an optional comma-separated ISO timestamp range. - + Parameters: - date_range (Optional[str]): Range in the form ``start,end``. - + date_range (Optional[str]): Range in the form ``start,end``. + Returns: - Optional[Tuple[datetime, datetime]]: The parsed start and end timestamps, or ``None`` when no range is provided. - + Optional[Tuple[datetime, datetime]]: The parsed start and end timestamps, or ``None`` when no range is provided. + Raises: - HTTPException: If the range is incomplete or contains invalid ISO timestamps. + HTTPException: If the range is incomplete or contains invalid ISO timestamps. """ if not date_range: return None @@ -87,13 +87,13 @@ def _parse_date_range(date_range: Optional[str]) -> Optional[Tuple[datetime, dat def _matches_date_range(value: Optional[str], parsed: Optional[Tuple[datetime, datetime]]) -> bool: """ Determine whether a timestamp falls within an optional inclusive date range. - + Parameters: - value (Optional[str]): ISO-formatted timestamp to evaluate. - parsed (Optional[Tuple[datetime, datetime]]): Inclusive start and end timestamps, or `None` to disable filtering. - + value (Optional[str]): ISO-formatted timestamp to evaluate. + parsed (Optional[Tuple[datetime, datetime]]): Inclusive start and end timestamps, or `None` to disable filtering. + Returns: - bool: `true` if filtering is disabled or the timestamp falls within the range, `false` otherwise. + bool: `true` if filtering is disabled or the timestamp falls within the range, `false` otherwise. """ if not parsed: return True @@ -112,12 +112,12 @@ def _matches_date_range(value: Optional[str], parsed: Optional[Tuple[datetime, d def _review_case(datastore, image_id: str, tag: str) -> Dict[str, Any]: """ Build a review record containing image metadata, review details, and label status. - + Parameters: datastore: Datastore used to retrieve image, label, and review information. image_id (str): Identifier of the image. tag (str): Label tag associated with the review. - + Returns: Dict[str, Any]: Review record with derived status, reviewer information, and label presence. """ @@ -153,19 +153,19 @@ def _list_review_cases( ) -> List[Dict[str, Any]]: """ Collect review cases that match the specified status, image, reviewer, date, and label tag filters. - + Parameters: - status_filter (Optional[str]): Review status to match. - search (Optional[str]): Comma-separated image IDs to include. - reviewer (Optional[str]): Reviewer name to match. - date_range (Optional[str]): ISO timestamp range in the format ``start,end``. - tag (str): Label tag used to build each review case. - + status_filter (Optional[str]): Review status to match. + search (Optional[str]): Comma-separated image IDs to include. + reviewer (Optional[str]): Reviewer name to match. + date_range (Optional[str]): ISO timestamp range in the format ``start,end``. + tag (str): Label tag used to build each review case. + Returns: - List[Dict[str, Any]]: Review cases that satisfy all provided filters. - + List[Dict[str, Any]]: Review cases that satisfy all provided filters. + Raises: - HTTPException: If ``date_range`` is not a valid ISO timestamp range. + HTTPException: If ``date_range`` is not a valid ISO timestamp range. """ datastore = app_instance().datastore() image_ids = datastore.list_images() @@ -195,12 +195,12 @@ def _list_review_cases( def _summary(items: List[Dict[str, Any]]) -> Dict[str, int]: """ Count review cases by overall total and status. - + Parameters: - items (List[Dict[str, Any]]): Review case records containing a status field. - + items (List[Dict[str, Any]]): Review case records containing a status field. + Returns: - Dict[str, int]: Counts for total, approved, flagged, pending, and unlabeled cases. + Dict[str, int]: Counts for total, approved, flagged, pending, and unlabeled cases. """ return { "total": len(items), @@ -214,10 +214,10 @@ def _summary(items: List[Dict[str, Any]]) -> Dict[str, int]: def _report_stats(items: List[Dict[str, Any]]) -> Dict[str, Any]: """ Summarize review cases by status and difficulty level. - + Parameters: items (List[Dict[str, Any]]): Review case records to summarize. - + Returns: Dict[str, Any]: Status and difficulty counts with the current recording timestamp. """ @@ -233,12 +233,12 @@ def _report_stats(items: List[Dict[str, Any]]) -> Dict[str, Any]: def _render_csv(items: List[Dict[str, Any]]) -> str: """ Render review case records as CSV text. - + Parameters: - items (List[Dict[str, Any]]): Review case records to include in the CSV output. - + items (List[Dict[str, Any]]): Review case records to include in the CSV output. + Returns: - str: CSV text containing a header row and one row for each review case. + str: CSV text containing a header row and one row for each review case. """ handle = io.StringIO() writer = csv.writer(handle) @@ -261,10 +261,10 @@ def _render_csv(items: List[Dict[str, Any]]) -> str: def _render_html(stats: Dict[str, Any]) -> str: """ Render review statistics as an HTML report. - + Parameters: stats (Dict[str, Any]): Statistics and generation timestamp to include in the report. - + Returns: str: An HTML document containing review status and difficulty counts with percentages. """ @@ -272,13 +272,13 @@ def _render_html(stats: Dict[str, Any]) -> str: def row(name: str, value: int) -> str: """Render an HTML table row containing a label, count, and percentage of the total. - + Parameters: - name (str): The label displayed in the row. - value (int): The count used to calculate the percentage. - + name (str): The label displayed in the row. + value (int): The count used to calculate the percentage. + Returns: - str: An escaped HTML table row with the label, count, and percentage. + str: An escaped HTML table row with the label, count, and percentage. """ return f"{escape(name)}{value}" f"{(100.0 * value / total):.1f}%" @@ -313,7 +313,7 @@ async def api_review_cases( ): """ List filtered review cases with pagination and aggregate status counts. - + Parameters: offset (int): Number of matching cases to skip. limit (int): Maximum number of cases to include in the results. @@ -322,7 +322,7 @@ async def api_review_cases( reviewer (Optional[str]): Reviewer name used to filter cases. date_range (Optional[str]): ISO timestamp range in the format ``start,end``. tag (str): Label tag used to build the review cases. - + Returns: Dict[str, Any]: A response containing summary counts, paginated results, and filter metadata. """ @@ -349,13 +349,13 @@ async def api_review_versions( ): """ Retrieve the available label versions for an image. - + Parameters: image (str): Identifier of the image whose label versions are requested. - + Returns: dict: A success response containing the image identifier and version metadata. - + Raises: HTTPException: If no labels are found for the image. """ @@ -391,17 +391,17 @@ async def api_review_report( ): """ Generate a review report in JSON, CSV, or HTML format. - + Parameters: fmt (str): Output format: `"json"`, `"csv"`, or `"html"`. reviewer (Optional[str]): Limits results to a specific reviewer. date_range (Optional[str]): ISO timestamp range in `start,end` format. tag (str): Label tag used to select review cases. - + Returns: dict: A formatted report containing review statistics and, for JSON output, the applied filters and matching review cases. - + Raises: HTTPException: If `fmt` is not `"json"`, `"csv"`, or `"html"`. """ diff --git a/plugins/slicer/MONAILabelReviewer/MONAILabelReviewer.py b/plugins/slicer/MONAILabelReviewer/MONAILabelReviewer.py index 2b9586517..322c5681f 100644 --- a/plugins/slicer/MONAILabelReviewer/MONAILabelReviewer.py +++ b/plugins/slicer/MONAILabelReviewer/MONAILabelReviewer.py @@ -442,12 +442,12 @@ def loadServerSelection(self): def normalizeServerUrl(self, serverUrl: str) -> str: """ Normalize a server URL for consistent use by removing surrounding whitespace and trailing slashes. - + Parameters: - serverUrl (str): The server URL to normalize. - + serverUrl (str): The server URL to normalize. + Returns: - str: The normalized server URL, or an empty string when no URL is provided. + str: The normalized server URL, or an empty string when no URL is provided. """ if not serverUrl: return "" @@ -456,7 +456,7 @@ def normalizeServerUrl(self, serverUrl: str) -> str: def init_dicom_stream(self): """ Connect to the configured MONAI Label server and initialize the reviewer interface. - + The selected server URL is normalized before connection. Displays a warning and leaves the interface uninitialized when the connection fails. """ @@ -1513,7 +1513,7 @@ def updateAfterEditingSegmentation(self): def reloadImageAfterEditingLabel(self): """ Reload the current image using its latest label version after an edit. - + The image display and label version selector are refreshed to reflect the updated segmentation. """ imageId = self.currentImageData.getFileName() @@ -1525,8 +1525,8 @@ def reloadImageAfterEditingLabel(self): def processDataStoreRecords(self): """ Process datastore records and display a warning when processing fails. - - The selected server address is normalized for inclusion in failure messages. + + The selected server address is normalized for inclusion in failure messages. """ serverUrl: str = self.normalizeServerUrl(self.ui.comboBox_server_url.currentText) result: bool = self.logic.initMetaDataProcessing() @@ -1693,7 +1693,7 @@ def updateLabelInfo( def loadDicomAndSegmentation(self, imageData: ImageData, tag: str): """ Load an image and, when available, its segmentation into the Slicer scene. - + Parameters: imageData (ImageData): Image metadata used to retrieve the DICOM image and segmentation. tag (str): Version tag identifying the segmentation to load. @@ -1742,23 +1742,23 @@ def getPathToStore(self, segmentationFileName: str, tempDirectory: str) -> str: def displaySegmention(self, destination: str): """ Display a segmentation file in the Slicer window. - + Parameters: - destination (str): Path to the segmentation file. + destination (str): Path to the segmentation file. """ segmentation = slicer.util.loadSegmentation(destination) def requestDicomImage(self, image_id: str, image_name: str, node_name: str): """ Download an image from the MONAI Label server and load it into Slicer. - + Parameters: - image_id (str): Identifier of the image to download. - image_name (str): File name used for temporary storage. - node_name (str): Name associated with the image node. - + image_id (str): Identifier of the image to download. + image_name (str): File name used for temporary storage. + node_name (str): Name associated with the image node. + Raises: - RuntimeError: If the server does not return the image. + RuntimeError: If the server does not return the image. """ response = self.imageDataController.requestImage(image_id) if response is None: @@ -1774,7 +1774,7 @@ def requestDicomImage(self, image_id: str, image_name: str, node_name: str): def setTempFolderDir(self): """ Create the temporary directory used to store downloaded segmentation files. - + The directory is created only once and its path is logged. """ if self.temp_dir is None: diff --git a/plugins/slicer/MONAILabelReviewer/MONAILabelReviewerLib/ImageDataController.py b/plugins/slicer/MONAILabelReviewer/MONAILabelReviewerLib/ImageDataController.py index 01fc67a86..71f799712 100644 --- a/plugins/slicer/MONAILabelReviewer/MONAILabelReviewerLib/ImageDataController.py +++ b/plugins/slicer/MONAILabelReviewer/MONAILabelReviewerLib/ImageDataController.py @@ -236,10 +236,10 @@ def reuqestSegmentation(self, image_id: str, tag: str) -> requests.models.Respon def getDicomDownloadUri(self, image_id: str) -> str: """Return the download URI for an image's DICOM data. - + Parameters: image_id (str): Identifier of the image. - + Returns: str: DICOM download URI. """ @@ -248,10 +248,10 @@ def getDicomDownloadUri(self, image_id: str) -> str: def requestImage(self, image_id: str) -> requests.models.Response: """ Request an image from the MONAI server. - + Parameters: image_id (str): Identifier of the image to request. - + Returns: requests.models.Response: The image response, or `None` if the request did not return data. """ @@ -267,7 +267,7 @@ def requestImage(self, image_id: str) -> requests.models.Response: def saveLabelInMonaiServer(self, image_in: str, label_in: str, tag: str, params: Dict): """ Save a label and its metadata to the MONAI server. - + Parameters: image_in (str): Identifier or path of the source image. label_in (str): Identifier or path of the label. diff --git a/plugins/slicer/MONAILabelReviewer/MONAILabelReviewerLib/MonaiServerREST.py b/plugins/slicer/MONAILabelReviewer/MONAILabelReviewerLib/MonaiServerREST.py index 56e5efd6a..c4dbbb0dc 100644 --- a/plugins/slicer/MONAILabelReviewer/MONAILabelReviewerLib/MonaiServerREST.py +++ b/plugins/slicer/MONAILabelReviewer/MONAILabelReviewerLib/MonaiServerREST.py @@ -27,7 +27,7 @@ class MonaiServerREST: def __init__(self, serverUrl: str): """ Initialize the REST client with a normalized server URL. - + Parameters: serverUrl (str): Base URL of the MONAI server. Trailing slashes are removed when provided. """ @@ -36,9 +36,9 @@ def __init__(self, serverUrl: str): def getServerUrl(self) -> str: """Return the configured MONAI server URL. - + Returns: - str: The server URL. + str: The server URL. """ return self.serverUrl @@ -65,10 +65,10 @@ def requestDataStoreInfo(self) -> dict: def getDicomDownloadUri(self, image_id: str) -> str: """Build the download URI for a DICOM image. - + Parameters: image_id (str): Identifier of the image to retrieve. - + Returns: str: The encoded DICOM image download URI. """ @@ -79,10 +79,10 @@ def getDicomDownloadUri(self, image_id: str) -> str: def requestImage(self, image_id: str) -> requests.models.Response: """ Request an image from the MONAI server. - + Parameters: image_id (str): Identifier of the image to request. - + Returns: requests.models.Response: The successful image response, or None if the request fails or returns a non-200 status. """ @@ -111,11 +111,11 @@ def requestImage(self, image_id: str) -> requests.models.Response: def requestSegmentation(self, image_id: str, tag: str) -> requests.models.Response: """ Request a segmentation for an image using the specified version tag. - + Parameters: image_id (str): Identifier of the image whose segmentation is requested. tag (str): Segmentation version tag; an empty string uses the ``final`` tag. - + Returns: requests.models.Response: The successful HTTP response, or ``None`` if the request fails or returns a non-200 status code. """ diff --git a/sample-apps/reviewer/app.py b/sample-apps/reviewer/app.py index df9a2c830..afefa8fa4 100644 --- a/sample-apps/reviewer/app.py +++ b/sample-apps/reviewer/app.py @@ -67,11 +67,11 @@ def __init__(self, app_dir: str, studies: str, conf: Dict): def _load_review_config(self, studies: str, conf: Dict) -> Dict[str, Any]: """ Load review configuration from supplied values and environment variables. - + Parameters: studies (str): Path or identifier for the studies datastore. conf (Dict): Optional configuration values. - + Returns: Dict[str, Any]: Resolved review configuration, including server, datastore, reviewer, and mode settings. @@ -97,7 +97,7 @@ def _load_review_config(self, studies: str, conf: Dict) -> Dict[str, Any]: def init_infers(self) -> Dict[str, Any]: """Indicate that this application provides no inference components. - + Returns: Dict[str, Any]: An empty dictionary. """ @@ -106,7 +106,7 @@ def init_infers(self) -> Dict[str, Any]: def init_trainers(self) -> Dict[str, Any]: """ Indicate that the application has no training components. - + Returns: Dict[str, Any]: An empty dictionary. """ @@ -115,7 +115,7 @@ def init_trainers(self) -> Dict[str, Any]: def init_strategies(self) -> Dict[str, Any]: """ Indicate that the application provides no strategy components. - + Returns: Dict[str, Any]: An empty dictionary. """ @@ -123,7 +123,7 @@ def init_strategies(self) -> Dict[str, Any]: def init_scoring_methods(self) -> Dict[str, Any]: """Indicate that no scoring methods are configured. - + Returns: Dict[str, Any]: An empty dictionary. """ @@ -132,7 +132,7 @@ def init_scoring_methods(self) -> Dict[str, Any]: def info(self) -> Dict[str, Any]: """ Provide application metadata and review workflow capabilities. - + Returns: Dict[str, Any]: Application metadata including the resolved studies path, review configuration, supported features, and review-only mode. diff --git a/sample-apps/reviewer/client.py b/sample-apps/reviewer/client.py index 4506f8a40..5fa480140 100644 --- a/sample-apps/reviewer/client.py +++ b/sample-apps/reviewer/client.py @@ -49,10 +49,10 @@ class LightweightReviewClient: def __init__(self, server_url: str = "http://localhost:8000", timeout: int = 30): """ Initialize a review client for the specified MONAI Label server. - + Parameters: - server_url (str): MONAI Label server URL. - timeout (int): Request timeout in seconds. + server_url (str): MONAI Label server URL. + timeout (int): Request timeout in seconds. """ self.server_url = server_url.rstrip("/") self.timeout = timeout @@ -66,7 +66,7 @@ def __init__(self, server_url: str = "http://localhost:8000", timeout: int = 30) def ping(self) -> bool: """ Check whether the server responds successfully. - + Returns: bool: `True` if the server responds with HTTP status 200, `False` otherwise. """ @@ -85,12 +85,12 @@ def ping(self) -> bool: def list_images(self, offset: int = 0, limit: int = 100, status_filter: Optional[str] = None) -> Dict[str, Any]: """ List reviewable images with optional pagination and status filtering. - + Parameters: offset (int): Number of images to skip. limit (int): Maximum number of images to return. status_filter (Optional[str]): Status by which to filter images. - + Returns: Dict[str, Any]: Review case data on success, or an error dictionary if the request fails. """ @@ -118,10 +118,10 @@ def list_images(self, offset: int = 0, limit: int = 100, status_filter: Optional def download_image(self, image_id: str) -> bytes: """ Download the image data identified by `image_id`. - + Parameters: image_id (str): Unique identifier of the image. - + Returns: bytes: Image data in its original format, or `None` if the download fails. """ @@ -145,11 +145,11 @@ def download_image(self, image_id: str) -> bytes: def download_label(self, label_id: str, tag: str = "final") -> Dict[str, Any]: """ Download a segmentation label for the specified version. - + Parameters: label_id (str): Identifier of the label to download. tag (str): Version or tag of the label. - + Returns: Dict[str, Any] or None: The decoded label data, or None if the request fails. """ @@ -173,10 +173,10 @@ def download_label(self, label_id: str, tag: str = "final") -> Dict[str, Any]: def download_labelinfo(self, label_id: str) -> Dict[str, Any]: """ Download metadata for a label using its final version. - + Parameters: label_id (str): Identifier of the label whose metadata to retrieve. - + Returns: Dict[str, Any] | None: The label metadata, or None if the request fails. """ @@ -210,7 +210,7 @@ def update_labelinfo( ) -> bool: """ Update review metadata for a label. - + Parameters: label_id (str): Label or segmentation identifier. status (str): Review status to assign. @@ -219,7 +219,7 @@ def update_labelinfo( reviewer_name (Optional[str]): Name of the reviewer. reviewer_email (Optional[str]): Email address of the reviewer. workflow_id (Optional[str]): Workflow identifier. - + Returns: bool: True if the metadata update succeeds; False otherwise. """ @@ -266,7 +266,7 @@ def save_label( ) -> bool: """ Upload a segmentation label for an image. - + Parameters: image_id (str): Identifier of the image associated with the label. label_file (Path): Path to the label file to upload. @@ -274,7 +274,7 @@ def save_label( reviewer_name (str): Name of the reviewer submitting the label. comment (Optional[str]): Comment associated with the label. version_note (Optional[str]): Note describing the label version. - + Returns: bool: True if the label is saved successfully, False otherwise. """ @@ -313,10 +313,10 @@ def save_label( def get_versions(self, image_id: str) -> Dict[str, Any]: """ List the available label versions for an image. - + Parameters: image_id (str): Identifier of the image whose label versions to retrieve. - + Returns: Dict[str, Any]: Version information on success, or an error dictionary if the request fails. """ @@ -340,11 +340,11 @@ def get_versions(self, image_id: str) -> Dict[str, Any]: def generate_report(self, fmt: str = "json", reviewer: str = None) -> Dict[str, Any]: """ Generate a review summary report, optionally filtered by reviewer. - + Parameters: fmt (str): Requested report format, such as "json", "csv", or "html". reviewer (str): Optional reviewer name used to filter the report. - + Returns: Dict[str, Any]: Report data on success, or an error dictionary when the request fails. """ diff --git a/sample-apps/reviewer/lib/config.py b/sample-apps/reviewer/lib/config.py index 399295d12..4a0098e0c 100644 --- a/sample-apps/reviewer/lib/config.py +++ b/sample-apps/reviewer/lib/config.py @@ -34,7 +34,7 @@ def __init__( ): """ Initialize reviewer configuration from arguments and environment variables. - + Parameters: server_url (Optional[str]): URL of the MONAI Label server. cache_dir (Optional[str]): Directory used for review data caching. @@ -92,7 +92,7 @@ def anaconda_channel(self) -> str: @property def server_mode(self) -> str: """Describe whether the reviewer operates in standalone or server-synchronized mode. - + Returns: str: The current review mode description. """ @@ -104,7 +104,7 @@ def server_mode(self) -> str: def dict(self) -> dict: """ Export the review configuration and its derived operating settings. - + Returns: dict: Configuration values including server details, reviewer identity, review mode, workspace settings, history and cache limits, server mode,