aignostics 0.2.30__tar.gz → 0.2.31__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. {aignostics-0.2.30 → aignostics-0.2.31}/PKG-INFO +1 -1
  2. {aignostics-0.2.30 → aignostics-0.2.31}/examples/notebook.py +1 -1
  3. {aignostics-0.2.30 → aignostics-0.2.31}/pyproject.toml +2 -2
  4. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/application/_gui/_page_application_describe.py +1 -1
  5. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/application/_gui/_page_application_run_describe.py +1 -1
  6. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/dataset/_gui.py +1 -1
  7. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/qupath/_cli.py +20 -11
  8. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/qupath/_gui.py +25 -14
  9. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/qupath/_service.py +304 -125
  10. aignostics-0.2.31/src/aignostics/qupath/annotate.groovy +79 -0
  11. aignostics-0.2.31/src/aignostics/qupath/assets/update.lottie +0 -0
  12. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/utils/_fs.py +18 -20
  13. {aignostics-0.2.30 → aignostics-0.2.31}/.gitignore +0 -0
  14. {aignostics-0.2.30 → aignostics-0.2.31}/LICENSE +0 -0
  15. {aignostics-0.2.30 → aignostics-0.2.31}/README.md +0 -0
  16. {aignostics-0.2.30 → aignostics-0.2.31}/codegen/out/.openapi-generator/FILES +0 -0
  17. {aignostics-0.2.30 → aignostics-0.2.31}/codegen/out/.openapi-generator/VERSION +0 -0
  18. {aignostics-0.2.30 → aignostics-0.2.31}/codegen/out/aignx/codegen/api/public_api.py +0 -0
  19. {aignostics-0.2.30 → aignostics-0.2.31}/codegen/out/aignx/codegen/api_client.py +0 -0
  20. {aignostics-0.2.30 → aignostics-0.2.31}/codegen/out/aignx/codegen/api_response.py +0 -0
  21. {aignostics-0.2.30 → aignostics-0.2.31}/codegen/out/aignx/codegen/configuration.py +0 -0
  22. {aignostics-0.2.30 → aignostics-0.2.31}/codegen/out/aignx/codegen/exceptions.py +0 -0
  23. {aignostics-0.2.30 → aignostics-0.2.31}/codegen/out/aignx/codegen/models/__init__.py +0 -0
  24. {aignostics-0.2.30 → aignostics-0.2.31}/codegen/out/aignx/codegen/models/application_read_response.py +0 -0
  25. {aignostics-0.2.30 → aignostics-0.2.31}/codegen/out/aignx/codegen/models/application_run_status.py +0 -0
  26. {aignostics-0.2.30 → aignostics-0.2.31}/codegen/out/aignx/codegen/models/application_version_read_response.py +0 -0
  27. {aignostics-0.2.30 → aignostics-0.2.31}/codegen/out/aignx/codegen/models/http_validation_error.py +0 -0
  28. {aignostics-0.2.30 → aignostics-0.2.31}/codegen/out/aignx/codegen/models/input_artifact_creation_request.py +0 -0
  29. {aignostics-0.2.30 → aignostics-0.2.31}/codegen/out/aignx/codegen/models/input_artifact_read_response.py +0 -0
  30. {aignostics-0.2.30 → aignostics-0.2.31}/codegen/out/aignx/codegen/models/item_creation_request.py +0 -0
  31. {aignostics-0.2.30 → aignostics-0.2.31}/codegen/out/aignx/codegen/models/item_result_read_response.py +0 -0
  32. {aignostics-0.2.30 → aignostics-0.2.31}/codegen/out/aignx/codegen/models/item_status.py +0 -0
  33. {aignostics-0.2.30 → aignostics-0.2.31}/codegen/out/aignx/codegen/models/output_artifact_read_response.py +0 -0
  34. {aignostics-0.2.30 → aignostics-0.2.31}/codegen/out/aignx/codegen/models/output_artifact_result_read_response.py +0 -0
  35. {aignostics-0.2.30 → aignostics-0.2.31}/codegen/out/aignx/codegen/models/output_artifact_scope.py +0 -0
  36. {aignostics-0.2.30 → aignostics-0.2.31}/codegen/out/aignx/codegen/models/payload_input_artifact.py +0 -0
  37. {aignostics-0.2.30 → aignostics-0.2.31}/codegen/out/aignx/codegen/models/payload_item.py +0 -0
  38. {aignostics-0.2.30 → aignostics-0.2.31}/codegen/out/aignx/codegen/models/payload_output_artifact.py +0 -0
  39. {aignostics-0.2.30 → aignostics-0.2.31}/codegen/out/aignx/codegen/models/run_creation_request.py +0 -0
  40. {aignostics-0.2.30 → aignostics-0.2.31}/codegen/out/aignx/codegen/models/run_creation_response.py +0 -0
  41. {aignostics-0.2.30 → aignostics-0.2.31}/codegen/out/aignx/codegen/models/run_read_response.py +0 -0
  42. {aignostics-0.2.30 → aignostics-0.2.31}/codegen/out/aignx/codegen/models/transfer_urls.py +0 -0
  43. {aignostics-0.2.30 → aignostics-0.2.31}/codegen/out/aignx/codegen/models/user_payload.py +0 -0
  44. {aignostics-0.2.30 → aignostics-0.2.31}/codegen/out/aignx/codegen/models/validation_error.py +0 -0
  45. {aignostics-0.2.30 → aignostics-0.2.31}/codegen/out/aignx/codegen/models/validation_error_loc_inner.py +0 -0
  46. {aignostics-0.2.30 → aignostics-0.2.31}/codegen/out/aignx/codegen/rest.py +0 -0
  47. {aignostics-0.2.30 → aignostics-0.2.31}/codegen/out/docs/PublicApi.md +0 -0
  48. {aignostics-0.2.30 → aignostics-0.2.31}/examples/__init__.py +0 -0
  49. {aignostics-0.2.30 → aignostics-0.2.31}/examples/e2e.py +0 -0
  50. {aignostics-0.2.30 → aignostics-0.2.31}/examples/notebook.ipynb +0 -0
  51. {aignostics-0.2.30 → aignostics-0.2.31}/examples/script.py +0 -0
  52. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/__init__.py +0 -0
  53. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/application/__init__.py +0 -0
  54. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/application/_cli.py +0 -0
  55. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/application/_gui/_frame.py +0 -0
  56. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/application/_gui/_page_builder.py +0 -0
  57. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/application/_gui/_page_index.py +0 -0
  58. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/application/_gui/_utils.py +0 -0
  59. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/application/_gui/assets/canceled.lottie +0 -0
  60. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/application/_gui/assets/done.lottie +0 -0
  61. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/application/_gui/assets/empty.lottie +0 -0
  62. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/application/_gui/assets/error.lottie +0 -0
  63. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/application/_gui/assets/error_alt.lottie +0 -0
  64. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/application/_gui/assets/home-card-1.png +0 -0
  65. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/application/_gui/assets/home-card-2.png +0 -0
  66. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/application/_gui/assets/home-card-3.png +0 -0
  67. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/application/_gui/assets/home-card-4.png +0 -0
  68. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/application/_gui/assets/home-card-5.png +0 -0
  69. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/application/_gui/assets/image-not-found.png +0 -0
  70. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/application/_gui/assets/pending.lottie +0 -0
  71. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/application/_gui/assets/pending_alt.lottie +0 -0
  72. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/application/_gui/assets/ruo.png +0 -0
  73. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/application/_gui/assets/ruo.svg +0 -0
  74. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/application/_service.py +0 -0
  75. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/application/_settings.py +0 -0
  76. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/application/_utils.py +0 -0
  77. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/bucket/__init__.py +0 -0
  78. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/bucket/_cli.py +0 -0
  79. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/bucket/_gui.py +0 -0
  80. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/bucket/_service.py +0 -0
  81. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/bucket/_settings.py +0 -0
  82. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/bucket/assets/Google-Cloud-logo.png +0 -0
  83. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/bucket/assets/Google-Cloud-logo.svg +0 -0
  84. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/cli.py +0 -0
  85. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/constants.py +0 -0
  86. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/dataset/__init__.py +0 -0
  87. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/dataset/_cli.py +0 -0
  88. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/dataset/_idc_index.py +0 -0
  89. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/dataset/_service.py +0 -0
  90. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/dataset/assets/NIH-IDC-logo.svg +0 -0
  91. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/gui/__init__.py +0 -0
  92. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/gui/_frame.py +0 -0
  93. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/gui/_theme.py +0 -0
  94. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/gui/assets/cabin-v27-latin-regular.woff2 +0 -0
  95. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/gui/assets/logo.png +0 -0
  96. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/notebook/__init__.py +0 -0
  97. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/notebook/_gui.py +0 -0
  98. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/notebook/_notebook.py +0 -0
  99. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/notebook/_service.py +0 -0
  100. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/notebook/assets/python.lottie +0 -0
  101. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/platform/__init__.py +0 -0
  102. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/platform/_authentication.py +0 -0
  103. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/platform/_client.py +0 -0
  104. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/platform/_constants.py +0 -0
  105. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/platform/_messages.py +0 -0
  106. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/platform/_service.py +0 -0
  107. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/platform/_settings.py +0 -0
  108. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/platform/_utils.py +0 -0
  109. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/platform/resources/__init__.py +0 -0
  110. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/platform/resources/applications.py +0 -0
  111. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/platform/resources/runs.py +0 -0
  112. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/platform/resources/utils.py +0 -0
  113. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/qupath/__init__.py +0 -0
  114. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/qupath/_settings.py +0 -0
  115. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/qupath/assets/download.lottie +0 -0
  116. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/qupath/assets/microscope.lottie +0 -0
  117. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/system/__init__.py +0 -0
  118. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/system/_cli.py +0 -0
  119. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/system/_exceptions.py +0 -0
  120. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/system/_gui.py +0 -0
  121. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/system/_service.py +0 -0
  122. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/system/_settings.py +0 -0
  123. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/system/assets/system.lottie +0 -0
  124. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/utils/.vendored/bottle.py +0 -0
  125. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/utils/__init__.py +0 -0
  126. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/utils/_cli.py +0 -0
  127. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/utils/_console.py +0 -0
  128. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/utils/_constants.py +0 -0
  129. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/utils/_di.py +0 -0
  130. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/utils/_gui.py +0 -0
  131. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/utils/_health.py +0 -0
  132. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/utils/_log.py +0 -0
  133. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/utils/_logfire.py +0 -0
  134. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/utils/_notebook.py +0 -0
  135. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/utils/_process.py +0 -0
  136. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/utils/_sentry.py +0 -0
  137. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/utils/_service.py +0 -0
  138. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/utils/_settings.py +0 -0
  139. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/utils/boot.py +0 -0
  140. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/wsi/__init__.py +0 -0
  141. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/wsi/_cli.py +0 -0
  142. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/wsi/_gui.py +0 -0
  143. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/wsi/_openslide_handler.py +0 -0
  144. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/wsi/_pydicom_handler.py +0 -0
  145. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/wsi/_service.py +0 -0
  146. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/wsi/_utils.py +0 -0
  147. {aignostics-0.2.30 → aignostics-0.2.31}/src/aignostics/wsi/assets/fallback.png +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aignostics
