From ad17828efeffb3a94db2f5a1422d277ecb30af8a Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Thu, 8 Feb 2024 11:42:32 +0100 Subject: [PATCH 1/5] config path fixing --- qiskit/visualization/circuit/qcstyle.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/qiskit/visualization/circuit/qcstyle.py b/qiskit/visualization/circuit/qcstyle.py index 5faed5b8c4eb..dad08c83d6b8 100644 --- a/qiskit/visualization/circuit/qcstyle.py +++ b/qiskit/visualization/circuit/qcstyle.py @@ -224,8 +224,7 @@ def load_style(style: dict | str | None) -> tuple[StyleDict, float]: config_path = config.get("circuit_mpl_style_path", "") if config_path: for path in config_path: - path_ = Path(config_path) / style_name - style_paths.append(path_) + style_paths.append(Path(path) / style_name) # check current directory cwd_path = Path("") / style_name From 42501a26673598c95a0552266ba01906c38262ec Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Thu, 8 Feb 2024 11:46:42 +0100 Subject: [PATCH 2/5] reno --- releasenotes/notes/fix_11536-c87d192a133b3dc3.yaml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 releasenotes/notes/fix_11536-c87d192a133b3dc3.yaml diff --git a/releasenotes/notes/fix_11536-c87d192a133b3dc3.yaml b/releasenotes/notes/fix_11536-c87d192a133b3dc3.yaml new file mode 100644 index 000000000000..a3600fb6a7d5 --- /dev/null +++ b/releasenotes/notes/fix_11536-c87d192a133b3dc3.yaml @@ -0,0 +1,4 @@ +--- +fixes: + - | + A bug when loading MPL style from the configuration was fixed. From dddca99d6cd588c60bd3ed3f834e5be9e15d124f Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Tue, 13 Feb 2024 12:53:42 +0100 Subject: [PATCH 3/5] add test --- test/python/visualization/test_circuit_drawer.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/python/visualization/test_circuit_drawer.py b/test/python/visualization/test_circuit_drawer.py index 36d80be4fb39..010b52071239 100644 --- a/test/python/visualization/test_circuit_drawer.py +++ b/test/python/visualization/test_circuit_drawer.py @@ -49,6 +49,21 @@ def test_default_output(self): out = visualization.circuit_drawer(circuit) self.assertIsInstance(out, text.TextDrawing) + @unittest.skipUnless(optionals.HAS_MATPLOTLIB, "Skipped because matplotlib is not available") + def test_mpl_config_with_path(self): + with patch( + "qiskit.user_config.get_config", + return_value={ + "circuit_drawer": "mpl", + "circuit_mpl_style": "quantum-light", + "circuit_mpl_style_path": ["~/.qiskit"], + }, + ): + circuit = QuantumCircuit(1) + circuit.h(0) + out = visualization.circuit_drawer(circuit) + self.assertIsInstance(out, figure.Figure) + @unittest.skipUnless(optionals.HAS_MATPLOTLIB, "Skipped because matplotlib is not available") def test_user_config_default_output(self): with patch("qiskit.user_config.get_config", return_value={"circuit_drawer": "mpl"}): From ae5f93c4c7ec7d0967a0122584221cd67fc3a31e Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Wed, 14 Feb 2024 20:12:57 +0100 Subject: [PATCH 4/5] temp file creation --- test/python/visualization/test_circuit_drawer.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/test/python/visualization/test_circuit_drawer.py b/test/python/visualization/test_circuit_drawer.py index 010b52071239..c364a4cb9a64 100644 --- a/test/python/visualization/test_circuit_drawer.py +++ b/test/python/visualization/test_circuit_drawer.py @@ -14,6 +14,8 @@ import unittest import os +import tempfile +import json from unittest.mock import patch from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister @@ -21,6 +23,7 @@ from qiskit import visualization from qiskit.visualization.circuit import text from qiskit.visualization.exceptions import VisualizationError +from qiskit.visualization.circuit.qcstyle import load_style from test import QiskitTestCase # pylint: disable=wrong-import-order if optionals.HAS_MATPLOTLIB: @@ -51,12 +54,18 @@ def test_default_output(self): @unittest.skipUnless(optionals.HAS_MATPLOTLIB, "Skipped because matplotlib is not available") def test_mpl_config_with_path(self): + with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False) as tmp_file: + tmp_style = os.path.basename(tmp_file.name).split(".")[0] + default_style = load_style("default")[0] + default_style["name"] = tmp_style + json.dump(load_style("default")[0], tmp_file) + with patch( "qiskit.user_config.get_config", return_value={ "circuit_drawer": "mpl", - "circuit_mpl_style": "quantum-light", - "circuit_mpl_style_path": ["~/.qiskit"], + "circuit_mpl_style": tmp_style, + "circuit_mpl_style_path": [os.path.dirname(tmp_file.name)], }, ): circuit = QuantumCircuit(1) From 05eb7692dd729db2687ad6c7c070fc814096afa8 Mon Sep 17 00:00:00 2001 From: Jake Lishman Date: Thu, 15 Feb 2024 13:12:46 +0000 Subject: [PATCH 5/5] Avoid using more internal details in style test --- .../visualization/circuit/styles/__init__.py | 13 +++++ .../visualization/test_circuit_drawer.py | 56 +++++++++++-------- 2 files changed, 47 insertions(+), 22 deletions(-) create mode 100644 qiskit/visualization/circuit/styles/__init__.py diff --git a/qiskit/visualization/circuit/styles/__init__.py b/qiskit/visualization/circuit/styles/__init__.py new file mode 100644 index 000000000000..edbac45d60af --- /dev/null +++ b/qiskit/visualization/circuit/styles/__init__.py @@ -0,0 +1,13 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2014. +# +# 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. + +"""Empty init for data directory.""" diff --git a/test/python/visualization/test_circuit_drawer.py b/test/python/visualization/test_circuit_drawer.py index c364a4cb9a64..0c16a57133d5 100644 --- a/test/python/visualization/test_circuit_drawer.py +++ b/test/python/visualization/test_circuit_drawer.py @@ -12,18 +12,19 @@ # pylint: disable=missing-docstring -import unittest import os +import pathlib +import shutil import tempfile -import json - +import unittest +import warnings from unittest.mock import patch + from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister from qiskit.utils import optionals from qiskit import visualization -from qiskit.visualization.circuit import text +from qiskit.visualization.circuit import text, styles from qiskit.visualization.exceptions import VisualizationError -from qiskit.visualization.circuit.qcstyle import load_style from test import QiskitTestCase # pylint: disable=wrong-import-order if optionals.HAS_MATPLOTLIB: @@ -54,24 +55,35 @@ def test_default_output(self): @unittest.skipUnless(optionals.HAS_MATPLOTLIB, "Skipped because matplotlib is not available") def test_mpl_config_with_path(self): - with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False) as tmp_file: - tmp_style = os.path.basename(tmp_file.name).split(".")[0] - default_style = load_style("default")[0] - default_style["name"] = tmp_style - json.dump(load_style("default")[0], tmp_file) - - with patch( - "qiskit.user_config.get_config", - return_value={ + # It's too easy to get too nested in a test with many context managers. + tempdir = tempfile.TemporaryDirectory() # pylint: disable=consider-using-with + self.addCleanup(tempdir.cleanup) + + clifford_style = pathlib.Path(styles.__file__).parent / "clifford.json" + shutil.copyfile(clifford_style, pathlib.Path(tempdir.name) / "my_clifford.json") + + circuit = QuantumCircuit(1) + circuit.h(0) + + def config(style_name): + return { "circuit_drawer": "mpl", - "circuit_mpl_style": tmp_style, - "circuit_mpl_style_path": [os.path.dirname(tmp_file.name)], - }, - ): - circuit = QuantumCircuit(1) - circuit.h(0) - out = visualization.circuit_drawer(circuit) - self.assertIsInstance(out, figure.Figure) + "circuit_mpl_style": style_name, + "circuit_mpl_style_path": [tempdir.name], + } + + with warnings.catch_warnings(): + warnings.filterwarnings("error", message="Style JSON file.*not found") + + # Test that a non-standard style can be loaded by name. + with patch("qiskit.user_config.get_config", return_value=config("my_clifford")): + self.assertIsInstance(visualization.circuit_drawer(circuit), figure.Figure) + + # Test that a non-existent style issues a warning, but still draws something. + with patch("qiskit.user_config.get_config", return_value=config("NONEXISTENT")): + with self.assertWarnsRegex(UserWarning, "Style JSON file.*not found"): + fig = visualization.circuit_drawer(circuit) + self.assertIsInstance(fig, figure.Figure) @unittest.skipUnless(optionals.HAS_MATPLOTLIB, "Skipped because matplotlib is not available") def test_user_config_default_output(self):