qua-libs-core 0.1.0__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.
- qua_libs_core-0.1.0/.gitignore +28 -0
- qua_libs_core-0.1.0/LICENSE +37 -0
- qua_libs_core-0.1.0/PKG-INFO +132 -0
- qua_libs_core-0.1.0/README.md +66 -0
- qua_libs_core-0.1.0/pyproject.toml +71 -0
- qua_libs_core-0.1.0/qua_libs_core/__init__.py +10 -0
- qua_libs_core-0.1.0/qua_libs_core/telemetry/__init__.py +50 -0
- qua_libs_core-0.1.0/qua_libs_core/telemetry/calibration_node.py +157 -0
- qua_libs_core-0.1.0/qua_libs_core/telemetry/config.py +138 -0
- qua_libs_core-0.1.0/qua_libs_core/telemetry/context_managers.py +65 -0
- qua_libs_core-0.1.0/qua_libs_core/telemetry/decorators.py +131 -0
- qua_libs_core-0.1.0/qua_libs_core/telemetry/file_config.py +137 -0
- qua_libs_core-0.1.0/qua_libs_core/telemetry/project_config.py +33 -0
- qua_libs_core-0.1.0/qua_libs_core/telemetry/utils.py +105 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
.eggs/
|
|
6
|
+
|
|
7
|
+
# Build artifacts
|
|
8
|
+
build/
|
|
9
|
+
dist/
|
|
10
|
+
*.whl
|
|
11
|
+
*.tar.gz
|
|
12
|
+
|
|
13
|
+
# Virtual environments / tooling
|
|
14
|
+
.venv/
|
|
15
|
+
.uv/
|
|
16
|
+
uv.lock.*
|
|
17
|
+
graphify-out/
|
|
18
|
+
|
|
19
|
+
# Test / type caches
|
|
20
|
+
.pytest_cache/
|
|
21
|
+
.mypy_cache/
|
|
22
|
+
.ruff_cache/
|
|
23
|
+
|
|
24
|
+
# Editor / OS
|
|
25
|
+
.idea/
|
|
26
|
+
.vscode/
|
|
27
|
+
.DS_Store
|
|
28
|
+
.cursor/
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
|
|
2
|
+
Quantum Machines End User License Agreement for qua-libs-core Software
|
|
3
|
+
|
|
4
|
+
PLEASE READ CAREFULLY THIS END USER LICENSE AGREEMENT (“EULA”) BEFORE INSTALLING, ACCESSING, DOWNLOADING OR OTHERWISE USING THE SOLUTION (AS DEFINED BELOW) (“USER”, “YOU”) BY QM (AS DEFINED BELOW). BY INSTALLING, HAVING INSTALLED, CONTROLLING, ACCESSING, OR OTHERWISE USING THE SOLUTION IN ANY MANNER, YOU ARE ACCEPTING AND AGREEING TO BE BOUND BY THIS EULA AND CONDITIONS HEREOF AND REPRESENTING THAT YOU HAVE FULL RIGHT, POWER, AND AUTHORITY TO ENTER INTO AND PERFORM HEREUNDER. YOU MAY NOT INSTALL, DEPLOY, CONTROL, ACCESS, OR USE THE SOLUTION IN ANY MANNER BEFORE YOU HAVE ACCEPTED THIS EULA. FURTHERMORE, YOU HEREBY WAIVE ANY RIGHTS OR REQUIREMENTS UNDER ANY LAWS OR REGULATIONS IN ANY JURISDICTION THAT REQUIRE AN ORIGINAL (NON-ELECTRONIC) SIGNATURE OR DELIVERY OR RETENTION OF NON-ELECTRONIC RECORDS, TO THE EXTENT PERMITTED UNDER APPLICABLE LAW. THIS EULA MADE BETWEEN YOU AND Q.M TECHNOLOGIES LTD. AND ITS AFFILIATES (AS DEFINED BELOW) (“QM”). WITH RESPECT TO THE SOLUTION YOU ASSUME ALL RESPONSIBILITY FOR THE SELECTION OF THE SOLUTION, FOR YOUR RELIANCE ON THE RESULTS OF THE USE OF THE SOLUTION AND RELATED SERVICES, AND FOR ANY USE OF THE SOLUTION NOT IN ACCORDANCE WITH THE EULA HEREOF OR AS CONTEMPLATED HEREUNDER.
|
|
5
|
+
THE PARTIES AGREE THAT UNLESS EXPRESSLY AND SPECIFICALLY AGREED TO IN WRITING BY QM , NO OTHER “CLICK THROGH”, “CLICK WRAP”, TERMS AND CONDITIONS OR OTHER STANDARD TERMS (INCLUDING WITHOUT LIMITATION CUSTOEMRS’ PURCHASE TERMS INCLUDING AS REFRESED IN A QUOTE, OR ORDER), SHALL HAVE ANY FORCE OR EFFECT WITH RESPECT TO THE SOLUTION, THE USE THEREOF AND QM’S RIGHTS, RESPONSIBILITIES AND LIABILITIES, AND IN THE EVENT OF CONFLICT BETWEEN THIS EULA AND THE PROVISIONS OF ANY SUCH OTHER INSTRUMNETS, THIS EULA SHALL PREVAIL.
|
|
6
|
+
1. DEFINITIONS
|
|
7
|
+
1.1 "Affiliate" means any entity which controls, is controlled, or is under common control with either of the parties. Any entity shall be deemed to "control" another entity if it owns directly or indirectly more than 50% of the outstanding voting securities or capital of another entity or other comparable equity with respect to an entity other than a company.
|
|
8
|
+
1.2 "Documentation" means the standard written materials regarding the Solution issued and generally provided by QM to its customers.
|
|
9
|
+
1.3 "Third Party Components" shall mean collectively any devices and products, whether hardware or software, which are (i) licensed by third parties and that are integrated into or with the Solution, or (ii) third-party equipment operated and/or used with the Solution, including any quantum computer equipment.
|
|
10
|
+
1.4 "Software" shall mean QM’s proprietary software components, provided with and/or incorporated into the Solution.
|
|
11
|
+
1.5 "Solution" shall mean QM’s proprietary dedicated Software, qua-libs-core, for designing, building, deploying, and running portable hybrid quantum-classical applications on top of QM’s proprietary products and services. The Solution specifically excludes QM proprietary products and any SW and HW in such products (or any other related products, either HW, or SW).
|
|
12
|
+
2. LICENSE RIGHTS; RESTRICTIONS
|
|
13
|
+
2.1 QM grants you, subject to full compliance with the EULA and conditions set forth, a non-exclusive, non-transferable, non-sublicensable, limited license to:
|
|
14
|
+
2.1.1 use, access, and operate the Solution as provided, installed, and configured by QM, solely for your internal or personal use and solely with QM’s proprietary products previously purchased by you from QM and other Third Party Components, which specifically allowed to under the Documentation ("Purpose") and in any event not for any further commercialization or provision of the Solution or any parts thereof, to any third party or for the development of similar products, services, or solutions; and
|
|
15
|
+
2.1.2 access, use, and make verbatim copies of the Documentation provided to you by QM, solely in connection with your internal or personal use of the Solution as permitted hereunder solely for the Purpose, and provided that all copyright notices are included and maintained therein.
|
|
16
|
+
2.2 Use Restrictions.
|
|
17
|
+
2.2.1 Unless otherwise expressly provided herein, you agree that you will not, nor will you allow any third party whether or not on your behalf to: (a) distribute, license, rent, lease, sublicense, loan, sell or otherwise allow any third party to access the Solution; (b) modify (except as specifically allowed by QM in the Documentation as part of your standard use of the Solution, and subject to Section 5 below), alter, copy, transfer, emulate or create any derivative works of the Solution or of any part thereof (including any of the Software components thereof); (c) reverse engineer, decompile, decode, decrypt, disassemble, or in any way attempt to derive source code or designs from the Solution or any part thereof (including of any of the Software components thereof); (d) remove, alter or obscure any copyright, trademark or other proprietary rights notice, on or in, the Solution, any of its components and/or the Documentation; (e) bundle, integrate, or attempt to integrate with the Solution or with any component thereof, any third-party software, hardware or technology other than as expressly permitted in writing by QM (including through the Documentation); (f) use the Solution for competing development activities, (g) publish or disclose to any third party any technical features, quality, performance or benchmark test, or comparative analyses relating to the Solution, except for your internal use or as expressly permitted by QM in writing; or (h) disable or otherwise circumvent any license management measures included in the Software and/or the Solution. You shall limit access to the Solution to your authorized employees, Affiliates, and personnel, and will administer account information and passwords accordingly, and will cause all such employees, Affiliates, and personnel to comply with the EULA of this EULA.
|
|
18
|
+
2.2.2 Without derogating from the foregoing, you shall take all commercially reasonable precautions to prevent any unauthorized access and/or unauthorized usage of the Solution. You shall be responsible and liable for any act or omission by anyone acting on your (or your Affiliates’) behalf or authorization, and/or anyone having obtained use of or access to the Solution from you (or your Affiliates), including without limitation your employees, representatives, personnel, or your Affiliates, and such Affiliates’ employees, representatives, and personnel ("Representatives"), as if performed by you.
|
|
19
|
+
2.3 Marks and Use of Name. This EULA does not grant you any rights to QM’s trademarks or service marks.
|
|
20
|
+
2.4 Third Party Software. IN ACCEPTING THIS EULA, YOU CONFIRM AND ACKNOWLEDGE THE UTILIZATION OF THIRD-PARTY COMPONENTS, IN THE SOLUTION, OR THE USE OF THE SOLUTION WITH CERTAIN THIRD PARTY COMPONENTS ALLOWED TO UNDER THE DOCUMENTATION AND ACKNOWLEDGE THAT SUCH THIRD-PARTY COMPONENTS ARE BEING INSTALLED WITH YOUR CONSENT. THIRD PARTY COMPONENTS ARE UTILIZED ON AN "AS-IS" BASIS WITHOUT ANY WARRANTY WHATSOEVER AND QM HEREBY EXPRESSLY DISCLAIMS WITH RESPECT TO ANY SUCH THIRD PARTY COMPONENTS, AND TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW ALL WARRANTIES, WHETHER EXPRESS, IMPLIED, OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|
21
|
+
2.5 Export Restrictions. You acknowledge that the Solution may be subject to applicable export jurisdiction and any other applicable laws and regulations concerning the transfer of the Solution or any part thereof across international borders. You will comply with all applicable national and international laws that apply to your use of the Solution, including the United States Export Administration Regulations, as well as end-user, end-use, and destination restrictions that may be issued by the United States and other governments from time to time.
|
|
22
|
+
3. SUPPORT; DISCLAIMERS
|
|
23
|
+
3.1 Alpha Version. You acknowledge that the Solution including all components thereof, is an Alpha/Beta version that is still under development, and as such (i) is not at the level of performance or compatibility of final, generally available products; (ii) may not operate correctly, (iii) may be further developed or modified; (iv) may not be made for general release, and (v) should not be used in a commercial production environment.
|
|
24
|
+
3.2 THE SOLUTION, IS PROVIDED BY QM "AS-IS" AND QM MAKES NO REPRESENTATIONS OR WARRANTIES, ORAL OR WRITTEN, EXPRESS OR IMPLIED, REGARDING THE SOLUTION, ARISING FROM THE COURSE OF DEALING, COURSE OF PERFORMANCE, USAGE OF TRADE, QUALITY OF INFORMATION, QUIET ENJOYMENT OR OTHERWISE, INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, OR NON-INTERFERENCE. YOU ACKNOWLEDGE THAT YOU HAVE NOT ENTERED INTO THIS EULA IN RELIANCE UPON ANY WARRANTY OR REPRESENTATION NOT EXPRESSLY CONTAINED IN THIS EULA.
|
|
25
|
+
4. FEES.
|
|
26
|
+
4.1 If you are a paying customer, you shall pay QM the fees described in the Quote added with any applicable VAT or sales taxes (as applicable). Payment shall be due as described in the Quote and made in United States Dollars by wire transfer to QM’s designated bank account. All fees shall be non-cancellable, and the sums paid non-refundable. If you are a paying customer, you are responsible for payment of any taxes resulting from the possession and use of the Solution, except for payment of any taxes based on or related to QM’s income.
|
|
27
|
+
5. PROPRIETARY RIGHTS.
|
|
28
|
+
5.1 You agree and acknowledge that QM is and shall remain the sole and exclusive owner of any and all Intellectual Property rights in or to the Solution, including any Feedback provided by you or generated by QM, and any part thereof, including any modifications, enhancements, improvements, updates and upgrades, and derivative works thereof including if originates, learned or derived from the use of the Solution or any part thereof by you or by any Representatives or from the information you or any Representatives provide to QM in connection with the Solution.
|
|
29
|
+
5.2 "Feedback" shall mean any feedback, including any code, documentation, or any original work of authorship, including any modifications or additions to an existing work, made by you as part of your use of the Solution.
|
|
30
|
+
5.3 "Intellectual Property" shall mean all inventions, ideas, concepts, analyses, (whether patented, or patentable, or not), methods, methodologies, designs, processes, patents, patent applications, rights associated with works of authorship, including copyrights, copyrights applications, copyrights restrictions, moral rights, any information, ancillary materials, devices, results, know-how, and all rights relating to the protection of trade secrets and confidential information; design rights and industrial property rights; mask works, software, all code including source code, object code, firmware; and any other proprietary rights relating to intangible property. Other than as explicitly stated hereunder, no right or license, express or implied, in or to the Intellectual Property of QM, is granted to you or any Representative under this EULA.
|
|
31
|
+
6. LIMITATION OF LIABILITY. IN NO EVENT WILL QM, ITS AFFILIATES, OR THEIR RESPECTIVE DIRECTORS, OFFICERS, SHAREHOLDER, AND EMPLOYEES’ ("QM’S PARTIES") AGGREGATE LIABILITY TO YOU, EXCEED THE AMOUNTS PAID BY YOU TO QM IN RESPECT OF THE SOLUTION. IN NO EVENT WILL QM OR QM PARTIES, HAVE ANY LIABILITY TO YOU FOR ANY INDIRECT, CONSEQUENTIAL, SPECIAL, EXEMPLARY, OR INCIDENTAL DAMAGES, INCLUDING WITHOUT LIMITATION DAMAGES FOR LOST PROFITS OR REVENUES, BUSINESS INTERRUPTION, LOSS OF GOODWILL, COMPUTER FAILURE OR MALFUNCTION, LOSS OF DATA OR BUSINESS INFORMATION ARISING FROM THE INSTALLATION, OPERATION, USE OF OR INABILITY TO USE THE SOLUTION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES OR IF SUCH POSSIBILITY WAS REASONABLY FORESEEABLE. NO ACTION, REGARDLESS OF FORM, ARISING OUT OF OR RELATING TO THIS EULA MAY BE BROUGHT AGAINST QM MORE THAN TWELVE (12) MONTHS AFTER THE TERMINATION OR EXPIRATION OF THIS EULA.
|
|
32
|
+
7. TERM AND TERMINATION. You will have the rights set forth herein for the duration set forth by QM at its discretion (unless otherwise agreed between QM and you under an applicable written agreement) and only for so long as you comply with this EULA. This EULA and all rights and licenses granted hereunder shall automatically terminate if you breach the EULA hereof and such breach is not cured within fourteen (14) days of written notice of such breach. Sections 1, 2.2, 2.3, 2.4, 2.5, 5, 6, 7, and 8, will survive any termination or expiration of This EULA.
|
|
33
|
+
8. GENERAL
|
|
34
|
+
8.1 Severability. In the event any provision or part of This EULA is held to be invalid or unenforceable by any court of competent jurisdiction, it shall be amended to the extent required to render it valid, legal, and enforceable, or deleted if no such amendment is feasible, and such amendment or deletion shall not affect the enforceability of the other provisions hereof.
|
|
35
|
+
8.2 Waiver. No waiver of any breach of This EULA will be a waiver of any other breach, and no waiver will be effective unless made in writing and signed by an authorized representative of the waiving party. The failure of either party to enforce any rights granted hereunder or to take action against the other party in the event of any breach hereunder shall not be deemed a waiver by that party as to subsequent enforcement of rights or subsequent actions in the event of future breaches.
|
|
36
|
+
8.3 Entire Agreement; Updates. This EULA is in addition to QM’s Terms of Sale and End User License Agreement that related to QM’s proprietary products and services, including without limitation QM’s proprietary Quantum Orchestration™ Platform and applies only with respect to the subject matter hereof between you and QM – i.e., the use of the QM [QUAlibs] Software, any other EULA not specifically changed and/or modified by this EULA, shall be as set forth in QM’s Terms of Sale and End User License Agreement.
|
|
37
|
+
8.4 Governing Law. The validity, interpretation, and performance of this EULA shall be controlled by and construed under the laws of the State of Israel as if performed wholly within Israel and without giving effect to the principles of conflicts of laws. The Parties hereby consent to the exclusive jurisdiction of the courts of Tel Aviv.
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: qua-libs-core
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Generic QUA tutorials and shared libraries for modality-specific qua-libs repos
|
|
5
|
+
Project-URL: Homepage, https://github.com/qua-platform/qua-libs-core
|
|
6
|
+
Project-URL: Documentation, https://github.com/qua-platform/qua-libs-core/tree/main/docs
|
|
7
|
+
Project-URL: Repository, https://github.com/qua-platform/qua-libs-core
|
|
8
|
+
Project-URL: Issues, https://github.com/qua-platform/qua-libs-core/issues
|
|
9
|
+
Author-email: Quantum Machines <info@quantum-machines.co>
|
|
10
|
+
License:
|
|
11
|
+
Quantum Machines End User License Agreement for qua-libs-core Software
|
|
12
|
+
|
|
13
|
+
PLEASE READ CAREFULLY THIS END USER LICENSE AGREEMENT (“EULA”) BEFORE INSTALLING, ACCESSING, DOWNLOADING OR OTHERWISE USING THE SOLUTION (AS DEFINED BELOW) (“USER”, “YOU”) BY QM (AS DEFINED BELOW). BY INSTALLING, HAVING INSTALLED, CONTROLLING, ACCESSING, OR OTHERWISE USING THE SOLUTION IN ANY MANNER, YOU ARE ACCEPTING AND AGREEING TO BE BOUND BY THIS EULA AND CONDITIONS HEREOF AND REPRESENTING THAT YOU HAVE FULL RIGHT, POWER, AND AUTHORITY TO ENTER INTO AND PERFORM HEREUNDER. YOU MAY NOT INSTALL, DEPLOY, CONTROL, ACCESS, OR USE THE SOLUTION IN ANY MANNER BEFORE YOU HAVE ACCEPTED THIS EULA. FURTHERMORE, YOU HEREBY WAIVE ANY RIGHTS OR REQUIREMENTS UNDER ANY LAWS OR REGULATIONS IN ANY JURISDICTION THAT REQUIRE AN ORIGINAL (NON-ELECTRONIC) SIGNATURE OR DELIVERY OR RETENTION OF NON-ELECTRONIC RECORDS, TO THE EXTENT PERMITTED UNDER APPLICABLE LAW. THIS EULA MADE BETWEEN YOU AND Q.M TECHNOLOGIES LTD. AND ITS AFFILIATES (AS DEFINED BELOW) (“QM”). WITH RESPECT TO THE SOLUTION YOU ASSUME ALL RESPONSIBILITY FOR THE SELECTION OF THE SOLUTION, FOR YOUR RELIANCE ON THE RESULTS OF THE USE OF THE SOLUTION AND RELATED SERVICES, AND FOR ANY USE OF THE SOLUTION NOT IN ACCORDANCE WITH THE EULA HEREOF OR AS CONTEMPLATED HEREUNDER.
|
|
14
|
+
THE PARTIES AGREE THAT UNLESS EXPRESSLY AND SPECIFICALLY AGREED TO IN WRITING BY QM , NO OTHER “CLICK THROGH”, “CLICK WRAP”, TERMS AND CONDITIONS OR OTHER STANDARD TERMS (INCLUDING WITHOUT LIMITATION CUSTOEMRS’ PURCHASE TERMS INCLUDING AS REFRESED IN A QUOTE, OR ORDER), SHALL HAVE ANY FORCE OR EFFECT WITH RESPECT TO THE SOLUTION, THE USE THEREOF AND QM’S RIGHTS, RESPONSIBILITIES AND LIABILITIES, AND IN THE EVENT OF CONFLICT BETWEEN THIS EULA AND THE PROVISIONS OF ANY SUCH OTHER INSTRUMNETS, THIS EULA SHALL PREVAIL.
|
|
15
|
+
1. DEFINITIONS
|
|
16
|
+
1.1 "Affiliate" means any entity which controls, is controlled, or is under common control with either of the parties. Any entity shall be deemed to "control" another entity if it owns directly or indirectly more than 50% of the outstanding voting securities or capital of another entity or other comparable equity with respect to an entity other than a company.
|
|
17
|
+
1.2 "Documentation" means the standard written materials regarding the Solution issued and generally provided by QM to its customers.
|
|
18
|
+
1.3 "Third Party Components" shall mean collectively any devices and products, whether hardware or software, which are (i) licensed by third parties and that are integrated into or with the Solution, or (ii) third-party equipment operated and/or used with the Solution, including any quantum computer equipment.
|
|
19
|
+
1.4 "Software" shall mean QM’s proprietary software components, provided with and/or incorporated into the Solution.
|
|
20
|
+
1.5 "Solution" shall mean QM’s proprietary dedicated Software, qua-libs-core, for designing, building, deploying, and running portable hybrid quantum-classical applications on top of QM’s proprietary products and services. The Solution specifically excludes QM proprietary products and any SW and HW in such products (or any other related products, either HW, or SW).
|
|
21
|
+
2. LICENSE RIGHTS; RESTRICTIONS
|
|
22
|
+
2.1 QM grants you, subject to full compliance with the EULA and conditions set forth, a non-exclusive, non-transferable, non-sublicensable, limited license to:
|
|
23
|
+
2.1.1 use, access, and operate the Solution as provided, installed, and configured by QM, solely for your internal or personal use and solely with QM’s proprietary products previously purchased by you from QM and other Third Party Components, which specifically allowed to under the Documentation ("Purpose") and in any event not for any further commercialization or provision of the Solution or any parts thereof, to any third party or for the development of similar products, services, or solutions; and
|
|
24
|
+
2.1.2 access, use, and make verbatim copies of the Documentation provided to you by QM, solely in connection with your internal or personal use of the Solution as permitted hereunder solely for the Purpose, and provided that all copyright notices are included and maintained therein.
|
|
25
|
+
2.2 Use Restrictions.
|
|
26
|
+
2.2.1 Unless otherwise expressly provided herein, you agree that you will not, nor will you allow any third party whether or not on your behalf to: (a) distribute, license, rent, lease, sublicense, loan, sell or otherwise allow any third party to access the Solution; (b) modify (except as specifically allowed by QM in the Documentation as part of your standard use of the Solution, and subject to Section 5 below), alter, copy, transfer, emulate or create any derivative works of the Solution or of any part thereof (including any of the Software components thereof); (c) reverse engineer, decompile, decode, decrypt, disassemble, or in any way attempt to derive source code or designs from the Solution or any part thereof (including of any of the Software components thereof); (d) remove, alter or obscure any copyright, trademark or other proprietary rights notice, on or in, the Solution, any of its components and/or the Documentation; (e) bundle, integrate, or attempt to integrate with the Solution or with any component thereof, any third-party software, hardware or technology other than as expressly permitted in writing by QM (including through the Documentation); (f) use the Solution for competing development activities, (g) publish or disclose to any third party any technical features, quality, performance or benchmark test, or comparative analyses relating to the Solution, except for your internal use or as expressly permitted by QM in writing; or (h) disable or otherwise circumvent any license management measures included in the Software and/or the Solution. You shall limit access to the Solution to your authorized employees, Affiliates, and personnel, and will administer account information and passwords accordingly, and will cause all such employees, Affiliates, and personnel to comply with the EULA of this EULA.
|
|
27
|
+
2.2.2 Without derogating from the foregoing, you shall take all commercially reasonable precautions to prevent any unauthorized access and/or unauthorized usage of the Solution. You shall be responsible and liable for any act or omission by anyone acting on your (or your Affiliates’) behalf or authorization, and/or anyone having obtained use of or access to the Solution from you (or your Affiliates), including without limitation your employees, representatives, personnel, or your Affiliates, and such Affiliates’ employees, representatives, and personnel ("Representatives"), as if performed by you.
|
|
28
|
+
2.3 Marks and Use of Name. This EULA does not grant you any rights to QM’s trademarks or service marks.
|
|
29
|
+
2.4 Third Party Software. IN ACCEPTING THIS EULA, YOU CONFIRM AND ACKNOWLEDGE THE UTILIZATION OF THIRD-PARTY COMPONENTS, IN THE SOLUTION, OR THE USE OF THE SOLUTION WITH CERTAIN THIRD PARTY COMPONENTS ALLOWED TO UNDER THE DOCUMENTATION AND ACKNOWLEDGE THAT SUCH THIRD-PARTY COMPONENTS ARE BEING INSTALLED WITH YOUR CONSENT. THIRD PARTY COMPONENTS ARE UTILIZED ON AN "AS-IS" BASIS WITHOUT ANY WARRANTY WHATSOEVER AND QM HEREBY EXPRESSLY DISCLAIMS WITH RESPECT TO ANY SUCH THIRD PARTY COMPONENTS, AND TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW ALL WARRANTIES, WHETHER EXPRESS, IMPLIED, OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|
30
|
+
2.5 Export Restrictions. You acknowledge that the Solution may be subject to applicable export jurisdiction and any other applicable laws and regulations concerning the transfer of the Solution or any part thereof across international borders. You will comply with all applicable national and international laws that apply to your use of the Solution, including the United States Export Administration Regulations, as well as end-user, end-use, and destination restrictions that may be issued by the United States and other governments from time to time.
|
|
31
|
+
3. SUPPORT; DISCLAIMERS
|
|
32
|
+
3.1 Alpha Version. You acknowledge that the Solution including all components thereof, is an Alpha/Beta version that is still under development, and as such (i) is not at the level of performance or compatibility of final, generally available products; (ii) may not operate correctly, (iii) may be further developed or modified; (iv) may not be made for general release, and (v) should not be used in a commercial production environment.
|
|
33
|
+
3.2 THE SOLUTION, IS PROVIDED BY QM "AS-IS" AND QM MAKES NO REPRESENTATIONS OR WARRANTIES, ORAL OR WRITTEN, EXPRESS OR IMPLIED, REGARDING THE SOLUTION, ARISING FROM THE COURSE OF DEALING, COURSE OF PERFORMANCE, USAGE OF TRADE, QUALITY OF INFORMATION, QUIET ENJOYMENT OR OTHERWISE, INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, OR NON-INTERFERENCE. YOU ACKNOWLEDGE THAT YOU HAVE NOT ENTERED INTO THIS EULA IN RELIANCE UPON ANY WARRANTY OR REPRESENTATION NOT EXPRESSLY CONTAINED IN THIS EULA.
|
|
34
|
+
4. FEES.
|
|
35
|
+
4.1 If you are a paying customer, you shall pay QM the fees described in the Quote added with any applicable VAT or sales taxes (as applicable). Payment shall be due as described in the Quote and made in United States Dollars by wire transfer to QM’s designated bank account. All fees shall be non-cancellable, and the sums paid non-refundable. If you are a paying customer, you are responsible for payment of any taxes resulting from the possession and use of the Solution, except for payment of any taxes based on or related to QM’s income.
|
|
36
|
+
5. PROPRIETARY RIGHTS.
|
|
37
|
+
5.1 You agree and acknowledge that QM is and shall remain the sole and exclusive owner of any and all Intellectual Property rights in or to the Solution, including any Feedback provided by you or generated by QM, and any part thereof, including any modifications, enhancements, improvements, updates and upgrades, and derivative works thereof including if originates, learned or derived from the use of the Solution or any part thereof by you or by any Representatives or from the information you or any Representatives provide to QM in connection with the Solution.
|
|
38
|
+
5.2 "Feedback" shall mean any feedback, including any code, documentation, or any original work of authorship, including any modifications or additions to an existing work, made by you as part of your use of the Solution.
|
|
39
|
+
5.3 "Intellectual Property" shall mean all inventions, ideas, concepts, analyses, (whether patented, or patentable, or not), methods, methodologies, designs, processes, patents, patent applications, rights associated with works of authorship, including copyrights, copyrights applications, copyrights restrictions, moral rights, any information, ancillary materials, devices, results, know-how, and all rights relating to the protection of trade secrets and confidential information; design rights and industrial property rights; mask works, software, all code including source code, object code, firmware; and any other proprietary rights relating to intangible property. Other than as explicitly stated hereunder, no right or license, express or implied, in or to the Intellectual Property of QM, is granted to you or any Representative under this EULA.
|
|
40
|
+
6. LIMITATION OF LIABILITY. IN NO EVENT WILL QM, ITS AFFILIATES, OR THEIR RESPECTIVE DIRECTORS, OFFICERS, SHAREHOLDER, AND EMPLOYEES’ ("QM’S PARTIES") AGGREGATE LIABILITY TO YOU, EXCEED THE AMOUNTS PAID BY YOU TO QM IN RESPECT OF THE SOLUTION. IN NO EVENT WILL QM OR QM PARTIES, HAVE ANY LIABILITY TO YOU FOR ANY INDIRECT, CONSEQUENTIAL, SPECIAL, EXEMPLARY, OR INCIDENTAL DAMAGES, INCLUDING WITHOUT LIMITATION DAMAGES FOR LOST PROFITS OR REVENUES, BUSINESS INTERRUPTION, LOSS OF GOODWILL, COMPUTER FAILURE OR MALFUNCTION, LOSS OF DATA OR BUSINESS INFORMATION ARISING FROM THE INSTALLATION, OPERATION, USE OF OR INABILITY TO USE THE SOLUTION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES OR IF SUCH POSSIBILITY WAS REASONABLY FORESEEABLE. NO ACTION, REGARDLESS OF FORM, ARISING OUT OF OR RELATING TO THIS EULA MAY BE BROUGHT AGAINST QM MORE THAN TWELVE (12) MONTHS AFTER THE TERMINATION OR EXPIRATION OF THIS EULA.
|
|
41
|
+
7. TERM AND TERMINATION. You will have the rights set forth herein for the duration set forth by QM at its discretion (unless otherwise agreed between QM and you under an applicable written agreement) and only for so long as you comply with this EULA. This EULA and all rights and licenses granted hereunder shall automatically terminate if you breach the EULA hereof and such breach is not cured within fourteen (14) days of written notice of such breach. Sections 1, 2.2, 2.3, 2.4, 2.5, 5, 6, 7, and 8, will survive any termination or expiration of This EULA.
|
|
42
|
+
8. GENERAL
|
|
43
|
+
8.1 Severability. In the event any provision or part of This EULA is held to be invalid or unenforceable by any court of competent jurisdiction, it shall be amended to the extent required to render it valid, legal, and enforceable, or deleted if no such amendment is feasible, and such amendment or deletion shall not affect the enforceability of the other provisions hereof.
|
|
44
|
+
8.2 Waiver. No waiver of any breach of This EULA will be a waiver of any other breach, and no waiver will be effective unless made in writing and signed by an authorized representative of the waiving party. The failure of either party to enforce any rights granted hereunder or to take action against the other party in the event of any breach hereunder shall not be deemed a waiver by that party as to subsequent enforcement of rights or subsequent actions in the event of future breaches.
|
|
45
|
+
8.3 Entire Agreement; Updates. This EULA is in addition to QM’s Terms of Sale and End User License Agreement that related to QM’s proprietary products and services, including without limitation QM’s proprietary Quantum Orchestration™ Platform and applies only with respect to the subject matter hereof between you and QM – i.e., the use of the QM [QUAlibs] Software, any other EULA not specifically changed and/or modified by this EULA, shall be as set forth in QM’s Terms of Sale and End User License Agreement.
|
|
46
|
+
8.4 Governing Law. The validity, interpretation, and performance of this EULA shall be controlled by and construed under the laws of the State of Israel as if performed wholly within Israel and without giving effect to the principles of conflicts of laws. The Parties hereby consent to the exclusive jurisdiction of the courts of Tel Aviv.
|
|
47
|
+
License-File: LICENSE
|
|
48
|
+
Classifier: License :: Other/Proprietary License
|
|
49
|
+
Classifier: Operating System :: OS Independent
|
|
50
|
+
Classifier: Programming Language :: Python :: 3
|
|
51
|
+
Requires-Python: <3.13,>=3.10
|
|
52
|
+
Requires-Dist: opentelemetry-api>=1.20.0
|
|
53
|
+
Requires-Dist: opentelemetry-exporter-otlp>=1.20.0
|
|
54
|
+
Requires-Dist: opentelemetry-sdk>=1.20.0
|
|
55
|
+
Requires-Dist: tomli>=2.0.1; python_version < '3.11'
|
|
56
|
+
Requires-Dist: uptrace>=1.20.0
|
|
57
|
+
Provides-Extra: tutorials
|
|
58
|
+
Requires-Dist: matplotlib>=3.2.2; extra == 'tutorials'
|
|
59
|
+
Requires-Dist: numpy>=1.18.5; extra == 'tutorials'
|
|
60
|
+
Requires-Dist: plotly>=5.24.1; extra == 'tutorials'
|
|
61
|
+
Requires-Dist: qm-qua>=1.2.0; extra == 'tutorials'
|
|
62
|
+
Requires-Dist: qm-saas; extra == 'tutorials'
|
|
63
|
+
Requires-Dist: qualang-tools>=0.19.0; extra == 'tutorials'
|
|
64
|
+
Requires-Dist: scipy>=1.7.0; extra == 'tutorials'
|
|
65
|
+
Description-Content-Type: text/markdown
|
|
66
|
+
|
|
67
|
+

