From 01ded73d1ded2342e39bc22d994ba0b50ffc8de7 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Wed, 9 Sep 2020 19:01:54 -0400 Subject: [PATCH] Add support for attachments to test execution (#3982) * Add support for attachments to test execution By default in CI and with tox locally we run all the tests in parallel. However, this makes things like printing to stdout, warnings on stderr, or logging during tests difficult to deal with. This is because we'll have multiple writers to the output streams simultaneously and no way to figure out which text goes to which test. Luckily stestr and the subunit protocl it uses internally has a method for adding attachments to test results to handle this kind of case. Using this each output stream is associated with the test which generated it and will get displayed as such. The only issue with this is that the stdlib unittest doesn't know how to write attachments to it's result stream. There is a unittest extension library testtools[1] that provides this functionality in a strictly compatible manner with unittest, however the current state of the library needs some work before it can work well with more modern features of stdlib unittest from python>3.5 so we either have to change the tests to not use these features or come up with an alternative solution for test attachments. This commit ports the necessary result streaming functionality from testtools into the QiskitTestCase base test class and then sets up the appropriate fixtures to attach output streams from each test. This works around the current limitation with testtools (I'm slowly working on fixing this in testtools) but still provides the functionality. When testtools is at the point it can be a drop in replacement for unittest as terra is using it we can drop this code. As part of this change all the test classes that define a setUp have a missing super() call added. This framework does not work without setUp in the base class being defined since that's what is used to setup the stream capture. Moving forward the base test class actually enforces that super() is called, otherwise the tests will fail. [1] https://github.com/testing-cabal/testtools * Fix lint * Update contributing doc * Fix copy paste error * Add missing super calls from new tests * Add missing super() calls and fix skip message * Fix lint Co-authored-by: Luciano Bello --- .travis.yml | 1 + CONTRIBUTING.md | 10 + Makefile | 2 +- azure-pipelines.yml | 5 + qiskit/test/base.py | 302 +++++++++++++++++- qiskit/test/runtest.py | 241 ++++++++++++++ .../basicaer/test_basicaer_integration.py | 1 + .../circuit/test_circuit_load_from_qasm.py | 1 + test/python/circuit/test_compose.py | 1 + test/python/circuit/test_controlled_gate.py | 2 +- .../circuit/test_extensions_standard.py | 3 + test/python/circuit/test_unitary.py | 4 - test/python/compiler/test_assembler.py | 4 + test/python/compiler/test_compiler.py | 1 + test/python/compiler/test_disassembler.py | 1 + test/python/compiler/test_transpiler.py | 1 + test/python/converters/test_ast_to_dag.py | 1 + test/python/dagcircuit/test_compose.py | 1 + test/python/dagcircuit/test_dagcircuit.py | 57 ++++ test/python/dagcircuit/test_dagdependency.py | 3 + .../providers/test_backendconfiguration.py | 1 + .../providers/test_backendproperties.py | 1 + test/python/providers/test_base_backend.py | 1 + test/python/providers/test_pulse_defaults.py | 1 + test/python/pulse/test_builder.py | 1 + test/python/pulse/test_macros.py | 2 + test/python/pulse/test_schedule.py | 2 + test/python/pulse/test_transforms.py | 2 + test/python/qobj/test_pulse_converter.py | 1 + test/python/qobj/test_qobj.py | 2 + test/python/qobj/test_qobj_identifiers.py | 1 + test/python/quantum_info/test_pauli.py | 1 + test/python/quantum_info/test_quaternions.py | 1 + test/python/scheduler/test_basic_scheduler.py | 1 + test/python/test_qasm_parser.py | 1 + test/python/test_schemas.py | 1 + test/python/tools/jupyter/test_notebooks.py | 1 + .../transpiler/test_commutation_analysis.py | 1 + .../test_commutative_cancellation.py | 2 +- test/python/transpiler/test_dense_layout.py | 1 + .../test_enlarge_with_ancilla_pass.py | 1 + test/python/transpiler/test_faulty_backend.py | 1 + .../transpiler/test_fixed_point_pass.py | 1 + .../test_full_ancilla_allocation.py | 1 + test/python/transpiler/test_layout.py | 1 + .../test_naming_transpiled_circuits.py | 1 + test/python/transpiler/test_pass_scheduler.py | 7 + .../transpiler/test_preset_passmanagers.py | 1 + test/python/transpiler/test_property_set.py | 1 + test/python/transpiler/test_sabre_layout.py | 1 + test/python/transpiler/test_token_swapper.py | 1 + test/python/transpiler/test_trivial_layout.py | 1 + test/python/transpiler/test_unroller.py | 1 + .../visualization/pulse_v2/test_generators.py | 1 + .../visualization/test_circuit_text_drawer.py | 1 + test/python/visualization/test_dag_drawer.py | 1 + test/python/visualization/test_gate_map.py | 1 + .../visualization/test_pass_manager_drawer.py | 1 + .../visualization/test_visualization.py | 1 + tox.ini | 1 + 60 files changed, 675 insertions(+), 18 deletions(-) create mode 100644 qiskit/test/runtest.py diff --git a/.travis.yml b/.travis.yml index fa07af9b1a..c9ad3e2d4f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -46,6 +46,7 @@ jobs: python: 3.6 env: - PYTHON="coverage run --source qiskit --parallel-mode" + - QISKIT_TEST_CAPTURE_STREAMS=1 after_success: - coverage combine || true - coveralls || true diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d63ce3bd46..c204148776 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -280,6 +280,16 @@ C:\..\> set LOG_LEVEL="INFO" C:\..\> python -m unittest test/python/circuit/test_circuit_operations.py ``` +##### STDOUT/STDERR and logging capture + +When running tests in parallel either via tox, the makefile, or in CI we set +the env variable `QISKIT_TEST_CAPTURE_STREAMS` which will capture any text +written to stdout, stderr, and log messages and add them as attachments to +the tests run so output can be associated with the test case it originated +from. However, if you run tests outside of these mechanisms by default the +streams are not captured. To enable stream capture just set the +`QISKIT_TEST_CAPTURE_STREAMS` env variable to `1`. + ##### Test Skip Options How and which tests are executed is controlled by an environment diff --git a/Makefile b/Makefile index 8b0e63af8d..792a4511dd 100644 --- a/Makefile +++ b/Makefile @@ -67,7 +67,7 @@ pytest_randomized: test_ci: echo "Detected $(NPROCS) CPUs running with $(CONCURRENCY) workers" - stestr run --concurrency $(CONCURRENCY) + QISKIT_TEST_CAPTURE_STREAMS=1 stestr run --concurrency $(CONCURRENCY) test_randomized: python3 -m unittest discover -s test/randomized -t . -v diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 551d0fde74..ddaad45092 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -132,6 +132,7 @@ stages: variables: QISKIT_SUPPRESS_PACKAGING_WARNINGS: Y PIP_CACHE_DIR: $(Pipeline.Workspace)/.pip + QISKIT_TEST_CAPTURE_STREAMS: 1 steps: - task: UsePythonVersion@0 inputs: @@ -285,6 +286,7 @@ stages: variables: QISKIT_SUPPRESS_PACKAGING_WARNINGS: Y PIP_CACHE_DIR: $(Pipeline.Workspace)/.pip + QISKIT_TEST_CAPTURE_STREAMS: 1 steps: - task: UsePythonVersion@0 inputs: @@ -358,6 +360,7 @@ stages: variables: QISKIT_SUPPRESS_PACKAGING_WARNINGS: Y PIP_CACHE_DIR: $(Pipeline.Workspace)/.pip + QISKIT_TEST_CAPTURE_STREAMS: 1 steps: - task: UsePythonVersion@0 inputs: @@ -426,6 +429,7 @@ stages: variables: QISKIT_SUPPRESS_PACKAGING_WARNINGS: Y PIP_CACHE_DIR: $(Pipeline.Workspace)/.pip + QISKIT_TEST_CAPTURE_STREAMS: 1 steps: - task: UsePythonVersion@0 inputs: @@ -495,6 +499,7 @@ stages: variables: QISKIT_SUPPRESS_PACKAGING_WARNINGS: Y PIP_CACHE_DIR: $(Pipeline.Workspace)/.pip + QISKIT_TEST_CAPTURE_STREAMS: 1 steps: - task: UsePythonVersion@0 inputs: diff --git a/qiskit/test/base.py b/qiskit/test/base.py index 0b3c1b9a05..9425ce9b4e 100644 --- a/qiskit/test/base.py +++ b/qiskit/test/base.py @@ -10,6 +10,9 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. +# pylint: disable=attribute-defined-outside-init,invalid-name,missing-type-doc +# pylint: disable=unused-argument,broad-except,bad-staticmethod-argument + """Base TestCases for the unit tests. Implementors of unit tests for Terra are encouraged to subclass @@ -18,39 +21,316 @@ the environment variables for customizing different options), and the decorators in the ``decorators`` package. """ -import inspect +import itertools import logging import os +import sys import unittest from unittest.util import safe_repr -from .utils import Path, _AssertNoLogsContext, setup_test_logging +import fixtures +from testtools.compat import advance_iterator +from testtools import content + +from .runtest import RunTest, MultipleExceptions +from .utils import Path, _AssertNoLogsContext __unittest = True # Allows shorter stack trace for .assertDictAlmostEqual +def _copy_content(content_object): + """Make a copy of the given content object. + + The content within ``content_object`` is iterated and saved. This is + useful when the source of the content is volatile, a log file in a + temporary directory for example. + + Args: + content_object (content.Content): A ``content.Content`` instance. + + Returns: + content.Content: An instance with the same mime-type as + ``content_object`` and a non-volatile copy of its content. + """ + content_bytes = list(content_object.iter_bytes()) + + def content_callback(): + return content_bytes + + return content.Content(content_object.content_type, content_callback) + + +def gather_details(source_dict, target_dict): + """Merge the details from ``source_dict`` into ``target_dict``. + + ``gather_details`` evaluates all details in ``source_dict``. Do not use it + if the details are not ready to be evaluated. + + :param source_dict: A dictionary of details will be gathered. + :param target_dict: A dictionary into which details will be gathered. + """ + for name, content_object in source_dict.items(): + new_name = name + disambiguator = itertools.count(1) + while new_name in target_dict: + new_name = '%s-%d' % (name, advance_iterator(disambiguator)) + name = new_name + target_dict[name] = _copy_content(content_object) + + class QiskitTestCase(unittest.TestCase): """Helper class that contains common functionality.""" - @classmethod - def setUpClass(cls): - # Determines if the TestCase is using IBMQ credentials. - cls.using_ibmq_credentials = False + run_tests_with = RunTest - # Set logging to file and stdout if the LOG_LEVEL envar is set. - cls.log = logging.getLogger(cls.__name__) - if os.getenv('LOG_LEVEL'): - filename = '%s.log' % os.path.splitext(inspect.getfile(cls))[0] - setup_test_logging(cls.log, os.getenv('LOG_LEVEL'), filename) + def __init__(self, *args, **kwargs): + """Construct a TestCase.""" + super(QiskitTestCase, self).__init__(*args, **kwargs) + self.__RunTest = self.run_tests_with + self._reset() + self.__exception_handlers = [] + self.exception_handlers = [ + (unittest.SkipTest, self._report_skip), + (self.failureException, self._report_failure), + (unittest.case._UnexpectedSuccess, self._report_unexpected_success), + (Exception, self._report_error)] + + def _reset(self): + """Reset the test case as if it had never been run.""" + self._cleanups = [] + self._unique_id_gen = itertools.count(1) + # Generators to ensure unique traceback ids. Maps traceback label to + # iterators. + self._traceback_id_gens = {} + self.__setup_called = False + self.__teardown_called = False + self.__details = None + + def onException(self, exc_info, tb_label='traceback'): + """Called when an exception propagates from test code. + + :seealso addOnException: + """ + if exc_info[0] not in [ + unittest.SkipTest, unittest.case._UnexpectedSuccess]: + self._report_traceback(exc_info, tb_label=tb_label) + for handler in self.__exception_handlers: + handler(exc_info) + + def _run_teardown(self, result): + """Run the tearDown function for this test.""" + self.tearDown() + if not self.__teardown_called: + raise ValueError( + "In File: %s\n" + "TestCase.tearDown was not called. Have you upcalled all the " + "way up the hierarchy from your tearDown? e.g. Call " + "super(%s, self).tearDown() from your tearDown()." + % (sys.modules[self.__class__.__module__].__file__, + self.__class__.__name__)) + + def _get_test_method(self): + method_name = getattr(self, '_testMethodName') + return getattr(self, method_name) + + def _run_test_method(self, result): + """Run the test method for this test.""" + return self._get_test_method()() + + def useFixture(self, fixture): + """Use fixture in a test case. + + The fixture will be setUp, and self.addCleanup(fixture.cleanUp) called. + + Args: + fixture: The fixture to use. + + Returns: + fixture: The fixture, after setting it up and scheduling a cleanup + for it. + + Raises: + MultipleExceptions: When there is an error during fixture setUp + Exception: If an exception is raised during fixture setUp + """ + try: + fixture.setUp() + except MultipleExceptions as e: + if (fixtures is not None and + e.args[-1][0] is fixtures.fixture.SetupError): + gather_details(e.args[-1][1].args[0], self.getDetails()) + raise + except Exception: + exc_info = sys.exc_info() + try: + # fixture._details is not available if using the newer + # _setUp() API in Fixtures because it already cleaned up + # the fixture. Ideally this whole try/except is not + # really needed any more, however, we keep this code to + # remain compatible with the older setUp(). + if (hasattr(fixture, '_details') and + fixture._details is not None): + gather_details(fixture.getDetails(), self.getDetails()) + except Exception: + # Report the setUp exception, then raise the error during + # gather_details. + self._report_traceback(exc_info) + raise + else: + # Gather_details worked, so raise the exception setUp + # encountered. + def reraise(exc_class, exc_obj, exc_tb, _marker=object()): + """Re-raise an exception received from sys.exc_info() or similar.""" + raise exc_obj.with_traceback(exc_tb) + + reraise(*exc_info) + else: + self.addCleanup(fixture.cleanUp) + self.addCleanup( + gather_details, fixture.getDetails(), self.getDetails()) + return fixture + + def _run_setup(self, result): + """Run the setUp function for this test.""" + self.setUp() + if not self.__setup_called: + raise ValueError( + "In File: %s\n" + "TestCase.setUp was not called. Have you upcalled all the " + "way up the hierarchy from your setUp? e.g. Call " + "super(%s, self).setUp() from your setUp()." + % (sys.modules[self.__class__.__module__].__file__, + self.__class__.__name__)) + + def _add_reason(self, reason): + self.addDetail('reason', content.text_content(reason)) + + @staticmethod + def _report_error(self, result, err): + result.addError(self, details=self.getDetails()) + + @staticmethod + def _report_expected_failure(self, result, err): + result.addExpectedFailure(self, details=self.getDetails()) + + @staticmethod + def _report_failure(self, result, err): + result.addFailure(self, details=self.getDetails()) + + @staticmethod + def _report_skip(self, result, err): + if err.args: + reason = err.args[0] + else: + reason = "no reason given." + self._add_reason(reason) + result.addSkip(self, details=self.getDetails()) + + def _report_traceback(self, exc_info, tb_label='traceback'): + id_gen = self._traceback_id_gens.setdefault( + tb_label, itertools.count(0)) + while True: + tb_id = advance_iterator(id_gen) + if tb_id: + tb_label = '%s-%d' % (tb_label, tb_id) + if tb_label not in self.getDetails(): + break + self.addDetail(tb_label, content.TracebackContent( + exc_info, self, capture_locals=getattr( + self, '__testtools_tb_locals__', False))) + + @staticmethod + def _report_unexpected_success(self, result, err): + result.addUnexpectedSuccess(self, details=self.getDetails()) + + def run(self, result=None): + self._reset() + try: + run_test = self.__RunTest( + self, self.exception_handlers, last_resort=self._report_error) + except TypeError: + # Backwards compat: if we can't call the constructor + # with last_resort, try without that. + run_test = self.__RunTest(self, self.exception_handlers) + return run_test.run(result) + + def setUp(self): + super().setUp() + if self.__setup_called: + raise ValueError( + "In File: %s\n" + "TestCase.setUp was already called. Do not explicitly call " + "setUp from your tests. In your own setUp, use super to call " + "the base setUp." + % (sys.modules[self.__class__.__module__].__file__,)) + self.__setup_called = True + if os.environ.get('QISKIT_TEST_CAPTURE_STREAMS'): + stdout = self.useFixture(fixtures.StringStream('stdout')).stream + self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout)) + stderr = self.useFixture(fixtures.StringStream('stderr')).stream + self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr)) + self.useFixture(fixtures.LoggerFixture(nuke_handlers=False, + level=None)) def tearDown(self): + super().tearDown() + if self.__teardown_called: + raise ValueError( + "In File: %s\n" + "TestCase.tearDown was already called. Do not explicitly call " + "tearDown from your tests. In your own tearDown, use super to " + "call the base tearDown." + % (sys.modules[self.__class__.__module__].__file__,)) + self.__teardown_called = True # Reset the default providers, as in practice they acts as a singleton # due to importing the instances from the top-level qiskit namespace. from qiskit.providers.basicaer import BasicAer BasicAer._backends = BasicAer._verify_backends() + def addDetail(self, name, content_object): + """Add a detail to be reported with this test's outcome. + + :param name: The name to give this detail. + :param content_object: The content object for this detail. See + testtools.content for more detail. + """ + if self.__details is None: + self.__details = {} + self.__details[name] = content_object + + def addDetailUniqueName(self, name, content_object): + """Add a detail to the test, but ensure it's name is unique. + + This method checks whether ``name`` conflicts with a detail that has + already been added to the test. If it does, it will modify ``name`` to + avoid the conflict. + + :param name: The name to give this detail. + :param content_object: The content object for this detail. See + testtools.content for more detail. + """ + existing_details = self.getDetails() + full_name = name + suffix = 1 + while full_name in existing_details: + full_name = "%s-%d" % (name, suffix) + suffix += 1 + self.addDetail(full_name, content_object) + + def getDetails(self): + """Get the details dict that will be reported with this test's outcome.""" + if self.__details is None: + self.__details = {} + return self.__details + + @classmethod + def setUpClass(cls): + # Determines if the TestCase is using IBMQ credentials. + cls.using_ibmq_credentials = False + cls.log = logging.getLogger(cls.__name__) + @staticmethod def _get_resource_path(filename, path=Path.TEST): """Get the absolute path to a resource. diff --git a/qiskit/test/runtest.py b/qiskit/test/runtest.py new file mode 100644 index 0000000000..ae300d257e --- /dev/null +++ b/qiskit/test/runtest.py @@ -0,0 +1,241 @@ +# -*- coding: utf-8 -*- + +# This code is part of Qiskit. +# +# (C) Copyright IBM 2017, 2018. +# +# 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. + +# Copyright (c) 2009-2010 testtools developers. + +# Forked from testing-cabal/testtools + +# pylint: disable=missing-return-type-doc,missing-type-doc,missing-type-doc,invalid-name +# pylint: disable=broad-except,attribute-defined-outside-init,unused-argument + +"""Individual test case execution.""" + +__all__ = [ + 'MultipleExceptions', + 'RunTest', + ] + +import sys + +from testtools.testresult import ExtendedToOriginalDecorator + + +class MultipleExceptions(Exception): + """Represents many exceptions raised from some operation. + :ivar args: The sys.exc_info() tuples for each exception. + """ + + +class RunTest: + """An object to run a test. + RunTest objects are used to implement the internal logic involved in + running a test. TestCase.__init__ stores _RunTest as the class of RunTest + to execute. Passing the runTest= parameter to TestCase.__init__ allows a + different RunTest class to be used to execute the test. + Subclassing or replacing RunTest can be useful to add functionality to the + way that tests are run in a given project. + :ivar case: The test case that is to be run. + :ivar result: The result object a case is reporting to. + :ivar handlers: A list of (ExceptionClass, handler_function) for + exceptions that should be caught if raised from the user + code. Exceptions that are caught are checked against this list in + first to last order. There is a catch-all of 'Exception' at the end + of the list, so to add a new exception to the list, insert it at the + front (which ensures that it will be checked before any existing base + classes in the list. If you add multiple exceptions some of which are + subclasses of each other, add the most specific exceptions last (so + they come before their parent classes in the list). + :ivar exception_caught: An object returned when _run_user catches an + exception. + :ivar _exceptions: A list of caught exceptions, used to do the single + reporting of error/failure/skip etc. + """ + + def __init__(self, case, handlers=None, last_resort=None): + """Create a RunTest to run a case. + + Args: + case: A test case object. + handlers: Exception handlers for this RunTest. These are stored + in self.handlers and can be modified later if needed. + last_resort: A handler of last resort: any exception which is + not handled by handlers will cause the last resort handler to be + called as last_resort(exc_info), and then the exception will be + raised - aborting the test run as this is inside the runner + machinery rather than the confined context of the test. + """ + self.case = case + self.handlers = handlers or [] + self.exception_caught = object() + self._exceptions = [] + self.last_resort = last_resort or (lambda case, result, exc: None) + + def run(self, result=None): + """Run self.case reporting activity to result. + Args: + result: Optional testtools.TestResult to report activity to. + + Returns: + The result object the test was run against. + """ + if result is None: + actual_result = self.case.defaultTestResult() + actual_result.startTestRun() + else: + actual_result = result + try: + return self._run_one(actual_result) + finally: + if result is None: + actual_result.stopTestRun() + + def _run_one(self, result): + """Run one test reporting to result. + :param result: A testtools.TestResult to report activity to. + This result object is decorated with an ExtendedToOriginalDecorator + to ensure that the latest TestResult API can be used with + confidence by client code. + :return: The result object the test was run against. + """ + return self._run_prepared_result(ExtendedToOriginalDecorator(result)) + + def _run_prepared_result(self, result): + """Run one test reporting to result. + :param result: A testtools.TestResult to report activity to. + :return: The result object the test was run against. + """ + result.startTest(self.case) + self.result = result + try: + self._exceptions = [] + self.case.__testtools_tb_locals__ = getattr( + result, 'tb_locals', False) + self._run_core() + if self._exceptions: + # One or more caught exceptions, now trigger the test's + # reporting method for just one. + e = self._exceptions.pop() + for exc_class, handler in self.handlers: + if isinstance(e, exc_class): + handler(self.case, self.result, e) + break + else: + self.last_resort(self.case, self.result, e) + raise e + finally: + result.stopTest(self.case) + return result + + def _run_core(self): + """Run the user supplied test code.""" + test_method = self.case._get_test_method() + skip_case = getattr(self.case, '__unittest_skip__', False) + if skip_case or getattr(test_method, '__unittest_skip__', False): + self.result.addSkip( + self.case, + reason=getattr(self.case if skip_case else test_method, + '__unittest_skip_why__', None) + ) + return + + if self.exception_caught == self._run_user(self.case._run_setup, + self.result): + # Don't run the test method if we failed getting here. + self._run_cleanups(self.result) + return + # Run everything from here on in. If any of the methods raise an + # exception we'll have failed. + failed = False + try: + if self.exception_caught == self._run_user( + self.case._run_test_method, self.result): + failed = True + finally: + try: + if self.exception_caught == self._run_user( + self.case._run_teardown, self.result): + failed = True + finally: + try: + if self.exception_caught == self._run_user( + self._run_cleanups, self.result): + failed = True + finally: + if getattr(self.case, 'force_failure', None): + self._run_user(_raise_force_fail_error) + failed = True + if not failed: + self.result.addSuccess(self.case, + details=self.case.getDetails()) + + def _run_cleanups(self, result): + """Run the cleanups that have been added with addCleanup. + See the docstring for addCleanup for more information. + :return: None if all cleanups ran without error, + ``exception_caught`` if there was an error. + """ + failing = False + while self.case._cleanups: + function, arguments, keywordArguments = self.case._cleanups.pop() + got_exception = self._run_user( + function, *arguments, **keywordArguments) + if got_exception == self.exception_caught: + failing = True + if failing: + return self.exception_caught + + def _run_user(self, fn, *args, **kwargs): + """Run a user supplied function. + Exceptions are processed by `_got_user_exception`. + :return: Either whatever 'fn' returns or ``exception_caught`` if + 'fn' raised an exception. + """ + try: + return fn(*args, **kwargs) + except Exception: + return self._got_user_exception(sys.exc_info()) + + def _got_user_exception(self, exc_info, tb_label='traceback'): + """Called when user code raises an exception. + If 'exc_info' is a `MultipleExceptions`, then we recurse into it + unpacking the errors that it's made up from. + :param exc_info: A sys.exc_info() tuple for the user error. + :param tb_label: An optional string label for the error. If + not specified, will default to 'traceback'. + :return: 'exception_caught' if we catch one of the exceptions that + have handlers in 'handlers', otherwise raise the error. + """ + if exc_info[0] is MultipleExceptions: + for sub_exc_info in exc_info[1].args: + self._got_user_exception(sub_exc_info, tb_label) + return self.exception_caught + try: + e = exc_info[1] + self.case.onException(exc_info, tb_label=tb_label) + finally: + del exc_info + self._exceptions.append(e) + # Yes, this means we catch everything - we re-raise KeyBoardInterrupt + # etc later, after tearDown and cleanUp - since those may be cleaning up + # external processes. + return self.exception_caught + + +def _raise_force_fail_error(): + raise AssertionError("Forced Test Failure") + + +# Signal that this is part of the testing framework, and that code from this +# should not normally appear in tracebacks. +__unittest = True diff --git a/test/python/basicaer/test_basicaer_integration.py b/test/python/basicaer/test_basicaer_integration.py index cbe70d60b5..13ac3ff9cf 100644 --- a/test/python/basicaer/test_basicaer_integration.py +++ b/test/python/basicaer/test_basicaer_integration.py @@ -26,6 +26,7 @@ class TestBasicAerIntegration(QiskitTestCase): """Qiskit BasicAer simulator integration tests.""" def setUp(self): + super().setUp() qr = QuantumRegister(1) cr = ClassicalRegister(1) self._qc1 = QuantumCircuit(qr, cr, name='qc1') diff --git a/test/python/circuit/test_circuit_load_from_qasm.py b/test/python/circuit/test_circuit_load_from_qasm.py index 37537c7282..206c53dd3c 100644 --- a/test/python/circuit/test_circuit_load_from_qasm.py +++ b/test/python/circuit/test_circuit_load_from_qasm.py @@ -25,6 +25,7 @@ class LoadFromQasmTest(QiskitTestCase): """Test circuit.from_qasm_* set of methods.""" def setUp(self): + super().setUp() self.qasm_file_name = 'entangled_registers.qasm' self.qasm_file_path = self._get_resource_path('qasm/' + self.qasm_file_name, Path.EXAMPLES) diff --git a/test/python/circuit/test_compose.py b/test/python/circuit/test_compose.py index 918ad18d5e..cee9947e15 100644 --- a/test/python/circuit/test_compose.py +++ b/test/python/circuit/test_compose.py @@ -25,6 +25,7 @@ class TestCircuitCompose(QiskitTestCase): """Test composition of two circuits.""" def setUp(self): + super().setUp() qreg1 = QuantumRegister(3, 'lqr_1') qreg2 = QuantumRegister(2, 'lqr_2') creg = ClassicalRegister(2, 'lcr') diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index 32e9a8dc73..2161bf45f7 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -1051,7 +1051,7 @@ class TestOpenControlledToMatrix(QiskitTestCase): try: actual = cgate.to_matrix() except CircuitError as cerr: - self.skipTest(cerr) + self.skipTest(str(cerr)) self.assertTrue(np.allclose(actual, target)) diff --git a/test/python/circuit/test_extensions_standard.py b/test/python/circuit/test_extensions_standard.py index dc52b26e21..cf0a349676 100644 --- a/test/python/circuit/test_extensions_standard.py +++ b/test/python/circuit/test_extensions_standard.py @@ -29,6 +29,7 @@ class TestStandard1Q(QiskitTestCase): """Standard Extension Test. Gates with a single Qubit""" def setUp(self): + super().setUp() self.qr = QuantumRegister(3, "q") self.qr2 = QuantumRegister(3, "r") self.cr = ClassicalRegister(3, "c") @@ -953,6 +954,7 @@ class TestStandard2Q(QiskitTestCase): """Standard Extension Test. Gates with two Qubits""" def setUp(self): + super().setUp() self.qr = QuantumRegister(3, "q") self.qr2 = QuantumRegister(3, "r") self.cr = ClassicalRegister(3, "c") @@ -1300,6 +1302,7 @@ class TestStandard3Q(QiskitTestCase): """Standard Extension Test. Gates with three Qubits""" def setUp(self): + super().setUp() self.qr = QuantumRegister(3, "q") self.qr2 = QuantumRegister(3, "r") self.qr3 = QuantumRegister(3, "s") diff --git a/test/python/circuit/test_unitary.py b/test/python/circuit/test_unitary.py index ee1d2c48e0..cadf40b56d 100644 --- a/test/python/circuit/test_unitary.py +++ b/test/python/circuit/test_unitary.py @@ -32,10 +32,6 @@ from qiskit.transpiler.passes import CXCancellation class TestUnitaryGate(QiskitTestCase): """Tests for the Unitary class.""" - def setUp(self): - """Setup.""" - pass - def test_set_matrix(self): """Test instantiation""" try: diff --git a/test/python/compiler/test_assembler.py b/test/python/compiler/test_assembler.py index 783aca8930..30867be19c 100644 --- a/test/python/compiler/test_assembler.py +++ b/test/python/compiler/test_assembler.py @@ -50,6 +50,7 @@ class TestCircuitAssembler(QiskitTestCase): """Tests for assembling circuits to qobj.""" def setUp(self): + super().setUp() qr = QuantumRegister(2, name='q') cr = ClassicalRegister(2, name='c') self.circ = QuantumCircuit(qr, cr, name='circ') @@ -460,6 +461,7 @@ class TestPulseAssembler(QiskitTestCase): """Tests for assembling schedules to qobj.""" def setUp(self): + super().setUp() self.backend = FakeOpenPulse2Q() self.backend_config = self.backend.configuration() @@ -1043,6 +1045,7 @@ class TestPulseAssemblerMissingKwargs(QiskitTestCase): """Verify that errors are raised in case backend is not provided and kwargs are missing.""" def setUp(self): + super().setUp() self.schedule = pulse.Schedule(name='fake_experiment') self.backend = FakeOpenPulse2Q() @@ -1219,6 +1222,7 @@ class TestLogAssembler(QiskitTestCase): """Testing the log_assembly option.""" def setUp(self): + super().setUp() logger = getLogger() logger.setLevel('DEBUG') self.output = io.StringIO() diff --git a/test/python/compiler/test_compiler.py b/test/python/compiler/test_compiler.py index 2722479a43..a2b6a01254 100644 --- a/test/python/compiler/test_compiler.py +++ b/test/python/compiler/test_compiler.py @@ -28,6 +28,7 @@ class TestCompiler(QiskitTestCase): """Qiskit Compiler Tests.""" def setUp(self): + super().setUp() self.seed_simulator = 42 self.backend = BasicAer.get_backend("qasm_simulator") diff --git a/test/python/compiler/test_disassembler.py b/test/python/compiler/test_disassembler.py index bce929ade9..8351cb32f6 100644 --- a/test/python/compiler/test_disassembler.py +++ b/test/python/compiler/test_disassembler.py @@ -216,6 +216,7 @@ class TestPulseScheduleDisassembler(QiskitTestCase): """Tests for disassembling pulse schedules to qobj.""" def setUp(self): + super().setUp() self.backend = FakeOpenPulse2Q() self.backend_config = self.backend.configuration() self.backend_config.parametric_pulses = [ diff --git a/test/python/compiler/test_transpiler.py b/test/python/compiler/test_transpiler.py index bad455a9b6..fb7284e2fa 100644 --- a/test/python/compiler/test_transpiler.py +++ b/test/python/compiler/test_transpiler.py @@ -769,6 +769,7 @@ class TestLogTranspile(QiskitTestCase): """Testing the log_transpile option.""" def setUp(self): + super().setUp() logger = getLogger() logger.setLevel('DEBUG') self.output = io.StringIO() diff --git a/test/python/converters/test_ast_to_dag.py b/test/python/converters/test_ast_to_dag.py index 010c90d515..d5427e8e62 100644 --- a/test/python/converters/test_ast_to_dag.py +++ b/test/python/converters/test_ast_to_dag.py @@ -24,6 +24,7 @@ class TestAstToDag(QiskitTestCase): """Test AST to DAG.""" def setUp(self): + super().setUp() qr = QuantumRegister(3) cr = ClassicalRegister(3) self.circuit = QuantumCircuit(qr, cr) diff --git a/test/python/dagcircuit/test_compose.py b/test/python/dagcircuit/test_compose.py index f77d1ffe5a..b30c7949da 100644 --- a/test/python/dagcircuit/test_compose.py +++ b/test/python/dagcircuit/test_compose.py @@ -24,6 +24,7 @@ class TestDagCompose(QiskitTestCase): """Test composition of two dags""" def setUp(self): + super().setUp() qreg1 = QuantumRegister(3, 'lqr_1') qreg2 = QuantumRegister(2, 'lqr_2') creg = ClassicalRegister(2, 'lcr') diff --git a/test/python/dagcircuit/test_dagcircuit.py b/test/python/dagcircuit/test_dagcircuit.py index 202acbf62d..f2a87be8c9 100644 --- a/test/python/dagcircuit/test_dagcircuit.py +++ b/test/python/dagcircuit/test_dagcircuit.py @@ -178,6 +178,7 @@ class TestDagApplyOperation(QiskitTestCase): """Test adding an op node to a dag.""" def setUp(self): + super().setUp() self.dag = DAGCircuit() qreg = QuantumRegister(3, 'qr') creg = ClassicalRegister(2, 'cr') @@ -353,6 +354,7 @@ class TestDagNodeSelection(QiskitTestCase): """Test methods that select certain dag nodes""" def setUp(self): + super().setUp() self.dag = DAGCircuit() qreg = QuantumRegister(3, 'qr') creg = ClassicalRegister(2, 'cr') @@ -767,6 +769,58 @@ class TestDagLayers(QiskitTestCase): self.assertEqual(comp, truth) +class TestCircuitProperties(QiskitTestCase): + """DAGCircuit properties test.""" + + def setUp(self): + super().setUp() + qr1 = QuantumRegister(4) + qr2 = QuantumRegister(2) + circ = QuantumCircuit(qr1, qr2) + circ.h(qr1[0]) + circ.cx(qr1[2], qr1[3]) + circ.h(qr1[2]) + circ.t(qr1[2]) + circ.ch(qr1[2], qr1[1]) + circ.u2(0.1, 0.2, qr1[3]) + circ.ccx(qr2[0], qr2[1], qr1[0]) + + self.dag = circuit_to_dag(circ) + + def test_circuit_size(self): + """Test total number of operations in circuit.""" + self.assertEqual(self.dag.size(), 7) + + def test_circuit_depth(self): + """Test circuit depth.""" + self.assertEqual(self.dag.depth(), 4) + + def test_circuit_width(self): + """Test number of qubits + clbits in circuit.""" + self.assertEqual(self.dag.width(), 6) + + def test_circuit_num_qubits(self): + """Test number of qubits in circuit.""" + self.assertEqual(self.dag.num_qubits(), 6) + + def test_circuit_operations(self): + """Test circuit operations breakdown by kind of op.""" + operations = { + 'h': 2, + 't': 1, + 'u2': 1, + 'cx': 1, + 'ch': 1, + 'ccx': 1 + } + + self.assertDictEqual(self.dag.count_ops(), operations) + + def test_circuit_factors(self): + """Test number of separable factors in circuit.""" + self.assertEqual(self.dag.num_tensor_factors(), 2) + + class TestCircuitSpecialCases(QiskitTestCase): """DAGCircuit test for special cases, usually for regression.""" @@ -790,6 +844,7 @@ class TestDagEquivalence(QiskitTestCase): """DAGCircuit equivalence check.""" def setUp(self): + super().setUp() self.qr1 = QuantumRegister(4, 'qr1') self.qr2 = QuantumRegister(2, 'qr2') circ1 = QuantumCircuit(self.qr2, self.qr1) @@ -855,6 +910,7 @@ class TestDagSubstitute(QiskitTestCase): """Test substituting a dag node with a sub-dag""" def setUp(self): + super().setUp() self.dag = DAGCircuit() qreg = QuantumRegister(3, 'qr') creg = ClassicalRegister(2, 'cr') @@ -1009,6 +1065,7 @@ class TestDagProperties(QiskitTestCase): """ def setUp(self): + super().setUp() qr1 = QuantumRegister(4) qr2 = QuantumRegister(2) circ = QuantumCircuit(qr1, qr2) diff --git a/test/python/dagcircuit/test_dagdependency.py b/test/python/dagcircuit/test_dagdependency.py index fa35c75184..28fa406c95 100644 --- a/test/python/dagcircuit/test_dagdependency.py +++ b/test/python/dagcircuit/test_dagdependency.py @@ -102,6 +102,7 @@ class TestDagNodeEdge(QiskitTestCase): """Test adding nodes and edges to a dag and related functions.""" def setUp(self): + super().setUp() self.dag = DAGDependency() self.qreg = QuantumRegister(2, 'qr') self.creg = ClassicalRegister(2, 'cr') @@ -164,6 +165,7 @@ class TestDagNodeSelection(QiskitTestCase): """Test methods that select successors and predecessors""" def setUp(self): + super().setUp() self.dag = DAGDependency() self.qreg = QuantumRegister(2, 'qr') self.creg = ClassicalRegister(2, 'cr') @@ -213,6 +215,7 @@ class TestDagProperties(QiskitTestCase): """ def setUp(self): + super().setUp() qr1 = QuantumRegister(4) qr2 = QuantumRegister(2) circ = QuantumCircuit(qr1, qr2) diff --git a/test/python/providers/test_backendconfiguration.py b/test/python/providers/test_backendconfiguration.py index 1b9b19f7b5..753b47683b 100644 --- a/test/python/providers/test_backendconfiguration.py +++ b/test/python/providers/test_backendconfiguration.py @@ -26,6 +26,7 @@ class TestBackendConfiguration(QiskitTestCase): """Test the methods on the BackendConfiguration class.""" def setUp(self): + super().setUp() self.provider = FakeProvider() self.config = self.provider.get_backend('fake_openpulse_2q').configuration() diff --git a/test/python/providers/test_backendproperties.py b/test/python/providers/test_backendproperties.py index 120c33c2cb..8af3af57ec 100644 --- a/test/python/providers/test_backendproperties.py +++ b/test/python/providers/test_backendproperties.py @@ -27,6 +27,7 @@ class BackendpropertiesTestCase(QiskitTestCase): backend_name = 'fake_ourense' def setUp(self): + super().setUp() self.provider = FakeProvider() self.backend = self.provider.get_backend('fake_ourense') self.properties = self.backend.properties() diff --git a/test/python/providers/test_base_backend.py b/test/python/providers/test_base_backend.py index 8df093d421..a2271f41fa 100644 --- a/test/python/providers/test_base_backend.py +++ b/test/python/providers/test_base_backend.py @@ -22,6 +22,7 @@ class TestBaseBackend(QiskitTestCase): """Test the backend methods.""" def setUp(self): + super().setUp() self.pulse_backend = FakeOpenPulse2Q() self.backend = FakeMelbourne() diff --git a/test/python/providers/test_pulse_defaults.py b/test/python/providers/test_pulse_defaults.py index 8e321d35b9..a8b4e51b9f 100644 --- a/test/python/providers/test_pulse_defaults.py +++ b/test/python/providers/test_pulse_defaults.py @@ -26,6 +26,7 @@ class TestPulseDefaults(QiskitTestCase): """Test the PulseDefaults creation and method usage.""" def setUp(self): + super().setUp() self.defs = FakeOpenPulse2Q().defaults() self.inst_map = self.defs.instruction_schedule_map diff --git a/test/python/pulse/test_builder.py b/test/python/pulse/test_builder.py index 9710c6e029..de61ebf927 100644 --- a/test/python/pulse/test_builder.py +++ b/test/python/pulse/test_builder.py @@ -31,6 +31,7 @@ class TestBuilder(QiskitTestCase): """Test the pulse builder context.""" def setUp(self): + super().setUp() self.backend = FakeOpenPulse2Q() self.configuration = self.backend.configuration() self.defaults = self.backend.defaults() diff --git a/test/python/pulse/test_macros.py b/test/python/pulse/test_macros.py index 53da690334..2dbbd99f9d 100644 --- a/test/python/pulse/test_macros.py +++ b/test/python/pulse/test_macros.py @@ -32,6 +32,7 @@ class TestMeasure(QiskitTestCase): """Pulse measure macro.""" def setUp(self): + super().setUp() self.backend = FakeOpenPulse2Q() self.inst_map = self.backend.defaults().instruction_schedule_map @@ -103,6 +104,7 @@ class TestMeasureAll(QiskitTestCase): """Pulse measure all macro.""" def setUp(self): + super().setUp() self.backend = FakeOpenPulse2Q() self.inst_map = self.backend.defaults().instruction_schedule_map diff --git a/test/python/pulse/test_schedule.py b/test/python/pulse/test_schedule.py index f3691a1878..5de1643348 100644 --- a/test/python/pulse/test_schedule.py +++ b/test/python/pulse/test_schedule.py @@ -52,6 +52,8 @@ class BaseTestSchedule(QiskitTestCase): """Schedule tests.""" def setUp(self): + super().setUp() + @functional_pulse def linear(duration, slope, intercept): x = np.linspace(0, duration - 1, duration) diff --git a/test/python/pulse/test_transforms.py b/test/python/pulse/test_transforms.py index 92d3b75f87..d803aee0d3 100644 --- a/test/python/pulse/test_transforms.py +++ b/test/python/pulse/test_transforms.py @@ -41,6 +41,7 @@ class TestAlignMeasures(QiskitTestCase): """Test the helper function which aligns acquires.""" def setUp(self): + super().setUp() self.backend = FakeOpenPulse2Q() self.config = self.backend.configuration() self.inst_map = self.backend.defaults().instruction_schedule_map @@ -198,6 +199,7 @@ class TestAddImplicitAcquires(QiskitTestCase): """Test the helper function which makes implicit acquires explicit.""" def setUp(self): + super().setUp() self.backend = FakeOpenPulse2Q() self.config = self.backend.configuration() self.short_pulse = pulse.Waveform(samples=np.array([0.02739068], dtype=np.complex128), diff --git a/test/python/qobj/test_pulse_converter.py b/test/python/qobj/test_pulse_converter.py index a9945e370e..e4e54f21eb 100644 --- a/test/python/qobj/test_pulse_converter.py +++ b/test/python/qobj/test_pulse_converter.py @@ -189,6 +189,7 @@ class TestQobjToInstructionConverter(QiskitTestCase): """Pulse converter tests.""" def setUp(self): + super().setUp() self.linear = Waveform(np.arange(0, 0.01), name='linear') self.pulse_library = [PulseLibraryItem(name=self.linear.name, samples=self.linear.samples.tolist())] diff --git a/test/python/qobj/test_qobj.py b/test/python/qobj/test_qobj.py index ef71665ba0..719b361c11 100644 --- a/test/python/qobj/test_qobj.py +++ b/test/python/qobj/test_qobj.py @@ -39,6 +39,7 @@ class TestQASMQobj(QiskitTestCase): """Tests for QasmQobj.""" def setUp(self): + super().setUp() self.valid_qobj = QasmQobj( qobj_id='12345', header=QobjHeader(), @@ -252,6 +253,7 @@ class TestPulseQobj(QiskitTestCase): """Tests for PulseQobj.""" def setUp(self): + super().setUp() self.valid_qobj = PulseQobj( qobj_id='12345', header=QobjHeader(), diff --git a/test/python/qobj/test_qobj_identifiers.py b/test/python/qobj/test_qobj_identifiers.py index 6a0eacd0a6..ab4b9a1cdc 100644 --- a/test/python/qobj/test_qobj_identifiers.py +++ b/test/python/qobj/test_qobj_identifiers.py @@ -25,6 +25,7 @@ class TestQobjIdentifiers(QiskitTestCase): """Check the Qobj compiled for different backends create names properly""" def setUp(self): + super().setUp() qr = QuantumRegister(2, name="qr2") cr = ClassicalRegister(2, name=None) qc = QuantumCircuit(qr, cr, name="qc10") diff --git a/test/python/quantum_info/test_pauli.py b/test/python/quantum_info/test_pauli.py index 03b7571c71..27843535b6 100644 --- a/test/python/quantum_info/test_pauli.py +++ b/test/python/quantum_info/test_pauli.py @@ -66,6 +66,7 @@ class TestPauli(QiskitTestCase): def setUp(self): """Setup.""" + super().setUp() z = np.asarray([1, 0, 1, 0]).astype(np.bool) x = np.asarray([1, 1, 0, 0]).astype(np.bool) self.ref_p = Pauli(z, x) diff --git a/test/python/quantum_info/test_quaternions.py b/test/python/quantum_info/test_quaternions.py index 05aa61f992..514022c2bb 100644 --- a/test/python/quantum_info/test_quaternions.py +++ b/test/python/quantum_info/test_quaternions.py @@ -27,6 +27,7 @@ class TestQuaternions(QiskitTestCase): """Tests qiskit.quantum_info.operators.quaternion""" def setUp(self): + super().setUp() self.rnd_array = np.array([0.5, 0.8, 0.9, -0.3]) self.quat_unnormalized = Quaternion(self.rnd_array) axes = ['x', 'y', 'z'] diff --git a/test/python/scheduler/test_basic_scheduler.py b/test/python/scheduler/test_basic_scheduler.py index ea61cbec49..b97af5ea1d 100644 --- a/test/python/scheduler/test_basic_scheduler.py +++ b/test/python/scheduler/test_basic_scheduler.py @@ -27,6 +27,7 @@ class TestBasicSchedule(QiskitTestCase): """Scheduling tests.""" def setUp(self): + super().setUp() self.backend = FakeOpenPulse2Q() self.inst_map = self.backend.defaults().instruction_schedule_map diff --git a/test/python/test_qasm_parser.py b/test/python/test_qasm_parser.py index cae0921635..c269ce296b 100644 --- a/test/python/test_qasm_parser.py +++ b/test/python/test_qasm_parser.py @@ -34,6 +34,7 @@ class TestParser(QiskitTestCase): """QasmParser""" def setUp(self): + super().setUp() self.qasm_file_path = self._get_resource_path('example.qasm', Path.QASMS) self.qasm_file_path_fail = self._get_resource_path( 'example_fail.qasm', Path.QASMS) diff --git a/test/python/test_schemas.py b/test/python/test_schemas.py index 7763d81894..70a31ca9e3 100644 --- a/test/python/test_schemas.py +++ b/test/python/test_schemas.py @@ -56,6 +56,7 @@ class TestSchemaExamples(QiskitTestCase): } def setUp(self): + super().setUp() self.examples_base_path = self._get_resource_path('examples', Path.SCHEMAS) diff --git a/test/python/tools/jupyter/test_notebooks.py b/test/python/tools/jupyter/test_notebooks.py index bc47844fb6..b373120415 100644 --- a/test/python/tools/jupyter/test_notebooks.py +++ b/test/python/tools/jupyter/test_notebooks.py @@ -33,6 +33,7 @@ JUPYTER_KERNEL = 'python3' class TestJupyter(QiskitTestCase): """Notebooks test case.""" def setUp(self): + super().setUp() self.execution_path = os.path.join(Path.SDK.value, '..') def _execute_notebook(self, filename): diff --git a/test/python/transpiler/test_commutation_analysis.py b/test/python/transpiler/test_commutation_analysis.py index e3506f3895..c2ac839fe8 100644 --- a/test/python/transpiler/test_commutation_analysis.py +++ b/test/python/transpiler/test_commutation_analysis.py @@ -26,6 +26,7 @@ class TestCommutationAnalysis(QiskitTestCase): """Test the Commutation pass.""" def setUp(self): + super().setUp() self.pass_ = CommutationAnalysis() self.pset = self.pass_.property_set = PropertySet() diff --git a/test/python/transpiler/test_commutative_cancellation.py b/test/python/transpiler/test_commutative_cancellation.py index 6844244d5b..c20155dbd6 100644 --- a/test/python/transpiler/test_commutative_cancellation.py +++ b/test/python/transpiler/test_commutative_cancellation.py @@ -26,7 +26,7 @@ class TestCommutativeCancellation(QiskitTestCase): """Test the CommutativeCancellation pass.""" def setUp(self): - + super().setUp() self.com_pass_ = CommutationAnalysis() self.pass_ = CommutativeCancellation() self.pset = self.pass_.property_set = PropertySet() diff --git a/test/python/transpiler/test_dense_layout.py b/test/python/transpiler/test_dense_layout.py index e32b15c414..574c6361dd 100644 --- a/test/python/transpiler/test_dense_layout.py +++ b/test/python/transpiler/test_dense_layout.py @@ -26,6 +26,7 @@ class TestDenseLayout(QiskitTestCase): """Tests the DenseLayout pass""" def setUp(self): + super().setUp() self.cmap20 = FakeTokyo().configuration().coupling_map def test_5q_circuit_20q_coupling(self): diff --git a/test/python/transpiler/test_enlarge_with_ancilla_pass.py b/test/python/transpiler/test_enlarge_with_ancilla_pass.py index 93db157ef7..676d460bea 100644 --- a/test/python/transpiler/test_enlarge_with_ancilla_pass.py +++ b/test/python/transpiler/test_enlarge_with_ancilla_pass.py @@ -25,6 +25,7 @@ class TestEnlargeWithAncilla(QiskitTestCase): """Tests the EnlargeWithAncilla pass.""" def setUp(self): + super().setUp() self.qr3 = QuantumRegister(3, 'qr') circuit = QuantumCircuit(self.qr3) circuit.h(self.qr3) diff --git a/test/python/transpiler/test_faulty_backend.py b/test/python/transpiler/test_faulty_backend.py index 2a8e817a80..b3072e565a 100644 --- a/test/python/transpiler/test_faulty_backend.py +++ b/test/python/transpiler/test_faulty_backend.py @@ -253,6 +253,7 @@ class TestFaultyQ1Unpickable(TestFaultyBackendCase): def setUp(self): """Creates a FakeBackend that is unpickable""" + super().setUp() backend = FakeOurenseFaultyQ1() backend.unpickable_prop = (lambda x: x) self.unpickable_backend = backend diff --git a/test/python/transpiler/test_fixed_point_pass.py b/test/python/transpiler/test_fixed_point_pass.py index 5674c712e5..a05fa605f3 100644 --- a/test/python/transpiler/test_fixed_point_pass.py +++ b/test/python/transpiler/test_fixed_point_pass.py @@ -21,6 +21,7 @@ class TestFixedPointPass(QiskitTestCase): """ Tests for FixedPoint pass. """ def setUp(self): + super().setUp() self.pass_ = FixedPoint('property') self.pset = self.pass_.property_set self.dag = None # The pass do not read the DAG. diff --git a/test/python/transpiler/test_full_ancilla_allocation.py b/test/python/transpiler/test_full_ancilla_allocation.py index ebbcdd735d..d5b6ef8ab9 100644 --- a/test/python/transpiler/test_full_ancilla_allocation.py +++ b/test/python/transpiler/test_full_ancilla_allocation.py @@ -25,6 +25,7 @@ class TestFullAncillaAllocation(QiskitTestCase): """Tests the ExtendLayout pass""" def setUp(self): + super().setUp() self.cmap5 = CouplingMap([[1, 0], [2, 0], [2, 1], [3, 2], [3, 4], [4, 2]]) def test_3q_circuit_5q_coupling(self): diff --git a/test/python/transpiler/test_layout.py b/test/python/transpiler/test_layout.py index 73635cf7f3..2d5485c5ab 100644 --- a/test/python/transpiler/test_layout.py +++ b/test/python/transpiler/test_layout.py @@ -26,6 +26,7 @@ class LayoutTest(QiskitTestCase): """Test the methods in the layout object.""" def setUp(self): + super().setUp() self.qr = QuantumRegister(3, 'qr') def test_default_layout(self): diff --git a/test/python/transpiler/test_naming_transpiled_circuits.py b/test/python/transpiler/test_naming_transpiled_circuits.py index 2d67ee8278..171d949b56 100644 --- a/test/python/transpiler/test_naming_transpiled_circuits.py +++ b/test/python/transpiler/test_naming_transpiled_circuits.py @@ -24,6 +24,7 @@ class TestNamingTranspiledCircuits(QiskitTestCase): """Testing the naming fuctionality for transpiled circuits.""" def setUp(self): + super().setUp() self.basis_gates = ['u1', 'u2', 'u3', 'cx'] self.backend = BasicAer.get_backend('qasm_simulator') diff --git a/test/python/transpiler/test_pass_scheduler.py b/test/python/transpiler/test_pass_scheduler.py index 2fe33dc023..dfa3dd4a84 100644 --- a/test/python/transpiler/test_pass_scheduler.py +++ b/test/python/transpiler/test_pass_scheduler.py @@ -91,6 +91,7 @@ class TestUseCases(SchedulerTestCase): in the right order.""" def setUp(self): + super().setUp() self.circuit = QuantumCircuit(QuantumRegister(1)) self.passmanager = PassManager() @@ -422,6 +423,7 @@ class TestControlFlowPlugin(SchedulerTestCase): """Testing the control flow plugin system.""" def setUp(self): + super().setUp() self.passmanager = PassManager() self.circuit = QuantumCircuit(QuantumRegister(1)) @@ -539,6 +541,7 @@ class TestLogPasses(QiskitTestCase): """Testing the log_passes option.""" def setUp(self): + super().setUp() logger = getLogger() logger.setLevel('DEBUG') self.output = io.StringIO() @@ -612,6 +615,7 @@ class TestPassManagerReuse(SchedulerTestCase): """The PassManager instance should be reusable.""" def setUp(self): + super().setUp() self.passmanager = PassManager() self.circuit = QuantumCircuit(QuantumRegister(1)) @@ -699,6 +703,7 @@ class TestPassManagerChanges(SchedulerTestCase): """Test PassManager manipulation with changes""" def setUp(self): + super().setUp() self.passmanager = PassManager() self.circuit = QuantumCircuit(QuantumRegister(1)) @@ -791,6 +796,7 @@ class TestPassManagerSlicing(SchedulerTestCase): """test PassManager slicing.""" def setUp(self): + super().setUp() self.passmanager = PassManager() self.circuit = QuantumCircuit(QuantumRegister(1)) @@ -919,6 +925,7 @@ class TestPassManagerConcatenation(SchedulerTestCase): """test PassManager concatenation by + operator.""" def setUp(self): + super().setUp() self.passmanager1 = PassManager() self.passmanager2 = PassManager() self.circuit = QuantumCircuit(QuantumRegister(1)) diff --git a/test/python/transpiler/test_preset_passmanagers.py b/test/python/transpiler/test_preset_passmanagers.py index d78ec2d913..8eb28c2974 100644 --- a/test/python/transpiler/test_preset_passmanagers.py +++ b/test/python/transpiler/test_preset_passmanagers.py @@ -107,6 +107,7 @@ class TestPassesInspection(QiskitTestCase): def setUp(self): """Sets self.callback to set self.passes with the passes that have been executed""" + super().setUp() self.passes = [] def callback(**kwargs): diff --git a/test/python/transpiler/test_property_set.py b/test/python/transpiler/test_property_set.py index 4f2fcd1226..b567a1647a 100644 --- a/test/python/transpiler/test_property_set.py +++ b/test/python/transpiler/test_property_set.py @@ -21,6 +21,7 @@ class TestPropertySet(QiskitTestCase): """ Tests for PropertySet methods. """ def setUp(self): + super().setUp() self.pset = PropertySet() def test_get_non_existent(self): diff --git a/test/python/transpiler/test_sabre_layout.py b/test/python/transpiler/test_sabre_layout.py index 53b00a92d2..8d5daf8895 100644 --- a/test/python/transpiler/test_sabre_layout.py +++ b/test/python/transpiler/test_sabre_layout.py @@ -26,6 +26,7 @@ class TestSabreLayout(QiskitTestCase): """Tests the SabreLayout pass""" def setUp(self): + super().setUp() self.cmap20 = FakeAlmaden().configuration().coupling_map def test_5q_circuit_20q_coupling(self): diff --git a/test/python/transpiler/test_token_swapper.py b/test/python/transpiler/test_token_swapper.py index b923cf425a..b8523de5b1 100644 --- a/test/python/transpiler/test_token_swapper.py +++ b/test/python/transpiler/test_token_swapper.py @@ -41,6 +41,7 @@ class TestGeneral(QiskitTestCase): def setUp(self) -> None: """Set up test cases.""" + super().setUp() random.seed(0) def test_simple(self) -> None: diff --git a/test/python/transpiler/test_trivial_layout.py b/test/python/transpiler/test_trivial_layout.py index dbd71c0628..83201f6f29 100644 --- a/test/python/transpiler/test_trivial_layout.py +++ b/test/python/transpiler/test_trivial_layout.py @@ -27,6 +27,7 @@ class TestTrivialLayout(QiskitTestCase): """Tests the TrivialLayout pass""" def setUp(self): + super().setUp() self.cmap5 = FakeTenerife().configuration().coupling_map self.cmap16 = FakeRueschlikon().configuration().coupling_map diff --git a/test/python/transpiler/test_unroller.py b/test/python/transpiler/test_unroller.py index d0abc111e3..066cf9408d 100644 --- a/test/python/transpiler/test_unroller.py +++ b/test/python/transpiler/test_unroller.py @@ -216,6 +216,7 @@ class TestUnrollAllInstructions(QiskitTestCase): """Test unrolling a circuit containing all standard instructions.""" def setUp(self): + super().setUp() qr = self.qr = QuantumRegister(3, 'qr') cr = self.cr = ClassicalRegister(3, 'cr') self.circuit = QuantumCircuit(qr, cr) diff --git a/test/python/visualization/pulse_v2/test_generators.py b/test/python/visualization/pulse_v2/test_generators.py index c924cf36ff..5d6c376d19 100644 --- a/test/python/visualization/pulse_v2/test_generators.py +++ b/test/python/visualization/pulse_v2/test_generators.py @@ -28,6 +28,7 @@ class TestGenerators(QiskitTestCase): """Tests for generators.""" def setUp(self) -> None: + super().setUp() self.style = stylesheet.QiskitPulseStyle() @staticmethod diff --git a/test/python/visualization/test_circuit_text_drawer.py b/test/python/visualization/test_circuit_text_drawer.py index b99e09defe..72165f81a3 100644 --- a/test/python/visualization/test_circuit_text_drawer.py +++ b/test/python/visualization/test_circuit_text_drawer.py @@ -2960,6 +2960,7 @@ class TestTextInitialValue(QiskitTestCase): """Testing the initial_state parameter""" def setUp(self) -> None: + super().setUp() qr = QuantumRegister(2, 'q') cr = ClassicalRegister(2, 'c') self.circuit = QuantumCircuit(qr, cr) diff --git a/test/python/visualization/test_dag_drawer.py b/test/python/visualization/test_dag_drawer.py index dea0cd2458..1def230988 100644 --- a/test/python/visualization/test_dag_drawer.py +++ b/test/python/visualization/test_dag_drawer.py @@ -25,6 +25,7 @@ class TestDagDrawer(QiskitTestCase): """Qiskit DAG drawer tests.""" def setUp(self): + super().setUp() qr = QuantumRegister(2, 'qr') circuit = QuantumCircuit(qr) circuit.cx(qr[0], qr[1]) diff --git a/test/python/visualization/test_gate_map.py b/test/python/visualization/test_gate_map.py index a2ea7b9fbe..6f2a859795 100644 --- a/test/python/visualization/test_gate_map.py +++ b/test/python/visualization/test_gate_map.py @@ -70,6 +70,7 @@ class TestGraphDist(QiskitTestCase): def setUp(self): """ setup plots for _GraphDist """ + super().setUp() ax1 = plt.subplots(figsize=(5, 5))[1] ax2 = plt.subplots(figsize=(9, 3))[1] ax1.axis("off") diff --git a/test/python/visualization/test_pass_manager_drawer.py b/test/python/visualization/test_pass_manager_drawer.py index c957e488ba..d478664592 100644 --- a/test/python/visualization/test_pass_manager_drawer.py +++ b/test/python/visualization/test_pass_manager_drawer.py @@ -50,6 +50,7 @@ class TestPassManagerDrawer(QiskitVisualizationTestCase): """Qiskit pass manager drawer tests.""" def setUp(self): + super().setUp() coupling = [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 6]] coupling_map = CouplingMap(couplinglist=coupling) basis_gates = ['u1', 'u3', 'u2', 'cx'] diff --git a/test/python/visualization/test_visualization.py b/test/python/visualization/test_visualization.py index 9ab4822c06..605982c5e6 100644 --- a/test/python/visualization/test_visualization.py +++ b/test/python/visualization/test_visualization.py @@ -158,6 +158,7 @@ class TestVisualizationUtils(QiskitTestCase): the need to be check if the interface or their result changes.""" def setUp(self): + super().setUp() self.qr1 = QuantumRegister(2, 'qr1') self.qr2 = QuantumRegister(2, 'qr2') self.cr1 = ClassicalRegister(2, 'cr1') diff --git a/tox.ini b/tox.ini index 2319749448..9b4e9a7632 100644 --- a/tox.ini +++ b/tox.ini @@ -12,6 +12,7 @@ setenv = LC_ALL=en_US.utf-8 ARGS="-V" QISKIT_SUPRESS_PACKAGING_WARNINGS=Y + QISKIT_TEST_CAPTURE_STREAMS=1 deps = -r{toxinidir}/requirements.txt -r{toxinidir}/requirements-dev.txt commands =