From f15151d339a87af7792d6c843df8f70fa10ca26d Mon Sep 17 00:00:00 2001 From: Christina Lee Date: Thu, 2 May 2024 14:00:41 -0400 Subject: [PATCH] improve error on setting shots on new device api (#5616) **Context:** As more devices switch to the new device interface, users may request properties or behaviours that are no longer there. The current error messages do not sufficiently alert users to the fact that the device interface has changed. **Description of the Change:** Make a more informative error when trying to set the shots or access a non-existant attribute. **Benefits:** **Possible Drawbacks:** **Related GitHub Issues:** --- doc/releases/changelog-0.36.0.md | 4 ++++ pennylane/devices/device_api.py | 18 ++++++++++++++++++ tests/devices/experimental/test_device_api.py | 13 ++++++++++++- 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/doc/releases/changelog-0.36.0.md b/doc/releases/changelog-0.36.0.md index 93a68f89887..e2b5ed49de2 100644 --- a/doc/releases/changelog-0.36.0.md +++ b/doc/releases/changelog-0.36.0.md @@ -551,6 +551,10 @@

Bug fixes 🐛

+* Improves the error message for setting shots on the new device interface, or trying to access a property + that no longer exists. + [(#5616)](https://github.com/PennyLaneAI/pennylane/pull/5616) + * Fixed a bug where `qml.draw` and `qml.draw_mpl` incorrectly raised errors for circuits collecting statistics on mid-circuit measurements while using `qml.defer_measurements`. [(#5610)](https://github.com/PennyLaneAI/pennylane/pull/5610) diff --git a/pennylane/devices/device_api.py b/pennylane/devices/device_api.py index 2f6abd19f1f..325861430b6 100644 --- a/pennylane/devices/device_api.py +++ b/pennylane/devices/device_api.py @@ -177,6 +177,14 @@ def __repr__(self): details = f"({', '.join(details)}) " if details else "" return f"<{self.name} device {details}at {hex(id(self))}>" + def __getattr__(self, key): + raise AttributeError( + f"{type(self).__name__} has no attribute '{key}'." + " You may be looking for a property or method present in the legacy device interface." + f" Please consult the {type(self).__name__} documentation for an updated list of public" + " properties and methods." + ) + @property def shots(self) -> Shots: """Default shots for execution workflows containing this device. @@ -187,6 +195,16 @@ def shots(self) -> Shots: """ return self._shots + @shots.setter + def shots(self, _): + raise AttributeError( + ( + "Shots can no longer be set on a device instance. " + "You can set shots on a call to a QNode, on individual tapes, or " + "create a new device instance instead." + ) + ) + @property def wires(self) -> Wires: """The device wires. diff --git a/tests/devices/experimental/test_device_api.py b/tests/devices/experimental/test_device_api.py index 78566e6d401..9ee1b854c10 100644 --- a/tests/devices/experimental/test_device_api.py +++ b/tests/devices/experimental/test_device_api.py @@ -71,9 +71,20 @@ def test_shots(self): shots_dev = self.MinimalDevice(shots=100) assert shots_dev.shots == qml.measurements.Shots(100) - with pytest.raises(AttributeError): + with pytest.raises( + AttributeError, match="Shots can no longer be set on a device instance." + ): self.dev.shots = 100 # pylint: disable=attribute-defined-outside-init + def test_getattr_error(self): + """Test that querying a property that doesn't exist informs about interface change.""" + + with pytest.raises( + AttributeError, + match=r"You may be looking for a property or method present in the legacy device", + ): + _ = self.dev.expand_fn + def test_tracker_set_on_initialization(self): """Test that a new tracker instance is initialized with the class.""" assert isinstance(self.dev.tracker, qml.Tracker)