Skip to content

Commit ef9f877

Browse files
mergify[bot]ElePT
andauthored
Do not raise deprecation warnings for internal uses of dag.duration and dag.unit (#14133) (#14140)
* Filter Rust deprecation warning when calling dag.duration/dag.unit internally Filter Rust deprecation warning when calling dag.duration/dag.unit internally * Apply Matt's suggestions: * Refactor access patterns: add dag._duration and dag._unit * Refactor internal uses of dag.duration and dag.unit to rely on internal methods * Remove blanket warning filters from unit test config On top of these: * Extend deprecation warnings to dag.duration and dag.unit setters (previously only in getters) * Clean up unit test config from old filters * Change stacklevel * Fix circuit_to_dag * Handle failing tests * _DAGDependencyV2 is private and not a DAGCircuit, so don't use internal attributes * Reduce duplication in getters and setters (cherry picked from commit d0aa100) Co-authored-by: Elena Peña Tapia <[email protected]>
1 parent 47e8edb commit ef9f877

File tree

14 files changed

+188
-165
lines changed

14 files changed

+188
-165
lines changed

crates/circuit/src/dag_circuit.rs

Lines changed: 78 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -211,10 +211,8 @@ pub struct DAGCircuit {
211211
/// Global phase.
212212
global_phase: Param,
213213
/// Duration.
214-
#[pyo3(set)]
215214
duration: Option<PyObject>,
216215
/// Unit of duration.
217-
#[pyo3(set)]
218216
unit: String,
219217

220218
// Note: these are tracked separately from `qubits` and `clbits`
@@ -500,11 +498,11 @@ impl DAGCircuit {
500498
self.clbit_locations.cached(py)
501499
}
502500

503-
/// The total duration of the circuit, set by a scheduling transpiler pass. Its unit is
501+
/// Returns the total duration of the circuit, set by a scheduling transpiler pass. Its unit is
504502
/// specified by :attr:`.unit`
505503
///
506504
/// DEPRECATED since Qiskit 1.3.0 and will be removed in Qiskit 3.0.0
507-
#[getter]
505+
#[getter("duration")]
508506
fn get_duration(&self, py: Python) -> PyResult<Option<Py<PyAny>>> {
509507
imports::WARNINGS_WARN.get_bound(py).call1((
510508
intern!(
@@ -515,12 +513,49 @@ impl DAGCircuit {
515513
)
516514
),
517515
py.get_type::<PyDeprecationWarning>(),
518-
2,
516+
1,
519517
))?;
518+
self.get_internal_duration(py)
519+
}
520+
521+
/// Returns the total duration of the circuit for internal use (no deprecation warning).
522+
///
523+
/// To be removed with get_duration.
524+
#[getter("_duration")]
525+
fn get_internal_duration(&self, py: Python) -> PyResult<Option<Py<PyAny>>> {
520526
Ok(self.duration.as_ref().map(|x| x.clone_ref(py)))
521527
}
522528

523-
/// The unit that duration is specified in.
529+
/// Sets the total duration of the circuit, set by a scheduling transpiler pass. Its unit is
530+
/// specified by :attr:`.unit`
531+
///
532+
/// DEPRECATED since Qiskit 1.3.0 and will be removed in Qiskit 3.0.0
533+
#[setter("duration")]
534+
fn set_duration(&mut self, py: Python, duration: Option<PyObject>) -> PyResult<()> {
535+
imports::WARNINGS_WARN.get_bound(py).call1((
536+
intern!(
537+
py,
538+
concat!(
539+
"The property ``qiskit.dagcircuit.dagcircuit.DAGCircuit.duration`` is ",
540+
"deprecated as of Qiskit 1.3.0. It will be removed in Qiskit 3.0.0.",
541+
)
542+
),
543+
py.get_type::<PyDeprecationWarning>(),
544+
1,
545+
))?;
546+
self.set_internal_duration(duration);
547+
Ok(())
548+
}
549+
550+
/// Sets the total duration of the circuit for internal use (no deprecation warning).
551+
///
552+
/// To be removed with set_duration.
553+
#[setter("_duration")]
554+
fn set_internal_duration(&mut self, duration: Option<PyObject>) {
555+
self.duration = duration
556+
}
557+
558+
/// Returns the unit that duration is specified in.
524559
///
525560
/// DEPRECATED since Qiskit 1.3.0 and will be removed in Qiskit 3.0.0
526561
#[getter]
@@ -534,11 +569,47 @@ impl DAGCircuit {
534569
)
535570
),
536571
py.get_type::<PyDeprecationWarning>(),
537-
2,
572+
1,
538573
))?;
574+
self.get_internal_unit()
575+
}
576+
577+
/// Returns the unit that duration is specified in for internal use (no deprecation warning).
578+
///
579+
/// To be removed with get_unit.
580+
#[getter("_unit")]
581+
fn get_internal_unit(&self) -> PyResult<String> {
539582
Ok(self.unit.clone())
540583
}
541584