|
|
68
|
+
|
|
69
|
+
[](https://discord.gg/7FfhhpswbP)
|
|
70
|
+
[](./LICENSE)
|
|
71
|
+
|
|
72
|
+
<!-- Netlify (docs deploy) and Zenodo (citable DOI) badges are placeholders;
|
|
73
|
+
fill in the IDs once this repo has its own Netlify site and Zenodo record. -->
|
|
74
|
+
[](https://app.netlify.com/sites/qua-libs-core/deploys)
|
|
75
|
+
[](https://zenodo.org/badge/latestdoi/REPLACE_WITH_ZENODO_ID)
|
|
76
|
+
|
|
77
|
+
# QUA Libraries
|
|
78
|
+
|
|
79
|
+
Hey! Glad to see you there!
|
|
80
|
+
|
|
81
|
+
Welcome to the QUA libraries. Your one-stop-shop for a batteries-included QUA experience.
|
|
82
|
+
|
|
83
|
+
This repo is where we share the general-purpose tutorials and tools that aren't tied to any particular qubit platform, and it points you to the platform-specific libraries below.
|
|
84
|
+
|
|
85
|
+
It includes:
|
|
86
|
+
* The ["Tutorials"](./Tutorials) folder contains various tutorials and guides for working with the OPX — timing, streams, demodulation, simulation, macros, Octave, and more.
|
|
87
|
+
|
|
88
|
+
## Installing
|
|
89
|
+
|
|
90
|
+
Install `qua-libs-core` from PyPI:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
pip install qua-libs-core
|
|
94
|
+
```
|
|
95
|
+
That gives you the importable `qua_libs_core` package, including `qua_libs_core.telemetry` used across the qua-libs repositories, without the QUA SDK.
|
|
96
|
+
|
|
97
|
+
Or clone this repository for tutorials and the installer in addition to telemetry:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
git clone https://github.com/qua-platform/qua-libs-core
|
|
101
|
+
cd qua-libs-core
|
|
102
|
+
uv sync --extra tutorials
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Documentation for telemetry is seen in
|
|
106
|
+
[`qua_libs_core.telemetry`](docs/telemetry/README.md).
|
|
107
|
+
|
|
108
|
+
### QUA Libraries installer
|
|
109
|
+
|
|
110
|
+
For a batteries-included modality setup (clone, virtualenv, QUAlibrate, optional
|
|
111
|
+
local Uptrace), use [`tools/installer/`](tools/installer/README.md).
|
|
112
|
+
See [telemetry installer docs](docs/telemetry/INSTALLER.md) for Docker and config
|
|
113
|
+
file behavior.
|
|
114
|
+
|
|
115
|
+
## QUA libraries by platform
|
|
116
|
+
|
|
117
|
+
Examples, use cases, and calibration protocols for specific qubit platforms live in their own repositories:
|
|
118
|
+
|
|
119
|
+
| Repository | Platform |
|
|
120
|
+
|---|---|
|
|
121
|
+
| [qua-libs-superconducting](https://github.com/qua-platform/qua-libs-superconducting) | Superconducting transmons |
|
|
122
|
+
| [qua-libs-nv](https://github.com/qua-platform/qua-libs-nv) | NV / optically addressable spin qubits |
|
|
123
|
+
| [qua-libs-quantum-dots](https://github.com/qua-platform/qua-libs-quantum-dots) | Quantum dots |
|
|
124
|
+
| [qua-libs-neutral-atoms](https://github.com/qua-platform/qua-libs-neutral-atoms) | Neutral atoms (Rydberg, cavity locking) |
|
|
125
|
+
| [qua-libs-trapped-ion](https://github.com/qua-platform/qua-libs-trapped-ion) | Trapped ions |
|
|
126
|
+
|
|
127
|
+
## Support and Contribution
|
|
128
|
+
This is a beta version of the repo, and thus, if you see quirks and inaccuracies please tell us!
|
|
129
|
+
Love to see some example that's not yet included? tell us! Have a request for a general purpose procedure? tell us!
|
|
130
|
+
Already have something cool that others could use? Open a pull request! You can follow [this guide](./CONTRIBUTING.md) and feel free to contact us if you need any help.
|
|
131
|
+
Issue reporting and requests should be done via the [GitHub issues system](https://github.com/qua-platform/qua-libs-core/issues), that should give a transparent experience where all users can see what's coming and which issues are already known.
|
|
132
|
+
We hope this repo becomes a useful resource, giving real contribution to the community, and we'd love to see your ideas and contributions too!
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
3
|
+
[](https://discord.gg/7FfhhpswbP)
|
|
4
|
+
[](./LICENSE)
|
|
5
|
+
|
|
6
|
+
<!-- Netlify (docs deploy) and Zenodo (citable DOI) badges are placeholders;
|
|
7
|
+
fill in the IDs once this repo has its own Netlify site and Zenodo record. -->
|
|
8
|
+
[](https://app.netlify.com/sites/qua-libs-core/deploys)
|
|
9
|
+
[](https://zenodo.org/badge/latestdoi/REPLACE_WITH_ZENODO_ID)
|
|
10
|
+
|
|
11
|
+
# QUA Libraries
|
|
12
|
+
|
|
13
|
+
Hey! Glad to see you there!
|
|
14
|
+
|
|
15
|
+
Welcome to the QUA libraries. Your one-stop-shop for a batteries-included QUA experience.
|
|
16
|
+
|
|
17
|
+
This repo is where we share the general-purpose tutorials and tools that aren't tied to any particular qubit platform, and it points you to the platform-specific libraries below.
|
|
18
|
+
|
|
19
|
+
It includes:
|
|
20
|
+
* The ["Tutorials"](./Tutorials) folder contains various tutorials and guides for working with the OPX — timing, streams, demodulation, simulation, macros, Octave, and more.
|
|
21
|
+
|
|
22
|
+
## Installing
|
|
23
|
+
|
|
24
|
+
Install `qua-libs-core` from PyPI:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pip install qua-libs-core
|
|
28
|
+
```
|
|
29
|
+
That gives you the importable `qua_libs_core` package, including `qua_libs_core.telemetry` used across the qua-libs repositories, without the QUA SDK.
|
|
30
|
+
|
|
31
|
+
Or clone this repository for tutorials and the installer in addition to telemetry:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
git clone https://github.com/qua-platform/qua-libs-core
|
|
35
|
+
cd qua-libs-core
|
|
36
|
+
uv sync --extra tutorials
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Documentation for telemetry is seen in
|
|
40
|
+
[`qua_libs_core.telemetry`](docs/telemetry/README.md).
|
|
41
|
+
|
|
42
|
+
### QUA Libraries installer
|
|
43
|
+
|
|
44
|
+
For a batteries-included modality setup (clone, virtualenv, QUAlibrate, optional
|
|
45
|
+
local Uptrace), use [`tools/installer/`](tools/installer/README.md).
|
|
46
|
+
See [telemetry installer docs](docs/telemetry/INSTALLER.md) for Docker and config
|
|
47
|
+
file behavior.
|
|
48
|
+
|
|
49
|
+
## QUA libraries by platform
|
|
50
|
+
|
|
51
|
+
Examples, use cases, and calibration protocols for specific qubit platforms live in their own repositories:
|
|
52
|
+
|
|
53
|
+
| Repository | Platform |
|
|
54
|
+
|---|---|
|
|
55
|
+
| [qua-libs-superconducting](https://github.com/qua-platform/qua-libs-superconducting) | Superconducting transmons |
|
|
56
|
+
| [qua-libs-nv](https://github.com/qua-platform/qua-libs-nv) | NV / optically addressable spin qubits |
|
|
57
|
+
| [qua-libs-quantum-dots](https://github.com/qua-platform/qua-libs-quantum-dots) | Quantum dots |
|
|
58
|
+
| [qua-libs-neutral-atoms](https://github.com/qua-platform/qua-libs-neutral-atoms) | Neutral atoms (Rydberg, cavity locking) |
|
|
59
|
+
| [qua-libs-trapped-ion](https://github.com/qua-platform/qua-libs-trapped-ion) | Trapped ions |
|
|
60
|
+
|
|
61
|
+
## Support and Contribution
|
|
62
|
+
This is a beta version of the repo, and thus, if you see quirks and inaccuracies please tell us!
|
|
63
|
+
Love to see some example that's not yet included? tell us! Have a request for a general purpose procedure? tell us!
|
|
64
|
+
Already have something cool that others could use? Open a pull request! You can follow [this guide](./CONTRIBUTING.md) and feel free to contact us if you need any help.
|
|
65
|
+
Issue reporting and requests should be done via the [GitHub issues system](https://github.com/qua-platform/qua-libs-core/issues), that should give a transparent experience where all users can see what's coming and which issues are already known.
|
|
66
|
+
We hope this repo becomes a useful resource, giving real contribution to the community, and we'd love to see your ideas and contributions too!
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# qua-libs-core: generic QUA tutorials, shared tooling, and the `qua_libs_core`
|
|
2
|
+
# package (including `qua_libs_core.telemetry` for modality repositories).
|
|
3
|
+
|
|
4
|
+
[project]
|
|
5
|
+
name = "qua-libs-core"
|
|
6
|
+
dynamic = ["version"]
|
|
7
|
+
description = "Generic QUA tutorials and shared libraries for modality-specific qua-libs repos"
|
|
8
|
+
readme = "README.md"
|
|
9
|
+
license = { file = "LICENSE" }
|
|
10
|
+
authors = [{ name = "Quantum Machines", email = "info@quantum-machines.co" }]
|
|
11
|
+
requires-python = ">=3.10,<3.13"
|
|
12
|
+
classifiers = [
|
|
13
|
+
"License :: Other/Proprietary License",
|
|
14
|
+
"Programming Language :: Python :: 3",
|
|
15
|
+
"Operating System :: OS Independent",
|
|
16
|
+
]
|
|
17
|
+
dependencies = [
|
|
18
|
+
"uptrace>=1.20.0",
|
|
19
|
+
"opentelemetry-api>=1.20.0",
|
|
20
|
+
"opentelemetry-sdk>=1.20.0",
|
|
21
|
+
"opentelemetry-exporter-otlp>=1.20.0",
|
|
22
|
+
"tomli>=2.0.1; python_version < '3.11'",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
[project.optional-dependencies]
|
|
26
|
+
tutorials = [
|
|
27
|
+
"qm-qua>=1.2.0",
|
|
28
|
+
"qualang-tools>=0.19.0",
|
|
29
|
+
"qm-saas",
|
|
30
|
+
"numpy>=1.18.5",
|
|
31
|
+
"scipy>=1.7.0",
|
|
32
|
+
"matplotlib>=3.2.2",
|
|
33
|
+
"plotly>=5.24.1",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
[project.urls]
|
|
37
|
+
Homepage = "https://github.com/qua-platform/qua-libs-core"
|
|
38
|
+
Documentation = "https://github.com/qua-platform/qua-libs-core/tree/main/docs"
|
|
39
|
+
Repository = "https://github.com/qua-platform/qua-libs-core"
|
|
40
|
+
Issues = "https://github.com/qua-platform/qua-libs-core/issues"
|
|
41
|
+
|
|
42
|
+
[build-system]
|
|
43
|
+
requires = ["hatchling"]
|
|
44
|
+
build-backend = "hatchling.build"
|
|
45
|
+
|
|
46
|
+
[tool.hatch.version]
|
|
47
|
+
path = "qua_libs_core/__init__.py"
|
|
48
|
+
|
|
49
|
+
[tool.hatch.build.targets.sdist]
|
|
50
|
+
only-include = ["qua_libs_core"]
|
|
51
|
+
|
|
52
|
+
[tool.hatch.build.targets.wheel]
|
|
53
|
+
packages = ["qua_libs_core"]
|
|
54
|
+
|
|
55
|
+
[dependency-groups]
|
|
56
|
+
dev = ["black>=24.3,<25", "ruff>=0.6,<1", "pytest>=8.0", "pre-commit>=4.0"]
|
|
57
|
+
|
|
58
|
+
[tool.pytest.ini_options]
|
|
59
|
+
testpaths = ["tests"]
|
|
60
|
+
|
|
61
|
+
[tool.black]
|
|
62
|
+
line-length = 120
|
|
63
|
+
|
|
64
|
+
[tool.ruff]
|
|
65
|
+
line-length = 120
|
|
66
|
+
|
|
67
|
+
[tool.ruff.lint]
|
|
68
|
+
# `from qm.qua import *` is the idiomatic QUA style (F403/F405); single-letter
|
|
69
|
+
# names like I/Q/l are standard in physics code (E741). Ignoring these keeps
|
|
70
|
+
# ruff's output useful. Run locally with: uv run ruff check .
|
|
71
|
+
ignore = ["F403", "F405", "E741"]
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""qua-libs-core importable package.
|
|
2
|
+
|
|
3
|
+
Currently ships the shared ``telemetry`` subpackage — OpenTelemetry + Uptrace
|
|
4
|
+
instrumentation used by the per-modality qua-libs repos. Telemetry is off by
|
|
5
|
+
default; see ``docs/telemetry/`` for usage. Import as::
|
|
6
|
+
|
|
7
|
+
from qua_libs_core.telemetry import instrument_calibration_node
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Telemetry module for OpenTelemetry + Uptrace integration.
|
|
3
|
+
|
|
4
|
+
Example usage:
|
|
5
|
+
from qua_libs_core.telemetry import init_telemetry, trace_function, trace_span
|
|
6
|
+
|
|
7
|
+
# Initialize once at application startup (reads .qua-libs/telemetry.toml)
|
|
8
|
+
init_telemetry()
|
|
9
|
+
|
|
10
|
+
# Option 1: Use decorator for automatic instrumentation
|
|
11
|
+
@trace_function("my_function")
|
|
12
|
+
def my_function():
|
|
13
|
+
...
|
|
14
|
+
|
|
15
|
+
# Option 2: Use context manager for manual spans
|
|
16
|
+
with trace_span("my_operation"):
|
|
17
|
+
...
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from .config import TelemetryConfig, init_telemetry, get_tracer
|
|
21
|
+
from .decorators import trace_function, trace_async_function
|
|
22
|
+
from .context_managers import trace_span, trace_span_with_attributes
|
|
23
|
+
from .utils import (
|
|
24
|
+
set_span_attribute,
|
|
25
|
+
add_span_event,
|
|
26
|
+
record_exception,
|
|
27
|
+
set_span_status,
|
|
28
|
+
get_current_span,
|
|
29
|
+
)
|
|
30
|
+
from .calibration_node import instrument_calibration_node
|
|
31
|
+
from .project_config import PROJECT_CONFIG, load_project_config
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
__all__ = [
|
|
35
|
+
"TelemetryConfig",
|
|
36
|
+
"init_telemetry",
|
|
37
|
+
"get_tracer",
|
|
38
|
+
"trace_function",
|
|
39
|
+
"trace_async_function",
|
|
40
|
+
"trace_span",
|
|
41
|
+
"trace_span_with_attributes",
|
|
42
|
+
"set_span_attribute",
|
|
43
|
+
"add_span_event",
|
|
44
|
+
"record_exception",
|
|
45
|
+
"set_span_status",
|
|
46
|
+
"get_current_span",
|
|
47
|
+
"instrument_calibration_node",
|
|
48
|
+
"PROJECT_CONFIG",
|
|
49
|
+
"load_project_config",
|
|
50
|
+
]
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Centralized telemetry instrumentation for calibration nodes.
|
|
3
|
+
|
|
4
|
+
Usage:
|
|
5
|
+
from qua_libs_core.telemetry import instrument_calibration_node
|
|
6
|
+
|
|
7
|
+
node = QualibrationNode[Parameters, Quam](name="my_node", ...)
|
|
8
|
+
instrument_calibration_node(node) # call once, before any @node.run_action defs
|
|
9
|
+
|
|
10
|
+
@node.run_action(skip_if=...)
|
|
11
|
+
def create_qua_program(node):
|
|
12
|
+
... # unchanged — telemetry is added automatically
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import functools
|
|
16
|
+
from datetime import datetime
|
|
17
|
+
from typing import Any, Dict, List, Optional
|
|
18
|
+
|
|
19
|
+
import uptrace
|
|
20
|
+
from opentelemetry.trace import Status, StatusCode
|
|
21
|
+
|
|
22
|
+
from .config import init_telemetry, TelemetryConfig, get_tracer
|
|
23
|
+
from .project_config import load_project_config
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
STANDARD_FUNCTIONS = [
|
|
27
|
+
"custom_param",
|
|
28
|
+
"create_qua_program",
|
|
29
|
+
"simulate_qua_program",
|
|
30
|
+
"execute_qua_program",
|
|
31
|
+
"load_data",
|
|
32
|
+
"analyse_data",
|
|
33
|
+
"plot_data",
|
|
34
|
+
"update_state",
|
|
35
|
+
"save_results",
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
# Parameter attributes to capture from node.parameters when available
|
|
39
|
+
_OPTIONAL_ATTRS = ["operation", "num_shots", "timeout", "load_data_id"]
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def instrument_calibration_node(
|
|
43
|
+
node,
|
|
44
|
+
config: Optional[TelemetryConfig] = None,
|
|
45
|
+
extra_attributes: Optional[List[str]] = None,
|
|
46
|
+
resource_attributes: Optional[Dict[str, Any]] = None,
|
|
47
|
+
) -> None:
|
|
48
|
+
"""
|
|
49
|
+
Instrument a calibration node's standard run_action functions with telemetry spans.
|
|
50
|
+
|
|
51
|
+
Patches node.run_action so every function listed in STANDARD_FUNCTIONS that is
|
|
52
|
+
subsequently decorated with @node.run_action gets automatically wrapped in a
|
|
53
|
+
trace span. Functions not in STANDARD_FUNCTIONS are passed through unchanged.
|
|
54
|
+
|
|
55
|
+
Call this ONCE, immediately after node creation and BEFORE any @node.run_action
|
|
56
|
+
function definitions.
|
|
57
|
+
|
|
58
|
+
Args:
|
|
59
|
+
node: A QualibrationNode instance.
|
|
60
|
+
config: Optional TelemetryConfig. If None, reloads ``.qua-libs/telemetry.toml``
|
|
61
|
+
from the current working directory (and parents).
|
|
62
|
+
extra_attributes: Optional list of additional parameter names to capture
|
|
63
|
+
from node.parameters as span attributes (extends the default set of
|
|
64
|
+
operation, num_shots, timeout, load_data_id).
|
|
65
|
+
resource_attributes: Optional dict of resource-level attributes passed to
|
|
66
|
+
Uptrace (e.g., experiment.category, experiment.run_at). Only takes
|
|
67
|
+
effect on the first init_telemetry call per process.
|
|
68
|
+
|
|
69
|
+
Advanced usage — accessing the span inside a function:
|
|
70
|
+
from qua_libs_core.telemetry import get_current_span, set_span_attribute
|
|
71
|
+
|
|
72
|
+
@node.run_action(skip_if=node.parameters.simulate)
|
|
73
|
+
def analyse_data(node):
|
|
74
|
+
span = get_current_span()
|
|
75
|
+
set_span_attribute(span, "fit.q1", "successful")
|
|
76
|
+
|
|
77
|
+
The span is also available via node.namespace["_telemetry_span"].
|
|
78
|
+
"""
|
|
79
|
+
if config is None:
|
|
80
|
+
config = load_project_config()
|
|
81
|
+
|
|
82
|
+
# Auto-populate resource attributes from node name and current time
|
|
83
|
+
auto_attrs = {
|
|
84
|
+
"experiment.node": node.name,
|
|
85
|
+
"experiment.run_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
|
86
|
+
}
|
|
87
|
+
# User-provided resource_attributes override auto ones
|
|
88
|
+
merged_attrs = {
|
|
89
|
+
**auto_attrs,
|
|
90
|
+
**(config.resource_attributes or {}),
|
|
91
|
+
**(resource_attributes or {}),
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if merged_attrs != (config.resource_attributes or {}):
|
|
95
|
+
config = TelemetryConfig(
|
|
96
|
+
dsn=config.dsn,
|
|
97
|
+
service_name=config.service_name,
|
|
98
|
+
service_version=config.service_version,
|
|
99
|
+
deployment_environment=config.deployment_environment,
|
|
100
|
+
enabled=config.enabled,
|
|
101
|
+
resource_attributes=merged_attrs,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
init_telemetry(config)
|
|
105
|
+
|
|
106
|
+
node_name = node.name
|
|
107
|
+
original_run_action = node.run_action
|
|
108
|
+
|
|
109
|
+
param_attributes = list(_OPTIONAL_ATTRS)
|
|
110
|
+
if extra_attributes:
|
|
111
|
+
param_attributes.extend(extra_attributes)
|
|
112
|
+
|
|
113
|
+
def traced_run_action(*args, **kwargs):
|
|
114
|
+
decorator = original_run_action(*args, **kwargs)
|
|
115
|
+
|
|
116
|
+
def wrapping_decorator(fn):
|
|
117
|
+
if fn.__name__ not in STANDARD_FUNCTIONS:
|
|
118
|
+
return decorator(fn)
|
|
119
|
+
|
|
120
|
+
@functools.wraps(fn)
|
|
121
|
+
def traced_fn(*fn_args, **fn_kwargs):
|
|
122
|
+
tracer = get_tracer()
|
|
123
|
+
attrs = {"node": node_name}
|
|
124
|
+
|
|
125
|
+
# Collect optional span attributes from node.parameters
|
|
126
|
+
if fn_args:
|
|
127
|
+
params = getattr(fn_args[0], "parameters", None)
|
|
128
|
+
if params is not None:
|
|
129
|
+
for attr in param_attributes:
|
|
130
|
+
val = getattr(params, attr, None)
|
|
131
|
+
if val is not None:
|
|
132
|
+
attrs[attr] = str(val)
|
|
133
|
+
|
|
134
|
+
with tracer.start_as_current_span(f"{node_name}.{fn.__name__}") as span:
|
|
135
|
+
for key, value in attrs.items():
|
|
136
|
+
span.set_attribute(key, value)
|
|
137
|
+
node.namespace["_telemetry_span"] = span
|
|
138
|
+
try:
|
|
139
|
+
result = fn(*fn_args, **fn_kwargs)
|
|
140
|
+
if fn.__name__ == "save_results":
|
|
141
|
+
try:
|
|
142
|
+
uptrace.force_flush()
|
|
143
|
+
except Exception:
|
|
144
|
+
pass
|
|
145
|
+
return result
|
|
146
|
+
except Exception as e:
|
|
147
|
+
span.record_exception(e)
|
|
148
|
+
span.set_status(Status(StatusCode.ERROR, str(e)))
|
|
149
|
+
raise
|
|
150
|
+
finally:
|
|
151
|
+
node.namespace.pop("_telemetry_span", None)
|
|
152
|
+
|
|
153
|
+
return decorator(traced_fn)
|
|
154
|
+
|
|
155
|
+
return wrapping_decorator
|
|
156
|
+
|
|
157
|
+
node.run_action = traced_run_action
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Telemetry configuration and initialization module.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
import os
|
|
7
|
+
from typing import Optional, Dict, Any
|
|
8
|
+
from opentelemetry import trace
|
|
9
|
+
import uptrace
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
# pylint: disable=too-many-arguments,too-many-positional-arguments,too-few-public-methods
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class TelemetryConfig:
|
|
17
|
+
"""Configuration class for telemetry settings."""
|
|
18
|
+
|
|
19
|
+
def __init__(
|
|
20
|
+
self,
|
|
21
|
+
dsn: Optional[str] = None,
|
|
22
|
+
service_name: Optional[str] = None,
|
|
23
|
+
service_version: Optional[str] = None,
|
|
24
|
+
deployment_environment: Optional[str] = None,
|
|
25
|
+
enabled: Optional[bool] = None,
|
|
26
|
+
resource_attributes: Optional[Dict[str, Any]] = None,
|
|
27
|
+
):
|
|
28
|
+
"""
|
|
29
|
+
Initialize telemetry configuration.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
dsn: Uptrace DSN (defaults to UPTRACE_DSN env var)
|
|
33
|
+
service_name: Service name (defaults to UPTRACE_SERVICE_NAME env var or "qua-libs")
|
|
34
|
+
service_version: Service version (defaults to UPTRACE_SERVICE_VERSION env var or "1.0.0")
|
|
35
|
+
deployment_environment: Deployment environment (defaults to UPTRACE_ENV env var or "production")
|
|
36
|
+
enabled: Whether telemetry is enabled (defaults to UPTRACE_ENABLED env var or False)
|
|
37
|
+
resource_attributes: Extra key-value metadata attached to every span automatically
|
|
38
|
+
"""
|
|
39
|
+
self.dsn = dsn or os.getenv("UPTRACE_DSN")
|
|
40
|
+
self.resource_attributes = resource_attributes or {}
|
|
41
|
+
self.service_name = service_name or os.getenv("UPTRACE_SERVICE_NAME", "qua-libs")
|
|
42
|
+
self.service_version = service_version or os.getenv("UPTRACE_SERVICE_VERSION", "1.0.0")
|
|
43
|
+
self.deployment_environment = deployment_environment or os.getenv("UPTRACE_ENV", "production")
|
|
44
|
+
|
|
45
|
+
# Off by default. Enable via .qua-libs/telemetry.toml, UPTRACE_ENABLED=true, or enabled=True.
|
|
46
|
+
enabled_str = os.getenv("UPTRACE_ENABLED", "false").lower()
|
|
47
|
+
self.enabled = enabled if enabled is not None else (enabled_str in ("true", "1", "yes"))
|
|
48
|
+
|
|
49
|
+
# Note: Enabled-but-no-DSN is handled in init_telemetry; do not raise in __init__.
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
# Global state
|
|
53
|
+
_telemetry_initialized = False
|
|
54
|
+
_tracer = None
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def init_telemetry(config: Optional[TelemetryConfig] = None) -> None:
|
|
58
|
+
"""
|
|
59
|
+
Initialize OpenTelemetry with Uptrace.
|
|
60
|
+
|
|
61
|
+
This should be called once at application startup.
|
|
62
|
+
Subsequent calls are safe and will be ignored.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
config: TelemetryConfig instance. If None, loads from .qua-libs/telemetry.toml,
|
|
66
|
+
environment variables, and built-in defaults via load_project_config().
|
|
67
|
+
"""
|
|
68
|
+
global _telemetry_initialized, _tracer
|
|
69
|
+
|
|
70
|
+
if _telemetry_initialized:
|
|
71
|
+
return
|
|
72
|
+
|
|
73
|
+
if config is None:
|
|
74
|
+
from .project_config import load_project_config
|
|
75
|
+
|
|
76
|
+
config = load_project_config()
|
|
77
|
+
|
|
78
|
+
if not config.enabled:
|
|
79
|
+
logger.info(
|
|
80
|
+
"Telemetry is disabled (off by default). "
|
|
81
|
+
"Set enabled=true in .qua-libs/telemetry.toml, UPTRACE_ENABLED=true, "
|
|
82
|
+
"or pass TelemetryConfig(enabled=True, dsn=...) to enable."
|
|
83
|
+
)
|
|
84
|
+
_telemetry_initialized = True
|
|
85
|
+
return
|
|
86
|
+
|
|
87
|
+
if not config.dsn:
|
|
88
|
+
# Enabled but no destination configured. Stay disabled rather than crash —
|
|
89
|
+
# telemetry must never break a calibration run.
|
|
90
|
+
logger.warning(
|
|
91
|
+
"Telemetry is enabled but no Uptrace DSN was provided. "
|
|
92
|
+
"Set UPTRACE_DSN (or pass dsn=...). Telemetry stays disabled."
|
|
93
|
+
)
|
|
94
|
+
_telemetry_initialized = True
|
|
95
|
+
return
|
|
96
|
+
|
|
97
|
+
try:
|
|
98
|
+
uptrace.configure_opentelemetry(
|
|
99
|
+
dsn=config.dsn,
|
|
100
|
+
service_name=config.service_name,
|
|
101
|
+
service_version=config.service_version,
|
|
102
|
+
deployment_environment=config.deployment_environment,
|
|
103
|
+
resource_attributes=config.resource_attributes,
|
|
104
|
+
)
|
|
105
|
+
_tracer = trace.get_tracer(config.service_name, config.service_version)
|
|
106
|
+
_telemetry_initialized = True
|
|
107
|
+
logger.info("Telemetry initialized: %s v%s", config.service_name, config.service_version)
|
|
108
|
+
except Exception as e:
|
|
109
|
+
logger.warning("Failed to initialize telemetry: %s", e)
|
|
110
|
+
# Continue without telemetry rather than crashing
|
|
111
|
+
_telemetry_initialized = True
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def get_tracer(name: Optional[str] = None, version: Optional[str] = None):
|
|
115
|
+
"""
|
|
116
|
+
Get the OpenTelemetry tracer instance.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
name: Optional tracer name (defaults to service name from config)
|
|
120
|
+
version: Optional tracer version (defaults to service version from config)
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
Tracer instance. Returns a no-op tracer if telemetry is not initialized or disabled.
|
|
124
|
+
"""
|
|
125
|
+
global _tracer, _telemetry_initialized
|
|
126
|
+
|
|
127
|
+
if not _telemetry_initialized:
|
|
128
|
+
# Auto-initialize if not done yet
|
|
129
|
+
init_telemetry()
|
|
130
|
+
|
|
131
|
+
if _tracer is None:
|
|
132
|
+
# Return a no-op tracer if telemetry is disabled
|
|
133
|
+
return trace.NoOpTracer()
|
|
134
|
+
|
|
135
|
+
if name or version:
|
|
136
|
+
return trace.get_tracer(name or "qua-libs", version or "1.0.0")
|
|
137
|
+
|
|
138
|
+
return _tracer
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Context managers for manual span creation.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from contextlib import contextmanager
|
|
6
|
+
from typing import Optional, Dict, Any
|
|
7
|
+
from .config import get_tracer
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@contextmanager
|
|
11
|
+
def trace_span(
|
|
12
|
+
span_name: str,
|
|
13
|
+
attributes: Optional[Dict[str, Any]] = None,
|
|
14
|
+
tracer_name: Optional[str] = None,
|
|
15
|
+
tracer_version: Optional[str] = None,
|
|
16
|
+
):
|
|
17
|
+
"""
|
|
18
|
+
Context manager for creating a trace span.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
span_name: Name for the span
|
|
22
|
+
attributes: Dictionary of attributes to set on the span
|
|
23
|
+
tracer_name: Optional custom tracer name
|
|
24
|
+
tracer_version: Optional custom tracer version
|
|
25
|
+
|
|
26
|
+
Example:
|
|
27
|
+
with trace_span("process_data", attributes={"component": "processor"}):
|
|
28
|
+
# Your code here
|
|
29
|
+
result = process(data)
|
|
30
|
+
"""
|
|
31
|
+
tracer = get_tracer(tracer_name, tracer_version)
|
|
32
|
+
|
|
33
|
+
with tracer.start_as_current_span(span_name) as span:
|
|
34
|
+
if attributes:
|
|
35
|
+
for key, value in attributes.items():
|
|
36
|
+
span.set_attribute(key, value)
|
|
37
|
+
yield span
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@contextmanager
|
|
41
|
+
def trace_span_with_attributes(
|
|
42
|
+
span_name: str,
|
|
43
|
+
tracer_name: Optional[str] = None,
|
|
44
|
+
tracer_version: Optional[str] = None,
|
|
45
|
+
):
|
|
46
|
+
"""
|
|
47
|
+
Context manager that yields a span for manual attribute setting.
|
|
48
|
+
|
|
49
|
+
This is useful when you need to set attributes dynamically within the span.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
span_name: Name for the span
|
|
53
|
+
tracer_name: Optional custom tracer name
|
|
54
|
+
tracer_version: Optional custom tracer version
|
|
55
|
+
|
|
56
|
+
Example:
|
|
57
|
+
with trace_span_with_attributes("simulation") as span:
|
|
58
|
+
span.set_attribute("duration", 100)
|
|
59
|
+
span.set_attribute("iterations", 50)
|
|
60
|
+
# Your code here
|
|
61
|
+
"""
|
|
62
|
+
tracer = get_tracer(tracer_name, tracer_version)
|
|
63
|
+
|
|
64
|
+
with tracer.start_as_current_span(span_name) as span:
|
|
65
|
+
yield span
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Decorators for automatic function instrumentation.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import functools
|
|
6
|
+
from typing import Callable, Any, Optional, Dict
|
|
7
|
+
from opentelemetry.trace import StatusCode
|
|
8
|
+
from .config import get_tracer
|
|
9
|
+
from .utils import record_exception, set_span_status
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def trace_function(
|
|
13
|
+
span_name: Optional[str] = None,
|
|
14
|
+
attributes: Optional[Dict[str, Any]] = None,
|
|
15
|
+
capture_args: bool = False,
|
|
16
|
+
capture_result: bool = False,
|
|
17
|
+
):
|
|
18
|
+
"""
|
|
19
|
+
Decorator to automatically trace a function with OpenTelemetry.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
span_name: Name for the span (defaults to function name)
|
|
23
|
+
attributes: Dictionary of attributes to set on the span
|
|
24
|
+
capture_args: Whether to capture function arguments as span attributes
|
|
25
|
+
capture_result: Whether to capture function return value as span attribute
|
|
26
|
+
|
|
27
|
+
Example:
|
|
28
|
+
@trace_function("process_data", attributes={"component": "data_processor"})
|
|
29
|
+
def process_data(x, y):
|
|
30
|
+
return x + y
|
|
31
|
+
|
|
32
|
+
@trace_function(capture_args=True, capture_result=True)
|
|
33
|
+
def calculate(a, b):
|
|
34
|
+
return a * b
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
def decorator(func: Callable) -> Callable:
|
|
38
|
+
name = span_name or f"{func.__module__}.{func.__name__}"
|
|
39
|
+
|
|
40
|
+
@functools.wraps(func)
|
|
41
|
+
def wrapper(*args, **kwargs):
|
|
42
|
+
tracer = get_tracer()
|
|
43
|
+
|
|
44
|
+
with tracer.start_as_current_span(name) as span:
|
|
45
|
+
# Set initial attributes
|
|
46
|
+
if attributes:
|
|
47
|
+
for key, value in attributes.items():
|
|
48
|
+
span.set_attribute(key, value)
|
|
49
|
+
|
|
50
|
+
# Capture function arguments
|
|
51
|
+
if capture_args:
|
|
52
|
+
for i, arg in enumerate(args):
|
|
53
|
+
span.set_attribute(f"function.arg.{i}", str(arg))
|
|
54
|
+
for key, value in kwargs.items():
|
|
55
|
+
span.set_attribute(f"function.kwarg.{key}", str(value))
|
|
56
|
+
|
|
57
|
+
try:
|
|
58
|
+
result = func(*args, **kwargs)
|
|
59
|
+
|
|
60
|
+
# Capture result
|
|
61
|
+
if capture_result:
|
|
62
|
+
span.set_attribute("function.result", str(result))
|
|
63
|
+
|
|
64
|
+
return result
|
|
65
|
+
except Exception as e:
|
|
66
|
+
record_exception(span, e)
|
|
67
|
+
set_span_status(span, StatusCode.ERROR, str(e))
|
|
68
|
+
raise
|
|
69
|
+
|
|
70
|
+
return wrapper
|
|
71
|
+
|
|
72
|
+
return decorator
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def trace_async_function(
|
|
76
|
+
span_name: Optional[str] = None,
|
|
77
|
+
attributes: Optional[Dict[str, Any]] = None,
|
|
78
|
+
capture_args: bool = False,
|
|
79
|
+
capture_result: bool = False,
|
|
80
|
+
):
|
|
81
|
+
"""
|
|
82
|
+
Decorator to automatically trace an async function with OpenTelemetry.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
span_name: Name for the span (defaults to function name)
|
|
86
|
+
attributes: Dictionary of attributes to set on the span
|
|
87
|
+
capture_args: Whether to capture function arguments as span attributes
|
|
88
|
+
capture_result: Whether to capture function return value as span attribute
|
|
89
|
+
|
|
90
|
+
Example:
|
|
91
|
+
@trace_async_function("async_process")
|
|
92
|
+
async def async_process(data):
|
|
93
|
+
return await process(data)
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
def decorator(func: Callable) -> Callable:
|
|
97
|
+
name = span_name or f"{func.__module__}.{func.__name__}"
|
|
98
|
+
|
|
99
|
+
@functools.wraps(func)
|
|
100
|
+
async def wrapper(*args, **kwargs):
|
|
101
|
+
tracer = get_tracer()
|
|
102
|
+
|
|
103
|
+
with tracer.start_as_current_span(name) as span:
|
|
104
|
+
# Set initial attributes
|
|
105
|
+
if attributes:
|
|
106
|
+
for key, value in attributes.items():
|
|
107
|
+
span.set_attribute(key, value)
|
|
108
|
+
|
|
109
|
+
# Capture function arguments
|
|
110
|
+
if capture_args:
|
|
111
|
+
for i, arg in enumerate(args):
|
|
112
|
+
span.set_attribute(f"function.arg.{i}", str(arg))
|
|
113
|
+
for key, value in kwargs.items():
|
|
114
|
+
span.set_attribute(f"function.kwarg.{key}", str(value))
|
|
115
|
+
|
|
116
|
+
try:
|
|
117
|
+
result = await func(*args, **kwargs)
|
|
118
|
+
|
|
119
|
+
# Capture result
|
|
120
|
+
if capture_result:
|
|
121
|
+
span.set_attribute("function.result", str(result))
|
|
122
|
+
|
|
123
|
+
return result
|
|
124
|
+
except Exception as e:
|
|
125
|
+
record_exception(span, e)
|
|
126
|
+
set_span_status(span, StatusCode.ERROR, str(e))
|
|
127
|
+
raise
|
|
128
|
+
|
|
129
|
+
return wrapper
|
|
130
|
+
|
|
131
|
+
return decorator
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Load project-level telemetry settings from ``.qua-libs/telemetry.toml``.
|
|
3
|
+
|
|
4
|
+
Create this file at the repository root:
|
|
5
|
+
|
|
6
|
+
``<install>/.qua-libs/telemetry.toml``
|
|
7
|
+
|
|
8
|
+
Discovery walks upward from the current working directory.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import os
|
|
14
|
+
import sys
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
from typing import Any, Mapping, Optional
|
|
17
|
+
|
|
18
|
+
from .config import TelemetryConfig
|
|
19
|
+
|
|
20
|
+
CONFIG_DIR_NAME = ".qua-libs"
|
|
21
|
+
CONFIG_FILE_NAME = "telemetry.toml"
|
|
22
|
+
ENV_CONFIG_PATH = "QUA_LIBS_TELEMETRY_CONFIG"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _load_toml(path: Path) -> dict[str, Any]:
|
|
26
|
+
if sys.version_info >= (3, 11):
|
|
27
|
+
import tomllib
|
|
28
|
+
|
|
29
|
+
loader = tomllib.load
|
|
30
|
+
else:
|
|
31
|
+
import tomli
|
|
32
|
+
|
|
33
|
+
loader = tomli.load
|
|
34
|
+
|
|
35
|
+
with path.open("rb") as handle:
|
|
36
|
+
return loader(handle)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _as_bool(value: Any) -> bool:
|
|
40
|
+
if isinstance(value, bool):
|
|
41
|
+
return value
|
|
42
|
+
if isinstance(value, str):
|
|
43
|
+
return value.lower() in ("true", "1", "yes")
|
|
44
|
+
return bool(value)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def find_telemetry_config_file(start: Optional[Path] = None) -> Optional[Path]:
|
|
48
|
+
"""
|
|
49
|
+
Locate the project telemetry config file.
|
|
50
|
+
|
|
51
|
+
Search order:
|
|
52
|
+
1. ``QUA_LIBS_TELEMETRY_CONFIG`` env var (explicit path)
|
|
53
|
+
2. Walk upward from *start* (default: cwd) for ``.qua-libs/telemetry.toml``
|
|
54
|
+
"""
|
|
55
|
+
env_path = os.getenv(ENV_CONFIG_PATH)
|
|
56
|
+
if env_path:
|
|
57
|
+
path = Path(env_path).expanduser()
|
|
58
|
+
return path if path.is_file() else None
|
|
59
|
+
|
|
60
|
+
current = (start or Path.cwd()).resolve()
|
|
61
|
+
for directory in (current, *current.parents):
|
|
62
|
+
candidate = directory / CONFIG_DIR_NAME / CONFIG_FILE_NAME
|
|
63
|
+
if candidate.is_file():
|
|
64
|
+
return candidate
|
|
65
|
+
return None
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def load_telemetry_file_config(start: Optional[Path] = None) -> Optional[dict[str, Any]]:
|
|
69
|
+
"""Return the ``[telemetry]`` table from the project config file, if present."""
|
|
70
|
+
path = find_telemetry_config_file(start)
|
|
71
|
+
if path is None:
|
|
72
|
+
return None
|
|
73
|
+
|
|
74
|
+
data = _load_toml(path)
|
|
75
|
+
section = data.get("telemetry")
|
|
76
|
+
if section is None:
|
|
77
|
+
return None
|
|
78
|
+
if not isinstance(section, dict):
|
|
79
|
+
raise ValueError(f"{path}: [telemetry] must be a table")
|
|
80
|
+
return section
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _resolve_enabled(file_value: Any, default: bool) -> bool:
|
|
84
|
+
env = os.getenv("UPTRACE_ENABLED")
|
|
85
|
+
if env is not None:
|
|
86
|
+
return env.lower() in ("true", "1", "yes")
|
|
87
|
+
if file_value is not None:
|
|
88
|
+
return _as_bool(file_value)
|
|
89
|
+
return default
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _resolve_str(file_value: Any, env_name: str, default: str) -> str:
|
|
93
|
+
env = os.getenv(env_name)
|
|
94
|
+
if env:
|
|
95
|
+
return env
|
|
96
|
+
if file_value is not None:
|
|
97
|
+
return str(file_value)
|
|
98
|
+
return default
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _resolve_optional_str(file_value: Any, env_name: str) -> Optional[str]:
|
|
102
|
+
env = os.getenv(env_name)
|
|
103
|
+
if env:
|
|
104
|
+
return env
|
|
105
|
+
if file_value is not None:
|
|
106
|
+
return str(file_value)
|
|
107
|
+
return None
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def build_project_config(
|
|
111
|
+
*,
|
|
112
|
+
defaults: Mapping[str, Any],
|
|
113
|
+
file_values: Optional[Mapping[str, Any]] = None,
|
|
114
|
+
) -> TelemetryConfig:
|
|
115
|
+
"""
|
|
116
|
+
Build a :class:`TelemetryConfig` from defaults, an optional TOML file, and env vars.
|
|
117
|
+
|
|
118
|
+
Environment variables override file values; file values override *defaults*.
|
|
119
|
+
"""
|
|
120
|
+
file_values = file_values or {}
|
|
121
|
+
|
|
122
|
+
resource_attributes = file_values.get("resource_attributes")
|
|
123
|
+
if resource_attributes is not None and not isinstance(resource_attributes, dict):
|
|
124
|
+
raise ValueError("[telemetry].resource_attributes must be a table")
|
|
125
|
+
|
|
126
|
+
return TelemetryConfig(
|
|
127
|
+
dsn=_resolve_optional_str(file_values.get("dsn"), "UPTRACE_DSN"),
|
|
128
|
+
service_name=_resolve_str(file_values.get("service_name"), "UPTRACE_SERVICE_NAME", defaults["service_name"]),
|
|
129
|
+
service_version=_resolve_str(
|
|
130
|
+
file_values.get("service_version"), "UPTRACE_SERVICE_VERSION", defaults["service_version"]
|
|
131
|
+
),
|
|
132
|
+
deployment_environment=_resolve_str(
|
|
133
|
+
file_values.get("deployment_environment"), "UPTRACE_ENV", defaults["deployment_environment"]
|
|
134
|
+
),
|
|
135
|
+
enabled=_resolve_enabled(file_values.get("enabled"), defaults.get("enabled", False)),
|
|
136
|
+
resource_attributes=resource_attributes or {},
|
|
137
|
+
)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Project-wide telemetry configuration.
|
|
3
|
+
|
|
4
|
+
Telemetry is off by default. Enable it with ``.qua-libs/telemetry.toml`` or
|
|
5
|
+
environment variables (``UPTRACE_ENABLED``, ``UPTRACE_DSN``, …).
|
|
6
|
+
|
|
7
|
+
Resolution order per setting: environment variables, then TOML, then the defaults
|
|
8
|
+
below.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Optional
|
|
13
|
+
|
|
14
|
+
from .config import TelemetryConfig
|
|
15
|
+
from .file_config import build_project_config, load_telemetry_file_config
|
|
16
|
+
|
|
17
|
+
_PROJECT_DEFAULTS = {
|
|
18
|
+
"service_name": "qua-libs",
|
|
19
|
+
"service_version": "1.0.0",
|
|
20
|
+
"deployment_environment": "production",
|
|
21
|
+
"enabled": False,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def load_project_config(start: Optional[Path] = None) -> TelemetryConfig:
|
|
26
|
+
"""Load telemetry settings from defaults, TOML, and environment variables."""
|
|
27
|
+
return build_project_config(
|
|
28
|
+
defaults=_PROJECT_DEFAULTS,
|
|
29
|
+
file_values=load_telemetry_file_config(start),
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
PROJECT_CONFIG = load_project_config()
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Utility functions for working with spans.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Any, Optional
|
|
6
|
+
from opentelemetry.trace import Span, Status, StatusCode
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def set_span_attribute(span: Span, key: str, value: Any) -> None:
|
|
10
|
+
"""
|
|
11
|
+
Set an attribute on a span.
|
|
12
|
+
|
|
13
|
+
Args:
|
|
14
|
+
span: The span to set the attribute on
|
|
15
|
+
key: Attribute key
|
|
16
|
+
value: Attribute value (will be converted to string if not a supported type)
|
|
17
|
+
|
|
18
|
+
Example:
|
|
19
|
+
with trace_span("operation") as span:
|
|
20
|
+
set_span_attribute(span, "user.id", user_id)
|
|
21
|
+
"""
|
|
22
|
+
span.set_attribute(key, value)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def add_span_event(span: Span, name: str, attributes: Optional[dict] = None) -> None:
|
|
26
|
+
"""
|
|
27
|
+
Add an event to a span.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
span: The span to add the event to
|
|
31
|
+
name: Event name
|
|
32
|
+
attributes: Optional dictionary of event attributes
|
|
33
|
+
|
|
34
|
+
Example:
|
|
35
|
+
with trace_span("operation") as span:
|
|
36
|
+
add_span_event(span, "checkpoint_reached", {"checkpoint": 1})
|
|
37
|
+
"""
|
|
38
|
+
span.add_event(name, attributes or {})
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def record_exception(span: Span, exception: Exception, attributes: Optional[dict] = None) -> None:
|
|
42
|
+
"""
|
|
43
|
+
Record an exception on a span.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
span: The span to record the exception on
|
|
47
|
+
exception: The exception to record
|
|
48
|
+
attributes: Optional additional attributes
|
|
49
|
+
|
|
50
|
+
Example:
|
|
51
|
+
try:
|
|
52
|
+
risky_operation()
|
|
53
|
+
except Exception as e:
|
|
54
|
+
with trace_span("operation") as span:
|
|
55
|
+
record_exception(span, e)
|
|
56
|
+
raise
|
|
57
|
+
"""
|
|
58
|
+
span.record_exception(exception, attributes)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def set_span_status(
|
|
62
|
+
span: Span,
|
|
63
|
+
status_code: StatusCode,
|
|
64
|
+
description: Optional[str] = None,
|
|
65
|
+
) -> None:
|
|
66
|
+
"""
|
|
67
|
+
Set the status of a span.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
span: The span to set the status on
|
|
71
|
+
status_code: StatusCode (OK, ERROR, UNSET)
|
|
72
|
+
description: Optional status description
|
|
73
|
+
|
|
74
|
+
Example:
|
|
75
|
+
with trace_span("operation") as span:
|
|
76
|
+
try:
|
|
77
|
+
result = operation()
|
|
78
|
+
set_span_status(span, StatusCode.OK)
|
|
79
|
+
except Exception as e:
|
|
80
|
+
set_span_status(span, StatusCode.ERROR, str(e))
|
|
81
|
+
"""
|
|
82
|
+
span.set_status(Status(status_code, description))
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def get_current_span() -> Span:
|
|
86
|
+
"""
|
|
87
|
+
Get the currently active telemetry span.
|
|
88
|
+
|
|
89
|
+
Use this inside any @node.run_action function that has been
|
|
90
|
+
instrumented with instrument_calibration_node() to access the
|
|
91
|
+
span and set custom attributes dynamically.
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
The current active span, or a no-op span if none is active.
|
|
95
|
+
|
|
96
|
+
Example:
|
|
97
|
+
@node.run_action(skip_if=node.parameters.simulate)
|
|
98
|
+
def analyse_data(node):
|
|
99
|
+
span = get_current_span()
|
|
100
|
+
# ... do analysis ...
|
|
101
|
+
set_span_attribute(span, "fit.q1", "successful")
|
|
102
|
+
"""
|
|
103
|
+
from opentelemetry import trace
|
|
104
|
+
|
|
105
|
+
return trace.get_current_span()
|