diff --git a/crates/qasm3/src/lib.rs b/crates/qasm3/src/lib.rs index 3c53093f49f4..552394e38a88 100644 --- a/crates/qasm3/src/lib.rs +++ b/crates/qasm3/src/lib.rs @@ -74,9 +74,9 @@ fn restore_include_path(include_path: Option<&OsStr>) { /// /// Args: /// source (str): the program source in a Python string. -/// custom_instructions (Iterable[CustomGate]): Python constructors to use for particular named -/// gates. If not supplied, Qiskit will use its own standard-library constructors for -/// gates defined in the OpenQASM 3.0 standard-library file ``stdgates.inc``. +/// custom_gates (Iterable[CustomGate]): Python constructors to use for particular named gates. +/// If not supplied, Qiskit will use its own standard-library constructors for gates +/// defined in the OpenQASM 3.0 standard-library file ``stdgates.inc``. /// include_path (Iterable[str]): the path to search when resolving ``include`` statements. /// If not given, Qiskit will arrange for this to point to a location containing /// ``stdgates.inc`` only. Paths are tried in the sequence order. @@ -95,12 +95,12 @@ fn restore_include_path(include_path: Option<&OsStr>) { /// In the case of a parsing error, most of the error messages are printed to the terminal /// and formatted, for better legibility. #[pyfunction] -#[pyo3(pass_module, signature = (source, /, *, custom_instructions=None, include_path=None))] +#[pyo3(pass_module, signature = (source, /, *, custom_gates=None, include_path=None))] pub fn loads( module: &PyModule, py: Python, source: String, - custom_instructions: Option>, + custom_gates: Option>, include_path: Option>, ) -> PyResult { let old_path = set_include_path(module, include_path.as_deref())?; @@ -112,7 +112,7 @@ pub fn loads( "errors during parsing; see printed errors", )); } - let gates = match custom_instructions { + let gates = match custom_gates { Some(gates) => gates .into_iter() .map(|gate| (gate.name().to_owned(), gate)) @@ -137,9 +137,9 @@ pub fn loads( /// opened it is consumed in Python space, whereas filenames are opened and consumed in /// Rust space; there might be slightly different performance characteristics, depending on /// your system and how the streams are buffered by default. -/// custom_instructions (Iterable[CustomGate]): Python constructors to use for particular named -/// gates. If not supplied, Qiskit will use its own standard-library constructors for -/// gates defined in the OpenQASM 3.0 standard-library file ``stdgates.inc``. +/// custom_gates (Iterable[CustomGate]): Python constructors to use for particular named gates. +/// If not supplied, Qiskit will use its own standard-library constructors for gates +/// defined in the OpenQASM 3.0 standard-library file ``stdgates.inc``. /// include_path (Iterable[str]): the path to search when resolving ``include`` statements. /// If not given, Qiskit will arrange for this to point to a location containing /// ``stdgates.inc`` only. Paths are tried in the sequence order. @@ -160,13 +160,13 @@ pub fn loads( #[pyfunction] #[pyo3( pass_module, - signature = (pathlike_or_filelike, /, *, custom_instructions=None, include_path=None), + signature = (pathlike_or_filelike, /, *, custom_gates=None, include_path=None), )] pub fn load( module: &PyModule, py: Python, pathlike_or_filelike: &PyAny, - custom_instructions: Option>, + custom_gates: Option>, include_path: Option>, ) -> PyResult { let source = @@ -183,7 +183,7 @@ pub fn load( QASM3ImporterError::new_err(format!("failed to read file '{:?}': {:?}", &path, err)) })? }; - loads(module, py, source, custom_instructions, include_path) + loads(module, py, source, custom_gates, include_path) } /// Create a suitable sequence for use with the ``custom_gates`` of :func:`load` and :func:`loads`, diff --git a/pyproject.toml b/pyproject.toml index d42b249a1058..60511c2b8197 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -173,6 +173,8 @@ select = [ extension-pkg-allow-list = [ "numpy", "qiskit._accelerate", + "qiskit._qasm2", + "qiskit._qasm3", # We can't allow pylint to load qiskit._qasm2 because it's not able to # statically resolve the cyclical load of the exception and it bugs out. "retworkx", diff --git a/qiskit/exceptions.py b/qiskit/exceptions.py index e26d4097fa90..796bc16d30b5 100644 --- a/qiskit/exceptions.py +++ b/qiskit/exceptions.py @@ -61,6 +61,25 @@ is not present, but will raise :exc:`OptionalDependencyImportWarning` to let you know about it. .. autoexception:: OptionalDependencyImportWarning + +When experimental features are being used, Qiskit will raise :exc:`ExperimentalWarning`. + +.. autoexception:: ExperimentalWarning + + +Filtering warnings +------------------ + +Python has built-in mechanisms to filter warnings, described in the documentation of the +:mod:`warnings` module. You can use these subclasses in your warning filters from within Python to +silence warnings you are not interested in. For example, if you are knowingly using experimental +features and are comfortable that they make break in later versions, you can silence +:exc:`ExperimentalWarning` like this: + + import warnings + from qiskit.exceptions import ExperimentalWarning + + warnings.filterwarnings("ignore", category=ExperimentalWarning) """ from typing import Optional @@ -124,3 +143,7 @@ class OptionalDependencyImportWarning(QiskitWarning): """Raised when an optional library raises errors during its import.""" # Not a subclass of `ImportWarning` because those are hidden by default. + + +class ExperimentalWarning(QiskitWarning): + """Raised when an experimental feature is being used.""" diff --git a/qiskit/qasm3/__init__.py b/qiskit/qasm3/__init__.py index 8e3de893ea3c..e2159c946fff 100644 --- a/qiskit/qasm3/__init__.py +++ b/qiskit/qasm3/__init__.py @@ -172,13 +172,60 @@ \"\"\" circuit = qiskit.qasm3.loads(program) circuit.draw("mpl") + + +Experimental import interface +----------------------------- + +The import functions given above rely on the ANTLR-based reference parser from the OpenQASM project +itself, which is more intended as a language reference than a performant parser. You need to have +the extension ``qiskit-qasm3-import`` installed to use it. + +Qiskit is developing a native parser, written in Rust, which is available as part of the core Qiskit +package. This parser is still in its early experimental stages, so is missing features and its +interface is changing and expanding, but it is typically orders of magnitude more performant for the +subset of OpenQASM 3 it currently supports. + +You can use the experimental interface immediately, with similar functions to the main interface +above: + +.. autofunction:: load_experimental +.. autofunction:: loads_experimental + +These two functions both raise :exc:`.ExperimentalWarning`; you can disable this warning by doing:: + + import warnings + from qiskit.exceptions import ExperimentalWarning + + warnings.filterwarnings("ignore", category=ExperimentalWarning, module="qiskit.qasm3") + +These two functions allow for specifying include paths as an iterable of paths, and for specifying +custom Python constructors to use for particular gates. These custom constructors are specified by +using the :class:`CustomGate` object: + +.. autoclass:: CustomGate + +In ``custom_gates`` is not given, Qiskit will attempt to use its standard-library gate objects for +the gates defined in OpenQASM 3 standard library file ``stdgates.inc``. This sequence of gates is +available on this module, if you wish to build on top of it: + +.. py:data:: STDGATES_INC_GATES + + A tuple of :class:`CustomGate` objects specifying the Qiskit constructors to use for the + ``stdgates.inc`` include file. """ +import functools +import warnings + +from qiskit import _qasm3 +from qiskit.exceptions import ExperimentalWarning from qiskit.utils import optionals as _optionals from .experimental import ExperimentalFeatures from .exporter import Exporter from .exceptions import QASM3Error, QASM3ImporterError, QASM3ExporterError +from qiskit._qasm3 import CustomGate, STDGATES_INC_GATES def dumps(circuit, **kwargs) -> str: @@ -253,3 +300,25 @@ def loads(program: str): return qiskit_qasm3_import.parse(program) except qiskit_qasm3_import.ConversionError as exc: raise QASM3ImporterError(str(exc)) from exc + + +@functools.wraps(_qasm3.loads) +def loads_experimental(source, /, *, custom_gates=None, include_path=None): + """""" + warnings.warn( + "This is an experimental native version of the OpenQASM 3 importer." + " Beware that its interface might change, and it might be missing features.", + category=ExperimentalWarning, + ) + return _qasm3.loads(source, custom_gates=custom_gates, include_path=include_path) + + +@functools.wraps(_qasm3.load) +def load_experimental(pathlike_or_filelike, /, *, custom_gates=None, include_path=None): + """""" + warnings.warn( + "This is an experimental native version of the OpenQASM 3 importer." + " Beware that its interface might change, and it might be missing features.", + category=ExperimentalWarning, + ) + return _qasm3.load(pathlike_or_filelike, custom_gates=custom_gates, include_path=include_path)