Repository: PennyLaneAI/pennylane
Pull request #7200 (2025-04-03 20:36:25)

fix problematic `__init__.py` imports
**Context:**

Replaced wildcard imports with explicit imports (e.g., `from module import * -> from module import SymbolA, SymbolB`) across relevant modules.

**Motivation:**

* Wildcard imports (`import *`) harm readability, obscure namespaces, hinder static analysis, and can cause name collisions.
* Explicit imports clarify dependencies and help mitigate circular import issues.
* Makes `I` alias accessible at the `ops` module level (and `ops.qubit` / `ops.qutrit`)

**Benefits:**

* **Improved Clarity & Maintainability:** Easier to understand code origins and track dependencies.
* **Namespace Safety:** Prevents accidental name clashes and pollution.
* **Better Tooling:** Enhances static analysis and IDE support.
* **Reduced Circular Import Risk:** Minimizes loaded symbols, clarifying the dependency graph.

**Potential Drawbacks:**

Minor risk that users are currently relying on symbols previously available only via wildcard imports. 🤷🏼 

[sc-88261]


github-actions[bot]: Hello. You may have forgotten to update the changelog!
Please edit [`doc/releases/changelog-dev.md`](/PennyLaneAI/pennylane/blob/master/doc/releases/changelog-dev.md) with:
* A one-to-two sentence description of the change. You may include a small working example for new features.
* A link back to this PR.
* Your name (or GitHub username) in the contributors section.
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/PennyLaneAI/pennylane/pull/7200?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 99.64%. Comparing base [(`def83ff`)](https://app.codecov.io/gh/PennyLaneAI/pennylane/commit/def83fff33a885aba6a2082155e8293d33b2543a?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) to head [(`b38f69e`)](https://app.codecov.io/gh/PennyLaneAI/pennylane/commit/b38f69ede1c5d2d617aa40252e436550aa0ea49a?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI).

<details><summary>Additional details and impacted files</summary>


```diff
@@           Coverage Diff           @@
##           master    #7200   +/-   ##
=======================================
  Coverage   99.64%   99.64%           
=======================================
  Files         511      511           
  Lines       49781    49782    +1     
=======================================
+ Hits        49605    49606    +1     
  Misses        176      176           
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/PennyLaneAI/pennylane/pull/7200?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI).

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>
JerryChen97: Mind adding `full tests` so that we don't miss any cornercases? @andrijapau 
andrijapau: > Mind adding `full tests` so that we don't miss any cornercases? @andrijapau

Good call! Will run the full suite now.

Patch:
diff --git a/.github/stable/external.txt b/.github/stable/external.txt
index 867982cf5..f07d8ce9d 100644
--- a/.github/stable/external.txt
+++ b/.github/stable/external.txt
@@ -140,10 +140,10 @@ pandocfilters==1.5.1
 parso==0.8.4
 pathspec==0.12.1
 pbr==6.1.1
-PennyLane-Catalyst==0.12.0.dev4
-PennyLane-qiskit @ git+https://github.com/PennyLaneAI/pennylane-qiskit.git@14779eb0cecfafd5a56c025bd22c411359936dd1
+PennyLane-Catalyst==0.11.0
+PennyLane-qiskit @ git+https://github.com/PennyLaneAI/pennylane-qiskit.git@af5226f4a10885e6e01935c6fc3564d94d30984d
 PennyLane_Lightning==0.41.0
-PennyLane_Lightning_Kokkos==0.41.0.dev22
+PennyLane_Lightning_Kokkos==0.41.0
 pexpect==4.9.0
 pillow==11.2.1
 platformdirs==4.3.7
diff --git a/doc/releases/changelog-dev.md b/doc/releases/changelog-dev.md
index 148200eb3..37d0caee0 100644
--- a/doc/releases/changelog-dev.md
+++ b/doc/releases/changelog-dev.md
@@ -6,12 +6,18 @@
 
 <h3>Improvements 🛠</h3>
 
+* Alias for Identity (`I`) is now accessible from `qml.ops`.
+  [(#7200)](https://github.com/PennyLaneAI/pennylane/pull/7200)
+
 <h3>Breaking changes 💔</h3>
 
 <h3>Deprecations 👋</h3>
 
 <h3>Internal changes ⚙️</h3>
 
+* Clean up `__init__.py` files in `math`, `ops`, `qaoa`, `tape` and `templates` to be explicit in what they import. 
+  [(#7200)](https://github.com/PennyLaneAI/pennylane/pull/7200)
+  
 * The `Tracker` class has been moved into the `devices` module.
   [(#7281)](https://github.com/PennyLaneAI/pennylane/pull/7281)
 
@@ -26,9 +32,14 @@
 * Using finite differences with program capture without x64 mode enabled now raises a warning.
   [(#7282)](https://github.com/PennyLaneAI/pennylane/pull/7282)
 
+* When the `mcm_method` is specified to the `"device"`, the `defer_measurements` transform will 
+  no longer be applied. Instead, the device will be responsible for all MCM handling.
+  [(#7243)](https://github.com/PennyLaneAI/pennylane/pull/7243)
+
 <h3>Contributors ✍️</h3>
 
 This release contains contributions from (in alphabetical order):
 
 Guillermo Alonso-Linaje
 Christina Lee
+Andrija Paurevic
diff --git a/pennylane/compiler/compiler.py b/pennylane/compiler/compiler.py
index 6c38bb3d2..c31f04522 100644
--- a/pennylane/compiler/compiler.py
+++ b/pennylane/compiler/compiler.py
@@ -23,7 +23,7 @@ from typing import List, Optional
 
 from packaging.version import Version
 
-PL_CATALYST_MIN_VERSION = Version("0.10.0")
+PL_CATALYST_MIN_VERSION = Version("0.11.0")
 
 
 class CompileError(Exception):
diff --git a/pennylane/devices/preprocess.py b/pennylane/devices/preprocess.py
index 510e83724..520f2dfc9 100644
--- a/pennylane/devices/preprocess.py
+++ b/pennylane/devices/preprocess.py
@@ -187,8 +187,9 @@ def mid_circuit_measurements(
 ) -> tuple[QuantumScriptBatch, PostprocessingFn]:
     """Provide the transform to handle mid-circuit measurements.
 
-    If the tape or device uses finite-shot, use the native implementation (i.e. no transform),
-    and use the ``qml.defer_measurements`` transform otherwise.
+    In the case where no method is specified, if the tape or device
+    uses finite-shot, the ``qml.dynamic_one_shot`` transform will be
+    applied, otherwise ``qml.defer_measurements`` is used instead.
     """
     if isinstance(mcm_config, dict):
         mcm_config = MCMConfig(**mcm_config)
@@ -198,7 +199,7 @@ def mid_circuit_measurements(
 
     if mcm_method == "one-shot":
         return qml.dynamic_one_shot(tape, postselect_mode=mcm_config.postselect_mode)
-    if mcm_method == "tree-traversal":
+    if mcm_method in ("tree-traversal", "device"):
         return (tape,), null_postprocessing
     return qml.defer_measurements(
         tape, allow_postselect=isinstance(device, qml.devices.DefaultQubit)
diff --git a/pennylane/math/__init__.py b/pennylane/math/__init__.py
index 84de8ffa7..273e00ae4 100644
--- a/pennylane/math/__init__.py
+++ b/pennylane/math/__init__.py
@@ -106,6 +106,17 @@ from .interface_utils import (
 from .grad import grad, jacobian
 
 sum = ar.numpy.sum
+conj = ar.numpy.conj
+transpose = ar.numpy.transpose
+sqrt = ar.numpy.sqrt
+zeros = ar.numpy.zeros
+moveaxis = ar.numpy.moveaxis
+mean = ar.numpy.mean
+round = ar.numpy.round
+shape = ar.numpy.shape
+flatten = ar.numpy.flatten
+reshape = ar.numpy.reshape
+multiply = ar.numpy.multiply
 toarray = ar.numpy.to_numpy
 T = ar.numpy.transpose
 
diff --git a/pennylane/ops/__init__.py b/pennylane/ops/__init__.py
index 6beae6b80..a35eb7e45 100644
--- a/pennylane/ops/__init__.py
+++ b/pennylane/ops/__init__.py
@@ -27,6 +27,7 @@ from .cv import __obs__ as _cv__obs__
 from .cv import __ops__ as _cv__ops__
 
 # we would like these to just live in .qubit, but can't because of circular imports
+from .identity import *
 from .op_math import *
 from .op_math import controlled_qubit_ops as _controlled_qubit__ops__
 from .qubit import *
diff --git a/pennylane/ops/qubit/__init__.py b/pennylane/ops/qubit/__init__.py
index 2c2b932ad..11b5ee505 100644
--- a/pennylane/ops/qubit/__init__.py
+++ b/pennylane/ops/qubit/__init__.py
@@ -29,17 +29,61 @@ The operations are divided into the following files:
 * ``special_unitary.py``: The ``SpecialUnitary`` operation.
 """
 
-from ..identity import GlobalPhase, Identity
+from ..identity import GlobalPhase, Identity, I
 from ..meta import Barrier, Snapshot, WireCut
-from .arithmetic_ops import *
-from .matrix_ops import *
-from .non_parametric_ops import *
-from .observables import *
-from .parametric_ops_multi_qubit import *
-from .parametric_ops_single_qubit import *
-from .qchem_ops import *
-from .special_unitary import SpecialUnitary
-from .state_preparation import *
+from .arithmetic_ops import QubitCarry, QubitSum, IntegerComparator
+from .matrix_ops import QubitUnitary, DiagonalQubitUnitary, BlockEncode
+from .non_parametric_ops import (
+    Hadamard,
+    H,
+    PauliX,
+    X,
+    PauliY,
+    Y,
+    PauliZ,
+    Z,
+    S,
+    T,
+    SX,
+    SWAP,
+    ECR,
+    ISWAP,
+    SISWAP,
+    SQISW,
+)
+from .observables import (
+    Hermitian,
+    SparseHamiltonian,
+    Projector,
+    BasisStateProjector,
+    StateVectorProjector,
+)
+from .parametric_ops_multi_qubit import (
+    MultiRZ,
+    PauliRot,
+    PCPhase,
+    IsingXX,
+    IsingYY,
+    IsingZZ,
+    IsingXY,
+    PSWAP,
+    CPhaseShift00,
+    CPhaseShift01,
+    CPhaseShift10,
+)
+from .parametric_ops_single_qubit import RX, RY, RZ, PhaseShift, Rot, U1, U2, U3
+from .qchem_ops import (
+    SingleExcitation,
+    SingleExcitationPlus,
+    SingleExcitationMinus,
+    DoubleExcitation,
+    DoubleExcitationPlus,
+    DoubleExcitationMinus,
+    OrbitalRotation,
+    FermionicSWAP,
+)
+from .special_unitary import SpecialUnitary, TmpPauliRot
+from .state_preparation import BasisState, StatePrep, QubitDensityMatrix
 
 __ops__ = {
     "Identity",
diff --git a/pennylane/ops/qutrit/__init__.py b/pennylane/ops/qutrit/__init__.py
index c91466c5d..27dc73dc2 100644
--- a/pennylane/ops/qutrit/__init__.py
+++ b/pennylane/ops/qutrit/__init__.py
@@ -20,13 +20,18 @@ The operations are in one file:
   either unitary or hermitian depending.
 """
 
-from ..identity import Identity
-from .matrix_ops import *
-from .non_parametric_ops import *
-from .observables import *
-from .parametric_ops import *
-from .state_preparation import *
-from .channel import *
+from ..identity import Identity, I
+from .channel import (
+    QutritDepolarizingChannel,
+    QutritAmplitudeDamping,
+    TritFlip,
+    QutritChannel,
+)
+from .matrix_ops import QutritUnitary, ControlledQutritUnitary
+from .non_parametric_ops import TShift, TClock, TAdd, TSWAP, THadamard
+from .parametric_ops import TRX, TRY, TRZ, validate_subspace
+from .observables import THermitian, GellMann
+from .state_preparation import QutritBasisState
 
 # TODO: Change `qml.Identity` for qutrit support or add `qml.TIdentity` for qutrits
 __ops__ = {
diff --git a/pennylane/qaoa/__init__.py b/pennylane/qaoa/__init__.py
index 01853a26a..d824c3538 100644
--- a/pennylane/qaoa/__init__.py
+++ b/pennylane/qaoa/__init__.py
@@ -16,7 +16,22 @@ This module provides a collection of methods that help in the construction of
 QAOA workflows.
 """
 
-import pennylane.qaoa.cycle
-from .mixers import *
-from .cost import *
-from .layers import *
+from .mixers import x_mixer, xy_mixer, bit_flip_mixer
+from .cycle import (
+    edges_to_wires,
+    wires_to_edges,
+    cycle_mixer,
+    loss_hamiltonian,
+    out_flow_constraint,
+    net_flow_constraint,
+)
+from .cost import (
+    bit_driver,
+    edge_driver,
+    maxcut,
+    max_independent_set,
+    min_vertex_cover,
+    max_clique,
+    max_weight_cycle,
+)
+from .layers import cost_layer, mixer_layer
diff --git a/pennylane/qaoa/cost.py b/pennylane/qaoa/cost.py
index a30bcc421..c777c6356 100644
--- a/pennylane/qaoa/cost.py
+++ b/pennylane/qaoa/cost.py
@@ -24,12 +24,13 @@ import rustworkx as rx
 
 import pennylane as qml
 from pennylane import qaoa
+from pennylane.wires import Wires
 
 ########################
 # Hamiltonian components
 
 
-def bit_driver(wires: Union[Iterable, qaoa.Wires], b: int):
+def bit_driver(wires: Union[Iterable, Wires], b: int):
     r"""Returns the bit-driver cost Hamiltonian.
 
     This Hamiltonian is defined as:
diff --git a/pennylane/tape/qscript.py b/pennylane/tape/qscript.py
index 2142cd80f..c101f0b8f 100644
--- a/pennylane/tape/qscript.py
+++ b/pennylane/tape/qscript.py
@@ -629,6 +629,7 @@ class QuantumScript:
             for the provided trainable parameter.
         """
         # get the index of the parameter in the script
+        # pylint: disable=unsubscriptable-object
         t_idx = self.trainable_params[idx]
 
         # get the info for the parameter
diff --git a/pennylane/templates/__init__.py b/pennylane/templates/__init__.py
index 7613a1724..c4029b16b 100644
--- a/pennylane/templates/__init__.py
+++ b/pennylane/templates/__init__.py
@@ -16,7 +16,7 @@ This module contains templates, which are pre-coded routines that can be used in
 """
 
 from .embeddings import *
-from .layer import *
+from .layer import layer
 from .layers import *
 from .state_preparations import *
 from .subroutines import *
diff --git a/pennylane/templates/layer.py b/pennylane/templates/layer.py
index 5f70f5766..d13660e11 100644
--- a/pennylane/templates/layer.py
+++ b/pennylane/templates/layer.py
@@ -14,8 +14,7 @@
 r"""
 Contains the ``layer`` template constructor.
 """
-# pylint: disable-msg=too-many-branches,too-many-arguments,protected-access
-from pennylane.math import shape
+from pennylane import math
 
 
 def _preprocess(args, depth):
@@ -30,7 +29,7 @@ def _preprocess(args, depth):
 
     for arg in args:
         # some TF objects don't have len
-        arg_depth = len(arg) if hasattr(arg, "__len__") else shape(arg)[0]
+        arg_depth = len(arg) if hasattr(arg, "__len__") else math.shape(arg)[0]
         if arg_depth != depth:
             raise ValueError(
                 f"Each positional argument must have length matching 'depth'; expected {depth} got {arg_depth}"
diff --git a/setup.py b/setup.py
index 20042551d..b65d80b52 100644
--- a/setup.py
+++ b/setup.py
@@ -30,7 +30,7 @@ requirements = [
     "appdirs",
     "autoray>=0.6.11",
     "cachetools",
-    "pennylane-lightning>=0.40",
+    "pennylane-lightning>=0.41",
     "requests",
     "typing_extensions",
     "packaging",


Test patch:
diff --git a/tests/devices/test_preprocess.py b/tests/devices/test_preprocess.py
index fba3deeff..d8208b781 100644
--- a/tests/devices/test_preprocess.py
+++ b/tests/devices/test_preprocess.py
@@ -22,6 +22,7 @@ from pennylane.devices.preprocess import (
     decompose,
     mid_circuit_measurements,
     no_sampling,
+    null_postprocessing,
     validate_adjoint_trainable_params,
     validate_device_wires,
     validate_measurements,
@@ -483,6 +484,20 @@ class TestMidCircuitMeasurements:
         _, _ = mid_circuit_measurements(tape, dev, mcm_config)
         spy.assert_called_once()
 
+    @pytest.mark.parametrize("mcm_method", ["device", "tree-traversal"])
+    @pytest.mark.parametrize("shots", [10, None])
+    def test_device_mcm_method(self, mcm_method, shots):
+        """Test that no transform is applied by mid_circuit_measurements when the
+        mcm method is handled by the device"""
+        dev = qml.device("default.qubit")
+        mcm_config = {"postselect_mode": None, "mcm_method": mcm_method}
+        tape = QuantumScript([qml.measurements.MidMeasureMP(0)], [], shots=shots)
+
+        (new_tape,), post_processing_fn = mid_circuit_measurements(tape, dev, mcm_config)
+
+        assert qml.equal(tape, new_tape)
+        assert post_processing_fn == null_postprocessing
+
     def test_error_incompatible_mcm_method(self):
         """Test that an error is raised if requesting the one-shot transform without shots"""
         dev = qml.device("default.qubit")
diff --git a/tests/ops/functions/conftest.py b/tests/ops/functions/conftest.py
index ccf5e94ad..cc7d1ab98 100644
--- a/tests/ops/functions/conftest.py
+++ b/tests/ops/functions/conftest.py
@@ -22,7 +22,7 @@ import numpy as np
 import pytest
 
 import pennylane as qml
-from pennylane.operation import Channel, Observable, Operation, Operator
+from pennylane.operation import Channel, Observable, Operation, Operator, StatePrepBase
 from pennylane.ops.op_math.adjoint import Adjoint, AdjointObs, AdjointOperation, AdjointOpObs
 from pennylane.ops.op_math.pow import PowObs, PowOperation, PowOpObs
 from pennylane.templates.subroutines.trotter import TrotterizedQfunc
@@ -150,7 +150,7 @@ _ABSTRACT_OR_META_TYPES = {
     qml.ops.ControlledOp,
     qml.ops.qubit.BasisStateProjector,
     qml.ops.qubit.StateVectorProjector,
-    qml.ops.qubit.StatePrepBase,
+    StatePrepBase,
     qml.resource.ResourcesOperation,
     qml.resource.ErrorOperation,
     PowOpObs,