From 60f99b68cf1e5f80e5bbdcf2789a3a1281433149 Mon Sep 17 00:00:00 2001 From: Jacob Feldman Date: Mon, 1 Jun 2026 11:06:54 -0700 Subject: [PATCH] deprecation: change Circuit.to_ir default to OPENQASM and warn on JAQCD (MCM-150287739) Amazon Braket service devices no longer accept JAQCD program submissions. This commit moves the customer-facing default off JAQCD and emits a UserWarning when callers explicitly request JAQCD. Changes: * src/braket/circuits/circuit.py: change Circuit.to_ir default ir_type from IRType.JAQCD to IRType.OPENQASM. When ir_type=IRType.JAQCD is passed explicitly, emit a UserWarning telling the customer to use IRType.OPENQASM and referencing MCM-150287739. The IRType.JAQCD conversion path itself is preserved. * src/braket/circuits/serialization.py: add a Sphinx `.. deprecated:: 1.117.4` note to the IRType enum docstring. The default flip is safe for internal callers: aws_quantum_task.py and local_simulator.py already pass ir_type explicitly. External callers relying on the no-arg JAQCD default see the new shape (OpenQASM) documented in the docstring's `.. versionchanged::` note. Test changes: * test/unit_tests/braket/circuits/test_circuit.py: existing test_ir_*_instructions_result_types tests now pass IRType.JAQCD explicitly (with pytest.warns) since they test the JAQCD conversion shape. test_barrier_jaqcd_export_fails likewise wraps in pytest.warns. New tests: - test_to_ir_default_is_openqasm - test_to_ir_jaqcd_emits_warning - test_to_ir_default_emits_no_jaqcd_warning * test/unit_tests/braket/devices/test_local_simulator.py: test_run_jaqcd_only wraps in pytest.warns, since LocalSimulator falling back to JAQCD payload construction now correctly emits the deprecation warning. UserWarning (not DeprecationWarning) is used deliberately: PEP 565's default filter hides DeprecationWarning from any code attributed outside __main__, which would silently hide the warning from any customer code that calls Braket from a helper function or library. UserWarning is visible by default, and matches every existing warnings.warn call site in the BDK (aws_device.py, quantum_job_creation.py, circuit_binding.py). See MCM-150287739. --- src/braket/circuits/circuit.py | 20 ++++++- src/braket/circuits/serialization.py | 10 +++- .../braket/circuits/test_circuit.py | 52 ++++++++++++++++--- .../braket/devices/test_local_simulator.py | 6 ++- 4 files changed, 79 insertions(+), 9 deletions(-) diff --git a/src/braket/circuits/circuit.py b/src/braket/circuits/circuit.py index 9b627a6a9..ceff6daa7 100644 --- a/src/braket/circuits/circuit.py +++ b/src/braket/circuits/circuit.py @@ -13,6 +13,7 @@ from __future__ import annotations +import warnings from collections import Counter from collections.abc import Callable, Iterable, Sequence from numbers import Number @@ -1311,13 +1312,24 @@ def diagram(self, circuit_diagram_class: type = UnicodeCircuitDiagram) -> str: def to_ir( self, - ir_type: IRType = IRType.JAQCD, + ir_type: IRType = IRType.OPENQASM, serialization_properties: SerializationProperties | None = None, gate_definitions: dict[tuple[Gate, QubitSet], PulseSequence] | None = None, ) -> OpenQasmProgram | JaqcdProgram: """Converts the circuit into the canonical intermediate representation. If the circuit is sent over the wire, this method is called before it is sent. + .. versionchanged:: 1.117.4 + The default ``ir_type`` is now :attr:`IRType.OPENQASM` (previously + :attr:`IRType.JAQCD`). Amazon Braket service devices no longer + accept JAQCD program submissions; see MCM-150287739. + + .. deprecated:: 1.117.4 + Passing ``ir_type=IRType.JAQCD`` is deprecated and emits a + ``UserWarning``. Use :attr:`IRType.OPENQASM` instead. The + ``IRType.JAQCD`` enum member and the JAQCD conversion path are + retained so historical task results continue to deserialize. + Args: ir_type (IRType): The IRType to use for converting the circuit object to its IR representation. @@ -1337,6 +1349,12 @@ def to_ir( """ gate_definitions = gate_definitions or {} if ir_type == IRType.JAQCD: + warnings.warn( + "JAQCD IR is deprecated and will be removed in a future release. " + "Use IRType.OPENQASM instead. Amazon Braket service devices no " + "longer accept JAQCD program submissions. See MCM-150287739.", + stacklevel=2, + ) return self._to_jaqcd() if ir_type == IRType.OPENQASM: if serialization_properties and not isinstance( diff --git a/src/braket/circuits/serialization.py b/src/braket/circuits/serialization.py index 102aeadd4..9b12514a2 100644 --- a/src/braket/circuits/serialization.py +++ b/src/braket/circuits/serialization.py @@ -17,7 +17,15 @@ class IRType(StrEnum): - """Defines the available IRTypes for circuit serialization.""" + """Defines the available IRTypes for circuit serialization. + + .. deprecated:: 1.117.4 + ``JAQCD`` is deprecated. Amazon Braket service devices no longer accept + JAQCD program submissions; use ``OPENQASM`` instead. The ``JAQCD`` + enum member is retained so circuits can still be converted to JAQCD + for legacy code paths and historical task-result parsing. See + MCM-150287739. + """ OPENQASM = "OPENQASM" JAQCD = "JAQCD" diff --git a/test/unit_tests/braket/circuits/test_circuit.py b/test/unit_tests/braket/circuits/test_circuit.py index 435051ea5..bcd5edd2e 100644 --- a/test/unit_tests/braket/circuits/test_circuit.py +++ b/test/unit_tests/braket/circuits/test_circuit.py @@ -11,6 +11,7 @@ # ANY KIND, either express or implied. See the License for the specific # language governing permissions and limitations under the License. +import warnings from unittest.mock import Mock import numpy as np @@ -1184,9 +1185,9 @@ def h_nested(target): def test_ir_empty_instructions_result_types(): circ = Circuit() - assert circ.to_ir() == jaqcd.Program( - instructions=[], results=[], basis_rotation_instructions=[] - ) + with pytest.warns(UserWarning, match="JAQCD"): + ir = circ.to_ir(IRType.JAQCD) + assert ir == jaqcd.Program(instructions=[], results=[], basis_rotation_instructions=[]) def test_ir_non_empty_instructions_result_types(): @@ -1196,7 +1197,9 @@ def test_ir_non_empty_instructions_result_types(): results=[jaqcd.Probability(targets=[0, 1])], basis_rotation_instructions=[], ) - assert circ.to_ir() == expected + with pytest.warns(UserWarning, match="JAQCD"): + ir = circ.to_ir(IRType.JAQCD) + assert ir == expected def test_ir_non_empty_instructions_result_types_basis_rotation_instructions(): @@ -1206,7 +1209,41 @@ def test_ir_non_empty_instructions_result_types_basis_rotation_instructions(): results=[jaqcd.Sample(observable=["x"], targets=[0])], basis_rotation_instructions=[jaqcd.H(target=0)], ) - assert circ.to_ir() == expected + with pytest.warns(UserWarning, match="JAQCD"): + ir = circ.to_ir(IRType.JAQCD) + assert ir == expected + + +def test_to_ir_default_is_openqasm(): + """Calling Circuit.to_ir() with no ir_type argument should return an + OpenQASM program (after the JAQCD-deprecation default flip).""" + circ = Circuit().h(0).cnot(0, 1) + assert isinstance(circ.to_ir(), OpenQasmProgram) + + +def test_to_ir_jaqcd_emits_warning(): + """Passing IRType.JAQCD explicitly should emit a UserWarning that + references JAQCD and points the customer at the migration path.""" + circ = Circuit().h(0) + with pytest.warns(UserWarning, match="JAQCD"): + out = circ.to_ir(IRType.JAQCD) + # The actual JAQCD program is still produced — only the warning is new. + assert out == jaqcd.Program( + instructions=[jaqcd.H(target=0)], results=[], basis_rotation_instructions=[] + ) + + +def test_to_ir_default_emits_no_jaqcd_warning(): + """The new default (OpenQASM) must not emit the JAQCD deprecation + warning. We assert specifically on JAQCD-message warnings rather than + erroring on all UserWarnings, since other unrelated warnings may fire + legitimately.""" + circ = Circuit().h(0) + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + circ.to_ir() + jaqcd_warnings = [x for x in w if "JAQCD" in str(x.message)] + assert jaqcd_warnings == [] @pytest.mark.parametrize( @@ -3815,5 +3852,8 @@ def test_barrier_openqasm_export_all_qubits(): def test_barrier_jaqcd_export_fails(): circ = Circuit().h(0).barrier([0, 1]) - with pytest.raises(NotImplementedError, match="Barrier is not supported in JAQCD"): + with ( + pytest.warns(UserWarning, match="JAQCD"), + pytest.raises(NotImplementedError, match="Barrier is not supported in JAQCD"), + ): circ.to_ir(IRType.JAQCD) diff --git a/test/unit_tests/braket/devices/test_local_simulator.py b/test/unit_tests/braket/devices/test_local_simulator.py index 4de37f289..00bbd2ef6 100644 --- a/test/unit_tests/braket/devices/test_local_simulator.py +++ b/test/unit_tests/braket/devices/test_local_simulator.py @@ -692,7 +692,11 @@ def test_run_program_model_inputs(): def test_run_jaqcd_only(): dummy = DummyJaqcdSimulator() sim = LocalSimulator(dummy) - task = sim.run(Circuit().h(0).cnot(0, 1), 10) + # When the local simulator advertises only JAQCD (no OpenQASM), the + # LocalSimulator payload constructor falls back to converting the + # circuit to JAQCD, which (per the JAQCD deprecation) emits a UserWarning. + with pytest.warns(UserWarning, match="JAQCD"): + task = sim.run(Circuit().h(0).cnot(0, 1), 10) dummy.assert_shots(10) dummy.assert_qubits(None) assert task.result() == GateModelQuantumTaskResult.from_object(GATE_MODEL_RESULT)