quapp-common 0.0.11.dev4__tar.gz → 0.0.11.dev6__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.dev4/quapp_common.egg-info → quapp_common-0.0.11.dev6}/PKG-INFO +1 -1
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/pyproject.toml +1 -1
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/async_tasks/export_circuit_task.py +21 -15
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/component/backend/invocation.py +10 -9
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/component/backend/job_fetcher.py +4 -4
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/component/backend/job_fetching.py +2 -2
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/component/callback/update_job_metadata.py +1 -1
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/component/device/device_selection.py +1 -1
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/config/logging_config.py +6 -4
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/data/request/invocation_request.py +2 -2
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/data/request/job_fetching_request.py +2 -2
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/data/response/job_response.py +2 -2
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/model/device/custom_device.py +1 -1
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/model/device/device.py +1 -1
- quapp_common-0.0.11.dev6/quapp_common/util/http_utils.py +141 -0
- quapp_common-0.0.11.dev6/quapp_common/util/response_utils.py +200 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6/quapp_common.egg-info}/PKG-INFO +1 -1
- quapp_common-0.0.11.dev4/quapp_common/util/http_utils.py +0 -93
- quapp_common-0.0.11.dev4/quapp_common/util/response_utils.py +0 -97
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/LICENSE +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/README.md +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/__init__.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/async_tasks/__init__.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/async_tasks/async_task.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/async_tasks/post_processing_task.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/component/__init__.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/component/backend/__init__.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/component/callback/__init__.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/component/device/__init__.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/config/__init__.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/config/thread_config.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/data/__init__.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/data/async_task/__init__.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/data/async_task/circuit_export/__init__.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/data/async_task/circuit_export/backend_holder.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/data/async_task/circuit_export/circuit_holder.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/data/backend/__init__.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/data/backend/backend_information.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/data/callback/__init__.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/data/callback/callback_url.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/data/device/__init__.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/data/device/circuit_running_option.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/data/promise/__init__.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/data/promise/post_processing_promise.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/data/promise/promise.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/data/request/__init__.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/data/request/request.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/data/response/__init__.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/data/response/authentication.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/data/response/custom_header.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/enum/__init__.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/enum/base_enum.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/enum/http_header.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/enum/invocation_step.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/enum/media_type.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/enum/processing_unit.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/enum/provider_tag.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/enum/sdk.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/enum/status/__init__.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/enum/status/job_status.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/enum/status/status_code.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/enum/token_type.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/factory/__init__.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/factory/device_factory.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/factory/handler_factory.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/factory/provider_factory.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/handler/__init__.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/handler/handler.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/model/__init__.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/model/device/__init__.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/model/provider/__init__.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/model/provider/provider.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/util/__init__.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/util/file_utils.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/util/json_parser_utils.py +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common.egg-info/SOURCES.txt +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common.egg-info/dependency_links.txt +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common.egg-info/requires.txt +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common.egg-info/top_level.txt +0 -0
- {quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/setup.cfg +0 -0
|
@@ -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.dev6"
|
|
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" }]
|
|
@@ -11,6 +11,7 @@ from .async_task import AsyncTask
|
|
|
11
11
|
from ..config.logging_config import job_logger
|
|
12
12
|
from ..data.async_task.circuit_export.backend_holder import BackendDataHolder
|
|
13
13
|
from ..data.async_task.circuit_export.circuit_holder import CircuitDataHolder
|
|
14
|
+
from ..data.response.custom_header import CustomHeader
|
|
14
15
|
from ..enum.media_type import MediaType
|
|
15
16
|
from ..util.file_utils import FileUtils
|
|
16
17
|
from ..util.http_utils import create_bearer_header, get_job_id_from_url
|
|
@@ -20,8 +21,11 @@ class CircuitExportTask(AsyncTask):
|
|
|
20
21
|
MAX_CIRCUIT_IMAGE_SIZE = 5 * (1024 ** 2)
|
|
21
22
|
|
|
22
23
|
def __init__(self, circuit_data_holder: CircuitDataHolder,
|
|
23
|
-
backend_data_holder: BackendDataHolder
|
|
24
|
+
backend_data_holder: BackendDataHolder,
|
|
25
|
+
project_header: CustomHeader, workspace_header: CustomHeader):
|
|
24
26
|
super().__init__()
|
|
27
|
+
self.project_header = project_header
|
|
28
|
+
self.workspace_header = workspace_header
|
|
25
29
|
self.circuit_data_holder = circuit_data_holder
|
|
26
30
|
self.backend_data_holder = backend_data_holder
|
|
27
31
|
self.logger = job_logger(
|
|
@@ -43,8 +47,8 @@ class CircuitExportTask(AsyncTask):
|
|
|
43
47
|
self.logger.debug('Converting circuit to SVG')
|
|
44
48
|
figure_buffer = self.__convert()
|
|
45
49
|
except Exception as e:
|
|
46
|
-
self.logger.
|
|
47
|
-
|
|
50
|
+
self.logger.exception(f"Error converting circuit to SVG: {e}",
|
|
51
|
+
exc_info=True)
|
|
48
52
|
return
|
|
49
53
|
|
|
50
54
|
try:
|
|
@@ -54,7 +58,7 @@ class CircuitExportTask(AsyncTask):
|
|
|
54
58
|
self.logger.debug(f"Content type: {content_type}")
|
|
55
59
|
self.logger.debug(f"Buffer size: {len(io_buffer_value)} bytes")
|
|
56
60
|
except Exception as e:
|
|
57
|
-
self.logger.
|
|
61
|
+
self.logger.exception(
|
|
58
62
|
f"Error determining if circuit SVG should be zipped: {e}",
|
|
59
63
|
exc_info=True)
|
|
60
64
|
return
|
|
@@ -64,11 +68,12 @@ class CircuitExportTask(AsyncTask):
|
|
|
64
68
|
self.__send(io_buffer_value=io_buffer_value,
|
|
65
69
|
content_type=content_type)
|
|
66
70
|
self.logger.debug("Circuit sent to backend successfully.")
|
|
71
|
+
return
|
|
67
72
|
except Exception as e:
|
|
68
|
-
self.logger.
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
73
|
+
self.logger.exception(
|
|
74
|
+
f"Error sending exported circuit to backend: {e}",
|
|
75
|
+
exc_info=True)
|
|
76
|
+
return
|
|
72
77
|
|
|
73
78
|
def __convert(self):
|
|
74
79
|
"""
|
|
@@ -81,8 +86,8 @@ class CircuitExportTask(AsyncTask):
|
|
|
81
86
|
try:
|
|
82
87
|
circuit_figure = transpiled_circuit.draw(output='mpl', fold=-1)
|
|
83
88
|
except Exception as exception:
|
|
84
|
-
self.logger.
|
|
85
|
-
|
|
89
|
+
self.logger.exception(f"Error drawing circuit: {exception}",
|
|
90
|
+
exc_info=True)
|
|
86
91
|
raise exception
|
|
87
92
|
|
|
88
93
|
self.logger.debug("Converting circuit figure to SVG file...")
|
|
@@ -93,7 +98,7 @@ class CircuitExportTask(AsyncTask):
|
|
|
93
98
|
self.logger.debug(
|
|
94
99
|
f"SVG export complete. Size: {figure_buffer.getbuffer().nbytes} bytes")
|
|
95
100
|
except Exception as exception:
|
|
96
|
-
self.logger.
|
|
101
|
+
self.logger.exception(
|
|
97
102
|
f"Error saving circuit figure to SVG: {exception}",
|
|
98
103
|
exc_info=True)
|
|
99
104
|
raise exception
|
|
@@ -135,16 +140,17 @@ class CircuitExportTask(AsyncTask):
|
|
|
135
140
|
|
|
136
141
|
try:
|
|
137
142
|
response = requests.post(url=url, headers=create_bearer_header(
|
|
138
|
-
self.backend_data_holder.user_token
|
|
143
|
+
self.backend_data_holder.user_token, self.project_header,
|
|
144
|
+
self.workspace_header), files=payload)
|
|
139
145
|
except Exception as exception:
|
|
140
|
-
self.logger.
|
|
141
|
-
|
|
146
|
+
self.logger.exception(f"HTTP request failed: {exception}",
|
|
147
|
+
exc_info=True)
|
|
142
148
|
raise
|
|
143
149
|
|
|
144
150
|
if response.ok:
|
|
145
151
|
self.logger.info("Request sent to QuaO backend successfully.")
|
|
146
152
|
else:
|
|
147
|
-
self.logger.
|
|
153
|
+
self.logger.exception(
|
|
148
154
|
f"Sending request to QuaO backend failed with status {response.status_code}! Response: {response.content}")
|
|
149
155
|
|
|
150
156
|
self.logger.debug("HTTP request complete.")
|
{quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/component/backend/invocation.py
RENAMED
|
@@ -77,9 +77,9 @@ class Invocation(ABC):
|
|
|
77
77
|
circuit = self.__prepare_circuit(circuit_preparation_fn)
|
|
78
78
|
|
|
79
79
|
if circuit is None:
|
|
80
|
-
self.logger.
|
|
80
|
+
self.logger.exception(
|
|
81
81
|
"Circuit preparation failed, returning None from pre-execute")
|
|
82
|
-
|
|
82
|
+
raise ValueError("Circuit preparation failed")
|
|
83
83
|
|
|
84
84
|
try:
|
|
85
85
|
self.logger.debug("Preparing backend data")
|
|
@@ -88,12 +88,13 @@ class Invocation(ABC):
|
|
|
88
88
|
f"Backend data prepared: device {self.backend_information.device_name}, provider {self.backend_information.provider_tag.value}")
|
|
89
89
|
|
|
90
90
|
except Exception as exception:
|
|
91
|
-
self.logger.
|
|
92
|
-
|
|
91
|
+
self.logger.exception(
|
|
92
|
+
f"Error when prepare backend data: {exception}",
|
|
93
|
+
exc_info=True)
|
|
93
94
|
|
|
94
95
|
job_response = build_error_job_response(exception,
|
|
95
96
|
message='Error when prepare backend data')
|
|
96
|
-
|
|
97
|
+
job_response.authentication = self.authentication
|
|
97
98
|
update_job_metadata(job_response, self.callback_dict.get(
|
|
98
99
|
InvocationStep.PREPARATION).on_error)
|
|
99
100
|
|
|
@@ -113,7 +114,7 @@ class Invocation(ABC):
|
|
|
113
114
|
|
|
114
115
|
try:
|
|
115
116
|
if self.backend_information is None:
|
|
116
|
-
self.logger.
|
|
117
|
+
self.logger.exception(
|
|
117
118
|
"Backend information is None before execution")
|
|
118
119
|
raise ValueError("Backend is not found")
|
|
119
120
|
|
|
@@ -129,7 +130,7 @@ class Invocation(ABC):
|
|
|
129
130
|
device = self._create_device(provider)
|
|
130
131
|
|
|
131
132
|
except Exception as exception:
|
|
132
|
-
self.logger.
|
|
133
|
+
self.logger.exception(
|
|
133
134
|
f"Exception when create provider or device: {exception}",
|
|
134
135
|
exc_info=True)
|
|
135
136
|
|
|
@@ -182,8 +183,8 @@ class Invocation(ABC):
|
|
|
182
183
|
return circuit
|
|
183
184
|
|
|
184
185
|
except Exception as exception:
|
|
185
|
-
self.logger.
|
|
186
|
-
|
|
186
|
+
self.logger.exception(f'Error when prepare circuit: {exception}',
|
|
187
|
+
exc_info=True)
|
|
187
188
|
|
|
188
189
|
job_response = build_error_job_response(exception, job_response,
|
|
189
190
|
message='Error when prepare circuit')
|
{quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/component/backend/job_fetcher.py
RENAMED
|
@@ -116,7 +116,7 @@ class JobFetcher(ABC):
|
|
|
116
116
|
update_job_metadata(job_response, self.callback_urls[
|
|
117
117
|
InvocationStep.EXECUTION].on_done)
|
|
118
118
|
elif job_status == JobStatus.ERROR.value:
|
|
119
|
-
self.logger.
|
|
119
|
+
self.logger.exception("Job resulted in error, handling failure")
|
|
120
120
|
|
|
121
121
|
self._handle_failed_job(original_job_result, job_response)
|
|
122
122
|
update_job_metadata(job_response, self.callback_urls[
|
|
@@ -127,7 +127,7 @@ class JobFetcher(ABC):
|
|
|
127
127
|
job_response.status_code = StatusCode.POLLING
|
|
128
128
|
|
|
129
129
|
except Exception as exception:
|
|
130
|
-
self.logger.
|
|
130
|
+
self.logger.exception(
|
|
131
131
|
f"Exception during job fetch for provider_job_id {self.provider_job_id}: {exception}",
|
|
132
132
|
exc_info=True)
|
|
133
133
|
|
|
@@ -151,7 +151,7 @@ class JobFetcher(ABC):
|
|
|
151
151
|
def _handle_failed_job(self, original_job_result,
|
|
152
152
|
job_response: JobResponse):
|
|
153
153
|
"""Handles the job result when the job has encountered an error."""
|
|
154
|
-
self.logger.
|
|
154
|
+
self.logger.exception("Parsing job result from failed job")
|
|
155
155
|
job_response.job_result = parse(original_job_result)
|
|
156
156
|
|
|
157
157
|
def _process_job_result(self, original_job_result,
|
|
@@ -205,7 +205,7 @@ class JobFetcher(ABC):
|
|
|
205
205
|
return job_response
|
|
206
206
|
|
|
207
207
|
except Exception as exception:
|
|
208
|
-
self.logger.
|
|
208
|
+
self.logger.exception(f"Exception during analysis: {exception}",
|
|
209
209
|
exc_info=True)
|
|
210
210
|
from ...util.response_utils import build_error_job_response
|
|
211
211
|
job_response = build_error_job_response(exception, job_response,
|
{quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/component/backend/job_fetching.py
RENAMED
|
@@ -75,7 +75,7 @@ class JobFetching(ABC):
|
|
|
75
75
|
InvocationStep.EXECUTION).on_done)
|
|
76
76
|
|
|
77
77
|
elif JobStatus.ERROR.value.__eq__(job_response.job_status):
|
|
78
|
-
self.logger.
|
|
78
|
+
self.logger.exception("Job resulted in error, handling failure")
|
|
79
79
|
|
|
80
80
|
job_response.job_result = parse(original_job_result)
|
|
81
81
|
|
|
@@ -152,7 +152,7 @@ class JobFetching(ABC):
|
|
|
152
152
|
return job_response
|
|
153
153
|
|
|
154
154
|
except Exception as exception:
|
|
155
|
-
self.logger.
|
|
155
|
+
self.logger.exception(
|
|
156
156
|
"Exception when analyst job result with provider_job_id {0}: {1}".format(
|
|
157
157
|
self.provider_job_id, str(exception)))
|
|
158
158
|
|
|
@@ -35,7 +35,7 @@ def update_job_metadata(job_response: JobResponse, callback_url: str):
|
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
except Exception as exception:
|
|
38
|
-
logger.
|
|
38
|
+
logger.exception(f"Error occurred while calling backend: {exception}",
|
|
39
39
|
exc_info=True)
|
|
40
40
|
|
|
41
41
|
raise exception
|
|
@@ -60,7 +60,7 @@ class DeviceSelection:
|
|
|
60
60
|
response = requests.get(self.url, params=request, headers=header)
|
|
61
61
|
|
|
62
62
|
if response.status_code != 200:
|
|
63
|
-
logger.
|
|
63
|
+
logger.exception(
|
|
64
64
|
'Select device fail with status code: {0} and content: {1}'.format(
|
|
65
65
|
response.status_code, response.content))
|
|
66
66
|
|
|
@@ -21,11 +21,13 @@ def __custom_format(record):
|
|
|
21
21
|
|
|
22
22
|
# Get the color for the current level, default to white if the level is unknown
|
|
23
23
|
level_color = level_colors.get(record["level"].name, "white")
|
|
24
|
-
return (
|
|
25
|
-
|
|
24
|
+
return (f"<yellow>[ConsoleJobLog][{context}]</yellow> "
|
|
25
|
+
f"<{level_color}>{{level}}</{level_color}> : "
|
|
26
|
+
f"<green>{{time:YYYY-MM-DD HH:mm:ss.SSS}}</green> : "
|
|
27
|
+
f"<{level_color}>{{message}}</{level_color}>: "
|
|
28
|
+
f"<magenta>{{process}}</magenta>\n")
|
|
26
29
|
|
|
27
30
|
|
|
28
31
|
logger.add(sink=sys.stderr, format=__custom_format, # Use custom format function
|
|
29
|
-
level="DEBUG", colorize=True
|
|
30
|
-
# Enable colors (supported by sys.stderr)
|
|
32
|
+
level="DEBUG", colorize=True# Enable colors (supported by sys.stderr)
|
|
31
33
|
)
|
|
@@ -45,7 +45,7 @@ class InvocationRequest(Request):
|
|
|
45
45
|
try:
|
|
46
46
|
Sdk.resolve(sdk_value)
|
|
47
47
|
except Exception:
|
|
48
|
-
self.logger.
|
|
48
|
+
self.logger.exception(
|
|
49
49
|
'sdk must be a valid Sdk value, got {0}'.format(
|
|
50
50
|
sdk_value))
|
|
51
51
|
raise ValueError(
|
|
@@ -54,7 +54,7 @@ class InvocationRequest(Request):
|
|
|
54
54
|
# Validate authentication (if provided)
|
|
55
55
|
authentication = request_data.get("authentication")
|
|
56
56
|
if authentication is not None and not isinstance(authentication, dict):
|
|
57
|
-
self.logger.
|
|
57
|
+
self.logger.exception(
|
|
58
58
|
'authentication must be a dictionary if provided, got {0}'.format(
|
|
59
59
|
type(authentication).__name__))
|
|
60
60
|
raise ValueError(
|
|
@@ -8,7 +8,7 @@ class JobFetchingRequest(Request):
|
|
|
8
8
|
def __init__(self, request_data: dict | None):
|
|
9
9
|
|
|
10
10
|
if not isinstance(request_data, dict):
|
|
11
|
-
self.logger.
|
|
11
|
+
self.logger.exception(
|
|
12
12
|
f"request_data must be a dictionary, got {type(request_data).__name__}")
|
|
13
13
|
raise ValueError(
|
|
14
14
|
f"request_data must be a dictionary, got {type(request_data).__name__}")
|
|
@@ -17,7 +17,7 @@ class JobFetchingRequest(Request):
|
|
|
17
17
|
provider_authentication = request_data.get("providerAuthentication")
|
|
18
18
|
if provider_authentication is not None and not isinstance(
|
|
19
19
|
provider_authentication, dict):
|
|
20
|
-
self.logger.
|
|
20
|
+
self.logger.exception(
|
|
21
21
|
f"Invalid provider_authentication: {type(provider_authentication).__name__}")
|
|
22
22
|
raise ValueError(
|
|
23
23
|
f"provider_authentication must be a dictionary if provided, got {type(provider_authentication).__name__}")
|
{quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/data/response/job_response.py
RENAMED
|
@@ -23,8 +23,8 @@ class JobResponse(object):
|
|
|
23
23
|
self.job_result = job_result
|
|
24
24
|
self.content_type = content_type
|
|
25
25
|
self.job_histogram = job_histogram
|
|
26
|
-
self.user_identity = authentication
|
|
27
|
-
self.user_token = authentication
|
|
26
|
+
self.user_identity = getattr(authentication, 'user_identity', None)
|
|
27
|
+
self.user_token = getattr(authentication, 'user_token', None)
|
|
28
28
|
self.execution_time = execution_time
|
|
29
29
|
self.status_code = status_code
|
|
30
30
|
self.project_header = project_header
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Quapp Platform Project
|
|
2
|
+
# http_utils.py
|
|
3
|
+
# Copyright © CITYNOW Co. Ltd. All rights reserved.
|
|
4
|
+
|
|
5
|
+
from urllib.parse import urlparse
|
|
6
|
+
|
|
7
|
+
from ..config.logging_config import logger
|
|
8
|
+
from ..data.response.custom_header import CustomHeader
|
|
9
|
+
from ..enum.http_header import HttpHeader
|
|
10
|
+
from ..enum.media_type import MediaType
|
|
11
|
+
from ..enum.token_type import TokenType
|
|
12
|
+
|
|
13
|
+
DEFAULT_WORKSPACE_HEADER = 'workspaceHeader'
|
|
14
|
+
DEFAULT_PROJECT_HEADER = 'projectHeader'
|
|
15
|
+
CUSTOM_HEADER_VALUE = 'value'
|
|
16
|
+
CUSTOM_HEADER_NAME = 'name'
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def create_bearer_header(token, project_header: CustomHeader,
|
|
20
|
+
workspace_header: CustomHeader):
|
|
21
|
+
"""
|
|
22
|
+
Creates an HTTP Bearer authorization header.
|
|
23
|
+
|
|
24
|
+
This function takes a token as an input and constructs a dictionary containing the
|
|
25
|
+
Bearer authorization header. The header consists of the token type "Bearer"
|
|
26
|
+
followed by the provided token.
|
|
27
|
+
|
|
28
|
+
Parameters:
|
|
29
|
+
token: str
|
|
30
|
+
The token string used for the authorization header.
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
dict
|
|
34
|
+
A dictionary containing the constructed Bearer authorization header.
|
|
35
|
+
"""
|
|
36
|
+
project_header_name = getattr(project_header, CUSTOM_HEADER_NAME,
|
|
37
|
+
DEFAULT_PROJECT_HEADER)
|
|
38
|
+
project_header_value = getattr(project_header, CUSTOM_HEADER_VALUE, None)
|
|
39
|
+
workspace_header_name = getattr(workspace_header, CUSTOM_HEADER_NAME,
|
|
40
|
+
DEFAULT_WORKSPACE_HEADER)
|
|
41
|
+
workspace_header_value = getattr(workspace_header, CUSTOM_HEADER_VALUE,
|
|
42
|
+
None)
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
HttpHeader.AUTHORIZATION.value: TokenType.BEARER.value + ' ' + token,
|
|
46
|
+
project_header_name : project_header_value,
|
|
47
|
+
workspace_header_name : workspace_header_value}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def create_application_json_header(token: str, project_header: CustomHeader,
|
|
51
|
+
workspace_header: CustomHeader) -> dict:
|
|
52
|
+
"""
|
|
53
|
+
Generates HTTP headers for JSON-based API requests, including authorization
|
|
54
|
+
and optional custom project and workspace headers.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
token: Authorization token of type string for the HTTP headers.
|
|
58
|
+
project_header: CustomHeader object representing the project-specific
|
|
59
|
+
custom header details.
|
|
60
|
+
workspace_header: CustomHeader object representing the workspace-specific
|
|
61
|
+
custom header details.
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
dict: Dictionary containing HTTP headers with authorization, content type,
|
|
65
|
+
accept headers, and custom project and workspace headers where applicable.
|
|
66
|
+
"""
|
|
67
|
+
project_header_name = getattr(project_header, CUSTOM_HEADER_NAME,
|
|
68
|
+
DEFAULT_PROJECT_HEADER)
|
|
69
|
+
project_header_value = getattr(project_header, CUSTOM_HEADER_VALUE, None)
|
|
70
|
+
workspace_header_name = getattr(workspace_header, CUSTOM_HEADER_NAME,
|
|
71
|
+
DEFAULT_WORKSPACE_HEADER)
|
|
72
|
+
workspace_header_value = getattr(workspace_header, CUSTOM_HEADER_VALUE,
|
|
73
|
+
None)
|
|
74
|
+
return {
|
|
75
|
+
HttpHeader.AUTHORIZATION.value: '{0} {1}'.format(TokenType.BEARER.value,
|
|
76
|
+
token),
|
|
77
|
+
HttpHeader.CONTENT_TYPE.value : MediaType.APPLICATION_JSON.value,
|
|
78
|
+
HttpHeader.ACCEPT.value : MediaType.APPLICATION_JSON.value,
|
|
79
|
+
project_header_name : project_header_value,
|
|
80
|
+
workspace_header_name : workspace_header_value}
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def get_custom_header(request_data: dict, key: str) -> CustomHeader:
|
|
84
|
+
"""
|
|
85
|
+
Retrieve and construct a CustomHeader object from request data.
|
|
86
|
+
|
|
87
|
+
This function accesses a specified key in the request_data dictionary
|
|
88
|
+
to extract the necessary information for creating a CustomHeader
|
|
89
|
+
object. It retrieves the 'name' and 'value' properties from the
|
|
90
|
+
nested dictionary corresponding to the provided key.
|
|
91
|
+
|
|
92
|
+
Parameters:
|
|
93
|
+
request_data (dict): The dictionary containing header details.
|
|
94
|
+
key (str): The key used to extract the relevant header data.
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
CustomHeader: An object that encapsulates the extracted 'name' and
|
|
98
|
+
'value' of the custom header.
|
|
99
|
+
"""
|
|
100
|
+
custom_header = request_data.get(key, {})
|
|
101
|
+
return CustomHeader(name=custom_header.get(CUSTOM_HEADER_NAME),
|
|
102
|
+
value=custom_header.get(CUSTOM_HEADER_VALUE))
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def get_job_id_from_url(url: str):
|
|
106
|
+
"""
|
|
107
|
+
Extracts the job ID from a given URL. This function securely parses the given URL
|
|
108
|
+
and attempts to retrieve the job ID located in the path, typically after the 'jobs'
|
|
109
|
+
keyword. If the pattern is not found or the URL is invalid, it returns None.
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
url: The URL string from which the job ID will be extracted.
|
|
113
|
+
|
|
114
|
+
Returns:
|
|
115
|
+
str or None: The extracted job ID if present, otherwise returns None.
|
|
116
|
+
"""
|
|
117
|
+
|
|
118
|
+
path = urlparse(url).path
|
|
119
|
+
segments = [seg for seg in path.split('/') if seg]
|
|
120
|
+
job_id = None
|
|
121
|
+
|
|
122
|
+
logger.debug(f'Parsed URL segments: {segments}')
|
|
123
|
+
|
|
124
|
+
if 'jobs' in segments:
|
|
125
|
+
idx = segments.index('jobs')
|
|
126
|
+
try:
|
|
127
|
+
job_id = segments[idx + 1]
|
|
128
|
+
logger.debug(f"Found job id after 'jobs': {job_id}")
|
|
129
|
+
except IndexError:
|
|
130
|
+
logger.exception("No job id found after 'jobs'")
|
|
131
|
+
elif 'job' in segments:
|
|
132
|
+
idx = segments.index('job')
|
|
133
|
+
try:
|
|
134
|
+
job_id = segments[idx + 1]
|
|
135
|
+
logger.debug(f"Found job id after 'job': {job_id}")
|
|
136
|
+
except IndexError:
|
|
137
|
+
logger.exception("No job id found after 'job'")
|
|
138
|
+
else:
|
|
139
|
+
logger.exception("Neither 'job' nor 'jobs' found in URL segments.")
|
|
140
|
+
|
|
141
|
+
return job_id
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# Quapp Platform Project
|
|
2
|
+
# response_utils.py
|
|
3
|
+
# Copyright © CITYNOW Co. Ltd. All rights reserved.
|
|
4
|
+
|
|
5
|
+
from .http_utils import CUSTOM_HEADER_VALUE
|
|
6
|
+
from ..component.backend.job_fetcher import JobFetcher
|
|
7
|
+
from ..data.promise.post_processing_promise import PostProcessingPromise
|
|
8
|
+
from ..data.response.job_response import JobResponse
|
|
9
|
+
from ..enum.status.job_status import JobStatus
|
|
10
|
+
from ..enum.status.status_code import StatusCode
|
|
11
|
+
|
|
12
|
+
AUTHENTICATION = 'authentication'
|
|
13
|
+
BACKEND_AUTHENTICATION = 'backend_authentication'
|
|
14
|
+
PROJECT_HEADER = 'project_header'
|
|
15
|
+
PROVIDER_JOB_ID = 'provider_job_id'
|
|
16
|
+
WORKSPACE_HEADER = 'workspace_header'
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def generate_response(job_response: JobResponse) -> dict:
|
|
20
|
+
"""
|
|
21
|
+
Generates a standardized response dictionary based on the given job response.
|
|
22
|
+
|
|
23
|
+
This function processes the provided JobResponse instance and constructs a
|
|
24
|
+
response dictionary containing relevant job details such as status code,
|
|
25
|
+
execution time, job results, and additional attributes if they exist. It ensures
|
|
26
|
+
that all necessary information is included in the response for further
|
|
27
|
+
processing or communication with other systems.
|
|
28
|
+
|
|
29
|
+
Parameters:
|
|
30
|
+
job_response (JobResponse): An instance of the JobResponse class containing
|
|
31
|
+
detailed job information.
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
dict: A dictionary containing the processed job response with keys such as
|
|
35
|
+
'statusCode', 'body', 'userIdentity', 'userToken', 'projectId', and
|
|
36
|
+
'workspaceId'.
|
|
37
|
+
|
|
38
|
+
Raises:
|
|
39
|
+
This function does not explicitly raise exceptions.
|
|
40
|
+
"""
|
|
41
|
+
if job_response:
|
|
42
|
+
status_code = job_response.status_code.value
|
|
43
|
+
body = {'providerJobId': job_response.provider_job_id,
|
|
44
|
+
'jobStatus' : job_response.job_status,
|
|
45
|
+
'jobResult' : job_response.job_result,
|
|
46
|
+
'contentType' : job_response.content_type.value,
|
|
47
|
+
'histogram' : job_response.job_histogram,
|
|
48
|
+
'executionTime': job_response.execution_time}
|
|
49
|
+
|
|
50
|
+
# Add 'shots' only if it exists in the job_response
|
|
51
|
+
if hasattr(job_response, 'shots'):
|
|
52
|
+
body['shots'] = job_response.shots
|
|
53
|
+
|
|
54
|
+
else:
|
|
55
|
+
status_code = job_response.status_code.value
|
|
56
|
+
body = 'Error in function code. Please contact the developer.'
|
|
57
|
+
|
|
58
|
+
return {'statusCode' : status_code,
|
|
59
|
+
'body' : body,
|
|
60
|
+
'userIdentity': job_response.user_identity,
|
|
61
|
+
'userToken' : job_response.user_token,
|
|
62
|
+
'projectId' : getattr(
|
|
63
|
+
job_response.project_header, CUSTOM_HEADER_VALUE, None),
|
|
64
|
+
'workspaceId' : getattr(
|
|
65
|
+
job_response.workspace_header, CUSTOM_HEADER_VALUE, None)}
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def build_done_job_response(fetcher: JobFetcher = None,
|
|
69
|
+
post_promise: PostProcessingPromise = None) -> JobResponse | None:
|
|
70
|
+
"""
|
|
71
|
+
Builds a JobResponse object for a completed job.
|
|
72
|
+
|
|
73
|
+
This function assembles a JobResponse object which signifies the completion
|
|
74
|
+
of a job. It extracts relevant information such as the provider job ID,
|
|
75
|
+
authentication details, project header, and workspace header, and sets the
|
|
76
|
+
status code to indicate the job is done. If both input parameters are missing,
|
|
77
|
+
the function returns None.
|
|
78
|
+
|
|
79
|
+
Parameters:
|
|
80
|
+
fetcher (JobFetcher, optional): An optional job fetcher instance used to
|
|
81
|
+
extract the provider job ID and other details.
|
|
82
|
+
post_promise (PostProcessingPromise, optional): An optional post-processing
|
|
83
|
+
promise instance to assist in extracting relevant details.
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
JobResponse | None: A JobResponse object with the completed job information,
|
|
87
|
+
or None if no inputs were provided.
|
|
88
|
+
"""
|
|
89
|
+
return JobResponse(
|
|
90
|
+
provider_job_id=__extract_value(PROVIDER_JOB_ID, fetcher,
|
|
91
|
+
post_promise),
|
|
92
|
+
authentication=__extract_authentication(fetcher, post_promise),
|
|
93
|
+
project_header=__extract_value(PROJECT_HEADER, fetcher,
|
|
94
|
+
post_promise),
|
|
95
|
+
workspace_header=__extract_value(WORKSPACE_HEADER, fetcher,
|
|
96
|
+
post_promise),
|
|
97
|
+
status_code=StatusCode.DONE)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def build_error_job_response(exception: Exception,
|
|
101
|
+
job_response: JobResponse = None,
|
|
102
|
+
fetcher: JobFetcher = None,
|
|
103
|
+
post_promise: PostProcessingPromise = None,
|
|
104
|
+
message: str = None) -> JobResponse:
|
|
105
|
+
"""
|
|
106
|
+
Builds and returns a JobResponse object populated with error-related information.
|
|
107
|
+
|
|
108
|
+
This function constructs a JobResponse object that provides comprehensive details
|
|
109
|
+
about an error occurrence. It extracts specific headers and identifiers from
|
|
110
|
+
the given fetcher or post-promise if provided, and includes information
|
|
111
|
+
about the error such as the exception and a corresponding message. The status
|
|
112
|
+
and result of the job indicate an error state.
|
|
113
|
+
|
|
114
|
+
Parameters:
|
|
115
|
+
exception: Exception
|
|
116
|
+
The exception instance representing the error that occurred.
|
|
117
|
+
|
|
118
|
+
job_response: JobResponse, optional
|
|
119
|
+
A JobResponse object to populate with error details. If not provided,
|
|
120
|
+
a new JobResponse object will be created.
|
|
121
|
+
|
|
122
|
+
fetcher: JobFetcher, optional
|
|
123
|
+
An optional fetcher from which relevant headers and identifiers can
|
|
124
|
+
be extracted.
|
|
125
|
+
|
|
126
|
+
post_promise: PostProcessingPromise, optional
|
|
127
|
+
An optional post-processing promise from which relevant headers and
|
|
128
|
+
identifiers can be extracted.
|
|
129
|
+
|
|
130
|
+
message: str, optional
|
|
131
|
+
A custom error message to be included in the job response. If not
|
|
132
|
+
specified, a default message "Unknown error occurred." will be used.
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
JobResponse
|
|
136
|
+
A JobResponse object populated with error-related details such as
|
|
137
|
+
status, exception, and error message.
|
|
138
|
+
"""
|
|
139
|
+
if job_response is None:
|
|
140
|
+
job_response = JobResponse()
|
|
141
|
+
job_response.provider_job_id = __extract_value(PROVIDER_JOB_ID, fetcher,
|
|
142
|
+
post_promise)
|
|
143
|
+
job_response.authentication = __extract_authentication(fetcher,
|
|
144
|
+
post_promise)
|
|
145
|
+
job_response.project_header = __extract_value(PROJECT_HEADER, fetcher,
|
|
146
|
+
post_promise)
|
|
147
|
+
job_response.tenant_header = __extract_value(WORKSPACE_HEADER, fetcher,
|
|
148
|
+
post_promise)
|
|
149
|
+
job_response.status_code = StatusCode.ERROR
|
|
150
|
+
job_response.job_status = JobStatus.ERROR.value
|
|
151
|
+
job_response.job_result = {'message' : message or 'Unknown error occurred.',
|
|
152
|
+
'exception': str(exception)}
|
|
153
|
+
return job_response
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def __extract_authentication(fetcher: JobFetcher,
|
|
157
|
+
post_promise: PostProcessingPromise):
|
|
158
|
+
"""
|
|
159
|
+
Extract authentication information from the provided fetcher or post promise.
|
|
160
|
+
|
|
161
|
+
This function retrieves authentication data by first attempting to extract it from
|
|
162
|
+
the JobFetcher instance. If it's not available on the JobFetcher, it then falls back
|
|
163
|
+
to extracting it from the PostProcessingPromise instance. If neither source contains
|
|
164
|
+
authentication data, a default value of None is returned.
|
|
165
|
+
|
|
166
|
+
Parameters:
|
|
167
|
+
fetcher (JobFetcher): The JobFetcher instance to retrieve authentication data from.
|
|
168
|
+
post_promise (PostProcessingPromise): The PostProcessingPromise instance to retrieve
|
|
169
|
+
authentication data from if not available on the fetcher.
|
|
170
|
+
|
|
171
|
+
Returns:
|
|
172
|
+
Any: The extracted authentication data, or None if no authentication data is found.
|
|
173
|
+
"""
|
|
174
|
+
return getattr(fetcher, BACKEND_AUTHENTICATION,
|
|
175
|
+
getattr(post_promise, AUTHENTICATION, None))
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def __extract_value(property_name: str, fetcher: JobFetcher,
|
|
179
|
+
post_promise: PostProcessingPromise):
|
|
180
|
+
"""
|
|
181
|
+
Extracts a specified property value from a fetcher object or a fallback
|
|
182
|
+
post-processing promise object.
|
|
183
|
+
|
|
184
|
+
Parameters:
|
|
185
|
+
property_name: str
|
|
186
|
+
The name of the property to extract.
|
|
187
|
+
fetcher: JobFetcher
|
|
188
|
+
The primary object from which the property value is retrieved.
|
|
189
|
+
post_promise: PostProcessingPromise
|
|
190
|
+
The fallback object from which the property value is retrieved if
|
|
191
|
+
unavailable in the fetcher.
|
|
192
|
+
|
|
193
|
+
Returns:
|
|
194
|
+
Any
|
|
195
|
+
The value of the specified property retrieved from the fetcher or the
|
|
196
|
+
fallback post-promise object.
|
|
197
|
+
|
|
198
|
+
"""
|
|
199
|
+
return getattr(fetcher, property_name,
|
|
200
|
+
getattr(post_promise, property_name, None))
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
# Quapp Platform Project
|
|
2
|
-
# http_utils.py
|
|
3
|
-
# Copyright © CITYNOW Co. Ltd. All rights reserved.
|
|
4
|
-
|
|
5
|
-
from urllib.parse import urlparse
|
|
6
|
-
|
|
7
|
-
from ..config.logging_config import logger
|
|
8
|
-
from ..data.response.custom_header import CustomHeader
|
|
9
|
-
from ..enum.http_header import HttpHeader
|
|
10
|
-
from ..enum.media_type import MediaType
|
|
11
|
-
from ..enum.token_type import TokenType
|
|
12
|
-
|
|
13
|
-
CUSTOM_HEADER_VALUE = 'value'
|
|
14
|
-
CUSTOM_HEADER_NAME = 'name'
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def create_bearer_header(token, project_header: CustomHeader = None,
|
|
18
|
-
workspace_header: CustomHeader = None):
|
|
19
|
-
"""
|
|
20
|
-
Creates an HTTP Bearer authorization header.
|
|
21
|
-
|
|
22
|
-
This function takes a token as an input and constructs a dictionary containing the
|
|
23
|
-
Bearer authorization header. The header consists of the token type "Bearer"
|
|
24
|
-
followed by the provided token.
|
|
25
|
-
|
|
26
|
-
Parameters:
|
|
27
|
-
token: str
|
|
28
|
-
The token string used for the authorization header.
|
|
29
|
-
|
|
30
|
-
Returns:
|
|
31
|
-
dict
|
|
32
|
-
A dictionary containing the constructed Bearer authorization header.
|
|
33
|
-
"""
|
|
34
|
-
|
|
35
|
-
return {
|
|
36
|
-
HttpHeader.AUTHORIZATION.value: TokenType.BEARER.value + ' ' + token,
|
|
37
|
-
project_header.name : project_header.value,
|
|
38
|
-
workspace_header.name : workspace_header.value}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
def create_application_json_header(token: str, project_header: CustomHeader,
|
|
42
|
-
workspace_header: CustomHeader):
|
|
43
|
-
return {
|
|
44
|
-
HttpHeader.AUTHORIZATION.value: TokenType.BEARER.value + ' ' + token,
|
|
45
|
-
HttpHeader.CONTENT_TYPE.value : MediaType.APPLICATION_JSON.value,
|
|
46
|
-
HttpHeader.ACCEPT.value : MediaType.APPLICATION_JSON.value,
|
|
47
|
-
project_header.name : project_header.value,
|
|
48
|
-
workspace_header.name : workspace_header.value}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
def get_custom_header(request_data: dict, key: str) -> CustomHeader:
|
|
52
|
-
custom_header = request_data.get(key, {})
|
|
53
|
-
return CustomHeader(name=custom_header.get(CUSTOM_HEADER_NAME),
|
|
54
|
-
value=custom_header.get(CUSTOM_HEADER_VALUE))
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
def get_job_id_from_url(url: str):
|
|
58
|
-
"""
|
|
59
|
-
Extracts the job ID from a given URL. This function securely parses the given URL
|
|
60
|
-
and attempts to retrieve the job ID located in the path, typically after the 'jobs'
|
|
61
|
-
keyword. If the pattern is not found or the URL is invalid, it returns None.
|
|
62
|
-
|
|
63
|
-
Args:
|
|
64
|
-
url: The URL string from which the job ID will be extracted.
|
|
65
|
-
|
|
66
|
-
Returns:
|
|
67
|
-
str or None: The extracted job ID if present, otherwise returns None.
|
|
68
|
-
"""
|
|
69
|
-
|
|
70
|
-
path = urlparse(url).path
|
|
71
|
-
segments = [seg for seg in path.split('/') if seg]
|
|
72
|
-
job_id = None
|
|
73
|
-
|
|
74
|
-
logger.debug(f'Parsed URL segments: {segments}')
|
|
75
|
-
|
|
76
|
-
if 'jobs' in segments:
|
|
77
|
-
idx = segments.index('jobs')
|
|
78
|
-
try:
|
|
79
|
-
job_id = segments[idx + 1]
|
|
80
|
-
logger.debug(f"Found job id after 'jobs': {job_id}")
|
|
81
|
-
except IndexError:
|
|
82
|
-
logger.error("No job id found after 'jobs'")
|
|
83
|
-
elif 'job' in segments:
|
|
84
|
-
idx = segments.index('job')
|
|
85
|
-
try:
|
|
86
|
-
job_id = segments[idx + 1]
|
|
87
|
-
logger.debug(f"Found job id after 'job': {job_id}")
|
|
88
|
-
except IndexError:
|
|
89
|
-
logger.error("No job id found after 'job'")
|
|
90
|
-
else:
|
|
91
|
-
logger.error("Neither 'job' nor 'jobs' found in URL segments.")
|
|
92
|
-
|
|
93
|
-
return job_id
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
'''
|
|
2
|
-
QApp Platform Project response_utils.py Copyright © CITYNOW Co. Ltd. All rights reserved.
|
|
3
|
-
'''
|
|
4
|
-
|
|
5
|
-
from ..component.backend.job_fetcher import JobFetcher
|
|
6
|
-
from ..config.logging_config import job_logger
|
|
7
|
-
from ..data.promise.post_processing_promise import PostProcessingPromise
|
|
8
|
-
from ..data.response.job_response import JobResponse
|
|
9
|
-
from ..enum.status.job_status import JobStatus
|
|
10
|
-
from ..enum.status.status_code import StatusCode
|
|
11
|
-
|
|
12
|
-
AUTHENTICATION = 'authentication'
|
|
13
|
-
BACKEND_AUTHENTICATION = 'backend_authentication'
|
|
14
|
-
PROJECT_HEADER = 'project_header'
|
|
15
|
-
PROVIDER_JOB_ID = 'provider_job_id'
|
|
16
|
-
WORKSPACE_HEADER = 'workspace_header'
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def generate_response(job_response: JobResponse) -> dict:
|
|
20
|
-
if job_response:
|
|
21
|
-
status_code = job_response.status_code.value
|
|
22
|
-
body = {'providerJobId': job_response.provider_job_id,
|
|
23
|
-
'jobStatus' : job_response.job_status,
|
|
24
|
-
'jobResult' : job_response.job_result,
|
|
25
|
-
'contentType' : job_response.content_type.value,
|
|
26
|
-
'histogram' : job_response.job_histogram,
|
|
27
|
-
'executionTime': job_response.execution_time}
|
|
28
|
-
|
|
29
|
-
# Add 'shots' only if it exists in the job_response
|
|
30
|
-
if hasattr(job_response, 'shots'):
|
|
31
|
-
body['shots'] = job_response.shots
|
|
32
|
-
|
|
33
|
-
else:
|
|
34
|
-
status_code = job_response.status_code.value
|
|
35
|
-
body = 'Error in function code. Please contact the developer.'
|
|
36
|
-
|
|
37
|
-
return {'statusCode' : status_code, 'body': body,
|
|
38
|
-
'userIdentity': job_response.user_identity,
|
|
39
|
-
'userToken' : job_response.user_token,
|
|
40
|
-
'projectId' : job_response.project_header.value,
|
|
41
|
-
'workspaceId' : job_response.workspace_header.value}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
def build_done_job_response(fetcher: JobFetcher = None,
|
|
45
|
-
post_promise: PostProcessingPromise = None) -> JobResponse | None:
|
|
46
|
-
return JobResponse(
|
|
47
|
-
provider_job_id=__extract_provider_job_id(fetcher, post_promise),
|
|
48
|
-
authentication=__extract_authentication(fetcher, post_promise),
|
|
49
|
-
project_header=__extract_project_header(fetcher, post_promise),
|
|
50
|
-
workspace_header=__extract_workspace_header(fetcher, post_promise),
|
|
51
|
-
status_code=StatusCode.DONE)
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
def build_error_job_response(exception: Exception,
|
|
55
|
-
job_response: JobResponse = None,
|
|
56
|
-
fetcher: JobFetcher = None,
|
|
57
|
-
post_promise: PostProcessingPromise = None,
|
|
58
|
-
message: str = None) -> JobResponse:
|
|
59
|
-
if job_response is None:
|
|
60
|
-
job_response = JobResponse()
|
|
61
|
-
job_response.provider_job_id = __extract_provider_job_id(fetcher,
|
|
62
|
-
post_promise)
|
|
63
|
-
job_response.authentication = __extract_authentication(fetcher,
|
|
64
|
-
post_promise)
|
|
65
|
-
job_response.project_header = __extract_project_header(fetcher,
|
|
66
|
-
post_promise)
|
|
67
|
-
job_response.tenant_header = __extract_workspace_header(fetcher,
|
|
68
|
-
post_promise)
|
|
69
|
-
job_response.status_code = StatusCode.ERROR
|
|
70
|
-
job_response.job_status = JobStatus.ERROR.value
|
|
71
|
-
job_response.job_result = {'message' : message or 'Unknown error occurred.',
|
|
72
|
-
'exception': str(exception)}
|
|
73
|
-
return job_response
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
def __extract_authentication(fetcher: JobFetcher,
|
|
77
|
-
post_promise: PostProcessingPromise):
|
|
78
|
-
return getattr(fetcher, BACKEND_AUTHENTICATION,
|
|
79
|
-
getattr(post_promise, AUTHENTICATION, None))
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
def __extract_project_header(fetcher: JobFetcher,
|
|
83
|
-
post_promise: PostProcessingPromise):
|
|
84
|
-
return getattr(fetcher, PROJECT_HEADER,
|
|
85
|
-
getattr(post_promise, PROJECT_HEADER, None))
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
def __extract_provider_job_id(fetcher: JobFetcher,
|
|
89
|
-
post_promise: PostProcessingPromise):
|
|
90
|
-
return getattr(fetcher, PROVIDER_JOB_ID,
|
|
91
|
-
getattr(post_promise, PROVIDER_JOB_ID, None))
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
def __extract_workspace_header(fetcher: JobFetcher,
|
|
95
|
-
post_promise: PostProcessingPromise):
|
|
96
|
-
return getattr(fetcher, WORKSPACE_HEADER,
|
|
97
|
-
getattr(post_promise, WORKSPACE_HEADER, None))
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/async_tasks/async_task.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/component/backend/__init__.py
RENAMED
|
File without changes
|
{quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/component/callback/__init__.py
RENAMED
|
File without changes
|
{quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/component/device/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/data/async_task/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/data/callback/__init__.py
RENAMED
|
File without changes
|
{quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/data/callback/callback_url.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/data/response/__init__.py
RENAMED
|
File without changes
|
{quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/data/response/authentication.py
RENAMED
|
File without changes
|
{quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/data/response/custom_header.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/enum/status/job_status.py
RENAMED
|
File without changes
|
{quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/enum/status/status_code.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/factory/device_factory.py
RENAMED
|
File without changes
|
{quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/factory/handler_factory.py
RENAMED
|
File without changes
|
{quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/factory/provider_factory.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/model/provider/__init__.py
RENAMED
|
File without changes
|
{quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/model/provider/provider.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common/util/json_parser_utils.py
RENAMED
|
File without changes
|
|
File without changes
|
{quapp_common-0.0.11.dev4 → quapp_common-0.0.11.dev6}/quapp_common.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|