Skip to content

Commit 4b1ac5f

Browse files
committed
trying a fixture-based approach
1 parent ee49af5 commit 4b1ac5f

File tree

7 files changed

+59
-52
lines changed

7 files changed

+59
-52
lines changed

test/conftest.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,17 @@
66
from model import Detector, ImageQuery, ImageQueryTypeEnum, ResultTypeEnum
77

88

9-
def generate_test_detector_name(prefix: str = "Test") -> str:
10-
"""Generates a unique detector name with a timestamp and random suffix to avoid collisions in parallel CI."""
9+
def _generate_test_detector_name(prefix: str = "Test") -> str:
10+
"""Generates a detector name with a timestamp and random suffix to ensure uniqueness."""
1111
return f"{prefix} {datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')}_{uuid4().hex[:8]}"
1212

1313

14+
@pytest.fixture(name="generate_test_detector_name")
15+
def fixture_test_detector_name():
16+
"""Fixture that provides a callable to generate unique detector names."""
17+
return _generate_test_detector_name
18+
19+
1420
def pytest_configure(config): # pylint: disable=unused-argument
1521
# Run environment check before tests
1622
gl = Groundlight()
@@ -33,7 +39,7 @@ def fixture_detector(gl: Groundlight) -> Detector:
3339
"""Creates a new Test detector."""
3440
query = "Is there a dog?"
3541
pipeline_config = "never-review"
36-
return gl.create_detector(name=generate_test_detector_name(), query=query, pipeline_config=pipeline_config)
42+
return gl.create_detector(name=_generate_test_detector_name(), query=query, pipeline_config=pipeline_config)
3743

3844

3945
@pytest.fixture(name="count_detector")
@@ -42,7 +48,7 @@ def fixture_count_detector(gl_experimental: ExperimentalApi) -> Detector:
4248
query = "How many dogs?"
4349
pipeline_config = "never-review-multi" # always predicts 0
4450
return gl_experimental.create_counting_detector(
45-
name=generate_test_detector_name(), query=query, class_name="dog", pipeline_config=pipeline_config
51+
name=_generate_test_detector_name(), query=query, class_name="dog", pipeline_config=pipeline_config
4652
)
4753

4854

test/integration/test_groundlight.py

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,9 @@
55
import random
66
import string
77
import time
8-
from typing import Any, Dict, Optional, Union
8+
from typing import Any, Callable, Dict, Optional, Union
99

1010
import pytest
11-
from conftest import generate_test_detector_name
1211
from groundlight import Groundlight
1312
from groundlight.binary_labels import VALID_DISPLAY_LABELS, Label, convert_internal_label_to_display
1413
from groundlight.internalapi import ApiException, InternalApiError, NotFoundError
@@ -96,7 +95,7 @@ def test_create_groundlight_with_retries():
9695
assert gl.api_client.configuration.retries.total == retries.total
9796

9897

99-
def test_create_detector(gl: Groundlight):
98+
def test_create_detector(gl: Groundlight, generate_test_detector_name: Callable):
10099
name = generate_test_detector_name()
101100
query = "Is there a dog?"
102101
_detector = gl.create_detector(name=name, query=query)
@@ -117,7 +116,7 @@ def test_create_detector(gl: Groundlight):
117116
assert str(multiclass_detector)
118117

119118

120-
def test_create_detector_with_pipeline_config(gl: Groundlight):
119+
def test_create_detector_with_pipeline_config(gl: Groundlight, generate_test_detector_name: Callable):
121120
# "never-review" is a special model that always returns the same result with 100% confidence.
122121
# It's useful for testing.
123122
name = generate_test_detector_name("Test never-review")
@@ -128,7 +127,7 @@ def test_create_detector_with_pipeline_config(gl: Groundlight):
128127
assert isinstance(_detector, Detector)
129128

130129

