Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add HAS_PYGMENTS lazy tester #9944

Merged
merged 4 commits into from
Jul 10, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 11 additions & 17 deletions qiskit/circuit/quantumcircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,15 @@
DefaultDict,
)
import numpy as np
from qiskit.exceptions import QiskitError, MissingOptionalLibraryError
from qiskit.exceptions import QiskitError
from qiskit.utils.multiprocessing import is_main_process
from qiskit.circuit.instruction import Instruction
from qiskit.circuit.gate import Gate
from qiskit.circuit.parameter import Parameter
from qiskit.qasm.qasm import Qasm
from qiskit.qasm.exceptions import QasmError
from qiskit.circuit.exceptions import CircuitError
from qiskit.utils import optionals as _optionals
from .parameterexpression import ParameterExpression, ParameterValueType
from .quantumregister import QuantumRegister, Qubit, AncillaRegister, AncillaQubit
from .classicalregister import ClassicalRegister, Clbit
Expand All @@ -60,16 +61,6 @@
from .measure import Measure
from .reset import Reset

try:
import pygments
from pygments.formatters import Terminal256Formatter # pylint: disable=no-name-in-module
from qiskit.qasm.pygments import OpenQASMLexer # pylint: disable=ungrouped-imports
from qiskit.qasm.pygments import QasmTerminalStyle # pylint: disable=ungrouped-imports

HAS_PYGMENTS = True
except Exception: # pylint: disable=broad-except
HAS_PYGMENTS = False

