Skip to content

Commit 3a91895

Browse files
Lazily fetch properties and pulse defaults only when attributes are accessed
1 parent 10f1c89 commit 3a91895

File tree

11 files changed

+51
-43
lines changed

11 files changed

+51
-43
lines changed

qiskit_ibm_runtime/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@
8989
params.measurement_error_mitigation = True
9090
9191
# Configure backend options
92-
options = {'backend_name': backend.name()}
92+
options = {'backend_name': backend.name}
9393
9494
# Execute the circuit using the "circuit-runner" program.
9595
job = service.run(program_id="circuit-runner",

qiskit_ibm_runtime/ibm_backend.py

+34-26
Original file line numberDiff line numberDiff line change
@@ -84,33 +84,41 @@ def __init__(
8484
online_date=configuration.online_date,
8585
backend_version=configuration.backend_version,
8686
)
87-
8887
self._configuration = configuration
8988
self._api_client = api_client
9089
self._properties = None
9190
self._qubit_properties = None
9291
self._defaults = None
93-
92+
self._target = None
9493
self._max_circuits = configuration.max_experiments
9594

96-
api_properties = self._api_client.backend_properties(self.name)
97-
if api_properties:
98-
backend_properties = properties_from_server_data(api_properties)
99-
self._properties = backend_properties
100-
101-
api_defaults = self._api_client.backend_pulse_defaults(self.name)
102-
if api_defaults:
103-
self._defaults = defaults_from_server_data(api_defaults)
104-
105-
self._target = convert_to_target(
106-
configuration=configuration.to_dict(),
107-
properties=self._properties.to_dict() if api_properties else None,
108-
defaults=self._defaults.to_dict() if api_defaults else None,
109-
)
110-
111-
if api_properties:
112-
self._qubit_properties = qubit_properties_dict_from_properties(
113-
self._properties.to_dict()
95+
def __getattr__(self, name: str) -> Any:
96+
if not self._properties:
97+
api_properties = self._api_client.backend_properties(self.name)
98+
if api_properties:
99+
backend_properties = properties_from_server_data(api_properties)
100+
self._properties = backend_properties
101+
if not self._qubit_properties:
102+
self._qubit_properties = qubit_properties_dict_from_properties(
103+
self._properties.to_dict()
104+
)
105+
if not self._defaults:
106+
api_defaults = self._api_client.backend_pulse_defaults(self.name)
107+
if api_defaults:
108+
self._defaults = defaults_from_server_data(api_defaults)
109+
if not self._target:
110+
self._target = convert_to_target(
111+
configuration=self._configuration.to_dict(),
112+
properties=self._properties.to_dict() if api_properties else None,
113+
defaults=self._defaults.to_dict() if api_defaults else None,
114+
)
115+
try:
116+
return super().__getattribute__(name)
117+
except KeyError:
118+
raise AttributeError(
119+
"'{}' object has no attribute '{}'".format(
120+
self.__class__.__name__, name
121+
)
114122
)
115123

116124
@classmethod
@@ -164,7 +172,7 @@ def qubit_properties(
164172
"""
165173
if not self._qubit_properties:
166174
return None
167-
if isinstance(qubit, int):
175+
if isinstance(qubit, int): # type: ignore[unreachable]
168176
return self._qubit_properties.get(qubit)
169177
if isinstance(qubit, List):
170178
return [self._qubit_properties.get(q) for q in qubit]
@@ -217,7 +225,7 @@ def properties(
217225

218226
if datetime or refresh or self._properties is None:
219227
api_properties = self._api_client.backend_properties(
220-
self.name(), datetime=datetime
228+
self.name, datetime=datetime
221229
)
222230
if not api_properties:
223231
return None
@@ -241,7 +249,7 @@ def status(self) -> BackendStatus:
241249
Raises:
242250
IBMBackendApiProtocolError: If the status for the backend cannot be formatted properly.
243251
"""
244-
api_status = self._api_client.backend_status(self.name())
252+
api_status = self._api_client.backend_status(self.name)
245253

246254
try:
247255
return BackendStatus.from_dict(api_status)
@@ -266,7 +274,7 @@ def defaults(self, refresh: bool = False) -> Optional[PulseDefaults]:
266274
The backend pulse defaults or ``None`` if the backend does not support pulse.
267275
"""
268276
if refresh or self._defaults is None:
269-
api_defaults = self._api_client.backend_pulse_defaults(self.name())
277+
api_defaults = self._api_client.backend_pulse_defaults(self.name)
270278
if api_defaults:
271279
self._defaults = defaults_from_server_data(api_defaults)
272280
else:
@@ -292,7 +300,7 @@ def configuration(
292300
return self._configuration
293301

294302
def __repr__(self) -> str:
295-
return "<{}('{}')>".format(self.__class__.__name__, self.name())
303+
return "<{}('{}')>".format(self.__class__.__name__, self.name)
296304

297305
def run(self, *args: Any, **kwargs: Any) -> None:
298306
"""Not supported method"""
@@ -335,7 +343,7 @@ def __init__(
335343
"""
336344
super().__init__(configuration, api_client)
337345
self._status = BackendStatus(
338-
backend_name=self.name(),
346+
backend_name=self.name,
339347
backend_version=self.configuration().backend_version,
340348
operational=False,
341349
pending_jobs=0,

qiskit_ibm_runtime/ibm_runtime_service.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ class IBMRuntimeService:
9090
params.measurement_error_mitigation = True
9191
9292
# Configure backend options
93-
options = {'backend_name': backend.name()}
93+
options = {'backend_name': backend.name}
9494
9595
# Execute the circuit using the "circuit-runner" program.
9696
job = service.run(program_id="circuit-runner",
@@ -456,7 +456,7 @@ def _get_hgp(
456456
def _discover_backends(self) -> None:
457457
"""Discovers the remote backends for this account, if not already known."""
458458
for backend in self._backends.values():
459-
backend_name = to_python_identifier(backend.name())
459+
backend_name = to_python_identifier(backend.name)
460460
# Append _ if duplicate
461461
while backend_name in self.__dict__:
462462
backend_name += "_"

qiskit_ibm_runtime/jupyter/backend_info.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def backend_widget(backend: Union[IBMBackend, FakeBackend]) -> None:
4343
vue.ToolbarTitle(
4444
children=[
4545
"{} @ ({}/{}/{})".format(
46-
backend.name(), cred.hub, cred.group, cred.project
46+
backend.name, cred.hub, cred.group, cred.project
4747
)
4848
],
4949
style_="color:white",

qiskit_ibm_runtime/jupyter/dashboard/backend_widget.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def make_backend_widget(backend_item: BackendWithProviders) -> wid.HBox:
4848
next_resrv = get_next_reservation(backend)
4949

5050
name_str = "<font size='5' face='monospace'>%s</font>"
51-
backend_name = wid.HTML(value=name_str % backend.name())
51+
backend_name = wid.HTML(value=name_str % backend.name)
5252

5353
qubits_wid = wid.HTML(value=STAT_FONT_TITLE.format("Qubits:"))
5454
qubits_val_wid = wid.HTML(value=STAT_FONT_VALUE.format(config.n_qubits))

qiskit_ibm_runtime/visualization/interactive/error_map.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -535,7 +535,7 @@ def iplot_error_map(
535535
for ann in fig["layout"]["annotations"]:
536536
ann["font"] = dict(size=13)
537537

538-
title_text = "{} Error Map".format(backend.name()) if show_title else ""
538+
title_text = "{} Error Map".format(backend.name) if show_title else ""
539539
fig.update_layout(
540540
showlegend=False,
541541
plot_bgcolor=background_color,

qiskit_runtime/qaoa/qaoa.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1885,7 +1885,7 @@ def __init__(
18851885
self._coupling_map = CouplingMap(coupling_map)
18861886
self._two_qubit_fidelity = {}
18871887
self._max_problem_size = backend.configuration().num_qubits
1888-
self._name = backend.name()
1888+
self._name = backend.name
18891889
self._use_fidelity = use_fidelity
18901890

18911891
props = backend.properties()

test/test_backend_retrieval.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ def test_filter_least_busy(self):
128128
for service in services:
129129
with self.subTest(service=service.auth):
130130
backend = service.least_busy()
131-
self.assertEqual(backend.name(), "bingo")
131+
self.assertEqual(backend.name, "bingo")
132132

133133
def test_filter_min_num_qubits(self):
134134
"""Test filtering by minimum number of qubits."""

test/test_integration_backend.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -59,34 +59,34 @@ def setUpClass(cls, devices):
5959
def test_backend_status(self):
6060
"""Check the status of a real chip."""
6161
for backend in self.devices:
62-
with self.subTest(backend=backend.name()):
62+
with self.subTest(backend=backend.name):
6363
self.assertTrue(backend.status().operational)
6464

6565
def test_backend_properties(self):
6666
"""Check the properties of calibration of a real chip."""
6767
for backend in self.devices:
68-
with self.subTest(backend=backend.name()):
68+
with self.subTest(backend=backend.name):
6969
if backend.configuration().simulator:
7070
raise SkipTest("Skip since simulator does not have properties.")
7171
self.assertIsNotNone(backend.properties())
7272

7373
def test_backend_pulse_defaults(self):
7474
"""Check the backend pulse defaults of each backend."""
7575
for backend in self.devices:
76-
with self.subTest(backend=backend.name()):
76+
with self.subTest(backend=backend.name):
7777
if backend.configuration().simulator:
7878
raise SkipTest("Skip since simulator does not have defaults.")
7979
self.assertIsNotNone(backend.defaults())
8080

8181
def test_backend_configuration(self):
8282
"""Check the backend configuration of each backend."""
8383
for backend in self.devices:
84-
with self.subTest(backend=backend.name()):
84+
with self.subTest(backend=backend.name):
8585
self.assertIsNotNone(backend.configuration())
8686

8787
def test_backend_run(self):
8888
"""Check one cannot do backend.run"""
8989
for backend in self.devices:
90-
with self.subTest(backend=backend.name()):
90+
with self.subTest(backend=backend.name):
9191
with self.assertRaises(RuntimeError):
9292
backend.run()

test/test_integration_job.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ def test_job_inputs(self, service):
202202
def test_job_backend(self, service):
203203
"""Test job backend."""
204204
job = self._run_program(service)
205-
self.assertEqual(self.sim_backends[service.auth], job.backend.name())
205+
self.assertEqual(self.sim_backends[service.auth], job.backend.name)
206206

207207
@run_cloud_legacy_real
208208
def test_job_program_id(self, service):

test/test_jobs.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ def test_run_program_default_hgp_backend(self):
8787
default_hgp = list(service._hgps.values())[0]
8888
self.assertIn(backend, default_hgp.backends.keys())
8989
job = run_program(service=service, backend_name=backend)
90-
self.assertEqual(job.backend.name(), backend)
90+
self.assertEqual(job.backend.name, backend)
9191
self.assertEqual(
9292
job.backend._api_client.hgp, FakeRuntimeService.DEFAULT_HGPS[0]
9393
)
@@ -99,7 +99,7 @@ def test_run_program_non_default_hgp_backend(self):
9999
default_hgp = list(service._hgps.values())[0]
100100
self.assertNotIn(backend, default_hgp.backends.keys())
101101
job = run_program(service=service, backend_name=backend)
102-
self.assertEqual(job.backend.name(), backend)
102+
self.assertEqual(job.backend.name, backend)
103103

104104
def test_run_program_by_hgp_backend(self):
105105
"""Test running a program with both backend and hgp."""
@@ -109,7 +109,7 @@ def test_run_program_by_hgp_backend(self):
109109
job = run_program(
110110
service=service, backend_name=backend, instance=non_default_hgp
111111
)
112-
self.assertEqual(job.backend.name(), backend)
112+
self.assertEqual(job.backend.name, backend)
113113
self.assertEqual(job.backend._api_client.hgp, non_default_hgp)
114114

115115
def test_run_program_by_hgp_bad_backend(self):

0 commit comments

Comments
 (0)