131-
def test_create_detector_with_edge_pipeline_config(gl: Groundlight):
130+
def test_create_detector_with_edge_pipeline_config(gl: Groundlight, generate_test_detector_name: Callable):
132131
name = generate_test_detector_name("Test edge-pipeline-config")
133132
query = "Is there a dog (edge-config)?"
134133
_detector = gl.create_detector(
@@ -141,7 +140,7 @@ def test_create_detector_with_edge_pipeline_config(gl: Groundlight):
141140
assert isinstance(_detector, Detector)
142141

143142

144-
def test_create_detector_with_confidence_threshold(gl: Groundlight):
143+
def test_create_detector_with_confidence_threshold(gl: Groundlight, generate_test_detector_name: Callable):
145144
# "never-review" is a special model that always returns the same result with 100% confidence.
146145
# It's useful for testing.
147146
name = generate_test_detector_name("Test with confidence")
@@ -197,7 +196,7 @@ def test_create_detector_with_confidence_threshold(gl: Groundlight):
197196

198197

199198
@pytest.mark.skip_for_edge_endpoint(reason="The edge-endpoint does not support passing detector metadata.")
200-
def test_create_detector_with_everything(gl: Groundlight):
199+
def test_create_detector_with_everything(gl: Groundlight, generate_test_detector_name: Callable):
201200
name = generate_test_detector_name()
202201
query = "Is there a dog?"
203202
group_name = "Test group"
@@ -232,7 +231,7 @@ def test_list_detectors(gl: Groundlight):
232231
assert isinstance(detectors, PaginatedDetectorList)
233232

234233

235-
def test_get_or_create_detector(gl: Groundlight):
234+
def test_get_or_create_detector(gl: Groundlight, generate_test_detector_name: Callable):
236235
# With a unique name, we should be creating a new detector.
237236
unique_name = generate_test_detector_name()
238237
query = "Is there a dog?"
@@ -410,7 +409,7 @@ def test_submit_image_query_with_low_request_timeout(gl: Groundlight, detector:
410409

411410

412411
@pytest.mark.skip_for_edge_endpoint(reason="The edge-endpoint does not support passing detector metadata.")
413-
def test_create_detector_with_metadata(gl: Groundlight):
412+
def test_create_detector_with_metadata(gl: Groundlight, generate_test_detector_name: Callable):
414413
name = generate_test_detector_name()
415414
query = "Is there a dog?"
416415
metadata = generate_random_dict(target_size_bytes=200)
@@ -422,7 +421,7 @@ def test_create_detector_with_metadata(gl: Groundlight):
422421

423422

424423
@pytest.mark.skip_for_edge_endpoint(reason="The edge-endpoint does not support passing detector metadata.")
425-
def test_get_or_create_detector_with_metadata(gl: Groundlight):
424+
def test_get_or_create_detector_with_metadata(gl: Groundlight, generate_test_detector_name: Callable):
426425
unique_name = generate_test_detector_name()
427426
query = "Is there a dog?"
428427
metadata = generate_random_dict(target_size_bytes=200)
@@ -443,7 +442,7 @@ def test_get_or_create_detector_with_metadata(gl: Groundlight):
443442
[""],
444443
],
445444
)
446-
def test_create_detector_with_invalid_metadata(gl: Groundlight, metadata_list: Any):
445+
def test_create_detector_with_invalid_metadata(gl: Groundlight, metadata_list: Any, generate_test_detector_name: Callable):
447446
name = generate_test_detector_name()
448447
query = "Is there a dog?"
449448

@@ -627,7 +626,7 @@ def test_list_image_queries(gl: Groundlight):
627626
assert is_valid_display_result(image_query.result)
628627

629628

630-
def test_list_image_queries_with_filter(gl: Groundlight):
629+
def test_list_image_queries_with_filter(gl: Groundlight, generate_test_detector_name: Callable):
631630
# We want a fresh detector so we know exactly what image queries are associated with it
632631
detector = gl.create_detector(name=generate_test_detector_name(), query="Is there a dog?")
633632
image_query_yes = gl.ask_async(detector=detector.id, image="test/assets/dog.jpeg", human_review="NEVER")
@@ -855,7 +854,7 @@ def test_submit_image_query_with_empty_inspection_id(gl: Groundlight, detector:
855854
)
856855

857856

858-
def test_binary_detector(gl: Groundlight):
857+
def test_binary_detector(gl: Groundlight, generate_test_detector_name: Callable):
859858
"""
860859
verify that we can create and submit to a binary detector
861860
"""
@@ -866,7 +865,7 @@ def test_binary_detector(gl: Groundlight):
866865
assert binary_iq.result.label is not None
867866

868867

869-
def test_counting_detector(gl: Groundlight):
868+
def test_counting_detector(gl: Groundlight, generate_test_detector_name: Callable):
870869
"""
871870
verify that we can create and submit to a counting detector
872871
"""
@@ -877,7 +876,7 @@ def test_counting_detector(gl: Groundlight):
877876
assert count_iq.result.count is not None
878877

879878