3
- Version: 0.2.30
3
+ Version: 0.2.31
4
4
  Summary: 🔬 Python SDK providing access to the Aignostics Platform. Includes Aignostics Launchpad (Desktop Application), Aignostics CLI (Command-Line Interface), example notebooks, and Aignostics Client Library.
5
5
  Project-URL: Homepage, https://aignostics.readthedocs.io/en/latest/
6
6
  Project-URL: Documentation, https://aignostics.readthedocs.io/en/latest/
@@ -2,7 +2,7 @@
2
2
  # requires-python = ">=3.13"
3
3
  # dependencies = [
4
4
  # "marimo",
5
- # "aignostics==0.2.30",
5
+ # "aignostics==0.2.31",
6
6
  # ]
7
7
  # ///
8
8
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "aignostics"
3
- version = "0.2.30"
3
+ version = "0.2.31"
4
4
  description = "🔬 Python SDK providing access to the Aignostics Platform. Includes Aignostics Launchpad (Desktop Application), Aignostics CLI (Command-Line Interface), example notebooks, and Aignostics Client Library."
5
5
  readme = "README.md"
6
6
  authors = [
@@ -355,7 +355,7 @@ source = ["src/"]
355
355
 
356
356
 
357
357
  [tool.bumpversion]
358
- current_version = "0.2.30"
358
+ current_version = "0.2.31"
359
359
  parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
360
360
  serialize = ["{major}.{minor}.{patch}"]
361
361
  search = "{current_version}"
@@ -596,7 +596,7 @@ async def _page_application_describe(application_id: str) -> None: # noqa: C901
596
596
  global upload_message_queue # noqa: PLW0602
597
597
  if submit_form.metadata is None:
598
598
  return
599
- if not upload_message_queue.empty():
599
+ while not upload_message_queue.empty():
600
600
  message = upload_message_queue.get()
601
601
  if message and isinstance(message, dict) and "reference" in message:
602
602
  for row in submit_form.metadata:
@@ -162,7 +162,7 @@ async def _page_application_run_describe(application_run_id: str) -> None: # no
162
162
 
163
163
  def update_download_progress() -> None:
164
164
  """Update the progress indicator with values from the queue."""
165
- if not progress_queue.empty():
165
+ while not progress_queue.empty():
166
166
  progress = progress_queue.get()
167
167
  download_item_status.set_text(
168
168
  progress.status
@@ -258,7 +258,7 @@ class PageBuilder(BasePageBuilder):
258
258
  if download_form.download_progress is None:
259
259
  return
260
260
 
261
- if download_message_queue and not download_message_queue.empty():
261
+ while download_message_queue and not download_message_queue.empty():
262
262
  new_value = download_message_queue.get()
263
263
  download_form.download_progress.set_value(new_value)
264
264
 
@@ -140,13 +140,25 @@ def launch(
140
140
  help="Path to image. Must be part of QuPath project",
141
141
  ),
142
142
  ] = None,
143
+ script: Annotated[
144
+ Path | None,
145
+ typer.Option(
146
+ help="Path to QuPath script to run on launch. Must be part of QuPath project.",
147
+ exists=True,
148
+ file_okay=True,
149
+ dir_okay=False,
150
+ writable=False,
151
+ readable=True,
152
+ resolve_path=True,
153
+ ),
154
+ ] = None,
143
155
  ) -> None:
