quapp-common 0.0.14.dev4__tar.gz → 0.0.14.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.14.dev4/quapp_common.egg-info → quapp_common-0.0.14.dev6}/PKG-INFO +59 -7
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/README.md +55 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/pyproject.toml +13 -8
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/async_tasks/post_processing_task.py +14 -9
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/component/circuit_adapter.py +79 -30
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/config/log_context.py +9 -1
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/model/device/custom_device.py +23 -15
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6/quapp_common.egg-info}/PKG-INFO +59 -7
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common.egg-info/SOURCES.txt +2 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common.egg-info/requires.txt +4 -6
- quapp_common-0.0.14.dev6/tests/test_circuit_adapter.py +174 -0
- quapp_common-0.0.14.dev6/tests/test_no_sdk_dependency.py +142 -0
- quapp_common-0.0.14.dev6/tests/test_phase_coverage.py +196 -0
- quapp_common-0.0.14.dev4/tests/test_circuit_adapter.py +0 -120
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/LICENSE +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/__init__.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/async_tasks/__init__.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/async_tasks/async_invocation_task.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/async_tasks/async_task.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/async_tasks/export_circuit_task.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/component/__init__.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/component/backend/__init__.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/component/backend/invocation.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/component/backend/job_fetcher.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/component/backend/job_fetching.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/component/backend/job_heartbeat.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/component/backend/job_manager.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/component/bridge.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/component/callback/__init__.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/component/callback/update_job_metadata.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/component/device/__init__.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/component/device/device_selection.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/component/dispatcher.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/component/result_serializer.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/config/__init__.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/config/logging_config.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/config/thread_config.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/data/__init__.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/data/async_task/__init__.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/data/async_task/circuit_export/__init__.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/data/async_task/circuit_export/backend_holder.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/data/async_task/circuit_export/circuit_holder.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/data/backend/__init__.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/data/backend/backend_information.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/data/callback/__init__.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/data/callback/callback_url.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/data/device/__init__.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/data/device/circuit_running_option.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/data/promise/__init__.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/data/promise/post_processing_promise.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/data/promise/promise.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/data/request/__init__.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/data/request/invocation_request.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/data/request/job_fetching_request.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/data/request/request.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/data/response/__init__.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/data/response/authentication.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/data/response/custom_header.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/data/response/error_report.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/data/response/job_response.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/enum/__init__.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/enum/base_enum.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/enum/error_category.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/enum/http_header.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/enum/invocation_step.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/enum/language.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/enum/media_type.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/enum/processing_unit.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/enum/provider_tag.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/enum/runtime_phase.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/enum/sdk.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/enum/status/__init__.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/enum/status/job_status.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/enum/status/status_code.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/enum/token_type.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/factory/__init__.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/factory/device_factory.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/factory/handler_factory.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/factory/provider_factory.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/handler/__init__.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/handler/handler.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/model/__init__.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/model/device/__init__.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/model/device/device.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/model/invocation.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/model/provider/__init__.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/model/provider/provider.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/util/__init__.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/util/error_classifier.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/util/file_utils.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/util/http_utils.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/util/invocation_failure.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/util/json_parser_utils.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/util/response_utils.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common.egg-info/dependency_links.txt +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common.egg-info/top_level.txt +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/setup.cfg +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/tests/test_dispatcher_runner_error.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/tests/test_error_classifier.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/tests/test_error_log_dedupe.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/tests/test_error_report.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/tests/test_invocation_failure.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/tests/test_job_heartbeat.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/tests/test_json_parser_utils.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/tests/test_language_dispatcher.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/tests/test_log_secret_leak.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/tests/test_logging_config.py +0 -0
- {quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/tests/test_result_serializer.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: quapp-common
|
|
3
|
-
Version: 0.0.14.
|
|
3
|
+
Version: 0.0.14.dev6
|
|
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,18 +25,15 @@ 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
|
|
30
|
-
Requires-Dist: qulacs
|
|
31
|
-
Requires-Dist: qiskit
|
|
32
|
-
Requires-Dist: pytket
|
|
33
|
-
Requires-Dist: pennylane
|
|
34
28
|
Provides-Extra: dev
|
|
35
29
|
Requires-Dist: black; extra == "dev"
|
|
36
30
|
Requires-Dist: bumpver; extra == "dev"
|
|
37
31
|
Requires-Dist: isort; extra == "dev"
|
|
38
32
|
Requires-Dist: pip-tools; extra == "dev"
|
|
39
33
|
Requires-Dist: pytest; extra == "dev"
|
|
34
|
+
Provides-Extra: test
|
|
35
|
+
Requires-Dist: pytest; extra == "test"
|
|
36
|
+
Requires-Dist: qiskit; extra == "test"
|
|
40
37
|
Dynamic: license-file
|
|
41
38
|
|
|
42
39
|
# quapp-common
|
|
@@ -114,6 +111,61 @@ Notes:
|
|
|
114
111
|
|
|
115
112
|
## Recently Changes Highlights
|
|
116
113
|
|
|
114
|
+
### v0.0.14.dev5 — Gỡ toàn bộ dependency SDK lượng tử
|
|
115
|
+
|
|
116
|
+
`quapp-common` không còn phụ thuộc SDK nào. SDK thuộc về lib con.
|
|
117
|
+
|
|
118
|
+
**Gỡ khỏi `dependencies`** — 6 package, chỉ được dùng trong `circuit_adapter.py`:
|
|
119
|
+
`qiskit`, `pennylane`, `qibo`, `qulacs`, `dimod`, `pytket`.
|
|
120
|
+
|
|
121
|
+
Còn lại: `loguru`, `requests`, `numpy`, `matplotlib`, `pylatexenc`, `starlette`
|
|
122
|
+
— đều được chính code của `quapp-common` dùng (`matplotlib`/`pylatexenc` cần cho
|
|
123
|
+
`CircuitExportTask.__convert()`, nơi gọi `circuit.draw(output='mpl')` rồi
|
|
124
|
+
`savefig()`).
|
|
125
|
+
|
|
126
|
+
**`circuit_adapter.py`: import SDK lazy.** Mỗi handler tự import SDK của nó ngay
|
|
127
|
+
trước khi dùng, qua helper `_require()`. Trước đây 7 SDK được import ở module
|
|
128
|
+
level, nên:
|
|
129
|
+
|
|
130
|
+
- `from quapp_common.component.bridge import SubprocessBridge` đòi có **đủ cả 6
|
|
131
|
+
SDK cùng lúc**, kể cả khi function chỉ chạy Qiskit. Điều này vô hiệu hoá thiết
|
|
132
|
+
kế lazy-import của `js-*/index.py` trong `quapp-sdk-templates` — comment trong
|
|
133
|
+
đó ghi rõ ý định *"so the server can start even if optional dependencies are
|
|
134
|
+
missing"*;
|
|
135
|
+
- buộc mọi function image tải cả 6 SDK, và cài chung chúng gây xung đột version
|
|
136
|
+
thật (`pytket`/`lark`, `pennylane-rigetti`/`pyquil` — xem
|
|
137
|
+
`revert/pennylane-to-0.0.4.dev6` trong `qapp-pennylane`).
|
|
138
|
+
|
|
139
|
+
`_require()` raise `ModuleNotFoundError` với thông điệp nêu tên package cần thêm
|
|
140
|
+
vào `requirements.txt`. Classifier map nó thành `DEPENDENCY_MISSING` nên user
|
|
141
|
+
nhận được hướng dẫn cụ thể thay vì traceback import.
|
|
142
|
+
|
|
143
|
+
**`tests/test_circuit_adapter.py`**: SDK được import trong từng test qua
|
|
144
|
+
`pytest.importorskip`. Trước đây file này import `qiskit` + `qibo` + `qulacs` ở
|
|
145
|
+
module level nên **cả file không collect được** nếu thiếu một SDK. Test
|
|
146
|
+
`test_qulacs_falls_back_to_string_on_parse_error` đổi target patch từ
|
|
147
|
+
`circuit_adapter.QiskitCircuit` (tên module-level đã bỏ) sang `_load_qasm_circuit`.
|
|
148
|
+
|
|
149
|
+
**`tests/test_no_sdk_dependency.py`** (mới) — khoá hồi quy bằng AST: quét từng
|
|
150
|
+
file, fail nếu có SDK nào được import ở module level; và đọc `pyproject.toml`,
|
|
151
|
+
fail nếu `dependencies` khai báo SDK.
|
|
152
|
+
|
|
153
|
+
Đã verify trong **venv sạch không có SDK nào**: 82/82 module import được, suite
|
|
154
|
+
300 passed / 7 skipped. Với venv chỉ có `qiskit`: 302 passed / 5 skipped.
|
|
155
|
+
|
|
156
|
+
> **Lib con cần bổ sung khai báo.** Hai lib đang dựa vào `quapp-common` kéo hộ và
|
|
157
|
+
> sẽ vỡ đường OpenQASM sau bản này:
|
|
158
|
+
> - `qapp-pyquil` — thiếu `pytket` (cần cho `_openqasm_to_pyquil`);
|
|
159
|
+
> - `quapp-qulacs` — thiếu `qiskit` (cầu nối OpenQASM → Qulacs đi qua Qiskit).
|
|
160
|
+
>
|
|
161
|
+
> Ngoài ra `qapp-dwave-ocean` import `matplotlib` trực tiếp nhưng không khai báo;
|
|
162
|
+
> hiện vẫn chạy vì `quapp-common` còn giữ `matplotlib`, nên nên khai báo tường
|
|
163
|
+
> minh để không phụ thuộc may mắn.
|
|
164
|
+
>
|
|
165
|
+
> `pytket-braket` và `pytket-pyquil` chưa từng được khai báo ở đâu — code dùng
|
|
166
|
+
> `importlib.import_module()` cho chúng từ trước. Cần thêm vào `qapp-braket` và
|
|
167
|
+
> `qapp-pyquil`.
|
|
168
|
+
|
|
117
169
|
### v0.0.14.dev2 — Fix: log lỗi bị nhân đôi
|
|
118
170
|
|
|
119
171
|
- **Fix**: mỗi lần lỗi phát **hai** dòng ERROR cùng `event=job_failed`, mỗi dòng
|
|
@@ -73,6 +73,61 @@ Notes:
|
|
|
73
73
|
|
|
74
74
|
## Recently Changes Highlights
|
|
75
75
|
|
|
76
|
+
### v0.0.14.dev5 — Gỡ toàn bộ dependency SDK lượng tử
|
|
77
|
+
|
|
78
|
+
`quapp-common` không còn phụ thuộc SDK nào. SDK thuộc về lib con.
|
|
79
|
+
|
|
80
|
+
**Gỡ khỏi `dependencies`** — 6 package, chỉ được dùng trong `circuit_adapter.py`:
|
|
81
|
+
`qiskit`, `pennylane`, `qibo`, `qulacs`, `dimod`, `pytket`.
|
|
82
|
+
|
|
83
|
+
Còn lại: `loguru`, `requests`, `numpy`, `matplotlib`, `pylatexenc`, `starlette`
|
|
84
|
+
— đều được chính code của `quapp-common` dùng (`matplotlib`/`pylatexenc` cần cho
|
|
85
|
+
`CircuitExportTask.__convert()`, nơi gọi `circuit.draw(output='mpl')` rồi
|
|
86
|
+
`savefig()`).
|
|
87
|
+
|
|
88
|
+
**`circuit_adapter.py`: import SDK lazy.** Mỗi handler tự import SDK của nó ngay
|
|
89
|
+
trước khi dùng, qua helper `_require()`. Trước đây 7 SDK được import ở module
|
|
90
|
+
level, nên:
|
|
91
|
+
|
|
92
|
+
- `from quapp_common.component.bridge import SubprocessBridge` đòi có **đủ cả 6
|
|
93
|
+
SDK cùng lúc**, kể cả khi function chỉ chạy Qiskit. Điều này vô hiệu hoá thiết
|
|
94
|
+
kế lazy-import của `js-*/index.py` trong `quapp-sdk-templates` — comment trong
|
|
95
|
+
đó ghi rõ ý định *"so the server can start even if optional dependencies are
|
|
96
|
+
missing"*;
|
|
97
|
+
- buộc mọi function image tải cả 6 SDK, và cài chung chúng gây xung đột version
|
|
98
|
+
thật (`pytket`/`lark`, `pennylane-rigetti`/`pyquil` — xem
|
|
99
|
+
`revert/pennylane-to-0.0.4.dev6` trong `qapp-pennylane`).
|
|
100
|
+
|
|
101
|
+
`_require()` raise `ModuleNotFoundError` với thông điệp nêu tên package cần thêm
|
|
102
|
+
vào `requirements.txt`. Classifier map nó thành `DEPENDENCY_MISSING` nên user
|
|
103
|
+
nhận được hướng dẫn cụ thể thay vì traceback import.
|
|
104
|
+
|
|
105
|
+
**`tests/test_circuit_adapter.py`**: SDK được import trong từng test qua
|
|
106
|
+
`pytest.importorskip`. Trước đây file này import `qiskit` + `qibo` + `qulacs` ở
|
|
107
|
+
module level nên **cả file không collect được** nếu thiếu một SDK. Test
|
|
108
|
+
`test_qulacs_falls_back_to_string_on_parse_error` đổi target patch từ
|
|
109
|
+
`circuit_adapter.QiskitCircuit` (tên module-level đã bỏ) sang `_load_qasm_circuit`.
|
|
110
|
+
|
|
111
|
+
**`tests/test_no_sdk_dependency.py`** (mới) — khoá hồi quy bằng AST: quét từng
|
|
112
|
+
file, fail nếu có SDK nào được import ở module level; và đọc `pyproject.toml`,
|
|
113
|
+
fail nếu `dependencies` khai báo SDK.
|
|
114
|
+
|
|
115
|
+
Đã verify trong **venv sạch không có SDK nào**: 82/82 module import được, suite
|
|
116
|
+
300 passed / 7 skipped. Với venv chỉ có `qiskit`: 302 passed / 5 skipped.
|
|
117
|
+
|
|
118
|
+
> **Lib con cần bổ sung khai báo.** Hai lib đang dựa vào `quapp-common` kéo hộ và
|
|
119
|
+
> sẽ vỡ đường OpenQASM sau bản này:
|
|
120
|
+
> - `qapp-pyquil` — thiếu `pytket` (cần cho `_openqasm_to_pyquil`);
|
|
121
|
+
> - `quapp-qulacs` — thiếu `qiskit` (cầu nối OpenQASM → Qulacs đi qua Qiskit).
|
|
122
|
+
>
|
|
123
|
+
> Ngoài ra `qapp-dwave-ocean` import `matplotlib` trực tiếp nhưng không khai báo;
|
|
124
|
+
> hiện vẫn chạy vì `quapp-common` còn giữ `matplotlib`, nên nên khai báo tường
|
|
125
|
+
> minh để không phụ thuộc may mắn.
|
|
126
|
+
>
|
|
127
|
+
> `pytket-braket` và `pytket-pyquil` chưa từng được khai báo ở đâu — code dùng
|
|
128
|
+
> `importlib.import_module()` cho chúng từ trước. Cần thêm vào `qapp-braket` và
|
|
129
|
+
> `qapp-pyquil`.
|
|
130
|
+
|
|
76
131
|
### v0.0.14.dev2 — Fix: log lỗi bị nhân đôi
|
|
77
132
|
|
|
78
133
|
- **Fix**: mỗi lần lỗi phát **hai** dòng ERROR cùng `event=job_failed`, mỗi dòng
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "quapp-common"
|
|
7
|
-
version = "0.0.14.
|
|
7
|
+
version = "0.0.14.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" }]
|
|
@@ -15,24 +15,29 @@ classifiers = [
|
|
|
15
15
|
"Programming Language :: Python :: 3",
|
|
16
16
|
]
|
|
17
17
|
keywords = ["quapp", "quapp-common", "quantum"]
|
|
18
|
+
# KHÔNG khai báo SDK lượng tử ở đây. Mỗi lib con (quapp-qiskit, qapp-pennylane,
|
|
19
|
+
# qapp-braket, ...) tự khai báo SDK của nó, và một function image chỉ cài đúng
|
|
20
|
+
# SDK nó dùng. circuit_adapter.py import SDK lazy nên quapp-common không cần
|
|
21
|
+
# chúng để import được.
|
|
22
|
+
#
|
|
23
|
+
# Lý do: cài chung qiskit + pennylane + qibo + qulacs + dimod + pytket gây xung
|
|
24
|
+
# đột version thật (pytket/lark, pennylane-rigetti/pyquil), và bắt mọi function
|
|
25
|
+
# tải cả 6 SDK dù chỉ dùng một.
|
|
18
26
|
dependencies = [
|
|
19
27
|
"loguru",
|
|
20
28
|
"requests",
|
|
21
29
|
"numpy",
|
|
22
30
|
"matplotlib",
|
|
23
31
|
"pylatexenc",
|
|
24
|
-
"starlette"
|
|
25
|
-
"qibo",
|
|
26
|
-
"dimod",
|
|
27
|
-
"qulacs",
|
|
28
|
-
"qiskit",
|
|
29
|
-
"pytket",
|
|
30
|
-
"pennylane"
|
|
32
|
+
"starlette"
|
|
31
33
|
]
|
|
32
34
|
requires-python = ">=3.7"
|
|
33
35
|
|
|
34
36
|
[project.optional-dependencies]
|
|
35
37
|
dev = ["black", "bumpver", "isort", "pip-tools", "pytest"]
|
|
38
|
+
# SDK chỉ để chạy test của chính quapp-common (tests/test_circuit_adapter.py
|
|
39
|
+
# cần qiskit). KHÔNG phải runtime dependency.
|
|
40
|
+
test = ["pytest", "qiskit"]
|
|
36
41
|
|
|
37
42
|
[project.urls]
|
|
38
43
|
Homepage = "https://citynow.asia/"
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
from .async_task import AsyncTask
|
|
5
5
|
from ..config.logging_config import job_logger
|
|
6
6
|
from ..data.promise.post_processing_promise import PostProcessingPromise
|
|
7
|
+
from ..config.log_context import phase
|
|
7
8
|
from ..enum.media_type import MediaType
|
|
8
9
|
from ..enum.runtime_phase import RuntimePhase
|
|
9
10
|
from ..util.http_utils import get_job_id_from_url
|
|
@@ -32,15 +33,19 @@ class PostProcessingTask(AsyncTask):
|
|
|
32
33
|
job_response.content_type = MediaType.APPLICATION_JSON
|
|
33
34
|
|
|
34
35
|
try:
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
36
|
+
# RuntimePhase.POST_PROCESSING duoc dinh nghia nhung truoc day khong
|
|
37
|
+
# noi nao dung, nen code user chay trong post_processing_fn khong he
|
|
38
|
+
# co phase trong log lan trong ErrorReport.
|
|
39
|
+
with phase(RuntimePhase.POST_PROCESSING):
|
|
40
|
+
self.logger.info("Execute post_processing ...")
|
|
41
|
+
job_result_post_processing = self.post_processing_fn(
|
|
42
|
+
self.promise.job_result)
|
|
43
|
+
|
|
44
|
+
# print() cũ ghi thẳng ra stdout, không qua sink nên không được
|
|
45
|
+
# redact và không có job_id.
|
|
46
|
+
self.logger.debug(
|
|
47
|
+
f"Parsing job result: type={type(job_result_post_processing).__name__}")
|
|
48
|
+
job_response.job_result = parse(job_result_post_processing)
|
|
44
49
|
|
|
45
50
|
update_job_metadata(job_response, self.promise.callback_url.on_done)
|
|
46
51
|
|
{quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/component/circuit_adapter.py
RENAMED
|
@@ -2,38 +2,73 @@
|
|
|
2
2
|
# circuit_adapter.py
|
|
3
3
|
# Copyright © CITYNOW Co. Ltd. All rights reserved.
|
|
4
4
|
|
|
5
|
+
"""Chuyển circuit từ định dạng trung gian (OpenQASM / QUBO / JSON) sang object
|
|
6
|
+
native của từng SDK.
|
|
7
|
+
|
|
8
|
+
Mọi SDK được import LAZY, ngay bên trong handler cần nó. Lý do:
|
|
9
|
+
|
|
10
|
+
``quapp-common`` không được phụ thuộc SDK nào. Mỗi lib con
|
|
11
|
+
(``quapp-qiskit``, ``qapp-pennylane``, ...) tự khai báo SDK của nó, và một
|
|
12
|
+
function image chỉ cài đúng SDK nó dùng. Nếu file này import ở module level thì:
|
|
13
|
+
|
|
14
|
+
- ``import quapp_common.component.bridge`` đòi có ĐỦ 6 SDK cùng lúc, kể cả khi
|
|
15
|
+
function chỉ chạy Qiskit -- điều này vô hiệu hoá thiết kế lazy-import của
|
|
16
|
+
``js-*/index.py`` trong quapp-sdk-templates (comment trong đó ghi rõ ý định
|
|
17
|
+
"so the server can start even if optional dependencies are missing");
|
|
18
|
+
- cài chung 6 SDK gây xung đột version thật, đã xảy ra với ``pytket``/``lark``
|
|
19
|
+
và ``pennylane-rigetti``/``pyquil``.
|
|
20
|
+
|
|
21
|
+
Khi SDK thiếu, handler raise ``ModuleNotFoundError`` -- classifier map thành
|
|
22
|
+
``DEPENDENCY_MISSING`` và user nhận được hướng dẫn thêm package vào
|
|
23
|
+
requirements.txt.
|
|
24
|
+
"""
|
|
25
|
+
|
|
5
26
|
import importlib
|
|
6
27
|
import re
|
|
7
28
|
from typing import Any, Dict
|
|
8
29
|
|
|
9
|
-
import numpy as np
|
|
10
|
-
import pennylane as qml
|
|
11
|
-
import pennylane.measurements as _plm
|
|
12
|
-
try:
|
|
13
|
-
import qiskit.qasm2 as _qasm2
|
|
14
|
-
except ImportError:
|
|
15
|
-
_qasm2 = None
|
|
16
|
-
from dimod import BinaryQuadraticModel
|
|
17
|
-
from pytket.qasm import circuit_from_qasm_str
|
|
18
|
-
from qibo.models import Circuit
|
|
19
|
-
from qiskit import QuantumCircuit as QiskitCircuit
|
|
20
|
-
from qulacs import QuantumCircuit as QulacsCircuit
|
|
21
|
-
from qulacs.gate import DenseMatrix as DenseMatrixGate
|
|
22
|
-
|
|
23
30
|
from ..config.logging_config import logger
|
|
24
31
|
from ..enum.sdk import Sdk
|
|
25
32
|
|
|
26
33
|
logger = logger.bind(context=__name__)
|
|
27
34
|
|
|
28
35
|
|
|
29
|
-
def
|
|
30
|
-
"""
|
|
36
|
+
def _require(module_name: str, package_hint: str = None):
|
|
37
|
+
"""Import module của SDK, báo lỗi rõ ràng nếu thiếu.
|
|
38
|
+
|
|
39
|
+
@param module_name: tên module cần import, ví dụ 'qiskit.qasm2'.
|
|
40
|
+
@param package_hint: tên package trên PyPI để nhắc user, nếu khác module.
|
|
41
|
+
@raise ModuleNotFoundError: giữ đúng kiểu này để classifier phân loại thành
|
|
42
|
+
DEPENDENCY_MISSING.
|
|
43
|
+
"""
|
|
44
|
+
try:
|
|
45
|
+
return importlib.import_module(module_name)
|
|
46
|
+
except ImportError as exception:
|
|
47
|
+
package = package_hint or module_name.split('.')[0]
|
|
48
|
+
raise ModuleNotFoundError(
|
|
49
|
+
f"SDK '{package}' chưa được cài trong function image nhưng "
|
|
50
|
+
f"circuit cần nó. Thêm '{package}' vào requirements.txt của "
|
|
51
|
+
f"function rồi deploy lại.") from exception
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _qiskit_quantum_circuit():
|
|
55
|
+
return _require('qiskit').QuantumCircuit
|
|
56
|
+
|
|
31
57
|
|
|
32
|
-
|
|
58
|
+
def _load_qasm_circuit(qasm_str: str):
|
|
59
|
+
"""Parse OpenQASM 2.0 string thành Qiskit QuantumCircuit.
|
|
60
|
+
|
|
61
|
+
Tương thích Qiskit >= 1.0 (``qiskit.qasm2.loads``) và < 1.0
|
|
62
|
+
(``QuantumCircuit.from_qasm_str``).
|
|
33
63
|
"""
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
64
|
+
try:
|
|
65
|
+
qasm2 = importlib.import_module('qiskit.qasm2')
|
|
66
|
+
except ImportError:
|
|
67
|
+
qasm2 = None
|
|
68
|
+
|
|
69
|
+
if qasm2 is not None:
|
|
70
|
+
return qasm2.loads(qasm_str)
|
|
71
|
+
return _qiskit_quantum_circuit().from_qasm_str(qasm_str)
|
|
37
72
|
|
|
38
73
|
|
|
39
74
|
def adapt(sdk: Sdk, result: dict):
|
|
@@ -91,7 +126,8 @@ def _adapt_qubo(sdk, qubo_raw: Dict[str, Any]):
|
|
|
91
126
|
qubo_dict[(key, key)] = val
|
|
92
127
|
|
|
93
128
|
logger.debug(f"QUBO parsed: {len(qubo_dict)} entries -> BinaryQuadraticModel")
|
|
94
|
-
|
|
129
|
+
binary_quadratic_model = _require('dimod').BinaryQuadraticModel
|
|
130
|
+
return binary_quadratic_model.from_qubo(qubo_dict)
|
|
95
131
|
|
|
96
132
|
|
|
97
133
|
def _count_qasm_qubits(qasm_str):
|
|
@@ -101,7 +137,9 @@ def _count_qasm_qubits(qasm_str):
|
|
|
101
137
|
|
|
102
138
|
def _openqasm_to_braket(qasm_str):
|
|
103
139
|
logger.debug("Converting OpenQASM via pytket -> tk_to_braket")
|
|
104
|
-
|
|
140
|
+
circuit_from_qasm_str = _require('pytket.qasm', 'pytket').circuit_from_qasm_str
|
|
141
|
+
tk_to_braket = _require('pytket.extensions.braket',
|
|
142
|
+
'pytket-braket').tk_to_braket
|
|
105
143
|
result = tk_to_braket(circuit_from_qasm_str(qasm_str))
|
|
106
144
|
# tk_to_braket returns (Circuit, n_shots) in pytket-braket >= 0.35
|
|
107
145
|
is_tuple = isinstance(result, tuple)
|
|
@@ -122,10 +160,13 @@ def _openqasm_to_cuda_quantum(qasm_str):
|
|
|
122
160
|
|
|
123
161
|
def _openqasm_to_pennylane(qasm_str):
|
|
124
162
|
logger.debug("Converting OpenQASM via PennyLane qml.from_qasm wrapper")
|
|
163
|
+
qml = _require('pennylane')
|
|
164
|
+
measurements = _require('pennylane.measurements', 'pennylane')
|
|
165
|
+
|
|
125
166
|
for _compat_name in ("Expectation", "Variance", "Sample", "Probability",
|
|
126
167
|
"State", "MidMeasure"):
|
|
127
|
-
if not hasattr(
|
|
128
|
-
setattr(
|
|
168
|
+
if not hasattr(measurements, _compat_name):
|
|
169
|
+
setattr(measurements, _compat_name, _compat_name)
|
|
129
170
|
|
|
130
171
|
num_wires = _count_qasm_qubits(qasm_str)
|
|
131
172
|
logger.debug(f"PennyLane: detected {num_wires} qubits; wrapping with qml.probs over all wires")
|
|
@@ -150,13 +191,15 @@ def _openqasm_to_pennylane(qasm_str):
|
|
|
150
191
|
|
|
151
192
|
def _openqasm_to_pyquil(qasm_str):
|
|
152
193
|
logger.debug("Converting OpenQASM via pytket -> tk_to_pyquil")
|
|
153
|
-
|
|
194
|
+
circuit_from_qasm_str = _require('pytket.qasm', 'pytket').circuit_from_qasm_str
|
|
195
|
+
tk_to_pyquil = _require('pytket.extensions.pyquil',
|
|
196
|
+
'pytket-pyquil').tk_to_pyquil
|
|
154
197
|
return tk_to_pyquil(circuit_from_qasm_str(qasm_str))
|
|
155
198
|
|
|
156
199
|
|
|
157
200
|
def _openqasm_to_qibo(qasm_str):
|
|
158
201
|
logger.debug("Converting OpenQASM via Qibo Circuit.from_qasm")
|
|
159
|
-
return Circuit.from_qasm(qasm_str)
|
|
202
|
+
return _require('qibo.models', 'qibo').Circuit.from_qasm(qasm_str)
|
|
160
203
|
|
|
161
204
|
|
|
162
205
|
def _openqasm_to_qiskit(qasm_str):
|
|
@@ -184,6 +227,9 @@ def _qiskit_to_pennylane(qasm_str, num_wires):
|
|
|
184
227
|
Fallback for environments where qml.from_qasm is unavailable because
|
|
185
228
|
pennylane-qiskit is not installed (PennyLane < 0.36).
|
|
186
229
|
"""
|
|
230
|
+
qml = _require('pennylane')
|
|
231
|
+
numpy = _require('numpy')
|
|
232
|
+
|
|
187
233
|
qiskit_circ = _load_qasm_circuit(qasm_str)
|
|
188
234
|
qubit_map = {bit: idx for idx, bit in enumerate(qiskit_circ.qubits)}
|
|
189
235
|
logger.debug(
|
|
@@ -205,9 +251,9 @@ def _qiskit_to_pennylane(qasm_str, num_wires):
|
|
|
205
251
|
'y': lambda q, p: qml.PauliY(wires=q[0]),
|
|
206
252
|
'z': lambda q, p: qml.PauliZ(wires=q[0]),
|
|
207
253
|
's': lambda q, p: qml.S(wires=q[0]),
|
|
208
|
-
'sdg': lambda q, p: qml.PhaseShift(-
|
|
254
|
+
'sdg': lambda q, p: qml.PhaseShift(-numpy.pi / 2, wires=q[0]),
|
|
209
255
|
't': lambda q, p: qml.T(wires=q[0]),
|
|
210
|
-
'tdg': lambda q, p: qml.PhaseShift(-
|
|
256
|
+
'tdg': lambda q, p: qml.PhaseShift(-numpy.pi / 4, wires=q[0]),
|
|
211
257
|
'cx': lambda q, p: qml.CNOT(wires=q),
|
|
212
258
|
'cz': lambda q, p: qml.CZ(wires=q),
|
|
213
259
|
'swap': lambda q, p: qml.SWAP(wires=q),
|
|
@@ -244,9 +290,12 @@ def _qiskit_to_qulacs(qiskit_circ):
|
|
|
244
290
|
unrecognized gates fall back to DenseMatrix (unitary passthrough).
|
|
245
291
|
Measurement, barrier, reset, and identity instructions are skipped.
|
|
246
292
|
"""
|
|
293
|
+
qulacs_quantum_circuit = _require('qulacs').QuantumCircuit
|
|
294
|
+
dense_matrix_gate = _require('qulacs.gate', 'qulacs').DenseMatrix
|
|
295
|
+
|
|
247
296
|
n = qiskit_circ.num_qubits
|
|
248
297
|
logger.debug(f"_qiskit_to_qulacs: num_qubits={n} num_instructions={len(qiskit_circ.data)}")
|
|
249
|
-
qulacs_circ =
|
|
298
|
+
qulacs_circ = qulacs_quantum_circuit(n)
|
|
250
299
|
qubit_map = {bit: idx for idx, bit in enumerate(qiskit_circ.qubits)}
|
|
251
300
|
|
|
252
301
|
_SINGLE = {
|
|
@@ -280,7 +329,7 @@ def _qiskit_to_qulacs(qiskit_circ):
|
|
|
280
329
|
# ambiguity; multi-qubit gates are passed with qulacs'
|
|
281
330
|
# index order matching Qiskit's instruction qubit order.
|
|
282
331
|
logger.debug(f"Gate '{name}' not in named map; converting via DenseMatrix on qubits={qubits}")
|
|
283
|
-
qulacs_circ.add_gate(
|
|
332
|
+
qulacs_circ.add_gate(dense_matrix_gate(qubits, gate.to_matrix()))
|
|
284
333
|
|
|
285
334
|
logger.debug(f"_qiskit_to_qulacs: conversion complete")
|
|
286
335
|
return qulacs_circ
|
|
@@ -69,8 +69,16 @@ def bind_job(job_id: str = None, *, sdk=None, provider=None, device=None,
|
|
|
69
69
|
@param trace_id: tự sinh nếu không truyền; dùng để join Function Log <-> Job Log
|
|
70
70
|
@return: logger đã bind toàn bộ context
|
|
71
71
|
"""
|
|
72
|
+
# Một job bị bind hai lần (AsyncInvocationTask rồi Handler.__init__), trước
|
|
73
|
+
# đây mỗi lần sinh một trace_id mới nên cùng một job có hai traceId khác
|
|
74
|
+
# nhau và filter theo traceId mất các dòng ở cửa vào. Giữ lại trace đang có
|
|
75
|
+
# khi vẫn là job đó; job khác thì phải sinh trace mới, không được trộn.
|
|
76
|
+
current = _JOB_CONTEXT.get()
|
|
77
|
+
inherited = (current.get(TRACE_ID)
|
|
78
|
+
if current.get(JOB_ID) in (None, job_id) else None)
|
|
79
|
+
|
|
72
80
|
context = {JOB_ID : job_id,
|
|
73
|
-
TRACE_ID : trace_id or uuid.uuid4().hex[:16],
|
|
81
|
+
TRACE_ID : trace_id or inherited or uuid.uuid4().hex[:16],
|
|
74
82
|
'sdk' : sdk,
|
|
75
83
|
'provider' : provider,
|
|
76
84
|
'device' : device,
|
{quapp_common-0.0.14.dev4 → quapp_common-0.0.14.dev6}/quapp_common/model/device/custom_device.py
RENAMED
|
@@ -8,6 +8,7 @@ from ...component.callback.update_job_metadata import update_job_metadata
|
|
|
8
8
|
from ...data.callback.callback_url import CallbackUrl
|
|
9
9
|
from ...data.response.job_response import JobResponse
|
|
10
10
|
from ...enum.runtime_phase import RuntimePhase
|
|
11
|
+
from ...config.log_context import phase
|
|
11
12
|
from ...model.device.device import Device
|
|
12
13
|
from ...model.provider.provider import Provider
|
|
13
14
|
from ...util.response_utils import build_error_job_response
|
|
@@ -34,21 +35,28 @@ class CustomDevice(Device, ABC):
|
|
|
34
35
|
update_job_metadata(job_response, analysis_callback.on_start)
|
|
35
36
|
|
|
36
37
|
try:
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
38
|
+
# Device._on_analysis co `with phase(...)`, ban override nay khong --
|
|
39
|
+
# va day moi la ban thuc su chay: QiskitDevice, OqcCloudDevice...
|
|
40
|
+
# deu ke thua CustomDevice. Thieu no thi log cua analysis khong co
|
|
41
|
+
# field `phase`, Grafana khong loc duoc va ErrorReport cua loi trong
|
|
42
|
+
# analysis ra phase=None.
|
|
43
|
+
with phase(RuntimePhase.ANALYSIS):
|
|
44
|
+
self.logger.debug(
|
|
45
|
+
"Producing histogram data from original job result")
|
|
46
|
+
|
|
47
|
+
job_response.job_histogram = self._produce_histogram_data(
|
|
48
|
+
original_job_result)
|
|
49
|
+
|
|
50
|
+
self.logger.debug("Parsing original job result")
|
|
51
|
+
original_job_result_dict = parse(original_job_result)
|
|
52
|
+
|
|
53
|
+
self.logger.debug(
|
|
54
|
+
"Calculating execution time from parsed results")
|
|
55
|
+
self._calculate_execution_time(original_job_result_dict)
|
|
56
|
+
job_response.execution_time = self.execution_time
|
|
57
|
+
|
|
58
|
+
self.logger.debug("Retrieving shot count from job result")
|
|
59
|
+
job_response.shots = self._get_shots(original_job_result)
|
|
52
60
|
|
|
53
61
|
update_job_metadata(job_response, analysis_callback.on_done)
|
|
54
62
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: quapp-common
|
|
3
|
-
Version: 0.0.14.
|
|
3
|
+
Version: 0.0.14.dev6
|
|
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,18 +25,15 @@ 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
|
|
30
|
-
Requires-Dist: qulacs
|
|
31
|
-
Requires-Dist: qiskit
|
|
32
|
-
Requires-Dist: pytket
|
|
33
|
-
Requires-Dist: pennylane
|
|
34
28
|
Provides-Extra: dev
|
|
35
29
|
Requires-Dist: black; extra == "dev"
|
|
36
30
|
Requires-Dist: bumpver; extra == "dev"
|
|
37
31
|
Requires-Dist: isort; extra == "dev"
|
|
38
32
|
Requires-Dist: pip-tools; extra == "dev"
|
|
39
33
|
Requires-Dist: pytest; extra == "dev"
|
|
34
|
+
Provides-Extra: test
|
|
35
|
+
Requires-Dist: pytest; extra == "test"
|
|
36
|
+
Requires-Dist: qiskit; extra == "test"
|
|
40
37
|
Dynamic: license-file
|
|
41
38
|
|
|
42
39
|
# quapp-common
|
|
@@ -114,6 +111,61 @@ Notes:
|
|
|
114
111
|
|
|
115
112
|
## Recently Changes Highlights
|
|
116
113
|
|
|
114
|
+
### v0.0.14.dev5 — Gỡ toàn bộ dependency SDK lượng tử
|
|
115
|
+
|
|
116
|
+
`quapp-common` không còn phụ thuộc SDK nào. SDK thuộc về lib con.
|
|
117
|
+
|
|
118
|
+
**Gỡ khỏi `dependencies`** — 6 package, chỉ được dùng trong `circuit_adapter.py`:
|
|
119
|
+
`qiskit`, `pennylane`, `qibo`, `qulacs`, `dimod`, `pytket`.
|
|
120
|
+
|
|
121
|
+
Còn lại: `loguru`, `requests`, `numpy`, `matplotlib`, `pylatexenc`, `starlette`
|
|
122
|
+
— đều được chính code của `quapp-common` dùng (`matplotlib`/`pylatexenc` cần cho
|
|
123
|
+
`CircuitExportTask.__convert()`, nơi gọi `circuit.draw(output='mpl')` rồi
|
|
124
|
+
`savefig()`).
|
|
125
|
+
|
|
126
|
+
**`circuit_adapter.py`: import SDK lazy.** Mỗi handler tự import SDK của nó ngay
|
|
127
|
+
trước khi dùng, qua helper `_require()`. Trước đây 7 SDK được import ở module
|
|
128
|
+
level, nên:
|
|
129
|
+
|
|
130
|
+
- `from quapp_common.component.bridge import SubprocessBridge` đòi có **đủ cả 6
|
|
131
|
+
SDK cùng lúc**, kể cả khi function chỉ chạy Qiskit. Điều này vô hiệu hoá thiết
|
|
132
|
+
kế lazy-import của `js-*/index.py` trong `quapp-sdk-templates` — comment trong
|
|
133
|
+
đó ghi rõ ý định *"so the server can start even if optional dependencies are
|
|
134
|
+
missing"*;
|
|
135
|
+
- buộc mọi function image tải cả 6 SDK, và cài chung chúng gây xung đột version
|
|
136
|
+
thật (`pytket`/`lark`, `pennylane-rigetti`/`pyquil` — xem
|
|
137
|
+
`revert/pennylane-to-0.0.4.dev6` trong `qapp-pennylane`).
|
|
138
|
+
|
|
139
|
+
`_require()` raise `ModuleNotFoundError` với thông điệp nêu tên package cần thêm
|
|
140
|
+
vào `requirements.txt`. Classifier map nó thành `DEPENDENCY_MISSING` nên user
|
|
141
|
+
nhận được hướng dẫn cụ thể thay vì traceback import.
|
|
142
|
+
|
|
143
|
+
**`tests/test_circuit_adapter.py`**: SDK được import trong từng test qua
|
|
144
|
+
`pytest.importorskip`. Trước đây file này import `qiskit` + `qibo` + `qulacs` ở
|
|
145
|
+
module level nên **cả file không collect được** nếu thiếu một SDK. Test
|
|
146
|
+
`test_qulacs_falls_back_to_string_on_parse_error` đổi target patch từ
|
|
147
|
+
`circuit_adapter.QiskitCircuit` (tên module-level đã bỏ) sang `_load_qasm_circuit`.
|
|
148
|
+
|
|
149
|
+
**`tests/test_no_sdk_dependency.py`** (mới) — khoá hồi quy bằng AST: quét từng
|
|
150
|
+
file, fail nếu có SDK nào được import ở module level; và đọc `pyproject.toml`,
|
|
151
|
+
fail nếu `dependencies` khai báo SDK.
|
|
152
|
+
|
|
153
|
+
Đã verify trong **venv sạch không có SDK nào**: 82/82 module import được, suite
|
|
154
|
+
300 passed / 7 skipped. Với venv chỉ có `qiskit`: 302 passed / 5 skipped.
|
|
155
|
+
|
|
156
|
+
> **Lib con cần bổ sung khai báo.** Hai lib đang dựa vào `quapp-common` kéo hộ và
|
|
157
|
+
> sẽ vỡ đường OpenQASM sau bản này:
|
|
158
|
+
> - `qapp-pyquil` — thiếu `pytket` (cần cho `_openqasm_to_pyquil`);
|
|
159
|
+
> - `quapp-qulacs` — thiếu `qiskit` (cầu nối OpenQASM → Qulacs đi qua Qiskit).
|
|
160
|
+
>
|
|
161
|
+
> Ngoài ra `qapp-dwave-ocean` import `matplotlib` trực tiếp nhưng không khai báo;
|
|
162
|
+
> hiện vẫn chạy vì `quapp-common` còn giữ `matplotlib`, nên nên khai báo tường
|
|
163
|
+
> minh để không phụ thuộc may mắn.
|
|
164
|
+
>
|
|
165
|
+
> `pytket-braket` và `pytket-pyquil` chưa từng được khai báo ở đâu — code dùng
|
|
166
|
+
> `importlib.import_module()` cho chúng từ trước. Cần thêm vào `qapp-braket` và
|
|
167
|
+
> `qapp-pyquil`.
|
|
168
|
+
|
|
117
169
|
### v0.0.14.dev2 — Fix: log lỗi bị nhân đôi
|
|
118
170
|
|
|
119
171
|
- **Fix**: mỗi lần lỗi phát **hai** dòng ERROR cùng `event=job_failed`, mỗi dòng
|