Skip to content

Disallow passing types as tags #6947

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jan 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion cirq-core/cirq/ops/raw_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
"""
Expand Down Expand Up @@ -779,14 +782,17 @@ 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.
"""

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':
Expand Down Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions cirq-core/cirq/ops/raw_types_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Original file line number Diff line number Diff line change
Expand Up @@ -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)
),
Expand Down