Skip to content

Commit 1216de9

Browse files
diego-plan9claude
andauthored
Revise QuantumProgram (and other bits) typing (#3294)
### Summary Revise some of the typing hints related to the `QuantumProgram` move in #3206 (only one notable item, see comments), and take the chance to revise other Pyright warnings (not emitted by `mypy`). ### Details and comments Fixes #3279 ### AI/LLM disclosure - [x] I used the following tool to generate or modify code: Claude Opus 4.8 (for the registries) --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 83036af commit 1216de9

7 files changed

Lines changed: 53 additions & 29 deletions

File tree

qiskit_ibm_runtime/decoders/executor_estimator/post_processor_v0_1.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ def _build_program_result_metadata(post_processor_data: dict) -> dict:
7676
if options is None:
7777
return {}
7878

79-
metadata = {"options": dict(options)}
79+
metadata: dict[str, Any] = {"options": dict(options)}
8080
if "resilience" in metadata["options"]:
8181
resilience = dict(metadata["options"]["resilience"])
8282
for flag_key, options_key in [
@@ -111,12 +111,13 @@ def estimator_v2_post_processor_v0_1(result: QuantumProgramResult) -> PrimitiveR
111111
if len(result) == 0:
112112
return PrimitiveResult([])
113113

114-
if not isinstance(passthrough := result.passthrough_data, dict):
114+
if not isinstance(result.passthrough_data, dict):
115115
raise ValueError(
116116
"Wrong type for passthrough data: Expected a 'dict', found "
117117
f"'{type(result.passthrough_data)}'."
118118
)
119119

120+
passthrough: dict[str, Any] = result.passthrough_data or {}
120121
if (post_processor_data := passthrough.get("post_processor", None)) is None:
121122
raise ValueError("Missing 'post_processor' in passthrough data.")
122123

qiskit_ibm_runtime/decoders/executor_sampler/post_processor_v0_1.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
from __future__ import annotations
1616

17-
from typing import TYPE_CHECKING
17+
from typing import TYPE_CHECKING, Any
1818

1919
from qiskit.primitives import PrimitiveResult
2020

@@ -51,7 +51,7 @@ def sampler_v2_post_processor_v0_1(result: QuantumProgramResult) -> PrimitiveRes
5151
f"'{type(result.passthrough_data)}'."
5252
)
5353

54-
passthrough = result.passthrough_data or {}
54+
passthrough: dict[str, Any] = result.passthrough_data or {}
5555
if (post_processor_data := passthrough.get("post_processor", None)) is None:
5656
raise ValueError("Missing 'post_processor' in passthrough data.")
5757
if (twirling := post_processor_data.get("twirling", None)) is None:

qiskit_ibm_runtime/decoders/quantum_program/converters.py

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,30 @@
2929
)
3030

3131
if TYPE_CHECKING:
32-
from ibm_quantum_schemas.executor.version_0_1 import QuantumProgramResultModel
32+
from ibm_quantum_schemas.executor.version_0_1 import (
33+
QuantumProgramResultModel as QuantumProgramResultModel_0_1,
34+
)
35+
from ibm_quantum_schemas.executor.version_0_2 import (
36+
QuantumProgramResultModel as QuantumProgramResultModel_0_2,
37+
)
38+
from ibm_quantum_schemas.executor.version_1_0 import (
39+
QuantumProgramResultModel as QuantumProgramResultModel_1_0,
40+
)
41+
from ibm_quantum_schemas.executor.version_1_1 import (
42+
QuantumProgramResultModel as QuantumProgramResultModel_1_1,
43+
)
44+
from ibm_quantum_schemas.executor.version_2_0 import (
45+
QuantumProgramResultModel as QuantumProgramResultModel_2_0,
46+
)
47+
3348

