Skip to content

Commit

Permalink
Update read only cached property for PyCharm auto-complete support (#149
Browse files Browse the repository at this point in the history
)

* fix: Update import statements to allow type hinting and auto-completion to work in the PyCharm IDE.

* refactor: Move regex string into a separate constant in functions.py to prevent PyCharm from showing false syntax errors.
  • Loading branch information
nfelt14 authored Feb 21, 2024
1 parent 6c0dcbd commit 3b328b8
Show file tree
Hide file tree
Showing 31 changed files with 173 additions and 93 deletions.
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ repos:
- id: check-github-actions
- id: check-github-workflows
- repo: https://github.com/commitizen-tools/commitizen
rev: v3.14.1
rev: v3.15.0
hooks:
- id: commitizen
stages: [commit-msg]
Expand Down Expand Up @@ -125,7 +125,7 @@ repos:
always_run: true
args: [., --min=10]
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.2.1
rev: v0.2.2
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ Things to be included in the next release go here.

- Updated the `get_model_series()` function to use a regex mapping instead of complicated logic to reduce maintenance costs.

### Fixed

- Updated import statements for the `ReadOnlyCachedProperty` decorator to allow PyCharm auto-complete to work properly.

______________________________________________________________________

## v1.2.0 (2024-02-09)
Expand Down
2 changes: 1 addition & 1 deletion docs/contributing/add_new_driver.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ This guide will walk through the steps needed to add a new device driver.
- See other `__init__.py` files for examples
04. Update the `SupportedModels` enum exposed in
`tm_devices/helpers/__init__.py`
05. Update the `_SUPPORTED_MODEL_REGEX_MAPPING` regex constant inside
05. Update the `___SUPPORTED_MODEL_REGEX_STRING` regex constant inside
`tm_devices/helpers/functions.py` to include a mapping of the new driver name (model series)
to a regex string matching the appropriate model strings
06. Update the `DEVICE_DRIVER_MODEL_MAPPING` lookup inside
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -105,15 +105,15 @@ poetry = ">=1.5.1"
pre-commit = ">=2.20.0"
pre-commit-update = ">=0.1.3"
pylint = {extras = ["spelling"], version = "3.0.3"} # Update this by running scripts/update_development_dependencies.py
pyright = "1.1.350" # Update this by running scripts/update_development_dependencies.py
pyright = "1.1.351" # Update this by running scripts/update_development_dependencies.py
pyroma = ">=4.2"
pytest = ">=7.1.2"
pytest-cov = ">=3.0.0"
pytest-html = ">=4.0"
pytest-order = ">=1.0.1"
pytest-profiling = ">=1.7.0"
python-semantic-release = ">=8.5.1"
ruff = "0.2.1" # Update this by running scripts/update_development_dependencies.py
ruff = "0.2.2" # Update this by running scripts/update_development_dependencies.py
safety = ">=2.1.1"
sphinx-autoapi = ">=2.0.0"
sphinx-copybutton = ">=0.5.1"
Expand Down
5 changes: 3 additions & 2 deletions src/tm_devices/driver_mixins/licensed_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
from abc import ABC, abstractmethod
from typing import final, Tuple

from tm_devices.helpers import ReadOnlyCachedProperty
# noinspection PyPep8Naming
from tm_devices.helpers import ReadOnlyCachedProperty as cached_property # noqa: N813


class LicensedMixin(ABC):
"""A mixin class which adds methods and properties for handling licenses."""

@ReadOnlyCachedProperty
@cached_property
@abstractmethod
def license_list(self) -> Tuple[str, ...]:
"""Return the list of licenses installed on the device."""
Expand Down
5 changes: 3 additions & 2 deletions src/tm_devices/driver_mixins/usb_drives_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
from abc import ABC, abstractmethod
from typing import Tuple

from tm_devices.helpers import ReadOnlyCachedProperty
# noinspection PyPep8Naming
from tm_devices.helpers import ReadOnlyCachedProperty as cached_property # noqa: N813


# pylint: disable=too-few-public-methods
class USBDrivesMixin(ABC):
"""A mixin class which adds the usb_drives property."""

@ReadOnlyCachedProperty
@cached_property
@abstractmethod
def usb_drives(self) -> Tuple[str, ...]:
"""Return a list of all connected USB drives."""
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@

from tm_devices.drivers.api.rest_api.rest_api_device import RESTAPIDevice
from tm_devices.drivers.device import family_base_class
from tm_devices.helpers import DeviceConfigEntry, DeviceTypes, ReadOnlyCachedProperty
from tm_devices.helpers import DeviceConfigEntry, DeviceTypes

# noinspection PyPep8Naming
from tm_devices.helpers import ReadOnlyCachedProperty as cached_property # noqa: N813