585+
/// Sets the unit that duration is specified in.
586+
///
587+
/// DEPRECATED since Qiskit 1.3.0 and will be removed in Qiskit 3.0.0
588+
#[setter("unit")]
589+
fn set_unit(&mut self, py: Python, unit: String) -> PyResult<()> {
590+
imports::WARNINGS_WARN.get_bound(py).call1((
591+
intern!(
592+
py,
593+
concat!(
594+
"The property ``qiskit.dagcircuit.dagcircuit.DAGCircuit.unit`` is ",
595+
"deprecated as of Qiskit 1.3.0. It will be removed in Qiskit 3.0.0.",
596+
)
597+
),
598+
py.get_type::<PyDeprecationWarning>(),
599+
1,
600+
))?;
601+
self.set_internal_unit(unit);
602+
Ok(())
603+
}
604+
605+
/// Sets the unit that duration is specified in for internal use (no deprecation warning).
606+
///
607+
/// To be removed with set_unit.
608+
#[setter("_unit")]
609+
fn set_internal_unit(&mut self, unit: String) {
610+
self.unit = unit
611+
}
612+
542613
#[getter]
543614
fn input_map(&self, py: Python) -> PyResult<Py<PyDict>> {
544615
let out_dict = PyDict::new(py);

qiskit/circuit/quantumcircuit.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1420,8 +1420,8 @@ def reverse_ops(self) -> "QuantumCircuit":
14201420
for instruction in reversed(self.data):
14211421
reverse_circ._append(instruction.replace(operation=instruction.operation.reverse_ops()))
14221422

1423-
reverse_circ.duration = self.duration
1424-
reverse_circ.unit = self.unit
1423+
reverse_circ._duration = self._duration
1424+
reverse_circ._unit = self._unit
14251425
return reverse_circ
14261426

14271427
def reverse_bits(self) -> "QuantumCircuit":
@@ -2559,8 +2559,8 @@ def _append(self, instruction, qargs=(), cargs=(), *, _standard_gate: bool = Fal
25592559
"""
25602560
if _standard_gate:
25612561
self._data.append(instruction)
2562-
self.duration = None
2563-
self.unit = "dt"
2562+
self._duration = None
2563+
self._unit = "dt"
25642564
return instruction
25652565

25662566
old_style = not isinstance(instruction, CircuitInstruction)
@@ -2582,8 +2582,8 @@ def _append(self, instruction, qargs=(), cargs=(), *, _standard_gate: bool = Fal
25822582
self._data.append_manual_params(instruction, params)
25832583

25842584
# Invalidate whole circuit duration if an instruction is added
2585-
self.duration = None
2586-
self.unit = "dt"
2585+
self._duration = None
2586+
self._unit = "dt"
25872587
return instruction.operation if old_style else instruction
25882588

25892589
@typing.overload
@@ -6951,7 +6951,7 @@ def qubit_start_time(self, *qubits: Union[Qubit, int]) -> float:
69516951
Raises:
69526952
CircuitError: if ``self`` is a not-yet scheduled circuit.
69536953
"""
6954-
if self.duration is None:
6954+
if self._duration is None:
69556955
# circuit has only delays, this is kind of scheduled
69566956
for instruction in self._data:
69576957
if not isinstance(instruction.operation, Delay):
@@ -6993,7 +6993,7 @@ def qubit_stop_time(self, *qubits: Union[Qubit, int]) -> float:
69936993
Raises:
69946994
CircuitError: if ``self`` is a not-yet scheduled circuit.
69956995
"""
6996-
if self.duration is None:
6996+
if self._duration is None:
69976997
# circuit has only delays, this is kind of scheduled
69986998
for instruction in self._data:
69996999
if not isinstance(instruction.operation, Delay):
@@ -7004,7 +7004,7 @@ def qubit_stop_time(self, *qubits: Union[Qubit, int]) -> float:
70047004

70057005
qubits = [self.qubits[q] if isinstance(q, int) else q for q in qubits]
70067006

7007-
stops = {q: self.duration for q in qubits}
7007+
stops = {q: self._duration for q in qubits}
70087008
dones = {q: False for q in qubits}
70097009
for instruction in reversed(self._data):
70107010
for q in qubits:

qiskit/converters/circuit_to_dag.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,6 @@ def circuit_to_dag(circuit, copy_operations=True, *, qubit_order=None, clbit_ord
7575

7676
dagcircuit = core_circuit_to_dag(circuit, copy_operations, qubit_order, clbit_order)
7777

78-
dagcircuit.duration = circuit._duration
79-
dagcircuit.unit = circuit._unit
78+
dagcircuit._duration = circuit._duration
79+
dagcircuit._unit = circuit._unit
8080
return dagcircuit

qiskit/converters/dag_to_circuit.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ def dag_to_circuit(dag, copy_operations=True):
7474
circuit.add_stretch(stretch)
7575
circuit.metadata = dag.metadata or {}
7676
circuit._data = circuit_data
77-
78-
circuit._duration = dag.duration
79-
circuit._unit = dag.unit
77+
circuit._duration = dag._duration
78+
circuit._unit = dag._unit
8079
return circuit

qiskit/dagcircuit/dagdependency_v2.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -447,15 +447,16 @@ def copy_empty_like(self):
447447
target_dag = _DAGDependencyV2()
448448
target_dag.name = self.name
449449
target_dag._global_phase = self._global_phase
450-
target_dag.duration = self.duration
451-
target_dag.unit = self.unit
452450
target_dag.metadata = self.metadata
453451
target_dag._key_cache = self._key_cache
454452
target_dag.comm_checker = self.comm_checker
455453

456454
target_dag.add_qubits(self.qubits)
457455
target_dag.add_clbits(self.clbits)
458456

457+
target_dag.duration = self.duration
458+
target_dag.unit = self.unit
459+
459460
for qreg in self.qregs.values():
460461
target_dag.add_qreg(qreg)
461462
for creg in self.cregs.values():

qiskit/transpiler/passes/scheduling/padding/base_padding.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ def run(self, dag: DAGCircuit):
124124

125125
new_dag.name = dag.name
126126
new_dag.metadata = dag.metadata
127-
new_dag.unit = self.property_set["time_unit"]
127+
new_dag._unit = self.property_set["time_unit"]
128128
new_dag.global_phase = dag.global_phase
129129

130130
idle_after = {bit: 0 for bit in dag.qubits}
@@ -186,7 +186,7 @@ def run(self, dag: DAGCircuit):
186186
prev_node=prev_node,
187187
)
188188

189-
new_dag.duration = circuit_duration
189+
new_dag._duration = circuit_duration
190190

191191
return new_dag
192192

qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -310,22 +310,22 @@ def _pad(
310310

311311
if not self.__is_dd_qubit(dag.qubits.index(qubit)):
312312
# Target physical qubit is not the target of this DD sequence.
313-
self._apply_scheduled_op(dag, t_start, Delay(time_interval, dag.unit), qubit)
313+
self._apply_scheduled_op(dag, t_start, Delay(time_interval, dag._unit), qubit)
314314
return
315315

316316
if self._skip_reset_qubits and (
317317
isinstance(prev_node, DAGInNode) or isinstance(prev_node.op, Reset)
318318
):
319319
# Previous node is the start edge or reset, i.e. qubit is ground state.
320-
self._apply_scheduled_op(dag, t_start, Delay(time_interval, dag.unit), qubit)
320+
self._apply_scheduled_op(dag, t_start, Delay(time_interval, dag._unit), qubit)
321321
return
322322

323323
slack = time_interval - np.sum(self._dd_sequence_lengths[qubit])
324324
sequence_gphase = self._sequence_phase
325325

326326
if slack <= 0:
327327
# Interval too short.
328-
self._apply_scheduled_op(dag, t_start, Delay(time_interval, dag.unit), qubit)
328+
self._apply_scheduled_op(dag, t_start, Delay(time_interval, dag._unit), qubit)
329329
return
330330

331331
if len(self._dd_sequence) == 1:
@@ -351,7 +351,7 @@ def _pad(
351351
sequence_gphase += phase
352352
else:
353353
# Don't do anything if there's no single-qubit gate to absorb the inverse
354-
self._apply_scheduled_op(dag, t_start, Delay(time_interval, dag.unit), qubit)
354+
self._apply_scheduled_op(dag, t_start, Delay(time_interval, dag._unit), qubit)
355355
return
356356

357357
def _constrained_length(values):
@@ -387,7 +387,7 @@ def _constrained_length(values):
387387
if dd_ind < len(taus):
388388
tau = taus[dd_ind]
389389
if tau > 0:
390-
self._apply_scheduled_op(dag, idle_after, Delay(tau, dag.unit), qubit)
390+
self._apply_scheduled_op(dag, idle_after, Delay(tau, dag._unit), qubit)
391391
idle_after += tau
392392
if dd_ind < len(self._dd_sequence):
393393
gate = self._dd_sequence[dd_ind]

qiskit/transpiler/passes/scheduling/padding/pad_delay.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,4 +87,4 @@ def _pad(
8787
return
8888

8989
time_interval = t_end - t_start
90-
self._apply_scheduled_op(dag, t_start, Delay(time_interval, dag.unit), qubit)
90+
self._apply_scheduled_op(dag, t_start, Delay(time_interval, dag._unit), qubit)

qiskit/visualization/timeline/core.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ def load_program(self, program: circuit.QuantumCircuit, target: Target | None =
260260
self.add_data(datum)
261261

262262
# update time range
263-
t_end = max(program.duration, self.formatter["margin.minimum_duration"])
263+
t_end = max(program._duration, self.formatter["margin.minimum_duration"])
264264
self.set_time_range(t_start=0, t_end=t_end)
265265

266266
def set_time_range(self, t_start: int, t_end: int):

0 commit comments

Comments
 (0)