From 63e4c7d85a11ce9af540e9a3bfc745467cced15b Mon Sep 17 00:00:00 2001 From: Doug Strain Date: Tue, 14 Jan 2025 09:16:04 -0800 Subject: [PATCH] Disallow passing types as tags (#6947) * Disallow passing types as tags - This has caused confusion when passing a tag type with PhysicalZTag as a tag when you mean the instance PhysicalZTag(). - Adds comments to TaggedOperation and Operation to explain the limitation. --- cirq-core/cirq/ops/raw_types.py | 11 ++++++++++- cirq-core/cirq/ops/raw_types_test.py | 6 ++++++ .../cirq_google/devices/google_noise_properties.py | 2 +- .../devices/google_noise_properties_test.py | 2 +- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/cirq-core/cirq/ops/raw_types.py b/cirq-core/cirq/ops/raw_types.py index 858bbcc441a..7eebac3254a 100644 --- a/cirq-core/cirq/ops/raw_types.py +++ b/cirq-core/cirq/ops/raw_types.py @@ -554,6 +554,9 @@ def with_tags(self, *new_tags: Hashable) -> 'cirq.Operation': resulting operation to be eventually serialized into JSON, you should also restrict the operation to be JSON serializable. + Please note that tags should be instantiated if classes are + used. Raw types are not allowed. + Args: *new_tags: The tags to wrap this operation in. """ @@ -779,7 +782,8 @@ class TaggedOperation(Operation): Tags added can be of any type, but they should be Hashable in order to allow equality checking. If you wish to serialize operations into JSON, you should restrict yourself to only use objects that have a JSON - serialization. + serialization. Tags cannot be raw types and should be instantiated + if classes are used. See `Operation.with_tags()` for more information on intended usage. """ @@ -787,6 +791,8 @@ class TaggedOperation(Operation): def __init__(self, sub_operation: 'cirq.Operation', *tags: Hashable): self._sub_operation = sub_operation self._tags = tuple(tags) + if any(isinstance(tag, type) for tag in tags): + raise ValueError('Tags cannot be types. Did you forget to instantiate the tag type?') @property def sub_operation(self) -> 'cirq.Operation': @@ -836,6 +842,9 @@ def with_tags(self, *new_tags: Hashable) -> 'cirq.TaggedOperation': Overloads Operation.with_tags to create a new TaggedOperation that has the tags of this operation combined with the new_tags specified as the parameter. + + Please note that tags should be instantiated if classes are + used. Raw types are not allowed. """ if not new_tags: return self diff --git a/cirq-core/cirq/ops/raw_types_test.py b/cirq-core/cirq/ops/raw_types_test.py index 97cfb3e5a13..45f6300630f 100644 --- a/cirq-core/cirq/ops/raw_types_test.py +++ b/cirq-core/cirq/ops/raw_types_test.py @@ -458,6 +458,12 @@ def test_tagged_operation(): assert op.with_qubits(q2).qubits == (q2,) assert not cirq.is_measurement(op) + # Tags can't be types + # This is to prevent typos of cirq.X(q1).with_tags(TagType) + # when you meant cirq.X(q1).with_tags(TagType()) + with pytest.raises(ValueError, match="cannot be types"): + _ = cirq.X(q1).with_tags(cirq.Circuit) + def test_with_tags_returns_same_instance_if_possible(): untagged = cirq.X(cirq.GridQubit(1, 1)) diff --git a/cirq-google/cirq_google/devices/google_noise_properties.py b/cirq-google/cirq_google/devices/google_noise_properties.py index 4b045a9e60e..cd6161974b4 100644 --- a/cirq-google/cirq_google/devices/google_noise_properties.py +++ b/cirq-google/cirq_google/devices/google_noise_properties.py @@ -310,6 +310,6 @@ class NoiseModelFromGoogleNoiseProperties(devices.NoiseModelFromNoiseProperties) """A noise model defined from noise properties of a Google device.""" def is_virtual(self, op: cirq.Operation) -> bool: - return isinstance(op.gate, cirq.ZPowGate) and cirq_google.PhysicalZTag not in op.tags + return isinstance(op.gate, cirq.ZPowGate) and cirq_google.PhysicalZTag() not in op.tags # noisy_moments is implemented by the superclass. diff --git a/cirq-google/cirq_google/devices/google_noise_properties_test.py b/cirq-google/cirq_google/devices/google_noise_properties_test.py index 93433ce6525..fc7eb5bd7e5 100644 --- a/cirq-google/cirq_google/devices/google_noise_properties_test.py +++ b/cirq-google/cirq_google/devices/google_noise_properties_test.py @@ -204,7 +204,7 @@ def test_with_params_opid_with_gate(): @pytest.mark.parametrize( 'op', [ - (cirq.Z(cirq.LineQubit(0)) ** 0.3).with_tags(cirq_google.PhysicalZTag), + (cirq.Z(cirq.LineQubit(0)) ** 0.3).with_tags(cirq_google.PhysicalZTag()), cirq.PhasedXZGate(x_exponent=0.8, z_exponent=0.2, axis_phase_exponent=0.1).on( cirq.LineQubit(0) ),