From ecd3b115afe177d8418694b1fd5ba3f628c1c24c Mon Sep 17 00:00:00 2001 From: Eric Hulburd Date: Mon, 25 Apr 2022 16:01:54 -0700 Subject: [PATCH 1/2] Update: support qcs account headers on engagement creation --- CHANGELOG.md | 2 ++ poetry.lock | 8 ++--- pyproject.toml | 2 +- test/unit/test_quantum_computer.py | 50 +++++++++++++++++++++++++++++- 4 files changed, 56 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d14c756b..d94072d89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ Changelog - `QAMExecutionResult` now includes `execution_duration_microseconds`, providing the amount of time a job held exclusive hardware access. (@randall-fulton, #1436) + +- Upgrade `qcs-api-client` so that clients can specify a QCS account on their profile, which `qcs-api-client` will in turn use to set `X-QCS-ACCOUNT-{ID/TYPE}` headers on outgoing QCS requests, most notably during engagement creation. (@erichulburd, #1439) ### Bugfixes diff --git a/poetry.lock b/poetry.lock index 1e1625a74..0af665e9f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1005,7 +1005,7 @@ py = {version = "*", markers = "implementation_name == \"pypy\""} [[package]] name = "qcs-api-client" -version = "0.20.10" +version = "0.20.12" description = "A client library for accessing the Rigetti QCS API" category = "main" optional = false @@ -1411,7 +1411,7 @@ latex = ["ipython"] [metadata] lock-version = "1.1" python-versions = "^3.7" -content-hash = "a2b41292a997e87f5cc8c599e8a824feb1d7f75c98cec276e04903282007a89e" +content-hash = "d2af98c6620da01edbf16ab8815b833152357794f62122671ca937e3a5ecede3" [metadata.files] alabaster = [ @@ -2057,8 +2057,8 @@ pyzmq = [ {file = "pyzmq-22.1.0.tar.gz", hash = "sha256:7040d6dd85ea65703904d023d7f57fab793d7ffee9ba9e14f3b897f34ff2415d"}, ] qcs-api-client = [ - {file = "qcs-api-client-0.20.10.tar.gz", hash = "sha256:4859884f43a3a29a90171c0470fb8a8e3524a50d6986ff5e12c4b877594ee837"}, - {file = "qcs_api_client-0.20.10-py3-none-any.whl", hash = "sha256:8ba34444f623cb684b9ee6717c95490fbf20e2209856964c02c3e5578a4dc16c"}, + {file = "qcs-api-client-0.20.12.tar.gz", hash = "sha256:e7815d0d3e819c95aac741716f664172e0e8d84caad8e29c1f6c2bf02cf497b4"}, + {file = "qcs_api_client-0.20.12-py3-none-any.whl", hash = "sha256:075b13bd97ed624d7f702c2f6a43dd7f1caf947bf73db5031e947377a63eb39c"}, ] recommonmark = [ {file = "recommonmark-0.7.1-py2.py3-none-any.whl", hash = "sha256:1b1db69af0231efce3fa21b94ff627ea33dee7079a01dd0a7f8482c3da148b3f"}, diff --git a/pyproject.toml b/pyproject.toml index fce69ff55..1f30998a0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,7 +28,7 @@ lark = "^0.11.1" rpcq = "^3.10.0" networkx = "^2.5" importlib-metadata = { version = "^3.7.3", python = "<3.8" } -qcs-api-client = ">=0.8.1,<0.21.0" +qcs-api-client = ">=0.20.12,<0.21.0" retry = "^0.9.2" # latex extra diff --git a/test/unit/test_quantum_computer.py b/test/unit/test_quantum_computer.py index fd8207f51..b9d66321e 100644 --- a/test/unit/test_quantum_computer.py +++ b/test/unit/test_quantum_computer.py @@ -1,6 +1,7 @@ import itertools import random from test.unit.utils import DummyCompiler +from typing import cast import networkx as nx import numpy as np @@ -8,7 +9,6 @@ import respx from pyquil import Program, list_quantum_computers -from pyquil.api import QCSClientConfiguration from pyquil.api._quantum_computer import ( QuantumComputer, _check_min_num_trials_for_symmetrized_readout, @@ -23,6 +23,7 @@ _symmetrization, get_qc, ) +from pyquil.api._qpu import QPU from pyquil.api._qvm import QVM from pyquil.experiment import Experiment, ExperimentSetting from pyquil.experiment._main import _pauli_to_product_state @@ -32,6 +33,7 @@ from pyquil.pyqvm import PyQVM from pyquil.quantum_processor import NxQuantumProcessor from pyquil.quilbase import Declare, MemoryReference +from qcs_api_client.client import QCSAccountType, QCSClientConfiguration from qcs_api_client.models.instruction_set_architecture import InstructionSetArchitecture from rpcq.messages import ParameterAref @@ -849,3 +851,49 @@ def test_get_qc_endpoint_id(client_configuration: QCSClientConfiguration, qcs_as qc = get_qc("test", endpoint_id="test-endpoint") assert qc.qam._qpu_client._endpoint_id == "test-endpoint" + + +@respx.mock +def test_get_qc_with_group_account(client_configuration: QCSClientConfiguration, qcs_aspen8_isa: InstructionSetArchitecture): + """ + Assert that a client may specify a ``QCSClientConfigurationSettingsProfile`` representing a QCS group + account and create a group account engagement via headers. + """ + respx.get( + url=f"{client_configuration.profile.api_url}/v1/quantumProcessors/test/instructionSetArchitecture", + ).respond(json=qcs_aspen8_isa.to_dict()) + + group_profile = client_configuration.profile.copy() + group_profile.account_id = "group0" + group_profile.account_type = QCSAccountType.group + client_configuration.settings.profiles["my-group-profile"] = group_profile + client_configuration.profile_name = "my-group-profile" + qc = get_qc("test", endpoint_id="test-endpoint", client_configuration=client_configuration) + + assert isinstance(qc, QuantumComputer) + quantum_computer = cast(QuantumComputer, qc) + assert isinstance(quantum_computer.qam, QPU) + qpu = cast(QPU, quantum_computer.qam) + engagement_manager = qpu._qpu_client._engagement_manager + + respx.post( + url=f"{client_configuration.profile.api_url}/v1/engagements", + headers__contains={ + 'X-QCS-ACCOUNT-ID': 'group0', + 'X-QCS-ACCOUNT-TYPE': QCSAccountType.group.value, + }, + ).respond(json={ + 'address': 'address', + 'endpointId': 'endpointId', + 'quantumProcessorId': 'quantumProcessorId', + 'userId': 'userId', + 'expiresAt': '01-01-2200T00:00:00Z', + 'credentials': { + 'clientPublic': 'faux', + 'clientSecret': 'faux', + 'serverPublic': 'faux', + } + }) + + engagement = engagement_manager.get_engagement(quantum_processor_id='test') + assert 'faux' == engagement.credentials.client_public From 69c4b50ea884355de451cc5090e258111711a6b8 Mon Sep 17 00:00:00 2001 From: Eric Hulburd Date: Wed, 27 Apr 2022 15:55:09 -0700 Subject: [PATCH 2/2] Docs: provide a link to QCS cli configuration --- pyquil/api/_quantum_computer.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyquil/api/_quantum_computer.py b/pyquil/api/_quantum_computer.py index c9e31b588..1c30c1b53 100644 --- a/pyquil/api/_quantum_computer.py +++ b/pyquil/api/_quantum_computer.py @@ -795,6 +795,8 @@ def get_qc( :param compiler_timeout: Time limit for compilation requests, in seconds. :param execution_timeout: Time limit for execution requests, in seconds. :param client_configuration: Optional client configuration. If none is provided, a default one will be loaded. + For more information on setting up QCS credentials, see documentation for using the QCS CLI: + [https://docs.rigetti.com/qcs/guides/using-the-qcs-cli#configuring-credentials]. :param endpoint_id: Optional quantum processor endpoint ID, as used in the `QCS API Docs`_. :param engagement_manager: Optional engagement manager. If none is provided, a default one will be created.