if typing.TYPE_CHECKING:
import qiskit # pylint: disable=cyclic-import
from qiskit.transpiler.layout import TranspileLayout # pylint: disable=cyclic-import
Expand Down Expand Up @@ -1759,12 +1750,15 @@ def qasm(
file.close()

if formatted:
if not HAS_PYGMENTS:
raise MissingOptionalLibraryError(
libname="pygments>2.4",
name="formatted QASM output",
pip_install="pip install pygments",
)
_optionals.HAS_PYGMENTS.require_now("formatted OpenQASM 2 output")

import pygments
from pygments.formatters import ( # pylint: disable=no-name-in-module
Terminal256Formatter,
)
from qiskit.qasm.pygments import OpenQASMLexer
from qiskit.qasm.pygments import QasmTerminalStyle

code = pygments.highlight(
string_temp, OpenQASMLexer(), Terminal256Formatter(style=QasmTerminalStyle)
)
Expand Down
25 changes: 11 additions & 14 deletions qiskit/qasm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,26 +33,23 @@
.. autosummary::
:toctree: ../stubs/

OpenQASMLexer
QasmHTMLStyle
QasmTerminalStyle

~qiskit.qasm.pygments.OpenQASMLexer
~qiskit.qasm.pygments.QasmHTMLStyle
~qiskit.qasm.pygments.QasmTerminalStyle
"""

from numpy import pi

from qiskit.utils.optionals import HAS_PYGMENTS

from .qasm import Qasm
from .exceptions import QasmError

try:
import pygments

HAS_PYGMENTS = True
except ImportError:
HAS_PYGMENTS = False
def __getattr__(name):
if name in ("OpenQASMLexer", "QasmHTMLStyle", "QasmTerminalStyle"):
import qiskit.qasm.pygments

return getattr(qiskit.qasm.pygments, name)

if HAS_PYGMENTS:
try:
from .pygments import OpenQASMLexer, QasmHTMLStyle, QasmTerminalStyle
except Exception: # pylint: disable=broad-except
HAS_PYGMENTS = False
raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
20 changes: 8 additions & 12 deletions qiskit/qasm/pygments/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,11 @@
QasmTerminalStyle
QasmHTMLStyle
"""
try:
import pygments

HAS_PYGMENTS = True
except ImportError:
HAS_PYGMENTS = False

if HAS_PYGMENTS:
try:
from .lexer import OpenQASMLexer, QasmTerminalStyle, QasmHTMLStyle
except Exception: # pylint: disable=broad-except
HAS_PYGMENTS = False

# pylint: disable=wrong-import-position

from qiskit.utils.optionals import HAS_PYGMENTS

HAS_PYGMENTS.require_now("built-in OpenQASM 2 syntax highlighting")

from .lexer import OpenQASMLexer, QasmTerminalStyle, QasmHTMLStyle
13 changes: 3 additions & 10 deletions qiskit/qasm/pygments/lexer.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,9 @@
"""Pygments tools for Qasm.
"""

from qiskit.exceptions import MissingOptionalLibraryError

try:
from pygments.lexer import RegexLexer
from pygments.token import Comment, String, Keyword, Name, Number, Text
from pygments.style import Style
except ImportError as ex:
raise MissingOptionalLibraryError(
"pygments>2.4", "qiskit.qasm.pygments", "pip install pygments"
) from ex
from pygments.lexer import RegexLexer
from pygments.token import Comment, String, Keyword, Name, Number, Text
from pygments.style import Style


class QasmTerminalStyle(Style):
Expand Down
24 changes: 5 additions & 19 deletions qiskit/tools/jupyter/library.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,8 @@
import ipywidgets as wid
from IPython.display import display
from qiskit import QuantumCircuit
from qiskit.exceptions import MissingOptionalLibraryError
from qiskit.utils import optionals as _optionals

try:
import pygments
from pygments.formatters import HtmlFormatter
from qiskit.qasm.pygments import QasmHTMLStyle, OpenQASMLexer

HAS_PYGMENTS = True
except Exception: # pylint: disable=broad-except
HAS_PYGMENTS = False


@_optionals.HAS_MATPLOTLIB.require_in_call
def _generate_circuit_library_visualization(circuit: QuantumCircuit):
Expand Down Expand Up @@ -130,6 +120,7 @@ def properties_widget(circuit: QuantumCircuit) -> wid.VBox:
return properties


@_optionals.HAS_PYGMENTS.require_in_call
def qasm_widget(circuit: QuantumCircuit) -> wid.VBox:
"""Generate a QASM widget with header for a quantum circuit.

Expand All @@ -138,16 +129,11 @@ def qasm_widget(circuit: QuantumCircuit) -> wid.VBox:

Returns:
Output widget.

Raises:
MissingOptionalLibraryError: If pygments is not installed
"""
if not HAS_PYGMENTS:
raise MissingOptionalLibraryError(
libname="pygments>2.4",
name="qasm_widget",
pip_install="pip install pygments",
)
import pygments
from pygments.formatters import HtmlFormatter
from qiskit.qasm.pygments import QasmHTMLStyle, OpenQASMLexer

qasm_code = circuit.qasm()
code = pygments.highlight(qasm_code, OpenQASMLexer(), HtmlFormatter())

Expand Down
6 changes: 6 additions & 0 deletions qiskit/utils/optionals.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,11 @@
- For some graph visualisations, Qiskit uses `pydot <https://github.com/pydot/pydot>`__ as an
interface to GraphViz (see :data:`HAS_GRAPHVIZ`).
* - .. py:data:: HAS_PYGMENTS
- Pygments is a code highlighter and formatter used by many environments that involve rich
display of code blocks, including Sphinx and Jupyter. Qiskit uses this when producing rich
output for these environments.
* - .. py:data:: HAS_PYLATEX
- Various LaTeX-based visualizations, especially the circuit drawers, need access to the
`pylatexenc <https://github.com/phfaist/pylatexenc>`__ project to work correctly.
Expand Down Expand Up @@ -261,6 +266,7 @@
HAS_NLOPT = _LazyImportTester("nlopt", name="NLopt Optimizer", install="pip install nlopt")
HAS_PIL = _LazyImportTester("PIL.Image", name="pillow", install="pip install pillow")
HAS_PYDOT = _LazyImportTester("pydot", install="pip install pydot")
HAS_PYGMENTS = _LazyImportTester("pygments", install="pip install pygments")
HAS_PYLATEX = _LazyImportTester(
{
"pylatexenc.latex2text": ("LatexNodes2Text",),
Expand Down
5 changes: 5 additions & 0 deletions releasenotes/notes/has-pygments-tester-3fb9f9c34907d45d.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
features:
- |
A new lazy import tester, :data:`.HAS_PYGMENTS`, is available for testing for the presence of
`the Pygments syntax highlighting library <https://pygments.org/>`__.
1 change: 1 addition & 0 deletions tools/find_optional_imports.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ def _main():
"networkx",
"sympy",
"pydot",
"pygments",
"ipywidgets",
"scipy.stats",
"matplotlib",
Expand Down