144
156
  """Launch QuPath application."""
145
157
  try:
146
158
  if not Service().is_qupath_installed():
147
159
  console.print("QuPath is not installed. Use 'uvx aignostics qupath install' to install it.")
148
160
  sys.exit(2)
149
- pid = Service().launch_qupath(project=project, image=image)
161
+ pid = Service().launch_qupath(project=project, image=image, script=script)
150
162
  if not pid:
151
163
  console.print("QuPath could not be launched.", style="error")
152
164
  sys.exit(1)
@@ -163,14 +175,11 @@ def launch(
163
175
  @cli.command()
164
176
  def info() -> None:
165
177
  """Get info about QuPath installation."""
178
+ if not Service().is_qupath_installed():
179
+ console.print("QuPath is not installed. Use 'uvx aignostics qupath install' to install it.", style="warning")
180
+ sys.exit(2)
166
181
  try:
167
- info = Service().get_qupath_info()
168
- if not info:
169
- console.print(
170
- "QuPath is not installed. Use 'uvx aignostics qupath install' to install it.", style="warning"
171
- )
172
- sys.exit(2)
173
- console.print_json(data=info)
182
+ console.print_json(data=Service().info())
174
183
  except Exception as e:
175
184
  message = f"Failed to get QuPath info: {e!s}."
176
185
  logger.exception(message)
@@ -193,11 +202,11 @@ def defaults() -> None:
193
202
  @cli.command()
194
203
  def uninstall(
195
204
  version: Annotated[
196
- str,
205
+ str | None,
197
206
  typer.Option(
198
- help="Version of QuPath to install. Do not change this unless you know what you are doing.",
207
+ help="Version of QuPath to install. If not specified, all versions will be uninstalled.",
199
208
  ),
200
- ] = QUPATH_VERSION,
209
+ ] = None,
201
210
  path: Annotated[
202
211
  Path,
203
212
  typer.Option(
@@ -30,7 +30,7 @@ class PageBuilder(BasePageBuilder):
30
30
  async def install_qupath() -> None:
31
31
  def update_install_progress() -> None:
32
32
  """Update the progress indicator with values from the queue."""
33
- if not progress_queue.empty():
33
+ while not progress_queue.empty():
34
34
  progress: InstallProgress = progress_queue.get()
35
35
  if progress.status is InstallProgressState.DOWNLOADING:
36
36
  if progress.archive_path and progress.archive_size:
@@ -101,7 +101,8 @@ class PageBuilder(BasePageBuilder):
101
101
 
102
102
  launch_button.props(remove="loading")
103
103
 
104
- installed_path = Service().find_qupath()
104
+ version = Service().get_version()
105
+ expected_version = Service().get_expected_version()
105
106
 
106
107
  ui.markdown(
107
108
  """
@@ -111,12 +112,18 @@ class PageBuilder(BasePageBuilder):
111
112
  with ui.row().classes("w-full justify-start"):
112
113
  with ui.column().classes("w-2/5"):
113
114
  with ui.card().classes("w-full"):
114
- if installed_path:
115
- install_info = ui.label(
116
- "QuPath is installed and ready to execute. "
117
- "Go to a completed application result and click the QuPath button, "
118
- "or open directly from here."
119
- )
115
+ if version:
116
+ if version.version == expected_version:
117
+ install_info = ui.label(
118
+ f"QuPath {expected_version} is installed and ready to execute. "
119
+ "Go to a completed application result and click the QuPath button, "
120
+ "or open directly from here."
121
+ )
122
+ else:
123
+ install_info = ui.label(
124
+ f"QuPath {version.version} is installed, but version {expected_version} "
125
+ "is expected. Please update to the latest version by reinstalling."
126
+ )
120
127
  else:
121
128
  install_info = ui.label(
122
129
  "Install QuPath to enable visualizing your Whole Slide Image and application results "
@@ -133,11 +140,11 @@ class PageBuilder(BasePageBuilder):
133
140
  on_click=launch_qupath,
134
141
  icon="visibility",
135
142
  ).mark("BUTTON_QUPATH_LAUNCH")
136
- if not installed_path:
143
+ if not version:
137
144
  launch_button.disable()
138
145
  ui.space()
139
146
  install_button = ui.button(
140
- "Install" if not installed_path else "Reinstall",
147
+ "Install" if not version else "Reinstall",
141
148
  on_click=install_qupath,
142
149
  icon="install_desktop",
143
150
  ).mark("BUTTON_QUPATH_INSTALL")
@@ -146,7 +153,7 @@ class PageBuilder(BasePageBuilder):
146
153
  on_click=uninstall_qupath,
147
154
  icon="extension_off",
148
155
  ).mark("BUTTON_QUPATH_INSTALL")
149
- if not installed_path:
156
+ if not version:
150
157
  uninstall_button.disable()
151
158
 
152
159
  ui.markdown(
@@ -174,9 +181,13 @@ class PageBuilder(BasePageBuilder):
174
181
  ui.space()
175
182
  with ui.column().classes("w-2/5"), ui.row().classes("w-1/2 justify-center content-center"):
176
183
  ui.space()
177
- animation = (
178
- "/qupath_assets/microscope.lottie" if installed_path else "/qupath_assets/download.lottie"
179
- )
184
+ if version:
185
+ if version.version == expected_version:
186
+ animation = "/qupath_assets/microscope.lottie"
187
+ else:
188
+ animation = "/qupath_assets/update.lottie"
189
+ else:
190
+ animation = "/qupath_assets/download.lottie"
180
191
  ui.html(
181
192
  f"<dotlottie-player "
182
193
  f'src="{animation}" '