From 70d9476fc0c528e591ef3cf90c16c0078c1b0e07 Mon Sep 17 00:00:00 2001 From: Matthew Neeley Date: Fri, 11 Feb 2022 15:37:42 -0800 Subject: [PATCH 1/6] Refactor qcs_notebook to use application default creds --- .../cirq_google/engine/qcs_notebook.py | 92 ++++++++----------- 1 file changed, 38 insertions(+), 54 deletions(-) diff --git a/cirq-google/cirq_google/engine/qcs_notebook.py b/cirq-google/cirq_google/engine/qcs_notebook.py index c3148a34826..5f832b3a742 100644 --- a/cirq-google/cirq_google/engine/qcs_notebook.py +++ b/cirq-google/cirq_google/engine/qcs_notebook.py @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import os import dataclasses from typing import Union, Optional @@ -24,8 +23,7 @@ Sycamore, SQRT_ISWAP_INV_PARAMETERS, PhasedFSimCharacterization, - get_engine_sampler, - get_engine_device, + get_engine, ) @@ -57,68 +55,54 @@ def get_qcs_objects_for_notebook( An instance of DeviceSamplerInfo. """ - # Converting empty strings to None for form field inputs + # Convert empty strings to None for form field inputs. if project_id == "": project_id = None if processor_id == "": processor_id = None - google_cloud_signin_failed: bool = False - if project_id is None: - if 'GOOGLE_CLOUD_PROJECT' not in os.environ: - print("No project_id provided and environment variable GOOGLE_CLOUD_PROJECT not set.") - google_cloud_signin_failed = True - else: # pragma: no cover - os.environ['GOOGLE_CLOUD_PROJECT'] = project_id - - # Following code runs the user through the Colab OAuth process. - - # Checks for Google Application Default Credentials and runs - # interactive login if the notebook is executed in Colab. In - # case the notebook is executed in Jupyter notebook or other - # IPython runtimes, no interactive login is provided, it is - # assumed that the `GOOGLE_APPLICATION_CREDENTIALS` env var is - # set or `gcloud auth application-default login` was executed - # already. For more information on using Application Default Credentials - # see https://cloud.google.com/docs/authentication/production - + # Check for Google Application Default Credentials and run + # interactive login if the notebook is executed in Colab. In + # case the notebook is executed in Jupyter notebook or other + # IPython runtimes, no interactive login is provided, it is + # assumed that the `GOOGLE_APPLICATION_CREDENTIALS` env var is + # set or `gcloud auth application-default login` was executed + # already. For more information on using Application Default Credentials + # see https://cloud.google.com/docs/authentication/production + try: + from IPython import get_ipython + + in_colab = 'google.colab' in str(get_ipython()) + except ImportError: in_colab = False - try: - from IPython import get_ipython - - in_colab = 'google.colab' in str(get_ipython()) - - if in_colab: - from google.colab import auth - - print("Getting OAuth2 credentials.") - print("Press enter after entering the verification code.") - auth.authenticate_user(clear_output=False) - print("Authentication complete.") - else: - print( - "Notebook isn't executed with Colab, assuming " - "Application Default Credentials are setup." - ) - except: - pass - # End of Google Colab Authentication segment + if in_colab: + from google.colab import auth - device: cirq.Device - sampler: Union[PhasedFSimEngineSimulator, QuantumEngineSampler] - if google_cloud_signin_failed or processor_id is None: + print("Getting OAuth2 credentials.") + print("Press enter after entering the verification code.") + try: + auth.authenticate_user(clear_output=False) + print("Authentication complete.") + except Exception as exc: + print(f"Authentication failed: {exc}") + else: + print("Not running in a colab kernel. Will use Application Default Credentials.") + + # Attempt to connect to the Quantum Engine API, and use a simulator if unable to connect. + try: + processor = get_engine(project_id).get_processor(processor_id) + device = processor.get_device() + sampler = processor.get_sampler() + signed_in = True + except Exception as exc: + print(f"Unable to connect to quantum engine: {exc}") print("Using a noisy simulator.") sampler = PhasedFSimEngineSimulator.create_with_random_gaussian_sqrt_iswap( mean=SQRT_ISWAP_INV_PARAMETERS, sigma=PhasedFSimCharacterization(theta=0.01, zeta=0.10, chi=0.01, gamma=0.10, phi=0.02), ) device = Sycamore - else: # pragma: no cover - device = get_engine_device(processor_id) - sampler = get_engine_sampler(processor_id, gate_set_name="sqrt_iswap") - return QCSObjectsForNotebook( - device=device, - sampler=sampler, - signed_in=not google_cloud_signin_failed, - ) + signed_in = False + + return QCSObjectsForNotebook(device=device, sampler=sampler, signed_in=signed_in) From c298fb6c1a77a8993d1a5871f190165cc73c77ad Mon Sep 17 00:00:00 2001 From: Matthew Neeley Date: Tue, 1 Mar 2022 17:07:30 -0800 Subject: [PATCH 2/6] Autoselect a processor if not specified --- cirq-google/cirq_google/engine/qcs_notebook.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/cirq-google/cirq_google/engine/qcs_notebook.py b/cirq-google/cirq_google/engine/qcs_notebook.py index 5f832b3a742..6716ee666bb 100644 --- a/cirq-google/cirq_google/engine/qcs_notebook.py +++ b/cirq-google/cirq_google/engine/qcs_notebook.py @@ -90,8 +90,18 @@ def get_qcs_objects_for_notebook( print("Not running in a colab kernel. Will use Application Default Credentials.") # Attempt to connect to the Quantum Engine API, and use a simulator if unable to connect. + sampler: Union[PhasedFSimEngineSimulator, QuantumEngineSampler] try: - processor = get_engine(project_id).get_processor(processor_id) + engine = get_engine(project_id) + if processor_id is None: + processors = engine.list_processors() + if not processors: + raise ValueError("No processors available.") + processor = processors[0] + print(f"Available processors: {[p.processor_id for p in processors]}") + print(f"Using processor: {processor.processor_id}") + else: + processor = engine.get_processor(processor_id) device = processor.get_device() sampler = processor.get_sampler() signed_in = True From 6854e146ddd7fa7784951f0edb52a3ab48e31d3f Mon Sep 17 00:00:00 2001 From: Matthew Neeley Date: Wed, 2 Mar 2022 11:24:44 -0800 Subject: [PATCH 3/6] Disable erroneous lint check --- cirq-google/cirq_google/engine/qcs_notebook.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cirq-google/cirq_google/engine/qcs_notebook.py b/cirq-google/cirq_google/engine/qcs_notebook.py index 6716ee666bb..151e926a317 100644 --- a/cirq-google/cirq_google/engine/qcs_notebook.py +++ b/cirq-google/cirq_google/engine/qcs_notebook.py @@ -38,6 +38,9 @@ def is_simulator(self): return isinstance(self.sampler, PhasedFSimEngineSimulator) +# Disable missing-raises-doc lint check, since pylint gets confused +# by exceptions that are raised and caught within this function. +# pylint: disable=missing-raises-doc def get_qcs_objects_for_notebook( project_id: Optional[str] = None, processor_id: Optional[str] = None ) -> QCSObjectsForNotebook: @@ -116,3 +119,5 @@ def get_qcs_objects_for_notebook( signed_in = False return QCSObjectsForNotebook(device=device, sampler=sampler, signed_in=signed_in) + +# pylint: enable=missing-raises-doc From 339bdf572fe8e9c89197e0629b2445f9643e0af0 Mon Sep 17 00:00:00 2001 From: Matthew Neeley Date: Thu, 10 Mar 2022 10:31:25 -0800 Subject: [PATCH 4/6] fmt --- cirq-google/cirq_google/engine/qcs_notebook.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cirq-google/cirq_google/engine/qcs_notebook.py b/cirq-google/cirq_google/engine/qcs_notebook.py index 151e926a317..ef1fb34722d 100644 --- a/cirq-google/cirq_google/engine/qcs_notebook.py +++ b/cirq-google/cirq_google/engine/qcs_notebook.py @@ -120,4 +120,5 @@ def get_qcs_objects_for_notebook( return QCSObjectsForNotebook(device=device, sampler=sampler, signed_in=signed_in) + # pylint: enable=missing-raises-doc From a45a1d31d98e4c9ca02750074c2169b9b3195b82 Mon Sep 17 00:00:00 2001 From: Matthew Neeley Date: Thu, 10 Mar 2022 10:49:35 -0800 Subject: [PATCH 5/6] Add nocover --- cirq-google/cirq_google/engine/qcs_notebook.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cirq-google/cirq_google/engine/qcs_notebook.py b/cirq-google/cirq_google/engine/qcs_notebook.py index ef1fb34722d..f73f650aeaf 100644 --- a/cirq-google/cirq_google/engine/qcs_notebook.py +++ b/cirq-google/cirq_google/engine/qcs_notebook.py @@ -43,7 +43,7 @@ def is_simulator(self): # pylint: disable=missing-raises-doc def get_qcs_objects_for_notebook( project_id: Optional[str] = None, processor_id: Optional[str] = None -) -> QCSObjectsForNotebook: +) -> QCSObjectsForNotebook: # pragma: nocover """Authenticates on Google Cloud, can return a Device and Simulator. Args: From 83a294ad70ad3bb5f6a806c2aa8c6fd94199c904 Mon Sep 17 00:00:00 2001 From: Matthew Neeley Date: Wed, 6 Apr 2022 00:08:22 -0700 Subject: [PATCH 6/6] Minor refactors --- .../cirq_google/engine/qcs_notebook.py | 25 +++++-------------- .../cirq_google/engine/qcs_notebook_test.py | 4 +-- 2 files changed, 8 insertions(+), 21 deletions(-) diff --git a/cirq-google/cirq_google/engine/qcs_notebook.py b/cirq-google/cirq_google/engine/qcs_notebook.py index f73f650aeaf..f26bdf0be9f 100644 --- a/cirq-google/cirq_google/engine/qcs_notebook.py +++ b/cirq-google/cirq_google/engine/qcs_notebook.py @@ -58,12 +58,6 @@ def get_qcs_objects_for_notebook( An instance of DeviceSamplerInfo. """ - # Convert empty strings to None for form field inputs. - if project_id == "": - project_id = None - if processor_id == "": - processor_id = None - # Check for Google Application Default Credentials and run # interactive login if the notebook is executed in Colab. In # case the notebook is executed in Jupyter notebook or other @@ -73,15 +67,10 @@ def get_qcs_objects_for_notebook( # already. For more information on using Application Default Credentials # see https://cloud.google.com/docs/authentication/production try: - from IPython import get_ipython - - in_colab = 'google.colab' in str(get_ipython()) - except ImportError: - in_colab = False - - if in_colab: from google.colab import auth - + except ImportError: + print("Not running in a colab kernel. Will use Application Default Credentials.") + else: print("Getting OAuth2 credentials.") print("Press enter after entering the verification code.") try: @@ -89,22 +78,20 @@ def get_qcs_objects_for_notebook( print("Authentication complete.") except Exception as exc: print(f"Authentication failed: {exc}") - else: - print("Not running in a colab kernel. Will use Application Default Credentials.") # Attempt to connect to the Quantum Engine API, and use a simulator if unable to connect. sampler: Union[PhasedFSimEngineSimulator, QuantumEngineSampler] try: engine = get_engine(project_id) - if processor_id is None: + if processor_id: + processor = engine.get_processor(processor_id) + else: processors = engine.list_processors() if not processors: raise ValueError("No processors available.") processor = processors[0] print(f"Available processors: {[p.processor_id for p in processors]}") print(f"Using processor: {processor.processor_id}") - else: - processor = engine.get_processor(processor_id) device = processor.get_device() sampler = processor.get_sampler() signed_in = True diff --git a/cirq-google/cirq_google/engine/qcs_notebook_test.py b/cirq-google/cirq_google/engine/qcs_notebook_test.py index ef446912f84..c0157a8bdf3 100644 --- a/cirq-google/cirq_google/engine/qcs_notebook_test.py +++ b/cirq-google/cirq_google/engine/qcs_notebook_test.py @@ -19,8 +19,8 @@ def test_get_device_sampler(): result = get_qcs_objects_for_notebook() assert result.device is cg.Sycamore - assert result.signed_in is False - assert type(result.sampler) is cg.PhasedFSimEngineSimulator + assert not result.signed_in + assert isinstance(result.sampler, cg.PhasedFSimEngineSimulator) assert result.is_simulator result = get_qcs_objects_for_notebook("", "")