@family_base_class
Expand All @@ -36,22 +39,22 @@ def __init__(self, config_entry: DeviceConfigEntry, verbose: bool) -> None:
################################################################################################
# Abstract Cached Properties
################################################################################################
@ReadOnlyCachedProperty
@cached_property
@abstractmethod
def adapter(self) -> str:
"""Return the device's connected adapter."""

@ReadOnlyCachedProperty
@cached_property
@abstractmethod
def fpga_version(self) -> Version:
"""Return the fpga version of the device."""

@ReadOnlyCachedProperty
@cached_property
@abstractmethod
def fw_version(self) -> Version:
"""Return the firmware version of the device."""

@ReadOnlyCachedProperty
@cached_property
@abstractmethod
def supported_technologies(self) -> Tuple[str, ...]:
"""Return the device's supported technologies."""
Expand Down
21 changes: 12 additions & 9 deletions src/tm_devices/drivers/api/rest_api/margin_testers/tmt4.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
from packaging.version import Version

from tm_devices.drivers.api.rest_api.margin_testers.margin_tester import MarginTester
from tm_devices.helpers import DeviceConfigEntry, ReadOnlyCachedProperty
from tm_devices.helpers import DeviceConfigEntry

# noinspection PyPep8Naming
from tm_devices.helpers import ReadOnlyCachedProperty as cached_property # noqa: N813


class TMT4(MarginTester):
Expand Down Expand Up @@ -42,12 +45,12 @@ def __init__(self, config_entry: DeviceConfigEntry, verbose: bool) -> None:
################################################################################################
# Properties
################################################################################################
@ReadOnlyCachedProperty
@cached_property
def adapter(self) -> str:
"""Return the device's connected adapter."""
return self._about_info["adapter"]

@ReadOnlyCachedProperty
@cached_property
def fpga_version(self) -> Version:
"""Return the fpga version of the device."""
# This key can return strings indicating a reboot is needed instead of Versions.
Expand All @@ -56,7 +59,7 @@ def fpga_version(self) -> Version:
except ValueError:
return Version("0")

@ReadOnlyCachedProperty
@cached_property
def fw_version(self) -> Version:
"""Return the firmware version of the device."""
# This key can (also) return strings indicating a reboot is needed instead of Versions.
Expand All @@ -65,12 +68,12 @@ def fw_version(self) -> Version:
except ValueError:
return Version("0")

@ReadOnlyCachedProperty
@cached_property
def manufacturer(self) -> str:
"""Return the manufacturer of the device."""
return self._about_info["manufacturer"]

@ReadOnlyCachedProperty
@cached_property
def model(self) -> str:
"""Return the full model of the device."""
return self._about_info["model"]
Expand All @@ -80,17 +83,17 @@ def port(self) -> Optional[int]:
"""Return the configured device port, defaults to 5000."""
return super().port or 5000

@ReadOnlyCachedProperty
@cached_property
def serial(self) -> str:
"""Return the serial number of the device."""
return self._about_info["serialNumber"]

@ReadOnlyCachedProperty
@cached_property
def supported_technologies(self) -> Tuple[str, ...]:
"""Return the device's supported technologies."""
return tuple(self._about_info["supportedTechnologies"].split(","))

@ReadOnlyCachedProperty
@cached_property
def sw_version(self) -> Version:
"""Return the software version of the device."""
return Version(self._about_info["sw_version"])
Expand Down
24 changes: 13 additions & 11 deletions src/tm_devices/drivers/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from abc import ABC, abstractmethod
from contextlib import contextmanager, suppress
from functools import cached_property
from functools import cached_property as functools_cached_property
from typing import (
Any,
final,
Expand All @@ -25,9 +25,11 @@
DeviceConfigEntry,
get_timestamp_string,
print_with_timestamp,
ReadOnlyCachedProperty,
)

# noinspection PyPep8Naming
from tm_devices.helpers import ReadOnlyCachedProperty as cached_property # noqa: N813

_T = TypeVar("_T")
_FAMILY_BASE_CLASS_PROPERTY_NAME = "_product_family_base_class"

Expand Down Expand Up @@ -100,22 +102,22 @@ def __str__(self) -> str:
################################################################################################
# Abstract Cached Properties
################################################################################################
@ReadOnlyCachedProperty
@cached_property
@abstractmethod
def manufacturer(self) -> str:
"""Return the manufacturer of the device."""

@ReadOnlyCachedProperty
@cached_property
@abstractmethod
def model(self) -> str:
"""Return the full model of the device."""

@ReadOnlyCachedProperty
@cached_property
@abstractmethod
def serial(self) -> str:
"""Return the serial number of the device."""

@ReadOnlyCachedProperty
@cached_property
@abstractmethod
def sw_version(self) -> Version:
"""Return the software version of the device."""
Expand Down Expand Up @@ -267,7 +269,7 @@ def port(self) -> Optional[int]:
"""Return the device port, or None if the device doesn't have a port."""
return self._config_entry.lan_port

