Skip to content

Commit

Permalink
feat: Added a mechanism to reset cached properties whenever a device …
Browse files Browse the repository at this point in the history
…is rebooted. (#118)
  • Loading branch information
nfelt14 authored Dec 12, 2023
1 parent 913a172 commit b67080c
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 8 deletions.
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

0 comments on commit b67080c

Please sign in to comment.