Coverage for /home/runner/work/tket/tket/pytket/pytket/backends/status.py: 95%
64 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-09 15:08 +0000
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-09 15:08 +0000
1# Copyright Quantinuum
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
15"""Status classes for circuits submitted to backends."""
17from datetime import datetime
18from enum import Enum
19from typing import TYPE_CHECKING, Any, NamedTuple
21if TYPE_CHECKING: 21 ↛ 22line 21 didn't jump to line 22 because the condition on line 21 was never true
22 from collections.abc import Callable
25class StatusEnum(Enum):
26 """Enumeration for the possible status of a circuit submitted to a backend."""
28 COMPLETED = "Circuit has completed. Results are ready."
29 QUEUED = "Circuit is queued."
30 SUBMITTED = "Circuit has been submitted."
31 RUNNING = "Circuit is running."
32 RETRYING = "Circuit is being retried."
33 CANCELLING = "Cancellation has been requested."
34 CANCELLED = "Circuit has been cancelled."
35 ERROR = "Circuit has errored. Check CircuitStatus.message for error message."
38class CircuitStatus(NamedTuple):
39 """The status of a circuit along with an optional description.
41 Optionally can also include extra fields such as:
42 * Detailed error information.
43 * Timestamps for changes in status.
44 * Queue position.
45 """
47 status: StatusEnum
48 message: str = ""
49 error_detail: str | None = None
51 # Timestamp for when a status was last entered.
52 completed_time: datetime | None = None
53 queued_time: datetime | None = None
54 submitted_time: datetime | None = None
55 running_time: datetime | None = None
56 cancelled_time: datetime | None = None
57 error_time: datetime | None = None
59 queue_position: int | None = None
61 def to_dict(self) -> dict[str, Any]:
62 """Return JSON serializable dictionary representation."""
63 circuit_status_dict: dict[str, Any] = {
64 "status": self.status.name,
65 "message": self.message,
66 }
67 if self.error_detail is not None:
68 circuit_status_dict["error_detail"] = self.error_detail
70 if self.completed_time is not None:
71 circuit_status_dict["completed_time"] = self.completed_time.isoformat()
72 if self.queued_time is not None:
73 circuit_status_dict["queued_time"] = self.queued_time.isoformat()
74 if self.submitted_time is not None:
75 circuit_status_dict["submitted_time"] = self.submitted_time.isoformat()
76 if self.running_time is not None:
77 circuit_status_dict["running_time"] = self.running_time.isoformat()
78 if self.cancelled_time is not None:
79 circuit_status_dict["cancelled_time"] = self.cancelled_time.isoformat()
80 if self.error_time is not None:
81 circuit_status_dict["error_time"] = self.error_time.isoformat()
83 if self.queue_position is not None:
84 circuit_status_dict["queue_position"] = self.queue_position
86 return circuit_status_dict
88 @classmethod
89 def from_dict(cls, dic: dict[str, Any]) -> "CircuitStatus":
90 """Construct from JSON serializable dictionary."""
91 invalid = ValueError(f"Dictionary invalid format for CircuitStatus: {dic}")
92 if "message" not in dic or "status" not in dic: 92 ↛ 93line 92 didn't jump to line 93 because the condition on line 92 was never true
93 raise invalid
95 try:
96 status = next(s for s in StatusEnum if dic["status"] == s.name)
97 except StopIteration as e:
98 raise invalid from e
100 error_detail = dic.get("error_detail")
102 read_optional_datetime: Callable[[str], datetime | None] = lambda key: (
103 datetime.fromisoformat(x) if (x := dic.get(key)) is not None else None
104 )
105 completed_time = read_optional_datetime("completed_time")
106 queued_time = read_optional_datetime("queued_time")
107 submitted_time = read_optional_datetime("submitted_time")
108 running_time = read_optional_datetime("running_time")
109 cancelled_time = read_optional_datetime("cancelled_time")
110 error_time = read_optional_datetime("error_time")
112 queue_position = dic.get("queue_position")
114 return cls(
115 status,
116 dic["message"],
117 error_detail,
118 completed_time,
119 queued_time,
120 submitted_time,
121 running_time,
122 cancelled_time,
123 error_time,
124 queue_position,
125 )
128WAITING_STATUS = {StatusEnum.QUEUED, StatusEnum.SUBMITTED, StatusEnum.RUNNING}