diff --git a/docs/conf.py b/docs/conf.py index 412080c4..3a1a96e9 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -88,7 +88,7 @@ def prep_jinja_env(jinja_env: JinjaEnvironment) -> None: Args: jinja_env: The Jinja environment. """ - jinja_env.tests["contains"] = item_in_sequence # pyright: ignore + jinja_env.tests["contains"] = item_in_sequence # pyright: ignore[reportArgumentType,reportUnknownMemberType] # FUTURE: # autoapi_prepare_jinja_env = prep_jinja_env @@ -228,4 +228,4 @@ def setup(sphinx: Sphinx) -> None: Args: sphinx: The sphinx object. """ - sphinx.connect("autoapi-skip-member", skip_member) # pyright: ignore + sphinx.connect("autoapi-skip-member", skip_member) # pyright: ignore[reportUnknownMemberType] diff --git a/examples/source_measure_units/2400/smu_2450_leakage_current.py b/examples/source_measure_units/2400/smu_2450_leakage_current.py index 1f167773..859285e7 100644 --- a/examples/source_measure_units/2400/smu_2450_leakage_current.py +++ b/examples/source_measure_units/2400/smu_2450_leakage_current.py @@ -62,9 +62,9 @@ READING_COUNT = int(float(inst.commands.buffer_var["defbuffer1"].n)) for x in range(1, READING_COUNT + 1): # Voltage readings are in defbuffer1. - timestamp_data.append( # type: ignore + timestamp_data.append( # pyright: ignore[reportUnknownMemberType] inst.commands.buffer_var["defbuffer1"].relativetimestamps[x] ) - buffer1_data.append(inst.commands.buffer_var["defbuffer1"].readings[x]) # type: ignore + buffer1_data.append(inst.commands.buffer_var["defbuffer1"].readings[x]) # pyright: ignore[reportUnknownMemberType] print(f"{x}, {timestamp_data[x-1]}, {buffer1_data[x-1]}") diff --git a/examples/source_measure_units/2400/smu_2450_linear_sweep_current.py b/examples/source_measure_units/2400/smu_2450_linear_sweep_current.py index 0666f948..1b97902c 100644 --- a/examples/source_measure_units/2400/smu_2450_linear_sweep_current.py +++ b/examples/source_measure_units/2400/smu_2450_linear_sweep_current.py @@ -64,9 +64,9 @@ READING_COUNT = int(float(smu2450.commands.buffer_var["defbuffer1"].n)) for x in range(1, READING_COUNT + 1): # Voltage readings are in defbuffer1. - timestamp_data.append( # type: ignore + timestamp_data.append( # pyright: ignore[reportUnknownMemberType] smu2450.commands.buffer_var["defbuffer1"].timestamps[x] ) - buffer1_data.append(smu2450.commands.buffer_var["defbuffer1"].readings[x]) # type: ignore + buffer1_data.append(smu2450.commands.buffer_var["defbuffer1"].readings[x]) # pyright: ignore[reportUnknownMemberType] print(f"{timestamp_data[x-1]}, {buffer1_data[x-1]}") diff --git a/examples/source_measure_units/2400/smu_2450_measuring_lowr_devices.py b/examples/source_measure_units/2400/smu_2450_measuring_lowr_devices.py index 690d3bfb..09454dc8 100644 --- a/examples/source_measure_units/2400/smu_2450_measuring_lowr_devices.py +++ b/examples/source_measure_units/2400/smu_2450_measuring_lowr_devices.py @@ -62,9 +62,9 @@ READING_COUNT = int(float(inst.commands.buffer_var["defbuffer1"].n)) for x in range(1, READING_COUNT + 1): # Resistance readings are in defbuffer1. - timestamp_data.append( # type:ignore + timestamp_data.append( # pyright: ignore[reportUnknownMemberType] inst.commands.buffer_var["defbuffer1"].timestamps[x] ) - buffer1_data.append(inst.commands.buffer_var["defbuffer1"].readings[x]) # type:ignore + buffer1_data.append(inst.commands.buffer_var["defbuffer1"].readings[x]) # pyright: ignore[reportUnknownMemberType] print(f"{timestamp_data[x-1]}, {buffer1_data[x-1]}") diff --git a/examples/source_measure_units/2400/smu_2450_rechargeable_battery.py b/examples/source_measure_units/2400/smu_2450_rechargeable_battery.py index 103eb168..f40f9a7b 100644 --- a/examples/source_measure_units/2400/smu_2450_rechargeable_battery.py +++ b/examples/source_measure_units/2400/smu_2450_rechargeable_battery.py @@ -83,7 +83,7 @@ reading = inst.commands.buffer_var["defbuffer1"].readings[i] source_value = inst.commands.buffer_var["defbuffer1"].sourcevalues[i] timestamp = float( - inst.commands.buffer_var["defbuffer1"].relativetimestamps.get[i] # type: ignore + inst.commands.buffer_var["defbuffer1"].relativetimestamps.get(i) # pyright: ignore[reportArgumentType] ) print(i, reading, source_value, timestamp) diff --git a/examples/source_measure_units/2400/smu_2460_pulse_train.py b/examples/source_measure_units/2400/smu_2460_pulse_train.py index 29e3613f..d0e75d63 100644 --- a/examples/source_measure_units/2400/smu_2460_pulse_train.py +++ b/examples/source_measure_units/2400/smu_2460_pulse_train.py @@ -79,12 +79,12 @@ inst.commands.trigger.model.setblock_trigger_block_config_recall(4, "OutputList") inst.commands.trigger.model.setblock_trigger_block_delay_constant( 5, - MEASURE_DELAY, # type: ignore + MEASURE_DELAY, # type: ignore[arg-type] ) inst.commands.trigger.model.setblock_trigger_block_measure_digitize(6) inst.commands.trigger.model.setblock_trigger_block_wait(7, "trigger.EVENT_TIMER2") inst.commands.trigger.model.setblock_trigger_block_config_next(8, "OutputList") - inst.commands.trigger.model.setblock_trigger_block_branch_counter(9, POINTS, 3) # type: ignore + inst.commands.trigger.model.setblock_trigger_block_branch_counter(9, POINTS, 3) # type: ignore[arg-type] inst.commands.trigger.model.setblock_trigger_block_source_output(10, inst.commands.smu.OFF) # Start the trigger model diff --git a/examples/source_measure_units/2600/smu_2600_diode_test_fast.py b/examples/source_measure_units/2600/smu_2600_diode_test_fast.py index c475b99d..e199031b 100644 --- a/examples/source_measure_units/2600/smu_2600_diode_test_fast.py +++ b/examples/source_measure_units/2600/smu_2600_diode_test_fast.py @@ -156,9 +156,9 @@ def diode_test(inst: SMU2602B) -> None: if SPEED == "FAST": inst.commands.display.clear() - inst.commands.display.setcursor(1, 1) # type: ignore + inst.commands.display.setcursor(1, 1) # type: ignore[arg-type] inst.commands.display.settext("Test In Progress") - inst.commands.display.setcursor(2, 1) # type: ignore + inst.commands.display.setcursor(2, 1) # type: ignore[arg-type] inst.commands.display.settext(f"Testing {NDIODES} Parts") start_time = time.time() diff --git a/examples/source_measure_units/2600/smu_2651_fast_adc_usage.py b/examples/source_measure_units/2600/smu_2651_fast_adc_usage.py index 7cdd7052..ad212ede 100644 --- a/examples/source_measure_units/2600/smu_2651_fast_adc_usage.py +++ b/examples/source_measure_units/2600/smu_2651_fast_adc_usage.py @@ -11,14 +11,17 @@ Converted to Python tm_devices script. DCA 4.12.23 """ -from datetime import date +from datetime import datetime + +from dateutil.tz import tzlocal from tm_devices import DeviceManager from tm_devices.drivers import SMU2651A +TODAY_DATE = datetime.now(tz=tzlocal()).date() RESOURCE_ID = "192.168.0.1" -V_FILENAME = "CapturePulseV_" + str(date.today()) + ".csv" -I_FILENAME = "CapturePulseI_" + str(date.today()) + ".csv" +V_FILENAME = "CapturePulseV_" + str(TODAY_DATE) + ".csv" +I_FILENAME = "CapturePulseI_" + str(TODAY_DATE) + ".csv" # TEST CONSTANTS NUM_PULSES = 5 diff --git a/pyproject.toml b/pyproject.toml index 83d149ba..81f4afdc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -233,6 +233,7 @@ ignore = [ pythonPlatform = "All" pythonVersion = "3.8" reportCallInDefaultInitializer = "error" +reportImplicitOverride = "none" # this check is not needed # TODO: turn on the check for implicit string concatenation reportImplicitStringConcatenation = "none" # this is allowed by this project's formatting standard reportImportCycles = "none" # other analysis tools catch these more effectively @@ -282,21 +283,21 @@ ignore = [ "ANN102", # Missing type annotation for cls in method "ANN401", # Dynamically typed expressions (typing.Any) are disallowed in *args and **kwargs "COM812", # Trailing comma missing - "DTZ", # flake8-datetimez # TODO: enable this later "EM102", # Exception must not use an f-string literal, assign to variable first - "FA100", # Missing `from __future__ import annotations`, but uses ... # TODO: enable this later + "FA100", # Missing `from __future__ import annotations`, but uses ... "FBT", # flake8-boolean-trap - "FIX002", # Line contains TODO + "FIX002", # Line contains TO DO "ISC001", # single-line-implicit-string-concatenation (handled by formatter) - "PGH003", # Use specific rule codes when ignoring type issues # TODO: enable this later - "PTH", # flake8-use-pathlib # TODO: enable this later + "PTH109", # `os.getcwd()` should be replaced by `Path.cwd()` + "PTH123", # `open()` should be replaced by `Path.open()` + "PTH207", # Replace `iglob` with `Path.glob` or `Path.rglob` "PYI021", # Docstrings should not be included in stubs "T20", # flake8-print - "TD002", # Missing author in TODO; try: `# TODO(): ...` # TODO: enable this later - "TD003", # Missing issue link on the line following this TODO # TODO: enable this later + "TD002", # Missing author in TO DO + "TD003", # Missing issue link on the line following this TO DO "TRY301", # Abstract raise to an inner function - "UP006", # Use {to} instead of {from} for type annotation # TODO: enable this later - "UP007", # Use `X | Y` for type annotations # TODO: enable this later + "UP006", # Use {to} instead of {from} for type annotation + "UP007", # Use `X | Y` for type annotations "UP024", # Replace aliased errors with `OSError` "UP037" # Remove quotes from type annotation ] @@ -348,6 +349,7 @@ order-by-type = false "tests/**" = [ "PLC1901", # compare-to-empty-string "PLR2004", # Magic value used in comparison + "PTH107", # `os.remove()` should be replaced by `Path.unlink()` "S101" # Use of assert detected ] "tests/samples/golden_stubs/**" = [ diff --git a/scripts/contributor_setup.py b/scripts/contributor_setup.py index 77a0f78b..20c1c6f9 100644 --- a/scripts/contributor_setup.py +++ b/scripts/contributor_setup.py @@ -2,6 +2,8 @@ This script will run through the commands listed in the CONTRIBUTING.md file. """ +from __future__ import annotations + import argparse import glob import os @@ -43,18 +45,21 @@ def running_in_virtualenv() -> bool: return sys.prefix != sys.base_prefix -def create_virtual_environment(virtual_env_dir: str, reset_env: bool) -> None: +def create_virtual_environment( + virtual_env_dir: Union[str, os.PathLike[str]], reset_env: bool +) -> None: """Create a virtual environment. Args: virtual_env_dir: The directory where the virtual environment should be created reset_env: Indicate if the virtual environment should be completely reset """ + virtual_env_dir = Path(virtual_env_dir) added_newline = False if ( reset_env - and os.path.exists(virtual_env_dir) - and not sys.prefix.startswith(virtual_env_dir) + and virtual_env_dir.exists() + and not sys.prefix.startswith(str(virtual_env_dir.resolve())) and not running_in_virtualenv() ): if not added_newline: @@ -62,7 +67,7 @@ def create_virtual_environment(virtual_env_dir: str, reset_env: bool) -> None: print("") print(f"Removing virtualenv located at '{virtual_env_dir}'") shutil.rmtree(virtual_env_dir) - if not os.path.exists(virtual_env_dir) and not running_in_virtualenv(): + if not virtual_env_dir.exists() and not running_in_virtualenv(): if not added_newline: print("") print(f"Creating virtualenv located at '{virtual_env_dir}'") @@ -113,8 +118,8 @@ def main() -> None: # Delete the previous poetry lock file lock_file = Path(starting_dir) / "poetry.lock" - if os.path.exists(lock_file): - os.remove(lock_file) + if lock_file.exists(): + lock_file.unlink() # Find the python executable from the new virtual environment files = list( diff --git a/scripts/project_version.py b/scripts/project_version.py index b79a6837..865b298c 100644 --- a/scripts/project_version.py +++ b/scripts/project_version.py @@ -1,6 +1,5 @@ """This script modifies or gets the current project version in the pyproject.toml file.""" import argparse -import os.path import pathlib import tomli @@ -8,7 +7,7 @@ from poetry.core.constraints.version import Version -PYPROJECT_FILE = pathlib.Path(f"{os.path.dirname(__file__)}/../pyproject.toml") +PYPROJECT_FILE = pathlib.Path(f"{pathlib.Path(__file__).parent}/../pyproject.toml") def parse_arguments() -> argparse.Namespace: diff --git a/scripts/update_development_dependencies.py b/scripts/update_development_dependencies.py index 1c3b4aa2..af25c9c8 100644 --- a/scripts/update_development_dependencies.py +++ b/scripts/update_development_dependencies.py @@ -11,7 +11,7 @@ from pathlib import Path from typing import List -from yamlfix import fix_files # pyright: ignore +from yamlfix import fix_files # pyright: ignore[reportUnknownVariableType] from pypi_latest_version import get_latest_version diff --git a/src/tm_devices/commands/_helpers/generic_commands.py b/src/tm_devices/commands/_helpers/generic_commands.py index 0e55f84a..c18556f2 100644 --- a/src/tm_devices/commands/_helpers/generic_commands.py +++ b/src/tm_devices/commands/_helpers/generic_commands.py @@ -27,7 +27,7 @@ class NoDeviceProvidedError(Exception): #################################################################################################### # Classes #################################################################################################### -class DefaultDictPassKeyToFactory(defaultdict): # type: ignore +class DefaultDictPassKeyToFactory(defaultdict): # pyright: ignore[reportMissingTypeArgument] """A custom defaultdict. This custom defaultdict passes the key used to access a missing value into the stored @@ -41,7 +41,7 @@ def __init__(self, default_factory: Callable[[Union[int, str]], Any], **kwargs: default_factory: The factory function used to create new values in the dictionary. kwargs: The keyword arguments. """ - super().__init__(default_factory, **kwargs) # type: ignore + super().__init__(default_factory, **kwargs) # type: ignore[arg-type] def __missing__(self, key: Any) -> Any: """Call the ``default_factory()`` function and pass the key as the only parameter. @@ -51,7 +51,7 @@ def __missing__(self, key: Any) -> Any: """ if self.default_factory: # noinspection PyArgumentList # pylint: disable=not-callable - dict.__setitem__(self, key, self.default_factory(key)) # type: ignore + dict.__setitem__(self, key, self.default_factory(key)) # type: ignore[arg-type] return cast(Any, self[key]) return cast(Any, super().__missing__(key)) # pyright: ignore [reportUnknownMemberType] diff --git a/src/tm_devices/commands/_helpers/scpi_commands.py b/src/tm_devices/commands/_helpers/scpi_commands.py index 14d4feb9..2d423b21 100644 --- a/src/tm_devices/commands/_helpers/scpi_commands.py +++ b/src/tm_devices/commands/_helpers/scpi_commands.py @@ -265,7 +265,7 @@ def __init__(self, device: Optional["PIDevice"], cmd_syntax: str) -> None: raise ValueError(msg) -class DefaultDictDeviceCommunication(defaultdict): # type: ignore +class DefaultDictDeviceCommunication(defaultdict): # pyright: ignore[reportMissingTypeArgument] """A custom default dictionary that can be used to send/receive commands to/from a device. The ``.query()`` method is used when ``__getitem__()`` is called and the result of the query is diff --git a/src/tm_devices/components/dm_config_parser.py b/src/tm_devices/components/dm_config_parser.py index c3376955..34322370 100644 --- a/src/tm_devices/components/dm_config_parser.py +++ b/src/tm_devices/components/dm_config_parser.py @@ -371,7 +371,7 @@ def __parse_config_file( KeyError: Indicates unrecognized option name. """ config_path = pathlib.Path(config_file_path) # normalize the path - if not os.path.isfile(config_path): + if not config_path.is_file(): raise FileNotFoundError(config_path) # read in data with open(config_path, encoding="utf-8") as config_file: diff --git a/src/tm_devices/device_manager.py b/src/tm_devices/device_manager.py index 89f70f43..dd016136 100644 --- a/src/tm_devices/device_manager.py +++ b/src/tm_devices/device_manager.py @@ -137,10 +137,13 @@ warnings.simplefilter("ignore", UserWarning) import pyvisa as visa - from pyvisa_py.protocols.rpc import RPCError # type: ignore + from pyvisa_py.protocols.rpc import RPCError # pyright: ignore[reportMissingTypeStubs] -# noinspection PyUnresolvedReferences # pylint: disable=unused-import,wrong-import-order -from traceback_with_variables import activate_by_import # noqa: F401 # type: ignore +# pylint: disable=unused-import,wrong-import-order +# noinspection PyUnresolvedReferences +from traceback_with_variables import ( # pyright: ignore[reportMissingTypeStubs] + activate_by_import, # noqa: F401 # pyright: ignore[reportUnusedImport] +) if TYPE_CHECKING: from pyvisa.resources import MessageBasedResource @@ -154,7 +157,7 @@ # TODO: this is temporary until python3.12 which will support TypeVar with defaults AFGAlias: TypeAlias = Union[AFG3K, AFG3KB, AFG3KC, AFG31K] AWGAlias: TypeAlias = Union[AWG5K, AWG5KB, AWG5KC, AWG7K, AWG7KB, AWG7KC, AWG5200, AWG70KA, AWG70KB] -DataAcquisitionSystemAlias: TypeAlias = Union[DAQ6510] # pyright: ignore +DataAcquisitionSystemAlias: TypeAlias = Union[DAQ6510] # pyright: ignore[reportInvalidTypeArguments] DigitalMultimeterAlias: TypeAlias = Union[DMM6500, DMM7510, DMM7512] ScopeAlias: TypeAlias = Union[ DPO5K, @@ -199,7 +202,7 @@ MSO70KC, MSO70KDX, ] -MarginTesterAlias: TypeAlias = Union[TMT4] # pyright: ignore +MarginTesterAlias: TypeAlias = Union[TMT4] # pyright: ignore[reportInvalidTypeArguments] PowerSupplyUnitAlias: TypeAlias = Union[ PSU2200, PSU2220, @@ -243,7 +246,7 @@ SMU6514, SMU6517B, ] -SystemsSwitchAlias: TypeAlias = Union[SS3706A] # pyright: ignore +SystemsSwitchAlias: TypeAlias = Union[SS3706A] # pyright: ignore[reportInvalidTypeArguments] #################################################################################################### @@ -1209,7 +1212,7 @@ def _add_device( # noqa: PLR0913 config_dict["serial_config"] = serial_config if device_driver: config_dict["device_driver"] = device_driver - new_device_name, new_device_config = self.__config.add_device(**config_dict) # type: ignore + new_device_name, new_device_config = self.__config.add_device(**config_dict) # pyright: ignore[reportArgumentType] return self.__create_device(new_device_name, new_device_config) @@ -1361,7 +1364,7 @@ def __protect_access(self) -> None: AttributeError: Indicates that the calling method should not have been used. """ if not self.__is_open and not self._suppress_protection: - previous_frame = cast(FrameType, inspect.currentframe().f_back.f_back) # type: ignore + previous_frame = cast(FrameType, inspect.currentframe().f_back.f_back) # pyright: ignore[reportOptionalMemberAccess] message = ( f"The {self.__class__.__name__} is closed, please use the .open() " f"method before continuing to use the {self.__class__.__name__}.\n" diff --git a/src/tm_devices/driver_mixins/class_extension_mixin.py b/src/tm_devices/driver_mixins/class_extension_mixin.py index d8550506..8681784c 100644 --- a/src/tm_devices/driver_mixins/class_extension_mixin.py +++ b/src/tm_devices/driver_mixins/class_extension_mixin.py @@ -68,7 +68,7 @@ def add_property( ... # pragma: no cover @classmethod - def add_property( # type: ignore + def add_property( # pyright: ignore[reportInconsistentOverload] cls: Type[_EM], method: Optional[Callable[[_EM], _T]] = None, /, diff --git a/src/tm_devices/drivers/api/rest_api/margin_testers/tmt4.py b/src/tm_devices/drivers/api/rest_api/margin_testers/tmt4.py index 5b06690f..baf1a861 100644 --- a/src/tm_devices/drivers/api/rest_api/margin_testers/tmt4.py +++ b/src/tm_devices/drivers/api/rest_api/margin_testers/tmt4.py @@ -127,7 +127,7 @@ def wait_till_unlocked(self, timeout: int = 120) -> None: start = time.time() while time.time() < start + timeout: _, res_json, _, _ = self.get("/device/status", allow_errors=True) - if res_json["usage"] == "NOT LOCKED": # type: ignore + if res_json["usage"] == "NOT LOCKED": # pyright: ignore[reportArgumentType,reportCallIssue] return time.sleep(1) msg = f"waited more than {timeout} seconds for {self.name} to unlock" diff --git a/src/tm_devices/drivers/pi/data_acquisition_systems/daq6510.py b/src/tm_devices/drivers/pi/data_acquisition_systems/daq6510.py index e3496d08..b2b1ab3b 100644 --- a/src/tm_devices/drivers/pi/data_acquisition_systems/daq6510.py +++ b/src/tm_devices/drivers/pi/data_acquisition_systems/daq6510.py @@ -45,7 +45,7 @@ def all_channel_names_list(self) -> Tuple[str, ...]: @property def ieee_cmds(self) -> LegacyTSPIEEE4882Commands: """Return an internal class containing methods for the standard IEEE 488.2 command set.""" - return self._ieee_cmds # type: ignore + return self._ieee_cmds # pyright: ignore[reportReturnType] @ReadOnlyCachedProperty def total_channels(self) -> int: diff --git a/src/tm_devices/drivers/pi/data_acquisition_systems/data_acquisition_system.py b/src/tm_devices/drivers/pi/data_acquisition_systems/data_acquisition_system.py index 9ad0eb0d..655b5770 100644 --- a/src/tm_devices/drivers/pi/data_acquisition_systems/data_acquisition_system.py +++ b/src/tm_devices/drivers/pi/data_acquisition_systems/data_acquisition_system.py @@ -25,6 +25,6 @@ def _reboot(self) -> None: """ # TODO: implement raise NotImplementedError( - f"``.{inspect.currentframe().f_code.co_name}()``" # pyright: ignore + f"``.{inspect.currentframe().f_code.co_name}()``" # pyright: ignore[reportOptionalMemberAccess] f" is not yet implemented for the {self.__class__.__name__} driver" ) diff --git a/src/tm_devices/drivers/pi/digital_multimeters/digital_multimeter.py b/src/tm_devices/drivers/pi/digital_multimeters/digital_multimeter.py index 18c56247..5f772de6 100644 --- a/src/tm_devices/drivers/pi/digital_multimeters/digital_multimeter.py +++ b/src/tm_devices/drivers/pi/digital_multimeters/digital_multimeter.py @@ -31,6 +31,6 @@ def _reboot(self) -> None: """ # TODO: implement raise NotImplementedError( - f"``.{inspect.currentframe().f_code.co_name}()``" # pyright: ignore + f"``.{inspect.currentframe().f_code.co_name}()``" # pyright: ignore[reportOptionalMemberAccess] f" is not yet implemented for the {self.__class__.__name__} driver" ) diff --git a/src/tm_devices/drivers/pi/digital_multimeters/dmm6500/dmm6500.py b/src/tm_devices/drivers/pi/digital_multimeters/dmm6500/dmm6500.py index 5c7d26c7..c04af637 100644 --- a/src/tm_devices/drivers/pi/digital_multimeters/dmm6500/dmm6500.py +++ b/src/tm_devices/drivers/pi/digital_multimeters/dmm6500/dmm6500.py @@ -28,7 +28,7 @@ def all_channel_names_list(self) -> Tuple[str, ...]: @property def ieee_cmds(self) -> LegacyTSPIEEE4882Commands: """Return an internal class containing methods for the standard IEEE 488.2 command set.""" - return self._ieee_cmds # type: ignore + return self._ieee_cmds # pyright: ignore[reportReturnType] ################################################################################################ # Public Methods diff --git a/src/tm_devices/drivers/pi/digital_multimeters/dmm7500/dmm7500.py b/src/tm_devices/drivers/pi/digital_multimeters/dmm7500/dmm7500.py index a8c4370a..c5234bb0 100644 --- a/src/tm_devices/drivers/pi/digital_multimeters/dmm7500/dmm7500.py +++ b/src/tm_devices/drivers/pi/digital_multimeters/dmm7500/dmm7500.py @@ -28,7 +28,7 @@ def all_channel_names_list(self) -> Tuple[str, ...]: @property def ieee_cmds(self) -> LegacyTSPIEEE4882Commands: """Return an internal class containing methods for the standard IEEE 488.2 command set.""" - return self._ieee_cmds # type: ignore + return self._ieee_cmds # pyright: ignore[reportReturnType] ################################################################################################ # Public Methods diff --git a/src/tm_devices/drivers/pi/pi_device.py b/src/tm_devices/drivers/pi/pi_device.py index 1774d886..5629815c 100644 --- a/src/tm_devices/drivers/pi/pi_device.py +++ b/src/tm_devices/drivers/pi/pi_device.py @@ -70,7 +70,7 @@ def __init__( if not bool(os.environ.get("TM_DEVICES_UNIT_TESTS_RUNNING")) else UNIT_TEST_TIMEOUT ) - self._ieee_cmds = self._IEEE_COMMANDS_CLASS(self) # type: ignore + self._ieee_cmds = self._IEEE_COMMANDS_CLASS(self) self.reset_visa_timeout() ################################################################################################ @@ -121,7 +121,7 @@ def turn_channel_off(self, channel_str: str) -> None: """ # TODO: implement for all driver subclasses then remove this blanket NotImplementedError raise NotImplementedError( - f"``.{inspect.currentframe().f_code.co_name}()``" # pyright: ignore + f"``.{inspect.currentframe().f_code.co_name}()``" # pyright: ignore[reportOptionalMemberAccess] f" is not yet implemented for the {self.__class__.__name__} driver" ) @@ -136,7 +136,7 @@ def turn_channel_on(self, channel_str: str) -> None: """ # TODO: implement for all driver subclasses then remove this blanket NotImplementedError raise NotImplementedError( - f"``.{inspect.currentframe().f_code.co_name}()``" # pyright: ignore + f"``.{inspect.currentframe().f_code.co_name}()``" # pyright: ignore[reportOptionalMemberAccess] f" is not yet implemented for the {self.__class__.__name__} driver" ) @@ -281,15 +281,15 @@ def device_clear(self) -> None: # pragma: no cover def disable_srq_events(self) -> None: # pragma: no cover """Disable the service request event for the device.""" self._visa_resource.disable_event( - visa_constants.VI_EVENT_SERVICE_REQ, # type: ignore - visa_constants.VI_QUEUE, # type: ignore + visa_constants.VI_EVENT_SERVICE_REQ, # pyright: ignore[reportArgumentType] + visa_constants.VI_QUEUE, # pyright: ignore[reportArgumentType] ) def enable_srq_events(self) -> None: # pragma: no cover """Enable the service request event for the device.""" self._visa_resource.enable_event( - visa_constants.VI_EVENT_SERVICE_REQ, # type: ignore - visa_constants.VI_QUEUE, # type: ignore + visa_constants.VI_EVENT_SERVICE_REQ, # pyright: ignore[reportArgumentType] + visa_constants.VI_QUEUE, # pyright: ignore[reportArgumentType] ) def get_visa_stb(self) -> int: # pragma: no cover @@ -361,7 +361,7 @@ def query_binary(self, query: str, verbose: bool = True) -> Sequence[float]: print_with_timestamp(f"({self._name_and_alias}) Query Binary Values >> {query!r}") try: - response = self._visa_resource.query_binary_values(query) # pyright: ignore + response = self._visa_resource.query_binary_values(query) # pyright: ignore[reportUnknownMemberType] except (visa.VisaIOError, socket.error) as error: pi_cmd_repr = f" for {query!r} " if self._verbose and verbose else " " msg = f"The query{pi_cmd_repr}failed with the following message: {error!r}" @@ -652,7 +652,7 @@ def wait_for_srq_event(self, timeout: int) -> visa.resources.resource.WaitRespon """ # The timeout value is multiplied by 1000 because the function expects milliseconds. return self._visa_resource.wait_on_event( - visa_constants.VI_EVENT_SERVICE_REQ, # type: ignore + visa_constants.VI_EVENT_SERVICE_REQ, # pyright: ignore[reportArgumentType] timeout * 1000, ) @@ -817,7 +817,7 @@ def _cleanup(self) -> None: def _close(self) -> None: """Close this device and all its used resources and components.""" self._visa_resource.close() - self._visa_resource = None # type: ignore + self._visa_resource = None # pyright: ignore[reportAttributeAccessIssue] self._is_open = False def _has_errors(self) -> bool: @@ -831,7 +831,7 @@ def _has_errors(self) -> bool: def _open(self) -> bool: """Open necessary resources and components and return a boolean indicating success.""" opened = True - if self._visa_resource is None: # type: ignore + if self._visa_resource is None: # pyright: ignore[reportUnnecessaryComparison] opened = False # 5 seconds when running unit tests, else 600 seconds (10 minutes) num_seconds_to_attempt_reconnection = ( diff --git a/src/tm_devices/drivers/pi/power_supplies/power_supply.py b/src/tm_devices/drivers/pi/power_supplies/power_supply.py index b2a3a222..3d88325f 100644 --- a/src/tm_devices/drivers/pi/power_supplies/power_supply.py +++ b/src/tm_devices/drivers/pi/power_supplies/power_supply.py @@ -31,7 +31,7 @@ def expect_esr(self, esr: Union[int, str], error_string: str = "") -> Tuple[bool Returns: Boolean indicating if the check passed or failed and a string with the results. """ - return SignalSource.expect_esr(self, esr, error_string) # type: ignore + return SignalSource.expect_esr(self, esr, error_string) # type: ignore[arg-type] def get_eventlog_status(self) -> Tuple[bool, str]: """Help function for getting the eventlog status. @@ -39,4 +39,4 @@ def get_eventlog_status(self) -> Tuple[bool, str]: Returns: Boolean indicating no error, String containing concatenated contents of event log. """ - return SignalSource.get_eventlog_status(self) # type: ignore + return SignalSource.get_eventlog_status(self) # type: ignore[arg-type] diff --git a/src/tm_devices/drivers/pi/scopes/scope.py b/src/tm_devices/drivers/pi/scopes/scope.py index 6236bc17..fb3cfa52 100644 --- a/src/tm_devices/drivers/pi/scopes/scope.py +++ b/src/tm_devices/drivers/pi/scopes/scope.py @@ -24,7 +24,7 @@ def single_sequence(self) -> None: """ # TODO: implement for all driver subclasses then convert to abstractmethod raise NotImplementedError( - f"``.{inspect.currentframe().f_code.co_name}()``" # pyright: ignore + f"``.{inspect.currentframe().f_code.co_name}()``" # pyright: ignore[reportOptionalMemberAccess] f" is not yet implemented for the {self.__class__.__name__} driver" ) @@ -61,7 +61,7 @@ def curve_query( NotImplementedError: Indicates the current driver has not implemented this method. """ raise NotImplementedError( - f"``.{inspect.currentframe().f_code.co_name}()``" # pyright: ignore + f"``.{inspect.currentframe().f_code.co_name}()``" # pyright: ignore[reportOptionalMemberAccess] f" is not yet implemented for the {self.__class__.__name__} driver" ) diff --git a/src/tm_devices/drivers/pi/scopes/tso/tsovu.py b/src/tm_devices/drivers/pi/scopes/tso/tsovu.py index 563648d7..b6612118 100644 --- a/src/tm_devices/drivers/pi/scopes/tso/tsovu.py +++ b/src/tm_devices/drivers/pi/scopes/tso/tsovu.py @@ -42,6 +42,6 @@ def _reboot(self) -> None: """ # TODO: implement raise NotImplementedError( - f"``.{inspect.currentframe().f_code.co_name}()``" # pyright: ignore + f"``.{inspect.currentframe().f_code.co_name}()``" # pyright: ignore[reportOptionalMemberAccess] f" is not yet implemented for the {self.__class__.__name__} driver" ) diff --git a/src/tm_devices/drivers/pi/signal_sources/afgs/afg.py b/src/tm_devices/drivers/pi/signal_sources/afgs/afg.py index 4a62029b..5d4ae797 100644 --- a/src/tm_devices/drivers/pi/signal_sources/afgs/afg.py +++ b/src/tm_devices/drivers/pi/signal_sources/afgs/afg.py @@ -30,7 +30,7 @@ class AFG(SignalSource, ABC): @property def source_device_constants(self) -> AFGSourceDeviceConstants: """Return the device constants.""" - return self._DEVICE_CONSTANTS # type: ignore + return self._DEVICE_CONSTANTS # type: ignore[attr-defined] @ReadOnlyCachedProperty def total_channels(self) -> int: diff --git a/src/tm_devices/drivers/pi/signal_sources/awgs/awg.py b/src/tm_devices/drivers/pi/signal_sources/awgs/awg.py index 4577842f..bbd89ded 100644 --- a/src/tm_devices/drivers/pi/signal_sources/awgs/awg.py +++ b/src/tm_devices/drivers/pi/signal_sources/awgs/awg.py @@ -1,10 +1,10 @@ """Base AWG device driver module.""" import inspect -import os import struct from abc import ABC from dataclasses import dataclass +from pathlib import Path from typing import Literal, Type from tm_devices.driver_mixins.signal_generator_mixin import SourceDeviceConstants @@ -36,7 +36,7 @@ class AWG(SignalSource, ABC): @property def source_device_constants(self) -> AWGSourceDeviceConstants: """Return the device constants.""" - return self._DEVICE_CONSTANTS # type: ignore + return self._DEVICE_CONSTANTS # type: ignore[attr-defined] @ReadOnlyCachedProperty def total_channels(self) -> int: @@ -93,7 +93,7 @@ def generate_waveform( # noqa: PLR0913 # pyright: ignore[reportIncompatibleMet """ # TODO: implement raise NotImplementedError( - f"``.{inspect.currentframe().f_code.co_name}()``" # pyright: ignore + f"``.{inspect.currentframe().f_code.co_name}()``" # pyright: ignore[reportOptionalMemberAccess] f" is not yet implemented for the {self.__class__.__name__} driver" ) @@ -122,7 +122,7 @@ def _send_waveform(self, target_file: str) -> None: # pragma: no cover bin_waveform = struct.unpack(">" + str(info_len) + "H", waveform_data) # Turn "path/to/stuff.wfm" into "stuff.wfm". - filename_target = os.path.basename(target_file) + filename_target = Path(target_file).name # Write the waveform data to the AWG memory. string_to_send = 'MMEMORY:DATA "' + filename_target + '",' self._visa_resource.write_binary_values( diff --git a/src/tm_devices/drivers/pi/source_measure_units/smu2400/smu2400_interactive.py b/src/tm_devices/drivers/pi/source_measure_units/smu2400/smu2400_interactive.py index add8212a..6ade8ad0 100644 --- a/src/tm_devices/drivers/pi/source_measure_units/smu2400/smu2400_interactive.py +++ b/src/tm_devices/drivers/pi/source_measure_units/smu2400/smu2400_interactive.py @@ -42,7 +42,7 @@ def commands( @property def ieee_cmds(self) -> LegacyTSPIEEE4882Commands: """Return an internal class containing methods for the standard IEEE 488.2 command set.""" - return self._ieee_cmds # type: ignore + return self._ieee_cmds # pyright: ignore[reportReturnType] @ReadOnlyCachedProperty def total_channels(self) -> int: diff --git a/src/tm_devices/drivers/pi/source_measure_units/smu2400/smu2400_standard.py b/src/tm_devices/drivers/pi/source_measure_units/smu2400/smu2400_standard.py index 24f2f1a8..26fe9c63 100644 --- a/src/tm_devices/drivers/pi/source_measure_units/smu2400/smu2400_standard.py +++ b/src/tm_devices/drivers/pi/source_measure_units/smu2400/smu2400_standard.py @@ -59,7 +59,7 @@ def expect_esr(self, esr: Union[int, str], error_string: str = "") -> Tuple[bool Returns: Boolean indicating if the check passed or failed and a string with the results. """ - return SignalSource.expect_esr(self, esr, error_string) # type: ignore + return SignalSource.expect_esr(self, esr, error_string) # type: ignore[arg-type] def get_eventlog_status(self) -> Tuple[bool, str]: """Help function for getting the eventlog status. @@ -67,7 +67,7 @@ def get_eventlog_status(self) -> Tuple[bool, str]: Returns: Boolean indicating no error, String containing concatenated contents of event log. """ - return SignalSource.get_eventlog_status(self) # type: ignore + return SignalSource.get_eventlog_status(self) # type: ignore[arg-type] def run_script(self, script_name: str) -> None: # noqa: ARG002 """Not Implemented.""" diff --git a/src/tm_devices/drivers/pi/source_measure_units/smu6000/smu6000.py b/src/tm_devices/drivers/pi/source_measure_units/smu6000/smu6000.py index 4b589f41..9e9d5e4a 100644 --- a/src/tm_devices/drivers/pi/source_measure_units/smu6000/smu6000.py +++ b/src/tm_devices/drivers/pi/source_measure_units/smu6000/smu6000.py @@ -61,7 +61,7 @@ def expect_esr(self, esr: Union[int, str], error_string: str = "") -> Tuple[bool Returns: Boolean indicating if the check passed or failed and a string with the results. """ - return SignalSource.expect_esr(self, esr, error_string) # type: ignore + return SignalSource.expect_esr(self, esr, error_string) # type: ignore[arg-type] def get_eventlog_status(self) -> Tuple[bool, str]: """Help function for getting the eventlog status. @@ -69,7 +69,7 @@ def get_eventlog_status(self) -> Tuple[bool, str]: Returns: Boolean indicating no error, String containing concatenated contents of event log. """ - return SignalSource.get_eventlog_status(self) # type: ignore + return SignalSource.get_eventlog_status(self) # type: ignore[arg-type] def run_script(self, script_name: str) -> None: # noqa: ARG002 """Not Implemented.""" @@ -139,6 +139,6 @@ def _reboot(self) -> None: """ # TODO: implement raise NotImplementedError( - f"``.{inspect.currentframe().f_code.co_name}()``" # pyright: ignore + f"``.{inspect.currentframe().f_code.co_name}()``" # pyright: ignore[reportOptionalMemberAccess] f" is not yet implemented for the {self.__class__.__name__} driver" ) diff --git a/src/tm_devices/drivers/pi/systems_switches/ss3706a.py b/src/tm_devices/drivers/pi/systems_switches/ss3706a.py index 6d6ed739..8bff5c70 100644 --- a/src/tm_devices/drivers/pi/systems_switches/ss3706a.py +++ b/src/tm_devices/drivers/pi/systems_switches/ss3706a.py @@ -77,6 +77,6 @@ def _reboot(self) -> None: """ # TODO: implement raise NotImplementedError( - f"``.{inspect.currentframe().f_code.co_name}()``" # pyright: ignore + f"``.{inspect.currentframe().f_code.co_name}()``" # pyright: ignore[reportOptionalMemberAccess] f" is not yet implemented for the {self.__class__.__name__} driver" ) diff --git a/src/tm_devices/drivers/pi/tsp_device.py b/src/tm_devices/drivers/pi/tsp_device.py index 63b83037..5ce01d3e 100644 --- a/src/tm_devices/drivers/pi/tsp_device.py +++ b/src/tm_devices/drivers/pi/tsp_device.py @@ -27,7 +27,7 @@ class TSPDevice(PIDevice, ABC): @property def ieee_cmds(self) -> TSPIEEE4882Commands: """Return an internal class containing methods for the standard IEEE 488.2 command set.""" - return self._ieee_cmds # type: ignore + return self._ieee_cmds # pyright: ignore[reportReturnType] ################################################################################################ # Public Methods diff --git a/src/tm_devices/helpers/constants_and_dataclasses.py b/src/tm_devices/helpers/constants_and_dataclasses.py index 2dcd27a6..a3c7b7f8 100644 --- a/src/tm_devices/helpers/constants_and_dataclasses.py +++ b/src/tm_devices/helpers/constants_and_dataclasses.py @@ -184,16 +184,16 @@ def __post_init__(self) -> None: # noqa: PLR0912,C901 # (this is the correct way to edit the frozen data) if self.lan_port is not None and isinstance(self.lan_port, str): object.__setattr__(self, "lan_port", int(self.lan_port)) - if not isinstance(self.address, str): # pyright: ignore + if not isinstance(self.address, str): # pyright: ignore[reportUnnecessaryIsInstance] object.__setattr__(self, "address", str(self.address)) # Validate the connection and interface types try: # device and connections are inside this try clause to raise a TypeError on bad values. # Convert them from strings (parsed from config/env) to appropriate enum value. - if not isinstance(self.device_type, DeviceTypes): # pyright: ignore + if not isinstance(self.device_type, DeviceTypes): # pyright: ignore[reportUnnecessaryIsInstance] object.__setattr__(self, "device_type", DeviceTypes(self.device_type)) - if not isinstance(self.connection_type, ConnectionTypes): # pyright: ignore + if not isinstance(self.connection_type, ConnectionTypes): # pyright: ignore[reportUnnecessaryIsInstance] object.__setattr__(self, "connection_type", ConnectionTypes(self.connection_type)) # While a SerialConfig is not frozen, if not created here then it cannot be added later. diff --git a/src/tm_devices/helpers/functions.py b/src/tm_devices/helpers/functions.py index 3a3e1676..4fd3a791 100644 --- a/src/tm_devices/helpers/functions.py +++ b/src/tm_devices/helpers/functions.py @@ -17,6 +17,7 @@ import requests +from dateutil.tz import tzlocal from packaging.version import InvalidVersion, Version from tm_devices.helpers.constants_and_dataclasses import ( @@ -34,7 +35,7 @@ warnings.simplefilter("ignore", UserWarning) import pyvisa as visa - from gpib_ctypes import make_default_gpib # type: ignore + from gpib_ctypes import make_default_gpib # pyright: ignore[reportMissingTypeStubs] from pyvisa import util as pyvisa_util from pyvisa.resources import MessageBasedResource @@ -216,7 +217,7 @@ def create_visa_connection( resource_expression = device_config_entry.get_visa_resource_expression() try: # noinspection PyTypeChecker - visa_object: MessageBasedResource = visa.ResourceManager( # type: ignore + visa_object: MessageBasedResource = visa.ResourceManager( # pyright: ignore[reportAssignmentType] visa_library ).open_resource(resource_expression) # Print a warning if PyVISA-py is used when the user didn't specify STANDALONE @@ -237,7 +238,7 @@ def create_visa_connection( time.sleep(60) # wait 60 seconds and try again try: # noinspection PyTypeChecker - visa_object: MessageBasedResource = visa.ResourceManager( # type: ignore + visa_object: MessageBasedResource = visa.ResourceManager( # pyright: ignore[reportAssignmentType] visa_library ).open_resource(resource_expression) # The broad except is because pyvisa_py can throw a base exception in the tcpip.py file @@ -390,7 +391,7 @@ def get_model_series(model: str) -> str: # noqa: PLR0912,C901,PLR0915 def get_timestamp_string() -> str: """Return a string containing the current timestamp.""" - return str(datetime.datetime.now())[:-3] + return str(datetime.datetime.now(tz=tzlocal()))[:-3] def get_version(version_string: str) -> Version: diff --git a/src/tm_devices/helpers/stubgen.py b/src/tm_devices/helpers/stubgen.py index 5fe87aa3..70f4d770 100644 --- a/src/tm_devices/helpers/stubgen.py +++ b/src/tm_devices/helpers/stubgen.py @@ -3,6 +3,7 @@ import os import re +from pathlib import Path from typing import Any, List _TYPING_IMPORT_REGEX = re.compile(r"typing\.([a-zA-Z]+)") @@ -43,16 +44,15 @@ def add_info_to_stub(cls: Any, method: Any, is_property: bool = False) -> None: """ if stub_dir := os.getenv("TM_DEVICES_STUB_DIR"): method_filepath = inspect.getfile(cls) - stub_dir = ( - os.path.join(stub_dir, "tm_devices") - if not stub_dir.endswith("tm_devices") - else stub_dir + stub_dir = str( + Path(stub_dir) / "tm_devices" if not stub_dir.endswith("tm_devices") else stub_dir ) - method_filepath = os.path.join( - stub_dir, method_filepath.rsplit("tm_devices", maxsplit=1)[-1].lstrip(os.path.sep) + method_filepath = str( + Path(stub_dir) + / method_filepath.rsplit("tm_devices", maxsplit=1)[-1].lstrip(os.path.sep) ) method_filepath += "i" # stub files have the .pyi extension - if not os.path.exists(method_filepath): + if not os.path.exists(method_filepath): # noqa: PTH110 msg = ( f'The stub file "{method_filepath}" must already exist in order to use this ' f"functionality to add method stubs." diff --git a/tests/conftest.py b/tests/conftest.py index 5b86e5c4..b4cb4200 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,6 +2,7 @@ import os import socket +from pathlib import Path from typing import Generator, List, Tuple from unittest import mock @@ -17,8 +18,8 @@ # Make sure to not use any local config files os.environ[DMConfigParser.CONFIG_FILE_PATH_ENV_VARIABLE] = "" -PROJECT_ROOT_DIR = f"{os.path.dirname(os.path.dirname(__file__))}" -SIMULATED_VISA_LIB = f"{os.path.dirname(__file__)}/sim_devices/devices.yaml@sim" +PROJECT_ROOT_DIR = Path(__file__).parent.parent +SIMULATED_VISA_LIB = str(Path(__file__).parent / "sim_devices/devices.yaml@sim") def mock_gethostbyname(address: str) -> str: @@ -93,5 +94,5 @@ def _fixture_mock_http_server() -> ( # pyright: ignore [reportUnusedFunction] Yields: The HTTP server instance. """ - with mocker_server.run("127.0.0.1", PORT): # pyright: ignore + with mocker_server.run("127.0.0.1", PORT): # pyright: ignore[reportUnknownMemberType] yield diff --git a/tests/mock_server.py b/tests/mock_server.py index d962cd67..a60e6b6f 100644 --- a/tests/mock_server.py +++ b/tests/mock_server.py @@ -4,7 +4,7 @@ from typing import Any, Dict from flask import request -from http_server_mock import HttpServerMock # type: ignore +from http_server_mock import HttpServerMock # pyright: ignore[reportMissingTypeStubs] from tm_devices.drivers.api.rest_api.rest_api_device import SupportedRequestTypes diff --git a/tests/test_afgs.py b/tests/test_afgs.py index a48c1468..4798ad21 100644 --- a/tests/test_afgs.py +++ b/tests/test_afgs.py @@ -107,7 +107,7 @@ def test_afg3kc(device_manager: DeviceManager) -> None: ): afg3kc.generate_waveform( 25e6, - afg3kc.source_device_constants.functions.PULSE.value, # type: ignore + afg3kc.source_device_constants.functions.PULSE.value, # pyright: ignore[reportArgumentType] 1.0, 0.0, "all", diff --git a/tests/test_auto_generated_commands.py b/tests/test_auto_generated_commands.py index 04991aa7..37c80e06 100644 --- a/tests/test_auto_generated_commands.py +++ b/tests/test_auto_generated_commands.py @@ -11,14 +11,14 @@ from tm_devices import commands -with open(os.path.dirname(__file__) + "/auto_gen_cmds_list.json", encoding="utf-8") as file_pointer: +with open(Path(__file__).parent / "auto_gen_cmds_list.json", encoding="utf-8") as file_pointer: json_dict = json.load(file_pointer) MASTER_COMMAND_SET: Set[str] = set(json_dict["commands"]) def get_driver_command_list() -> List[str]: """Return a list of all auto-generated files with command definitions.""" - commands_dir = os.path.dirname(commands.__file__) + commands_dir = Path(commands.__file__).parent auto_generated_file_list = [Path(x) for x in glob.glob(f"{commands_dir}/**", recursive=True)] auto_generated_file_list = list( filter( diff --git a/tests/test_config_parser.py b/tests/test_config_parser.py index cd710185..90c9c6b1 100644 --- a/tests/test_config_parser.py +++ b/tests/test_config_parser.py @@ -1,7 +1,6 @@ # pyright: reportPrivateUsage=none """Tests for the config_parser.py file.""" -import os - +from pathlib import Path from types import MappingProxyType from typing import Dict, Mapping, Optional, Type from unittest import mock @@ -166,7 +165,7 @@ def test_file_config_default_path() -> None: ), } with mock.patch.dict("os.environ", {}, clear=True), mock.patch( - "os.path.isfile", mock.MagicMock(return_value=True) + "pathlib.Path.is_file", mock.MagicMock(return_value=True) ), mock.patch("builtins.open", mock.mock_open(read_data=file_contents)): config = DMConfigParser() @@ -181,18 +180,12 @@ def test_file_config_default_path() -> None: [ # test with toml ( - { - "TM_DEVICES_CONFIG": f"{os.path.dirname(os.path.abspath(__file__))}/" - f"samples/sample_devices.toml" - }, + {"TM_DEVICES_CONFIG": str(Path(__file__).parent / "samples/sample_devices.toml")}, DMConfigParser.FileType.TOML, ), # test with yaml ( - { - "TM_DEVICES_CONFIG": f"{os.path.dirname(os.path.abspath(__file__))}/" - f"samples/sample_devices.yaml" - }, + {"TM_DEVICES_CONFIG": str(Path(__file__).parent / "samples/sample_devices.yaml")}, DMConfigParser.FileType.YAML, ), ], @@ -366,12 +359,7 @@ def test_invalid_config_creation_from_file() -> None: """Test loading a config file with an invalid option.""" with mock.patch.dict( "os.environ", - { - "TM_DEVICES_CONFIG": ( - f"{os.path.dirname(os.path.abspath(__file__))}/" - f"samples/invalid_config_option.yaml" - ) - }, + {"TM_DEVICES_CONFIG": str(Path(__file__).parent / "samples/invalid_config_option.yaml")}, clear=True, ): with pytest.raises(KeyError) as error: diff --git a/tests/test_device_manager.py b/tests/test_device_manager.py index 78c8b80a..368434d8 100644 --- a/tests/test_device_manager.py +++ b/tests/test_device_manager.py @@ -1,10 +1,15 @@ # pyright: reportUnusedFunction=none +# pyright: reportUnknownMemberType=none +# pyright: reportAttributeAccessIssue=none +# pyright: reportUnknownVariableType=none +# pyright: reportArgumentType=none """Tests for the device_manager.py file.""" import contextlib import os import subprocess import sys +from pathlib import Path from typing import Generator, Iterator, List from unittest import mock @@ -253,20 +258,18 @@ def __init__(self, config_entry: DeviceConfigEntry, verbose: bool) -> None: ... def already_exists(self) -> None: """Return nothing.""" ''' - sub_filepath = os.path.join("drivers", "device.pyi") - generated_stub_dir = os.path.join( - os.path.dirname(__file__), - "samples", - "generated_stubs", - f"output_{sys.version_info.major}{sys.version_info.minor}", - "tm_devices", + sub_filepath = Path("drivers/device.pyi") + generated_stub_dir = ( + Path(__file__).parent + / "samples/generated_stubs" + / f"output_{sys.version_info.major}{sys.version_info.minor}/tm_devices" ) - generated_stub_file = os.path.join(generated_stub_dir, sub_filepath) - golden_stub_dir = os.path.join(os.path.dirname(__file__), "samples", "golden_stubs") - os.makedirs(os.path.dirname(generated_stub_file), exist_ok=True) + generated_stub_file = generated_stub_dir / sub_filepath + golden_stub_dir = Path(__file__).parent / "samples" / "golden_stubs" + generated_stub_file.parent.mkdir(parents=True, exist_ok=True) with open(generated_stub_file, "w", encoding="utf-8") as generated_file: generated_file.write(initial_input) - with mock.patch.dict("os.environ", {"TM_DEVICES_STUB_DIR": generated_stub_dir}): + with mock.patch.dict("os.environ", {"TM_DEVICES_STUB_DIR": str(generated_stub_dir)}): # noinspection PyUnusedLocal,PyShadowingNames @Device.add_property(is_cached=True) def inc_cached_count(self: Device) -> int: # noqa: ARG001 @@ -303,20 +306,20 @@ def custom_list(self: Device) -> List[str]: """Return the model and serial in a list.""" return [self.model, self.serial] - @Device.add_method # type: ignore + @Device.add_method def custom_return_none() -> None: """Return nothing. This has a multi-line description. """ - @Device.add_method # type: ignore + @Device.add_method def already_exists() -> None: """Return nothing.""" with pytest.raises(AssertionError): - @Scope.add_method # type: ignore + @Scope.add_method def custom_return() -> None: """Return nothing.""" @@ -348,7 +351,7 @@ def custom_model_getter_afg3kc(device: AFG3KC, value: str) -> str: ############################################################################################ start_dir = os.getcwd() try: - os.chdir(os.path.dirname(generated_stub_file)) + os.chdir(generated_stub_file.parent) subprocess.check_call( [ # noqa: S603 sys.executable, @@ -356,7 +359,7 @@ def custom_model_getter_afg3kc(device: AFG3KC, value: str) -> str: "ruff", "format", "--quiet", - os.path.basename(generated_stub_file), + generated_stub_file.name, ] ) subprocess.check_call( @@ -368,12 +371,12 @@ def custom_model_getter_afg3kc(device: AFG3KC, value: str) -> str: "check", "--select=I", "--fix", - os.path.basename(generated_stub_file), + generated_stub_file.name, ] ) finally: os.chdir(start_dir) - with open(os.path.join(golden_stub_dir, sub_filepath), encoding="utf-8") as golden_file: + with open(golden_stub_dir / sub_filepath, encoding="utf-8") as golden_file: golden_contents = golden_file.read() with open(generated_stub_file, encoding="utf-8") as generated_file: generated_contents = generated_file.read() @@ -382,32 +385,30 @@ def custom_model_getter_afg3kc(device: AFG3KC, value: str) -> str: # Test the custom added properties afg = device_manager.add_afg("afg3kc-hostname", alias="testing") # noinspection PyUnresolvedReferences - assert afg.class_name == "AFG3KC" # type: ignore + assert afg.class_name == "AFG3KC" # noinspection PyUnresolvedReferences - _ = afg.inc_cached_count # type: ignore + _ = afg.inc_cached_count # noinspection PyUnresolvedReferences - assert afg.inc_cached_count == 1, "cached property is not working" # type: ignore + assert afg.inc_cached_count == 1, "cached property is not working" # noinspection PyUnresolvedReferences - _ = afg.inc_count # type: ignore + _ = afg.inc_count # noinspection PyUnresolvedReferences - assert afg.inc_count == 3, "uncached property is not working" # type: ignore + assert afg.inc_count == 3, "uncached property is not working" # Test the custom added methods # noinspection PyUnresolvedReferences - assert afg.custom_model_getter("a", "b", "c", 0.1) == ( # type: ignore - "Device AFG3252C a b c 0.1" - ) + assert afg.custom_model_getter("a", "b", "c", 0.1) == "Device AFG3252C a b c 0.1" # noinspection PyUnresolvedReferences - assert afg.custom_model_getter_ss("hello") == "SignalSource AFG3252C hello" # type: ignore + assert afg.custom_model_getter_ss("hello") == "SignalSource AFG3252C hello" # noinspection PyUnresolvedReferences - assert afg.custom_model_getter_afg("hello") == "AFG AFG3252C hello" # type: ignore + assert afg.custom_model_getter_afg("hello") == "AFG AFG3252C hello" # noinspection PyUnresolvedReferences - assert afg.custom_model_getter_afg3k("hello") == "AFG3K AFG3252C hello" # type: ignore + assert afg.custom_model_getter_afg3k("hello") == "AFG3K AFG3252C hello" # noinspection PyUnresolvedReferences - assert afg.custom_model_getter_afg3kc("hello") == "AFG3KC AFG3252C hello" # type: ignore + assert afg.custom_model_getter_afg3kc("hello") == "AFG3KC AFG3252C hello" with pytest.raises(AttributeError): # noinspection PyUnresolvedReferences - afg.custom_model_getter_scope("hello") # type: ignore + afg.custom_model_getter_scope("hello") # Test VISA methods assert afg.set_and_check("OUTPUT1:STATE", "1", custom_message_prefix="Custom prefix") == "1" @@ -618,7 +619,7 @@ def test_deleting_device_manager(self) -> None: num_closes = 3 args = [ sys.executable, - f"{os.path.dirname(__file__)}/validate_device_manager_delete.py", + str(Path(__file__).parent / "validate_device_manager_delete.py"), ] stdout = subprocess.check_output(args).decode("utf-8") # noqa: S603 @@ -643,9 +644,7 @@ def test_loading_isolated_config_file( assert len(device_manager.devices) == 1 _ = capsys.readouterr() # clear the output - device_manager.load_config_file( - f"{os.path.dirname(os.path.abspath(__file__))}/samples/simulated_config.yaml" - ) + device_manager.load_config_file(Path(__file__).parent / "samples/simulated_config.yaml") assert len(device_manager.devices) == 3 stdout = capsys.readouterr().out assert "Beginning Device Cleanup on AFG " in stdout @@ -655,7 +654,7 @@ def test_loading_isolated_config_file( device_manager.remove_all_devices() _ = capsys.readouterr() # clear the output device_manager.load_config_file( - f"{os.path.dirname(os.path.abspath(__file__))}/samples/simulated_config_no_cleanup.yaml" + Path(__file__).parent / "samples/simulated_config_no_cleanup.yaml" ) assert len(device_manager.devices) == 3 stdout = capsys.readouterr().out @@ -666,7 +665,7 @@ def test_loading_isolated_config_file( device_manager.remove_all_devices() _ = capsys.readouterr() # clear the output device_manager.load_config_file( - f"{os.path.dirname(os.path.abspath(__file__))}/samples/simulated_config_no_devices.yaml" + Path(__file__).parent / "samples/simulated_config_no_devices.yaml" ) assert not device_manager.devices stdout = capsys.readouterr().out diff --git a/tests/test_helpers.py b/tests/test_helpers.py index 921fff1e..69350e57 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -11,9 +11,11 @@ from typing import Any, ClassVar, Dict, List, Optional, Tuple from unittest import mock +import dateutil.parser import pytest import pyvisa as visa +from dateutil.tz import tzlocal from packaging.version import InvalidVersion, Version from requests import Response @@ -166,14 +168,14 @@ def test_print_with_timestamp() -> None: """Test the print_with_timestamp helper function.""" stdout = StringIO() with redirect_stdout(stdout): - now = datetime.datetime.now() + now = datetime.datetime.now(tz=tzlocal()) print_with_timestamp("message") message = stdout.getvalue() message_parts = message.split(" - ") assert len(message_parts) == 2 assert message_parts[1] == "message\n" - parsed_datetime = datetime.datetime.strptime(message_parts[0].strip(), "%Y-%m-%d %H:%M:%S.%f") + parsed_datetime = dateutil.parser.parse(message_parts[0].strip()) allowed_difference = datetime.timedelta( days=0, hours=0, diff --git a/tests/test_margin_testers.py b/tests/test_margin_testers.py index 71a81275..28991cf7 100644 --- a/tests/test_margin_testers.py +++ b/tests/test_margin_testers.py @@ -1,7 +1,6 @@ # pyright: reportPrivateUsage=none """Unit tests for tmt4.py.""" -import os - +from pathlib import Path from unittest import mock import pytest @@ -12,9 +11,7 @@ from tm_devices import DeviceManager from tm_devices.drivers.api.rest_api.margin_testers.margin_tester import MarginTester -AUTH_TOKEN_FILE_PATH = ( - f"{os.path.dirname(os.path.abspath(__file__))}/samples/token.auth_token_file_path" # nosec -) +AUTH_TOKEN_FILE_PATH = f"{Path(__file__).parent}/samples/token.auth_token_file_path" # nosec ################################################################################################ @@ -57,7 +54,7 @@ def test_margin_tester(tmt4: MarginTester, device_manager: DeviceManager) -> Non # cover what happens when there is a string in the fw_version/fpga_version field with mock.patch.dict( - tmt4._about_info, # noqa: SLF001 # pyright: ignore + tmt4._about_info, # type: ignore[attr-defined] # noqa: SLF001 {"fpga_version": "UNIT TEST STRING", "fw_version": "UNIT TEST STRING"}, ): assert tmt4.fw_version == Version("0") diff --git a/tests/test_rest_api_device.py b/tests/test_rest_api_device.py index 04b1a787..b11572c5 100644 --- a/tests/test_rest_api_device.py +++ b/tests/test_rest_api_device.py @@ -160,7 +160,7 @@ def test_unsupported_request_type(rest_api_device: CustomRestApiDevice) -> None: """ with pytest.raises(ValueError, match="UNSUPPORTED is an unsupported request type."): rest_api_device._send_request( # noqa: SLF001 - request_type="UNSUPPORTED", # type: ignore + request_type="UNSUPPORTED", # type: ignore[arg-type] url="/api", ) diff --git a/tests/test_scopes.py b/tests/test_scopes.py index eec81df7..27c93ce5 100644 --- a/tests/test_scopes.py +++ b/tests/test_scopes.py @@ -132,7 +132,7 @@ def test_tekscope(device_manager: DeviceManager) -> None: # noqa: PLR0915 ): scope.generate_waveform( 25e6, - scope.source_device_constants.functions.PULSE.value, # type: ignore + scope.source_device_constants.functions.PULSE.value, # pyright: ignore[reportArgumentType] 1.0, 0.0, "all", @@ -334,7 +334,7 @@ def test_long_device_name(device_manager: DeviceManager) -> None: assert scope.all_channel_names_list == () # noinspection PyUnresolvedReferences - assert scope.custom_mso5_method("test-value") == ( # type: ignore + assert scope.custom_mso5_method("test-value") == ( # pyright: ignore[reportUnknownMemberType,reportAttributeAccessIssue] "This is a custom method for the LONGNAMEINSTRUMENT device. value='test-value'" ) diff --git a/tests/test_smu.py b/tests/test_smu.py index 7e2f4f66..a9088a16 100644 --- a/tests/test_smu.py +++ b/tests/test_smu.py @@ -4,6 +4,7 @@ import socket import sys +from pathlib import Path from typing import cast from unittest import mock @@ -47,7 +48,7 @@ def test_smu( # noqa: PLR0915 assert "Query" in stdout smu.load_script( - file_path=f"{os.path.dirname(os.path.realpath(__file__))}/samples/tsp_script.py", + file_path=f"{Path(os.path.realpath(__file__)).parent}/samples/tsp_script.py", run_script=True, to_nv_memory=True, ) @@ -59,7 +60,7 @@ def test_smu( # noqa: PLR0915 assert "loadfuncs()" in stdout smu.expect_esr(0) smu.load_script( - file_path=f"{os.path.dirname(os.path.realpath(__file__))}/samples/tsp_script.py", + file_path=f"{Path(os.path.realpath(__file__)).parent}/samples/tsp_script.py", script_name="tsp_function", ) stdout = capsys.readouterr().out @@ -214,7 +215,7 @@ def test_smu( # noqa: PLR0915 filepath = f"./temp_test_{sys.version_info.major}{sys.version_info.minor}.csv" try: smu.write_buffers(filepath, "smua.nvbuffer1") - assert os.path.exists(filepath) + assert os.path.exists(filepath) # noqa: PTH110 with open(filepath, encoding="utf-8") as file: lines = file.readlines() for index, value in enumerate(["smua.nvbuffer1", "1.0", "2.0", "3.0", "4.0", "5.0"]): diff --git a/tests/verify_physical_device_support.py b/tests/verify_physical_device_support.py index 696b271a..6bd16e5b 100644 --- a/tests/verify_physical_device_support.py +++ b/tests/verify_physical_device_support.py @@ -6,10 +6,12 @@ """ import os +from pathlib import Path + from tm_devices import DeviceManager if __name__ == "__main__": - os.environ["TM_DEVICES_CONFIG"] = f"{os.path.dirname(__file__)}/verify_devices.yaml" + os.environ["TM_DEVICES_CONFIG"] = f"{Path(__file__).parent}/verify_devices.yaml" with DeviceManager(verbose=False) as device_manager: device_manager.setup_cleanup_enabled = False