@ReadOnlyCachedProperty
@cached_property
def series(self) -> str:
"""Return the series of the device.
Expand All @@ -284,7 +286,7 @@ def verbose(self) -> bool:
################################################################################################
# Cached Properties
################################################################################################
@ReadOnlyCachedProperty
@cached_property
def hostname(self) -> str:
"""Return the hostname of the device or an empty string if unable to fetch that."""
if self._config_entry.connection_type not in {ConnectionTypes.USB}:
Expand All @@ -295,7 +297,7 @@ def hostname(self) -> str:
pass
return ""

@ReadOnlyCachedProperty
@cached_property
def ip_address(self) -> str:
"""Return the IPv4 address of the device or an empty string if unable to fetch that."""
if self._config_entry.connection_type not in {ConnectionTypes.USB}:
Expand Down Expand Up @@ -471,7 +473,7 @@ def reboot(self, quiet_period: int = 0) -> bool:
"""
# Reset the cached properties
for prop in self._get_self_properties():
if isinstance(getattr(self.__class__, prop), cached_property):
if isinstance(getattr(self.__class__, prop), functools_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.
Expand Down Expand Up @@ -689,7 +691,7 @@ def _get_self_properties(self) -> Tuple[str, ...]:
return tuple(
p
for p in dir(self.__class__)
if isinstance(getattr(self.__class__, p), (cached_property, property))
if isinstance(getattr(self.__class__, p), (functools_cached_property, property))
)

@staticmethod
Expand Down
7 changes: 5 additions & 2 deletions src/tm_devices/drivers/pi/data_acquisition_systems/daq6510.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@
from tm_devices.drivers.pi.data_acquisition_systems.data_acquisition_system import (
DataAcquisitionSystem,
)
from tm_devices.helpers import DeviceConfigEntry, ReadOnlyCachedProperty
from tm_devices.helpers import DeviceConfigEntry

# noinspection PyPep8Naming
from tm_devices.helpers import ReadOnlyCachedProperty as cached_property # noqa: N813


class DAQ6510(DAQ6510Mixin, DataAcquisitionSystem):
Expand Down Expand Up @@ -47,7 +50,7 @@ def ieee_cmds(self) -> LegacyTSPIEEE4882Commands:
"""Return an internal class containing methods for the standard IEEE 488.2 command set."""
return self._ieee_cmds # pyright: ignore[reportReturnType]

@ReadOnlyCachedProperty
@cached_property
def total_channels(self) -> int:
"""Return the total number of channels (all types)."""
return 1
Expand Down
20 changes: 11 additions & 9 deletions src/tm_devices/drivers/pi/pi_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@
get_visa_backend,
print_with_timestamp,
PYVISA_PY_BACKEND,
ReadOnlyCachedProperty,
)

# noinspection PyPep8Naming
from tm_devices.helpers import ReadOnlyCachedProperty as cached_property # noqa: N813
from tm_devices.helpers.constants_and_dataclasses import UNIT_TEST_TIMEOUT


Expand Down Expand Up @@ -83,7 +85,7 @@ def __init__(
def all_channel_names_list(self) -> Tuple[str, ...]:
"""Return a tuple containing all the channel names."""

@ReadOnlyCachedProperty
@cached_property
@abstractmethod
def total_channels(self) -> int:
"""Return the total number of channels (all types)."""
Expand Down Expand Up @@ -187,7 +189,7 @@ def visa_resource(self) -> visa.resources.MessageBasedResource:
################################################################################################
# Cached Properties
################################################################################################
@ReadOnlyCachedProperty
@cached_property
def sw_version(self) -> Version:
"""Return the software version of the device."""
id_string_parts = self.idn_string.split(",")
Expand All @@ -204,27 +206,27 @@ def sw_version(self) -> Version:
retval = get_version(sw_version)
return retval

@ReadOnlyCachedProperty
@cached_property
def idn_string(self) -> str:
r"""Return the string returned from the ``*IDN?`` query when the device was created."""
return self.ieee_cmds.idn()

@ReadOnlyCachedProperty
@cached_property
def manufacturer(self) -> str:
"""Return the manufacturer of the device."""
return self.idn_string.split(",")[0].strip()

@ReadOnlyCachedProperty
@cached_property
def model(self) -> str:
"""Return the full model of the device."""
return self.idn_string.split(",")[1].strip()

@ReadOnlyCachedProperty
@cached_property
def serial(self) -> str:
"""Return the serial number of the device."""
return self.idn_string.split(",")[2].strip()

@ReadOnlyCachedProperty
@cached_property
def series(self) -> str:
"""Return the series of the device.
Expand All @@ -233,7 +235,7 @@ def series(self) -> str:
"""
return get_model_series(self.model)

@ReadOnlyCachedProperty
@cached_property
def visa_backend(self) -> str:
"""Return the VISA backend in use."""
return get_visa_backend(self._visa_resource.visalib.library_path.path)
Expand Down
Loading

0 comments on commit 3b328b8

Please sign in to comment.