Repository: PennyLaneAI/pennylane
Pull request #4933 (2023-12-08 22:58:06)

Allow checking if `MeasurementProcess` objects are in an `Attribute` set.
**Context:**
`Attribute.__contains__` raises a `TypeError` if someone tries to use a `MeasurementProcess`. This breaks `qml.measure` as mid-circuit measurements are part of the operator queue, not measurements queue.

**Description of the Change:**
Allow `MeasurementProcess` objects to be used with `Attribute`.

**Benefits:**

**Possible Drawbacks:**

**Related GitHub Issues:**


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/4933?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:
> Comparison is base [(`2560851`)](https://app.codecov.io/gh/PennyLaneAI/pennylane/commit/25608515cea487910ae59710b25e1be52fc9cda5?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) 99.66% compared to head [(`adea309`)](https://app.codecov.io/gh/PennyLaneAI/pennylane/pull/4933?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) 99.66%.


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


```diff
@@           Coverage Diff            @@
##           master    #4933    +/-   ##
========================================
  Coverage   99.66%   99.66%            
========================================
  Files         388      388            
  Lines       35285    35020   -265     
========================================
- Hits        35166    34902   -264     
+ Misses        119      118     -1     
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/PennyLaneAI/pennylane/pull/4933?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).

mudit2812: [sc-51773]
timmysilv: what exactly depends on this module? the change from raising an error to returning False makes sense (if we know _everything_ that should be true, it makes sense to just return false otherwise to me!), but I don't know what effect this will have
albi3ro: > what exactly depends on this module? the change from raising an error to returning False makes sense (if we know _everything_ that should be true, it makes sense to just return false otherwise to me!), but I don't know what effect this will have

I think basically just a couple of compilation transforms.

Patch:
diff --git a/doc/releases/changelog-dev.md b/doc/releases/changelog-dev.md
index 77e1e0344..5b219021d 100644
--- a/doc/releases/changelog-dev.md
+++ b/doc/releases/changelog-dev.md
@@ -525,6 +525,10 @@
 
 <h3>Bug fixes 🐛</h3>
 
+* `Attribute` objects now return `False` instead of raising a `TypeError` when checking if an object is inside
+  the set.
+  [(#4933)](https://github.com/PennyLaneAI/pennylane/pull/4933)
+
 * Fixed a bug where the parameter-shift rule of `qml.ctrl(op)` was wrong if `op` had a generator
   that has two or more eigenvalues and is stored as a `SparseHamiltonian`.
   [(#4899)](https://github.com/PennyLaneAI/pennylane/pull/4899)
diff --git a/pennylane/ops/qubit/attributes.py b/pennylane/ops/qubit/attributes.py
index 2d1f704eb..f516bee19 100644
--- a/pennylane/ops/qubit/attributes.py
+++ b/pennylane/ops/qubit/attributes.py
@@ -74,26 +74,20 @@ class Attribute(set):
         if isinstance(obj, str):
             return super().__contains__(obj)
 
-        try:
-            # Hotfix: return False for all tensors.
-            # Can be removed or updated when tensor class is
-            # improved.
-            if isinstance(obj, Tensor):
-                return False
+        # Hotfix: return False for all tensors.
+        # Can be removed or updated when tensor class is
+        # improved.
+        if isinstance(obj, Tensor):
+            return False
 
-            if isinstance(obj, Operator):
-                return super().__contains__(obj.name)
+        if isinstance(obj, Operator):
+            return super().__contains__(obj.name)
 
-            if isclass(obj):
-                if issubclass(obj, Operator):
-                    return super().__contains__(obj.__name__)
+        if isclass(obj):
+            if issubclass(obj, Operator):
+                return super().__contains__(obj.__name__)
 
-            raise TypeError
-
-        except TypeError as e:
-            raise TypeError(
-                "Only an Operator or string representing an Operator can be checked for attribute inclusion."
-            ) from e
+        return False
 
 
 composable_rotations = Attribute(


Test patch:
diff --git a/tests/ops/qubit/test_attributes.py b/tests/ops/qubit/test_attributes.py
index cd55193be..8a50ae60a 100644
--- a/tests/ops/qubit/test_attributes.py
+++ b/tests/ops/qubit/test_attributes.py
@@ -31,14 +31,16 @@ class TestAttribute:
     """Test addition and inclusion of operations and subclasses in attributes."""
 
     def test_invalid_input(self):
-        """Test that anything that is not a string or Operation throws an error."""
-        # Test something that is not an object
-        with pytest.raises(TypeError, match="can be checked for attribute inclusion"):
-            assert 3 not in new_attribute
+        """Test that anything that is not a string or Operation returns False."""
+        assert 3 not in new_attribute
 
         # Test a dummy object that is not an Operation.
-        with pytest.raises(TypeError, match="can be checked for attribute inclusion"):
-            assert object() not in new_attribute
+        assert object() not in new_attribute
+
+    def test_measurement_process_input(self):
+        """Test that MeasurementProcesses are valid objects to check inside Attributes"""
+        assert qml.measurements.MidMeasureMP(0) not in new_attribute
+        assert qml.expval(qml.PauliX(0)) not in new_attribute
 
     def test_string_inclusion(self):
         """Test that we can check inclusion using strings."""