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

feat: Added a mechanism to reset cached properties whenever a device is rebooted. #118

Merged
merged 1 commit into from
Dec 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ ______________________________________________________________________

Things to be included in the next release go here.

### Added

- Added a step during a device reboot that will reset all the cached properties in the event that one of them changed.

### Changed

- Switched to ruff's formatter instead of black's formatter for python code
Expand Down
30 changes: 22 additions & 8 deletions src/tm_devices/drivers/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import time

from abc import ABC, abstractmethod
from contextlib import contextmanager
from contextlib import contextmanager, suppress
from functools import cached_property
from typing import (
Any,
Expand Down Expand Up @@ -89,13 +89,9 @@ def __str__(self) -> str:
retval = f"{'=' * (line_break_length // 2)} {self.name} {'=' * (line_break_length // 2)}\n"
retval += f" {self.__class__} object at {id(self)}"

for prop in [
p
for p in dir(self.__class__)
if isinstance(getattr(self.__class__, p), (cached_property, property))
and not p.startswith("_")
]:
retval += f"\n {prop}={self.__getattribute__(prop)!r}"
for prop in self._get_self_properties():
if not prop.startswith("_"):
retval += f"\n {prop}={self.__getattribute__(prop)!r}"

retval += f"\n{'=' * (line_break_length + 2 + len(self.name))}"
return retval
Expand Down Expand Up @@ -472,6 +468,16 @@ def reboot(self, quiet_period: int = 0) -> bool:
Returns:
A boolean representing the status of the reboot.
"""
# Reset the cached properties
for prop in self._get_self_properties():
if isinstance(getattr(self.__class__, prop), cached_property):
# Try to delete the cached_property, if it raises an AttributeError,
# that means that it has not previously been accessed and
# there is no need to delete the cached_property.
with suppress(AttributeError):
self.__delattr__(prop) # pylint: disable=unnecessary-dunder-call

# Reboot the device
print_with_timestamp(f"Rebooting {self._name_and_alias}")
self._reboot()
self.close()
Expand Down Expand Up @@ -677,6 +683,14 @@ def wait_for_port_connection(
# Private Methods
################################################################################################

def _get_self_properties(self) -> Tuple[str, ...]:
"""Get a complete list of all the properties of the device."""
return tuple(
p
for p in dir(self.__class__)
if isinstance(getattr(self.__class__, p), (cached_property, property))
)

@staticmethod
@final
def _verify_numerical_value(
Expand Down
10 changes: 10 additions & 0 deletions tests/test_afgs.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,19 @@ def test_afg31k(device_manager: DeviceManager, capsys: pytest.CaptureFixture[str
afg31k = device_manager.add_afg("afg31k-hostname")

_ = capsys.readouterr().out # throw away stdout

# Check hostname
assert afg31k.hostname == "AFG31K-HOSTNAME"
# Change hostname to test the reset of cached properties
afg31k.hostname = "temp-hostname"
assert afg31k.hostname == "temp-hostname"

# simulate a reboot
afg31k.reboot()

# Test that the cached property was reset
assert afg31k.hostname == "AFG31K-HOSTNAME"

stdout = capsys.readouterr().out
assert "SYSTem:RESTart" in stdout

Expand Down
Loading