quapp-common 0.0.11.dev1__tar.gz → 0.0.11.dev3__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.
Files changed (84) hide show
  1. {quapp_common-0.0.11.dev1/quapp_common.egg-info → quapp_common-0.0.11.dev3}/PKG-INFO +20 -5
  2. quapp_common-0.0.11.dev3/README.md +22 -0
  3. {quapp_common-0.0.11.dev1 → quapp_common-0.0.11.dev3}/pyproject.toml +1 -1
  4. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/async_tasks/export_circuit_task.py +11 -9
  5. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/async_tasks/post_processing_task.py +2 -0
  6. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/component/backend/invocation.py +14 -14
  7. quapp_common-0.0.11.dev3/quapp_common/component/backend/job_fetcher.py +231 -0
  8. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/component/backend/job_fetching.py +9 -6
  9. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/component/callback/update_job_metadata.py +1 -0
  10. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/component/device/device_selection.py +6 -4
  11. quapp_common-0.0.11.dev3/quapp_common/config/logging_config.py +34 -0
  12. quapp_common-0.0.11.dev3/quapp_common/data/request/invocation_request.py +78 -0
  13. quapp_common-0.0.11.dev3/quapp_common/data/request/job_fetching_request.py +27 -0
  14. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/enum/provider_tag.py +1 -0
  15. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/enum/sdk.py +1 -0
  16. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/model/device/custom_device.py +5 -3
  17. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/model/provider/provider.py +5 -3
  18. {quapp_common-0.0.11.dev1 → quapp_common-0.0.11.dev3/quapp_common.egg-info}/PKG-INFO +20 -5
  19. quapp_common-0.0.11.dev3/quapp_common.egg-info/SOURCES.txt +76 -0
  20. quapp_common-0.0.11.dev3/quapp_common.egg-info/top_level.txt +1 -0
  21. quapp_common-0.0.11.dev1/README.md +0 -7
  22. quapp_common-0.0.11.dev1/qapp_common/config/logging_config.py +0 -8
  23. quapp_common-0.0.11.dev1/qapp_common/data/request/invocation_request.py +0 -24
  24. quapp_common-0.0.11.dev1/qapp_common/data/request/job_fetching_request.py +0 -11
  25. quapp_common-0.0.11.dev1/quapp_common.egg-info/SOURCES.txt +0 -75
  26. quapp_common-0.0.11.dev1/quapp_common.egg-info/top_level.txt +0 -1
  27. {quapp_common-0.0.11.dev1 → quapp_common-0.0.11.dev3}/LICENSE +0 -0
  28. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/__init__.py +0 -0
  29. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/async_tasks/__init__.py +0 -0
  30. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/async_tasks/async_task.py +0 -0
  31. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/component/__init__.py +0 -0
  32. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/component/backend/__init__.py +0 -0
  33. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/component/callback/__init__.py +0 -0
  34. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/component/device/__init__.py +0 -0
  35. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/config/__init__.py +0 -0
  36. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/config/thread_config.py +0 -0
  37. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/data/__init__.py +0 -0
  38. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/data/async_task/__init__.py +0 -0
  39. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/data/async_task/circuit_export/__init__.py +0 -0
  40. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/data/async_task/circuit_export/backend_holder.py +0 -0
  41. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/data/async_task/circuit_export/circuit_holder.py +0 -0
  42. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/data/backend/__init__.py +0 -0
  43. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/data/backend/backend_information.py +0 -0
  44. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/data/callback/__init__.py +0 -0
  45. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/data/callback/callback_url.py +0 -0
  46. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/data/device/__init__.py +0 -0
  47. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/data/device/circuit_running_option.py +0 -0
  48. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/data/promise/__init__.py +0 -0
  49. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/data/promise/post_processing_promise.py +0 -0
  50. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/data/promise/promise.py +0 -0
  51. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/data/request/__init__.py +0 -0
  52. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/data/request/request.py +0 -0
  53. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/data/response/__init__.py +0 -0
  54. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/data/response/authentication.py +0 -0
  55. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/data/response/job_response.py +0 -0
  56. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/data/response/project_header.py +0 -0
  57. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/enum/__init__.py +0 -0
  58. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/enum/base_enum.py +0 -0
  59. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/enum/http_header.py +0 -0
  60. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/enum/invocation_step.py +0 -0
  61. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/enum/media_type.py +0 -0
  62. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/enum/processing_unit.py +0 -0
  63. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/enum/status/__init__.py +0 -0
  64. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/enum/status/job_status.py +0 -0
  65. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/enum/status/status_code.py +0 -0
  66. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/enum/token_type.py +0 -0
  67. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/factory/__init__.py +0 -0
  68. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/factory/device_factory.py +0 -0
  69. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/factory/handler_factory.py +0 -0
  70. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/factory/provider_factory.py +0 -0
  71. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/handler/__init__.py +0 -0
  72. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/handler/handler.py +0 -0
  73. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/model/__init__.py +0 -0
  74. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/model/device/__init__.py +0 -0
  75. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/model/device/device.py +0 -0
  76. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/model/provider/__init__.py +0 -0
  77. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/util/__init__.py +0 -0
  78. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/util/file_utils.py +0 -0
  79. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/util/http_utils.py +0 -0
  80. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/util/json_parser_utils.py +0 -0
  81. {quapp_common-0.0.11.dev1/qapp_common → quapp_common-0.0.11.dev3/quapp_common}/util/response_utils.py +0 -0
  82. {quapp_common-0.0.11.dev1 → quapp_common-0.0.11.dev3}/quapp_common.egg-info/dependency_links.txt +0 -0
  83. {quapp_common-0.0.11.dev1 → quapp_common-0.0.11.dev3}/quapp_common.egg-info/requires.txt +0 -0
  84. {quapp_common-0.0.11.dev1 → quapp_common-0.0.11.dev3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: quapp-common
3
- Version: 0.0.11.dev1
3
+ Version: 0.0.11.dev3
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
- # qapp-common
35
+ # quapp-common
36
36
 
37
- # changes
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.dev1"
7
+ version = "0.0.11.dev3"
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("[Circuit export] Start")
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("[Circuit export] Preparing circuit figure...")
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("[Circuit export] Converting circuit figure to svg file...")
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("[Circuit export] Checking max file size")
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("[Circuit export] Zip file")
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
- "[Circuit export] Sending circuit svg image to [{0}] with POST method ...".format(
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.debug("Sending request to QuaO backend failed with status {0}!".format(
110
+ logger.error("Sending request to QuaO backend failed with status {0}!".format(
109
111
  response.status_code))
110
112
 
111
- logger.debug("[Circuit export] Finish")
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 abstractmethod, ABC
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("[Invocation] Invoke job")
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("[Invocation] Execute job")
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
- "[Invocation] Execute job with provider tag: {0}".format(
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
- "[Invocation] Execute job with device name: {0}".format(device_name)
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("[Invocation] Prepare circuit")
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.info("before")
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.info("after")
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('[Invocation] _export_circuit() method must be implemented')
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('[Invocation] _create_provider() method must be implemented')
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('[Invocation] _create_device() method must be implemented')
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('[Invocation] _get_qubit_amount() method must be implemented')
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("[Fetching] Fetch job")
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("[Fetching] On analysis")
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("[Fetching] On finalization")
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("[Fetching] Produce histogram")
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
  """
@@ -9,6 +9,7 @@ from ...util.http_utils import HttpUtils
9
9
  from ...util.response_utils import ResponseUtils
10
10
  from ...config.logging_config import logger
11
11
 
12
+ logger = logger.bind(context='UpdateJobMetadata')
12
13
 
13
14
  def update_job_metadata(
14
15
  job_response: JobResponse,
@@ -1,6 +1,6 @@
1
- """
2
- QApp Platform Project device_selection.py Copyright © CITYNOW Co. Ltd. All rights reserved.
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
- return None
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
+ )