quapp-common 0.0.11.dev10__tar.gz → 0.0.12.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.dev10/quapp_common.egg-info → quapp_common-0.0.12.dev2}/PKG-INFO +41 -3
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/README.md +38 -2
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/pyproject.toml +4 -2
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/async_tasks/async_invocation_task.py +8 -1
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/component/backend/invocation.py +2 -2
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/component/backend/job_fetcher.py +2 -2
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/component/backend/job_fetching.py +1 -1
- quapp_common-0.0.12.dev2/quapp_common/component/bridge.py +94 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/component/callback/update_job_metadata.py +13 -5
- quapp_common-0.0.12.dev2/quapp_common/component/circuit_adapter.py +124 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/component/device/device_selection.py +1 -1
- quapp_common-0.0.12.dev2/quapp_common/component/dispatcher.py +79 -0
- quapp_common-0.0.12.dev2/quapp_common/component/result_serializer.py +22 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/data/request/invocation_request.py +1 -1
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/data/request/job_fetching_request.py +6 -2
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/data/request/request.py +1 -1
- quapp_common-0.0.12.dev2/quapp_common/enum/language.py +22 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/model/invocation.py +0 -1
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/util/http_utils.py +1 -1
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2/quapp_common.egg-info}/PKG-INFO +41 -3
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common.egg-info/SOURCES.txt +5 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common.egg-info/requires.txt +2 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/LICENSE +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/__init__.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/async_tasks/__init__.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/async_tasks/async_task.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/async_tasks/export_circuit_task.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/async_tasks/post_processing_task.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/component/__init__.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/component/backend/__init__.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/component/backend/job_manager.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/component/callback/__init__.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/component/device/__init__.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/config/__init__.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/config/logging_config.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/config/thread_config.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/data/__init__.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/data/async_task/__init__.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/data/async_task/circuit_export/__init__.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/data/async_task/circuit_export/backend_holder.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/data/async_task/circuit_export/circuit_holder.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/data/backend/__init__.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/data/backend/backend_information.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/data/callback/__init__.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/data/callback/callback_url.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/data/device/__init__.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/data/device/circuit_running_option.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/data/promise/__init__.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/data/promise/post_processing_promise.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/data/promise/promise.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/data/request/__init__.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/data/response/__init__.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/data/response/authentication.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/data/response/custom_header.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/data/response/job_response.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/enum/__init__.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/enum/base_enum.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/enum/http_header.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/enum/invocation_step.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/enum/media_type.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/enum/processing_unit.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/enum/provider_tag.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/enum/sdk.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/enum/status/__init__.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/enum/status/job_status.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/enum/status/status_code.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/enum/token_type.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/factory/__init__.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/factory/device_factory.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/factory/handler_factory.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/factory/provider_factory.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/handler/__init__.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/handler/handler.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/model/__init__.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/model/device/__init__.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/model/device/custom_device.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/model/device/device.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/model/provider/__init__.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/model/provider/provider.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/util/__init__.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/util/file_utils.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/util/json_parser_utils.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/util/response_utils.py +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common.egg-info/dependency_links.txt +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common.egg-info/top_level.txt +0 -0
- {quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: quapp-common
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.12.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)
|
|
@@ -25,6 +25,8 @@ Requires-Dist: numpy
|
|
|
25
25
|
Requires-Dist: matplotlib
|
|
26
26
|
Requires-Dist: pylatexenc
|
|
27
27
|
Requires-Dist: starlette
|
|
28
|
+
Requires-Dist: qibo
|
|
29
|
+
Requires-Dist: dimod
|
|
28
30
|
Provides-Extra: dev
|
|
29
31
|
Requires-Dist: black; extra == "dev"
|
|
30
32
|
Requires-Dist: bumpver; extra == "dev"
|
|
@@ -46,8 +48,12 @@ quantum providers and devices.
|
|
|
46
48
|
Recent improvements add first-class asynchronous job processing with a
|
|
47
49
|
cross-process JobManager,
|
|
48
50
|
background task execution, and standardized result models for immediate client
|
|
49
|
-
responses while work
|
|
50
|
-
|
|
51
|
+
responses while work continues in the background.
|
|
52
|
+
Version 0.0.12.dev1 introduces multi-language SDK support, enabling
|
|
53
|
+
dispatching quantum tasks to non-Python runtimes (e.g., JavaScript) via
|
|
54
|
+
subprocess with circuit adaptation and result serialization.
|
|
55
|
+
Version 0.0.12.dev2 fixes the JavaScript handler runner path in
|
|
56
|
+
`SubprocessDispatcher` so that the subprocess command resolves correctly.
|
|
51
57
|
|
|
52
58
|
## Features
|
|
53
59
|
|
|
@@ -72,6 +78,16 @@ continues in the background.
|
|
|
72
78
|
scheduler.
|
|
73
79
|
- Safety: updates to jobs already DONE/FAILED are ignored to prevent
|
|
74
80
|
post-completion mutations.
|
|
81
|
+
- Multi-language SDK support (v0.0.12.dev1):
|
|
82
|
+
- Language enum for validating and resolving Python/JavaScript runtimes.
|
|
83
|
+
- SubprocessDispatcher to delegate tasks to non-Python runtimes via
|
|
84
|
+
subprocess with timeout management and JSON payload processing.
|
|
85
|
+
- SubprocessBridge integrating dispatcher, circuit adapter, and result
|
|
86
|
+
serializer for seamless JS-Python handler interaction.
|
|
87
|
+
- CircuitAdapter for converting JS subprocess circuit outputs into native
|
|
88
|
+
SDK formats (OpenQASM, QUBO, JSON) across Qiskit, Braket, PennyLane, etc.
|
|
89
|
+
- ResultSerializer for converting complex job results into JSON-serializable
|
|
90
|
+
dictionaries for subprocess communication.
|
|
75
91
|
|
|
76
92
|
## Installation
|
|
77
93
|
|
|
@@ -85,9 +101,31 @@ Notes:
|
|
|
85
101
|
|
|
86
102
|
- From version 0.0.11.dev7, `starlette` is a direct dependency to support
|
|
87
103
|
background execution helpers.
|
|
104
|
+
- From version 0.0.12.dev1, `qibo` and `dimod` are added as dependencies to
|
|
105
|
+
support Qibo and D-Wave Ocean SDK integrations.
|
|
88
106
|
|
|
89
107
|
## Recently Changes Highlights
|
|
90
108
|
|
|
109
|
+
### v0.0.12.dev2
|
|
110
|
+
- Version bumps to 0.0.12.dev2.
|
|
111
|
+
- Fix: correct JavaScript handler runner path in `SubprocessDispatcher.RUNNER_MAP` —
|
|
112
|
+
removed the erroneous `function/` directory prefix so the subprocess command
|
|
113
|
+
resolves to `handler_runner.js` relative to the working directory.
|
|
114
|
+
|
|
115
|
+
### v0.0.12.dev1
|
|
116
|
+
- Version bump to 0.0.12.dev1 and dependency update (add `qibo`, `dimod`).
|
|
117
|
+
- Introduce multi-language SDK support primitives:
|
|
118
|
+
- `Language` enum for validating and resolving Python/JavaScript runtimes.
|
|
119
|
+
- `SubprocessDispatcher` for delegating tasks to non-Python runtimes via
|
|
120
|
+
subprocess with runner configuration and timeout management.
|
|
121
|
+
- `SubprocessBridge` integrating dispatcher, circuit adapter, and result
|
|
122
|
+
serializer for JS-Python handler interaction.
|
|
123
|
+
- `CircuitAdapter` for converting JS subprocess circuit outputs into native
|
|
124
|
+
SDK formats (OpenQASM, QUBO, JSON) across Qiskit, Braket, PennyLane, etc.
|
|
125
|
+
- `ResultSerializer` for converting complex job results (numpy, complex
|
|
126
|
+
numbers, Enums, datetime) into JSON-serializable dictionaries.
|
|
127
|
+
|
|
128
|
+
### v0.0.11.dev7 – v0.0.11.dev10
|
|
91
129
|
- Version bump to 0.0.11.dev7 and dependency update (add `starlette`).
|
|
92
130
|
- Introduce asynchronous job processing primitives:
|
|
93
131
|
- AsyncInvocationTask for background execution with immediate client
|
|
@@ -11,8 +11,12 @@ quantum providers and devices.
|
|
|
11
11
|
Recent improvements add first-class asynchronous job processing with a
|
|
12
12
|
cross-process JobManager,
|
|
13
13
|
background task execution, and standardized result models for immediate client
|
|
14
|
-
responses while work
|
|
15
|
-
|
|
14
|
+
responses while work continues in the background.
|
|
15
|
+
Version 0.0.12.dev1 introduces multi-language SDK support, enabling
|
|
16
|
+
dispatching quantum tasks to non-Python runtimes (e.g., JavaScript) via
|
|
17
|
+
subprocess with circuit adaptation and result serialization.
|
|
18
|
+
Version 0.0.12.dev2 fixes the JavaScript handler runner path in
|
|
19
|
+
`SubprocessDispatcher` so that the subprocess command resolves correctly.
|
|
16
20
|
|
|
17
21
|
## Features
|
|
18
22
|
|
|
@@ -37,6 +41,16 @@ continues in the background.
|
|
|
37
41
|
scheduler.
|
|
38
42
|
- Safety: updates to jobs already DONE/FAILED are ignored to prevent
|
|
39
43
|
post-completion mutations.
|
|
44
|
+
- Multi-language SDK support (v0.0.12.dev1):
|
|
45
|
+
- Language enum for validating and resolving Python/JavaScript runtimes.
|
|
46
|
+
- SubprocessDispatcher to delegate tasks to non-Python runtimes via
|
|
47
|
+
subprocess with timeout management and JSON payload processing.
|
|
48
|
+
- SubprocessBridge integrating dispatcher, circuit adapter, and result
|
|
49
|
+
serializer for seamless JS-Python handler interaction.
|
|
50
|
+
- CircuitAdapter for converting JS subprocess circuit outputs into native
|
|
51
|
+
SDK formats (OpenQASM, QUBO, JSON) across Qiskit, Braket, PennyLane, etc.
|
|
52
|
+
- ResultSerializer for converting complex job results into JSON-serializable
|
|
53
|
+
dictionaries for subprocess communication.
|
|
40
54
|
|
|
41
55
|
## Installation
|
|
42
56
|
|
|
@@ -50,9 +64,31 @@ Notes:
|
|
|
50
64
|
|
|
51
65
|
- From version 0.0.11.dev7, `starlette` is a direct dependency to support
|
|
52
66
|
background execution helpers.
|
|
67
|
+
- From version 0.0.12.dev1, `qibo` and `dimod` are added as dependencies to
|
|
68
|
+
support Qibo and D-Wave Ocean SDK integrations.
|
|
53
69
|
|
|
54
70
|
## Recently Changes Highlights
|
|
55
71
|
|
|
72
|
+
### v0.0.12.dev2
|
|
73
|
+
- Version bumps to 0.0.12.dev2.
|
|
74
|
+
- Fix: correct JavaScript handler runner path in `SubprocessDispatcher.RUNNER_MAP` —
|
|
75
|
+
removed the erroneous `function/` directory prefix so the subprocess command
|
|
76
|
+
resolves to `handler_runner.js` relative to the working directory.
|
|
77
|
+
|
|
78
|
+
### v0.0.12.dev1
|
|
79
|
+
- Version bump to 0.0.12.dev1 and dependency update (add `qibo`, `dimod`).
|
|
80
|
+
- Introduce multi-language SDK support primitives:
|
|
81
|
+
- `Language` enum for validating and resolving Python/JavaScript runtimes.
|
|
82
|
+
- `SubprocessDispatcher` for delegating tasks to non-Python runtimes via
|
|
83
|
+
subprocess with runner configuration and timeout management.
|
|
84
|
+
- `SubprocessBridge` integrating dispatcher, circuit adapter, and result
|
|
85
|
+
serializer for JS-Python handler interaction.
|
|
86
|
+
- `CircuitAdapter` for converting JS subprocess circuit outputs into native
|
|
87
|
+
SDK formats (OpenQASM, QUBO, JSON) across Qiskit, Braket, PennyLane, etc.
|
|
88
|
+
- `ResultSerializer` for converting complex job results (numpy, complex
|
|
89
|
+
numbers, Enums, datetime) into JSON-serializable dictionaries.
|
|
90
|
+
|
|
91
|
+
### v0.0.11.dev7 – v0.0.11.dev10
|
|
56
92
|
- Version bump to 0.0.11.dev7 and dependency update (add `starlette`).
|
|
57
93
|
- Introduce asynchronous job processing primitives:
|
|
58
94
|
- AsyncInvocationTask for background execution with immediate client
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "quapp-common"
|
|
7
|
-
version = "0.0.
|
|
7
|
+
version = "0.0.12.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" }]
|
|
@@ -21,7 +21,9 @@ dependencies = [
|
|
|
21
21
|
"numpy",
|
|
22
22
|
"matplotlib",
|
|
23
23
|
"pylatexenc",
|
|
24
|
-
"starlette"
|
|
24
|
+
"starlette",
|
|
25
|
+
"qibo",
|
|
26
|
+
"dimod"
|
|
25
27
|
]
|
|
26
28
|
requires-python = ">=3.7"
|
|
27
29
|
|
|
@@ -69,7 +69,14 @@ class AsyncInvocationTask(AsyncTask):
|
|
|
69
69
|
self.post_processing_fn).handle()
|
|
70
70
|
|
|
71
71
|
# Run in the background threadpool so this request can return immediately
|
|
72
|
-
asyncio.create_task(run_in_threadpool(_run_handle))
|
|
72
|
+
task = asyncio.create_task(run_in_threadpool(_run_handle))
|
|
73
|
+
|
|
74
|
+
def _on_task_done(t: asyncio.Task):
|
|
75
|
+
if not t.cancelled() and t.exception():
|
|
76
|
+
logger.exception(
|
|
77
|
+
f"Background job task failed for job {job_id}: {t.exception()}")
|
|
78
|
+
|
|
79
|
+
task.add_done_callback(_on_task_done)
|
|
73
80
|
|
|
74
81
|
# Respond immediately so clients can poll GET /jobs/{job_id}
|
|
75
82
|
return JSONResponse(status_code=200, content=Success(
|
{quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/component/backend/invocation.py
RENAMED
|
@@ -77,7 +77,7 @@ 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.error(
|
|
81
81
|
"Circuit preparation failed, returning None from pre-execute")
|
|
82
82
|
raise ValueError("Circuit preparation failed")
|
|
83
83
|
|
|
@@ -114,7 +114,7 @@ class Invocation(ABC):
|
|
|
114
114
|
|
|
115
115
|
try:
|
|
116
116
|
if self.backend_information is None:
|
|
117
|
-
self.logger.
|
|
117
|
+
self.logger.error(
|
|
118
118
|
"Backend information is None before execution")
|
|
119
119
|
raise ValueError("Backend is not found")
|
|
120
120
|
|
{quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/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.error("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[
|
|
@@ -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.error("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,
|
|
@@ -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.error("Job resulted in error, handling failure")
|
|
79
79
|
|
|
80
80
|
job_response.job_result = parse(original_job_result)
|
|
81
81
|
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"""
|
|
2
|
+
QApp Platform Project
|
|
3
|
+
bridge.py
|
|
4
|
+
Copyright © CITYNOW Co. Ltd. All rights reserved.
|
|
5
|
+
"""
|
|
6
|
+
# Quapp Platform Project
|
|
7
|
+
# bridge.py
|
|
8
|
+
# Copyright © CITYNOW Co. Ltd. All rights reserved.
|
|
9
|
+
|
|
10
|
+
import logging
|
|
11
|
+
|
|
12
|
+
from .circuit_adapter import CircuitAdapter
|
|
13
|
+
from .dispatcher import SubprocessDispatcher
|
|
14
|
+
from .result_serializer import ResultSerializer
|
|
15
|
+
from ..enum.language import Language
|
|
16
|
+
from ..enum.sdk import Sdk
|
|
17
|
+
|
|
18
|
+
logger = logging.getLogger(__name__)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class SubprocessBridge:
|
|
22
|
+
"""Bridge between the Python invocation chain and JS subprocess handlers.
|
|
23
|
+
|
|
24
|
+
Provides processing() and post_processing() callables that can be passed
|
|
25
|
+
to AsyncInvocationTask in place of Python handler functions. Internally,
|
|
26
|
+
each call dispatches to the JS subprocess with the appropriate action,
|
|
27
|
+
then converts the result (circuit or post-processed data) back to
|
|
28
|
+
Python-native objects.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def __init__(self, language: Language, sdk: Sdk):
|
|
32
|
+
self.language = language
|
|
33
|
+
self.sdk = sdk
|
|
34
|
+
|
|
35
|
+
def processing(self, invocation_input: dict):
|
|
36
|
+
"""Call JS handler's processing() and convert a result to a native circuit.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
invocation_input: The input dict from the invocation request.
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
A native SDK circuit object (QuantumCircuit, BQM, etc.)
|
|
43
|
+
|
|
44
|
+
Raises:
|
|
45
|
+
RuntimeError: If the JS subprocess returns an error status.
|
|
46
|
+
"""
|
|
47
|
+
logger.info(
|
|
48
|
+
f"SubprocessBridge.processing: dispatching to {self.language.value}")
|
|
49
|
+
|
|
50
|
+
result = SubprocessDispatcher.dispatch(self.language, {
|
|
51
|
+
"action": "processing",
|
|
52
|
+
"input" : invocation_input
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
if result.get("status") == "error":
|
|
56
|
+
raise RuntimeError(f"JS processing failed: {result.get('error')}")
|
|
57
|
+
|
|
58
|
+
payload = result.get("result")
|
|
59
|
+
if payload is None:
|
|
60
|
+
raise RuntimeError("JS processing returned no 'result' field")
|
|
61
|
+
logger.debug(
|
|
62
|
+
f"SubprocessBridge.processing: JS returned format={payload.get('format')}")
|
|
63
|
+
|
|
64
|
+
return CircuitAdapter.adapt(self.sdk, payload)
|
|
65
|
+
|
|
66
|
+
def post_processing(self, job_result):
|
|
67
|
+
"""Serialize a job result, send to JS handler's postProcessing(), return a result.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
job_result: The raw job results from the quantum device execution.
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
The post-processed result from the JS handler.
|
|
74
|
+
|
|
75
|
+
Raises:
|
|
76
|
+
RuntimeError: If the JS subprocess returns an error status.
|
|
77
|
+
"""
|
|
78
|
+
logger.info(
|
|
79
|
+
f"SubprocessBridge.post_processing: dispatching to {self.language.value}")
|
|
80
|
+
|
|
81
|
+
serialized = ResultSerializer.serialize(job_result)
|
|
82
|
+
|
|
83
|
+
result = SubprocessDispatcher.dispatch(self.language, {
|
|
84
|
+
"action" : "post_processing",
|
|
85
|
+
"job_result": serialized
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
if result.get("status") == "error":
|
|
89
|
+
raise RuntimeError(f"JS post_processing failed: {result.get('error')}")
|
|
90
|
+
|
|
91
|
+
payload = result.get("result")
|
|
92
|
+
if payload is None:
|
|
93
|
+
raise RuntimeError("JS post_processing returned no 'result' field")
|
|
94
|
+
return payload
|
|
@@ -38,8 +38,16 @@ def update_job_metadata(job_response: JobResponse, callback_url: str):
|
|
|
38
38
|
|
|
39
39
|
def _patch_scheduler() -> None:
|
|
40
40
|
job_details = JobManager.get_job(job_id)
|
|
41
|
-
|
|
41
|
+
if job_details is None:
|
|
42
|
+
logger.warning(
|
|
43
|
+
f"Job {job_id} not found in JobManager, skipping scheduler patch")
|
|
44
|
+
return
|
|
45
|
+
scheduler_callback_url = job_details.get('meta', {}).get(
|
|
42
46
|
'scheduler_callback_url')
|
|
47
|
+
if not scheduler_callback_url:
|
|
48
|
+
logger.debug(
|
|
49
|
+
f"No scheduler callback URL for job {job_id}, skipping")
|
|
50
|
+
return
|
|
43
51
|
scheduler_payload = {'job_id' : job_id,
|
|
44
52
|
'status' : job_details.get('status'),
|
|
45
53
|
'updated_at': job_details.get('updated_at')}
|
|
@@ -55,10 +63,6 @@ def update_job_metadata(job_response: JobResponse, callback_url: str):
|
|
|
55
63
|
request_body = generate_response(job_response)
|
|
56
64
|
|
|
57
65
|
try:
|
|
58
|
-
# Update local job status and notify scheduler
|
|
59
|
-
_update_local_status()
|
|
60
|
-
_patch_scheduler()
|
|
61
|
-
|
|
62
66
|
request_headers = create_application_json_header(
|
|
63
67
|
token=job_response.user_token,
|
|
64
68
|
project_header=job_response.project_header,
|
|
@@ -70,6 +74,10 @@ def update_job_metadata(job_response: JobResponse, callback_url: str):
|
|
|
70
74
|
# Log backend response
|
|
71
75
|
_log_http_result('backend', response)
|
|
72
76
|
|
|
77
|
+
# Update local job status and notify scheduler only after backend confirms
|
|
78
|
+
_update_local_status()
|
|
79
|
+
_patch_scheduler()
|
|
80
|
+
|
|
73
81
|
except Exception as exception:
|
|
74
82
|
logger.exception(f'Error occurred while calling backend: {exception}',
|
|
75
83
|
exc_info=True)
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"""
|
|
2
|
+
QApp Platform Project circuit_adapter.py Copyright © CITYNOW Co. Ltd. All rights reserved.
|
|
3
|
+
"""
|
|
4
|
+
# Quapp Platform Project
|
|
5
|
+
# circuit_adapter.py
|
|
6
|
+
# Copyright © CITYNOW Co. Ltd. All rights reserved.
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
|
|
10
|
+
from ..enum.sdk import Sdk
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class CircuitAdapter:
|
|
16
|
+
"""Convert JS subprocess circuit output to native SDK circuit objects.
|
|
17
|
+
|
|
18
|
+
Supported interchange formats:
|
|
19
|
+
- openqasm: OpenQASM 2.0 string -> SDK-specific QuantumCircuit
|
|
20
|
+
- qubo: QUBO dict -> dimod.BinaryQuadraticModel
|
|
21
|
+
- json: Arbitrary JSON pass-through
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
@staticmethod
|
|
25
|
+
def adapt(sdk: Sdk, result: dict):
|
|
26
|
+
"""Route to the appropriate adapter based on the 'format' field."""
|
|
27
|
+
fmt = result.get("format")
|
|
28
|
+
if fmt == "openqasm":
|
|
29
|
+
circuit = result.get("circuit")
|
|
30
|
+
if circuit is None:
|
|
31
|
+
raise ValueError("Missing 'circuit' field in openqasm response")
|
|
32
|
+
return CircuitAdapter._adapt_openqasm(sdk, circuit)
|
|
33
|
+
elif fmt == "qubo":
|
|
34
|
+
qubo = result.get("qubo")
|
|
35
|
+
if qubo is None:
|
|
36
|
+
raise ValueError("Missing 'qubo' field in qubo response")
|
|
37
|
+
return CircuitAdapter._adapt_qubo(sdk, qubo)
|
|
38
|
+
elif fmt == "json":
|
|
39
|
+
return result.get("data")
|
|
40
|
+
raise ValueError(f"Unsupported circuit interchange format: {fmt}")
|
|
41
|
+
|
|
42
|
+
@staticmethod
|
|
43
|
+
def _adapt_openqasm(sdk, qasm_str):
|
|
44
|
+
"""Convert an OpenQASM 2.0 string to a native SDK circuit object."""
|
|
45
|
+
logger.debug(f"Adapting OpenQASM circuit for SDK: {sdk}")
|
|
46
|
+
|
|
47
|
+
if sdk == Sdk.QISKIT:
|
|
48
|
+
from qiskit import QuantumCircuit
|
|
49
|
+
return QuantumCircuit.from_qasm_str(qasm_str)
|
|
50
|
+
|
|
51
|
+
elif sdk == Sdk.BRAKET:
|
|
52
|
+
from pytket.qasm import circuit_from_qasm_str
|
|
53
|
+
from pytket.extensions.braket import tk_to_braket
|
|
54
|
+
return tk_to_braket(circuit_from_qasm_str(qasm_str))
|
|
55
|
+
|
|
56
|
+
elif sdk == Sdk.PENNYLANE:
|
|
57
|
+
import pennylane as qml
|
|
58
|
+
# PennyLane >=0.37 treats QASM `measure` statements as mid-circuit
|
|
59
|
+
# measurements returning MeasurementValue, which fails QNode
|
|
60
|
+
# validation. Override with a terminal `qml.probs` over all qubits
|
|
61
|
+
# so the QNode produces valid output and downstream histogram
|
|
62
|
+
# logic (which already looks for ProbabilityMP) keeps working.
|
|
63
|
+
#
|
|
64
|
+
# NOTE: `qml.from_qasm(..., measurements=[...])` attaches those
|
|
65
|
+
# measurements via `make_qscript` internally, which means they are
|
|
66
|
+
# NOT queued into an active `QuantumTape()` context. Downstream
|
|
67
|
+
# code uses `with QuantumTape() as tape: circuit()` to discover
|
|
68
|
+
# the circuit's wires, which would then miss the measurement
|
|
69
|
+
# wires and cause `WireError` at device execution. We therefore
|
|
70
|
+
# return a wrapper that runs the QASM ops (measurements=[] to
|
|
71
|
+
# drop QASM's terminal measures) and then explicitly queue a
|
|
72
|
+
# fresh `qml.probs` over all qubits, so the wires are visible in
|
|
73
|
+
# both `QuantumTape` capture and full QNode execution.
|
|
74
|
+
num_wires = CircuitAdapter._count_qasm_qubits(qasm_str)
|
|
75
|
+
base_fn = qml.from_qasm(qasm_str, measurements=[])
|
|
76
|
+
|
|
77
|
+
def _circuit():
|
|
78
|
+
base_fn()
|
|
79
|
+
if num_wires > 0:
|
|
80
|
+
return qml.probs(wires=list(range(num_wires)))
|
|
81
|
+
return None
|
|
82
|
+
|
|
83
|
+
return _circuit
|
|
84
|
+
|
|
85
|
+
elif sdk == Sdk.PYQUIL:
|
|
86
|
+
from pytket.qasm import circuit_from_qasm_str
|
|
87
|
+
from pytket.extensions.pyquil import tk_to_pyquil
|
|
88
|
+
return tk_to_pyquil(circuit_from_qasm_str(qasm_str))
|
|
89
|
+
|
|
90
|
+
elif sdk == Sdk.QIBO:
|
|
91
|
+
from qibo.models import Circuit
|
|
92
|
+
return Circuit.from_qasm(qasm_str)
|
|
93
|
+
|
|
94
|
+
elif sdk in (Sdk.CUDA_QUANTUM, Sdk.CU_QUANTUM):
|
|
95
|
+
# CUDA-Q accepts OpenQASM directly via kernel builder
|
|
96
|
+
return qasm_str
|
|
97
|
+
|
|
98
|
+
raise ValueError(f"OpenQASM adaptation not supported for SDK: {sdk}")
|
|
99
|
+
|
|
100
|
+
@staticmethod
|
|
101
|
+
def _count_qasm_qubits(qasm_str):
|
|
102
|
+
"""Sum qubit counts across all `qreg <name>[<n>];` declarations."""
|
|
103
|
+
import re
|
|
104
|
+
return sum(int(m) for m in re.findall(r'qreg\s+\w+\[(\d+)\]', qasm_str))
|
|
105
|
+
|
|
106
|
+
@staticmethod
|
|
107
|
+
def _adapt_qubo(sdk, qubo_raw):
|
|
108
|
+
"""Convert a QUBO dict with string keys ('x0,x1') to a BinaryQuadraticModel.
|
|
109
|
+
|
|
110
|
+
JS returns keys like "x0,x1" as strings. We parse them into tuple keys
|
|
111
|
+
for dimod's from_qubo() method.
|
|
112
|
+
"""
|
|
113
|
+
logger.debug(f"Adapting QUBO for SDK: {sdk}")
|
|
114
|
+
|
|
115
|
+
qubo_dict = {}
|
|
116
|
+
for key, val in qubo_raw.items():
|
|
117
|
+
if isinstance(key, str) and "," in key:
|
|
118
|
+
parts = tuple(k.strip() for k in key.split(",", 1))
|
|
119
|
+
qubo_dict[parts] = val
|
|
120
|
+
else:
|
|
121
|
+
qubo_dict[(key, key)] = val
|
|
122
|
+
|
|
123
|
+
from dimod import BinaryQuadraticModel
|
|
124
|
+
return BinaryQuadraticModel.from_qubo(qubo_dict)
|
|
@@ -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.error(
|
|
64
64
|
'Select device fail with status code: {0} and content: {1}'.format(
|
|
65
65
|
response.status_code, response.content))
|
|
66
66
|
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"""
|
|
2
|
+
QApp Platform Project dispatcher.py Copyright © CITYNOW Co. Ltd. All rights reserved.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
# Quapp Platform Project
|
|
6
|
+
# dispatcher.py
|
|
7
|
+
# Copyright © CITYNOW Co. Ltd. All rights reserved.
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
import logging
|
|
11
|
+
import os
|
|
12
|
+
import subprocess
|
|
13
|
+
|
|
14
|
+
from ..enum.language import Language
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class SubprocessDispatcher:
|
|
20
|
+
"""Dispatch handler execution to non-Python runtimes via subprocess."""
|
|
21
|
+
|
|
22
|
+
# Override this at application startup to set a stable working directory
|
|
23
|
+
# for subprocess runners (e.g., the project root containing function/).
|
|
24
|
+
# Defaults to os.getcwd() at dispatch time if not set.
|
|
25
|
+
WORKING_DIR: str = None
|
|
26
|
+
|
|
27
|
+
RUNNER_MAP = {
|
|
28
|
+
Language.JAVASCRIPT: {
|
|
29
|
+
'command': ['node', 'handler_runner.js'],
|
|
30
|
+
'timeout': 300,
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@staticmethod
|
|
35
|
+
def dispatch(language: Language, request_data: dict,
|
|
36
|
+
timeout: int = None) -> dict:
|
|
37
|
+
"""Dispatch request_data to a subprocess runner.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
language: The target language runtime.
|
|
41
|
+
request_data: Dict to serialize as JSON and pipe to stdin.
|
|
42
|
+
timeout: Optional timeout in seconds. Overrides the runner by default.
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
Parsed JSON dict from the subprocess stdout.
|
|
46
|
+
"""
|
|
47
|
+
runner = SubprocessDispatcher.RUNNER_MAP.get(language)
|
|
48
|
+
if runner is None:
|
|
49
|
+
raise ValueError(f"No runner configured for language: {language}")
|
|
50
|
+
|
|
51
|
+
effective_timeout = timeout if timeout is not None else runner['timeout']
|
|
52
|
+
action = request_data.get('action', 'handle')
|
|
53
|
+
logger.info(f"Dispatching to {language.value} runner, action={action}, "
|
|
54
|
+
f"timeout={effective_timeout}s")
|
|
55
|
+
|
|
56
|
+
payload = json.dumps(request_data)
|
|
57
|
+
cwd = SubprocessDispatcher.WORKING_DIR or os.getcwd()
|
|
58
|
+
result = subprocess.run(runner['command'], input=payload,
|
|
59
|
+
capture_output=True, text=True,
|
|
60
|
+
timeout=effective_timeout, cwd=cwd)
|
|
61
|
+
|
|
62
|
+
if result.stderr:
|
|
63
|
+
logger.debug(f"Subprocess stderr: {result.stderr[:500]}")
|
|
64
|
+
|
|
65
|
+
if result.returncode != 0:
|
|
66
|
+
logger.error(
|
|
67
|
+
f"Handler runner failed (exit={result.returncode}): {result.stderr[:500]}")
|
|
68
|
+
raise RuntimeError(f"Handler runner failed: {result.stderr}")
|
|
69
|
+
|
|
70
|
+
logger.debug(f"Subprocess completed successfully, action={action}")
|
|
71
|
+
return json.loads(result.stdout)
|
|
72
|
+
|
|
73
|
+
@staticmethod
|
|
74
|
+
def is_subprocess_language(language_str: str) -> bool:
|
|
75
|
+
try:
|
|
76
|
+
lang = Language.resolve(language_str)
|
|
77
|
+
return lang != Language.PYTHON
|
|
78
|
+
except Exception:
|
|
79
|
+
return False
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""
|
|
2
|
+
QApp Platform Project result_serializer.py Copyright © CITYNOW Co. Ltd. All rights reserved.
|
|
3
|
+
"""
|
|
4
|
+
from ..util.json_parser_utils import parse
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ResultSerializer:
|
|
8
|
+
"""Serialize Python job results into JSON-safe dicts for subprocess communication."""
|
|
9
|
+
|
|
10
|
+
@staticmethod
|
|
11
|
+
def serialize(job_result):
|
|
12
|
+
"""
|
|
13
|
+
Convert a job result (which may contain numpy arrays, complex numbers,
|
|
14
|
+
Qiskit/Braket objects, etc.) into a plain JSON-serializable dict.
|
|
15
|
+
|
|
16
|
+
Reuses the existing parse() utility that handles numpy, complex, datetime,
|
|
17
|
+
Enum, and custom objects with to_dict()/__dict__.
|
|
18
|
+
"""
|
|
19
|
+
try:
|
|
20
|
+
return parse(job_result)
|
|
21
|
+
except Exception as e:
|
|
22
|
+
raise RuntimeError(f"Failed to serialize job result: {e}") from e
|
|
@@ -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.error(
|
|
58
58
|
'authentication must be a dictionary if provided, got {0}'.format(
|
|
59
59
|
type(authentication).__name__))
|
|
60
60
|
raise ValueError(
|
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
# Quapp Platform Project
|
|
2
2
|
# job_fetching_request.py
|
|
3
3
|
# Copyright © CITYNOW Co. Ltd. All rights reserved.
|
|
4
|
+
import logging
|
|
5
|
+
|
|
4
6
|
from .request import Request
|
|
5
7
|
|
|
8
|
+
_logger = logging.getLogger(__name__)
|
|
9
|
+
|
|
6
10
|
|
|
7
11
|
class JobFetchingRequest(Request):
|
|
8
12
|
def __init__(self, request_data: dict | None):
|
|
9
13
|
|
|
10
14
|
if not isinstance(request_data, dict):
|
|
11
|
-
|
|
15
|
+
_logger.error(
|
|
12
16
|
f"request_data must be a dictionary, got {type(request_data).__name__}")
|
|
13
17
|
raise ValueError(
|
|
14
18
|
f"request_data must be a dictionary, got {type(request_data).__name__}")
|
|
@@ -17,7 +21,7 @@ class JobFetchingRequest(Request):
|
|
|
17
21
|
provider_authentication = request_data.get("providerAuthentication")
|
|
18
22
|
if provider_authentication is not None and not isinstance(
|
|
19
23
|
provider_authentication, dict):
|
|
20
|
-
|
|
24
|
+
_logger.error(
|
|
21
25
|
f"Invalid provider_authentication: {type(provider_authentication).__name__}")
|
|
22
26
|
raise ValueError(
|
|
23
27
|
f"provider_authentication must be a dictionary if provided, got {type(provider_authentication).__name__}")
|
|
@@ -27,7 +27,7 @@ class Request:
|
|
|
27
27
|
self.workspace_header: CustomHeader = get_custom_header(request_data,
|
|
28
28
|
'workspaceHeader')
|
|
29
29
|
self.logger = job_logger(self.job_id)
|
|
30
|
-
JobManager.add_job(job_id=self.job_id, status='
|
|
30
|
+
JobManager.add_job(job_id=self.job_id, status='PENDING', meta={
|
|
31
31
|
'scheduler_callback_url': request_data.get('schedulerCallBackURL')})
|
|
32
32
|
self.logger.info(
|
|
33
33
|
f"Initializing Request with job id: {self.job_id} and provider job id: {self.provider_job_id}")
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""
|
|
2
|
+
QApp Platform Project language.py Copyright © CITYNOW Co. Ltd. All rights reserved.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
# Quapp Platform Project
|
|
6
|
+
# language.py
|
|
7
|
+
# Copyright © CITYNOW Co. Ltd. All rights reserved.
|
|
8
|
+
|
|
9
|
+
from ..enum.base_enum import BaseEnum
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Language(BaseEnum):
|
|
13
|
+
PYTHON = 'python'
|
|
14
|
+
JAVASCRIPT = 'javascript'
|
|
15
|
+
|
|
16
|
+
@staticmethod
|
|
17
|
+
def resolve(language: str):
|
|
18
|
+
for element in Language:
|
|
19
|
+
if element.value == language:
|
|
20
|
+
return element
|
|
21
|
+
|
|
22
|
+
raise ValueError(f"Language '{language}' is not supported!")
|
|
@@ -136,6 +136,6 @@ def get_job_id_from_url(url: str):
|
|
|
136
136
|
except IndexError:
|
|
137
137
|
logger.exception("No job id found after 'job'")
|
|
138
138
|
else:
|
|
139
|
-
logger.
|
|
139
|
+
logger.error("Neither 'job' nor 'jobs' found in URL segments.")
|
|
140
140
|
|
|
141
141
|
return job_id
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: quapp-common
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.12.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)
|
|
@@ -25,6 +25,8 @@ Requires-Dist: numpy
|
|
|
25
25
|
Requires-Dist: matplotlib
|
|
26
26
|
Requires-Dist: pylatexenc
|
|
27
27
|
Requires-Dist: starlette
|
|
28
|
+
Requires-Dist: qibo
|
|
29
|
+
Requires-Dist: dimod
|
|
28
30
|
Provides-Extra: dev
|
|
29
31
|
Requires-Dist: black; extra == "dev"
|
|
30
32
|
Requires-Dist: bumpver; extra == "dev"
|
|
@@ -46,8 +48,12 @@ quantum providers and devices.
|
|
|
46
48
|
Recent improvements add first-class asynchronous job processing with a
|
|
47
49
|
cross-process JobManager,
|
|
48
50
|
background task execution, and standardized result models for immediate client
|
|
49
|
-
responses while work
|
|
50
|
-
|
|
51
|
+
responses while work continues in the background.
|
|
52
|
+
Version 0.0.12.dev1 introduces multi-language SDK support, enabling
|
|
53
|
+
dispatching quantum tasks to non-Python runtimes (e.g., JavaScript) via
|
|
54
|
+
subprocess with circuit adaptation and result serialization.
|
|
55
|
+
Version 0.0.12.dev2 fixes the JavaScript handler runner path in
|
|
56
|
+
`SubprocessDispatcher` so that the subprocess command resolves correctly.
|
|
51
57
|
|
|
52
58
|
## Features
|
|
53
59
|
|
|
@@ -72,6 +78,16 @@ continues in the background.
|
|
|
72
78
|
scheduler.
|
|
73
79
|
- Safety: updates to jobs already DONE/FAILED are ignored to prevent
|
|
74
80
|
post-completion mutations.
|
|
81
|
+
- Multi-language SDK support (v0.0.12.dev1):
|
|
82
|
+
- Language enum for validating and resolving Python/JavaScript runtimes.
|
|
83
|
+
- SubprocessDispatcher to delegate tasks to non-Python runtimes via
|
|
84
|
+
subprocess with timeout management and JSON payload processing.
|
|
85
|
+
- SubprocessBridge integrating dispatcher, circuit adapter, and result
|
|
86
|
+
serializer for seamless JS-Python handler interaction.
|
|
87
|
+
- CircuitAdapter for converting JS subprocess circuit outputs into native
|
|
88
|
+
SDK formats (OpenQASM, QUBO, JSON) across Qiskit, Braket, PennyLane, etc.
|
|
89
|
+
- ResultSerializer for converting complex job results into JSON-serializable
|
|
90
|
+
dictionaries for subprocess communication.
|
|
75
91
|
|
|
76
92
|
## Installation
|
|
77
93
|
|
|
@@ -85,9 +101,31 @@ Notes:
|
|
|
85
101
|
|
|
86
102
|
- From version 0.0.11.dev7, `starlette` is a direct dependency to support
|
|
87
103
|
background execution helpers.
|
|
104
|
+
- From version 0.0.12.dev1, `qibo` and `dimod` are added as dependencies to
|
|
105
|
+
support Qibo and D-Wave Ocean SDK integrations.
|
|
88
106
|
|
|
89
107
|
## Recently Changes Highlights
|
|
90
108
|
|
|
109
|
+
### v0.0.12.dev2
|
|
110
|
+
- Version bumps to 0.0.12.dev2.
|
|
111
|
+
- Fix: correct JavaScript handler runner path in `SubprocessDispatcher.RUNNER_MAP` —
|
|
112
|
+
removed the erroneous `function/` directory prefix so the subprocess command
|
|
113
|
+
resolves to `handler_runner.js` relative to the working directory.
|
|
114
|
+
|
|
115
|
+
### v0.0.12.dev1
|
|
116
|
+
- Version bump to 0.0.12.dev1 and dependency update (add `qibo`, `dimod`).
|
|
117
|
+
- Introduce multi-language SDK support primitives:
|
|
118
|
+
- `Language` enum for validating and resolving Python/JavaScript runtimes.
|
|
119
|
+
- `SubprocessDispatcher` for delegating tasks to non-Python runtimes via
|
|
120
|
+
subprocess with runner configuration and timeout management.
|
|
121
|
+
- `SubprocessBridge` integrating dispatcher, circuit adapter, and result
|
|
122
|
+
serializer for JS-Python handler interaction.
|
|
123
|
+
- `CircuitAdapter` for converting JS subprocess circuit outputs into native
|
|
124
|
+
SDK formats (OpenQASM, QUBO, JSON) across Qiskit, Braket, PennyLane, etc.
|
|
125
|
+
- `ResultSerializer` for converting complex job results (numpy, complex
|
|
126
|
+
numbers, Enums, datetime) into JSON-serializable dictionaries.
|
|
127
|
+
|
|
128
|
+
### v0.0.11.dev7 – v0.0.11.dev10
|
|
91
129
|
- Version bump to 0.0.11.dev7 and dependency update (add `starlette`).
|
|
92
130
|
- Introduce asynchronous job processing primitives:
|
|
93
131
|
- AsyncInvocationTask for background execution with immediate client
|
|
@@ -13,6 +13,10 @@ quapp_common/async_tasks/async_task.py
|
|
|
13
13
|
quapp_common/async_tasks/export_circuit_task.py
|
|
14
14
|
quapp_common/async_tasks/post_processing_task.py
|
|
15
15
|
quapp_common/component/__init__.py
|
|
16
|
+
quapp_common/component/bridge.py
|
|
17
|
+
quapp_common/component/circuit_adapter.py
|
|
18
|
+
quapp_common/component/dispatcher.py
|
|
19
|
+
quapp_common/component/result_serializer.py
|
|
16
20
|
quapp_common/component/backend/__init__.py
|
|
17
21
|
quapp_common/component/backend/invocation.py
|
|
18
22
|
quapp_common/component/backend/job_fetcher.py
|
|
@@ -51,6 +55,7 @@ quapp_common/enum/__init__.py
|
|
|
51
55
|
quapp_common/enum/base_enum.py
|
|
52
56
|
quapp_common/enum/http_header.py
|
|
53
57
|
quapp_common/enum/invocation_step.py
|
|
58
|
+
quapp_common/enum/language.py
|
|
54
59
|
quapp_common/enum/media_type.py
|
|
55
60
|
quapp_common/enum/processing_unit.py
|
|
56
61
|
quapp_common/enum/provider_tag.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/async_tasks/async_task.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/component/backend/__init__.py
RENAMED
|
File without changes
|
{quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/component/backend/job_manager.py
RENAMED
|
File without changes
|
{quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/component/callback/__init__.py
RENAMED
|
File without changes
|
{quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/component/device/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/config/logging_config.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/data/async_task/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/data/backend/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/data/callback/__init__.py
RENAMED
|
File without changes
|
{quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/data/callback/callback_url.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/data/promise/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/data/request/__init__.py
RENAMED
|
File without changes
|
{quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/data/response/__init__.py
RENAMED
|
File without changes
|
{quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/data/response/authentication.py
RENAMED
|
File without changes
|
{quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/data/response/custom_header.py
RENAMED
|
File without changes
|
{quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/data/response/job_response.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.dev10 → quapp_common-0.0.12.dev2}/quapp_common/enum/status/job_status.py
RENAMED
|
File without changes
|
{quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/enum/status/status_code.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/factory/device_factory.py
RENAMED
|
File without changes
|
{quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/factory/handler_factory.py
RENAMED
|
File without changes
|
{quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/factory/provider_factory.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/model/device/__init__.py
RENAMED
|
File without changes
|
{quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/model/device/custom_device.py
RENAMED
|
File without changes
|
|
File without changes
|
{quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/model/provider/__init__.py
RENAMED
|
File without changes
|
{quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/model/provider/provider.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common/util/json_parser_utils.py
RENAMED
|
File without changes
|
|
File without changes
|
{quapp_common-0.0.11.dev10 → quapp_common-0.0.12.dev2}/quapp_common.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|