From 03764b43c86c36381d67ae69205d776c591da82d Mon Sep 17 00:00:00 2001 From: Ian Davis Date: Thu, 26 Sep 2024 11:02:10 -0700 Subject: [PATCH] Add `from_str` to `TargetProfile` --- pip/qsharp/_native.pyi | 8 ++++++++ pip/src/interpreter.rs | 29 +++++++++++++++++++++++++---- pip/tests/test_qsharp.py | 15 +++++++++++++++ 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/pip/qsharp/_native.pyi b/pip/qsharp/_native.pyi index 3a2aa32dd9..97492c78e1 100644 --- a/pip/qsharp/_native.pyi +++ b/pip/qsharp/_native.pyi @@ -72,6 +72,14 @@ class TargetProfile(Enum): which will be used to run the Q# program. """ + @classmethod + def from_str(cls, value: str) -> TargetProfile: ... + """ + Creates a target profile from a string. + :param value: The string to parse. + :raises ValueError: If the string does not match any target profile. + """ + Base: TargetProfile """ Target supports the minimal set of capabilities required to run a quantum diff --git a/pip/src/interpreter.rs b/pip/src/interpreter.rs index f4d61bafaf..780897ad01 100644 --- a/pip/src/interpreter.rs +++ b/pip/src/interpreter.rs @@ -15,9 +15,9 @@ use num_bigint::BigUint; use num_complex::Complex64; use pyo3::{ create_exception, - exceptions::PyException, + exceptions::{PyException, PyValueError}, prelude::*, - types::{PyComplex, PyDict, PyList, PyTuple}, + types::{PyComplex, PyDict, PyList, PyTuple, PyType}, }; use qsc::{ fir, @@ -33,7 +33,7 @@ use qsc::{ }; use resource_estimator::{self as re, estimate_expr}; -use std::{cell::RefCell, fmt::Write, path::PathBuf, rc::Rc}; +use std::{cell::RefCell, fmt::Write, path::PathBuf, rc::Rc, str::FromStr}; /// If the classes are not Send, the Python interpreter /// will not be able to use them in a separate thread. @@ -111,11 +111,32 @@ pub(crate) enum TargetProfile { } #[pymethods] -#[allow(clippy::trivially_copy_pass_by_ref)] impl TargetProfile { + #[allow(clippy::trivially_copy_pass_by_ref)] fn __str__(&self) -> String { Into::::into(*self).to_str().to_owned() } + + /// Creates a target profile from a string. + /// :param value: The string to parse. + /// :raises ValueError: If the string does not match any target profile. + #[classmethod] + #[allow(clippy::needless_pass_by_value)] + fn from_str(_cls: &Bound<'_, PyType>, key: String) -> pyo3::PyResult { + let profile = Profile::from_str(key.as_str()) + .map_err(|()| PyValueError::new_err(format!("{key} is not a valid target profile")))?; + Ok(TargetProfile::from(profile)) + } +} + +impl From for TargetProfile { + fn from(profile: Profile) -> Self { + match profile { + Profile::Base => TargetProfile::Base, + Profile::AdaptiveRI => TargetProfile::Adaptive_RI, + Profile::Unrestricted => TargetProfile::Unrestricted, + } + } } impl From for Profile { diff --git a/pip/tests/test_qsharp.py b/pip/tests/test_qsharp.py index 9d7cf906f3..322ffed9ca 100644 --- a/pip/tests/test_qsharp.py +++ b/pip/tests/test_qsharp.py @@ -1,6 +1,7 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. +import pytest import qsharp import qsharp.utils from contextlib import redirect_stdout @@ -343,3 +344,17 @@ def test_target_profile_str_values_match_enum_values() -> None: target_profile = qsharp.TargetProfile.Unrestricted str_value = str(target_profile) assert str_value == "Unrestricted" + + +def test_target_profile_from_str_match_enum_values() -> None: + target_profile = qsharp.TargetProfile.Base + str_value = str(target_profile) + assert qsharp.TargetProfile.from_str(str_value) == target_profile + target_profile = qsharp.TargetProfile.Adaptive_RI + str_value = str(target_profile) + assert qsharp.TargetProfile.from_str(str_value) == target_profile + target_profile = qsharp.TargetProfile.Unrestricted + str_value = str(target_profile) + assert qsharp.TargetProfile.from_str(str_value) == target_profile + with pytest.raises(ValueError): + qsharp.TargetProfile.from_str("Invalid")