880-
def test_counting_detector_async(gl: Groundlight):
879+
def test_counting_detector_async(gl: Groundlight, generate_test_detector_name: Callable):
881880
"""
882881
verify that we can create and submit to a counting detector
883882
"""
@@ -896,7 +895,7 @@ def test_counting_detector_async(gl: Groundlight):
896895
assert _image_query.result is not None
897896

898897

899-
def test_multiclass_detector(gl: Groundlight):
898+
def test_multiclass_detector(gl: Groundlight, generate_test_detector_name: Callable):
900899
"""
901900
verify that we can create and submit to a multi-class detector
902901
"""
@@ -911,7 +910,7 @@ def test_multiclass_detector(gl: Groundlight):
911910
assert mc_iq.result.label in class_names
912911

913912

914-
def test_delete_detector(gl: Groundlight):
913+
def test_delete_detector(gl: Groundlight, generate_test_detector_name: Callable):
915914
"""
916915
Test deleting a detector by both ID and object, and verify proper error handling.
917916
"""
@@ -952,7 +951,7 @@ def test_delete_detector(gl: Groundlight):
952951
gl.delete_detector(fake_detector_id) # type: ignore
953952

954953

955-
def test_create_detector_with_invalid_priming_group_id(gl: Groundlight):
954+
def test_create_detector_with_invalid_priming_group_id(gl: Groundlight, generate_test_detector_name: Callable):
956955
"""
957956
Test that creating a detector with a non-existent priming_group_id returns an appropriate error.
958957

test/integration/test_groundlight_expensive.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
# pylint: disable=wildcard-import,unused-wildcard-import,redefined-outer-name,import-outside-toplevel
88
import random
99
import time
10+
from typing import Callable
1011

1112
import pytest
12-
from conftest import generate_test_detector_name
1313
from groundlight import Groundlight
1414
from groundlight.internalapi import iq_is_answered, iq_is_confident
1515
from groundlight.optional_imports import *
@@ -30,7 +30,7 @@ def fixture_gl() -> Groundlight:
3030

3131

3232
@pytest.mark.skip(reason="This test requires a human labeler who does not need to be in the testing loop")
33-
def test_human_label(gl: Groundlight):
33+
def test_human_label(gl: Groundlight, generate_test_detector_name: Callable):
3434
detector = gl.create_detector(name=generate_test_detector_name(), query="Is there a dog?")
3535
img_query = gl.submit_image_query(
3636
detector=detector.id, image="test/assets/dog.jpeg", wait=60, human_review="ALWAYS"
@@ -52,7 +52,7 @@ def test_human_label(gl: Groundlight):
5252

5353
@pytest.mark.skip(reason="This test can block development depending on the state of the service")
5454
@pytest.mark.skipif(MISSING_PIL, reason="Needs pillow") # type: ignore
55-
def test_detector_improvement(gl: Groundlight):
55+
def test_detector_improvement(gl: Groundlight, generate_test_detector_name: Callable):
5656
# test that we get confidence improvement after sending images in
5757
# Pass two of each type of image in
5858
import time
@@ -122,7 +122,7 @@ def submit_noisy_image(image, label=None):
122122
@pytest.mark.skip(
123123
reason="We don't yet have an SLA level to test ask_confident against, and the test is flakey as a result"
124124
)
125-
def test_ask_method_quality(gl: Groundlight, detector: Detector):
125+
def test_ask_method_quality(gl: Groundlight, detector: Detector, generate_test_detector_name: Callable):
126126
# asks for some level of quality on how fast ask_ml is and that we will get a confident result from ask_confident
127127
fast_always_yes_iq = gl.ask_ml(detector=detector.id, image="test/assets/dog.jpeg", wait=0)
128128
assert iq_is_answered(fast_always_yes_iq)

test/unit/test_cli.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
import os
22
import re
33
import subprocess
4+
from typing import Callable
45
from unittest.mock import patch
56

6-
from conftest import generate_test_detector_name
7-
87

98
def test_whoami():
109
completed_process = subprocess.run(
@@ -24,7 +23,7 @@ def test_list_detector():
2423
assert completed_process.returncode == 0
2524

2625

27-
def test_detector_and_image_queries():
26+
def test_detector_and_image_queries(generate_test_detector_name: Callable):
2827
# test creating a detector
2928
test_detector_name = generate_test_detector_name("testdetector")
3029
completed_process = subprocess.run(

test/unit/test_detector_reset.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import time
2+
from typing import Callable
23

34
import pytest
4-
from conftest import generate_test_detector_name
55
from groundlight import ExperimentalApi
66
from groundlight_openapi_client.exceptions import NotFoundException
77

88

99
@pytest.mark.skip(reason="This is an expensive test, reset may take some time")
10-
def test_reset_retry(gl_experimental: ExperimentalApi):
10+
def test_reset_retry(gl_experimental: ExperimentalApi, generate_test_detector_name: Callable):
1111
# Reset the detector, retrying in case the reset is still ongoing
1212
det = gl_experimental.create_detector(generate_test_detector_name(), "test_query")
1313
iq = gl_experimental.submit_image_query(det, "test/assets/cat.jpeg")
@@ -27,7 +27,7 @@ def test_reset_retry(gl_experimental: ExperimentalApi):
2727

2828

2929
@pytest.mark.skip(reason="This test does not work with strong 0 shot models, enabled by default based on your account")
30-
def test_reset_training(gl_experimental: ExperimentalApi):
30+
def test_reset_training(gl_experimental: ExperimentalApi, generate_test_detector_name: Callable):
3131
# If we reset a detector, we should have low confidence after the reset
3232
low_confidence_threshold = 0.6
3333
det = gl_experimental.create_detector(generate_test_detector_name(), "is this a cat")

test/unit/test_experimental.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import time
2+
from typing import Callable
23

34
import pytest
4-
from conftest import generate_test_detector_name
55
from groundlight import ExperimentalApi
66
from model import Detector, ImageQuery
77

88

9-
def test_detector_groups(gl_experimental: ExperimentalApi):
9+
def test_detector_groups(gl_experimental: ExperimentalApi, generate_test_detector_name: Callable):
1010
"""
1111
verify that we can create a detector group and retrieve it
1212
"""
@@ -30,7 +30,7 @@ def test_update_detector_confidence_threshold(gl_experimental: ExperimentalApi,
3030
assert updated_detector.confidence_threshold == newer_confidence
3131

3232

33-
def test_update_detector_name(gl_experimental: ExperimentalApi, detector: Detector):
33+
def test_update_detector_name(gl_experimental: ExperimentalApi, detector: Detector, generate_test_detector_name: Callable):
3434
"""
3535
verify that we can update the name of a detector
3636
"""
@@ -40,7 +40,7 @@ def test_update_detector_name(gl_experimental: ExperimentalApi, detector: Detect
4040
assert updated_detector.name == new_name
4141

4242

43-
def test_update_detector_status(gl_experimental: ExperimentalApi):
43+
def test_update_detector_status(gl_experimental: ExperimentalApi, generate_test_detector_name: Callable):
4444
"""
4545
verify that we can update the status of a detector
4646
"""
@@ -53,7 +53,7 @@ def test_update_detector_status(gl_experimental: ExperimentalApi):
5353
assert updated_detector.status.value == "ON"
5454

5555

56-
def test_update_detector_escalation_type(gl_experimental: ExperimentalApi):
56+
def test_update_detector_escalation_type(gl_experimental: ExperimentalApi, generate_test_detector_name: Callable):
5757
"""
5858
verify that we can update the escalation type of a detector
5959
"""
@@ -90,7 +90,7 @@ def test_submit_multiple_rois(gl_experimental: ExperimentalApi, image_query_one:
9090
gl_experimental.add_label(image_query_one, 3, [roi] * 3)
9191

9292

93-
def test_text_recognition_detector(gl_experimental: ExperimentalApi):
93+
def test_text_recognition_detector(gl_experimental: ExperimentalApi, generate_test_detector_name: Callable):
9494
"""
9595
verify that we can create and submit to a text recognition detector
9696
"""
@@ -103,7 +103,7 @@ def test_text_recognition_detector(gl_experimental: ExperimentalApi):
103103
assert mc_iq.result.text is not None
104104

105105

106-
def test_bounding_box_detector(gl_experimental: ExperimentalApi):
106+
def test_bounding_box_detector(gl_experimental: ExperimentalApi, generate_test_detector_name: Callable):
107107
"""
108108
Verify that we can create and submit to a bounding box detector
109109
"""
@@ -117,7 +117,7 @@ def test_bounding_box_detector(gl_experimental: ExperimentalApi):
117117
assert bbox_iq.rois is not None
118118

119119

120-
def test_bounding_box_detector_async(gl_experimental: ExperimentalApi):
120+
def test_bounding_box_detector_async(gl_experimental: ExperimentalApi, generate_test_detector_name: Callable):
121121
"""
122122
Verify that we can create and submit to a bounding box detector with ask_async
123123
"""

0 commit comments

Comments
 (0)