Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disallow unsupported options #1108

Merged
merged 23 commits into from
Oct 26, 2023
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
6f33efa
Disallow unsupported options
merav-aharoni Sep 26, 2023
a8655f7
Merge branch 'main' into kwargs_options
merav-aharoni Sep 26, 2023
9891584
Merge branch 'main' into kwargs_options
merav-aharoni Sep 27, 2023
2cf63f7
Moved checking of unsupported options to 'flexible' decorator
merav-aharoni Sep 28, 2023
89829b3
Modified the test to give TypeError where needed
merav-aharoni Sep 28, 2023
681a3c1
Merge branch 'kwargs_options' of github.com:merav-aharoni/qiskit-ibm-…
merav-aharoni Sep 28, 2023
5a5539d
Removed empty newline
merav-aharoni Sep 28, 2023
f8a026f
Moved tests from test_ibm_primitives to test_options, because they do…
merav-aharoni Sep 28, 2023
e6ccc89
typo
merav-aharoni Sep 28, 2023
071bcfc
Release note
merav-aharoni Sep 28, 2023
3d58ffe
black and lint
merav-aharoni Sep 28, 2023
f74d67f
Merge branch 'main' into kwargs_options
merav-aharoni Sep 28, 2023
9daf047
black again
merav-aharoni Sep 28, 2023
e8a5888
Merge branch 'kwargs_options' of github.com:merav-aharoni/qiskit-ibm-…
merav-aharoni Sep 28, 2023
a8df842
Fixed test failing in CI
merav-aharoni Sep 28, 2023
7f97ada
Removed _flexible decorator. Moved _post_init into Options class
merav-aharoni Oct 23, 2023
d08c064
Merge branch 'main' into kwargs_options
merav-aharoni Oct 23, 2023
27cb46a
lint
merav-aharoni Oct 23, 2023
41ce99d
Merge branch 'kwargs_options' of github.com:merav-aharoni/qiskit-ibm-…
merav-aharoni Oct 23, 2023
8ae4299
lint
merav-aharoni Oct 23, 2023
9e89ba8
Fixed bug
merav-aharoni Oct 23, 2023
a9c03ab
lint
merav-aharoni Oct 24, 2023
507e188
Merge branch 'main' into kwargs_options
kt474 Oct 25, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions qiskit_ibm_runtime/options/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

"""Utility functions for options."""

from dataclasses import fields, field, make_dataclass
from dataclasses import fields, make_dataclass
from ..ibm_backend import IBMBackend


Expand Down Expand Up @@ -92,8 +92,8 @@ def __new__(cls, *_, **kwargs): # type: ignore
orig_field_names.add(fld.name)

for key, val in kwargs.items():
if key not in orig_field_names:
all_fields.append((key, type(val), field(default=None)))
if key in dir(cls):
setattr(cls, key, val)
kt474 marked this conversation as resolved.
Show resolved Hide resolved

new_cls = make_dataclass(
cls.__name__,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
features:
- |
Arbitrary keys and values are no longer allowed in ``Options``.
43 changes: 0 additions & 43 deletions test/unit/test_ibm_primitives.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
import copy
import os
from unittest.mock import MagicMock, patch
import warnings
from dataclasses import asdict
from typing import Dict

Expand Down Expand Up @@ -85,28 +84,6 @@ def test_dict_options(self):
self._update_dict(expected, copy.deepcopy(options))
self.assertDictEqual(expected, inst.options.__dict__)

def test_backend_in_options(self):
"""Test specifying backend in options."""
primitives = [Sampler, Estimator]
backend_name = "ibm_gotham"
backend = MagicMock(spec=IBMBackend)
backend._instance = None
backend.name = backend_name
backends = [backend_name, backend]
for cls in primitives:
for backend in backends:
with self.subTest(primitive=cls, backend=backend):
options = {"backend": backend}
with warnings.catch_warnings(record=True) as warn:
warnings.simplefilter("always")
cls(session=MagicMock(spec=MockSession), options=options)
self.assertTrue(
all(
issubclass(one_warn.category, DeprecationWarning)
for one_warn in warn
)
)

def test_runtime_options(self):
"""Test RuntimeOptions specified as primitive options."""
session = MagicMock(spec=MockSession)
Expand Down Expand Up @@ -415,22 +392,6 @@ def test_run_overwrite_runtime_options(self):
rt_options = kwargs["options"]
self._assert_dict_partially_equal(rt_options, options)

def test_kwarg_options(self):
"""Test specifying arbitrary options."""
session = MagicMock(spec=MockSession)
primitives = [Sampler, Estimator]
for cls in primitives:
with self.subTest(primitive=cls):
options = Options(foo="foo") # pylint: disable=unexpected-keyword-arg
inst = cls(session=session, options=options)
inst.run(self.qx, observables=self.obs)
if sys.version_info >= (3, 8):
inputs = session.run.call_args.kwargs["inputs"]
else:
_, kwargs = session.run.call_args
inputs = kwargs["inputs"]
self.assertEqual(inputs.get("foo"), "foo")

def test_run_kwarg_options(self):
"""Test specifying arbitrary options in run."""
session = MagicMock(spec=MockSession)
Expand Down Expand Up @@ -477,10 +438,6 @@ def test_set_options(self):
new_options = [
({"optimization_level": 2}, Options()),
({"optimization_level": 3, "shots": 200}, Options()),
(
{"shots": 300, "foo": "foo"},
Options(foo="foo"), # pylint: disable=unexpected-keyword-arg
),
]

session = MagicMock(spec=MockSession)
Expand Down
79 changes: 25 additions & 54 deletions test/unit/test_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@

"""Tests for Options class."""

import warnings
from dataclasses import asdict

from ddt import data, ddt
Expand Down Expand Up @@ -62,51 +61,6 @@ def test_merge_options(self):
f"options={options}, combined={combined}",
)

def test_merge_options_extra_fields(self):
"""Test merging options with extra fields."""
options_vars = [
(
{
"initial_layout": [2, 3],
"transpilation": {"layout_method": "trivial"},
"foo": "foo",
},
Options(foo="foo"), # pylint: disable=unexpected-keyword-arg
),
(
{
"initial_layout": [3, 4],
"transpilation": {"layout_method": "dense", "bar": "bar"},
},
Options(transpilation={"bar": "bar"}),
),
(
{
"initial_layout": [1, 2],
"foo": "foo",
"transpilation": {"layout_method": "dense", "foo": "foo"},
},
Options( # pylint: disable=unexpected-keyword-arg
foo="foo", transpilation={"foo": "foo"}
),
),
]
for new_ops, expected in options_vars:
with self.subTest(new_ops=new_ops):
options = Options()
combined = Options._merge_options(asdict(options), new_ops)

# Make sure the values are equal.
self.assertTrue(
flat_dict_partially_equal(combined, new_ops),
f"new_ops={new_ops}, combined={combined}",
)
# Make sure the structure didn't change.
self.assertTrue(
dict_keys_equal(combined, asdict(expected)),
f"expected={expected}, combined={combined}",
)

def test_runtime_options(self):
"""Test converting runtime options."""
full_options = RuntimeOptions(
Expand Down Expand Up @@ -137,14 +91,8 @@ def test_program_inputs(self):
environment={"log_level": "DEBUG"},
simulator={"noise_model": noise_model},
resilience={"noise_factors": (0, 2, 4)},
foo="foo",
bar="bar",
)

with warnings.catch_warnings(record=True) as warn:
warnings.simplefilter("always")
inputs = Options._get_program_inputs(asdict(options))
self.assertEqual(len(warn), 2)
inputs = Options._get_program_inputs(asdict(options))

expected = {
"run_options": {"shots": 100, "noise_model": noise_model},
Expand All @@ -157,7 +105,6 @@ def test_program_inputs(self):
"level": 2,
"noise_factors": (0, 2, 4),
},
"foo": "foo",
}
self.assertTrue(
dict_paritally_equal(inputs, expected),
Expand Down Expand Up @@ -191,6 +138,30 @@ def test_init_options_with_dictionary(self):
# Make sure the structure didn't change.
self.assertTrue(dict_keys_equal(asdict(Options()), options), f"options={options}")

def test_kwargs_options(self):
"""Test specifying arbitrary options."""
with self.assertRaises(TypeError) as exc:
_ = Options(foo="foo") # pylint: disable=unexpected-keyword-arg
self.assertIn(
"__init__() got an unexpected keyword argument 'foo'",
str(exc.exception),
)

def test_backend_in_options(self):
"""Test specifying backend in options."""
backend_name = "ibm_gotham"
backend = FakeManila()
backend._instance = None
backend.name = backend_name
backends = [backend_name, backend]
for backend in backends:
with self.assertRaises(TypeError) as exc:
_ = Options(backend=backend) # pylint: disable=unexpected-keyword-arg
self.assertIn(
"__init__() got an unexpected keyword argument 'backend'",
str(exc.exception),
)

def test_unsupported_options(self):
"""Test error on unsupported second level options"""
# defining minimal dict of options
Expand Down