diff --git a/qiskit_experiments/framework/__init__.py b/qiskit_experiments/framework/__init__.py index 40aceadd5c..fde8669855 100644 --- a/qiskit_experiments/framework/__init__.py +++ b/qiskit_experiments/framework/__init__.py @@ -236,7 +236,7 @@ from qiskit_experiments.database_service.db_analysis_result import DbAnalysisResultV1 from qiskit_experiments.database_service.db_fitval import FitVal from .base_analysis import BaseAnalysis -from .base_experiment import BaseExperiment, ExperimentConfig, fix_class_docs +from .base_experiment import BaseExperiment, ExperimentConfig from .analysis_result_data import AnalysisResultData from .experiment_data import ExperimentData from .composite import ( diff --git a/qiskit_experiments/framework/base_experiment.py b/qiskit_experiments/framework/base_experiment.py index e08ae49721..3cb393c7a3 100644 --- a/qiskit_experiments/framework/base_experiment.py +++ b/qiskit_experiments/framework/base_experiment.py @@ -15,9 +15,7 @@ from abc import ABC, abstractmethod import copy -import inspect import dataclasses -from functools import wraps from collections import OrderedDict from typing import Sequence, Optional, Tuple, List, Dict, Union, Any @@ -28,6 +26,7 @@ from qiskit.exceptions import QiskitError from qiskit.qobj.utils import MeasLevel from qiskit.providers.options import Options +from qiskit_experiments.framework.settings import Settings from qiskit_experiments.framework.experiment_data import ExperimentData from qiskit_experiments.version import __version__ @@ -86,7 +85,7 @@ def experiment(self) -> "BaseExperiment": raise QiskitError("{}\nError Message:\n{}".format(msg, str(ex))) from ex -class BaseExperiment(ABC): +class BaseExperiment(ABC, Settings): """Abstract base class for experiments. Class Attributes: @@ -143,39 +142,6 @@ def __init__( if isinstance(backend, (Backend, BaseBackend)): self._set_backend(backend) - def __new__(cls, *args, **kwargs): - """Store init args and kwargs for subclass __init__ methods""" - # This method automatically stores all arg and kwargs from subclass - # init methods for use in converting an experiment to config - - # Get all non-self init args and kwarg names for subclass - spec = inspect.getfullargspec(cls.__init__) - init_arg_names = spec.args[1:] - num_init_kwargs = len(spec.defaults) if spec.defaults else 0 - num_init_args = len(init_arg_names) - num_init_kwargs - - # Convert passed values for args and kwargs into an ordered dict - # This will sort args passed as kwargs and kwargs passed as - # positional args in the function call - num_call_args = len(args) - ord_args = OrderedDict() - ord_kwargs = OrderedDict() - for i, argname in enumerate(init_arg_names): - if i < num_init_args: - update = ord_args - else: - update = ord_kwargs - if i < num_call_args: - update[argname] = args[i] - elif argname in kwargs: - update[argname] = kwargs[argname] - - # pylint: disable = attribute-defined-outside-init - instance = super(BaseExperiment, cls).__new__(cls) - instance.__init_args__ = ord_args - instance.__init_kwargs__ = ord_kwargs - return instance - @property def experiment_type(self) -> str: """Return experiment type.""" @@ -546,20 +512,3 @@ def _add_job_metadata(self, metadata: Dict[str, Any], jobs: BaseJob, **run_optio "run_options": copy.copy(run_options), } ] - - -def fix_class_docs(wrapped_cls): - """Experiment class decorator to fix class doc formatting. - - This fixes the BaseExperiment subclass documentation so that - the correct init arg and kwargs are shown for the class documentation, - rather than the generic args of the BaseExperiment.__new__ method. - """ - - @wraps(wrapped_cls.__init__, assigned=("__annotations__",)) - def __new__(cls, *args, **kwargs): - return super(wrapped_cls, cls).__new__(cls, *args, **kwargs) - - wrapped_cls.__new__ = __new__ - - return wrapped_cls diff --git a/qiskit_experiments/framework/composite/batch_experiment.py b/qiskit_experiments/framework/composite/batch_experiment.py index 274a72a267..718c630ec2 100644 --- a/qiskit_experiments/framework/composite/batch_experiment.py +++ b/qiskit_experiments/framework/composite/batch_experiment.py @@ -18,11 +18,9 @@ from qiskit import QuantumCircuit from qiskit.providers.backend import Backend -from qiskit_experiments.framework.base_experiment import fix_class_docs from .composite_experiment import CompositeExperiment, BaseExperiment -@fix_class_docs class BatchExperiment(CompositeExperiment): """Combine multiple experiments into a batch experiment. diff --git a/qiskit_experiments/framework/composite/parallel_experiment.py b/qiskit_experiments/framework/composite/parallel_experiment.py index c6a842ddac..d1ad92abd1 100644 --- a/qiskit_experiments/framework/composite/parallel_experiment.py +++ b/qiskit_experiments/framework/composite/parallel_experiment.py @@ -16,11 +16,9 @@ from qiskit import QuantumCircuit, ClassicalRegister from qiskit.providers.backend import Backend -from qiskit_experiments.framework.base_experiment import fix_class_docs from .composite_experiment import CompositeExperiment, BaseExperiment -@fix_class_docs class ParallelExperiment(CompositeExperiment): """Combine multiple experiments into a parallel experiment. diff --git a/qiskit_experiments/framework/settings.py b/qiskit_experiments/framework/settings.py new file mode 100644 index 0000000000..c8c407515c --- /dev/null +++ b/qiskit_experiments/framework/settings.py @@ -0,0 +1,114 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2021. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. +""" +Settings mixing class +""" + +import inspect +from collections import OrderedDict +from functools import wraps +from typing import Dict, Any + + +class Settings: + """Class mixing for storing instance init settings. + + This mixin adds a ``__new__`` method that stores the values of args + and kwargs passed to the class instances ``__init__`` method and a + ``settings`` property that returns an ordered dict of these values. + + .. note:: + + This mixin is intended as a mixing for base classes so that when + creating subclasses, those subclasses can inherit the logic for + saving and returning settings. + + Note that there is small performance overhead to initializing classes + with this mixin so it should not be used for adding settings to all + classes without consideration. For classes that already store values + required to recover the ``__init__`` args they should instead + implement an appropriate :meth:`settings` property directly. + """ + + def __new__(cls, *args, **kwargs): + # This method automatically stores all arg and kwargs from subclass + # init methods + spec = inspect.getfullargspec(cls.__init__) + if spec.varargs: + # raise exception if class init accepts variadic positional args + raise TypeError( + "Settings mixin cannot be used with an init method that " + " accepts variadic positional args " + ) + + # Get lists of named args and kwargs for classes init method + init_args = spec.args[1:] + defaults_kwargs = spec.defaults or [] + num_named_kwargs = len(defaults_kwargs) + num_named_args = len(init_args) - num_named_kwargs + named_args = init_args[0:num_named_args] + named_kwargs = init_args[num_named_args:] + + # Initialize ordered dicts for named args and kwargs using the + # argspec ordering + ord_args = OrderedDict(zip(named_args, [None] * num_named_args)) + ord_kwargs = OrderedDict(zip(named_kwargs, defaults_kwargs)) + + # Sort called positional args + for i, (argname, argval) in enumerate(zip(init_args, args)): + if i < num_named_args: + ord_args[argname] = argval + else: + ord_kwargs[argname] = argval + + # Sort called kwargs + for argname, argval in kwargs.items(): + if argname in named_args: + ord_args[argname] = argval + else: + ord_kwargs[argname] = argval + + # pylint: disable = attribute-defined-outside-init + instance = super().__new__(cls) + instance.__init_args__ = ord_args + instance.__init_kwargs__ = ord_kwargs + return instance + + def __init_subclass__(cls, **kwargs): + # This method fixes class documentations for subclass + # that inherit the base class new method + super().__init_subclass__(**kwargs) + + # Copy the doc string and annotation from the subclasses + # init method to its new method to override base class + # __new__ documentation + @wraps(cls.__init__, assigned=("__annotations__",)) + def __new__(sub_cls, *args, **kwargs): + return super(cls, sub_cls).__new__(sub_cls, *args, **kwargs) + + # Monkey patch the subclass new method with the method with + # fixed documentation annotations + cls.__new__ = __new__ + + @property + def settings(self) -> Dict[str, Any]: + """Return the settings used to initialize this instance.""" + settings = {} + # Note that this relies on dicts entries being implicitly ordered + # to store init args as kwargs. + args = getattr(self, "__init_args__", {}) + for key, val in args.items(): + settings[key] = val + kwargs = getattr(self, "__init_kwargs__", {}) + for key, val in kwargs.items(): + settings[key] = val + return settings diff --git a/qiskit_experiments/library/calibration/fine_amplitude.py b/qiskit_experiments/library/calibration/fine_amplitude.py index 8803a2b7ac..9cbd3c3c34 100644 --- a/qiskit_experiments/library/calibration/fine_amplitude.py +++ b/qiskit_experiments/library/calibration/fine_amplitude.py @@ -23,12 +23,11 @@ BackendCalibrations, ) from qiskit_experiments.library.characterization import FineAmplitude -from qiskit_experiments.framework import ExperimentData, Options, fix_class_docs +from qiskit_experiments.framework import ExperimentData, Options from qiskit_experiments.calibration_management.update_library import BaseUpdater from qiskit_experiments.library.characterization.analysis import FineXAmplitudeAnalysis -@fix_class_docs class FineAmplitudeCal(BaseCalibrationExperiment, FineAmplitude): r"""A calibration version of the :class:`FineAmplitude` experiment. @@ -148,7 +147,6 @@ def update_calibrations(self, experiment_data: ExperimentData): ) -@fix_class_docs class FineXAmplitudeCal(FineAmplitudeCal): """A calibration experiment to calibrate the amplitude of the X schedule.""" @@ -196,7 +194,6 @@ def _default_analysis_options(cls) -> Options: return options -@fix_class_docs class FineSXAmplitudeCal(FineAmplitudeCal): """A calibration experiment to calibrate the amplitude of the SX schedule.""" diff --git a/qiskit_experiments/library/calibration/fine_drag_cal.py b/qiskit_experiments/library/calibration/fine_drag_cal.py index 6961aef7ea..1929d81c7f 100644 --- a/qiskit_experiments/library/calibration/fine_drag_cal.py +++ b/qiskit_experiments/library/calibration/fine_drag_cal.py @@ -20,7 +20,7 @@ from qiskit.pulse import Play from qiskit_experiments.exceptions import CalibrationError -from qiskit_experiments.framework import ExperimentData, fix_class_docs, Options +from qiskit_experiments.framework import ExperimentData, Options from qiskit_experiments.calibration_management import ( BaseCalibrationExperiment, BackendCalibrations, @@ -29,7 +29,6 @@ from qiskit_experiments.library.characterization.fine_drag import FineDrag -@fix_class_docs class FineDragCal(BaseCalibrationExperiment, FineDrag): """A calibration version of the fine drag experiment.""" @@ -150,7 +149,6 @@ def update_calibrations(self, experiment_data: ExperimentData): ) -@fix_class_docs class FineXDragCal(FineDragCal): """Fine drag calibration of X gate.""" @@ -182,7 +180,6 @@ def __init__( ) -@fix_class_docs class FineSXDragCal(FineDragCal): """Fine drag calibration of X gate.""" diff --git a/qiskit_experiments/library/calibration/frequency_cal.py b/qiskit_experiments/library/calibration/frequency_cal.py index db8acf95fe..61440e32fe 100644 --- a/qiskit_experiments/library/calibration/frequency_cal.py +++ b/qiskit_experiments/library/calibration/frequency_cal.py @@ -17,7 +17,7 @@ from qiskit import QuantumCircuit from qiskit.providers.backend import Backend -from qiskit_experiments.framework import ExperimentData, fix_class_docs +from qiskit_experiments.framework import ExperimentData from qiskit_experiments.library.characterization.ramsey_xy import RamseyXY from qiskit_experiments.calibration_management.backend_calibrations import BackendCalibrations from qiskit_experiments.calibration_management.update_library import BaseUpdater @@ -26,7 +26,6 @@ ) -@fix_class_docs class FrequencyCal(BaseCalibrationExperiment, RamseyXY): """A qubit frequency calibration experiment based on the Ramsey XY experiment. diff --git a/qiskit_experiments/library/calibration/half_angle_cal.py b/qiskit_experiments/library/calibration/half_angle_cal.py index 58bbabf1a6..56cbeae1a1 100644 --- a/qiskit_experiments/library/calibration/half_angle_cal.py +++ b/qiskit_experiments/library/calibration/half_angle_cal.py @@ -18,7 +18,7 @@ from qiskit import QuantumCircuit from qiskit.providers.backend import Backend -from qiskit_experiments.framework import ExperimentData, fix_class_docs +from qiskit_experiments.framework import ExperimentData from qiskit_experiments.calibration_management import ( BaseCalibrationExperiment, BackendCalibrations, @@ -27,7 +27,6 @@ from qiskit_experiments.calibration_management.update_library import BaseUpdater -@fix_class_docs class HalfAngleCal(BaseCalibrationExperiment, HalfAngle): """Calibration version of the half-angle experiment.""" diff --git a/qiskit_experiments/library/calibration/rough_amplitude_cal.py b/qiskit_experiments/library/calibration/rough_amplitude_cal.py index 4f5344abaa..5b2fce026e 100644 --- a/qiskit_experiments/library/calibration/rough_amplitude_cal.py +++ b/qiskit_experiments/library/calibration/rough_amplitude_cal.py @@ -20,7 +20,7 @@ from qiskit.circuit import Parameter from qiskit.providers.backend import Backend -from qiskit_experiments.framework import ExperimentData, Options, fix_class_docs +from qiskit_experiments.framework import ExperimentData, Options from qiskit_experiments.calibration_management import BaseCalibrationExperiment, BackendCalibrations from qiskit_experiments.library.characterization import Rabi from qiskit_experiments.calibration_management.update_library import BaseUpdater @@ -31,7 +31,6 @@ ) -@fix_class_docs class RoughAmplitudeCal(BaseCalibrationExperiment, Rabi): """A calibration version of the Rabi experiment. @@ -198,7 +197,6 @@ def update_calibrations(self, experiment_data: ExperimentData): ) -@fix_class_docs class RoughXSXAmplitudeCal(RoughAmplitudeCal): """A rough amplitude calibration of x and sx gates.""" @@ -228,7 +226,6 @@ def __init__( ] -@fix_class_docs class EFRoughXSXAmplitudeCal(RoughAmplitudeCal): """A rough amplitude calibration of x and sx gates on the 1<->2 transition.""" diff --git a/qiskit_experiments/library/calibration/rough_drag_cal.py b/qiskit_experiments/library/calibration/rough_drag_cal.py index 4710400563..92d3e620ad 100644 --- a/qiskit_experiments/library/calibration/rough_drag_cal.py +++ b/qiskit_experiments/library/calibration/rough_drag_cal.py @@ -18,7 +18,7 @@ from qiskit.circuit import Parameter from qiskit.providers.backend import Backend -from qiskit_experiments.framework import ExperimentData, fix_class_docs +from qiskit_experiments.framework import ExperimentData from qiskit_experiments.calibration_management import ( BaseCalibrationExperiment, BackendCalibrations, @@ -27,7 +27,6 @@ from qiskit_experiments.library.characterization.drag import RoughDrag -@fix_class_docs class RoughDragCal(BaseCalibrationExperiment, RoughDrag): """A calibration version of the Drag experiment. diff --git a/qiskit_experiments/library/calibration/rough_frequency.py b/qiskit_experiments/library/calibration/rough_frequency.py index a7cfefc7d0..bc5dc1a77c 100644 --- a/qiskit_experiments/library/calibration/rough_frequency.py +++ b/qiskit_experiments/library/calibration/rough_frequency.py @@ -15,7 +15,6 @@ from typing import Iterable, Optional from qiskit.providers.backend import Backend -from qiskit_experiments.framework import fix_class_docs from qiskit_experiments.library.characterization.qubit_spectroscopy import QubitSpectroscopy from qiskit_experiments.library.characterization.ef_spectroscopy import EFSpectroscopy from qiskit_experiments.calibration_management.update_library import Frequency @@ -25,7 +24,6 @@ ) -@fix_class_docs class RoughFrequencyCal(BaseCalibrationExperiment, QubitSpectroscopy): """A calibration experiment that runs QubitSpectroscopy.""" @@ -70,7 +68,6 @@ def __init__( ) -@fix_class_docs class RoughEFFrequencyCal(BaseCalibrationExperiment, EFSpectroscopy): """A calibration experiment that runs QubitSpectroscopy.""" diff --git a/qiskit_experiments/library/characterization/cr_hamiltonian.py b/qiskit_experiments/library/characterization/cr_hamiltonian.py index 562855ccbe..e0ba73b8e9 100644 --- a/qiskit_experiments/library/characterization/cr_hamiltonian.py +++ b/qiskit_experiments/library/characterization/cr_hamiltonian.py @@ -20,11 +20,10 @@ from qiskit.exceptions import QiskitError from qiskit.providers import Backend from qiskit.utils import apply_prefix -from qiskit_experiments.framework import BaseExperiment, Options, fix_class_docs +from qiskit_experiments.framework import BaseExperiment, Options from qiskit_experiments.library.characterization.analysis import CrossResonanceHamiltonianAnalysis -@fix_class_docs class CrossResonanceHamiltonian(BaseExperiment): r"""Cross resonance Hamiltonian tomography experiment. diff --git a/qiskit_experiments/library/characterization/drag.py b/qiskit_experiments/library/characterization/drag.py index 76f7bc119a..a7dce60792 100644 --- a/qiskit_experiments/library/characterization/drag.py +++ b/qiskit_experiments/library/characterization/drag.py @@ -21,12 +21,11 @@ from qiskit.providers.backend import Backend from qiskit.pulse import ScheduleBlock -from qiskit_experiments.framework import BaseExperiment, Options, fix_class_docs +from qiskit_experiments.framework import BaseExperiment, Options from qiskit_experiments.exceptions import CalibrationError from qiskit_experiments.library.characterization.analysis import DragCalAnalysis -@fix_class_docs class RoughDrag(BaseExperiment): r"""An experiment that scans the DRAG parameter to find the optimal value. diff --git a/qiskit_experiments/library/characterization/ef_spectroscopy.py b/qiskit_experiments/library/characterization/ef_spectroscopy.py index 6ef339a7ef..16a8ee3cb8 100644 --- a/qiskit_experiments/library/characterization/ef_spectroscopy.py +++ b/qiskit_experiments/library/characterization/ef_spectroscopy.py @@ -17,10 +17,9 @@ from qiskit_experiments.curve_analysis import ParameterRepr from qiskit_experiments.library.characterization.qubit_spectroscopy import QubitSpectroscopy -from qiskit_experiments.framework import Options, fix_class_docs +from qiskit_experiments.framework import Options -@fix_class_docs class EFSpectroscopy(QubitSpectroscopy): """Class that runs spectroscopy on the e-f transition by scanning the frequency. diff --git a/qiskit_experiments/library/characterization/fine_amplitude.py b/qiskit_experiments/library/characterization/fine_amplitude.py index 45db8a2648..e9947fa795 100644 --- a/qiskit_experiments/library/characterization/fine_amplitude.py +++ b/qiskit_experiments/library/characterization/fine_amplitude.py @@ -19,7 +19,7 @@ from qiskit.circuit import Gate from qiskit.circuit.library import XGate, SXGate from qiskit.providers.backend import Backend -from qiskit_experiments.framework import BaseExperiment, Options, fix_class_docs +from qiskit_experiments.framework import BaseExperiment, Options from qiskit_experiments.library.characterization.analysis import ( FineAmplitudeAnalysis, FineXAmplitudeAnalysis, @@ -27,7 +27,6 @@ from qiskit_experiments.exceptions import CalibrationError -@fix_class_docs class FineAmplitude(BaseExperiment): r"""Error amplifying fine amplitude calibration experiment. @@ -204,7 +203,6 @@ def circuits(self) -> List[QuantumCircuit]: return circuits -@fix_class_docs class FineXAmplitude(FineAmplitude): r"""A fine amplitude experiment with all the options set for the :math:`\pi`-rotation. @@ -250,7 +248,6 @@ def _default_analysis_options(cls) -> Options: return options -@fix_class_docs class FineSXAmplitude(FineAmplitude): r"""A fine amplitude experiment with all the options set for the :math:`\pi/2`-rotation. diff --git a/qiskit_experiments/library/characterization/fine_drag.py b/qiskit_experiments/library/characterization/fine_drag.py index 632bbd22bc..9d6b170782 100644 --- a/qiskit_experiments/library/characterization/fine_drag.py +++ b/qiskit_experiments/library/characterization/fine_drag.py @@ -19,13 +19,12 @@ from qiskit.circuit import Gate from qiskit.circuit.library import XGate, SXGate from qiskit.providers.backend import Backend -from qiskit_experiments.framework import BaseExperiment, Options, fix_class_docs +from qiskit_experiments.framework import BaseExperiment, Options from qiskit_experiments.library.characterization.analysis import ( FineDragAnalysis, ) -@fix_class_docs class FineDrag(BaseExperiment): r"""Fine DRAG experiment. @@ -227,7 +226,6 @@ def circuits(self) -> List[QuantumCircuit]: return circuits -@fix_class_docs class FineXDrag(FineDrag): """Class to fine calibrate the DRAG parameter of an X gate. diff --git a/qiskit_experiments/library/characterization/half_angle.py b/qiskit_experiments/library/characterization/half_angle.py index 1fd3f67216..288bed9714 100644 --- a/qiskit_experiments/library/characterization/half_angle.py +++ b/qiskit_experiments/library/characterization/half_angle.py @@ -18,12 +18,11 @@ from qiskit import QuantumCircuit from qiskit.providers import Backend -from qiskit_experiments.framework import BaseExperiment, Options, fix_class_docs +from qiskit_experiments.framework import BaseExperiment, Options from qiskit_experiments.library.characterization.analysis import FineHalfAngleAnalysis from qiskit_experiments.curve_analysis import ParameterRepr -@fix_class_docs class HalfAngle(BaseExperiment): r"""An experiment class to measure the amount by which sx and x are not parallel. diff --git a/qiskit_experiments/library/characterization/qubit_spectroscopy.py b/qiskit_experiments/library/characterization/qubit_spectroscopy.py index d59c61efff..09314d0131 100644 --- a/qiskit_experiments/library/characterization/qubit_spectroscopy.py +++ b/qiskit_experiments/library/characterization/qubit_spectroscopy.py @@ -23,11 +23,10 @@ from qiskit.qobj.utils import MeasLevel from qiskit.utils import apply_prefix -from qiskit_experiments.framework import BaseExperiment, Options, fix_class_docs +from qiskit_experiments.framework import BaseExperiment, Options from qiskit_experiments.curve_analysis import ParameterRepr, ResonanceAnalysis -@fix_class_docs class QubitSpectroscopy(BaseExperiment): """Class that runs spectroscopy by sweeping the qubit frequency. diff --git a/qiskit_experiments/library/characterization/rabi.py b/qiskit_experiments/library/characterization/rabi.py index 761774ced7..39acc029aa 100644 --- a/qiskit_experiments/library/characterization/rabi.py +++ b/qiskit_experiments/library/characterization/rabi.py @@ -22,11 +22,10 @@ from qiskit.pulse import ScheduleBlock from qiskit.exceptions import QiskitError -from qiskit_experiments.framework import BaseExperiment, Options, fix_class_docs +from qiskit_experiments.framework import BaseExperiment, Options from qiskit_experiments.curve_analysis import ParameterRepr, OscillationAnalysis -@fix_class_docs class Rabi(BaseExperiment): """An experiment that scans a pulse amplitude to calibrate rotations between 0 and 1. @@ -173,7 +172,6 @@ def circuits(self) -> List[QuantumCircuit]: return circs -@fix_class_docs class EFRabi(Rabi): """An experiment that scans the amplitude of a pulse inducing rotations between 1 and 2. diff --git a/qiskit_experiments/library/characterization/ramsey_xy.py b/qiskit_experiments/library/characterization/ramsey_xy.py index c508a6ad1a..0a0d5b820d 100644 --- a/qiskit_experiments/library/characterization/ramsey_xy.py +++ b/qiskit_experiments/library/characterization/ramsey_xy.py @@ -20,11 +20,10 @@ from qiskit.utils import apply_prefix from qiskit.providers.backend import Backend -from qiskit_experiments.framework import BaseExperiment, fix_class_docs +from qiskit_experiments.framework import BaseExperiment from qiskit_experiments.library.characterization.analysis import RamseyXYAnalysis -@fix_class_docs class RamseyXY(BaseExperiment): r"""Ramsey XY experiment to measure the frequency of a qubit. diff --git a/qiskit_experiments/library/characterization/t1.py b/qiskit_experiments/library/characterization/t1.py index 96f51678c5..95a3f525f4 100644 --- a/qiskit_experiments/library/characterization/t1.py +++ b/qiskit_experiments/library/characterization/t1.py @@ -21,11 +21,10 @@ from qiskit.providers.backend import Backend from qiskit.test.mock import FakeBackend -from qiskit_experiments.framework import BaseExperiment, Options, fix_class_docs +from qiskit_experiments.framework import BaseExperiment, Options from qiskit_experiments.library.characterization.analysis.t1_analysis import T1Analysis -@fix_class_docs class T1(BaseExperiment): r""" T1 experiment class diff --git a/qiskit_experiments/library/characterization/t2ramsey.py b/qiskit_experiments/library/characterization/t2ramsey.py index 4941aae206..84b0bce963 100644 --- a/qiskit_experiments/library/characterization/t2ramsey.py +++ b/qiskit_experiments/library/characterization/t2ramsey.py @@ -23,11 +23,10 @@ from qiskit.providers.backend import Backend from qiskit.test.mock import FakeBackend -from qiskit_experiments.framework import BaseExperiment, Options, fix_class_docs +from qiskit_experiments.framework import BaseExperiment, Options from qiskit_experiments.library.characterization.analysis.t2ramsey_analysis import T2RamseyAnalysis -@fix_class_docs class T2Ramsey(BaseExperiment): r"""T2 Ramsey Experiment. diff --git a/qiskit_experiments/library/quantum_volume/qv_experiment.py b/qiskit_experiments/library/quantum_volume/qv_experiment.py index 6b435cd50a..dc14a32336 100644 --- a/qiskit_experiments/library/quantum_volume/qv_experiment.py +++ b/qiskit_experiments/library/quantum_volume/qv_experiment.py @@ -27,11 +27,10 @@ from qiskit.circuit.library import QuantumVolume as QuantumVolumeCircuit from qiskit import transpile from qiskit.providers.backend import Backend -from qiskit_experiments.framework import BaseExperiment, Options, fix_class_docs +from qiskit_experiments.framework import BaseExperiment, Options from .qv_analysis import QuantumVolumeAnalysis -@fix_class_docs class QuantumVolume(BaseExperiment): """Quantum Volume Experiment class. diff --git a/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py index a1793389e1..ac7ec741c9 100644 --- a/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py @@ -22,11 +22,10 @@ from qiskit.exceptions import QiskitError from qiskit.providers.backend import Backend -from .rb_experiment import StandardRB, fix_class_docs +from .rb_experiment import StandardRB from .interleaved_rb_analysis import InterleavedRBAnalysis -@fix_class_docs class InterleavedRB(StandardRB): """Interleaved randomized benchmarking experiment. diff --git a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py index ac5b49afa6..40dee19a51 100644 --- a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py @@ -23,13 +23,12 @@ from qiskit.providers.backend import Backend import qiskit_experiments.data_processing as dp -from qiskit_experiments.framework import BaseExperiment, ParallelExperiment, Options, fix_class_docs +from qiskit_experiments.framework import BaseExperiment, ParallelExperiment, Options from .rb_analysis import RBAnalysis from .clifford_utils import CliffordUtils from .rb_utils import RBUtils -@fix_class_docs class StandardRB(BaseExperiment): """Standard randomized benchmarking experiment. diff --git a/qiskit_experiments/library/tomography/qpt_experiment.py b/qiskit_experiments/library/tomography/qpt_experiment.py index ff3fc24019..91733f7c78 100644 --- a/qiskit_experiments/library/tomography/qpt_experiment.py +++ b/qiskit_experiments/library/tomography/qpt_experiment.py @@ -16,13 +16,12 @@ from typing import Union, Optional, Iterable, List, Tuple, Sequence from qiskit.circuit import QuantumCircuit, Instruction from qiskit.quantum_info.operators.base_operator import BaseOperator -from qiskit_experiments.framework import Options, fix_class_docs +from qiskit_experiments.framework import Options from .tomography_experiment import TomographyExperiment from .qpt_analysis import ProcessTomographyAnalysis from . import basis -@fix_class_docs class ProcessTomography(TomographyExperiment): """Quantum process tomography experiment. diff --git a/qiskit_experiments/library/tomography/qst_experiment.py b/qiskit_experiments/library/tomography/qst_experiment.py index 7103fd1b4f..781bdf3933 100644 --- a/qiskit_experiments/library/tomography/qst_experiment.py +++ b/qiskit_experiments/library/tomography/qst_experiment.py @@ -17,13 +17,12 @@ from qiskit.circuit import QuantumCircuit, Instruction from qiskit.quantum_info.operators.base_operator import BaseOperator from qiskit.quantum_info import Statevector -from qiskit_experiments.framework import Options, fix_class_docs +from qiskit_experiments.framework import Options from .tomography_experiment import TomographyExperiment from .qst_analysis import StateTomographyAnalysis from . import basis -@fix_class_docs class StateTomography(TomographyExperiment): """Quantum state tomography experiment. diff --git a/test/test_settings.py b/test/test_settings.py new file mode 100644 index 0000000000..6e6594eb4f --- /dev/null +++ b/test/test_settings.py @@ -0,0 +1,132 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2021. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. + +"""Tests for base experiment framework.""" + +from qiskit.test import QiskitTestCase +from qiskit_experiments.framework.settings import Settings + + +class ExampleSettingsVariadic(Settings): + """Test class with args and kwargs property""" + + def __init__(self, a, b, c="default_c", d="default_d", **kwargs): + pass + + @property + def args(self): + """Return sotred init args""" + return tuple(getattr(self, "__init_args__", {}).values()) + + @property + def kwargs(self): + """Return stored init kwargs""" + return dict(getattr(self, "__init_kwargs__", {})) + + +class ExampleSettings(Settings): + """Test class with args and kwargs property""" + + def __init__(self, a, b, c="default_c", d="default_d"): + pass + + @property + def args(self): + """Return sotred init args""" + return tuple(getattr(self, "__init_args__", {}).values()) + + @property + def kwargs(self): + """Return stored init kwargs""" + return dict(getattr(self, "__init_kwargs__", {})) + + +class TestSettings(QiskitTestCase): + """Test Settings mixin""" + + def test_standard(self): + """Test mixing for standard init class""" + obj = ExampleSettings(1, 2, c="custom_c") + self.assertEqual(obj.args, (1, 2)) + self.assertEqual(obj.kwargs, {"c": "custom_c", "d": "default_d"}) + self.assertEqual(obj.settings, {"a": 1, "b": 2, "c": "custom_c", "d": "default_d"}) + + def test_standard_pos_kwargs(self): + """Test mixing for standard init class with kwargs passed positionally""" + obj = ExampleSettings(1, 2, "custom_c") + self.assertEqual(obj.args, (1, 2)) + self.assertEqual(obj.kwargs, {"c": "custom_c", "d": "default_d"}) + self.assertEqual(obj.settings, {"a": 1, "b": 2, "c": "custom_c", "d": "default_d"}) + + def test_standard_named_args(self): + """Test mixing for standard init class with kwargs passed positionally""" + obj = ExampleSettings(b=2, a=1, c="custom_c") + self.assertEqual(obj.args, (1, 2)) + self.assertEqual(obj.kwargs, {"c": "custom_c", "d": "default_d"}) + self.assertEqual(obj.settings, {"a": 1, "b": 2, "c": "custom_c", "d": "default_d"}) + + def test_variadic(self): + """Test mixing for standard init class""" + obj = ExampleSettingsVariadic(1, 2, c="custom_c") + self.assertEqual(obj.args, (1, 2)) + self.assertEqual(obj.kwargs, {"c": "custom_c", "d": "default_d"}) + self.assertEqual(obj.settings, {"a": 1, "b": 2, "c": "custom_c", "d": "default_d"}) + + def test_variadic_pos_kwargs(self): + """Test mixing for standard init class with kwargs passed positionally""" + obj = ExampleSettingsVariadic(1, 2, "custom_c") + self.assertEqual(obj.args, (1, 2)) + self.assertEqual(obj.kwargs, {"c": "custom_c", "d": "default_d"}) + self.assertEqual(obj.settings, {"a": 1, "b": 2, "c": "custom_c", "d": "default_d"}) + + def test_variadic_named_args(self): + """Test mixing for standard init class with kwargs passed positionally""" + obj = ExampleSettingsVariadic(b=2, a=1, c="custom_c") + self.assertEqual(obj.args, (1, 2)) + self.assertEqual(obj.kwargs, {"c": "custom_c", "d": "default_d"}) + self.assertEqual(obj.settings, {"a": 1, "b": 2, "c": "custom_c", "d": "default_d"}) + + def test_variadic_kwargs(self): + """Test mixing for standard init class""" + obj = ExampleSettingsVariadic(1, 2, d="custom_d", f="kwarg_f", g="kwarg_g") + self.assertEqual(obj.args, (1, 2)) + self.assertEqual( + obj.kwargs, {"c": "default_c", "d": "custom_d", "f": "kwarg_f", "g": "kwarg_g"} + ) + self.assertEqual( + obj.settings, + {"a": 1, "b": 2, "c": "default_c", "d": "custom_d", "f": "kwarg_f", "g": "kwarg_g"}, + ) + + def test_variadic_kwargs_pos_kwargs(self): + """Test mixing for standard init class""" + obj = ExampleSettingsVariadic(1, 2, "custom_c", f="kwarg_f", g="kwarg_g") + self.assertEqual(obj.args, (1, 2)) + self.assertEqual( + obj.kwargs, {"c": "custom_c", "d": "default_d", "f": "kwarg_f", "g": "kwarg_g"} + ) + self.assertEqual( + obj.settings, + {"a": 1, "b": 2, "c": "custom_c", "d": "default_d", "f": "kwarg_f", "g": "kwarg_g"}, + ) + + def test_variadic_kwargs_named_args(self): + """Test mixing for standard init class""" + obj = ExampleSettingsVariadic(b=2, a=1, d="custom_d", f="kwarg_f", g="kwarg_g") + self.assertEqual(obj.args, (1, 2)) + self.assertEqual( + obj.kwargs, {"c": "default_c", "d": "custom_d", "f": "kwarg_f", "g": "kwarg_g"} + ) + self.assertEqual( + obj.settings, + {"a": 1, "b": 2, "c": "default_c", "d": "custom_d", "f": "kwarg_f", "g": "kwarg_g"}, + )