diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 13c037a..f620d1f 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -19,9 +19,12 @@ jobs: - name: Update pip run: pip install --upgrade pip - name: Install black and pylint - run: pip install black pylint + run: pip install black pylint ruff - name: Check files are formatted with black run: | black --check . + - name: Run ruff + run: | + ruff check . - name: Run pylint run: pylint */ diff --git a/pytket/extensions/projectq/__init__.py b/pytket/extensions/projectq/__init__.py index 15a9c55..dd6e8ab 100644 --- a/pytket/extensions/projectq/__init__.py +++ b/pytket/extensions/projectq/__init__.py @@ -14,6 +14,6 @@ """Module for conversion between ProjectQ and tket primitives.""" # _metadata.py is copied to the folder after installation. -from ._metadata import __extension_version__, __extension_name__ +from ._metadata import __extension_name__, __extension_version__ from .backends import ProjectQBackend from .projectq_convert import tk_to_projectq, tketBackendEngine, tketOptimiser diff --git a/pytket/extensions/projectq/backends/projectq_backend.py b/pytket/extensions/projectq/backends/projectq_backend.py index f5b8308..148ff06 100644 --- a/pytket/extensions/projectq/backends/projectq_backend.py +++ b/pytket/extensions/projectq/backends/projectq_backend.py @@ -15,54 +15,52 @@ """Methods to allow tket circuits to be ran on ProjectQ simulator """ +from collections.abc import Sequence +from logging import warning from typing import ( Any, - Dict, - List, Optional, - Sequence, Union, ) from uuid import uuid4 -from logging import warning import numpy as np + import projectq # type: ignore from projectq import MainEngine from projectq.backends import Simulator # type: ignore from projectq.cengines import ForwarderEngine # type: ignore -from pytket.circuit import Circuit, OpType -from pytket.circuit import Qubit from pytket.backends import ( Backend, CircuitNotRunError, - ResultHandle, CircuitStatus, + ResultHandle, StatusEnum, ) from pytket.backends.backendinfo import BackendInfo -from pytket.backends.resulthandle import _ResultIdTuple from pytket.backends.backendresult import BackendResult +from pytket.backends.resulthandle import _ResultIdTuple +from pytket.circuit import Circuit, OpType, Qubit +from pytket.extensions.projectq._metadata import __extension_version__ +from pytket.extensions.projectq.projectq_convert import _REBASE, tk_to_projectq from pytket.passes import ( BasePass, - SequencePass, - SynthesiseTket, - FullPeepholeOptimise, DecomposeBoxes, FlattenRegisters, + FullPeepholeOptimise, + SequencePass, + SynthesiseTket, ) from pytket.pauli import QubitPauliString from pytket.predicates import ( - NoSymbolsPredicate, - NoMidMeasurePredicate, + DefaultRegisterPredicate, GateSetPredicate, NoClassicalControlPredicate, NoFastFeedforwardPredicate, - DefaultRegisterPredicate, + NoMidMeasurePredicate, + NoSymbolsPredicate, Predicate, ) -from pytket.extensions.projectq.projectq_convert import tk_to_projectq, _REBASE -from pytket.extensions.projectq._metadata import __extension_version__ from pytket.utils.operators import QubitPauliOperator from pytket.utils.results import KwargTypes @@ -106,7 +104,7 @@ def _result_id_type(self) -> _ResultIdTuple: return (str,) @property - def characterisation(self) -> Dict[str, Any]: + def characterisation(self) -> dict[str, Any]: return dict() @property @@ -121,7 +119,7 @@ def backend_info(self) -> BackendInfo: return backend_info @property - def required_predicates(self) -> List[Predicate]: + def required_predicates(self) -> list[Predicate]: return [ NoClassicalControlPredicate(), NoFastFeedforwardPredicate(), @@ -165,7 +163,7 @@ def process_circuits( n_shots: Union[None, int, Sequence[Optional[int]]] = None, valid_check: bool = True, **kwargs: KwargTypes, - ) -> List[ResultHandle]: + ) -> list[ResultHandle]: """ See :py:meth:`pytket.backends.Backend.process_circuits`. Supported kwargs: `seed`. diff --git a/pytket/extensions/projectq/projectq_convert.py b/pytket/extensions/projectq/projectq_convert.py index 4f3e08f..1688581 100644 --- a/pytket/extensions/projectq/projectq_convert.py +++ b/pytket/extensions/projectq/projectq_convert.py @@ -15,20 +15,22 @@ """Methods to allow conversion between ProjectQ and tket data types """ -from typing import Any, Iterable +from collections.abc import Iterable +from typing import Any import numpy as np +from projectq import MainEngine from projectq import ops as pqo # type: ignore from projectq.cengines import BasicEngine, LastEngineException # type: ignore -from projectq import MainEngine from projectq.meta import get_control_count # type: ignore -from projectq.ops._command import Command as ProjectQCommand, apply_command # type: ignore +from projectq.ops._command import Command as ProjectQCommand # type: ignore +from projectq.ops._command import apply_command from projectq.types._qubit import Qureg # type: ignore -from pytket.circuit import OpType, Op, Circuit, Command, Bit -from pytket.transform import Transform -from pytket.passes import RebaseCustom +from pytket.circuit import Bit, Circuit, Command, Op, OpType from pytket.circuit_library import CX, TK1_to_RzRx +from pytket.passes import RebaseCustom +from pytket.transform import Transform _pq_to_tk_singleqs = { pqo.XGate: OpType.X, @@ -81,11 +83,9 @@ TK1_to_RzRx, ) _tk_to_pq_singleqs: dict = dict( - ((item[1], item[0]) for item in _pq_to_tk_singleqs.items()) -) -_tk_to_pq_multiqs: dict = dict( - ((item[1], item[0]) for item in _pq_to_tk_multiqs.items()) + (item[1], item[0]) for item in _pq_to_tk_singleqs.items() ) +_tk_to_pq_multiqs: dict = dict((item[1], item[0]) for item in _pq_to_tk_multiqs.items()) def _get_pq_command_from_tk_command( @@ -108,7 +108,7 @@ def _get_pq_command_from_tk_command( raise Exception(f"A Rotation Gate has {len(params)} parameters") try: gate = gatetype(params[0].evalf() * np.pi) # type: ignore - except: + except: # noqa: E722 gate = gatetype(params[0] * np.pi) elif issubclass(gatetype, pqo.BasicGate): gate = gatetype() @@ -169,7 +169,7 @@ def _handle_gate( and len(command.qubits) == 1 ): engine._translate_single_qubit_op(command) - elif type(command.gate) == pqo.DaggeredGate: + elif type(command.gate) is pqo.DaggeredGate: engine._translate_daggered_op(command) else: raise Exception( @@ -184,9 +184,9 @@ def _handle_gate( def _add_daggered_op_to_circuit(cmd: ProjectQCommand, circ: Circuit) -> bool: undaggered_gate = cmd.gate.get_inverse() - if type(undaggered_gate) == pqo.TGate: + if type(undaggered_gate) is pqo.TGate: op = Op.create(OpType.Tdg) - elif type(undaggered_gate) == pqo.SGate: + elif type(undaggered_gate) is pqo.SGate: op = Op.create(OpType.Sdg) else: raise Exception("cannot recognise daggered op of type " + str(cmd.gate)) @@ -218,7 +218,7 @@ def _add_single_qubit_op_to_circuit(cmd: ProjectQCommand, circ: Circuit) -> bool if qubit_no >= circ.n_qubits: circ.add_blank_wires(1 + qubit_no - circ.n_qubits) new_qubit = True - if type(cmd.gate) == pqo.MeasureGate: + if type(cmd.gate) is pqo.MeasureGate: bit = Bit("c", qubit_no) if bit not in circ.bits: circ.add_bit(bit) @@ -244,7 +244,7 @@ def _add_multi_qubit_op_to_circuit(cmd: ProjectQCommand, circ: Circuit) -> list: if qubit_no >= circ.n_qubits: circ.add_blank_wires(1 + qubit_no - circ.n_qubits) new_qubits.append(q) - if type(cmd.gate) == pqo.CRz: + if type(cmd.gate) is pqo.CRz: op = Op.create(_pq_to_tk_multiqs[type(cmd.gate)], cmd.gate.angle / np.pi) else: op = Op.create(_pq_to_tk_multiqs[type(cmd.gate)]) diff --git a/ruff.toml b/ruff.toml new file mode 100644 index 0000000..f2146f6 --- /dev/null +++ b/ruff.toml @@ -0,0 +1,44 @@ +target-version = "py39" + +line-length = 88 + +extend-exclude = ["examples"] + +select = [ + "E", # pycodestyle Errors + "W", # pycodestyle Warnings + + # "A", # flake8-builtins + # "B", # flake8-Bugbear + # "C4", # flake8-comprehensions + # "COM", # flake8-commas + # "EXE", # flake8-executable + "F", # pyFlakes + # "FA", # flake8-future-annotations + # "FIX", # flake8-fixme + # "FLY", # flynt + "I", # isort + # "INP", # flake8-no-pep420 + # "ISC", # flake8-implicit-str-concat + # "N", # pep8-Naming + # "NPY", # NumPy-specific + # "PERF", # Perflint + # "PGH", # pygrep-hooks + # "PIE", # flake8-pie + # "PL", # pylint + # "PT", # flake8-pytest-style + # "RSE", # flake8-raise + # "RUF", # Ruff-specific + # "S", # flake8-bandit (Security) + "SIM", # flake8-simplify + # "SLF", # flake8-self + "T20", # flake8-print + "TCH", # flake8-type-checking + # "TRY", # tryceratops + "UP", # pyupgrade + # "YTT", # flake8-2020 +] + +[per-file-ignores] +".github/workflows/docs/conf.py" = ["E402"] +"__init__.py" = ["F401"] # module imported but unused (6) diff --git a/setup.py b/setup.py index 9dd5ca1..dabe803 100644 --- a/setup.py +++ b/setup.py @@ -12,9 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -import shutil import os -from setuptools import setup, find_namespace_packages # type: ignore +import shutil +from pathlib import Path + +from setuptools import find_namespace_packages, setup # type: ignore metadata: dict = {} with open("_metadata.py") as fp: @@ -38,7 +40,7 @@ }, description="Extension for pytket, providing translation to and from the ProjectQ " "framework", - long_description=open("README.md").read(), + long_description=(Path(__file__).parent / "README.md").read_text(), long_description_content_type="text/markdown", license="Apache 2", packages=find_namespace_packages(include=["pytket.*"]), diff --git a/tests/projectq_backend_test.py b/tests/projectq_backend_test.py index 777ab47..a5783b5 100644 --- a/tests/projectq_backend_test.py +++ b/tests/projectq_backend_test.py @@ -16,19 +16,20 @@ # https://github.com/ProjectQ-Framework/ProjectQ/blob/develop/examples/variational_quantum_eigensolver.ipynb import math +import platform import warnings from collections import Counter -import platform -from hypothesis import given, strategies import numpy as np import pytest +from hypothesis import given, strategies + from pytket.backends.backend import ResultHandleTypeError from pytket.backends.backend_exceptions import CircuitNotRunError +from pytket.backends.resulthandle import ResultHandle from pytket.backends.status import StatusEnum +from pytket.circuit import BasisOrder, Circuit, OpType, Qubit from pytket.extensions.projectq import ProjectQBackend -from pytket.backends.resulthandle import ResultHandle -from pytket.circuit import BasisOrder, Circuit, Qubit, OpType from pytket.passes import CliffordSimp from pytket.pauli import Pauli, QubitPauliString from pytket.utils.expectations import ( @@ -166,9 +167,11 @@ def test_resulthandle() -> None: with pytest.raises(CircuitNotRunError) as errorinfocirc: _ = b.get_result(wronghandle) - assert "Circuit corresponding to {0!r} ".format( - wronghandle - ) + "has not been run by this backend instance." in str(errorinfocirc.value) + assert ( + f"Circuit corresponding to {wronghandle!r} " + + "has not been run by this backend instance." + in str(errorinfocirc.value) + ) @pytest.mark.skipif( diff --git a/tests/projectq_convert_test.py b/tests/projectq_convert_test.py index 83ab3c9..b5ff348 100644 --- a/tests/projectq_convert_test.py +++ b/tests/projectq_convert_test.py @@ -13,13 +13,14 @@ # limitations under the License. from math import isclose -import pytest +import pytest from projectq import MainEngine # type: ignore -from projectq.ops import All, Measure, H, NOT, CNOT, Rz, X # type: ignore from projectq.cengines._basics import ForwarderEngine # type: ignore -from pytket.extensions.projectq import tketBackendEngine, tk_to_projectq, tketOptimiser +from projectq.ops import CNOT, NOT, All, H, Measure, Rz, X # type: ignore + from pytket.circuit import Circuit, OpType +from pytket.extensions.projectq import tk_to_projectq, tketBackendEngine, tketOptimiser eps = 1e-7