From a5518480ad0e55d39b113e0177a4a96f016cf7ef Mon Sep 17 00:00:00 2001 From: Rahil Jain <51580546+RahilJain1366@users.noreply.github.com> Date: Fri, 7 Nov 2025 08:49:25 -0600 Subject: [PATCH 1/4] Migrate contrib JSON tests to test data files and deprecate DEFAULT_CONTRIB_RESOLVERS --- cirq-core/cirq/contrib/json.py | 31 +++- cirq-core/cirq/contrib/json_test.py | 33 ---- .../json_test_data/BayesianNetworkGate.json | 10 ++ .../json_test_data/BayesianNetworkGate.repr | 1 + .../json_test_data/QuantumVolumeResult.json | 169 ++++++++++++++++++ .../json_test_data/QuantumVolumeResult.repr | 1 + .../json_test_data/SwapPermutationGate.json | 3 + .../json_test_data/SwapPermutationGate.repr | 1 + cirq-core/cirq/contrib/json_test_data/spec.py | 3 +- json_test_data_generator.py | 48 +++++ 10 files changed, 264 insertions(+), 36 deletions(-) delete mode 100644 cirq-core/cirq/contrib/json_test.py create mode 100644 cirq-core/cirq/contrib/json_test_data/BayesianNetworkGate.json create mode 100644 cirq-core/cirq/contrib/json_test_data/BayesianNetworkGate.repr create mode 100644 cirq-core/cirq/contrib/json_test_data/QuantumVolumeResult.json create mode 100644 cirq-core/cirq/contrib/json_test_data/QuantumVolumeResult.repr create mode 100644 cirq-core/cirq/contrib/json_test_data/SwapPermutationGate.json create mode 100644 cirq-core/cirq/contrib/json_test_data/SwapPermutationGate.repr create mode 100644 json_test_data_generator.py diff --git a/cirq-core/cirq/contrib/json.py b/cirq-core/cirq/contrib/json.py index 8c66f12abed..d26a3fad517 100644 --- a/cirq-core/cirq/contrib/json.py +++ b/cirq-core/cirq/contrib/json.py @@ -2,7 +2,7 @@ """Functions for JSON serialization and de-serialization for classes in Contrib.""" from __future__ import annotations - +import warnings import functools from cirq.protocols.json_serialization import _register_resolver, DEFAULT_RESOLVERS, ObjectFactory @@ -38,7 +38,34 @@ def _class_resolver_dictionary() -> dict[str, ObjectFactory]: ] return {cls.__name__: cls for cls in classes} +class _DeprecatedDefaultContribResolvers(list): + """Wrapper to emit deprecation warning when DEFAULT_CONTRIB_RESOLVERS is accessed.""" + + def __init__(self): + super().__init__([contrib_class_resolver] + DEFAULT_RESOLVERS) + self._warning_shown = False + + def __iter__(self): + self._show_warning() + return super().__iter__() + + def __getitem__(self, item): + self._show_warning() + return super().__getitem__(item) + + def _show_warning(self): + if not self._warning_shown: + warnings.warn( + "DEFAULT_CONTRIB_RESOLVERS is deprecated. " + "Contrib classes are now automatically resolved through the standard JSON resolver. " + "You can remove the 'resolvers' parameter from assert_json_roundtrip_works calls.", + DeprecationWarning, + stacklevel=4 + ) + self._warning_shown = True + + +DEFAULT_CONTRIB_RESOLVERS = _DeprecatedDefaultContribResolvers() -DEFAULT_CONTRIB_RESOLVERS = [contrib_class_resolver] + DEFAULT_RESOLVERS _register_resolver(_class_resolver_dictionary) diff --git a/cirq-core/cirq/contrib/json_test.py b/cirq-core/cirq/contrib/json_test.py deleted file mode 100644 index bba8b2687f1..00000000000 --- a/cirq-core/cirq/contrib/json_test.py +++ /dev/null @@ -1,33 +0,0 @@ -# pylint: disable=wrong-or-nonexistent-copyright-notice - -from __future__ import annotations - -import cirq -from cirq.contrib.acquaintance import SwapPermutationGate -from cirq.contrib.bayesian_network import BayesianNetworkGate -from cirq.contrib.json import DEFAULT_CONTRIB_RESOLVERS -from cirq.contrib.quantum_volume import QuantumVolumeResult -from cirq.testing import assert_json_roundtrip_works - - -def test_bayesian_network_gate() -> None: - gate = BayesianNetworkGate( - init_probs=[('q0', 0.125), ('q1', None)], arc_probs=[('q1', ('q0',), [0.25, 0.5])] - ) - assert_json_roundtrip_works(gate, resolvers=DEFAULT_CONTRIB_RESOLVERS) - - -def test_quantum_volume() -> None: - qubits = cirq.LineQubit.range(5) - qvr = QuantumVolumeResult( - model_circuit=cirq.Circuit(cirq.H.on_each(qubits)), - heavy_set=[1, 2, 3], - compiled_circuit=cirq.Circuit(cirq.H.on_each(qubits)), - sampler_result=0.1, - ) - assert_json_roundtrip_works(qvr, resolvers=DEFAULT_CONTRIB_RESOLVERS) - - -def test_swap_permutation_gate() -> None: - gate = SwapPermutationGate(swap_gate=cirq.SWAP) - assert_json_roundtrip_works(gate, resolvers=DEFAULT_CONTRIB_RESOLVERS) diff --git a/cirq-core/cirq/contrib/json_test_data/BayesianNetworkGate.json b/cirq-core/cirq/contrib/json_test_data/BayesianNetworkGate.json new file mode 100644 index 00000000000..6a2937aa78b --- /dev/null +++ b/cirq-core/cirq/contrib/json_test_data/BayesianNetworkGate.json @@ -0,0 +1,10 @@ +{ + "cirq_type": "BayesianNetworkGate", + "init_probs": [ + ["q0", 0.125], + ["q1", null] + ], + "arc_probs": [ + ["q1", ["q0"], [0.25, 0.5]] + ] +} \ No newline at end of file diff --git a/cirq-core/cirq/contrib/json_test_data/BayesianNetworkGate.repr b/cirq-core/cirq/contrib/json_test_data/BayesianNetworkGate.repr new file mode 100644 index 00000000000..da7f2b65dcc --- /dev/null +++ b/cirq-core/cirq/contrib/json_test_data/BayesianNetworkGate.repr @@ -0,0 +1 @@ +cirq.contrib.bayesian_network.BayesianNetworkGate(init_probs=[('q0', 0.125), ('q1', None)], arc_probs=[('q1', ('q0',), [0.25, 0.5])]) \ No newline at end of file diff --git a/cirq-core/cirq/contrib/json_test_data/QuantumVolumeResult.json b/cirq-core/cirq/contrib/json_test_data/QuantumVolumeResult.json new file mode 100644 index 00000000000..5ebaf831224 --- /dev/null +++ b/cirq-core/cirq/contrib/json_test_data/QuantumVolumeResult.json @@ -0,0 +1,169 @@ +{ + "cirq_type": "QuantumVolumeResult", + "model_circuit": { + "cirq_type": "Circuit", + "moments": [ + { + "cirq_type": "Moment", + "operations": [ + { + "cirq_type": "GateOperation", + "gate": { + "cirq_type": "HPowGate", + "exponent": 1.0, + "global_shift": 0.0 + }, + "qubits": [ + { + "cirq_type": "LineQubit", + "x": 0 + } + ] + }, + { + "cirq_type": "GateOperation", + "gate": { + "cirq_type": "HPowGate", + "exponent": 1.0, + "global_shift": 0.0 + }, + "qubits": [ + { + "cirq_type": "LineQubit", + "x": 1 + } + ] + }, + { + "cirq_type": "GateOperation", + "gate": { + "cirq_type": "HPowGate", + "exponent": 1.0, + "global_shift": 0.0 + }, + "qubits": [ + { + "cirq_type": "LineQubit", + "x": 2 + } + ] + }, + { + "cirq_type": "GateOperation", + "gate": { + "cirq_type": "HPowGate", + "exponent": 1.0, + "global_shift": 0.0 + }, + "qubits": [ + { + "cirq_type": "LineQubit", + "x": 3 + } + ] + }, + { + "cirq_type": "GateOperation", + "gate": { + "cirq_type": "HPowGate", + "exponent": 1.0, + "global_shift": 0.0 + }, + "qubits": [ + { + "cirq_type": "LineQubit", + "x": 4 + } + ] + } + ] + } + ] + }, + "heavy_set": [ + 1, + 2, + 3 + ], + "compiled_circuit": { + "cirq_type": "Circuit", + "moments": [ + { + "cirq_type": "Moment", + "operations": [ + { + "cirq_type": "GateOperation", + "gate": { + "cirq_type": "HPowGate", + "exponent": 1.0, + "global_shift": 0.0 + }, + "qubits": [ + { + "cirq_type": "LineQubit", + "x": 0 + } + ] + }, + { + "cirq_type": "GateOperation", + "gate": { + "cirq_type": "HPowGate", + "exponent": 1.0, + "global_shift": 0.0 + }, + "qubits": [ + { + "cirq_type": "LineQubit", + "x": 1 + } + ] + }, + { + "cirq_type": "GateOperation", + "gate": { + "cirq_type": "HPowGate", + "exponent": 1.0, + "global_shift": 0.0 + }, + "qubits": [ + { + "cirq_type": "LineQubit", + "x": 2 + } + ] + }, + { + "cirq_type": "GateOperation", + "gate": { + "cirq_type": "HPowGate", + "exponent": 1.0, + "global_shift": 0.0 + }, + "qubits": [ + { + "cirq_type": "LineQubit", + "x": 3 + } + ] + }, + { + "cirq_type": "GateOperation", + "gate": { + "cirq_type": "HPowGate", + "exponent": 1.0, + "global_shift": 0.0 + }, + "qubits": [ + { + "cirq_type": "LineQubit", + "x": 4 + } + ] + } + ] + } + ] + }, + "sampler_result": 0.1 +} \ No newline at end of file diff --git a/cirq-core/cirq/contrib/json_test_data/QuantumVolumeResult.repr b/cirq-core/cirq/contrib/json_test_data/QuantumVolumeResult.repr new file mode 100644 index 00000000000..a6999dffe59 --- /dev/null +++ b/cirq-core/cirq/contrib/json_test_data/QuantumVolumeResult.repr @@ -0,0 +1 @@ +cirq.contrib.quantum_volume.QuantumVolumeResult(model_circuit=cirq.Circuit(cirq.Moment(cirq.H(cirq.LineQubit(0)), cirq.H(cirq.LineQubit(1)), cirq.H(cirq.LineQubit(2)), cirq.H(cirq.LineQubit(3)), cirq.H(cirq.LineQubit(4)))), heavy_set=[1, 2, 3], compiled_circuit=cirq.Circuit(cirq.Moment(cirq.H(cirq.LineQubit(0)), cirq.H(cirq.LineQubit(1)), cirq.H(cirq.LineQubit(2)), cirq.H(cirq.LineQubit(3)), cirq.H(cirq.LineQubit(4)))), sampler_result=0.1) \ No newline at end of file diff --git a/cirq-core/cirq/contrib/json_test_data/SwapPermutationGate.json b/cirq-core/cirq/contrib/json_test_data/SwapPermutationGate.json new file mode 100644 index 00000000000..9618536752f --- /dev/null +++ b/cirq-core/cirq/contrib/json_test_data/SwapPermutationGate.json @@ -0,0 +1,3 @@ +{ + "cirq_type": "SwapPermutationGate" +} \ No newline at end of file diff --git a/cirq-core/cirq/contrib/json_test_data/SwapPermutationGate.repr b/cirq-core/cirq/contrib/json_test_data/SwapPermutationGate.repr new file mode 100644 index 00000000000..72eeec124bf --- /dev/null +++ b/cirq-core/cirq/contrib/json_test_data/SwapPermutationGate.repr @@ -0,0 +1 @@ +cirq.contrib.acquaintance.SwapPermutationGate(swap_gate=cirq.SWAP) \ No newline at end of file diff --git a/cirq-core/cirq/contrib/json_test_data/spec.py b/cirq-core/cirq/contrib/json_test_data/spec.py index 343a566dca9..35823343818 100644 --- a/cirq-core/cirq/contrib/json_test_data/spec.py +++ b/cirq-core/cirq/contrib/json_test_data/spec.py @@ -28,5 +28,6 @@ resolver_cache=_class_resolver_dictionary(), deprecated={}, # TODO: #7520 - create .json and .repr for these so they can be tested here - tested_elsewhere=["QuantumVolumeResult", "SwapPermutationGate", "BayesianNetworkGate"], + #tested_elsewhere=["QuantumVolumeResult", "SwapPermutationGate", "BayesianNetworkGate"], + tested_elsewhere=[] ) diff --git a/json_test_data_generator.py b/json_test_data_generator.py new file mode 100644 index 00000000000..fd48fa965b7 --- /dev/null +++ b/json_test_data_generator.py @@ -0,0 +1,48 @@ +"""Generate correct JSON test data for contrib classes.""" + +import cirq +from cirq.contrib.acquaintance import SwapPermutationGate +from cirq.contrib.bayesian_network import BayesianNetworkGate +from cirq.contrib.quantum_volume import QuantumVolumeResult +import pathlib + +# Create test objects matching the original json_test.py +bayesian_gate = BayesianNetworkGate( + init_probs=[('q0', 0.125), ('q1', None)], + arc_probs=[('q1', ('q0',), [0.25, 0.5])] +) + +qubits = cirq.LineQubit.range(5) +qvr = QuantumVolumeResult( + model_circuit=cirq.Circuit(cirq.H.on_each(qubits)), + heavy_set=[1, 2, 3], + compiled_circuit=cirq.Circuit(cirq.H.on_each(qubits)), + sampler_result=0.1, +) + +swap_gate = SwapPermutationGate(swap_gate=cirq.SWAP) + +# Define output directory +output_dir = pathlib.Path("cirq-core/cirq/contrib/json_test_data") + +# Generate and write files +test_objects = [ + ("BayesianNetworkGate", bayesian_gate), + ("QuantumVolumeResult", qvr), + ("SwapPermutationGate", swap_gate), +] + +for name, obj in test_objects: + # Write JSON file + json_path = output_dir / f"{name}.json" + with open(json_path, 'w') as f: + f.write(cirq.to_json(obj)) + print(f"Created {json_path}") + + # Write repr file + repr_path = output_dir / f"{name}.repr" + with open(repr_path, 'w') as f: + f.write(repr(obj)) + print(f"Created {repr_path}") + +print("\nAll test data files created successfully!") \ No newline at end of file From 2741a75b0d23a033e9a9cc1faf52231b1eb44542 Mon Sep 17 00:00:00 2001 From: Rahil Jain <51580546+RahilJain1366@users.noreply.github.com> Date: Fri, 7 Nov 2025 08:53:06 -0600 Subject: [PATCH 2/4] removing unnecessay files for #7520 fix --- json_test_data_generator.py | 48 ------------------------------------- 1 file changed, 48 deletions(-) delete mode 100644 json_test_data_generator.py diff --git a/json_test_data_generator.py b/json_test_data_generator.py deleted file mode 100644 index fd48fa965b7..00000000000 --- a/json_test_data_generator.py +++ /dev/null @@ -1,48 +0,0 @@ -"""Generate correct JSON test data for contrib classes.""" - -import cirq -from cirq.contrib.acquaintance import SwapPermutationGate -from cirq.contrib.bayesian_network import BayesianNetworkGate -from cirq.contrib.quantum_volume import QuantumVolumeResult -import pathlib - -# Create test objects matching the original json_test.py -bayesian_gate = BayesianNetworkGate( - init_probs=[('q0', 0.125), ('q1', None)], - arc_probs=[('q1', ('q0',), [0.25, 0.5])] -) - -qubits = cirq.LineQubit.range(5) -qvr = QuantumVolumeResult( - model_circuit=cirq.Circuit(cirq.H.on_each(qubits)), - heavy_set=[1, 2, 3], - compiled_circuit=cirq.Circuit(cirq.H.on_each(qubits)), - sampler_result=0.1, -) - -swap_gate = SwapPermutationGate(swap_gate=cirq.SWAP) - -# Define output directory -output_dir = pathlib.Path("cirq-core/cirq/contrib/json_test_data") - -# Generate and write files -test_objects = [ - ("BayesianNetworkGate", bayesian_gate), - ("QuantumVolumeResult", qvr), - ("SwapPermutationGate", swap_gate), -] - -for name, obj in test_objects: - # Write JSON file - json_path = output_dir / f"{name}.json" - with open(json_path, 'w') as f: - f.write(cirq.to_json(obj)) - print(f"Created {json_path}") - - # Write repr file - repr_path = output_dir / f"{name}.repr" - with open(repr_path, 'w') as f: - f.write(repr(obj)) - print(f"Created {repr_path}") - -print("\nAll test data files created successfully!") \ No newline at end of file From 580b7981abf17dc8d5f8e1d0588e85e89769e8ac Mon Sep 17 00:00:00 2001 From: Rahil Jain <51580546+RahilJain1366@users.noreply.github.com> Date: Fri, 7 Nov 2025 18:17:24 -0600 Subject: [PATCH 3/4] review fixes #7520 --- cirq-core/cirq/contrib/json.py | 47 +++++++------------ cirq-core/cirq/contrib/json_test_data/spec.py | 3 -- 2 files changed, 16 insertions(+), 34 deletions(-) diff --git a/cirq-core/cirq/contrib/json.py b/cirq-core/cirq/contrib/json.py index d26a3fad517..fb7d9ca4ab3 100644 --- a/cirq-core/cirq/contrib/json.py +++ b/cirq-core/cirq/contrib/json.py @@ -2,7 +2,6 @@ """Functions for JSON serialization and de-serialization for classes in Contrib.""" from __future__ import annotations -import warnings import functools from cirq.protocols.json_serialization import _register_resolver, DEFAULT_RESOLVERS, ObjectFactory @@ -38,34 +37,20 @@ def _class_resolver_dictionary() -> dict[str, ObjectFactory]: ] return {cls.__name__: cls for cls in classes} -class _DeprecatedDefaultContribResolvers(list): - """Wrapper to emit deprecation warning when DEFAULT_CONTRIB_RESOLVERS is accessed.""" - - def __init__(self): - super().__init__([contrib_class_resolver] + DEFAULT_RESOLVERS) - self._warning_shown = False - - def __iter__(self): - self._show_warning() - return super().__iter__() - - def __getitem__(self, item): - self._show_warning() - return super().__getitem__(item) - - def _show_warning(self): - if not self._warning_shown: - warnings.warn( - "DEFAULT_CONTRIB_RESOLVERS is deprecated. " - "Contrib classes are now automatically resolved through the standard JSON resolver. " - "You can remove the 'resolvers' parameter from assert_json_roundtrip_works calls.", - DeprecationWarning, - stacklevel=4 - ) - self._warning_shown = True - - -DEFAULT_CONTRIB_RESOLVERS = _DeprecatedDefaultContribResolvers() - - _register_resolver(_class_resolver_dictionary) + +DEFAULT_CONTRIB_RESOLVERS = [contrib_class_resolver, *DEFAULT_RESOLVERS] + +_DEFAULT_CONTRIB_RESOLVERS_DEPRECATION_MESSAGE = ( + 'DEFAULT_CONTRIB_RESOLVERS will no longer be supported.' + 'Contrib classes are now automatically resolved through the standard JSON resolver.' + 'You can remove the "resolvers" parameter from assert_json_roundtrip_works calls.' +) +from cirq import _compat + +_compat.deprecate_attributes( + __name__, + { + 'DEFAULT_CONTRIB_RESOLVERS': ('v1.8', _DEFAULT_CONTRIB_RESOLVERS_DEPRECATION_MESSAGE), + }, +) \ No newline at end of file diff --git a/cirq-core/cirq/contrib/json_test_data/spec.py b/cirq-core/cirq/contrib/json_test_data/spec.py index 35823343818..ac77111f236 100644 --- a/cirq-core/cirq/contrib/json_test_data/spec.py +++ b/cirq-core/cirq/contrib/json_test_data/spec.py @@ -27,7 +27,4 @@ should_not_be_serialized=["Unique", "CircuitDag"], resolver_cache=_class_resolver_dictionary(), deprecated={}, - # TODO: #7520 - create .json and .repr for these so they can be tested here - #tested_elsewhere=["QuantumVolumeResult", "SwapPermutationGate", "BayesianNetworkGate"], - tested_elsewhere=[] ) From c6422ea2a4acaddef36bf81c96c2510bd80dd44f Mon Sep 17 00:00:00 2001 From: Pavol Juhas Date: Fri, 7 Nov 2025 20:08:20 -0800 Subject: [PATCH 4/4] CI - wake up now