diff --git a/Cargo.lock b/Cargo.lock index d55768cbd1..f77fa50a7b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -237,7 +237,7 @@ version = "4.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", "syn", @@ -499,12 +499,6 @@ dependencies = [ "crunchy", ] -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - [[package]] name = "heck" version = "0.5.0" @@ -625,16 +619,6 @@ dependencies = [ "qsc", ] -[[package]] -name = "lock_api" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" -dependencies = [ - "autocfg", - "scopeguard", -] - [[package]] name = "log" version = "0.4.22" @@ -833,29 +817,6 @@ version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "caff54706df99d2a78a5a4e3455ff45448d81ef1bb63c22cd14052ca0e993a3f" -[[package]] -name = "parking_lot" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets", -] - [[package]] name = "paste" version = "1.0.15" @@ -910,9 +871,9 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.20.3" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53bdbb96d49157e65d45cc287af5f32ffadd5f4761438b527b055fb0d4bb8233" +checksum = "831e8e819a138c36e212f3af3fd9eeffed6bf1510a805af35b0edee5ffa59433" dependencies = [ "cfg-if", "indoc", @@ -920,7 +881,7 @@ dependencies = [ "memoffset", "num-bigint", "num-complex", - "parking_lot", + "once_cell", "portable-atomic", "pyo3-build-config", "pyo3-ffi", @@ -930,9 +891,9 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.20.3" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deaa5745de3f5231ce10517a1f5dd97d53e5a2fd77aa6b5842292085831d48d7" +checksum = "1e8730e591b14492a8945cdff32f089250b05f5accecf74aeddf9e8272ce1fa8" dependencies = [ "once_cell", "python3-dll-a", @@ -941,9 +902,9 @@ dependencies = [ [[package]] name = "pyo3-ffi" -version = "0.20.3" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b42531d03e08d4ef1f6e85a2ed422eb678b8cd62b762e53891c05faf0d4afa" +checksum = "5e97e919d2df92eb88ca80a037969f44e5e70356559654962cbb3316d00300c6" dependencies = [ "libc", "pyo3-build-config", @@ -951,9 +912,9 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.20.3" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7305c720fa01b8055ec95e484a6eca7a83c841267f0dd5280f0c8b8551d2c158" +checksum = "eb57983022ad41f9e683a599f2fd13c3664d7063a3ac5714cae4b7bee7d3f206" dependencies = [ "proc-macro2", "pyo3-macros-backend", @@ -963,11 +924,11 @@ dependencies = [ [[package]] name = "pyo3-macros-backend" -version = "0.20.3" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c7e9b68bb9c3149c5b0cade5d07f953d6d125eb4337723c4ccdb665f1f96185" +checksum = "ec480c0c51ddec81019531705acac51bcdbeae563557c982aa8263bb96880372" dependencies = [ - "heck 0.4.1", + "heck", "proc-macro2", "pyo3-build-config", "quote", @@ -1428,15 +1389,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" -[[package]] -name = "redox_syscall" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" -dependencies = [ - "bitflags", -] - [[package]] name = "regex" version = "1.10.6" @@ -1537,12 +1489,6 @@ dependencies = [ "qsc_project", ] -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - [[package]] name = "serde" version = "1.0.208" @@ -1614,12 +1560,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "smallvec" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" - [[package]] name = "smawk" version = "0.3.2" diff --git a/Cargo.toml b/Cargo.toml index a3cc5bbc65..1ac2c00287 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -70,7 +70,7 @@ wasm-bindgen = "0.2" wasm-bindgen-futures = "0.4" rand = "0.8" serde_json = "1.0" -pyo3 = "0.20" +pyo3 = "0.22" quantum-sparse-sim = { git = "https://github.com/qir-alliance/qir-runner", tag = "v0.7.4" } async-trait = "0.1" tokio = { version = "1.35", features = ["macros", "rt"] } diff --git a/pip/src/fs.rs b/pip/src/fs.rs index b3e4936cdb..453a43ac22 100644 --- a/pip/src/fs.rs +++ b/pip/src/fs.rs @@ -104,23 +104,24 @@ impl FileSystem for Py<'_> { } fn read_file(py: Python, read_file: &PyObject, path: &Path) -> PyResult<(Arc, Arc)> { - let read_file_result = read_file.call1(py, PyTuple::new(py, &[path.to_string_lossy()]))?; + let read_file_result = + read_file.call1(py, PyTuple::new_bound(py, &[path.to_string_lossy()]))?; - let tuple = read_file_result.downcast::(py)?; + let tuple = read_file_result.downcast_bound::(py)?; Ok((get_tuple_string(tuple, 0)?, get_tuple_string(tuple, 1)?)) } fn list_directory(py: Python, list_directory: &PyObject, path: &Path) -> PyResult> { let list_directory_result = - list_directory.call1(py, PyTuple::new(py, &[path.to_string_lossy()]))?; + list_directory.call1(py, PyTuple::new_bound(py, &[path.to_string_lossy()]))?; list_directory_result - .downcast::(py)? + .downcast_bound::(py)? .into_iter() .map(|e| { let dict = e.downcast::()?; - let entry_type = match get_dict_string(dict, "type")? { + let entry_type = match get_dict_string(dict, "type")?.to_string().as_str() { "file" => EntryType::File, "folder" => EntryType::Folder, "symlink" => EntryType::Symlink, @@ -146,11 +147,14 @@ fn resolve_path( ) -> PyResult { let resolve_path_result = resolve_path.call1( py, - PyTuple::new(py, &[base.to_string_lossy(), path.to_string_lossy()]), + PyTuple::new_bound(py, &[base.to_string_lossy(), path.to_string_lossy()]), )?; Ok(PathBuf::from( - resolve_path_result.downcast::(py)?.to_str()?, + resolve_path_result + .downcast_bound::(py)? + .str()? + .to_string(), )) } @@ -163,15 +167,15 @@ fn fetch_github( path: &str, ) -> PyResult> { let fetch_github_result = - fetch_github.call1(py, PyTuple::new(py, [owner, repo, r#ref, path]))?; + fetch_github.call1(py, PyTuple::new_bound(py, [owner, repo, r#ref, path]))?; Ok(fetch_github_result - .downcast::(py)? + .downcast_bound::(py)? .to_string() .into()) } -fn get_tuple_string(tuple: &PyTuple, index: usize) -> PyResult> { +fn get_tuple_string(tuple: &Bound<'_, PyTuple>, index: usize) -> PyResult> { Ok(tuple .get_item(index)? .downcast::()? @@ -179,15 +183,15 @@ fn get_tuple_string(tuple: &PyTuple, index: usize) -> PyResult> { .into()) } -fn get_dict_string<'a>(dict: &'a PyDict, key: &'a str) -> PyResult<&'a str> { +fn get_dict_string<'a>(dict: &Bound<'a, PyDict>, key: &'a str) -> PyResult> { match dict.get_item(key)? { - Some(item) => Ok(item.downcast::()?.to_str()?), + Some(item) => Ok(item.downcast::()?.str()?), None => Err(PyException::new_err(format!("missing key `{key}` in dict"))), } } fn diagnostic_from(py: Python<'_>, err: &PyErr) -> miette::Report { - if let Some(traceback) = err.traceback(py) { + if let Some(traceback) = err.traceback_bound(py) { match traceback.format() { Ok(traceback) => miette!(format!("{err}\n{traceback}",)), Err(traceback_err) => { diff --git a/pip/src/interpreter.rs b/pip/src/interpreter.rs index bbaab8cfc2..c6ff589d27 100644 --- a/pip/src/interpreter.rs +++ b/pip/src/interpreter.rs @@ -13,7 +13,6 @@ use pyo3::{ create_exception, exceptions::PyException, prelude::*, - pyclass::CompareOp, types::{PyComplex, PyDict, PyList, PyTuple}, }; use qsc::{ @@ -32,7 +31,7 @@ use resource_estimator::{self as re, estimate_expr}; use std::{cell::RefCell, fmt::Write, path::PathBuf, rc::Rc}; #[pymodule] -fn _native(py: Python, m: &PyModule) -> PyResult<()> { +fn _native<'a>(py: Python<'a>, m: &Bound<'a, PyModule>) -> PyResult<()> { m.add_class::()?; m.add_class::()?; m.add_class::()?; @@ -41,14 +40,14 @@ fn _native(py: Python, m: &PyModule) -> PyResult<()> { m.add_class::()?; m.add_class::()?; m.add_function(wrap_pyfunction!(physical_estimates, m)?)?; - m.add("QSharpError", py.get_type::())?; + m.add("QSharpError", py.get_type_bound::())?; register_noisy_simulator_submodule(py, m)?; Ok(()) } // This ordering must match the _native.pyi file. -#[derive(Clone, Copy)] -#[pyclass(unsendable)] +#[derive(Clone, Copy, PartialEq)] +#[pyclass(unsendable, eq, eq_int)] #[allow(non_camel_case_types)] /// A Q# target profile. /// @@ -83,6 +82,7 @@ thread_local! { static PACKAGE_CACHE: Rc> = Rc::default(); impl Interpreter { #[allow(clippy::too_many_arguments)] #[allow(clippy::needless_pass_by_value)] + #[pyo3(signature = (target, language_features=None, project_root=None, read_file=None, list_directory=None, resolve_path=None, fetch_github=None))] #[new] /// Initializes a new Q# interpreter. pub(crate) fn new( @@ -152,6 +152,7 @@ impl Interpreter { /// :returns value: The value returned by the last statement in the input. /// /// :raises QSharpError: If there is an error interpreting the input. + #[pyo3(signature=(input, callback=None))] fn interpret( &mut self, py: Python, @@ -166,11 +167,13 @@ impl Interpreter { } /// Sets the quantum seed for the interpreter. + #[pyo3(signature=(seed=None))] fn set_quantum_seed(&mut self, seed: Option) { self.interpreter.set_quantum_seed(seed); } /// Sets the classical seed for the interpreter. + #[pyo3(signature=(seed=None))] fn set_classical_seed(&mut self, seed: Option) { self.interpreter.set_classical_seed(seed); } @@ -191,6 +194,7 @@ impl Interpreter { Circuit(self.interpreter.get_circuit()).into_py(py) } + #[pyo3(signature=(entry_expr=None, callback=None))] fn run( &mut self, py: Python, @@ -224,6 +228,7 @@ impl Interpreter { /// qubits or arrays of qubits as parameters. /// /// :raises QSharpError: If there is an error synthesizing the circuit. + #[pyo3(signature=(entry_expr=None, operation=None))] fn circuit( &mut self, py: Python, @@ -364,28 +369,23 @@ pub(crate) struct StateDumpData(pub(crate) DisplayableState); #[pymethods] impl StateDumpData { - fn get_dict(&self, py: Python) -> PyResult> { - Ok(PyDict::from_sequence( + fn get_dict<'a>(&self, py: Python<'a>) -> PyResult> { + PyDict::from_sequence_bound(&PyList::new_bound( py, - PyList::new( - py, - self.0 - .0 - .iter() - .map(|(k, v)| { - PyTuple::new( - py, - &[ - k.clone().into_py(py), - PyComplex::from_doubles(py, v.re, v.im).into(), - ], - ) - }) - .collect::>(), - ) - .into_py(py), - )? - .into_py(py)) + self.0 + .0 + .iter() + .map(|(k, v)| { + PyTuple::new_bound( + py, + &[ + k.clone().into_py(py), + PyComplex::from_doubles_bound(py, v.re, v.im).into(), + ], + ) + }) + .collect::>(), + )) } #[getter] @@ -414,8 +414,8 @@ impl StateDumpData { } } -#[pyclass(unsendable)] #[derive(PartialEq)] +#[pyclass(unsendable, eq, eq_int)] /// A Q# measurement result. pub(crate) enum Result { Zero, @@ -441,22 +441,10 @@ impl Result { Result::One => 1, } } - - fn __richcmp__(&self, other: &Self, op: CompareOp) -> bool { - let this = i32::from(*self == Result::One); - let other = i32::from(*other == Result::One); - match op { - CompareOp::Lt => this < other, - CompareOp::Le => this <= other, - CompareOp::Eq => this == other, - CompareOp::Ne => this != other, - CompareOp::Gt => this > other, - CompareOp::Ge => this >= other, - } - } } -#[pyclass(unsendable)] +#[derive(PartialEq)] +#[pyclass(unsendable, eq, eq_int)] /// A Q# Pauli operator. pub(crate) enum Pauli { I, @@ -493,12 +481,13 @@ impl IntoPy for ValueWrapper { // Special case Value::unit as None py.None() } else { - PyTuple::new(py, val.iter().map(|v| ValueWrapper(v.clone()).into_py(py))) + PyTuple::new_bound(py, val.iter().map(|v| ValueWrapper(v.clone()).into_py(py))) .into_py(py) } } Value::Array(val) => { - PyList::new(py, val.iter().map(|v| ValueWrapper(v.clone()).into_py(py))).into_py(py) + PyList::new_bound(py, val.iter().map(|v| ValueWrapper(v.clone()).into_py(py))) + .into_py(py) } _ => format!("<{}> {}", Value::type_name(&self.0), &self.0).into_py(py), } @@ -521,7 +510,7 @@ impl Receiver for OptionalCallbackReceiver<'_> { callback .call1( self.py, - PyTuple::new( + PyTuple::new_bound( self.py, &[Py::new(self.py, Output(out)).expect("should be able to create output")], ), @@ -537,7 +526,7 @@ impl Receiver for OptionalCallbackReceiver<'_> { callback .call1( self.py, - PyTuple::new( + PyTuple::new_bound( self.py, &[Py::new(self.py, Output(out)).expect("should be able to create output")], ), diff --git a/pip/src/noisy_simulator.rs b/pip/src/noisy_simulator.rs index e2f394c284..d536940765 100644 --- a/pip/src/noisy_simulator.rs +++ b/pip/src/noisy_simulator.rs @@ -8,8 +8,14 @@ use num_complex::Complex; use pyo3::{exceptions::PyException, prelude::*}; type PythonMatrix = Vec>>; -pub(crate) fn register_noisy_simulator_submodule(py: Python, m: &PyModule) -> PyResult<()> { - m.add("NoisySimulatorError", py.get_type::())?; +pub(crate) fn register_noisy_simulator_submodule<'a>( + py: Python<'a>, + m: &Bound<'a, PyModule>, +) -> PyResult<()> { + m.add( + "NoisySimulatorError", + py.get_type_bound::(), + )?; m.add_class::()?; m.add_class::()?; m.add_class::()?; @@ -186,6 +192,7 @@ pub(crate) struct DensityMatrixSimulator(noisy_simulator::DensityMatrixSimulator #[pymethods] impl DensityMatrixSimulator { #[new] + #[pyo3(signature=(number_of_qubits, seed=None))] pub fn new(number_of_qubits: usize, seed: Option) -> Self { if let Some(seed) = seed { Self(noisy_simulator::DensityMatrixSimulator::new_with_seed( @@ -319,6 +326,7 @@ pub(crate) struct StateVectorSimulator(noisy_simulator::StateVectorSimulator); #[pymethods] impl StateVectorSimulator { #[new] + #[pyo3(signature=(number_of_qubits, seed=None))] pub fn new(number_of_qubits: usize, seed: Option) -> Self { if let Some(seed) = seed { Self(noisy_simulator::StateVectorSimulator::new_with_seed(