quapp-common 0.0.11.dev1__tar.gz → 0.0.11.dev2__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.
- {quapp_common-0.0.11.dev1/quapp_common.egg-info → quapp_common-0.0.11.dev2}/PKG-INFO +20 -5
- quapp_common-0.0.11.dev2/README.md +22 -0
- {quapp_common-0.0.11.dev1 → quapp_common-0.0.11.dev2}/pyproject.toml +1 -1
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/async_tasks/export_circuit_task.py +11 -9
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/async_tasks/post_processing_task.py +2 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/component/backend/invocation.py +14 -14
- quapp_common-0.0.11.dev2/quapp_common/component/backend/job_fetcher.py +231 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/component/backend/job_fetching.py +9 -6
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/component/callback/update_job_metadata.py +1 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/component/device/device_selection.py +6 -4
- quapp_common-0.0.11.dev2/quapp_common/config/logging_config.py +34 -0
- quapp_common-0.0.11.dev2/quapp_common/data/request/invocation_request.py +78 -0
- quapp_common-0.0.11.dev2/quapp_common/data/request/job_fetching_request.py +27 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/model/device/custom_device.py +5 -3
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/model/provider/provider.py +5 -3
- {quapp_common-0.0.11.dev1 → quapp_common-0.0.11.dev2/quapp_common.egg-info}/PKG-INFO +20 -5
- quapp_common-0.0.11.dev2/quapp_common.egg-info/SOURCES.txt +76 -0
- quapp_common-0.0.11.dev2/quapp_common.egg-info/top_level.txt +1 -0
- quapp_common-0.0.11.dev1/README.md +0 -7
- quapp_common-0.0.11.dev1/qapp_common/config/logging_config.py +0 -8
- quapp_common-0.0.11.dev1/qapp_common/data/request/invocation_request.py +0 -24
- quapp_common-0.0.11.dev1/qapp_common/data/request/job_fetching_request.py +0 -11
- quapp_common-0.0.11.dev1/quapp_common.egg-info/SOURCES.txt +0 -75
- quapp_common-0.0.11.dev1/quapp_common.egg-info/top_level.txt +0 -1
- {quapp_common-0.0.11.dev1 → quapp_common-0.0.11.dev2}/LICENSE +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/__init__.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/async_tasks/__init__.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/async_tasks/async_task.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/component/__init__.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/component/backend/__init__.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/component/callback/__init__.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/component/device/__init__.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/config/__init__.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/config/thread_config.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/data/__init__.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/data/async_task/__init__.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/data/async_task/circuit_export/__init__.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/data/async_task/circuit_export/backend_holder.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/data/async_task/circuit_export/circuit_holder.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/data/backend/__init__.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/data/backend/backend_information.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/data/callback/__init__.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/data/callback/callback_url.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/data/device/__init__.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/data/device/circuit_running_option.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/data/promise/__init__.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/data/promise/post_processing_promise.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/data/promise/promise.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/data/request/__init__.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/data/request/request.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/data/response/__init__.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/data/response/authentication.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/data/response/job_response.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/data/response/project_header.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/enum/__init__.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/enum/base_enum.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/enum/http_header.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/enum/invocation_step.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/enum/media_type.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/enum/processing_unit.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/enum/provider_tag.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/enum/sdk.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/enum/status/__init__.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/enum/status/job_status.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/enum/status/status_code.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/enum/token_type.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/factory/__init__.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/factory/device_factory.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/factory/handler_factory.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/factory/provider_factory.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/handler/__init__.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/handler/handler.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/model/__init__.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/model/device/__init__.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/model/device/device.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/model/provider/__init__.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/util/__init__.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/util/file_utils.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/util/http_utils.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/util/json_parser_utils.py +0 -0
- {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev2/quapp_common}/util/response_utils.py +0 -0
- {quapp_common-0.0.11.dev1 → quapp_common-0.0.11.dev2}/quapp_common.egg-info/dependency_links.txt +0 -0
- {quapp_common-0.0.11.dev1 → quapp_common-0.0.11.dev2}/quapp_common.egg-info/requires.txt +0 -0
- {quapp_common-0.0.11.dev1 → quapp_common-0.0.11.dev2}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: quapp-common
|
|
3
|
-
Version: 0.0.11.
|
|
3
|
+
Version: 0.0.11.dev2
|
|
4
4
|
Summary: Quapp common library supporting Quapp Platform for Quantum Computing
|
|
5
5
|
Author-email: "CITYNOW Co. Ltd. " <corp@citynow.vn>
|
|
6
6
|
License: The MIT License (MIT)
|
|
@@ -32,10 +32,25 @@ Requires-Dist: pip-tools; extra == "dev"
|
|
|
32
32
|
Requires-Dist: pytest; extra == "dev"
|
|
33
33
|
Dynamic: license-file
|
|
34
34
|
|
|
35
|
-
#
|
|
35
|
+
# quapp-common
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
- Add pennylane in enum sdk
|
|
39
|
-
- Change function in `device.py` to protected to override in pennylane sdk
|
|
37
|
+
Quapp common library supporting Quapp Platform for Quantum Computing.
|
|
40
38
|
|
|
39
|
+
## Overview
|
|
41
40
|
|
|
41
|
+
`quapp-common` is a Python library designed to support the Quapp Platform for Quantum Computing by
|
|
42
|
+
providing common utilities, configurations, and abstractions for working with quantum providers and
|
|
43
|
+
devices.
|
|
44
|
+
|
|
45
|
+
## Features
|
|
46
|
+
|
|
47
|
+
- Provider and device factory for quantum computing platforms.
|
|
48
|
+
- Logging and configuration utilities.
|
|
49
|
+
- Support for AWS Braket, OQC Cloud, Qiskit, PennyLane, DWave Ocean and Quapp quantum simulators.
|
|
50
|
+
|
|
51
|
+
## Installation
|
|
52
|
+
|
|
53
|
+
Install via pip:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pip install quapp-common
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# quapp-common
|
|
2
|
+
|
|
3
|
+
Quapp common library supporting Quapp Platform for Quantum Computing.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
`quapp-common` is a Python library designed to support the Quapp Platform for Quantum Computing by
|
|
8
|
+
providing common utilities, configurations, and abstractions for working with quantum providers and
|
|
9
|
+
devices.
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- Provider and device factory for quantum computing platforms.
|
|
14
|
+
- Logging and configuration utilities.
|
|
15
|
+
- Support for AWS Braket, OQC Cloud, Qiskit, PennyLane, DWave Ocean and Quapp quantum simulators.
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
Install via pip:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pip install quapp-common
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "quapp-common"
|
|
7
|
-
version = "0.0.11.
|
|
7
|
+
version = "0.0.11.dev2"
|
|
8
8
|
description = "Quapp common library supporting Quapp Platform for Quantum Computing"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
authors = [{ name = "CITYNOW Co. Ltd. ", email = "corp@citynow.vn" }]
|
|
@@ -6,13 +6,15 @@ from io import BytesIO
|
|
|
6
6
|
import requests
|
|
7
7
|
|
|
8
8
|
from .async_task import AsyncTask
|
|
9
|
+
from ..config.logging_config import logger
|
|
9
10
|
from ..data.async_task.circuit_export.backend_holder import BackendDataHolder
|
|
10
11
|
from ..data.async_task.circuit_export.circuit_holder import CircuitDataHolder
|
|
11
|
-
from ..config.logging_config import logger
|
|
12
12
|
from ..enum.media_type import MediaType
|
|
13
13
|
from ..util.file_utils import FileUtils
|
|
14
14
|
from ..util.http_utils import HttpUtils
|
|
15
15
|
|
|
16
|
+
logger = logger.bind(context='CircuitExportTask')
|
|
17
|
+
|
|
16
18
|
|
|
17
19
|
class CircuitExportTask(AsyncTask):
|
|
18
20
|
MAX_CIRCUIT_IMAGE_SIZE = 5 * (1024 ** 2)
|
|
@@ -28,7 +30,7 @@ class CircuitExportTask(AsyncTask):
|
|
|
28
30
|
"""
|
|
29
31
|
Export circuit to svg file then send to QuaO server for saving
|
|
30
32
|
"""
|
|
31
|
-
logger.debug("
|
|
33
|
+
logger.debug("Start")
|
|
32
34
|
|
|
33
35
|
circuit_export_url = self.circuit_data_holder.export_url
|
|
34
36
|
|
|
@@ -47,11 +49,11 @@ class CircuitExportTask(AsyncTask):
|
|
|
47
49
|
|
|
48
50
|
@return:
|
|
49
51
|
"""
|
|
50
|
-
logger.debug("
|
|
52
|
+
logger.debug("Preparing circuit figure...")
|
|
51
53
|
transpiled_circuit = self._transpile_circuit()
|
|
52
54
|
circuit_figure = transpiled_circuit.draw(output='mpl', fold=-1)
|
|
53
55
|
|
|
54
|
-
logger.debug("
|
|
56
|
+
logger.debug("Converting circuit figure to svg file...")
|
|
55
57
|
figure_buffer = BytesIO()
|
|
56
58
|
circuit_figure.savefig(figure_buffer, format='svg', bbox_inches='tight')
|
|
57
59
|
|
|
@@ -67,11 +69,11 @@ class CircuitExportTask(AsyncTask):
|
|
|
67
69
|
buffer_value = figure_buffer.getvalue()
|
|
68
70
|
content_type = MediaType.SVG_XML
|
|
69
71
|
|
|
70
|
-
logger.debug("
|
|
72
|
+
logger.debug("Checking max file size")
|
|
71
73
|
estimated_file_size = len(buffer_value)
|
|
72
74
|
|
|
73
75
|
if estimated_file_size > CircuitExportTask.MAX_CIRCUIT_IMAGE_SIZE:
|
|
74
|
-
logger.debug("
|
|
76
|
+
logger.debug("Zip file")
|
|
75
77
|
zip_file_buffer = FileUtils.zip(io_buffer_value=buffer_value,
|
|
76
78
|
file_name="circuit_image.svg")
|
|
77
79
|
|
|
@@ -89,7 +91,7 @@ class CircuitExportTask(AsyncTask):
|
|
|
89
91
|
url = self.circuit_data_holder.export_url
|
|
90
92
|
|
|
91
93
|
logger.debug(
|
|
92
|
-
"
|
|
94
|
+
"Sending circuit svg image to [{0}] with POST method ...".format(
|
|
93
95
|
url))
|
|
94
96
|
|
|
95
97
|
payload = {'circuit': (
|
|
@@ -105,10 +107,10 @@ class CircuitExportTask(AsyncTask):
|
|
|
105
107
|
if response.ok:
|
|
106
108
|
logger.debug("Sending request to QuaO backend successfully!")
|
|
107
109
|
else:
|
|
108
|
-
logger.
|
|
110
|
+
logger.error("Sending request to QuaO backend failed with status {0}!".format(
|
|
109
111
|
response.status_code))
|
|
110
112
|
|
|
111
|
-
logger.debug("
|
|
113
|
+
logger.debug("Finish")
|
|
112
114
|
|
|
113
115
|
def _transpile_circuit(self):
|
|
114
116
|
"""
|
|
@@ -11,6 +11,8 @@ from ..enum.status.job_status import JobStatus
|
|
|
11
11
|
from ..enum.status.status_code import StatusCode
|
|
12
12
|
from ..util.json_parser_utils import JsonParserUtils
|
|
13
13
|
|
|
14
|
+
logger = logger.bind(context='PostProcessingTask')
|
|
15
|
+
|
|
14
16
|
|
|
15
17
|
class PostProcessingTask(AsyncTask):
|
|
16
18
|
def __init__(self,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
QApp Platform Project backend.py Copyright © CITYNOW Co. Ltd. All rights reserved.
|
|
3
3
|
"""
|
|
4
|
-
from abc import
|
|
4
|
+
from abc import ABC, abstractmethod
|
|
5
5
|
|
|
6
6
|
from ..callback.update_job_metadata import update_job_metadata
|
|
7
7
|
from ...component.device.device_selection import DeviceSelection
|
|
@@ -22,6 +22,8 @@ from ...model.provider.provider import Provider
|
|
|
22
22
|
|
|
23
23
|
EXPORT_CIRCUIT_SDK = {Sdk.QISKIT, Sdk.BRAKET}
|
|
24
24
|
|
|
25
|
+
logger = logger.bind(context='Invocation')
|
|
26
|
+
|
|
25
27
|
|
|
26
28
|
class Invocation(ABC):
|
|
27
29
|
def __init__(self, request_data: InvocationRequest):
|
|
@@ -54,7 +56,7 @@ class Invocation(ABC):
|
|
|
54
56
|
@param circuit_preparation_fn: Circuit-preparation function
|
|
55
57
|
@return: Job result
|
|
56
58
|
"""
|
|
57
|
-
logger.debug("
|
|
59
|
+
logger.debug("Invoke job")
|
|
58
60
|
|
|
59
61
|
circuit = self.__pre_execute(circuit_preparation_fn)
|
|
60
62
|
|
|
@@ -105,7 +107,7 @@ class Invocation(ABC):
|
|
|
105
107
|
@return: Job response
|
|
106
108
|
"""
|
|
107
109
|
|
|
108
|
-
logger.debug("
|
|
110
|
+
logger.debug("Execute job")
|
|
109
111
|
|
|
110
112
|
try:
|
|
111
113
|
if self.backend_information is None:
|
|
@@ -116,7 +118,7 @@ class Invocation(ABC):
|
|
|
116
118
|
backend_authentication = self.backend_information.authentication
|
|
117
119
|
|
|
118
120
|
logger.debug(
|
|
119
|
-
"
|
|
121
|
+
"Execute job with provider tag: {0}".format(
|
|
120
122
|
provider_tag.value
|
|
121
123
|
)
|
|
122
124
|
)
|
|
@@ -124,7 +126,7 @@ class Invocation(ABC):
|
|
|
124
126
|
provider = self._create_provider()
|
|
125
127
|
|
|
126
128
|
logger.debug(
|
|
127
|
-
"
|
|
129
|
+
"Execute job with device name: {0}".format(device_name)
|
|
128
130
|
)
|
|
129
131
|
device = self._create_device(provider)
|
|
130
132
|
|
|
@@ -159,7 +161,7 @@ class Invocation(ABC):
|
|
|
159
161
|
@param circuit_preparation_fn: Circuit preparation function
|
|
160
162
|
@return: circuit
|
|
161
163
|
"""
|
|
162
|
-
logger.debug("
|
|
164
|
+
logger.debug("Prepare circuit")
|
|
163
165
|
|
|
164
166
|
job_response = JobResponse(
|
|
165
167
|
status_code=StatusCode.DONE,
|
|
@@ -215,11 +217,9 @@ class Invocation(ABC):
|
|
|
215
217
|
)
|
|
216
218
|
|
|
217
219
|
self.backend_information = device_selection.select()
|
|
218
|
-
logger.
|
|
219
|
-
logger.info(self.backend_information.authentication)
|
|
220
|
+
logger.debug(f"Updating backend authentication")
|
|
220
221
|
self.backend_information.authentication = self.invoke_authentication
|
|
221
|
-
logger.
|
|
222
|
-
logger.info(self.backend_information.authentication)
|
|
222
|
+
logger.debug(f"Backend authentication updated")
|
|
223
223
|
|
|
224
224
|
@abstractmethod
|
|
225
225
|
def _export_circuit(self, circuit):
|
|
@@ -228,7 +228,7 @@ class Invocation(ABC):
|
|
|
228
228
|
@param circuit: Circuit was exported
|
|
229
229
|
"""
|
|
230
230
|
|
|
231
|
-
raise NotImplemented('
|
|
231
|
+
raise NotImplemented('_export_circuit() method must be implemented')
|
|
232
232
|
|
|
233
233
|
@abstractmethod
|
|
234
234
|
def _create_provider(self, ):
|
|
@@ -236,7 +236,7 @@ class Invocation(ABC):
|
|
|
236
236
|
Create provider with ProviderFactory
|
|
237
237
|
"""
|
|
238
238
|
|
|
239
|
-
raise NotImplemented('
|
|
239
|
+
raise NotImplemented('_create_provider() method must be implemented')
|
|
240
240
|
|
|
241
241
|
@abstractmethod
|
|
242
242
|
def _create_device(self, provider: Provider):
|
|
@@ -244,7 +244,7 @@ class Invocation(ABC):
|
|
|
244
244
|
Create device with DeviceFactory
|
|
245
245
|
"""
|
|
246
246
|
|
|
247
|
-
raise NotImplemented('
|
|
247
|
+
raise NotImplemented('_create_device() method must be implemented')
|
|
248
248
|
|
|
249
249
|
@abstractmethod
|
|
250
250
|
def _get_qubit_amount(self, circuit):
|
|
@@ -252,4 +252,4 @@ class Invocation(ABC):
|
|
|
252
252
|
Get number qubit of circuit
|
|
253
253
|
"""
|
|
254
254
|
|
|
255
|
-
raise NotImplemented('
|
|
255
|
+
raise NotImplemented('_get_qubit_amount() method must be implemented')
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
"""
|
|
2
|
+
QApp Platform Project job_fetching.py Copyright © CITYNOW Co. Ltd. All rights reserved.
|
|
3
|
+
"""
|
|
4
|
+
from abc import ABC, abstractmethod
|
|
5
|
+
from typing import Dict
|
|
6
|
+
|
|
7
|
+
from ..callback.update_job_metadata import update_job_metadata
|
|
8
|
+
from ...async_tasks.post_processing_task import PostProcessingTask
|
|
9
|
+
from ...config.logging_config import logger
|
|
10
|
+
from ...config.thread_config import circuit_running_pool
|
|
11
|
+
from ...data.callback.callback_url import CallbackUrl
|
|
12
|
+
from ...data.promise.post_processing_promise import PostProcessingPromise
|
|
13
|
+
from ...data.request.job_fetching_request import JobFetchingRequest
|
|
14
|
+
from ...data.response.authentication import Authentication
|
|
15
|
+
from ...data.response.job_response import JobResponse
|
|
16
|
+
from ...data.response.project_header import ProjectHeader
|
|
17
|
+
from ...enum.invocation_step import InvocationStep
|
|
18
|
+
from ...enum.media_type import MediaType
|
|
19
|
+
from ...enum.status.job_status import JobStatus
|
|
20
|
+
from ...enum.status.status_code import StatusCode
|
|
21
|
+
from ...util.json_parser_utils import JsonParserUtils
|
|
22
|
+
from ...util.response_utils import ResponseUtils
|
|
23
|
+
|
|
24
|
+
logger = logger.bind(context='JobFetcher')
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class JobFetcher(ABC):
|
|
28
|
+
"""
|
|
29
|
+
Abstract base class for fetching job results from different providers.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
def __init__(self, request_data: JobFetchingRequest):
|
|
33
|
+
"""Initializes the JobFetcher with request data."""
|
|
34
|
+
self.provider_authentication: Dict = request_data.provider_authentication
|
|
35
|
+
self.provider_job_id: str = request_data.provider_job_id
|
|
36
|
+
self.backend_authentication: Authentication = request_data.authentication
|
|
37
|
+
self.project_header: ProjectHeader = request_data.project_header
|
|
38
|
+
self.callback_urls: Dict[InvocationStep, CallbackUrl] = {
|
|
39
|
+
InvocationStep.EXECUTION: request_data.execution,
|
|
40
|
+
InvocationStep.ANALYSIS: request_data.analysis,
|
|
41
|
+
InvocationStep.FINALIZATION: request_data.finalization
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
logger.debug(f"[{self.provider_job_id}] Initialized JobFetcher")
|
|
45
|
+
|
|
46
|
+
@abstractmethod
|
|
47
|
+
def _collect_provider(self):
|
|
48
|
+
"""Abstract method to create and return the provider client."""
|
|
49
|
+
raise NotImplementedError('[JobFetcher] _collect_provider() method must be implemented')
|
|
50
|
+
|
|
51
|
+
@abstractmethod
|
|
52
|
+
def _retrieve_job(self, provider):
|
|
53
|
+
"""Abstract method to retrieve the job object from the provider."""
|
|
54
|
+
raise NotImplementedError('[JobFetcher] _retrieve_job() method must be implemented')
|
|
55
|
+
|
|
56
|
+
@abstractmethod
|
|
57
|
+
def _get_job_status(self, job):
|
|
58
|
+
"""Abstract method to extract the job status from the provider's job object."""
|
|
59
|
+
raise NotImplementedError('[JobFetcher] _get_job_status() method must be implemented')
|
|
60
|
+
|
|
61
|
+
@abstractmethod
|
|
62
|
+
def _get_job_result(self, job):
|
|
63
|
+
"""Abstract method to extract the raw job result from the provider's job object."""
|
|
64
|
+
raise NotImplementedError('[JobFetcher] _get_job_result() method must be implemented')
|
|
65
|
+
|
|
66
|
+
@abstractmethod
|
|
67
|
+
def _produce_histogram_data(self, job_result) -> dict | None:
|
|
68
|
+
"""Abstract method to produce histogram data from the raw job result."""
|
|
69
|
+
raise NotImplementedError(
|
|
70
|
+
'[JobFetcher] _produce_histogram_data() method must be implemented')
|
|
71
|
+
|
|
72
|
+
@abstractmethod
|
|
73
|
+
def _get_execution_time(self, job_result):
|
|
74
|
+
"""Abstract method to extract the execution time from the raw job result."""
|
|
75
|
+
raise NotImplementedError('[JobFetcher] _get_execution_time() method must be implemented')
|
|
76
|
+
|
|
77
|
+
@abstractmethod
|
|
78
|
+
def _get_shots(self, job_result):
|
|
79
|
+
"""Abstract method to extract the number of shots from the raw job result."""
|
|
80
|
+
raise NotImplementedError('[JobFetcher] _get_shots() method must be implemented')
|
|
81
|
+
|
|
82
|
+
def fetch(self, post_processing_fn):
|
|
83
|
+
"""Fetches the job, handles different job statuses, and initiates post-processing."""
|
|
84
|
+
logger.debug(f'[{self.provider_job_id}] Fetch job')
|
|
85
|
+
job_response = JobResponse(
|
|
86
|
+
provider_job_id=self.provider_job_id,
|
|
87
|
+
authentication=self.backend_authentication,
|
|
88
|
+
project_header=self.project_header,
|
|
89
|
+
status_code=StatusCode.DONE
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
try:
|
|
93
|
+
logger.debug(f'[{self.provider_job_id}] Collecting provider')
|
|
94
|
+
provider = self._collect_provider()
|
|
95
|
+
|
|
96
|
+
logger.debug(
|
|
97
|
+
f'[{self.provider_job_id}] Retrieving job from provider')
|
|
98
|
+
job = self._retrieve_job(provider)
|
|
99
|
+
|
|
100
|
+
logger.debug(f'[{self.provider_job_id}] Getting job status')
|
|
101
|
+
job_status = self._get_job_status(job)
|
|
102
|
+
|
|
103
|
+
logger.debug(
|
|
104
|
+
f'[{self.provider_job_id}] Getting original job result')
|
|
105
|
+
original_job_result = self._get_job_result(job)
|
|
106
|
+
|
|
107
|
+
logger.info(f'[{self.provider_job_id}] Job status: {job_status}')
|
|
108
|
+
job_response.job_status = job_status
|
|
109
|
+
|
|
110
|
+
if job_status == JobStatus.DONE.value:
|
|
111
|
+
self._handle_successful_job(original_job_result, job_response, post_processing_fn)
|
|
112
|
+
update_job_metadata(job_response=job_response, callback_url=self.callback_urls[
|
|
113
|
+
InvocationStep.EXECUTION].on_done)
|
|
114
|
+
elif job_status == JobStatus.ERROR.value:
|
|
115
|
+
self._handle_failed_job(original_job_result, job_response)
|
|
116
|
+
update_job_metadata(job_response=job_response, callback_url=self.callback_urls[
|
|
117
|
+
InvocationStep.EXECUTION].on_error)
|
|
118
|
+
else:
|
|
119
|
+
logger.info(
|
|
120
|
+
f'[{self.provider_job_id}] Job is in {job_status}, setting status to POLLING')
|
|
121
|
+
job_response.status_code = StatusCode.POLLING
|
|
122
|
+
|
|
123
|
+
except Exception as e:
|
|
124
|
+
self._handle_fetch_exception(job_response, e)
|
|
125
|
+
update_job_metadata(job_response=job_response,
|
|
126
|
+
callback_url=self.callback_urls[InvocationStep.EXECUTION].on_error)
|
|
127
|
+
|
|
128
|
+
logger.debug(f'[{self.provider_job_id}] Returning response')
|
|
129
|
+
return ResponseUtils.generate_response(job_response)
|
|
130
|
+
|
|
131
|
+
def _handle_successful_job(self, original_job_result, job_response: JobResponse,
|
|
132
|
+
post_processing_fn):
|
|
133
|
+
"""Handles the job result when the job is successfully completed."""
|
|
134
|
+
logger.debug(
|
|
135
|
+
f'[{self.provider_job_id}] Handling successful job')
|
|
136
|
+
circuit_running_pool.submit(
|
|
137
|
+
self._process_job_result,
|
|
138
|
+
original_job_result,
|
|
139
|
+
job_response,
|
|
140
|
+
self.callback_urls,
|
|
141
|
+
post_processing_fn
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
def _handle_failed_job(self, original_job_result, job_response: JobResponse):
|
|
145
|
+
"""Handles the job result when the job has encountered an error."""
|
|
146
|
+
logger.error(f'[{self.provider_job_id}] Handling failed job')
|
|
147
|
+
job_response.job_result = JsonParserUtils.parse(original_job_result)
|
|
148
|
+
|
|
149
|
+
def _handle_fetch_exception(self, job_response: JobResponse, exception: Exception):
|
|
150
|
+
"""Handles exceptions that occur during the job fetching process."""
|
|
151
|
+
logger.error(
|
|
152
|
+
f'[{self.provider_job_id}] Exception when fetching job: {exception}')
|
|
153
|
+
job_response.job_result = {
|
|
154
|
+
'error': f'Exception when fetching job: {exception}',
|
|
155
|
+
'exception': str(exception),
|
|
156
|
+
}
|
|
157
|
+
job_response.status_code = StatusCode.ERROR
|
|
158
|
+
job_response.job_status = JobStatus.ERROR.value
|
|
159
|
+
|
|
160
|
+
def _process_job_result(self, original_job_result, job_response: JobResponse,
|
|
161
|
+
callback_urls: Dict[InvocationStep, CallbackUrl], post_processing_fn):
|
|
162
|
+
"""Processes the job result through analysis and finalization steps."""
|
|
163
|
+
logger.debug(
|
|
164
|
+
f'[{self.provider_job_id}] Processing job result')
|
|
165
|
+
|
|
166
|
+
job_response = self._on_analysis(
|
|
167
|
+
callback_url=callback_urls[InvocationStep.ANALYSIS],
|
|
168
|
+
job_response=job_response,
|
|
169
|
+
original_job_result=original_job_result
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
if job_response:
|
|
173
|
+
self._on_finalization(
|
|
174
|
+
post_processing_fn=post_processing_fn,
|
|
175
|
+
callback_url=callback_urls[InvocationStep.FINALIZATION],
|
|
176
|
+
original_job_result=original_job_result
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
def _on_analysis(self, callback_url: CallbackUrl, job_response: JobResponse,
|
|
180
|
+
original_job_result) -> JobResponse | None:
|
|
181
|
+
"""Handles the analysis step of the job result."""
|
|
182
|
+
logger.debug(f'[{self.provider_job_id}] On analysis')
|
|
183
|
+
update_job_metadata(job_response=job_response, callback_url=callback_url.on_start)
|
|
184
|
+
logger.debug(
|
|
185
|
+
f'[{self.provider_job_id}] Calling update_job_metadata on_start')
|
|
186
|
+
|
|
187
|
+
try:
|
|
188
|
+
job_response.content_type = MediaType.APPLICATION_JSON
|
|
189
|
+
|
|
190
|
+
logger.debug(f'[{self.provider_job_id}] Producing histogram data')
|
|
191
|
+
job_response.job_histogram = self._produce_histogram_data(original_job_result)
|
|
192
|
+
|
|
193
|
+
logger.debug(f'[{self.provider_job_id}] Getting execution time')
|
|
194
|
+
job_response.execution_time = self._get_execution_time(original_job_result)
|
|
195
|
+
|
|
196
|
+
logger.debug(f'[{self.provider_job_id}] Getting shots')
|
|
197
|
+
job_response.shots = self._get_shots(original_job_result)
|
|
198
|
+
|
|
199
|
+
update_job_metadata(job_response=job_response, callback_url=callback_url.on_done)
|
|
200
|
+
logger.debug(
|
|
201
|
+
f'[{self.provider_job_id}] Calling update_job_metadata on_done')
|
|
202
|
+
|
|
203
|
+
return job_response
|
|
204
|
+
|
|
205
|
+
except Exception as e:
|
|
206
|
+
logger.error(
|
|
207
|
+
f'[{self.provider_job_id}] Exception during analysis: {e}')
|
|
208
|
+
job_response.status_code = StatusCode.ERROR
|
|
209
|
+
job_response.job_status = JobStatus.ERROR.value
|
|
210
|
+
job_response.job_result = {
|
|
211
|
+
"error": f'Exception during analysis: {e}',
|
|
212
|
+
"exception": str(e),
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
update_job_metadata(job_response=job_response, callback_url=callback_url.on_error)
|
|
216
|
+
logger.debug(
|
|
217
|
+
f'[{self.provider_job_id}] Calling update_job_metadata on_error')
|
|
218
|
+
return None
|
|
219
|
+
|
|
220
|
+
def _on_finalization(self, post_processing_fn, callback_url: CallbackUrl, original_job_result):
|
|
221
|
+
"""Handles the finalization step of the job result."""
|
|
222
|
+
logger.debug(f'[{self.provider_job_id}] On finalization')
|
|
223
|
+
promise = PostProcessingPromise(
|
|
224
|
+
callback_url=callback_url,
|
|
225
|
+
authentication=self.backend_authentication,
|
|
226
|
+
job_result=original_job_result,
|
|
227
|
+
project_header=self.project_header
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
logger.debug(f'[{self.provider_job_id}]Creating PostProcessingTask')
|
|
231
|
+
PostProcessingTask(post_processing_fn=post_processing_fn, promise=promise).do()
|
|
@@ -6,6 +6,7 @@ from typing import Any
|
|
|
6
6
|
|
|
7
7
|
from ..callback.update_job_metadata import update_job_metadata
|
|
8
8
|
from ...async_tasks.post_processing_task import PostProcessingTask
|
|
9
|
+
from ...config.logging_config import logger
|
|
9
10
|
from ...config.thread_config import circuit_running_pool
|
|
10
11
|
from ...data.callback.callback_url import CallbackUrl
|
|
11
12
|
from ...data.promise.post_processing_promise import PostProcessingPromise
|
|
@@ -14,13 +15,14 @@ from ...data.response.authentication import Authentication
|
|
|
14
15
|
from ...data.response.job_response import JobResponse
|
|
15
16
|
from ...data.response.project_header import ProjectHeader
|
|
16
17
|
from ...enum.invocation_step import InvocationStep
|
|
17
|
-
from ...config.logging_config import logger
|
|
18
18
|
from ...enum.media_type import MediaType
|
|
19
19
|
from ...enum.status.job_status import JobStatus
|
|
20
20
|
from ...enum.status.status_code import StatusCode
|
|
21
21
|
from ...util.json_parser_utils import JsonParserUtils
|
|
22
22
|
from ...util.response_utils import ResponseUtils
|
|
23
23
|
|
|
24
|
+
logger = logger.bind(context='JobFetching')
|
|
25
|
+
|
|
24
26
|
|
|
25
27
|
class JobFetching(ABC):
|
|
26
28
|
def __init__(self, request_data: JobFetchingRequest):
|
|
@@ -40,7 +42,7 @@ class JobFetching(ABC):
|
|
|
40
42
|
@param post_processing_fn:
|
|
41
43
|
@return:
|
|
42
44
|
"""
|
|
43
|
-
logger.debug("
|
|
45
|
+
logger.debug("Fetch job")
|
|
44
46
|
|
|
45
47
|
job_response = JobResponse(
|
|
46
48
|
provider_job_id=self.provider_job_id,
|
|
@@ -130,7 +132,7 @@ class JobFetching(ABC):
|
|
|
130
132
|
@param original_job_result:
|
|
131
133
|
@return:
|
|
132
134
|
"""
|
|
133
|
-
logger.debug("
|
|
135
|
+
logger.debug("On analysis")
|
|
134
136
|
|
|
135
137
|
update_job_metadata(job_response=job_response,
|
|
136
138
|
callback_url=callback_url.on_start)
|
|
@@ -141,7 +143,7 @@ class JobFetching(ABC):
|
|
|
141
143
|
job_response.job_histogram = self.__produce_histogram_data(original_job_result)
|
|
142
144
|
|
|
143
145
|
job_result_parse = JsonParserUtils.parse(original_job_result.result())
|
|
144
|
-
|
|
146
|
+
|
|
145
147
|
job_response.execution_time = self.__get_execution_time(original_job_result)
|
|
146
148
|
|
|
147
149
|
update_job_metadata(
|
|
@@ -178,7 +180,7 @@ class JobFetching(ABC):
|
|
|
178
180
|
@param callback_url:
|
|
179
181
|
@param original_job_result:
|
|
180
182
|
"""
|
|
181
|
-
logger.debug("
|
|
183
|
+
logger.debug("On finalization")
|
|
182
184
|
|
|
183
185
|
promise = PostProcessingPromise(callback_url=callback_url,
|
|
184
186
|
authentication=self.backend_authentication,
|
|
@@ -195,7 +197,7 @@ class JobFetching(ABC):
|
|
|
195
197
|
@param job_result:
|
|
196
198
|
@return:
|
|
197
199
|
"""
|
|
198
|
-
logger.debug("
|
|
200
|
+
logger.debug("Produce histogram")
|
|
199
201
|
|
|
200
202
|
try:
|
|
201
203
|
histogram_data = job_result.result()[0].data.meas.get_counts()
|
|
@@ -214,6 +216,7 @@ class JobFetching(ABC):
|
|
|
214
216
|
@return:
|
|
215
217
|
"""
|
|
216
218
|
return job_result.usage()
|
|
219
|
+
|
|
217
220
|
@abstractmethod
|
|
218
221
|
def _collect_provider(self, ):
|
|
219
222
|
"""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
# Quapp Platform Project
|
|
2
|
+
# device_selection.py
|
|
3
|
+
# Copyright © CITYNOW Co. Ltd. All rights reserved.
|
|
4
4
|
|
|
5
5
|
from json import JSONDecodeError
|
|
6
6
|
|
|
@@ -11,6 +11,8 @@ from ...data.backend.backend_information import BackendInformation
|
|
|
11
11
|
from ...enum.provider_tag import ProviderTag
|
|
12
12
|
from ...util.http_utils import HttpUtils
|
|
13
13
|
|
|
14
|
+
logger = logger.bind(context='DeviceSelection')
|
|
15
|
+
|
|
14
16
|
|
|
15
17
|
class DeviceSelection:
|
|
16
18
|
def __init__(self,
|
|
@@ -66,7 +68,7 @@ class DeviceSelection:
|
|
|
66
68
|
logger.error('Select device fail with status code: {0} and content: {1}'.format(
|
|
67
69
|
response.status_code, response.content))
|
|
68
70
|
|
|
69
|
-
|
|
71
|
+
raise ValueError(f"Select device failed: {response.content}")
|
|
70
72
|
|
|
71
73
|
try:
|
|
72
74
|
response_dict = response.json().get("data")
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""
|
|
2
|
+
QApp Platform Project logging_config.py Copyright © CITYNOW Co. Ltd. All rights reserved.
|
|
3
|
+
"""
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
from loguru import logger
|
|
7
|
+
|
|
8
|
+
# Define colors for each log level
|
|
9
|
+
level_colors = {
|
|
10
|
+
"DEBUG": "blue",
|
|
11
|
+
"INFO": "white",
|
|
12
|
+
"WARNING": "yellow",
|
|
13
|
+
"ERROR": "red",
|
|
14
|
+
"CRITICAL": "bold red"
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def __custom_format(record):
|
|
19
|
+
# Safely get context, default to "QuappLibs" if missing
|
|
20
|
+
context = record["extra"].get("context", "QuappLibs")
|
|
21
|
+
|
|
22
|
+
# Get the color for the current level, default to white if level is unknown
|
|
23
|
+
level_color = level_colors.get(record["level"].name, "white")
|
|
24
|
+
return (
|
|
25
|
+
f"<{level_color}>{{level}}</{level_color}> : <green>{{time: %Y-%m-%d %H:%M:%S}}</green> : <yellow>[{context}]</yellow> <{level_color}>{{message}}</{level_color}> : <magenta>{{process}}</magenta>\n"
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
logger.add(
|
|
30
|
+
sink=sys.stderr,
|
|
31
|
+
format=__custom_format, # Use custom format function
|
|
32
|
+
level="DEBUG",
|
|
33
|
+
colorize=True # Enable colors (supported by sys.stderr)
|
|
34
|
+
)
|