diff --git a/docs/apidocs/execute.rst b/docs/apidocs/execute.rst index d16dc0b9d1e9..a5b075efa71a 100644 --- a/docs/apidocs/execute.rst +++ b/docs/apidocs/execute.rst @@ -1,6 +1,6 @@ .. _qiskit-execute: -.. automodule:: qiskit.execute +.. automodule:: qiskit.execute_function :no-members: :no-inherited-members: :no-special-members: diff --git a/qiskit/__init__.py b/qiskit/__init__.py index a32d77ef91b4..318c04f7748e 100644 --- a/qiskit/__init__.py +++ b/qiskit/__init__.py @@ -73,14 +73,14 @@ # Moved to after IBMQ and Aer imports due to import issues # with other modules that check for IBMQ (tools) -from qiskit.execute import execute # noqa +from qiskit.execute_function import execute # noqa from qiskit.compiler import transpile, assemble, schedule, sequence # noqa from .version import __version__ # noqa -from .version import _get_qiskit_versions # noqa +from .version import QiskitVersion # noqa -__qiskit_version__ = _get_qiskit_versions() +__qiskit_version__ = QiskitVersion() if sys.version_info[0] == 3 and sys.version_info[1] == 6: diff --git a/qiskit/compiler/__init__.py b/qiskit/compiler/__init__.py index 96ed587a46d8..fd6429260db4 100644 --- a/qiskit/compiler/__init__.py +++ b/qiskit/compiler/__init__.py @@ -30,7 +30,7 @@ """ -from .assemble import assemble -from .transpile import transpile -from .schedule import schedule -from .sequence import sequence +from .assembler import assemble +from .transpiler import transpile +from .scheduler import schedule +from .sequencer import sequence diff --git a/qiskit/compiler/assemble.py b/qiskit/compiler/assembler.py similarity index 100% rename from qiskit/compiler/assemble.py rename to qiskit/compiler/assembler.py diff --git a/qiskit/compiler/schedule.py b/qiskit/compiler/scheduler.py similarity index 100% rename from qiskit/compiler/schedule.py rename to qiskit/compiler/scheduler.py diff --git a/qiskit/compiler/sequence.py b/qiskit/compiler/sequencer.py similarity index 100% rename from qiskit/compiler/sequence.py rename to qiskit/compiler/sequencer.py diff --git a/qiskit/compiler/transpile.py b/qiskit/compiler/transpiler.py similarity index 100% rename from qiskit/compiler/transpile.py rename to qiskit/compiler/transpiler.py diff --git a/qiskit/execute.py b/qiskit/execute_function.py similarity index 98% rename from qiskit/execute.py rename to qiskit/execute_function.py index adcd8a952328..78ea202a258c 100644 --- a/qiskit/execute.py +++ b/qiskit/execute_function.py @@ -11,11 +11,11 @@ # that they have been altered from the originals. """ -============================================= -Executing Experiments (:mod:`qiskit.execute`) -============================================= +====================================================== +Executing Experiments (:mod:`qiskit.execute_function`) +====================================================== -.. currentmodule:: qiskit.execute +.. currentmodule:: qiskit.execute_function .. autofunction:: execute """ diff --git a/qiskit/version.py b/qiskit/version.py index 2c2f2776fcac..ca264340bfdf 100644 --- a/qiskit/version.py +++ b/qiskit/version.py @@ -14,6 +14,7 @@ """Contains the terra version.""" +from collections.abc import Mapping import os import subprocess import pkg_resources @@ -81,35 +82,70 @@ def get_version_info(): __version__ = get_version_info() -def _get_qiskit_versions(): - out_dict = {} - out_dict['qiskit-terra'] = __version__ - try: - from qiskit.providers import aer - out_dict['qiskit-aer'] = aer.__version__ - except Exception: - out_dict['qiskit-aer'] = None - try: - from qiskit import ignis - out_dict['qiskit-ignis'] = ignis.__version__ - except Exception: - out_dict['qiskit-ignis'] = None - try: - from qiskit.providers import ibmq - out_dict['qiskit-ibmq-provider'] = ibmq.__version__ - except Exception: - out_dict['qiskit-ibmq-provider'] = None - try: - from qiskit import aqua - out_dict['qiskit-aqua'] = aqua.__version__ - except Exception: - out_dict['qiskit-aqua'] = None - try: - out_dict['qiskit'] = pkg_resources.get_distribution('qiskit').version - except Exception: - out_dict['qiskit'] = None - - return out_dict - - -__qiskit_version__ = _get_qiskit_versions() +class QiskitVersion(Mapping): + """A lazy loading wrapper to get qiskit versions.""" + + __slots__ = ['_version_dict', '_loaded'] + + def __init__(self): + self._version_dict = { + 'qiskit-terra': __version__, + 'qiskit-aer': None, + 'qiskit-ignis': None, + 'qiskit-ibmq-provider': None, + 'qiskit-aqua': None, + 'qiskit': None} + self._loaded = False + + def _load_versions(self): + try: + from qiskit.providers import aer + self._version_dict['qiskit-aer'] = aer.__version__ + except Exception: + self._version_dict['qiskit-aer'] = None + try: + from qiskit import ignis + self._version_dict['qiskit-ignis'] = ignis.__version__ + except Exception: + self._version_dict['qiskit-ignis'] = None + try: + from qiskit.providers import ibmq + self._version_dict['qiskit-ibmq-provider'] = ibmq.__version__ + except Exception: + self._version_dict['qiskit-ibmq-provider'] = None + try: + from qiskit import aqua + self._version_dict['qiskit-aqua'] = aqua.__version__ + except Exception: + self._version_dict['qiskit-aqua'] = None + try: + self._version_dict['qiskit'] = pkg_resources.get_distribution('qiskit').version + except Exception: + self._version_dict['qiskit'] = None + self._loaded = True + + def __repr__(self): + if not self._loaded: + self._load_versions() + return repr(self._version_dict) + + def __str__(self): + if not self._loaded: + self._load_versions() + return str(self._version_dict) + + def __getitem__(self, key): + if not self._loaded: + self._load_versions() + return self._version_dict[key] + + def __iter__(self): + if not self._loaded: + self._load_versions() + return iter(self._version_dict) + + def __len__(self): + return len(self._version_dict) + + +__qiskit_version__ = QiskitVersion() diff --git a/releasenotes/notes/qiskit-version-wrapper-90cb7fcffeaafd6a.yaml b/releasenotes/notes/qiskit-version-wrapper-90cb7fcffeaafd6a.yaml new file mode 100644 index 000000000000..0bc3fbf78fff --- /dev/null +++ b/releasenotes/notes/qiskit-version-wrapper-90cb7fcffeaafd6a.yaml @@ -0,0 +1,45 @@ +--- +upgrade: + - | + The ``qiskit.__qiskit_version__`` module attribute was previously a ``dict`` + will now return a custom read-only ``Mapping`` object that checks the + version of qiskit elements at runtime instead of at import time. This was + done to speed up the import path of qiskit and eliminate a possible import + cycle by only importing the element packages at runtime if the version + is needed from the package. This should be fully compatible with the + ``dict`` previously return and for most normal use cases there will be no + difference. However, if some applications were relying on either mutating + the contents or explicitly type checking it may require updates to adapt to + this change. + - | + The ``qiskit.execute`` module has been renamed to + :mod:`qiskit.execute_function`. This was necessary to avoid a potentical + name conflict between the :func:`~qiskit.execute_function.execute` function + which is re-exported as ``qiskit.execute``. ``qiskit.execute`` the function + in some situations could conflict with ``qiskit.execute`` the module which + would lead to a cryptic error because Python was treating ``qiskit.execute`` + as the module when the intent was to the function or vice versa. The module + rename was necessary to avoid this conflict. If you're importing + ``qiskit.execute`` to get the module (typical usage was + ``from qiskit.execute import execute``) you will need to update this to + use ``qiskit.execute_function`` instead. ``qiskit.execute`` will now always + resolve to the function. + - | + The ``qiskit.compiler.transpile``, ``qiskit.compiler.assemble``, + ``qiskit.compiler.schedule``, and ``qiskit.compiler.sequence`` modules have + been renamed to ``qiskit.compiler.transpiler``, + ``qiskit.compiler.assembler``, ``qiskit.compiler.scheduler``, and + ``qiskit.compiler.sequence`` respectively. This was necessary to avoid a + potentical name conflict between the modules and the re-exported function + paths :func:`qiskit.compiler.transpile`, :func:`qiskit.compiler.assemble`, + :func:`qiskit.compiler.schedule`, and :func:`qiskit.compiler.sequence`. + In some situations this name conflict between the module path and + re-exported function path would lead to a cryptic error because Python was + treating an import as the module when the intent was to use the function or + vice versa. The module rename was necessary to avoid this conflict. If + you were using the imports to get the modules before (typical usage would + be like``from qiskit.compiler.transpile import transpile``) you will need + to update this to use the new module paths. + :func:`qiskit.compiler.transpile`, :func:`qiskit.compiler.assemble`, + :func:`qiskit.compiler.schedule`, and :func:`qiskit.compiler.sequence` + will now always resolve to the functions. diff --git a/test/python/circuit/test_parameters.py b/test/python/circuit/test_parameters.py index 11bd9bc0e5d0..efaaefe6395d 100644 --- a/test/python/circuit/test_parameters.py +++ b/test/python/circuit/test_parameters.py @@ -28,7 +28,7 @@ ParameterVector) from qiskit.circuit.exceptions import CircuitError from qiskit.compiler import assemble, transpile -from qiskit.execute import execute +from qiskit.execute_function import execute from qiskit import pulse from qiskit.quantum_info import Operator from qiskit.test import QiskitTestCase diff --git a/test/python/compiler/test_assembler.py b/test/python/compiler/test_assembler.py index c018f55d4672..bc7998c5fcae 100644 --- a/test/python/compiler/test_assembler.py +++ b/test/python/compiler/test_assembler.py @@ -21,7 +21,7 @@ import qiskit.pulse as pulse from qiskit.circuit import Instruction, Gate, Parameter, ParameterVector, ParameterExpression from qiskit.circuit import QuantumRegister, ClassicalRegister, QuantumCircuit -from qiskit.compiler.assemble import assemble +from qiskit.compiler.assembler import assemble from qiskit.exceptions import QiskitError from qiskit.pulse import Schedule, Acquire, Play from qiskit.pulse.channels import MemorySlot, AcquireChannel, DriveChannel, MeasureChannel diff --git a/test/python/compiler/test_disassembler.py b/test/python/compiler/test_disassembler.py index 93a2b193f052..8abeb8c71dcc 100644 --- a/test/python/compiler/test_disassembler.py +++ b/test/python/compiler/test_disassembler.py @@ -22,7 +22,7 @@ from qiskit.assembler.run_config import RunConfig from qiskit.circuit import QuantumRegister, ClassicalRegister, QuantumCircuit from qiskit.circuit import Instruction -from qiskit.compiler.assemble import assemble +from qiskit.compiler.assembler import assemble from qiskit.test import QiskitTestCase from qiskit.test.mock import FakeOpenPulse2Q import qiskit.quantum_info as qi diff --git a/test/python/providers/test_fake_backends.py b/test/python/providers/test_fake_backends.py index 9b2520ea6b64..f237bc15d71e 100644 --- a/test/python/providers/test_fake_backends.py +++ b/test/python/providers/test_fake_backends.py @@ -19,7 +19,7 @@ from ddt import ddt, data from qiskit.circuit import QuantumCircuit -from qiskit.execute import execute +from qiskit.execute_function import execute from qiskit.test.base import QiskitTestCase from qiskit.test.mock import FakeProvider from qiskit.test.mock.fake_backend import HAS_AER diff --git a/test/python/quantum_info/test_local_invariance.py b/test/python/quantum_info/test_local_invariance.py index c0c8cd7ccdc9..a3293d5d66a9 100644 --- a/test/python/quantum_info/test_local_invariance.py +++ b/test/python/quantum_info/test_local_invariance.py @@ -16,7 +16,7 @@ import unittest from numpy.testing import assert_allclose -from qiskit.execute import execute +from qiskit.execute_function import execute from qiskit.circuit import QuantumCircuit, QuantumRegister from qiskit.test import QiskitTestCase from qiskit.providers.basicaer import UnitarySimulatorPy diff --git a/test/python/test_version.py b/test/python/test_version.py new file mode 100644 index 000000000000..3bfc1bb99f5e --- /dev/null +++ b/test/python/test_version.py @@ -0,0 +1,25 @@ +# 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 qiskit/version.py""" + +from qiskit import __qiskit_version__ +from qiskit import __version__ +from qiskit.test import QiskitTestCase + + +class TestVersion(QiskitTestCase): + """Tests for qiskit/version.py""" + + def test_qiskit_version(self): + """Test qiskit-version sets the correct version for terra.""" + self.assertEqual(__version__, __qiskit_version__['qiskit-terra'])