3449
from ...quantum_program.converters.converters_0_2 import passthrough_data_from_0_2
3550
from ...quantum_program.converters.converters_1_0 import passthrough_data_from_1_0
3651
from ...quantum_program.converters.converters_1_1 import passthrough_data_from_1_1
3752
from ...quantum_program.converters.converters_2_0 import passthrough_data_from_2_0
3853

3954

40-
def quantum_program_result_from_0_1(model: QuantumProgramResultModel) -> QuantumProgramResult:
55+
def quantum_program_result_from_0_1(model: QuantumProgramResultModel_0_1) -> QuantumProgramResult:
4156
"""Convert a V0.1 model to a :class:`QuantumProgramResult`."""
4257
metadata = Metadata(
4358
chunk_timing=[
@@ -58,7 +73,7 @@ def quantum_program_result_from_0_1(model: QuantumProgramResultModel) -> Quantum
5873
)
5974

6075

61-
def quantum_program_result_from_0_2(model: QuantumProgramResultModel) -> QuantumProgramResult:
76+
def quantum_program_result_from_0_2(model: QuantumProgramResultModel_0_2) -> QuantumProgramResult:
6277
"""Convert a V0.2 model to a :class:`QuantumProgramResult`."""
6378
metadata = Metadata(
6479
chunk_timing=[
@@ -95,7 +110,7 @@ def quantum_program_result_from_0_2(model: QuantumProgramResultModel) -> Quantum
95110
)
96111

97112

98-
def quantum_program_result_from_1_0(model: QuantumProgramResultModel) -> QuantumProgramResult:
113+
def quantum_program_result_from_1_0(model: QuantumProgramResultModel_1_0) -> QuantumProgramResult:
99114
"""Convert a V1.0 model to a :class:`QuantumProgramResult`."""
100115
metadata = Metadata(
101116
chunk_timing=[
@@ -134,7 +149,7 @@ def quantum_program_result_from_1_0(model: QuantumProgramResultModel) -> Quantum
134149
return result
135150

136151

137-
def quantum_program_result_from_1_1(model: QuantumProgramResultModel) -> QuantumProgramResult:
152+
def quantum_program_result_from_1_1(model: QuantumProgramResultModel_1_1) -> QuantumProgramResult:
138153
"""Convert a V1.1 model to a :class:`QuantumProgramResult`."""
139154
metadata = Metadata(
140155
chunk_timing=[
@@ -173,7 +188,7 @@ def quantum_program_result_from_1_1(model: QuantumProgramResultModel) -> Quantum
173188
return result
174189

175190

176-
def quantum_program_result_from_2_0(model: QuantumProgramResultModel) -> QuantumProgramResult:
191+
def quantum_program_result_from_2_0(model: QuantumProgramResultModel_2_0) -> QuantumProgramResult:
177192
"""Convert a V2.0 model to a :class:`QuantumProgramResult`."""
178193
metadata = Metadata(
179194
chunk_timing=[

qiskit_ibm_runtime/executor_estimator/utils.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@
2828
import numpy.typing as npt
2929
from qiskit import QuantumCircuit
3030
from qiskit.circuit import BoxOp, CircuitInstruction
31-
from qiskit.primitives import EstimatorPub, SamplerPub
31+
from qiskit.primitives.containers.estimator_pub import EstimatorPub
32+
from qiskit.primitives.containers.sampler_pub import SamplerPub
3233
from samplomatic.samplex import Samplex
3334

3435
from ..options_models.measure_noise_learning import MeasureNoiseLearningOptions

qiskit_ibm_runtime/noise_learner_v3/params_converters.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414

1515
from __future__ import annotations
1616

17-
from typing import TYPE_CHECKING, NamedTuple
17+
from dataclasses import dataclass
18+
from typing import TYPE_CHECKING, Generic, TypeVar
1819

1920
from ibm_quantum_schemas.noise_learner_v3.version_0_1 import ParamsModel as ParamsModel_0_1
2021
from ibm_quantum_schemas.noise_learner_v3.version_0_2 import ParamsModel as ParamsModel_0_2
@@ -38,16 +39,20 @@
3839
from ..options_models import NoiseLearnerV3Options
3940

4041

41-
class ParamsConverter(NamedTuple):
42+
ModelT = TypeVar("ModelT", bound="BaseParamsModel")
43+
44+
45+
@dataclass(frozen=True)
46+
class ParamsConverter(Generic[ModelT]):
4247
"""A helper to store params models and converters."""
4348

44-
model: type[BaseParamsModel]
49+
model: type[ModelT]
4550
"""The model describing the NLV3 inputs, or 'params'."""
4651

47-
decoder: Callable[[BaseParamsModel], tuple[list[CircuitInstruction], NoiseLearnerV3Options]]
52+
decoder: Callable[[ModelT], tuple[list[CircuitInstruction], NoiseLearnerV3Options]]
4853
"""A function to decode the inputs of NLV3."""
4954

50-
encoder: Callable[[Iterable[CircuitInstruction], NoiseLearnerV3Options], BaseParamsModel]
55+
encoder: Callable[[Iterable[CircuitInstruction], NoiseLearnerV3Options], ModelT]
5156
"""A function to encode the inputs of NLV3."""
5257

5358

qiskit_ibm_runtime/quantum_program/params_converters.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414

1515
from __future__ import annotations
1616

17-
from typing import TYPE_CHECKING, NamedTuple
17+
from dataclasses import dataclass
18+
from typing import TYPE_CHECKING, Generic, TypeVar
1819

1920
from ibm_quantum_schemas.executor.version_0_1 import ParamsModel as ParamsModel_0_1
2021
from ibm_quantum_schemas.executor.version_0_2 import ParamsModel as ParamsModel_0_2
@@ -44,16 +45,20 @@
4445
from .quantum_program import QuantumProgram
4546

4647

47-
class ParamsConverter(NamedTuple):
48+
ModelT = TypeVar("ModelT", bound="BaseParamsModel")
49+
50+
51+
@dataclass(frozen=True)
52+
class ParamsConverter(Generic[ModelT]):
4853
"""A helper to store params models and converters."""
4954

50-
model: type[BaseParamsModel]
55+
model: type[ModelT]
5156
"""The model describing the executor inputs, or 'params'."""
5257

53-
decoder: Callable[[BaseParamsModel], tuple[QuantumProgram, ExecutorOptions]]
58+
decoder: Callable[[ModelT], tuple[QuantumProgram, ExecutorOptions]]
5459
"""A function to decode the inputs of executor."""
5560

56-
encoder: Callable[[QuantumProgram, ExecutorOptions], BaseParamsModel]
61+
encoder: Callable[[QuantumProgram, ExecutorOptions], ModelT]
5762
"""A function to encode the inputs of executor."""
5863

5964

qiskit_ibm_runtime/results/quantum_program.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -204,15 +204,12 @@ def __getitem__(self, idx: int) -> QuantumProgramItemResult: ...
204204
def __getitem__(self, idx: slice) -> list[QuantumProgramItemResult]: ...
205205

206206
def __getitem__(
207-
self, index: int | slice
207+
self, idx: int | slice
208208
) -> QuantumProgramItemResult | list[QuantumProgramItemResult]:
209-
get_item = super().__getitem__
210-
if isinstance(index, int):
211-
return cast("QuantumProgramItemResult", get_item(index))
212-
return [
213-
cast("QuantumProgramItemResult", get_item(idx))
214-
for idx in range(*index.indices(len(self)))
215-
]
209+
return cast(
210+
"QuantumProgramItemResult | list[QuantumProgramItemResult]",
211+
super().__getitem__(idx),
212+
)
216213

217214
def __iter__(self) -> Iterator[QuantumProgramItemResult]:
218215
return cast("Iterator[QuantumProgramItemResult]", super().__iter__())

0 commit comments

Comments
 (0)