From ab2211eebd052f27df79b21e7bfc25fa3117c480 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
 <41898282+github-actions[bot]@users.noreply.github.com>
Date: Wed, 27 Apr 2022 12:35:17 +0200
Subject: [PATCH 01/25] Merge master into develop branch (#436)

* Preparing release vv0.7.2

* Fix missed bug in optimize.py

* Fix typo in _optimize.py

* Fix linters/formatters warnings

* Update missed hooks

* Hotfix: fix GitHub action workflows

* Release version v0.7.3 (#435)

* Merge master into develop branch (#431)

* Preparing release vv0.7.2

* Fix missed bug in optimize.py

* Fix typo in _optimize.py

* Fix linters/formatters warnings

* Update missed hooks

* Hotfix: fix GitHub action workflows

Co-authored-by: GitHub actions <noreply@github.com>
Co-authored-by: Nguyen Damien <ngn.damien@gmail.com>

* IonQ API: Move to v0.2, and fixup backends path (#433)

* Move to v0.2, and fixup backends path

The previous path was mistakenly incorrect, could we release this as a patch release of project-Q? Happy to help how I can.

* changelog

* fix

* One more fixup

* remove urljoin

* fmt

* Preparing release v0.7.3

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: GitHub actions <noreply@github.com>
Co-authored-by: Nguyen Damien <ngn.damien@gmail.com>
Co-authored-by: Jon Donovan <donovan@ionq.co>

Co-authored-by: GitHub actions <noreply@github.com>
Co-authored-by: Nguyen Damien <ngn.damien@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Jon Donovan <donovan@ionq.co>
---
 .github/workflows/publish_release.yml | 12 ++++++++----
 CHANGELOG.md                          |  8 +++++++-
 2 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/.github/workflows/publish_release.yml b/.github/workflows/publish_release.yml
index 9865fee58..0849ee1fa 100644
--- a/.github/workflows/publish_release.yml
+++ b/.github/workflows/publish_release.yml
@@ -51,6 +51,7 @@ jobs:
         run: |
           BRANCH_NAME="${{ github.event.pull_request.head.ref }}"
           VERSION=${BRANCH_NAME#release/}
+          echo "VERSION = ${VERSION}"
           git tag ${VERSION} master
 
       - name: Extract version from branch name (for hotfix branches) (Unix)
@@ -58,7 +59,8 @@ jobs:
         run: |
           BRANCH_NAME="${{ github.event.pull_request.head.ref }}"
           VERSION=${BRANCH_NAME#hotfix/}
-          git tag v${VERSION} master
+          echo "VERSION = ${VERSION}"
+          git tag ${VERSION} master
 
       # ------------------------------------------------------------------------
 
@@ -67,14 +69,16 @@ jobs:
         run: |
           $BRANCH_NAME="${{ github.event.pull_request.head.ref }}"
           $VERSION = $BRANCH_NAME -replace "release/",""
-          git tag v${VERSION} master
+          Write-Output "VERSION = ${VERSION}"
+          git tag ${VERSION} master
 
       - name: Extract version from branch name (for hotfix branches) (Windows)
         if: github.event_name == 'pull_request'  && startsWith(github.event.pull_request.head.ref, 'hotfix/') && runner.os == 'Windows'
         run: |
           $BRANCH_NAME="${{ github.event.pull_request.head.ref }}"
           $VERSION = $BRANCH_NAME -replace "hotfix/",""
-          git tag v${VERSION} master
+          Write-Output "VERSION = ${VERSION}"
+          git tag ${VERSION} master
 
       # ========================================================================
 
@@ -164,7 +168,7 @@ jobs:
         if: github.event_name == 'pull_request'  && startsWith(github.event.pull_request.head.ref, 'hotfix/')
         run: |
           BRANCH_NAME="${{ github.event.pull_request.head.ref }}"
-          VERSION=${BRANCH_NAME#hotfix/}
+          VERSION=${BRANCH_NAME#hotfix/v}
 
           echo "RELEASE_VERSION=$VERSION" >> $GITHUB_ENV
 
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e66940441..31e3d2685 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ## [Unreleased]
 
+## [v0.7.3] - 2022-04-27
+
+### Fixed
+
 -   Fixed IonQ dynamic backends fetch, which relied on an incorrect path.
 
 ## [v0.7.2] - 2022-04-11
@@ -186,7 +190,9 @@ The ProjectQ v0.5.x release branch is the last one that is guaranteed to work wi
 
 Future releases might introduce changes that will require Python 3.5 (Python 3.4 and earlier have already been declared deprecated at the time of this writing)
 
-[Unreleased]: https://github.com/ProjectQ-Framework/ProjectQ/compare/v0.7.2...HEAD
+[Unreleased]: https://github.com/ProjectQ-Framework/ProjectQ/compare/v0.7.3...HEAD
+
+[v0.7.3]: https://github.com/ProjectQ-Framework/ProjectQ/compare/v0.7.2...v0.7.3
 
 [v0.7.2]: https://github.com/ProjectQ-Framework/ProjectQ/compare/v0.7.1...v0.7.2
 

From 78afc11353387ff9657bf65ac9dfdb834c966792 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 9 May 2022 23:32:05 +0200
Subject: [PATCH 02/25] Bump docker/setup-qemu-action from 1 to 2 (#437)

* Bump docker/setup-qemu-action from 1 to 2

Bumps [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) from 1 to 2.
- [Release notes](https://github.com/docker/setup-qemu-action/releases)
- [Commits](https://github.com/docker/setup-qemu-action/compare/v1...v2)

---
updated-dependencies:
- dependency-name: docker/setup-qemu-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* Update CHANGELOG

* Fix CentOS 7 build

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Nguyen Damien <ngn.damien@gmail.com>
---
 .github/workflows/ci.yml              | 4 +++-
 .github/workflows/publish_release.yml | 2 +-
 CHANGELOG.md                          | 5 +++++
 3 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 5a5939e11..73db64348 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -242,7 +242,9 @@ jobs:
       run: yum -y install https://packages.endpointdev.com/rhel/7/os/x86_64/endpoint-repo.x86_64.rpm
 
     - name: Install Git > 2.18
-      run: yum install -y git
+      run: |
+        yum install -y git
+        git config --global --add safe.directory /__w/ProjectQ/ProjectQ
 
     - uses: actions/checkout@v2
 
diff --git a/.github/workflows/publish_release.yml b/.github/workflows/publish_release.yml
index 0849ee1fa..ff4bcd221 100644
--- a/.github/workflows/publish_release.yml
+++ b/.github/workflows/publish_release.yml
@@ -26,7 +26,7 @@ jobs:
     steps:
       - name: Set up QEMU
         if: matrix.cibw_archs == 'aarch64'
-        uses: docker/setup-qemu-action@v1
+        uses: docker/setup-qemu-action@v2
         with:
           platforms: arm64
 
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 31e3d2685..0b85aab65 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ## [Unreleased]
 
+### Repository
+
+-   Update `docker/setup-qemu-action` GitHub action to v2
+-   Fixed CentOS 7 configuration issue
+
 ## [v0.7.3] - 2022-04-27
 
 ### Fixed

From 8d9e4652f5f98f4157043c408b3dea25dc6ada2d Mon Sep 17 00:00:00 2001
From: Nguyen Damien <ngn.damien@gmail.com>
Date: Sun, 10 Jul 2022 22:37:53 +0200
Subject: [PATCH 03/25] Fix setuptools-scm version for Python 3.6 (#440)

---
 CHANGELOG.md   |  2 ++
 pyproject.toml |  4 +++-
 setup.cfg      |  3 ---
 setup.py       | 15 +++++++++++++--
 4 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0b85aab65..601765f00 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 -   Update `docker/setup-qemu-action` GitHub action to v2
 -   Fixed CentOS 7 configuration issue
+-   Remove deprecated `setup_requires` field in setup.cfg
+-   Fixed installation issue with newer versions of `setuptool-scm`and Python¨ 3.6
 
 ## [v0.7.3] - 2022-04-27
 
diff --git a/pyproject.toml b/pyproject.toml
index 7752fa4bf..db6087272 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,5 +1,7 @@
 [build-system]
-requires = ["setuptools>=42", "wheel", "pybind11>=2", "setuptools_scm[toml]>=3.4"]
+requires = ["setuptools>=42", "wheel", "pybind11>=2",
+            "setuptools_scm[toml]<7;python_version<'3.7'",
+            "setuptools_scm[toml]>6;python_version>='3.7'"]
 build-backend = "setuptools.build_meta"
 
 # ==============================================================================
diff --git a/setup.cfg b/setup.cfg
index 0f5a22bfd..4bea68081 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -31,9 +31,6 @@ classifier =
 zip_safe = False
 packages = find:
 python_requires = >= 3
-setup_requires =
-  setuptools_scm[toml]
-  pybind11 >= 2
 install_requires =
     matplotlib >= 2.2.3
     networkx >= 2
diff --git a/setup.py b/setup.py
index 46c394d1b..7b3c66489 100755
--- a/setup.py
+++ b/setup.py
@@ -58,6 +58,14 @@
 from setuptools import Extension, setup
 from setuptools.command.build_ext import build_ext
 
+try:
+    import setuptools_scm  # noqa: F401  # pylint: disable=unused-import
+
+    _HAS_SETUPTOOLS_SCM = True
+except ImportError:
+    _HAS_SETUPTOOLS_SCM = False
+
+
 # ==============================================================================
 # Helper functions and classes
 
@@ -645,9 +653,12 @@ def run_setup(with_cext):
     else:
         kwargs['ext_modules'] = []
 
+    # NB: Workaround for people calling setup.py without a proper environment containing setuptools-scm
+    #     This can typically be the case when calling the `gen_reqfile` or `clang_tidy`commands
+    if not _HAS_SETUPTOOLS_SCM:
+        kwargs['version'] = '0.0.0'
+
     setup(
-        use_scm_version={'local_scheme': 'no-local-version'},
-        setup_requires=['setuptools_scm'],
         cmdclass={
             'build_ext': BuildExt,
             'clang_tidy': ClangTidy,

From 6bbda5343291d81e33a4cf10ac015679c9aefdc7 Mon Sep 17 00:00:00 2001
From: Nguyen Damien <ngn.damien@gmail.com>
Date: Tue, 19 Jul 2022 10:47:25 +0200
Subject: [PATCH 04/25] Add `blacken-docs` and `pyupgrade` to pre-commit
 configuration (#441)

* Add `blacken-docs` and `pyupgrade` to pre-commit configuration

* Apply new pre-commit hooks and fix related issues.

* Update CHANGELOG

* Fix unit tests failures

* Fix pre-commit failure

* Generalise the use of f-strings

* Fix IonQ tests

* Run `pyupgrade` before `isort` and `black`
---
 .pre-commit-config.yaml                       |  14 +-
 CHANGELOG.md                                  |   1 +
 README.rst                                    |  55 +++---
 docs/conf.py                                  |   6 +-
 docs/package_description.py                   |  25 ++-
 docs/tutorials.rst                            |   7 +-
 examples/aqt.py                               |   3 +-
 examples/bellpair_circuit.py                  |   1 -
 examples/control_tester.py                    |   1 -
 examples/gate_zoo.py                          |   7 +-
 examples/grover.py                            |   1 -
 examples/hws4.py                              |   3 +-
 examples/hws6.py                              |   3 +-
 examples/ibm.py                               |   3 +-
 examples/ibmq_tutorial.ipynb                  |   2 +-
 examples/ionq.py                              |   3 +-
 examples/ionq_bv.py                           |   3 +-
 examples/ionq_half_adder.py                   |   1 -
 examples/mapper_tutorial.ipynb                |  20 +-
 examples/quantum_random_numbers.py            |   3 +-
 examples/quantum_random_numbers_ibm.py        |   3 +-
 examples/shor.py                              |  14 +-
 examples/simulator_tutorial.ipynb             |  32 ++--
 examples/spectral_measurement.ipynb           |   2 +-
 examples/teleport.py                          |   3 +-
 examples/teleport_circuit.py                  |   1 -
 examples/unitary_simulator.py                 |   1 -
 projectq/__init__.py                          |   1 -
 projectq/backends/__init__.py                 |   1 -
 projectq/backends/_aqt/__init__.py            |   1 -
 projectq/backends/_aqt/_aqt.py                |  15 +-
 projectq/backends/_aqt/_aqt_http_client.py    |  20 +-
 .../backends/_aqt/_aqt_http_client_test.py    |   1 -
 projectq/backends/_aqt/_aqt_test.py           |   1 -
 projectq/backends/_awsbraket/__init__.py      |   1 -
 projectq/backends/_awsbraket/_awsbraket.py    |  17 +-
 .../_awsbraket/_awsbraket_boto3_client.py     |  34 ++--
 .../_awsbraket_boto3_client_test.py           |   5 +-
 .../_awsbraket_boto3_client_test_fixtures.py  |   1 -
 .../backends/_awsbraket/_awsbraket_test.py    |   4 +-
 .../_awsbraket/_awsbraket_test_fixtures.py    |   1 -
 projectq/backends/_circuits/__init__.py       |   1 -
 projectq/backends/_circuits/_drawer.py        |  77 ++++----
 .../backends/_circuits/_drawer_matplotlib.py  |  10 +-
 .../_circuits/_drawer_matplotlib_test.py      |  34 ++--
 projectq/backends/_circuits/_drawer_test.py   |  28 ++-
 projectq/backends/_circuits/_plot.py          |  10 +-
 projectq/backends/_circuits/_plot_test.py     |  13 +-
 projectq/backends/_circuits/_to_latex.py      | 172 +++++++-----------
 projectq/backends/_circuits/_to_latex_test.py |   9 +-
 projectq/backends/_exceptions.py              |   1 -
 projectq/backends/_ibm/__init__.py            |   1 -
 projectq/backends/_ibm/_ibm.py                |  22 +--
 projectq/backends/_ibm/_ibm_http_client.py    |  20 +-
 .../backends/_ibm/_ibm_http_client_test.py    |  45 ++---
 projectq/backends/_ibm/_ibm_test.py           |   1 -
 projectq/backends/_ionq/__init__.py           |   1 -
 projectq/backends/_ionq/_ionq.py              |  11 +-
 projectq/backends/_ionq/_ionq_http_client.py  |  37 ++--
 .../backends/_ionq/_ionq_http_client_test.py  |   1 -
 projectq/backends/_ionq/_ionq_mapper.py       |   5 +-
 projectq/backends/_ionq/_ionq_mapper_test.py  |   1 -
 projectq/backends/_ionq/_ionq_test.py         |   1 -
 projectq/backends/_printer.py                 |   6 +-
 projectq/backends/_printer_test.py            |  11 +-
 projectq/backends/_resource.py                |   1 -
 projectq/backends/_resource_test.py           |   3 +-
 projectq/backends/_sim/__init__.py            |   1 -
 .../backends/_sim/_classical_simulator.py     |   1 -
 .../_sim/_classical_simulator_test.py         |   1 -
 projectq/backends/_sim/_pysim.py              |   5 +-
 projectq/backends/_sim/_simulator.py          |  10 +-
 projectq/backends/_sim/_simulator_test.py     |   5 +-
 .../backends/_sim/_simulator_test_fixtures.py |   1 -
 projectq/backends/_unitary.py                 |   3 +-
 projectq/backends/_unitary_test.py            |   3 +-
 projectq/cengines/__init__.py                 |   1 -
 projectq/cengines/_basicmapper.py             |   1 -
 projectq/cengines/_basicmapper_test.py        |   1 -
 projectq/cengines/_basics.py                  |   7 +-
 projectq/cengines/_basics_test.py             |   1 -
 projectq/cengines/_cmdmodifier.py             |   3 +-
 projectq/cengines/_cmdmodifier_test.py        |   1 -
 projectq/cengines/_ibm5qubitmapper.py         |   1 -
 projectq/cengines/_ibm5qubitmapper_test.py    |   1 -
 projectq/cengines/_linearmapper.py            |   3 +-
 projectq/cengines/_linearmapper_test.py       |   1 -
 projectq/cengines/_main.py                    |  21 ++-
 projectq/cengines/_main_test.py               |   1 -
 projectq/cengines/_manualmapper.py            |   1 -
 projectq/cengines/_manualmapper_test.py       |   1 -
 projectq/cengines/_optimize.py                |   1 -
 projectq/cengines/_optimize_test.py           |   1 -
 projectq/cengines/_replacer/__init__.py       |   1 -
 .../cengines/_replacer/_decomposition_rule.py |   1 -
 .../_replacer/_decomposition_rule_set.py      |   4 +-
 .../_replacer/_decomposition_rule_test.py     |   1 -
 projectq/cengines/_replacer/_replacer.py      |   5 +-
 projectq/cengines/_replacer/_replacer_test.py |   1 -
 projectq/cengines/_swapandcnotflipper.py      |   7 +-
 projectq/cengines/_swapandcnotflipper_test.py |   1 -
 projectq/cengines/_tagremover.py              |   3 +-
 projectq/cengines/_tagremover_test.py         |   3 +-
 projectq/cengines/_testengine.py              |   7 +-
 projectq/cengines/_testengine_test.py         |   6 +-
 projectq/cengines/_twodmapper.py              |   1 -
 projectq/cengines/_twodmapper_test.py         |   1 -
 projectq/libs/__init__.py                     |   1 -
 projectq/libs/hist/__init__.py                |   1 -
 projectq/libs/hist/_histogram.py              |   3 +-
 projectq/libs/hist/_histogram_test.py         |   1 -
 projectq/libs/math/__init__.py                |   1 -
 projectq/libs/math/_constantmath.py           |   1 -
 projectq/libs/math/_constantmath_test.py      |   1 -
 projectq/libs/math/_default_rules.py          |   1 -
 projectq/libs/math/_gates.py                  |  93 +++++-----
 projectq/libs/math/_gates_math_test.py        |   3 +-
 projectq/libs/math/_gates_test.py             |   1 -
 projectq/libs/math/_quantummath.py            |   1 -
 projectq/libs/math/_quantummath_test.py       |   3 +-
 projectq/libs/revkit/__init__.py              |   1 -
 projectq/libs/revkit/_control_function.py     |   5 +-
 .../libs/revkit/_control_function_test.py     |   1 -
 projectq/libs/revkit/_permutation.py          |   1 -
 projectq/libs/revkit/_permutation_test.py     |   1 -
 projectq/libs/revkit/_phase.py                |   5 +-
 projectq/libs/revkit/_phase_test.py           |   1 -
 projectq/libs/revkit/_utils.py                |   1 -
 projectq/meta/__init__.py                     |   1 -
 projectq/meta/_compute.py                     |   7 +-
 projectq/meta/_compute_test.py                |   5 +-
 projectq/meta/_control.py                     |  14 +-
 projectq/meta/_control_test.py                |   3 +-
 projectq/meta/_dagger.py                      |   8 +-
 projectq/meta/_dagger_test.py                 |   1 -
 projectq/meta/_dirtyqubit.py                  |   1 -
 projectq/meta/_dirtyqubit_test.py             |   1 -
 projectq/meta/_exceptions.py                  |   1 -
 projectq/meta/_logicalqubit.py                |   1 -
 projectq/meta/_logicalqubit_test.py           |   1 -
 projectq/meta/_loop.py                        |  12 +-
 projectq/meta/_loop_test.py                   |   1 -
 projectq/meta/_util.py                        |   1 -
 projectq/meta/_util_test.py                   |   1 -
 projectq/ops/__init__.py                      |   1 -
 projectq/ops/_basics.py                       |  37 ++--
 projectq/ops/_basics_test.py                  |   3 +-
 projectq/ops/_command.py                      |   7 +-
 projectq/ops/_command_test.py                 |   7 +-
 projectq/ops/_gates.py                        |  10 +-
 projectq/ops/_gates_test.py                   |   1 -
 projectq/ops/_metagates.py                    |  29 ++-
 projectq/ops/_metagates_test.py               |  11 +-
 projectq/ops/_qaagate.py                      |  15 +-
 projectq/ops/_qaagate_test.py                 |   1 -
 projectq/ops/_qftgate.py                      |   1 -
 projectq/ops/_qftgate_test.py                 |   1 -
 projectq/ops/_qpegate.py                      |   3 +-
 projectq/ops/_qpegate_test.py                 |   1 -
 projectq/ops/_qubit_operator.py               |  26 ++-
 projectq/ops/_qubit_operator_test.py          |   1 -
 projectq/ops/_shortcuts.py                    |   1 -
 projectq/ops/_shortcuts_test.py               |   1 -
 projectq/ops/_state_prep.py                   |   3 +-
 projectq/ops/_state_prep_test.py              |   1 -
 projectq/ops/_time_evolution.py               |   3 +-
 projectq/ops/_time_evolution_test.py          |   1 -
 .../ops/_uniformly_controlled_rotation.py     |  17 +-
 .../_uniformly_controlled_rotation_test.py    |   1 -
 projectq/setups/__init__.py                   |   1 -
 projectq/setups/_utils.py                     |   1 -
 projectq/setups/aqt.py                        |   1 -
 projectq/setups/aqt_test.py                   |   1 -
 projectq/setups/awsbraket.py                  |   3 +-
 projectq/setups/awsbraket_test.py             |   1 -
 projectq/setups/decompositions/__init__.py    |   1 -
 projectq/setups/decompositions/_gates_test.py |   1 -
 .../decompositions/amplitudeamplification.py  |  15 +-
 .../amplitudeamplification_test.py            |  11 +-
 .../decompositions/arb1qubit2rzandry.py       |   7 +-
 .../decompositions/arb1qubit2rzandry_test.py  |   1 -
 projectq/setups/decompositions/barrier.py     |   1 -
 .../setups/decompositions/barrier_test.py     |   1 -
 .../decompositions/carb1qubit2cnotrzandry.py  |   1 -
 .../carb1qubit2cnotrzandry_test.py            |   1 -
 projectq/setups/decompositions/cnot2cz.py     |   1 -
 .../setups/decompositions/cnot2cz_test.py     |   1 -
 projectq/setups/decompositions/cnot2rxx.py    |   1 -
 .../setups/decompositions/cnot2rxx_test.py    |   1 -
 .../setups/decompositions/cnu2toffoliandcu.py |   1 -
 .../decompositions/cnu2toffoliandcu_test.py   |   1 -
 .../setups/decompositions/controlstate.py     |   1 -
 .../decompositions/controlstate_test.py       |   1 -
 projectq/setups/decompositions/crz2cxandrz.py |   1 -
 projectq/setups/decompositions/entangle.py    |   1 -
 projectq/setups/decompositions/globalphase.py |   1 -
 projectq/setups/decompositions/h2rx.py        |   1 -
 projectq/setups/decompositions/h2rx_test.py   |   1 -
 projectq/setups/decompositions/ph2r.py        |   1 -
 .../setups/decompositions/phaseestimation.py  |  25 +--
 .../decompositions/phaseestimation_test.py    |  21 +--
 .../decompositions/qft2crandhadamard.py       |   1 -
 .../setups/decompositions/qubitop2onequbit.py |   1 -
 .../decompositions/qubitop2onequbit_test.py   |   3 +-
 projectq/setups/decompositions/r2rzandph.py   |   1 -
 projectq/setups/decompositions/rx2rz.py       |   1 -
 projectq/setups/decompositions/rx2rz_test.py  |   1 -
 projectq/setups/decompositions/ry2rz.py       |   1 -
 projectq/setups/decompositions/ry2rz_test.py  |   1 -
 projectq/setups/decompositions/rz2rx.py       |   1 -
 projectq/setups/decompositions/rz2rx_test.py  |   1 -
 .../setups/decompositions/sqrtswap2cnot.py    |   1 -
 .../decompositions/sqrtswap2cnot_test.py      |   1 -
 .../setups/decompositions/stateprep2cnot.py   |   1 -
 .../decompositions/stateprep2cnot_test.py     |   1 -
 projectq/setups/decompositions/swap2cnot.py   |   1 -
 .../setups/decompositions/time_evolution.py   |   1 -
 .../decompositions/time_evolution_test.py     |   1 -
 .../decompositions/toffoli2cnotandtgate.py    |   1 -
 .../uniformlycontrolledr2cnot.py              |   1 -
 .../uniformlycontrolledr2cnot_test.py         |   3 +-
 projectq/setups/default.py                    |   1 -
 projectq/setups/grid.py                       |   1 -
 projectq/setups/grid_test.py                  |   1 -
 projectq/setups/ibm.py                        |   1 -
 projectq/setups/ibm_test.py                   |   1 -
 projectq/setups/ionq.py                       |   3 +-
 projectq/setups/ionq_test.py                  |   3 +-
 projectq/setups/linear.py                     |   1 -
 projectq/setups/linear_test.py                |   1 -
 projectq/setups/restrictedgateset.py          |   1 -
 projectq/setups/restrictedgateset_test.py     |   1 -
 projectq/setups/trapped_ion_decomposer.py     |   1 -
 .../setups/trapped_ion_decomposer_test.py     |   1 -
 projectq/tests/__init__.py                    |   1 -
 projectq/tests/_factoring_test.py             |   1 -
 projectq/types/__init__.py                    |   1 -
 projectq/types/_qubit.py                      |   6 +-
 projectq/types/_qubit_test.py                 |   3 +-
 setup.py                                      |  27 ++-
 240 files changed, 625 insertions(+), 894 deletions(-)

diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 2d74edd3f..804d6e47f 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -35,7 +35,6 @@ repos:
       - id: end-of-file-fixer
       - id: mixed-line-ending
       - id: trailing-whitespace
-      - id: fix-encoding-pragma
 
   # Changes tabs to spaces
   - repo: https://github.com/Lucas-C/pre-commit-hooks
@@ -43,6 +42,12 @@ repos:
     hooks:
       - id: remove-tabs
 
+  - repo: https://github.com/asottile/pyupgrade
+    rev: v2.34.0
+    hooks:
+      - id: pyupgrade
+        args: [--py36-plus, --keep-mock]
+
   - repo: https://github.com/PyCQA/isort
     rev: 5.10.1
     hooks:
@@ -57,6 +62,13 @@ repos:
         # This is a slow hook, so only run this if --hook-stage manual is passed
         stages: [manual]
 
+  - repo: https://github.com/asottile/blacken-docs
+    rev: v1.12.1
+    hooks:
+      - id: blacken-docs
+        args: [-S, -l, '120']
+        additional_dependencies: [black==22.3.0]
+
   - repo: https://gitlab.com/PyCQA/flake8
     rev: 3.9.2
     hooks:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 601765f00..4228cb015 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 -   Update `docker/setup-qemu-action` GitHub action to v2
 -   Fixed CentOS 7 configuration issue
+-   Added two new pre-commit hooks: `blacken-docs` and `pyupgrade`
 -   Remove deprecated `setup_requires` field in setup.cfg
 -   Fixed installation issue with newer versions of `setuptool-scm`and Python¨ 3.6
 
diff --git a/README.rst b/README.rst
index 3e24d7332..1f85c2cc2 100755
--- a/README.rst
+++ b/README.rst
@@ -43,7 +43,10 @@ Examples
 .. code-block:: python
 
     from projectq import MainEngine  # import the main compiler engine
-    from projectq.ops import H, Measure  # import the operations we want to perform (Hadamard and measurement)
+    from projectq.ops import (
+        H,
+        Measure,
+    )  # import the operations we want to perform (Hadamard and measurement)
 
     eng = MainEngine()  # create a default compiler (the back-end is a simulator)
     qubit = eng.allocate_qubit()  # allocate a quantum register with 1 qubit
@@ -52,7 +55,7 @@ Examples
     Measure | qubit  # measure the qubit
 
     eng.flush()  # flush all gates (and execute measurements)
-    print("Measured {}".format(int(qubit)))  # converting a qubit to int or bool gives access to the measurement result
+    print(f"Measured {int(qubit)}")  # converting a qubit to int or bool gives access to the measurement result
 
 
 ProjectQ features a lean syntax which is close to the mathematical notation used in quantum physics. For example, a rotation of a qubit around the x-axis is usually specified as:
@@ -80,9 +83,7 @@ Instead of simulating a quantum program, one can use our resource counter (as a
     from projectq.ops import QFT
     from projectq.setups import linear
 
-    compiler_engines = linear.get_engine_list(num_qubits=16,
-                                              one_qubit_gates='any',
-                                              two_qubit_gates=(CNOT, Swap))
+    compiler_engines = linear.get_engine_list(num_qubits=16, one_qubit_gates='any', two_qubit_gates=(CNOT, Swap))
     resource_counter = ResourceCounter()
     eng = MainEngine(backend=resource_counter, engine_list=compiler_engines)
     qureg = eng.allocate_qureg(16)
@@ -112,12 +113,13 @@ To run a program on the IBM Quantum Experience chips, all one has to do is choos
     import projectq.setups.ibm
     from projectq.backends import IBMBackend
 
-    token='MY_TOKEN'
-    device='ibmq_16_melbourne'
-    compiler_engines = projectq.setups.ibm.get_engine_list(token=token,device=device)
-    eng = MainEngine(IBMBackend(token=token, use_hardware=True, num_runs=1024,
-                                verbose=False, device=device),
-                     engine_list=compiler_engines)
+    token = 'MY_TOKEN'
+    device = 'ibmq_16_melbourne'
+    compiler_engines = projectq.setups.ibm.get_engine_list(token=token, device=device)
+    eng = MainEngine(
+        IBMBackend(token=token, use_hardware=True, num_runs=1024, verbose=False, device=device),
+        engine_list=compiler_engines,
+    )
 
 
 **Running a quantum program on AQT devices**
@@ -129,12 +131,13 @@ To run a program on the AQT trapped ion quantum computer, choose the `AQTBackend
     import projectq.setups.aqt
     from projectq.backends import AQTBackend
 
-    token='MY_TOKEN'
-    device='aqt_device'
-    compiler_engines = projectq.setups.aqt.get_engine_list(token=token,device=device)
-    eng = MainEngine(AQTBackend(token=token,use_hardware=True, num_runs=1024,
-                                verbose=False, device=device),
-                     engine_list=compiler_engines)
+    token = 'MY_TOKEN'
+    device = 'aqt_device'
+    compiler_engines = projectq.setups.aqt.get_engine_list(token=token, device=device)
+    eng = MainEngine(
+        AQTBackend(token=token, use_hardware=True, num_runs=1024, verbose=False, device=device),
+        engine_list=compiler_engines,
+    )
 
 
 **Running a quantum program on a AWS Braket provided device**
@@ -150,13 +153,21 @@ IonQ from IonQ and the state vector simulator SV1:
     creds = {
         'AWS_ACCESS_KEY_ID': 'your_aws_access_key_id',
         'AWS_SECRET_KEY': 'your_aws_secret_key',
-        }
+    }
 
     s3_folder = ['S3Bucket', 'S3Directory']
-    device='IonQ'
-    eng = MainEngine(AWSBraketBackend(use_hardware=True, credentials=creds, s3_folder=s3_folder,
-                     num_runs=1024, verbose=False, device=device),
-                     engine_list=[])
+    device = 'IonQ'
+    eng = MainEngine(
+        AWSBraketBackend(
+            use_hardware=True,
+            credentials=creds,
+            s3_folder=s3_folder,
+            num_runs=1024,
+            verbose=False,
+            device=device,
+        ),
+        engine_list=[],
+    )
 
 
 .. note::
diff --git a/docs/conf.py b/docs/conf.py
index 4b2b99fa2..a9d5efc09 100755
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -1,5 +1,4 @@
 #!/usr/bin/env python3
-# -*- coding: utf-8 -*-
 #
 # projectq documentation build configuration file, created by
 # sphinx-quickstart on Tue Nov 29 11:51:46 2016.
@@ -533,6 +532,7 @@ def linkcode_resolve(domain, info):
 
         import projectq.setups.ibm as ibm_setup
         from projectq import MainEngine
+
         eng = MainEngine(engine_list=ibm_setup.get_engine_list())
         # eng uses the default Simulator backend
 
@@ -560,10 +560,10 @@ def linkcode_resolve(domain, info):
     os.mkdir(docgen_path)
 
 for desc in descriptions:
-    fname = os.path.join(docgen_path, 'projectq.{}.rst'.format(desc.name))
+    fname = os.path.join(docgen_path, f'projectq.{desc.name}.rst')
     lines = None
     if os.path.exists(fname):
-        with open(fname, 'r') as fd:
+        with open(fname) as fd:
             lines = [line[:-1] for line in fd.readlines()]
 
     new_lines = desc.get_ReST()
diff --git a/docs/package_description.py b/docs/package_description.py
index fcfbb5b21..d04ba67c3 100644
--- a/docs/package_description.py
+++ b/docs/package_description.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -52,7 +51,7 @@ def __init__(  # pylint: disable=too-many-arguments
         if pkg_name not in PackageDescription.package_list:
             PackageDescription.package_list.append(pkg_name)
 
-        self.module = importlib.import_module('projectq.{}'.format(self.name))
+        self.module = importlib.import_module(f'projectq.{self.name}')
         self.module_special_members = module_special_members
 
         self.submodule_special_members = submodule_special_members
@@ -72,7 +71,7 @@ def __init__(  # pylint: disable=too-many-arguments
         self.subpackages = []
         self.submodules = []
         for name, obj in sub:
-            if '{}.{}'.format(self.name, name) in PackageDescription.package_list:
+            if f'{self.name}.{name}' in PackageDescription.package_list:
                 self.subpackages.append((name, obj))
             else:
                 self.submodules.append((name, obj))
@@ -115,7 +114,7 @@ def get_ReST(self):  # pylint: disable=invalid-name,too-many-branches,too-many-s
             new_lines.append('    :maxdepth: 1')
             new_lines.append('')
             for name, _ in self.subpackages:
-                new_lines.append('    projectq.{}.{}'.format(self.name, name))
+                new_lines.append(f'    projectq.{self.name}.{name}')
             new_lines.append('')
         else:
             submodule_has_index = True
@@ -123,11 +122,11 @@ def get_ReST(self):  # pylint: disable=invalid-name,too-many-branches,too-many-s
             new_lines.append('')
             if self.submodules:
                 for name, _ in self.submodules:
-                    new_lines.append('\tprojectq.{}.{}'.format(self.name, name))
+                    new_lines.append(f'\tprojectq.{self.name}.{name}')
                 new_lines.append('')
             if self.members:
                 for name, _ in self.members:
-                    new_lines.append('\tprojectq.{}.{}'.format(self.name, name))
+                    new_lines.append(f'\tprojectq.{self.name}.{name}')
                 new_lines.append('')
 
         if self.submodules:
@@ -142,27 +141,27 @@ def get_ReST(self):  # pylint: disable=invalid-name,too-many-branches,too-many-s
                 new_lines.append('.. autosummary::')
                 new_lines.append('')
                 for name, _ in self.submodules:
-                    new_lines.append('    projectq.{}.{}'.format(self.name, name))
+                    new_lines.append(f'    projectq.{self.name}.{name}')
                 new_lines.append('')
 
             for name, _ in self.submodules:
                 new_lines.append(name)
                 new_lines.append('^' * len(new_lines[-1]))
                 new_lines.append('')
-                new_lines.append('.. automodule:: projectq.{}.{}'.format(self.name, name))
+                new_lines.append(f'.. automodule:: projectq.{self.name}.{name}')
                 new_lines.append('    :members:')
                 if self.submodule_special_members:
-                    new_lines.append('    :special-members: {}'.format(self.submodule_special_members))
+                    new_lines.append(f'    :special-members: {self.submodule_special_members}')
                 new_lines.append('    :undoc-members:')
                 new_lines.append('')
 
         new_lines.append('Module contents')
         new_lines.append('-' * len(new_lines[-1]))
         new_lines.append('')
-        new_lines.append('.. automodule:: projectq.{}'.format(self.name))
+        new_lines.append(f'.. automodule:: projectq.{self.name}')
         new_lines.append('    :members:')
         new_lines.append('    :undoc-members:')
-        new_lines.append('    :special-members: {}'.format(self.module_special_members))
+        new_lines.append(f'    :special-members: {self.module_special_members}')
         new_lines.append('    :imported-members:')
         new_lines.append('')
 
@@ -174,9 +173,9 @@ def get_ReST(self):  # pylint: disable=invalid-name,too-many-branches,too-many-s
                 new_lines.append(title)
                 new_lines.append('^' * len(title))
                 new_lines.append('')
-                new_lines.append('.. automodule:: projectq.{}.{}'.format(self.name, name))
+                new_lines.append(f'.. automodule:: projectq.{self.name}.{name}')
                 for param in params:
-                    new_lines.append('    {}'.format(param))
+                    new_lines.append(f'    {param}')
                 new_lines.append('')
 
         return new_lines[:-1]
diff --git a/docs/tutorials.rst b/docs/tutorials.rst
index 58d8de1c9..669ec9eb0 100755
--- a/docs/tutorials.rst
+++ b/docs/tutorials.rst
@@ -239,7 +239,10 @@ To check out the ProjectQ syntax in action and to see whether the installation w
 .. code-block:: python
 
     from projectq import MainEngine  # import the main compiler engine
-    from projectq.ops import H, Measure  # import the operations we want to perform (Hadamard and measurement)
+    from projectq.ops import (
+        H,
+        Measure,
+    )  # import the operations we want to perform (Hadamard and measurement)
 
     eng = MainEngine()  # create a default compiler (the back-end is a simulator)
     qubit = eng.allocate_qubit()  # allocate 1 qubit
@@ -248,6 +251,6 @@ To check out the ProjectQ syntax in action and to see whether the installation w
     Measure | qubit  # measure the qubit
 
     eng.flush()  # flush all gates (and execute measurements)
-    print("Measured {}".format(int(qubit)))  # output measurement result
+    print(f"Measured {int(qubit)}")  # output measurement result
 
 Which creates random bits (0 or 1).
diff --git a/examples/aqt.py b/examples/aqt.py
index 68da13606..1be765189 100644
--- a/examples/aqt.py
+++ b/examples/aqt.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 # pylint: skip-file
 
 """Example of running a quantum circuit using the AQT APIs."""
@@ -40,7 +39,7 @@ def run_entangle(eng, num_qubits=3):
     # access the probabilities via the back-end:
     # results = eng.backend.get_probabilities(qureg)
     # for state in results:
-    #     print("Measured {} with p = {}.".format(state, results[state]))
+    #     print(f"Measured {state} with p = {results[state]}.")
     # or plot them directly:
     histogram(eng.backend, qureg)
     plt.show()
diff --git a/examples/bellpair_circuit.py b/examples/bellpair_circuit.py
index c4343f801..611e1ffe5 100755
--- a/examples/bellpair_circuit.py
+++ b/examples/bellpair_circuit.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 # pylint: skip-file
 
 """Example implementation of a quantum circuit generating a Bell pair state."""
diff --git a/examples/control_tester.py b/examples/control_tester.py
index 8f9463735..3175404a7 100755
--- a/examples/control_tester.py
+++ b/examples/control_tester.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/examples/gate_zoo.py b/examples/gate_zoo.py
index c8e97ed97..684addfa4 100644
--- a/examples/gate_zoo.py
+++ b/examples/gate_zoo.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 # pylint: skip-file
 
 """Showcase most of the quantum gates available in ProjectQ."""
@@ -95,12 +94,12 @@ def add(x, y):
     # generate latex code to draw the circuit
     s = drawing_engine.get_latex()
     prefix = 'zoo'
-    with open('{}.tex'.format(prefix), 'w') as f:
+    with open(f'{prefix}.tex', 'w') as f:
         f.write(s)
 
     # compile latex source code and open pdf file
-    os.system('pdflatex {}.tex'.format(prefix))
-    openfile('{}.pdf'.format(prefix))
+    os.system(f'pdflatex {prefix}.tex')
+    openfile(f'{prefix}.pdf')
 
 
 def openfile(filename):
diff --git a/examples/grover.py b/examples/grover.py
index 539fc525a..1d1511db1 100755
--- a/examples/grover.py
+++ b/examples/grover.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 # pylint: skip-file
 
 """Example implementation of Grover's algorithm."""
diff --git a/examples/hws4.py b/examples/hws4.py
index 8ba5b6174..4225480b2 100644
--- a/examples/hws4.py
+++ b/examples/hws4.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 # pylint: skip-file
 
 """Example of a 4-qubit phase function."""
@@ -30,4 +29,4 @@ def f(a, b, c, d):
 
 eng.flush()
 
-print("Shift is {}".format(8 * int(x4) + 4 * int(x3) + 2 * int(x2) + int(x1)))
+print(f"Shift is {8 * int(x4) + 4 * int(x3) + 2 * int(x2) + int(x1)}")
diff --git a/examples/hws6.py b/examples/hws6.py
index bf5540d07..4aa9a30e4 100644
--- a/examples/hws6.py
+++ b/examples/hws6.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 # pylint: skip-file
 
 """Example of a 6-qubit phase function."""
@@ -44,4 +43,4 @@ def f(a, b, c, d, e, f):
 All(Measure) | qubits
 
 # measurement result
-print("Shift is {}".format(sum(int(q) << i for i, q in enumerate(qubits))))
+print(f"Shift is {sum(int(q) << i for i, q in enumerate(qubits))}")
diff --git a/examples/ibm.py b/examples/ibm.py
index 24bd0c097..ce19e5491 100755
--- a/examples/ibm.py
+++ b/examples/ibm.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 # pylint: skip-file
 
 """Example of running a quantum circuit using the IBM QE APIs."""
@@ -40,7 +39,7 @@ def run_entangle(eng, num_qubits=3):
     # access the probabilities via the back-end:
     # results = eng.backend.get_probabilities(qureg)
     # for state in results:
-    #     print("Measured {} with p = {}.".format(state, results[state]))
+    #     print(f"Measured {state} with p = {results[state]}.")
     # or plot them directly:
     histogram(eng.backend, qureg)
     plt.show()
diff --git a/examples/ibmq_tutorial.ipynb b/examples/ibmq_tutorial.ipynb
index 358bdcf9e..9721b71fb 100644
--- a/examples/ibmq_tutorial.ipynb
+++ b/examples/ibmq_tutorial.ipynb
@@ -133,7 +133,7 @@
     "    # access the probabilities via the back-end:\n",
     "    # results = eng.backend.get_probabilities(qureg)\n",
     "    # for state in results:\n",
-    "    #     print(\"Measured {} with p = {}.\".format(state, results[state]))\n",
+    "    #     print(f\"Measured {state} with p = {results[state]}.\")\n",
     "    # or plot them directly:\n",
     "    histogram(eng.backend, qureg)\n",
     "    plt.show()\n",
diff --git a/examples/ionq.py b/examples/ionq.py
index 71f0c6831..472f45281 100644
--- a/examples/ionq.py
+++ b/examples/ionq.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -53,7 +52,7 @@ def run_entangle(eng, num_qubits=3):
     # access the probabilities via the back-end:
     # results = eng.backend.get_probabilities(qureg)
     # for state in results:
-    #     print("Measured {} with p = {}.".format(state, results[state]))
+    #     print(f"Measured {state} with p = {results[state]}.")
     # or plot them directly:
     histogram(eng.backend, qureg)
     plt.show()
diff --git a/examples/ionq_bv.py b/examples/ionq_bv.py
index afaf48c78..5cbe839fa 100644
--- a/examples/ionq_bv.py
+++ b/examples/ionq_bv.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -37,7 +36,7 @@ def oracle(qureg, input_size, s):
 
 def run_bv_circuit(eng, input_size, s_int):
     """Run the quantum circuit."""
-    s = ('{0:0' + str(input_size) + 'b}').format(s_int)
+    s = f"{s_int:0{input_size}b}"
     print("Secret string: ", s)
     print("Number of qubits: ", str(input_size + 1))
     circuit = eng.allocate_qureg(input_size + 1)
diff --git a/examples/ionq_half_adder.py b/examples/ionq_half_adder.py
index 905fa38e9..2efbe7a45 100644
--- a/examples/ionq_half_adder.py
+++ b/examples/ionq_half_adder.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/examples/mapper_tutorial.ipynb b/examples/mapper_tutorial.ipynb
index 5027819b2..b5c50881d 100644
--- a/examples/mapper_tutorial.ipynb
+++ b/examples/mapper_tutorial.ipynb
@@ -361,9 +361,9 @@
     "\n",
     "# Remember that allocate_qubit returns a quantum register (Qureg) of size 1,\n",
     "# so accessing the qubit requires qubit[0]\n",
-    "print(\"This logical qubit0 has the unique ID: {}\".format(qubit0[0].id))\n",
-    "print(\"This logical qubit1 has the unique ID: {}\".format(qubit1[0].id))\n",
-    "print(\"This logical qubit2 has the unique ID: {}\".format(qubit2[0].id)) \n",
+    "print(f\"This logical qubit0 has the unique ID: {qubit0[0].id}\")\n",
+    "print(f\"This logical qubit1 has the unique ID: {qubit1[0].id}\")\n",
+    "print(f\"This logical qubit2 has the unique ID: {qubit2[0].id}\") \n",
     "\n",
     "eng4.flush()"
    ]
@@ -400,9 +400,9 @@
     "# current_mapping is a dictionary with keys being the\n",
     "# logical qubit ids and the values being the physical ids on\n",
     "# on the linear chain\n",
-    "print(\"Physical location of qubit0: {}\".format(current_mapping[qubit0[0].id]))\n",
-    "print(\"Physical location of qubit1: {}\".format(current_mapping[qubit1[0].id]))\n",
-    "print(\"Physical location of qubit2: {}\".format(current_mapping[qubit2[0].id]))"
+    "print(f\"Physical location of qubit0: {current_mapping[qubit0[0].id]}\")\n",
+    "print(f\"Physical location of qubit1: {current_mapping[qubit1[0].id]}\")\n",
+    "print(f\"Physical location of qubit2: {current_mapping[qubit2[0].id]}\")"
    ]
   },
   {
@@ -435,9 +435,9 @@
     "eng4.flush()\n",
     "# Get current mapping:\n",
     "current_mapping = eng4.mapper.current_mapping\n",
-    "print(\"\\nPhysical location of qubit0: {}\".format(current_mapping[qubit0[0].id]))\n",
-    "print(\"Physical location of qubit1: {}\".format(current_mapping[qubit1[0].id]))\n",
-    "print(\"Physical location of qubit2: {}\".format(current_mapping[qubit2[0].id]))"
+    "print(f\"\\nPhysical location of qubit0: {current_mapping[qubit0[0].id]}\")\n",
+    "print(f\"Physical location of qubit1: {current_mapping[qubit1[0].id]}\")\n",
+    "print(f\"Physical location of qubit2: {current_mapping[qubit2[0].id]}\")"
    ]
   },
   {
@@ -491,7 +491,7 @@
     "Measure | qubit0\n",
     "eng5.flush()\n",
     "\n",
-    "print(\"qubit0 was measured in state: {}\".format(int(qubit0)))"
+    "print(f\"qubit0 was measured in state: {int(qubit0)}\")"
    ]
   },
   {
diff --git a/examples/quantum_random_numbers.py b/examples/quantum_random_numbers.py
index afa09dc4f..34dc61acc 100755
--- a/examples/quantum_random_numbers.py
+++ b/examples/quantum_random_numbers.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 # pylint: skip-file
 
 """Example of a simple quantum random number generator."""
@@ -20,4 +19,4 @@
 
 eng.flush()
 # print the result:
-print("Measured: {}".format(int(q1)))
+print(f"Measured: {int(q1)}")
diff --git a/examples/quantum_random_numbers_ibm.py b/examples/quantum_random_numbers_ibm.py
index adfcb7101..2cbf35b93 100755
--- a/examples/quantum_random_numbers_ibm.py
+++ b/examples/quantum_random_numbers_ibm.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 # pylint: skip-file
 
 """Example of a simple quantum random number generator using IBM's API."""
@@ -22,4 +21,4 @@
 
 eng.flush()
 # print the result:
-print("Measured: {}".format(int(q1)))
+print(f"Measured: {int(q1)}")
diff --git a/examples/shor.py b/examples/shor.py
index 39dce16dc..76ef9fd57 100755
--- a/examples/shor.py
+++ b/examples/shor.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 # pylint: skip-file
 
 """Example implementation of Shor's algorithm."""
@@ -13,7 +12,6 @@
 except ImportError:
     from fractions import gcd
 
-from builtins import input
 
 import projectq.libs.math
 import projectq.setups.decompositions
@@ -75,12 +73,12 @@ def run_shor(eng, N, a, verbose=False):
             X | ctrl_qubit
 
         if verbose:
-            print("\033[95m{}\033[0m".format(measurements[k]), end="")
+            print(f"\033[95m{measurements[k]}\033[0m", end="")
             sys.stdout.flush()
 
     All(Measure) | x
     # turn the measured values into a number in [0,1)
-    y = sum([(measurements[2 * n - 1 - i] * 1.0 / (1 << (i + 1))) for i in range(2 * n)])
+    y = sum((measurements[2 * n - 1 - i] * 1.0 / (1 << (i + 1))) for i in range(2 * n))
 
     # continued fraction expansion to get denominator (the period?)
     r = Fraction(y).limit_denominator(N - 1).denominator
@@ -130,13 +128,13 @@ def high_level_gates(eng, cmd):
         end="",
     )
     N = int(input('\n\tNumber to factor: '))
-    print("\n\tFactoring N = {}: \033[0m".format(N), end="")
+    print(f"\n\tFactoring N = {N}: \033[0m", end="")
 
     # choose a base at random:
     a = int(random.random() * N)
     if not gcd(a, N) == 1:
         print("\n\n\t\033[92mOoops, we were lucky: Chose non relative prime" " by accident :)")
-        print("\tFactor: {}\033[0m".format(gcd(a, N)))
+        print(f"\tFactor: {gcd(a, N)}\033[0m")
     else:
         # run the quantum subroutine
         r = run_shor(eng, N, a, True)
@@ -150,8 +148,8 @@ def high_level_gates(eng, cmd):
         if (not f1 * f2 == N) and f1 * f2 > 1 and int(1.0 * N / (f1 * f2)) * f1 * f2 == N:
             f1, f2 = f1 * f2, int(N / (f1 * f2))
         if f1 * f2 == N and f1 > 1 and f2 > 1:
-            print("\n\n\t\033[92mFactors found :-) : {} * {} = {}\033[0m".format(f1, f2, N))
+            print(f"\n\n\t\033[92mFactors found :-) : {f1} * {f2} = {N}\033[0m")
         else:
-            print("\n\n\t\033[91mBad luck: Found {} and {}\033[0m".format(f1, f2))
+            print(f"\n\n\t\033[91mBad luck: Found {f1} and {f2}\033[0m")
 
         print(resource_counter)  # print resource usage
diff --git a/examples/simulator_tutorial.ipynb b/examples/simulator_tutorial.ipynb
index f95ac662b..437011ad8 100644
--- a/examples/simulator_tutorial.ipynb
+++ b/examples/simulator_tutorial.ipynb
@@ -301,14 +301,14 @@
     "\n",
     "# Amplitude will be 1 as Hadamard gate is not yet executed on the simulator backend\n",
     "# We forgot the eng.flush()!\n",
-    "print(\"Amplitude saved in amp_before: {}\".format(amp_before))\n",
+    "print(f\"Amplitude saved in amp_before: {amp_before}\")\n",
     "\n",
     "eng.flush() # Makes sure that all the gates are sent to the backend and executed\n",
     "\n",
     "amp_after = eng.backend.get_amplitude('00', qubit + qubit2)\n",
     "\n",
     "# Amplitude will be 1/sqrt(2) as Hadamard gate was executed on the simulator backend\n",
-    "print(\"Amplitude saved in amp_after: {}\".format(amp_after))\n",
+    "print(f\"Amplitude saved in amp_after: {amp_after}\")\n",
     "\n",
     "# To avoid triggering the warning of deallocating qubits which are in a superposition\n",
     "Measure | qubit\n",
@@ -363,11 +363,11 @@
     "prob00 = eng.backend.get_probability('00', qureg)\n",
     "prob_second_0 = eng.backend.get_probability('0', [qureg[1]])\n",
     "\n",
-    "print(\"Probability to measure 11: {}\".format(prob11))\n",
-    "print(\"Probability to measure 00: {}\".format(prob00))\n",
-    "print(\"Probability to measure 01: {}\".format(prob01))\n",
-    "print(\"Probability to measure 10: {}\".format(prob10))\n",
-    "print(\"Probability that second qubit is in state 0: {}\".format(prob_second_0))\n",
+    "print(f\"Probability to measure 11: {prob11}\")\n",
+    "print(f\"Probability to measure 00: {prob00}\")\n",
+    "print(f\"Probability to measure 01: {prob01}\")\n",
+    "print(f\"Probability to measure 10: {prob10}\")\n",
+    "print(f\"Probability that second qubit is in state 0: {prob_second_0}\")\n",
     "\n",
     "All(Measure) | qureg"
    ]
@@ -406,11 +406,11 @@
     "eng.flush()\n",
     "op0 = QubitOperator('Z0') # Z applied to qureg[0] tensor identity on qureg[1], qureg[2]\n",
     "expectation = eng.backend.get_expectation_value(op0, qureg)\n",
-    "print(\"Expectation value = <Psi|Z0|Psi> = {}\".format(expectation))\n",
+    "print(f\"Expectation value = <Psi|Z0|Psi> = {expectation}\")\n",
     "\n",
     "op_sum = QubitOperator('Z0 X1') - 0.5 * QubitOperator('X1')\n",
     "expectation2 = eng.backend.get_expectation_value(op_sum, qureg)\n",
-    "print(\"Expectation value = <Psi|-0.5 X1 + 1.0 Z0 X1|Psi> = {}\".format(expectation2))\n",
+    "print(f\"Expectation value = <Psi|-0.5 X1 + 1.0 Z0 X1|Psi> = {expectation2}\")\n",
     "\n",
     "All(Measure) | qureg # To avoid error message of deallocating qubits in a superposition"
    ]
@@ -452,7 +452,7 @@
     "Measure | qureg[1]\n",
     "eng.flush() # required such that all above gates are executed before accessing the measurement result\n",
     "\n",
-    "print(\"First qubit measured in state: {} and second qubit in state: {}\".format(int(qureg[0]), int(qureg[1])))"
+    "print(f\"First qubit measured in state: {int(qureg[0])} and second qubit in state: {int(qureg[1])}\")"
    ]
   },
   {
@@ -496,7 +496,7 @@
     "prob_0 = eng.backend.get_probability('0', [qureg[1]])\n",
     "\n",
     "print(\"After forcing a measurement outcome of the first qubit to be 0, \\n\"\n",
-    "      \"the second qubit is in state 0 with probability: {}\".format(prob_0))"
+    "      f\"the second qubit is in state 0 with probability: {prob_0}\")"
    ]
   },
   {
@@ -573,18 +573,18 @@
     "# also if the Python simulator is used, one should make a deepcopy:\n",
     "mapping, wavefunction = copy.deepcopy(eng.backend.cheat())\n",
     "\n",
-    "print(\"The full wavefunction is: {}\".format(wavefunction))\n",
+    "print(f\"The full wavefunction is: {wavefunction}\")\n",
     "# Note: qubit1 is a qureg of length 1, i.e. a list containing one qubit objects, therefore the\n",
     "#       unique qubit id can be accessed via qubit1[0].id\n",
-    "print(\"qubit1 has bit-location {}\".format(mapping[qubit1[0].id]))\n",
-    "print(\"qubit2 has bit-location {}\".format(mapping[qubit2[0].id]))\n",
+    "print(f\"qubit1 has bit-location {mapping[qubit1[0].id]}\")\n",
+    "print(f\"qubit2 has bit-location {mapping[qubit2[0].id]}\")\n",
     "\n",
     "# Suppose we want to know the amplitude of the qubit1 in state 0 and qubit2 in state 1:\n",
     "state = 0 + (1 << mapping[qubit2[0].id])\n",
-    "print(\"Amplitude of state qubit1 in state 0 and qubit2 in state 1: {}\".format(wavefunction[state]))\n",
+    "print(f\"Amplitude of state qubit1 in state 0 and qubit2 in state 1: {wavefunction[state]}\")\n",
     "# If one only wants to access one (or a few) amplitudes, get_amplitude provides an easier interface:\n",
     "amplitude  = eng.backend.get_amplitude('01', qubit1 + qubit2)\n",
-    "print(\"Accessing same amplitude but using get_amplitude instead: {}\".format(amplitude))\n",
+    "print(f\"Accessing same amplitude but using get_amplitude instead: {amplitude}\")\n",
     "\n",
     "All(Measure) | qubit1 + qubit2 # In order to not deallocate a qubit in a superposition state"
    ]
diff --git a/examples/spectral_measurement.ipynb b/examples/spectral_measurement.ipynb
index 0c791ecc0..825d2c7a5 100644
--- a/examples/spectral_measurement.ipynb
+++ b/examples/spectral_measurement.ipynb
@@ -334,7 +334,7 @@
     }
    ],
    "source": [
-    "print(\"We measured {} corresponding to energy {}\".format(est_phase, math.cos(2*math.pi*est_phase)))"
+    "print(f\"We measured {est_phase} corresponding to energy {math.cos(2*math.pi*est_phase)}\")"
    ]
   },
   {
diff --git a/examples/teleport.py b/examples/teleport.py
index 4d2e684aa..e662aef49 100755
--- a/examples/teleport.py
+++ b/examples/teleport.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 # pylint: skip-file
 
 """Example of a quantum teleportation circuit."""
@@ -65,7 +64,7 @@ def run_teleport(eng, state_creation_function, verbose=False):
     Measure | b1
     msg_to_bob = [int(psi), int(b1)]
     if verbose:
-        print("Alice is sending the message {} to Bob.".format(msg_to_bob))
+        print(f"Alice is sending the message {msg_to_bob} to Bob.")
 
     # Bob may have to apply up to two operation depending on the message sent
     # by Alice:
diff --git a/examples/teleport_circuit.py b/examples/teleport_circuit.py
index 1dfd3a485..f626f595e 100755
--- a/examples/teleport_circuit.py
+++ b/examples/teleport_circuit.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 # pylint: skip-file
 
 """Example if drawing of a quantum teleportation circuit."""
diff --git a/examples/unitary_simulator.py b/examples/unitary_simulator.py
index d2fd4ecdf..d91b0ede9 100644
--- a/examples/unitary_simulator.py
+++ b/examples/unitary_simulator.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/__init__.py b/projectq/__init__.py
index d09243a4a..2da4bc1f8 100755
--- a/projectq/__init__.py
+++ b/projectq/__init__.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/backends/__init__.py b/projectq/backends/__init__.py
index 8a8a50646..0b72a8b71 100755
--- a/projectq/backends/__init__.py
+++ b/projectq/backends/__init__.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/backends/_aqt/__init__.py b/projectq/backends/_aqt/__init__.py
index 7c5dcb45e..d971c1b35 100644
--- a/projectq/backends/_aqt/__init__.py
+++ b/projectq/backends/_aqt/__init__.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2020 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/backends/_aqt/_aqt.py b/projectq/backends/_aqt/_aqt.py
index 709a97bb8..48942b475 100644
--- a/projectq/backends/_aqt/_aqt.py
+++ b/projectq/backends/_aqt/_aqt.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2020, 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -167,7 +166,7 @@ def _store(self, cmd):
             return
         if gate == Barrier:
             return
-        raise InvalidCommandError('Invalid command: ' + str(cmd))
+        raise InvalidCommandError(f"Invalid command: {str(cmd)}")
 
     def _logical_to_physical(self, qb_id):
         """
@@ -182,17 +181,15 @@ def _logical_to_physical(self, qb_id):
             mapping = self.main_engine.mapper.current_mapping
             if qb_id not in mapping:
                 raise RuntimeError(
-                    "Unknown qubit id {}. Please make sure "
-                    "eng.flush() was called and that the qubit "
-                    "was eliminated during optimization.".format(qb_id)
+                    f"Unknown qubit id {qb_id}. "
+                    "Please make sure eng.flush() was called and that the qubit was eliminated during optimization."
                 )
             return mapping[qb_id]
         except AttributeError as err:
             if qb_id not in self._mapper:
                 raise RuntimeError(
-                    "Unknown qubit id {}. Please make sure "
-                    "eng.flush() was called and that the qubit "
-                    "was eliminated during optimization.".format(qb_id)
+                    f"Unknown qubit id {qb_id}. Please make sure eng.flush() was called and that the qubit was "
+                    "eliminated during optimization."
                 ) from err
             return qb_id
 
@@ -288,7 +285,7 @@ def _run(self):
                     star = "*"
                 self._probabilities[state] = probability
                 if self._verbose and probability > 0:
-                    print(str(state) + " with p = " + str(probability) + star)
+                    print(f"{str(state)} with p = {probability}{star}")
 
             # register measurement result from AQT
             for qubit_id in self._measured_ids:
diff --git a/projectq/backends/_aqt/_aqt_http_client.py b/projectq/backends/_aqt/_aqt_http_client.py
index 7f869d254..ac1a5094c 100644
--- a/projectq/backends/_aqt/_aqt_http_client.py
+++ b/projectq/backends/_aqt/_aqt_http_client.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2020, 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -126,12 +125,12 @@ def get_result(  # pylint: disable=too-many-arguments
     ):
         """Get the result of an execution."""
         if verbose:
-            print("Waiting for results. [Job ID: {}]".format(execution_id))
+            print(f"Waiting for results. [Job ID: {execution_id}]")
 
         original_sigint_handler = signal.getsignal(signal.SIGINT)
 
         def _handle_sigint_during_get_result(*_):  # pragma: no cover
-            raise Exception("Interrupted. The ID of your submitted job is {}.".format(execution_id))
+            raise Exception(f"Interrupted. The ID of your submitted job is {execution_id}.")
 
         try:
             signal.signal(signal.SIGINT, _handle_sigint_during_get_result)
@@ -145,7 +144,7 @@ def _handle_sigint_during_get_result(*_):  # pragma: no cover
                 if r_json['status'] == 'finished' or 'samples' in r_json:
                     return r_json['samples']
                 if r_json['status'] != 'running':
-                    raise Exception("Error while running the code: {}.".format(r_json['status']))
+                    raise Exception(f"Error while running the code: {r_json['status']}.")
                 time.sleep(interval)
                 if self.is_online(device) and retries % 60 == 0:
                     self.update_devices_list()
@@ -154,14 +153,14 @@ def _handle_sigint_during_get_result(*_):  # pragma: no cover
                     #       available
                     if not self.is_online(device):  # pragma: no cover
                         raise DeviceOfflineError(
-                            "Device went offline. The ID of your submitted job is {}.".format(execution_id)
+                            f"Device went offline. The ID of your submitted job is {execution_id}."
                         )
 
         finally:
             if original_sigint_handler is not None:
                 signal.signal(signal.SIGINT, original_sigint_handler)
 
-        raise RequestTimeoutError("Timeout. The ID of your submitted job is {}.".format(execution_id))
+        raise RequestTimeoutError(f"Timeout. The ID of your submitted job is {execution_id}.")
 
 
 def show_devices(verbose=False):
@@ -226,7 +225,7 @@ def send(
         if verbose:
             print("- Authenticating...")
         if token is not None:
-            print('user API token: ' + token)
+            print(f"user API token: {token}")
         aqt_session.authenticate(token)
 
         # check if the device is online
@@ -241,13 +240,12 @@ def send(
         runnable, qmax, qneeded = aqt_session.can_run_experiment(info, device)
         if not runnable:
             print(
-                "The device is too small ({} qubits available) for the code "
-                "requested({} qubits needed). Try to look for another device "
-                "with more qubits".format(qmax, qneeded)
+                f"The device is too small ({qmax} qubits available) for the code requested({qneeded} qubits needed).",
+                "Try to look for another device with more qubits",
             )
             raise DeviceTooSmall("Device is too small.")
         if verbose:
-            print("- Running code: {}".format(info))
+            print(f"- Running code: {info}")
         execution_id = aqt_session.run(info, device)
         if verbose:
             print("- Waiting for results...")
diff --git a/projectq/backends/_aqt/_aqt_http_client_test.py b/projectq/backends/_aqt/_aqt_http_client_test.py
index 64e50fee2..1159bc02b 100644
--- a/projectq/backends/_aqt/_aqt_http_client_test.py
+++ b/projectq/backends/_aqt/_aqt_http_client_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2020, 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/backends/_aqt/_aqt_test.py b/projectq/backends/_aqt/_aqt_test.py
index 397f6ffd9..d35bcaf6a 100644
--- a/projectq/backends/_aqt/_aqt_test.py
+++ b/projectq/backends/_aqt/_aqt_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2020, 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/backends/_awsbraket/__init__.py b/projectq/backends/_awsbraket/__init__.py
index 2d01597e0..7e2ed0f91 100644
--- a/projectq/backends/_awsbraket/__init__.py
+++ b/projectq/backends/_awsbraket/__init__.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/backends/_awsbraket/_awsbraket.py b/projectq/backends/_awsbraket/_awsbraket.py
index de7c82ecc..56f1a4be6 100755
--- a/projectq/backends/_awsbraket/_awsbraket.py
+++ b/projectq/backends/_awsbraket/_awsbraket.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -299,13 +298,13 @@ def _store(self, cmd):  # pylint: disable=too-many-branches
             json_cmd['angle'] = gate.angle
 
         if isinstance(gate, DaggeredGate):
-            json_cmd['type'] = 'c' * num_controls + self._gationary[gate_type] + 'i'
+            json_cmd['type'] = f"{'c' * num_controls + self._gationary[gate_type]}i"
         elif isinstance(gate, (XGate)) and num_controls > 0:
-            json_cmd['type'] = 'c' * (num_controls - 1) + 'cnot'
+            json_cmd['type'] = f"{'c' * (num_controls - 1)}cnot"
         else:
             json_cmd['type'] = 'c' * num_controls + self._gationary[gate_type]
 
-        self._circuit += json.dumps(json_cmd) + ", "
+        self._circuit += f"{json.dumps(json_cmd)}, "
 
         # TODO: Add unitary for the SV1 simulator as MatrixGate
 
@@ -320,10 +319,8 @@ def _logical_to_physical(self, qb_id):
             mapping = self.main_engine.mapper.current_mapping
             if qb_id not in mapping:
                 raise RuntimeError(
-                    (
-                        "Unknown qubit id {} in current mapping. Please make sure eng.flush() was called and that the"
-                        "qubit was eliminated during optimization."
-                    ).format(qb_id)
+                    f"Unknown qubit id {qb_id} in current mapping. "
+                    "Please make sure eng.flush() was called and that the qubit was eliminated during optimization."
                 )
             return mapping[qb_id]
         return qb_id
@@ -367,7 +364,7 @@ def get_probabilities(self, qureg):
             mapped_state = ['0'] * len(qureg)
             for i, qubit in enumerate(qureg):
                 if self._logical_to_physical(qubit.id) >= len(state):  # pragma: no cover
-                    raise IndexError('Physical ID {} > length of internal probabilities array'.format(qubit.id))
+                    raise IndexError(f'Physical ID {qubit.id} > length of internal probabilities array')
                 mapped_state[i] = state[self._logical_to_physical(qubit.id)]
             mapped_state = "".join(mapped_state)
             if mapped_state not in probability_dict:
@@ -437,7 +434,7 @@ def _run(self):
                 star = "*"
             self._probabilities[state] = probability
             if self._verbose and probability > 0:
-                print(state + " with p = " + str(probability) + star)
+                print(f"{state} with p = {probability}{star}")
 
         # register measurement result
         for qubit_id in self._measured_ids:
diff --git a/projectq/backends/_awsbraket/_awsbraket_boto3_client.py b/projectq/backends/_awsbraket/_awsbraket_boto3_client.py
index 39ad3b265..bc7d531a4 100755
--- a/projectq/backends/_awsbraket/_awsbraket_boto3_client.py
+++ b/projectq/backends/_awsbraket/_awsbraket_boto3_client.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -218,12 +217,12 @@ def run(self, info, device):
     def get_result(self, execution_id, num_retries=30, interval=1, verbose=False):  # pylint: disable=too-many-locals
         """Get the result of an execution."""
         if verbose:
-            print("Waiting for results. [Job Arn: {}]".format(execution_id))
+            print(f"Waiting for results. [Job Arn: {execution_id}]")
 
         original_sigint_handler = signal.getsignal(signal.SIGINT)
 
         def _handle_sigint_during_get_result(*_):  # pragma: no cover
-            raise Exception("Interrupted. The Arn of your submitted job is {}.".format(execution_id))
+            raise Exception(f"Interrupted. The Arn of your submitted job is {execution_id}.")
 
         def _calculate_measurement_probs(measurements):
             """
@@ -269,7 +268,7 @@ def _calculate_measurement_probs(measurements):
                 status = quantum_task['status']
                 bucket = quantum_task['outputS3Bucket']
                 directory = quantum_task['outputS3Directory']
-                resultsojectname = directory + '/results.json'
+                resultsojectname = f"{directory}/results.json"
                 if status == 'COMPLETED':
                     # Get the device type to obtian the correct measurement
                     # structure
@@ -282,7 +281,7 @@ def _calculate_measurement_probs(measurements):
                     )
                     s3result = client_s3.get_object(Bucket=bucket, Key=resultsojectname)
                     if verbose:
-                        print("Results obtained. [Status: {}]".format(status))
+                        print(f"Results obtained. [Status: {status}]")
                     result_content = json.loads(s3result['Body'].read())
 
                     if devicetype_used == 'QPU':
@@ -291,11 +290,11 @@ def _calculate_measurement_probs(measurements):
                         return _calculate_measurement_probs(result_content['measurements'])
                 if status == 'FAILED':
                     raise Exception(
-                        "Error while running the code: {}. "
-                        "The failure reason was: {}.".format(status, quantum_task['failureReason'])
+                        f'Error while running the code: {status}. '
+                        f'The failure reason was: {quantum_task["failureReason"]}.'
                     )
                 if status == 'CANCELLING':
-                    raise Exception("The job received a CANCEL operation: {}.".format(status))
+                    raise Exception(f"The job received a CANCEL operation: {status}.")
                 time.sleep(interval)
                 # NOTE: Be aware that AWS is billing if a lot of API calls are
                 # executed, therefore the num_repetitions is set to a small
@@ -311,9 +310,7 @@ def _calculate_measurement_probs(measurements):
                 signal.signal(signal.SIGINT, original_sigint_handler)
 
         raise RequestTimeoutError(
-            "Timeout. "
-            "The Arn of your submitted job is {} and the status "
-            "of the job is {}.".format(execution_id, status)
+            f"Timeout. The Arn of your submitted job is {execution_id} and the status of the job is {status}."
         )
 
 
@@ -352,7 +349,7 @@ def retrieve(credentials, task_arn, num_retries=30, interval=1, verbose=False):
         if verbose:
             print("- Authenticating...")
             if credentials is not None:
-                print("AWS credentials: " + credentials['AWS_ACCESS_KEY_ID'] + ", " + credentials['AWS_SECRET_KEY'])
+                print(f"AWS credentials: {credentials['AWS_ACCESS_KEY_ID']}, {credentials['AWS_SECRET_KEY']}")
         awsbraket_session.authenticate(credentials=credentials)
         res = awsbraket_session.get_result(task_arn, num_retries=num_retries, interval=interval, verbose=verbose)
         return res
@@ -386,7 +383,7 @@ def send(  # pylint: disable=too-many-branches,too-many-arguments,too-many-local
         if verbose:
             print("- Authenticating...")
             if credentials is not None:
-                print("AWS credentials: " + credentials['AWS_ACCESS_KEY_ID'] + ", " + credentials['AWS_SECRET_KEY'])
+                print(f"AWS credentials: {credentials['AWS_ACCESS_KEY_ID']}, {credentials['AWS_SECRET_KEY']}")
         awsbraket_session.authenticate(credentials=credentials)
         awsbraket_session.get_s3_folder(s3_folder=s3_folder)
 
@@ -403,17 +400,14 @@ def send(  # pylint: disable=too-many-branches,too-many-arguments,too-many-local
         runnable, qmax, qneeded = awsbraket_session.can_run_experiment(info, device)
         if not runnable:
             print(
-                (
-                    "The device is too small ({} qubits available) for the code "
-                    + "requested({} qubits needed) Try to look for another "
-                    + "device with more qubits"
-                ).format(qmax, qneeded)
+                f"The device is too small ({qmax} qubits available) for the code",
+                f"requested({qneeded} qubits needed). Try to look for another device with more qubits",
             )
             raise DeviceTooSmall("Device is too small.")
         if verbose:
-            print("- Running code: {}".format(info))
+            print(f"- Running code: {info}")
         task_arn = awsbraket_session.run(info, device)
-        print("Your task Arn is: {}. Make note of that for future reference".format(task_arn))
+        print(f"Your task Arn is: {task_arn}. Make note of that for future reference")
 
         if verbose:
             print("- Waiting for results...")
diff --git a/projectq/backends/_awsbraket/_awsbraket_boto3_client_test.py b/projectq/backends/_awsbraket/_awsbraket_boto3_client_test.py
index 795d9e308..93cc994de 100644
--- a/projectq/backends/_awsbraket/_awsbraket_boto3_client_test.py
+++ b/projectq/backends/_awsbraket/_awsbraket_boto3_client_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -262,7 +261,7 @@ def test_send_that_errors_are_caught(mocker, var_error, send_that_error_setup):
     mock_boto3_client.search_devices.return_value = search_value
     mock_boto3_client.get_device.return_value = device_value
     mock_boto3_client.create_quantum_task.side_effect = botocore.exceptions.ClientError(
-        {"Error": {"Code": var_error, "Message": "Msg error for " + var_error}},
+        {"Error": {"Code": var_error, "Message": f"Msg error for {var_error}"}},
         "create_quantum_task",
     )
     mocker.patch('boto3.client', return_value=mock_boto3_client, autospec=True)
@@ -289,7 +288,7 @@ def test_retrieve_error_arn_not_exist(mocker, var_error, arntask, creds):
 
     mock_boto3_client = mocker.MagicMock(spec=['get_quantum_task'])
     mock_boto3_client.get_quantum_task.side_effect = botocore.exceptions.ClientError(
-        {"Error": {"Code": var_error, "Message": "Msg error for " + var_error}},
+        {"Error": {"Code": var_error, "Message": f"Msg error for {var_error}"}},
         "get_quantum_task",
     )
     mocker.patch('boto3.client', return_value=mock_boto3_client, autospec=True)
diff --git a/projectq/backends/_awsbraket/_awsbraket_boto3_client_test_fixtures.py b/projectq/backends/_awsbraket/_awsbraket_boto3_client_test_fixtures.py
index 0fa5cb2b9..ba38906b3 100644
--- a/projectq/backends/_awsbraket/_awsbraket_boto3_client_test_fixtures.py
+++ b/projectq/backends/_awsbraket/_awsbraket_boto3_client_test_fixtures.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/backends/_awsbraket/_awsbraket_test.py b/projectq/backends/_awsbraket/_awsbraket_test.py
index 22205a2f1..1a5288c88 100644
--- a/projectq/backends/_awsbraket/_awsbraket_test.py
+++ b/projectq/backends/_awsbraket/_awsbraket_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -319,6 +318,7 @@ def test_awsbraket_backend_is_available_control_singlequbit_sv1(ctrl_singlequbit
     assert aws_backend.is_available(cmd) == is_available_sv1
 
 
+@has_boto3
 def test_awsbraket_backend_is_available_negative_control():
     backend = _awsbraket.AWSBraketBackend()
 
@@ -426,7 +426,7 @@ def test_awsbraket_sent_error(mocker, sent_error_setup):
     mock_boto3_client.search_devices.return_value = search_value
     mock_boto3_client.get_device.return_value = device_value
     mock_boto3_client.create_quantum_task.side_effect = botocore.exceptions.ClientError(
-        {"Error": {"Code": var_error, "Message": "Msg error for " + var_error}},
+        {"Error": {"Code": var_error, "Message": f"Msg error for {var_error}"}},
         "create_quantum_task",
     )
     mocker.patch('boto3.client', return_value=mock_boto3_client, autospec=True)
diff --git a/projectq/backends/_awsbraket/_awsbraket_test_fixtures.py b/projectq/backends/_awsbraket/_awsbraket_test_fixtures.py
index 71968697d..7ee1dd7b9 100644
--- a/projectq/backends/_awsbraket/_awsbraket_test_fixtures.py
+++ b/projectq/backends/_awsbraket/_awsbraket_test_fixtures.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/backends/_circuits/__init__.py b/projectq/backends/_circuits/__init__.py
index 638ddfbbc..eaf0abb56 100755
--- a/projectq/backends/_circuits/__init__.py
+++ b/projectq/backends/_circuits/__init__.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/backends/_circuits/_drawer.py b/projectq/backends/_circuits/_drawer.py
index 7d67f6190..071ad2cea 100755
--- a/projectq/backends/_circuits/_drawer.py
+++ b/projectq/backends/_circuits/_drawer.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017, 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +14,6 @@
 
 """Contain a compiler engine which generates TikZ Latex code describing the circuit."""
 
-from builtins import input
 
 from projectq.cengines import BasicEngine, LastEngineException
 from projectq.meta import get_control_count
@@ -64,65 +62,66 @@ class CircuitDrawer(BasicEngine):
     .. code-block:: python
 
         circuit_backend = CircuitDrawer()
-        circuit_backend.set_qubit_locations({0: 1, 1: 0}) # swap lines 0 and 1
+        circuit_backend.set_qubit_locations({0: 1, 1: 0})  # swap lines 0 and 1
         eng = MainEngine(circuit_backend)
 
-        ... # run quantum algorithm on this main engine
+        ...  # run quantum algorithm on this main engine
 
-        print(circuit_backend.get_latex()) # prints LaTeX code
+        print(circuit_backend.get_latex())  # prints LaTeX code
 
     To see the qubit IDs in the generated circuit, simply set the `draw_id` option in the settings.json file under
     "gates":"AllocateQubitGate" to True:
 
     .. code-block:: python
 
-        "gates": {
-            "AllocateQubitGate": {
-                "draw_id": True,
-                "height": 0.15,
-                "width": 0.2,
-                "pre_offset": 0.1,
-                "offset": 0.1
-            },
-            ...
+        {
+            "gates": {
+                "AllocateQubitGate": {
+                    "draw_id": True,
+                    "height": 0.15,
+                    "width": 0.2,
+                    "pre_offset": 0.1,
+                    "offset": 0.1,
+                },
+                # ...
+            }
+        }
 
     The settings.json file has the following structure:
 
     .. code-block:: python
 
         {
-            "control": { # settings for control "circle"
-                    "shadow": false,
-                    "size": 0.1
-            },
-            "gate_shadow": true, # enable/disable shadows for all gates
+            "control": {"shadow": false, "size": 0.1},  # settings for control "circle"
+            "gate_shadow": true,  # enable/disable shadows for all gates
             "gates": {
-                    "GateClassString": {
-                        GATE_PROPERTIES
-                    }
-                    "GateClassString2": {
-                        ...
+                "GateClassString": {GATE_PROPERTIES},
+                "GateClassString2": {
+                    # ...
+                },
+            },
+            "lines": {  # settings for qubit lines
+                "double_classical": true,  # draw double-lines for
+                # classical bits
+                "double_lines_sep": 0.04,  # gap between the two lines
+                # for double lines
+                "init_quantum": true,  # start out with quantum bits
+                "style": "very thin",  # line style
             },
-            "lines": { # settings for qubit lines
-                    "double_classical": true, # draw double-lines for
-                                              # classical bits
-                    "double_lines_sep": 0.04, # gap between the two lines
-                                              # for double lines
-                    "init_quantum": true, # start out with quantum bits
-                    "style": "very thin" # line style
-            }
         }
 
     All gates (except for the ones requiring special treatment) support the following properties:
 
     .. code-block:: python
 
-        "GateClassString": {
-            "height": GATE_HEIGHT,
-            "width": GATE_WIDTH
-            "pre_offset": OFFSET_BEFORE_PLACEMENT,
-            "offset": OFFSET_AFTER_PLACEMENT,
-        },
+        {
+            "GateClassString": {
+                "height": GATE_HEIGHT,
+                "width": GATE_WIDTH,
+                "pre_offset": OFFSET_BEFORE_PLACEMENT,
+                "offset": OFFSET_AFTER_PLACEMENT,
+            }
+        }
 
     """
 
@@ -228,7 +227,7 @@ def _print_cmd(self, cmd):
                     if self._accept_input:
                         meas = None
                         while meas not in ('0', '1', 1, 0):
-                            prompt = "Input measurement result (0 or 1) for qubit " + str(qubit) + ": "
+                            prompt = f"Input measurement result (0 or 1) for qubit {str(qubit)}: "
                             meas = input(prompt)
                     else:
                         meas = self._default_measure
diff --git a/projectq/backends/_circuits/_drawer_matplotlib.py b/projectq/backends/_circuits/_drawer_matplotlib.py
index 6098ebfde..7c6b58555 100644
--- a/projectq/backends/_circuits/_drawer_matplotlib.py
+++ b/projectq/backends/_circuits/_drawer_matplotlib.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2020 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +16,6 @@
 
 import itertools
 import re
-from builtins import input
 
 from projectq.cengines import BasicEngine, LastEngineException
 from projectq.meta import get_control_count
@@ -37,14 +35,14 @@ def _format_gate_str(cmd):
         params_str_list = []
         for param in params:
             try:
-                params_str_list.append('{0:.2f}'.format(float(param)))
+                params_str_list.append(f'{float(param):.2f}')
             except ValueError:
                 if len(param) < 8:
                     params_str_list.append(param)
                 else:
-                    params_str_list.append(param[:5] + '...')
+                    params_str_list.append(f"{param[:5]}...")
 
-        gate_name += '(' + ','.join(params_str_list) + ')'
+        gate_name += f"({','.join(params_str_list)})"
     return gate_name
 
 
@@ -120,7 +118,7 @@ def _process(self, cmd):  # pylint: disable=too-many-branches
                     if self._accept_input:
                         measurement = None
                         while measurement not in ('0', '1', 1, 0):
-                            prompt = "Input measurement result (0 or 1) for qubit {}: ".format(qubit)
+                            prompt = f"Input measurement result (0 or 1) for qubit {qubit}: "
                             measurement = input(prompt)
                     else:
                         measurement = self._default_measure
diff --git a/projectq/backends/_circuits/_drawer_matplotlib_test.py b/projectq/backends/_circuits/_drawer_matplotlib_test.py
index 885d835fa..9744599a4 100644
--- a/projectq/backends/_circuits/_drawer_matplotlib_test.py
+++ b/projectq/backends/_circuits/_drawer_matplotlib_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2020 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,6 +26,22 @@
 from ._drawer_matplotlib import CircuitDrawerMatplotlib
 
 
+class MockInputFunction:
+    def __init__(self, return_value=None):
+        self.return_value = return_value
+        self._orig_input_fn = __builtins__['input']
+
+    def _mock_input_fn(self, prompt):
+        print(prompt + str(self.return_value))
+        return self.return_value
+
+    def __enter__(self):
+        __builtins__['input'] = self._mock_input_fn
+
+    def __exit__(self, type, value, traceback):
+        __builtins__['input'] = self._orig_input_fn
+
+
 def test_drawer_measurement():
     drawer = CircuitDrawerMatplotlib(default_measure=0)
     eng = MainEngine(drawer, [])
@@ -44,12 +59,9 @@ def test_drawer_measurement():
     eng = MainEngine(drawer, [])
     qubit = eng.allocate_qubit()
 
-    old_input = _drawer.input
-
-    _drawer.input = lambda x: '1'
-    Measure | qubit
-    assert int(qubit) == 1
-    _drawer.input = old_input
+    with MockInputFunction(return_value='1'):
+        Measure | qubit
+        assert int(qubit) == 1
 
     qb1 = WeakQubitRef(engine=eng, idx=1)
     qb2 = WeakQubitRef(engine=eng, idx=2)
@@ -57,7 +69,7 @@ def test_drawer_measurement():
         eng.backend._process(Command(engine=eng, gate=Measure, qubits=([qb1],), controls=[qb2]))
 
 
-class MockEngine(object):
+class MockEngine:
     def is_available(self, cmd):
         self.cmd = cmd
         self.called = True
@@ -112,10 +124,10 @@ def __init__(self, *args):
         self.params = args
 
     def __str__(self):
-        param_str = '{}'.format(self.params[0])
+        param_str = f'{self.params[0]}'
         for param in self.params[1:]:
-            param_str += ',{}'.format(param)
-        return str(self.__class__.__name__) + "(" + param_str + ")"
+            param_str += f',{param}'
+        return f"{str(self.__class__.__name__)}({param_str})"
 
 
 def test_drawer_draw():
diff --git a/projectq/backends/_circuits/_drawer_test.py b/projectq/backends/_circuits/_drawer_test.py
index d9b94b42c..cec9488a0 100755
--- a/projectq/backends/_circuits/_drawer_test.py
+++ b/projectq/backends/_circuits/_drawer_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017, 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -25,6 +24,22 @@
 from projectq.types import WeakQubitRef
 
 
+class MockInputFunction:
+    def __init__(self, return_value=None):
+        self.return_value = return_value
+        self._orig_input_fn = __builtins__['input']
+
+    def _mock_input_fn(self, prompt):
+        print(prompt + str(self.return_value))
+        return self.return_value
+
+    def __enter__(self):
+        __builtins__['input'] = self._mock_input_fn
+
+    def __exit__(self, type, value, traceback):
+        __builtins__['input'] = self._orig_input_fn
+
+
 @pytest.mark.parametrize("ordered", [False, True])
 def test_drawer_getlatex(ordered):
     old_latex = _drawer.to_latex
@@ -73,12 +88,9 @@ def test_drawer_measurement():
     eng = MainEngine(drawer, [])
     qubit = eng.allocate_qubit()
 
-    old_input = _drawer.input
-
-    _drawer.input = lambda x: '1'
-    Measure | qubit
-    assert int(qubit) == 1
-    _drawer.input = old_input
+    with MockInputFunction(return_value='1'):
+        Measure | qubit
+        assert int(qubit) == 1
 
     qb1 = WeakQubitRef(engine=eng, idx=1)
     qb2 = WeakQubitRef(engine=eng, idx=2)
@@ -108,7 +120,7 @@ def test_drawer_qubitmapping():
         drawer.set_qubit_locations({0: 1, 1: 0})
 
 
-class MockEngine(object):
+class MockEngine:
     def is_available(self, cmd):
         self.cmd = cmd
         self.called = True
diff --git a/projectq/backends/_circuits/_plot.py b/projectq/backends/_circuits/_plot.py
index 7be85711d..b450309f4 100644
--- a/projectq/backends/_circuits/_plot.py
+++ b/projectq/backends/_circuits/_plot.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -109,11 +108,9 @@ def to_draw(qubit_lines, qubit_labels=None, drawing_order=None, **kwargs):
         drawing_order = {qubit_id: n_qubits - qubit_id - 1 for qubit_id in list(qubit_lines)}
     else:
         if set(drawing_order) != set(qubit_lines):
-            raise RuntimeError('Qubit IDs in drawing_order do not match ' + 'qubit IDs in qubit_lines!')
+            raise RuntimeError("Qubit IDs in drawing_order do not match qubit IDs in qubit_lines!")
         if set(drawing_order.values()) != set(range(len(drawing_order))):
-            raise RuntimeError(
-                'Indices of qubit wires in drawing_order must be between 0 and {}!'.format(len(drawing_order))
-            )
+            raise RuntimeError(f'Indices of qubit wires in drawing_order must be between 0 and {len(drawing_order)}!')
 
     plot_params = deepcopy(_DEFAULT_PLOT_PARAMS)
     plot_params.update(kwargs)
@@ -357,8 +354,7 @@ def draw_gate(
         else:
             if sorted(targets_order) != list(range(min(targets_order), max(targets_order) + 1)):
                 raise RuntimeError(
-                    'Multi-qubit gate with non-neighbouring qubits!\n'
-                    + 'Gate: {} on wires {}'.format(gate_str, targets_order)
+                    f"Multi-qubit gate with non-neighbouring qubits!\nGate: {gate_str} on wires {targets_order}"
                 )
 
             multi_qubit_gate(
diff --git a/projectq/backends/_circuits/_plot_test.py b/projectq/backends/_circuits/_plot_test.py
index d5f3f4f64..3e81d23d1 100644
--- a/projectq/backends/_circuits/_plot_test.py
+++ b/projectq/backends/_circuits/_plot_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -29,7 +28,7 @@
 # ==============================================================================
 
 
-class PseudoCanvas(object):
+class PseudoCanvas:
     def __init__(self):
         pass
 
@@ -40,19 +39,19 @@ def get_renderer(self):
         return
 
 
-class PseudoFigure(object):
+class PseudoFigure:
     def __init__(self):
         self.canvas = PseudoCanvas()
         self.dpi = 1
 
 
-class PseudoBBox(object):
+class PseudoBBox:
     def __init__(self, width, height):
         self.width = width
         self.height = height
 
 
-class PseudoText(object):
+class PseudoText:
     def __init__(self, text):
         self.text = text
         self.figure = PseudoFigure()
@@ -64,7 +63,7 @@ def remove(self):
         pass
 
 
-class PseudoTransform(object):
+class PseudoTransform:
     def __init__(self):
         pass
 
@@ -75,7 +74,7 @@ def transform_bbox(self, bbox):
         return bbox
 
 
-class PseudoAxes(object):
+class PseudoAxes:
     def __init__(self):
         self.figure = PseudoFigure()
         self.transData = PseudoTransform()
diff --git a/projectq/backends/_circuits/_to_latex.py b/projectq/backends/_circuits/_to_latex.py
index ae3f05cd5..45499526a 100755
--- a/projectq/backends/_circuits/_to_latex.py
+++ b/projectq/backends/_circuits/_to_latex.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017, 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -62,7 +61,7 @@ def to_latex(circuit, drawing_order=None, draw_gates_in_parallel=True):
     Example:
         .. code-block:: python
 
-            settings['gates']['HGate'] = {'width': .5, 'offset': .15}
+            settings['gates']['HGate'] = {'width': 0.5, 'offset': 0.15}
 
     The default settings can be acquired using the get_default_settings() function, and written using write_settings().
 
@@ -182,27 +181,21 @@ def _header(settings):
     gate_style += "]\n"
 
     gate_style += (
-        "\\tikzstyle{operator}=[basic,minimum size=1.5em]\n"
-        "\\tikzstyle{phase}=[fill=black,shape=circle,"
-        + "minimum size={}".format(settings['control']['size'])
-        + "cm,inner sep=0pt,outer sep=0pt,draw=black"
+        "\\tikzstyle{{operator}}=[basic,minimum size=1.5em]\n"
+        f"\\tikzstyle{{phase}}=[fill=black,shape=circle,minimum size={settings['control']['size']}cm,"
+        "inner sep=0pt,outer sep=0pt,draw=black"
     )
     if settings['control']['shadow']:
         gate_style += ",basicshadow"
     gate_style += (
-        "]\n\\tikzstyle{none}=[inner sep=0pt,outer sep=-.5pt,"
-        "minimum height=0.5cm+1pt]\n"
-        "\\tikzstyle{measure}=[operator,inner sep=0pt,minimum "
-        + "height={}cm, minimum width={}cm]\n".format(
-            settings['gates']['MeasureGate']['height'],
-            settings['gates']['MeasureGate']['width'],
-        )
-        + "\\tikzstyle{xstyle}=[circle,basic,minimum height="
+        "]\n\\tikzstyle{{none}}=[inner sep=0pt,outer sep=-.5pt,minimum height=0.5cm+1pt]\n"
+        "\\tikzstyle{{measure}}=[operator,inner sep=0pt,"
+        f"minimum height={settings['gates']['MeasureGate']['height']}cm,"
+        f"minimum width={settings['gates']['MeasureGate']['width']}cm]\n"
+        "\\tikzstyle{{xstyle}}=[circle,basic,minimum height="
     )
     x_gate_radius = min(settings['gates']['XGate']['height'], settings['gates']['XGate']['width'])
-    gate_style += ("{x_rad}cm,minimum width={x_rad}cm,inner sep=-1pt," "{linestyle}]\n").format(
-        x_rad=x_gate_radius, linestyle=settings['lines']['style']
-    )
+    gate_style += f"{x_gate_radius}cm,minimum width={x_gate_radius}cm,inner sep=-1pt,{settings['lines']['style']}]\n"
     if settings['gate_shadow']:
         gate_style += (
             "\\tikzset{\nshadowed/.style={preaction={transform "
@@ -211,7 +204,7 @@ def _header(settings):
         )
     gate_style += "\\tikzstyle{swapstyle}=["
     gate_style += "inner sep=-1pt, outer sep=-1pt, minimum width=0pt]\n"
-    edge_style = "\\tikzstyle{edgestyle}=[" + settings['lines']['style'] + "]\n"
+    edge_style = f"\\tikzstyle{{edgestyle}}=[{settings['lines']['style']}]\n"
 
     return packages + init + gate_style + edge_style
 
@@ -327,7 +320,7 @@ def to_tikz(  # pylint: disable=too-many-branches,too-many-locals,too-many-state
                 circuit[_line] = circuit[_line][1:]
 
             all_lines = lines + ctrl_lines
-            pos = max([self.pos[ll] for ll in range(min(all_lines), max(all_lines) + 1)])
+            pos = max(self.pos[ll] for ll in range(min(all_lines), max(all_lines) + 1))
             for _line in range(min(all_lines), max(all_lines) + 1):
                 self.pos[_line] = pos + self._gate_pre_offset(gate)
 
@@ -340,7 +333,7 @@ def to_tikz(  # pylint: disable=too-many-branches,too-many-locals,too-many-state
                 add_str = self._x_gate(lines, ctrl_lines)
                 # and make the target qubit quantum if one of the controls is
                 if not self.is_quantum[lines[0]]:
-                    if sum([self.is_quantum[i] for i in ctrl_lines]) > 0:
+                    if sum(self.is_quantum[i] for i in ctrl_lines) > 0:
                         self.is_quantum[lines[0]] = True
             elif gate == Z and len(ctrl_lines) > 0:
                 add_str = self._cz_gate(lines + ctrl_lines)
@@ -360,32 +353,24 @@ def to_tikz(  # pylint: disable=too-many-branches,too-many-locals,too-many-state
                     shift1 = 0.36 * height
                     shift2 = 0.1 * width
                     add_str += (
-                        "\n\\node[measure,edgestyle] ({op}) at ({pos}"
-                        ",-{line}) {{}};\n\\draw[edgestyle] ([yshift="
-                        "-{shift1}cm,xshift={shift2}cm]{op}.west) to "
-                        "[out=60,in=180] ([yshift={shift0}cm]{op}."
-                        "center) to [out=0, in=120] ([yshift=-{shift1}"
-                        "cm,xshift=-{shift2}cm]{op}.east);\n"
-                        "\\draw[edgestyle] ([yshift=-{shift1}cm]{op}."
-                        "center) to ([yshift=-{shift2}cm,xshift=-"
-                        "{shift1}cm]{op}.north east);"
-                    ).format(
-                        op=op,
-                        pos=self.pos[_line],
-                        line=_line,
-                        shift0=shift0,
-                        shift1=shift1,
-                        shift2=shift2,
+                        f"\n\\node[measure,edgestyle] ({op}) at ({self.pos[_line]}"
+                        f",-{_line}) {{}};\n\\draw[edgestyle] ([yshift="
+                        f"-{shift1}cm,xshift={shift2}cm]{op}.west) to "
+                        f"[out=60,in=180] ([yshift={shift0}cm]{op}."
+                        f"center) to [out=0, in=120] ([yshift=-{shift1}"
+                        f"cm,xshift=-{shift2}cm]{op}.east);\n"
+                        f"\\draw[edgestyle] ([yshift=-{shift1}cm]{op}."
+                        f"center) to ([yshift=-{shift2}cm,xshift=-"
+                        f"{shift1}cm]{op}.north east);"
                     )
                     self.op_count[_line] += 1
                     self.pos[_line] += self._gate_width(gate) + self._gate_offset(gate)
                     self.is_quantum[_line] = False
             elif gate == Allocate:
                 # draw 'begin line'
-                add_str = "\n\\node[none] ({}) at ({},-{}) {{$\\Ket{{0}}{}$}};"
                 id_str = ""
                 if self.settings['gates']['AllocateQubitGate']['draw_id']:
-                    id_str = "^{{\\textcolor{{red}}{{{}}}}}".format(cmds[i].id)
+                    id_str = f"^{{\\textcolor{{red}}{{{cmds[i].id}}}}}"
                 xpos = self.pos[line]
                 try:
                     if self.settings['gates']['AllocateQubitGate']['allocate_at_zero']:
@@ -397,18 +382,15 @@ def to_tikz(  # pylint: disable=too-many-branches,too-many-locals,too-many-state
                     xpos + self._gate_offset(gate) + self._gate_width(gate),
                     self.pos[line],
                 )
-                add_str = add_str.format(self._op(line), xpos, line, id_str)
+                add_str = f"\n\\node[none] ({self._op(line)}) at ({xpos},-{line}) {{$\\Ket{{0}}{id_str}$}};"
                 self.op_count[line] += 1
                 self.is_quantum[line] = self.settings['lines']['init_quantum']
             elif gate == Deallocate:
                 # draw 'end of line'
                 op = self._op(line)
-                add_str = "\n\\node[none] ({}) at ({},-{}) {{}};"
-                add_str = add_str.format(op, self.pos[line], line)
-                yshift = str(self._gate_height(gate)) + "cm]"
-                add_str += (
-                    "\n\\draw ([yshift={yshift}{op}.center) edge [edgestyle] ([yshift=-{yshift}{op}.center);"
-                ).format(op=op, yshift=yshift)
+                add_str = f"\n\\node[none] ({op}) at ({self.pos[line]},-{line}) {{}};"
+                yshift = f"{str(self._gate_height(gate))}cm]"
+                add_str += f"\n\\draw ([yshift={yshift}{op}.center) edge [edgestyle] ([yshift=-{yshift}{op}.center);"
                 self.op_count[line] += 1
                 self.pos[line] += self._gate_width(gate) + self._gate_offset(gate)
             else:
@@ -449,46 +431,29 @@ def _sqrtswap_gate(self, lines, ctrl_lines, daggered):  # pylint: disable=too-ma
         gate_str = ""
         for line in lines:
             op = self._op(line)
-            width = "{}cm".format(0.5 * gate_width)
-            blc = "[xshift=-{w},yshift=-{w}]{op}.center".format(w=width, op=op)
-            trc = "[xshift={w},yshift={w}]{op}.center".format(w=width, op=op)
-            tlc = "[xshift=-{w},yshift={w}]{op}.center".format(w=width, op=op)
-            brc = "[xshift={w},yshift=-{w}]{op}.center".format(w=width, op=op)
+            width = f"{0.5 * gate_width}cm"
+            blc = f"[xshift=-{width},yshift=-{width}]{op}.center"
+            trc = f"[xshift={width},yshift={width}]{op}.center"
+            tlc = f"[xshift=-{width},yshift={width}]{op}.center"
+            brc = f"[xshift={width},yshift=-{width}]{op}.center"
             swap_style = "swapstyle,edgestyle"
             if self.settings['gate_shadow']:
                 swap_style += ",shadowed"
             gate_str += (
-                "\n\\node[swapstyle] ({op}) at ({pos},-{line}) {{}};"
-                "\n\\draw[{swap_style}] ({s1})--({s2});\n"
-                "\\draw[{swap_style}] ({s3})--({s4});"
-            ).format(
-                op=op,
-                s1=blc,
-                s2=trc,
-                s3=tlc,
-                s4=brc,
-                line=line,
-                pos=self.pos[line],
-                swap_style=swap_style,
+                f"\n\\node[swapstyle] ({op}) at ({self.pos[line]},-{line}) {{}};"
+                f"\n\\draw[{swap_style}] ({blc})--({trc});\n"
+                f"\\draw[{swap_style}] ({tlc})--({brc});"
             )
-
         # add a circled 1/2
         midpoint = (lines[0] + lines[1]) / 2.0
         pos = self.pos[lines[0]]
-        op_mid = "line{}_gate{}".format('{}-{}'.format(*lines), self.op_count[lines[0]])
-        gate_str += (
-            "\n\\node[xstyle] ({op}) at ({pos},-{line})\
-                {{\\scriptsize $\\frac{{1}}{{2}}{dagger}$}};"
-        ).format(
-            op=op_mid,
-            line=midpoint,
-            pos=pos,
-            dagger='^{{\\dagger}}' if daggered else '',
-        )
+        op_mid = f"line{'{}-{}'.format(*lines)}_gate{self.op_count[lines[0]]}"
+        dagger = '^{{\\dagger}}' if daggered else ''
+        gate_str += f"\n\\node[xstyle] ({op}) at ({pos},-{midpoint}){{\\scriptsize $\\frac{{1}}{{2}}{dagger}$}};"
 
         # add two vertical lines to connect circled 1/2
-        gate_str += "\n\\draw ({}) edge[edgestyle] ({});".format(self._op(lines[0]), op_mid)
-        gate_str += "\n\\draw ({}) edge[edgestyle] ({});".format(op_mid, self._op(lines[1]))
+        gate_str += f"\n\\draw ({self._op(lines[0])}) edge[edgestyle] ({op_mid});"
+        gate_str += f"\n\\draw ({op_mid}) edge[edgestyle] ({self._op(lines[1])});"
 
         if len(ctrl_lines) > 0:
             for ctrl in ctrl_lines:
@@ -526,27 +491,18 @@ def _swap_gate(self, lines, ctrl_lines):  # pylint: disable=too-many-locals
         gate_str = ""
         for line in lines:
             op = self._op(line)
-            width = "{}cm".format(0.5 * gate_width)
-            blc = "[xshift=-{w},yshift=-{w}]{op}.center".format(w=width, op=op)
-            trc = "[xshift={w},yshift={w}]{op}.center".format(w=width, op=op)
-            tlc = "[xshift=-{w},yshift={w}]{op}.center".format(w=width, op=op)
-            brc = "[xshift={w},yshift=-{w}]{op}.center".format(w=width, op=op)
+            width = f"{0.5 * gate_width}cm"
+            blc = f"[xshift=-{width},yshift=-{width}]{op}.center"
+            trc = f"[xshift={width},yshift={width}]{op}.center"
+            tlc = f"[xshift=-{width},yshift={width}]{op}.center"
+            brc = f"[xshift={width},yshift=-{width}]{op}.center"
             swap_style = "swapstyle,edgestyle"
             if self.settings['gate_shadow']:
                 swap_style += ",shadowed"
             gate_str += (
-                "\n\\node[swapstyle] ({op}) at ({pos},-{line}) {{}};"
-                "\n\\draw[{swap_style}] ({s1})--({s2});\n"
-                "\\draw[{swap_style}] ({s3})--({s4});"
-            ).format(
-                op=op,
-                s1=blc,
-                s2=trc,
-                s3=tlc,
-                s4=brc,
-                line=line,
-                pos=self.pos[line],
-                swap_style=swap_style,
+                f"\n\\node[swapstyle] ({op}) at ({self.pos[line]},-{line}) {{}};"
+                f"\n\\draw[{swap_style}] ({blc})--({trc});\n"
+                f"\\draw[{swap_style}] ({tlc})--({brc});"
             )
         gate_str += self._line(lines[0], lines[1])
 
@@ -584,10 +540,10 @@ def _x_gate(self, lines, ctrl_lines):
         gate_width = self._gate_width(X)
         op = self._op(line)
         gate_str = (
-            "\n\\node[xstyle] ({op}) at ({pos},-{line}) {{}};\n\\draw"
-            "[edgestyle] ({op}.north)--({op}.south);\n\\draw"
-            "[edgestyle] ({op}.west)--({op}.east);"
-        ).format(op=op, line=line, pos=self.pos[line])
+            f"\n\\node[xstyle] ({op}) at ({self.pos[line]},-{line}) {{}};\n\\draw"
+            f"[edgestyle] ({op}.north)--({op}.south);\n\\draw"
+            f"[edgestyle] ({op}.west)--({op}.east);"
+        )
 
         if len(ctrl_lines) > 0:
             for ctrl in ctrl_lines:
@@ -705,8 +661,7 @@ def _phase(self, line, pos):
             tex_str (string): Latex string representing a control circle at the
                 given position.
         """
-        phase_str = "\n\\node[phase] ({}) at ({},-{}) {{}};"
-        return phase_str.format(self._op(line), pos, line)
+        return f"\n\\node[phase] ({self._op(line)}) at ({pos},-{line}) {{}};"
 
     def _op(self, line, op=None, offset=0):
         """
@@ -722,7 +677,7 @@ def _op(self, line, op=None, offset=0):
         """
         if op is None:
             op = self.op_count[line]
-        return "line{}_gate{}".format(line, op + offset)
+        return f"line{line}_gate{op + offset}"
 
     def _line(self, point1, point2, double=False, line=None):  # pylint: disable=too-many-locals,unused-argument
         """
@@ -755,7 +710,7 @@ def _line(self, point1, point2, double=False, line=None):  # pylint: disable=too
             shift = "yshift={}cm"
 
         if quantum:
-            return "\n\\draw ({}) edge[edgestyle] ({});".format(op1, op2)
+            return f"\n\\draw ({op1}) edge[edgestyle] ({op2});"
 
         if point2 > point1:
             loc1, loc2 = loc2, loc1
@@ -799,8 +754,9 @@ def _regular_gate(self, gate, lines, ctrl_lines):  # pylint: disable=too-many-lo
         node_str = "\n\\node[none] ({}) at ({},-{}) {{}};"
         for line in lines:
             node1 = node_str.format(self._op(line), pos, line)
-            node2 = ("\n\\node[none,minimum height={}cm,outer sep=0] ({}) at ({},-{}) {{}};").format(
-                gate_height, self._op(line, offset=1), pos + gate_width / 2.0, line
+            node2 = (
+                "\n\\node[none,minimum height={gate_height}cm,outer sep=0] ({self._op(line, offset=1)}) "
+                f"at ({pos + gate_width / 2.0},-{line}) {{}};"
             )
             node3 = node_str.format(self._op(line, offset=2), pos + gate_width, line)
             tex_str += node1 + node2 + node3
@@ -808,15 +764,9 @@ def _regular_gate(self, gate, lines, ctrl_lines):  # pylint: disable=too-many-lo
                 tex_str += self._line(self.op_count[line] - 1, self.op_count[line], line=line)
 
         tex_str += (
-            "\n\\draw[operator,edgestyle,outer sep={width}cm] (["
-            "yshift={half_height}cm]{op1}) rectangle ([yshift=-"
-            "{half_height}cm]{op2}) node[pos=.5] {{{name}}};"
-        ).format(
-            width=gate_width,
-            op1=self._op(imin),
-            op2=self._op(imax, offset=2),
-            half_height=0.5 * gate_height,
-            name=name,
+            f"\n\\draw[operator,edgestyle,outer sep={gate_width}cm] (["
+            f"yshift={0.5 * gate_height}cm]{self._op(imin)}) rectangle ([yshift=-"
+            f"{0.5 * gate_height}cm]{self._op(imax, offset=2)}) node[pos=.5] {{{name}}};"
         )
 
         for line in lines:
diff --git a/projectq/backends/_circuits/_to_latex_test.py b/projectq/backends/_circuits/_to_latex_test.py
index 0ebdc1054..3369e681a 100755
--- a/projectq/backends/_circuits/_to_latex_test.py
+++ b/projectq/backends/_circuits/_to_latex_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -175,12 +174,12 @@ def test_body():
     assert code.count("swapstyle") == 36
     # CZ is two phases plus 2 from CNOTs + 2 from cswap + 2 from csqrtswap
     assert code.count("phase") == 8
-    assert code.count("{{{}}}".format(str(H))) == 2  # 2 hadamard gates
+    assert code.count(f"{{{str(H)}}}") == 2  # 2 hadamard gates
     assert code.count("{$\\Ket{0}") == 3  # 3 qubits allocated
     # 1 cnot, 1 not gate, 3 SqrtSwap, 1 inv(SqrtSwap)
     assert code.count("xstyle") == 7
     assert code.count("measure") == 1  # 1 measurement
-    assert code.count("{{{}}}".format(str(Z))) == 1  # 1 Z gate
+    assert code.count(f"{{{str(Z)}}}") == 1  # 1 Z gate
     assert code.count("{red}") == 3
 
 
@@ -378,7 +377,7 @@ def test_qubit_lines_classicalvsquantum2():
         H | action
 
     code = drawer.get_latex()
-    assert code.count("{{{}}}".format(str(H))) == 1  # 1 Hadamard
+    assert code.count(f"{{{str(H)}}}") == 1  # 1 Hadamard
     assert code.count("{$") == 4  # four allocate gates
     assert code.count("node[phase]") == 3  # 3 controls
 
@@ -397,7 +396,7 @@ def test_qubit_lines_classicalvsquantum3():
         H | (action1, action2)
 
     code = drawer.get_latex()
-    assert code.count("{{{}}}".format(str(H))) == 1  # 1 Hadamard
+    assert code.count(f"{{{str(H)}}}") == 1  # 1 Hadamard
     assert code.count("{$") == 7  # 8 allocate gates
     assert code.count("node[phase]") == 3  # 1 control
     # (other controls are within the gate -> are not drawn)
diff --git a/projectq/backends/_exceptions.py b/projectq/backends/_exceptions.py
index 8626df65c..9ebd6390a 100644
--- a/projectq/backends/_exceptions.py
+++ b/projectq/backends/_exceptions.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/backends/_ibm/__init__.py b/projectq/backends/_ibm/__init__.py
index 21c3b1789..db7bbddb4 100755
--- a/projectq/backends/_ibm/__init__.py
+++ b/projectq/backends/_ibm/__init__.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/backends/_ibm/_ibm.py b/projectq/backends/_ibm/_ibm.py
index 238f11bae..2a11aa5a7 100755
--- a/projectq/backends/_ibm/_ibm.py
+++ b/projectq/backends/_ibm/_ibm.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -169,15 +168,15 @@ def _store(self, cmd):  # pylint: disable=too-many-branches,too-many-statements
         elif gate == NOT and get_control_count(cmd) == 1:
             ctrl_pos = cmd.control_qubits[0].id
             qb_pos = cmd.qubits[0][0].id
-            self.qasm += "\ncx q[{}], q[{}];".format(ctrl_pos, qb_pos)
+            self.qasm += f"\ncx q[{ctrl_pos}], q[{qb_pos}];"
             self._json.append({'qubits': [ctrl_pos, qb_pos], 'name': 'cx'})
         elif gate == Barrier:
             qb_pos = [qb.id for qr in cmd.qubits for qb in qr]
             self.qasm += "\nbarrier "
             qb_str = ""
             for pos in qb_pos:
-                qb_str += "q[{}], ".format(pos)
-            self.qasm += qb_str[:-2] + ";"
+                qb_str += f"q[{pos}], "
+            self.qasm += f"{qb_str[:-2]};"
             self._json.append({'qubits': qb_pos, 'name': 'barrier'})
         elif isinstance(gate, (Rx, Ry, Rz)):
             qb_pos = cmd.qubits[0][0].id
@@ -191,11 +190,11 @@ def _store(self, cmd):  # pylint: disable=too-many-branches,too-many-statements
             gate_qasm = u_strs[str(gate)[0:2]].format(gate.angle)
             gate_name = u_name[str(gate)[0:2]]
             params = u_angle[str(gate)[0:2]]
-            self.qasm += "\n{} q[{}];".format(gate_qasm, qb_pos)
+            self.qasm += f"\n{gate_qasm} q[{qb_pos}];"
             self._json.append({'qubits': [qb_pos], 'name': gate_name, 'params': params})
         elif gate == H:
             qb_pos = cmd.qubits[0][0].id
-            self.qasm += "\nu2(0,pi/2) q[{}];".format(qb_pos)
+            self.qasm += f"\nu2(0,pi/2) q[{qb_pos}];"
             self._json.append({'qubits': [qb_pos], 'name': 'u2', 'params': [0, 3.141592653589793]})
         else:
             raise InvalidCommandError(
@@ -213,9 +212,8 @@ def _logical_to_physical(self, qb_id):
         mapping = self.main_engine.mapper.current_mapping
         if qb_id not in mapping:
             raise RuntimeError(
-                "Unknown qubit id {}. Please make sure "
-                "eng.flush() was called and that the qubit "
-                "was eliminated during optimization.".format(qb_id)
+                f"Unknown qubit id {qb_id}. "
+                "Please make sure eng.flush() was called and that the qubit was eliminated during optimization."
             )
         return mapping[qb_id]
 
@@ -268,7 +266,7 @@ def _run(self):  # pylint: disable=too-many-locals
         # finally: add measurements (no intermediate measurements are allowed)
         for measured_id in self._measured_ids:
             qb_loc = self.main_engine.mapper.current_mapping[measured_id]
-            self.qasm += "\nmeasure q[{0}] -> c[{0}];".format(qb_loc)
+            self.qasm += f"\nmeasure q[{qb_loc}] -> c[{qb_loc}];"
             self._json.append({'qubits': [qb_loc], 'name': 'measure', 'memory': [qb_loc]})
         # return if no operations / measurements have been performed.
         if self.qasm == "":
@@ -307,7 +305,7 @@ def _run(self):  # pylint: disable=too-many-locals
             measured = ""
             for state in counts:
                 probability = counts[state] * 1.0 / self._num_runs
-                state = "{0:b}".format(int(state, 0))
+                state = f"{int(state, 0):b}"
                 state = state.zfill(max_qubit_id)
                 # states in ibmq are right-ordered, so need to reverse state string
                 state = state[::-1]
@@ -318,7 +316,7 @@ def _run(self):  # pylint: disable=too-many-locals
                     star = "*"
                 self._probabilities[state] = probability
                 if self._verbose and probability > 0:
-                    print(str(state) + " with p = " + str(probability) + star)
+                    print(f"{str(state)} with p = {probability}{star}")
 
             # register measurement result from IBM
             for qubit_id in self._measured_ids:
diff --git a/projectq/backends/_ibm/_ibm_http_client.py b/projectq/backends/_ibm/_ibm_http_client.py
index a30233b44..400e235ee 100755
--- a/projectq/backends/_ibm/_ibm_http_client.py
+++ b/projectq/backends/_ibm/_ibm_http_client.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -219,12 +218,12 @@ def get_result(
         job_status_url = 'Network/ibm-q/Groups/open/Projects/main/Jobs/' + execution_id
 
         if verbose:
-            print("Waiting for results. [Job ID: {}]".format(execution_id))
+            print(f"Waiting for results. [Job ID: {execution_id}]")
 
         original_sigint_handler = signal.getsignal(signal.SIGINT)
 
         def _handle_sigint_during_get_result(*_):  # pragma: no cover
-            raise Exception("Interrupted. The ID of your submitted job is {}.".format(execution_id))
+            raise Exception(f"Interrupted. The ID of your submitted job is {execution_id}.")
 
         try:
             signal.signal(signal.SIGINT, _handle_sigint_during_get_result)
@@ -271,20 +270,20 @@ def _handle_sigint_during_get_result(*_):  # pragma: no cover
                 # Note: if stays stuck if 'Validating' mode, then sthg went
                 #       wrong in step 3
                 if r_json['status'] not in acceptable_status:
-                    raise Exception("Error while running the code. Last status: {}.".format(r_json['status']))
+                    raise Exception(f"Error while running the code. Last status: {r_json['status']}.")
                 time.sleep(interval)
                 if self.is_online(device) and retries % 60 == 0:
                     self.get_list_devices()
                     if not self.is_online(device):
                         raise DeviceOfflineError(
-                            "Device went offline. The ID of your submitted job is {}.".format(execution_id)
+                            f"Device went offline. The ID of your submitted job is {execution_id}."
                         )
 
         finally:
             if original_sigint_handler is not None:
                 signal.signal(signal.SIGINT, original_sigint_handler)
 
-        raise Exception("Timeout. The ID of your submitted job is {}.".format(execution_id))
+        raise Exception(f"Timeout. The ID of your submitted job is {execution_id}.")
 
 
 def show_devices(token=None, verbose=False):
@@ -368,15 +367,12 @@ def send(
         runnable, qmax, qneeded = ibmq_session.can_run_experiment(info, device)
         if not runnable:
             print(
-                (
-                    "The device is too small ({} qubits available) for the code "
-                    + "requested({} qubits needed) Try to look for another "
-                    + "device with more qubits"
-                ).format(qmax, qneeded)
+                f"The device is too small ({qmax} qubits available) for the code "
+                f"requested({qneeded} qubits needed) Try to look for another device with more qubits"
             )
             raise DeviceTooSmall("Device is too small.")
         if verbose:
-            print("- Running code: {}".format(info))
+            print(f"- Running code: {info}")
         execution_id = ibmq_session.run(info, device)
         if verbose:
             print("- Waiting for results...")
diff --git a/projectq/backends/_ibm/_ibm_http_client_test.py b/projectq/backends/_ibm/_ibm_http_client_test.py
index 69b067723..655a698e3 100755
--- a/projectq/backends/_ibm/_ibm_http_client_test.py
+++ b/projectq/backends/_ibm/_ibm_http_client_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -96,7 +95,7 @@ def raise_for_status(self):
                 200,
             )
         # STEP2
-        elif args[1] == "/" + execution_id + "/jobUploadUrl" and request_num[0] == 3:
+        elif args[1] == f"/{execution_id}/jobUploadUrl" and request_num[0] == 3:
             request_num[0] += 1
             return MockResponse({"url": "s3_url"}, 200)
         # STEP5
@@ -104,7 +103,7 @@ def raise_for_status(self):
             args[1]
             == urljoin(
                 _API_URL,
-                "Network/ibm-q/Groups/open/Projects/main/Jobs/{execution_id}".format(execution_id=execution_id),
+                f"Network/ibm-q/Groups/open/Projects/main/Jobs/{execution_id}",
             )
             and not result_ready[0]
             and request_num[0] == 5
@@ -116,7 +115,7 @@ def raise_for_status(self):
             args[1]
             == urljoin(
                 _API_URL,
-                "Network/ibm-q/Groups/open/Projects/main/Jobs/{execution_id}".format(execution_id=execution_id),
+                f"Network/ibm-q/Groups/open/Projects/main/Jobs/{execution_id}",
             )
             and result_ready[0]
             and request_num[0] == 7
@@ -128,9 +127,7 @@ def raise_for_status(self):
             args[1]
             == urljoin(
                 _API_URL,
-                "Network/ibm-q/Groups/open/Projects/main/Jobs/{execution_id}/resultDownloadUrl".format(
-                    execution_id=execution_id
-                ),
+                f"Network/ibm-q/Groups/open/Projects/main/Jobs/{execution_id}/resultDownloadUrl",
             )
             and request_num[0] == 8
         ):
@@ -170,7 +167,7 @@ def raise_for_status(self):
             answer1 = {
                 'objectStorageInfo': {
                     'downloadQObjectUrlEndpoint': 'url_dld_endpoint',
-                    'uploadQobjectUrlEndpoint': '/' + execution_id + '/jobUploadUrl',
+                    'uploadQobjectUrlEndpoint': f"/{execution_id}/jobUploadUrl",
                     'uploadUrl': 'url_upld',
                 },
                 'id': execution_id,
@@ -178,7 +175,7 @@ def raise_for_status(self):
             return MockPostResponse(answer1, 200)
 
         # STEP4
-        elif args[1] == urljoin(_API_URL, jobs_url + "/" + execution_id + "/jobDataUploaded") and request_num[0] == 4:
+        elif args[1] == urljoin(_API_URL, f"{jobs_url}/{execution_id}/jobDataUploaded") and request_num[0] == 4:
             request_num[0] += 1
             return MockPostResponse({}, 200)
 
@@ -187,9 +184,7 @@ def raise_for_status(self):
             args[1]
             == urljoin(
                 _API_URL,
-                "Network/ibm-q/Groups/open/Projects/main/Jobs/{execution_id}/resultDownloaded".format(
-                    execution_id=execution_id
-                ),
+                f"Network/ibm-q/Groups/open/Projects/main/Jobs/{execution_id}/resultDownloaded",
             )
             and request_num[0] == 10
         ):
@@ -552,18 +547,18 @@ def raise_for_status(self):
                 ],
                 200,
             )
-        job_url = "Network/ibm-q/Groups/open/Projects/main/Jobs/{}".format(execution_id)
+        job_url = f"Network/ibm-q/Groups/open/Projects/main/Jobs/{execution_id}"
         if args[1] == urljoin(_API_URL, job_url):
             tries[0] += 1
             return MockResponse({"status": "RUNNING"}, 200)
 
         # STEP2
-        elif args[1] == "/" + execution_id + "/jobUploadUrl":
+        elif args[1] == f"/{execution_id}/jobUploadUrl":
             return MockResponse({"url": "s3_url"}, 200)
         # STEP5
         elif args[1] == urljoin(
             _API_URL,
-            "Network/ibm-q/Groups/open/Projects/main/Jobs/{execution_id}".format(execution_id=execution_id),
+            f"Network/ibm-q/Groups/open/Projects/main/Jobs/{execution_id}",
         ):
             return MockResponse({"status": "RUNNING"}, 200)
 
@@ -593,7 +588,7 @@ def raise_for_status(self):
             answer1 = {
                 'objectStorageInfo': {
                     'downloadQObjectUrlEndpoint': 'url_dld_endpoint',
-                    'uploadQobjectUrlEndpoint': '/' + execution_id + '/jobUploadUrl',
+                    'uploadQobjectUrlEndpoint': f"/{execution_id}/jobUploadUrl",
                     'uploadUrl': 'url_upld',
                 },
                 'id': execution_id,
@@ -601,7 +596,7 @@ def raise_for_status(self):
             return MockPostResponse(answer1, 200)
 
         # STEP4
-        elif args[1] == urljoin(_API_URL, jobs_url + "/" + execution_id + "/jobDataUploaded"):
+        elif args[1] == urljoin(_API_URL, f"{jobs_url}/{execution_id}/jobDataUploaded"):
             return MockPostResponse({}, 200)
 
     def mocked_requests_put(*args, **kwargs):
@@ -685,8 +680,8 @@ def raise_for_status(self):
                 ],
                 200,
             )
-        job_url = "Network/ibm-q/Groups/open/Projects/main/Jobs/{}".format("123e")
-        err_url = "Network/ibm-q/Groups/open/Projects/main/Jobs/{}".format("123ee")
+        job_url = "Network/ibm-q/Groups/open/Projects/main/Jobs/123e"
+        err_url = "Network/ibm-q/Groups/open/Projects/main/Jobs/123ee"
         if args[1] == urljoin(_API_URL, job_url):
             request_num[0] += 1
             return MockResponse({"status": "RUNNING", 'iteration': request_num[0]}, 200)
@@ -760,7 +755,7 @@ def raise_for_status(self):
             args[1]
             == urljoin(
                 _API_URL,
-                "Network/ibm-q/Groups/open/Projects/main/Jobs/{execution_id}".format(execution_id=execution_id),
+                f"Network/ibm-q/Groups/open/Projects/main/Jobs/{execution_id}",
             )
             and request_num[0] < 1
         ):
@@ -768,15 +763,13 @@ def raise_for_status(self):
             return MockResponse({"status": "RUNNING"}, 200)
         elif args[1] == urljoin(
             _API_URL,
-            "Network/ibm-q/Groups/open/Projects/main/Jobs/{execution_id}".format(execution_id=execution_id),
+            f"Network/ibm-q/Groups/open/Projects/main/Jobs/{execution_id}",
         ):
             return MockResponse({"status": "COMPLETED"}, 200)
         # STEP6
         elif args[1] == urljoin(
             _API_URL,
-            "Network/ibm-q/Groups/open/Projects/main/Jobs/{execution_id}/resultDownloadUrl".format(
-                execution_id=execution_id
-            ),
+            f"Network/ibm-q/Groups/open/Projects/main/Jobs/{execution_id}/resultDownloadUrl",
         ):
             return MockResponse({"url": "result_download_url"}, 200)
         # STEP7
@@ -806,9 +799,7 @@ def raise_for_status(self):
         # STEP8
         elif args[1] == urljoin(
             _API_URL,
-            "Network/ibm-q/Groups/open/Projects/main/Jobs/{execution_id}/resultDownloaded".format(
-                execution_id=execution_id
-            ),
+            f"Network/ibm-q/Groups/open/Projects/main/Jobs/{execution_id}/resultDownloaded",
         ):
             return MockPostResponse({}, 200)
 
diff --git a/projectq/backends/_ibm/_ibm_test.py b/projectq/backends/_ibm/_ibm_test.py
index 8d744222f..dc9e2c2c7 100755
--- a/projectq/backends/_ibm/_ibm_test.py
+++ b/projectq/backends/_ibm/_ibm_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/backends/_ionq/__init__.py b/projectq/backends/_ionq/__init__.py
index dfc37dc08..9f1b6b9ea 100644
--- a/projectq/backends/_ionq/__init__.py
+++ b/projectq/backends/_ionq/__init__.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/backends/_ionq/_ionq.py b/projectq/backends/_ionq/_ionq.py
index 7645f3531..089b26ce4 100644
--- a/projectq/backends/_ionq/_ionq.py
+++ b/projectq/backends/_ionq/_ionq.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -208,11 +207,11 @@ def _store(self, cmd):
         gate_name = GATE_MAP.get(gate_type)
         # Daggered gates get special treatment.
         if isinstance(gate, DaggeredGate):
-            gate_name = GATE_MAP[type(gate._gate)] + 'i'  # pylint: disable=protected-access
+            gate_name = f"{GATE_MAP[type(gate._gate)]}i"  # pylint: disable=protected-access
 
         # Unable to determine a gate mapping here, so raise out.
         if gate_name is None:
-            raise InvalidCommandError('Invalid command: ' + str(cmd))
+            raise InvalidCommandError(f"Invalid command: {str(cmd)}")
 
         # Now make sure there are no existing measurements on qubits involved
         #   in this operation.
@@ -230,7 +229,7 @@ def _store(self, cmd):
             if len(already_measured) > 0:
                 err = (
                     'Mid-circuit measurement is not supported. '
-                    'The following qubits have already been measured: {}.'.format(list(already_measured))
+                    f'The following qubits have already been measured: {list(already_measured)}.'
                 )
                 raise MidCircuitMeasurementError(err)
 
@@ -331,7 +330,7 @@ def _run(self):  # pylint: disable=too-many-locals
                 verbose=self._verbose,
             )
             if res is None:
-                raise RuntimeError("Failed to retrieve job with id: '{}'!".format(self._retrieve_execution))
+                raise RuntimeError(f"Failed to retrieve job with id: '{self._retrieve_execution}'!")
             self._measured_ids = measured_ids = res['meas_qubit_ids']
 
         # Determine random outcome from probable states.
@@ -352,7 +351,7 @@ def _run(self):  # pylint: disable=too-many-locals
                 star = "*"
             self._probabilities[state] = probability
             if self._verbose and probability > 0:  # pragma: no cover
-                print(state + " with p = " + str(probability) + star)
+                print(f"{state} with p = {probability}{star}")
 
         # Register measurement results
         for idx, qubit_id in enumerate(measured_ids):
diff --git a/projectq/backends/_ionq/_ionq_http_client.py b/projectq/backends/_ionq/_ionq_http_client.py
index 4a92ecc57..b7f90cd82 100644
--- a/projectq/backends/_ionq/_ionq_http_client.py
+++ b/projectq/backends/_ionq/_ionq_http_client.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -114,7 +113,7 @@ def authenticate(self, token=None):
             token = getpass.getpass(prompt='IonQ apiKey > ')
         if not token:
             raise RuntimeError('An authentication token is required!')
-        self.headers.update({'Authorization': 'apiKey {}'.format(token)})
+        self.headers.update({'Authorization': f'apiKey {token}'})
         self.token = token
 
     def run(self, info, device):
@@ -165,13 +164,7 @@ def run(self, info, device):
             'code': 'UnknownError',
             'error': 'An unknown error occurred!',
         }
-        raise JobSubmissionError(
-            "{}: {} (status={})".format(
-                failure['code'],
-                failure['error'],
-                status,
-            )
-        )
+        raise JobSubmissionError(f"{failure['code']}: {failure['error']} (status={status})")
 
     def get_result(self, device, execution_id, num_retries=3000, interval=1):
         """
@@ -201,12 +194,12 @@ def get_result(self, device, execution_id, num_retries=3000, interval=1):
             dict: A dict of job data for an engine to consume.
         """
         if self._verbose:  # pragma: no cover
-            print("Waiting for results. [Job ID: {}]".format(execution_id))
+            print(f"Waiting for results. [Job ID: {execution_id}]")
 
         original_sigint_handler = signal.getsignal(signal.SIGINT)
 
         def _handle_sigint_during_get_result(*_):  # pragma: no cover
-            raise Exception("Interrupted. The ID of your submitted job is {}.".format(execution_id))
+            raise Exception(f"Interrupted. The ID of your submitted job is {execution_id}.")
 
         signal.signal(signal.SIGINT, _handle_sigint_during_get_result)
 
@@ -232,7 +225,7 @@ def _handle_sigint_during_get_result(*_):  # pragma: no cover
                 # Otherwise, make sure it is in a known healthy state.
                 if status not in ('ready', 'running', 'submitted'):
                     # TODO: Add comprehensive API error processing here.
-                    raise Exception("Error while running the code: {}.".format(status))
+                    raise Exception(f"Error while running the code: {status}.")
 
                 # Sleep, then check availability before trying again.
                 time.sleep(interval)
@@ -240,13 +233,13 @@ def _handle_sigint_during_get_result(*_):  # pragma: no cover
                     self.update_devices_list()
                     if not self.is_online(device):  # pragma: no cover
                         raise DeviceOfflineError(
-                            "Device went offline. The ID of " "your submitted job is {}.".format(execution_id)
+                            f"Device went offline. The ID of your submitted job is {execution_id}."
                         )
         finally:
             if original_sigint_handler is not None:
                 signal.signal(signal.SIGINT, original_sigint_handler)
 
-        raise RequestTimeoutError("Timeout. The ID of your submitted job is {}.".format(execution_id))
+        raise RequestTimeoutError(f"Timeout. The ID of your submitted job is {execution_id}.")
 
     def show_devices(self):
         """Show the currently available device list for the IonQ provider.
@@ -337,7 +330,7 @@ def send(
         if verbose:  # pragma: no cover
             print("- Authenticating...")
         if verbose and token is not None:  # pragma: no cover
-            print('user API token: ' + token)
+            print(f"user API token: {token}")
         ionq_session.authenticate(token)
 
         # check if the device is online
@@ -353,13 +346,12 @@ def send(
         runnable, qmax, qneeded = ionq_session.can_run_experiment(info, device)
         if not runnable:
             print(
-                "The device is too small ({} qubits available) for the code "
-                "requested({} qubits needed). Try to look for another device "
-                "with more qubits".format(qmax, qneeded)
+                f'The device is too small ({qmax} qubits available) for the code requested({qneeded} qubits needed).',
+                'Try to look for another device with more qubits',
             )
             raise DeviceTooSmall("Device is too small.")
         if verbose:  # pragma: no cover
-            print("- Running code: {}".format(info))
+            print(f"- Running code: {info}")
         execution_id = ionq_session.run(info, device)
         if verbose:  # pragma: no cover
             print("- Waiting for results...")
@@ -382,12 +374,7 @@ def send(
             # Try to parse client errors
             if status_code == 400:
                 err_json = err.response.json()
-                raise JobSubmissionError(
-                    '{}: {}'.format(
-                        err_json['error'],
-                        err_json['message'],
-                    )
-                ) from err
+                raise JobSubmissionError(f"{err_json['error']}: {err_json['message']}") from err
 
         # Else, just print:
         print("- There was an error running your code:")
diff --git a/projectq/backends/_ionq/_ionq_http_client_test.py b/projectq/backends/_ionq/_ionq_http_client_test.py
index d92fb88f4..d1df8fb68 100644
--- a/projectq/backends/_ionq/_ionq_http_client_test.py
+++ b/projectq/backends/_ionq/_ionq_http_client_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the 'License');
diff --git a/projectq/backends/_ionq/_ionq_mapper.py b/projectq/backends/_ionq/_ionq_mapper.py
index 3a5eb5a57..e77b92c17 100644
--- a/projectq/backends/_ionq/_ionq_mapper.py
+++ b/projectq/backends/_ionq/_ionq_mapper.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -42,10 +41,10 @@ def _process_cmd(self, cmd):
         if isinstance(cmd.gate, AllocateQubitGate):
             qubit_id = cmd.qubits[0][0].id
             if qubit_id in current_mapping:
-                raise RuntimeError("Qubit with id {} has already been allocated!".format(qubit_id))
+                raise RuntimeError(f"Qubit with id {qubit_id} has already been allocated!")
 
             if self._qubit_idx >= self.max_qubits:
-                raise RuntimeError("Cannot allocate more than {} qubits!".format(self.max_qubits))
+                raise RuntimeError(f"Cannot allocate more than {self.max_qubits} qubits!")
 
             new_id = self._qubit_idx
             self._qubit_idx += 1
diff --git a/projectq/backends/_ionq/_ionq_mapper_test.py b/projectq/backends/_ionq/_ionq_mapper_test.py
index f86fb10d9..634f7d14a 100644
--- a/projectq/backends/_ionq/_ionq_mapper_test.py
+++ b/projectq/backends/_ionq/_ionq_mapper_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/backends/_ionq/_ionq_test.py b/projectq/backends/_ionq/_ionq_test.py
index b23450353..5a846b033 100644
--- a/projectq/backends/_ionq/_ionq_test.py
+++ b/projectq/backends/_ionq/_ionq_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/backends/_printer.py b/projectq/backends/_printer.py
index 9016b4753..50c20eb5c 100755
--- a/projectq/backends/_printer.py
+++ b/projectq/backends/_printer.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +15,6 @@
 """Contains a compiler engine which prints commands to stdout prior to sending them on to the next engines."""
 
 import sys
-from builtins import input
 
 from projectq.cengines import BasicEngine, LastEngineException
 from projectq.meta import LogicalQubitIDTag, get_control_count
@@ -85,7 +83,7 @@ def _print_cmd(self, cmd):
                     if self._accept_input:
                         meas = None
                         while meas not in ('0', '1', 1, 0):
-                            prompt = "Input measurement result (0 or 1) for qubit " + str(qubit) + ": "
+                            prompt = f"Input measurement result (0 or 1) for qubit {str(qubit)}: "
                             meas = input(prompt)
                     else:
                         meas = self._default_measure
@@ -100,7 +98,7 @@ def _print_cmd(self, cmd):
                     self.main_engine.set_measurement_result(qubit, meas)
         else:
             if self._in_place:  # pragma: no cover
-                sys.stdout.write("\0\r\t\x1b[K" + str(cmd) + "\r")
+                sys.stdout.write(f'\x00\r\t\x1b[K{str(cmd)}\r')
             else:
                 print(cmd)
 
diff --git a/projectq/backends/_printer_test.py b/projectq/backends/_printer_test.py
index 8d81ffc1b..658fb78c7 100755
--- a/projectq/backends/_printer_test.py
+++ b/projectq/backends/_printer_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,6 +15,8 @@
 Tests for projectq.backends._printer.py.
 """
 
+import io
+
 import pytest
 
 from projectq import MainEngine
@@ -47,11 +48,15 @@ def available_cmd(self, cmd):
 def test_command_printer_accept_input(monkeypatch):
     cmd_printer = _printer.CommandPrinter()
     eng = MainEngine(backend=cmd_printer, engine_list=[DummyEngine()])
-    monkeypatch.setattr(_printer, "input", lambda x: 1)
+
+    number_input = io.StringIO('1\n')
+    monkeypatch.setattr('sys.stdin', number_input)
     qubit = eng.allocate_qubit()
     Measure | qubit
     assert int(qubit) == 1
-    monkeypatch.setattr(_printer, "input", lambda x: 0)
+
+    number_input = io.StringIO('0\n')
+    monkeypatch.setattr('sys.stdin', number_input)
     qubit = eng.allocate_qubit()
     NOT | qubit
     Measure | qubit
diff --git a/projectq/backends/_resource.py b/projectq/backends/_resource.py
index e279d579f..ec741746c 100755
--- a/projectq/backends/_resource.py
+++ b/projectq/backends/_resource.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/backends/_resource_test.py b/projectq/backends/_resource_test.py
index 89ebeef0f..426d2916e 100755
--- a/projectq/backends/_resource_test.py
+++ b/projectq/backends/_resource_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -25,7 +24,7 @@
 from projectq.types import WeakQubitRef
 
 
-class MockEngine(object):
+class MockEngine:
     def is_available(self, cmd):
         return False
 
diff --git a/projectq/backends/_sim/__init__.py b/projectq/backends/_sim/__init__.py
index 1557d03a1..3cdb3731b 100755
--- a/projectq/backends/_sim/__init__.py
+++ b/projectq/backends/_sim/__init__.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/backends/_sim/_classical_simulator.py b/projectq/backends/_sim/_classical_simulator.py
index eb270e219..f873d1096 100755
--- a/projectq/backends/_sim/_classical_simulator.py
+++ b/projectq/backends/_sim/_classical_simulator.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/backends/_sim/_classical_simulator_test.py b/projectq/backends/_sim/_classical_simulator_test.py
index f8e9121bb..67db700ec 100755
--- a/projectq/backends/_sim/_classical_simulator_test.py
+++ b/projectq/backends/_sim/_classical_simulator_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/backends/_sim/_pysim.py b/projectq/backends/_sim/_pysim.py
index a98bad4ca..05b7477c0 100755
--- a/projectq/backends/_sim/_pysim.py
+++ b/projectq/backends/_sim/_pysim.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -331,9 +330,9 @@ def emulate_time_evolution(self, terms_dict, time, ids, ctrlids):  # pylint: dis
             ctrlids (list): A list of control qubit IDs.
         """
         # Determine the (normalized) trace, which is nonzero only for identity terms:
-        trace = sum([c for (t, c) in terms_dict if len(t) == 0])
+        trace = sum(c for (t, c) in terms_dict if len(t) == 0)
         terms_dict = [(t, c) for (t, c) in terms_dict if len(t) > 0]
-        op_nrm = abs(time) * sum([abs(c) for (_, c) in terms_dict])
+        op_nrm = abs(time) * sum(abs(c) for (_, c) in terms_dict)
         # rescale the operator by s:
         scale = int(op_nrm + 1.0)
         correction = _np.exp(-1j * time * trace / float(scale))
diff --git a/projectq/backends/_sim/_simulator.py b/projectq/backends/_sim/_simulator.py
index ff5c4f4fc..9752ea669 100755
--- a/projectq/backends/_sim/_simulator.py
+++ b/projectq/backends/_sim/_simulator.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017, 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -407,10 +406,8 @@ def _handle(self, cmd):  # pylint: disable=too-many-branches,too-many-locals,too
             ids = [qb.id for qureg in cmd.qubits for qb in qureg]
             if not 2 ** len(ids) == len(cmd.gate.matrix):
                 raise Exception(
-                    "Simulator: Error applying {} gate: "
-                    "{}-qubit gate applied to {} qubits.".format(
-                        str(cmd.gate), int(math.log(len(cmd.gate.matrix), 2)), len(ids)
-                    )
+                    f"Simulator: Error applying {str(cmd.gate)} gate: {int(math.log(len(cmd.gate.matrix), 2))}-qubit"
+                    f" gate applied to {len(ids)} qubits."
                 )
             self._simulator.apply_controlled_gate(matrix.tolist(), ids, [qb.id for qb in cmd.control_qubits])
 
@@ -418,8 +415,7 @@ def _handle(self, cmd):  # pylint: disable=too-many-branches,too-many-locals,too
                 self._simulator.run()
         else:
             raise Exception(
-                "This simulator only supports controlled k-qubit"
-                " gates with k < 6!\nPlease add an auto-replacer"
+                "This simulator only supports controlled k-qubit gates with k < 6!\nPlease add an auto-replacer"
                 " engine to your list of compiler engines."
             )
 
diff --git a/projectq/backends/_sim/_simulator_test.py b/projectq/backends/_sim/_simulator_test.py
index 67f14eb9a..1b4b6b7bf 100755
--- a/projectq/backends/_sim/_simulator_test.py
+++ b/projectq/backends/_sim/_simulator_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -228,7 +227,7 @@ def test_simulator_functional_measurement(sim):
 
     All(Measure) | qubits
 
-    bit_value_sum = sum([int(qubit) for qubit in qubits])
+    bit_value_sum = sum(int(qubit) for qubit in qubits)
     assert bit_value_sum == 0 or bit_value_sum == 5
 
     qb1 = WeakQubitRef(engine=eng, idx=qubits[0].id)
@@ -644,7 +643,7 @@ def test_simulator_no_uncompute_exception(sim):
     assert qubit[0].id == -1
 
 
-class MockSimulatorBackend(object):
+class MockSimulatorBackend:
     def __init__(self):
         self.run_cnt = 0
 
diff --git a/projectq/backends/_sim/_simulator_test_fixtures.py b/projectq/backends/_sim/_simulator_test_fixtures.py
index 8d256fbc2..e04f9084d 100644
--- a/projectq/backends/_sim/_simulator_test_fixtures.py
+++ b/projectq/backends/_sim/_simulator_test_fixtures.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/backends/_unitary.py b/projectq/backends/_unitary.py
index 74fc47f17..a8941b1e3 100644
--- a/projectq/backends/_unitary.py
+++ b/projectq/backends/_unitary.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -146,7 +145,7 @@ def is_available(self, cmd):
         try:
             gate_mat = cmd.gate.matrix
             if len(gate_mat) > 2**6:
-                warnings.warn("Potentially large matrix gate encountered! ({} qubits)".format(math.log2(len(gate_mat))))
+                warnings.warn(f"Potentially large matrix gate encountered! ({math.log2(len(gate_mat))} qubits)")
             return True
         except AttributeError:
             return False
diff --git a/projectq/backends/_unitary_test.py b/projectq/backends/_unitary_test.py
index bd150697a..4053bd413 100644
--- a/projectq/backends/_unitary_test.py
+++ b/projectq/backends/_unitary_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -258,7 +257,7 @@ def test_unitary_functional_measurement():
     eng.flush()
     All(Measure) | qubits
 
-    bit_value_sum = sum([int(qubit) for qubit in qubits])
+    bit_value_sum = sum(int(qubit) for qubit in qubits)
     assert bit_value_sum == 0 or bit_value_sum == 5
 
     qb1 = WeakQubitRef(engine=eng, idx=qubits[0].id)
diff --git a/projectq/cengines/__init__.py b/projectq/cengines/__init__.py
index e9ca6e132..aa36092f2 100755
--- a/projectq/cengines/__init__.py
+++ b/projectq/cengines/__init__.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/cengines/_basicmapper.py b/projectq/cengines/_basicmapper.py
index e81a96c19..45f477d30 100644
--- a/projectq/cengines/_basicmapper.py
+++ b/projectq/cengines/_basicmapper.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2018 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/cengines/_basicmapper_test.py b/projectq/cengines/_basicmapper_test.py
index 42c6e3cbf..2d319702d 100644
--- a/projectq/cengines/_basicmapper_test.py
+++ b/projectq/cengines/_basicmapper_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2018 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/cengines/_basics.py b/projectq/cengines/_basics.py
index a8f393a81..8737d36d9 100755
--- a/projectq/cengines/_basics.py
+++ b/projectq/cengines/_basics.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -31,9 +30,9 @@ def __init__(self, engine):
         """Initialize the exception."""
         super().__init__(
             (
-                "\nERROR: Sending to next engine failed. {} as last engine?\nIf this is legal, please override"
-                "'isAvailable' to adapt its behavior."
-            ).format(engine.__class__.__name__),
+                f"\nERROR: Sending to next engine failed. {engine.__class__.__name__} as last engine?"
+                "\nIf this is legal, please override 'isAvailable' to adapt its behavior."
+            ),
         )
 
 
diff --git a/projectq/cengines/_basics_test.py b/projectq/cengines/_basics_test.py
index cb4b2e0b2..b521abf28 100755
--- a/projectq/cengines/_basics_test.py
+++ b/projectq/cengines/_basics_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/cengines/_cmdmodifier.py b/projectq/cengines/_cmdmodifier.py
index f5deae94a..1f8769304 100755
--- a/projectq/cengines/_cmdmodifier.py
+++ b/projectq/cengines/_cmdmodifier.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -42,6 +41,8 @@ def __init__(self, cmd_mod_fun):
 
                 def cmd_mod_fun(cmd):
                     cmd.tags += [MyOwnTag()]
+
+
                 compiler_engine = CommandModifier(cmd_mod_fun)
                 ...
         """
diff --git a/projectq/cengines/_cmdmodifier_test.py b/projectq/cengines/_cmdmodifier_test.py
index 5b7ed9fb6..06fd5ae82 100755
--- a/projectq/cengines/_cmdmodifier_test.py
+++ b/projectq/cengines/_cmdmodifier_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/cengines/_ibm5qubitmapper.py b/projectq/cengines/_ibm5qubitmapper.py
index 8c121ac5d..bb7549ea6 100755
--- a/projectq/cengines/_ibm5qubitmapper.py
+++ b/projectq/cengines/_ibm5qubitmapper.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/cengines/_ibm5qubitmapper_test.py b/projectq/cengines/_ibm5qubitmapper_test.py
index d56e9e7ed..f0b3285b4 100755
--- a/projectq/cengines/_ibm5qubitmapper_test.py
+++ b/projectq/cengines/_ibm5qubitmapper_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/cengines/_linearmapper.py b/projectq/cengines/_linearmapper.py
index 098d464a1..ca4b45320 100644
--- a/projectq/cengines/_linearmapper.py
+++ b/projectq/cengines/_linearmapper.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2018 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -162,7 +161,7 @@ def return_new_mapping(num_qubits, cyclic, currently_allocated_ids, stored_comma
                     qubit_ids.append(qubit.id)
 
             if len(qubit_ids) > 2 or len(qubit_ids) == 0:
-                raise Exception("Invalid command (number of qubits): " + str(cmd))
+                raise Exception(f"Invalid command (number of qubits): {str(cmd)}")
 
             if isinstance(cmd.gate, AllocateQubitGate):
                 qubit_id = cmd.qubits[0][0].id
diff --git a/projectq/cengines/_linearmapper_test.py b/projectq/cengines/_linearmapper_test.py
index 0b414fd12..5a5657adf 100644
--- a/projectq/cengines/_linearmapper_test.py
+++ b/projectq/cengines/_linearmapper_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2018 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/cengines/_main.py b/projectq/cengines/_main.py
index 6f13e25e0..dfbf5b7e4 100755
--- a/projectq/cengines/_main.py
+++ b/projectq/cengines/_main.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -90,7 +89,8 @@ def __init__(  # pylint: disable=too-many-statements,too-many-branches
             .. code-block:: python
 
                 from projectq import MainEngine
-                eng = MainEngine() # uses default engine_list and the Simulator
+
+                eng = MainEngine()  # uses default engine_list and the Simulator
 
         Instead of the default `engine_list` one can use, e.g., one of the IBM
         setups which defines a custom `engine_list` useful for one of the IBM
@@ -101,6 +101,7 @@ def __init__(  # pylint: disable=too-many-statements,too-many-branches
 
                 import projectq.setups.ibm as ibm_setup
                 from projectq import MainEngine
+
                 eng = MainEngine(engine_list=ibm_setup.get_engine_list())
                 # eng uses the default Simulator backend
 
@@ -109,14 +110,17 @@ def __init__(  # pylint: disable=too-many-statements,too-many-branches
         Example:
             .. code-block:: python
 
-                from projectq.cengines import (TagRemover, AutoReplacer,
-                                               LocalOptimizer,
-                                               DecompositionRuleSet)
+                from projectq.cengines import (
+                    TagRemover,
+                    AutoReplacer,
+                    LocalOptimizer,
+                    DecompositionRuleSet,
+                )
                 from projectq.backends import Simulator
                 from projectq import MainEngine
+
                 rule_set = DecompositionRuleSet()
-                engines = [AutoReplacer(rule_set), TagRemover(),
-                           LocalOptimizer(3)]
+                engines = [AutoReplacer(rule_set), TagRemover(), LocalOptimizer(3)]
                 eng = MainEngine(Simulator(), engines)
         """
         super().__init__()
@@ -250,8 +254,9 @@ def get_measurement_result(self, qubit):
 
                 from projectq.ops import H, Measure
                 from projectq import MainEngine
+
                 eng = MainEngine()
-                qubit = eng.allocate_qubit() # quantum register of size 1
+                qubit = eng.allocate_qubit()  # quantum register of size 1
                 H | qubit
                 Measure | qubit
                 eng.get_measurement_result(qubit[0]) == int(qubit)
diff --git a/projectq/cengines/_main_test.py b/projectq/cengines/_main_test.py
index 6600fd865..392fff73a 100755
--- a/projectq/cengines/_main_test.py
+++ b/projectq/cengines/_main_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017, 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/cengines/_manualmapper.py b/projectq/cengines/_manualmapper.py
index 8699feb88..4e7701021 100755
--- a/projectq/cengines/_manualmapper.py
+++ b/projectq/cengines/_manualmapper.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/cengines/_manualmapper_test.py b/projectq/cengines/_manualmapper_test.py
index c84301742..f627bea2f 100755
--- a/projectq/cengines/_manualmapper_test.py
+++ b/projectq/cengines/_manualmapper_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/cengines/_optimize.py b/projectq/cengines/_optimize.py
index 957ec63f8..8d6b83678 100755
--- a/projectq/cengines/_optimize.py
+++ b/projectq/cengines/_optimize.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/cengines/_optimize_test.py b/projectq/cengines/_optimize_test.py
index 104dfcef3..72aa4656e 100755
--- a/projectq/cengines/_optimize_test.py
+++ b/projectq/cengines/_optimize_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/cengines/_replacer/__init__.py b/projectq/cengines/_replacer/__init__.py
index bae476ff6..312e4b22e 100755
--- a/projectq/cengines/_replacer/__init__.py
+++ b/projectq/cengines/_replacer/__init__.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/cengines/_replacer/_decomposition_rule.py b/projectq/cengines/_replacer/_decomposition_rule.py
index 812ca1e81..24392fe24 100755
--- a/projectq/cengines/_replacer/_decomposition_rule.py
+++ b/projectq/cengines/_replacer/_decomposition_rule.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/cengines/_replacer/_decomposition_rule_set.py b/projectq/cengines/_replacer/_decomposition_rule_set.py
index 738ea0420..9cdb5d9da 100755
--- a/projectq/cengines/_replacer/_decomposition_rule_set.py
+++ b/projectq/cengines/_replacer/_decomposition_rule_set.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -103,8 +102,7 @@ def recogn_toffoli(cmd):
 
         .. code-block:: python
 
-            register_decomposition(X.__class__, decompose_toffoli,
-                                   recogn_toffoli)
+            register_decomposition(X.__class__, decompose_toffoli, recogn_toffoli)
 
         Note:
             See projectq.setups.decompositions for more example codes.
diff --git a/projectq/cengines/_replacer/_decomposition_rule_test.py b/projectq/cengines/_replacer/_decomposition_rule_test.py
index a67759dc7..1989275d6 100755
--- a/projectq/cengines/_replacer/_decomposition_rule_test.py
+++ b/projectq/cengines/_replacer/_decomposition_rule_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/cengines/_replacer/_replacer.py b/projectq/cengines/_replacer/_replacer.py
index a0a942196..69cedf7ac 100755
--- a/projectq/cengines/_replacer/_replacer.py
+++ b/projectq/cengines/_replacer/_replacer.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -113,6 +112,8 @@ def __init__(
 
             def decomposition_chooser(cmd, decomp_list):
                 return decomp_list[0]
+
+
             repl = AutoReplacer(decomposition_chooser)
         """
         super().__init__()
@@ -186,7 +187,7 @@ def _process_command(self, cmd):  # pylint: disable=too-many-locals,too-many-bra
                             break
 
                 if len(decomp_list) == 0:
-                    raise NoGateDecompositionError("\nNo replacement found for " + str(cmd) + "!")
+                    raise NoGateDecompositionError(f"\nNo replacement found for {str(cmd)}!")
 
                 # use decomposition chooser to determine the best decomposition
                 chosen_decomp = self._decomp_chooser(cmd, decomp_list)
diff --git a/projectq/cengines/_replacer/_replacer_test.py b/projectq/cengines/_replacer/_replacer_test.py
index dbf68ea2e..b6dabffa2 100755
--- a/projectq/cengines/_replacer/_replacer_test.py
+++ b/projectq/cengines/_replacer/_replacer_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/cengines/_swapandcnotflipper.py b/projectq/cengines/_swapandcnotflipper.py
index 2d7943abb..d25ac7222 100755
--- a/projectq/cengines/_swapandcnotflipper.py
+++ b/projectq/cengines/_swapandcnotflipper.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -89,7 +88,7 @@ def _needs_flipping(self, cmd):
         control = cmd.control_qubits[0].id
         is_possible = (control, target) in self.connectivity
         if not is_possible and (target, control) not in self.connectivity:
-            raise RuntimeError("The provided connectivity does not allow to execute the CNOT gate {}.".format(str(cmd)))
+            raise RuntimeError(f"The provided connectivity does not allow to execute the CNOT gate {str(cmd)}.")
         return not is_possible
 
     def _send_cnot(self, cmd, control, target, flip=False):
@@ -139,9 +138,7 @@ def receive(self, command_list):
                     control = [qubits[1]]
                     target = [qubits[0]]
                 else:
-                    raise RuntimeError(
-                        "The provided connectivity does not allow to execute the Swap gate {}.".format(str(cmd))
-                    )
+                    raise RuntimeError(f"The provided connectivity does not allow to execute the Swap gate {str(cmd)}.")
                 self._send_cnot(cmd, control, target)
                 self._send_cnot(cmd, target, control, True)
                 self._send_cnot(cmd, control, target)
diff --git a/projectq/cengines/_swapandcnotflipper_test.py b/projectq/cengines/_swapandcnotflipper_test.py
index dc9611a48..c00fe0805 100755
--- a/projectq/cengines/_swapandcnotflipper_test.py
+++ b/projectq/cengines/_swapandcnotflipper_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/cengines/_tagremover.py b/projectq/cengines/_tagremover.py
index 2c6497ac5..a939366ef 100755
--- a/projectq/cengines/_tagremover.py
+++ b/projectq/cengines/_tagremover.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -48,7 +47,7 @@ def __init__(self, tags=None):
         elif isinstance(tags, list):
             self._tags = tags
         else:
-            raise TypeError('tags should be a list! Got: {}'.format(tags))
+            raise TypeError(f'tags should be a list! Got: {tags}')
 
     def receive(self, command_list):
         """
diff --git a/projectq/cengines/_tagremover_test.py b/projectq/cengines/_tagremover_test.py
index c9679dcd0..6d61dad8a 100755
--- a/projectq/cengines/_tagremover_test.py
+++ b/projectq/cengines/_tagremover_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -34,7 +33,7 @@ def test_tagremover_invalid():
 
 def test_tagremover():
     backend = DummyEngine(save_commands=True)
-    tag_remover = _tagremover.TagRemover([type("")])
+    tag_remover = _tagremover.TagRemover([str])
     eng = MainEngine(backend=backend, engine_list=[tag_remover])
     # Create a command_list and check if "NewTag" is removed
     qubit = eng.allocate_qubit()
diff --git a/projectq/cengines/_testengine.py b/projectq/cengines/_testengine.py
index c89b42095..2933bde82 100755
--- a/projectq/cengines/_testengine.py
+++ b/projectq/cengines/_testengine.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -95,10 +94,10 @@ def __str__(self):
         """Return a string representation of the object."""
         string = ""
         for qubit_id, _l in enumerate(self._l):
-            string += "Qubit {0} : ".format(qubit_id)
+            string += f"Qubit {qubit_id} : "
             for command in self._l[qubit_id]:
-                string += str(command) + ", "
-            string = string[:-2] + "\n"
+                string += f"{str(command)}, "
+            string = f"{string[:-2]}\n"
         return string
 
 
diff --git a/projectq/cengines/_testengine_test.py b/projectq/cengines/_testengine_test.py
index fee0866e5..ff0786ff0 100755
--- a/projectq/cengines/_testengine_test.py
+++ b/projectq/cengines/_testengine_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -28,9 +27,8 @@ def test_compare_engine_str():
     CNOT | (qb0, qb1)
     eng.flush()
     expected = (
-        "Qubit 0 : Allocate | Qureg[0], H | Qureg[0], "
-        + "CX | ( Qureg[0], Qureg[1] )\nQubit 1 : Allocate | Qureg[1],"
-        + " CX | ( Qureg[0], Qureg[1] )\n"
+        "Qubit 0 : Allocate | Qureg[0], H | Qureg[0], CX | ( Qureg[0], Qureg[1] )\n"
+        "Qubit 1 : Allocate | Qureg[1], CX | ( Qureg[0], Qureg[1] )\n"
     )
     assert str(compare_engine) == expected
 
diff --git a/projectq/cengines/_twodmapper.py b/projectq/cengines/_twodmapper.py
index 5aa1dc26f..7a54a0291 100644
--- a/projectq/cengines/_twodmapper.py
+++ b/projectq/cengines/_twodmapper.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2018 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/cengines/_twodmapper_test.py b/projectq/cengines/_twodmapper_test.py
index f86c4ee02..5722b21c9 100644
--- a/projectq/cengines/_twodmapper_test.py
+++ b/projectq/cengines/_twodmapper_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2018 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/libs/__init__.py b/projectq/libs/__init__.py
index 0690f2b10..a60e7ce84 100755
--- a/projectq/libs/__init__.py
+++ b/projectq/libs/__init__.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/libs/hist/__init__.py b/projectq/libs/hist/__init__.py
index b4e9085db..07911534a 100644
--- a/projectq/libs/hist/__init__.py
+++ b/projectq/libs/hist/__init__.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2020 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/libs/hist/_histogram.py b/projectq/libs/hist/_histogram.py
index 18a674e23..d2bf255aa 100644
--- a/projectq/libs/hist/_histogram.py
+++ b/projectq/libs/hist/_histogram.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2020 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -47,7 +46,7 @@ def histogram(backend, qureg):
             qubit_list.append(qb)
 
     if len(qubit_list) > 5:
-        print('Warning: For {0} qubits there are 2^{0} different outcomes'.format(len(qubit_list)))
+        print(f'Warning: For {len(qubit_list)} qubits there are 2^{len(qubit_list)} different outcomes')
         print("The resulting histogram may look bad and/or take too long.")
         print("Consider calling histogram() with a sublist of the qubits.")
 
diff --git a/projectq/libs/hist/_histogram_test.py b/projectq/libs/hist/_histogram_test.py
index 6181a0161..55d6fb470 100644
--- a/projectq/libs/hist/_histogram_test.py
+++ b/projectq/libs/hist/_histogram_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2020 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/libs/math/__init__.py b/projectq/libs/math/__init__.py
index 06dc384c7..c2433cf34 100755
--- a/projectq/libs/math/__init__.py
+++ b/projectq/libs/math/__init__.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/libs/math/_constantmath.py b/projectq/libs/math/_constantmath.py
index 1b502aabc..14c87e7b4 100755
--- a/projectq/libs/math/_constantmath.py
+++ b/projectq/libs/math/_constantmath.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2020 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/libs/math/_constantmath_test.py b/projectq/libs/math/_constantmath_test.py
index aafcff127..d4ff4cf4d 100755
--- a/projectq/libs/math/_constantmath_test.py
+++ b/projectq/libs/math/_constantmath_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2020 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/libs/math/_default_rules.py b/projectq/libs/math/_default_rules.py
index ca4ad4a4f..7243feae4 100755
--- a/projectq/libs/math/_default_rules.py
+++ b/projectq/libs/math/_default_rules.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2020 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/libs/math/_gates.py b/projectq/libs/math/_gates.py
index e541a34ea..ed6d9d26c 100755
--- a/projectq/libs/math/_gates.py
+++ b/projectq/libs/math/_gates.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2020 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -25,9 +24,9 @@ class AddConstant(BasicMathGate):
     Example:
         .. code-block:: python
 
-            qunum = eng.allocate_qureg(5) # 5-qubit number
-            X | qunum[1] # qunum is now equal to 2
-            AddConstant(3) | qunum # qunum is now equal to 5
+            qunum = eng.allocate_qureg(5)  # 5-qubit number
+            X | qunum[1]  # qunum is now equal to 2
+            AddConstant(3) | qunum  # qunum is now equal to 5
 
     Important: if you run with conditional and carry, carry needs to
     be a quantum register for the compiler/decomposition to work.
@@ -52,7 +51,7 @@ def get_inverse(self):
 
     def __str__(self):
         """Return a string representation of the object."""
-        return "AddConstant({})".format(self.a)
+        return f"AddConstant({self.a})"
 
     def __eq__(self, other):
         """Equal operator."""
@@ -73,9 +72,9 @@ def SubConstant(a):  # pylint: disable=invalid-name
     Example:
         .. code-block:: python
 
-            qunum = eng.allocate_qureg(5) # 5-qubit number
-            X | qunum[2] # qunum is now equal to 4
-            SubConstant(3) | qunum # qunum is now equal to 1
+            qunum = eng.allocate_qureg(5)  # 5-qubit number
+            X | qunum[2]  # qunum is now equal to 4
+            SubConstant(3) | qunum  # qunum is now equal to 1
     """
     return AddConstant(-a)
 
@@ -89,9 +88,9 @@ class AddConstantModN(BasicMathGate):
     Example:
         .. code-block:: python
 
-            qunum = eng.allocate_qureg(5) # 5-qubit number
-            X | qunum[1] # qunum is now equal to 2
-            AddConstantModN(3, 4) | qunum # qunum is now equal to 1
+            qunum = eng.allocate_qureg(5)  # 5-qubit number
+            X | qunum[1]  # qunum is now equal to 2
+            AddConstantModN(3, 4) | qunum  # qunum is now equal to 1
 
     .. note::
 
@@ -119,7 +118,7 @@ def __init__(self, a, N):
 
     def __str__(self):
         """Return a string representation of the object."""
-        return "AddConstantModN({}, {})".format(self.a, self.N)
+        return f"AddConstantModN({self.a}, {self.N})"
 
     def get_inverse(self):
         """Return the inverse gate (subtraction of the same number a modulo the same number N)."""
@@ -147,9 +146,9 @@ def SubConstantModN(a, N):  # pylint: disable=invalid-name
     Example:
         .. code-block:: python
 
-            qunum = eng.allocate_qureg(3) # 3-qubit number
-            X | qunum[1] # qunum is now equal to 2
-            SubConstantModN(4,5) | qunum # qunum is now -2 = 6 = 1 (mod 5)
+            qunum = eng.allocate_qureg(3)  # 3-qubit number
+            X | qunum[1]  # qunum is now equal to 2
+            SubConstantModN(4, 5) | qunum  # qunum is now -2 = 6 = 1 (mod 5)
 
     .. note::
 
@@ -171,9 +170,9 @@ class MultiplyByConstantModN(BasicMathGate):
     Example:
         .. code-block:: python
 
-            qunum = eng.allocate_qureg(5) # 5-qubit number
-            X | qunum[2] # qunum is now equal to 4
-            MultiplyByConstantModN(3,5) | qunum # qunum is now 2.
+            qunum = eng.allocate_qureg(5)  # 5-qubit number
+            X | qunum[2]  # qunum is now equal to 4
+            MultiplyByConstantModN(3, 5) | qunum  # qunum is now 2.
 
     .. note::
 
@@ -203,7 +202,7 @@ def __init__(self, a, N):  # pylint: disable=invalid-name
 
     def __str__(self):
         """Return a string representation of the object."""
-        return "MultiplyByConstantModN({}, {})".format(self.a, self.N)
+        return f"MultiplyByConstantModN({self.a}, {self.N})"
 
     def __eq__(self, other):
         """Equal operator."""
@@ -223,12 +222,12 @@ class AddQuantumGate(BasicMathGate):
     Example:
         .. code-block:: python
 
-            qunum_a = eng.allocate_qureg(5) # 5-qubit number
-            qunum_b = eng.allocate_qureg(5) # 5-qubit number
+            qunum_a = eng.allocate_qureg(5)  # 5-qubit number
+            qunum_b = eng.allocate_qureg(5)  # 5-qubit number
             carry_bit = eng.allocate_qubit()
 
-            X | qunum_a[2] #qunum_a is now equal to 4
-            X | qunum_b[3] #qunum_b is now equal to 8
+            X | qunum_a[2]  # qunum_a is now equal to 4
+            X | qunum_b[3]  # qunum_b is now equal to 8
             AddQuantum | (qunum_a, qunum_b, carry)
             # qunum_a remains 4, qunum_b is now 12 and carry_bit is 0
     """
@@ -303,10 +302,10 @@ class SubtractQuantumGate(BasicMathGate):
     Example:
     .. code-block:: python
 
-            qunum_a = eng.allocate_qureg(5) # 5-qubit number
-            qunum_b = eng.allocate_qureg(5) # 5-qubit number
-            X | qunum_a[2] #qunum_a is now equal to 4
-            X | qunum_b[3] #qunum_b is now equal to 8
+            qunum_a = eng.allocate_qureg(5)  # 5-qubit number
+            qunum_b = eng.allocate_qureg(5)  # 5-qubit number
+            X | qunum_a[2]  # qunum_a is now equal to 4
+            X | qunum_b[3]  # qunum_b is now equal to 8
             SubtractQuantum | (qunum_a, qunum_b)
             # qunum_a remains 4, qunum_b is now 4
 
@@ -353,15 +352,13 @@ class ComparatorQuantumGate(BasicMathGate):
     Example:
         .. code-block:: python
 
-            qunum_a = eng.allocate_qureg(5) # 5-qubit number
-            qunum_b = eng.allocate_qureg(5) # 5-qubit number
+            qunum_a = eng.allocate_qureg(5)  # 5-qubit number
+            qunum_b = eng.allocate_qureg(5)  # 5-qubit number
             compare_bit = eng.allocate_qubit()
-            X | qunum_a[4] #qunum_a is now equal to 16
-            X | qunum_b[3] #qunum_b is now equal to 8
+            X | qunum_a[4]  # qunum_a is now equal to 16
+            X | qunum_b[3]  # qunum_b is now equal to 8
             ComparatorQuantum | (qunum_a, qunum_b, compare_bit)
-            # qunum_a and qunum_b remain 16 and 8, qunum_b is now 12 and
-            compare bit is now 1
-
+            # qunum_a and qunum_b remain 16 and 8, qunum_b is now 12 and compare bit is now 1
     """
 
     def __init__(self):
@@ -416,18 +413,18 @@ class DivideQuantumGate(BasicMathGate):
     Example:
     .. code-block:: python
 
-            qunum_a = eng.allocate_qureg(5) # 5-qubit number
-            qunum_b = eng.allocate_qureg(5) # 5-qubit number
-            qunum_c = eng.allocate_qureg(5) # 5-qubit number
+            qunum_a = eng.allocate_qureg(5)  # 5-qubit number
+            qunum_b = eng.allocate_qureg(5)  # 5-qubit number
+            qunum_c = eng.allocate_qureg(5)  # 5-qubit number
 
-            All(X) | [qunum_a[0],qunum_a[3]] #qunum_a is now equal to 9
-            X | qunum_c[2] #qunum_c is now equal to 4
+            All(X) | [qunum_a[0], qunum_a[3]]  # qunum_a is now equal to 9
+            X | qunum_c[2]  # qunum_c is now equal to 4
 
-            DivideQuantum | (qunum_a, qunum_b,qunum_c)
+            DivideQuantum | (qunum_a, qunum_b, qunum_c)
             # qunum_a is now equal to 1 (remainder), qunum_b is now
             # equal to 2 (quotient) and qunum_c remains 4 (divisor)
 
-            |dividend>|remainder>|divisor> -> |remainder>|quotient>|divisor>
+            # |dividend>|remainder>|divisor> -> |remainder>|quotient>|divisor>
     """
 
     def __init__(self):
@@ -499,13 +496,13 @@ class MultiplyQuantumGate(BasicMathGate):
     Example:
         .. code-block:: python
 
-        qunum_a = eng.allocate_qureg(4)
-        qunum_b = eng.allocate_qureg(4)
-        qunum_c = eng.allocate_qureg(9)
-        X | qunum_a[2] # qunum_a is now 4
-        X | qunum_b[3] # qunum_b is now 8
-        MultiplyQuantum() | (qunum_a, qunum_b, qunum_c)
-        # qunum_a remains 4 and qunum_b remains 8, qunum_c is now equal to 32
+            qunum_a = eng.allocate_qureg(4)
+            qunum_b = eng.allocate_qureg(4)
+            qunum_c = eng.allocate_qureg(9)
+            X | qunum_a[2]  # qunum_a is now 4
+            X | qunum_b[3]  # qunum_b is now 8
+            MultiplyQuantum() | (qunum_a, qunum_b, qunum_c)
+            # qunum_a remains 4 and qunum_b remains 8, qunum_c is now equal to 32
     """
 
     def __init__(self):
diff --git a/projectq/libs/math/_gates_math_test.py b/projectq/libs/math/_gates_math_test.py
index 8463fa75b..6bf28f77c 100644
--- a/projectq/libs/math/_gates_math_test.py
+++ b/projectq/libs/math/_gates_math_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2020 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -43,7 +42,7 @@ def print_all_probabilities(eng, qureg):
     i = 0
     y = len(qureg)
     while i < (2**y):
-        qubit_list = [int(x) for x in list(('{0:0b}'.format(i)).zfill(y))]
+        qubit_list = [int(x) for x in list((f'{i:0b}').zfill(y))]
         qubit_list = qubit_list[::-1]
         prob = eng.backend.get_probability(qubit_list, qureg)
         if prob != 0.0:
diff --git a/projectq/libs/math/_gates_test.py b/projectq/libs/math/_gates_test.py
index aa78ebf8e..6eb9613e9 100755
--- a/projectq/libs/math/_gates_test.py
+++ b/projectq/libs/math/_gates_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2020 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/libs/math/_quantummath.py b/projectq/libs/math/_quantummath.py
index 8b66fbb69..fb3dcbdc6 100644
--- a/projectq/libs/math/_quantummath.py
+++ b/projectq/libs/math/_quantummath.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2020 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/libs/math/_quantummath_test.py b/projectq/libs/math/_quantummath_test.py
index c71ae0ef7..d32715ca6 100644
--- a/projectq/libs/math/_quantummath_test.py
+++ b/projectq/libs/math/_quantummath_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2020 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -35,7 +34,7 @@ def print_all_probabilities(eng, qureg):
     i = 0
     y = len(qureg)
     while i < (2**y):
-        qubit_list = [int(x) for x in list(('{0:0b}'.format(i)).zfill(y))]
+        qubit_list = [int(x) for x in list((f'{i:0b}').zfill(y))]
         qubit_list = qubit_list[::-1]
         prob = eng.backend.get_probability(qubit_list, qureg)
         if prob != 0.0:
diff --git a/projectq/libs/revkit/__init__.py b/projectq/libs/revkit/__init__.py
index a411ab55d..e527091be 100644
--- a/projectq/libs/revkit/__init__.py
+++ b/projectq/libs/revkit/__init__.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/libs/revkit/_control_function.py b/projectq/libs/revkit/_control_function.py
index 341cb5f9f..c20db35f5 100644
--- a/projectq/libs/revkit/_control_function.py
+++ b/projectq/libs/revkit/_control_function.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -38,7 +37,7 @@ class ControlFunctionOracle:  # pylint: disable=too-few-public-methods
 
         .. code-block:: python
 
-            ControlFunctionOracle(0x8e) | ([a, b, c], d)
+            ControlFunctionOracle(0x8E) | ([a, b, c], d)
     """
 
     def __init__(self, function, **kwargs):
@@ -103,7 +102,7 @@ def __or__(self, qubits):
 
         # create truth table from function integer
         hex_length = max(2 ** (len(qs) - 1) // 4, 1)
-        revkit.tt(table="{0:#0{1}x}".format(self.function, hex_length))
+        revkit.tt(table=f"{self.function:#0{hex_length}x}")
 
         # create reversible circuit from truth table
         self.kwargs.get("synth", revkit.esopbs)()
diff --git a/projectq/libs/revkit/_control_function_test.py b/projectq/libs/revkit/_control_function_test.py
index 3ea58c58a..ff4d24fe5 100644
--- a/projectq/libs/revkit/_control_function_test.py
+++ b/projectq/libs/revkit/_control_function_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/libs/revkit/_permutation.py b/projectq/libs/revkit/_permutation.py
index b5bc522b1..87f6e09f1 100644
--- a/projectq/libs/revkit/_permutation.py
+++ b/projectq/libs/revkit/_permutation.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/libs/revkit/_permutation_test.py b/projectq/libs/revkit/_permutation_test.py
index 06c9e0d33..19d7be0ac 100644
--- a/projectq/libs/revkit/_permutation_test.py
+++ b/projectq/libs/revkit/_permutation_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/libs/revkit/_phase.py b/projectq/libs/revkit/_phase.py
index edfc0afef..399697449 100644
--- a/projectq/libs/revkit/_phase.py
+++ b/projectq/libs/revkit/_phase.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -38,7 +37,7 @@ class PhaseOracle:  # pylint: disable=too-few-public-methods
 
         .. code-block:: python
 
-            PhaseOracle(0x8e) | (a, b, c)
+            PhaseOracle(0x8E) | (a, b, c)
     """
 
     def __init__(self, function, **kwargs):
@@ -99,7 +98,7 @@ def __or__(self, qubits):
 
         # create truth table from function integer
         hex_length = max(2 ** (len(qs) - 1) // 4, 1)
-        revkit.tt(table="{0:#0{1}x}".format(self.function, hex_length))
+        revkit.tt(table=f"{self.function:#0{hex_length}x}")
 
         # create phase circuit from truth table
         self.kwargs.get("synth", revkit.esopps)()
diff --git a/projectq/libs/revkit/_phase_test.py b/projectq/libs/revkit/_phase_test.py
index 5c06a9162..37152e027 100644
--- a/projectq/libs/revkit/_phase_test.py
+++ b/projectq/libs/revkit/_phase_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/libs/revkit/_utils.py b/projectq/libs/revkit/_utils.py
index 7fd44ca9a..e1f47c025 100644
--- a/projectq/libs/revkit/_utils.py
+++ b/projectq/libs/revkit/_utils.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/meta/__init__.py b/projectq/meta/__init__.py
index 634b046c7..764081800 100755
--- a/projectq/meta/__init__.py
+++ b/projectq/meta/__init__.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/meta/_compute.py b/projectq/meta/_compute.py
index dcf7932ab..295c4b7a4 100755
--- a/projectq/meta/_compute.py
+++ b/projectq/meta/_compute.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -259,7 +258,7 @@ class Compute:
             with Compute(eng):
                 do_something(qubits)
             action(qubits)
-            Uncompute(eng) # runs inverse of the compute section
+            Uncompute(eng)  # runs inverse of the compute section
 
     Warning:
         If qubits are allocated within the compute section, they must either be uncomputed and deallocated within that
@@ -279,7 +278,7 @@ class Compute:
             do_something_else(qubits)
 
             Uncompute(eng)  # will allocate a new ancilla (with a different id)
-                            # and then deallocate it again
+            # and then deallocate it again
 
         .. code-block:: python
 
@@ -400,7 +399,7 @@ def Uncompute(engine):  # pylint: disable=invalid-name
             with Compute(eng):
                 do_something(qubits)
             action(qubits)
-            Uncompute(eng) # runs inverse of the compute section
+            Uncompute(eng)  # runs inverse of the compute section
     """
     compute_eng = engine.next_engine
     if not isinstance(compute_eng, ComputeEngine):
diff --git a/projectq/meta/_compute_test.py b/projectq/meta/_compute_test.py
index 1a87d413f..b32cd1f2f 100755
--- a/projectq/meta/_compute_test.py
+++ b/projectq/meta/_compute_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -29,7 +28,7 @@ def test_compute_tag():
     tag0 = _compute.ComputeTag()
     tag1 = _compute.ComputeTag()
 
-    class MyTag(object):
+    class MyTag:
         pass
 
     assert not tag0 == MyTag()
@@ -41,7 +40,7 @@ def test_uncompute_tag():
     tag0 = _compute.UncomputeTag()
     tag1 = _compute.UncomputeTag()
 
-    class MyTag(object):
+    class MyTag:
         pass
 
     assert not tag0 == MyTag()
diff --git a/projectq/meta/_control.py b/projectq/meta/_control.py
index 90c97e503..543ebfe80 100755
--- a/projectq/meta/_control.py
+++ b/projectq/meta/_control.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -62,12 +61,11 @@ def canonical_ctrl_state(ctrl_state, num_qubits):
 
     if isinstance(ctrl_state, int):
         # If the user inputs an integer, convert it to binary bit string
-        converted_str = '{0:b}'.format(ctrl_state).zfill(num_qubits)[::-1]
+        converted_str = f'{ctrl_state:b}'.zfill(num_qubits)[::-1]
         if len(converted_str) != num_qubits:
             raise ValueError(
-                'Control state specified as {} ({}) is higher than maximum for {} qubits: {}'.format(
-                    ctrl_state, converted_str, num_qubits, 2**num_qubits - 1
-                )
+                f'Control state specified as {ctrl_state} ({converted_str}) is higher than maximum for {num_qubits} '
+                f'qubits: {2 ** num_qubits - 1}'
             )
         return converted_str
 
@@ -75,12 +73,10 @@ def canonical_ctrl_state(ctrl_state, num_qubits):
         # If the user inputs bit string, directly use it
         if len(ctrl_state) != num_qubits:
             raise ValueError(
-                'Control state {} has different length than the number of control qubits {}'.format(
-                    ctrl_state, num_qubits
-                )
+                f'Control state {ctrl_state} has different length than the number of control qubits {num_qubits}'
             )
         if not set(ctrl_state).issubset({'0', '1'}):
-            raise ValueError('Control state {} has string other than 1 and 0'.format(ctrl_state))
+            raise ValueError(f'Control state {ctrl_state} has string other than 1 and 0')
         return ctrl_state
 
     raise TypeError('Input must be a string, an integer or an enum value of class State')
diff --git a/projectq/meta/_control_test.py b/projectq/meta/_control_test.py
index e30bda335..73810b95e 100755
--- a/projectq/meta/_control_test.py
+++ b/projectq/meta/_control_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -36,7 +35,7 @@ def test_canonical_representation():
 
     num_qubits = 4
     for i in range(2**num_qubits):
-        state = '{0:0b}'.format(i).zfill(num_qubits)
+        state = f'{i:0b}'.zfill(num_qubits)
         assert _control.canonical_ctrl_state(i, num_qubits) == state[::-1]
         assert _control.canonical_ctrl_state(state, num_qubits) == state
 
diff --git a/projectq/meta/_dagger.py b/projectq/meta/_dagger.py
index 36ead9f48..8987b1b2a 100755
--- a/projectq/meta/_dagger.py
+++ b/projectq/meta/_dagger.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -81,7 +80,8 @@ class Dagger:
     .. code-block:: python
 
         with Dagger(eng):
-            [code to invert]
+            # [code to invert]
+            pass
 
     Warning:
         If the code to invert contains allocation of qubits, those qubits have
@@ -93,7 +93,7 @@ class Dagger:
 
             with Dagger(eng):
                 qb = eng.allocate_qubit()
-                H | qb # qb is still available!!!
+                H | qb  # qb is still available!!!
 
         The **correct way** of handling qubit (de-)allocation is as follows:
 
@@ -102,7 +102,7 @@ class Dagger:
             with Dagger(eng):
                 qb = eng.allocate_qubit()
                 ...
-                del qb # sends deallocate gate (which becomes an allocate)
+                del qb  # sends deallocate gate (which becomes an allocate)
     """
 
     def __init__(self, engine):
diff --git a/projectq/meta/_dagger_test.py b/projectq/meta/_dagger_test.py
index a95beeda1..330e0d106 100755
--- a/projectq/meta/_dagger_test.py
+++ b/projectq/meta/_dagger_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/meta/_dirtyqubit.py b/projectq/meta/_dirtyqubit.py
index 3e9ba9833..c13ed2afb 100755
--- a/projectq/meta/_dirtyqubit.py
+++ b/projectq/meta/_dirtyqubit.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/meta/_dirtyqubit_test.py b/projectq/meta/_dirtyqubit_test.py
index 74e4d94f3..09e942c1e 100755
--- a/projectq/meta/_dirtyqubit_test.py
+++ b/projectq/meta/_dirtyqubit_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/meta/_exceptions.py b/projectq/meta/_exceptions.py
index 2f12ff361..b9c5858b1 100644
--- a/projectq/meta/_exceptions.py
+++ b/projectq/meta/_exceptions.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/meta/_logicalqubit.py b/projectq/meta/_logicalqubit.py
index 2c6295235..0aaf4ddd3 100644
--- a/projectq/meta/_logicalqubit.py
+++ b/projectq/meta/_logicalqubit.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2018 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/meta/_logicalqubit_test.py b/projectq/meta/_logicalqubit_test.py
index c64a79837..43ed2943a 100644
--- a/projectq/meta/_logicalqubit_test.py
+++ b/projectq/meta/_logicalqubit_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2018 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/meta/_loop.py b/projectq/meta/_loop.py
index cc64034ca..47681b764 100755
--- a/projectq/meta/_loop.py
+++ b/projectq/meta/_loop.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,7 +19,7 @@
 
         with Loop(eng, 4):
             H | qb
-        Rz(M_PI/3.) | qb
+        Rz(M_PI / 3.0) | qb
 """
 
 from copy import deepcopy
@@ -191,6 +190,7 @@ class Loop:
 
             with Loop(eng, 4):
                 # [quantum gates to be executed 4 times]
+                pass
 
     Warning:
         If the code in the loop contains allocation of qubits, those qubits have to be deleted prior to exiting the
@@ -202,7 +202,7 @@ class Loop:
 
             with Loop(eng, 4):
                 qb = eng.allocate_qubit()
-                H | qb # qb is still available!!!
+                H | qb  # qb is still available!!!
 
         The **correct way** of handling qubit (de-)allocation is as follows:
 
@@ -210,8 +210,8 @@ class Loop:
 
             with Loop(eng, 4):
                 qb = eng.allocate_qubit()
-                ...
-                del qb # sends deallocate gate
+                # ...
+                del qb  # sends deallocate gate
     """
 
     def __init__(self, engine, num):
@@ -227,7 +227,7 @@ def __init__(self, engine, num):
 
                 with Loop(eng, 4):
                     H | qb
-                    Rz(M_PI/3.) | qb
+                    Rz(M_PI / 3.0) | qb
         Raises:
             TypeError: If number of iterations (num) is not an integer
             ValueError: If number of iterations (num) is not >= 0
diff --git a/projectq/meta/_loop_test.py b/projectq/meta/_loop_test.py
index 618c5f16a..01ef872ce 100755
--- a/projectq/meta/_loop_test.py
+++ b/projectq/meta/_loop_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/meta/_util.py b/projectq/meta/_util.py
index 414930f50..79f4dc43c 100755
--- a/projectq/meta/_util.py
+++ b/projectq/meta/_util.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/meta/_util_test.py b/projectq/meta/_util_test.py
index 90b781b53..a60d4ac51 100755
--- a/projectq/meta/_util_test.py
+++ b/projectq/meta/_util_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/ops/__init__.py b/projectq/ops/__init__.py
index 67b570263..13d23ebaf 100755
--- a/projectq/ops/__init__.py
+++ b/projectq/ops/__init__.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/ops/_basics.py b/projectq/ops/_basics.py
index 17485e921..c07563fca 100755
--- a/projectq/ops/_basics.py
+++ b/projectq/ops/_basics.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -79,26 +78,26 @@ def __init__(self):
 
             .. code-block:: python
 
-                ExampleGate | (a,b,c,d,e)
+                ExampleGate | (a, b, c, d, e)
 
             where a and b are interchangeable. Then, call this function as follows:
 
             .. code-block:: python
 
-                self.set_interchangeable_qubit_indices([[0,1]])
+                self.set_interchangeable_qubit_indices([[0, 1]])
 
             As another example, consider
 
             .. code-block:: python
 
-                ExampleGate2 | (a,b,c,d,e)
+                ExampleGate2 | (a, b, c, d, e)
 
             where a and b are interchangeable and, in addition, c, d, and e are interchangeable among
             themselves. Then, call this function as
 
             .. code-block:: python
 
-                self.set_interchangeable_qubit_indices([[0,1],[2,3,4]])
+                self.set_interchangeable_qubit_indices([[0, 1], [2, 3, 4]])
         """
         self.interchangeable_qubit_indices = []
 
@@ -290,7 +289,7 @@ def __eq__(self, other):
 
     def __str__(self):
         """Return a string representation of the object."""
-        return "MatrixGate(" + str(self.matrix.tolist()) + ")"
+        return f"MatrixGate({str(self.matrix.tolist())})"
 
     def __hash__(self):
         """Compute the hash of the object."""
@@ -362,9 +361,9 @@ def to_string(self, symbols=False):
                             angle written in radian otherwise.
         """
         if symbols:
-            angle = "(" + str(round(self.angle / math.pi, 3)) + unicodedata.lookup("GREEK SMALL LETTER PI") + ")"
+            angle = f"({str(round(self.angle / math.pi, 3))}{unicodedata.lookup('GREEK SMALL LETTER PI')})"
         else:
-            angle = "(" + str(self.angle) + ")"
+            angle = f"({str(self.angle)})"
         return str(self.__class__.__name__) + angle
 
     def tex_str(self):
@@ -377,7 +376,7 @@ def tex_str(self):
 
             [CLASSNAME]$_[ANGLE]$
         """
-        return str(self.__class__.__name__) + "$_{" + str(round(self.angle / math.pi, 3)) + "\\pi}$"
+        return f"{str(self.__class__.__name__)}$_{{{str(round(self.angle / math.pi, 3))}\\pi}}$"
 
     def get_inverse(self):
         """Return the inverse of this rotation gate (negate the angle, return new object)."""
@@ -451,7 +450,7 @@ def __str__(self):
 
             [CLASSNAME]([ANGLE])
         """
-        return str(self.__class__.__name__) + "(" + str(self.angle) + ")"
+        return f"{str(self.__class__.__name__)}({str(self.angle)})"
 
     def tex_str(self):
         """
@@ -463,7 +462,7 @@ def tex_str(self):
 
             [CLASSNAME]$_[ANGLE]$
         """
-        return str(self.__class__.__name__) + "$_{" + str(self.angle) + "}$"
+        return f"{str(self.__class__.__name__)}$_{{{str(self.angle)}}}$"
 
     def get_inverse(self):
         """Return the inverse of this rotation gate (negate the angle, return new object)."""
@@ -545,7 +544,7 @@ class BasicMathGate(BasicGate):
     .. code-block:: python
 
         def add(x):
-            return (x+a,)
+            return (x + a,)
 
     upon initialization. More generally, the function takes integers as parameters and returns a tuple / list of
     outputs, each entry corresponding to the function input. As an example, consider out-of-place multiplication,
@@ -554,8 +553,8 @@ def add(x):
 
     .. code-block:: python
 
-        def multiply(a,b,c)
-            return (a,b,c+a*b)
+        def multiply(a, b, c):
+            return (a, b, c + a * b)
     """
 
     def __init__(self, math_fun):
@@ -569,8 +568,10 @@ def __init__(self, math_fun):
         Example:
             .. code-block:: python
 
-                def add(a,b):
-                    return (a,a+b)
+                def add(a, b):
+                    return (a, a + b)
+
+
                 super().__init__(add)
 
         If the gate acts on, e.g., fixed point numbers, the number of bits per register is also required in order to
@@ -587,9 +588,11 @@ def add(a,b):
 
                 def get_math_function(self, qubits):
                     n = len(qubits[0])
-                    scal = 2.**n
+                    scal = 2.0**n
+
                     def math_fun(a):
                         return (int(scal * (math.sin(math.pi * a / scal))),)
+
                     return math_fun
 
         """
diff --git a/projectq/ops/_basics_test.py b/projectq/ops/_basics_test.py
index af3ab34b2..35b19986d 100755
--- a/projectq/ops/_basics_test.py
+++ b/projectq/ops/_basics_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -170,7 +169,7 @@ def test_basic_rotation_gate_init(input_angle, modulo_angle):
 def test_basic_rotation_gate_str():
     gate = _basics.BasicRotationGate(math.pi)
     assert str(gate) == "BasicRotationGate(3.14159265359)"
-    assert gate.to_string(symbols=True) == u"BasicRotationGate(1.0π)"
+    assert gate.to_string(symbols=True) == "BasicRotationGate(1.0π)"
     assert gate.to_string(symbols=False) == "BasicRotationGate(3.14159265359)"
 
 
diff --git a/projectq/ops/_command.py b/projectq/ops/_command.py
index c67de0683..481efcc16 100755
--- a/projectq/ops/_command.py
+++ b/projectq/ops/_command.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -284,7 +283,7 @@ def add_control_qubits(self, qubits, state=CtrlAll.One):
             qubits, states = list(zip(*data))
             if len(set(states)) != 1:
                 raise IncompatibleControlState(
-                    'Control qubits {} cannot have conflicting control states: {}'.format(list(qubits), states)
+                    f'Control qubits {list(qubits)} cannot have conflicting control states: {states}'
                 )
 
     @property
@@ -356,6 +355,6 @@ def to_string(self, symbols=False):
             for qreg in qubits:
                 qstring += str(Qureg(qreg))
                 qstring += ", "
-            qstring = qstring[:-2] + " )"
+            qstring = f"{qstring[:-2]} )"
         cstring = "C" * len(ctrlqubits)
-        return cstring + self.gate.to_string(symbols) + " | " + qstring
+        return f"{cstring + self.gate.to_string(symbols)} | {qstring}"
diff --git a/projectq/ops/_command_test.py b/projectq/ops/_command_test.py
index 27377a558..9fcbf544e 100755
--- a/projectq/ops/_command_test.py
+++ b/projectq/ops/_command_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017, 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -219,7 +218,7 @@ def test_commmand_add_control_qubits_two(main_engine, state):
     cmd = _command.Command(main_engine, Rx(0.5), (qubit0,), qubit1)
     cmd.add_control_qubits(qubit2 + qubit3, state)
     assert cmd.control_qubits[0].id == 1
-    assert cmd.control_state == '1' + canonical_ctrl_state(state, 2)
+    assert cmd.control_state == f"1{canonical_ctrl_state(state, 2)}"
 
 
 def test_command_all_qubits(main_engine):
@@ -304,8 +303,8 @@ def test_command_to_string(main_engine):
     cmd.add_control_qubits(ctrl_qubit)
     cmd2 = _command.Command(main_engine, Rx(0.5 * math.pi), (qubit,))
 
-    assert cmd.to_string(symbols=True) == u"CRx(0.5π) | ( Qureg[1], Qureg[0] )"
-    assert cmd2.to_string(symbols=True) == u"Rx(0.5π) | Qureg[0]"
+    assert cmd.to_string(symbols=True) == "CRx(0.5π) | ( Qureg[1], Qureg[0] )"
+    assert cmd2.to_string(symbols=True) == "Rx(0.5π) | Qureg[0]"
     if sys.version_info.major == 3:
         assert cmd.to_string(symbols=False) == "CRx(1.570796326795) | ( Qureg[1], Qureg[0] )"
         assert cmd2.to_string(symbols=False) == "Rx(1.570796326795) | Qureg[0]"
diff --git a/projectq/ops/_gates.py b/projectq/ops/_gates.py
index 97acd12bc..88024b7cf 100755
--- a/projectq/ops/_gates.py
+++ b/projectq/ops/_gates.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -515,16 +514,15 @@ def __init__(self, bits_to_flip):
 
     def __str__(self):
         """Return a string representation of the object."""
-        return "FlipBits(" + str(self.bits_to_flip) + ")"
+        return f"FlipBits({self.bits_to_flip})"
 
     def __or__(self, qubits):
         """Operator| overload which enables the syntax Gate | qubits."""
         quregs_tuple = self.make_tuple_of_qureg(qubits)
         if len(quregs_tuple) > 1:
             raise ValueError(
-                self.__str__() + ' can only be applied to qubits,'
-                'quregs, arrays of qubits, and tuples with one'
-                'individual qubit'
+                f"{str(self)} can only be applied to qubits, quregs, arrays of qubits, "
+                "and tuples with one individual qubit"
             )
         for qureg in quregs_tuple:
             for i, qubit in enumerate(qureg):
@@ -539,4 +537,4 @@ def __eq__(self, other):
 
     def __hash__(self):
         """Compute the hash of the object."""
-        return hash(self.__str__())
+        return hash(str(self))
diff --git a/projectq/ops/_gates_test.py b/projectq/ops/_gates_test.py
index 12b49f7a9..ab431b923 100755
--- a/projectq/ops/_gates_test.py
+++ b/projectq/ops/_gates_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/ops/_metagates.py b/projectq/ops/_metagates.py
index f67e4927f..0c1f89f3f 100644
--- a/projectq/ops/_metagates.py
+++ b/projectq/ops/_metagates.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,7 +21,7 @@
   Example:
         .. code-block:: python
 
-          Tensor(H) | (qubit1, qubit2) # apply H to qubit #1 and #2
+          Tensor(H) | (qubit1, qubit2)  # apply H to qubit #1 and #2
 
 As well as the meta functions
 * get_inverse (Tries to access the get_inverse member function of a gate and upon failure returns a DaggeredGate)
@@ -75,13 +74,13 @@ def __init__(self, gate):
 
     def __str__(self):
         r"""Return string representation (str(gate) + \"^\dagger\")."""
-        return str(self._gate) + r"^\dagger"
+        return f"{str(self._gate)}^\\dagger"
 
     def tex_str(self):
         """Return the Latex string representation of a Daggered gate."""
         if hasattr(self._gate, 'tex_str'):
-            return self._gate.tex_str() + r"${}^\dagger$"
-        return str(self._gate) + r"${}^\dagger$"
+            return f"{self._gate.tex_str()}${{}}^\\dagger$"
+        return f"{str(self._gate)}${{}}^\\dagger$"
 
     def get_inverse(self):
         """Return the inverse gate (the inverse of the inverse of a gate is the gate itself)."""
@@ -108,7 +107,7 @@ def get_inverse(gate):
     Example:
         .. code-block:: python
 
-            get_inverse(H) # returns a Hadamard gate (HGate object)
+            get_inverse(H)  # returns a Hadamard gate (HGate object)
     """
     try:
         return gate.get_inverse()
@@ -128,8 +127,8 @@ def is_identity(gate):
     Example:
         .. code-block:: python
 
-            get_inverse(Rx(2*math.pi)) # returns True
-            get_inverse(Rx(math.pi)) # returns False
+            get_inverse(Rx(2 * math.pi))  # returns True
+            get_inverse(Rx(math.pi))  # returns False
     """
     return gate.is_identity()
 
@@ -147,9 +146,9 @@ class ControlledGate(BasicGate):
     Example:
         .. code-block:: python
 
-            ControlledGate(gate, 2) | (qb0, qb2, qb3) # qb0 & qb2 are controls
-            C(gate, 2) | (qb0, qb2, qb3) # This is much nicer.
-            C(gate, 2) | ([qb0,qb2], qb3) # Is equivalent
+            ControlledGate(gate, 2) | (qb0, qb2, qb3)  # qb0 & qb2 are controls
+            C(gate, 2) | (qb0, qb2, qb3)  # This is much nicer.
+            C(gate, 2) | ([qb0, qb2], qb3)  # Is equivalent
 
     Note:
         Use :func:`C` rather than ControlledGate, i.e.,
@@ -235,7 +234,7 @@ def C(gate, n_qubits=1):
     Example:
         .. code-block:: python
 
-            C(NOT) | (c, q) # equivalent to CNOT | (c, q)
+            C(NOT) | (c, q)  # equivalent to CNOT | (c, q)
     """
     return ControlledGate(gate, n_qubits)
 
@@ -249,8 +248,8 @@ class Tensor(BasicGate):
     Example:
         .. code-block:: python
 
-            Tensor(H) | x # applies H to every qubit in the list of qubits x
-            Tensor(H) | (x,) # alternative to be consistent with other syntax
+            Tensor(H) | x  # applies H to every qubit in the list of qubits x
+            Tensor(H) | (x,)  # alternative to be consistent with other syntax
     """
 
     def __init__(self, gate):
@@ -260,7 +259,7 @@ def __init__(self, gate):
 
     def __str__(self):
         """Return a string representation of the object."""
-        return "Tensor(" + str(self._gate) + ")"
+        return f"Tensor({str(self._gate)})"
 
     def get_inverse(self):
         """Return the inverse of this tensored gate (which is the tensored inverse of the gate)."""
diff --git a/projectq/ops/_metagates_test.py b/projectq/ops/_metagates_test.py
index e00d4b617..cacd1fb8c 100755
--- a/projectq/ops/_metagates_test.py
+++ b/projectq/ops/_metagates_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -89,7 +88,7 @@ def test_daggered_gate_init():
 
 def test_daggered_gate_str():
     daggered_gate = _metagates.DaggeredGate(Y)
-    assert str(daggered_gate) == str(Y) + r"^\dagger"
+    assert str(daggered_gate) == f"{str(Y)}^\\dagger"
 
 
 def test_daggered_gate_hashable():
@@ -104,13 +103,13 @@ def test_daggered_gate_hashable():
 def test_daggered_gate_tex_str():
     daggered_gate = _metagates.DaggeredGate(Y)
     str_Y = Y.tex_str() if hasattr(Y, 'tex_str') else str(Y)
-    assert daggered_gate.tex_str() == str_Y + r"${}^\dagger$"
+    assert daggered_gate.tex_str() == f"{str_Y}${{}}^\\dagger$"
 
     # test for a gate with tex_str method
     rx = Rx(0.5)
     daggered_rx = _metagates.DaggeredGate(rx)
     str_rx = rx.tex_str() if hasattr(rx, 'tex_str') else str(rx)
-    assert daggered_rx.tex_str() == str_rx + r"${}^\dagger$"
+    assert daggered_rx.tex_str() == f"{str_rx}${{}}^\\dagger$"
 
 
 def test_daggered_gate_get_inverse():
@@ -164,7 +163,7 @@ def test_controlled_gate_init():
 
 def test_controlled_gate_str():
     one_control = _metagates.ControlledGate(Y, 2)
-    assert str(one_control) == "CC" + str(Y)
+    assert str(one_control) == f"CC{str(Y)}"
 
 
 def test_controlled_gate_get_inverse():
@@ -234,7 +233,7 @@ def test_tensor_init():
 
 def test_tensor_str():
     gate = _metagates.Tensor(Y)
-    assert str(gate) == "Tensor(" + str(Y) + ")"
+    assert str(gate) == f"Tensor({str(Y)})"
 
 
 def test_tensor_get_inverse():
diff --git a/projectq/ops/_qaagate.py b/projectq/ops/_qaagate.py
index 565d61498..5e2d889c4 100755
--- a/projectq/ops/_qaagate.py
+++ b/projectq/ops/_qaagate.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2019 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -32,17 +31,19 @@ class QAA(BasicGate):
     Example:
         .. code-block:: python
 
-           def func_algorithm(eng,system_qubits):
+           def func_algorithm(eng, system_qubits):
                All(H) | system_qubits
 
-           def func_oracle(eng,system_qubits,qaa_ancilla):
+
+           def func_oracle(eng, system_qubits, qaa_ancilla):
                # This oracle selects the state |010> as the one marked
                with Compute(eng):
-                  All(X) | system_qubits[0::2]
+                   All(X) | system_qubits[0::2]
                with Control(eng, system_qubits):
-                  X | qaa_ancilla
+                   X | qaa_ancilla
                Uncompute(eng)
 
+
            system_qubits = eng.allocate_qureg(3)
            # Prepare the qaa_ancilla qubit in the |-> state
            qaa_ancilla = eng.allocate_qubit()
@@ -52,7 +53,7 @@ def func_oracle(eng,system_qubits,qaa_ancilla):
            # Creates the initial state form the Algorithm
            func_algorithm(eng, system_qubits)
            # Apply Quantum Amplitude Amplification the correct number of times
-           num_it = int(math.pi/4.*math.sqrt(1 << 3))
+           num_it = int(math.pi / 4.0 * math.sqrt(1 << 3))
            with Loop(eng, num_it):
                QAA(func_algorithm, func_oracle) | (system_qubits, qaa_ancilla)
 
@@ -78,4 +79,4 @@ def __init__(self, algorithm, oracle):
 
     def __str__(self):
         """Return a string representation of the object."""
-        return 'QAA(Algorithm = {0}, Oracle = {1})'.format(str(self.algorithm.__name__), str(self.oracle.__name__))
+        return f'QAA(Algorithm = {str(self.algorithm.__name__)}, Oracle = {str(self.oracle.__name__)})'
diff --git a/projectq/ops/_qaagate_test.py b/projectq/ops/_qaagate_test.py
index 707fb2fd5..e6d68688b 100755
--- a/projectq/ops/_qaagate_test.py
+++ b/projectq/ops/_qaagate_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2019 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/ops/_qftgate.py b/projectq/ops/_qftgate.py
index 0ea56c032..3a14de37a 100755
--- a/projectq/ops/_qftgate.py
+++ b/projectq/ops/_qftgate.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/ops/_qftgate_test.py b/projectq/ops/_qftgate_test.py
index 8fa43058f..a790506f0 100755
--- a/projectq/ops/_qftgate_test.py
+++ b/projectq/ops/_qftgate_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/ops/_qpegate.py b/projectq/ops/_qpegate.py
index 96ed00a5d..3eab6e84c 100755
--- a/projectq/ops/_qpegate.py
+++ b/projectq/ops/_qpegate.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -32,4 +31,4 @@ def __init__(self, unitary):
 
     def __str__(self):
         """Return a string representation of the object."""
-        return 'QPE({})'.format(str(self.unitary))
+        return f'QPE({str(self.unitary)})'
diff --git a/projectq/ops/_qpegate_test.py b/projectq/ops/_qpegate_test.py
index 557b980bd..d404127ff 100755
--- a/projectq/ops/_qpegate_test.py
+++ b/projectq/ops/_qpegate_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/ops/_qubit_operator.py b/projectq/ops/_qubit_operator.py
index 6e2abda8c..f15a4ed40 100644
--- a/projectq/ops/_qubit_operator.py
+++ b/projectq/ops/_qubit_operator.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -82,7 +81,7 @@ class QubitOperator(BasicGate):
 
         eng = projectq.MainEngine()
         qureg = eng.allocate_qureg(6)
-        QubitOperator('X0 X5', 1.j) | qureg # Applies X to qubit 0 and 5 with an additional global phase of 1.j
+        QubitOperator('X0 X5', 1.0j) | qureg  # Applies X to qubit 0 and 5 with an additional global phase of 1.j
 
 
     Attributes:
@@ -105,8 +104,7 @@ def __init__(self, term=None, coefficient=1.0):  # pylint: disable=too-many-bran
         Example:
             .. code-block:: python
 
-                ham = ((QubitOperator('X0 Y3', 0.5)
-                        + 0.6 * QubitOperator('X0 Y3')))
+                ham = QubitOperator('X0 Y3', 0.5) + 0.6 * QubitOperator('X0 Y3')
                 # Equivalently
                 ham2 = QubitOperator('X0 Y3', 0.5)
                 ham2 += 0.6 * QubitOperator('X0 Y3')
@@ -247,9 +245,9 @@ def __or__(self, qubits):  # pylint: disable=too-many-locals
 
             eng = projectq.MainEngine()
             qureg = eng.allocate_qureg(6)
-            QubitOperator('X0 X5', 1.j) | qureg  # Applies X to qubit 0 and 5
-                                                 # with an additional global
-                                                 # phase of 1.j
+            QubitOperator('X0 X5', 1.0j) | qureg  # Applies X to qubit 0 and 5
+            # with an additional global
+            # phase of 1.j
 
         While in the above example the QubitOperator gate is applied to 6
         qubits, it only acts non-trivially on the two qubits qureg[0] and
@@ -259,7 +257,7 @@ def __or__(self, qubits):  # pylint: disable=too-many-locals
 
         .. code-block:: python
 
-            QubitOperator('X0 X1', 1.j) | [qureg[0], qureg[5]]
+            QubitOperator('X0 X1', 1.0j) | [qureg[0], qureg[5]]
 
         which is only a two qubit gate.
 
@@ -423,7 +421,7 @@ def __imul__(self, multiplier):  # pylint: disable=too-many-locals,too-many-bran
                         result_terms[tmp_key] = new_coefficient
             self.terms = result_terms
             return self
-        raise TypeError('Cannot in-place multiply term of invalid type ' + 'to QubitTerm.')
+        raise TypeError('Cannot in-place multiply term of invalid type to QubitTerm.')
 
     def __mul__(self, multiplier):
         """
@@ -564,19 +562,19 @@ def __str__(self):
             return '0'
         string_rep = ''
         for term, coeff in self.terms.items():
-            tmp_string = '{}'.format(coeff)
+            tmp_string = f'{coeff}'
             if term == ():
                 tmp_string += ' I'
             for operator in term:
                 if operator[1] == 'X':
-                    tmp_string += ' X{}'.format(operator[0])
+                    tmp_string += f' X{operator[0]}'
                 elif operator[1] == 'Y':
-                    tmp_string += ' Y{}'.format(operator[0])
+                    tmp_string += f' Y{operator[0]}'
                 elif operator[1] == 'Z':
-                    tmp_string += ' Z{}'.format(operator[0])
+                    tmp_string += f' Z{operator[0]}'
                 else:  # pragma: no cover
                     raise ValueError('Internal compiler error: operator must be one of X, Y, Z!')
-            string_rep += '{} +\n'.format(tmp_string)
+            string_rep += f'{tmp_string} +\n'
         return string_rep[:-3]
 
     def __repr__(self):
diff --git a/projectq/ops/_qubit_operator_test.py b/projectq/ops/_qubit_operator_test.py
index 3bbd09e2b..3b5e30508 100644
--- a/projectq/ops/_qubit_operator_test.py
+++ b/projectq/ops/_qubit_operator_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/ops/_shortcuts.py b/projectq/ops/_shortcuts.py
index afcc8bdf4..bc80c6fcc 100755
--- a/projectq/ops/_shortcuts.py
+++ b/projectq/ops/_shortcuts.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/ops/_shortcuts_test.py b/projectq/ops/_shortcuts_test.py
index 345f8396c..8c55d6625 100755
--- a/projectq/ops/_shortcuts_test.py
+++ b/projectq/ops/_shortcuts_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/ops/_state_prep.py b/projectq/ops/_state_prep.py
index 74c26d97a..a2f3564df 100644
--- a/projectq/ops/_state_prep.py
+++ b/projectq/ops/_state_prep.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2018 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -54,4 +53,4 @@ def __eq__(self, other):
 
     def __hash__(self):
         """Compute the hash of the object."""
-        return hash("StatePreparation(" + str(self.final_state) + ")")
+        return hash(f"StatePreparation({str(self.final_state)})")
diff --git a/projectq/ops/_state_prep_test.py b/projectq/ops/_state_prep_test.py
index 198ace500..f6cac5358 100644
--- a/projectq/ops/_state_prep_test.py
+++ b/projectq/ops/_state_prep_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2018 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/ops/_time_evolution.py b/projectq/ops/_time_evolution.py
index aa10944a9..957a1d21d 100644
--- a/projectq/ops/_time_evolution.py
+++ b/projectq/ops/_time_evolution.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -202,4 +201,4 @@ def __eq__(self, other):
 
     def __str__(self):
         """Return a string representation of the object."""
-        return "exp({0} * ({1}))".format(-1j * self.time, self.hamiltonian)
+        return f"exp({-1j * self.time} * ({self.hamiltonian}))"
diff --git a/projectq/ops/_time_evolution_test.py b/projectq/ops/_time_evolution_test.py
index 078c96f39..af7914fa1 100644
--- a/projectq/ops/_time_evolution_test.py
+++ b/projectq/ops/_time_evolution_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/ops/_uniformly_controlled_rotation.py b/projectq/ops/_uniformly_controlled_rotation.py
index 393467406..46cf023f7 100644
--- a/projectq/ops/_uniformly_controlled_rotation.py
+++ b/projectq/ops/_uniformly_controlled_rotation.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2018 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -31,9 +30,9 @@ class UniformlyControlledRy(BasicGate):
     Example:
         .. code-block:: python
 
-        controls = eng.allocate_qureg(2)
-        target = eng.allocate_qubit()
-        UniformlyControlledRy(angles=[0.1, 0.2, 0.3, 0.4]) | (controls, target)
+            controls = eng.allocate_qureg(2)
+            target = eng.allocate_qubit()
+            UniformlyControlledRy(angles=[0.1, 0.2, 0.3, 0.4]) | (controls, target)
 
     Note:
         The first quantum register contains the control qubits. When converting the classical state k of the control
@@ -69,7 +68,7 @@ def get_merged(self, other):
 
     def __str__(self):
         """Return a string representation of the object."""
-        return "UniformlyControlledRy(" + str(self.angles) + ")"
+        return f"UniformlyControlledRy({str(self.angles)})"
 
     def __eq__(self, other):
         """Return True if same class, same rotation angles."""
@@ -93,9 +92,9 @@ class UniformlyControlledRz(BasicGate):
     Example:
         .. code-block:: python
 
-        controls = eng.allocate_qureg(2)
-        target = eng.allocate_qubit()
-        UniformlyControlledRz(angles=[0.1, 0.2, 0.3, 0.4]) | (controls, target)
+            controls = eng.allocate_qureg(2)
+            target = eng.allocate_qubit()
+            UniformlyControlledRz(angles=[0.1, 0.2, 0.3, 0.4]) | (controls, target)
 
     Note:
         The first quantum register are the contains qubits. When converting the classical state k of the control
@@ -131,7 +130,7 @@ def get_merged(self, other):
 
     def __str__(self):
         """Return a string representation of the object."""
-        return "UniformlyControlledRz(" + str(self.angles) + ")"
+        return f"UniformlyControlledRz({str(self.angles)})"
 
     def __eq__(self, other):
         """Return True if same class, same rotation angles."""
diff --git a/projectq/ops/_uniformly_controlled_rotation_test.py b/projectq/ops/_uniformly_controlled_rotation_test.py
index 362932483..49bef25ed 100644
--- a/projectq/ops/_uniformly_controlled_rotation_test.py
+++ b/projectq/ops/_uniformly_controlled_rotation_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2018 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/__init__.py b/projectq/setups/__init__.py
index f279b3d1d..dc799ab87 100755
--- a/projectq/setups/__init__.py
+++ b/projectq/setups/__init__.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/_utils.py b/projectq/setups/_utils.py
index 6f933aac6..434eb5424 100644
--- a/projectq/setups/_utils.py
+++ b/projectq/setups/_utils.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2018 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/aqt.py b/projectq/setups/aqt.py
index 02ac24b19..5b668aaf5 100644
--- a/projectq/setups/aqt.py
+++ b/projectq/setups/aqt.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2020 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/aqt_test.py b/projectq/setups/aqt_test.py
index e36146e0b..415b5a4a8 100644
--- a/projectq/setups/aqt_test.py
+++ b/projectq/setups/aqt_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2020 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/awsbraket.py b/projectq/setups/awsbraket.py
index 0268b834f..46247ca9d 100644
--- a/projectq/setups/awsbraket.py
+++ b/projectq/setups/awsbraket.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -86,4 +85,4 @@ def get_engine_list(credentials=None, device=None):
             other_gates=(Barrier,),
         )
         return setup
-    raise DeviceNotHandledError('Unsupported device type: {}!'.format(device))  # pragma: no cover
+    raise DeviceNotHandledError(f'Unsupported device type: {device}!')  # pragma: no cover
diff --git a/projectq/setups/awsbraket_test.py b/projectq/setups/awsbraket_test.py
index 6f8ad41b7..a0455258f 100644
--- a/projectq/setups/awsbraket_test.py
+++ b/projectq/setups/awsbraket_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/decompositions/__init__.py b/projectq/setups/decompositions/__init__.py
index 908b04cc9..ec5fcb277 100755
--- a/projectq/setups/decompositions/__init__.py
+++ b/projectq/setups/decompositions/__init__.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/decompositions/_gates_test.py b/projectq/setups/decompositions/_gates_test.py
index 5ea730ff0..12c05cdc8 100755
--- a/projectq/setups/decompositions/_gates_test.py
+++ b/projectq/setups/decompositions/_gates_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/decompositions/amplitudeamplification.py b/projectq/setups/decompositions/amplitudeamplification.py
index cbf2b0af7..bd38f8086 100644
--- a/projectq/setups/decompositions/amplitudeamplification.py
+++ b/projectq/setups/decompositions/amplitudeamplification.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2019 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -28,17 +27,19 @@
 Example:
     .. code-block:: python
 
-       def func_algorithm(eng,system_qubits):
+       def func_algorithm(eng, system_qubits):
            All(H) | system_qubits
 
-       def func_oracle(eng,system_qubits,qaa_ancilla):
+
+       def func_oracle(eng, system_qubits, qaa_ancilla):
            # This oracle selects the state |010> as the one marked
            with Compute(eng):
-              All(X) | system_qubits[0::2]
+               All(X) | system_qubits[0::2]
            with Control(eng, system_qubits):
-              X | qaa_ancilla
+               X | qaa_ancilla
            Uncompute(eng)
 
+
        system_qubits = eng.allocate_qureg(3)
        # Prepare the qaa_ancilla qubit in the |-> state
        qaa_ancilla = eng.allocate_qubit()
@@ -48,9 +49,9 @@ def func_oracle(eng,system_qubits,qaa_ancilla):
        # Creates the initial state form the Algorithm
        func_algorithm(eng, system_qubits)
        # Apply Quantum Amplitude Amplification the correct number of times
-       num_it = int(math.pi/4.*math.sqrt(1 << 3))
+       num_it = int(math.pi / 4.0 * math.sqrt(1 << 3))
        with Loop(eng, num_it):
-         QAA(func_algorithm, func_oracle) | (system_qubits, qaa_ancilla)
+           QAA(func_algorithm, func_oracle) | (system_qubits, qaa_ancilla)
 
        All(Measure) | system_qubits
 
diff --git a/projectq/setups/decompositions/amplitudeamplification_test.py b/projectq/setups/decompositions/amplitudeamplification_test.py
index adab7cd92..34b490de9 100644
--- a/projectq/setups/decompositions/amplitudeamplification_test.py
+++ b/projectq/setups/decompositions/amplitudeamplification_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2019 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -90,10 +89,7 @@ def test_simple_grover():
 
     assert total_prob_after == pytest.approx(
         theoretical_prob, abs=1e-6
-    ), "The obtained probability is less than expected %f vs. %f" % (
-        total_prob_after,
-        theoretical_prob,
-    )
+    ), f"The obtained probability is less than expected {total_prob_after:f} vs. {theoretical_prob:f}"
 
 
 def complex_algorithm(eng, qreg):
@@ -172,10 +168,7 @@ def test_complex_aa():
 
     assert total_prob_after == pytest.approx(
         theoretical_prob, abs=1e-2
-    ), "The obtained probability is less than expected %f vs. %f" % (
-        total_prob_after,
-        theoretical_prob,
-    )
+    ), f"The obtained probability is less than expected {total_prob_after:f} vs. {theoretical_prob:f}"
 
 
 def test_string_functions():
diff --git a/projectq/setups/decompositions/arb1qubit2rzandry.py b/projectq/setups/decompositions/arb1qubit2rzandry.py
index 699b1fcfd..e7392da9d 100644
--- a/projectq/setups/decompositions/arb1qubit2rzandry.py
+++ b/projectq/setups/decompositions/arb1qubit2rzandry.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017, 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -129,7 +128,7 @@ def _find_parameters(matrix):  # pylint: disable=too-many-branches,too-many-stat
             raise Exception(
                 "Couldn't find parameters for matrix ",
                 matrix,
-                "This shouldn't happen. Maybe the matrix is " + "not unitary?",
+                "This shouldn't happen. Maybe the matrix is not unitary?",
             )
     # Case 2: cos(c/2) == 0:
     elif abs(matrix[0][0]) < TOLERANCE:
@@ -158,7 +157,7 @@ def _find_parameters(matrix):  # pylint: disable=too-many-branches,too-many-stat
             raise Exception(
                 "Couldn't find parameters for matrix ",
                 matrix,
-                "This shouldn't happen. Maybe the matrix is " + "not unitary?",
+                "This shouldn't happen. Maybe the matrix is not unitary?",
             )
     # Case 3: sin(c/2) != 0 and cos(c/2) !=0:
     else:
@@ -196,7 +195,7 @@ def _find_parameters(matrix):  # pylint: disable=too-many-branches,too-many-stat
             raise Exception(
                 "Couldn't find parameters for matrix ",
                 matrix,
-                "This shouldn't happen. Maybe the matrix is " + "not unitary?",
+                "This shouldn't happen. Maybe the matrix is not unitary?",
             )
     return (a, b_half, c_half, d_half)
 
diff --git a/projectq/setups/decompositions/arb1qubit2rzandry_test.py b/projectq/setups/decompositions/arb1qubit2rzandry_test.py
index 90a72057a..452e4d9c9 100644
--- a/projectq/setups/decompositions/arb1qubit2rzandry_test.py
+++ b/projectq/setups/decompositions/arb1qubit2rzandry_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/decompositions/barrier.py b/projectq/setups/decompositions/barrier.py
index f3e94f408..6711e838b 100755
--- a/projectq/setups/decompositions/barrier.py
+++ b/projectq/setups/decompositions/barrier.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/decompositions/barrier_test.py b/projectq/setups/decompositions/barrier_test.py
index c7b3ca158..a09bb2f70 100755
--- a/projectq/setups/decompositions/barrier_test.py
+++ b/projectq/setups/decompositions/barrier_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 # -*- codingf53: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
diff --git a/projectq/setups/decompositions/carb1qubit2cnotrzandry.py b/projectq/setups/decompositions/carb1qubit2cnotrzandry.py
index b2f8b701a..6f3f35d9e 100644
--- a/projectq/setups/decompositions/carb1qubit2cnotrzandry.py
+++ b/projectq/setups/decompositions/carb1qubit2cnotrzandry.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017, 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/decompositions/carb1qubit2cnotrzandry_test.py b/projectq/setups/decompositions/carb1qubit2cnotrzandry_test.py
index 280df747b..e3464bdf3 100644
--- a/projectq/setups/decompositions/carb1qubit2cnotrzandry_test.py
+++ b/projectq/setups/decompositions/carb1qubit2cnotrzandry_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/decompositions/cnot2cz.py b/projectq/setups/decompositions/cnot2cz.py
index ea60ce2f3..950b12b68 100644
--- a/projectq/setups/decompositions/cnot2cz.py
+++ b/projectq/setups/decompositions/cnot2cz.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2018 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/decompositions/cnot2cz_test.py b/projectq/setups/decompositions/cnot2cz_test.py
index ca9b3af2f..6738f0483 100644
--- a/projectq/setups/decompositions/cnot2cz_test.py
+++ b/projectq/setups/decompositions/cnot2cz_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2018 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/decompositions/cnot2rxx.py b/projectq/setups/decompositions/cnot2rxx.py
index 7565ef062..f60ee89ed 100644
--- a/projectq/setups/decompositions/cnot2rxx.py
+++ b/projectq/setups/decompositions/cnot2rxx.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2018 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/decompositions/cnot2rxx_test.py b/projectq/setups/decompositions/cnot2rxx_test.py
index 9cb72fc3e..e131ab928 100644
--- a/projectq/setups/decompositions/cnot2rxx_test.py
+++ b/projectq/setups/decompositions/cnot2rxx_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2018 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/decompositions/cnu2toffoliandcu.py b/projectq/setups/decompositions/cnu2toffoliandcu.py
index cd4b79901..a463de0c2 100644
--- a/projectq/setups/decompositions/cnu2toffoliandcu.py
+++ b/projectq/setups/decompositions/cnu2toffoliandcu.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/decompositions/cnu2toffoliandcu_test.py b/projectq/setups/decompositions/cnu2toffoliandcu_test.py
index 178813beb..b64203bfd 100644
--- a/projectq/setups/decompositions/cnu2toffoliandcu_test.py
+++ b/projectq/setups/decompositions/cnu2toffoliandcu_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/decompositions/controlstate.py b/projectq/setups/decompositions/controlstate.py
index f10a8add3..7aa0b5924 100755
--- a/projectq/setups/decompositions/controlstate.py
+++ b/projectq/setups/decompositions/controlstate.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/decompositions/controlstate_test.py b/projectq/setups/decompositions/controlstate_test.py
index f50a9b01a..02512e5e7 100755
--- a/projectq/setups/decompositions/controlstate_test.py
+++ b/projectq/setups/decompositions/controlstate_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/decompositions/crz2cxandrz.py b/projectq/setups/decompositions/crz2cxandrz.py
index b36f356ba..b56603cc9 100755
--- a/projectq/setups/decompositions/crz2cxandrz.py
+++ b/projectq/setups/decompositions/crz2cxandrz.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/decompositions/entangle.py b/projectq/setups/decompositions/entangle.py
index 30d921a9d..0f692f669 100755
--- a/projectq/setups/decompositions/entangle.py
+++ b/projectq/setups/decompositions/entangle.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/decompositions/globalphase.py b/projectq/setups/decompositions/globalphase.py
index 69e38f081..679c08a51 100755
--- a/projectq/setups/decompositions/globalphase.py
+++ b/projectq/setups/decompositions/globalphase.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/decompositions/h2rx.py b/projectq/setups/decompositions/h2rx.py
index 9a0eb4239..608629b10 100644
--- a/projectq/setups/decompositions/h2rx.py
+++ b/projectq/setups/decompositions/h2rx.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/decompositions/h2rx_test.py b/projectq/setups/decompositions/h2rx_test.py
index 551517e42..fb3d2045b 100644
--- a/projectq/setups/decompositions/h2rx_test.py
+++ b/projectq/setups/decompositions/h2rx_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/decompositions/ph2r.py b/projectq/setups/decompositions/ph2r.py
index c72f459ee..2fefe0dcd 100755
--- a/projectq/setups/decompositions/ph2r.py
+++ b/projectq/setups/decompositions/ph2r.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/decompositions/phaseestimation.py b/projectq/setups/decompositions/phaseestimation.py
index efc788bdb..50d02253f 100644
--- a/projectq/setups/decompositions/phaseestimation.py
+++ b/projectq/setups/decompositions/phaseestimation.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2018 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -35,29 +34,31 @@
        n_qpe_ancillas = 3
        qpe_ancillas = eng.allocate_qureg(n_qpe_ancillas)
        system_qubits = eng.allocate_qureg(1)
-       angle = cmath.pi*2.*0.125
-       U = Ph(angle) # unitary_specfic_to_the_problem()
+       angle = cmath.pi * 2.0 * 0.125
+       U = Ph(angle)  # unitary_specfic_to_the_problem()
 
        # Apply Quantum Phase Estimation
        QPE(U) | (qpe_ancillas, system_qubits)
 
        All(Measure) | qpe_ancillas
        # Compute the phase from the ancilla measurement
-       #(https://en.wikipedia.org/wiki/Quantum_phase_estimation_algorithm)
+       # (https://en.wikipedia.org/wiki/Quantum_phase_estimation_algorithm)
        phasebinlist = [int(q) for q in qpe_ancillas]
        phase_in_bin = ''.join(str(j) for j in phasebinlist)
-       phase_int = int(phase_in_bin,2)
-       phase = phase_int / (2 ** n_qpe_ancillas)
-       print (phase)
+       phase_int = int(phase_in_bin, 2)
+       phase = phase_int / (2**n_qpe_ancillas)
+       print(phase)
 
        # Example using a function (two_qubit_gate).
        # Instead of applying QPE on a gate U one could provide a function
 
+
        def two_qubit_gate(system_q, time):
            CNOT | (system_q[0], system_q[1])
-           Ph(2.0*cmath.pi*(time * 0.125)) | system_q[1]
+           Ph(2.0 * cmath.pi * (time * 0.125)) | system_q[1]
            CNOT | (system_q[0], system_q[1])
 
+
        n_qpe_ancillas = 3
        qpe_ancillas = eng.allocate_qureg(n_qpe_ancillas)
        system_qubits = eng.allocate_qureg(2)
@@ -68,12 +69,12 @@ def two_qubit_gate(system_q, time):
 
        All(Measure) | qpe_ancillas
        # Compute the phase from the ancilla measurement
-       #(https://en.wikipedia.org/wiki/Quantum_phase_estimation_algorithm)
+       # (https://en.wikipedia.org/wiki/Quantum_phase_estimation_algorithm)
        phasebinlist = [int(q) for q in qpe_ancillas]
        phase_in_bin = ''.join(str(j) for j in phasebinlist)
-       phase_int = int(phase_in_bin,2)
-       phase = phase_int / (2 ** n_qpe_ancillas)
-       print (phase)
+       phase_int = int(phase_in_bin, 2)
+       phase = phase_int / (2**n_qpe_ancillas)
+       print(phase)
 
 Attributes:
     unitary (BasicGate): Unitary Operation either a ProjectQ gate or a function f.
diff --git a/projectq/setups/decompositions/phaseestimation_test.py b/projectq/setups/decompositions/phaseestimation_test.py
index 151b8643a..08e33e587 100644
--- a/projectq/setups/decompositions/phaseestimation_test.py
+++ b/projectq/setups/decompositions/phaseestimation_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -58,10 +57,7 @@ def test_simple_test_X_eigenvectors():
         eng.flush()
 
     num_phase = (results == 0.5).sum()
-    assert num_phase / N >= 0.35, "Statistics phase calculation are not correct (%f vs. %f)" % (
-        num_phase / N,
-        0.35,
-    )
+    assert num_phase / N >= 0.35, f"Statistics phase calculation are not correct ({num_phase / N:f} vs. {0.35:f})"
 
 
 @flaky(max_runs=5, min_passes=2)
@@ -91,10 +87,7 @@ def test_Ph_eigenvectors():
         eng.flush()
 
     num_phase = (results == 0.125).sum()
-    assert num_phase / N >= 0.35, "Statistics phase calculation are not correct (%f vs. %f)" % (
-        num_phase / N,
-        0.35,
-    )
+    assert num_phase / N >= 0.35, f"Statistics phase calculation are not correct ({num_phase / N:f} vs. {0.35:f})"
 
 
 def two_qubit_gate(system_q, time):
@@ -129,10 +122,7 @@ def test_2qubitsPh_andfunction_eigenvectors():
         eng.flush()
 
     num_phase = (results == 0.125).sum()
-    assert num_phase / N >= 0.34, "Statistics phase calculation are not correct (%f vs. %f)" % (
-        num_phase / N,
-        0.34,
-    )
+    assert num_phase / N >= 0.34, f"Statistics phase calculation are not correct ({num_phase / N:f} vs. {0.34:f})"
 
 
 def test_X_no_eigenvectors():
@@ -179,10 +169,7 @@ def test_X_no_eigenvectors():
     assert total == pytest.approx(N, abs=5)
     assert plus_probability == pytest.approx(
         1.0 / 4.0, abs=1e-1
-    ), "Statistics on |+> probability are not correct (%f vs. %f)" % (
-        plus_probability,
-        1.0 / 4.0,
-    )
+    ), f"Statistics on |+> probability are not correct ({plus_probability:f} vs. {1.0 / 4.0:f})"
 
 
 def test_string():
diff --git a/projectq/setups/decompositions/qft2crandhadamard.py b/projectq/setups/decompositions/qft2crandhadamard.py
index 4d8f9ebb1..de7346bbf 100755
--- a/projectq/setups/decompositions/qft2crandhadamard.py
+++ b/projectq/setups/decompositions/qft2crandhadamard.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/decompositions/qubitop2onequbit.py b/projectq/setups/decompositions/qubitop2onequbit.py
index 4109759ed..5fd68e345 100644
--- a/projectq/setups/decompositions/qubitop2onequbit.py
+++ b/projectq/setups/decompositions/qubitop2onequbit.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2018 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/decompositions/qubitop2onequbit_test.py b/projectq/setups/decompositions/qubitop2onequbit_test.py
index 44567fc9b..ed124c963 100644
--- a/projectq/setups/decompositions/qubitop2onequbit_test.py
+++ b/projectq/setups/decompositions/qubitop2onequbit_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2018 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -96,7 +95,7 @@ def test_qubitop2singlequbit():
     correct_eng.flush()
 
     for fstate in range(2 ** (num_qubits + 1)):
-        binary_state = format(fstate, '0' + str(num_qubits + 1) + 'b')
+        binary_state = format(fstate, f"0{num_qubits + 1}b")
         test = test_eng.backend.get_amplitude(binary_state, test_qureg + test_ctrl_qb)
         correct = correct_eng.backend.get_amplitude(binary_state, correct_qureg + correct_ctrl_qb)
         assert correct == pytest.approx(test, rel=1e-10, abs=1e-10)
diff --git a/projectq/setups/decompositions/r2rzandph.py b/projectq/setups/decompositions/r2rzandph.py
index 918038e59..9fca9ed52 100755
--- a/projectq/setups/decompositions/r2rzandph.py
+++ b/projectq/setups/decompositions/r2rzandph.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/decompositions/rx2rz.py b/projectq/setups/decompositions/rx2rz.py
index e7839461e..6fe1f22be 100644
--- a/projectq/setups/decompositions/rx2rz.py
+++ b/projectq/setups/decompositions/rx2rz.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/decompositions/rx2rz_test.py b/projectq/setups/decompositions/rx2rz_test.py
index 35896f29f..767c805a0 100644
--- a/projectq/setups/decompositions/rx2rz_test.py
+++ b/projectq/setups/decompositions/rx2rz_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/decompositions/ry2rz.py b/projectq/setups/decompositions/ry2rz.py
index 040907b3f..089d9c018 100644
--- a/projectq/setups/decompositions/ry2rz.py
+++ b/projectq/setups/decompositions/ry2rz.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/decompositions/ry2rz_test.py b/projectq/setups/decompositions/ry2rz_test.py
index e5e0c909f..61f9e1cfd 100644
--- a/projectq/setups/decompositions/ry2rz_test.py
+++ b/projectq/setups/decompositions/ry2rz_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/decompositions/rz2rx.py b/projectq/setups/decompositions/rz2rx.py
index f61c10a11..d3116ed23 100644
--- a/projectq/setups/decompositions/rz2rx.py
+++ b/projectq/setups/decompositions/rz2rx.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/decompositions/rz2rx_test.py b/projectq/setups/decompositions/rz2rx_test.py
index 63dbc1f60..7418c5a1d 100644
--- a/projectq/setups/decompositions/rz2rx_test.py
+++ b/projectq/setups/decompositions/rz2rx_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/decompositions/sqrtswap2cnot.py b/projectq/setups/decompositions/sqrtswap2cnot.py
index 8e5392a51..e2b645eaa 100644
--- a/projectq/setups/decompositions/sqrtswap2cnot.py
+++ b/projectq/setups/decompositions/sqrtswap2cnot.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2018 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/decompositions/sqrtswap2cnot_test.py b/projectq/setups/decompositions/sqrtswap2cnot_test.py
index 0ec4706cd..2e920a70f 100644
--- a/projectq/setups/decompositions/sqrtswap2cnot_test.py
+++ b/projectq/setups/decompositions/sqrtswap2cnot_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2018 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/decompositions/stateprep2cnot.py b/projectq/setups/decompositions/stateprep2cnot.py
index 6b95bc30d..80e399acd 100644
--- a/projectq/setups/decompositions/stateprep2cnot.py
+++ b/projectq/setups/decompositions/stateprep2cnot.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2018 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/decompositions/stateprep2cnot_test.py b/projectq/setups/decompositions/stateprep2cnot_test.py
index 72372e77b..dd1c1aced 100644
--- a/projectq/setups/decompositions/stateprep2cnot_test.py
+++ b/projectq/setups/decompositions/stateprep2cnot_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2018 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/decompositions/swap2cnot.py b/projectq/setups/decompositions/swap2cnot.py
index df17b4e4c..23ffa8c69 100755
--- a/projectq/setups/decompositions/swap2cnot.py
+++ b/projectq/setups/decompositions/swap2cnot.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/decompositions/time_evolution.py b/projectq/setups/decompositions/time_evolution.py
index 9453f767e..9e029391e 100644
--- a/projectq/setups/decompositions/time_evolution.py
+++ b/projectq/setups/decompositions/time_evolution.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/decompositions/time_evolution_test.py b/projectq/setups/decompositions/time_evolution_test.py
index e8eecaa1d..8d0197a56 100644
--- a/projectq/setups/decompositions/time_evolution_test.py
+++ b/projectq/setups/decompositions/time_evolution_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/decompositions/toffoli2cnotandtgate.py b/projectq/setups/decompositions/toffoli2cnotandtgate.py
index cdaaf5bd6..b46c92ba8 100755
--- a/projectq/setups/decompositions/toffoli2cnotandtgate.py
+++ b/projectq/setups/decompositions/toffoli2cnotandtgate.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/decompositions/uniformlycontrolledr2cnot.py b/projectq/setups/decompositions/uniformlycontrolledr2cnot.py
index 62571e82e..e865e939d 100644
--- a/projectq/setups/decompositions/uniformlycontrolledr2cnot.py
+++ b/projectq/setups/decompositions/uniformlycontrolledr2cnot.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2018 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/decompositions/uniformlycontrolledr2cnot_test.py b/projectq/setups/decompositions/uniformlycontrolledr2cnot_test.py
index dbc5e75f9..08564ecd9 100644
--- a/projectq/setups/decompositions/uniformlycontrolledr2cnot_test.py
+++ b/projectq/setups/decompositions/uniformlycontrolledr2cnot_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2018 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -142,7 +141,7 @@ def test_uniformly_controlled_ry(n, gate_classes):
         correct_eng.flush()
 
         for fstate in range(2 ** (n + 1)):
-            binary_state = format(fstate, '0' + str(n + 1) + 'b')
+            binary_state = format(fstate, f"0{n + 1}b")
             test = test_sim.get_amplitude(binary_state, test_qb + test_ctrl_qureg)
             correct = correct_sim.get_amplitude(binary_state, correct_qb + correct_ctrl_qureg)
             assert correct == pytest.approx(test, rel=1e-10, abs=1e-10)
diff --git a/projectq/setups/default.py b/projectq/setups/default.py
index 8ac280417..109f9c10b 100755
--- a/projectq/setups/default.py
+++ b/projectq/setups/default.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/grid.py b/projectq/setups/grid.py
index 1261a72d4..65021b930 100644
--- a/projectq/setups/grid.py
+++ b/projectq/setups/grid.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2018 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/grid_test.py b/projectq/setups/grid_test.py
index 20ed6a7f2..7760d487f 100644
--- a/projectq/setups/grid_test.py
+++ b/projectq/setups/grid_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2018 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/ibm.py b/projectq/setups/ibm.py
index bab8ee824..122febaa6 100755
--- a/projectq/setups/ibm.py
+++ b/projectq/setups/ibm.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/ibm_test.py b/projectq/setups/ibm_test.py
index d7ca80710..1cdef3425 100644
--- a/projectq/setups/ibm_test.py
+++ b/projectq/setups/ibm_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/ionq.py b/projectq/setups/ionq.py
index e0c678a02..3c451048c 100644
--- a/projectq/setups/ionq.py
+++ b/projectq/setups/ionq.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -52,7 +51,7 @@ def get_engine_list(token=None, device=None):
         service.authenticate(token=token)
     devices = service.show_devices()
     if not device or device not in devices:
-        raise DeviceOfflineError("Error checking engine list: no '{}' devices available".format(device))
+        raise DeviceOfflineError(f"Error checking engine list: no '{device}' devices available")
 
     #
     # Qubit mapper
diff --git a/projectq/setups/ionq_test.py b/projectq/setups/ionq_test.py
index 6a3cde827..2b632bef7 100644
--- a/projectq/setups/ionq_test.py
+++ b/projectq/setups/ionq_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2021 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -53,4 +52,4 @@ def mock_show_devices(*args, **kwargs):
     )
 
     with pytest.raises(DeviceOfflineError):
-        projectq.setups.ionq.get_engine_list(device='simulator')
+        projectq.setups.ionq.get_engine_list(token='TOKEN', device='simulator')
diff --git a/projectq/setups/linear.py b/projectq/setups/linear.py
index 223ac2d26..299a64f80 100644
--- a/projectq/setups/linear.py
+++ b/projectq/setups/linear.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2018 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/linear_test.py b/projectq/setups/linear_test.py
index 7e838f460..a5e1ed773 100644
--- a/projectq/setups/linear_test.py
+++ b/projectq/setups/linear_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2018 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/restrictedgateset.py b/projectq/setups/restrictedgateset.py
index 86811b682..9e8049d4e 100644
--- a/projectq/setups/restrictedgateset.py
+++ b/projectq/setups/restrictedgateset.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2018 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/restrictedgateset_test.py b/projectq/setups/restrictedgateset_test.py
index 163386902..92144bde7 100644
--- a/projectq/setups/restrictedgateset_test.py
+++ b/projectq/setups/restrictedgateset_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2018 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/trapped_ion_decomposer.py b/projectq/setups/trapped_ion_decomposer.py
index 0eda14f37..3841b638a 100644
--- a/projectq/setups/trapped_ion_decomposer.py
+++ b/projectq/setups/trapped_ion_decomposer.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2018 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/setups/trapped_ion_decomposer_test.py b/projectq/setups/trapped_ion_decomposer_test.py
index ba5d1518d..2638aac83 100644
--- a/projectq/setups/trapped_ion_decomposer_test.py
+++ b/projectq/setups/trapped_ion_decomposer_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2018 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/tests/__init__.py b/projectq/tests/__init__.py
index 16fc4afdf..ee1451dcd 100755
--- a/projectq/tests/__init__.py
+++ b/projectq/tests/__init__.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/tests/_factoring_test.py b/projectq/tests/_factoring_test.py
index 5cb409d4c..541c1492c 100755
--- a/projectq/tests/_factoring_test.py
+++ b/projectq/tests/_factoring_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/types/__init__.py b/projectq/types/__init__.py
index d81996907..ad912d2ba 100755
--- a/projectq/types/__init__.py
+++ b/projectq/types/__init__.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/projectq/types/_qubit.py b/projectq/types/_qubit.py
index 74daedcac..41021fe1c 100755
--- a/projectq/types/_qubit.py
+++ b/projectq/types/_qubit.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,6 +22,7 @@
     .. code-block:: python
 
         from projectq import MainEngine
+
         eng = MainEngine()
         qubit = eng.allocate_qubit()
 
@@ -189,11 +189,11 @@ def __str__(self):
                 count += 1
                 continue
 
-            out_list.append('{}-{}'.format(start_id, start_id + count - 1) if count > 1 else '{}'.format(start_id))
+            out_list.append(f'{start_id}-{start_id + count - 1}' if count > 1 else f'{start_id}')
             start_id = qubit_id
             count = 1
 
-        return "Qureg[{}]".format(', '.join(out_list))
+        return f"Qureg[{', '.join(out_list)}]"
 
     @property
     def engine(self):
diff --git a/projectq/types/_qubit_test.py b/projectq/types/_qubit_test.py
index 35fc961e6..fb5fb394b 100755
--- a/projectq/types/_qubit_test.py
+++ b/projectq/types/_qubit_test.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -85,7 +84,7 @@ def test_basic_qubit_hash():
 
 @pytest.fixture
 def mock_main_engine():
-    class MockMainEngine(object):
+    class MockMainEngine:
         def __init__(self):
             self.num_calls = 0
             self.active_qubits = set()
diff --git a/setup.py b/setup.py
index 7b3c66489..a1fb2056e 100755
--- a/setup.py
+++ b/setup.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 # Some of the setup.py code is inspired or copied from SQLAlchemy
 
 # SQLAlchemy was created by Michael Bayer.
@@ -118,7 +117,7 @@ def compiler_test(
     """Return a boolean indicating whether a flag name is supported on the specified compiler."""
     fname = None
     with tempfile.NamedTemporaryFile('w', suffix='.cpp', delete=False) as temp:
-        temp.write('{}\nint main (int argc, char **argv) {{ {} return 0; }}'.format(include, body))
+        temp.write(f'{include}\nint main (int argc, char **argv) {{ {body} return 0; }}')
         fname = temp.name
 
     if compile_postargs is None:
@@ -147,7 +146,7 @@ def compiler_test(
         if compiler.compiler_type == 'msvc':
             err.close()
             os.dup2(olderr, sys.stderr.fileno())
-            with open('err.txt', 'r') as err_file:
+            with open('err.txt') as err_file:
                 if err_file.readlines():
                     raise RuntimeError('')
     except (CompileError, LinkError, RuntimeError):
@@ -370,7 +369,7 @@ def _configure_compiler(self):
         # Other compiler tests
 
         status_msgs('Other compiler tests')
-        self.compiler.define_macro('VERSION_INFO', '"{}"'.format(self.distribution.get_version()))
+        self.compiler.define_macro('VERSION_INFO', f'"{self.distribution.get_version()}"')
         if compiler_type == 'unix' and compiler_test(self.compiler, '-fvisibility=hidden'):
             self.opts.append('-fvisibility=hidden')
 
@@ -402,7 +401,7 @@ def _configure_openmp(self):
                 # Only add the flag if the compiler we are using is the one
                 # from HomeBrew
                 if llvm_root in compiler_root:
-                    l_arg = '-L{}/lib'.format(llvm_root)
+                    l_arg = f'-L{llvm_root}/lib'
                     if compiler_test(self.compiler, flag, link_postargs=[l_arg, flag], **kwargs):
                         self.opts.append(flag)
                         self.link_opts.extend((l_arg, flag))
@@ -419,8 +418,8 @@ def _configure_openmp(self):
                 # Only add the flag if the compiler we are using is the one
                 # from MacPorts
                 if macports_root in compiler_root:
-                    inc_dir = '{}/include/libomp'.format(macports_root)
-                    lib_dir = '{}/lib/libomp'.format(macports_root)
+                    inc_dir = f'{macports_root}/include/libomp'
+                    lib_dir = f'{macports_root}/lib/libomp'
                     c_arg = '-I' + inc_dir
                     l_arg = '-L' + lib_dir
 
@@ -476,11 +475,11 @@ def _configure_cxx_standard(self):
                 cxx_standards = [year for year in cxx_standards if year < 17]
 
         for year in cxx_standards:
-            flag = '-std=c++{}'.format(year)
+            flag = f'-std=c++{year}'
             if compiler_test(self.compiler, flag):
                 self.opts.append(flag)
                 return
-            flag = '/Qstd=c++{}'.format(year)
+            flag = f'/Qstd=c++{year}'
             if compiler_test(self.compiler, flag):
                 self.opts.append(flag)
                 return
@@ -512,7 +511,7 @@ def _cleanup_compiler_flags(self):
             if compiler_test(compiler, flag, link_shared_lib=True, compile_postargs=['-fPIC']):
                 flags.append(flag)
             else:
-                important_msgs('WARNING: ignoring unsupported compiler flag: {}'.format(flag))
+                important_msgs(f'WARNING: ignoring unsupported compiler flag: {flag}')
 
         self.compiler.compiler = [compiler_exe] + list(compiler_flags)
         self.compiler.compiler_so = [compiler_exe_so] + list(compiler_so_flags)
@@ -526,7 +525,7 @@ def _cleanup_compiler_flags(self):
             if compiler_test(self.compiler, flag):
                 flags.append(flag)
             else:
-                important_msgs('WARNING: ignoring unsupported compiler flag: {}'.format(flag))
+                important_msgs(f'WARNING: ignoring unsupported compiler flag: {flag}')
 
         self.compiler.compiler.extend(flags)
         self.compiler.compiler_so.extend(flags)
@@ -616,13 +615,13 @@ def run(self):
         with open('requirements.txt', 'w') as req_file:
             try:
                 for pkg in self.distribution.install_requires:
-                    req_file.write('{}\n'.format(pkg))
+                    req_file.write(f'{pkg}\n')
             except TypeError:  # Mostly for old setuptools (< 30.x)
                 for pkg in self.distribution.command_options['options']['install_requires']:
-                    req_file.write('{}\n'.format(pkg))
+                    req_file.write(f'{pkg}\n')
             req_file.write('\n')
             for pkg in self.extra_pkgs:
-                req_file.write('{}\n'.format(pkg))
+                req_file.write(f'{pkg}\n')
 
 
 # ------------------------------------------------------------------------------

From 74442132ee228d22c76cd4304b03d9e55db149c2 Mon Sep 17 00:00:00 2001
From: Nguyen Damien <ngn.damien@gmail.com>
Date: Fri, 29 Jul 2022 10:24:40 +0200
Subject: [PATCH 05/25] Deprecate support for Python 3.6 (#442)

---
 .github/workflows/ci.yml                      |   9 +-
 .pre-commit-config.yaml                       |   2 +-
 CHANGELOG.md                                  |   7 +-
 examples/shor.py                              |   1 -
 .../decompositions/arb1qubit2rzandry.py       |  34 +++---
 .../decompositions/carb1qubit2cnotrzandry.py  |  12 +-
 .../carb1qubit2cnotrzandry_test.py            |   5 +-
 pyproject.toml                                |  75 ++++++++++--
 setup.cfg                                     |  55 +--------
 setup.py                                      | 112 +++++++++++++++---
 10 files changed, 201 insertions(+), 111 deletions(-)

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 73db64348..a209f9c9f 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -16,7 +16,6 @@ jobs:
       matrix:
         runs-on: [ubuntu-latest, windows-latest, macos-latest]
         python:
-        - 3.6
         - 3.7
         - 3.8
         - 3.9
@@ -64,6 +63,8 @@ jobs:
 
     - name: Prepare env
       run: |
+        python -m pip install -U pip setuptools wheel
+        cat requirements.txt
         python -m pip install -r requirements.txt --prefer-binary
         python -m pip install coveralls
 
@@ -143,6 +144,8 @@ jobs:
     - name: Prepare Python env
       run: |
         python3 setup.py gen_reqfile --include-extras=test,braket
+        python3 -m pip install -U pip setuptools wheel
+        cat requirements.txt
         python3 -m pip install -r requirements.txt --prefer-binary
 
     - name: Upgrade pybind11 and flaky
@@ -188,6 +191,8 @@ jobs:
     - name: Prepare Python env
       run: |
         python3 setup.py gen_reqfile --include-extras=test,braket
+        python3 -m pip install -U pip setuptools wheel
+        cat requirements.txt
         python3 -m pip install -r requirements.txt --prefer-binary
 
     - name: Upgrade pybind11 and flaky
@@ -270,6 +275,8 @@ jobs:
     - name: Install dependencies
       run: |
         python3 setup.py gen_reqfile --include-extras=test,braket
+        python3 -m pip install -U pip setuptools wheel
+        cat requirements.txt
         python3 -m pip install -r requirements.txt --prefer-binary
 
     - name: Build and install package
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 804d6e47f..7b1ba27a8 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -46,7 +46,7 @@ repos:
     rev: v2.34.0
     hooks:
       - id: pyupgrade
-        args: [--py36-plus, --keep-mock]
+        args: [--py37-plus, --keep-mock]
 
   - repo: https://github.com/PyCQA/isort
     rev: 5.10.1
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4228cb015..ec2209730 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,13 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ## [Unreleased]
 
+### Changed
+
+-   Support for Python 3.6 and earlier is now deprecated
+-   Moved package metadata into pyproject.toml
+
 ### Repository
 
 -   Update `docker/setup-qemu-action` GitHub action to v2
 -   Fixed CentOS 7 configuration issue
 -   Added two new pre-commit hooks: `blacken-docs` and `pyupgrade`
--   Remove deprecated `setup_requires` field in setup.cfg
--   Fixed installation issue with newer versions of `setuptool-scm`and Python¨ 3.6
 
 ## [v0.7.3] - 2022-04-27
 
diff --git a/examples/shor.py b/examples/shor.py
index 76ef9fd57..cb5d41bd8 100755
--- a/examples/shor.py
+++ b/examples/shor.py
@@ -12,7 +12,6 @@
 except ImportError:
     from fractions import gcd
 
-
 import projectq.libs.math
 import projectq.setups.decompositions
 from projectq.backends import ResourceCounter, Simulator
diff --git a/projectq/setups/decompositions/arb1qubit2rzandry.py b/projectq/setups/decompositions/arb1qubit2rzandry.py
index e7392da9d..33da891ea 100644
--- a/projectq/setups/decompositions/arb1qubit2rzandry.py
+++ b/projectq/setups/decompositions/arb1qubit2rzandry.py
@@ -170,22 +170,26 @@ def _find_parameters(matrix):  # pylint: disable=too-many-branches,too-many-stat
         else:
             a = two_a / 2.0  # pylint: disable=invalid-name
         two_d = 2.0 * cmath.phase(matrix[0][1]) - 2.0 * cmath.phase(matrix[0][0])
-        # yapf: disable
-        possible_d_half = [two_d/4. % (2*math.pi),
-                           (two_d/4.+math.pi/2.) % (2*math.pi),
-                           (two_d/4.+math.pi) % (2*math.pi),
-                           (two_d/4.+3./2.*math.pi) % (2*math.pi)]
-        two_b = 2. * cmath.phase(matrix[1][0]) - 2. * cmath.phase(matrix[0][0])
-        possible_b_half = [two_b/4. % (2*math.pi),
-                           (two_b/4.+math.pi/2.) % (2*math.pi),
-                           (two_b/4.+math.pi) % (2*math.pi),
-                           (two_b/4.+3./2.*math.pi) % (2*math.pi)]
+        possible_d_half = [
+            two_d / 4.0 % (2 * math.pi),
+            (two_d / 4.0 + math.pi / 2.0) % (2 * math.pi),
+            (two_d / 4.0 + math.pi) % (2 * math.pi),
+            (two_d / 4.0 + 3.0 / 2.0 * math.pi) % (2 * math.pi),
+        ]
+        two_b = 2.0 * cmath.phase(matrix[1][0]) - 2.0 * cmath.phase(matrix[0][0])
+        possible_b_half = [
+            two_b / 4.0 % (2 * math.pi),
+            (two_b / 4.0 + math.pi / 2.0) % (2 * math.pi),
+            (two_b / 4.0 + math.pi) % (2 * math.pi),
+            (two_b / 4.0 + 3.0 / 2.0 * math.pi) % (2 * math.pi),
+        ]
         tmp = math.acos(abs(matrix[1][1]))
-        possible_c_half = [tmp % (2*math.pi),
-                           (tmp+math.pi) % (2*math.pi),
-                           (-1.*tmp) % (2*math.pi),
-                           (-1.*tmp+math.pi) % (2*math.pi)]
-        # yapf: enable
+        possible_c_half = [
+            tmp % (2 * math.pi),
+            (tmp + math.pi) % (2 * math.pi),
+            (-1.0 * tmp) % (2 * math.pi),
+            (-1.0 * tmp + math.pi) % (2 * math.pi),
+        ]
         found = False
         for b_half, c_half, d_half in itertools.product(possible_b_half, possible_c_half, possible_d_half):
             if _test_parameters(matrix, a, b_half, c_half, d_half):
diff --git a/projectq/setups/decompositions/carb1qubit2cnotrzandry.py b/projectq/setups/decompositions/carb1qubit2cnotrzandry.py
index 6f3f35d9e..48490a814 100644
--- a/projectq/setups/decompositions/carb1qubit2cnotrzandry.py
+++ b/projectq/setups/decompositions/carb1qubit2cnotrzandry.py
@@ -138,12 +138,12 @@ def _recognize_v(matrix):  # pylint: disable=too-many-branches
         (two_b / 2.0 + math.pi) % (2 * math.pi),
     ]
     tmp = math.acos(abs(matrix[1][0]))
-    # yapf: disable
-    possible_c_half = [tmp % (2*math.pi),
-                       (tmp+math.pi) % (2*math.pi),
-                       (-1.*tmp) % (2*math.pi),
-                       (-1.*tmp+math.pi) % (2*math.pi)]
-    # yapf: enable
+    possible_c_half = [
+        tmp % (2 * math.pi),
+        (tmp + math.pi) % (2 * math.pi),
+        (-1.0 * tmp) % (2 * math.pi),
+        (-1.0 * tmp + math.pi) % (2 * math.pi),
+    ]
     for b, c_half in itertools.product(possible_b, possible_c_half):  # pylint: disable=invalid-name
         if _test_parameters(matrix, a, b, c_half):
             return (a, b, c_half)
diff --git a/projectq/setups/decompositions/carb1qubit2cnotrzandry_test.py b/projectq/setups/decompositions/carb1qubit2cnotrzandry_test.py
index e3464bdf3..f402f7027 100644
--- a/projectq/setups/decompositions/carb1qubit2cnotrzandry_test.py
+++ b/projectq/setups/decompositions/carb1qubit2cnotrzandry_test.py
@@ -98,12 +98,9 @@ def _decomp_gates(eng, cmd):
     return False
 
 
-# yapf: disable
-@pytest.mark.parametrize("gate_matrix", [[[1, 0], [0, -1]],
-                                         [[0, -1j], [1j, 0]]])
+@pytest.mark.parametrize("gate_matrix", [[[1, 0], [0, -1]], [[0, -1j], [1j, 0]]])
 def test_recognize_v(gate_matrix):
     assert carb1q._recognize_v(gate_matrix)
-# yapf: enable
 
 
 @pytest.mark.parametrize("gate_matrix", arb1q_t.create_test_matrices())
diff --git a/pyproject.toml b/pyproject.toml
index db6087272..82f728b54 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,20 +1,81 @@
 [build-system]
-requires = ["setuptools>=42", "wheel", "pybind11>=2",
-            "setuptools_scm[toml]<7;python_version<'3.7'",
-            "setuptools_scm[toml]>6;python_version>='3.7'"]
+requires = [
+    'setuptools>=61;python_version>="3.7"',
+    'setuptools>=59;python_version<"3.7"',
+    'wheel',
+    'pybind11>=2',
+    'setuptools_scm[toml]>6;python_version>="3.7"'
+]
 build-backend = "setuptools.build_meta"
 
+[project]
+name = 'projectq'
+authors = [
+     {name = 'ProjectQ', email = 'info@projectq.ch'}
+]
+description = 'ProjectQ - An open source software framework for quantum computing'
+requires-python = '>= 3.7'
+license = {text= 'Apache License Version 2.0'}
+readme = 'README.rst'
+classifiers = [
+    'License :: OSI Approved :: Apache Software License',
+    'Topic :: Software Development :: Libraries :: Python Modules',
+    'Programming Language :: Python :: 3 :: Only',
+    'Programming Language :: Python :: 3.7',
+    'Programming Language :: Python :: 3.8',
+    'Programming Language :: Python :: 3.9',
+    'Programming Language :: Python :: 3.10'
+]
+dynamic = ["version"]
+
+dependencies = [
+    'matplotlib >= 2.2.3',
+    'networkx >= 2',
+    'numpy',
+    'requests',
+    'scipy'
+]
+
+[project.urls]
+'Homepage' = 'http://www.projectq.ch'
+'Documentation' = 'https://projectq.readthedocs.io/en/latest/'
+'Issue Tracker' = 'https://github.com/ProjectQ-Framework/ProjectQ/'
+
+[project.optional-dependencies]
+
+braket = [
+      'boto3'
+]
+
+revkit = [
+     'revkit == 3.0a2.dev2',
+      'dormouse'
+]
+
+test = [
+     'flaky',
+     'mock',
+     'pytest >= 6.0',
+     'pytest-cov',
+     'pytest-mock'
+]
+
+docs = [
+     'sphinx',
+     'sphinx_rtd_theme'
+]
+
 # ==============================================================================
 
 [tool.black]
 
     line-length = 120
-    target-version = ['py36','py37','py38']
+    target-version = ['py37','py38','py39','py310']
     skip-string-normalization = true
 
 
 [tool.check-manifest]
-    ignore = [
+ignore = [
     'PKG-INFO',
     '*.egg-info',
     '*.egg-info/*',
@@ -112,10 +173,6 @@ write_to = 'VERSION.txt'
 write_to_template = '{version}'
 local_scheme = 'no-local-version'
 
-[tool.yapf]
-
-column_limit = 120
-
 [tool.cibuildwheel]
 
 archs = ['auto64']
diff --git a/setup.cfg b/setup.cfg
index 4bea68081..c5248b57f 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,66 +1,14 @@
-[metadata]
-
-name = projectq
-version = file:VERSION.txt
-url = http://www.projectq.ch
-author = ProjectQ
-author_email = info@projectq.ch
-project_urls =
-       Documentation = https://projectq.readthedocs.io/en/latest/
-        Issue Tracker = https://github.com/ProjectQ-Framework/ProjectQ/
-license = Apache License Version 2.0
-license_file = LICENSE
-description = ProjectQ - An open source software framework for quantum computing
-long_description = file:README.rst
-long_description_content_type = text/x-rst; charset=UTF-8
-home_page = http://www.projectq.ch
-requires_dist = setuptools
-classifier =
-    License :: OSI Approved :: Apache Software License
-    Topic :: Software Development :: Libraries :: Python Modules
-    Programming Language :: Python :: 3 :: Only
-    Programming Language :: Python :: 3.5
-    Programming Language :: Python :: 3.6
-    Programming Language :: Python :: 3.7
-    Programming Language :: Python :: 3.8
-    Programming Language :: Python :: 3.9
-    Programming Language :: Python :: 3.10
-
 [options]
 
 zip_safe = False
 packages = find:
-python_requires = >= 3
-install_requires =
-    matplotlib >= 2.2.3
-    networkx >= 2
-    numpy
-    requests
-    scipy
-
-[options.extras_require]
-
-braket = boto3
-revkit =
-     revkit == 3.0a2.dev2
-     dormouse
-test =
-     flaky
-     mock
-     pytest >= 6.0
-     pytest-cov
-     pytest-mock
-
-docs =
-     sphinx
-     sphinx_rtd_theme
-
 
 # ==============================================================================
 
 [flake8]
 
 max-line-length = 120
+ignore = E203,W503,E800
 exclude =
         .git,
         __pycache__,
@@ -68,6 +16,5 @@ exclude =
         dist,
         __init__.py
 docstring-quotes = """
-eradicate-whitelist = # yapf: disable# yapf: enable
 
 # ==============================================================================
diff --git a/setup.py b/setup.py
index a1fb2056e..9d23f1b60 100755
--- a/setup.py
+++ b/setup.py
@@ -52,6 +52,8 @@
     LinkError,
 )
 from distutils.spawn import find_executable, spawn
+from operator import itemgetter
+from pathlib import Path
 
 from setuptools import Distribution as _Distribution
 from setuptools import Extension, setup
@@ -64,6 +66,86 @@
 except ImportError:
     _HAS_SETUPTOOLS_SCM = False
 
+try:
+    import tomllib
+
+    def parse_toml(filename):
+        """Parse a TOML file."""
+        with open(str(filename), 'rb') as toml_file:
+            return tomllib.load(toml_file)
+
+except ImportError:
+    try:
+        import toml
+
+        def parse_toml(filename):
+            """Parse a TOML file."""
+            return toml.load(filename)
+
+    except ImportError:
+
+        def _find_toml_section_end(lines, start):
+            """Find the index of the start of the next section."""
+            return (
+                next(filter(itemgetter(1), enumerate(line.startswith('[') for line in lines[start + 1 :])))[0]
+                + start
+                + 1
+            )
+
+        def _parse_list(lines):
+            """Parse a TOML list into a Python list."""
+            # NB: This function expects the TOML list to be formatted like so (ignoring leading and trailing spaces):
+            #     name = [
+            #          '...',
+            #     ]
+            #     Any other format is not supported.
+            name = None
+            elements = []
+
+            for idx, line in enumerate(lines):
+                if name is None and not line.startswith("'"):
+                    name = line.split('=')[0].strip()
+                    continue
+                if line.startswith("]"):
+                    return (name, elements, idx + 1)
+                elements.append(line.rstrip(',').strip("'").strip('"'))
+
+            raise RuntimeError(f'Failed to locate closing "]" for {name}')
+
+        def parse_toml(filename):
+            """Very simple parser routine for pyproject.toml."""
+            result = {'project': {'optional-dependencies': {}}}
+            with open(filename) as toml_file:
+                lines = [line.strip() for line in toml_file.readlines()]
+            lines = [line for line in lines if line and not line.startswith('#')]
+
+            start = lines.index('[project]')
+            project_data = lines[start : _find_toml_section_end(lines, start)]
+
+            start = lines.index('[project.optional-dependencies]')
+            optional_dependencies = lines[start + 1 : _find_toml_section_end(lines, start)]
+
+            idx = 0
+            N = len(project_data)
+            while idx < N:
+                line = project_data[idx]
+                shift = 1
+                if line.startswith('name'):
+                    result['project']['name'] = line.split('=')[1].strip().strip("'")
+                elif line.startswith('dependencies'):
+                    (name, pkgs, shift) = _parse_list(project_data[idx:])
+                    result['project'][name] = pkgs
+                idx += shift
+
+            idx = 0
+            N = len(optional_dependencies)
+            while idx < N:
+                (opt_name, opt_pkgs, shift) = _parse_list(optional_dependencies[idx:])
+                result['project']['optional-dependencies'][opt_name] = opt_pkgs
+                idx += shift
+
+            return result
+
 
 # ==============================================================================
 # Helper functions and classes
@@ -178,7 +260,7 @@ def _fix_macosx_header_paths(*args):
                 compiler_args[idx] = item.replace(_MACOSX_DEVTOOLS_REF_PATH, _MACOSX_XCODE_REF_PATH)
 
 
-# ------------------------------------------------------------------------------
+# ==============================================================================
 
 
 class BuildFailed(Exception):
@@ -465,9 +547,6 @@ def _configure_cxx_standard(self):
             return
 
         cxx_standards = [17, 14, 11]
-        if sys.version_info[0] < 3:
-            cxx_standards = [year for year in cxx_standards if year < 17]
-
         if sys.platform == 'darwin':
             major_version = int(platform.mac_ver()[0].split('.')[0])
             minor_version = int(platform.mac_ver()[0].split('.')[1])
@@ -595,30 +674,27 @@ def initialize_options(self):
         self.include_extras = None
         self.include_all_extras = None
         self.extra_pkgs = []
+        self.dependencies = []
 
     def finalize_options(self):
         """Finalize this command's options."""
         include_extras = self.include_extras.split(',') if self.include_extras else []
+        pyproject_toml = parse_toml(Path(__file__).parent / 'pyproject.toml')
 
-        try:
-            for name, pkgs in self.distribution.extras_require.items():
-                if self.include_all_extras or name in include_extras:
-                    self.extra_pkgs.extend(pkgs)
+        for name, pkgs in pyproject_toml['project']['optional-dependencies'].items():
+            if self.include_all_extras or name in include_extras:
+                self.extra_pkgs.extend(pkgs)
 
-        except TypeError:  # Mostly for old setuptools (< 30.x)
-            for name, pkgs in self.distribution.command_options['options.extras_require'].items():
-                if self.include_all_extras or name in include_extras:
-                    self.extra_pkgs.extend(pkgs)
+        # pylint: disable=attribute-defined-outside-init
+        self.dependencies = self.distribution.install_requires
+        if not self.dependencies:
+            self.dependencies = pyproject_toml['project']['dependencies']
 
     def run(self):
         """Execute this command."""
         with open('requirements.txt', 'w') as req_file:
-            try:
-                for pkg in self.distribution.install_requires:
-                    req_file.write(f'{pkg}\n')
-            except TypeError:  # Mostly for old setuptools (< 30.x)
-                for pkg in self.distribution.command_options['options']['install_requires']:
-                    req_file.write(f'{pkg}\n')
+            for pkg in self.dependencies:
+                req_file.write(f'{pkg}\n')
             req_file.write('\n')
             for pkg in self.extra_pkgs:
                 req_file.write(f'{pkg}\n')

From 739f78231c003f0b6ab2697d49e3a7ff9440bd0e Mon Sep 17 00:00:00 2001
From: Sai Seshu Chadaram <ssc1729@outlook.com>
Date: Mon, 8 Aug 2022 12:54:42 +0530
Subject: [PATCH 06/25] Azure Quantum backend (#439)

* Add Azure Quantum backend template files

* Add implementation of Azure Quantum

* Add support for Honeywell and improve exception handling

* Fixes and reformatting

* Fixes and Improvements

* Fixes and Improvements

* Fixes and Improvements

* Fixes and Improvements

* Fix QASM transulation

* Fixes and Improvements

* Documentation related changes

* Fix typos

* Add docstrings to util methods

* Fix typos

* Add Unittests

* Add Unittests

* Add Unittests & rename honeywell to quantinuum

* Fixes for QSAM convector

* Add Unittests

* Add Unittests

* Add Unittests

* Add Unittests

* Fix Quantinuum Backend for Azure Quantum

* Add Unittests

* Add Unittests

* Add Unittests

* Add Unittests

* Fix Vdag gate for IonQ backend

* Minor updates

* Update Docs

* Add Azure Quantum example

* Update README.rst

* Update Docs

* Update Docs

* Update Unittests

* Azure Quantum: CI Fixes (#4)

* Azure Quantum: CI Fixes

* Fix optional dependency problem

* Update pre-commit reformatting

* Fix pylint issues

* Fix pylint issues

* Update CHANGELOG.md

* Update CHANGELOG.md

* Update CHANGELOG.md

* Resolve comments (#5)

* Resolve comments

* Remove rearrange_result method from _utils.py

* Update with pytest.approx for assert floating numbers

* Pytest skipif testcases for Azure Quantum (#6)

* Pytest skipif testcases for Azure Quantum

* Fix projectq.backends._azure._exceptions import

* Add common utils module (#7)

* Create common utils module

* Optimize _rearrange_result method

* Make sure pip, setuptools and wheel packages are up to date on CI

* Fix formatting issues from latest changes in develop branch

* Improve coveralls (#8)

* Improve coveralls

* Improve coveralls

* Rename util.py to utils.py

* Minor fixes

* Update testcases

* Update testcases

* Improve coveralls (#9)

* Improve coveralls

* Improve coveralls

* Precommit reformatting

* Improve coveralls (#10)

* Improve coveralls

* Precommit formatting

* Fix CI failures

* Avoid a few more #pragma: no cover

* Fix flake8 warning

* Remove one more # pragma: no cover

* Reformat file

Co-authored-by: Nguyen Damien <ngn.damien@gmail.com>
---
 .github/workflows/ci.yml                      |  20 +-
 .travis.yml                                   |   1 +
 CHANGELOG.md                                  |   4 +
 README.rst                                    |  31 +-
 docs/tutorials.rst                            |   8 +
 examples/azure-quantum.ipynb                  | 264 ++++++
 projectq/backends/__init__.py                 |   2 +
 projectq/backends/_aqt/_aqt.py                |   7 +-
 projectq/backends/_azure/__init__.py          |  27 +
 projectq/backends/_azure/_azure_quantum.py    | 387 ++++++++
 .../backends/_azure/_azure_quantum_client.py  |  96 ++
 .../_azure/_azure_quantum_client_test.py      | 420 +++++++++
 .../backends/_azure/_azure_quantum_test.py    | 862 ++++++++++++++++++
 projectq/backends/_azure/_exceptions.py       |  19 +
 projectq/backends/_azure/_utils.py            | 307 +++++++
 projectq/backends/_azure/_utils_test.py       | 642 +++++++++++++
 projectq/backends/_ionq/_ionq.py              |  15 +-
 projectq/backends/_utils.py                   |  28 +
 projectq/backends/_utils_test.py              |  35 +
 pyproject.toml                                |   4 +
 20 files changed, 3148 insertions(+), 31 deletions(-)
 create mode 100644 examples/azure-quantum.ipynb
 create mode 100644 projectq/backends/_azure/__init__.py
 create mode 100644 projectq/backends/_azure/_azure_quantum.py
 create mode 100644 projectq/backends/_azure/_azure_quantum_client.py
 create mode 100644 projectq/backends/_azure/_azure_quantum_client_test.py
 create mode 100644 projectq/backends/_azure/_azure_quantum_test.py
 create mode 100644 projectq/backends/_azure/_exceptions.py
 create mode 100644 projectq/backends/_azure/_utils.py
 create mode 100644 projectq/backends/_azure/_utils_test.py
 create mode 100644 projectq/backends/_utils.py
 create mode 100644 projectq/backends/_utils_test.py

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index a209f9c9f..ffda8c62b 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -54,12 +54,12 @@ jobs:
     - name: Generate requirement file (Unix)
       if: runner.os != 'Windows'
       run: |
-        python setup.py gen_reqfile --include-extras=test,braket,revkit
+        python setup.py gen_reqfile --include-extras=test,azure-quantum,braket,revkit
 
     - name: Generate requirement file (Windows)
       if: runner.os == 'Windows'
       run: |
-        python setup.py gen_reqfile --include-extras=test,braket
+        python setup.py gen_reqfile --include-extras=test,azure-quantum,braket
 
     - name: Prepare env
       run: |
@@ -74,11 +74,11 @@ jobs:
 
     - name: Build and install package (Unix)
       if: runner.os != 'Windows'
-      run: python -m pip install -ve .[braket,revkit,test]
+      run: python -m pip install -ve .[azure-quantum,braket,revkit,test]
 
     - name: Build and install package (Windows)
       if: runner.os == 'Windows'
-      run: python -m pip install -ve .[braket,test]
+      run: python -m pip install -ve .[azure-quantum,braket,test]
 
     - name: Pytest
       run: |
@@ -143,8 +143,8 @@ jobs:
 
     - name: Prepare Python env
       run: |
-        python3 setup.py gen_reqfile --include-extras=test,braket
         python3 -m pip install -U pip setuptools wheel
+        python3 setup.py gen_reqfile --include-extras=test,azure-quantum,braket
         cat requirements.txt
         python3 -m pip install -r requirements.txt --prefer-binary
 
@@ -152,7 +152,7 @@ jobs:
       run: python3 -m pip install --upgrade pybind11 flaky --prefer-binary
 
     - name: Build and install package
-      run: python3 -m pip install -ve .[braket,test]
+      run: python3 -m pip install -ve .[azure-quantum,braket,test]
 
     - name: Pytest
       run: |
@@ -190,8 +190,8 @@ jobs:
 
     - name: Prepare Python env
       run: |
-        python3 setup.py gen_reqfile --include-extras=test,braket
         python3 -m pip install -U pip setuptools wheel
+        python3 setup.py gen_reqfile --include-extras=test,azure-quantum,braket
         cat requirements.txt
         python3 -m pip install -r requirements.txt --prefer-binary
 
@@ -199,7 +199,7 @@ jobs:
       run: python3 -m pip install --upgrade pybind11 flaky --prefer-binary
 
     - name: Build and install package
-      run: python3 -m pip install -ve .[braket,test]
+      run: python3 -m pip install -ve .[azure-quantum,braket,test]
 
     - name: Pytest
       run: |
@@ -274,13 +274,13 @@ jobs:
 
     - name: Install dependencies
       run: |
-        python3 setup.py gen_reqfile --include-extras=test,braket
         python3 -m pip install -U pip setuptools wheel
+        python3 setup.py gen_reqfile --include-extras=test,azure-quantum,braket
         cat requirements.txt
         python3 -m pip install -r requirements.txt --prefer-binary
 
     - name: Build and install package
-      run: python3 -m pip install -ve .[braket,test]
+      run: python3 -m pip install -ve .[azure-quantum,braket,test]
 
     - name: Pytest
       run: |
diff --git a/.travis.yml b/.travis.yml
index 0dd408af0..b4ab7159f 100755
--- a/.travis.yml
+++ b/.travis.yml
@@ -60,6 +60,7 @@ install:
   - env
   - python3 -m pip install -U pip setuptools wheel
   - python3 -m pip install -U pybind11 dormouse revkit flaky pytest-cov coveralls boto3
+  - python3 -m pip install -U azure-quantum
   - python3 -m pip install -r requirements.txt
   - python3 -m pip install -ve .
 
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ec2209730..c7a5f625b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ## [Unreleased]
 
+### Added
+
+-   New backend for the Azure Quantum platform
+
 ### Changed
 
 -   Support for Python 3.6 and earlier is now deprecated
diff --git a/README.rst b/README.rst
index 1f85c2cc2..a2c794bb0 100755
--- a/README.rst
+++ b/README.rst
@@ -27,7 +27,7 @@ targeting various types of hardware, a high-performance quantum computer
 simulator with emulation capabilities, and various compiler plug-ins.
 This allows users to
 
--  run quantum programs on the IBM Quantum Experience chip, AQT devices, AWS Braket, or IonQ service provided devices
+-  run quantum programs on the IBM Quantum Experience chip, AQT devices, AWS Braket, Azure Quantum, or IonQ service provided devices
 -  simulate quantum programs on classical computers
 -  emulate quantum programs at a higher level of abstraction (e.g.,
    mimicking the action of large oracles instead of compiling them to
@@ -186,6 +186,35 @@ IonQ from IonQ and the state vector simulator SV1:
        python3 -m pip install -ve .[braket]
 
 
+**Running a quantum program on a Azure Quantum provided device**
+
+To run a program on devices provided by the `Azure Quantum <https://azure.microsoft.com/en-us/services/quantum/>`_.
+
+Use `AzureQuantumBackend` to run ProjectQ circuits on hardware devices and simulator devices from providers `IonQ` and `Quantinuum`.
+
+.. code-block:: python
+
+    from projectq.backends import AzureQuantumBackend
+
+    azure_quantum_backend = AzureQuantumBackend(
+        use_hardware=False, target_name='ionq.simulator', resource_id='<resource-id>', location='<location>', verbose=True
+    )
+
+.. note::
+
+   In order to use the AzureQuantumBackend, you need to install ProjectQ with the 'azure-quantum' extra requirement:
+
+   .. code-block:: bash
+
+       python3 -m pip install projectq[azure-quantum]
+
+   or
+
+   .. code-block:: bash
+
+       cd /path/to/projectq/source/code
+       python3 -m pip install -ve .[azure-quantum]
+
 **Running a quantum program on IonQ devices**
 
 To run a program on the IonQ trapped ion hardware, use the `IonQBackend` and its corresponding setup.
diff --git a/docs/tutorials.rst b/docs/tutorials.rst
index 669ec9eb0..bcc7e2d67 100755
--- a/docs/tutorials.rst
+++ b/docs/tutorials.rst
@@ -54,6 +54,14 @@ AWS Braket Backend requires the use of the official AWS SDK for Python, Boto3. T
 
     python -m pip install --user projectq[braket]
 
+**Install Azure Quantum Backend requirement**
+
+Azure Quantum Backend requires the use of the official `Azure Quantum SDK <https://github.com/microsoft/qdk-python>`_ for Python. This is an extra requirement only needed if you plan to use the Azure Quantum Backend. To install ProjectQ inluding this requirement you can include it in the installation instruction as
+
+.. code-block:: bash
+
+    python -m pip install --user projectq[azure-quantum]
+
 
 Detailed instructions and OS-specific hints
 -------------------------------------------
diff --git a/examples/azure-quantum.ipynb b/examples/azure-quantum.ipynb
new file mode 100644
index 000000000..bd126815d
--- /dev/null
+++ b/examples/azure-quantum.ipynb
@@ -0,0 +1,264 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "id": "2f4b2787-f008-4331-83ee-e743c64017aa",
+   "metadata": {},
+   "source": [
+    "# Azure Quantum Backend"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "2bc9b3a4-23d8-4638-b875-386295010a3d",
+   "metadata": {},
+   "source": [
+    "## Prerequisites\n",
+    "\n",
+    "- An Azure account with active subcription.\n",
+    "- An Azure Quantum workspace. ([How to create this?](https://docs.microsoft.com/en-us/azure/quantum/how-to-create-workspace?tabs=tabid-quick))\n",
+    "- Resource ID and location of Azure Quantum workspace.\n",
+    "- Install Azure Quantum dependencies for ProjectQ.\n",
+    "```\n",
+    "python -m pip install --user projectq[azure-quantum]\n",
+    "```"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "e8e87193-fc98-4718-a62d-cbbde662b82f",
+   "metadata": {},
+   "source": [
+    "## Load Imports\n",
+    "\n",
+    "Run following cell to load requried imports"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "a239f2e4-dcc1-4c9f-b8db-0a775a9e2863",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import matplotlib.pyplot as plt\n",
+    "\n",
+    "from projectq import MainEngine\n",
+    "from projectq.ops import H, CX, All, Measure\n",
+    "from projectq.cengines import BasicMapperEngine\n",
+    "from projectq.backends import AzureQuantumBackend\n",
+    "from projectq.libs.hist import histogram"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "e98cedd2-3d13-4b81-8776-59ef74a0ca2c",
+   "metadata": {},
+   "source": [
+    "## Initialize Azure Quantum backend\n",
+    "\n",
+    "Update `resource_id` and `location` of your Azure Quantum workspace in below cell and run to initialize Azure Quantum workspace.\n",
+    "\n",
+    "Following are valid `target_names`:\n",
+    "- ionq.simulator\n",
+    "- ionq.qpu\n",
+    "- quantinuum.hqs-lt-s1-apival\n",
+    "- quantinuum.hqs-lt-s1-sim\n",
+    "- quantinuum.hqs-lt-s1\n",
+    "\n",
+    "Flag `use_hardware` represents wheather or not use real hardware or just a simulator. If False regardless of the value of `target_name`, simulator will be used."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "7e160b42-039e-4d5b-8333-7169bc77c57f",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "azure_quantum_backend = AzureQuantumBackend(\n",
+    "    use_hardware=False,\n",
+    "    target_name='ionq.simulator',\n",
+    "    resource_id=\"<resource-id>\",  # resource id of workspace\n",
+    "    location=\"<location>\",  # location of workspace\n",
+    "    verbose=True\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "321876bd-dbbf-446d-9732-3627037d49f0",
+   "metadata": {},
+   "source": [
+    "## Create ProjectQ Engine\n",
+    "\n",
+    "Initialize ProjectQ `MainEngine` using Azure Quantum as backend."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "6fbc7650-fa8a-4047-8739-ee79aa2e6c2a",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "mapper = BasicMapperEngine()\n",
+    "max_qubits = 3\n",
+    "\n",
+    "mapping = {}\n",
+    "for i in range(max_qubits):\n",
+    "    mapping[i] = i\n",
+    "\n",
+    "mapper.current_mapping = mapping\n",
+    "\n",
+    "main_engine = MainEngine(\n",
+    "    backend=azure_quantum_backend,\n",
+    "    engine_list=[mapper]\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "d2665b04-0903-4176-b62d-b8fed5d5e041",
+   "metadata": {},
+   "source": [
+    "## Create circuit using ProjectQ lean syntax!\n",
+    "\n",
+    "Allocate qubits, build circuit and measure qubits."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "4a8e84c3-cf1c-44db-80f1-e0a229a38eb9",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "circuit = main_engine.allocate_qureg(3)\n",
+    "q0, q1, q2 = circuit\n",
+    "\n",
+    "H | q0\n",
+    "CX | (q0, q1)\n",
+    "CX | (q1, q2)\n",
+    "All(Measure) | circuit"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "4a9901e8-ed74-4859-a004-8f1b9b72dd45",
+   "metadata": {},
+   "source": [
+    "## Run circuit and get result\n",
+    "\n",
+    "Flush down circuit to Azure Quantum backend and wait for results. It prints `job-id` for the reference (in case this operation timed-out). "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "9af5ea10-1edc-4fe9-9d8d-c021c196779d",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "main_engine.flush()\n",
+    "\n",
+    "print(azure_quantum_backend.get_probabilities(circuit))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "b7dfc230-d4fc-4460-8acb-c42ebccc1659",
+   "metadata": {},
+   "source": [
+    "## Timed out! Re-run the circuit with retrieve_execution argument\n",
+    "\n",
+    "If job execution timed-out, use `retrieve_execution` argument retrive result instead of re-running the circuit. Use `job-id` from previous cell."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "b05001b5-25ca-4dfd-a165-123ac7e83b38",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "azure_quantum_backend = AzureQuantumBackend(\n",
+    "    use_hardware=False,\n",
+    "    target_name='ionq.simulator',\n",
+    "    resource_id=\"<resource-id>\",  # resource id of workspace\n",
+    "    location=\"<location>\",  # location of workspace\n",
+    "    retrieve_execution=\"<job-id>\",  # job-id of Azure Quantum job\n",
+    "    verbose=True\n",
+    ")\n",
+    "\n",
+    "mapper = BasicMapperEngine()\n",
+    "max_qubits = 10\n",
+    "\n",
+    "mapping = {}\n",
+    "for i in range(max_qubits):\n",
+    "    mapping[i] = i\n",
+    "\n",
+    "mapper.current_mapping = mapping\n",
+    "\n",
+    "main_engine = MainEngine(\n",
+    "    backend=azure_quantum_backend,\n",
+    "    engine_list=[mapper]\n",
+    ")\n",
+    "\n",
+    "circuit = main_engine.allocate_qureg(3)\n",
+    "q0, q1, q2 = circuit\n",
+    "\n",
+    "H | q0\n",
+    "CX | (q0, q1)\n",
+    "CX | (q1, q2)\n",
+    "All(Measure) | circuit\n",
+    "\n",
+    "main_engine.flush()\n",
+    "\n",
+    "print(azure_quantum_backend.get_probabilities(circuit))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "b658cb79-15c8-4e25-acbd-77788af08f9e",
+   "metadata": {},
+   "source": [
+    "# Plot Histogram\n",
+    "\n",
+    "Now, let's plot histogram with above result."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "68b3fa8d-a06d-4049-8350-d179304bf045",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "histogram(main_engine.backend, circuit)\n",
+    "plt.show()"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python [conda env:projectq] *",
+   "language": "python",
+   "name": "conda-env-projectq-py"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.10.4"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/projectq/backends/__init__.py b/projectq/backends/__init__.py
index 0b72a8b71..e531ed9f2 100755
--- a/projectq/backends/__init__.py
+++ b/projectq/backends/__init__.py
@@ -25,10 +25,12 @@
 * an interface to the IBM Quantum Experience chip (and simulator).
 * an interface to the AQT trapped ion system (and simulator).
 * an interface to the AWS Braket service decives (and simulators)
+* an interface to the Azure Quantum service devices (and simulators)
 * an interface to the IonQ trapped ionq hardware (and simulator).
 """
 from ._aqt import AQTBackend
 from ._awsbraket import AWSBraketBackend
+from ._azure import AzureQuantumBackend
 from ._circuits import CircuitDrawer, CircuitDrawerMatplotlib
 from ._exceptions import DeviceNotHandledError, DeviceOfflineError, DeviceTooSmall
 from ._ibm import IBMBackend
diff --git a/projectq/backends/_aqt/_aqt.py b/projectq/backends/_aqt/_aqt.py
index 48942b475..cb1993099 100644
--- a/projectq/backends/_aqt/_aqt.py
+++ b/projectq/backends/_aqt/_aqt.py
@@ -23,15 +23,10 @@
 from projectq.types import WeakQubitRef
 
 from .._exceptions import InvalidCommandError
+from .._utils import _rearrange_result
 from ._aqt_http_client import retrieve, send
 
 
-# _rearrange_result & _format_counts imported and modified from qiskit
-def _rearrange_result(input_result, length):
-    bin_input = list(bin(input_result)[2:].rjust(length, '0'))
-    return ''.join(bin_input)[::-1]
-
-
 def _format_counts(samples, length):
     counts = {}
     for result in samples:
diff --git a/projectq/backends/_azure/__init__.py b/projectq/backends/_azure/__init__.py
new file mode 100644
index 000000000..8c06e2392
--- /dev/null
+++ b/projectq/backends/_azure/__init__.py
@@ -0,0 +1,27 @@
+#   Copyright 2022 ProjectQ-Framework (www.projectq.ch)
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+
+"""ProjectQ module for supporting the Azure Quantum platform."""
+
+try:
+    from ._azure_quantum import AzureQuantumBackend
+except ImportError:  # pragma: no cover
+
+    class AzureQuantumBackend:
+        """Dummy class"""
+
+        def __init__(self, *args, **kwargs):
+            raise ImportError(
+                "Missing optional 'azure-quantum' dependencies. To install run: pip install projectq[azure-quantum]"
+            )
diff --git a/projectq/backends/_azure/_azure_quantum.py b/projectq/backends/_azure/_azure_quantum.py
new file mode 100644
index 000000000..e8187c87c
--- /dev/null
+++ b/projectq/backends/_azure/_azure_quantum.py
@@ -0,0 +1,387 @@
+#   Copyright 2022 ProjectQ-Framework (www.projectq.ch)
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+
+"""Back-end to run quantum programs using Azure Quantum."""
+
+from collections import Counter
+
+import numpy as np
+
+from projectq.cengines import BasicEngine
+from projectq.meta import LogicalQubitIDTag
+from projectq.ops import AllocateQubitGate, DeallocateQubitGate, FlushGate, MeasureGate
+from projectq.types import WeakQubitRef
+
+from .._utils import _rearrange_result
+from ._azure_quantum_client import retrieve, send
+from ._exceptions import AzureQuantumTargetNotFoundError
+from ._utils import (
+    IONQ_PROVIDER_ID,
+    QUANTINUUM_PROVIDER_ID,
+    is_available_ionq,
+    is_available_quantinuum,
+    to_json,
+    to_qasm,
+)
+
+try:
+    from azure.quantum import Workspace
+    from azure.quantum.target import IonQ, Quantinuum, Target
+    from azure.quantum.target.target_factory import TargetFactory
+except ImportError:  # pragma: no cover
+    raise ImportError(  # pylint: disable=raise-missing-from
+        "Missing optional 'azure-quantum' dependencies. To install run: pip install projectq[azure-quantum]"
+    )
+
+
+class AzureQuantumBackend(BasicEngine):  # pylint: disable=too-many-instance-attributes
+    """Backend for building circuits and submitting them to the Azure Quantum."""
+
+    DEFAULT_TARGETS = {IONQ_PROVIDER_ID: IonQ, QUANTINUUM_PROVIDER_ID: Quantinuum}
+
+    def __init__(
+        self,
+        use_hardware=False,
+        num_runs=100,
+        verbose=False,
+        workspace=None,
+        target_name='ionq.simulator',
+        num_retries=100,
+        interval=1,
+        retrieve_execution=None,
+        **kwargs,
+    ):  # pylint: disable=too-many-arguments
+        """
+        Initialize an Azure Quantum Backend object.
+
+        Args:
+            use_hardware (bool, optional): Whether or not to use real hardware or just a simulator. If False,
+                regardless of the value of ```target_name```, ```ionq.simulator``` used for IonQ provider and
+                ```quantinuum.hqs-lt-s1-apival``` used for Quantinuum provider. Defaults to False.
+            num_runs (int, optional): Number of times to run circuits. Defaults to 100.
+            verbose (bool, optional): If True, print statistics after job results have been collected. Defaults to
+                False.
+            workspace (Workspace, optional): Azure Quantum workspace. If workspace is None, kwargs will be used to
+                create Workspace object.
+            target_name (str, optional): Target to run jobs on. Defaults to ```ionq.simulator```.
+            num_retries (int, optional): Number of times to retry fetching a job after it has been submitted. Defaults
+                to 100.
+            interval (int, optional): Number of seconds to wait in between result fetch retries. Defaults to 1.
+            retrieve_execution (str, optional): An Azure Quantum Job ID. If provided, a job result with this ID will be
+                fetched. Defaults to None.
+        """
+        super().__init__()
+
+        if target_name in IonQ.target_names:
+            self._provider_id = IONQ_PROVIDER_ID
+        elif target_name in Quantinuum.target_names:
+            self._provider_id = QUANTINUUM_PROVIDER_ID
+        else:
+            raise AzureQuantumTargetNotFoundError(f'Target {target_name} does not exit.')
+
+        if use_hardware:
+            self._target_name = target_name
+        else:
+            if self._provider_id == IONQ_PROVIDER_ID:
+                self._target_name = 'ionq.simulator'
+            elif self._provider_id == QUANTINUUM_PROVIDER_ID:
+                if target_name == 'quantinuum.hqs-lt-s1':
+                    self._target_name = 'quantinuum.hqs-lt-s1-apival'
+                else:
+                    self._target_name = target_name
+            else:  # pragma: no cover
+                raise RuntimeError("Invalid Azure Quantum target.")
+
+        if workspace is None:
+            workspace = Workspace(**kwargs)
+
+        workspace.append_user_agent('projectq')
+        self._workspace = workspace
+
+        self._num_runs = num_runs
+        self._verbose = verbose
+        self._num_retries = num_retries
+        self._interval = interval
+        self._retrieve_execution = retrieve_execution
+        self._circuit = None
+        self._measured_ids = []
+        self._probabilities = {}
+        self._clear = True
+
+    def _reset(self):
+        """
+        Reset this backend.
+
+        Note:
+            This sets ``_clear = True``, which will trigger state cleanup on the next call to ``_store``.
+        """
+        # Lastly, reset internal state for measured IDs and circuit body.
+        self._circuit = None
+        self._clear = True
+
+    def _store(self, cmd):  # pylint: disable=too-many-branches
+        """
+        Temporarily store the command cmd.
+
+        Translates the command and stores it in a local variable (self._cmds).
+
+        Args:
+            cmd (Command): Command to store
+        """
+        if self._clear:
+            self._probabilities = {}
+            self._clear = False
+            self._circuit = None
+
+        gate = cmd.gate
+
+        # No-op/Meta gates
+        if isinstance(gate, (AllocateQubitGate, DeallocateQubitGate)):
+            return
+
+        # Measurement
+        if isinstance(gate, MeasureGate):
+            logical_id = None
+            for tag in cmd.tags:
+                if isinstance(tag, LogicalQubitIDTag):
+                    logical_id = tag.logical_qubit_id
+                    break
+
+            if logical_id is None:
+                raise RuntimeError('No LogicalQubitIDTag found in command!')
+
+            self._measured_ids.append(logical_id)
+            return
+
+        if self._provider_id == IONQ_PROVIDER_ID:
+            if not self._circuit:
+                self._circuit = []
+
+            json_cmd = to_json(cmd)
+            if json_cmd:
+                self._circuit.append(json_cmd)
+
+        elif self._provider_id == QUANTINUUM_PROVIDER_ID:
+            if not self._circuit:
+                self._circuit = ''
+
+            qasm_cmd = to_qasm(cmd)
+            if qasm_cmd:
+                self._circuit += f'\n{qasm_cmd}'
+
+        else:
+            raise RuntimeError("Invalid Azure Quantum target.")
+
+    def is_available(self, cmd):
+        """
+        Test if this backend is available to process the provided command.
+
+        Args:
+            cmd (Command): A command to process.
+
+        Returns:
+            bool: If this backend can process the command.
+        """
+        if self._provider_id == IONQ_PROVIDER_ID:
+            return is_available_ionq(cmd)
+
+        if self._provider_id == QUANTINUUM_PROVIDER_ID:
+            return is_available_quantinuum(cmd)
+
+        return False
+
+    @staticmethod
+    def _target_factory(workspace, target_name, provider_id):  # pragma: no cover
+        target_factory = TargetFactory(
+            base_cls=Target, workspace=workspace, default_targets=AzureQuantumBackend.DEFAULT_TARGETS
+        )
+
+        return target_factory.get_targets(name=target_name, provider_id=provider_id)
+
+    @property
+    def _target(self):
+        target = self._target_factory(
+            workspace=self._workspace, target_name=self._target_name, provider_id=self._provider_id
+        )
+
+        if isinstance(target, list) and len(target) == 0:  # pragma: no cover
+            raise AzureQuantumTargetNotFoundError(
+                f'Target {self._target_name} is not available on workspace {self._workspace.name}.'
+            )
+
+        return target
+
+    @property
+    def current_availability(self):
+        """Get current availability for given target."""
+        return self._target.current_availability
+
+    @property
+    def average_queue_time(self):
+        """Get average queue time for given target."""
+        return self._target.average_queue_time
+
+    def get_probability(self, state, qureg):
+        """Shortcut to get a specific state's probability.
+
+        Args:
+            state (str): A state in bit-string format.
+            qureg (Qureg): A ProjectQ Qureg object.
+
+        Returns:
+            float: The probability for the provided state.
+        """
+        if len(state) != len(qureg):
+            raise ValueError('Desired state and register must be the same length!')
+
+        probs = self.get_probabilities(qureg)
+
+        return probs.get(state, 0.0)
+
+    def get_probabilities(self, qureg):
+        """
+        Given the provided qubit register, determine the probability of each possible outcome.
+
+        Note:
+            This method should only be called *after* a circuit has been run and its results are available.
+
+        Args:
+            qureg (Qureg): A ProjectQ Qureg object.
+
+        Returns:
+            dict: A dict mapping of states -> probability.
+        """
+        if len(self._probabilities) == 0:
+            raise RuntimeError("Please, run the circuit first!")
+
+        probability_dict = {}
+        for state in self._probabilities:
+            mapped_state = ['0'] * len(qureg)
+            for i, qubit in enumerate(qureg):
+                try:
+                    meas_idx = self._measured_ids.index(qubit.id)
+                except ValueError:
+                    continue
+                mapped_state[i] = state[meas_idx]
+            probability = self._probabilities[state]
+            mapped_state = "".join(mapped_state)
+            probability_dict[mapped_state] = probability_dict.get(mapped_state, 0) + probability
+        return probability_dict
+
+    @property
+    def _input_data(self):
+        qubit_mapping = self.main_engine.mapper.current_mapping
+        qubits = len(qubit_mapping.keys())
+
+        if self._provider_id == IONQ_PROVIDER_ID:
+            return {"qubits": qubits, "circuit": self._circuit}
+
+        if self._provider_id == QUANTINUUM_PROVIDER_ID:
+            measurement_gates = ""
+
+            for measured_id in self._measured_ids:
+                qb_loc = self.main_engine.mapper.current_mapping[measured_id]
+                measurement_gates += "measure q[{0}] -> c[{0}];\n".format(qb_loc)
+
+            return (
+                f"OPENQASM 2.0;\ninclude \"qelib1.inc\";\nqreg q[{qubits}];\ncreg c[{qubits}];"
+                f"{self._circuit}\n{measurement_gates}"
+            )
+
+        raise RuntimeError("Invalid Azure Quantum target.")
+
+    @property
+    def _metadata(self):
+        qubit_mapping = self.main_engine.mapper.current_mapping
+        num_qubits = len(qubit_mapping.keys())
+        meas_map = [qubit_mapping[qubit_id] for qubit_id in self._measured_ids]
+
+        return {"num_qubits": num_qubits, "meas_map": meas_map}
+
+    def estimate_cost(self, **kwargs):
+        """Estimate cost for the circuit this object has built during engine execution."""
+        return self._target.estimate_cost(circuit=self._input_data, num_shots=self._num_runs, **kwargs)
+
+    def _run(self):  # pylint: disable=too-many-locals
+        """Run the circuit this object has built during engine execution."""
+        # Nothing to do with an empty circuit.
+        if not self._circuit:
+            return
+
+        if self._retrieve_execution is None:
+            res = send(
+                input_data=self._input_data,
+                metadata=self._metadata,
+                num_shots=self._num_runs,
+                target=self._target,
+                num_retries=self._num_retries,
+                interval=self._interval,
+                verbose=self._verbose,
+            )
+
+            if res is None:  # pragma: no cover
+                raise RuntimeError('Failed to submit job to the Azure Quantum!')
+        else:
+            res = retrieve(
+                job_id=self._retrieve_execution,
+                target=self._target,
+                num_retries=self._num_retries,
+                interval=self._interval,
+                verbose=self._verbose,
+            )
+
+            if res is None:
+                raise RuntimeError(
+                    f"Failed to retrieve job from Azure Quantum with job id: '{self._retrieve_execution}'!"
+                )
+
+        if self._provider_id == IONQ_PROVIDER_ID:
+            self._probabilities = {
+                _rearrange_result(int(k), len(self._measured_ids)): v for k, v in res["histogram"].items()
+            }
+        elif self._provider_id == QUANTINUUM_PROVIDER_ID:
+            histogram = Counter(res["c"])
+            self._probabilities = {k: v / self._num_runs for k, v in histogram.items()}
+        else:  # pragma: no cover
+            raise RuntimeError("Invalid Azure Quantum target.")
+
+        # Set a single measurement result
+        bitstring = np.random.choice(list(self._probabilities.keys()), p=list(self._probabilities.values()))
+        for qid in self._measured_ids:
+            qubit_ref = WeakQubitRef(self.main_engine, qid)
+            self.main_engine.set_measurement_result(qubit_ref, bitstring[qid])
+
+    def receive(self, command_list):
+        """Receive a command list from the ProjectQ engine pipeline.
+
+        If a given command is a "flush" operation, the pending circuit will be
+        submitted to Azure Quantum for processing.
+
+        Args:
+            command_list (list[Command]): A list of ProjectQ Command objects.
+        """
+        for cmd in command_list:
+            if not isinstance(cmd.gate, FlushGate):
+                self._store(cmd)
+            else:
+                # After that, the circuit is ready to be submitted.
+                try:
+                    self._run()
+                finally:
+                    # Make sure we always reset engine state so as not to leave
+                    #    anything dirty atexit.
+                    self._reset()
+
+
+__all__ = ['AzureQuantumBackend']
diff --git a/projectq/backends/_azure/_azure_quantum_client.py b/projectq/backends/_azure/_azure_quantum_client.py
new file mode 100644
index 000000000..86c3f1891
--- /dev/null
+++ b/projectq/backends/_azure/_azure_quantum_client.py
@@ -0,0 +1,96 @@
+#   Copyright 2022 ProjectQ-Framework (www.projectq.ch)
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+
+"""Client methods to run quantum programs using Azure Quantum."""
+
+from .._exceptions import DeviceOfflineError, RequestTimeoutError
+
+
+def _get_results(job, num_retries=100, interval=1, verbose=False):
+    if verbose:  # pragma: no cover
+        print(f"- Waiting for results. [Job ID: {job.id}]")
+
+    try:
+        return job.get_results(timeout_secs=num_retries * interval)
+    except TimeoutError:
+        raise RequestTimeoutError(  # pylint: disable=raise-missing-from
+            f"Timeout. The ID of your submitted job is {job.id}."
+        )
+
+
+def send(
+    input_data, num_shots, target, num_retries=100, interval=1, verbose=False, **kwargs
+):  # pylint: disable=too-many-arguments
+    """
+    Submit a job to the Azure Quantum.
+
+    Args:
+        input_data (any): Input data for Quantum job.
+        num_shots (int): Number of runs.
+        target (Target), The target to run this on.
+        num_retries (int, optional): Number of times to retry while the job is
+            not finished. Defaults to 100.
+        interval (int, optional): Sleep interval between retries, in seconds.
+            Defaults to 1.
+        verbose (bool, optional): Whether to print verbose output.
+            Defaults to False.
+
+    Raises:
+        DeviceOfflineError: If the desired device is not available for job
+            processing.
+
+    Returns:
+        dict: An intermediate dict representation of an Azure Quantum job result.
+    """
+    if target.current_availability != 'Available':
+        raise DeviceOfflineError('Device is offline.')
+
+    if verbose:
+        print(f"- Running code: {input_data}")
+
+    job = target.submit(circuit=input_data, num_shots=num_shots, **kwargs)
+
+    res = _get_results(job=job, num_retries=num_retries, interval=interval, verbose=verbose)
+
+    if verbose:
+        print("- Done.")
+
+    return res
+
+
+def retrieve(job_id, target, num_retries=100, interval=1, verbose=False):
+    """
+    Retrieve a job from Azure Quantum.
+
+    Args:
+        job_id (str), Azure Quantum job id.
+        target (Target), The target job runs on.
+        num_retries (int, optional): Number of times to retry while the job is
+            not finished. Defaults to 100.
+        interval (int, optional): Sleep interval between retries, in seconds.
+            Defaults to 1.
+        verbose (bool, optional): Whether to print verbose output.
+            Defaults to False.
+
+    Returns:
+        dict: An intermediate dict representation of an Azure Quantum job result.
+    """
+    job = target.workspace.get_job(job_id=job_id)
+
+    res = _get_results(job=job, num_retries=num_retries, interval=interval, verbose=verbose)
+
+    if verbose:
+        print("- Done.")
+
+    return res
diff --git a/projectq/backends/_azure/_azure_quantum_client_test.py b/projectq/backends/_azure/_azure_quantum_client_test.py
new file mode 100644
index 000000000..5ce1a6d8f
--- /dev/null
+++ b/projectq/backends/_azure/_azure_quantum_client_test.py
@@ -0,0 +1,420 @@
+#   Copyright 2022 ProjectQ-Framework (www.projectq.ch)
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+
+"""Tests for projectq.backends._azure._azure_quantum_client.py."""
+
+from unittest import mock
+
+import pytest
+
+from .._exceptions import DeviceOfflineError, RequestTimeoutError
+
+_has_azure_quantum = True
+try:
+    import azure.quantum  # noqa: F401
+
+    from projectq.backends._azure._azure_quantum_client import retrieve, send
+except ImportError:
+    _has_azure_quantum = False
+
+has_azure_quantum = pytest.mark.skipif(not _has_azure_quantum, reason="azure quantum package is not installed")
+
+ZERO_GUID = '00000000-0000-0000-0000-000000000000'
+
+
+@has_azure_quantum
+def test_is_online():
+    def get_mock_target():
+        mock_target = mock.MagicMock()
+        mock_target.current_availability = 'Offline'
+
+        return mock_target
+
+    with pytest.raises(DeviceOfflineError):
+        send(
+            input_data={},
+            metadata={},
+            num_shots=100,
+            target=get_mock_target(),
+            num_retries=1000,
+            interval=1,
+            verbose=True,
+        )
+
+
+@has_azure_quantum
+@pytest.mark.parametrize('verbose', (False, True))
+def test_send_ionq(verbose):
+    expected_res = {'0': 0.125, '1': 0.125, '2': 0.125, '3': 0.125, '4': 0.125, '5': 0.125, '6': 0.125, '7': 0.125}
+
+    def get_mock_target():
+        mock_job = mock.MagicMock()
+        mock_job.id = ZERO_GUID
+        mock_job.get_results = mock.MagicMock(return_value=expected_res)
+
+        mock_target = mock.MagicMock()
+        mock_target.current_availability = 'Available'
+        mock_target.submit = mock.MagicMock(return_value=mock_job)
+
+        return mock_target
+
+    input_data = {
+        'qubits': 3,
+        'circuit': [{'gate': 'h', 'targets': [0]}, {'gate': 'h', 'targets': [1]}, {'gate': 'h', 'targets': [2]}],
+    }
+    metadata = {'num_qubits': 3, 'meas_map': [0, 1, 2]}
+
+    actual_res = send(
+        input_data=input_data,
+        metadata=metadata,
+        num_shots=100,
+        target=get_mock_target(),
+        num_retries=1000,
+        interval=1,
+        verbose=verbose,
+    )
+
+    assert actual_res == expected_res
+
+
+@has_azure_quantum
+@pytest.mark.parametrize('verbose', (False, True))
+def test_send_quantinuum(verbose):
+    expected_res = {
+        'c': [
+            '010',
+            '100',
+            '110',
+            '000',
+            '101',
+            '111',
+            '000',
+            '100',
+            '000',
+            '110',
+            '111',
+            '100',
+            '100',
+            '000',
+            '101',
+            '110',
+            '111',
+            '011',
+            '101',
+            '100',
+            '001',
+            '110',
+            '001',
+            '001',
+            '100',
+            '011',
+            '110',
+            '000',
+            '101',
+            '101',
+            '010',
+            '100',
+            '110',
+            '111',
+            '010',
+            '000',
+            '010',
+            '110',
+            '000',
+            '110',
+            '001',
+            '100',
+            '110',
+            '011',
+            '010',
+            '111',
+            '100',
+            '110',
+            '100',
+            '100',
+            '011',
+            '000',
+            '001',
+            '101',
+            '000',
+            '011',
+            '111',
+            '101',
+            '101',
+            '001',
+            '011',
+            '110',
+            '001',
+            '010',
+            '001',
+            '110',
+            '101',
+            '000',
+            '010',
+            '001',
+            '011',
+            '100',
+            '110',
+            '100',
+            '110',
+            '101',
+            '110',
+            '111',
+            '110',
+            '001',
+            '011',
+            '101',
+            '111',
+            '011',
+            '100',
+            '111',
+            '100',
+            '001',
+            '111',
+            '111',
+            '100',
+            '100',
+            '110',
+            '101',
+            '100',
+            '110',
+            '100',
+            '000',
+            '011',
+            '000',
+        ]
+    }
+
+    def get_mock_target():
+        mock_job = mock.MagicMock()
+        mock_job.id = ZERO_GUID
+        mock_job.get_results = mock.MagicMock(return_value=expected_res)
+
+        mock_target = mock.MagicMock()
+        mock_target.current_availability = 'Available'
+        mock_target.submit = mock.MagicMock(return_value=mock_job)
+
+        return mock_target
+
+    input_data = ''''OPENQASM 2.0;
+        include "qelib1.inc";
+        qreg q[3];
+        creg c[3];
+        h q[0];
+        h q[1];
+        h q[2];
+        measure q[0] -> c[0];
+        measure q[1] -> c[1];
+        measure q[2] -> c[2];
+'''
+
+    metadata = {'num_qubits': 3, 'meas_map': [0, 1, 2]}
+
+    actual_res = send(
+        input_data=input_data,
+        metadata=metadata,
+        num_shots=100,
+        target=get_mock_target(),
+        num_retries=1000,
+        interval=1,
+        verbose=verbose,
+    )
+
+    assert actual_res == expected_res
+
+
+@has_azure_quantum
+@pytest.mark.parametrize('verbose', (False, True))
+def test_retrieve_ionq(verbose):
+    expected_res = {'0': 0.125, '1': 0.125, '2': 0.125, '3': 0.125, '4': 0.125, '5': 0.125, '6': 0.125, '7': 0.125}
+
+    def get_mock_target():
+        mock_job = mock.MagicMock()
+        mock_job.id = ZERO_GUID
+        mock_job.get_results = mock.MagicMock(return_value=expected_res)
+
+        mock_workspace = mock.MagicMock()
+        mock_workspace.get_job = mock.MagicMock(return_value=mock_job)
+
+        mock_target = mock.MagicMock()
+        mock_target.current_availability = 'Available'
+        mock_target.workspace = mock_workspace
+        mock_target.submit = mock.MagicMock(return_value=mock_job)
+
+        return mock_target
+
+    actual_res = retrieve(job_id=ZERO_GUID, target=get_mock_target(), num_retries=1000, interval=1, verbose=verbose)
+
+    assert actual_res == expected_res
+
+
+@has_azure_quantum
+@pytest.mark.parametrize('verbose', (False, True))
+def test_retrieve_quantinuum(verbose):
+    expected_res = {
+        'c': [
+            '010',
+            '100',
+            '110',
+            '000',
+            '101',
+            '111',
+            '000',
+            '100',
+            '000',
+            '110',
+            '111',
+            '100',
+            '100',
+            '000',
+            '101',
+            '110',
+            '111',
+            '011',
+            '101',
+            '100',
+            '001',
+            '110',
+            '001',
+            '001',
+            '100',
+            '011',
+            '110',
+            '000',
+            '101',
+            '101',
+            '010',
+            '100',
+            '110',
+            '111',
+            '010',
+            '000',
+            '010',
+            '110',
+            '000',
+            '110',
+            '001',
+            '100',
+            '110',
+            '011',
+            '010',
+            '111',
+            '100',
+            '110',
+            '100',
+            '100',
+            '011',
+            '000',
+            '001',
+            '101',
+            '000',
+            '011',
+            '111',
+            '101',
+            '101',
+            '001',
+            '011',
+            '110',
+            '001',
+            '010',
+            '001',
+            '110',
+            '101',
+            '000',
+            '010',
+            '001',
+            '011',
+            '100',
+            '110',
+            '100',
+            '110',
+            '101',
+            '110',
+            '111',
+            '110',
+            '001',
+            '011',
+            '101',
+            '111',
+            '011',
+            '100',
+            '111',
+            '100',
+            '001',
+            '111',
+            '111',
+            '100',
+            '100',
+            '110',
+            '101',
+            '100',
+            '110',
+            '100',
+            '000',
+            '011',
+            '000',
+        ]
+    }
+
+    def get_mock_target():
+        mock_job = mock.MagicMock()
+        mock_job.id = ZERO_GUID
+        mock_job.get_results = mock.MagicMock(return_value=expected_res)
+
+        mock_workspace = mock.MagicMock()
+        mock_workspace.get_job = mock.MagicMock(return_value=mock_job)
+
+        mock_target = mock.MagicMock()
+        mock_target.current_availability = 'Available'
+        mock_target.workspace = mock_workspace
+        mock_target.submit = mock.MagicMock(return_value=mock_job)
+
+        return mock_target
+
+    actual_res = retrieve(job_id=ZERO_GUID, target=get_mock_target(), num_retries=1000, interval=1, verbose=verbose)
+
+    assert actual_res == expected_res
+
+
+@has_azure_quantum
+@pytest.mark.parametrize('verbose', (False, True))
+def test_send_timeout_error(verbose):
+    def get_mock_target():
+        mock_job = mock.MagicMock()
+        mock_job.id = ZERO_GUID
+        mock_job.get_results = mock.MagicMock()
+        mock_job.get_results.side_effect = TimeoutError()
+
+        mock_target = mock.MagicMock()
+        mock_target.current_availability = 'Available'
+        mock_target.submit = mock.MagicMock(return_value=mock_job)
+
+        return mock_target
+
+    input_data = {
+        'qubits': 3,
+        'circuit': [{'gate': 'h', 'targets': [0]}, {'gate': 'h', 'targets': [1]}, {'gate': 'h', 'targets': [2]}],
+    }
+    metadata = {'num_qubits': 3, 'meas_map': [0, 1, 2]}
+
+    with pytest.raises(RequestTimeoutError):
+        _ = send(
+            input_data=input_data,
+            metadata=metadata,
+            num_shots=100,
+            target=get_mock_target(),
+            num_retries=1000,
+            interval=1,
+            verbose=verbose,
+        )
diff --git a/projectq/backends/_azure/_azure_quantum_test.py b/projectq/backends/_azure/_azure_quantum_test.py
new file mode 100644
index 000000000..3cdc51bb2
--- /dev/null
+++ b/projectq/backends/_azure/_azure_quantum_test.py
@@ -0,0 +1,862 @@
+#   Copyright 2022 ProjectQ-Framework (www.projectq.ch)
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+
+"""Tests for projectq.backends._azure._azure_quantum.py."""
+
+from unittest import mock
+
+import pytest
+
+from projectq.cengines import BasicMapperEngine, MainEngine
+from projectq.ops import CX, All, Command, H, Measure
+from projectq.types import WeakQubitRef
+
+_has_azure_quantum = True
+try:
+    from azure.quantum import Workspace
+
+    import projectq.backends._azure._azure_quantum
+    from projectq.backends import AzureQuantumBackend
+    from projectq.backends._azure._exceptions import AzureQuantumTargetNotFoundError
+except ImportError:
+    _has_azure_quantum = False
+
+has_azure_quantum = pytest.mark.skipif(not _has_azure_quantum, reason="azure quantum package is not installed")
+
+ZERO_GUID = '00000000-0000-0000-0000-000000000000'
+
+
+def mock_target(target_id, current_availability, average_queue_time):
+    target = mock.MagicMock()
+
+    estimate_cost = mock.Mock()
+    estimate_cost.estimated_total = 10
+
+    target.id = target_id
+    target.current_availability = current_availability
+    target.average_queue_time = average_queue_time
+    target.estimate_cost = mock.MagicMock(return_value=estimate_cost)
+
+    return target
+
+
+def mock_providers():
+    ionq_provider = mock.MagicMock()
+    ionq_provider.id = 'ionq'
+    ionq_provider.targets = [
+        mock_target(target_id='ionq.simulator', current_availability='Available', average_queue_time=1000),
+        mock_target(target_id='ionq.qpu', current_availability='Available', average_queue_time=2000),
+    ]
+
+    quantinuum_provider = mock.MagicMock()
+    quantinuum_provider.id = 'quantinuum'
+    quantinuum_provider.targets = [
+        mock_target(target_id='quantinuum.hqs-lt-s1-apival', current_availability='Available', average_queue_time=3000),
+        mock_target(target_id='quantinuum.hqs-lt-s1-sim', current_availability='Available', average_queue_time=4000),
+        mock_target(target_id='quantinuum.hqs-lt-s1', current_availability='Degraded', average_queue_time=5000),
+    ]
+
+    return [ionq_provider, quantinuum_provider]
+
+
+def mock_target_factory(target_name):
+    for provider in mock_providers():
+        for target in provider.targets:
+            if target.id == target_name:
+                return target
+
+    return []
+
+
+def _get_azure_backend(use_hardware, target_name, retrieve_execution=None):
+    AzureQuantumBackend._target_factory = mock.MagicMock(return_value=mock_target_factory(target_name))
+
+    workspace = Workspace(
+        subscription_id=ZERO_GUID, resource_group='testResourceGroup', name='testWorkspace', location='East US'
+    )
+
+    backend = AzureQuantumBackend(
+        use_hardware=use_hardware,
+        target_name=target_name,
+        workspace=workspace,
+        retrieve_execution=retrieve_execution,
+        verbose=True,
+    )
+
+    return backend
+
+
+def _get_main_engine(backend, max_qubits=3):
+    mapper = BasicMapperEngine()
+
+    mapping = {}
+    for i in range(max_qubits):
+        mapping[i] = i
+    mapper.current_mapping = mapping
+
+    main_engine = MainEngine(backend=backend, engine_list=[mapper], verbose=True)
+
+    return main_engine
+
+
+@has_azure_quantum
+@pytest.mark.parametrize(
+    "use_hardware, target_name, provider_id, expected_target_name",
+    [
+        (False, 'ionq.simulator', 'ionq', 'ionq.simulator'),
+        (True, 'ionq.qpu', 'ionq', 'ionq.qpu'),
+        (False, 'ionq.qpu', 'ionq', 'ionq.simulator'),
+    ],
+)
+def test_azure_quantum_ionq_target(use_hardware, target_name, provider_id, expected_target_name):
+    backend = _get_azure_backend(use_hardware=use_hardware, target_name=target_name)
+
+    assert backend._target_name == expected_target_name
+
+
+@has_azure_quantum
+@pytest.mark.parametrize(
+    "use_hardware, target_name, provider_id, expected_target_name",
+    [
+        (False, 'quantinuum.hqs-lt-s1-apival', 'quantinuum', 'quantinuum.hqs-lt-s1-apival'),
+        (False, 'quantinuum.hqs-lt-s1-sim', 'quantinuum', 'quantinuum.hqs-lt-s1-sim'),
+        (True, 'quantinuum.hqs-lt-s1', 'quantinuum', 'quantinuum.hqs-lt-s1'),
+        (False, 'quantinuum.hqs-lt-s1', 'quantinuum', 'quantinuum.hqs-lt-s1-apival'),
+        (False, 'quantinuum.hqs-lt-s1-sim', 'quantinuum', 'quantinuum.hqs-lt-s1-sim'),
+    ],
+)
+def test_azure_quantum_quantinuum_target(use_hardware, target_name, provider_id, expected_target_name):
+    backend = _get_azure_backend(use_hardware=use_hardware, target_name=target_name)
+
+    assert backend._target_name == expected_target_name
+
+
+@has_azure_quantum
+def test_initialize_azure_backend_using_kwargs():
+    backend = AzureQuantumBackend(
+        use_hardware=False,
+        target_name='ionq.simulator',
+        subscription_id=ZERO_GUID,
+        resource_group='testResourceGroup',
+        name='testWorkspace',
+        location='East US',
+    )
+
+    assert backend._target_name == 'ionq.simulator'
+
+
+@has_azure_quantum
+def test_azure_quantum_invalid_target():
+    with pytest.raises(AzureQuantumTargetNotFoundError):
+        _get_azure_backend(use_hardware=False, target_name='invalid-target')
+
+
+@has_azure_quantum
+def test_is_available_ionq():
+    with mock.patch('projectq.backends._azure._azure_quantum.is_available_ionq') as is_available_ionq_patch:
+        backend = _get_azure_backend(use_hardware=False, target_name='ionq.simulator')
+        main_engine = _get_main_engine(backend=backend)
+
+        q0 = main_engine.allocate_qubit()
+
+        cmd = Command(main_engine, H, (q0,))
+        main_engine.is_available(cmd)
+
+        is_available_ionq_patch.assert_called()
+
+
+@has_azure_quantum
+def test_is_available_quantinuum():
+    with mock.patch('projectq.backends._azure._azure_quantum.is_available_quantinuum') as is_available_quantinuum_patch:
+        backend = _get_azure_backend(use_hardware=False, target_name='quantinuum.hqs-lt-s1-sim')
+        main_engine = _get_main_engine(backend=backend)
+
+        q0 = main_engine.allocate_qubit()
+
+        cmd = Command(main_engine, H, (q0,))
+        main_engine.is_available(cmd)
+
+        is_available_quantinuum_patch.assert_called()
+
+
+@has_azure_quantum
+@pytest.mark.parametrize(
+    "use_hardware, target_name, provider_id, current_availability",
+    [
+        (False, 'ionq.simulator', 'ionq', 'Available'),
+        (True, 'ionq.qpu', 'ionq', 'Available'),
+        (False, 'quantinuum.hqs-lt-s1-apival', 'quantinuum', 'Available'),
+        (False, 'quantinuum.hqs-lt-s1-sim', 'quantinuum', 'Available'),
+        (True, 'quantinuum.hqs-lt-s1', 'quantinuum', 'Degraded'),
+    ],
+)
+def test_current_availability(use_hardware, target_name, provider_id, current_availability):
+    backend = _get_azure_backend(use_hardware=use_hardware, target_name=target_name)
+
+    assert backend.current_availability == current_availability
+
+
+@has_azure_quantum
+@pytest.mark.parametrize(
+    "use_hardware, target_name, provider_id, average_queue_time",
+    [
+        (False, 'ionq.simulator', 'ionq', 1000),
+        (True, 'ionq.qpu', 'ionq', 2000),
+        (False, 'quantinuum.hqs-lt-s1-apival', 'quantinuum', 3000),
+        (False, 'quantinuum.hqs-lt-s1-sim', 'quantinuum', 4000),
+        (True, 'quantinuum.hqs-lt-s1', 'quantinuum', 5000),
+    ],
+)
+def test_average_queue_time(use_hardware, target_name, provider_id, average_queue_time):
+    backend = _get_azure_backend(use_hardware=use_hardware, target_name=target_name)
+
+    assert backend.average_queue_time == average_queue_time
+
+
+@has_azure_quantum
+@pytest.mark.parametrize(
+    "use_hardware, target_name, provider_id",
+    [(False, 'ionq.simulator', 'ionq'), (True, 'ionq.qpu', 'ionq')],
+)
+def test_run_ionq_get_probabilities(use_hardware, target_name, provider_id):
+    projectq.backends._azure._azure_quantum.send = mock.MagicMock(
+        return_value={'histogram': {'0': 0.5, '1': 0.0, '2': 0.0, '3': 0.0, '4': 0.0, '5': 0.0, '6': 0.0, '7': 0.5}}
+    )
+
+    backend = _get_azure_backend(use_hardware=use_hardware, target_name=target_name)
+    main_engine = _get_main_engine(backend=backend)
+
+    circuit = main_engine.allocate_qureg(3)
+    q0, q1, q2 = circuit
+
+    H | q0
+    CX | (q0, q1)
+    CX | (q1, q2)
+    All(Measure) | circuit
+
+    main_engine.flush()
+
+    result = backend.get_probabilities(circuit)
+
+    assert len(result) == 8
+    assert result['000'] == pytest.approx(0.5)
+    assert result['001'] == 0.0
+    assert result['010'] == 0.0
+    assert result['011'] == 0.0
+    assert result['100'] == 0.0
+    assert result['101'] == 0.0
+    assert result['110'] == 0.0
+    assert result['111'] == pytest.approx(0.5)
+
+
+@has_azure_quantum
+@pytest.mark.parametrize(
+    "use_hardware, target_name, provider_id",
+    [
+        (False, 'quantinuum.hqs-lt-s1-apival', 'quantinuum'),
+        (False, 'quantinuum.hqs-lt-s1-sim', 'quantinuum'),
+        (True, 'quantinuum.hqs-lt-s1', 'quantinuum'),
+    ],
+)
+def test_run_quantinuum_get_probabilities(use_hardware, target_name, provider_id):
+    projectq.backends._azure._azure_quantum.send = mock.MagicMock(
+        return_value={
+            'c': [
+                '000',
+                '000',
+                '000',
+                '111',
+                '111',
+                '000',
+                '000',
+                '111',
+                '000',
+                '111',
+                '000',
+                '000',
+                '111',
+                '000',
+                '111',
+                '111',
+                '111',
+                '000',
+                '111',
+                '111',
+                '000',
+                '111',
+                '000',
+                '111',
+                '111',
+                '111',
+                '000',
+                '111',
+                '000',
+                '111',
+                '111',
+                '111',
+                '111',
+                '111',
+                '000',
+                '111',
+                '111',
+                '111',
+                '111',
+                '111',
+                '111',
+                '111',
+                '000',
+                '000',
+                '111',
+                '000',
+                '111',
+                '111',
+                '000',
+                '000',
+                '000',
+                '000',
+                '000',
+                '111',
+                '000',
+                '111',
+                '000',
+                '111',
+                '111',
+                '111',
+                '111',
+                '111',
+                '111',
+                '111',
+                '000',
+                '111',
+                '000',
+                '111',
+                '111',
+                '111',
+                '111',
+                '000',
+                '000',
+                '000',
+                '000',
+                '111',
+                '111',
+                '000',
+                '111',
+                '111',
+                '000',
+                '000',
+                '111',
+                '000',
+                '111',
+                '000',
+                '111',
+                '000',
+                '111',
+                '111',
+                '000',
+                '111',
+                '000',
+                '111',
+                '111',
+                '111',
+                '000',
+                '111',
+                '111',
+                '000',
+            ]
+        }
+    )
+
+    backend = _get_azure_backend(use_hardware=use_hardware, target_name=target_name)
+    main_engine = _get_main_engine(backend=backend)
+
+    circuit = main_engine.allocate_qureg(3)
+    q0, q1, q2 = circuit
+
+    H | q0
+    CX | (q0, q1)
+    CX | (q1, q2)
+    All(Measure) | circuit
+
+    main_engine.flush()
+
+    result = backend.get_probabilities(circuit)
+
+    assert len(result) == 2
+    assert result['000'] == pytest.approx(0.41)
+    assert result['111'] == pytest.approx(0.59)
+
+
+@has_azure_quantum
+def test_run_get_probabilities_unused_qubit():
+    projectq.backends._azure._azure_quantum.send = mock.MagicMock(
+        return_value={'histogram': {'0': 0.5, '1': 0.0, '2': 0.0, '3': 0.0, '4': 0.0, '5': 0.0, '6': 0.0, '7': 0.5}}
+    )
+
+    backend = _get_azure_backend(use_hardware=False, target_name='ionq.simulator')
+    main_engine = _get_main_engine(backend=backend, max_qubits=4)
+
+    circuit = main_engine.allocate_qureg(3)
+    unused_qubit = main_engine.allocate_qubit()
+    q0, q1, q2 = circuit
+
+    H | q0
+    CX | (q0, q1)
+    CX | (q1, q2)
+    All(Measure) | circuit
+
+    main_engine.flush()
+
+    result = backend.get_probabilities(unused_qubit)
+
+    assert len(result) == 1
+    assert result['0'] == pytest.approx(1)
+
+
+@has_azure_quantum
+@pytest.mark.parametrize(
+    "use_hardware, target_name, provider_id",
+    [(False, 'ionq.simulator', 'ionq'), (True, 'ionq.qpu', 'ionq')],
+)
+def test_run_ionq_get_probability(use_hardware, target_name, provider_id):
+    projectq.backends._azure._azure_quantum.send = mock.MagicMock(
+        return_value={'histogram': {'0': 0.5, '1': 0.0, '2': 0.0, '3': 0.0, '4': 0.0, '5': 0.0, '6': 0.0, '7': 0.5}}
+    )
+
+    backend = _get_azure_backend(use_hardware=use_hardware, target_name=target_name)
+    main_engine = _get_main_engine(backend=backend)
+
+    circuit = main_engine.allocate_qureg(3)
+    q0, q1, q2 = circuit
+
+    H | q0
+    CX | (q0, q1)
+    CX | (q1, q2)
+    All(Measure) | circuit
+
+    main_engine.flush()
+
+    assert backend.get_probability('000', circuit) == pytest.approx(0.5)
+    assert backend.get_probability('001', circuit) == 0.0
+    assert backend.get_probability('010', circuit) == 0.0
+    assert backend.get_probability('011', circuit) == 0.0
+    assert backend.get_probability('100', circuit) == 0.0
+    assert backend.get_probability('101', circuit) == 0.0
+    assert backend.get_probability('110', circuit) == 0.0
+    assert backend.get_probability('111', circuit) == pytest.approx(0.5)
+
+
+@has_azure_quantum
+@pytest.mark.parametrize(
+    "use_hardware, target_name, provider_id",
+    [
+        (False, 'quantinuum.hqs-lt-s1-apival', 'quantinuum'),
+        (False, 'quantinuum.hqs-lt-s1-sim', 'quantinuum'),
+        (True, 'quantinuum.hqs-lt-s1', 'quantinuum'),
+    ],
+)
+def test_run_quantinuum_get_probability(use_hardware, target_name, provider_id):
+    projectq.backends._azure._azure_quantum.send = mock.MagicMock(
+        return_value={
+            'c': [
+                '000',
+                '000',
+                '000',
+                '111',
+                '111',
+                '000',
+                '000',
+                '111',
+                '000',
+                '111',
+                '000',
+                '000',
+                '111',
+                '000',
+                '111',
+                '111',
+                '111',
+                '000',
+                '111',
+                '111',
+                '000',
+                '111',
+                '000',
+                '111',
+                '111',
+                '111',
+                '000',
+                '111',
+                '000',
+                '111',
+                '111',
+                '111',
+                '111',
+                '111',
+                '000',
+                '111',
+                '111',
+                '111',
+                '111',
+                '111',
+                '111',
+                '111',
+                '000',
+                '000',
+                '111',
+                '000',
+                '111',
+                '111',
+                '000',
+                '000',
+                '000',
+                '000',
+                '000',
+                '111',
+                '000',
+                '111',
+                '000',
+                '111',
+                '111',
+                '111',
+                '111',
+                '111',
+                '111',
+                '111',
+                '000',
+                '111',
+                '000',
+                '111',
+                '111',
+                '111',
+                '111',
+                '000',
+                '000',
+                '000',
+                '000',
+                '111',
+                '111',
+                '000',
+                '111',
+                '111',
+                '000',
+                '000',
+                '111',
+                '000',
+                '111',
+                '000',
+                '111',
+                '000',
+                '111',
+                '111',
+                '000',
+                '111',
+                '000',
+                '111',
+                '111',
+                '111',
+                '000',
+                '111',
+                '111',
+                '000',
+            ]
+        }
+    )
+
+    backend = _get_azure_backend(use_hardware=use_hardware, target_name=target_name)
+    main_engine = _get_main_engine(backend=backend)
+
+    circuit = main_engine.allocate_qureg(3)
+    q0, q1, q2 = circuit
+
+    H | q0
+    CX | (q0, q1)
+    CX | (q1, q2)
+    All(Measure) | circuit
+
+    main_engine.flush()
+
+    assert backend.get_probability('000', circuit) == pytest.approx(0.41)
+    assert backend.get_probability('001', circuit) == 0.0
+    assert backend.get_probability('010', circuit) == 0.0
+    assert backend.get_probability('011', circuit) == 0.0
+    assert backend.get_probability('100', circuit) == 0.0
+    assert backend.get_probability('101', circuit) == 0.0
+    assert backend.get_probability('110', circuit) == 0.0
+    assert backend.get_probability('111', circuit) == pytest.approx(0.59)
+
+
+@has_azure_quantum
+def test_estimate_cost():
+    projectq.backends._azure._azure_quantum.send = mock.MagicMock(
+        return_value={'histogram': {'0': 0.5, '1': 0.0, '2': 0.0, '3': 0.0, '4': 0.0, '5': 0.0, '6': 0.0, '7': 0.5}}
+    )
+
+    backend = _get_azure_backend(use_hardware=False, target_name='ionq.simulator')
+    main_engine = _get_main_engine(backend=backend)
+
+    circuit = main_engine.allocate_qureg(3)
+    q0, q1, q2 = circuit
+
+    H | q0
+    CX | (q0, q1)
+    CX | (q1, q2)
+    All(Measure) | circuit
+
+    estimate_cost = backend.estimate_cost()
+
+    assert estimate_cost.estimated_total == 10
+
+
+@has_azure_quantum
+def test_run_get_probability_invalid_state():
+    projectq.backends._azure._azure_quantum.send = mock.MagicMock(
+        return_value={'histogram': {'0': 0.5, '1': 0.0, '2': 0.0, '3': 0.0, '4': 0.0, '5': 0.0, '6': 0.0, '7': 0.5}}
+    )
+
+    backend = _get_azure_backend(use_hardware=False, target_name='ionq.simulator')
+    main_engine = _get_main_engine(backend=backend)
+
+    circuit = main_engine.allocate_qureg(3)
+    q0, q1, q2 = circuit
+
+    H | q0
+    CX | (q0, q1)
+    CX | (q1, q2)
+    All(Measure) | circuit
+
+    main_engine.flush()
+
+    with pytest.raises(ValueError):
+        _ = backend.get_probability('0000', circuit)
+
+
+@has_azure_quantum
+def test_run_no_circuit():
+    backend = _get_azure_backend(use_hardware=False, target_name='ionq.simulator')
+    main_engine = _get_main_engine(backend=backend)
+
+    circuit = main_engine.allocate_qureg(3)
+
+    main_engine.flush()
+
+    with pytest.raises(RuntimeError):
+        _ = backend.get_probabilities(circuit)
+
+
+@has_azure_quantum
+@pytest.mark.parametrize(
+    "use_hardware, target_name, provider_id",
+    [(False, 'ionq.simulator', 'ionq'), (True, 'ionq.qpu', 'ionq')],
+)
+@pytest.mark.parametrize(
+    'retrieve_retval',
+    (None, {'histogram': {'0': 0.5, '1': 0.0, '2': 0.0, '3': 0.0, '4': 0.0, '5': 0.0, '6': 0.0, '7': 0.5}}),
+    ids=('retrieve-FAIL', 'retrieve-SUCESS'),
+)
+def test_run_ionq_retrieve_execution(use_hardware, target_name, provider_id, retrieve_retval):
+    projectq.backends._azure._azure_quantum.retrieve = mock.MagicMock(return_value=retrieve_retval)
+
+    backend = _get_azure_backend(use_hardware=use_hardware, target_name=target_name, retrieve_execution=ZERO_GUID)
+    main_engine = _get_main_engine(backend=backend)
+
+    circuit = main_engine.allocate_qureg(3)
+    q0, q1, q2 = circuit
+
+    H | q0
+    CX | (q0, q1)
+    CX | (q1, q2)
+    All(Measure) | circuit
+
+    if retrieve_retval is None:
+        with pytest.raises(RuntimeError):
+            main_engine.flush()
+    else:
+        main_engine.flush()
+        result = backend.get_probabilities(circuit)
+
+        assert len(result) == 8
+        assert result['000'] == pytest.approx(0.5)
+        assert result['001'] == 0.0
+        assert result['010'] == 0.0
+        assert result['011'] == 0.0
+        assert result['100'] == 0.0
+        assert result['101'] == 0.0
+        assert result['110'] == 0.0
+        assert result['111'] == pytest.approx(0.5)
+
+
+@has_azure_quantum
+@pytest.mark.parametrize(
+    "use_hardware, target_name, provider_id",
+    [
+        (False, 'quantinuum.hqs-lt-s1-apival', 'quantinuum'),
+        (False, 'quantinuum.hqs-lt-s1-sim', 'quantinuum'),
+        (True, 'quantinuum.hqs-lt-s1', 'quantinuum'),
+    ],
+)
+def test_run_quantinuum_retrieve_execution(use_hardware, target_name, provider_id):
+    projectq.backends._azure._azure_quantum.retrieve = mock.MagicMock(
+        return_value={
+            'c': [
+                '000',
+                '000',
+                '000',
+                '111',
+                '111',
+                '000',
+                '000',
+                '111',
+                '000',
+                '111',
+                '000',
+                '000',
+                '111',
+                '000',
+                '111',
+                '111',
+                '111',
+                '000',
+                '111',
+                '111',
+                '000',
+                '111',
+                '000',
+                '111',
+                '111',
+                '111',
+                '000',
+                '111',
+                '000',
+                '111',
+                '111',
+                '111',
+                '111',
+                '111',
+                '000',
+                '111',
+                '111',
+                '111',
+                '111',
+                '111',
+                '111',
+                '111',
+                '000',
+                '000',
+                '111',
+                '000',
+                '111',
+                '111',
+                '000',
+                '000',
+                '000',
+                '000',
+                '000',
+                '111',
+                '000',
+                '111',
+                '000',
+                '111',
+                '111',
+                '111',
+                '111',
+                '111',
+                '111',
+                '111',
+                '000',
+                '111',
+                '000',
+                '111',
+                '111',
+                '111',
+                '111',
+                '000',
+                '000',
+                '000',
+                '000',
+                '111',
+                '111',
+                '000',
+                '111',
+                '111',
+                '000',
+                '000',
+                '111',
+                '000',
+                '111',
+                '000',
+                '111',
+                '000',
+                '111',
+                '111',
+                '000',
+                '111',
+                '000',
+                '111',
+                '111',
+                '111',
+                '000',
+                '111',
+                '111',
+                '000',
+            ]
+        }
+    )
+
+    backend = _get_azure_backend(use_hardware=use_hardware, target_name=target_name, retrieve_execution=ZERO_GUID)
+    main_engine = _get_main_engine(backend=backend)
+
+    circuit = main_engine.allocate_qureg(3)
+    q0, q1, q2 = circuit
+
+    H | q0
+    CX | (q0, q1)
+    CX | (q1, q2)
+    All(Measure) | circuit
+
+    main_engine.flush()
+
+    result = backend.get_probabilities(circuit)
+
+    assert len(result) == 2
+    assert result['000'] == pytest.approx(0.41)
+    assert result['111'] == pytest.approx(0.59)
+
+
+@has_azure_quantum
+def test_error_no_logical_id_tag():
+    backend = _get_azure_backend(use_hardware=False, target_name='ionq.simulator')
+    main_engine = _get_main_engine(backend=backend)
+
+    q0 = WeakQubitRef(engine=None, idx=0)
+
+    with pytest.raises(RuntimeError):
+        main_engine.backend._store(Command(engine=main_engine, gate=Measure, qubits=([q0],)))
+
+
+@has_azure_quantum
+def test_error_invalid_provider():
+    backend = _get_azure_backend(use_hardware=False, target_name='ionq.simulator')
+    backend._provider_id = 'INVALID'  # NB: this is forcing it... should actually never happen in practice
+    main_engine = _get_main_engine(backend=backend)
+
+    q0 = WeakQubitRef(engine=None, idx=0)
+
+    cmd = Command(engine=main_engine, gate=H, qubits=([q0],))
+    with pytest.raises(RuntimeError):
+        main_engine.backend._store(cmd)
+
+    with pytest.raises(RuntimeError):
+        main_engine.backend._input_data
+
+    assert not main_engine.backend.is_available(cmd)
diff --git a/projectq/backends/_azure/_exceptions.py b/projectq/backends/_azure/_exceptions.py
new file mode 100644
index 000000000..20f8e65c5
--- /dev/null
+++ b/projectq/backends/_azure/_exceptions.py
@@ -0,0 +1,19 @@
+#   Copyright 2022 ProjectQ-Framework (www.projectq.ch)
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+
+"""Exception classes for projectq.backends._azure."""
+
+
+class AzureQuantumTargetNotFoundError(Exception):
+    """Raised when a Azure Quantum target doesn't exist with given target name."""
diff --git a/projectq/backends/_azure/_utils.py b/projectq/backends/_azure/_utils.py
new file mode 100644
index 000000000..0031f8438
--- /dev/null
+++ b/projectq/backends/_azure/_utils.py
@@ -0,0 +1,307 @@
+#   Copyright 2022 ProjectQ-Framework (www.projectq.ch)
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+
+"""Utility functions for Azure Quantum."""
+
+from projectq.meta import get_control_count, has_negative_control
+from projectq.ops import (
+    AllocateQubitGate,
+    BarrierGate,
+    ControlledGate,
+    DaggeredGate,
+    DeallocateQubitGate,
+    HGate,
+    MeasureGate,
+    R,
+    Rx,
+    Rxx,
+    Ry,
+    Ryy,
+    Rz,
+    Rzz,
+    Sdag,
+    SGate,
+    SqrtXGate,
+    SwapGate,
+    Tdag,
+    TGate,
+    XGate,
+    YGate,
+    ZGate,
+    get_inverse,
+)
+
+from .._exceptions import InvalidCommandError
+
+IONQ_PROVIDER_ID = 'ionq'
+QUANTINUUM_PROVIDER_ID = 'quantinuum'
+
+# https://docs.ionq.com/#section/Supported-Gates
+IONQ_GATE_MAP = {
+    HGate: 'h',
+    SGate: 's',
+    SqrtXGate: 'v',
+    SwapGate: 'swap',
+    TGate: 't',
+    Rx: 'rx',
+    Rxx: 'xx',
+    Ry: 'ry',
+    Ryy: 'yy',
+    Rz: 'rz',
+    Rzz: 'zz',
+    XGate: 'x',
+    YGate: 'y',
+    ZGate: 'z',
+}  # excluding controlled, conjugate-transpose and meta gates
+
+IONQ_SUPPORTED_GATES = tuple(IONQ_GATE_MAP.keys())
+
+QUANTINUUM_GATE_MAP = {
+    BarrierGate: 'barrier',
+    HGate: 'h',
+    Rx: 'rx',
+    Rxx: 'rxx',
+    Ry: 'ry',
+    Ryy: 'ryy',
+    Rz: 'rz',
+    Rzz: 'rzz',
+    SGate: 's',
+    TGate: 't',
+    XGate: 'x',
+    YGate: 'y',
+    ZGate: 'z',
+}  # excluding controlled, conjugate-transpose and meta gates
+
+QUANTINUUM_SUPPORTED_GATES = tuple(QUANTINUUM_GATE_MAP.keys())
+
+V = SqrtXGate()
+Vdag = get_inverse(V)
+
+
+def is_available_ionq(cmd):
+    """
+    Test if IonQ backend is available to process the provided command.
+
+    Args:
+        cmd (Command): A command to process.
+
+    Returns:
+        bool: If this backend can process the command.
+    """
+    gate = cmd.gate
+
+    if has_negative_control(cmd):
+        return False
+
+    if isinstance(gate, ControlledGate):
+        num_ctrl_qubits = gate._n  # pylint: disable=protected-access
+    else:
+        num_ctrl_qubits = get_control_count(cmd)
+
+    # Get base gate wrapped in ControlledGate class
+    if isinstance(gate, ControlledGate):
+        gate = gate._gate  # pylint: disable=protected-access
+
+    # NOTE: IonQ supports up to 7 control qubits
+    if 0 < num_ctrl_qubits <= 7:
+        return isinstance(gate, (XGate,))
+
+    # Gates without control bits
+    if num_ctrl_qubits == 0:
+        supported = isinstance(gate, IONQ_SUPPORTED_GATES)
+        supported_meta = isinstance(gate, (MeasureGate, AllocateQubitGate, DeallocateQubitGate))
+        supported_transpose = gate in (Sdag, Tdag, Vdag)
+
+        return supported or supported_meta or supported_transpose
+
+    return False
+
+
+def is_available_quantinuum(cmd):
+    """
+    Test if Quantinuum backend is available to process the provided command.
+
+    Args:
+        cmd (Command): A command to process.
+
+    Returns:
+        bool: If this backend can process the command.
+    """
+    gate = cmd.gate
+
+    if has_negative_control(cmd):
+        return False
+
+    if isinstance(gate, ControlledGate):
+        num_ctrl_qubits = gate._n  # pylint: disable=protected-access
+    else:
+        num_ctrl_qubits = get_control_count(cmd)
+
+    # Get base gate wrapped in ControlledGate class
+    if isinstance(gate, ControlledGate):
+        gate = gate._gate  # pylint: disable=protected-access
+
+    # TODO: NEEDED CONFIRMATION- Does Quantinuum support more than 2 control gates?
+    if 0 < num_ctrl_qubits <= 2:
+        return isinstance(gate, (XGate, ZGate))
+
+    # Gates without control bits.
+    if num_ctrl_qubits == 0:
+        supported = isinstance(gate, QUANTINUUM_SUPPORTED_GATES)
+        supported_meta = isinstance(gate, (MeasureGate, AllocateQubitGate, DeallocateQubitGate, BarrierGate))
+        supported_transpose = gate in (Sdag, Tdag)
+        return supported or supported_meta or supported_transpose
+
+    return False
+
+
+def to_json(cmd):
+    """
+    Convert ProjectQ command to JSON format.
+
+    Args:
+        cmd (Command): A command to process.
+
+    Returns:
+        dict: JSON format of given command.
+    """
+    # Invalid command, raise exception
+    if not is_available_ionq(cmd):
+        raise InvalidCommandError('Invalid command:', str(cmd))
+
+    gate = cmd.gate
+
+    if isinstance(gate, ControlledGate):
+        inner_gate = gate._gate  # pylint: disable=protected-access
+        gate_type = type(inner_gate)
+    elif isinstance(gate, DaggeredGate):
+        gate_type = type(gate.get_inverse())
+    else:
+        gate_type = type(gate)
+
+    gate_name = IONQ_GATE_MAP.get(gate_type)
+
+    # Daggered gates get special treatment
+    if isinstance(gate, DaggeredGate):
+        gate_name = gate_name + 'i'
+
+    # Controlled gates get special treatment too
+    if isinstance(gate, ControlledGate):
+        all_qubits = [qb.id for qureg in cmd.qubits for qb in qureg]
+        controls = all_qubits[: gate._n]  # pylint: disable=protected-access
+        targets = all_qubits[gate._n :]  # noqa: E203  # pylint: disable=protected-access
+    else:
+        controls = [qb.id for qb in cmd.control_qubits]
+        targets = [qb.id for qureg in cmd.qubits for qb in qureg]
+
+    # Initialize the gate dict
+    gate_dict = {'gate': gate_name, 'targets': targets}
+
+    # Check if we have a rotation
+    if isinstance(gate, (R, Rx, Ry, Rz, Rxx, Ryy, Rzz)):
+        gate_dict['rotation'] = gate.angle
+
+    # Set controls
+    if len(controls) > 0:
+        gate_dict['controls'] = controls
+
+    return gate_dict
+
+
+def to_qasm(cmd):  # pylint: disable=too-many-return-statements,too-many-branches
+    """
+    Convert ProjectQ command to QASM format.
+
+    Args:
+        cmd (Command): A command to process.
+
+    Returns:
+        dict: QASM format of given command.
+    """
+    # Invalid command, raise exception
+    if not is_available_quantinuum(cmd):
+        raise InvalidCommandError('Invalid command:', str(cmd))
+
+    gate = cmd.gate
+
+    if isinstance(gate, ControlledGate):
+        inner_gate = gate._gate  # pylint: disable=protected-access
+        gate_type = type(inner_gate)
+    elif isinstance(gate, DaggeredGate):
+        gate_type = type(gate.get_inverse())
+    else:
+        gate_type = type(gate)
+
+    gate_name = QUANTINUUM_GATE_MAP.get(gate_type)
+
+    # Daggered gates get special treatment
+    if isinstance(gate, DaggeredGate):
+        gate_name = gate_name + 'dg'
+
+    # Controlled gates get special treatment too
+    if isinstance(gate, ControlledGate):
+        all_qubits = [qb.id for qureg in cmd.qubits for qb in qureg]
+        controls = all_qubits[: gate._n]  # pylint: disable=protected-access
+        targets = all_qubits[gate._n :]  # noqa: E203  # pylint: disable=protected-access
+    else:
+        controls = [qb.id for qb in cmd.control_qubits]
+        targets = [qb.id for qureg in cmd.qubits for qb in qureg]
+
+    # Barrier gate
+    if isinstance(gate, BarrierGate):
+        qb_str = ""
+        for pos in targets:
+            qb_str += f"q[{pos}], "
+        return f"{gate_name} {qb_str[:-2]};"
+
+    # Daggered gates
+    if gate in (Sdag, Tdag):
+        return f"{gate_name} q[{targets[0]}];"
+
+    # Controlled gates
+    if len(controls) > 0:
+        # 1-Controlled gates
+        if len(controls) == 1:
+            gate_name = 'c' + gate_name
+            return f"{gate_name} q[{controls[0]}], q[{targets[0]}];"
+
+        # 2-Controlled gates
+        if len(controls) == 2:
+            gate_name = 'cc' + gate_name
+            return f"{gate_name} q[{controls[0]}], q[{controls[1]}], q[{targets[0]}];"
+
+        raise InvalidCommandError('Invalid command:', str(cmd))  # pragma: no cover
+
+    # Single qubit gates
+    if len(targets) == 1:
+        # Standard gates
+        if isinstance(gate, (HGate, XGate, YGate, ZGate, SGate, TGate)):
+            return f"{gate_name} q[{targets[0]}];"
+
+        # Rotational gates
+        if isinstance(gate, (Rx, Ry, Rz)):
+            return f"{gate_name}({gate.angle}) q[{targets[0]}];"
+
+        raise InvalidCommandError('Invalid command:', str(cmd))  # pragma: no cover
+
+    # Two qubit gates
+    if len(targets) == 2:
+        # Rotational gates
+        if isinstance(gate, (Rxx, Ryy, Rzz)):
+            return f"{gate_name}({gate.angle}) q[{targets[0]}], q[{targets[1]}];"
+
+        raise InvalidCommandError('Invalid command:', str(cmd))
+
+    # Invalid command
+    raise InvalidCommandError('Invalid command:', str(cmd))  # pragma: no cover
diff --git a/projectq/backends/_azure/_utils_test.py b/projectq/backends/_azure/_utils_test.py
new file mode 100644
index 000000000..8fdf70b48
--- /dev/null
+++ b/projectq/backends/_azure/_utils_test.py
@@ -0,0 +1,642 @@
+#   Copyright 2022 ProjectQ-Framework (www.projectq.ch)
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+
+"""Tests for projectq.backends._azure._utils.py."""
+
+import math
+
+import pytest
+
+from projectq.cengines import DummyEngine, MainEngine
+from projectq.ops import (
+    CNOT,
+    CX,
+    NOT,
+    Allocate,
+    Barrier,
+    C,
+    Command,
+    Deallocate,
+    H,
+    Measure,
+    Rx,
+    Rxx,
+    Ry,
+    Ryy,
+    Rz,
+    Rzz,
+    S,
+    Sdag,
+    Sdagger,
+    SqrtX,
+    SqrtXGate,
+    Swap,
+    T,
+    Tdag,
+    Tdagger,
+    X,
+    Y,
+    Z,
+    get_inverse,
+)
+from projectq.types import WeakQubitRef
+
+from .._exceptions import InvalidCommandError
+
+_has_azure_quantum = True
+try:
+    import azure.quantum  # noqa: F401
+
+    from projectq.backends._azure._utils import (
+        is_available_ionq,
+        is_available_quantinuum,
+        to_json,
+        to_qasm,
+    )
+except ImportError:
+    _has_azure_quantum = False
+
+has_azure_quantum = pytest.mark.skipif(not _has_azure_quantum, reason="azure quantum package is not installed")
+
+V = SqrtXGate()
+Vdag = get_inverse(V)
+
+
+@has_azure_quantum
+@pytest.mark.parametrize(
+    "single_qubit_gate, expected_result",
+    [
+        (NOT, True),
+        (X, True),
+        (Y, True),
+        (Z, True),
+        (H, True),
+        (S, True),
+        (T, True),
+        (SqrtX, True),
+        (Rx(math.pi / 2), True),
+        (Ry(math.pi / 2), True),
+        (Rz(math.pi / 2), True),
+        (Sdag, True),
+        (Sdagger, True),
+        (Tdag, True),
+        (Tdagger, True),
+        (Vdag, True),
+        (Measure, True),
+        (Allocate, True),
+        (Deallocate, True),
+        (Barrier, False),
+    ],
+)
+def test_ionq_is_available_single_qubit_gates(single_qubit_gate, expected_result):
+    eng = MainEngine(backend=DummyEngine(), engine_list=[DummyEngine()])
+    qb0 = eng.allocate_qubit()
+
+    cmd = Command(eng, single_qubit_gate, (qb0,))
+    assert is_available_ionq(cmd) == expected_result, f'Failing on {single_qubit_gate} gate'
+
+
+@has_azure_quantum
+@pytest.mark.parametrize(
+    "two_qubit_gate, expected_result",
+    [
+        (Swap, True),
+        (CNOT, True),
+        (CX, True),
+        (Rxx(math.pi / 2), True),
+        (Ryy(math.pi / 2), True),
+        (Rzz(math.pi / 2), True),
+    ],
+)
+def test_ionq_is_available_two_qubit_gates(two_qubit_gate, expected_result):
+    eng = MainEngine(backend=DummyEngine(), engine_list=[DummyEngine()])
+    qb0 = eng.allocate_qubit()
+    qb1 = eng.allocate_qubit()
+
+    cmd = Command(eng, two_qubit_gate, (qb0, qb1))
+    assert is_available_ionq(cmd) == expected_result, f'Failing on {two_qubit_gate} gate'
+
+
+@has_azure_quantum
+@pytest.mark.parametrize(
+    "base_gate, num_ctrl_qubits, expected_result",
+    [
+        (X, 0, True),
+        (X, 1, True),
+        (X, 2, True),
+        (X, 3, True),
+        (X, 4, True),
+        (X, 5, True),
+        (X, 6, True),
+        (X, 7, True),
+        (X, 8, False),
+        (Y, 1, False),
+    ],
+)
+def test_ionq_is_available_n_controlled_qubits_type_1(base_gate, num_ctrl_qubits, expected_result):
+    eng = MainEngine(backend=DummyEngine(), engine_list=[DummyEngine()])
+    qb0 = eng.allocate_qubit()
+    qureg = eng.allocate_qureg(num_ctrl_qubits)
+
+    # pass controls as parameter
+    cmd = Command(eng, base_gate, (qb0,), controls=qureg)
+    assert is_available_ionq(cmd) == expected_result, 'Failing on {}-controlled {} gate'.format(
+        num_ctrl_qubits, base_gate
+    )
+
+
+@has_azure_quantum
+@pytest.mark.parametrize(
+    "base_gate, num_ctrl_qubits, expected_result",
+    [
+        (X, 0, True),
+        (X, 1, True),
+        (X, 2, True),
+        (X, 3, True),
+        (X, 4, True),
+        (X, 5, True),
+        (X, 6, True),
+        (X, 7, True),
+        (X, 8, False),
+        (Y, 1, False),
+    ],
+)
+def test_ionq_is_available_n_controlled_qubits_type_2(base_gate, num_ctrl_qubits, expected_result):
+    eng = MainEngine(backend=DummyEngine(), engine_list=[DummyEngine()])
+    qb0 = eng.allocate_qubit()
+    qureg = eng.allocate_qureg(num_ctrl_qubits)
+
+    n_controlled_gate = base_gate
+    for index in range(num_ctrl_qubits):
+        n_controlled_gate = C(n_controlled_gate)
+
+    # pass controls as targets
+    cmd = Command(
+        eng,
+        n_controlled_gate,
+        (
+            qureg,
+            qb0,
+        ),
+    )
+    assert is_available_ionq(cmd) == expected_result, 'Failing on {}-controlled {} gate'.format(
+        num_ctrl_qubits, base_gate
+    )
+
+
+@has_azure_quantum
+def test_ionq_is_available_negative_control():
+    eng = MainEngine(backend=DummyEngine(), engine_list=[DummyEngine()])
+    qb0 = eng.allocate_qubit()
+    qureg = eng.allocate_qureg(1)
+
+    cmd = Command(eng, X, qubits=(qb0,), controls=qureg)
+    assert is_available_ionq(cmd), "Failing on negative controlled gate"
+
+    cmd = Command(eng, X, qubits=(qb0,), controls=qureg, control_state='1')
+    assert is_available_ionq(cmd), "Failing on negative controlled gate"
+
+    cmd = Command(eng, X, qubits=(qb0,), controls=qureg, control_state='0')
+    assert not is_available_ionq(cmd), "Failing on negative controlled gate"
+
+
+@has_azure_quantum
+@pytest.mark.parametrize(
+    "single_qubit_gate, expected_result",
+    [
+        (NOT, True),
+        (X, True),
+        (Y, True),
+        (Z, True),
+        (H, True),
+        (S, True),
+        (T, True),
+        (Rx(math.pi / 2), True),
+        (Ry(math.pi / 2), True),
+        (Rz(math.pi / 2), True),
+        (Sdag, True),
+        (Sdagger, True),
+        (Tdag, True),
+        (Tdagger, True),
+        (Measure, True),
+        (Allocate, True),
+        (Deallocate, True),
+        (Barrier, True),
+        (SqrtX, False),
+        (Vdag, False),
+    ],
+)
+def test_quantinuum_is_available_single_qubit_gates(single_qubit_gate, expected_result):
+    eng = MainEngine(backend=DummyEngine(), engine_list=[DummyEngine()])
+    qb0 = eng.allocate_qubit()
+
+    cmd = Command(eng, single_qubit_gate, (qb0,))
+    assert is_available_quantinuum(cmd) == expected_result, f'Failing on {single_qubit_gate} gate'
+
+
+@has_azure_quantum
+@pytest.mark.parametrize(
+    "two_qubit_gate, expected_result",
+    [
+        (CNOT, True),
+        (CX, True),
+        (Rxx(math.pi / 2), True),
+        (Ryy(math.pi / 2), True),
+        (Rzz(math.pi / 2), True),
+        (Swap, False),
+    ],
+)
+def test_quantinuum_is_available_two_qubit_gates(two_qubit_gate, expected_result):
+    eng = MainEngine(backend=DummyEngine(), engine_list=[DummyEngine()])
+    qb0 = eng.allocate_qubit()
+    qb1 = eng.allocate_qubit()
+
+    cmd = Command(eng, two_qubit_gate, (qb0, qb1))
+    assert is_available_quantinuum(cmd) == expected_result, f'Failing on {two_qubit_gate} gate'
+
+
+@has_azure_quantum
+@pytest.mark.parametrize(
+    "base_gate, num_ctrl_qubits, expected_result",
+    [
+        (X, 0, True),
+        (X, 1, True),
+        (X, 2, True),
+        (X, 3, False),
+        (Z, 0, True),
+        (Z, 1, True),
+        (Z, 2, True),
+        (Z, 3, False),
+        (Y, 1, False),
+    ],
+)
+def test_quantinuum_is_available_n_controlled_qubits_type_1(base_gate, num_ctrl_qubits, expected_result):
+    eng = MainEngine(backend=DummyEngine(), engine_list=[DummyEngine()])
+    qb0 = eng.allocate_qubit()
+    qureg = eng.allocate_qureg(num_ctrl_qubits)
+
+    cmd = Command(eng, base_gate, (qb0,), controls=qureg)
+    assert is_available_quantinuum(cmd) == expected_result, 'Failing on {}-controlled {} gate'.format(
+        num_ctrl_qubits, base_gate
+    )
+
+
+@has_azure_quantum
+@pytest.mark.parametrize(
+    "base_gate, num_ctrl_qubits, expected_result",
+    [
+        (X, 0, True),
+        (X, 1, True),
+        (X, 2, True),
+        (X, 3, False),
+        (Z, 0, True),
+        (Z, 1, True),
+        (Z, 2, True),
+        (Z, 3, False),
+        (Y, 1, False),
+    ],
+)
+def test_quantinuum_is_available_n_controlled_qubits_type_2(base_gate, num_ctrl_qubits, expected_result):
+    eng = MainEngine(backend=DummyEngine(), engine_list=[DummyEngine()])
+    qb0 = eng.allocate_qubit()
+    qureg = eng.allocate_qureg(num_ctrl_qubits)
+
+    n_controlled_gate = base_gate
+    for index in range(num_ctrl_qubits):
+        n_controlled_gate = C(n_controlled_gate)
+
+    # pass controls as targets
+    cmd = Command(
+        eng,
+        n_controlled_gate,
+        (
+            qureg,
+            qb0,
+        ),
+    )
+    assert is_available_quantinuum(cmd) == expected_result, 'Failing on {}-controlled {} gate'.format(
+        num_ctrl_qubits, base_gate
+    )
+
+
+@has_azure_quantum
+def test_quantinuum_is_available_negative_control():
+    eng = MainEngine(backend=DummyEngine(), engine_list=[DummyEngine()])
+    qb0 = eng.allocate_qubit()
+    qureg = eng.allocate_qureg(1)
+
+    cmd = Command(eng, X, qubits=(qb0,), controls=qureg)
+    assert is_available_quantinuum(cmd), "Failing on negative controlled gate"
+
+    cmd = Command(eng, X, qubits=(qb0,), controls=qureg, control_state='1')
+    assert is_available_quantinuum(cmd), "Failing on negative controlled gate"
+
+    cmd = Command(eng, X, qubits=(qb0,), controls=qureg, control_state='0')
+    assert not is_available_quantinuum(cmd), "Failing on negative controlled gate"
+
+
+@has_azure_quantum
+@pytest.mark.parametrize(
+    "single_qubit_gate, expected_result",
+    [
+        (NOT, {'gate': 'x', 'targets': [0]}),
+        (X, {'gate': 'x', 'targets': [0]}),
+        (Y, {'gate': 'y', 'targets': [0]}),
+        (Z, {'gate': 'z', 'targets': [0]}),
+        (H, {'gate': 'h', 'targets': [0]}),
+        (S, {'gate': 's', 'targets': [0]}),
+        (T, {'gate': 't', 'targets': [0]}),
+        (Rx(0), {'gate': 'rx', 'rotation': 0.0, 'targets': [0]}),
+        (Ry(0), {'gate': 'ry', 'rotation': 0.0, 'targets': [0]}),
+        (Rz(0), {'gate': 'rz', 'rotation': 0.0, 'targets': [0]}),
+        (Rx(math.pi / 4), {'gate': 'rx', 'rotation': 0.785398163397, 'targets': [0]}),
+        (Ry(math.pi / 4), {'gate': 'ry', 'rotation': 0.785398163397, 'targets': [0]}),
+        (Rz(math.pi / 4), {'gate': 'rz', 'rotation': 0.785398163397, 'targets': [0]}),
+        (Rx(math.pi / 2), {'gate': 'rx', 'rotation': 1.570796326795, 'targets': [0]}),
+        (Ry(math.pi / 2), {'gate': 'ry', 'rotation': 1.570796326795, 'targets': [0]}),
+        (Rz(math.pi / 2), {'gate': 'rz', 'rotation': 1.570796326795, 'targets': [0]}),
+        (Rx(math.pi), {'gate': 'rx', 'rotation': 3.14159265359, 'targets': [0]}),
+        (Ry(math.pi), {'gate': 'ry', 'rotation': 3.14159265359, 'targets': [0]}),
+        (Rz(math.pi), {'gate': 'rz', 'rotation': 3.14159265359, 'targets': [0]}),
+        (Sdag, {'gate': 'si', 'targets': [0]}),
+        (Sdagger, {'gate': 'si', 'targets': [0]}),
+        (Tdag, {'gate': 'ti', 'targets': [0]}),
+        (Tdagger, {'gate': 'ti', 'targets': [0]}),
+        (SqrtX, {'gate': 'v', 'targets': [0]}),
+        (Vdag, {'gate': 'vi', 'targets': [0]}),
+    ],
+)
+def test_to_json_single_qubit_gates(single_qubit_gate, expected_result):
+    eng = MainEngine(backend=DummyEngine(), engine_list=[DummyEngine()])
+    qb0 = WeakQubitRef(engine=eng, idx=0)
+
+    actual_result = to_json(Command(eng, single_qubit_gate, ([qb0],)))
+
+    assert len(actual_result) == len(expected_result)
+    assert actual_result['gate'] == expected_result['gate']
+    assert actual_result['targets'] == expected_result['targets']
+    if 'rotation' in expected_result:
+        assert actual_result['rotation'] == pytest.approx(expected_result['rotation'])
+
+
+@has_azure_quantum
+@pytest.mark.parametrize(
+    "two_qubit_gate, expected_result",
+    [
+        (Swap, {'gate': 'swap', 'targets': [0, 1]}),
+        (CNOT, {'gate': 'x', 'targets': [1], 'controls': [0]}),
+        (CX, {'gate': 'x', 'targets': [1], 'controls': [0]}),
+        (Rxx(0), {'gate': 'xx', 'rotation': 0.0, 'targets': [0, 1]}),
+        (Ryy(0), {'gate': 'yy', 'rotation': 0.0, 'targets': [0, 1]}),
+        (Rzz(0), {'gate': 'zz', 'rotation': 0.0, 'targets': [0, 1]}),
+        (Rxx(math.pi / 4), {'gate': 'xx', 'rotation': 0.785398163397, 'targets': [0, 1]}),
+        (Ryy(math.pi / 4), {'gate': 'yy', 'rotation': 0.785398163397, 'targets': [0, 1]}),
+        (Rzz(math.pi / 4), {'gate': 'zz', 'rotation': 0.785398163397, 'targets': [0, 1]}),
+        (Rxx(math.pi / 2), {'gate': 'xx', 'rotation': 1.570796326795, 'targets': [0, 1]}),
+        (Ryy(math.pi / 2), {'gate': 'yy', 'rotation': 1.570796326795, 'targets': [0, 1]}),
+        (Rzz(math.pi / 2), {'gate': 'zz', 'rotation': 1.570796326795, 'targets': [0, 1]}),
+        (Rxx(math.pi), {'gate': 'xx', 'rotation': 3.14159265359, 'targets': [0, 1]}),
+        (Ryy(math.pi), {'gate': 'yy', 'rotation': 3.14159265359, 'targets': [0, 1]}),
+        (Rzz(math.pi), {'gate': 'zz', 'rotation': 3.14159265359, 'targets': [0, 1]}),
+    ],
+)
+def test_to_json_two_qubit_gates(two_qubit_gate, expected_result):
+    eng = MainEngine(backend=DummyEngine(), engine_list=[DummyEngine()])
+    qb0 = WeakQubitRef(engine=eng, idx=0)
+    qb1 = WeakQubitRef(engine=eng, idx=1)
+
+    actual_result = to_json(Command(eng, two_qubit_gate, ([qb0], [qb1])))
+
+    assert len(actual_result) == len(expected_result)
+    assert actual_result['gate'] == expected_result['gate']
+    assert actual_result['targets'] == expected_result['targets']
+    if 'rotation' in expected_result:
+        assert actual_result['rotation'] == pytest.approx(expected_result['rotation'])
+
+
+@has_azure_quantum
+@pytest.mark.parametrize(
+    "base_gate, num_ctrl_qubits, expected_result",
+    [
+        (X, 0, {'gate': 'x', 'targets': [0]}),
+        (X, 1, {'gate': 'x', 'targets': [0], 'controls': [1]}),
+        (X, 2, {'gate': 'x', 'targets': [0], 'controls': [1, 2]}),
+        (X, 3, {'gate': 'x', 'targets': [0], 'controls': [1, 2, 3]}),
+        (X, 4, {'gate': 'x', 'targets': [0], 'controls': [1, 2, 3, 4]}),
+        (X, 5, {'gate': 'x', 'targets': [0], 'controls': [1, 2, 3, 4, 5]}),
+        (X, 6, {'gate': 'x', 'targets': [0], 'controls': [1, 2, 3, 4, 5, 6]}),
+        (X, 7, {'gate': 'x', 'targets': [0], 'controls': [1, 2, 3, 4, 5, 6, 7]}),
+    ],
+)
+def test_to_json_n_controlled_qubits_type_1(base_gate, num_ctrl_qubits, expected_result):
+    eng = MainEngine(backend=DummyEngine(), engine_list=[DummyEngine()])
+    qb0 = eng.allocate_qubit()
+    qureg = eng.allocate_qureg(num_ctrl_qubits)
+
+    cmd = Command(eng, base_gate, (qb0,), controls=qureg)
+    assert to_json(cmd) == expected_result, f'Failing on {num_ctrl_qubits}-controlled {base_gate} gate'
+
+
+@has_azure_quantum
+@pytest.mark.parametrize(
+    "base_gate, num_ctrl_qubits, expected_result",
+    [
+        (X, 0, {'gate': 'x', 'targets': [0]}),
+        (X, 1, {'gate': 'x', 'targets': [0], 'controls': [1]}),
+        (X, 2, {'gate': 'x', 'targets': [0], 'controls': [1, 2]}),
+        (X, 3, {'gate': 'x', 'targets': [0], 'controls': [1, 2, 3]}),
+        (X, 4, {'gate': 'x', 'targets': [0], 'controls': [1, 2, 3, 4]}),
+        (X, 5, {'gate': 'x', 'targets': [0], 'controls': [1, 2, 3, 4, 5]}),
+        (X, 6, {'gate': 'x', 'targets': [0], 'controls': [1, 2, 3, 4, 5, 6]}),
+        (X, 7, {'gate': 'x', 'targets': [0], 'controls': [1, 2, 3, 4, 5, 6, 7]}),
+    ],
+)
+def test_to_json_n_controlled_qubits_type_2(base_gate, num_ctrl_qubits, expected_result):
+    eng = MainEngine(backend=DummyEngine(), engine_list=[DummyEngine()])
+    qb0 = eng.allocate_qubit()
+    qureg = eng.allocate_qureg(num_ctrl_qubits)
+
+    n_controlled_gate = base_gate
+    for index in range(num_ctrl_qubits):
+        n_controlled_gate = C(n_controlled_gate)
+
+    # pass controls as targets
+    cmd = Command(
+        eng,
+        n_controlled_gate,
+        (
+            qureg,
+            qb0,
+        ),
+    )
+    assert to_json(cmd) == expected_result, f'Failing on {num_ctrl_qubits}-controlled {base_gate} gate'
+
+
+@has_azure_quantum
+def test_to_json_invalid_command_gate_not_available():
+    eng = MainEngine(backend=DummyEngine(), engine_list=[DummyEngine()])
+    qb0 = eng.allocate_qubit()
+
+    cmd = Command(eng, Barrier, (qb0,))
+    with pytest.raises(InvalidCommandError):
+        to_json(cmd)
+
+
+@has_azure_quantum
+@pytest.mark.parametrize(
+    "single_qubit_gate, expected_result",
+    [
+        (NOT, 'x q[0];'),
+        (X, 'x q[0];'),
+        (Y, 'y q[0];'),
+        (Z, 'z q[0];'),
+        (H, 'h q[0];'),
+        (S, 's q[0];'),
+        (T, 't q[0];'),
+        (Rx(0), 'rx(0.0) q[0];'),
+        (Ry(0), 'ry(0.0) q[0];'),
+        (Rz(0), 'rz(0.0) q[0];'),
+        (Rx(math.pi / 4), 'rx(0.785398163397) q[0];'),
+        (Ry(math.pi / 4), 'ry(0.785398163397) q[0];'),
+        (Rz(math.pi / 4), 'rz(0.785398163397) q[0];'),
+        (Rx(math.pi / 2), 'rx(1.570796326795) q[0];'),
+        (Ry(math.pi / 2), 'ry(1.570796326795) q[0];'),
+        (Rz(math.pi / 2), 'rz(1.570796326795) q[0];'),
+        (Rx(math.pi), 'rx(3.14159265359) q[0];'),
+        (Ry(math.pi), 'ry(3.14159265359) q[0];'),
+        (Rz(math.pi), 'rz(3.14159265359) q[0];'),
+        (Sdag, 'sdg q[0];'),
+        (Sdagger, 'sdg q[0];'),
+        (Tdag, 'tdg q[0];'),
+        (Tdagger, 'tdg q[0];'),
+    ],
+)
+def test_to_qasm_single_qubit_gates(single_qubit_gate, expected_result):
+    eng = MainEngine(backend=DummyEngine(), engine_list=[DummyEngine()])
+    qb0 = WeakQubitRef(engine=eng, idx=0)
+
+    assert to_qasm(Command(eng, single_qubit_gate, ([qb0],))) == expected_result
+
+
+@has_azure_quantum
+@pytest.mark.parametrize(
+    "two_qubit_gate, expected_result",
+    [
+        (CNOT, 'cx q[0], q[1];'),
+        (CX, 'cx q[0], q[1];'),
+        (Rxx(0), 'rxx(0.0) q[0], q[1];'),
+        (Ryy(0), 'ryy(0.0) q[0], q[1];'),
+        (Rzz(0), 'rzz(0.0) q[0], q[1];'),
+        (Rxx(math.pi / 4), 'rxx(0.785398163397) q[0], q[1];'),
+        (Ryy(math.pi / 4), 'ryy(0.785398163397) q[0], q[1];'),
+        (Rzz(math.pi / 4), 'rzz(0.785398163397) q[0], q[1];'),
+        (Rxx(math.pi / 2), 'rxx(1.570796326795) q[0], q[1];'),
+        (Ryy(math.pi / 2), 'ryy(1.570796326795) q[0], q[1];'),
+        (Rzz(math.pi / 2), 'rzz(1.570796326795) q[0], q[1];'),
+        (Rxx(math.pi), 'rxx(3.14159265359) q[0], q[1];'),
+        (Ryy(math.pi), 'ryy(3.14159265359) q[0], q[1];'),
+        (Rzz(math.pi), 'rzz(3.14159265359) q[0], q[1];'),
+    ],
+)
+def test_to_qasm_two_qubit_gates(two_qubit_gate, expected_result):
+    eng = MainEngine(backend=DummyEngine(), engine_list=[DummyEngine()])
+    qb0 = WeakQubitRef(engine=eng, idx=0)
+    qb1 = WeakQubitRef(engine=eng, idx=1)
+
+    assert to_qasm(Command(eng, two_qubit_gate, ([qb0], [qb1]))) == expected_result
+
+
+@has_azure_quantum
+@pytest.mark.parametrize(
+    "n_qubit_gate, n, expected_result",
+    [
+        (Barrier, 2, 'barrier q[0], q[1];'),
+        (Barrier, 3, 'barrier q[0], q[1], q[2];'),
+        (Barrier, 4, 'barrier q[0], q[1], q[2], q[3];'),
+    ],
+)
+def test_to_qasm_n_qubit_gates(n_qubit_gate, n, expected_result):
+    eng = MainEngine(backend=DummyEngine(), engine_list=[DummyEngine()])
+    qureg = eng.allocate_qureg(n)
+
+    assert to_qasm(Command(eng, n_qubit_gate, (qureg,))) == expected_result
+
+
+@has_azure_quantum
+@pytest.mark.parametrize(
+    "base_gate, num_ctrl_qubits, expected_result",
+    [
+        (X, 0, 'x q[0];'),
+        (X, 1, 'cx q[1], q[0];'),
+        (X, 2, 'ccx q[1], q[2], q[0];'),
+        (Z, 0, 'z q[0];'),
+        (Z, 1, 'cz q[1], q[0];'),
+        (Z, 2, 'ccz q[1], q[2], q[0];'),
+    ],
+)
+def test_to_qasm_n_controlled_qubits_type_1(base_gate, num_ctrl_qubits, expected_result):
+    eng = MainEngine(backend=DummyEngine(), engine_list=[DummyEngine()])
+    qb0 = eng.allocate_qubit()
+    qureg = eng.allocate_qureg(num_ctrl_qubits)
+
+    cmd = Command(eng, base_gate, (qb0,), controls=qureg)
+    assert to_qasm(cmd) == expected_result, f'Failing on {num_ctrl_qubits}-controlled {base_gate} gate'
+
+
+@has_azure_quantum
+@pytest.mark.parametrize(
+    "base_gate, num_ctrl_qubits, expected_result",
+    [
+        (X, 0, 'x q[0];'),
+        (X, 1, 'cx q[1], q[0];'),
+        (X, 2, 'ccx q[1], q[2], q[0];'),
+        (Z, 0, 'z q[0];'),
+        (Z, 1, 'cz q[1], q[0];'),
+        (Z, 2, 'ccz q[1], q[2], q[0];'),
+    ],
+)
+def test_to_qasm_n_controlled_qubits_type_2(base_gate, num_ctrl_qubits, expected_result):
+    eng = MainEngine(backend=DummyEngine(), engine_list=[DummyEngine()])
+    qb0 = eng.allocate_qubit()
+    qureg = eng.allocate_qureg(num_ctrl_qubits)
+
+    n_controlled_gate = base_gate
+    for index in range(num_ctrl_qubits):
+        n_controlled_gate = C(n_controlled_gate)
+
+    # pass controls as targets
+    cmd = Command(
+        eng,
+        n_controlled_gate,
+        (
+            qureg,
+            qb0,
+        ),
+    )
+    assert to_qasm(cmd) == expected_result, f'Failing on {num_ctrl_qubits}-controlled {base_gate} gate'
+
+
+@has_azure_quantum
+def test_to_qasm_invalid_command_gate_not_available():
+    qb0 = WeakQubitRef(None, idx=0)
+    qb1 = WeakQubitRef(None, idx=1)
+
+    cmd = Command(None, SqrtX, qubits=((qb0,),))
+    with pytest.raises(InvalidCommandError):
+        to_qasm(cmd)
+
+    # NB: unsupported gate for 2 qubits
+    cmd = Command(None, X, qubits=((qb0, qb1),))
+    with pytest.raises(InvalidCommandError):
+        to_qasm(cmd)
diff --git a/projectq/backends/_ionq/_ionq.py b/projectq/backends/_ionq/_ionq.py
index 089b26ce4..392864461 100644
--- a/projectq/backends/_ionq/_ionq.py
+++ b/projectq/backends/_ionq/_ionq.py
@@ -46,6 +46,7 @@
 from projectq.types import WeakQubitRef
 
 from .._exceptions import InvalidCommandError, MidCircuitMeasurementError
+from .._utils import _rearrange_result
 from . import _ionq_http_client as http_client
 
 GATE_MAP = {
@@ -67,20 +68,6 @@
 SUPPORTED_GATES = tuple(GATE_MAP.keys())
 
 
-def _rearrange_result(input_result, length):
-    """Turn ``input_result`` from an integer into a bit-string.
-
-    Args:
-        input_result (int): An integer representation of qubit states.
-        length (int): The total number of bits (for padding, if needed).
-
-    Returns:
-        str: A bit-string representation of ``input_result``.
-    """
-    bin_input = list(bin(input_result)[2:].rjust(length, '0'))
-    return ''.join(bin_input)[::-1]
-
-
 class IonQBackend(BasicEngine):  # pylint: disable=too-many-instance-attributes
     """Backend for building circuits and submitting them to the IonQ API."""
 
diff --git a/projectq/backends/_utils.py b/projectq/backends/_utils.py
new file mode 100644
index 000000000..2c33068ae
--- /dev/null
+++ b/projectq/backends/_utils.py
@@ -0,0 +1,28 @@
+#   Copyright 2022 ProjectQ-Framework (www.projectq.ch)
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+
+"""Module containing some utility functions."""
+
+
+def _rearrange_result(input_result, length):
+    """Turn ``input_result`` from an integer into a bit-string.
+
+    Args:
+        input_result (int): An integer representation of qubit states.
+        length (int): The total number of bits (for padding, if needed).
+
+    Returns:
+        str: A bit-string representation of ``input_result``.
+    """
+    return f'{input_result:0{length}b}'[::-1]
diff --git a/projectq/backends/_utils_test.py b/projectq/backends/_utils_test.py
new file mode 100644
index 000000000..f2dddcd9b
--- /dev/null
+++ b/projectq/backends/_utils_test.py
@@ -0,0 +1,35 @@
+#   Copyright 2022 ProjectQ-Framework (www.projectq.ch)
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+
+"""Tests for projectq._utils.py."""
+
+import pytest
+
+from ._utils import _rearrange_result
+
+
+@pytest.mark.parametrize(
+    "input_result, length, expected_result",
+    [
+        (5, 3, '101'),
+        (5, 4, '1010'),
+        (5, 5, '10100'),
+        (16, 5, '00001'),
+        (16, 6, '000010'),
+        (63, 6, '111111'),
+        (63, 7, '1111110'),
+    ],
+)
+def test_rearrange_result(input_result, length, expected_result):
+    assert expected_result == _rearrange_result(input_result, length)
diff --git a/pyproject.toml b/pyproject.toml
index 82f728b54..5e0559d69 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -43,6 +43,10 @@ dependencies = [
 
 [project.optional-dependencies]
 
+azure-quantum = [
+      'azure-quantum'
+]
+
 braket = [
       'boto3'
 ]

From e73397f78df8610b72cca7bc263a1f52499a53d4 Mon Sep 17 00:00:00 2001
From: Nguyen Damien <ngn.damien@gmail.com>
Date: Fri, 14 Oct 2022 07:55:18 +0200
Subject: [PATCH 07/25] Fix installation on Apple Silicon and older Python
 versions (#444)

---
 CHANGELOG.md |  4 ++++
 setup.py     | 11 +++++++++++
 2 files changed, 15 insertions(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index c7a5f625b..bbce61d83 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 -   Support for Python 3.6 and earlier is now deprecated
 -   Moved package metadata into pyproject.toml
 
+### Fixed
+
+-   Fixed installation on Apple Silicon with older Python versions (< 3.9)
+
 ### Repository
 
 -   Update `docker/setup-qemu-action` GitHub action to v2
diff --git a/setup.py b/setup.py
index 9d23f1b60..32426d594 100755
--- a/setup.py
+++ b/setup.py
@@ -523,6 +523,17 @@ def _configure_intrinsics(self):
             '/arch:AVX',
         ]
 
+        if int(os.environ.get('PROJECTQ_NOINTRIN', '0')) or (
+            sys.platform == 'darwin'
+            and platform.machine() == 'arm64'
+            and (sys.version_info.major == 3 and sys.version_info.minor < 9)
+        ):
+            important_msgs(
+                'Either requested no-intrinsics or detected potentially unsupported Python version on '
+                'Apple Silicon: disabling intrinsics'
+            )
+            self.compiler.define_macro('NOINTRIN')
+            return
         if os.environ.get('PROJECTQ_DISABLE_ARCH_NATIVE'):
             flags = flags[1:]
 

From b4b839e32907972458aa54f2539b59a4e5b7f2d2 Mon Sep 17 00:00:00 2001
From: Christian Clauss <cclauss@me.com>
Date: Thu, 27 Oct 2022 10:01:08 +0200
Subject: [PATCH 08/25] Context Manager: with flushing(MainEngine()) as eng:
 (#449)

* Context Manager: with flushing(MainEngine()) as eng:

Simplify the creation, use, and flushing of any Engine using a Python context manager.

When exiting the `with` block, the engine is _automatically_ flushed.

Modeled after https://docs.python.org/3/library/contextlib.html#contextlib.closing
```python
from projectq import MainEngine, flushing  # import the main compiler engine
from projectq.ops import (
    H,
    Measure,
)  # import the operations we want to perform (Hadamard and measurement)

with flushing(MainEngine()) as eng:  # create a default compiler (the back-end is a simulator)
    qubit = eng.allocate_qubit()  # allocate a quantum register with 1 qubit

    H | qubit  # apply a Hadamard gate
    Measure | qubit  # measure the qubit

    # This line is no longer required... eng.flush()

print(f"Measured {int(qubit)}")  # converting a qubit to int or bool gives access to the measurement result

* Add tests

* Run linters/formatters on code

* Fix isort comment pragmas

* Really fix isort issues in cengines/__init__.py

Co-authored-by: Damien Nguyen <ngn.damien@gmail.com>
---
 CHANGELOG.md                            |  6 ++++
 projectq/cengines/__init__.py           | 23 +++++++++++++++
 projectq/cengines/_withflushing_test.py | 38 +++++++++++++++++++++++++
 3 files changed, 67 insertions(+)
 create mode 100644 projectq/cengines/_withflushing_test.py

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8839518a3..ec8c85b9e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
+## [Unreleased]
+
+### Added
+
+-   Python context manager `with flusing(MainEngine()) as eng:`
+
 ## [v0.8.0] - 2022-10-18
 
 ### Added
diff --git a/projectq/cengines/__init__.py b/projectq/cengines/__init__.py
index aa36092f2..bb487c748 100755
--- a/projectq/cengines/__init__.py
+++ b/projectq/cengines/__init__.py
@@ -14,10 +14,14 @@
 
 """ProjectQ module containing all compiler engines."""
 
+from contextlib import contextmanager
+
 from ._basics import BasicEngine, ForwarderEngine, LastEngineException  # isort:skip
 from ._cmdmodifier import CommandModifier  # isort:skip
 from ._basicmapper import BasicMapperEngine  # isort:skip
 
+# isort: split
+
 from ._ibm5qubitmapper import IBM5QubitMapper
 from ._linearmapper import LinearMapper, return_swap_depth
 from ._main import MainEngine, NotYetMeasuredError, UnsupportedEngineError
@@ -33,3 +37,22 @@
 from ._tagremover import TagRemover
 from ._testengine import CompareEngine, DummyEngine
 from ._twodmapper import GridMapper
+
+
+@contextmanager
+def flushing(engine):
+    """
+    Context manager to flush the given engine at the end of the 'with' context block.
+
+    Example:
+        with flushing(MainEngine()) as eng:
+            qubit = eng.allocate_qubit()
+            ...
+
+    Calling 'eng.flush()' is no longer needed because the engine will be flushed at the
+    end of the 'with' block even if an exception has been raised within that block.
+    """
+    try:
+        yield engine
+    finally:
+        engine.flush()
diff --git a/projectq/cengines/_withflushing_test.py b/projectq/cengines/_withflushing_test.py
new file mode 100644
index 000000000..b0e844bf5
--- /dev/null
+++ b/projectq/cengines/_withflushing_test.py
@@ -0,0 +1,38 @@
+#   Copyright 2017 ProjectQ-Framework (www.projectq.ch)
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+"""Tests for projectq.cengines.__init__.py."""
+
+from unittest.mock import MagicMock
+
+from projectq.cengines import DummyEngine, flushing
+
+
+def test_with_flushing():
+    """Test with flushing() as eng:"""
+    with flushing(DummyEngine()) as engine:
+        engine.flush = MagicMock()
+        assert engine.flush.call_count == 0
+    assert engine.flush.call_count == 1
+
+
+def test_with_flushing_with_exception():
+    """Test with flushing() as eng: with an exception raised in the 'with' block."""
+    try:
+        with flushing(DummyEngine()) as engine:
+            engine.flush = MagicMock()
+            assert engine.flush.call_count == 0
+            raise ValueError("An exception is raised in the 'with' block")
+    except ValueError:
+        pass
+    assert engine.flush.call_count == 1

From e73d5822cf411fa0f3dafb2066642c04e495c09a Mon Sep 17 00:00:00 2001
From: Christian Clauss <cclauss@me.com>
Date: Thu, 27 Oct 2022 10:33:01 +0200
Subject: [PATCH 09/25] Upgrade GitHub Actions (#450)

* Upgrade GitHub Actions

https://github.com/actions/cache/releases
https://github.com/actions/checkout/releases
https://github.com/actions/setup-python/releases

* Update CHANGELOG

* Properly update CHANGELOG

Co-authored-by: Damien Nguyen <ngn.damien@gmail.com>
---
 .github/workflows/ci.yml | 22 +++++++++++-----------
 CHANGELOG.md             |  4 ++++
 2 files changed, 15 insertions(+), 11 deletions(-)

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index ffda8c62b..cbbfb6183 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -25,7 +25,7 @@ jobs:
     runs-on: ${{ matrix.runs-on }}
 
     steps:
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v3
 
     - name: Get history and tags for SCM versioning to work
       if: ${{ !env.ACT }}
@@ -34,7 +34,7 @@ jobs:
         git fetch --depth=1 origin +refs/tags/*:refs/tags/*
 
     - name: Setup Python ${{ matrix.python }}
-      uses: actions/setup-python@v2
+      uses: actions/setup-python@v4
       with:
         python-version: ${{ matrix.python }}
         architecture: 'x64'
@@ -45,7 +45,7 @@ jobs:
         echo "::set-output name=dir::$(python -m pip  cache dir)"
 
     - name: Cache wheels
-      uses: actions/cache@v2
+      uses: actions/cache@v3
       with:
         path: ${{ steps.pip-cache.outputs.dir }}
         key: ${{ runner.os }}-${{ matrix.python }}-pip-${{ hashFiles('**/setup.cfg') }}
@@ -125,7 +125,7 @@ jobs:
     container: "silkeh/clang:${{ matrix.clang }}"
 
     steps:
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v3
 
     - name: Get history and tags for SCM versioning to work
       if: ${{ !env.ACT }}
@@ -173,7 +173,7 @@ jobs:
     container: "gcc:${{ matrix.gcc }}"
 
     steps:
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v3
 
     - name: Get history and tags for SCM versioning to work
       if: ${{ !env.ACT }}
@@ -226,7 +226,7 @@ jobs:
       run: echo 'keepcache=1' >> /etc/yum.conf
 
     - name: Setup yum cache
-      uses: actions/cache@v2
+      uses: actions/cache@v3
       with:
         path: |
           /var/cache/yum/
@@ -251,7 +251,7 @@ jobs:
         yum install -y git
         git config --global --add safe.directory /__w/ProjectQ/ProjectQ
 
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v3
 
     - name: Get history and tags for SCM versioning to work
       if: ${{ !env.ACT }}
@@ -263,7 +263,7 @@ jobs:
       run: mkdir -p ~/.cache/pip
 
     - name: Cache wheels
-      uses: actions/cache@v2
+      uses: actions/cache@v3
       with:
         path: ~/.cache/pip
         key: ${{ runner.os }}-centos${{ matrix.centos }}-pip-${{ hashFiles('**/setup.cfg') }}
@@ -293,13 +293,13 @@ jobs:
     runs-on: ubuntu-latest
 
     steps:
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v3
 
     - name: Create pip cache dir
       run: mkdir -p ~/.cache/pip
 
     - name: Cache wheels
-      uses: actions/cache@v2
+      uses: actions/cache@v3
       with:
         path: ~/.cache/pip
         key: ${{ runner.os }}-doc-pip-${{ hashFiles('**/setup.cfg') }}
@@ -311,7 +311,7 @@ jobs:
         git fetch --prune --unshallow
         git fetch --depth=1 origin +refs/tags/*:refs/tags/*
 
-    - uses: actions/setup-python@v2
+    - uses: actions/setup-python@v4
 
     - name: Install docs & setup requirements
       run: |
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ec8c85b9e..cb610947c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 -   Python context manager `with flusing(MainEngine()) as eng:`
 
+### Repository
+
+-   Update GitHub workflow action versions
+
 ## [v0.8.0] - 2022-10-18
 
 ### Added

From 71a3af0c3ca265a72023968d96473df99f29048a Mon Sep 17 00:00:00 2001
From: Nguyen Damien <ngn.damien@gmail.com>
Date: Sun, 30 Oct 2022 20:13:11 +0100
Subject: [PATCH 10/25] Feature/upgrade GitHub workflows (#452)

* Update GitHub Action versions

* Also update actions/checkout

* Update CHANGELOG
---
 .github/workflows/ci.yml              | 19 +++++++------------
 .github/workflows/draft_release.yml   |  2 +-
 .github/workflows/format.yml          | 11 +++++++----
 .github/workflows/publish_release.yml | 26 +++++++++++++++-----------
 .github/workflows/pull_request.yml    |  2 +-
 CHANGELOG.md                          |  2 +-
 6 files changed, 32 insertions(+), 30 deletions(-)

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index cbbfb6183..9f89399a4 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -38,18 +38,10 @@ jobs:
       with:
         python-version: ${{ matrix.python }}
         architecture: 'x64'
-
-    - name: Get pip cache dir
-      id: pip-cache
-      run: |
-        echo "::set-output name=dir::$(python -m pip  cache dir)"
-
-    - name: Cache wheels
-      uses: actions/cache@v3
-      with:
-        path: ${{ steps.pip-cache.outputs.dir }}
-        key: ${{ runner.os }}-${{ matrix.python }}-pip-${{ hashFiles('**/setup.cfg') }}
-        restore-keys: ${{ runner.os }}-${{ matrix.python }}-pip-
+        cache: 'pip'
+        cache-dependency-path: |
+          setup.cfg
+          pyproject.toml
 
     - name: Generate requirement file (Unix)
       if: runner.os != 'Windows'
@@ -312,6 +304,9 @@ jobs:
         git fetch --depth=1 origin +refs/tags/*:refs/tags/*
 
     - uses: actions/setup-python@v4
+      with:
+        python-version: '3.x'
+        architecture: 'x64'
 
     - name: Install docs & setup requirements
       run: |
diff --git a/.github/workflows/draft_release.yml b/.github/workflows/draft_release.yml
index 6594b2253..c4854cd2c 100644
--- a/.github/workflows/draft_release.yml
+++ b/.github/workflows/draft_release.yml
@@ -14,7 +14,7 @@ jobs:
     - name: Install git-flow
       run: sudo apt update && sudo apt install -y git-flow
 
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v3
 
     - name: Configure git-flow
       run: |
diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml
index 752d64fc9..1a3b4cb96 100644
--- a/.github/workflows/format.yml
+++ b/.github/workflows/format.yml
@@ -14,19 +14,22 @@ jobs:
     name: Format and static analysis
     runs-on: ubuntu-latest
     steps:
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v3
     - name: Get history and tags for SCM versioning to work
       if: ${{ !env.ACT }}
       run: |
         git fetch --prune --unshallow
         git fetch --depth=1 origin +refs/tags/*:refs/tags/*
-    - uses: actions/setup-python@v2
+
+    - uses: actions/setup-python@v4
+      with:
+        python-version: '3.x'
 
     - name: Install pre-commit
       run: python3 -m pip install --upgrade pre-commit 'virtualenv!=20.11'
 
     - name: Cache pre-commit hooks
-      uses: actions/cache@v2
+      uses: actions/cache@v3
       with:
         path: ~/.cache/pre-commit
         key: pre-commit-${{ hashFiles('**/.pre-commit-config.yaml') }}
@@ -46,7 +49,7 @@ jobs:
       CXX: clang++
 
     steps:
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v3
 
     - name: Prepare env
       run: >
diff --git a/.github/workflows/publish_release.yml b/.github/workflows/publish_release.yml
index ff4bcd221..aa88b802a 100644
--- a/.github/workflows/publish_release.yml
+++ b/.github/workflows/publish_release.yml
@@ -30,10 +30,10 @@ jobs:
         with:
           platforms: arm64
 
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v3
         if: github.event_name != 'workflow_dispatch'
 
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v3
         if: github.event_name == 'workflow_dispatch'
         with:
           ref: 'master'
@@ -82,7 +82,9 @@ jobs:
 
       # ========================================================================
 
-      - uses: actions/setup-python@v2
+      - uses: actions/setup-python@v4
+        with:
+          python-version: '3.x'
 
       - name: Install Python packages
         run: python -m pip install -U --prefer-binary pip setuptools build wheel twine 'cibuildwheel<3,>=2'
@@ -113,21 +115,21 @@ jobs:
           CIBW_TEST_SKIP: '*'
 
       - name: Files for Pypi upload
-        uses: actions/upload-artifact@v2
+        uses: actions/upload-artifact@v3
         if: steps.src-dist.outcome == 'success'
         with:
           name: pypy_wheels
           path: ./dist
 
       - name: Binary wheels
-        uses: actions/upload-artifact@v2
+        uses: actions/upload-artifact@v3
         if: steps.binary-dist.outcome == 'success'
         with:
           name: wheels
           path: ./binary_dist
 
       - name: Binary wheels that failed tests
-        uses: actions/upload-artifact@v2
+        uses: actions/upload-artifact@v3
         if: steps.failed-dist.outcome == 'success'
         with:
           name: failed_wheels
@@ -175,17 +177,17 @@ jobs:
       # ------------------------------------------------------------------------
       # Checkout repository to get CHANGELOG
 
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v3
         if: github.event_name != 'workflow_dispatch'
 
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v3
         if: github.event_name == 'workflow_dispatch'
         with:
           ref: 'master'
 
       # ------------------------------------------------------------------------
 
-      - uses: actions/download-artifact@v2
+      - uses: actions/download-artifact@v3
 
       # Code below inspired from this action:
       # - uses: taiki-e/create-gh-release-action@v1
@@ -220,9 +222,11 @@ jobs:
     runs-on: ubuntu-latest
     needs: release
     steps:
-    - uses: actions/setup-python@v2
+    - uses: actions/setup-python@v4
+      with:
+        python-version: '3.x'
 
-    - uses: actions/download-artifact@v2
+    - uses: actions/download-artifact@v3
 
     - name: Publish standard package
       uses: pypa/gh-action-pypi-publish@release/v1
diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml
index acabd22ce..35eae58cc 100644
--- a/.github/workflows/pull_request.yml
+++ b/.github/workflows/pull_request.yml
@@ -9,7 +9,7 @@ jobs:
     runs-on: ubuntu-latest
     if: github.ref != 'refs/heads/master'
     steps:
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v3
 
     - id: changelog-enforcer
       uses: dangoslen/changelog-enforcer@v3
diff --git a/CHANGELOG.md b/CHANGELOG.md
index cb610947c..f3d65056a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,7 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Repository
 
--   Update GitHub workflow action versions
+-   Update all GitHub workflow action versions
 
 ## [v0.8.0] - 2022-10-18
 

From ff757e75f205dc401fd9377de1f5806155c44b5c Mon Sep 17 00:00:00 2001
From: Nguyen Damien <ngn.damien@gmail.com>
Date: Sun, 30 Oct 2022 21:57:35 +0100
Subject: [PATCH 11/25] Prepare the introduction of pre-commit CI + repository
 configuration updates (#453)

* Remove pre-commit from GitHub workflows in favour of pre-commit CI

* Remove manual tag for pre-commit hooks

* Update CHANGELOG

* Update pre-commit configuration file + add .yamllint

- Added new pre-commit hooks
  + codespell
  + pydocstyle
  + doc8
  + yamllint
- Update pre-commit hook versions
- Add .yamllint configuration file
- Add .codespell.allow file for codespell

* Delete .travis.yml file since not used anymore

* Update YAML files to satisfy yamllint

* Update Markdown files to fix linter/formatter warnings

* Update ReST files to fix linter/formatter warnings

* Update Python files to fix linter/formatter warnings

* Rename CI jobs

* Install pybind11 earlier in CI build

* Update CHANGELOG

* Address pre-commit CI virtualenv size limitations
---
 .codespell.allow                              |   5 +
 .github/workflows/ci.yml                      | 445 +++++++++---------
 .github/workflows/draft_release.yml           |  87 ++--
 .github/workflows/format.yml                  |  58 +--
 .github/workflows/publish_release.yml         |  62 ++-
 .github/workflows/pull_request.yml            |  16 +-
 .pre-commit-config.yaml                       |  50 +-
 .readthedocs.yaml                             |   6 +-
 .travis.yml                                   |  76 ---
 .yamllint                                     |   8 +
 CHANGELOG.md                                  |  10 +-
 README.rst                                    |  60 ++-
 docs/README.rst                               |   7 +-
 docs/conf.py                                  |   2 +-
 docs/examples.rst                             |  67 ++-
 docs/index.rst                                |  12 +-
 docs/projectq.rst                             |   3 +-
 docs/tutorials.rst                            |  74 ++-
 examples/README.rst                           |  36 +-
 projectq/__init__.py                          |   2 +-
 projectq/backends/_aqt/__init__.py            |   2 +-
 projectq/backends/_aqt/_aqt.py                |   2 +-
 projectq/backends/_aqt/_aqt_http_client.py    |   4 +-
 projectq/backends/_awsbraket/__init__.py      |   5 +-
 projectq/backends/_awsbraket/_awsbraket.py    |   4 +-
 .../_awsbraket/_awsbraket_boto3_client.py     |  16 +-
 projectq/backends/_azure/__init__.py          |   3 +-
 projectq/backends/_azure/_azure_quantum.py    |   2 +-
 projectq/backends/_circuits/__init__.py       |   2 +-
 projectq/backends/_circuits/_to_latex.py      |   1 +
 projectq/backends/_ibm/__init__.py            |   2 +-
 projectq/backends/_ibm/_ibm_http_client.py    |   2 +-
 projectq/backends/_ionq/__init__.py           |   2 +-
 projectq/backends/_ionq/_ionq.py              |   4 +-
 projectq/backends/_ionq/_ionq_http_client.py  |   2 +-
 projectq/backends/_resource.py                |   2 +-
 projectq/backends/_sim/__init__.py            |   2 +-
 projectq/backends/_sim/_simulator.py          |   2 +-
 projectq/cengines/_linearmapper.py            |   6 +-
 projectq/cengines/_main.py                    |   4 +-
 projectq/cengines/_optimize.py                |   2 +-
 projectq/cengines/_swapandcnotflipper.py      |   4 +-
 projectq/cengines/_testengine.py              |   2 +-
 projectq/libs/__init__.py                     |   2 +-
 projectq/libs/hist/__init__.py                |   5 +-
 projectq/libs/math/__init__.py                |   2 +
 projectq/libs/math/_gates.py                  |   4 +-
 projectq/libs/math/_quantummath.py            |   2 +-
 projectq/libs/revkit/__init__.py              |   2 +-
 projectq/libs/revkit/_control_function.py     |   2 +-
 projectq/libs/revkit/_phase.py                |   2 +-
 projectq/libs/revkit/_utils.py                |   4 +-
 projectq/meta/__init__.py                     |   5 +-
 projectq/meta/_compute.py                     |   4 +-
 projectq/meta/_compute_test.py                |   2 +-
 projectq/meta/_control.py                     |   2 +-
 projectq/meta/_dagger.py                      |   2 +-
 projectq/meta/_loop.py                        |   2 +-
 projectq/ops/__init__.py                      |   2 +-
 projectq/ops/_basics.py                       |  14 +-
 projectq/ops/_command_test.py                 |   4 +-
 projectq/ops/_gates.py                        |   2 +-
 projectq/ops/_qaagate.py                      |   6 +-
 projectq/ops/_qubit_operator.py               |   4 +-
 projectq/ops/_time_evolution.py               |   2 +-
 projectq/setups/__init__.py                   |   2 +-
 projectq/setups/_utils.py                     |   2 +-
 projectq/setups/aqt.py                        |   2 +-
 projectq/setups/decompositions/__init__.py    |   2 +
 .../decompositions/amplitudeamplification.py  |   6 +-
 .../amplitudeamplification_test.py            |   8 +-
 .../decompositions/arb1qubit2rzandry.py       |   2 +-
 .../decompositions/carb1qubit2cnotrzandry.py  |   6 +-
 .../setups/decompositions/controlstate.py     |   2 +-
 .../setups/decompositions/phaseestimation.py  |   2 +-
 projectq/setups/grid.py                       |   2 +-
 projectq/setups/linear.py                     |   2 +-
 projectq/setups/restrictedgateset.py          |   4 +-
 projectq/setups/trapped_ion_decomposer.py     |   6 +-
 projectq/tests/__init__.py                    |   2 +
 projectq/types/__init__.py                    |   2 +-
 projectq/types/_qubit.py                      |   2 +-
 pyproject.toml                                |  12 +-
 setup.py                                      |   4 +-
 84 files changed, 706 insertions(+), 603 deletions(-)
 create mode 100644 .codespell.allow
 delete mode 100755 .travis.yml
 create mode 100644 .yamllint

diff --git a/.codespell.allow b/.codespell.allow
new file mode 100644
index 000000000..1edf5ded2
--- /dev/null
+++ b/.codespell.allow
@@ -0,0 +1,5 @@
+Braket
+braket
+te
+Ket
+ket
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 9f89399a4..a9a252762 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1,3 +1,5 @@
+---
+
 name: CI
 
 on:
@@ -16,86 +18,85 @@ jobs:
       matrix:
         runs-on: [ubuntu-latest, windows-latest, macos-latest]
         python:
-        - 3.7
-        - 3.8
-        - 3.9
-        - '3.10'
+          - 3.7
+          - 3.8
+          - 3.9
+          - '3.10'
 
-    name: "🐍 ${{ matrix.python }} • ${{ matrix.runs-on }} • x64 ${{ matrix.args }}"
+    name: "Python ${{ matrix.python }} • ${{ matrix.runs-on }} • x64 ${{ matrix.args }}"
     runs-on: ${{ matrix.runs-on }}
 
     steps:
-    - uses: actions/checkout@v3
-
-    - name: Get history and tags for SCM versioning to work
-      if: ${{ !env.ACT }}
-      run: |
-        git fetch --prune --unshallow
-        git fetch --depth=1 origin +refs/tags/*:refs/tags/*
-
-    - name: Setup Python ${{ matrix.python }}
-      uses: actions/setup-python@v4
-      with:
-        python-version: ${{ matrix.python }}
-        architecture: 'x64'
-        cache: 'pip'
-        cache-dependency-path: |
-          setup.cfg
-          pyproject.toml
-
-    - name: Generate requirement file (Unix)
-      if: runner.os != 'Windows'
-      run: |
-        python setup.py gen_reqfile --include-extras=test,azure-quantum,braket,revkit
-
-    - name: Generate requirement file (Windows)
-      if: runner.os == 'Windows'
-      run: |
-        python setup.py gen_reqfile --include-extras=test,azure-quantum,braket
-
-    - name: Prepare env
-      run: |
-        python -m pip install -U pip setuptools wheel
-        cat requirements.txt
-        python -m pip install -r requirements.txt --prefer-binary
-        python -m pip install coveralls
-
-    - name: Setup annotations on Linux
-      if: runner.os == 'Linux'
-      run: python -m pip install pytest-github-actions-annotate-failures
-
-    - name: Build and install package (Unix)
-      if: runner.os != 'Windows'
-      run: python -m pip install -ve .[azure-quantum,braket,revkit,test]
-
-    - name: Build and install package (Windows)
-      if: runner.os == 'Windows'
-      run: python -m pip install -ve .[azure-quantum,braket,test]
-
-    - name: Pytest
-      run: |
-        echo 'backend: Agg' > matplotlibrc
-        python -m pytest -p no:warnings --cov=projectq
-
-    - name: Coveralls.io
-      run: coveralls --service=github
-      env:
-        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-        COVERALLS_FLAG_NAME: python-${{ matrix.python }}-${{ matrix.runs-on }}-x64
-        COVERALLS_PARALLEL: true
-
+      - uses: actions/checkout@v3
+
+      - name: Get history and tags for SCM versioning to work
+        if: ${{ !env.ACT }}
+        run: |
+          git fetch --prune --unshallow
+          git fetch --depth=1 origin +refs/tags/*:refs/tags/*
+
+      - name: Setup Python ${{ matrix.python }}
+        uses: actions/setup-python@v4
+        with:
+          python-version: ${{ matrix.python }}
+          architecture: 'x64'
+          cache: 'pip'
+          cache-dependency-path: |
+            setup.cfg
+            pyproject.toml
+
+      - name: Generate requirement file (Unix)
+        if: runner.os != 'Windows'
+        run: |
+          python setup.py gen_reqfile --include-extras=test,azure-quantum,braket,revkit
+
+      - name: Generate requirement file (Windows)
+        if: runner.os == 'Windows'
+        run: |
+          python setup.py gen_reqfile --include-extras=test,azure-quantum,braket
+
+      - name: Prepare env
+        run: |
+          python -m pip install -U pip setuptools wheel pybind11
+          cat requirements.txt
+          python -m pip install -r requirements.txt --prefer-binary
+          python -m pip install coveralls
+
+      - name: Setup annotations on Linux
+        if: runner.os == 'Linux'
+        run: python -m pip install pytest-github-actions-annotate-failures
+
+      - name: Build and install package (Unix)
+        if: runner.os != 'Windows'
+        run: python -m pip install -ve .[azure-quantum,braket,revkit,test]
+
+      - name: Build and install package (Windows)
+        if: runner.os == 'Windows'
+        run: python -m pip install -ve .[azure-quantum,braket,test]
+
+      - name: Pytest
+        run: |
+          echo 'backend: Agg' > matplotlibrc
+          python -m pytest -p no:warnings --cov=projectq
+
+      - name: Coveralls.io
+        run: coveralls --service=github
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          COVERALLS_FLAG_NAME: python-${{ matrix.python }}-${{ matrix.runs-on }}-x64
+          COVERALLS_PARALLEL: true
 
   finish:
     needs: standard
     runs-on: ubuntu-latest
     container: python:3-slim
     steps:
-    - name: Coveralls Finished
-      run: |
-        pip3 install --upgrade coveralls
-        coveralls --finish
-      env:
-        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+      - name: Coveralls Finished
+        run: |
+          pip3 install --upgrade coveralls
+          coveralls --finish
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
 
 
   clang:
@@ -113,43 +114,43 @@ jobs:
       CXX: clang++
       PROJECTQ_CLEANUP_COMPILER_FLAGS: ${{ (matrix.clang < 10) && 1 || 0 }}
 
-    name: "🐍 3 • Clang ${{ matrix.clang }} • x64"
+    name: "Python 3 • Clang ${{ matrix.clang }} • x64"
     container: "silkeh/clang:${{ matrix.clang }}"
 
     steps:
-    - uses: actions/checkout@v3
+      - uses: actions/checkout@v3
 
-    - name: Get history and tags for SCM versioning to work
-      if: ${{ !env.ACT }}
-      run: |
-        git fetch --prune --unshallow
-        git fetch --depth=1 origin +refs/tags/*:refs/tags/*
+      - name: Get history and tags for SCM versioning to work
+        if: ${{ !env.ACT }}
+        run: |
+          git fetch --prune --unshallow
+          git fetch --depth=1 origin +refs/tags/*:refs/tags/*
 
-    - name: Prepare env
-      run: >
-        apt-get update && apt-get install -y python3-dev python3-pip python3-setuptools python3-wheel
-        python3-numpy python3-scipy python3-matplotlib python3-requests python3-networkx
-        python3-pytest python3-pytest-cov python3-flaky
-        libomp-dev
-        --no-install-recommends
+      - name: Prepare env
+        run: >
+          apt-get update && apt-get install -y python3-dev python3-pip python3-setuptools python3-wheel
+          python3-numpy python3-scipy python3-matplotlib python3-requests python3-networkx
+          python3-pytest python3-pytest-cov python3-flaky
+          libomp-dev
+          --no-install-recommends
 
-    - name: Prepare Python env
-      run: |
-        python3 -m pip install -U pip setuptools wheel
-        python3 setup.py gen_reqfile --include-extras=test,azure-quantum,braket
-        cat requirements.txt
-        python3 -m pip install -r requirements.txt --prefer-binary
+      - name: Prepare Python env
+        run: |
+          python3 -m pip install -U pip setuptools wheel
+          python3 setup.py gen_reqfile --include-extras=test,azure-quantum,braket
+          cat requirements.txt
+          python3 -m pip install -r requirements.txt --prefer-binary
 
-    - name: Upgrade pybind11 and flaky
-      run: python3 -m pip install --upgrade pybind11 flaky --prefer-binary
+      - name: Upgrade pybind11 and flaky
+        run: python3 -m pip install --upgrade pybind11 flaky --prefer-binary
 
-    - name: Build and install package
-      run: python3 -m pip install -ve .[azure-quantum,braket,test]
+      - name: Build and install package
+        run: python3 -m pip install -ve .[azure-quantum,braket,test]
 
-    - name: Pytest
-      run: |
-        echo 'backend: Agg' > matplotlibrc
-        python3 -m pytest -p no:warnings
+      - name: Pytest
+        run: |
+          echo 'backend: Agg' > matplotlibrc
+          python3 -m pytest -p no:warnings
 
 
   gcc:
@@ -161,42 +162,42 @@ jobs:
           - 7  # C++17 earliest version
           - latest
 
-    name: "🐍 3 • GCC ${{ matrix.gcc }} • x64"
+    name: "Python 3 • GCC ${{ matrix.gcc }} • x64"
     container: "gcc:${{ matrix.gcc }}"
 
     steps:
-    - uses: actions/checkout@v3
+      - uses: actions/checkout@v3
 
-    - name: Get history and tags for SCM versioning to work
-      if: ${{ !env.ACT }}
-      run: |
-        git fetch --prune --unshallow
-        git fetch --depth=1 origin +refs/tags/*:refs/tags/*
+      - name: Get history and tags for SCM versioning to work
+        if: ${{ !env.ACT }}
+        run: |
+          git fetch --prune --unshallow
+          git fetch --depth=1 origin +refs/tags/*:refs/tags/*
 
-    - name: Prepare env
-      run: >
-        apt-get update && apt-get install -y python3-dev python3-pip python3-setuptools python3-wheel
-        python3-numpy python3-scipy python3-matplotlib python3-requests python3-networkx
-        python3-pytest python3-pytest-cov python3-flaky
-        --no-install-recommends
+      - name: Prepare env
+        run: >
+          apt-get update && apt-get install -y python3-dev python3-pip python3-setuptools python3-wheel
+          python3-numpy python3-scipy python3-matplotlib python3-requests python3-networkx
+          python3-pytest python3-pytest-cov python3-flaky
+          --no-install-recommends
 
-    - name: Prepare Python env
-      run: |
-        python3 -m pip install -U pip setuptools wheel
-        python3 setup.py gen_reqfile --include-extras=test,azure-quantum,braket
-        cat requirements.txt
-        python3 -m pip install -r requirements.txt --prefer-binary
+      - name: Prepare Python env
+        run: |
+          python3 -m pip install -U pip setuptools wheel
+          python3 setup.py gen_reqfile --include-extras=test,azure-quantum,braket
+          cat requirements.txt
+          python3 -m pip install -r requirements.txt --prefer-binary
 
-    - name: Upgrade pybind11 and flaky
-      run: python3 -m pip install --upgrade pybind11 flaky --prefer-binary
+      - name: Upgrade pybind11 and flaky
+        run: python3 -m pip install --upgrade pybind11 flaky --prefer-binary
 
-    - name: Build and install package
-      run: python3 -m pip install -ve .[azure-quantum,braket,test]
+      - name: Build and install package
+        run: python3 -m pip install -ve .[azure-quantum,braket,test]
 
-    - name: Pytest
-      run: |
-        echo 'backend: Agg' > matplotlibrc
-        python3 -m pytest -p no:warnings
+      - name: Pytest
+        run: |
+          echo 'backend: Agg' > matplotlibrc
+          python3 -m pytest -p no:warnings
 
 
   # Testing on CentOS (manylinux uses a centos base, and this is an easy way
@@ -210,74 +211,74 @@ jobs:
           - 7  # GCC 4.8
           - 8
 
-    name: "🐍 3 • CentOS ${{ matrix.centos }} • x64"
+    name: "Python 3 • CentOS ${{ matrix.centos }} • x64"
     container: "centos:${{ matrix.centos }}"
 
     steps:
-    - name: Enable cache for yum
-      run: echo 'keepcache=1' >> /etc/yum.conf
-
-    - name: Setup yum cache
-      uses: actions/cache@v3
-      with:
-        path: |
-          /var/cache/yum/
-          /var/cache/dnf/
-        key: ${{ runner.os }}-centos${{ matrix.centos }}-yum-${{ secrets.yum_cache }}
-
-    - name: Fix repository URLs (CentOS 8 only)
-      if: matrix.centos == 8
-      run: |
-        sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*
-        sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
-
-    - name: Add Python 3 and other dependencies
-      run: yum update -y && yum install -y python3-devel gcc-c++ make
-
-    - name: Setup Endpoint repository (CentOS 7 only)
-      if: matrix.centos == 7
-      run: yum -y install https://packages.endpointdev.com/rhel/7/os/x86_64/endpoint-repo.x86_64.rpm
-
-    - name: Install Git > 2.18
-      run: |
-        yum install -y git
-        git config --global --add safe.directory /__w/ProjectQ/ProjectQ
-
-    - uses: actions/checkout@v3
-
-    - name: Get history and tags for SCM versioning to work
-      if: ${{ !env.ACT }}
-      run: |
-        git fetch --prune --unshallow
-        git fetch --depth=1 origin +refs/tags/*:refs/tags/*
-
-    - name: Create pip cache dir
-      run: mkdir -p ~/.cache/pip
-
-    - name: Cache wheels
-      uses: actions/cache@v3
-      with:
-        path: ~/.cache/pip
-        key: ${{ runner.os }}-centos${{ matrix.centos }}-pip-${{ hashFiles('**/setup.cfg') }}
-        restore-keys: ${{ runner.os }}-centos-pip-
-
-    - name: Update pip
-      run: python3 -m pip install --upgrade pip
-
-    - name: Install dependencies
-      run: |
-        python3 -m pip install -U pip setuptools wheel
-        python3 setup.py gen_reqfile --include-extras=test,azure-quantum,braket
-        cat requirements.txt
-        python3 -m pip install -r requirements.txt --prefer-binary
-
-    - name: Build and install package
-      run: python3 -m pip install -ve .[azure-quantum,braket,test]
-
-    - name: Pytest
-      run: |
-        echo 'backend: Agg' > matplotlibrc
-        python3 -m pytest -p no:warnings
+      - name: Enable cache for yum
+        run: echo 'keepcache=1' >> /etc/yum.conf
+
+      - name: Setup yum cache
+        uses: actions/cache@v3
+        with:
+          path: |
+            /var/cache/yum/
+            /var/cache/dnf/
+          key: ${{ runner.os }}-centos${{ matrix.centos }}-yum-${{ secrets.yum_cache }}
+
+      - name: Fix repository URLs (CentOS 8 only)
+        if: matrix.centos == 8
+        run: |
+          sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*
+          sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
+
+      - name: Add Python 3 and other dependencies
+        run: yum update -y && yum install -y python3-devel gcc-c++ make
+
+      - name: Setup Endpoint repository (CentOS 7 only)
+        if: matrix.centos == 7
+        run: yum -y install https://packages.endpointdev.com/rhel/7/os/x86_64/endpoint-repo.x86_64.rpm
+
+      - name: Install Git > 2.18
+        run: |
+          yum install -y git
+          git config --global --add safe.directory /__w/ProjectQ/ProjectQ
+
+      - uses: actions/checkout@v3
+
+      - name: Get history and tags for SCM versioning to work
+        if: ${{ !env.ACT }}
+        run: |
+          git fetch --prune --unshallow
+          git fetch --depth=1 origin +refs/tags/*:refs/tags/*
+
+      - name: Create pip cache dir
+        run: mkdir -p ~/.cache/pip
+
+      - name: Cache wheels
+        uses: actions/cache@v3
+        with:
+          path: ~/.cache/pip
+          key: ${{ runner.os }}-centos${{ matrix.centos }}-pip-${{ hashFiles('**/setup.cfg') }}
+          restore-keys: ${{ runner.os }}-centos-pip-
+
+      - name: Update pip
+        run: python3 -m pip install --upgrade pip
+
+      - name: Install dependencies
+        run: |
+          python3 -m pip install -U pip setuptools wheel
+          python3 setup.py gen_reqfile --include-extras=test,azure-quantum,braket
+          cat requirements.txt
+          python3 -m pip install -r requirements.txt --prefer-binary
+
+      - name: Build and install package
+        run: python3 -m pip install -ve .[azure-quantum,braket,test]
+
+      - name: Pytest
+        run: |
+          echo 'backend: Agg' > matplotlibrc
+          python3 -m pytest -p no:warnings
 
 
   documentation:
@@ -285,35 +286,35 @@ jobs:
     runs-on: ubuntu-latest
 
     steps:
-    - uses: actions/checkout@v3
-
-    - name: Create pip cache dir
-      run: mkdir -p ~/.cache/pip
-
-    - name: Cache wheels
-      uses: actions/cache@v3
-      with:
-        path: ~/.cache/pip
-        key: ${{ runner.os }}-doc-pip-${{ hashFiles('**/setup.cfg') }}
-        restore-keys: ${{ runner.os }}-doc-pip-
-
-    - name: Get history and tags for SCM versioning to work
-      if: ${{ !env.ACT }}
-      run: |
-        git fetch --prune --unshallow
-        git fetch --depth=1 origin +refs/tags/*:refs/tags/*
-
-    - uses: actions/setup-python@v4
-      with:
-        python-version: '3.x'
-        architecture: 'x64'
-
-    - name: Install docs & setup requirements
-      run: |
-        python3 -m pip install .[docs]
-
-    - name: Build docs
-      run: python3 -m sphinx -b html docs docs/.build
-
-    - name: Make SDist
-      run: python3 setup.py sdist
+      - uses: actions/checkout@v3
+
+      - name: Create pip cache dir
+        run: mkdir -p ~/.cache/pip
+
+      - name: Cache wheels
+        uses: actions/cache@v3
+        with:
+          path: ~/.cache/pip
+          key: ${{ runner.os }}-doc-pip-${{ hashFiles('**/setup.cfg') }}
+          restore-keys: ${{ runner.os }}-doc-pip-
+
+      - name: Get history and tags for SCM versioning to work
+        if: ${{ !env.ACT }}
+        run: |
+          git fetch --prune --unshallow
+          git fetch --depth=1 origin +refs/tags/*:refs/tags/*
+
+      - uses: actions/setup-python@v4
+        with:
+          python-version: '3.x'
+          architecture: 'x64'
+
+      - name: Install docs & setup requirements
+        run: |
+          python3 -m pip install .[docs]
+
+      - name: Build docs
+        run: python3 -m sphinx -b html docs docs/.build
+
+      - name: Make SDist
+        run: python3 setup.py sdist
diff --git a/.github/workflows/draft_release.yml b/.github/workflows/draft_release.yml
index c4854cd2c..2c54ffd07 100644
--- a/.github/workflows/draft_release.yml
+++ b/.github/workflows/draft_release.yml
@@ -1,3 +1,5 @@
+---
+
 name: "Draft new release"
 
 on:
@@ -11,56 +13,57 @@ jobs:
     name: "Draft a new release"
     runs-on: ubuntu-latest
     steps:
-    - name: Install git-flow
-      run: sudo apt update && sudo apt install -y git-flow
+      - name: Install git-flow
+        run: sudo apt update && sudo apt install -y git-flow
 
-    - uses: actions/checkout@v3
+      - uses: actions/checkout@v3
 
-    - name: Configure git-flow
-      run: |
-        git fetch --tags --depth=1 origin master develop
-        git flow init --default --tag v
+      - name: Configure git-flow
+        run: |
+          git fetch --tags --depth=1 origin master develop
+          git flow init --default --tag v
 
-    - name: Create release branch
-      run: git flow release start ${{ github.event.inputs.tag }}
+      - name: Create release branch
+        run: git flow release start ${{ github.event.inputs.tag }}
 
-    - name: Update changelog
-      uses: thomaseizinger/keep-a-changelog-new-release@1.3.0
-      with:
-        version: ${{ github.event.inputs.tag }}
+      - name: Update changelog
+        uses: thomaseizinger/keep-a-changelog-new-release@1.3.0
+        with:
+          version: ${{ github.event.inputs.tag }}
 
-    - name: Initialize mandatory git config
-      run: |
-        git config user.name "GitHub actions"
-        git config user.email noreply@github.com
+      - name: Initialize mandatory git config
+        run: |
+          git config user.name "GitHub actions"
+          git config user.email noreply@github.com
 
-    - name: Commit changelog and manifest files
-      id: make-commit
-      run: |
-        git add CHANGELOG.md
-        git commit --message "Preparing release ${{ github.event.inputs.tag }}"
+      - name: Commit changelog and manifest files
+        id: make-commit
+        run: |
+          git add CHANGELOG.md
+          git commit --message "Preparing release ${{ github.event.inputs.tag }}"
 
-        echo "::set-output name=commit::$(git rev-parse HEAD)"
+          echo "::set-output name=commit::$(git rev-parse HEAD)"
 
-    - name: Push new branch
-      run: git flow release publish ${{ github.event.inputs.tag }}
+      - name: Push new branch
+        run: git flow release publish ${{ github.event.inputs.tag }}
 
-    - name: Create pull request
-      uses: thomaseizinger/create-pull-request@1.2.2
-      env:
-        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-      with:
-        head: release/${{ github.event.inputs.tag }}
-        base: master
-        title: Release version ${{ github.event.inputs.tag }}
-        reviewers: ${{ github.actor }}
-        # Write a nice message to the user.
-        # We are claiming things here based on the `publish-new-release.yml` workflow.
-        # You should obviously adopt it to say the truth depending on your release workflow :)
-        body: |
-          Hi @${{ github.actor }}!
+      # yamllint disable rule:line-length
+      - name: Create pull request
+        uses: thomaseizinger/create-pull-request@1.2.2
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+        with:
+          head: release/${{ github.event.inputs.tag }}
+          base: master
+          title: Release version ${{ github.event.inputs.tag }}
+          reviewers: ${{ github.actor }}
+          # Write a nice message to the user.
+          # We are claiming things here based on the `publish-new-release.yml` workflow.
+          # You should obviously adopt it to say the truth depending on your release workflow :)
+          body: |
+            Hi @${{ github.actor }}!
 
-          This PR was created in response to a manual trigger of the release workflow here: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}.
-          I've updated the changelog and bumped the versions in the manifest files in this commit: ${{ steps.make-commit.outputs.commit }}.
+            This PR was created in response to a manual trigger of the release workflow here: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}.
+            I've updated the changelog and bumped the versions in the manifest files in this commit: ${{ steps.make-commit.outputs.commit }}.
 
-          Merging this PR will create a GitHub release and upload any assets that are created as part of the release build.
+            Merging this PR will create a GitHub release and upload any assets that are created as part of the release build.
diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml
index 1a3b4cb96..c2ce1e4bf 100644
--- a/.github/workflows/format.yml
+++ b/.github/workflows/format.yml
@@ -1,3 +1,5 @@
+---
+
 name: Format
 
 on:
@@ -5,59 +7,29 @@ on:
   pull_request:
   push:
     branches:
-    - master
-    - stable
-    - "v*"
+      - master
+      - stable
+      - "v*"
 
 jobs:
-  pre-commit:
-    name: Format and static analysis
-    runs-on: ubuntu-latest
-    steps:
-    - uses: actions/checkout@v3
-    - name: Get history and tags for SCM versioning to work
-      if: ${{ !env.ACT }}
-      run: |
-        git fetch --prune --unshallow
-        git fetch --depth=1 origin +refs/tags/*:refs/tags/*
-
-    - uses: actions/setup-python@v4
-      with:
-        python-version: '3.x'
-
-    - name: Install pre-commit
-      run: python3 -m pip install --upgrade pre-commit 'virtualenv!=20.11'
-
-    - name: Cache pre-commit hooks
-      uses: actions/cache@v3
-      with:
-        path: ~/.cache/pre-commit
-        key: pre-commit-${{ hashFiles('**/.pre-commit-config.yaml') }}
-        restore-keys: pre-commit-
-
-    - name: Run pre-commit
-      run: |
-          # Slow hooks are marked with manual - slow is okay here, run them too
-          pre-commit run --hook-stage manual --all-files
-
   clang-tidy:
     name: Clang-Tidy
     runs-on: ubuntu-latest
-    container: silkeh/clang:10
+    container: silkeh/clang:14
     env:
       CC: clang
       CXX: clang++
 
     steps:
-    - uses: actions/checkout@v3
+      - uses: actions/checkout@v3
 
-    - name: Prepare env
-      run: >
-        apt-get update && apt-get install -y python3-dev python3-pip python3-setuptools python3-wheel
-        --no-install-recommends
+      - name: Prepare env
+        run: >
+          apt-get update && apt-get install -y python3-dev python3-pip python3-setuptools python3-wheel
+          --no-install-recommends
 
-    - name: Upgrade pybind11
-      run: python3 -m pip install --upgrade pybind11 --prefer-binary
+      - name: Upgrade pybind11
+        run: python3 -m pip install --upgrade pybind11 --prefer-binary
 
-    - name: Run Clang-Tidy
-      run: python3 setup.py clang_tidy --warning-as-errors
+      - name: Run clang-tidy
+        run: python3 setup.py clang_tidy --warning-as-errors
diff --git a/.github/workflows/publish_release.yml b/.github/workflows/publish_release.yml
index aa88b802a..f6a25fd07 100644
--- a/.github/workflows/publish_release.yml
+++ b/.github/workflows/publish_release.yml
@@ -1,3 +1,5 @@
+---
+
 name: "Publish new release"
 
 on:
@@ -15,7 +17,12 @@ jobs:
   packaging:
     name: Build wheels on ${{ matrix.os }}
     runs-on: ${{ matrix.os }}
-    if: startsWith(github.ref, 'refs/tags/') || (github.event_name == 'pull_request' && github.event.pull_request.merged == true) || github.event_name == 'workflow_dispatch'
+    if: >
+      startsWith(github.ref, 'refs/tags/')
+      || (github.event_name == 'pull_request'
+          && github.event.pull_request.merged == true)
+      || github.event_name == 'workflow_dispatch'
+
     strategy:
       matrix:
         cibw_archs: ["auto64"]
@@ -47,7 +54,10 @@ jobs:
       # ========================================================================
 
       - name: Extract version from branch name (for release branches) (Unix)
-        if:  github.event_name == 'pull_request' && startsWith(github.event.pull_request.head.ref, 'release/') && runner.os != 'Windows'
+        if: >
+          github.event_name == 'pull_request'
+          && startsWith(github.event.pull_request.head.ref, 'release/')
+          && runner.os != 'Windows'
         run: |
           BRANCH_NAME="${{ github.event.pull_request.head.ref }}"
           VERSION=${BRANCH_NAME#release/}
@@ -55,7 +65,10 @@ jobs:
           git tag ${VERSION} master
 
       - name: Extract version from branch name (for hotfix branches) (Unix)
-        if: github.event_name == 'pull_request'  && startsWith(github.event.pull_request.head.ref, 'hotfix/') && runner.os != 'Windows'
+        if: >
+          github.event_name == 'pull_request'
+          && startsWith(github.event.pull_request.head.ref, 'hotfix/')
+          && runner.os != 'Windows'
         run: |
           BRANCH_NAME="${{ github.event.pull_request.head.ref }}"
           VERSION=${BRANCH_NAME#hotfix/}
@@ -65,7 +78,10 @@ jobs:
       # ------------------------------------------------------------------------
 
       - name: Extract version from branch name (for release branches) (Windows)
-        if:  github.event_name == 'pull_request' && startsWith(github.event.pull_request.head.ref, 'release/') && runner.os == 'Windows'
+        if: >
+          github.event_name == 'pull_request'
+          && startsWith(github.event.pull_request.head.ref, 'release/')
+          && runner.os == 'Windows'
         run: |
           $BRANCH_NAME="${{ github.event.pull_request.head.ref }}"
           $VERSION = $BRANCH_NAME -replace "release/",""
@@ -73,7 +89,10 @@ jobs:
           git tag ${VERSION} master
 
       - name: Extract version from branch name (for hotfix branches) (Windows)
-        if: github.event_name == 'pull_request'  && startsWith(github.event.pull_request.head.ref, 'hotfix/') && runner.os == 'Windows'
+        if: >
+          github.event_name == 'pull_request'
+          && startsWith(github.event.pull_request.head.ref, 'hotfix/')
+          && runner.os == 'Windows'
         run: |
           $BRANCH_NAME="${{ github.event.pull_request.head.ref }}"
           $VERSION = $BRANCH_NAME -replace "hotfix/",""
@@ -159,7 +178,7 @@ jobs:
           echo "RELEASE_VERSION=$VERSION" >> $GITHUB_ENV
 
       - name: Extract version from branch name (for release branches)
-        if:  github.event_name == 'pull_request' && startsWith(github.event.pull_request.head.ref, 'release/')
+        if: github.event_name == 'pull_request' && startsWith(github.event.pull_request.head.ref, 'release/')
         run: |
           BRANCH_NAME="${{ github.event.pull_request.head.ref }}"
           VERSION=${BRANCH_NAME#release/v}
@@ -200,12 +219,13 @@ jobs:
       - name: Create release
         env:
           target: x86_64-unknown-linux-musl
-          parse_changelog_tag: v0.3.0
+          source_url: https://github.com/taiki-e/parse-changelog/releases/download
+          parse_changelog_tag: v0.5.1
           changelog: CHANGELOG.md
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
         run: |
           # https://github.com/taiki-e/parse-changelog
-          curl -LsSf "https://github.com/taiki-e/parse-changelog/releases/download/${parse_changelog_tag}/parse-changelog-${target}.tar.gz" | tar xzf -
+          curl -LsSf "${source_url}/${parse_changelog_tag}/parse-changelog-${target}.tar.gz" | tar xzf -
           notes=$(./parse-changelog "${changelog}" "${RELEASE_VERSION}")
           rm -f ./parse-changelog
 
@@ -214,7 +234,10 @@ jobs:
           fi
 
           mkdir -p wheels pypy_wheels
-          gh release create "v${RELEASE_VERSION}" ${prerelease:-} --title "ProjectQ v${RELEASE_VERSION}" --notes "${notes:-}" pypy_wheels/* wheels/*
+          gh release create "v${RELEASE_VERSION}" ${prerelease:-} \
+            --title "ProjectQ v${RELEASE_VERSION}" \
+            --notes "${notes:-}" \
+            pypy_wheels/* wheels/*
 
 
   upload_to_pypi:
@@ -222,18 +245,18 @@ jobs:
     runs-on: ubuntu-latest
     needs: release
     steps:
-    - uses: actions/setup-python@v4
-      with:
-        python-version: '3.x'
+      - uses: actions/setup-python@v4
+        with:
+          python-version: '3.x'
 
-    - uses: actions/download-artifact@v3
+      - uses: actions/download-artifact@v3
 
-    - name: Publish standard package
-      uses: pypa/gh-action-pypi-publish@release/v1
-      with:
-        user: __token__
-        password: ${{ secrets.pypi_password }}
-        packages_dir: pypy_wheels/
+      - name: Publish standard package
+        uses: pypa/gh-action-pypi-publish@release/v1
+        with:
+          user: __token__
+          password: ${{ secrets.pypi_password }}
+          packages_dir: pypy_wheels/
 
   master_to_develop_pr:
     name: Merge master back into develop
@@ -250,6 +273,7 @@ jobs:
           head: master
           base: develop
           title: Merge master into develop branch
+          # yamllint disable rule:line-length
           body: |
             This PR merges the master branch back into develop.
             This happens to ensure that the updates that happend on the release branch, i.e. CHANGELOG and manifest updates are also present on the develop branch.
diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml
index 35eae58cc..9325a3ab6 100644
--- a/.github/workflows/pull_request.yml
+++ b/.github/workflows/pull_request.yml
@@ -1,7 +1,9 @@
+---
+
 name: PR
 on:
   pull_request:
-      types: [opened, synchronize, reopened, ready_for_review, labeled, unlabeled]
+    types: [opened, synchronize, reopened, ready_for_review, labeled, unlabeled]
 
 jobs:
   # Enforces the update of a changelog file on every pull request
@@ -9,10 +11,10 @@ jobs:
     runs-on: ubuntu-latest
     if: github.ref != 'refs/heads/master'
     steps:
-    - uses: actions/checkout@v3
+      - uses: actions/checkout@v3
 
-    - id: changelog-enforcer
-      uses: dangoslen/changelog-enforcer@v3
-      with:
-        changeLogPath: 'CHANGELOG.md'
-        skipLabels: 'Skip-Changelog'
+      - id: changelog-enforcer
+        uses: dangoslen/changelog-enforcer@v3
+        with:
+          changeLogPath: 'CHANGELOG.md'
+          skipLabels: 'Skip-Changelog'
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 7b1ba27a8..729fded8d 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -23,14 +23,16 @@ repos:
       - id: check-useless-excludes
 
   - repo: https://github.com/pre-commit/pre-commit-hooks
-    rev: v4.2.0
+    rev: v4.3.0
     hooks:
       - id: check-added-large-files
+      - id: check-ast
+      - id: check-builtin-literals
       - id: check-case-conflict
       - id: check-merge-conflict
       - id: check-symlinks
-      - id: check-yaml
       - id: check-toml
+      - id: check-yaml
       - id: debug-statements
       - id: end-of-file-fixer
       - id: mixed-line-ending
@@ -38,12 +40,40 @@ repos:
 
   # Changes tabs to spaces
   - repo: https://github.com/Lucas-C/pre-commit-hooks
-    rev: v1.1.13
+    rev: v1.3.1
     hooks:
       - id: remove-tabs
 
+  - repo: https://github.com/pycqa/pydocstyle
+    rev: 6.1.1
+    hooks:
+      - id: pydocstyle
+        exclude: (_test.*\.py)$
+        additional_dependencies: [toml]
+
+  - repo: https://github.com/PyCQA/doc8/
+    rev: v1.0.0
+    hooks:
+      - id: doc8
+        require_serial: false
+        additional_dependencies: [tomli]
+
+  - repo: https://github.com/codespell-project/codespell
+    rev: v2.2.2
+    hooks:
+      - id: codespell
+        require_serial: false
+        files: .*\.(py|txt|cmake|md|rst|sh|ps1|hpp|tpp|cpp|cc)$
+        args: [-S, '.git,third_party', -I, .codespell.allow]
+
+  - repo: https://github.com/adrienverge/yamllint.git
+    rev: v1.28.0
+    hooks:
+      - id: yamllint
+        require_serial: false
+
   - repo: https://github.com/asottile/pyupgrade
-    rev: v2.34.0
+    rev: v3.1.0
     hooks:
       - id: pyupgrade
         args: [--py37-plus, --keep-mock]
@@ -55,19 +85,17 @@ repos:
         name: isort (python)
 
   - repo: https://github.com/psf/black
-    rev: 22.3.0
+    rev: 22.10.0
     hooks:
       - id: black
         language_version: python3
-        # This is a slow hook, so only run this if --hook-stage manual is passed
-        stages: [manual]
 
   - repo: https://github.com/asottile/blacken-docs
     rev: v1.12.1
     hooks:
       - id: blacken-docs
         args: [-S, -l, '120']
-        additional_dependencies: [black==22.3.0]
+        additional_dependencies: [black==22.10.0]
 
   - repo: https://gitlab.com/PyCQA/flake8
     rev: 3.9.2
@@ -85,13 +113,11 @@ repos:
         files: ^(.*_test\.py)$
 
   - repo: https://github.com/pre-commit/mirrors-pylint
-    rev: 'v3.0.0a4'
+    rev: 'v3.0.0a5'
     hooks:
       - id: pylint
         args: ['--score=n']
-        # This is a slow hook, so only run this if --hook-stage manual is passed
-        stages: [manual]
-        additional_dependencies: [pybind11>=2.6, numpy, requests, boto3, matplotlib, networkx, sympy]
+        additional_dependencies: [pybind11>=2.6, numpy, requests, matplotlib, networkx]
 
   - repo: https://github.com/mgedmin/check-manifest
     rev: '0.48'
diff --git a/.readthedocs.yaml b/.readthedocs.yaml
index 9199f30a8..e43492a1b 100644
--- a/.readthedocs.yaml
+++ b/.readthedocs.yaml
@@ -1,3 +1,5 @@
+---
+
 # .readthedocs.yaml
 # Read the Docs configuration file
 # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
@@ -11,8 +13,8 @@ sphinx:
 formats: all
 
 python:
-   version: 3.8
-   install:
+  version: 3.8
+  install:
     - method: pip
       path: .
       extra_requirements:
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100755
index b4ab7159f..000000000
--- a/.travis.yml
+++ /dev/null
@@ -1,76 +0,0 @@
-# ==============================================================================
-
-addons:
-  apt:
-    sources: ['ubuntu-toolchain-r-test']
-    # update: true
-    packages:
-      - gcc-9
-      - g++-9
-      - build-essential
-      - python3
-      - python3-pip
-
-  homebrew:
-    update: false
-
-# ==============================================================================
-
-env:
-  global:
-    - OMP_NUM_THREADS=1
-    - CC=gcc-9
-    - CXX=g++-9
-
-os: linux
-language: python
-
-python:
-  - 3.5
-  - 3.6
-  - 3.7
-  - 3.8
-  - 3.9
-
-jobs:
-  fast_finish: true
-  # Limit the number of builds to use less credits on Travis-CI
-  # include:
-  # - os: osx
-  #   osx_image: xcode12.2
-  #   language: shell
-  #   name: "Mac OS Python Homebrew"
-  #   env: CC=clang CXX=clang++
-  #   before_install:
-  #     - clang++ --version
-  # - os: windows
-  #   name: "Windows Python 3.8"
-  #   language: shell
-  #   before_install:
-  #     - unset CC CXX
-  #     - choco install python3 --version 3.8.8
-  #     - ln -s /c/Python38/python.exe /c/Python38/python3.exe
-  #     - python3 -m pip install --upgrade pip
-  #   env: PATH=/c/Python38:/c/Python38/Scripts:$PATH
-
-# ==============================================================================
-# Installation and testing
-
-install:
-  - env
-  - python3 -m pip install -U pip setuptools wheel
-  - python3 -m pip install -U pybind11 dormouse revkit flaky pytest-cov coveralls boto3
-  - python3 -m pip install -U azure-quantum
-  - python3 -m pip install -r requirements.txt
-  - python3 -m pip install -ve .
-
-before_script:
-  - "echo 'backend: Agg' > matplotlibrc"
-
-script:
-  - python3 -m pytest projectq --cov projectq -p no:warnings
-
-after_success:
-  - coveralls
-
-# ==============================================================================
diff --git a/.yamllint b/.yamllint
new file mode 100644
index 000000000..9770e81ca
--- /dev/null
+++ b/.yamllint
@@ -0,0 +1,8 @@
+---
+
+extends: default
+
+rules:
+  line-length:
+    max: 120
+    level: error
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f3d65056a..b1fae5e28 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,11 +9,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Added
 
--   Python context manager `with flusing(MainEngine()) as eng:`
+-   Python context manager `with flushing(MainEngine()) as eng:`
 
 ### Repository
 
--   Update all GitHub workflow action versions
+-   Update GitHub workflow action versions: `actions/cache@v3`, `actions/checkout@v3`, `actions/setup-python@v4`
+-   Introduce pre-commit CI
+-   Update to clang-tidy 14 in GitHub workflow
+-   Update pre-commit hook versions
+-   Added new pre-commit hooks: `codespell`, `doc8`, `pydocstyle` and `yamllint`
 
 ## [v0.8.0] - 2022-10-18
 
@@ -170,7 +174,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 -   Added CHANGELOG.md
 
 -   Added support for GitHub Actions
-    -   Build and testing on various plaforms and compilers
+    -   Build and testing on various platforms and compilers
     -   Automatic draft of new release
     -   Automatic publication of new release once ready
     -   Automatic upload of releases artifacts to PyPi and GitHub
diff --git a/README.rst b/README.rst
index a2c794bb0..e8451dfae 100755
--- a/README.rst
+++ b/README.rst
@@ -27,7 +27,8 @@ targeting various types of hardware, a high-performance quantum computer
 simulator with emulation capabilities, and various compiler plug-ins.
 This allows users to
 
--  run quantum programs on the IBM Quantum Experience chip, AQT devices, AWS Braket, Azure Quantum, or IonQ service provided devices
+-  run quantum programs on the IBM Quantum Experience chip, AQT devices, AWS Braket, Azure Quantum, or IonQ service
+   provided devices
 -  simulate quantum programs on classical computers
 -  emulate quantum programs at a higher level of abstraction (e.g.,
    mimicking the action of large oracles instead of compiling them to
@@ -58,7 +59,8 @@ Examples
     print(f"Measured {int(qubit)}")  # converting a qubit to int or bool gives access to the measurement result
 
 
-ProjectQ features a lean syntax which is close to the mathematical notation used in quantum physics. For example, a rotation of a qubit around the x-axis is usually specified as:
+ProjectQ features a lean syntax which is close to the mathematical notation used in quantum physics. For example, a
+rotation of a qubit around the x-axis is usually specified as:
 
 .. image:: docs/images/braket_notation.svg
     :alt: Rx(theta)|qubit>
@@ -70,11 +72,14 @@ The same statement in ProjectQ's syntax is:
 
     Rx(theta) | qubit
 
-The **|**-operator separates the specification of the gate operation (left-hand side) from the quantum bits to which the operation is applied (right-hand side).
+The **|**-operator separates the specification of the gate operation (left-hand side) from the quantum bits to which the
+operation is applied (right-hand side).
 
 **Changing the compiler and using a resource counter as a back-end**
 
-Instead of simulating a quantum program, one can use our resource counter (as a back-end) to determine how many operations it would take on a future quantum computer with a given architecture. Suppose the qubits are arranged on a linear chain and the architecture supports any single-qubit gate as well as the two-qubit CNOT and Swap operations:
+Instead of simulating a quantum program, one can use our resource counter (as a back-end) to determine how many
+operations it would take on a future quantum computer with a given architecture. Suppose the qubits are arranged on a
+linear chain and the architecture supports any single-qubit gate as well as the two-qubit CNOT and Swap operations:
 
 .. code-block:: python
 
@@ -106,7 +111,8 @@ Instead of simulating a quantum program, one can use our resource counter (as a
 
 **Running a quantum program on IBM's QE chips**
 
-To run a program on the IBM Quantum Experience chips, all one has to do is choose the `IBMBackend` and the corresponding setup:
+To run a program on the IBM Quantum Experience chips, all one has to do is choose the `IBMBackend` and the corresponding
+setup:
 
 .. code-block:: python
 
@@ -142,9 +148,8 @@ To run a program on the AQT trapped ion quantum computer, choose the `AQTBackend
 
 **Running a quantum program on a AWS Braket provided device**
 
-To run a program on some of the devices provided by the AWS Braket service,
-choose the `AWSBraketBackend`. The currend devices supported are Aspen-8 from Rigetti,
-IonQ from IonQ and the state vector simulator SV1:
+To run a program on some of the devices provided by the AWS Braket service, choose the `AWSBraketBackend`. The currend
+devices supported are Aspen-8 from Rigetti, IonQ from IonQ and the state vector simulator SV1:
 
 .. code-block:: python
 
@@ -190,7 +195,8 @@ IonQ from IonQ and the state vector simulator SV1:
 
 To run a program on devices provided by the `Azure Quantum <https://azure.microsoft.com/en-us/services/quantum/>`_.
 
-Use `AzureQuantumBackend` to run ProjectQ circuits on hardware devices and simulator devices from providers `IonQ` and `Quantinuum`.
+Use `AzureQuantumBackend` to run ProjectQ circuits on hardware devices and simulator devices from providers `IonQ` and
+`Quantinuum`.
 
 .. code-block:: python
 
@@ -248,10 +254,17 @@ Currently available devices are:
 
 **Classically simulate a quantum program**
 
-ProjectQ has a high-performance simulator which allows simulating up to about 30 qubits on a regular laptop. See the `simulator tutorial <https://github.com/ProjectQ-Framework/ProjectQ/blob/feature/update-readme/examples/simulator_tutorial.ipynb>`__ for more information. Using the emulation features of our simulator (fast classical shortcuts), one can easily emulate Shor's algorithm for problem sizes for which a quantum computer would require above 50 qubits, see our `example codes <http://projectq.readthedocs.io/en/latest/examples.html#shor-s-algorithm-for-factoring>`__.
+ProjectQ has a high-performance simulator which allows simulating up to about 30 qubits on a regular laptop. See the
+`simulator tutorial
+<https://github.com/ProjectQ-Framework/ProjectQ/blob/feature/update-readme/examples/simulator_tutorial.ipynb>`__ for
+more information. Using the emulation features of our simulator (fast classical shortcuts), one can easily emulate
+Shor's algorithm for problem sizes for which a quantum computer would require above 50 qubits, see our `example codes
+<http://projectq.readthedocs.io/en/latest/examples.html#shor-s-algorithm-for-factoring>`__.
 
 
-The advanced features of the simulator are also particularly useful to investigate algorithms for the simulation of quantum systems. For example, the simulator can evolve a quantum system in time (without Trotter errors) and it gives direct access to expectation values of Hamiltonians leading to extremely fast simulations of VQE type algorithms:
+The advanced features of the simulator are also particularly useful to investigate algorithms for the simulation of
+quantum systems. For example, the simulator can evolve a quantum system in time (without Trotter errors) and it gives
+direct access to expectation values of Hamiltonians leading to extremely fast simulations of VQE type algorithms:
 
 .. code-block:: python
 
@@ -264,7 +277,7 @@ The advanced features of the simulator are also particularly useful to investiga
     hamiltonian = QubitOperator("X0 X1") + 0.5 * QubitOperator("Y0 Y1")
     # Apply exp(-i * Hamiltonian * time) (without Trotter error)
     TimeEvolution(time=1, hamiltonian=hamiltonian) | wavefunction
-    # Measure the expection value using the simulator shortcut:
+    # Measure the expectation value using the simulator shortcut:
     eng.flush()
     value = eng.backend.get_expectation_value(hamiltonian, wavefunction)
 
@@ -277,17 +290,20 @@ The advanced features of the simulator are also particularly useful to investiga
 Getting started
 ---------------
 
-To start using ProjectQ, simply follow the installation instructions in the `tutorials <http://projectq.readthedocs.io/en/latest/tutorials.html>`__. There, you will also find OS-specific hints, a small introduction to the ProjectQ syntax, and a few `code examples <http://projectq.readthedocs.io/en/latest/examples.html>`__. More example codes and tutorials can be found in the examples folder `here <https://github.com/ProjectQ-Framework/ProjectQ/tree/develop/examples>`__ on GitHub.
+To start using ProjectQ, simply follow the installation instructions in the `tutorials
+<http://projectq.readthedocs.io/en/latest/tutorials.html>`__. There, you will also find OS-specific hints, a small
+introduction to the ProjectQ syntax, and a few `code examples
+<http://projectq.readthedocs.io/en/latest/examples.html>`__. More example codes and tutorials can be found in the
+examples folder `here <https://github.com/ProjectQ-Framework/ProjectQ/tree/develop/examples>`__ on GitHub.
 
-Also, make sure to check out the `ProjectQ
-website <http://www.projectq.ch>`__ and the detailed `code documentation <http://projectq.readthedocs.io/en/latest/>`__.
+Also, make sure to check out the `ProjectQ website <http://www.projectq.ch>`__ and the detailed `code documentation
+<http://projectq.readthedocs.io/en/latest/>`__.
 
 How to contribute
 -----------------
 
-For information on how to contribute, please visit the `ProjectQ
-website <http://www.projectq.ch>`__ or send an e-mail to
-info@projectq.ch.
+For information on how to contribute, please visit the `ProjectQ website <http://www.projectq.ch>`__ or send an e-mail
+to info@projectq.ch.
 
 Please cite
 -----------
@@ -299,8 +315,9 @@ When using ProjectQ for research projects, please cite
    `Quantum 2, 49 (2018) <https://doi.org/10.22331/q-2018-01-31-49>`__
    (published on `arXiv <https://arxiv.org/abs/1612.08091>`__ on 23 Dec 2016)
 -  Thomas Haener, Damian S. Steiger, Krysta M. Svore, and Matthias Troyer
-   "A Software Methodology for Compiling Quantum Programs" `Quantum Sci. Technol. 3 (2018) 020501 <https://doi.org/10.1088/2058-9565/aaa5cc>`__
-   (published on `arXiv <http://arxiv.org/abs/1604.01401>`__ on 5 Apr 2016)
+   "A Software Methodology for Compiling Quantum Programs" `Quantum Sci. Technol. 3 (2018) 020501
+   <https://doi.org/10.1088/2058-9565/aaa5cc>`__ (published on `arXiv <http://arxiv.org/abs/1604.01401>`__ on 5
+   Apr 2016)
 
 Authors
 -------
@@ -313,7 +330,8 @@ in the group of `Prof. Dr. Matthias
 Troyer <http://www.comp.phys.ethz.ch/people/troyer.html>`__ at ETH
 Zurich.
 
-ProjectQ is constantly growing and `many other people <https://github.com/ProjectQ-Framework/ProjectQ/graphs/contributors>`__ have already contributed to it in the meantime.
+ProjectQ is constantly growing and `many other people
+<https://github.com/ProjectQ-Framework/ProjectQ/graphs/contributors>`__ have already contributed to it in the meantime.
 
 License
 -------
diff --git a/docs/README.rst b/docs/README.rst
index 96dacc34e..2521e47ff 100644
--- a/docs/README.rst
+++ b/docs/README.rst
@@ -6,12 +6,15 @@ Documentation
     :alt: Documentation Status
 
 
-Our detailed code documentation can be found online at `Read the Docs <http://projectq.readthedocs.io/en/latest/>`__ and gets updated automatically. Besides the latest code documentation, there are also previous and offline versions available for download.
+Our detailed code documentation can be found online at `Read the Docs <http://projectq.readthedocs.io/en/latest/>`__ and
+gets updated automatically. Besides the latest code documentation, there are also previous and offline versions
+available for download.
 
 Building the docs locally
 -------------------------
 
-Before submitting new code, please make sure that the new or changed docstrings render nicely by building the docs manually. To this end, one has to install sphinx and the Read the Docs theme:
+Before submitting new code, please make sure that the new or changed docstrings render nicely by building the docs
+manually. To this end, one has to install sphinx and the Read the Docs theme:
 
 .. code-block:: bash
 
diff --git a/docs/conf.py b/docs/conf.py
index a9d5efc09..382a41366 100755
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -457,7 +457,7 @@ def linkcode_resolve(domain, info):
     PackageDescription(
         'libs.math',
         desc='''
-A tiny math library which will be extended thoughout the next weeks. Right now, it only contains the math functions
+A tiny math library which will be extended throughout the next weeks. Right now, it only contains the math functions
 necessary to run Beauregard's implementation of Shor's algorithm.
 ''',
     ),
diff --git a/docs/examples.rst b/docs/examples.rst
index 609b8bf90..667f4e7f0 100755
--- a/docs/examples.rst
+++ b/docs/examples.rst
@@ -11,7 +11,8 @@ All of these example codes **and more** can be found on `GitHub <https://github.
 Quantum Random Numbers
 ----------------------
 
-The most basic example is a quantum random number generator (QRNG). It can be found in the examples-folder of ProjectQ. The code looks as follows
+The most basic example is a quantum random number generator (QRNG). It can be found in the examples-folder of
+ProjectQ. The code looks as follows
 
 .. literalinclude:: ../examples/quantum_random_numbers.py
     :tab-width: 2
@@ -27,7 +28,8 @@ Running this code three times may yield, e.g.,
     $ python examples/quantum_random_numbers.py
     Measured: 1
 
-These values are obtained by simulating this quantum algorithm classically. By changing three lines of code, we can run an actual quantum random number generator using the IBM Quantum Experience back-end:
+These values are obtained by simulating this quantum algorithm classically. By changing three lines of code, we can run
+an actual quantum random number generator using the IBM Quantum Experience back-end:
 
 .. code-block:: bash
 
@@ -51,14 +53,19 @@ All you need to do is:
 Quantum Teleportation
 ---------------------
 
-Alice has a qubit in some interesting state :math:`|\psi\rangle`, which she would like to show to Bob. This does not really make sense, since Bob would not be able to look at the qubit without collapsing the superposition; but let's just assume Alice wants to send her state to Bob for some reason.
-What she can do is use quantum teleportation to achieve this task. Yet, this only works if Alice and Bob share a Bell-pair (which luckily happens to be the case). A Bell-pair is a pair of qubits in the state
+Alice has a qubit in some interesting state :math:`|\psi\rangle`, which she would like to show to Bob. This does not
+really make sense, since Bob would not be able to look at the qubit without collapsing the superposition; but let's just
+assume Alice wants to send her state to Bob for some reason.  What she can do is use quantum teleportation to achieve
+this task. Yet, this only works if Alice and Bob share a Bell-pair (which luckily happens to be the case). A Bell-pair
+is a pair of qubits in the state
 
 .. math::
 
     |A\rangle \otimes |B\rangle = \frac 1{\sqrt 2} \left( |0\rangle\otimes|0\rangle + |1\rangle\otimes|1\rangle \right)
 
-They can create a Bell-pair using a very simple circuit which first applies a Hadamard gate to the first qubit, and then flips the second qubit conditional on the first qubit being in :math:`|1\rangle`. The circuit diagram can be generated by calling the function
+They can create a Bell-pair using a very simple circuit which first applies a Hadamard gate to the first qubit, and then
+flips the second qubit conditional on the first qubit being in :math:`|1\rangle`. The circuit diagram can be generated
+by calling the function
 
 .. literalinclude:: ../examples/teleport.py
     :lines: 6,18-25
@@ -82,7 +89,9 @@ The output looks as follows:
     :align: center
 
 
-Now, this Bell-pair can be used to achieve the quantum teleportation: Alice entangles her qubit with her share of the Bell-pair. Then, she measures both qubits; one in the Z-basis (Measure) and one in the Hadamard basis (Hadamard, then Measure). She then sends her measurement results to Bob who, depending on these outcomes, applies a Pauli-X or -Z gate.
+Now, this Bell-pair can be used to achieve the quantum teleportation: Alice entangles her qubit with her share of the
+Bell-pair. Then, she measures both qubits; one in the Z-basis (Measure) and one in the Hadamard basis (Hadamard, then
+Measure). She then sends her measurement results to Bob who, depending on these outcomes, applies a Pauli-X or -Z gate.
 
 The complete example looks as follows:
 
@@ -109,40 +118,56 @@ which produces (after renaming of the qubits inside the tex-file):
 Shor's algorithm for factoring
 ------------------------------
 
-As a third example, consider Shor's algorithm for factoring, which for a given (large) number :math:`N` determines the two prime factor :math:`p_1` and :math:`p_2` such that
-:math:`p_1\cdot p_2 = N` in polynomial time! This is a superpolynomial speed-up over the best known classical algorithm (which is the number field sieve) and enables the breaking of modern encryption schemes such as RSA on a future quantum computer.
+As a third example, consider Shor's algorithm for factoring, which for a given (large) number :math:`N` determines the
+two prime factor :math:`p_1` and :math:`p_2` such that :math:`p_1\cdot p_2 = N` in polynomial time! This is a
+superpolynomial speed-up over the best known classical algorithm (which is the number field sieve) and enables the
+breaking of modern encryption schemes such as RSA on a future quantum computer.
 
 **A tiny bit of number theory**
-    There is a small amount of number theory involved, which reduces the problem of factoring to period-finding of the function
+    There is a small amount of number theory involved, which reduces the problem of factoring to period-finding of the
+    function
 
     .. math::
         f(x) = a^x\operatorname{mod} N
 
-    for some `a` (relative prime to N, otherwise we get a factor right away anyway by calling `gcd(a,N)`). The period `r` for a function `f(x)` is the number for which :math:`f(x) = f(x+r)\forall x` holds. In this case, this means that :math:`a^x = a^{x+r}\;\; (\operatorname{mod} N)\;\forall x`. Therefore, :math:`a^r = 1 + qN` for some integer q and hence, :math:`a^r - 1 = (a^{r/2} - 1)(a^{r/2}+1) = qN`. This suggests that using the gcd on `N` and :math:`a^{r/2} \pm 1` we may find a factor of `N`!
+    for some `a` (relative prime to N, otherwise we get a factor right away anyway by calling `gcd(a,N)`). The period
+    `r` for a function `f(x)` is the number for which :math:`f(x) = f(x+r)\forall x` holds. In this case, this means
+    that :math:`a^x = a^{x+r}\;\; (\operatorname{mod} N)\;\forall x`. Therefore, :math:`a^r = 1 + qN` for some integer q
+    and hence, :math:`a^r - 1 = (a^{r/2} - 1)(a^{r/2}+1) = qN`. This suggests that using the gcd on `N` and
+    :math:`a^{r/2} \pm 1` we may find a factor of `N`!
 
 **Factoring on a quantum computer: An example**
-    At the heart of Shor's algorithm lies modular exponentiation of a classically known constant (denoted by `a` in the code) by a quantum superposition of numbers :math:`x`, i.e.,
+    At the heart of Shor's algorithm lies modular exponentiation of a classically known constant (denoted by `a` in the
+    code) by a quantum superposition of numbers :math:`x`, i.e.,
 
     .. math::
 
         |x\rangle|0\rangle \mapsto |x\rangle|a^x\operatorname{mod} N\rangle
 
-    Using :math:`N=15` and :math:`a=2`, and applying this operation to the uniform superposition over all :math:`x` leads to the superposition (modulo renormalization)
+    Using :math:`N=15` and :math:`a=2`, and applying this operation to the uniform superposition over all :math:`x`
+    leads to the superposition (modulo renormalization)
 
     .. math::
 
         |0\rangle|1\rangle + |1\rangle|2\rangle + |2\rangle|4\rangle + |3\rangle|8\rangle + |4\rangle|1\rangle + |5\rangle|2\rangle + |6\rangle|4\rangle + \cdots
 
-    In Shor's algorithm, the second register will not be touched again before the end of the quantum program, which means it might as well be measured now. Let's assume we measure 2; this collapses the state above to
+    In Shor's algorithm, the second register will not be touched again before the end of the quantum program, which
+    means it might as well be measured now. Let's assume we measure 2; this collapses the state above to
 
     .. math::
 
         |1\rangle|2\rangle + |5\rangle|2\rangle + |9\rangle|2\rangle + \cdots
 
-    The period of `a` modulo `N` can now be read off. On a quantum computer, this information can be accessed by applying an inverse quantum Fourier transform to the x-register, followed by a measurement of x.
+    The period of `a` modulo `N` can now be read off. On a quantum computer, this information can be accessed by
+    applying an inverse quantum Fourier transform to the x-register, followed by a measurement of x.
 
 **Implementation**
-    There is an implementation of Shor's algorithm in the examples folder. It uses the implementation by Beauregard, `arxiv:0205095 <https://arxiv.org/abs/quant-ph/0205095>`_ to factor an n-bit number using 2n+3 qubits. In this implementation, the modular exponentiation is carried out using modular multiplication and shift. Furthermore it uses the semi-classical quantum Fourier transform [see `arxiv:9511007 <https://arxiv.org/abs/quant-ph/9511007>`_]: Pulling the final measurement of the `x`-register through the final inverse quantum Fourier transform allows to run the 2n modular multiplications serially, which keeps one from having to store the 2n qubits of x.
+    There is an implementation of Shor's algorithm in the examples folder. It uses the implementation by Beauregard,
+    `arxiv:0205095 <https://arxiv.org/abs/quant-ph/0205095>`_ to factor an n-bit number using 2n+3 qubits. In this
+    implementation, the modular exponentiation is carried out using modular multiplication and shift. Furthermore it
+    uses the semi-classical quantum Fourier transform [see `arxiv:9511007 <https://arxiv.org/abs/quant-ph/9511007>`_]:
+    Pulling the final measurement of the `x`-register through the final inverse quantum Fourier transform allows to run
+    the 2n modular multiplications serially, which keeps one from having to store the 2n qubits of x.
 
     Let's run it using the ProjectQ simulator:
 
@@ -159,7 +184,9 @@ As a third example, consider Shor's algorithm for factoring, which for a given (
 
         Factors found :-) : 3 * 5 = 15
 
-    Simulating Shor's algorithm at the level of single-qubit gates and CNOTs already takes quite a bit of time for larger numbers than 15. To turn on our **emulation feature**, which does not decompose the modular arithmetic to low-level gates, but carries it out directly instead, we can change the line
+    Simulating Shor's algorithm at the level of single-qubit gates and CNOTs already takes quite a bit of time for
+    larger numbers than 15. To turn on our **emulation feature**, which does not decompose the modular arithmetic to
+    low-level gates, but carries it out directly instead, we can change the line
 
     .. literalinclude:: ../examples/shor.py
         :lineno-start: 86
@@ -168,7 +195,8 @@ As a third example, consider Shor's algorithm for factoring, which for a given (
         :linenos:
         :tab-width: 2
 
-    in examples/shor.py to `return True`. This allows to factor, e.g. :math:`N=4,028,033` in under 3 minutes on a regular laptop!
+    in examples/shor.py to `return True`. This allows to factor, e.g. :math:`N=4,028,033` in under 3 minutes on a
+    regular laptop!
 
     The most important part of the code is
 
@@ -179,4 +207,7 @@ As a third example, consider Shor's algorithm for factoring, which for a given (
         :dedent: 1
         :tab-width: 2
 
-    which executes the 2n modular multiplications conditioned on a control qubit `ctrl_qubit` in a uniform superposition of 0 and 1. The control qubit is then measured after performing the semi-classical inverse quantum Fourier transform and the measurement outcome is saved in the list `measurements`, followed by a reset of the control qubit to state 0.
+    which executes the 2n modular multiplications conditioned on a control qubit `ctrl_qubit` in a uniform superposition
+    of 0 and 1. The control qubit is then measured after performing the semi-classical inverse quantum Fourier transform
+    and the measurement outcome is saved in the list `measurements`, followed by a reset of the control qubit to
+    state 0.
diff --git a/docs/index.rst b/docs/index.rst
index 0c3f5ec4d..6a71e8dc9 100755
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -3,7 +3,9 @@
 ProjectQ
 ========
 
-ProjectQ is an open-source software framework for quantum computing. It aims at providing tools which facilitate **inventing**, **implementing**, **testing**, **debugging**, and **running** quantum algorithms using either classical hardware or actual quantum devices.
+ProjectQ is an open-source software framework for quantum computing. It aims at providing tools which facilitate
+**inventing**, **implementing**, **testing**, **debugging**, and **running** quantum algorithms using either classical
+hardware or actual quantum devices.
 
 The **four core principles** of this open-source effort are
 
@@ -14,8 +16,12 @@ The **four core principles** of this open-source effort are
 
 
 Please cite
-    * Damian S. Steiger, Thomas Häner, and Matthias Troyer "ProjectQ: An Open Source Software Framework for Quantum Computing" `Quantum 2, 49 (2018) <https://doi.org/10.22331/q-2018-01-31-49>`__ (published on `arXiv <https://arxiv.org/abs/1612.08091>`__ on 23 Dec 2016)
-    * Thomas Häner, Damian S. Steiger, Krysta M. Svore, and Matthias Troyer "A Software Methodology for Compiling Quantum Programs" `Quantum Sci. Technol. 3 (2018) 020501 <https://doi.org/10.1088/2058-9565/aaa5cc>`__ (published on `arXiv <http://arxiv.org/abs/1604.01401>`__ on 5 Apr 2016)
+    * Damian S. Steiger, Thomas Häner, and Matthias Troyer "ProjectQ: An Open Source Software Framework for Quantum
+      Computing" `Quantum 2, 49 (2018) <https://doi.org/10.22331/q-2018-01-31-49>`__ (published on `arXiv
+      <https://arxiv.org/abs/1612.08091>`__ on 23 Dec 2016)
+    * Thomas Häner, Damian S. Steiger, Krysta M. Svore, and Matthias Troyer "A Software Methodology for Compiling
+      Quantum Programs" `Quantum Sci. Technol. 3 (2018) 020501 <https://doi.org/10.1088/2058-9565/aaa5cc>`__ (published
+      on `arXiv <http://arxiv.org/abs/1604.01401>`__ on 5 Apr 2016)
 
 
 Contents
diff --git a/docs/projectq.rst b/docs/projectq.rst
index 35a6f7285..ffcb10c26 100755
--- a/docs/projectq.rst
+++ b/docs/projectq.rst
@@ -3,7 +3,8 @@
 Code Documentation
 ==================
 
-Welcome to the package documentation of ProjectQ. You may now browse through the entire documentation and discover the capabilities of the ProjectQ framework.
+Welcome to the package documentation of ProjectQ. You may now browse through the entire documentation and discover the
+capabilities of the ProjectQ framework.
 
 For a detailed documentation of a subpackage or module, click on its name below:
 
diff --git a/docs/tutorials.rst b/docs/tutorials.rst
index bcc7e2d67..3fba8c9da 100755
--- a/docs/tutorials.rst
+++ b/docs/tutorials.rst
@@ -15,21 +15,30 @@ To start using ProjectQ, simply run
 
     python -m pip install --user projectq
 
-Since version 0.6.0, ProjectQ is available as pre-compiled binary wheels in addition to the traditional source package. These wheels should work on most platforms, provided that your processor supports AVX2 instructions. Should you encounter any troubles while installation ProjectQ in binary form, you can always try tom compile the project manually as described below. You may want to pass the `--no-binary projectq` flag to Pip during the installation to make sure that you are downloading the source package.
+Since version 0.6.0, ProjectQ is available as pre-compiled binary wheels in addition to the traditional source
+package. These wheels should work on most platforms, provided that your processor supports AVX2 instructions. Should you
+encounter any troubles while installation ProjectQ in binary form, you can always try tom compile the project manually
+as described below. You may want to pass the `--no-binary projectq` flag to Pip during the installation to make sure
+that you are downloading the source package.
 
-Alternatively, you can also `clone/download <https://github.com/projectq-framework>`_ this repository (e.g., to your /home directory) and run
+Alternatively, you can also `clone/download <https://github.com/projectq-framework>`_ this repository (e.g., to
+your /home directory) and run
 
 .. code-block:: bash
 
     cd /home/projectq
     python -m pip install --user .
 
-ProjectQ comes with a high-performance quantum simulator written in C++. Please see the detailed OS specific installation instructions below to make sure that you are installing the fastest version.
+ProjectQ comes with a high-performance quantum simulator written in C++. Please see the detailed OS specific
+installation instructions below to make sure that you are installing the fastest version.
 
 .. note::
-    The setup will try to build a C++-Simulator, which is much faster than the Python implementation. If the C++ compilation were to fail, the setup will install a pure Python implementation of the simulator instead. The Python simulator should work fine for small examples (e.g., running Shor's algorithm for factoring 15 or 21).
+    The setup will try to build a C++-Simulator, which is much faster than the Python implementation. If the C++
+    compilation were to fail, the setup will install a pure Python implementation of the simulator instead. The Python
+    simulator should work fine for small examples (e.g., running Shor's algorithm for factoring 15 or 21).
 
-    If you want to skip the installation of the C++-Simulator altogether, you can define the ``PROJECTQ_DISABLE_CEXT`` environment variable to avoid any compilation steps.
+    If you want to skip the installation of the C++-Simulator altogether, you can define the ``PROJECTQ_DISABLE_CEXT``
+    environment variable to avoid any compilation steps.
 
 .. note::
     If building the C++-Simulator does not work out of the box, consider specifying a different compiler. For example:
@@ -41,14 +50,20 @@ ProjectQ comes with a high-performance quantum simulator written in C++. Please
     Please note that the compiler you specify must support at least **C++11**!
 
 .. note::
-    Please use pip version v6.1.0 or higher as this ensures that dependencies are installed in the `correct order <https://pip.pypa.io/en/stable/reference/pip_install/#installation-order>`_.
+    Please use pip version v6.1.0 or higher as this ensures that dependencies are installed in the `correct order
+    <https://pip.pypa.io/en/stable/reference/pip_install/#installation-order>`_.
 
 .. note::
-    ProjectQ should be installed on each computer individually as the C++ simulator compilation creates binaries which are optimized for the specific hardware on which it is being installed (potentially using our AVX version and `-march=native`). Therefore, sharing the same ProjectQ installation across different hardware may cause some problems.
+    ProjectQ should be installed on each computer individually as the C++ simulator compilation creates binaries which
+    are optimized for the specific hardware on which it is being installed (potentially using our AVX version and
+    `-march=native`). Therefore, sharing the same ProjectQ installation across different hardware may cause some
+    problems.
 
 **Install AWS Braket Backend requirement**
 
-AWS Braket Backend requires the use of the official AWS SDK for Python, Boto3. This is an extra requirement only needed if you plan to use the AWS Braket Backend. To install ProjectQ inluding this requirement you can include it in the installation instruction as
+AWS Braket Backend requires the use of the official AWS SDK for Python, Boto3. This is an extra requirement only needed
+if you plan to use the AWS Braket Backend. To install ProjectQ including this requirement you can include it in the
+installation instruction as
 
 .. code-block:: bash
 
@@ -56,7 +71,9 @@ AWS Braket Backend requires the use of the official AWS SDK for Python, Boto3. T
 
 **Install Azure Quantum Backend requirement**
 
-Azure Quantum Backend requires the use of the official `Azure Quantum SDK <https://github.com/microsoft/qdk-python>`_ for Python. This is an extra requirement only needed if you plan to use the Azure Quantum Backend. To install ProjectQ inluding this requirement you can include it in the installation instruction as
+Azure Quantum Backend requires the use of the official `Azure Quantum SDK <https://github.com/microsoft/qdk-python>`_
+for Python. This is an extra requirement only needed if you plan to use the Azure Quantum Backend. To install ProjectQ
+including this requirement you can include it in the installation instruction as
 
 .. code-block:: bash
 
@@ -114,16 +131,24 @@ Detailed instructions and OS-specific hints
 
 **Windows**:
 
-    It is easiest to install a pre-compiled version of Python, including numpy and many more useful packages. One way to do so is using, e.g., the Python 3.7 installers from `python.org <https://www.python.org/downloads>`_ or `ANACONDA <https://www.continuum.io/downloads>`_. Installing ProjectQ right away will succeed for the (slow) Python simulator. For a compiled version of the simulator, install the Visual C++ Build Tools and the Microsoft Windows SDK prior to doing a pip install. The built simulator will not support multi-threading due to the limited OpenMP support of the Visual Studio compiler.
+    It is easiest to install a pre-compiled version of Python, including numpy and many more useful packages. One way to
+    do so is using, e.g., the Python 3.7 installers from `python.org <https://www.python.org/downloads>`_ or `ANACONDA
+    <https://www.continuum.io/downloads>`_. Installing ProjectQ right away will succeed for the (slow) Python
+    simulator. For a compiled version of the simulator, install the Visual C++ Build Tools and the Microsoft Windows SDK
+    prior to doing a pip install. The built simulator will not support multi-threading due to the limited OpenMP support
+    of the Visual Studio compiler.
 
-    If the Python executable is added to your PATH (option normally suggested at the end of the Python installation procedure), you can then open a cmdline window (WIN + R, type "cmd" and click *OK*) and enter the following in order to install ProjectQ:
+    If the Python executable is added to your PATH (option normally suggested at the end of the Python installation
+    procedure), you can then open a cmdline window (WIN + R, type "cmd" and click *OK*) and enter the following in order
+    to install ProjectQ:
 
     .. code-block:: batch
 
         python -m pip install --user projectq
 
 
-    Should you want to run multi-threaded simulations, you can install a compiler which supports newer OpenMP versions, such as MinGW GCC and then manually build the C++ simulator with OpenMP enabled.
+    Should you want to run multi-threaded simulations, you can install a compiler which supports newer OpenMP versions,
+    such as MinGW GCC and then manually build the C++ simulator with OpenMP enabled.
 
 
 **macOS**:
@@ -135,7 +160,8 @@ Detailed instructions and OS-specific hints
         python3 -m pip install --user projectq
 
 
-    In order to install the fast C++ simulator, we require that a C++ compiler is installed on your system. There are essentially three options you can choose from:
+    In order to install the fast C++ simulator, we require that a C++ compiler is installed on your system. There are
+    essentially three options you can choose from:
 
     1. Using the compiler provided by Apple through the XCode command line tools.
     2. Using Homebrew
@@ -152,7 +178,9 @@ Detailed instructions and OS-specific hints
 
         xcode-select --install
 
-    Next, you will need to install Python and pip. See options 2 and 3 for information on how to install a newer python version with either Homebrew or MacPorts. Here, we are using the standard python which is preinstalled with macOS. Pip can be installed by:
+    Next, you will need to install Python and pip. See options 2 and 3 for information on how to install a newer python
+    version with either Homebrew or MacPorts. Here, we are using the standard python which is preinstalled with
+    macOS. Pip can be installed by:
 
     .. code-block:: bash
 
@@ -189,7 +217,8 @@ Detailed instructions and OS-specific hints
 
     **MacPorts**
 
-    Visit `macports.org <https://www.macports.org/install.php>`_ and install the latest version that corresponds to your operating system's version. Afterwards, open a new terminal window.
+    Visit `macports.org <https://www.macports.org/install.php>`_ and install the latest version that corresponds to your
+    operating system's version. Afterwards, open a new terminal window.
 
     Then, use macports to install Python 3.7 by entering the following command
 
@@ -209,7 +238,9 @@ Detailed instructions and OS-specific hints
 
         sudo port install py37-pip
 
-    Next, we can install ProjectQ with the high performance simulator written in C++. First, we will need to install a suitable compiler with support for **C++11**, OpenMP, and instrinsics. The best option is to install clang 9.0 also using macports (note: gcc installed via macports does not work).
+    Next, we can install ProjectQ with the high performance simulator written in C++. First, we will need to install a
+    suitable compiler with support for **C++11**, OpenMP, and instrinsics. The best option is to install clang 9.0 also
+    using macports (note: gcc installed via macports does not work).
 
     .. code-block:: bash
 
@@ -225,7 +256,8 @@ Detailed instructions and OS-specific hints
 The ProjectQ syntax
 -------------------
 
-Our goal is to have an intuitive syntax in order to enable an easy learning curve. Therefore, ProjectQ features a lean syntax which is close to the mathematical notation used in physics.
+Our goal is to have an intuitive syntax in order to enable an easy learning curve. Therefore, ProjectQ features a lean
+syntax which is close to the mathematical notation used in physics.
 
 For example, consider applying an x-rotation by an angle `theta` to a qubit. In ProjectQ, this looks as follows:
 
@@ -237,12 +269,16 @@ whereas the corresponding notation in physics would be
 
 :math:`R_x(\theta) \; |\text{qubit}\rangle`
 
-Moreover, the `|`-operator separates the classical arguments (on the left) from the quantum arguments (on the right). Next, you will see a basic quantum program using this syntax. Further examples can be found in the docs (`Examples` in the panel on the left) and in the ProjectQ examples folder on `GitHub <https://github.com/ProjectQ-Framework/ProjectQ>`_.
+Moreover, the `|`-operator separates the classical arguments (on the left) from the quantum arguments (on the
+right). Next, you will see a basic quantum program using this syntax. Further examples can be found in the docs
+(`Examples` in the panel on the left) and in the ProjectQ examples folder on `GitHub
+<https://github.com/ProjectQ-Framework/ProjectQ>`_.
 
 Basic quantum program
 ---------------------
 
-To check out the ProjectQ syntax in action and to see whether the installation worked, try to run the following basic example
+To check out the ProjectQ syntax in action and to see whether the installation worked, try to run the following basic
+example
 
 .. code-block:: python
 
diff --git a/examples/README.rst b/examples/README.rst
index 14ff5190e..821663817 100644
--- a/examples/README.rst
+++ b/examples/README.rst
@@ -1,32 +1,48 @@
 Examples and Tutorials
 ======================
 
-This folder contains a collection of **examples** and **tutorials** for how to use ProjectQ. They offer a great way to get started. While this collection is growing, it will never be possible to cover everything. Therefore, we refer the readers to also have a look at:
+This folder contains a collection of **examples** and **tutorials** for how to use ProjectQ. They offer a great way to
+get started. While this collection is growing, it will never be possible to cover everything. Therefore, we refer the
+readers to also have a look at:
 
-* Our complete **code documentation** which can be found online `here <http://projectq.readthedocs.io/en/latest/>`__. Besides the newest version of the documentation it also provides older versions. Moreover, these docs can be downloaded for offline usage.
+* Our complete **code documentation** which can be found online `here
+  <http://projectq.readthedocs.io/en/latest/>`__. Besides the newest version of the documentation it also provides older
+  versions. Moreover, these docs can be downloaded for offline usage.
 
-* Our **unit tests**. More than 99% of all lines of code are covered with various unit tests since the first release. Tests are really important to us. Therefore, if you are wondering how a specific feature can be used, have a look at the **unit tests**, where you can find plenty of examples. Finding the unit tests is very easy: E.g., the tests of the simulator implemented in *ProjectQ/projectq/backends/_sim/_simulator.py* can all be found in the same folder in the file *ProjectQ/projectq/backends/_sim/_simulator_test.py*.
+* Our **unit tests**. More than 99% of all lines of code are covered with various unit tests since the first
+  release. Tests are really important to us. Therefore, if you are wondering how a specific feature can be used, have a
+  look at the **unit tests**, where you can find plenty of examples. Finding the unit tests is very easy: E.g., the
+  tests of the simulator implemented in *ProjectQ/projectq/backends/_sim/_simulator.py* can all be found in the same
+  folder in the file *ProjectQ/projectq/backends/_sim/_simulator_test.py*.
 
 Getting started / background information
 ----------------------------------------
 
-It might be a good starting point to have a look at our paper which explains the goals of the ProjectQ framework and also gives a good overview:
+It might be a good starting point to have a look at our paper which explains the goals of the ProjectQ framework and
+also gives a good overview:
 
-* Damian S. Steiger, Thomas Häner, and Matthias Troyer "ProjectQ: An Open Source Software Framework for Quantum Computing" `Quantum 2, 49 (2018) <https://doi.org/10.22331/q-2018-01-31-49>`__ (published on `arXiv <https://arxiv.org/abs/1612.08091>`__ on 23 Dec 2016)
+* Damian S. Steiger, Thomas Häner, and Matthias Troyer "ProjectQ: An Open Source Software Framework for Quantum
+  Computing" `Quantum 2, 49 (2018) <https://doi.org/10.22331/q-2018-01-31-49>`__ (published on `arXiv
+  <https://arxiv.org/abs/1612.08091>`__ on 23 Dec 2016)
 
 Our second paper looks at a few aspects of ProjectQ in more details:
 
-* Damian S. Steiger, Thomas Häner, and Matthias Troyer "Advantages of a modular high-level quantum programming framework" `[arxiv:1806.01861] <https://arxiv.org/abs/1806.01861>`__
+* Damian S. Steiger, Thomas Häner, and Matthias Troyer "Advantages of a modular high-level quantum programming
+  framework" `[arxiv:1806.01861] <https://arxiv.org/abs/1806.01861>`__
 
 Examples and tutorials in this folder
 -------------------------------------
 
-1. Some of the files in this folder are explained in the `documentation <http://projectq.readthedocs.io/en/latest/examples.html>`__.
+1. Some of the files in this folder are explained in the `documentation
+   <http://projectq.readthedocs.io/en/latest/examples.html>`__.
 
-2. Take a look at the *simulator_tutorial.ipynb* for a detailed introduction to most of the features of our high performance quantum simulator.
+2. Take a look at the *simulator_tutorial.ipynb* for a detailed introduction to most of the features of our high
+   performance quantum simulator.
 
 3. Running on the IBM QE chip is explained in more details in *ibm_entangle.ipynb*.
 
-4. A small tutorial on the compiler is available in *compiler_tutorial.ipynb* which explains how to compile to a specific gate set.
+4. A small tutorial on the compiler is available in *compiler_tutorial.ipynb* which explains how to compile to a
+   specific gate set.
 
-5. A small tutorial on the mappers is available in *mapper_tutorial.ipynb* which explains how to map a quantum circuit to a linear chain or grid of physical qubits.
+5. A small tutorial on the mappers is available in *mapper_tutorial.ipynb* which explains how to map a quantum circuit
+   to a linear chain or grid of physical qubits.
diff --git a/projectq/__init__.py b/projectq/__init__.py
index 2da4bc1f8..430859a3a 100755
--- a/projectq/__init__.py
+++ b/projectq/__init__.py
@@ -12,7 +12,7 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 """
-ProjectQ - An open source software framework for quantum computing
+ProjectQ - An open source software framework for quantum computing.
 
 Get started:
     Simply import the main compiler engine (from projectq import MainEngine)
diff --git a/projectq/backends/_aqt/__init__.py b/projectq/backends/_aqt/__init__.py
index d971c1b35..37d42fcd9 100644
--- a/projectq/backends/_aqt/__init__.py
+++ b/projectq/backends/_aqt/__init__.py
@@ -12,6 +12,6 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 
-"""ProjectQ module for supporting the AQT platform"""
+"""ProjectQ module for supporting the AQT platform."""
 
 from ._aqt import AQTBackend
diff --git a/projectq/backends/_aqt/_aqt.py b/projectq/backends/_aqt/_aqt.py
index cb1993099..9d5e5e2fe 100644
--- a/projectq/backends/_aqt/_aqt.py
+++ b/projectq/backends/_aqt/_aqt.py
@@ -233,7 +233,7 @@ def _run(self):
         # NOTE AQT DOESN'T SEEM TO HAVE MEASUREMENT INSTRUCTIONS (no
         # intermediate measurements are allowed, so implicit at the end)
         # return if no operations.
-        if self._circuit == []:
+        if not self._circuit:
             return
 
         n_qubit = max(self._allocated_qubits) + 1
diff --git a/projectq/backends/_aqt/_aqt_http_client.py b/projectq/backends/_aqt/_aqt_http_client.py
index ac1a5094c..a545ab2d0 100644
--- a/projectq/backends/_aqt/_aqt_http_client.py
+++ b/projectq/backends/_aqt/_aqt_http_client.py
@@ -206,7 +206,7 @@ def send(
     verbose=False,
 ):  # pylint: disable=too-many-arguments
     """
-    Send cicruit through the AQT API and runs the quantum circuit.
+    Send circuit through the AQT API and runs the quantum circuit.
 
     Args:
         info(dict): Contains representation of the circuit to run.
@@ -233,7 +233,7 @@ def send(
         online = aqt_session.is_online(device)
         # useless for the moment
         if not online:  # pragma: no cover
-            print("The device is offline (for maintenance?). Use the " "simulator instead or try again later.")
+            print("The device is offline (for maintenance?). Use the simulator instead or try again later.")
             raise DeviceOfflineError("Device is offline.")
 
         # check if the device has enough qubit to run the code
diff --git a/projectq/backends/_awsbraket/__init__.py b/projectq/backends/_awsbraket/__init__.py
index 7e2ed0f91..985fc1b10 100644
--- a/projectq/backends/_awsbraket/__init__.py
+++ b/projectq/backends/_awsbraket/__init__.py
@@ -12,16 +12,17 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 
-"""ProjectQ module for supporting the AWS Braket platform"""
+"""ProjectQ module for supporting the AWS Braket platform."""
 
 try:
     from ._awsbraket import AWSBraketBackend
 except ImportError:  # pragma: no cover
 
     class AWSBraketBackend:  # pylint: disable=too-few-public-methods
-        """Dummy class"""
+        """Dummy class."""
 
         def __init__(self, *args, **kwargs):
+            """Initialize dummy class."""
             raise RuntimeError(
                 "Failed to import one of the dependencies required to use "
                 "the Amazon Braket Backend.\n"
diff --git a/projectq/backends/_awsbraket/_awsbraket.py b/projectq/backends/_awsbraket/_awsbraket.py
index 56f1a4be6..78fe5bd01 100755
--- a/projectq/backends/_awsbraket/_awsbraket.py
+++ b/projectq/backends/_awsbraket/_awsbraket.py
@@ -137,7 +137,7 @@ def is_available(self, cmd):  # pylint: disable=too-many-return-statements,too-m
 
         Depending on the device chosen, the operations available differ.
 
-        The operations avialable for the Aspen-8 Rigetti device are:
+        The operations available for the Aspen-8 Rigetti device are:
         - "cz" = Control Z, "xy" = Not available in ProjectQ, "ccnot" = Toffoli (ie. controlled CNOT), "cnot" =
           Control X, "cphaseshift" = Control R, "cphaseshift00" "cphaseshift01" "cphaseshift10" = Not available
           in ProjectQ,
@@ -349,7 +349,7 @@ def get_probabilities(self, qureg):
             Only call this function after the circuit has been executed!
 
             This is maintained in the same form of IBM and AQT for compatibility but in AWSBraket, a previously
-            executed circuit will store the results in the S3 bucket and it can be retreived at any point in time
+            executed circuit will store the results in the S3 bucket and it can be retrieved at any point in time
             thereafter.
             No circuit execution should be required at the time of retrieving the results and probabilities if the
             circuit has already been executed.
diff --git a/projectq/backends/_awsbraket/_awsbraket_boto3_client.py b/projectq/backends/_awsbraket/_awsbraket_boto3_client.py
index bc7d531a4..7924a40b8 100755
--- a/projectq/backends/_awsbraket/_awsbraket_boto3_client.py
+++ b/projectq/backends/_awsbraket/_awsbraket_boto3_client.py
@@ -73,7 +73,7 @@ def get_list_devices(self, verbose=False):
         Get the list of available devices with their basic properties.
 
         Args:
-            verbose (bool): print the returned dictionnary if True
+            verbose (bool): print the returned dictionary if True
 
         Returns:
             (dict) backends dictionary by deviceName, containing the qubit size 'nq', the coupling map 'coupling_map'
@@ -112,8 +112,7 @@ def get_list_devices(self, verbose=False):
                             'GateModelParameters'
                         ]['properties']['braketSchemaHeader']['const'],
                     }
-                # Unfortunatelly the Capabilities schemas are not homogeneus
-                # for real devices and simulators
+                # Unfortunately the Capabilities schemas are not homogeneus for real devices and simulators
                 elif result['deviceType'] == 'SIMULATOR':
                     device_capabilities = json.loads(
                         client.get_device(deviceArn=result['deviceArn'])['deviceCapabilities']
@@ -301,7 +300,7 @@ def _calculate_measurement_probs(measurements):
                 # number by default.
                 # For QPU devices the job is always queued and there are some
                 # working hours available.
-                # In addition the results and state is writen in the
+                # In addition the results and state is written in the
                 # results.json file in the S3 Bucket and does not depend on the
                 # status of the device
 
@@ -339,7 +338,8 @@ def retrieve(credentials, task_arn, num_retries=30, interval=1, verbose=False):
 
     Args:
         credentials (dict): Dictionary storing the AWS credentials with keys AWS_ACCESS_KEY_ID and AWS_SECRET_KEY.
-        task_arn (str): The Arn of the task to retreive
+        task_arn (str): The Arn of the task to retrieve
+
 
     Returns:
         (dict) measurement probabilities from the result stored in the S3 folder
@@ -365,7 +365,7 @@ def send(  # pylint: disable=too-many-branches,too-many-arguments,too-many-local
     info, device, credentials, s3_folder, num_retries=30, interval=1, verbose=False
 ):
     """
-    Send cicruit through the Boto3 SDK and runs the quantum circuit.
+    Send circuit through the Boto3 SDK and runs the quantum circuit.
 
     Args:
         info(dict): Contains representation of the circuit to run.
@@ -391,7 +391,7 @@ def send(  # pylint: disable=too-many-branches,too-many-arguments,too-many-local
         awsbraket_session.get_list_devices(verbose)
         online = awsbraket_session.is_online(device)
         if online:
-            print("The job will be queued in any case, plase take this into account")
+            print("The job will be queued in any case, please take this into account")
         else:
             print("The device is not available. Use the simulator instead or try another device.")
             raise DeviceOfflineError("Device is not available.")
@@ -423,7 +423,7 @@ def send(  # pylint: disable=too-many-branches,too-many-arguments,too-many-local
         if error_code == 'DeviceOfflineException':
             print("- There was an error: the device is offline")
         if error_code == 'InternalServiceException':
-            print("- There was an interal Bracket service error")
+            print("- There was an internal Bracket service error")
         if error_code == 'ServiceQuotaExceededException':
             print("- There was an error: the quota on Braket was exceed")
         if error_code == 'ValidationException':
diff --git a/projectq/backends/_azure/__init__.py b/projectq/backends/_azure/__init__.py
index 8c06e2392..23d2cb3c8 100644
--- a/projectq/backends/_azure/__init__.py
+++ b/projectq/backends/_azure/__init__.py
@@ -19,9 +19,10 @@
 except ImportError:  # pragma: no cover
 
     class AzureQuantumBackend:
-        """Dummy class"""
+        """Dummy class."""
 
         def __init__(self, *args, **kwargs):
+            """Initialize dummy class."""
             raise ImportError(
                 "Missing optional 'azure-quantum' dependencies. To install run: pip install projectq[azure-quantum]"
             )
diff --git a/projectq/backends/_azure/_azure_quantum.py b/projectq/backends/_azure/_azure_quantum.py
index e8187c87c..682caa69d 100644
--- a/projectq/backends/_azure/_azure_quantum.py
+++ b/projectq/backends/_azure/_azure_quantum.py
@@ -292,7 +292,7 @@ def _input_data(self):
 
             for measured_id in self._measured_ids:
                 qb_loc = self.main_engine.mapper.current_mapping[measured_id]
-                measurement_gates += "measure q[{0}] -> c[{0}];\n".format(qb_loc)
+                measurement_gates += f"measure q[{qb_loc}] -> c[{qb_loc}];\n"
 
             return (
                 f"OPENQASM 2.0;\ninclude \"qelib1.inc\";\nqreg q[{qubits}];\ncreg c[{qubits}];"
diff --git a/projectq/backends/_circuits/__init__.py b/projectq/backends/_circuits/__init__.py
index eaf0abb56..62dd8861a 100755
--- a/projectq/backends/_circuits/__init__.py
+++ b/projectq/backends/_circuits/__init__.py
@@ -12,7 +12,7 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 
-"""ProjectQ module for exporting/printing quantum circuits"""
+"""ProjectQ module for exporting/printing quantum circuits."""
 
 from ._drawer import CircuitDrawer
 from ._drawer_matplotlib import CircuitDrawerMatplotlib
diff --git a/projectq/backends/_circuits/_to_latex.py b/projectq/backends/_circuits/_to_latex.py
index 45499526a..c2f870b7d 100755
--- a/projectq/backends/_circuits/_to_latex.py
+++ b/projectq/backends/_circuits/_to_latex.py
@@ -447,6 +447,7 @@ def _sqrtswap_gate(self, lines, ctrl_lines, daggered):  # pylint: disable=too-ma
         # add a circled 1/2
         midpoint = (lines[0] + lines[1]) / 2.0
         pos = self.pos[lines[0]]
+        # pylint: disable=consider-using-f-string
         op_mid = f"line{'{}-{}'.format(*lines)}_gate{self.op_count[lines[0]]}"
         dagger = '^{{\\dagger}}' if daggered else ''
         gate_str += f"\n\\node[xstyle] ({op}) at ({pos},-{midpoint}){{\\scriptsize $\\frac{{1}}{{2}}{dagger}$}};"
diff --git a/projectq/backends/_ibm/__init__.py b/projectq/backends/_ibm/__init__.py
index db7bbddb4..254142fbc 100755
--- a/projectq/backends/_ibm/__init__.py
+++ b/projectq/backends/_ibm/__init__.py
@@ -12,6 +12,6 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 
-"""ProjectQ module for supporting the IBM QE platform"""
+"""ProjectQ module for supporting the IBM QE platform."""
 
 from ._ibm import IBMBackend
diff --git a/projectq/backends/_ibm/_ibm_http_client.py b/projectq/backends/_ibm/_ibm_http_client.py
index 400e235ee..815a04626 100755
--- a/projectq/backends/_ibm/_ibm_http_client.py
+++ b/projectq/backends/_ibm/_ibm_http_client.py
@@ -51,7 +51,7 @@ def get_list_devices(self, verbose=False):
         Get the list of available IBM backends with their properties.
 
         Args:
-            verbose (bool): print the returned dictionnary if True
+            verbose (bool): print the returned dictionary if True
 
         Returns:
             (dict) backends dictionary by name device, containing the qubit size 'nq', the coupling map 'coupling_map'
diff --git a/projectq/backends/_ionq/__init__.py b/projectq/backends/_ionq/__init__.py
index 9f1b6b9ea..8d132eaf8 100644
--- a/projectq/backends/_ionq/__init__.py
+++ b/projectq/backends/_ionq/__init__.py
@@ -12,7 +12,7 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 
-"""ProjectQ module for supporting the IonQ platform"""
+"""ProjectQ module for supporting the IonQ platform."""
 
 from ._ionq import IonQBackend
 
diff --git a/projectq/backends/_ionq/_ionq.py b/projectq/backends/_ionq/_ionq.py
index 392864461..cd70b75a0 100644
--- a/projectq/backends/_ionq/_ionq.py
+++ b/projectq/backends/_ionq/_ionq.py
@@ -96,7 +96,7 @@ def __init__(
                 ``'ionq_simulator'``.  Defaults to ``'ionq_simulator'``.
             num_retries (int, optional): Number of times to retry fetching a job after it has been submitted. Defaults
                 to 3000.
-            interval (int, optional): Number of seconds to wait inbetween result fetch retries. Defaults to 1.
+            interval (int, optional): Number of seconds to wait in between result fetch retries. Defaults to 1.
             retrieve_execution (str, optional): An IonQ API Job ID.  If provided, a job with this ID will be
                 fetched. Defaults to None.
         """
@@ -138,7 +138,7 @@ def is_available(self, cmd):
         if 0 < num_ctrl_qubits <= 7:
             return isinstance(gate, (XGate,))
 
-        # Gates witout control bits.
+        # Gates without control bits.
         if num_ctrl_qubits == 0:
             supported = isinstance(gate, SUPPORTED_GATES)
             supported_transpose = gate in (Sdag, Tdag)
diff --git a/projectq/backends/_ionq/_ionq_http_client.py b/projectq/backends/_ionq/_ionq_http_client.py
index b7f90cd82..72e16555f 100644
--- a/projectq/backends/_ionq/_ionq_http_client.py
+++ b/projectq/backends/_ionq/_ionq_http_client.py
@@ -339,7 +339,7 @@ def send(
 
         # useless for the moment
         if not online:  # pragma: no cover
-            print("The device is offline (for maintenance?). Use the " "simulator instead or try again later.")
+            print("The device is offline (for maintenance?). Use the simulator instead or try again later.")
             raise DeviceOfflineError("Device is offline.")
 
         # check if the device has enough qubit to run the code
diff --git a/projectq/backends/_resource.py b/projectq/backends/_resource.py
index ec741746c..fa73d74e6 100755
--- a/projectq/backends/_resource.py
+++ b/projectq/backends/_resource.py
@@ -14,7 +14,7 @@
 """
 Contain a compiler engine to calculate resource count used by a quantum circuit.
 
-A resrouce counter compiler engine counts the number of calls for each type of gate used in a circuit, in addition to
+A resource counter compiler engine counts the number of calls for each type of gate used in a circuit, in addition to
 the max. number of active qubits.
 """
 
diff --git a/projectq/backends/_sim/__init__.py b/projectq/backends/_sim/__init__.py
index 3cdb3731b..8898be48f 100755
--- a/projectq/backends/_sim/__init__.py
+++ b/projectq/backends/_sim/__init__.py
@@ -12,7 +12,7 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 
-"""ProjectQ module dedicated to simulation"""
+"""ProjectQ module dedicated to simulation."""
 
 from ._classical_simulator import ClassicalSimulator
 from ._simulator import Simulator
diff --git a/projectq/backends/_sim/_simulator.py b/projectq/backends/_sim/_simulator.py
index 9752ea669..f3365fbcc 100755
--- a/projectq/backends/_sim/_simulator.py
+++ b/projectq/backends/_sim/_simulator.py
@@ -74,7 +74,7 @@ def __init__(self, gate_fusion=False, rnd_seed=None):
             implementation of the kernels.  While this is much slower, it is still good enough to run basic quantum
             algorithms.
 
-            If you need to run large simulations, check out the tutorial in the docs which gives futher hints on how
+            If you need to run large simulations, check out the tutorial in the docs which gives further hints on how
             to build the C++ extension.
         """
         if rnd_seed is None:
diff --git a/projectq/cengines/_linearmapper.py b/projectq/cengines/_linearmapper.py
index ca4b45320..c544fa9b6 100644
--- a/projectq/cengines/_linearmapper.py
+++ b/projectq/cengines/_linearmapper.py
@@ -143,7 +143,7 @@ def return_new_mapping(num_qubits, cyclic, currently_allocated_ids, stored_comma
         allocated_qubits = deepcopy(currently_allocated_ids)
         active_qubits = deepcopy(currently_allocated_ids)
         # Segments contains a list of segments. A segment is a list of
-        # neighouring qubit ids
+        # neighbouring qubit ids
         segments = []
         # neighbour_ids only used to speedup the lookup process if qubits
         # are already connected. key: qubit_id, value: set of neighbour ids
@@ -207,7 +207,7 @@ def _process_two_qubit_gate(  # pylint: disable=too-many-arguments,too-many-bran
         """
         Process a two qubit gate.
 
-        It either removes the two qubits from active_qubits if the gate is not possible or updates the segements such
+        It either removes the two qubits from active_qubits if the gate is not possible or updates the segments such
         that the gate is possible.
 
         Args:
@@ -232,7 +232,7 @@ def _process_two_qubit_gate(  # pylint: disable=too-many-arguments,too-many-bran
             active_qubits.discard(qubit0)
             active_qubits.discard(qubit1)
         # qubits are both active and either not yet in a segment or at
-        # the end of segement:
+        # the end of segment:
         else:
             segment_index_qb0 = None
             qb0_is_left_end = None
diff --git a/projectq/cengines/_main.py b/projectq/cengines/_main.py
index dfbf5b7e4..87ec1b3d3 100755
--- a/projectq/cengines/_main.py
+++ b/projectq/cengines/_main.py
@@ -321,6 +321,6 @@ def flush(self, deallocate_qubits=False):
         """
         if deallocate_qubits:
             while [qb for qb in self.active_qubits if qb is not None]:
-                qb = self.active_qubits.pop()
-                qb.__del__()
+                qb = self.active_qubits.pop()  # noqa: F841
+                qb.__del__()  # pylint: disable=unnecessary-dunder-call
         self.receive([Command(self, FlushGate(), ([WeakQubitRef(self, -1)],))])
diff --git a/projectq/cengines/_optimize.py b/projectq/cengines/_optimize.py
index 8d6b83678..1cce7317a 100755
--- a/projectq/cengines/_optimize.py
+++ b/projectq/cengines/_optimize.py
@@ -248,7 +248,7 @@ def receive(self, command_list):
                     if len(_l) > 0:  # pragma: no cover
                         new_dict[idx] = _l
                 self._l = new_dict
-                if self._l != {}:  # pragma: no cover
+                if self._l:  # pragma: no cover
                     raise RuntimeError('Internal compiler error: qubits remaining in LocalOptimizer after a flush!')
                 self.send([cmd])
             else:
diff --git a/projectq/cengines/_swapandcnotflipper.py b/projectq/cengines/_swapandcnotflipper.py
index d25ac7222..997274a0a 100755
--- a/projectq/cengines/_swapandcnotflipper.py
+++ b/projectq/cengines/_swapandcnotflipper.py
@@ -56,7 +56,7 @@ def is_available(self, cmd):
         """
         return self._is_swap(cmd) or self.next_engine.is_available(cmd)
 
-    def _is_cnot(self, cmd):  # pylint: disable=no-self-use
+    def _is_cnot(self, cmd):
         """
         Check if the command corresponds to a CNOT (controlled NOT gate).
 
@@ -65,7 +65,7 @@ def _is_cnot(self, cmd):  # pylint: disable=no-self-use
         """
         return isinstance(cmd.gate, NOT.__class__) and get_control_count(cmd) == 1
 
-    def _is_swap(self, cmd):  # pylint: disable=no-self-use
+    def _is_swap(self, cmd):
         """
         Check if the command corresponds to a Swap gate.
 
diff --git a/projectq/cengines/_testengine.py b/projectq/cengines/_testengine.py
index 2933bde82..3e9b0379b 100755
--- a/projectq/cengines/_testengine.py
+++ b/projectq/cengines/_testengine.py
@@ -32,7 +32,7 @@ class CompareEngine(BasicEngine):
     Command list comparison compiler engine for testing purposes.
 
     CompareEngine is an engine which saves all commands. It is only intended for testing purposes. Two CompareEngine
-    backends can be compared and return True if they contain the same commmands.
+    backends can be compared and return True if they contain the same commands.
     """
 
     def __init__(self):
diff --git a/projectq/libs/__init__.py b/projectq/libs/__init__.py
index a60e7ce84..ff6f1e495 100755
--- a/projectq/libs/__init__.py
+++ b/projectq/libs/__init__.py
@@ -12,4 +12,4 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 
-"""ProjectQ module containing libraries expanding the basic functionalities of ProjectQ"""
+"""ProjectQ module containing libraries expanding the basic functionalities of ProjectQ."""
diff --git a/projectq/libs/hist/__init__.py b/projectq/libs/hist/__init__.py
index 07911534a..d55514dda 100644
--- a/projectq/libs/hist/__init__.py
+++ b/projectq/libs/hist/__init__.py
@@ -12,8 +12,9 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 """
-contains a function to plot measurement outcome probabilities
-as a histogram for the simulator
+Measurement histogram plot helper functions.
+
+Contains a function to plot measurement outcome probabilities as a histogram for the simulator
 """
 
 from ._histogram import histogram
diff --git a/projectq/libs/math/__init__.py b/projectq/libs/math/__init__.py
index c2433cf34..87e1eee3e 100755
--- a/projectq/libs/math/__init__.py
+++ b/projectq/libs/math/__init__.py
@@ -12,6 +12,8 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 
+"""Math gate definitions."""
+
 from ._default_rules import all_defined_decomposition_rules
 from ._gates import (
     AddConstant,
diff --git a/projectq/libs/math/_gates.py b/projectq/libs/math/_gates.py
index ed6d9d26c..ad466d2d7 100755
--- a/projectq/libs/math/_gates.py
+++ b/projectq/libs/math/_gates.py
@@ -346,7 +346,7 @@ def get_inverse(self):
 
 class ComparatorQuantumGate(BasicMathGate):
     """
-    Flip a compare qubit if the binary value of first imput is higher than the second input.
+    Flip a compare qubit if the binary value of first input is higher than the second input.
 
     The numbers are stored from low- to high-bit, i.e., qunum[0] is the LSB.
     Example:
@@ -363,7 +363,7 @@ class ComparatorQuantumGate(BasicMathGate):
 
     def __init__(self):
         """
-        Initilize a ComparatorQuantumGate object.
+        Initialize a ComparatorQuantumGate object.
 
         Initialize the gate and its base class, BasicMathGate, with the corresponding function, so it can be emulated
         efficiently.
diff --git a/projectq/libs/math/_quantummath.py b/projectq/libs/math/_quantummath.py
index fb3dcbdc6..59aa7cf9f 100644
--- a/projectq/libs/math/_quantummath.py
+++ b/projectq/libs/math/_quantummath.py
@@ -315,7 +315,7 @@ def quantum_division(eng, dividend, remainder, divisor):
     Quantum Restoring Integer Division from:
     https://arxiv.org/pdf/1609.01241.pdf.
     """
-    # The circuit consits of three parts
+    # The circuit consists of three parts
     # i) leftshift
     # ii) subtraction
     # iii) conditional add operation.
diff --git a/projectq/libs/revkit/__init__.py b/projectq/libs/revkit/__init__.py
index e527091be..f8d80db0e 100644
--- a/projectq/libs/revkit/__init__.py
+++ b/projectq/libs/revkit/__init__.py
@@ -12,7 +12,7 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 
-"""Module containing code to interface with RevKit"""
+"""Module containing code to interface with RevKit."""
 
 from ._control_function import ControlFunctionOracle
 from ._permutation import PermutationOracle
diff --git a/projectq/libs/revkit/_control_function.py b/projectq/libs/revkit/_control_function.py
index c20db35f5..40a07fe9f 100644
--- a/projectq/libs/revkit/_control_function.py
+++ b/projectq/libs/revkit/_control_function.py
@@ -119,4 +119,4 @@ def _check_function(self):
         # function must be positive. We check in __or__ whether function is
         # too large
         if self.function < 0:
-            raise AttributeError("Function must be a postive integer")
+            raise AttributeError("Function must be a positive integer")
diff --git a/projectq/libs/revkit/_phase.py b/projectq/libs/revkit/_phase.py
index 399697449..8d0eb2931 100644
--- a/projectq/libs/revkit/_phase.py
+++ b/projectq/libs/revkit/_phase.py
@@ -115,4 +115,4 @@ def _check_function(self):
         # function must be positive.  We check in __or__ whether function is
         # too large
         if self.function < 0:
-            raise AttributeError("Function must be a postive integer")
+            raise AttributeError("Function must be a positive integer")
diff --git a/projectq/libs/revkit/_utils.py b/projectq/libs/revkit/_utils.py
index e1f47c025..1dfb2287b 100644
--- a/projectq/libs/revkit/_utils.py
+++ b/projectq/libs/revkit/_utils.py
@@ -13,7 +13,7 @@
 #   limitations under the License.
 
 
-"""Module containing some utility functions"""
+"""Module containing some utility functions."""
 
 # flake8: noqa
 # pylint: skip-file
@@ -21,7 +21,7 @@
 
 def _exec(code, qs):
     """
-    Executes the Python code in 'filename'.
+    Execute the Python code in 'filename'.
 
     Args:
         code (string): ProjectQ code.
diff --git a/projectq/meta/__init__.py b/projectq/meta/__init__.py
index 764081800..382148d7f 100755
--- a/projectq/meta/__init__.py
+++ b/projectq/meta/__init__.py
@@ -12,8 +12,9 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 """
-The projectq.meta package features meta instructions which help both the user and the compiler in writing/producing
-efficient code. It includes, e.g.,
+Provides meta instructions which help both the user and the compiler in writing/producing efficient code.
+
+It includes, e.g.,
 
 * Loop (with Loop(eng): ...)
 * Compute/Uncompute (with Compute(eng): ..., [...], Uncompute(eng))
diff --git a/projectq/meta/_compute.py b/projectq/meta/_compute.py
index 295c4b7a4..84cde8a7a 100755
--- a/projectq/meta/_compute.py
+++ b/projectq/meta/_compute.py
@@ -102,7 +102,7 @@ def run_uncompute(self):  # pylint: disable=too-many-branches,too-many-statement
                     for active_qubit in self.main_engine.active_qubits:
                         if active_qubit.id == qubit_id:
                             active_qubit.id = -1
-                            active_qubit.__del__()
+                            del active_qubit
                             qubit_found = True
                             break
                     if not qubit_found:
@@ -158,7 +158,7 @@ def add_uncompute(command, old_tags=deepcopy(cmd.tags)):
                     for active_qubit in self.main_engine.active_qubits:
                         if active_qubit.id == qubit_id:
                             active_qubit.id = -1
-                            active_qubit.__del__()
+                            del active_qubit
                             qubit_found = True
                             break
                     if not qubit_found:
diff --git a/projectq/meta/_compute_test.py b/projectq/meta/_compute_test.py
index b32cd1f2f..e5caa360b 100755
--- a/projectq/meta/_compute_test.py
+++ b/projectq/meta/_compute_test.py
@@ -307,7 +307,7 @@ def allow_dirty_qubits(self, meta_tag):
     assert backend.received_commands[18].qubits[0][0].id == ancilla_uncompt_id
     assert backend.received_commands[19].qubits[0][0].id == qubit_id
     assert backend.received_commands[20].qubits[0][0].id == qubit_id
-    # Test that ancilla qubits should have seperate ids
+    # Test that ancilla qubits should have separate ids
     assert ancilla_uncompt_id != ancilla_compt_id
 
     # Do the same thing with CustomUncompute and compare using the
diff --git a/projectq/meta/_control.py b/projectq/meta/_control.py
index 543ebfe80..549e0e9e5 100755
--- a/projectq/meta/_control.py
+++ b/projectq/meta/_control.py
@@ -45,7 +45,7 @@ def canonical_ctrl_state(ctrl_state, num_qubits):
         In case of integer values for `ctrl_state`, the least significant bit applies to the first qubit in the qubit
         register, e.g. if ctrl_state == 2, its binary representation if '10' with the least significan bit being 0.
 
-        This means in particular that the followings are equivalent:
+        This means in particular that the following are equivalent:
 
         .. code-block:: python
 
diff --git a/projectq/meta/_dagger.py b/projectq/meta/_dagger.py
index 8987b1b2a..f2a7dc243 100755
--- a/projectq/meta/_dagger.py
+++ b/projectq/meta/_dagger.py
@@ -43,7 +43,7 @@ def run(self):
         if self._deallocated_qubit_ids != self._allocated_qubit_ids:
             raise QubitManagementError(
                 "\n Error. Qubits have been allocated in 'with "
-                + "Dagger(eng)' context,\n which have not explicitely "
+                + "Dagger(eng)' context,\n which have not explicitly "
                 + "been deallocated.\n"
                 + "Correct usage:\n"
                 + "with Dagger(eng):\n"
diff --git a/projectq/meta/_loop.py b/projectq/meta/_loop.py
index 47681b764..5fd94157f 100755
--- a/projectq/meta/_loop.py
+++ b/projectq/meta/_loop.py
@@ -88,7 +88,7 @@ def run(self):
         error_message = (
             "\n Error. Qubits have been allocated in with "
             "Loop(eng, num) context,\n which have not "
-            "explicitely been deallocated in the Loop context.\n"
+            "explicitly been deallocated in the Loop context.\n"
             "Correct usage:\nwith Loop(eng, 5):\n"
             "    qubit = eng.allocate_qubit()\n"
             "    ...\n"
diff --git a/projectq/ops/__init__.py b/projectq/ops/__init__.py
index 13d23ebaf..2a931b617 100755
--- a/projectq/ops/__init__.py
+++ b/projectq/ops/__init__.py
@@ -12,7 +12,7 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 
-"""ProjectQ module containing all basic gates (operations)"""
+"""ProjectQ module containing all basic gates (operations)."""
 
 from ._basics import (
     BasicGate,
diff --git a/projectq/ops/_basics.py b/projectq/ops/_basics.py
index c07563fca..854696586 100755
--- a/projectq/ops/_basics.py
+++ b/projectq/ops/_basics.py
@@ -27,7 +27,7 @@
     Gate | qubit
     Gate | (qubit,)
 
-This means that for more than one quantum argument (right side of | ), a tuple needs to be made explicitely, while for
+This means that for more than one quantum argument (right side of | ), a tuple needs to be made explicitly, while for
 one argument it is optional.
 """
 
@@ -101,7 +101,7 @@ def __init__(self):
         """
         self.interchangeable_qubit_indices = []
 
-    def get_inverse(self):  # pylint: disable=no-self-use
+    def get_inverse(self):
         """
         Return the inverse gate.
 
@@ -112,7 +112,7 @@ def get_inverse(self):  # pylint: disable=no-self-use
         """
         raise NotInvertible("BasicGate: No get_inverse() implemented.")
 
-    def get_merged(self, other):  # pylint: disable=no-self-use
+    def get_merged(self, other):
         """
         Return this gate merged with another gate.
 
@@ -158,7 +158,7 @@ def make_tuple_of_qureg(qubits):
         qubits = list(qubits)
 
         for i, qubit in enumerate(qubits):
-            if isinstance(qubits[i], BasicQubit):
+            if isinstance(qubit, BasicQubit):
                 qubits[i] = [qubit]
 
         return tuple(qubits)
@@ -230,7 +230,7 @@ def __hash__(self):
         """Compute the hash of the object."""
         return hash(str(self))
 
-    def is_identity(self):  # pylint: disable=no-self-use
+    def is_identity(self):
         """Return True if the gate is an identity gate. In this base class, always returns False."""
         return False
 
@@ -274,7 +274,7 @@ def __eq__(self, other):
         """
         Equal operator.
 
-        Return True only if both gates have a matrix respresentation and the matrices are (approximately)
+        Return True only if both gates have a matrix representation and the matrices are (approximately)
         equal. Otherwise return False.
         """
         if not hasattr(other, 'matrix'):
@@ -415,7 +415,7 @@ def __hash__(self):
 
     def is_identity(self):
         """Return True if the gate is equivalent to an Identity gate."""
-        return self.angle == 0.0 or self.angle == 4 * math.pi
+        return self.angle in (0.0, 4 * math.pi)
 
 
 class BasicPhaseGate(BasicGate):
diff --git a/projectq/ops/_command_test.py b/projectq/ops/_command_test.py
index 9fcbf544e..0a315d64d 100755
--- a/projectq/ops/_command_test.py
+++ b/projectq/ops/_command_test.py
@@ -182,7 +182,7 @@ def test_command_interchangeable_qubit_indices(main_engine):
     [0, 1, '0', '1', CtrlAll.One, CtrlAll.Zero],
     ids=['int(0)', 'int(1)', 'str(0)', 'str(1)', 'CtrlAll.One', 'CtrlAll.Zero'],
 )
-def test_commmand_add_control_qubits_one(main_engine, state):
+def test_command_add_control_qubits_one(main_engine, state):
     qubit0 = Qureg([Qubit(main_engine, 0)])
     qubit1 = Qureg([Qubit(main_engine, 1)])
     cmd = _command.Command(main_engine, Rx(0.5), (qubit0,))
@@ -210,7 +210,7 @@ def test_commmand_add_control_qubits_one(main_engine, state):
         'CtrlAll.Zero',
     ],
 )
-def test_commmand_add_control_qubits_two(main_engine, state):
+def test_command_add_control_qubits_two(main_engine, state):
     qubit0 = Qureg([Qubit(main_engine, 0)])
     qubit1 = Qureg([Qubit(main_engine, 1)])
     qubit2 = Qureg([Qubit(main_engine, 2)])
diff --git a/projectq/ops/_gates.py b/projectq/ops/_gates.py
index 88024b7cf..10527a868 100755
--- a/projectq/ops/_gates.py
+++ b/projectq/ops/_gates.py
@@ -173,7 +173,7 @@ def matrix(self):
         """Access to the matrix property of this gate."""
         return 0.5 * np.matrix([[1 + 1j, 1 - 1j], [1 - 1j, 1 + 1j]])
 
-    def tex_str(self):  # pylint: disable=no-self-use
+    def tex_str(self):
         """Return the Latex string representation of a SqrtXGate."""
         return r'$\sqrt{X}$'
 
diff --git a/projectq/ops/_qaagate.py b/projectq/ops/_qaagate.py
index 5e2d889c4..c5561eaa4 100755
--- a/projectq/ops/_qaagate.py
+++ b/projectq/ops/_qaagate.py
@@ -19,14 +19,14 @@
 
 class QAA(BasicGate):
     """
-    Quantum Aplitude Amplification gate.
+    Quantum Amplitude Amplification gate.
 
     (Quick reference https://en.wikipedia.org/wiki/Amplitude_amplification.  Complete reference G. Brassard, P. Hoyer,
     M. Mosca, A. Tapp (2000) Quantum Amplitude Amplification and Estimation https://arxiv.org/abs/quant-ph/0005055)
 
     Quantum Amplitude Amplification (QAA) executes the algorithm, but not the final measurement required to obtain the
-    marked state(s) with high probability. The starting state on wich the QAA algorithm is executed is the one
-    resulting of aplying the Algorithm on the |0> state.
+    marked state(s) with high probability. The starting state on which the QAA algorithm is executed is the one
+    resulting of applying the Algorithm on the |0> state.
 
     Example:
         .. code-block:: python
diff --git a/projectq/ops/_qubit_operator.py b/projectq/ops/_qubit_operator.py
index f15a4ed40..80c901dd3 100644
--- a/projectq/ops/_qubit_operator.py
+++ b/projectq/ops/_qubit_operator.py
@@ -53,7 +53,7 @@ class QubitOperator(BasicGate):
 
     A term is an operator acting on n qubits and can be represented as:
 
-    coefficent * local_operator[0] x ... x local_operator[n-1]
+    coefficient * local_operator[0] x ... x local_operator[n-1]
 
     where x is the tensor product. A local operator is a Pauli operator ('I', 'X', 'Y', or 'Z') which acts on one
     qubit. In math notation a term is, for example, 0.5 * 'X0 X5', which means that a Pauli X operator acts on qubit 0
@@ -117,7 +117,7 @@ def __init__(self, term=None, coefficient=1.0):  # pylint: disable=too-many-bran
         Args:
             coefficient (complex float, optional): The coefficient of the first term of this QubitOperator. Default is
                 1.0.
-            term (optional, empy tuple, a tuple of tuples, or a string):
+            term (optional, empty tuple, a tuple of tuples, or a string):
                 1) Default is None which means there are no terms in the QubitOperator hence it is the "zero" Operator
                 2) An empty tuple means there are no non-trivial Pauli operators acting on the qubits hence only
                    identities with a coefficient (which by default is 1.0).
diff --git a/projectq/ops/_time_evolution.py b/projectq/ops/_time_evolution.py
index 957a1d21d..c28de10c2 100644
--- a/projectq/ops/_time_evolution.py
+++ b/projectq/ops/_time_evolution.py
@@ -33,7 +33,7 @@ class TimeEvolution(BasicGate):
     This gate is the unitary time evolution propagator:
     exp(-i * H * t),
     where H is the Hamiltonian of the system and t is the time. Note that -i
-    factor is stored implicitely.
+    factor is stored implicitly.
 
     Example:
         .. code-block:: python
diff --git a/projectq/setups/__init__.py b/projectq/setups/__init__.py
index dc799ab87..32d24fd1e 100755
--- a/projectq/setups/__init__.py
+++ b/projectq/setups/__init__.py
@@ -12,4 +12,4 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 
-"""ProjectQ module containing the basic setups for ProjectQ as well as the decomposition rules"""
+"""ProjectQ module containing the basic setups for ProjectQ as well as the decomposition rules."""
diff --git a/projectq/setups/_utils.py b/projectq/setups/_utils.py
index 434eb5424..20c531abe 100644
--- a/projectq/setups/_utils.py
+++ b/projectq/setups/_utils.py
@@ -69,7 +69,7 @@ def get_engine_list_linear_grid_base(mapper, one_qubit_gates="any", two_qubit_ga
         If you choose a new gate set for which the compiler does not yet have standard rules, it raises an
         `NoGateDecompositionError` or a `RuntimeError: maximum recursion depth exceeded...`. Also note that even the
         gate sets which work might not yet be optimized. So make sure to double check and potentially extend the
-        decomposition rules.  This implemention currently requires that the one qubit gates must contain Rz and at
+        decomposition rules.  This implementation currently requires that the one qubit gates must contain Rz and at
         least one of {Ry(best), Rx, H} and the two qubit gate must contain CNOT (recommended) or CZ.
 
     Note:
diff --git a/projectq/setups/aqt.py b/projectq/setups/aqt.py
index 5b668aaf5..96465842b 100644
--- a/projectq/setups/aqt.py
+++ b/projectq/setups/aqt.py
@@ -33,7 +33,7 @@
 
 
 def get_engine_list(token=None, device=None):
-    """Return the default list of compiler engine for the AQT plaftorm."""
+    """Return the default list of compiler engine for the AQT platform."""
     # Access to the hardware properties via show_devices
     # Can also be extended to take into account gate fidelities, new available
     # gate, etc..
diff --git a/projectq/setups/decompositions/__init__.py b/projectq/setups/decompositions/__init__.py
index ec5fcb277..f377093ab 100755
--- a/projectq/setups/decompositions/__init__.py
+++ b/projectq/setups/decompositions/__init__.py
@@ -12,6 +12,8 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 
+"""ProjectQ's decomposition rules."""
+
 from . import (
     amplitudeamplification,
     arb1qubit2rzandry,
diff --git a/projectq/setups/decompositions/amplitudeamplification.py b/projectq/setups/decompositions/amplitudeamplification.py
index bd38f8086..5a8528367 100644
--- a/projectq/setups/decompositions/amplitudeamplification.py
+++ b/projectq/setups/decompositions/amplitudeamplification.py
@@ -21,8 +21,8 @@
 
 Quantum Amplitude Amplification (QAA) executes the algorithm, but not
 the final measurement required to obtain the marked state(s) with high
-probability. The starting state on wich the QAA algorithm is executed
-is the one resulting of aplying the Algorithm on the |0> state.
+probability. The starting state on which the QAA algorithm is executed
+is the one resulting of applying the algorithm on the |0> state.
 
 Example:
     .. code-block:: python
@@ -92,7 +92,7 @@ def _decompose_QAA(cmd):  # pylint: disable=invalid-name
     oracle(eng, system_qubits, qaa_ancilla)
 
     # Apply the inversion of the Algorithm,
-    # the inversion of the aplitude of |0> and the Algorithm
+    # the inversion of the amplitude of |0> and the Algorithm
 
     with Compute(eng):
         with Dagger(eng):
diff --git a/projectq/setups/decompositions/amplitudeamplification_test.py b/projectq/setups/decompositions/amplitudeamplification_test.py
index 34b490de9..8e68aad1b 100644
--- a/projectq/setups/decompositions/amplitudeamplification_test.py
+++ b/projectq/setups/decompositions/amplitudeamplification_test.py
@@ -75,8 +75,8 @@ def test_simple_grover():
     with Loop(eng, num_it):
         QAA(hache_algorithm, simple_oracle) | (system_qubits, control)
 
-    # Get the probabilty of getting the marked state after the AA
-    # to compare with the theoretical probability after teh AA
+    # Get the probability of getting the marked state after the AA
+    # to compare with the theoretical probability after the AA
     eng.flush()
     prob1010101 = eng.backend.get_probability('1010101', system_qubits)
     total_prob_after = prob1010101
@@ -135,7 +135,7 @@ def test_complex_aa():
     # Creates the initial state form the Algorithm
     complex_algorithm(eng, system_qubits)
 
-    # Get the probabilty of getting the marked state before the AA
+    # Get the probability of getting the marked state before the AA
     # to calculate the number of iterations
     eng.flush()
     prob000000 = eng.backend.get_probability('000000', system_qubits)
@@ -153,7 +153,7 @@ def test_complex_aa():
     with Loop(eng, num_it):
         QAA(complex_algorithm, complex_oracle) | (system_qubits, control)
 
-    # Get the probabilty of getting the marked state after the AA
+    # Get the probability of getting the marked state after the AA
     # to compare with the theoretical probability after the AA
     eng.flush()
     prob000000 = eng.backend.get_probability('000000', system_qubits)
diff --git a/projectq/setups/decompositions/arb1qubit2rzandry.py b/projectq/setups/decompositions/arb1qubit2rzandry.py
index 33da891ea..fc9d1a4c0 100644
--- a/projectq/setups/decompositions/arb1qubit2rzandry.py
+++ b/projectq/setups/decompositions/arb1qubit2rzandry.py
@@ -208,7 +208,7 @@ def _decompose_arb1qubit(cmd):
     """
     Use Z-Y decomposition of Nielsen and Chuang (Theorem 4.1).
 
-    An arbitrary one qubit gate matrix can be writen as
+    An arbitrary one qubit gate matrix can be written as
     U = [[exp(j*(a-b/2-d/2))*cos(c/2), -exp(j*(a-b/2+d/2))*sin(c/2)],
          [exp(j*(a+b/2-d/2))*sin(c/2), exp(j*(a+b/2+d/2))*cos(c/2)]]
     where a,b,c,d are real numbers.
diff --git a/projectq/setups/decompositions/carb1qubit2cnotrzandry.py b/projectq/setups/decompositions/carb1qubit2cnotrzandry.py
index 48490a814..549db3af1 100644
--- a/projectq/setups/decompositions/carb1qubit2cnotrzandry.py
+++ b/projectq/setups/decompositions/carb1qubit2cnotrzandry.py
@@ -12,7 +12,7 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 """
-Register the decomposition of an controlled arbitary single qubit gate.
+Register the decomposition of an controlled arbitrary single qubit gate.
 
 See paper "Elementary gates for quantum computing" by Adriano Barenco et al.,
 arXiv:quant-ph/9503016v1. (Note: They use different gate definitions!) or
@@ -156,7 +156,7 @@ def _decompose_carb1qubit(cmd):  # pylint: disable=too-many-branches
 
     See Nielsen and Chuang chapter 4.3.
 
-    An arbitrary one qubit gate matrix can be writen as
+    An arbitrary one qubit gate matrix can be written as
     U = [[exp(j*(a-b/2-d/2))*cos(c/2), -exp(j*(a-b/2+d/2))*sin(c/2)],
          [exp(j*(a+b/2-d/2))*sin(c/2), exp(j*(a+b/2+d/2))*cos(c/2)]]
     where a,b,c,d are real numbers.
@@ -170,7 +170,7 @@ def _decompose_carb1qubit(cmd):  # pylint: disable=too-many-branches
     the controlled phase C(exp(ia)) can be implemented with single
     qubit gates.
 
-    If the one qubit gate matrix can be writen as
+    If the one qubit gate matrix can be written as
     V = [[-sin(c/2) * exp(j*a), exp(j*(a-b)) * cos(c/2)],
          [exp(j*(a+b)) * cos(c/2), exp(j*a) * sin(c/2)]]
     Then C(V) = C(exp(ja))* E * CNOT * D with
diff --git a/projectq/setups/decompositions/controlstate.py b/projectq/setups/decompositions/controlstate.py
index 7aa0b5924..b8d180ecc 100755
--- a/projectq/setups/decompositions/controlstate.py
+++ b/projectq/setups/decompositions/controlstate.py
@@ -15,7 +15,7 @@
 """
 Register a decomposition to replace turn negatively controlled qubits into positively controlled qubits.
 
-This achived by applying X gates to selected qubits.
+This achieved by applying X gates to selected qubits.
 """
 
 from copy import deepcopy
diff --git a/projectq/setups/decompositions/phaseestimation.py b/projectq/setups/decompositions/phaseestimation.py
index 50d02253f..0913064e5 100644
--- a/projectq/setups/decompositions/phaseestimation.py
+++ b/projectq/setups/decompositions/phaseestimation.py
@@ -21,7 +21,7 @@
 phase should be executed outside of the QPE.
 
 The decomposition uses as ancillas (qpe_ancillas) the first qubit/qureg in
-the Command and as system qubits teh second qubit/qureg in the Command.
+the Command and as system qubits the second qubit/qureg in the Command.
 
 The unitary operator for which the phase estimation is estimated (unitary)
 is the gate in Command
diff --git a/projectq/setups/grid.py b/projectq/setups/grid.py
index 65021b930..6d58e7924 100644
--- a/projectq/setups/grid.py
+++ b/projectq/setups/grid.py
@@ -35,7 +35,7 @@ def get_engine_list(num_rows, num_columns, one_qubit_gates="any", two_qubit_gate
         If you choose a new gate set for which the compiler does not yet have standard rules, it raises an
         `NoGateDecompositionError` or a `RuntimeError: maximum recursion depth exceeded...`. Also note that even the
         gate sets which work might not yet be optimized. So make sure to double check and potentially extend the
-        decomposition rules.  This implemention currently requires that the one qubit gates must contain Rz and at
+        decomposition rules. This implementation currently requires that the one qubit gates must contain Rz and at
         least one of {Ry(best), Rx, H} and the two qubit gate must contain CNOT (recommended) or CZ.
 
     Note:
diff --git a/projectq/setups/linear.py b/projectq/setups/linear.py
index 299a64f80..5ee1e0193 100644
--- a/projectq/setups/linear.py
+++ b/projectq/setups/linear.py
@@ -34,7 +34,7 @@ def get_engine_list(num_qubits, cyclic=False, one_qubit_gates="any", two_qubit_g
         If you choose a new gate set for which the compiler does not yet have standard rules, it raises an
         `NoGateDecompositionError` or a `RuntimeError: maximum recursion depth exceeded...`. Also note that even the
         gate sets which work might not yet be optimized. So make sure to double check and potentially extend the
-        decomposition rules.  This implemention currently requires that the one qubit gates must contain Rz and at
+        decomposition rules.  This implementation currently requires that the one qubit gates must contain Rz and at
         least one of {Ry(best), Rx, H} and the two qubit gate must contain CNOT (recommended) or CZ.
 
     Note:
diff --git a/projectq/setups/restrictedgateset.py b/projectq/setups/restrictedgateset.py
index 9e8049d4e..202bb990d 100644
--- a/projectq/setups/restrictedgateset.py
+++ b/projectq/setups/restrictedgateset.py
@@ -15,7 +15,7 @@
 Defines a setup to compile to a restricted gate set.
 
 It provides the `engine_list` for the `MainEngine`. This engine list contains an AutoReplacer with most of the gate
-decompositions of ProjectQ, which are used to decompose a circuit into a restricted gate set (with some limitions on
+decompositions of ProjectQ, which are used to decompose a circuit into a restricted gate set (with some limitations on
 the choice of gates).
 """
 
@@ -54,7 +54,7 @@ def get_engine_list(  # pylint: disable=too-many-branches,too-many-statements
         If you choose a new gate set for which the compiler does not yet have standard rules, it raises an
         `NoGateDecompositionError` or a `RuntimeError: maximum recursion depth exceeded...`. Also note that even the
         gate sets which work might not yet be optimized. So make sure to double check and potentially extend the
-        decomposition rules.  This implemention currently requires that the one qubit gates must contain Rz and at
+        decomposition rules.  This implementation currently requires that the one qubit gates must contain Rz and at
         least one of {Ry(best), Rx, H} and the two qubit gate must contain CNOT (recommended) or CZ.
 
     Note:
diff --git a/projectq/setups/trapped_ion_decomposer.py b/projectq/setups/trapped_ion_decomposer.py
index 3841b638a..320c8a6ad 100644
--- a/projectq/setups/trapped_ion_decomposer.py
+++ b/projectq/setups/trapped_ion_decomposer.py
@@ -34,8 +34,7 @@
 from projectq.setups import restrictedgateset
 
 # ------------------chooser_Ry_reducer-------------------#
-# If the qubit is not in the prev_Ry_sign dictionary, then no decomposition
-# occured
+# If the qubit is not in the prev_Ry_sign dictionary, then no decomposition occurred
 # If the value is:
 #  -1 then the last gate applied (during a decomposition!) was Ry(-math.pi/2)
 #   1 then the last gate applied (during a decomposition!) was Ry(+math.pi/2)
@@ -117,8 +116,7 @@ def chooser_Ry_reducer(cmd, decomposition_list):  # pylint: disable=invalid-name
         local_prev_Ry_sign[qubit_id] = 1
         return decomp_rule['P']
 
-    # No decomposition chosen, so use the first decompostion in the list
-    # like the default function
+    # No decomposition chosen, so use the first decomposition in the list like the default function
     return decomposition_list[0]
 
 
diff --git a/projectq/tests/__init__.py b/projectq/tests/__init__.py
index ee1451dcd..7d98bf34e 100755
--- a/projectq/tests/__init__.py
+++ b/projectq/tests/__init__.py
@@ -11,3 +11,5 @@
 #   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
+
+"""ProjectQ testing module."""
diff --git a/projectq/types/__init__.py b/projectq/types/__init__.py
index ad912d2ba..dd1bc28b5 100755
--- a/projectq/types/__init__.py
+++ b/projectq/types/__init__.py
@@ -12,6 +12,6 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 
-"""ProjectQ module containing all basic types"""
+"""ProjectQ module containing all basic types."""
 
 from ._qubit import BasicQubit, Qubit, Qureg, WeakQubitRef
diff --git a/projectq/types/_qubit.py b/projectq/types/_qubit.py
index 41021fe1c..39631410b 100755
--- a/projectq/types/_qubit.py
+++ b/projectq/types/_qubit.py
@@ -16,7 +16,7 @@
 
 A Qureg represents a list of Qubit or WeakQubit objects.
 A Qubit represents a (logical-level) qubit with a unique index provided by the MainEngine. Qubit objects are
-automatically deallocated if they go out of scope and intented to be used within Qureg objects in user code.
+automatically deallocated if they go out of scope and intended to be used within Qureg objects in user code.
 
 Example:
     .. code-block:: python
diff --git a/pyproject.toml b/pyproject.toml
index 5e0559d69..8d3b23afd 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -155,9 +155,14 @@ ignore = [
     disable = [
          'expression-not-assigned',
          'pointless-statement',
-         'fixme'
+         'fixme',
+         'unspecified-encoding',
+         'R0801',
     ]
 
+    [tool.pylint.typecheck]
+    ignored-modules = ['boto3', 'botocore', 'sympy']
+
 
 [tool.pytest.ini_options]
 
@@ -167,6 +172,11 @@ testpaths = ['projectq']
 ignore-glob = ['*flycheck*.py']
 mock_use_standalone_module = true
 
+[tool.doc8]
+
+verbose = 0
+max_line_length = 120
+
 [tool.isort]
 
 profile = "black"
diff --git a/setup.py b/setup.py
index 32426d594..84e6d57af 100755
--- a/setup.py
+++ b/setup.py
@@ -37,6 +37,8 @@
 
 """Setup.py file."""
 
+# pylint: disable=deprecated-module
+
 import distutils.log
 import os
 import platform
@@ -717,7 +719,7 @@ def run(self):
 class Distribution(_Distribution):
     """Distribution class."""
 
-    def has_ext_modules(self):  # pylint: disable=no-self-use
+    def has_ext_modules(self):
         """Return whether this distribution has some external modules."""
         # We want to always claim that we have ext_modules. This will be fine
         # if we don't actually have them (such as on PyPy) because nothing

From b2fff97d1669c91c5f732133c9ebde7b47ddde2b Mon Sep 17 00:00:00 2001
From: Damien Nguyen <ngn.damien@gmail.com>
Date: Sun, 30 Oct 2022 22:49:05 +0100
Subject: [PATCH 12/25] Fix formatting in CHANGELOG and cleanup CI builds
 workflows

---
 .github/workflows/ci.yml | 40 ++++++++++++++++++++++------------------
 CHANGELOG.md             |  8 --------
 2 files changed, 22 insertions(+), 26 deletions(-)

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index a9a252762..81e77c60d 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -210,6 +210,13 @@ jobs:
         centos:
           - 7  # GCC 4.8
           - 8
+        include:
+          - centos: 7
+            python_pkg: rh-python38-python-pip rh-python38-python-devel
+            enable_repo: --enablerepo=centos-sclo-rh
+          - centos: 8
+            python_pkg: python38-devel
+
 
     name: "Python 3 • CentOS ${{ matrix.centos }} • x64"
     container: "centos:${{ matrix.centos }}"
@@ -232,12 +239,18 @@ jobs:
           sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*
           sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
 
-      - name: Add Python 3 and other dependencies
-        run: yum update -y && yum install -y python3-devel gcc-c++ make
+      - name: Update YUM/DNF
+        run: yum update -y
 
-      - name: Setup Endpoint repository (CentOS 7 only)
+      - name: Enable extra repositories && modify PATH (CentOS 7)
         if: matrix.centos == 7
-        run: yum -y install https://packages.endpointdev.com/rhel/7/os/x86_64/endpoint-repo.x86_64.rpm
+        run: |
+          yum install -y centos-release-scl-rh
+          yum -y install https://packages.endpointdev.com/rhel/7/os/x86_64/endpoint-repo.x86_64.rpm
+          echo '/opt/rh/rh-python38/root/usr/bin' >> $GITHUB_PATH
+
+      - name: Add Python 3 and other dependencies
+        run: yum install -y ${{ matrix.enable_repo }} ${{ matrix.python_pkg }} gcc-c++ make
 
       - name: Install Git > 2.18
         run: |
@@ -259,12 +272,9 @@ jobs:
         uses: actions/cache@v3
         with:
           path: ~/.cache/pip
-          key: ${{ runner.os }}-centos${{ matrix.centos }}-pip-${{ hashFiles('**/setup.cfg') }}
+          key: ${{ runner.os }}-centos${{ matrix.centos }}-pip-${{ hashFiles('**/setup.cfg', '**/pyproject.toml') }}
           restore-keys: ${{ runner.os }}-centos-pip-
 
-      - name: Update pip
-        run: python3 -m pip install --upgrade pip
-
       - name: Install dependencies
         run: |
           python3 -m pip install -U pip setuptools wheel
@@ -288,16 +298,6 @@ jobs:
     steps:
       - uses: actions/checkout@v3
 
-      - name: Create pip cache dir
-        run: mkdir -p ~/.cache/pip
-
-      - name: Cache wheels
-        uses: actions/cache@v3
-        with:
-          path: ~/.cache/pip
-          key: ${{ runner.os }}-doc-pip-${{ hashFiles('**/setup.cfg') }}
-          restore-keys: ${{ runner.os }}-doc-pip-
-
       - name: Get history and tags for SCM versioning to work
         if: ${{ !env.ACT }}
         run: |
@@ -308,6 +308,10 @@ jobs:
         with:
           python-version: '3.x'
           architecture: 'x64'
+          cache: 'pip'
+          cache-dependency-path: |
+            setup.cfg
+            pyproject.toml
 
       - name: Install docs & setup requirements
         run: |
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b1fae5e28..52e8ba08a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -223,19 +223,11 @@ The ProjectQ v0.5.x release branch is the last one that is guaranteed to work wi
 
 Future releases might introduce changes that will require Python 3.5 (Python 3.4 and earlier have already been declared deprecated at the time of this writing)
 
-<<<<<<< HEAD
-[Unreleased]: https://github.com/ProjectQ-Framework/ProjectQ/compare/v0.7.3...HEAD
-
-[v0.7.3]: https://github.com/ProjectQ-Framework/ProjectQ/compare/v0.7.2...v0.7.3
-||||||| 41e608d
-[Unreleased]: https://github.com/ProjectQ-Framework/ProjectQ/compare/v0.7.2...HEAD
-=======
 [Unreleased]: https://github.com/ProjectQ-Framework/ProjectQ/compare/v0.8.0...HEAD
 
 [v0.8.0]: https://github.com/ProjectQ-Framework/ProjectQ/compare/v0.7.3...v0.8.0
 
 [v0.7.3]: https://github.com/ProjectQ-Framework/ProjectQ/compare/v0.7.2...v0.7.3
->>>>>>> master
 
 [v0.7.2]: https://github.com/ProjectQ-Framework/ProjectQ/compare/v0.7.1...v0.7.2
 

From 7cac539230fe5025833fe1804e758e2c44fe0ec7 Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
 <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Mon, 31 Oct 2022 22:44:06 +0100
Subject: [PATCH 13/25] [pre-commit.ci] pre-commit autoupdate (#454)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* [pre-commit.ci] pre-commit autoupdate

updates:
- [github.com/asottile/pyupgrade: v3.1.0 → v3.2.0](https://github.com/asottile/pyupgrade/compare/v3.1.0...v3.2.0)
- https://gitlab.com/PyCQA/flake8 → https://github.com/PyCQA/flake8
- [github.com/PyCQA/flake8: 3.9.2 → 5.0.4](https://github.com/PyCQA/flake8/compare/3.9.2...5.0.4)

* Update CHANGELOG

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Nguyen Damien <ngn.damien@gmail.com>
---
 .pre-commit-config.yaml | 6 +++---
 CHANGELOG.md            | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 729fded8d..770f638c3 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -73,7 +73,7 @@ repos:
         require_serial: false
 
   - repo: https://github.com/asottile/pyupgrade
-    rev: v3.1.0
+    rev: v3.2.0
     hooks:
       - id: pyupgrade
         args: [--py37-plus, --keep-mock]
@@ -97,8 +97,8 @@ repos:
         args: [-S, -l, '120']
         additional_dependencies: [black==22.10.0]
 
-  - repo: https://gitlab.com/PyCQA/flake8
-    rev: 3.9.2
+  - repo: https://github.com/PyCQA/flake8
+    rev: 5.0.4
     hooks:
       - id: flake8
         name: flake8-strict
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 52e8ba08a..a95a98fd3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,8 +16,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 -   Update GitHub workflow action versions: `actions/cache@v3`, `actions/checkout@v3`, `actions/setup-python@v4`
 -   Introduce pre-commit CI
 -   Update to clang-tidy 14 in GitHub workflow
--   Update pre-commit hook versions
 -   Added new pre-commit hooks: `codespell`, `doc8`, `pydocstyle` and `yamllint`
+-   Update pre-commit hook versions
 
 ## [v0.8.0] - 2022-10-18
 

From 4b278330d20dbe5f0000a61d17bafaf1e1c5ce08 Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
 <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Mon, 30 Jan 2023 23:32:07 +0100
Subject: [PATCH 14/25] [pre-commit.ci] pre-commit autoupdate (#455)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* [pre-commit.ci] pre-commit autoupdate

updates:
- [github.com/pre-commit/pre-commit-hooks: v4.3.0 → v4.4.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.3.0...v4.4.0)
- [github.com/Lucas-C/pre-commit-hooks: v1.3.1 → v1.4.2](https://github.com/Lucas-C/pre-commit-hooks/compare/v1.3.1...v1.4.2)
- [github.com/pycqa/pydocstyle: 6.1.1 → 6.3.0](https://github.com/pycqa/pydocstyle/compare/6.1.1...6.3.0)
- https://github.com/PyCQA/doc8/: v1.0.0 → v1.1.1
- [github.com/adrienverge/yamllint.git: v1.28.0 → v1.29.0](https://github.com/adrienverge/yamllint.git/compare/v1.28.0...v1.29.0)
- [github.com/asottile/pyupgrade: v3.2.0 → v3.3.1](https://github.com/asottile/pyupgrade/compare/v3.2.0...v3.3.1)
- [github.com/PyCQA/isort: 5.10.1 → 5.12.0](https://github.com/PyCQA/isort/compare/5.10.1...5.12.0)
- [github.com/psf/black: 22.10.0 → 22.12.0](https://github.com/psf/black/compare/22.10.0...22.12.0)
- [github.com/asottile/blacken-docs: v1.12.1 → 1.13.0](https://github.com/asottile/blacken-docs/compare/v1.12.1...1.13.0)
- [github.com/PyCQA/flake8: 5.0.4 → 6.0.0](https://github.com/PyCQA/flake8/compare/5.0.4...6.0.0)
- [github.com/mgedmin/check-manifest: 0.48 → 0.49](https://github.com/mgedmin/check-manifest/compare/0.48...0.49)

* Update CHANGELOG and keep Flake8 5.X

* Disable `no-member` Pylint warning on pre-commit CI

* Fix failing GitHub workflows

* Proper fix for Clang-10 workflow

* New attempt at fixing build for Clang-10

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Add Git workaround on all container workflows

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Fix Clang-10 build again

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Nguyen Damien <ngn.damien@gmail.com>
---
 .github/workflows/ci.yml | 19 ++++++++++++++++++-
 .pre-commit-config.yaml  | 22 +++++++++++-----------
 CHANGELOG.md             |  3 +++
 3 files changed, 32 insertions(+), 12 deletions(-)

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 81e77c60d..0086ff23b 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -112,12 +112,21 @@ jobs:
     env:
       CC: clang
       CXX: clang++
-      PROJECTQ_CLEANUP_COMPILER_FLAGS: ${{ (matrix.clang < 10) && 1 || 0 }}
+      PROJECTQ_CLEANUP_COMPILER_FLAGS: ${{ (matrix.clang <= 10) && 1 || 0 }}
 
     name: "Python 3 • Clang ${{ matrix.clang }} • x64"
     container: "silkeh/clang:${{ matrix.clang }}"
 
     steps:
+      - name: Install Git
+        if: matrix.clang == 10
+        run: |
+          apt-get update && apt-get install -y git --no-install-recommends
+
+      # Work-around for https://github.com/actions/runner-images/issues/6775
+      - name: Change Owner of Container Working Directory
+        run: chown root:root .
+
       - uses: actions/checkout@v3
 
       - name: Get history and tags for SCM versioning to work
@@ -168,6 +177,10 @@ jobs:
     steps:
       - uses: actions/checkout@v3
 
+      # Work-around for https://github.com/actions/runner-images/issues/6775
+      - name: Change Owner of Container Working Directory
+        run: chown root:root .
+
       - name: Get history and tags for SCM versioning to work
         if: ${{ !env.ACT }}
         run: |
@@ -257,6 +270,10 @@ jobs:
           yum install -y git
           git config --global --add safe.directory /__w/ProjectQ/ProjectQ
 
+      # Work-around for https://github.com/actions/runner-images/issues/6775
+      - name: Change Owner of Container Working Directory
+        run: chown root:root .
+
       - uses: actions/checkout@v3
 
       - name: Get history and tags for SCM versioning to work
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 770f638c3..424f0f1d7 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -23,7 +23,7 @@ repos:
       - id: check-useless-excludes
 
   - repo: https://github.com/pre-commit/pre-commit-hooks
-    rev: v4.3.0
+    rev: v4.4.0
     hooks:
       - id: check-added-large-files
       - id: check-ast
@@ -40,19 +40,19 @@ repos:
 
   # Changes tabs to spaces
   - repo: https://github.com/Lucas-C/pre-commit-hooks
-    rev: v1.3.1
+    rev: v1.4.2
     hooks:
       - id: remove-tabs
 
   - repo: https://github.com/pycqa/pydocstyle
-    rev: 6.1.1
+    rev: 6.3.0
     hooks:
       - id: pydocstyle
         exclude: (_test.*\.py)$
         additional_dependencies: [toml]
 
   - repo: https://github.com/PyCQA/doc8/
-    rev: v1.0.0
+    rev: v1.1.1
     hooks:
       - id: doc8
         require_serial: false
@@ -67,31 +67,31 @@ repos:
         args: [-S, '.git,third_party', -I, .codespell.allow]
 
   - repo: https://github.com/adrienverge/yamllint.git
-    rev: v1.28.0
+    rev: v1.29.0
     hooks:
       - id: yamllint
         require_serial: false
 
   - repo: https://github.com/asottile/pyupgrade
-    rev: v3.2.0
+    rev: v3.3.1
     hooks:
       - id: pyupgrade
         args: [--py37-plus, --keep-mock]
 
   - repo: https://github.com/PyCQA/isort
-    rev: 5.10.1
+    rev: 5.12.0
     hooks:
       - id: isort
         name: isort (python)
 
   - repo: https://github.com/psf/black
-    rev: 22.10.0
+    rev: 22.12.0
     hooks:
       - id: black
         language_version: python3
 
   - repo: https://github.com/asottile/blacken-docs
-    rev: v1.12.1
+    rev: 1.13.0
     hooks:
       - id: blacken-docs
         args: [-S, -l, '120']
@@ -116,11 +116,11 @@ repos:
     rev: 'v3.0.0a5'
     hooks:
       - id: pylint
-        args: ['--score=n']
+        args: ['--score=n', '--disable=no-member']
         additional_dependencies: [pybind11>=2.6, numpy, requests, matplotlib, networkx]
 
   - repo: https://github.com/mgedmin/check-manifest
-    rev: '0.48'
+    rev: '0.49'
     hooks:
       - id: check-manifest
         additional_dependencies: ['setuptools-scm', 'pybind11>=2.6']
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a95a98fd3..0aae8b1f5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,10 +14,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 ### Repository
 
 -   Update GitHub workflow action versions: `actions/cache@v3`, `actions/checkout@v3`, `actions/setup-python@v4`
+-   Fix failing GitHub workflows (Clang-10)
 -   Introduce pre-commit CI
 -   Update to clang-tidy 14 in GitHub workflow
 -   Added new pre-commit hooks: `codespell`, `doc8`, `pydocstyle` and `yamllint`
 -   Update pre-commit hook versions
+-   Keep `flake8` hook to version 5.0.4 until plugin support Flake8 6.X
+-   Disable `no-member` warning for Pylint on pre-commit CI
 
 ## [v0.8.0] - 2022-10-18
 

From 9f2198221e3f2b92b736fe23bd0c6723ccdfc87c Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 31 Jan 2023 00:03:48 +0100
Subject: [PATCH 15/25] Bump thomaseizinger/create-pull-request from 1.2.2 to
 1.3.0 (#456)

* Bump thomaseizinger/create-pull-request from 1.2.2 to 1.3.0

Bumps [thomaseizinger/create-pull-request](https://github.com/thomaseizinger/create-pull-request) from 1.2.2 to 1.3.0.
- [Release notes](https://github.com/thomaseizinger/create-pull-request/releases)
- [Changelog](https://github.com/thomaseizinger/create-pull-request/blob/master/CHANGELOG.md)
- [Commits](https://github.com/thomaseizinger/create-pull-request/compare/1.2.2...1.3.0)

---
updated-dependencies:
- dependency-name: thomaseizinger/create-pull-request
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* Update CHANGELOG

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Nguyen Damien <ngn.damien@gmail.com>
---
 .github/workflows/draft_release.yml   | 2 +-
 .github/workflows/publish_release.yml | 2 +-
 CHANGELOG.md                          | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/draft_release.yml b/.github/workflows/draft_release.yml
index 2c54ffd07..514bf0346 100644
--- a/.github/workflows/draft_release.yml
+++ b/.github/workflows/draft_release.yml
@@ -49,7 +49,7 @@ jobs:
 
       # yamllint disable rule:line-length
       - name: Create pull request
-        uses: thomaseizinger/create-pull-request@1.2.2
+        uses: thomaseizinger/create-pull-request@1.3.0
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
         with:
diff --git a/.github/workflows/publish_release.yml b/.github/workflows/publish_release.yml
index f6a25fd07..d2c988358 100644
--- a/.github/workflows/publish_release.yml
+++ b/.github/workflows/publish_release.yml
@@ -266,7 +266,7 @@ jobs:
       - upload_to_pypi
     steps:
       - name: Merge master into develop branch
-        uses: thomaseizinger/create-pull-request@1.2.2
+        uses: thomaseizinger/create-pull-request@1.3.0
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
         with:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0aae8b1f5..7d0af631a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,7 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Repository
 
--   Update GitHub workflow action versions: `actions/cache@v3`, `actions/checkout@v3`, `actions/setup-python@v4`
+-   Update GitHub workflow action versions: `actions/cache@v3`, `actions/checkout@v3`, `actions/setup-python@v4`, `thomaseizinger/create-pull-request`
 -   Fix failing GitHub workflows (Clang-10)
 -   Introduce pre-commit CI
 -   Update to clang-tidy 14 in GitHub workflow

From 439ffd5110a0fe982306743a95910ba816403a1d Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
 <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Mon, 6 Feb 2023 23:14:15 +0100
Subject: [PATCH 16/25] [pre-commit.ci] pre-commit autoupdate (#458)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* [pre-commit.ci] pre-commit autoupdate

updates:
- [github.com/psf/black: 22.12.0 → 23.1.0](https://github.com/psf/black/compare/22.12.0...23.1.0)
- [github.com/PyCQA/flake8: 5.0.4 → 6.0.0](https://github.com/PyCQA/flake8/compare/5.0.4...6.0.0)

* Update CHANGELOG and keep flake8 5.0.4 for pre-commit hooks

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Damien Nguyen <ngn.damien@gmail.com>
---
 .pre-commit-config.yaml                                   | 2 +-
 CHANGELOG.md                                              | 2 +-
 projectq/backends/_aqt/_aqt_http_client.py                | 1 -
 .../backends/_awsbraket/_awsbraket_boto3_client_test.py   | 2 --
 projectq/backends/_ibm/_ibm_http_client.py                | 1 -
 projectq/backends/_ionq/_ionq.py                          | 1 -
 projectq/backends/_sim/_pysim.py                          | 4 ++--
 projectq/setups/awsbraket_test.py                         | 2 --
 projectq/setups/trapped_ion_decomposer_test.py            | 1 -
 setup.py                                                  | 8 +++++++-
 10 files changed, 11 insertions(+), 13 deletions(-)

diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 424f0f1d7..5bbc0be35 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -85,7 +85,7 @@ repos:
         name: isort (python)
 
   - repo: https://github.com/psf/black
-    rev: 22.12.0
+    rev: 23.1.0
     hooks:
       - id: black
         language_version: python3
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7d0af631a..726187b7e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,7 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 -   Update to clang-tidy 14 in GitHub workflow
 -   Added new pre-commit hooks: `codespell`, `doc8`, `pydocstyle` and `yamllint`
 -   Update pre-commit hook versions
--   Keep `flake8` hook to version 5.0.4 until plugin support Flake8 6.X
+-   Keep `flake8` hook to version 5.0.4 until plugins support Flake8 6.X
 -   Disable `no-member` warning for Pylint on pre-commit CI
 
 ## [v0.8.0] - 2022-10-18
diff --git a/projectq/backends/_aqt/_aqt_http_client.py b/projectq/backends/_aqt/_aqt_http_client.py
index a545ab2d0..b2c8d9048 100644
--- a/projectq/backends/_aqt/_aqt_http_client.py
+++ b/projectq/backends/_aqt/_aqt_http_client.py
@@ -136,7 +136,6 @@ def _handle_sigint_during_get_result(*_):  # pragma: no cover
             signal.signal(signal.SIGINT, _handle_sigint_during_get_result)
 
             for retries in range(num_retries):
-
                 argument = {'id': execution_id, 'access_token': self.token}
                 req = super().put(urljoin(_API_URL, self.backends[device]['url']), data=argument)
                 req.raise_for_status()
diff --git a/projectq/backends/_awsbraket/_awsbraket_boto3_client_test.py b/projectq/backends/_awsbraket/_awsbraket_boto3_client_test.py
index 93cc994de..2b6e33e05 100644
--- a/projectq/backends/_awsbraket/_awsbraket_boto3_client_test.py
+++ b/projectq/backends/_awsbraket/_awsbraket_boto3_client_test.py
@@ -180,7 +180,6 @@ def test_send_too_many_qubits(mocker, send_too_many_setup):
     ],
 )
 def test_send_real_device_online_verbose(mocker, var_status, var_result, real_device_online_setup):
-
     (
         qtarntask,
         creds,
@@ -285,7 +284,6 @@ def test_send_that_errors_are_caught(mocker, var_error, send_that_error_setup):
 @has_boto3
 @pytest.mark.parametrize("var_error", [('ResourceNotFoundException')])
 def test_retrieve_error_arn_not_exist(mocker, var_error, arntask, creds):
-
     mock_boto3_client = mocker.MagicMock(spec=['get_quantum_task'])
     mock_boto3_client.get_quantum_task.side_effect = botocore.exceptions.ClientError(
         {"Error": {"Code": var_error, "Message": f"Msg error for {var_error}"}},
diff --git a/projectq/backends/_ibm/_ibm_http_client.py b/projectq/backends/_ibm/_ibm_http_client.py
index 815a04626..27602984b 100755
--- a/projectq/backends/_ibm/_ibm_http_client.py
+++ b/projectq/backends/_ibm/_ibm_http_client.py
@@ -228,7 +228,6 @@ def _handle_sigint_during_get_result(*_):  # pragma: no cover
         try:
             signal.signal(signal.SIGINT, _handle_sigint_during_get_result)
             for retries in range(num_retries):
-
                 # STEP5: WAIT FOR THE JOB TO BE RUN
                 json_step5 = {'allow_redirects': True, 'timeout': (self.timeout, None)}
                 request = super().get(urljoin(_API_URL, job_status_url), **json_step5)
diff --git a/projectq/backends/_ionq/_ionq.py b/projectq/backends/_ionq/_ionq.py
index cd70b75a0..4c59369c7 100644
--- a/projectq/backends/_ionq/_ionq.py
+++ b/projectq/backends/_ionq/_ionq.py
@@ -205,7 +205,6 @@ def _store(self, cmd):
         targets = [qb.id for qureg in cmd.qubits for qb in qureg]
         controls = [qb.id for qb in cmd.control_qubits]
         if len(self._measured_ids) > 0:
-
             # Check any qubits we are trying to operate on.
             gate_qubits = set(targets) | set(controls)
 
diff --git a/projectq/backends/_sim/_pysim.py b/projectq/backends/_sim/_pysim.py
index 05b7477c0..51a4eb165 100755
--- a/projectq/backends/_sim/_pysim.py
+++ b/projectq/backends/_sim/_pysim.py
@@ -236,7 +236,7 @@ def get_expectation_value(self, terms_dict, ids):
         """
         expectation = 0.0
         current_state = _np.copy(self._state)
-        for (term, coefficient) in terms_dict:
+        for term, coefficient in terms_dict:
             self._apply_term(term, ids)
             delta = coefficient * _np.vdot(current_state, self._state).real
             expectation += delta
@@ -253,7 +253,7 @@ def apply_qubit_operator(self, terms_dict, ids):
         """
         new_state = _np.zeros_like(self._state)
         current_state = _np.copy(self._state)
-        for (term, coefficient) in terms_dict:
+        for term, coefficient in terms_dict:
             self._apply_term(term, ids)
             self._state *= coefficient
             new_state += self._state
diff --git a/projectq/setups/awsbraket_test.py b/projectq/setups/awsbraket_test.py
index a0455258f..a4a95d469 100644
--- a/projectq/setups/awsbraket_test.py
+++ b/projectq/setups/awsbraket_test.py
@@ -132,7 +132,6 @@
 @patch('boto3.client')
 @pytest.mark.parametrize("var_device", ['SV1', 'Aspen-8', 'IonQ Device'])
 def test_awsbraket_get_engine_list(mock_boto3_client, var_device):
-
     mock_boto3_client.return_value = mock_boto3_client
     mock_boto3_client.search_devices.return_value = search_value
     mock_boto3_client.get_device.return_value = device_value
@@ -144,7 +143,6 @@ def test_awsbraket_get_engine_list(mock_boto3_client, var_device):
 @has_boto3
 @patch('boto3.client')
 def test_awsbraket_error(mock_boto3_client):
-
     mock_boto3_client.return_value = mock_boto3_client
     mock_boto3_client.search_devices.return_value = search_value
     mock_boto3_client.get_device.return_value = device_value
diff --git a/projectq/setups/trapped_ion_decomposer_test.py b/projectq/setups/trapped_ion_decomposer_test.py
index 2638aac83..8670ef1e9 100644
--- a/projectq/setups/trapped_ion_decomposer_test.py
+++ b/projectq/setups/trapped_ion_decomposer_test.py
@@ -138,7 +138,6 @@ def test_chooser_Ry_reducer():
         ),
         (get_engine_list(), 11),
     ]:
-
         backend = DummyEngine(save_commands=True)
         eng = projectq.MainEngine(backend, engine_list, verbose=True)
         qubit1 = eng.allocate_qubit()
diff --git a/setup.py b/setup.py
index 84e6d57af..5605d3e0c 100755
--- a/setup.py
+++ b/setup.py
@@ -380,7 +380,13 @@ def build_extensions(self):
 
     def _get_compilation_commands(self, ext):
         # pylint: disable=protected-access
-        (_, objects, extra_postargs, pp_opts, build,) = self.compiler._setup_compile(
+        (
+            _,
+            objects,
+            extra_postargs,
+            pp_opts,
+            build,
+        ) = self.compiler._setup_compile(
             outdir=self.build_temp,
             sources=ext.sources,
             macros=ext.define_macros,

From 92594453a89c8cb1746237a57aaf953b643347dd Mon Sep 17 00:00:00 2001
From: Nguyen Damien <ngn.damien@gmail.com>
Date: Thu, 9 Mar 2023 17:01:56 +0100
Subject: [PATCH 17/25] Update GitHub workflows to work with merge queues
 (#461)

---
 .github/workflows/ci.yml           | 1 +
 .github/workflows/format.yml       | 1 +
 .github/workflows/pull_request.yml | 1 +
 CHANGELOG.md                       | 1 +
 4 files changed, 4 insertions(+)

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 0086ff23b..84a63d78a 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -4,6 +4,7 @@ name: CI
 
 on:
   workflow_dispatch:
+  merge_group:
   pull_request:
   push:
     branches:
diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml
index c2ce1e4bf..6c83dd693 100644
--- a/.github/workflows/format.yml
+++ b/.github/workflows/format.yml
@@ -4,6 +4,7 @@ name: Format
 
 on:
   workflow_dispatch:
+  merge_group:
   pull_request:
   push:
     branches:
diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml
index 9325a3ab6..b7a90cdde 100644
--- a/.github/workflows/pull_request.yml
+++ b/.github/workflows/pull_request.yml
@@ -2,6 +2,7 @@
 
 name: PR
 on:
+  merge_group:
   pull_request:
     types: [opened, synchronize, reopened, ready_for_review, labeled, unlabeled]
 
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 726187b7e..3e50339fb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Repository
 
+-   Update GitHub workflows to work with merge queues
 -   Update GitHub workflow action versions: `actions/cache@v3`, `actions/checkout@v3`, `actions/setup-python@v4`, `thomaseizinger/create-pull-request`
 -   Fix failing GitHub workflows (Clang-10)
 -   Introduce pre-commit CI

From 67c660ca18725d23ab0b261a45e34873b6a58d03 Mon Sep 17 00:00:00 2001
From: Ikko Eltociear Ashimine <eltociear@gmail.com>
Date: Fri, 10 Mar 2023 01:03:57 +0900
Subject: [PATCH 18/25] Fix typo in compiler_tutorial.ipynb (#460)

* Fix typo in compiler_tutorial.ipynb

documention -> documentation

* Update CHANGELOG

---------

Co-authored-by: Nguyen Damien <ngn.damien@gmail.com>
---
 CHANGELOG.md                     | 4 ++++
 examples/compiler_tutorial.ipynb | 4 ++--
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3e50339fb..08fef0a62 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 -   Python context manager `with flushing(MainEngine()) as eng:`
 
+### Fixed
+
+-   Fixed some typos (thanks to @eltociear)
+
 ### Repository
 
 -   Update GitHub workflows to work with merge queues
diff --git a/examples/compiler_tutorial.ipynb b/examples/compiler_tutorial.ipynb
index 92cab21d7..68419fc4e 100644
--- a/examples/compiler_tutorial.ipynb
+++ b/examples/compiler_tutorial.ipynb
@@ -231,7 +231,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "Please have a look at the documention of the [restrictedgateset](http://projectq.readthedocs.io/en/latest/projectq.setups.html#module-projectq.setups.restrictedgateset) for details. The above compiler compiles the circuit to gates consisting of any single qubit gate, the `CNOT` and `Toffoli` gate. The gate specifications can either be a gate class, e.g., `Rz` or a specific instance `Rz(math.pi)`. A smaller but still universal gate set would be for example `CNOT` and `Rz, Ry`:"
+    "Please have a look at the documentation of the [restrictedgateset](http://projectq.readthedocs.io/en/latest/projectq.setups.html#module-projectq.setups.restrictedgateset) for details. The above compiler compiles the circuit to gates consisting of any single qubit gate, the `CNOT` and `Toffoli` gate. The gate specifications can either be a gate class, e.g., `Rz` or a specific instance `Rz(math.pi)`. A smaller but still universal gate set would be for example `CNOT` and `Rz, Ry`:"
    ]
   },
   {
@@ -292,7 +292,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "As mentioned in the documention of [this setup](http://projectq.readthedocs.io/en/latest/projectq.setups.html#module-projectq.setups.restrictedgateset), one cannot (yet) choose an arbitrary gate set but there is a limited choice. If it doesn't work for a specified gate set, the compiler will either raises a `NoGateDecompositionError` or a `RuntimeError: maximum recursion depth exceeded...` which means that for this particular choice of gate set, one would be required to write more [decomposition rules](https://github.com/ProjectQ-Framework/ProjectQ/tree/develop/projectq/setups/decompositions) to make it work. Also for some choice of gate set there might be compiler engines producing more optimal code."
+    "As mentioned in the documentation of [this setup](http://projectq.readthedocs.io/en/latest/projectq.setups.html#module-projectq.setups.restrictedgateset), one cannot (yet) choose an arbitrary gate set but there is a limited choice. If it doesn't work for a specified gate set, the compiler will either raises a `NoGateDecompositionError` or a `RuntimeError: maximum recursion depth exceeded...` which means that for this particular choice of gate set, one would be required to write more [decomposition rules](https://github.com/ProjectQ-Framework/ProjectQ/tree/develop/projectq/setups/decompositions) to make it work. Also for some choice of gate set there might be compiler engines producing more optimal code."
    ]
   },
   {

From 8cc782bdd205c6baa268aa567cc1885aa2f48506 Mon Sep 17 00:00:00 2001
From: Valentin Stauber <Darkdragon84@users.noreply.github.com>
Date: Sun, 7 Jan 2024 16:15:58 +0100
Subject: [PATCH 19/25] Update README.rst (#467)

* Update README.rst

fix imports in README example

* Update CHANGELOG.md
---
 CHANGELOG.md | 2 +-
 README.rst   | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 08fef0a62..3a099c501 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,7 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Fixed
 
--   Fixed some typos (thanks to @eltociear)
+-   Fixed some typos (thanks to @eltociear, @Darkdragon84)
 
 ### Repository
 
diff --git a/README.rst b/README.rst
index e8451dfae..3397c4070 100755
--- a/README.rst
+++ b/README.rst
@@ -85,7 +85,7 @@ linear chain and the architecture supports any single-qubit gate as well as the
 
     from projectq import MainEngine
     from projectq.backends import ResourceCounter
-    from projectq.ops import QFT
+    from projectq.ops import QFT, CNOT, Swap
     from projectq.setups import linear
 
     compiler_engines = linear.get_engine_list(num_qubits=16, one_qubit_gates='any', two_qubit_gates=(CNOT, Swap))

From cdb4d044eccc948eeea5f56d6a2bbd4a01099498 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Sun, 7 Jan 2024 16:16:25 +0100
Subject: [PATCH 20/25] Bump docker/setup-qemu-action from 2 to 3 (#466)

Bumps [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) from 2 to 3.
- [Release notes](https://github.com/docker/setup-qemu-action/releases)
- [Commits](https://github.com/docker/setup-qemu-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: docker/setup-qemu-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Nguyen Damien <ngn.damien@gmail.com>
---
 .github/workflows/publish_release.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/publish_release.yml b/.github/workflows/publish_release.yml
index d2c988358..d203057c5 100644
--- a/.github/workflows/publish_release.yml
+++ b/.github/workflows/publish_release.yml
@@ -33,7 +33,7 @@ jobs:
     steps:
       - name: Set up QEMU
         if: matrix.cibw_archs == 'aarch64'
-        uses: docker/setup-qemu-action@v2
+        uses: docker/setup-qemu-action@v3
         with:
           platforms: arm64
 

From c30dfec479c48092f261a93d34b60ce8740b26a1 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Sun, 7 Jan 2024 16:16:55 +0100
Subject: [PATCH 21/25] Bump thomaseizinger/create-pull-request from 1.3.0 to
 1.3.1 (#464)

* Bump thomaseizinger/create-pull-request from 1.3.0 to 1.3.1

Bumps [thomaseizinger/create-pull-request](https://github.com/thomaseizinger/create-pull-request) from 1.3.0 to 1.3.1.
- [Release notes](https://github.com/thomaseizinger/create-pull-request/releases)
- [Changelog](https://github.com/thomaseizinger/create-pull-request/blob/master/CHANGELOG.md)
- [Commits](https://github.com/thomaseizinger/create-pull-request/compare/1.3.0...1.3.1)

---
updated-dependencies:
- dependency-name: thomaseizinger/create-pull-request
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* Update CHANGELOG

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Nguyen Damien <ngn.damien@gmail.com>
---
 .github/workflows/draft_release.yml   | 2 +-
 .github/workflows/publish_release.yml | 2 +-
 CHANGELOG.md                          | 1 +
 3 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/draft_release.yml b/.github/workflows/draft_release.yml
index 514bf0346..7518c4a38 100644
--- a/.github/workflows/draft_release.yml
+++ b/.github/workflows/draft_release.yml
@@ -49,7 +49,7 @@ jobs:
 
       # yamllint disable rule:line-length
       - name: Create pull request
-        uses: thomaseizinger/create-pull-request@1.3.0
+        uses: thomaseizinger/create-pull-request@1.3.1
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
         with:
diff --git a/.github/workflows/publish_release.yml b/.github/workflows/publish_release.yml
index d203057c5..b431279fb 100644
--- a/.github/workflows/publish_release.yml
+++ b/.github/workflows/publish_release.yml
@@ -266,7 +266,7 @@ jobs:
       - upload_to_pypi
     steps:
       - name: Merge master into develop branch
-        uses: thomaseizinger/create-pull-request@1.3.0
+        uses: thomaseizinger/create-pull-request@1.3.1
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
         with:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3a099c501..62d3ab86a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -27,6 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 -   Keep `flake8` hook to version 5.0.4 until plugins support Flake8 6.X
 -   Disable `no-member` warning for Pylint on pre-commit CI
 
+
 ## [v0.8.0] - 2022-10-18
 
 ### Added

From dad48c59e0a7f4c114b5885a38439e7774698b39 Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
 <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Sun, 7 Jan 2024 17:05:07 +0100
Subject: [PATCH 22/25] [pre-commit.ci] pre-commit autoupdate (#459)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* [pre-commit.ci] pre-commit autoupdate

updates:
- [github.com/pre-commit/pre-commit-hooks: v4.4.0 → v4.5.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.4.0...v4.5.0)
- [github.com/Lucas-C/pre-commit-hooks: v1.4.2 → v1.5.4](https://github.com/Lucas-C/pre-commit-hooks/compare/v1.4.2...v1.5.4)
- [github.com/codespell-project/codespell: v2.2.2 → v2.2.6](https://github.com/codespell-project/codespell/compare/v2.2.2...v2.2.6)
- [github.com/adrienverge/yamllint.git: v1.29.0 → v1.33.0](https://github.com/adrienverge/yamllint.git/compare/v1.29.0...v1.33.0)
- [github.com/asottile/pyupgrade: v3.3.1 → v3.15.0](https://github.com/asottile/pyupgrade/compare/v3.3.1...v3.15.0)
- [github.com/PyCQA/isort: 5.12.0 → 5.13.2](https://github.com/PyCQA/isort/compare/5.12.0...5.13.2)
- [github.com/psf/black: 23.1.0 → 23.12.1](https://github.com/psf/black/compare/23.1.0...23.12.1)
- [github.com/asottile/blacken-docs: 1.13.0 → 1.16.0](https://github.com/asottile/blacken-docs/compare/1.13.0...1.16.0)
- [github.com/PyCQA/flake8: 5.0.4 → 6.1.0](https://github.com/PyCQA/flake8/compare/5.0.4...6.1.0)

* Temporary disable Azure Quantum backend

* Fix CI issues

* Fix CI issues with GCC build

* Fix typos

* Use virtualenv for GCC and Clang builds

* Update CHANGELOG

* Fix failing CI tests

* Fix failing CI tests

* Fix pre-commit issues + remove distutils.log

* Temporary disable step in failing CI job

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Nguyen Damien <ngn.damien@gmail.com>
---
 .github/workflows/ci.yml                      | 37 ++++++++++---------
 .pre-commit-config.yaml                       | 18 ++++-----
 CHANGELOG.md                                  |  2 +-
 docs/tutorials.rst                            |  2 +-
 .../backends/_azure/_azure_quantum_test.py    |  3 +-
 projectq/cengines/_linearmapper.py            |  2 +-
 projectq/cengines/_main_test.py               |  2 +-
 projectq/meta/_control.py                     |  2 +-
 projectq/ops/_command_test.py                 |  2 +-
 setup.py                                      |  5 +--
 10 files changed, 38 insertions(+), 37 deletions(-)

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 84a63d78a..ebe2d38d0 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -120,7 +120,6 @@ jobs:
 
     steps:
       - name: Install Git
-        if: matrix.clang == 10
         run: |
           apt-get update && apt-get install -y git --no-install-recommends
 
@@ -140,27 +139,27 @@ jobs:
         run: >
           apt-get update && apt-get install -y python3-dev python3-pip python3-setuptools python3-wheel
           python3-numpy python3-scipy python3-matplotlib python3-requests python3-networkx
-          python3-pytest python3-pytest-cov python3-flaky
-          libomp-dev
+          python3-pytest python3-pytest-cov python3-flaky python3-venv
           --no-install-recommends
 
       - name: Prepare Python env
         run: |
-          python3 -m pip install -U pip setuptools wheel
-          python3 setup.py gen_reqfile --include-extras=test,azure-quantum,braket
+          python3 -m venv venv
+          ./venv/bin/python3 -m pip install -U pip setuptools wheel
+          ./venv/bin/python3 setup.py gen_reqfile --include-extras=test,azure-quantum,braket
           cat requirements.txt
-          python3 -m pip install -r requirements.txt --prefer-binary
+          ./venv/bin/python3 -m pip install -r requirements.txt --prefer-binary
 
       - name: Upgrade pybind11 and flaky
-        run: python3 -m pip install --upgrade pybind11 flaky --prefer-binary
+        run: ./venv/bin/python3 -m pip install --upgrade pybind11 flaky --prefer-binary
 
       - name: Build and install package
-        run: python3 -m pip install -ve .[azure-quantum,braket,test]
+        run: ./venv/bin/python3 -m pip install -ve .[azure-quantum,braket,test]
 
       - name: Pytest
         run: |
           echo 'backend: Agg' > matplotlibrc
-          python3 -m pytest -p no:warnings
+          ./venv/bin/python3 -m pytest -p no:warnings
 
 
   gcc:
@@ -192,26 +191,27 @@ jobs:
         run: >
           apt-get update && apt-get install -y python3-dev python3-pip python3-setuptools python3-wheel
           python3-numpy python3-scipy python3-matplotlib python3-requests python3-networkx
-          python3-pytest python3-pytest-cov python3-flaky
+          python3-pytest python3-pytest-cov python3-flaky python3-venv
           --no-install-recommends
 
       - name: Prepare Python env
         run: |
-          python3 -m pip install -U pip setuptools wheel
-          python3 setup.py gen_reqfile --include-extras=test,azure-quantum,braket
+          python3 -m venv venv
+          ./venv/bin/python3 -m pip install -U pip setuptools wheel
+          ./venv/bin/python3 setup.py gen_reqfile --include-extras=test,azure-quantum,braket
           cat requirements.txt
-          python3 -m pip install -r requirements.txt --prefer-binary
+          ./venv/bin/python3 -m pip install -r requirements.txt --prefer-binary
 
       - name: Upgrade pybind11 and flaky
-        run: python3 -m pip install --upgrade pybind11 flaky --prefer-binary
+        run: ./venv/bin/python3 -m pip install --upgrade pybind11 flaky --prefer-binary
 
       - name: Build and install package
-        run: python3 -m pip install -ve .[azure-quantum,braket,test]
+        run: ./venv/bin/python3 -m pip install -ve .[azure-quantum,braket,test]
 
       - name: Pytest
         run: |
           echo 'backend: Agg' > matplotlibrc
-          python3 -m pytest -p no:warnings
+          ./venv/bin/python3 -m pytest -p no:warnings
 
 
   # Testing on CentOS (manylinux uses a centos base, and this is an easy way
@@ -338,5 +338,6 @@ jobs:
       - name: Build docs
         run: python3 -m sphinx -b html docs docs/.build
 
-      - name: Make SDist
-        run: python3 setup.py sdist
+      # NB: disabling until setup.py is updated to remove any mention of distutils
+      # - name: Make SDist
+      #  run: python3 setup.py sdist
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 5bbc0be35..27cfb9c49 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -23,7 +23,7 @@ repos:
       - id: check-useless-excludes
 
   - repo: https://github.com/pre-commit/pre-commit-hooks
-    rev: v4.4.0
+    rev: v4.5.0
     hooks:
       - id: check-added-large-files
       - id: check-ast
@@ -40,7 +40,7 @@ repos:
 
   # Changes tabs to spaces
   - repo: https://github.com/Lucas-C/pre-commit-hooks
-    rev: v1.4.2
+    rev: v1.5.4
     hooks:
       - id: remove-tabs
 
@@ -59,7 +59,7 @@ repos:
         additional_dependencies: [tomli]
 
   - repo: https://github.com/codespell-project/codespell
-    rev: v2.2.2
+    rev: v2.2.6
     hooks:
       - id: codespell
         require_serial: false
@@ -67,38 +67,38 @@ repos:
         args: [-S, '.git,third_party', -I, .codespell.allow]
 
   - repo: https://github.com/adrienverge/yamllint.git
-    rev: v1.29.0
+    rev: v1.33.0
     hooks:
       - id: yamllint
         require_serial: false
 
   - repo: https://github.com/asottile/pyupgrade
-    rev: v3.3.1
+    rev: v3.15.0
     hooks:
       - id: pyupgrade
         args: [--py37-plus, --keep-mock]
 
   - repo: https://github.com/PyCQA/isort
-    rev: 5.12.0
+    rev: 5.13.2
     hooks:
       - id: isort
         name: isort (python)
 
   - repo: https://github.com/psf/black
-    rev: 23.1.0
+    rev: 23.12.1
     hooks:
       - id: black
         language_version: python3
 
   - repo: https://github.com/asottile/blacken-docs
-    rev: 1.13.0
+    rev: 1.16.0
     hooks:
       - id: blacken-docs
         args: [-S, -l, '120']
         additional_dependencies: [black==22.10.0]
 
   - repo: https://github.com/PyCQA/flake8
-    rev: 5.0.4
+    rev: 6.1.0
     hooks:
       - id: flake8
         name: flake8-strict
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 62d3ab86a..d7fe748f0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -23,9 +23,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 -   Introduce pre-commit CI
 -   Update to clang-tidy 14 in GitHub workflow
 -   Added new pre-commit hooks: `codespell`, `doc8`, `pydocstyle` and `yamllint`
--   Update pre-commit hook versions
 -   Keep `flake8` hook to version 5.0.4 until plugins support Flake8 6.X
 -   Disable `no-member` warning for Pylint on pre-commit CI
+-   Update pre-commit hook versions
 
 
 ## [v0.8.0] - 2022-10-18
diff --git a/docs/tutorials.rst b/docs/tutorials.rst
index 3fba8c9da..dd264073d 100755
--- a/docs/tutorials.rst
+++ b/docs/tutorials.rst
@@ -239,7 +239,7 @@ Detailed instructions and OS-specific hints
         sudo port install py37-pip
 
     Next, we can install ProjectQ with the high performance simulator written in C++. First, we will need to install a
-    suitable compiler with support for **C++11**, OpenMP, and instrinsics. The best option is to install clang 9.0 also
+    suitable compiler with support for **C++11**, OpenMP, and intrinsics. The best option is to install clang 9.0 also
     using macports (note: gcc installed via macports does not work).
 
     .. code-block:: bash
diff --git a/projectq/backends/_azure/_azure_quantum_test.py b/projectq/backends/_azure/_azure_quantum_test.py
index 3cdc51bb2..f6d2193d2 100644
--- a/projectq/backends/_azure/_azure_quantum_test.py
+++ b/projectq/backends/_azure/_azure_quantum_test.py
@@ -22,7 +22,8 @@
 from projectq.ops import CX, All, Command, H, Measure
 from projectq.types import WeakQubitRef
 
-_has_azure_quantum = True
+# NB: temporary workaround until Azure Quantum backend is fixed
+_has_azure_quantum = False
 try:
     from azure.quantum import Workspace
 
diff --git a/projectq/cengines/_linearmapper.py b/projectq/cengines/_linearmapper.py
index c544fa9b6..0e39bbf56 100644
--- a/projectq/cengines/_linearmapper.py
+++ b/projectq/cengines/_linearmapper.py
@@ -121,7 +121,7 @@ def return_new_mapping(num_qubits, cyclic, currently_allocated_ids, stored_comma
         Build a mapping of qubits to a linear chain.
 
         It goes through stored_commands and tries to find a mapping to apply these gates on a first come first served
-        basis.  More compilicated scheme could try to optimize to apply as many gates as possible between the Swaps.
+        basis.  More complicated scheme could try to optimize to apply as many gates as possible between the Swaps.
 
         Args:
             num_qubits(int): Total number of qubits in the linear chain
diff --git a/projectq/cengines/_main_test.py b/projectq/cengines/_main_test.py
index 392fff73a..665e8815f 100755
--- a/projectq/cengines/_main_test.py
+++ b/projectq/cengines/_main_test.py
@@ -67,7 +67,7 @@ def test_main_engine_init_defaults():
 
     default_engines = projectq.setups.default.get_engine_list()
     for engine, expected in zip(eng_list, default_engines):
-        assert type(engine) == type(expected)
+        assert type(engine) is type(expected)
 
 
 def test_main_engine_too_many_compiler_engines():
diff --git a/projectq/meta/_control.py b/projectq/meta/_control.py
index 549e0e9e5..176892709 100755
--- a/projectq/meta/_control.py
+++ b/projectq/meta/_control.py
@@ -43,7 +43,7 @@ def canonical_ctrl_state(ctrl_state, num_qubits):
 
     Note:
         In case of integer values for `ctrl_state`, the least significant bit applies to the first qubit in the qubit
-        register, e.g. if ctrl_state == 2, its binary representation if '10' with the least significan bit being 0.
+        register, e.g. if ctrl_state == 2, its binary representation if '10' with the least significant bit being 0.
 
         This means in particular that the following are equivalent:
 
diff --git a/projectq/ops/_command_test.py b/projectq/ops/_command_test.py
index 0a315d64d..19db3644c 100755
--- a/projectq/ops/_command_test.py
+++ b/projectq/ops/_command_test.py
@@ -45,7 +45,7 @@ def test_command_init(main_engine):
     for cmd_qureg, expected_qureg in zip(cmd.qubits, expected_tuple):
         assert cmd_qureg[0].id == expected_qureg[0].id
         # Testing that Qubits are now WeakQubitRef objects
-        assert type(cmd_qureg[0]) == WeakQubitRef
+        assert type(cmd_qureg[0]) is WeakQubitRef
     assert cmd._engine == main_engine
     # Test that quregs are ordered if gate has interchangeable qubits:
     symmetric_gate = BasicGate()
diff --git a/setup.py b/setup.py
index 5605d3e0c..934c31ccf 100755
--- a/setup.py
+++ b/setup.py
@@ -39,7 +39,6 @@
 
 # pylint: disable=deprecated-module
 
-import distutils.log
 import os
 import platform
 import subprocess
@@ -655,7 +654,7 @@ def run(self):
         # that --dry-run --gen-compiledb are passed to build_ext regardless of
         # other arguments
         command = 'build_ext'
-        distutils.log.info("running %s --dry-run --gen-compiledb", command)
+        # distutils.log.info("running %s --dry-run --gen-compiledb", command)
         cmd_obj = self.get_finalized_command(command)
         cmd_obj.dry_run = True
         cmd_obj.gen_compiledb = True
@@ -663,7 +662,7 @@ def run(self):
             cmd_obj.run()
             self.distribution.have_run[command] = 1
         except BuildFailed as err:
-            distutils.log.error('build_ext --dry-run --gen-compiledb command failed!')
+            # distutils.log.error('build_ext --dry-run --gen-compiledb command failed!')
             raise RuntimeError('build_ext --dry-run --gen-compiledb command failed!') from err
 
         command = ['clang-tidy']

From 3897613f1f9dba2ba1845140d4b641ebcf53c9ba Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
 <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Mon, 25 Mar 2024 19:18:41 +0000
Subject: [PATCH 23/25] [pre-commit.ci] pre-commit autoupdate
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

updates:
- [github.com/Lucas-C/pre-commit-hooks: v1.5.4 → v1.5.5](https://github.com/Lucas-C/pre-commit-hooks/compare/v1.5.4...v1.5.5)
- [github.com/adrienverge/yamllint.git: v1.33.0 → v1.35.1](https://github.com/adrienverge/yamllint.git/compare/v1.33.0...v1.35.1)
- [github.com/asottile/pyupgrade: v3.15.0 → v3.15.2](https://github.com/asottile/pyupgrade/compare/v3.15.0...v3.15.2)
- [github.com/psf/black: 23.12.1 → 24.3.0](https://github.com/psf/black/compare/23.12.1...24.3.0)
- [github.com/PyCQA/flake8: 6.1.0 → 7.0.0](https://github.com/PyCQA/flake8/compare/6.1.0...7.0.0)
---
 .pre-commit-config.yaml | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 27cfb9c49..cf59ca9c0 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -40,7 +40,7 @@ repos:
 
   # Changes tabs to spaces
   - repo: https://github.com/Lucas-C/pre-commit-hooks
-    rev: v1.5.4
+    rev: v1.5.5
     hooks:
       - id: remove-tabs
 
@@ -67,13 +67,13 @@ repos:
         args: [-S, '.git,third_party', -I, .codespell.allow]
 
   - repo: https://github.com/adrienverge/yamllint.git
-    rev: v1.33.0
+    rev: v1.35.1
     hooks:
       - id: yamllint
         require_serial: false
 
   - repo: https://github.com/asottile/pyupgrade
-    rev: v3.15.0
+    rev: v3.15.2
     hooks:
       - id: pyupgrade
         args: [--py37-plus, --keep-mock]
@@ -85,7 +85,7 @@ repos:
         name: isort (python)
 
   - repo: https://github.com/psf/black
-    rev: 23.12.1
+    rev: 24.3.0
     hooks:
       - id: black
         language_version: python3
@@ -98,7 +98,7 @@ repos:
         additional_dependencies: [black==22.10.0]
 
   - repo: https://github.com/PyCQA/flake8
-    rev: 6.1.0
+    rev: 7.0.0
     hooks:
       - id: flake8
         name: flake8-strict

From 088c97380c88e3600e4d66fd2b411d9e833c5525 Mon Sep 17 00:00:00 2001
From: Nguyen Damien <ngn.damien@gmail.com>
Date: Tue, 2 Apr 2024 22:20:32 +0200
Subject: [PATCH 24/25] Update CHANGELOG

---
 CHANGELOG.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index d7fe748f0..6ac525fdf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,13 +19,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 -   Update GitHub workflows to work with merge queues
 -   Update GitHub workflow action versions: `actions/cache@v3`, `actions/checkout@v3`, `actions/setup-python@v4`, `thomaseizinger/create-pull-request`
+-   Update pre-commit hook versions
 -   Fix failing GitHub workflows (Clang-10)
 -   Introduce pre-commit CI
 -   Update to clang-tidy 14 in GitHub workflow
 -   Added new pre-commit hooks: `codespell`, `doc8`, `pydocstyle` and `yamllint`
 -   Keep `flake8` hook to version 5.0.4 until plugins support Flake8 6.X
 -   Disable `no-member` warning for Pylint on pre-commit CI
--   Update pre-commit hook versions
 
 
 ## [v0.8.0] - 2022-10-18

From f2a2c2117a668869b3864f8da2b14260276527de Mon Sep 17 00:00:00 2001
From: Nguyen Damien <ngn.damien@gmail.com>
Date: Tue, 23 Apr 2024 21:20:47 +0200
Subject: [PATCH 25/25] Remove Python 3.7 + add Python 3.11 + 3.12 (#471)

* Remove Python 3.7 + add Python 3.11 + 3.12

* Update cibuildwheel config

* Update black config

* Update minimum GCC and Clang version on CI

* Fix refcheck=False when in CI

* Update minimum package versions for 3rd-party dependencies

* Update CHANGELOG

* Fix compatibility with Python 3.12

* Fix linter warnings

* Update GitHub release workflows

* Fix setup.py

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Fix setup.py

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Automatically cancel redundant GitHub workflows

* Fix clang-tidy workflow

* Fix setuptools installation for CI runs

* Fix setup.py

* Test with naked except clause

* Fix exception handling when testing for compiler flags

* Fix linter warnings

* Fix typo

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
---
 .github/workflows/ci.yml              | 17 +++++++----
 .github/workflows/draft_release.yml   | 20 +++++++++----
 .github/workflows/format.yml          |  9 ++++--
 .github/workflows/publish_release.yml | 20 +++++--------
 CHANGELOG.md                          |  5 ++++
 docs/tutorials.rst                    | 12 ++++----
 projectq/backends/_sim/_pysim.py      |  2 +-
 pyproject.toml                        | 34 ++++++++-------------
 setup.py                              | 43 ++++++++++++++++-----------
 9 files changed, 92 insertions(+), 70 deletions(-)

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index ebe2d38d0..bb242ba80 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -12,6 +12,10 @@ on:
       - develop
       - v*
 
+concurrency:
+  group: ${{ github.workflow }}-${{ github.ref }}
+  cancel-in-progress: true
+
 jobs:
   standard:
     strategy:
@@ -19,10 +23,11 @@ jobs:
       matrix:
         runs-on: [ubuntu-latest, windows-latest, macos-latest]
         python:
-          - 3.7
           - 3.8
           - 3.9
           - '3.10'
+          - '3.11'
+          - '3.12'
 
     name: "Python ${{ matrix.python }} • ${{ matrix.runs-on }} • x64 ${{ matrix.args }}"
     runs-on: ${{ matrix.runs-on }}
@@ -46,6 +51,10 @@ jobs:
             setup.cfg
             pyproject.toml
 
+      - name: Prepare env
+        run: |
+          python -m pip install -U "setuptools>=61.0.0"
+
       - name: Generate requirement file (Unix)
         if: runner.os != 'Windows'
         run: |
@@ -106,9 +115,7 @@ jobs:
       fail-fast: false
       matrix:
         clang:
-          - 3.5  # version for full C++14 support (3.4 fails because of -fstack-protector-strong)
-          - 5    # earliest version for reasonable C++17 support
-          - 10   # version for full C++17 support (with patches)
+          - 11
           - latest
     env:
       CC: clang
@@ -168,7 +175,7 @@ jobs:
       fail-fast: false
       matrix:
         gcc:
-          - 7  # C++17 earliest version
+          - 9
           - latest
 
     name: "Python 3 • GCC ${{ matrix.gcc }} • x64"
diff --git a/.github/workflows/draft_release.yml b/.github/workflows/draft_release.yml
index 7518c4a38..63092b6dc 100644
--- a/.github/workflows/draft_release.yml
+++ b/.github/workflows/draft_release.yml
@@ -2,7 +2,7 @@
 
 name: "Draft new release"
 
-on:
+on:  # yamllint disable-line rule:truthy
   workflow_dispatch:
     inputs:
       tag:
@@ -18,6 +18,13 @@ jobs:
 
       - uses: actions/checkout@v3
 
+      - name: Setup Python
+        uses: actions/setup-python@v3
+        with:
+          python-version: '3.11'
+          cache: 'pip'
+          cache-dependency-path: '**/setup.cfg'
+
       - name: Configure git-flow
         run: |
           git fetch --tags --depth=1 origin master develop
@@ -26,16 +33,17 @@ jobs:
       - name: Create release branch
         run: git flow release start ${{ github.event.inputs.tag }}
 
-      - name: Update changelog
-        uses: thomaseizinger/keep-a-changelog-new-release@1.3.0
-        with:
-          version: ${{ github.event.inputs.tag }}
-
       - name: Initialize mandatory git config
         run: |
           git config user.name "GitHub actions"
           git config user.email noreply@github.com
 
+      - name: Update CHANGELOG
+        run: |
+          python3 -m pip install mdformat-gfm 'git+https://github.com/Takishima/keepachangelog@v1.0.1'
+          python3 -m keepachangelog release "${{ github.event.inputs.tag }}"
+          python3 -m mdformat CHANGELOG.md
+
       - name: Commit changelog and manifest files
         id: make-commit
         run: |
diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml
index 6c83dd693..18a5a10c3 100644
--- a/.github/workflows/format.yml
+++ b/.github/workflows/format.yml
@@ -12,6 +12,11 @@ on:
       - stable
       - "v*"
 
+concurrency:
+  group: ${{ github.workflow }}-${{ github.ref }}
+  cancel-in-progress: true
+
+
 jobs:
   clang-tidy:
     name: Clang-Tidy
@@ -29,8 +34,8 @@ jobs:
           apt-get update && apt-get install -y python3-dev python3-pip python3-setuptools python3-wheel
           --no-install-recommends
 
-      - name: Upgrade pybind11
-        run: python3 -m pip install --upgrade pybind11 --prefer-binary
+      - name: Upgrade pybind11 and setuptools
+        run: python3 -m pip install --upgrade pybind11 "setuptools>=61.0.0" --prefer-binary
 
       - name: Run clang-tidy
         run: python3 setup.py clang_tidy --warning-as-errors
diff --git a/.github/workflows/publish_release.yml b/.github/workflows/publish_release.yml
index b431279fb..1695a745d 100644
--- a/.github/workflows/publish_release.yml
+++ b/.github/workflows/publish_release.yml
@@ -59,10 +59,9 @@ jobs:
           && startsWith(github.event.pull_request.head.ref, 'release/')
           && runner.os != 'Windows'
         run: |
-          BRANCH_NAME="${{ github.event.pull_request.head.ref }}"
-          VERSION=${BRANCH_NAME#release/}
-          echo "VERSION = ${VERSION}"
-          git tag ${VERSION} master
+          TAG_NAME="${GITHUB_REF/refs\/tags\//}"
+          VERSION=${TAG_NAME#v}
+          echo "RELEASE_VERSION=$VERSION" >> $GITHUB_ENV
 
       - name: Extract version from branch name (for hotfix branches) (Unix)
         if: >
@@ -71,9 +70,8 @@ jobs:
           && runner.os != 'Windows'
         run: |
           BRANCH_NAME="${{ github.event.pull_request.head.ref }}"
-          VERSION=${BRANCH_NAME#hotfix/}
-          echo "VERSION = ${VERSION}"
-          git tag ${VERSION} master
+          VERSION=${BRANCH_NAME#release/v}
+          echo "RELEASE_VERSION=$VERSION" >> $GITHUB_ENV
 
       # ------------------------------------------------------------------------
 
@@ -84,9 +82,8 @@ jobs:
           && runner.os == 'Windows'
         run: |
           $BRANCH_NAME="${{ github.event.pull_request.head.ref }}"
-          $VERSION = $BRANCH_NAME -replace "release/",""
-          Write-Output "VERSION = ${VERSION}"
-          git tag ${VERSION} master
+          $VERSION = $BRANCH_NAME -replace "release/v",""
+          Write-Output "VERSION = ${VERSION}" >> $Env:GITHUB_ENV
 
       - name: Extract version from branch name (for hotfix branches) (Windows)
         if: >
@@ -96,8 +93,7 @@ jobs:
         run: |
           $BRANCH_NAME="${{ github.event.pull_request.head.ref }}"
           $VERSION = $BRANCH_NAME -replace "hotfix/",""
-          Write-Output "VERSION = ${VERSION}"
-          git tag ${VERSION} master
+          Write-Output "VERSION = ${VERSION}" >> $Env:GITHUB_ENV
 
       # ========================================================================
 
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6ac525fdf..e58e12027 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,6 +14,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 ### Fixed
 
 -   Fixed some typos (thanks to @eltociear, @Darkdragon84)
+-   Fixed support for Python 3.12
+
+### Removed
+
+-   Support for Python 3.7
 
 ### Repository
 
diff --git a/docs/tutorials.rst b/docs/tutorials.rst
index dd264073d..fd6b8c08a 100755
--- a/docs/tutorials.rst
+++ b/docs/tutorials.rst
@@ -132,7 +132,7 @@ Detailed instructions and OS-specific hints
 **Windows**:
 
     It is easiest to install a pre-compiled version of Python, including numpy and many more useful packages. One way to
-    do so is using, e.g., the Python 3.7 installers from `python.org <https://www.python.org/downloads>`_ or `ANACONDA
+    do so is using, e.g., the Python 3.8 installers from `python.org <https://www.python.org/downloads>`_ or `ANACONDA
     <https://www.continuum.io/downloads>`_. Installing ProjectQ right away will succeed for the (slow) Python
     simulator. For a compiled version of the simulator, install the Visual C++ Build Tools and the Microsoft Windows SDK
     prior to doing a pip install. The built simulator will not support multi-threading due to the limited OpenMP support
@@ -220,23 +220,23 @@ Detailed instructions and OS-specific hints
     Visit `macports.org <https://www.macports.org/install.php>`_ and install the latest version that corresponds to your
     operating system's version. Afterwards, open a new terminal window.
 
-    Then, use macports to install Python 3.7 by entering the following command
+    Then, use macports to install Python 3.8 by entering the following command
 
     .. code-block:: bash
 
-        sudo port install python37
+        sudo port install python38
 
     It might show a warning that if you intend to use python from the terminal. In this case, you should also install
 
     .. code-block:: bash
 
-        sudo port install py37-gnureadline
+        sudo port install py38-gnureadline
 
     Install pip by
 
     .. code-block:: bash
 
-        sudo port install py37-pip
+        sudo port install py38-pip
 
     Next, we can install ProjectQ with the high performance simulator written in C++. First, we will need to install a
     suitable compiler with support for **C++11**, OpenMP, and intrinsics. The best option is to install clang 9.0 also
@@ -250,7 +250,7 @@ Detailed instructions and OS-specific hints
 
     .. code-block:: bash
 
-        env CC=clang-mp-9.0 env CXX=clang++-mp-9.0 /opt/local/bin/python3.7 -m pip install --user projectq
+        env CC=clang-mp-9.0 env CXX=clang++-mp-9.0 /opt/local/bin/python3.8 -m pip install --user projectq
 
 
 The ProjectQ syntax
diff --git a/projectq/backends/_sim/_pysim.py b/projectq/backends/_sim/_pysim.py
index 51a4eb165..f6fb58fd5 100755
--- a/projectq/backends/_sim/_pysim.py
+++ b/projectq/backends/_sim/_pysim.py
@@ -24,7 +24,7 @@
 import numpy as _np
 
 _USE_REFCHECK = True
-if 'TRAVIS' in os.environ:  # pragma: no cover
+if 'CI' in os.environ:  # pragma: no cover
     _USE_REFCHECK = False
 
 
diff --git a/pyproject.toml b/pyproject.toml
index 8d3b23afd..6e4686e23 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,10 +1,9 @@
 [build-system]
 requires = [
-    'setuptools>=61;python_version>="3.7"',
-    'setuptools>=59;python_version<"3.7"',
+    'setuptools>=61',
     'wheel',
     'pybind11>=2',
-    'setuptools_scm[toml]>6;python_version>="3.7"'
+    'setuptools_scm[toml]>6'
 ]
 build-backend = "setuptools.build_meta"
 
@@ -14,26 +13,27 @@ authors = [
      {name = 'ProjectQ', email = 'info@projectq.ch'}
 ]
 description = 'ProjectQ - An open source software framework for quantum computing'
-requires-python = '>= 3.7'
+requires-python = '>= 3.8'
 license = {text= 'Apache License Version 2.0'}
 readme = 'README.rst'
 classifiers = [
     'License :: OSI Approved :: Apache Software License',
     'Topic :: Software Development :: Libraries :: Python Modules',
     'Programming Language :: Python :: 3 :: Only',
-    'Programming Language :: Python :: 3.7',
     'Programming Language :: Python :: 3.8',
     'Programming Language :: Python :: 3.9',
-    'Programming Language :: Python :: 3.10'
+    'Programming Language :: Python :: 3.10',
+    'Programming Language :: Python :: 3.11',
+    'Programming Language :: Python :: 3.12'
 ]
 dynamic = ["version"]
 
 dependencies = [
     'matplotlib >= 2.2.3',
-    'networkx >= 2',
-    'numpy',
-    'requests',
-    'scipy'
+    'networkx >= 2.4',
+    'numpy>=1.21.5',
+    'requests>=2.25.1',
+    'scipy>=1.8.0'
 ]
 
 [project.urls]
@@ -57,7 +57,7 @@ revkit = [
 ]
 
 test = [
-     'flaky',
+     'flaky>=3.7.0',
      'mock',
      'pytest >= 6.0',
      'pytest-cov',
@@ -65,7 +65,7 @@ test = [
 ]
 
 docs = [
-     'sphinx',
+     'sphinx>=4.3.2',
      'sphinx_rtd_theme'
 ]
 
@@ -74,7 +74,7 @@ docs = [
 [tool.black]
 
     line-length = 120
-    target-version = ['py37','py38','py39','py310']
+    target-version = ['py38','py39','py310','py311','py312']
     skip-string-normalization = true
 
 
@@ -205,11 +205,3 @@ test-command = 'python {package}/examples/grover.py'
 
 # Normal options, etc.
 manylinux-x86_64-image = 'manylinux2014'
-
-[[tool.cibuildwheel.overrides]]
-select = 'cp36-*'
-manylinux-x86_64-image = 'manylinux1'
-
-[[tool.cibuildwheel.overrides]]
-select = 'cp3{7,8,9}-*'
-manylinux-x86_64-image = 'manylinux2010'
diff --git a/setup.py b/setup.py
index 934c31ccf..24a647bd4 100755
--- a/setup.py
+++ b/setup.py
@@ -37,29 +37,36 @@
 
 """Setup.py file."""
 
-# pylint: disable=deprecated-module
+# pylint: disable=deprecated-module,attribute-defined-outside-init
 
 import os
 import platform
 import subprocess
 import sys
 import tempfile
-from distutils.cmd import Command
-from distutils.errors import (
-    CCompilerError,
-    CompileError,
-    DistutilsExecError,
-    DistutilsPlatformError,
-    LinkError,
-)
-from distutils.spawn import find_executable, spawn
 from operator import itemgetter
 from pathlib import Path
 
+from setuptools import Command
 from setuptools import Distribution as _Distribution
 from setuptools import Extension, setup
 from setuptools.command.build_ext import build_ext
 
+try:
+    from setuptools._distutils.errors import (
+        CCompilerError,
+        CompileError,
+        DistutilsError,
+    )
+    from setuptools._distutils.spawn import DistutilsExecError, find_executable, spawn
+    from setuptools.errors import PlatformError
+
+    _SETUPTOOL_IMPORT_ERROR = None
+
+except ImportError as setuptools_import_error:
+    _SETUPTOOL_IMPORT_ERROR = setuptools_import_error
+
+
 try:
     import setuptools_scm  # noqa: F401  # pylint: disable=unused-import
 
@@ -232,7 +239,7 @@ def compiler_test(
             with open('err.txt') as err_file:
                 if err_file.readlines():
                     raise RuntimeError('')
-    except (CompileError, LinkError, RuntimeError):
+    except Exception:  # pylint: disable=broad-except
         return False
     else:
         return True
@@ -277,7 +284,9 @@ def __init__(self):
 # Python build related variable
 
 cpython = platform.python_implementation() == 'CPython'
-ext_errors = (CCompilerError, DistutilsExecError, DistutilsPlatformError)
+ext_errors = ()
+if _SETUPTOOL_IMPORT_ERROR is None:
+    ext_errors = (CCompilerError, DistutilsError, CompileError, DistutilsExecError)
 if sys.platform == 'win32':
     # 2.6's distutils.msvc9compiler can raise an IOError when failing to
     # find the compiler
@@ -329,13 +338,16 @@ def finalize_options(self):
         """Finalize this command's options."""
         build_ext.finalize_options(self)
         if self.gen_compiledb:
-            self.dry_run = True  # pylint: disable=attribute-defined-outside-init
+            self.dry_run = True
 
     def run(self):
         """Execute this command."""
+        if _SETUPTOOL_IMPORT_ERROR is not None:
+            raise _SETUPTOOL_IMPORT_ERROR
+
         try:
             build_ext.run(self)
-        except DistutilsPlatformError as err:
+        except PlatformError as err:
             raise BuildFailed() from err
 
     def build_extensions(self):
@@ -416,8 +428,6 @@ def _get_compilation_commands(self, ext):
         return commands
 
     def _configure_compiler(self):
-        # pylint: disable=attribute-defined-outside-init
-
         # Force dry_run = False to allow for compiler feature testing
         dry_run_old = self.compiler.dry_run
         self.compiler.dry_run = False
@@ -703,7 +713,6 @@ def finalize_options(self):
             if self.include_all_extras or name in include_extras:
                 self.extra_pkgs.extend(pkgs)
 
-        # pylint: disable=attribute-defined-outside-init
         self.dependencies = self.distribution.install_requires
         if not self.dependencies:
             self.dependencies = pyproject_toml['project']['dependencies']
