From f5b5ceb838281ce92ab0adb57ed95ad482128ab4 Mon Sep 17 00:00:00 2001 From: brandon Date: Wed, 11 Dec 2024 15:54:54 -0800 Subject: [PATCH 1/7] wip --- src/groundlight/experimental_api.py | 18 +++++------------- test/unit/test_actions.py | 15 ++++++--------- 2 files changed, 11 insertions(+), 22 deletions(-) diff --git a/src/groundlight/experimental_api.py b/src/groundlight/experimental_api.py index 5b8765b8..fbe8c214 100644 --- a/src/groundlight/experimental_api.py +++ b/src/groundlight/experimental_api.py @@ -255,13 +255,11 @@ def list_rules(self, page=1, page_size=10) -> PaginatedRuleList: obj = self.actions_api.list_rules(page=page, page_size=page_size) return PaginatedRuleList.parse_obj(obj.to_dict()) - def delete_all_rules(self, detector: Union[None, str, Detector] = None) -> int: + def delete_all_rules(self, detector: Union[str, Detector]) -> int: """ - Deletes all rules associated with the given detector. If no detector is specified, - deletes all rules in the account. + Deletes all rules associated with the given detector. - WARNING: If no detector is specified, this will delete ALL rules in your account. - This action cannot be undone. Use with caution. + WARNING: This action cannot be undone. Use with caution. **Example usage**:: @@ -272,11 +270,7 @@ def delete_all_rules(self, detector: Union[None, str, Detector] = None) -> int: num_deleted = gl.delete_all_rules(detector) print(f"Deleted {num_deleted} rules") - # Delete all rules in the account - num_deleted = gl.delete_all_rules() - print(f"Deleted {num_deleted} rules") - - :param detector: the detector to delete the rules from. If None, deletes all rules. + :param detector: the detector to delete the rules from. :return: the number of rules deleted """ @@ -286,9 +280,7 @@ def delete_all_rules(self, detector: Union[None, str, Detector] = None) -> int: num_rules = self.list_rules().count for page in range(1, (num_rules // self.ITEMS_PER_PAGE) + 2): for rule in self.list_rules(page=page, page_size=self.ITEMS_PER_PAGE).results: - if det_id is None: - ids_to_delete.append(rule.id) - elif rule.detector_id == det_id: + if rule.detector_id == det_id: ids_to_delete.append(rule.id) for rule_id in ids_to_delete: self.delete_rule(rule_id) diff --git a/test/unit/test_actions.py b/test/unit/test_actions.py index d620255b..b2a9fe86 100644 --- a/test/unit/test_actions.py +++ b/test/unit/test_actions.py @@ -6,8 +6,6 @@ def test_create_action(gl_experimental: ExperimentalApi): - # We first clear out any rules in case the account has any left over from a previous test - gl_experimental.delete_all_rules() name = f"Test {datetime.utcnow()}" det = gl_experimental.get_or_create_detector(name, "test_query") rule = gl_experimental.create_rule(det, f"test_rule_{name}", "EMAIL", "test@example.com") @@ -15,24 +13,23 @@ def test_create_action(gl_experimental: ExperimentalApi): assert rule == rule2 -@pytest.mark.skip(reason="actions are global on account, the test matrix collides with itself") # type: ignore def test_get_all_actions(gl_experimental: ExperimentalApi): name = f"Test {datetime.utcnow()}" num_test_rules = 13 # needs to be larger than the default page size gl_experimental.ITEMS_PER_PAGE = 10 assert gl_experimental.ITEMS_PER_PAGE < num_test_rules det = gl_experimental.get_or_create_detector(name, "test_query") - gl_experimental.delete_all_rules() for i in range(num_test_rules): _ = gl_experimental.create_rule(det, f"test_rule_{i}", "EMAIL", "test@example.com") rules = gl_experimental.list_rules(page_size=gl_experimental.ITEMS_PER_PAGE) - assert rules.count == num_test_rules + # The exact number of actions is not guaranteed if another client is making calls at the same time + assert rules.count > num_test_rules assert len(rules.results) == gl_experimental.ITEMS_PER_PAGE - num_deleted = gl_experimental.delete_all_rules() - assert num_deleted == num_test_rules - rules = gl_experimental.list_rules() - assert rules.count == 0 +def test_delete_actions(): + name = f"Test {datetime.utcnow()}" + num_test_rules = 13 # needs to be larger than the default page size + # TODO: get actions by detector def test_create_action_with_human_review(gl_experimental: ExperimentalApi): name = f"Test {datetime.utcnow()}" From b6b22b6a6df07446665f8a7797255c2eed547b51 Mon Sep 17 00:00:00 2001 From: brandon Date: Wed, 11 Dec 2024 16:51:01 -0800 Subject: [PATCH 2/7] fetch rules by detector --- src/groundlight/experimental_api.py | 18 ++++++++++++++++++ test/unit/test_actions.py | 11 +++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/groundlight/experimental_api.py b/src/groundlight/experimental_api.py index fbe8c214..e16539bc 100644 --- a/src/groundlight/experimental_api.py +++ b/src/groundlight/experimental_api.py @@ -214,6 +214,24 @@ def get_rule(self, action_id: int) -> Rule: """ return Rule.model_validate(self.actions_api.get_rule(action_id).to_dict()) + def list_detector_rules(self, detector: Union[str, Detector]) -> List[Rule]: + """ + Gets all rules associated with the given detector. + + **Example usage**:: + + gl = ExperimentalApi() + + # Get all rules for a specific detector + rules = gl.list_detector_rules(det_mydetectorid) + for rule in rules: + print(f"Rule {rule.id}: {rule.name}") + + :param detector: the detector or detector_id to get the rules for + :return: a list of Rule objects associated with the given detector + """ + return [Rule.model_validate(rule.to_dict()) for rule in self.actions_api.list_detector_rules(detector.id)] + def delete_rule(self, action_id: int) -> None: """ Deletes the rule with the given id. diff --git a/test/unit/test_actions.py b/test/unit/test_actions.py index b2a9fe86..0749df57 100644 --- a/test/unit/test_actions.py +++ b/test/unit/test_actions.py @@ -26,10 +26,17 @@ def test_get_all_actions(gl_experimental: ExperimentalApi): assert rules.count > num_test_rules assert len(rules.results) == gl_experimental.ITEMS_PER_PAGE -def test_delete_actions(): +def test_delete_actions(gl_experimental: ExperimentalApi): name = f"Test {datetime.utcnow()}" num_test_rules = 13 # needs to be larger than the default page size - # TODO: get actions by detector + det = gl_experimental.get_or_create_detector(name, "test_query") + for i in range(num_test_rules): + _ = gl_experimental.create_rule(det, f"test_rule_{i}", "EMAIL", "test@example.com") + rules = gl_experimental.list_detector_rules(det.id) + assert rules.count == num_test_rules + gl_experimental.delete_all_rules(det.id) + rules = gl_experimental.list_detector_rules(det.id) + assert rules.count == 0 def test_create_action_with_human_review(gl_experimental: ExperimentalApi): name = f"Test {datetime.utcnow()}" From 3fad2433a86c2b8c229c6dd5f12ee3723dd8e1e7 Mon Sep 17 00:00:00 2001 From: Auto-format Bot Date: Thu, 12 Dec 2024 00:52:57 +0000 Subject: [PATCH 3/7] Automatically reformatting code --- test/unit/test_actions.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/unit/test_actions.py b/test/unit/test_actions.py index 0749df57..6f014b46 100644 --- a/test/unit/test_actions.py +++ b/test/unit/test_actions.py @@ -26,6 +26,7 @@ def test_get_all_actions(gl_experimental: ExperimentalApi): assert rules.count > num_test_rules assert len(rules.results) == gl_experimental.ITEMS_PER_PAGE + def test_delete_actions(gl_experimental: ExperimentalApi): name = f"Test {datetime.utcnow()}" num_test_rules = 13 # needs to be larger than the default page size @@ -38,6 +39,7 @@ def test_delete_actions(gl_experimental: ExperimentalApi): rules = gl_experimental.list_detector_rules(det.id) assert rules.count == 0 + def test_create_action_with_human_review(gl_experimental: ExperimentalApi): name = f"Test {datetime.utcnow()}" det = gl_experimental.get_or_create_detector(name, "test_query") From 4af46715aa388d450963a4bfac93b8795cc7f924 Mon Sep 17 00:00:00 2001 From: brandon Date: Thu, 12 Dec 2024 15:00:13 -0800 Subject: [PATCH 4/7] small fix --- src/groundlight/experimental_api.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/groundlight/experimental_api.py b/src/groundlight/experimental_api.py index e16539bc..b3a687fd 100644 --- a/src/groundlight/experimental_api.py +++ b/src/groundlight/experimental_api.py @@ -230,7 +230,9 @@ def list_detector_rules(self, detector: Union[str, Detector]) -> List[Rule]: :param detector: the detector or detector_id to get the rules for :return: a list of Rule objects associated with the given detector """ - return [Rule.model_validate(rule.to_dict()) for rule in self.actions_api.list_detector_rules(detector.id)] + if isinstance(detector, Detector): + detector = detector.id + return [Rule.model_validate(rule.to_dict()) for rule in self.actions_api.list_detector_rules(detector)] def delete_rule(self, action_id: int) -> None: """ From 028998aed852c209242595ddcfe90c84e67ce265 Mon Sep 17 00:00:00 2001 From: brandon Date: Thu, 12 Dec 2024 15:41:24 -0800 Subject: [PATCH 5/7] regenerating api spec, correcting parameter --- generated/docs/ActionsApi.md | 12 ++++++++++++ generated/docs/ImageQueriesApi.md | 6 +++--- .../api/actions_api.py | 10 ++++++++++ .../api/image_queries_api.py | 10 +++++----- generated/model.py | 2 +- spec/public-api.yaml | 19 ++++++++++++++++++- src/groundlight/experimental_api.py | 15 +++++++++++---- test/unit/test_actions.py | 3 +++ 8 files changed, 63 insertions(+), 14 deletions(-) diff --git a/generated/docs/ActionsApi.md b/generated/docs/ActionsApi.md index f1d5b017..306424fb 100644 --- a/generated/docs/ActionsApi.md +++ b/generated/docs/ActionsApi.md @@ -296,6 +296,8 @@ with groundlight_openapi_client.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = actions_api.ActionsApi(api_client) detector_id = "detector_id_example" # str | + page = 1 # int | A page number within the paginated result set. (optional) + page_size = 1 # int | Number of results to return per page. (optional) # example passing only required values which don't have defaults set try: @@ -303,6 +305,14 @@ with groundlight_openapi_client.ApiClient(configuration) as api_client: pprint(api_response) except groundlight_openapi_client.ApiException as e: print("Exception when calling ActionsApi->list_detector_rules: %s\n" % e) + + # example passing only required values which don't have defaults set + # and optional values + try: + api_response = api_instance.list_detector_rules(detector_id, page=page, page_size=page_size) + pprint(api_response) + except groundlight_openapi_client.ApiException as e: + print("Exception when calling ActionsApi->list_detector_rules: %s\n" % e) ``` @@ -311,6 +321,8 @@ with groundlight_openapi_client.ApiClient(configuration) as api_client: Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **detector_id** | **str**| | + **page** | **int**| A page number within the paginated result set. | [optional] + **page_size** | **int**| Number of results to return per page. | [optional] ### Return type diff --git a/generated/docs/ImageQueriesApi.md b/generated/docs/ImageQueriesApi.md index 47a65ae5..e3f91416 100644 --- a/generated/docs/ImageQueriesApi.md +++ b/generated/docs/ImageQueriesApi.md @@ -201,14 +201,14 @@ configuration.api_key['ApiToken'] = 'YOUR_API_KEY' with groundlight_openapi_client.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = image_queries_api.ImageQueriesApi(api_client) + detector_id = "detector_id_example" # str | Optionally filter image queries by detector ID. (optional) page = 1 # int | A page number within the paginated result set. (optional) page_size = 1 # int | Number of items to return per page. (optional) - predictor_id = "predictor_id_example" # str | Optionally filter image queries by detector ID. (optional) # example passing only required values which don't have defaults set # and optional values try: - api_response = api_instance.list_image_queries(page=page, page_size=page_size, predictor_id=predictor_id) + api_response = api_instance.list_image_queries(detector_id=detector_id, page=page, page_size=page_size) pprint(api_response) except groundlight_openapi_client.ApiException as e: print("Exception when calling ImageQueriesApi->list_image_queries: %s\n" % e) @@ -219,9 +219,9 @@ with groundlight_openapi_client.ApiClient(configuration) as api_client: Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- + **detector_id** | **str**| Optionally filter image queries by detector ID. | [optional] **page** | **int**| A page number within the paginated result set. | [optional] **page_size** | **int**| Number of items to return per page. | [optional] - **predictor_id** | **str**| Optionally filter image queries by detector ID. | [optional] ### Return type diff --git a/generated/groundlight_openapi_client/api/actions_api.py b/generated/groundlight_openapi_client/api/actions_api.py index 47ac8d0d..4f9d42f5 100644 --- a/generated/groundlight_openapi_client/api/actions_api.py +++ b/generated/groundlight_openapi_client/api/actions_api.py @@ -173,6 +173,8 @@ def __init__(self, api_client=None): params_map={ "all": [ "detector_id", + "page", + "page_size", ], "required": [ "detector_id", @@ -186,12 +188,18 @@ def __init__(self, api_client=None): "allowed_values": {}, "openapi_types": { "detector_id": (str,), + "page": (int,), + "page_size": (int,), }, "attribute_map": { "detector_id": "detector_id", + "page": "page", + "page_size": "page_size", }, "location_map": { "detector_id": "path", + "page": "query", + "page_size": "query", }, "collection_format_map": {}, }, @@ -434,6 +442,8 @@ def list_detector_rules(self, detector_id, **kwargs): detector_id (str): Keyword Args: + page (int): A page number within the paginated result set.. [optional] + page_size (int): Number of results to return per page.. [optional] _return_http_data_only (bool): response data without head status code and headers. Default is True. _preload_content (bool): if False, the urllib3.HTTPResponse object diff --git a/generated/groundlight_openapi_client/api/image_queries_api.py b/generated/groundlight_openapi_client/api/image_queries_api.py index b25ad772..03ad2600 100644 --- a/generated/groundlight_openapi_client/api/image_queries_api.py +++ b/generated/groundlight_openapi_client/api/image_queries_api.py @@ -127,9 +127,9 @@ def __init__(self, api_client=None): }, params_map={ "all": [ + "detector_id", "page", "page_size", - "predictor_id", ], "required": [], "nullable": [], @@ -140,19 +140,19 @@ def __init__(self, api_client=None): "validations": {}, "allowed_values": {}, "openapi_types": { + "detector_id": (str,), "page": (int,), "page_size": (int,), - "predictor_id": (str,), }, "attribute_map": { + "detector_id": "detector_id", "page": "page", "page_size": "page_size", - "predictor_id": "predictor_id", }, "location_map": { + "detector_id": "query", "page": "query", "page_size": "query", - "predictor_id": "query", }, "collection_format_map": {}, }, @@ -377,9 +377,9 @@ def list_image_queries(self, **kwargs): Keyword Args: + detector_id (str): Optionally filter image queries by detector ID.. [optional] page (int): A page number within the paginated result set.. [optional] page_size (int): Number of items to return per page.. [optional] - predictor_id (str): Optionally filter image queries by detector ID.. [optional] _return_http_data_only (bool): response data without head status code and headers. Default is True. _preload_content (bool): if False, the urllib3.HTTPResponse object diff --git a/generated/model.py b/generated/model.py index 827e7ea1..bf5c9086 100644 --- a/generated/model.py +++ b/generated/model.py @@ -1,6 +1,6 @@ # generated by datamodel-codegen: # filename: public-api.yaml -# timestamp: 2024-12-10T01:13:13+00:00 +# timestamp: 2024-12-12T23:38:24+00:00 from __future__ import annotations diff --git a/spec/public-api.yaml b/spec/public-api.yaml index 89f9f0c0..10ab8471 100644 --- a/spec/public-api.yaml +++ b/spec/public-api.yaml @@ -19,6 +19,18 @@ paths: schema: type: string required: true + - name: page + required: false + in: query + description: A page number within the paginated result set. + schema: + type: integer + - name: page_size + required: false + in: query + description: Number of results to return per page. + schema: + type: integer tags: - actions security: @@ -313,6 +325,11 @@ paths: operationId: List image queries description: Retrieve a list of image-queries. parameters: + - in: query + name: detector_id + schema: + type: string + description: Optionally filter image queries by detector ID. - in: query name: page schema: @@ -1457,4 +1474,4 @@ servers: - url: https://device.positronix.ai/device-api description: Device Prod - url: https://device.integ.positronix.ai/device-api - description: Device Integ \ No newline at end of file + description: Device Integ diff --git a/src/groundlight/experimental_api.py b/src/groundlight/experimental_api.py index b3a687fd..ee8d6ed7 100644 --- a/src/groundlight/experimental_api.py +++ b/src/groundlight/experimental_api.py @@ -214,9 +214,9 @@ def get_rule(self, action_id: int) -> Rule: """ return Rule.model_validate(self.actions_api.get_rule(action_id).to_dict()) - def list_detector_rules(self, detector: Union[str, Detector]) -> List[Rule]: + def list_detector_rules(self, detector: Union[str, Detector], page=1, page_size=10) -> PaginatedRuleList: """ - Gets all rules associated with the given detector. + Gets a paginated list of rules associated with the given detector. **Example usage**:: @@ -224,15 +224,22 @@ def list_detector_rules(self, detector: Union[str, Detector]) -> List[Rule]: # Get all rules for a specific detector rules = gl.list_detector_rules(det_mydetectorid) - for rule in rules: + for rule in rules.results: print(f"Rule {rule.id}: {rule.name}") + # Get next page + next_page = gl.list_detector_rules(det_mydetectorid, page=2) + :param detector: the detector or detector_id to get the rules for + :param page: the page number to retrieve (default: 1) + :param page_size: the number of rules per page (default: 10) :return: a list of Rule objects associated with the given detector """ if isinstance(detector, Detector): detector = detector.id - return [Rule.model_validate(rule.to_dict()) for rule in self.actions_api.list_detector_rules(detector)] + return PaginatedRuleList.parse_obj( + self.actions_api.list_detector_rules(detector, page=page, page_size=page_size).to_dict() + ) def delete_rule(self, action_id: int) -> None: """ diff --git a/test/unit/test_actions.py b/test/unit/test_actions.py index 6f014b46..3c1b9eec 100644 --- a/test/unit/test_actions.py +++ b/test/unit/test_actions.py @@ -33,6 +33,9 @@ def test_delete_actions(gl_experimental: ExperimentalApi): det = gl_experimental.get_or_create_detector(name, "test_query") for i in range(num_test_rules): _ = gl_experimental.create_rule(det, f"test_rule_{i}", "EMAIL", "test@example.com") + import IPython + + IPython.embed() rules = gl_experimental.list_detector_rules(det.id) assert rules.count == num_test_rules gl_experimental.delete_all_rules(det.id) From 588bc77cc65af4dd8bfd3cfe9f1cd2b2fcccf26f Mon Sep 17 00:00:00 2001 From: brandon Date: Thu, 12 Dec 2024 16:09:35 -0800 Subject: [PATCH 6/7] remove debug line --- test/unit/test_actions.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/unit/test_actions.py b/test/unit/test_actions.py index 3c1b9eec..6f014b46 100644 --- a/test/unit/test_actions.py +++ b/test/unit/test_actions.py @@ -33,9 +33,6 @@ def test_delete_actions(gl_experimental: ExperimentalApi): det = gl_experimental.get_or_create_detector(name, "test_query") for i in range(num_test_rules): _ = gl_experimental.create_rule(det, f"test_rule_{i}", "EMAIL", "test@example.com") - import IPython - - IPython.embed() rules = gl_experimental.list_detector_rules(det.id) assert rules.count == num_test_rules gl_experimental.delete_all_rules(det.id) From 1a08fc760178b93145aea8605176702d81fc5858 Mon Sep 17 00:00:00 2001 From: brandon Date: Thu, 19 Dec 2024 15:22:39 -0800 Subject: [PATCH 7/7] reduce the diff --- spec/public-api.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/public-api.yaml b/spec/public-api.yaml index 10ab8471..d5f49198 100644 --- a/spec/public-api.yaml +++ b/spec/public-api.yaml @@ -325,11 +325,6 @@ paths: operationId: List image queries description: Retrieve a list of image-queries. parameters: - - in: query - name: detector_id - schema: - type: string - description: Optionally filter image queries by detector ID. - in: query name: page schema: @@ -340,6 +335,11 @@ paths: schema: type: integer description: Number of items to return per page. + - in: query + name: detector_id + schema: + type: string + description: Optionally filter image queries by detector ID. tags: - image-queries security: