From 763141f7a0c1238878e3c5da2b75883f14baa87e Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Tue, 4 May 2021 17:14:44 -0400 Subject: [PATCH] Update options to be a mapping instead of a simple namespace This commit changes the options class to be a mapping instead of a simple namespace. While we wanted to preserve attribute based access primarily the simple namespace is too limited in practice and involves a lot of hacking around the internals such as frequent calls to Options.__dict__ to get an iterator of fields in the options. To improve the usability of the class without breaking existing users this changes the base class to be a MutableMapping and adds the necessary methods to make it usable like a dict or a simple namespace. --- qiskit/providers/basicaer/qasm_simulator.py | 2 +- qiskit/providers/options.py | 61 +++++++++++++++++++-- 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/qiskit/providers/basicaer/qasm_simulator.py b/qiskit/providers/basicaer/qasm_simulator.py index b3d163006556..320d328c1877 100644 --- a/qiskit/providers/basicaer/qasm_simulator.py +++ b/qiskit/providers/basicaer/qasm_simulator.py @@ -125,7 +125,7 @@ def __init__(self, configuration=None, provider=None, **fields): self._shots = 0 self._memory = False self._initial_statevector = self.options.get("initial_statevector") - self._chop_threshold = self.options.get("chop_threashold") + self._chop_threshold = self.options.get("chop_threshold") self._qobj_config = None # TEMP self._sample_measure = False diff --git a/qiskit/providers/options.py b/qiskit/providers/options.py index b5d2469d16c4..e8c4b90aa2f4 100644 --- a/qiskit/providers/options.py +++ b/qiskit/providers/options.py @@ -12,10 +12,10 @@ """Container class for backend options.""" -import types +from collections.abc import MutableMapping -class Options(types.SimpleNamespace): +class Options(MutableMapping): """Base options object This class is the abstract class that all backend options are based @@ -26,10 +26,63 @@ class Options(types.SimpleNamespace): options. """ + _dict = {} + + def __init__(self, **kwargs): + self._dict = {} + super().__init__() + self._dict = kwargs + + def __getattr__(self, field): + if field == "_dict": + super().__getattribute__(field) + elif field not in self._dict: + raise AttributeError("%s not a valid option" % field) + self._dict[field] + + def __getitem__(self, field): + if field not in self._dict: + raise KeyError("%s not a valid option" % field) + self._dict.get(field, default) + + def __setitem__(self, field, value): + if field in self._dict: + self._dict[field] = value + else: + raise KeyError("%s not a valid option" % field) + + def __delitem__(self, field): + del self._dict[field] + + def __len__(self): + return len(self._dict) + + def __iter__(self): + return iter(self._dict) + + def __setattr__(self, field, value): + if field == "_dict": + super().__setattr__(field, value) + elif field in self._dict: + self._dict[field] = value + else: + raise AttributeError("%s not a valid option" % field) + + def __repr__(self): + return "Options(%s)" % ", ".join("k=v" for k, v in self._dict.items()) + def update_options(self, **fields): """Update options with kwargs""" - self.__dict__.update(fields) + self._dict.update(fields) def get(self, field, default=None): """Get an option value for a given key.""" - return getattr(self, field, default) + return self._dict.get(field, default) + + def __dict__(self): + return self._dict + + def __eq__(self, other): + if isinstance(other, Options): + return self._dict == other._dict + return NotImplementedError