aignostics 0.2.19__tar.gz → 0.2.22__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.
- {aignostics-0.2.19 → aignostics-0.2.22}/PKG-INFO +11 -10
- {aignostics-0.2.19 → aignostics-0.2.22}/examples/notebook.py +1 -1
- {aignostics-0.2.19 → aignostics-0.2.22}/pyproject.toml +18 -17
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/application/__init__.py +1 -1
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/application/_cli.py +46 -25
- aignostics-0.2.22/src/aignostics/application/_gui/_frame.py +164 -0
- aignostics-0.2.22/src/aignostics/application/_gui/_page_application_describe.py +634 -0
- aignostics-0.2.22/src/aignostics/application/_gui/_page_application_run_describe.py +546 -0
- aignostics-0.2.22/src/aignostics/application/_gui/_page_builder.py +42 -0
- aignostics-0.2.22/src/aignostics/application/_gui/_page_index.py +49 -0
- aignostics-0.2.22/src/aignostics/application/_gui/_utils.py +99 -0
- aignostics-0.2.22/src/aignostics/application/_gui/assets/canceled.lottie +0 -0
- aignostics-0.2.22/src/aignostics/application/_gui/assets/done.lottie +0 -0
- aignostics-0.2.22/src/aignostics/application/_gui/assets/empty.lottie +0 -0
- aignostics-0.2.22/src/aignostics/application/_gui/assets/error.lottie +0 -0
- aignostics-0.2.22/src/aignostics/application/_gui/assets/error_alt.lottie +0 -0
- aignostics-0.2.22/src/aignostics/application/_gui/assets/pending.lottie +0 -0
- aignostics-0.2.22/src/aignostics/application/_gui/assets/pending_alt.lottie +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/application/_service.py +183 -64
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/application/_utils.py +53 -3
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/bucket/_cli.py +10 -10
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/bucket/_gui.py +5 -1
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/bucket/_service.py +2 -1
- aignostics-0.2.22/src/aignostics/bucket/assets/Google-Cloud-logo.png +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/cli.py +0 -4
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/constants.py +3 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/dataset/_cli.py +36 -12
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/dataset/_gui.py +46 -30
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/dataset/_idc_index.py +18 -2
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/gui/_frame.py +82 -29
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/gui/_theme.py +10 -4
- aignostics-0.2.22/src/aignostics/notebook/_gui.py +98 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/notebook/_service.py +13 -6
- aignostics-0.2.22/src/aignostics/notebook/assets/python.lottie +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/platform/__init__.py +6 -2
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/platform/resources/runs.py +3 -1
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/qupath/__init__.py +3 -1
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/qupath/_cli.py +181 -14
- aignostics-0.2.22/src/aignostics/qupath/_gui.py +192 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/qupath/_service.py +582 -58
- aignostics-0.2.22/src/aignostics/qupath/assets/download.lottie +0 -0
- aignostics-0.2.22/src/aignostics/qupath/assets/microscope.lottie +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/system/_cli.py +104 -1
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/system/_gui.py +2 -1
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/system/_service.py +115 -2
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/utils/_logfire.py +10 -1
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/utils/_sentry.py +9 -1
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/utils/boot.py +3 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/wsi/_service.py +10 -8
- aignostics-0.2.19/src/aignostics/application/_gui.py +0 -1194
- aignostics-0.2.19/src/aignostics/notebook/_gui.py +0 -33
- aignostics-0.2.19/src/aignostics/qupath/_gui.py +0 -110
- {aignostics-0.2.19 → aignostics-0.2.22}/.gitignore +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/LICENSE +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/README.md +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/codegen/out/.openapi-generator/FILES +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/codegen/out/.openapi-generator/VERSION +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/codegen/out/aignx/codegen/api/public_api.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/codegen/out/aignx/codegen/api_client.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/codegen/out/aignx/codegen/api_response.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/codegen/out/aignx/codegen/configuration.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/codegen/out/aignx/codegen/exceptions.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/codegen/out/aignx/codegen/models/__init__.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/codegen/out/aignx/codegen/models/application_read_response.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/codegen/out/aignx/codegen/models/application_run_status.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/codegen/out/aignx/codegen/models/application_version_read_response.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/codegen/out/aignx/codegen/models/http_validation_error.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/codegen/out/aignx/codegen/models/input_artifact_creation_request.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/codegen/out/aignx/codegen/models/input_artifact_read_response.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/codegen/out/aignx/codegen/models/item_creation_request.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/codegen/out/aignx/codegen/models/item_result_read_response.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/codegen/out/aignx/codegen/models/item_status.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/codegen/out/aignx/codegen/models/output_artifact_read_response.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/codegen/out/aignx/codegen/models/output_artifact_result_read_response.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/codegen/out/aignx/codegen/models/output_artifact_scope.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/codegen/out/aignx/codegen/models/payload_input_artifact.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/codegen/out/aignx/codegen/models/payload_item.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/codegen/out/aignx/codegen/models/payload_output_artifact.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/codegen/out/aignx/codegen/models/run_creation_request.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/codegen/out/aignx/codegen/models/run_creation_response.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/codegen/out/aignx/codegen/models/run_read_response.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/codegen/out/aignx/codegen/models/transfer_urls.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/codegen/out/aignx/codegen/models/user_payload.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/codegen/out/aignx/codegen/models/validation_error.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/codegen/out/aignx/codegen/models/validation_error_loc_inner.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/codegen/out/aignx/codegen/rest.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/codegen/out/docs/PublicApi.md +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/examples/__init__.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/examples/e2e.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/examples/notebook.ipynb +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/examples/script.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/__init__.py +0 -0
- {aignostics-0.2.19/src/aignostics/gui → aignostics-0.2.22/src/aignostics/application/_gui}/assets/home-card-1.png +0 -0
- {aignostics-0.2.19/src/aignostics/gui → aignostics-0.2.22/src/aignostics/application/_gui}/assets/home-card-2.png +0 -0
- {aignostics-0.2.19/src/aignostics/gui → aignostics-0.2.22/src/aignostics/application/_gui}/assets/home-card-3.png +0 -0
- {aignostics-0.2.19/src/aignostics/gui → aignostics-0.2.22/src/aignostics/application/_gui}/assets/home-card-4.png +0 -0
- {aignostics-0.2.19/src/aignostics/gui → aignostics-0.2.22/src/aignostics/application/_gui}/assets/home-card-5.png +0 -0
- {aignostics-0.2.19/src/aignostics/gui → aignostics-0.2.22/src/aignostics/application/_gui}/assets/image-not-found.png +0 -0
- {aignostics-0.2.19/src/aignostics/gui → aignostics-0.2.22/src/aignostics/application/_gui}/assets/ruo.png +0 -0
- {aignostics-0.2.19/src/aignostics/gui → aignostics-0.2.22/src/aignostics/application/_gui}/assets/ruo.svg +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/application/_settings.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/bucket/__init__.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/bucket/_settings.py +0 -0
- {aignostics-0.2.19/src/aignostics/gui → aignostics-0.2.22/src/aignostics/bucket}/assets/Google-Cloud-logo.svg +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/dataset/__init__.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/dataset/_service.py +0 -0
- {aignostics-0.2.19/src/aignostics/gui → aignostics-0.2.22/src/aignostics/dataset}/assets/NIH-IDC-logo.svg +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/gui/__init__.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/gui/assets/cabin-v27-latin-regular.woff2 +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/gui/assets/logo.png +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/notebook/__init__.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/notebook/_notebook.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/platform/_authentication.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/platform/_client.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/platform/_constants.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/platform/_messages.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/platform/_service.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/platform/_settings.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/platform/_utils.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/platform/resources/__init__.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/platform/resources/applications.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/platform/resources/utils.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/qupath/_settings.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/system/__init__.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/system/_exceptions.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/system/_settings.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/utils/.vendored/bottle.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/utils/__init__.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/utils/_cli.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/utils/_console.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/utils/_constants.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/utils/_di.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/utils/_gui.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/utils/_health.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/utils/_log.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/utils/_notebook.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/utils/_process.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/utils/_service.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/utils/_settings.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/wsi/__init__.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/wsi/_cli.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/wsi/_gui.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/wsi/_openslide_handler.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/wsi/_pydicom_handler.py +0 -0
- {aignostics-0.2.19 → aignostics-0.2.22}/src/aignostics/wsi/_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aignostics
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.22
|
|
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/
|
|
@@ -49,22 +49,23 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
49
49
|
Classifier: Typing :: Typed
|
|
50
50
|
Requires-Python: <4.0,>=3.11
|
|
51
51
|
Requires-Dist: appdirs>=1.4.4
|
|
52
|
-
Requires-Dist: boto3>=1.38.
|
|
52
|
+
Requires-Dist: boto3>=1.38.27
|
|
53
53
|
Requires-Dist: click
|
|
54
|
-
Requires-Dist: dicom-validator>=0.
|
|
55
|
-
Requires-Dist: dicomweb-client[gcp]>=0.59.
|
|
54
|
+
Requires-Dist: dicom-validator>=0.7.1
|
|
55
|
+
Requires-Dist: dicomweb-client[gcp]>=0.59.2
|
|
56
56
|
Requires-Dist: duckdb<=1.2.1,>=0.10.0
|
|
57
57
|
Requires-Dist: fastapi[all,standard]>=0.115.12
|
|
58
|
-
Requires-Dist: google-cloud-storage>=
|
|
58
|
+
Requires-Dist: google-cloud-storage>=2.12.0
|
|
59
59
|
Requires-Dist: google-crc32c>=1.7.1
|
|
60
60
|
Requires-Dist: highdicom>=0.25.1
|
|
61
61
|
Requires-Dist: httpx>=0.28.1
|
|
62
62
|
Requires-Dist: humanize>=4.12.3
|
|
63
63
|
Requires-Dist: idc-index-data==21.0.0
|
|
64
|
+
Requires-Dist: ijson>=3.4.0
|
|
64
65
|
Requires-Dist: jsf>=0.11.2
|
|
65
|
-
Requires-Dist: jsonschema>=4.
|
|
66
|
-
Requires-Dist: logfire[system-metrics]>=3.16.
|
|
67
|
-
Requires-Dist: nicegui[native]>=2.
|
|
66
|
+
Requires-Dist: jsonschema>=4.24.0
|
|
67
|
+
Requires-Dist: logfire[system-metrics]>=3.16.1
|
|
68
|
+
Requires-Dist: nicegui[native]>=2.18.0
|
|
68
69
|
Requires-Dist: openslide-bin>=4.0.0.8
|
|
69
70
|
Requires-Dist: openslide-python>=1.4.2
|
|
70
71
|
Requires-Dist: opentelemetry-instrumentation-fastapi>=0.53b0
|
|
@@ -97,7 +98,7 @@ Requires-Dist: show-in-file-manager>=1.1.5
|
|
|
97
98
|
Requires-Dist: sphinx-click
|
|
98
99
|
Requires-Dist: tqdm
|
|
99
100
|
Requires-Dist: tqdm>=4.67.1
|
|
100
|
-
Requires-Dist: typer>=0.
|
|
101
|
+
Requires-Dist: typer>=0.16.0
|
|
101
102
|
Requires-Dist: uptime>=3.0.1
|
|
102
103
|
Requires-Dist: urllib3>=2.2.3
|
|
103
104
|
Requires-Dist: wsidicom>=0.27.1
|
|
@@ -105,7 +106,7 @@ Provides-Extra: jupyter
|
|
|
105
106
|
Requires-Dist: jupyter>=1.1.1; extra == 'jupyter'
|
|
106
107
|
Provides-Extra: marimo
|
|
107
108
|
Requires-Dist: cloudpathlib>=0.21.1; extra == 'marimo'
|
|
108
|
-
Requires-Dist: marimo>=0.13.
|
|
109
|
+
Requires-Dist: marimo>=0.13.15; extra == 'marimo'
|
|
109
110
|
Requires-Dist: matplotlib>=3.10.3; extra == 'marimo'
|
|
110
111
|
Requires-Dist: shapely>=2.1.0; extra == 'marimo'
|
|
111
112
|
Provides-Extra: qupath
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "aignostics"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.22"
|
|
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 = [
|
|
@@ -75,8 +75,8 @@ requires-python = ">=3.11, <4.0"
|
|
|
75
75
|
dependencies = [
|
|
76
76
|
# From Template
|
|
77
77
|
"fastapi[standard,all]>=0.115.12",
|
|
78
|
-
"logfire[system-metrics]>=3.16.
|
|
79
|
-
"nicegui[native]>=2.
|
|
78
|
+
"logfire[system-metrics]>=3.16.1",
|
|
79
|
+
"nicegui[native]>=2.18.0",
|
|
80
80
|
"opentelemetry-instrumentation-fastapi>=0.53b0",
|
|
81
81
|
"opentelemetry-instrumentation-httpx>=0.53b0",
|
|
82
82
|
"opentelemetry-instrumentation-jinja2>=0.53b0",
|
|
@@ -89,20 +89,20 @@ dependencies = [
|
|
|
89
89
|
"pydantic-settings>=2.9.1",
|
|
90
90
|
"pywin32>=310 ; sys_platform == 'win32'",
|
|
91
91
|
"sentry-sdk>=2.29.1",
|
|
92
|
-
"typer>=0.
|
|
92
|
+
"typer>=0.16.0",
|
|
93
93
|
"uptime>=3.0.1",
|
|
94
94
|
# Custom
|
|
95
95
|
"appdirs>=1.4.4",
|
|
96
|
-
"boto3>=1.38.
|
|
97
|
-
"dicom-validator>=0.
|
|
98
|
-
"dicomweb-client[gcp]>=0.59.
|
|
99
|
-
"google-cloud-storage>=
|
|
96
|
+
"boto3>=1.38.27",
|
|
97
|
+
"dicom-validator>=0.7.1",
|
|
98
|
+
"dicomweb-client[gcp]>=0.59.2",
|
|
99
|
+
"google-cloud-storage>=2.12.0",
|
|
100
100
|
"google-crc32c>=1.7.1",
|
|
101
101
|
"highdicom>=0.25.1",
|
|
102
102
|
"httpx>=0.28.1",
|
|
103
103
|
"humanize>=4.12.3",
|
|
104
104
|
"jsf>=0.11.2",
|
|
105
|
-
"jsonschema>=4.
|
|
105
|
+
"jsonschema>=4.24.0",
|
|
106
106
|
"openslide-bin>=4.0.0.8",
|
|
107
107
|
"openslide-python>=1.4.2",
|
|
108
108
|
"pyjwt[crypto]>=2.10.1",
|
|
@@ -130,13 +130,14 @@ dependencies = [
|
|
|
130
130
|
"s5cmd",
|
|
131
131
|
"sphinx-click",
|
|
132
132
|
"tqdm",
|
|
133
|
+
"ijson>=3.4.0",
|
|
133
134
|
]
|
|
134
135
|
|
|
135
136
|
[project.optional-dependencies]
|
|
136
137
|
jupyter = ["jupyter>=1.1.1"]
|
|
137
138
|
marimo = [
|
|
138
139
|
"cloudpathlib>=0.21.1",
|
|
139
|
-
"marimo>=0.13.
|
|
140
|
+
"marimo>=0.13.15",
|
|
140
141
|
"matplotlib>=3.10.3",
|
|
141
142
|
"shapely>=2.1.0",
|
|
142
143
|
]
|
|
@@ -151,25 +152,25 @@ dev = [
|
|
|
151
152
|
"furo>=2024.8.6",
|
|
152
153
|
"git-cliff>=2.8.0",
|
|
153
154
|
"matplotlib>=3.10.1",
|
|
154
|
-
"mypy>=1.
|
|
155
|
+
"mypy>=1.16.0",
|
|
155
156
|
"nox[uv]>=2025.5.1",
|
|
156
157
|
"pip-audit>=2.9.0",
|
|
157
158
|
"pip-licenses @ git+https://github.com/neXenio/pip-licenses.git@master", # https://github.com/raimon49/pip-licenses/pull/224
|
|
158
159
|
"pre-commit>=4.1.0",
|
|
159
160
|
"pyright>=1.1.401",
|
|
160
161
|
"pytest>=8.3.5",
|
|
161
|
-
"pytest-asyncio>=0.
|
|
162
|
+
"pytest-asyncio>=1.0.0",
|
|
162
163
|
"pytest-cov>=6.1.1",
|
|
163
|
-
"pytest-docker>=3.2.
|
|
164
|
+
"pytest-docker>=3.2.2",
|
|
164
165
|
"pytest-env>=1.1.5",
|
|
165
166
|
"pytest-md-report>=0.7.0",
|
|
166
|
-
"pytest-regressions>=2.
|
|
167
|
+
"pytest-regressions>=2.8.0",
|
|
167
168
|
"pytest-selenium>=4.1.0",
|
|
168
169
|
"pytest-subprocess>=1.5.3",
|
|
169
170
|
"pytest-timeout>=2.4.0",
|
|
170
171
|
"pytest-watcher>=0.4.3",
|
|
171
|
-
"pytest-xdist[psutil]>=3.
|
|
172
|
-
"ruff>=0.11.
|
|
172
|
+
"pytest-xdist[psutil]>=3.7.0",
|
|
173
|
+
"ruff>=0.11.12",
|
|
173
174
|
"scalene>=1.5.51",
|
|
174
175
|
"sphinx>=8.2.3",
|
|
175
176
|
"sphinx-autobuild>=2024.10.3",
|
|
@@ -354,7 +355,7 @@ source = ["src/"]
|
|
|
354
355
|
|
|
355
356
|
|
|
356
357
|
[tool.bumpversion]
|
|
357
|
-
current_version = "0.2.
|
|
358
|
+
current_version = "0.2.22"
|
|
358
359
|
parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
|
|
359
360
|
serialize = ["{major}.{minor}.{patch}"]
|
|
360
361
|
search = "{current_version}"
|
|
@@ -6,24 +6,10 @@ from pathlib import Path
|
|
|
6
6
|
from typing import Annotated
|
|
7
7
|
|
|
8
8
|
import typer
|
|
9
|
-
from rich.console import Group
|
|
10
|
-
from rich.live import Live
|
|
11
|
-
from rich.panel import Panel
|
|
12
|
-
from rich.progress import (
|
|
13
|
-
BarColumn,
|
|
14
|
-
FileSizeColumn,
|
|
15
|
-
Progress,
|
|
16
|
-
TaskID,
|
|
17
|
-
TaskProgressColumn,
|
|
18
|
-
TextColumn,
|
|
19
|
-
TimeElapsedColumn,
|
|
20
|
-
TimeRemainingColumn,
|
|
21
|
-
TotalFileSizeColumn,
|
|
22
|
-
TransferSpeedColumn,
|
|
23
|
-
)
|
|
24
9
|
|
|
25
10
|
from aignostics.bucket import Service as BucketService
|
|
26
11
|
from aignostics.platform import NotFoundException
|
|
12
|
+
from aignostics.system import Service as SystemService
|
|
27
13
|
from aignostics.utils import console, get_logger
|
|
28
14
|
|
|
29
15
|
from ._service import DownloadProgress, DownloadProgressState, Service
|
|
@@ -370,6 +356,17 @@ def run_upload(
|
|
|
370
356
|
2. Uploads the files referenced in the CSV file to the Aignostics platform.
|
|
371
357
|
3. Incrementally updates the CSV file with upload progress and the signed URLs for the uploaded files.
|
|
372
358
|
"""
|
|
359
|
+
from rich.progress import ( # noqa: PLC0415
|
|
360
|
+
BarColumn,
|
|
361
|
+
FileSizeColumn,
|
|
362
|
+
Progress,
|
|
363
|
+
TaskProgressColumn,
|
|
364
|
+
TextColumn,
|
|
365
|
+
TimeRemainingColumn,
|
|
366
|
+
TotalFileSizeColumn,
|
|
367
|
+
TransferSpeedColumn,
|
|
368
|
+
)
|
|
369
|
+
|
|
373
370
|
metadata_dict = read_metadata_csv_to_dict(metadata_csv_file=metadata_csv_file)
|
|
374
371
|
if not metadata_dict:
|
|
375
372
|
sys.exit(2)
|
|
@@ -542,7 +539,7 @@ def run_cancel(
|
|
|
542
539
|
|
|
543
540
|
|
|
544
541
|
@result_app.command("download")
|
|
545
|
-
def result_download(
|
|
542
|
+
def result_download( # noqa: PLR0913, PLR0917
|
|
546
543
|
run_id: Annotated[str, typer.Argument(..., help="Id of the run to download results for")],
|
|
547
544
|
destination_directory: Annotated[
|
|
548
545
|
Path,
|
|
@@ -555,7 +552,7 @@ def result_download(
|
|
|
555
552
|
readable=True,
|
|
556
553
|
resolve_path=True,
|
|
557
554
|
),
|
|
558
|
-
],
|
|
555
|
+
] = SystemService.get_user_data_directory("results"), # noqa: B008
|
|
559
556
|
create_subdirectory_for_run: Annotated[
|
|
560
557
|
bool,
|
|
561
558
|
typer.Option(
|
|
@@ -574,20 +571,46 @@ def result_download(
|
|
|
574
571
|
help="Wait for run completion and download results incrementally",
|
|
575
572
|
),
|
|
576
573
|
] = True,
|
|
574
|
+
qupath_project: Annotated[
|
|
575
|
+
bool,
|
|
576
|
+
typer.Option(
|
|
577
|
+
help="Create a QuPath project referencing input slides and results. \n"
|
|
578
|
+
"The QuPath project will be created in a subfolder of the destination directory. \n"
|
|
579
|
+
"This option requires the QuPath extension for Launchpad: "
|
|
580
|
+
'start the Launchpad with `uvx --with "aignostics[qupath]" aignostics ...` \n'
|
|
581
|
+
"This options requires installation of the QuPath application: "
|
|
582
|
+
'Run uvx --with "aignostics[qupath]" aignostics qupath install'
|
|
583
|
+
),
|
|
584
|
+
] = False,
|
|
577
585
|
) -> None:
|
|
578
586
|
"""Download results of a run."""
|
|
579
587
|
logger.debug(
|
|
580
588
|
"Downloading results for run with ID '%s' to '%s' with options: "
|
|
581
|
-
"create_subdirectory_for_run=%s, create_subdirectory_per_item=%s, wait_for_completion=%s",
|
|
589
|
+
"create_subdirectory_for_run=%s, create_subdirectory_per_item=%s, wait_for_completion=%s, qupath_project=%r",
|
|
582
590
|
run_id,
|
|
583
591
|
destination_directory,
|
|
584
592
|
create_subdirectory_for_run,
|
|
585
593
|
create_subdirectory_per_item,
|
|
586
594
|
wait_for_completion,
|
|
595
|
+
qupath_project,
|
|
596
|
+
)
|
|
597
|
+
from rich.console import Group # noqa: PLC0415
|
|
598
|
+
from rich.live import Live # noqa: PLC0415
|
|
599
|
+
from rich.panel import Panel # noqa: PLC0415
|
|
600
|
+
from rich.progress import ( # noqa: PLC0415
|
|
601
|
+
BarColumn,
|
|
602
|
+
FileSizeColumn,
|
|
603
|
+
Progress,
|
|
604
|
+
TaskID,
|
|
605
|
+
TaskProgressColumn,
|
|
606
|
+
TextColumn,
|
|
607
|
+
TimeElapsedColumn,
|
|
608
|
+
TimeRemainingColumn,
|
|
609
|
+
TotalFileSizeColumn,
|
|
610
|
+
TransferSpeedColumn,
|
|
587
611
|
)
|
|
588
612
|
|
|
589
613
|
try:
|
|
590
|
-
progress: DownloadProgress = DownloadProgress()
|
|
591
614
|
download_tasks: dict[str, TaskID] = {}
|
|
592
615
|
|
|
593
616
|
main_download_progress_ui = Progress(
|
|
@@ -612,15 +635,13 @@ def result_download(
|
|
|
612
635
|
panel = Panel(
|
|
613
636
|
Group(main_download_progress_ui, artifact_download_progress_ui),
|
|
614
637
|
title=f"Run {run_id}",
|
|
615
|
-
subtitle=
|
|
638
|
+
subtitle="",
|
|
616
639
|
highlight=True,
|
|
617
640
|
)
|
|
618
641
|
with Live(panel):
|
|
619
|
-
main_task = main_download_progress_ui.add_task(
|
|
620
|
-
description=progress.status, total=None, extra_description=""
|
|
621
|
-
)
|
|
642
|
+
main_task = main_download_progress_ui.add_task(description="", total=None, extra_description="")
|
|
622
643
|
|
|
623
|
-
def update_progress() -> None:
|
|
644
|
+
def update_progress(progress: DownloadProgress) -> None:
|
|
624
645
|
"""Update progress bar for file downloads."""
|
|
625
646
|
if progress.run:
|
|
626
647
|
panel.title = f"Run {progress.run.application_run_id} of {progress.run.application_version_id}"
|
|
@@ -669,12 +690,12 @@ def result_download(
|
|
|
669
690
|
)
|
|
670
691
|
|
|
671
692
|
destination_directory = Service().application_run_download(
|
|
672
|
-
progress=progress,
|
|
673
693
|
run_id=run_id,
|
|
674
694
|
destination_directory=destination_directory,
|
|
675
695
|
create_subdirectory_for_run=create_subdirectory_for_run,
|
|
676
696
|
create_subdirectory_per_item=create_subdirectory_per_item,
|
|
677
697
|
wait_for_completion=wait_for_completion,
|
|
698
|
+
qupath_project=qupath_project,
|
|
678
699
|
download_progress_callable=update_progress,
|
|
679
700
|
)
|
|
680
701
|
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from nicegui import app, background_tasks, context, ui # noq
|
|
4
|
+
from nicegui import run as nicegui_run
|
|
5
|
+
|
|
6
|
+
from aignostics.gui import frame
|
|
7
|
+
from aignostics.utils import get_logger
|
|
8
|
+
|
|
9
|
+
from .._service import Service # noqa: TID252
|
|
10
|
+
from ._utils import application_id_to_icon, run_status_to_icon_and_color
|
|
11
|
+
|
|
12
|
+
logger = get_logger(__name__)
|
|
13
|
+
|
|
14
|
+
BORDERED_SEPARATOR = "bordered separator"
|
|
15
|
+
RUNS_LIMIT = 500
|
|
16
|
+
STORAGE_TAB_RUNS_COMPLETED_ONLY = "runs_completed_only"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
async def _frame( # noqa: C901, PLR0913, PLR0915, PLR0917
|
|
20
|
+
navigation_title: str,
|
|
21
|
+
navigation_icon: str | None = None,
|
|
22
|
+
navigation_icon_color: str | None = None,
|
|
23
|
+
navigation_icon_tooltip: str | None = None,
|
|
24
|
+
left_sidebar: bool = False,
|
|
25
|
+
args: dict[str, Any] | None = None,
|
|
26
|
+
) -> None:
|
|
27
|
+
if args is None:
|
|
28
|
+
args = {}
|
|
29
|
+
service = Service()
|
|
30
|
+
with frame( # noqa: PLR1702
|
|
31
|
+
navigation_title=navigation_title,
|
|
32
|
+
navigation_icon=navigation_icon,
|
|
33
|
+
navigation_icon_color=navigation_icon_color,
|
|
34
|
+
navigation_icon_tooltip=navigation_icon_tooltip,
|
|
35
|
+
left_sidebar=left_sidebar,
|
|
36
|
+
):
|
|
37
|
+
try:
|
|
38
|
+
with ui.list().props(BORDERED_SEPARATOR).classes("full-width"):
|
|
39
|
+
ui.item_label("Applications").props("header")
|
|
40
|
+
ui.separator()
|
|
41
|
+
for application in service.applications():
|
|
42
|
+
with (
|
|
43
|
+
ui.item(
|
|
44
|
+
on_click=lambda app_id=application.application_id: ui.navigate.to(f"/application/{app_id}")
|
|
45
|
+
)
|
|
46
|
+
.mark(f"SIDEBAR_APPLICATION:{application.application_id}")
|
|
47
|
+
.props("clickable")
|
|
48
|
+
):
|
|
49
|
+
with (
|
|
50
|
+
ui.item_section().props("avatar"),
|
|
51
|
+
ui.icon(application_id_to_icon(application.application_id), color="primary"),
|
|
52
|
+
):
|
|
53
|
+
ui.tooltip(application.application_id)
|
|
54
|
+
with ui.item_section():
|
|
55
|
+
ui.label(f"{application.name}").tailwind.font_weight(
|
|
56
|
+
"bold"
|
|
57
|
+
if context.client.page.path == "/application/{application_id}"
|
|
58
|
+
and args
|
|
59
|
+
and args.get("application_id") == application.application_id
|
|
60
|
+
else "normal"
|
|
61
|
+
)
|
|
62
|
+
except Exception as e: # noqa: BLE001
|
|
63
|
+
ui.label(f"Failed to list applications: {e!s}").mark("LABEL_ERROR")
|
|
64
|
+
|
|
65
|
+
async def application_runs_load_and_render(runs_column: ui.column, completed_only: bool = False) -> None:
|
|
66
|
+
with runs_column:
|
|
67
|
+
try:
|
|
68
|
+
runs = await nicegui_run.io_bound(
|
|
69
|
+
Service.application_runs_static, limit=RUNS_LIMIT, completed_only=completed_only
|
|
70
|
+
)
|
|
71
|
+
if runs is None:
|
|
72
|
+
message = "nicegui_run.io_bound(Service.application_runs_static) returned None" # type: ignore[unreachable]
|
|
73
|
+
logger.error(message)
|
|
74
|
+
raise RuntimeError(message) # noqa: TRY301
|
|
75
|
+
runs_column.clear()
|
|
76
|
+
for index, run_data in enumerate(runs):
|
|
77
|
+
with (
|
|
78
|
+
ui.item(
|
|
79
|
+
on_click=lambda run_id=run_data["application_run_id"]: ui.navigate.to(
|
|
80
|
+
f"/application/run/{run_id}"
|
|
81
|
+
)
|
|
82
|
+
)
|
|
83
|
+
.props("clickable")
|
|
84
|
+
.classes("w-full")
|
|
85
|
+
.mark(f"SIDEBAR_RUN_ITEM:{index}")
|
|
86
|
+
):
|
|
87
|
+
with ui.item_section().props("avatar"):
|
|
88
|
+
icon, color = run_status_to_icon_and_color(run_data["status"])
|
|
89
|
+
with ui.icon(icon, color=color):
|
|
90
|
+
ui.tooltip(
|
|
91
|
+
f"Run {run_data['application_run_id']}, "
|
|
92
|
+
f"status {run_data['status'].value.upper()}"
|
|
93
|
+
)
|
|
94
|
+
with ui.item_section():
|
|
95
|
+
ui.label(f"{run_data['application_version_id']}").tailwind.font_weight(
|
|
96
|
+
"bold"
|
|
97
|
+
if context.client.page.path == "/application/run/{application_run_id}"
|
|
98
|
+
and args
|
|
99
|
+
and args.get("application_run_id") == run_data["application_run_id"]
|
|
100
|
+
else "normal"
|
|
101
|
+
)
|
|
102
|
+
ui.label(
|
|
103
|
+
f"triggered on {run_data['triggered_at'].astimezone().strftime('%m-%d %H:%M')}"
|
|
104
|
+
)
|
|
105
|
+
if not runs:
|
|
106
|
+
with ui.item():
|
|
107
|
+
with ui.item_section().props("avatar"):
|
|
108
|
+
ui.icon("info")
|
|
109
|
+
with ui.item_section():
|
|
110
|
+
ui.label("You did not yet create a run.")
|
|
111
|
+
except Exception:
|
|
112
|
+
runs_column.clear()
|
|
113
|
+
with ui.item():
|
|
114
|
+
with ui.item_section().props("avatar"):
|
|
115
|
+
ui.icon("error")
|
|
116
|
+
with ui.item_section():
|
|
117
|
+
ui.label("Failed to load application runs.")
|
|
118
|
+
logger.exception("Failed to load application runs")
|
|
119
|
+
|
|
120
|
+
@ui.refreshable
|
|
121
|
+
async def _runs_list() -> None:
|
|
122
|
+
with ui.column().classes("full-width justify-center") as runs_column:
|
|
123
|
+
with ui.row().classes("w-full justify-center"):
|
|
124
|
+
ui.spinner(size="lg").classes("m-5")
|
|
125
|
+
await ui.context.client.connected()
|
|
126
|
+
background_tasks.create_lazy(
|
|
127
|
+
coroutine=application_runs_load_and_render(
|
|
128
|
+
runs_column=runs_column,
|
|
129
|
+
completed_only=app.storage.tab.get(STORAGE_TAB_RUNS_COMPLETED_ONLY, False),
|
|
130
|
+
),
|
|
131
|
+
name="_runs_list",
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
class RunFilterButton(ui.icon):
|
|
135
|
+
def __init__(self, *args, **kwargs) -> None: # type: ignore[no-untyped-def]
|
|
136
|
+
super().__init__(*args, **kwargs)
|
|
137
|
+
self._state = app.storage.tab.get(STORAGE_TAB_RUNS_COMPLETED_ONLY, False)
|
|
138
|
+
self.on("click", self.toggle)
|
|
139
|
+
|
|
140
|
+
def toggle(self) -> None:
|
|
141
|
+
self._state = not self._state
|
|
142
|
+
app.storage.tab[STORAGE_TAB_RUNS_COMPLETED_ONLY] = self._state
|
|
143
|
+
self.update()
|
|
144
|
+
_runs_list.refresh()
|
|
145
|
+
|
|
146
|
+
def update(self) -> None:
|
|
147
|
+
self.props(f"color={'positive' if self._state else 'grey'}")
|
|
148
|
+
super().update()
|
|
149
|
+
|
|
150
|
+
def is_active(self) -> bool:
|
|
151
|
+
return bool(self._state)
|
|
152
|
+
|
|
153
|
+
try:
|
|
154
|
+
with ui.list().props(BORDERED_SEPARATOR).classes("full-width"):
|
|
155
|
+
with ui.row(align_items="center").classes("justify-center"):
|
|
156
|
+
ui.item_label("Runs").props("header")
|
|
157
|
+
ui.space()
|
|
158
|
+
await ui.context.client.connected()
|
|
159
|
+
with RunFilterButton("done_all", size="sm").classes("mr-3").mark("BUTTON_RUNS_FILTER_COMPLETED"):
|
|
160
|
+
ui.tooltip("Show completed runs only")
|
|
161
|
+
ui.separator()
|
|
162
|
+
await _runs_list()
|
|
163
|
+
except Exception as e: # noqa: BLE001
|
|
164
|
+
ui.label(f"Failed to list application runs: {e!s}").mark("LABEL_ERROR")
|