qctrl-workflow-client 1.0.0__tar.gz → 1.2.0__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: qctrl-workflow-client
3
- Version: 1.0.0
3
+ Version: 1.2.0
4
4
  Summary: Q-CTRL Client
5
5
  Home-page: https://q-ctrl.com
6
6
  License: https://q-ctrl.com/terms
@@ -33,7 +33,7 @@ Requires-Dist: gql (>=3.4.0,<4.0.0)
33
33
  Requires-Dist: importlib-metadata (>=6.8.0,<7.0.0)
34
34
  Requires-Dist: packaging (>=23.1.0,<24.0.0)
35
35
  Requires-Dist: qctrl-client (>=9.0.1,<10.0.0)
36
- Requires-Dist: qctrl-commons (>=20.0.0,<21.0.0)
36
+ Requires-Dist: qctrl-commons (>=21.0.0,<22.0.0)
37
37
  Requires-Dist: requests (>=2.31.0,<3.0.0)
38
38
  Requires-Dist: tenacity (>=8.1.0,<9.0.0)
39
39
  Requires-Dist: tomli (>=2.0.1,<3.0.0)
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "qctrl-workflow-client"
3
- version = "1.0.0"
3
+ version = "1.2.0"
4
4
  description = "Q-CTRL Client"
5
5
  license = "https://q-ctrl.com/terms"
6
6
  authors = ["Q-CTRL <support@q-ctrl.com>"]
@@ -83,7 +83,7 @@ tenacity = "^8.1.0"
83
83
  click = "^8.1.3"
84
84
  requests = "^2.31.0"
85
85
  packaging = "^23.1.0"
86
- qctrl-commons = { version = "^20.0.0", source = "PyPI" }
86
+ qctrl-commons = { version = "^21.0.0", source = "PyPI" }
87
87
  qctrl-client = { version = "^9.0.1", source = "PyPI" }
88
88
 
89
89
  [tool.poetry.group.dev.dependencies]
@@ -11,7 +11,7 @@
11
11
  # distributed under the License is distributed on an "AS IS" BASIS. See the
12
12
  # License for the specific language.
13
13
 
14
- __version__ = "1.0.0"
14
+ __version__ = "1.2.0"
15
15
 
16
16
  from .defaults import (
17
17
  get_authenticated_client_for_product,
@@ -10,6 +10,7 @@
10
10
  # Unless required by applicable law or agreed to in writing, software
11
11
  # distributed under the License is distributed on an "AS IS" BASIS. See the
12
12
  # License for the specific language.
13
+ from __future__ import annotations
13
14
 
14
15
  import json
15
16
  from dataclasses import dataclass
@@ -26,6 +27,7 @@ from warnings import warn
26
27
  import gql
27
28
  from qctrlclient import GraphQLClient
28
29
  from qctrlclient.exceptions import GraphQLClientError
30
+ from qctrlcommons.preconditions import check_argument
29
31
  from qctrlcommons.serializers import (
30
32
  DataTypeDecoder,
31
33
  DataTypeEncoder,
@@ -57,9 +59,13 @@ class ActionStatus(Enum):
57
59
  Valid Action statuses.
58
60
  """
59
61
 
60
- SUCCESS = "SUCCESS"
61
- FAILURE = "FAILURE"
62
- REVOKED = "REVOKED"
62
+ SUCCESS = "SUCCESS" # has completed
63
+ FAILURE = "FAILURE" # has failed
64
+ REVOKED = "REVOKED" # has been cancelled
65
+ PENDING = "PENDING" # is queued
66
+ RECEIVED = "RECEIVED" # has been received
67
+ RETRY = "RETRY" # is retrying
68
+ STARTED = "STARTED" # has started
63
69
 
64
70
 
65
71
  @dataclass
@@ -569,7 +575,7 @@ class ApiRouter(BaseRouter):
569
575
  Wait until the requested number of machines are online.
570
576
  """
571
577
 
572
- number_of_machines_online = self._get_number_of_machines_online()
578
+ number_of_machines_online = self.get_machine_status()["online"]
573
579
 
574
580
  def machines(count: int) -> str:
575
581
  if count == 1:
@@ -585,9 +591,9 @@ class ApiRouter(BaseRouter):
585
591
  "requested": number_of_machines_requested,
586
592
  }
587
593
 
588
- def _get_number_of_machines_online(self) -> int:
594
+ def get_machine_status(self) -> dict[str, int]:
589
595
  """
590
- Return the number of machines that are online.
596
+ Return the current state of all machines.
591
597
  """
592
598
  _query = gql.gql(
593
599
  """
@@ -595,8 +601,12 @@ class ApiRouter(BaseRouter):
595
601
  tenant(organizationId:$organizationId) {
596
602
  tenant {
597
603
  currentInstances {
604
+ initializing
605
+ offline
598
606
  online
599
- }
607
+ pending
608
+ terminating
609
+ }
600
610
  }
601
611
  errors {
602
612
  message
@@ -610,10 +620,73 @@ class ApiRouter(BaseRouter):
610
620
  _query,
611
621
  {"organizationId": self._get_configured_organization().organization_id},
612
622
  )
613
- number_of_machines_online = response["tenant"]["tenant"]["currentInstances"][
614
- "online"
615
- ]
616
- return number_of_machines_online
623
+ return response["tenant"]["tenant"]["currentInstances"]
624
+
625
+ def activity_monitor(
626
+ self,
627
+ limit: int,
628
+ offset: int = 0,
629
+ status: Optional[str] = None,
630
+ ) -> list[dict[str, Any]]:
631
+ """
632
+ Fetch metadata from previously submitted actions.
633
+
634
+ Parameters
635
+ ----------
636
+ limit : int
637
+ The number of actions to fetch.
638
+ offset : int, optional
639
+ The number of recent actions to ignore before starting to fetch.
640
+ Defaults to 0.
641
+ status : str or None, optional
642
+ The filter for action status. Defaults to None.
643
+
644
+ Returns
645
+ -------
646
+ list[dict[str, Any]]
647
+ Action metadata with one raw JSON-style dictionary per action.
648
+ """
649
+ _query = gql.gql(
650
+ """
651
+ query getActions($limit: Int, $offset: Int, $filterBy: ActionFilter) {
652
+ actions(limit:$limit, offset:$offset, filterBy:$filterBy) {
653
+ actions {
654
+ name
655
+ status
656
+ modelType
657
+ progress
658
+ createdAt
659
+ updatedAt
660
+ modelId
661
+ }
662
+ errors {
663
+ message
664
+ }
665
+ }
666
+ }
667
+ """
668
+ )
669
+
670
+ check_argument(limit >= 1, "Limit must be at least 1.", {"limit": limit})
671
+ check_argument(offset >= 0, "Offset must be at least 0.", {"offset": offset})
672
+
673
+ filter_by = {}
674
+ if status is not None:
675
+ valid_statuses = [status.value for status in ActionStatus]
676
+ check_argument(
677
+ condition=status in valid_statuses,
678
+ description="Status is not valid. "
679
+ "Please choose from a valid status type: "
680
+ f"{valid_statuses}",
681
+ arguments={"status": status},
682
+ )
683
+ filter_by["status"] = {"exact": status}
684
+
685
+ response = self._client.execute(
686
+ _query,
687
+ {"limit": limit, "offset": offset, "filterBy": filter_by},
688
+ )
689
+ return response["actions"]["actions"]
617
690
 
618
691
 
619
692
  class ParallelCollector: