From b5e35ecca9484f6b2231f7bbc0c51e01e09e884d Mon Sep 17 00:00:00 2001 From: brandon Date: Wed, 11 Dec 2024 17:19:23 -0800 Subject: [PATCH 1/6] Consider the async case for internal functions --- pyproject.toml | 2 +- src/groundlight/internalapi.py | 4 ++++ test/unit/test_internalapi.py | 13 +++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 test/unit/test_internalapi.py diff --git a/pyproject.toml b/pyproject.toml index 8bdb11d7..4e2eaebb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ packages = [ {include = "**/*.py", from = "src"}, ] readme = "README.md" -version = "0.21.0" +version = "0.21.1" [tool.poetry.dependencies] # For certifi, use ">=" instead of "^" since it upgrades its "major version" every year, not really following semver diff --git a/src/groundlight/internalapi.py b/src/groundlight/internalapi.py index 18f2f3a7..bff192cd 100644 --- a/src/groundlight/internalapi.py +++ b/src/groundlight/internalapi.py @@ -65,6 +65,8 @@ def iq_is_confident(iq: ImageQuery, confidence_threshold: float) -> bool: The only subtlety here is that currently confidence of None means human label, which is treated as confident. """ + if not iq.result: + return False return iq.result.confidence >= confidence_threshold # type: ignore @@ -72,6 +74,8 @@ def iq_is_answered(iq: ImageQuery) -> bool: """Returns True if the image query has a ML or human label. Placeholder and special labels (out of domain) have confidences exactly 0.5 """ + if not iq.result: + return False if (iq.result.source == Source.STILL_PROCESSING) or (iq.result.source is None): # Should never be None return False return True diff --git a/test/unit/test_internalapi.py b/test/unit/test_internalapi.py new file mode 100644 index 00000000..1270c4cd --- /dev/null +++ b/test/unit/test_internalapi.py @@ -0,0 +1,13 @@ +from groundlight import ExperimentalApi +from groundlight.internalapi import iq_is_answered, iq_is_confident + +def test_iq_is_confident(gl_experimental: ExperimentalApi): + det = gl_experimental.get_or_create_detector("Test", "test_query") + iq = gl_experimental.ask_async(det, image="test/assets/dog.jpeg", wait=10) + assert not iq_is_confident(iq, 0.9) + +def test_iq_is_answered(gl_experimental: ExperimentalApi): + det = gl_experimental.get_or_create_detector("Test", "test_query") + iq = gl_experimental.ask_async(det, image="test/assets/dog.jpeg", wait=10) + assert not iq_is_answered(iq) + From 8329ae28474a2070bc85ce44cd21c4f02b10dbe3 Mon Sep 17 00:00:00 2001 From: brandon Date: Wed, 11 Dec 2024 23:50:22 -0800 Subject: [PATCH 2/6] hotfix --- test/unit/test_internalapi.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit/test_internalapi.py b/test/unit/test_internalapi.py index 1270c4cd..9da08c2f 100644 --- a/test/unit/test_internalapi.py +++ b/test/unit/test_internalapi.py @@ -3,11 +3,11 @@ def test_iq_is_confident(gl_experimental: ExperimentalApi): det = gl_experimental.get_or_create_detector("Test", "test_query") - iq = gl_experimental.ask_async(det, image="test/assets/dog.jpeg", wait=10) + iq = gl_experimental.ask_async(det, image="test/assets/dog.jpeg") assert not iq_is_confident(iq, 0.9) def test_iq_is_answered(gl_experimental: ExperimentalApi): det = gl_experimental.get_or_create_detector("Test", "test_query") - iq = gl_experimental.ask_async(det, image="test/assets/dog.jpeg", wait=10) + iq = gl_experimental.ask_async(det, image="test/assets/dog.jpeg") assert not iq_is_answered(iq) From 20ab3d23d9f16d3701d2bddeb472e736e51668b6 Mon Sep 17 00:00:00 2001 From: Auto-format Bot Date: Thu, 12 Dec 2024 07:52:39 +0000 Subject: [PATCH 3/6] Automatically reformatting code --- test/unit/test_internalapi.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/unit/test_internalapi.py b/test/unit/test_internalapi.py index 9da08c2f..e6f6fbca 100644 --- a/test/unit/test_internalapi.py +++ b/test/unit/test_internalapi.py @@ -1,13 +1,14 @@ from groundlight import ExperimentalApi from groundlight.internalapi import iq_is_answered, iq_is_confident + def test_iq_is_confident(gl_experimental: ExperimentalApi): det = gl_experimental.get_or_create_detector("Test", "test_query") iq = gl_experimental.ask_async(det, image="test/assets/dog.jpeg") assert not iq_is_confident(iq, 0.9) + def test_iq_is_answered(gl_experimental: ExperimentalApi): det = gl_experimental.get_or_create_detector("Test", "test_query") iq = gl_experimental.ask_async(det, image="test/assets/dog.jpeg") assert not iq_is_answered(iq) - From 1f03ec947adc90936b55a4a77204ec392bb143c6 Mon Sep 17 00:00:00 2001 From: brandon Date: Wed, 11 Dec 2024 23:54:37 -0800 Subject: [PATCH 4/6] ruff fix --- test/unit/test_internalapi.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/unit/test_internalapi.py b/test/unit/test_internalapi.py index 9da08c2f..a71611c3 100644 --- a/test/unit/test_internalapi.py +++ b/test/unit/test_internalapi.py @@ -1,6 +1,7 @@ from groundlight import ExperimentalApi from groundlight.internalapi import iq_is_answered, iq_is_confident + def test_iq_is_confident(gl_experimental: ExperimentalApi): det = gl_experimental.get_or_create_detector("Test", "test_query") iq = gl_experimental.ask_async(det, image="test/assets/dog.jpeg") From 0899dc7c7961490ecbdba398d641594074c6edea Mon Sep 17 00:00:00 2001 From: brandon Date: Thu, 12 Dec 2024 00:10:46 -0800 Subject: [PATCH 5/6] test fix related to multiclass --- test/integration/test_groundlight.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/integration/test_groundlight.py b/test/integration/test_groundlight.py index ab82f0e7..6329f9bb 100644 --- a/test/integration/test_groundlight.py +++ b/test/integration/test_groundlight.py @@ -20,6 +20,7 @@ CountingResult, Detector, ImageQuery, + MultiClassificationResult, PaginatedDetectorList, PaginatedImageQueryList, ) @@ -30,7 +31,7 @@ def is_valid_display_result(result: Any) -> bool: """Is the image query result valid to display to the user?.""" - if not isinstance(result, BinaryClassificationResult) and not isinstance(result, CountingResult): + if not isinstance(result, BinaryClassificationResult) and not isinstance(result, CountingResult) and not isinstance(result, MultiClassificationResult): return False if not is_valid_display_label(result.label): return False From 5e5d864351bd5ff6c310b34e9b6226ff10a367a3 Mon Sep 17 00:00:00 2001 From: Auto-format Bot Date: Thu, 12 Dec 2024 08:11:45 +0000 Subject: [PATCH 6/6] Automatically reformatting code --- test/integration/test_groundlight.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/integration/test_groundlight.py b/test/integration/test_groundlight.py index 6329f9bb..3e183263 100644 --- a/test/integration/test_groundlight.py +++ b/test/integration/test_groundlight.py @@ -31,7 +31,11 @@ def is_valid_display_result(result: Any) -> bool: """Is the image query result valid to display to the user?.""" - if not isinstance(result, BinaryClassificationResult) and not isinstance(result, CountingResult) and not isinstance(result, MultiClassificationResult): + if ( + not isinstance(result, BinaryClassificationResult) + and not isinstance(result, CountingResult) + and not isinstance(result, MultiClassificationResult) + ): return False if not is_valid_display_label(result.label): return False