From 40067f5f26991b33e302b92d1ae37908a5b22e2b Mon Sep 17 00:00:00 2001 From: Bernhard Arnold Date: Thu, 12 Sep 2024 14:57:00 +0200 Subject: [PATCH 1/2] added type hints, PEP8 --- src/comet/driver/__init__.py | 2 + src/comet/driver/corvus/__init__.py | 2 + src/comet/driver/cts/__init__.py | 2 + src/comet/driver/cts/itc.py | 27 ++- src/comet/driver/driver.py | 5 +- src/comet/driver/generic/switching_matrix.py | 9 +- src/comet/driver/hephy/__init__.py | 2 + src/comet/driver/hephy/brandbox.py | 45 +++-- src/comet/driver/hephy/environbox.py | 11 +- src/comet/driver/hephy/shuntbox.py | 19 +-- src/comet/driver/itk/__init__.py | 2 + src/comet/driver/itk/corvustt.py | 26 +-- src/comet/driver/itk/hydra.py | 30 ++-- src/comet/driver/keithley/__init__.py | 12 ++ src/comet/driver/keithley/k237.py | 91 +++++----- src/comet/driver/keithley/k2400.py | 99 ++++++----- src/comet/driver/keithley/k2410.py | 6 +- src/comet/driver/keithley/k2470.py | 90 +++++----- src/comet/driver/keithley/k2657a.py | 72 ++++---- src/comet/driver/keithley/k6514.py | 34 ++-- src/comet/driver/keithley/k6517b.py | 25 ++- src/comet/driver/keithley/k707b.py | 45 ++--- src/comet/driver/keithley/k708b.py | 7 +- src/comet/driver/keysight/__init__.py | 2 + src/comet/driver/keysight/e4980a.py | 91 +++++----- src/comet/driver/marzhauser/__init__.py | 2 + src/comet/driver/marzhauser/tango.py | 21 +-- src/comet/driver/marzhauser/venus.py | 24 +-- src/comet/driver/nkt_photonics/__init__.py | 2 + src/comet/driver/nkt_photonics/pilas.py | 3 +- src/comet/driver/photonic/__init__.py | 2 + src/comet/driver/photonic/f3000.py | 6 +- src/comet/driver/rohde_schwarz/__init__.py | 4 +- src/comet/driver/rohde_schwarz/nge100.py | 14 +- src/comet/driver/rohde_schwarz/sma100b.py | 2 - src/comet/driver/smc/__init__.py | 4 +- src/comet/driver/smc/corvus.py | 26 +-- src/comet/driver/thorlabs/__init__.py | 2 + src/comet/driver/thorlabs/pm100.py | 5 +- src/comet/emulator/__init__.py | 2 + src/comet/emulator/__main__.py | 34 ++-- src/comet/emulator/cts/itc.py | 43 +++-- src/comet/emulator/emulator.py | 46 +++-- src/comet/emulator/hephy/brandbox.py | 70 ++++---- src/comet/emulator/hephy/environbox.py | 171 +++++++++---------- src/comet/emulator/hephy/shuntbox.py | 18 +- src/comet/emulator/iec60488.py | 16 +- src/comet/emulator/itk/corvustt.py | 74 ++++---- src/comet/emulator/itk/hydra.py | 33 ++-- src/comet/emulator/keithley/k2400.py | 114 ++++++------- src/comet/emulator/keithley/k2470.py | 111 ++++++------ src/comet/emulator/keithley/k2657a.py | 77 +++++---- src/comet/emulator/keithley/k2700.py | 42 +++-- src/comet/emulator/keithley/k6514.py | 70 ++++---- src/comet/emulator/keithley/k6517b.py | 97 ++++++----- src/comet/emulator/keithley/k707b.py | 26 ++- src/comet/emulator/keithley/k708b.py | 4 +- src/comet/emulator/keysight/e4980a.py | 16 +- src/comet/emulator/marzhauser/tango.py | 57 ++++--- src/comet/emulator/rohde_schwarz/nge100.py | 29 +--- src/comet/emulator/rohde_schwarz/sma100b.py | 48 +++--- src/comet/emulator/tcpserver.py | 24 ++- src/comet/emulator/thorlabs/pm100.py | 26 ++- src/comet/estimate.py | 5 +- src/comet/parameter.py | 8 +- src/comet/utils.py | 6 +- 66 files changed, 1066 insertions(+), 1074 deletions(-) diff --git a/src/comet/driver/__init__.py b/src/comet/driver/__init__.py index 15d2f51..f5f3424 100644 --- a/src/comet/driver/__init__.py +++ b/src/comet/driver/__init__.py @@ -1 +1,3 @@ from .driver import Driver + +__all__ = ["Driver"] diff --git a/src/comet/driver/corvus/__init__.py b/src/comet/driver/corvus/__init__.py index ce24fb3..bc4750e 100644 --- a/src/comet/driver/corvus/__init__.py +++ b/src/comet/driver/corvus/__init__.py @@ -1 +1,3 @@ from .venus1 import Venus1 + +__all__ = ["Venus1"] diff --git a/src/comet/driver/cts/__init__.py b/src/comet/driver/cts/__init__.py index f10b5d2..254cb7c 100644 --- a/src/comet/driver/cts/__init__.py +++ b/src/comet/driver/cts/__init__.py @@ -1 +1,3 @@ from .itc import ITC + +__all__ = ["ITC"] diff --git a/src/comet/driver/cts/itc.py b/src/comet/driver/cts/itc.py index 9ab4af8..c449b19 100644 --- a/src/comet/driver/cts/itc.py +++ b/src/comet/driver/cts/itc.py @@ -1,6 +1,6 @@ import datetime -from typing import Tuple from collections import namedtuple +from typing import Union from comet.driver import Driver @@ -10,7 +10,7 @@ class ITCDriver(Driver): """ITC driver base class.""" - def query_bytes(self, message, count) -> str: + def query_bytes(self, message: Union[str, bytes], count: int) -> str: """Raw query for bytes. >>> instr.query_bytes("P", 4) @@ -23,8 +23,7 @@ def query_bytes(self, message, count) -> str: class AnalogChannel(ITCDriver): - - CHANNELS = { + CHANNELS: dict[int, bytes] = { 1: b"A0", 2: b"A1", 3: b"A2", @@ -45,7 +44,7 @@ class AnalogChannel(ITCDriver): """Mapping analog channel index to channel code. When writing convert to lower case.""" - def __getitem__(self, index: int) -> Tuple[float, float]: + def __getitem__(self, index: int) -> tuple[float, float]: """Read analog channel, returns tuple containing actual value and target value. >>> instr.analog_channel[1] # read temperature target/actual @@ -57,7 +56,7 @@ def __getitem__(self, index: int) -> Tuple[float, float]: raise RuntimeError(f"invalid channel returned: '{result}'") return float(actual), float(target) - def __setitem__(self, index: int, value: float): + def __setitem__(self, index: int, value: float) -> None: """Set target value for analog channel. >>> instr.set_analog_channel[1] = 42.0 @@ -73,7 +72,7 @@ def __setitem__(self, index: int, value: float): class ITC(ITCDriver): """Interface for CTS Climate Chambers.""" - WARNING_MESSAGES = { + WARNING_MESSAGES: dict[str, str] = { "\x01": "Wassernachfüllen", "\x02": "Temp. Toleranzband Oben", "\x03": "Temp. Toleranzband Unten", @@ -83,7 +82,7 @@ class ITC(ITCDriver): } """Warning messages.""" - ERROR_MESSAGES = { + ERROR_MESSAGES: dict[str, str] = { "\x31": "Temperatur Grenze Min 08-B1", "\x32": "Temperatur Grenze Max 08-B1", "\x33": "Temp. Begrenzer Pruefr. 01-F1.1", @@ -114,11 +113,11 @@ class ITC(ITCDriver): Status = namedtuple("Status", ("running", "warning", "error", "channels")) """Status type container.""" - def __init__(self, resource): + def __init__(self, resource) -> None: super().__init__(resource) self.analog_channel = AnalogChannel(resource) - def identify(self): + def identify(self) -> str: """Returns instrument identification.""" self.time # perform device access return "ITC climate chamber" @@ -134,7 +133,7 @@ def time(self) -> datetime.datetime: return datetime.datetime.strptime(result, "T%d%m%y%H%M%S") @time.setter - def time(self, dt: datetime.datetime): + def time(self, dt: datetime.datetime) -> None: """Update device date and time, returns updated data and time as datetime object. >>> instr.time = datetime.datetime.now() @@ -145,7 +144,7 @@ def time(self, dt: datetime.datetime): raise RuntimeError("failed to set date and time") @property - def status(self) -> object: + def status(self) -> Status: """Returns device status as object. >>> instr.status @@ -160,7 +159,7 @@ def status(self) -> object: error_nr = result[9] warning = type(self).WARNING_MESSAGES[error_nr] if is_error and error_nr in type(self).WARNING_MESSAGES else None error = type(self).ERROR_MESSAGES[error_nr] if is_error and error_nr in type(self).ERROR_MESSAGES else None - return self.Status(running, warning, error, channels) + return type(self).Status(running, warning, error, channels) @property def error_message(self) -> str: @@ -183,7 +182,7 @@ def program(self) -> int: return int(result[1:]) @program.setter - def program(self, number: int): + def program(self, number: int) -> None: """Starts a program. Returns program number or 0 for no program. >>> instr.program = 42 diff --git a/src/comet/driver/driver.py b/src/comet/driver/driver.py index 3b9fbae..e8ee9e0 100644 --- a/src/comet/driver/driver.py +++ b/src/comet/driver/driver.py @@ -1,7 +1,8 @@ -from abc import ABC, abstractmethod +from abc import ABC class Driver(ABC): + """Base class for instrument drivers.""" - def __init__(self, resource): + def __init__(self, resource) -> None: self.resource = resource diff --git a/src/comet/driver/generic/switching_matrix.py b/src/comet/driver/generic/switching_matrix.py index ae68e49..234e7fe 100644 --- a/src/comet/driver/generic/switching_matrix.py +++ b/src/comet/driver/generic/switching_matrix.py @@ -1,5 +1,4 @@ from abc import abstractmethod -from typing import List from .instrument import Instrument @@ -7,17 +6,17 @@ class SwitchingMatrix(Instrument): - CHANNELS: List[str] = [] + CHANNELS: list[str] = [] @property @abstractmethod - def closed_channels(self) -> List[str]: ... + def closed_channels(self) -> list[str]: ... @abstractmethod - def close_channels(self, channels: List[str]) -> None: ... + def close_channels(self, channels: list[str]) -> None: ... @abstractmethod - def open_channels(self, channels: List[str]) -> None: ... + def open_channels(self, channels: list[str]) -> None: ... @abstractmethod def open_all_channels(self) -> None: ... diff --git a/src/comet/driver/hephy/__init__.py b/src/comet/driver/hephy/__init__.py index 025ad59..1efd074 100644 --- a/src/comet/driver/hephy/__init__.py +++ b/src/comet/driver/hephy/__init__.py @@ -1,3 +1,5 @@ from .brandbox import BrandBox from .environbox import EnvironBox from .shuntbox import ShuntBox + +__all__ = ["BrandBox", "EnvironBox", "ShuntBox"] diff --git a/src/comet/driver/hephy/brandbox.py b/src/comet/driver/hephy/brandbox.py index 61c2cb8..54ce180 100644 --- a/src/comet/driver/hephy/brandbox.py +++ b/src/comet/driver/hephy/brandbox.py @@ -1,27 +1,25 @@ import re -from typing import Dict, List, Optional, Tuple +from typing import Optional from comet.driver.generic import InstrumentError from comet.driver.generic.switching_matrix import SwitchingMatrix from comet.utils import combine_matrix -__all__ = ['BrandBox'] +__all__ = ["BrandBox"] -ERROR_MESSAGES: Dict[int, str] = { - 99: "Invalid command" -} +ERROR_MESSAGES: dict[int, str] = {99: "Invalid command"} -def split_channels(channels: str) -> List[str]: - return [channel.strip() for channel in channels.split(',') if channel.strip()] +def split_channels(channels: str) -> list[str]: + return [channel.strip() for channel in channels.split(",") if channel.strip()] -def join_channels(channels: List[str]) -> str: - return ','.join([format(channel).strip() for channel in channels]) +def join_channels(channels: list[str]) -> str: + return ",".join([format(channel).strip() for channel in channels]) def parse_error(response: str) -> Optional[InstrumentError]: - m = re.match(r'^err(\d+)', response.lower()) + m = re.match(r"^err(\d+)", response.lower()) if m: code = int(m.group(1)) message = ERROR_MESSAGES.get(code, "") @@ -30,21 +28,20 @@ def parse_error(response: str) -> Optional[InstrumentError]: class BrandBox(SwitchingMatrix): + CHANNELS: list[str] = combine_matrix("ABC", "12") - CHANNELS = combine_matrix('ABC', '12') - - _error_queue: List[InstrumentError] = [] + _error_queue: list[InstrumentError] = [] def identify(self) -> str: - return self.query('*IDN?') + return self.query("*IDN?") def reset(self) -> None: self._error_queue.clear() - self.write('*RST') + self.write("*RST") def clear(self) -> None: self._error_queue.clear() - self.write('*CLS') + self.write("*CLS") # Error queue @@ -56,21 +53,21 @@ def next_error(self) -> Optional[InstrumentError]: # Switching matrix @property - def closed_channels(self) -> List[str]: - channels = self.query(':CLOS:STAT?') + def closed_channels(self) -> list[str]: + channels = self.query(":CLOS:STAT?") return split_channels(channels) - def close_channels(self, channels: List[str]) -> None: + def close_channels(self, channels: list[str]) -> None: channel_list = join_channels(sorted(channels)) - self.write(f':CLOS {channel_list}') + self.write(f":CLOS {channel_list}") - def open_channels(self, channels: List[str]) -> None: + def open_channels(self, channels: list[str]) -> None: channel_list = join_channels(sorted(channels)) - self.write(f':OPEN {channel_list}') + self.write(f":OPEN {channel_list}") def open_all_channels(self) -> None: channel_list = join_channels(type(self).CHANNELS) - self.write(f':OPEN {channel_list}') + self.write(f":OPEN {channel_list}") # Helper @@ -79,7 +76,7 @@ def query(self, message: str) -> str: error = parse_error(response) if error: self._error_queue.append(error) - return '' + return "" return response def write(self, message: str) -> None: diff --git a/src/comet/driver/hephy/environbox.py b/src/comet/driver/hephy/environbox.py index f150b05..f60e823 100644 --- a/src/comet/driver/hephy/environbox.py +++ b/src/comet/driver/hephy/environbox.py @@ -1,12 +1,12 @@ import re -from typing import Any, Dict, List, Optional, Tuple +from typing import Any, Optional from comet.driver.generic import Instrument from comet.driver.generic import InstrumentError __all__ = ["EnvironBox"] -ERROR_MESSAGES: Dict[int, str] = { +ERROR_MESSAGES: dict[int, str] = { 1: "RTC not running", 2: "RTC read error", 80: "DAC not found", @@ -32,7 +32,7 @@ def parse_error(response: str) -> Optional[InstrumentError]: return None -def parse_pc_data(response: str) -> Dict[str, Any]: +def parse_pc_data(response: str) -> dict[str, Any]: values = response.split(",") relay_status = int(values[23]) return { @@ -85,8 +85,7 @@ def parse_pc_data(response: str) -> Dict[str, Any]: class EnvironBox(Instrument): - - _error_queue: List[InstrumentError] = [] + _error_queue: list[InstrumentError] = [] def identify(self) -> str: return self.query("*IDN?") @@ -225,7 +224,7 @@ def set_door_auto_light(self, state: bool) -> None: value = {self.DOOR_AUTO_LIGHT_OFF: "OFF", self.DOOR_AUTO_LIGHT_ON: "ON"}[state] self.write(f"SET:DOOR_AUTO_LIGHT {value}") - def get_data(self) -> Dict[str, Any]: + def get_data(self) -> dict[str, Any]: """Return dictionary of PC_DATA.""" return parse_pc_data(self.query("GET:PC_DATA ?")) diff --git a/src/comet/driver/hephy/shuntbox.py b/src/comet/driver/hephy/shuntbox.py index a1af3d1..94def6a 100644 --- a/src/comet/driver/hephy/shuntbox.py +++ b/src/comet/driver/hephy/shuntbox.py @@ -1,18 +1,16 @@ import re -from typing import Dict, List, Optional, Tuple +from typing import Optional from comet.driver.generic import Instrument from comet.driver.generic import InstrumentError -__all__ = ['ShuntBox'] +__all__ = ["ShuntBox"] -ERROR_MESSAGES: Dict[int, str] = { - 99: "Unknown command" -} +ERROR_MESSAGES: dict[int, str] = {99: "Unknown command"} def parse_error(response: str) -> Optional[InstrumentError]: - m = re.match(r'^err(\d+)', response.lower()) + m = re.match(r"^err(\d+)", response.lower()) if m: code = int(m.group(1)) message = ERROR_MESSAGES.get(code, "") @@ -21,15 +19,14 @@ def parse_error(response: str) -> Optional[InstrumentError]: class ShuntBox(Instrument): - - _error_queue: List[InstrumentError] = [] + _error_queue: list[InstrumentError] = [] def identify(self) -> str: - return self.query('*IDN?') + return self.query("*IDN?") def reset(self) -> None: self._error_queue.clear() - self.write('*RST') + self.write("*RST") def clear(self) -> None: self._error_queue.clear() @@ -49,7 +46,7 @@ def query(self, message: str) -> str: error = parse_error(response) if error: self._error_queue.append(error) - return '' + return "" return response def write(self, message: str) -> None: diff --git a/src/comet/driver/itk/__init__.py b/src/comet/driver/itk/__init__.py index 0bba03e..724f3bc 100644 --- a/src/comet/driver/itk/__init__.py +++ b/src/comet/driver/itk/__init__.py @@ -1,2 +1,4 @@ from .corvustt import CorvusTT from .hydra import Hydra + +__all__ = ["CorvusTT", "Hydra"] diff --git a/src/comet/driver/itk/corvustt.py b/src/comet/driver/itk/corvustt.py index 7ca2e5a..b9e98d8 100644 --- a/src/comet/driver/itk/corvustt.py +++ b/src/comet/driver/itk/corvustt.py @@ -1,11 +1,15 @@ -from typing import Dict, Optional +from typing import Optional from comet.driver.generic import InstrumentError -from comet.driver.generic.motion_controller import Position, MotionControllerAxis, MotionController +from comet.driver.generic.motion_controller import ( + Position, + MotionControllerAxis, + MotionController, +) __all__ = ["CorvusTT"] -ERROR_MESSAGES: Dict[int, str] = { +ERROR_MESSAGES: dict[int, str] = { 1: "internal error", 2: "internal error", 3: "internal error", @@ -32,7 +36,6 @@ def parse_error(response: str) -> Optional[InstrumentError]: class CorvusAxis(MotionControllerAxis): - def calibrate(self) -> None: self.resource.write(f"{self.index:d} ncal") @@ -63,15 +66,12 @@ def is_moving(self) -> bool: class CorvusTT(MotionController): - def identify(self) -> str: return self.resource.query("identify").strip() - def reset(self) -> None: - ... + def reset(self) -> None: ... - def clear(self) -> None: - ... + def clear(self) -> None: ... def next_error(self) -> Optional[InstrumentError]: response = self.resource.query("geterror") @@ -93,17 +93,17 @@ def is_calibrated(self) -> bool: return [int(value) for value in values].count(0x3) == len(values) def move_absolute(self, position: Position) -> None: - values = " ".join([format(value, '.3f') for value in position]) + values = " ".join([format(value, ".3f") for value in position]) self.resource.write(f"{values} move") def move_relative(self, position: Position) -> None: - values = " ".join([format(value, '.3f') for value in position]) + values = " ".join([format(value, ".3f") for value in position]) self.resource.write(f"{values} rmove") - def abort(self): + def abort(self) -> None: self.resource.write("abort") - def force_abort(self): + def force_abort(self) -> None: self.resource.write(chr(0x03)) # Ctrl+C @property diff --git a/src/comet/driver/itk/hydra.py b/src/comet/driver/itk/hydra.py index 4d97128..009a571 100644 --- a/src/comet/driver/itk/hydra.py +++ b/src/comet/driver/itk/hydra.py @@ -1,11 +1,15 @@ -from typing import Dict, Optional +from typing import Optional from comet.driver.generic import InstrumentError -from comet.driver.generic.motion_controller import Position, MotionControllerAxis, MotionController +from comet.driver.generic.motion_controller import ( + Position, + MotionControllerAxis, + MotionController, +) __all__ = ["Hydra"] -ERROR_MESSAGES: Dict[int, str] = { +ERROR_MESSAGES: dict[int, str] = { 0: "no error", 4: "internal error", 100: "devicenumber out of range", @@ -31,7 +35,6 @@ def parse_error(response: str) -> Optional[InstrumentError]: class HydraAxis(MotionControllerAxis): - def calibrate(self) -> None: self.resource.write(f"{self.index:d} ncal") @@ -62,17 +65,14 @@ def is_moving(self) -> bool: class Hydra(MotionController): - - AXES = (1, 2) + AXES: list[int] = [1, 2] def identify(self) -> str: return self.resource.query("identify").strip() - def reset(self) -> None: - ... + def reset(self) -> None: ... - def clear(self) -> None: - ... + def clear(self) -> None: ... def next_error(self) -> Optional[InstrumentError]: response = self.resource.query("ge") @@ -98,18 +98,18 @@ def is_calibrated(self) -> bool: return bool(int(status & 0x18)) def move_absolute(self, position: Position) -> None: - values = [format(value, '.3f') for value in position] + values = [format(value, ".3f") for value in position] self.resource.write(f"{values[0]} {values[1]} m") def move_relative(self, position: Position) -> None: - values = [format(value, '.3f') for value in position] + values = [format(value, ".3f") for value in position] self.resource.write(f"{values[0]} {values[1]} r") - def abort(self): + def abort(self) -> None: for index in type(self).AXES: self.resource.write(f"{index:d} nabort") - def force_abort(self): + def force_abort(self) -> None: self.resource.write(chr(0x03)) # Ctrl+C @property @@ -132,6 +132,6 @@ def joystick_enabled(self) -> bool: @joystick_enabled.setter def joystick_enabled(self, value: bool) -> None: - states = 0xf if value else 0x0 + states = 0xF if value else 0x0 for index in type(self).AXES: self.resource.write(f"{states:d} {index:d} setmanctrl") diff --git a/src/comet/driver/keithley/__init__.py b/src/comet/driver/keithley/__init__.py index a9cbef4..843834a 100644 --- a/src/comet/driver/keithley/__init__.py +++ b/src/comet/driver/keithley/__init__.py @@ -7,3 +7,15 @@ from .k2657a import K2657A from .k6514 import K6514 from .k6517b import K6517B + +__all__ = [ + "K237", + "K707B", + "K708B", + "K2400", + "K2410", + "K2470", + "K2657A", + "K6514", + "K6517B", +] diff --git a/src/comet/driver/keithley/k237.py b/src/comet/driver/keithley/k237.py index 438ea69..df5a64f 100644 --- a/src/comet/driver/keithley/k237.py +++ b/src/comet/driver/keithley/k237.py @@ -4,9 +4,9 @@ from comet.driver.generic import InstrumentError from comet.driver.generic.source_meter_unit import SourceMeterUnit -__all__ = ['K237'] +__all__ = ["K237"] -ERROR_MESSAGES = { +ERROR_MESSAGES: dict[int, str] = { 0: "Trigger Overrun", 1: "IDDC", 2: "IDDCO", @@ -32,11 +32,11 @@ 22: "Cal Compliance Error", 23: "Cal Value Error", 24: "Cal Constants Error", - 25: "Cal Invalid Error" + 25: "Cal Invalid Error", } -def select_range_index(values: dict, level: float) -> int: +def select_range_index(values: dict[int, float], level: float) -> int: level = abs(level) for index, value in sorted(values.items()): if level <= value: @@ -45,19 +45,18 @@ def select_range_index(values: dict, level: float) -> int: class K237(SourceMeterUnit): + WRITE_DELAY: float = 0.250 - WRITE_DELAY = 0.250 - - VOLTAGE_RANGES = { - 0: 0., + VOLTAGE_RANGES: dict[int, float] = { + 0: 0.0, 1: 1.1, - 2: 11., - 3: 110., - 4: 1100., + 2: 11.0, + 3: 110.0, + 4: 1100.0, } - CURRENT_RANGES = { - 0: 0., + CURRENT_RANGES: dict[int, float] = { + 0: 0.0, 1: 1e-09, 2: 1e-08, 3: 1e-07, @@ -67,14 +66,14 @@ class K237(SourceMeterUnit): 7: 1e-03, 8: 1e-02, 9: 1e-01, - 10: 1e-00 + 10: 1e-00, } def identify(self) -> str: - value = self.query('U0X') + value = self.query("U0X") model = value[0:3] revision = value[3:6] - return f'Keithley Inc., Model {model}, rev. {revision}' + return f"Keithley Inc., Model {model}, rev. {revision}" def reset(self) -> None: self.resource.clear() @@ -83,9 +82,9 @@ def clear(self) -> None: self.resource.clear() def next_error(self) -> Optional[InstrumentError]: - values = self.query('U1X')[3:] + values = self.query("U1X")[3:] for index, value in enumerate(values): - if value == '1': + if value == "1": message = ERROR_MESSAGES.get(index, "Unknown Error") return InstrumentError(index, message) return None @@ -94,48 +93,44 @@ def next_error(self) -> Optional[InstrumentError]: @property def output(self) -> bool: - return self.query('U3X')[18:20] == 'N1' + return self.query("U3X")[18:20] == "N1" @output.setter def output(self, state: bool) -> None: - value = {False: 'N0X', True: 'N1X'}[state] + value = {False: "N0X", True: "N1X"}[state] self.write(value) @property def function(self) -> str: - return { - 0: self.FUNCTION_VOLTAGE, - 1: self.FUNCTION_CURRENT - }[int(self.query('U4X')[8])] + return {0: self.FUNCTION_VOLTAGE, 1: self.FUNCTION_CURRENT}[ + int(self.query("U4X")[8]) + ] @function.setter def function(self, function: str) -> None: - value = { - self.FUNCTION_VOLTAGE: 0, - self.FUNCTION_CURRENT: 1 - }[function] - self.write(f'F{value:d},0X') + value = {self.FUNCTION_VOLTAGE: 0, self.FUNCTION_CURRENT: 1}[function] + self.write(f"F{value:d},0X") # Voltage source @property def voltage_level(self) -> float: - self.write('G1,2,0X') # set output format - return float(self.query('X')) + self.write("G1,2,0X") # set output format + return float(self.query("X")) @voltage_level.setter def voltage_level(self, level: float) -> None: - self.write(f'B{level:.3E},,X') + self.write(f"B{level:.3E},,X") @property def voltage_range(self) -> float: - index = int(self.query('U4X')[5:7]) + index = int(self.query("U4X")[5:7]) return type(self).VOLTAGE_RANGES[index] @voltage_range.setter def voltage_range(self, level: float) -> None: index = select_range_index(type(self).VOLTAGE_RANGES, level) - self.write(f'B,{index:d},X') + self.write(f"B,{index:d},X") @property def voltage_compliance(self) -> float: @@ -143,28 +138,28 @@ def voltage_compliance(self) -> float: @voltage_compliance.setter def voltage_compliance(self, level: float) -> None: - self.write(f'L{level:.3E},0X') + self.write(f"L{level:.3E},0X") # Current source @property def current_level(self) -> float: - self.write('G1,2,0X') # set output format - return float(self.query('X')) + self.write("G1,2,0X") # set output format + return float(self.query("X")) @current_level.setter def current_level(self, level: float) -> None: - self.write(f'B{level:.3E},,X') + self.write(f"B{level:.3E},,X") @property def current_range(self) -> float: - index = int(self.query('U4X')[5:7]) + index = int(self.query("U4X")[5:7]) return type(self).CURRENT_RANGES[index] @current_range.setter def current_range(self, level: float) -> None: index = select_range_index(type(self).CURRENT_RANGES, level) - self.write(f'B,{index:d},X') + self.write(f"B,{index:d},X") @property def current_compliance(self) -> float: @@ -172,26 +167,26 @@ def current_compliance(self) -> float: @current_compliance.setter def current_compliance(self, level: float) -> None: - self.write(f'L{level:.3E},0X') + self.write(f"L{level:.3E},0X") @property def compliance_tripped(self) -> bool: - self.write('G1,0,0X') # set output format - return self.query('X')[0:2] == 'OS' + self.write("G1,0,0X") # set output format + return self.query("X")[0:2] == "OS" # Measurements def measure_voltage(self) -> float: - self.write('G4,2,0X') # set output format - return float(self.query('X')) + self.write("G4,2,0X") # set output format + return float(self.query("X")) def measure_current(self) -> float: - self.write('G4,2,0X') # set output format - return float(self.query('X')) + self.write("G4,2,0X") # set output format + return float(self.query("X")) # Helper - def write(self, message): + def write(self, message: str) -> None: self.resource.write(message) # throttle consecutive writes time.sleep(self.WRITE_DELAY) diff --git a/src/comet/driver/keithley/k2400.py b/src/comet/driver/keithley/k2400.py index 994e381..88cd4a6 100644 --- a/src/comet/driver/keithley/k2400.py +++ b/src/comet/driver/keithley/k2400.py @@ -5,39 +5,38 @@ from comet.driver.generic import InstrumentError from comet.driver.generic.source_meter_unit import SourceMeterUnit -__all__ = ['K2400'] +__all__ = ["K2400"] -def parse_error(response: str): - code, message = [token.strip() for token in response.split(',')][:2] - return int(code), message.strip('\"') +def parse_error(response: str) -> tuple[int, str]: + code, message = [token.strip() for token in response.split(",")][:2] + return int(code), message.strip('"') class K2400(BeeperMixin, RouteTerminalMixin, SourceMeterUnit): - def identify(self) -> str: - return self.query('*IDN?') + return self.query("*IDN?") def reset(self) -> None: - self.write('*RST') + self.write("*RST") def clear(self) -> None: - self.write('*CLS') + self.write("*CLS") # Beeper @property def beeper(self) -> bool: - return bool(int(self.query(':SYST:BEEP:STAT?'))) + return bool(int(self.query(":SYST:BEEP:STAT?"))) @beeper.setter def beeper(self, value: bool) -> None: - self.write(f':SYST:BEEP:STAT {value:d}') + self.write(f":SYST:BEEP:STAT {value:d}") # Error queue def next_error(self) -> Optional[InstrumentError]: - code, message = parse_error(self.query(':SYST:ERR:NEXT?')) + code, message = parse_error(self.query(":SYST:ERR:NEXT?")) if code: return InstrumentError(code, message) return None @@ -46,118 +45,118 @@ def next_error(self) -> Optional[InstrumentError]: @property def route_terminal(self) -> str: - value = self.query(':ROUT:TERM?') + value = self.query(":ROUT:TERM?") return { - 'FRON': self.ROUTE_TERMINAL_FRONT, - 'REAR': self.ROUTE_TERMINAL_REAR + "FRON": self.ROUTE_TERMINAL_FRONT, + "REAR": self.ROUTE_TERMINAL_REAR, }[value] @route_terminal.setter def route_terminal(self, route_terminal: str) -> None: value = { - self.ROUTE_TERMINAL_FRONT: 'FRON', - self.ROUTE_TERMINAL_REAR: 'REAR' + self.ROUTE_TERMINAL_FRONT: "FRON", + self.ROUTE_TERMINAL_REAR: "REAR", }[route_terminal] - self.write(f':ROUT:TERM {value}') + self.write(f":ROUT:TERM {value}") # Source meter unit @property def output(self) -> bool: - value = int(float(self.query(':OUTP:STAT?'))) + value = int(float(self.query(":OUTP:STAT?"))) return { 0: self.OUTPUT_OFF, - 1: self.OUTPUT_ON + 1: self.OUTPUT_ON, }[value] @output.setter def output(self, state: bool) -> None: value = { - self.OUTPUT_OFF: 'OFF', - self.OUTPUT_ON: 'ON' + self.OUTPUT_OFF: "OFF", + self.OUTPUT_ON: "ON", }[state] - self.write(f':OUTP:STAT {value}') + self.write(f":OUTP:STAT {value}") @property def function(self) -> str: - value = self.query(':SOUR:FUNC:MODE?') + value = self.query(":SOUR:FUNC:MODE?") return { - 'VOLT': self.FUNCTION_VOLTAGE, - 'CURR': self.FUNCTION_CURRENT + "VOLT": self.FUNCTION_VOLTAGE, + "CURR": self.FUNCTION_CURRENT, }[value] @function.setter def function(self, function: str) -> None: function_mode = { - self.FUNCTION_VOLTAGE: 'VOLT', - self.FUNCTION_CURRENT: 'CURR' + self.FUNCTION_VOLTAGE: "VOLT", + self.FUNCTION_CURRENT: "CURR", }[function] - self.write(f':SOUR:FUNC:MODE {function_mode}') + self.write(f":SOUR:FUNC:MODE {function_mode}") sense_function = { - self.FUNCTION_VOLTAGE: 'CURR', - self.FUNCTION_CURRENT: 'VOLT' + self.FUNCTION_VOLTAGE: "CURR", + self.FUNCTION_CURRENT: "VOLT", }[function] - self.write(f':SENS:FUNC \'{sense_function}\'') + self.write(f":SENS:FUNC '{sense_function}'") # Voltage source @property def voltage_level(self) -> float: - return float(self.query(':SOUR:VOLT:LEV?')) + return float(self.query(":SOUR:VOLT:LEV?")) @voltage_level.setter def voltage_level(self, level: float) -> None: - self.write(f':SOUR:VOLT:LEV {level:E}') + self.write(f":SOUR:VOLT:LEV {level:E}") @property def voltage_range(self) -> float: - return float(self.query(':SOUR:VOLT:RANG?')) + return float(self.query(":SOUR:VOLT:RANG?")) @voltage_range.setter def voltage_range(self, level: float) -> None: - self.write(f':SOUR:VOLT:RANG {level:E}') + self.write(f":SOUR:VOLT:RANG {level:E}") @property def voltage_compliance(self) -> float: - return float(self.query(':SENS:VOLT:PROT:LEV?')) + return float(self.query(":SENS:VOLT:PROT:LEV?")) @voltage_compliance.setter def voltage_compliance(self, level: float) -> None: - self.write(f':SENS:VOLT:PROT:LEV {level:.3E}') + self.write(f":SENS:VOLT:PROT:LEV {level:.3E}") @property def voltage_compliance_tripped(self) -> bool: - return bool(int(self.query(':SENS:VOLT:PROT:TRIP?'))) + return bool(int(self.query(":SENS:VOLT:PROT:TRIP?"))) # Current source @property def current_level(self) -> float: - return float(self.query(':SOUR:CURR:LEV?')) + return float(self.query(":SOUR:CURR:LEV?")) @current_level.setter def current_level(self, level: float) -> None: - self.write(f':SOUR:CURR:LEV {level:E}') + self.write(f":SOUR:CURR:LEV {level:E}") @property def current_range(self) -> float: - return float(self.query(':SOUR:CURR:RANG?')) + return float(self.query(":SOUR:CURR:RANG?")) @current_range.setter def current_range(self, level: float) -> None: - self.write(f':SOUR:CURR:RANG {level:E}') + self.write(f":SOUR:CURR:RANG {level:E}") @property def current_compliance(self) -> float: - return float(self.query(':SENS:CURR:PROT:LEV?')) + return float(self.query(":SENS:CURR:PROT:LEV?")) @current_compliance.setter def current_compliance(self, level: float) -> None: - self.write(f':SENS:CURR:PROT:LEV {level:.3E}') + self.write(f":SENS:CURR:PROT:LEV {level:.3E}") @property def current_compliance_tripped(self) -> bool: - return bool(int(self.query(':SENS:CURR:PROT:TRIP?'))) + return bool(int(self.query(":SENS:CURR:PROT:TRIP?"))) @property def compliance_tripped(self) -> bool: @@ -166,12 +165,12 @@ def compliance_tripped(self) -> bool: # Measurements def measure_voltage(self) -> float: - self.write(':FORM:ELEM VOLT') - return float(self.query(':READ?')) + self.write(":FORM:ELEM VOLT") + return float(self.query(":READ?")) def measure_current(self) -> float: - self.write(':FORM:ELEM CURR') - return float(self.query(':READ?')) + self.write(":FORM:ELEM CURR") + return float(self.query(":READ?")) # Helper @@ -180,4 +179,4 @@ def query(self, message: str) -> str: def write(self, message: str) -> None: self.resource.write(message) - self.resource.query('*OPC?') + self.resource.query("*OPC?") diff --git a/src/comet/driver/keithley/k2410.py b/src/comet/driver/keithley/k2410.py index 99b40fa..a654ee3 100644 --- a/src/comet/driver/keithley/k2410.py +++ b/src/comet/driver/keithley/k2410.py @@ -1,10 +1,6 @@ -from typing import Optional - from .k2400 import K2400 __all__ = ["K2410"] -class K2410(K2400): - - ... +class K2410(K2400): ... diff --git a/src/comet/driver/keithley/k2470.py b/src/comet/driver/keithley/k2470.py index 72b39ee..825e12d 100644 --- a/src/comet/driver/keithley/k2470.py +++ b/src/comet/driver/keithley/k2470.py @@ -6,24 +6,23 @@ from .k2400 import parse_error -__all__ = ['K2470'] +__all__ = ["K2470"] class K2470(RouteTerminalMixin, SourceMeterUnit): - def identify(self) -> str: - return self.query('*IDN?') + return self.query("*IDN?") def reset(self) -> None: - self.write('*RST') + self.write("*RST") def clear(self) -> None: - self.write('*CLS') + self.write("*CLS") # Error queue def next_error(self) -> Optional[InstrumentError]: - code, message = parse_error(self.query(':SYST:ERR:NEXT?')) + code, message = parse_error(self.query(":SYST:ERR:NEXT?")) if code: return InstrumentError(code, message) return None @@ -32,131 +31,132 @@ def next_error(self) -> Optional[InstrumentError]: @property def route_terminal(self) -> str: - value = self.query(':ROUT:TERM?') + value = self.query(":ROUT:TERM?") return { - 'FRON': self.ROUTE_TERMINAL_FRONT, - 'REAR': self.ROUTE_TERMINAL_REAR + "FRON": self.ROUTE_TERMINAL_FRONT, + "REAR": self.ROUTE_TERMINAL_REAR, }[value] @route_terminal.setter def route_terminal(self, route_terminal: str) -> None: value = { - self.ROUTE_TERMINAL_FRONT: 'FRON', - self.ROUTE_TERMINAL_REAR: 'REAR' + self.ROUTE_TERMINAL_FRONT: "FRON", + self.ROUTE_TERMINAL_REAR: "REAR", }[route_terminal] - self.write(f':ROUT:TERM {value}') + self.write(f":ROUT:TERM {value}") # Source meter unit @property def output(self) -> bool: - value = int(float(self.query(':OUTP:STAT?'))) + value = int(float(self.query(":OUTP:STAT?"))) return { 0: self.OUTPUT_OFF, - 1: self.OUTPUT_ON + 1: self.OUTPUT_ON, }[value] @output.setter def output(self, state: bool) -> None: value = { - self.OUTPUT_OFF: 'OFF', - self.OUTPUT_ON: 'ON' + self.OUTPUT_OFF: "OFF", + self.OUTPUT_ON: "ON", }[state] - self.write(f':OUTP:STAT {value}') + self.write(f":OUTP:STAT {value}") @property def function(self) -> str: - value = self.query(':SOUR:FUNC:MODE?') + value = self.query(":SOUR:FUNC:MODE?") return { - 'VOLT': self.FUNCTION_VOLTAGE, - 'CURR': self.FUNCTION_CURRENT + "VOLT": self.FUNCTION_VOLTAGE, + "CURR": self.FUNCTION_CURRENT, }[value] @function.setter def function(self, function: str) -> None: function_mode = { - self.FUNCTION_VOLTAGE: 'VOLT', - self.FUNCTION_CURRENT: 'CURR' + self.FUNCTION_VOLTAGE: "VOLT", + self.FUNCTION_CURRENT: "CURR", }[function] - self.write(f':SOUR:FUNC:MODE {function_mode}') + self.write(f":SOUR:FUNC:MODE {function_mode}") sense_function = { - self.FUNCTION_VOLTAGE: 'CURR', - self.FUNCTION_CURRENT: 'VOLT' + self.FUNCTION_VOLTAGE: "CURR", + self.FUNCTION_CURRENT: "VOLT", }[function] - self.write(f':SENS:FUNC \'{sense_function}\'') + self.write(f":SENS:FUNC '{sense_function}'") # Voltage source @property def voltage_level(self) -> float: - return float(self.query(':SOUR:VOLT:LEV?')) + return float(self.query(":SOUR:VOLT:LEV?")) @voltage_level.setter def voltage_level(self, level: float) -> None: - self.write(f':SOUR:VOLT:LEV {level:E}') + self.write(f":SOUR:VOLT:LEV {level:E}") @property def voltage_range(self) -> float: - return float(self.query(':SOUR:VOLT:RANG?')) + return float(self.query(":SOUR:VOLT:RANG?")) @voltage_range.setter def voltage_range(self, level: float) -> None: - self.write(f':SOUR:VOLT:RANG {level:E}') + self.write(f":SOUR:VOLT:RANG {level:E}") @property def voltage_compliance(self) -> float: - return float(self.query(':SOUR:CURR:VLIM:LEV?')) + return float(self.query(":SOUR:CURR:VLIM:LEV?")) @voltage_compliance.setter def voltage_compliance(self, level: float) -> None: - self.write(f':SOUR:CURR:VLIM:LEV {level:.3E}') + self.write(f":SOUR:CURR:VLIM:LEV {level:.3E}") @property def voltage_compliance_tripped(self) -> bool: - return bool(int(self.query(':SOUR:VOLT:ILIM:LEV:TRIP?'))) + return bool(int(self.query(":SOUR:VOLT:ILIM:LEV:TRIP?"))) # Current source @property def current_level(self) -> float: - return float(self.query(':SOUR:CURR:LEV?')) + return float(self.query(":SOUR:CURR:LEV?")) @current_level.setter def current_level(self, level: float) -> None: - self.write(f':SOUR:CURR:LEV {level:E}') + self.write(f":SOUR:CURR:LEV {level:E}") @property def current_range(self) -> float: - return float(self.query(':SOUR:CURR:RANG?')) + return float(self.query(":SOUR:CURR:RANG?")) @current_range.setter def current_range(self, level: float) -> None: - self.write(f':SOUR:CURR:RANG {level:E}') + self.write(f":SOUR:CURR:RANG {level:E}") @property def current_compliance(self) -> float: - return float(self.query(':SOUR:VOLT:ILIM:LEV?')) + return float(self.query(":SOUR:VOLT:ILIM:LEV?")) @current_compliance.setter def current_compliance(self, level: float) -> None: - self.write(f':SOUR:VOLT:ILIM:LEV {level:.3E}') + self.write(f":SOUR:VOLT:ILIM:LEV {level:.3E}") @property def current_compliance_tripped(self) -> bool: - return bool(int(self.query(':SOUR:CURR:VLIM:LEV:TRIP?'))) + return bool(int(self.query(":SOUR:CURR:VLIM:LEV:TRIP?"))) @property def compliance_tripped(self) -> bool: - return bool(int(self.query(':SOUR:CURR:VLIM:LEV:TRIP?'))) or \ - bool(int(self.query(':SOUR:VOLT:ILIM:LEV:TRIP?'))) + return bool(int(self.query(":SOUR:CURR:VLIM:LEV:TRIP?"))) or ( + bool(int(self.query(":SOUR:VOLT:ILIM:LEV:TRIP?"))) + ) # Measurements def measure_voltage(self) -> float: - return float(self.query(':MEAS:VOLT?')) + return float(self.query(":MEAS:VOLT?")) def measure_current(self) -> float: - return float(self.query(':MEAS:CURR?')) + return float(self.query(":MEAS:CURR?")) # Helper @@ -165,4 +165,4 @@ def query(self, message: str) -> str: def write(self, message: str) -> None: self.resource.write(message) - self.query('*OPC?') + self.query("*OPC?") diff --git a/src/comet/driver/keithley/k2657a.py b/src/comet/driver/keithley/k2657a.py index c01ef2c..cdbfd9b 100644 --- a/src/comet/driver/keithley/k2657a.py +++ b/src/comet/driver/keithley/k2657a.py @@ -4,135 +4,137 @@ from comet.driver.generic import InstrumentError from comet.driver.generic.source_meter_unit import SourceMeterUnit -__all__ = ['K2657A'] +__all__ = ["K2657A"] class K2657A(BeeperMixin, SourceMeterUnit): - def identify(self) -> str: - return self.query('*IDN?') + return self.query("*IDN?") def reset(self) -> None: - self.write('*RST') + self.write("*RST") def clear(self) -> None: - self.write('*CLS') + self.write("*CLS") # Beeper @property def beeper(self) -> bool: - return bool(float(self.tsp_print('beeper.enable'))) + return bool(float(self.tsp_print("beeper.enable"))) @beeper.setter def beeper(self, value: bool) -> None: - self.tsp_assign('beeper.enable', format(value, 'd')) + self.tsp_assign("beeper.enable", format(value, "d")) # Error queue def next_error(self) -> Optional[InstrumentError]: - code, message = self.tsp_print('errorqueue.next()').split('\t')[:2] + code, message = self.tsp_print("errorqueue.next()").split("\t")[:2] if int(float(code)): - return InstrumentError(int(float(code)), message.strip('\"\' ')) + return InstrumentError(int(float(code)), message.strip("\"' ")) return None # Source meter unit @property def output(self) -> bool: - value = int(float(self.tsp_print('smua.source.output'))) + value = int(float(self.tsp_print("smua.source.output"))) return { 0: self.OUTPUT_OFF, - 1: self.OUTPUT_ON + 1: self.OUTPUT_ON, }[value] @output.setter def output(self, state: bool) -> None: value = { self.OUTPUT_OFF: 0, - self.OUTPUT_ON: 1 + self.OUTPUT_ON: 1, }[state] - self.tsp_assign('smua.source.output', format(value, 'd')) + self.tsp_assign("smua.source.output", format(value, "d")) @property def function(self) -> str: - value = int(float(self.tsp_print('smua.source.func'))) + value = int(float(self.tsp_print("smua.source.func"))) return { 1: self.FUNCTION_VOLTAGE, - 0: self.FUNCTION_CURRENT + 0: self.FUNCTION_CURRENT, }[value] @function.setter def function(self, function: str) -> None: value = { self.FUNCTION_VOLTAGE: 1, - self.FUNCTION_CURRENT: 0 + self.FUNCTION_CURRENT: 0, }[function] - self.tsp_assign('smua.source.func', format(value, 'd')) + self.tsp_assign("smua.source.func", format(value, "d")) # Voltage source @property def voltage_level(self) -> float: - return float(self.tsp_print('smua.source.levelv')) + return float(self.tsp_print("smua.source.levelv")) @voltage_level.setter def voltage_level(self, level: float) -> None: - self.tsp_assign('smua.source.levelv', format(level, 'E')) + self.tsp_assign("smua.source.levelv", format(level, "E")) @property def voltage_range(self) -> float: - return float(self.tsp_print('smua.source.rangev')) + return float(self.tsp_print("smua.source.rangev")) @voltage_range.setter def voltage_range(self, level: float) -> None: - self.tsp_assign('smua.source.rangev', format(level, 'E')) + self.tsp_assign("smua.source.rangev", format(level, "E")) @property def voltage_compliance(self) -> float: - return float(self.tsp_print('smua.source.limitv')) + return float(self.tsp_print("smua.source.limitv")) @voltage_compliance.setter def voltage_compliance(self, level: float) -> None: - self.tsp_assign('smua.source.limitv', format(level, 'E')) + self.tsp_assign("smua.source.limitv", format(level, "E")) # Current source @property def current_level(self) -> float: - return float(self.tsp_print('smua.source.leveli')) + return float(self.tsp_print("smua.source.leveli")) @current_level.setter def current_level(self, level: float) -> None: - self.tsp_assign('smua.source.leveli', format(level, 'E')) + self.tsp_assign("smua.source.leveli", format(level, "E")) @property def current_range(self) -> float: - return float(self.tsp_print('smua.source.rangei')) + return float(self.tsp_print("smua.source.rangei")) @current_range.setter def current_range(self, level: float) -> None: - self.tsp_assign('smua.source.rangei', format(level, 'E')) + self.tsp_assign("smua.source.rangei", format(level, "E")) @property def current_compliance(self) -> float: - return float(self.tsp_print('smua.source.limiti')) + return float(self.tsp_print("smua.source.limiti")) @current_compliance.setter def current_compliance(self, level: float) -> None: - self.tsp_assign('smua.source.limiti', format(level, 'E')) + self.tsp_assign("smua.source.limiti", format(level, "E")) @property def compliance_tripped(self) -> bool: - return {'false': False, 'true': True}[self.tsp_print('smua.source.compliance')] + return { + "false": False, + "true": True, + }[self.tsp_print("smua.source.compliance")] # Measurements def measure_voltage(self) -> float: - return float(self.tsp_print('smua.measure.v()')) + return float(self.tsp_print("smua.measure.v()")) def measure_current(self) -> float: - return float(self.tsp_print('smua.measure.i()')) + return float(self.tsp_print("smua.measure.i()")) # Helper @@ -141,10 +143,10 @@ def query(self, message: str) -> str: def write(self, message: str) -> None: self.resource.write(message) - self.query('*OPC?') + self.query("*OPC?") def tsp_print(self, expression: str) -> str: - return self.query(f'print({expression})') + return self.query(f"print({expression})") def tsp_assign(self, expression: str, value: str) -> None: - self.write(f'{expression} = {value}') + self.write(f"{expression} = {value}") diff --git a/src/comet/driver/keithley/k6514.py b/src/comet/driver/keithley/k6514.py index 83246d3..b5d8ae5 100644 --- a/src/comet/driver/keithley/k6514.py +++ b/src/comet/driver/keithley/k6514.py @@ -3,29 +3,28 @@ from comet.driver.generic import InstrumentError from comet.driver.generic.electrometer import Electrometer -__all__ = ['K6514'] +__all__ = ["K6514"] -def parse_error(response: str): - code, message = [token.strip() for token in response.split(',')][:2] - return int(code), message.strip('\"') +def parse_error(response: str) -> tuple[int, str]: + code, message = [token.strip() for token in response.split(",")][:2] + return int(code), message.strip('"') class K6514(Electrometer): - def identify(self) -> str: - return self.query('*IDN?') + return self.query("*IDN?") def reset(self) -> None: - self.write('*RST') + self.write("*RST") def clear(self) -> None: - self.write('*CLS') + self.write("*CLS") # Error queue def next_error(self) -> Optional[InstrumentError]: - code, message = parse_error(self.query(':SYST:ERR:NEXT?')) + code, message = parse_error(self.query(":SYST:ERR:NEXT?")) if code: return InstrumentError(code, message) return None @@ -33,16 +32,16 @@ def next_error(self) -> Optional[InstrumentError]: # Electrometer def measure_voltage(self) -> float: - return float(self.query(':MEAS:VOLT?')) + return float(self.query(":MEAS:VOLT?")) def measure_current(self) -> float: - return float(self.query(':MEAS:CURR?')) + return float(self.query(":MEAS:CURR?")) def measure_resistance(self) -> float: - return float(self.query(':MEAS:RES?')) + return float(self.query(":MEAS:RES?")) def measure_charge(self) -> float: - return float(self.query(':MEAS:CHAR?')) + return float(self.query(":MEAS:CHAR?")) # Zero check @@ -50,8 +49,11 @@ def get_zero_check(self): return bool(int(self.query(":SYST:ZCH?"))) def set_zero_check(self, enabled: bool): - value = {False: 'OFF', True: 'ON'}[enabled] - self.write(f':SYST:ZCH {value}') + value = { + False: "OFF", + True: "ON", + }[enabled] + self.write(f":SYST:ZCH {value}") # Helper @@ -60,4 +62,4 @@ def query(self, message: str) -> str: def write(self, message: str) -> None: self.resource.write(message) - self.query('*OPC?') + self.query("*OPC?") diff --git a/src/comet/driver/keithley/k6517b.py b/src/comet/driver/keithley/k6517b.py index 68697d6..55f528f 100644 --- a/src/comet/driver/keithley/k6517b.py +++ b/src/comet/driver/keithley/k6517b.py @@ -3,29 +3,28 @@ from comet.driver.generic import InstrumentError from comet.driver.generic.electrometer import Electrometer -__all__ = ['K6517B'] +__all__ = ["K6517B"] def parse_error(response: str): - code, message = [token.strip() for token in response.split(',')][:2] - return int(code), message.strip('\"') + code, message = [token.strip() for token in response.split(",")][:2] + return int(code), message.strip('"') class K6517B(Electrometer): - def identify(self) -> str: - return self.query('*IDN?') + return self.query("*IDN?") def reset(self) -> None: - self.write('*RST') + self.write("*RST") def clear(self) -> None: - self.write('*CLS') + self.write("*CLS") # Error queue def next_error(self) -> Optional[InstrumentError]: - code, message = parse_error(self.query(':SYST:ERR:NEXT?')) + code, message = parse_error(self.query(":SYST:ERR:NEXT?")) if code: return InstrumentError(code, message) return None @@ -33,16 +32,16 @@ def next_error(self) -> Optional[InstrumentError]: # Electrometer def measure_voltage(self) -> float: - return float(self.query(':MEAS:VOLT?')) + return float(self.query(":MEAS:VOLT?")) def measure_current(self) -> float: - return float(self.query(':MEAS:CURR?')) + return float(self.query(":MEAS:CURR?")) def measure_resistance(self) -> float: - return float(self.query(':MEAS:RES?')) + return float(self.query(":MEAS:RES?")) def measure_charge(self) -> float: - return float(self.query(':MEAS:CHAR?')) + return float(self.query(":MEAS:CHAR?")) # Helper @@ -51,4 +50,4 @@ def query(self, message: str) -> str: def write(self, message: str) -> None: self.resource.write(message) - self.query('*OPC?') + self.query("*OPC?") diff --git a/src/comet/driver/keithley/k707b.py b/src/comet/driver/keithley/k707b.py index d9ca69a..95846bb 100644 --- a/src/comet/driver/keithley/k707b.py +++ b/src/comet/driver/keithley/k707b.py @@ -1,65 +1,66 @@ -from typing import List, Optional +from typing import Optional from comet.driver.generic import InstrumentError from comet.driver.generic.switching_matrix import SwitchingMatrix from comet.utils import combine_matrix -__all__ = ['K707B'] +__all__ = ["K707B"] -def split_channels(channels: str) -> List[str]: - return [channel.strip() for channel in channels.split(';') if channel.strip()] +def split_channels(channels: str) -> list[str]: + return [channel.strip() for channel in channels.split(";") if channel.strip()] -def join_channels(channels: List[str]) -> str: - return ','.join([format(channel).strip() for channel in channels]) +def join_channels(channels: list[str]) -> str: + return ",".join([format(channel).strip() for channel in channels]) class K707B(SwitchingMatrix): - - CHANNELS = combine_matrix('1234', 'ABCDEFG', combine_matrix('0', '123456789') + combine_matrix('1', '12')) + CHANNELS: list[str] = combine_matrix( + "1234", "ABCDEFG", combine_matrix("0", "123456789") + combine_matrix("1", "12") + ) def identify(self) -> str: - return self.query('*IDN?') + return self.query("*IDN?") def reset(self) -> None: - self.write('*RST') + self.write("*RST") def clear(self) -> None: - self.write('*CLS') + self.write("*CLS") # Beeper @property def beeper(self) -> bool: - return bool(float(self.tsp_print('beeper.enable'))) + return bool(float(self.tsp_print("beeper.enable"))) @beeper.setter def beeper(self, value: bool) -> None: - self.tsp_assign('beeper.enable', format(value, 'd')) + self.tsp_assign("beeper.enable", format(value, "d")) # Error queue def next_error(self) -> Optional[InstrumentError]: - code, message = self.tsp_print('errorqueue.next()').split('\t')[:2] + code, message = self.tsp_print("errorqueue.next()").split("\t")[:2] if int(code): - return InstrumentError(int(code), message.strip('\"\' ')) + return InstrumentError(int(code), message.strip("\"' ")) return None # Switching matrix @property - def closed_channels(self) -> List[str]: + def closed_channels(self) -> list[str]: channels = self.tsp_print('channel.getclose("allslots")') - if channels == 'nil': + if channels == "nil": return [] return sorted(split_channels(channels)) - def close_channels(self, channels: List[str]) -> None: + def close_channels(self, channels: list[str]) -> None: channel_list = join_channels(channels) self.write(f'channel.close("{channel_list}")') - def open_channels(self, channels: List[str]) -> None: + def open_channels(self, channels: list[str]) -> None: channel_list = join_channels(channels) self.write(f'channel.open("{channel_list}")') @@ -73,10 +74,10 @@ def query(self, message: str) -> str: def write(self, message: str) -> None: self.resource.write(message) - self.query('*OPC?') + self.query("*OPC?") def tsp_print(self, expression: str) -> str: - return self.query(f'print({expression})') + return self.query(f"print({expression})") def tsp_assign(self, expression: str, value: str) -> None: - self.write(f'{expression} = {value}') + self.write(f"{expression} = {value}") diff --git a/src/comet/driver/keithley/k708b.py b/src/comet/driver/keithley/k708b.py index 3e4fd8e..ea2e910 100644 --- a/src/comet/driver/keithley/k708b.py +++ b/src/comet/driver/keithley/k708b.py @@ -1,10 +1,9 @@ from comet.utils import combine_matrix -from .k707b import K707B, combine_matrix +from .k707b import K707B -__all__ = ['K708B'] +__all__ = ["K708B"] class K708B(K707B): - - CHANNELS = combine_matrix('1', 'ABCDEFG', '0', '012345678') + CHANNELS: list[str] = combine_matrix("1", "ABCDEFG", "0", "012345678") diff --git a/src/comet/driver/keysight/__init__.py b/src/comet/driver/keysight/__init__.py index 4268a74..9b7c7be 100644 --- a/src/comet/driver/keysight/__init__.py +++ b/src/comet/driver/keysight/__init__.py @@ -1 +1,3 @@ from .e4980a import E4980A + +__all__ = ["E4980A"] diff --git a/src/comet/driver/keysight/e4980a.py b/src/comet/driver/keysight/e4980a.py index ea62694..b72c586 100644 --- a/src/comet/driver/keysight/e4980a.py +++ b/src/comet/driver/keysight/e4980a.py @@ -1,107 +1,106 @@ -from typing import Optional, Tuple +from typing import Optional from comet.driver.generic import InstrumentError from comet.driver.generic.lcr_meter import LCRMeter -__all__ = ['E4980A'] +__all__ = ["E4980A"] class E4980A(LCRMeter): - - FUNCTION_CPD = 'CPD' - FUNCTION_CPQ = 'CPQ' - FUNCTION_CPG = 'CPG' - FUNCTION_CPRP = 'CPRP' - FUNCTION_CSD = 'CSD' - FUNCTION_CSQ = 'CSQ' - FUNCTION_CSRS = 'CSRS' - FUNCTION_LPD = 'LPD' - FUNCTION_LPQ = 'LPQ' - FUNCTION_LPG = 'LPG' - FUNCTION_LPRP = 'LPRP' - FUNCTION_LPRD = 'LPRD' - FUNCTION_LSD = 'LSD' - FUNCTION_LSQ = 'LSQ' - FUNCTION_LSRS = 'LSRS' - FUNCTION_LS = 'LS' - FUNCTION_RD = 'RD' - FUNCTION_RX = 'RX' - FUNCTION_ZTD = 'ZTD' - FUNCTION_ZTR = 'ZTR' - FUNCTION_GB = 'GB' - FUNCTION_YTD = 'YTD' - FUNCTION_YTR = 'YTR' - FUNCTION_VDID = 'VDID' + FUNCTION_CPD: str = "CPD" + FUNCTION_CPQ: str = "CPQ" + FUNCTION_CPG: str = "CPG" + FUNCTION_CPRP: str = "CPRP" + FUNCTION_CSD: str = "CSD" + FUNCTION_CSQ: str = "CSQ" + FUNCTION_CSRS: str = "CSRS" + FUNCTION_LPD: str = "LPD" + FUNCTION_LPQ: str = "LPQ" + FUNCTION_LPG: str = "LPG" + FUNCTION_LPRP: str = "LPRP" + FUNCTION_LPRD: str = "LPRD" + FUNCTION_LSD: str = "LSD" + FUNCTION_LSQ: str = "LSQ" + FUNCTION_LSRS: str = "LSRS" + FUNCTION_LS: str = "LS" + FUNCTION_RD: str = "RD" + FUNCTION_RX: str = "RX" + FUNCTION_ZTD: str = "ZTD" + FUNCTION_ZTR: str = "ZTR" + FUNCTION_GB: str = "GB" + FUNCTION_YTD: str = "YTD" + FUNCTION_YTR: str = "YTR" + FUNCTION_VDID: str = "VDID" def identify(self) -> str: - return self.query('*IDN?') + return self.query("*IDN?") def reset(self) -> None: - self.write('*RST') + self.write("*RST") def clear(self) -> None: - self.write('*CLS') + self.write("*CLS") # Beeper @property def beeper(self) -> bool: - return bool(int(self.query(':SYST:BEEP:STAT?'))) + return bool(int(self.query(":SYST:BEEP:STAT?"))) @beeper.setter def beeper(self, value: bool) -> None: - self.write(f':SYST:BEEP:STAT {value:d}') + self.write(f":SYST:BEEP:STAT {value:d}") # Error Queue def next_error(self) -> Optional[InstrumentError]: - code, message = self.query(':SYST:ERR:NEXT?').split(',')[:2] + code, message = self.query(":SYST:ERR:NEXT?").split(",")[:2] if int(code): - return InstrumentError(int(code), message.strip('\"\' ')) + return InstrumentError(int(code), message.strip("\"' ")) return None # LCR Meter @property def function(self) -> str: - return self.query(':FUNC:IMP:TYPE?') + return self.query(":FUNC:IMP:TYPE?") @function.setter def function(self, function: str) -> None: - self.write(f':FUNC:IMP:TYPE {function}') + self.write(f":FUNC:IMP:TYPE {function}") @property def amplitude(self) -> float: - return float(self.query(':VOLT:LEV?')) + return float(self.query(":VOLT:LEV?")) @amplitude.setter def amplitude(self, level: float) -> None: - self.write(f':VOLT:LEV {level:E}') + self.write(f":VOLT:LEV {level:E}") @property def frequency(self) -> float: - return float(self.query(':FREQ:CW?')) + return float(self.query(":FREQ:CW?")) @frequency.setter def frequency(self, frequency: float) -> None: - self.write(f':FREQ:CW {frequency:E}') + self.write(f":FREQ:CW {frequency:E}") # TODO def set_measurement_time(self, apterture: str) -> None: - self.write(f':APER {apterture}') + self.write(f":APER {apterture}") @property def correction_length(self) -> int: - return int(float(self.query(':CORR:LENG?'))) + return int(float(self.query(":CORR:LENG?"))) @correction_length.setter def correction_length(self, meters: int) -> None: - self.write(f':CORR:LENG {meters:d}') + self.write(f":CORR:LENG {meters:d}") # Measurements - def measure_impedance(self) -> Tuple[float, float]: - first, second = self.query(':FETC:IMP:FORM?').split(',')[:2] + def measure_impedance(self) -> tuple[float, float]: + first, second = self.query(":FETC:IMP:FORM?").split(",")[:2] return float(first), float(second) # Helper @@ -111,4 +110,4 @@ def query(self, message: str) -> str: def write(self, message: str) -> None: self.resource.write(message) - self.query('*OPC?') + self.query("*OPC?") diff --git a/src/comet/driver/marzhauser/__init__.py b/src/comet/driver/marzhauser/__init__.py index 38710b5..307005f 100644 --- a/src/comet/driver/marzhauser/__init__.py +++ b/src/comet/driver/marzhauser/__init__.py @@ -1,2 +1,4 @@ from .tango import Tango from .venus import Venus + +__all__ = ["Tango", "Venus"] diff --git a/src/comet/driver/marzhauser/tango.py b/src/comet/driver/marzhauser/tango.py index a71cb07..3e1c701 100644 --- a/src/comet/driver/marzhauser/tango.py +++ b/src/comet/driver/marzhauser/tango.py @@ -1,11 +1,15 @@ -from typing import Dict, Optional +from typing import Optional from comet.driver.generic import InstrumentError -from comet.driver.generic.motion_controller import Position, MotionControllerAxis, MotionController +from comet.driver.generic.motion_controller import ( + Position, + MotionControllerAxis, + MotionController, +) __all__ = ["Tango"] -ERROR_MESSAGES: Dict[int, str] = { +ERROR_MESSAGES: dict[int, str] = { 1: "no valid axis name", 2: "no executable instruction", 3: "too many characters in command line", @@ -45,7 +49,7 @@ 85: "overload on AUX I/O +12V supply or AUX mini +24V supply", 86: "low brake output voltage", 87: "overload on motor 4 connector +5V", - 88: "overload on a supply output pin (latched overload state), clear by \"!err\"", + 88: 'overload on a supply output pin (latched overload state), clear by "!err"', 89: "not executable while in standby mode", 90: "temperature error", 91: "encoder error", @@ -61,7 +65,6 @@ def parse_error(response: str) -> Optional[InstrumentError]: class TangoAxis(MotionControllerAxis): - @property def name(self) -> str: return "xyza"[self.index] @@ -100,12 +103,10 @@ def is_moving(self) -> bool: class Tango(MotionController): - def identify(self) -> str: return self.resource.query("?version").strip() - def reset(self) -> None: - ... + def reset(self) -> None: ... def clear(self) -> None: self.resource.write("!err") # clear error state @@ -131,12 +132,12 @@ def is_calibrated(self) -> bool: return [(int(value) & 0x3) for value in values].count(0x3) == len(values) def move_absolute(self, position: Position) -> None: - values = " ".join([format(value, '.3f') for value in position]) + values = " ".join([format(value, ".3f") for value in position]) self.resource.write("!autostatus 0") self.resource.write(f"!moa {values}") def move_relative(self, position: Position) -> None: - values = " ".join([format(value, '.3f') for value in position]) + values = " ".join([format(value, ".3f") for value in position]) self.resource.write("!autostatus 0") self.resource.write(f"!mor {values}") diff --git a/src/comet/driver/marzhauser/venus.py b/src/comet/driver/marzhauser/venus.py index a48872b..f19f738 100644 --- a/src/comet/driver/marzhauser/venus.py +++ b/src/comet/driver/marzhauser/venus.py @@ -1,11 +1,15 @@ -from typing import Dict, Optional +from typing import Optional from comet.driver.generic import InstrumentError -from comet.driver.generic.motion_controller import Position, MotionControllerAxis, MotionController +from comet.driver.generic.motion_controller import ( + Position, + MotionControllerAxis, + MotionController, +) __all__ = ["Venus"] -ERROR_MESSAGES: Dict[int, str] = { +ERROR_MESSAGES: dict[int, str] = { 1: "no valid axis name", 2: "no executable instruction", 3: "too many characters in command line", @@ -45,7 +49,7 @@ 85: "overload on AUX I/O +12V supply or AUX mini +24V supply", 86: "low brake output voltage", 87: "overload on motor 4 connector +5V", - 88: "overload on a supply output pin (latched overload state), clear by \"!err\"", + 88: 'overload on a supply output pin (latched overload state), clear by "!err"', 89: "not executable while in standby mode", 90: "temperature error", 91: "encoder error", @@ -61,7 +65,6 @@ def parse_error(response: str) -> Optional[InstrumentError]: class VenusAxis(MotionControllerAxis): - def calibrate(self) -> None: self.resource.write(f"{self.index:d} ncal") @@ -92,17 +95,14 @@ def is_moving(self) -> bool: class Venus(MotionController): - def identify(self) -> str: result = self.resource.query("tango").strip() self.resource.read() # 2nd line return result - def reset(self) -> None: - ... + def reset(self) -> None: ... - def clear(self) -> None: - ... + def clear(self) -> None: ... def next_error(self) -> Optional[InstrumentError]: response = self.resource.query("geterror") @@ -124,11 +124,11 @@ def is_calibrated(self) -> bool: return [int(value) for value in values].count(0x3) == len(values) def move_absolute(self, position: Position) -> None: - values = " ".join([format(value, '.3f') for value in position]) + values = " ".join([format(value, ".3f") for value in position]) self.resource.write(f"{values} move") def move_relative(self, position: Position) -> None: - values = " ".join([format(value, '.3f') for value in position]) + values = " ".join([format(value, ".3f") for value in position]) self.resource.write(f"{values} rmove") def abort(self): diff --git a/src/comet/driver/nkt_photonics/__init__.py b/src/comet/driver/nkt_photonics/__init__.py index 32c604d..d8735a3 100644 --- a/src/comet/driver/nkt_photonics/__init__.py +++ b/src/comet/driver/nkt_photonics/__init__.py @@ -1 +1,3 @@ from .pilas import PILAS + +__all__ = ["PILAS"] diff --git a/src/comet/driver/nkt_photonics/pilas.py b/src/comet/driver/nkt_photonics/pilas.py index ee05751..c31a249 100644 --- a/src/comet/driver/nkt_photonics/pilas.py +++ b/src/comet/driver/nkt_photonics/pilas.py @@ -1,7 +1,6 @@ -""" Driver for NKT Photonics PILAS picosecond pulsed diode laser """ +"""Driver for NKT Photonics PILAS picosecond pulsed diode laser.""" from comet.driver import Driver -from typing import Optional __all__ = ["PILAS"] diff --git a/src/comet/driver/photonic/__init__.py b/src/comet/driver/photonic/__init__.py index aba73bf..42a7067 100644 --- a/src/comet/driver/photonic/__init__.py +++ b/src/comet/driver/photonic/__init__.py @@ -1 +1,3 @@ from .f3000 import F3000 + +__all__ = ["F3000"] diff --git a/src/comet/driver/photonic/f3000.py b/src/comet/driver/photonic/f3000.py index 78eac6f..ce010ca 100644 --- a/src/comet/driver/photonic/f3000.py +++ b/src/comet/driver/photonic/f3000.py @@ -21,7 +21,7 @@ def brightness(self) -> int: return int(response.replace("B", "")) @brightness.setter - def brightness(self, brightness: int): + def brightness(self, brightness: int) -> None: """Set brightness of light source in percent Args: @@ -46,7 +46,7 @@ def light_enabled(self) -> bool: return int(response) == 0 @light_enabled.setter - def light_enabled(self, light_enabled: bool): + def light_enabled(self, light_enabled: bool) -> None: """Turn on / off shutter (light source) Args: @@ -59,7 +59,7 @@ def light_enabled(self, light_enabled: bool): self.resource.read() - def identify(self): + def identify(self) -> str: """Acquire identification string""" self.resource.write("V?") return self.resource.read() diff --git a/src/comet/driver/rohde_schwarz/__init__.py b/src/comet/driver/rohde_schwarz/__init__.py index c4520d1..3f25c0b 100644 --- a/src/comet/driver/rohde_schwarz/__init__.py +++ b/src/comet/driver/rohde_schwarz/__init__.py @@ -1,2 +1,4 @@ from .nge100 import NGE100 -from .sma100b import SMA100B \ No newline at end of file +from .sma100b import SMA100B + +__all__ = ["NGE100", "SMA100B"] diff --git a/src/comet/driver/rohde_schwarz/nge100.py b/src/comet/driver/rohde_schwarz/nge100.py index 59030da..a19e186 100644 --- a/src/comet/driver/rohde_schwarz/nge100.py +++ b/src/comet/driver/rohde_schwarz/nge100.py @@ -3,7 +3,6 @@ from comet.driver.generic import InstrumentError from comet.driver.generic.power_supply import PowerSupply, PowerSupplyChannel - __all__ = ["NGE100", "NGE100Channel"] @@ -13,13 +12,11 @@ class NGE100Channel(PowerSupplyChannel): @property def enabled(self) -> bool: value = int(self.query("OUTPut?")) - return {0: self.OUTPUT_OFF, 1: self.OUTPUT_ON}[value] @enabled.setter def enabled(self, state: bool) -> None: value = {self.OUTPUT_OFF: 0, self.OUTPUT_ON: 1}[state] - self.write(f"OUTPut {value}") @property @@ -32,7 +29,6 @@ def voltage_level(self, level: float) -> None: raise ValueError("Voltage level must be non-negative") if level > 32: raise ValueError("Voltage level must be less than 32 V") - self.write(f"SOURce:VOLTage:LEVel:IMMediate:AMPLitude {level}") @property @@ -45,7 +41,6 @@ def current_limit(self, level: float) -> None: raise ValueError("Current limit must be non-negative") if level > 3: raise ValueError("Current limit must be less than 3 A") - self.write(f"SOURce:CURRent:LEVel:IMMediate:AMPLitude {level}") def measure_voltage(self) -> float: @@ -71,6 +66,8 @@ def write(self, message: str) -> None: class NGE100(PowerSupply): """Rohde & Schwarz NGE100 power supply featuring multiple channels""" + N_CHANNELS: int = 3 + def identify(self) -> str: return self.query("*IDN?") @@ -94,17 +91,14 @@ def write(self, message: str) -> None: self.query("*OPC?") def __getitem__(self, channel: int) -> NGE100Channel: - if not isinstance(channel, int): raise TypeError("Channel index must be an integer") - - if channel not in range(3): + if channel not in range(type(self).N_CHANNELS): raise IndexError("Channel index out of range") - return NGE100Channel(self.resource, channel) def __iter__(self) -> Iterator[NGE100Channel]: return iter([NGE100Channel(self.resource, channel) for channel in range(3)]) def __len__(self) -> int: - return 3 + return type(self).N_CHANNELS diff --git a/src/comet/driver/rohde_schwarz/sma100b.py b/src/comet/driver/rohde_schwarz/sma100b.py index 254f128..ed01a62 100644 --- a/src/comet/driver/rohde_schwarz/sma100b.py +++ b/src/comet/driver/rohde_schwarz/sma100b.py @@ -71,7 +71,6 @@ def frequency(self, frequency: float) -> None: if frequency < 8e3 or frequency > 12.75e9: raise ValueError("Frequency must be in range 8 kHz to 12.75 GHz") - self.write(f"SOUR1:FREQuency:FIXed {frequency:.4f}") @property @@ -92,7 +91,6 @@ def output_power(self, power: float) -> None: """ if power < -145 or power > 40: raise ValueError("Power must be in range -145 dBm to 40 dBm") - self.write(f"SOUR1:POWer:POWer {power}") @property diff --git a/src/comet/driver/smc/__init__.py b/src/comet/driver/smc/__init__.py index bac80e8..fa8827e 100644 --- a/src/comet/driver/smc/__init__.py +++ b/src/comet/driver/smc/__init__.py @@ -1 +1,3 @@ -from .corvus import Corvus \ No newline at end of file +from .corvus import Corvus + +__all__ = ["Corvus"] diff --git a/src/comet/driver/smc/corvus.py b/src/comet/driver/smc/corvus.py index b61a2f8..d2f3508 100644 --- a/src/comet/driver/smc/corvus.py +++ b/src/comet/driver/smc/corvus.py @@ -1,11 +1,15 @@ -from typing import Dict, Optional +from typing import Optional from comet.driver.generic import InstrumentError -from comet.driver.generic.motion_controller import Position, MotionControllerAxis, MotionController +from comet.driver.generic.motion_controller import ( + Position, + MotionControllerAxis, + MotionController, +) __all__ = ["Corvus"] -ERROR_MESSAGES: Dict[int, str] = { +ERROR_MESSAGES: dict[int, str] = { 1: "internal error", 2: "internal error", 3: "internal error", @@ -32,6 +36,7 @@ def parse_error(response: str) -> Optional[InstrumentError]: class CorvusAxis(MotionControllerAxis): + """Axis for SMC Corvus motion controller.""" def calibrate(self) -> None: self.resource.write(f"{self.index:d} ncal") @@ -63,15 +68,14 @@ def is_moving(self) -> bool: class Corvus(MotionController): + """Driver for SMC Corvus motion controller.""" def identify(self) -> str: return self.resource.query("identify").strip() - def reset(self) -> None: - ... + def reset(self) -> None: ... - def clear(self) -> None: - ... + def clear(self) -> None: ... def next_error(self) -> Optional[InstrumentError]: response = self.resource.query("geterror") @@ -93,17 +97,17 @@ def is_calibrated(self) -> bool: return [int(value) for value in values].count(0x3) == len(values) def move_absolute(self, position: Position) -> None: - values = " ".join([format(value, '.3f') for value in position]) + values = " ".join([format(value, ".3f") for value in position]) self.resource.write(f"{values} move") def move_relative(self, position: Position) -> None: - values = " ".join([format(value, '.3f') for value in position]) + values = " ".join([format(value, ".3f") for value in position]) self.resource.write(f"{values} rmove") - def abort(self): + def abort(self) -> None: self.resource.write("abort") - def force_abort(self): + def force_abort(self) -> None: self.resource.write(chr(0x03)) # Ctrl+C @property diff --git a/src/comet/driver/thorlabs/__init__.py b/src/comet/driver/thorlabs/__init__.py index 9a1cd70..6d8f4a3 100644 --- a/src/comet/driver/thorlabs/__init__.py +++ b/src/comet/driver/thorlabs/__init__.py @@ -1 +1,3 @@ from .pm100 import PM100 + +__all__ = ["PM100"] diff --git a/src/comet/driver/thorlabs/pm100.py b/src/comet/driver/thorlabs/pm100.py index 4d97fb4..e7ece00 100644 --- a/src/comet/driver/thorlabs/pm100.py +++ b/src/comet/driver/thorlabs/pm100.py @@ -4,7 +4,7 @@ __all__ = ["PM100"] -def parse_error(response: str): +def parse_error(response: str) -> tuple[int, str]: code, message = [token.strip() for token in response.split(",")][:2] return int(code), message.strip('"') @@ -67,10 +67,8 @@ def wavelength(self, value: int) -> None: Args: wavelength (int): Wavelength in nm """ - if value > 1100 or value < 350: raise ValueError("Wavelength must be between 350 and 1100 nm") - self.write(f"SENSe:CORRection:WAVelength {value}") def measure_power(self) -> float: @@ -79,7 +77,6 @@ def measure_power(self) -> float: Returns: float: Power in W """ - return float(self.query("MEASure:POWer?").strip()) # Helpers diff --git a/src/comet/emulator/__init__.py b/src/comet/emulator/__init__.py index 6837540..91f90ad 100644 --- a/src/comet/emulator/__init__.py +++ b/src/comet/emulator/__init__.py @@ -1,2 +1,4 @@ from .emulator import Emulator, message, run from .iec60488 import IEC60488Emulator + +__all__ = ["Emulator", "message", "run", "IEC60488Emulator"] diff --git a/src/comet/emulator/__main__.py b/src/comet/emulator/__main__.py index 003db49..9ddf9ff 100644 --- a/src/comet/emulator/__main__.py +++ b/src/comet/emulator/__main__.py @@ -32,9 +32,7 @@ import logging import os import signal -import socketserver import threading -import time import schema import yaml @@ -42,26 +40,28 @@ from .emulator import emulator_factory from .tcpserver import TCPServer, TCPServerThread, TCPServerContext -default_config_filenames = ["emulators.yaml", "emulators.yml"] +default_config_filenames: list[str] = ["emulators.yaml", "emulators.yml"] default_hostname: str = "" default_termination: str = "\r\n" default_request_delay: float = 0.1 version_schema = schema.Regex(r"^\d+\.\d+$") -config_schema = schema.Schema({ - "version": version_schema, - "emulators": { - str: { - "module": str, - schema.Optional("hostname"): str, - "port": int, - schema.Optional("termination"): str, - schema.Optional("request_delay"): float, - schema.Optional("options"): dict, - } - }, -}) +config_schema = schema.Schema( + { + "version": version_schema, + "emulators": { + str: { + "module": str, + schema.Optional("hostname"): str, + "port": int, + schema.Optional("termination"): str, + schema.Optional("request_delay"): float, + schema.Optional("options"): dict, + } + }, + } +) def load_config(filename: str) -> dict: @@ -102,8 +102,10 @@ def locate_config_filename() -> str: def event_loop() -> None: """Blocks execution until termination or interrupt from keyboard signal.""" e = threading.Event() + def handle_event(signum, frame): e.set() + signal.signal(signal.SIGTERM, handle_event) signal.signal(signal.SIGINT, handle_event) e.wait() diff --git a/src/comet/emulator/cts/itc.py b/src/comet/emulator/cts/itc.py index 7566b82..a6a2e57 100644 --- a/src/comet/emulator/cts/itc.py +++ b/src/comet/emulator/cts/itc.py @@ -2,7 +2,6 @@ import datetime import random -import time from comet.emulator import Emulator from comet.emulator import message, run @@ -33,92 +32,92 @@ def __init__(self) -> None: self.program: int = 0 @message(r'^T$') - def get_t(self): + def get_t(self) -> str: return datetime.datetime.now().strftime("T%d%m%y%H%M%S") @message(r'^(t\d{6}\d{6})$') - def set_t(self, value): + def set_t(self, value) -> str: t = datetime.datetime.strptime(value, "t%d%m%y%H%M%S") return t.strftime("T%d%m%y%H%M%S") @message(r'^(A0)$') - def get_a0(self, channel): + def get_a0(self, channel) -> str: self.current_temp += random.uniform(-.25, +.25) self.current_temp = min(60., max(20., self.current_temp)) return f"{channel} {self.current_temp:05.1f} {self.target_temp:05.1f}" @message(r'^(A[34])$') - def get_a3(self, channel): + def get_a3(self, channel) -> str: return fake_analog_channel(channel, -45., +185.) @message(r'^(A1)$') - def get_a1(self, channel): + def get_a1(self, channel) -> str: self.current_humid += random.uniform(-.25, +.25) self.current_humid = min(95., max(15., self.current_humid)) return f"{channel} {self.current_humid:05.1f} {self.target_humid:05.1f}" @message(r'^(A2)$') - def get_a2(self, channel): + def get_a2(self, channel) -> str: return fake_analog_channel(channel, +0., +15.) @message(r'^(A[56])$') - def get_a5(self, channel): + def get_a5(self, channel) -> str: return fake_analog_channel(channel, +5., +98.) @message(r'^(A7)$') - def get_a7(self, channel): + def get_a7(self, channel) -> str: return fake_analog_channel(channel, -50., +150.) @message(r'^(A8)$') - def get_a8(self, channel): + def get_a8(self, channel) -> str: return fake_analog_channel(channel, -80., +190.) @message(r'^(A9)$') - def get_a9(self, channel): + def get_a9(self, channel) -> str: return fake_analog_channel(channel, -0., +25.) @message(r'^(A\:)$') - def get_a10(self, channel): + def get_a10(self, channel) -> str: return fake_analog_channel(channel, -50., +100.) @message(r'^(A\;)$') - def get_a11(self, channel): + def get_a11(self, channel) -> str: return fake_analog_channel(channel, -0., +25.) @message(r'^(A\<)$') - def get_a12(self, channel): + def get_a12(self, channel) -> str: return fake_analog_channel(channel, +2., +5.) @message(r'^(A[\=\>])$') - def get_a13(self, channel): + def get_a13(self, channel) -> str: return fake_analog_channel(channel, -100., +200.) @message(r'^(A\?)$') - def get_a14(self, channel): + def get_a14(self, channel) -> str: return fake_analog_channel(channel, -80., +200.) @message(r'^a[1-7]\s(-?\d+.\d)$') - def set_a15(self, value): + def set_a15(self, value) -> str: return "a" @message(r'^a[0-6]\s+\d+\.\d+$') - def set_a(self): + def set_a(self) -> str: return "a" @message(r'^O$') - def get_o(self): + def get_o(self) -> str: return "O1000000000000" @message(r'^S$') - def get_s(self): + def get_s(self) -> str: return "S11110100\x06" @message(r'^P$') - def get_p(self): + def get_p(self) -> str: return f"P{self.program:03d}" @message(r'^P(\d{3})$') - def set_p(self, program): + def set_p(self, program) -> str: self.program = int(program) return f"P{self.program:03d}" diff --git a/src/comet/emulator/emulator.py b/src/comet/emulator/emulator.py index f0ab402..235a877 100644 --- a/src/comet/emulator/emulator.py +++ b/src/comet/emulator/emulator.py @@ -4,8 +4,7 @@ import logging import re import signal -import threading -from typing import Any, Callable, Dict, List, Optional, Tuple, Type, Union +from typing import Any, Callable, Type, Union from .tcpserver import TCPServer, TCPServerThread, TCPServerContext @@ -13,7 +12,7 @@ logger = logging.getLogger(__name__) -emulator_registry: Dict[str, Type] = {} +emulator_registry: dict[str, Type] = {} def emulator_factory(module_name: str) -> Type: @@ -60,7 +59,7 @@ def __call__(self, *args, **kwargs) -> Any: return self.method(*args, **kwargs) -def get_routes(cls: type) -> List[Route]: +def get_routes(cls: type) -> list[Route]: """Return sorted list of routes defined by method decorator.""" routes = [] for cls_ in cls.__mro__: @@ -74,9 +73,8 @@ def get_routes(cls: type) -> List[Route]: class Emulator: - def __init__(self) -> None: - self.options: Dict[str, Any] = {} + self.options: dict[str, Any] = {} def __call__(self, message: str) -> Union[None, str, list]: logging.debug("handle message: %s", message) @@ -97,7 +95,7 @@ def __call__(self, message: str) -> Union[None, str, list]: return None -def option_type(value: str) -> Tuple[str, str]: +def option_type(value: str) -> tuple[str, str]: m = re.match(r"^([\w_][\w\d_]*)=(.*)$", value) if m: return m.group(1), m.group(2) @@ -106,11 +104,33 @@ def option_type(value: str) -> Tuple[str, str]: def parse_args() -> argparse.Namespace: parser = argparse.ArgumentParser() - parser.add_argument("--hostname", default="", help="hostname, default is 'localhost'") - parser.add_argument("-p", "--port", type=int, default=10000, help="port, default is 10000") - parser.add_argument("-t", "--termination", default="\r\n", help="message termination, default is '\\r\\n'") - parser.add_argument("-d", "--request-delay", type=float, default=0.1, help="delay between requests in seconds, default is 0.1 sec") - parser.add_argument("-o", "--option", type=option_type, action="append", default=[], help="set emulator specific option(s), e.g. '-o version=2.1'") + parser.add_argument( + "--hostname", default="", help="hostname, default is 'localhost'" + ) + parser.add_argument( + "-p", "--port", type=int, default=10000, help="port, default is 10000" + ) + parser.add_argument( + "-t", + "--termination", + default="\r\n", + help="message termination, default is '\\r\\n'", + ) + parser.add_argument( + "-d", + "--request-delay", + type=float, + default=0.1, + help="delay between requests in seconds, default is 0.1 sec", + ) + parser.add_argument( + "-o", + "--option", + type=option_type, + action="append", + default=[], + help="set emulator specific option(s), e.g. '-o version=2.1'", + ) return parser.parse_args() @@ -150,4 +170,4 @@ def handle_event(signum, frame): thread.join() - return 0 + return 0 # TODO diff --git a/src/comet/emulator/hephy/brandbox.py b/src/comet/emulator/hephy/brandbox.py index d13e885..6820440 100644 --- a/src/comet/emulator/hephy/brandbox.py +++ b/src/comet/emulator/hephy/brandbox.py @@ -1,16 +1,14 @@ -from typing import Set - from comet.emulator import Emulator from comet.emulator import message, run __all__ = ["BrandBoxEmulator"] -def split_channels(channels: str) -> set: - return {channel.strip() for channel in channels.split(",") if channel.strip()} +def split_channels(channels: str) -> list[str]: + return list({channel.strip() for channel in channels.split(",") if channel.strip()}) -def join_channels(channels: set) -> str: +def join_channels(channels: list[str]) -> str: return ",".join([format(channel) for channel in channels]) @@ -24,8 +22,8 @@ def format_error(code: int) -> str: class BrandBoxEmulator(Emulator): - CHANNELS = ["A1", "A2", "B1", "B2", "C1", "C2"] - MODS = ["IV", "CV"] + CHANNELS: list[str] = ["A1", "A2", "B1", "B2", "C1", "C2"] + MODS: list[str] = ["IV", "CV"] IDENTITY: str = "BrandBox, v2.0 (Emulator)" SUCCESS: str = "OK" @@ -33,43 +31,43 @@ class BrandBoxEmulator(Emulator): def __init__(self) -> None: super().__init__() - self.closed_channels: Set[str] = set() + self.closed_channels: set[str] = set() self.test_state: bool = False self.mod: str = "N/A" @property - def opened_channels(self): + def opened_channels(self) -> set[str]: return set(self.CHANNELS) - self.closed_channels @message(r'\*IDN\?') - def get_idn(self): + def get_idn(self) -> str: return self.options.get("identity", self.IDENTITY) @message(r'\*RST') - def set_rst(self): + def set_rst(self) -> str: return self.SUCCESS @message(r'\*CLS') - def set_cls(self): + def set_cls(self) -> str: return self.SUCCESS @message(r'\*STB\?') - def get_stb(self): + def get_stb(self) -> str: states = [] for channel in self.CHANNELS: states.append("1" if channel in self.closed_channels else "0") return ",".join(states) @message(r'\*STR\?') - def get_str(self): - return 0 + def get_str(self) -> str: + return "0" @message(r'\*OPC\?') - def get_opc(self): - return 1 + def get_opc(self) -> str: + return "1" @message(r':CLOS (.+)') - def set_close(self, channels): + def set_close(self, channels) -> str: for channel in split_channels(channels): if self.has_channel(channel): self.closed_channels.add(channel) @@ -78,7 +76,7 @@ def set_close(self, channels): return self.SUCCESS @message(r':OPEN (.+)') - def set_open(self, channels): + def set_open(self, channels) -> str: for channel in split_channels(channels): if self.has_channel(channel): if channel in self.closed_channels: @@ -88,19 +86,19 @@ def set_open(self, channels): return self.SUCCESS @message(r':CLOS:STAT\?') - def get_close_state(self): + def get_close_state(self) -> str: return join_channels(sorted(self.closed_channels)) @message(r':OPEN:STAT\?') - def get_open_state(self): + def get_open_state(self) -> str: return join_channels(sorted(self.opened_channels)) @message(r':DEBUG?') - def get_debug(self): + def get_debug(self) -> str: return self.COMMAND_ERROR @message(r'SET:A_(ON|OFF)') - def set_a(self, state): + def set_a(self, state) -> str: for channel in ("A1", "A2"): if state == "ON": self.closed_channels.add(channel) @@ -110,7 +108,7 @@ def set_a(self, state): return self.SUCCESS @message(r'SET:B_(ON|OFF)') - def set_b(self, state): + def set_b(self, state) -> str: for channel in ("B1", "B2"): if state == "ON": self.closed_channels.add(channel) @@ -120,7 +118,7 @@ def set_b(self, state): return self.SUCCESS @message(r'SET:C_(ON|OFF)') - def set_c(self, state): + def set_c(self, state) -> str: for channel in ("C1", "C2"): if state == "ON": self.closed_channels.add(channel) @@ -130,7 +128,7 @@ def set_c(self, state): return self.SUCCESS @message(r'SET:(A1|A2|B1|B2|C1|C2)_(ON|OFF)') - def set_abc(self, channel, state): + def set_abc(self, channel, state) -> str: if state == "ON": self.closed_channels.add(channel) else: @@ -139,55 +137,55 @@ def set_abc(self, channel, state): return self.SUCCESS @message(r'SET:MOD (IV|CV)') - def set_mod(self, mod): + def set_mod(self, mod) -> str: if mod not in self.MODS: return self.COMMAND_ERROR self.mod = mod return self.SUCCESS @message(r'GET:A \?') - def get_a(self): + def get_a(self) -> str: states = [] for channel in ("A1", "A2"): states.append(format_state(channel in self.closed_channels)) return ",".join(states) @message(r'GET:B \?') - def get_b(self): + def get_b(self) -> str: states = [] for channel in ("B1", "B2"): states.append(format_state(channel in self.closed_channels)) return ",".join(states) @message(r'GET:C \?') - def get_c(self): + def get_c(self) -> str: states = [] for channel in ("C1", "C2"): states.append(format_state(channel in self.closed_channels)) return ",".join(states) @message(r'GET:(A1|A2|B1|B2|C1|C2) \?') - def get_abc(self, channel): + def get_abc(self, channel) -> str: return format_state(channel in self.closed_channels) @message(r'GET:MOD \?') - def get_mod(self): + def get_mod(self) -> str: return format(self.mod) @message(r'GET:TST \?') - def get_test(self): + def get_test(self) -> str: return {False: "OFF", True: "ON"}[self.test_state] @message(r'SET:TST (ON|OFF)') - def set_test(self, value): + def set_test(self, value) -> str: self.test_state = value == "ON" return self.SUCCESS @message(r'.*') - def unknown_message(self): + def unknown_message(self) -> str: return self.COMMAND_ERROR - def has_channel(self, channel): + def has_channel(self, channel) -> bool: return channel in self.CHANNELS diff --git a/src/comet/emulator/hephy/environbox.py b/src/comet/emulator/hephy/environbox.py index 81c4005..9bebf77 100644 --- a/src/comet/emulator/hephy/environbox.py +++ b/src/comet/emulator/hephy/environbox.py @@ -1,6 +1,5 @@ import random import time -from typing import Dict, List, Tuple from comet.emulator import Emulator from comet.emulator import message, run @@ -13,7 +12,7 @@ def format_error(code: int) -> str: return f"Err{abs(code):d}" -def split_seconds(delta_seconds: float) -> Tuple[int, int, int, int]: +def split_seconds(delta_seconds: float) -> tuple[int, int, int, int]: days, remainder = divmod(delta_seconds, 60 * 60 * 24) hours, remainder = divmod(remainder, 60 * 60) minutes, seconds = divmod(remainder, 60) @@ -26,13 +25,13 @@ class EnvironBoxEmulator(Emulator): VERSION: str = "V2.0" SUCCESS: str = "OK" PC_DATA_SIZE: int = 39 - SENSOR_ADRESSES: List[int] = [40, 41, 42, 43, 44, 45] + SENSOR_ADRESSES: list[int] = [40, 41, 42, 43, 44, 45] def __init__(self) -> None: super().__init__() self.boot_timestamp: float = time.time() - self.sensor_address: List[int] = [40, 41, 42] + self.sensor_address: list[int] = [40, 41, 42] self.free_memory: int = 1081 self.debug_mode: bool = False self.discharge: str = "OFF" @@ -57,7 +56,7 @@ def __init__(self) -> None: self.pt100_2_enabled: bool = False self.pid_control: bool = False self.pid_control_mode: str = "HUM" - self.pid_setpoints: Dict[str, float] = {"HUM": 30., "DEW": 30.} + self.pid_setpoints: dict[str, float] = {"HUM": 30.0, "DEW": 30.0} self.pid_kp: float = 0.25 self.pid_ki: float = 0.01 self.pid_kd: float = 1.23 @@ -161,8 +160,8 @@ def power_relay_states(self) -> int: power_relay_states |= 1 << 6 return power_relay_states - def create_pc_data(self) -> List[str]: - pc_data: List[str] = ["0"] * type(self).PC_DATA_SIZE + def create_pc_data(self) -> list[str]: + pc_data: list[str] = ["0"] * type(self).PC_DATA_SIZE pc_data[0] = format(self.sensor_count, "d") pc_data[1] = format(self.box_humidity, ".1F") pc_data[2] = format(self.box_temperature, ".1F") @@ -205,11 +204,11 @@ def create_pc_data(self) -> List[str]: return pc_data @message(r"\*IDN\?") - def get_idn(self): + def get_idn(self) -> str: return self.options.get("identity", self.IDENTITY) @message(r"SET:NEW_ADDR (\d+)") - def set_new_addr(self, address): + def set_new_addr(self, address) -> str: value = int(address) if value not in type(self).SENSOR_ADRESSES: return format_error(14) @@ -226,12 +225,12 @@ def get_test_led(self) -> str: return {True: "1", False: "0"}[self.test_led] @message(r"SET:DISCHARGE (AUTO|ON|OFF)") - def set_discharge(self, state): + def set_discharge(self, state) -> str: self.discharge = state return self.SUCCESS @message(r"SET:DISCHARGE_TIME (\d+)") - def set_discharge_time(self, seconds): + def set_discharge_time(self, seconds) -> str: seconds = int(seconds) if 0 <= seconds <= 9999: self.discharge_time = seconds @@ -239,43 +238,43 @@ def set_discharge_time(self, seconds): return format_error(44) @message(r"GET:DISCHARGE_TIME \?") - def get_discharge_time(self): + def get_discharge_time(self) -> str: return format(self.discharge_time) @message(r"SET:PT100_1 (ON|OFF)") - def set_pt100_1(self, value): + def set_pt100_1(self, value) -> str: self.pt100_1_enabled = value == "ON" return self.SUCCESS @message(r"GET:PT100_1 \?") - def get_pt100_1(self): + def get_pt100_1(self) -> str: return format(self.pt100_1, ".2F") @message(r"SET:PT100_2 (ON|OFF)") - def set_pt100_2(self, value): + def set_pt100_2(self, value) -> str: self.pt100_2_enabled = value == "ON" return self.SUCCESS @message(r"GET:PT100_2 \?") - def get_pt100_2(self): + def get_pt100_2(self) -> str: return format(self.pt100_2, ".2F") @message(r"SET:CTRL (ON|OFF)") - def set_ctrl(self, value): + def set_ctrl(self, value) -> str: self.pid_control = value == "ON" return self.SUCCESS @message(r"GET:CTRL \?") - def get_ctrl(self): + def get_ctrl(self) -> str: return format(self.pid_control, "d") @message(r"SET:CTRL_MODE (HUM|DEW)") - def set_ctrl_mode(self, mode): + def set_ctrl_mode(self, mode) -> str: self.pid_control_mode = mode return self.SUCCESS @message(r"SET:SETPOINT (.+)") - def set_setpoint(self, setpoint): + def set_setpoint(self, setpoint) -> str: try: self.pid_setpoint = float(setpoint) except Exception: @@ -283,11 +282,11 @@ def set_setpoint(self, setpoint): return self.SUCCESS @message(r"GET:SETPOINT \?") - def get_setpoint(self): + def get_setpoint(self) -> str: return format(self.pid_setpoint, ".2F") @message(r"SET:PID_KP (.+)") - def set_pid_kp(self, value): + def set_pid_kp(self, value) -> str: try: self.pid_kp = float(value) except Exception: @@ -295,11 +294,11 @@ def set_pid_kp(self, value): return self.SUCCESS @message(r"GET:PID_KP \?") - def get_pid_kp(self): + def get_pid_kp(self) -> str: return format(self.pid_kp, ".2F") @message(r"SET:PID_KI (.+)") - def set_pid_ki(self, value): + def set_pid_ki(self, value) -> str: try: self.pid_ki = float(value) except Exception: @@ -307,11 +306,11 @@ def set_pid_ki(self, value): return self.SUCCESS @message(r"GET:PID_KI \?") - def get_pid_ki(self): + def get_pid_ki(self) -> str: return format(self.pid_ki, ".2F") @message(r"SET:PID_KD (.+)") - def set_pid_kd(self, value): + def set_pid_kd(self, value) -> str: try: self.pid_kd = float(value) except Exception: @@ -319,11 +318,11 @@ def set_pid_kd(self, value): return self.SUCCESS @message(r"GET:PID_KD \?") - def get_pid_kd(self): + def get_pid_kd(self) -> str: return format(self.pid_kd, ".2F") @message(r"SET:PID_KP2 (.+)") - def set_pid_kp2(self, value): + def set_pid_kp2(self, value) -> str: try: self.pid_kp2 = float(value) except Exception: @@ -331,11 +330,11 @@ def set_pid_kp2(self, value): return self.SUCCESS @message(r"GET:PID_KP2 \?") - def get_pid_kp2(self): + def get_pid_kp2(self) -> str: return format(self.pid_kp2, ".2F") @message(r"SET:PID_KI2 (.+)") - def set_pid_ki2(self, value): + def set_pid_ki2(self, value) -> str: try: self.pid_ki2 = float(value) except Exception: @@ -343,11 +342,11 @@ def set_pid_ki2(self, value): return self.SUCCESS @message(r"GET:PID_KI2 \?") - def get_pid_ki2(self): + def get_pid_ki2(self) -> str: return format(self.pid_ki2, ".2F") @message(r"SET:PID_KD2 (.+)") - def set_pid_kd2(self, value): + def set_pid_kd2(self, value) -> str: try: self.pid_kd2 = float(value) except Exception: @@ -355,65 +354,65 @@ def set_pid_kd2(self, value): return self.SUCCESS @message(r"GET:PID_KD2 (.+)") - def get_pid_kd2(self): + def get_pid_kd2(self) -> str: return format(self.pid_kd2, ".2F") @message(r"SET:PID_MIN (\d+)") - def set_pid_min(self, value): + def set_pid_min(self, value) -> str: self.pid_min = int(value) return self.SUCCESS @message(r"GET:PID_MIN \?") - def get_pid_min(self): + def get_pid_min(self) -> str: return format(self.pid_min, "d") @message(r"SET:PID_MAX (\d+)") - def set_pid_max(self, value): + def set_pid_max(self, value) -> str: self.pid_max = int(value) return self.SUCCESS @message(r"GET:PID_MAX \?") - def get_pid_max(self): + def get_pid_max(self) -> str: return format(self.pid_max, "d") @message(r"SET:PID_SAMPLE_TIME (\d+)") - def set_pid_sample_time(self, value): + def set_pid_sample_time(self, value) -> str: self.pid_sample_time = int(value) return self.SUCCESS @message(r"GET:PID_SAMPLE_TIME \?") - def get_pid_sample_time(self): + def get_pid_sample_time(self) -> str: return format(self.pid_sample_time, "d") @message(r"SET:PID_PROP_MODE (M|E)") - def set_pid_prop_mode(self, mode): + def set_pid_prop_mode(self, mode) -> str: self.pid_prop_mode = mode return self.SUCCESS @message(r"GET:PID_PROP_MODE \?") - def get_pid_prop_mode(self): - return self.pid_prop_mode_index + def get_pid_prop_mode(self) -> str: + return format(self.pid_prop_mode_index, "d") @message(r"SET:PID_THRESHOLD (\d+)") - def set_pid_threshold(self, value): + def set_pid_threshold(self, value) -> str: self.pid_threshold = int(value) return self.SUCCESS @message(r"GET:PID_THRESHOLD \?") - def get_pid_threshold(self): + def get_pid_threshold(self) -> str: return format(self.pid_threshold, "d") @message(r"SET:PARAMETER_SET (1|2)") - def set_parameter_set(self, value): + def set_parameter_set(self, value) -> str: self.parameter_set = int(value) return self.SUCCESS @message(r"GET:PARAMETER_SET \?") - def get_parameter_set(self): + def get_parameter_set(self) -> str: return format(self.parameter_set, "d") @message(r"SET:PARA_THRESHOLD (.+)") - def set_parameter_threshold(self, value): + def set_parameter_threshold(self, value) -> str: try: self.parameter_threshold = float(value) except Exception: @@ -421,164 +420,164 @@ def set_parameter_threshold(self, value): return self.SUCCESS @message(r"GET:PARA_THRESHOLD \?") - def get_parameter_threshold(self): + def get_parameter_threshold(self) -> str: return format(self.parameter_threshold, ".2F") @message(r"SET:DAC (\d+)") - def set_dac(self, value): + def set_dac(self, value) -> str: self.dac = int(value) return self.SUCCESS @message(r"SET:MICROSCOPE_CTRL (ON|OFF)") - def set_microscope_control(self, value): + def set_microscope_control(self, value) -> str: self.microscope_control = value == "ON" return self.SUCCESS @message(r"GET:MICROSCOPE_CTRL \?") - def get_microscope_control(self): + def get_microscope_control(self) -> str: return format(int(self.microscope_control)) @message(r"SET:MICROSCOPE_LIGHT (ON|OFF)") - def set_microscope_light(self, value): + def set_microscope_light(self, value) -> str: self.microscope_light = value == "ON" return self.SUCCESS @message(r"GET:MICROSCOPE_LIGHT \?") - def get_microscope_light(self): + def get_microscope_light(self) -> str: return format(int(self.microscope_light)) @message(r"SET:MICROSCOPE_CAM (ON|OFF)") - def set_microscope_camera(self, value): + def set_microscope_camera(self, value) -> str: self.microscope_camera = value == "ON" return self.SUCCESS @message(r"GET:MICROSCOPE_CAM \?") - def get_microscope_camera(self): + def get_microscope_camera(self) -> str: return format(int(self.microscope_camera)) @message(r"SET:PROBCARD_LIGHT (ON|OFF)") - def set_probecard_light(self, value): + def set_probecard_light(self, value) -> str: self.probecard_light = value == "ON" return self.SUCCESS @message(r"GET:PROBCARD_LIGHT \?") - def get_probecard_light(self): + def get_probecard_light(self) -> str: return format(int(self.probecard_light)) @message(r"SET:PROBCARD_CAM (ON|OFF)") - def set_probecard_camera(self, value): + def set_probecard_camera(self, value) -> str: self.probecard_camera = value == "ON" return self.SUCCESS @message(r"GET:PROBCARD_CAM \?") - def get_probecard_camera(self): + def get_probecard_camera(self) -> str: return format(self.probecard_camera, "d") @message(r"SET:LASER_SENSOR (ON|OFF)") - def set_laser_sensor(self, value): + def set_laser_sensor(self, value) -> str: self.laser_sensor = value == "ON" return self.SUCCESS @message(r"SET:BOX_LIGHT (ON|OFF)") - def set_box_light(self, value): + def set_box_light(self, value) -> str: self.box_light = value == "ON" return self.SUCCESS @message(r"GET:LIGHT \?") - def get_box_light(self): + def get_box_light(self) -> str: return format(self.box_light, "d") @message(r'SET:ENV_II_PCB (YES|NO)') - def set_env_ii_pcb(self, value): + def set_env_ii_pcb(self, value) -> str: self.env_ii_pcb = value == "YES" return self.SUCCESS @message(r"SET:PID_DOOR_STOP (ON|OFF)") - def set_pid_door_stop(self, value): + def set_pid_door_stop(self, value) -> str: self.pid_door_stop = value == "ON" return self.SUCCESS @message(r"GET:PID_DOOR_STOP \?") - def get_pid_door_stop(self): + def get_pid_door_stop(self) -> str: return format(int(self.pid_door_stop) + 1, "d") # [1=OFF,2=ON] @message(r"SET:DOOR_AUTO_LIGHT (ON|OFF)") - def set_door_auto_light(self, value): + def set_door_auto_light(self, value) -> str: self.door_auto_light = value == "ON" return self.SUCCESS @message(r"GET:DOOR_AUTO_LIGHT \?") - def get_door_auto_light(self): + def get_door_auto_light(self) -> str: return format(int(self.door_auto_light) + 1, "d") # [1=OFF,2=ON] @message(r'SET:DEBUG_MODE (ON|OFF)\?') - def set_debug_mode(self, value): + def set_debug_mode(self, value) -> None: self.debug_mode = value == "ON" @message(r'GET:DEBUG_MODE \?') - def get_debug_mode(self): + def get_debug_mode(self) -> str: return format(int(self.debug_mode) + 1, "d") # [1=Off/2=On] @message(r'GET:FREE_MEMORY \?') - def get_free_memory(self): + def get_free_memory(self) -> str: return format(self.free_memory, "d") @message(r'GET:UPTIME \?') - def get_uptime(self): + def get_uptime(self) -> str: delta_seconds = time.time() - self.boot_timestamp days, hours, minutes, seconds = split_seconds(delta_seconds) return f"{days:02d},{hours:02d},{minutes:02d},{seconds:02d}" @message(r'GET:CHIP_ADDR (1|2|3)') - def get_chip_addr(self, value): + def get_chip_addr(self, value) -> str: return format(self.sensor_address[int(value) - 1], "d") @message(r'GET:CHIP_NBR \?') - def get_chip_nbr(self): + def get_chip_nbr(self) -> str: return format(self.sensor_count, "d") @message(r"GET:TEMP \?") - def get_temp(self): + def get_temp(self) -> str: return format(self.box_temperature, ".2F") @message(r"GET:HUM \?") - def get_hum(self): + def get_hum(self) -> str: return format(self.box_humidity, ".2F") @message(r"GET:LUX \?") - def get_lux(self): + def get_lux(self) -> str: return format(self.box_lux, ".1F") @message(r"GET:FLOW_RATE \?") - def get_flow_rate(self): + def get_flow_rate(self) -> str: return format(self.flow_rate, ".1F") @message(r"GET:VALVE_ON \?") - def get_valve_on(self): + def get_valve_on(self) -> str: return format(self.valve_on, "d") @message(r"GET:DOOR \?") - def get_door(self): + def get_door(self) -> str: return format(int(self.door_open)) @message(r"GET:LASER \?") - def get_laser(self): + def get_laser(self) -> str: return format(int(self.laser_enabled)) @message(r"GET:LASER_POWER \?") - def get_laser_power(self): + def get_laser_power(self) -> str: return format(self.laser_power, "d") @message(r"GET:PC_DATA \?") - def get_pc_data(self): + def get_pc_data(self) -> str: return ",".join(map(format, self.create_pc_data())) @message(r"GET:RELAY_STATUS \?") - def get_relay_status(self): + def get_relay_status(self) -> str: return format(self.power_relay_states()) @message(r"GET:ENV \?") - def get_env(self): + def get_env(self) -> str: values = [ format(self.box_temperature, ".1F"), format(self.box_humidity, ".1F"), @@ -588,11 +587,11 @@ def get_env(self): return ",".join(values) @message(r"GET:VERSION \?") - def get_version(self): + def get_version(self) -> str: return self.options.get("version", self.VERSION) @message(r".*") - def unknown_message(self): + def unknown_message(self) -> str: return format_error(999) diff --git a/src/comet/emulator/hephy/shuntbox.py b/src/comet/emulator/hephy/shuntbox.py index 7bcd574..1d66bee 100644 --- a/src/comet/emulator/hephy/shuntbox.py +++ b/src/comet/emulator/hephy/shuntbox.py @@ -29,42 +29,42 @@ def uptime(self) -> int: return int(round(time.time() - self.start_time)) @message(r'\*IDN\?') - def get_idn(self): + def get_idn(self) -> str: return self.options.get("identity", self.IDENTITY) @message(r'GET:UP \?') - def get_up(self): + def get_up(self) -> str: return format(self.uptime) @message(r'GET:RAM \?') - def get_ram(self): + def get_ram(self) -> str: return format(self.MEMORY_BYTES) @message(r'GET:TEMP ALL') - def get_temp_all(self): + def get_temp_all(self) -> str: values = [] for i in range(self.CHANNELS): values.append(format(random.uniform(22.0, 26.0), ".1f")) return ",".join(values) @message(r'GET:TEMP (\d+)') - def get_temp(self, value): + def get_temp(self, value) -> str: return format(random.uniform(22.0, 26.0), ".1f") @message(r'SET:REL_(ON|OFF) (\d+|ALL)') - def set_rel(self, state, value): + def set_rel(self, state, value) -> str: return self.SUCCESS @message(r'GET:REL (\d+)') - def get_rel(self, value): + def get_rel(self, value) -> str: return "0" @message(r'GET:REL ALL') - def get_rel_all(self): + def get_rel_all(self) -> str: return ",".join(["0"] * (self.CHANNELS + 4)) @message(r'.*') - def unknown_message(self): + def unknown_message(self) -> str: return format_error(99) diff --git a/src/comet/emulator/iec60488.py b/src/comet/emulator/iec60488.py index c4a17fa..affc45e 100644 --- a/src/comet/emulator/iec60488.py +++ b/src/comet/emulator/iec60488.py @@ -7,7 +7,6 @@ class IEC60488Emulator(Emulator): - IDENTITY: str = "Generic IEC60488 Instrument (Emulator)" @message(r"\*IDN\?") @@ -23,8 +22,7 @@ def get_ese(self): return 0 @message(r"\*ESE (\d+)") - def set_ese(self, value): - ... + def set_ese(self, value): ... @message(r"\*STB\?") def get_stb(self): @@ -35,21 +33,17 @@ def get_opc(self): return 1 @message(r"\*OPC") - def set_opc(self): - ... + def set_opc(self): ... @message(r"\*RST") - def set_rst(self): - ... + def set_rst(self): ... @message(r"\*CLS") - def set_cls(self): - ... + def set_cls(self): ... @message(r"\*TST?") def get_tst(self): return 0 @message(r"\*WAI") - def set_wai(self): - ... + def set_wai(self): ... diff --git a/src/comet/emulator/itk/corvustt.py b/src/comet/emulator/itk/corvustt.py index d65ad37..7439cf3 100644 --- a/src/comet/emulator/itk/corvustt.py +++ b/src/comet/emulator/itk/corvustt.py @@ -2,7 +2,7 @@ import random import time -from typing import List +from typing import Optional from comet.emulator import Emulator, message, run @@ -30,8 +30,8 @@ def __init__(self) -> None: self.table_limits = [0.0, 0.0, 0.0, 1000000.0, 100000.0, 25000.0] - self.getcaldone: List[int] = [3, 3, 3] - self.getaxis: List[int] = [1, 1, 1] + self.getcaldone: list[int] = [3, 3, 3] + self.getaxis: list[int] = [1, 1, 1] self.geterror: int = 0 self.getmerror: int = 0 @@ -42,119 +42,120 @@ def __init__(self) -> None: self.ticks_t0: float = time.monotonic() @message(r'^identify$') - def get_identify(self): + def get_identify(self) -> str: return self.options.get("identity", self.IDENTITY) @message(r'^version$') - def get_version(self): + def get_version(self) -> str: return self.options.get("version", self.VERSION) @message(r'^getmacadr$') - def get_macadr(self): + def get_macadr(self) -> str: return self.options.get("macaddr", self.MAC_ADDR) @message(r'^getserialno$') - def get_serialno(self): + def get_serialno(self) -> str: return self.options.get("serialno", self.SERIAL_NO) @message(r'^getoptions$') - def get_options(self): + def get_options(self) -> int: return 0x3 @message(r'^getticks|gt$') - def get_ticks(self): + def get_ticks(self) -> str: dt = time.monotonic() - self.ticks_t0 ticks = int(dt * (1 / 250e-6)) # 250us ticks return f"{ticks:d}" @message(r'^(\d)\s+beep$') - def set_beep(self, millisec): - ... + def set_beep(self, millisec) -> None: ... @message(r'^reset$') - def set_reset(self): + def set_reset(self) -> None: self.getcaldone = [0, 0, 0] self.status = 0 @message(r'^status|st$') - def get_status(self): + def get_status(self) -> str: return f"{self.status:d}" @message(r'^pos|p$') - def get_pos(self): + def get_pos(self) -> str: return f'{self.x_pos:.6f} {self.y_pos:.6f} {self.z_pos:.6f}' @message(r'^(.+)\s+setlimit$') - def set_limit(self, value): + def set_limit(self, value) -> None: a1, b1, c1, a2, b2, c2 = map(float, value.split()) - self.table_limits = a1, b1, c1, a2, b2, c2 + self.table_limits = [a1, b1, c1, a2, b2, c2] @message(r'^getlimit$') - def get_limit(self): + def get_limit(self) -> tuple[str, str, str]: a1, b1, c1, a2, b2, c2 = self.table_limits return f"{a1:.6f} {b1:.6f}", f"{c1:.6f} {a2:.6f}", f"{b2:.6f} {c2:.6f}" @message(r'^([+-]?\d+(?:\.\d+)?)\s+([+-]?\d+(?:\.\d+)?)\s+([+-]?\d+(?:\.\d+)?)\s+(?:move|m)$') - def set_move(self, x, y, z): + def set_move(self, x, y, z) -> None: self.x_pos = max(0.0, float(x)) self.y_pos = max(0.0, float(y)) self.z_pos = max(0.0, float(z)) @message(r'^([+-]?\d+(?:\.\d+)?)\s+([+-]?\d+(?:\.\d+)?)\s+([+-]?\d+(?:\.\d+)?)\s+(?:rmove|r)$') - def set_rmove(self, x, y, z): + def set_rmove(self, x, y, z) -> None: self.x_pos = max(0.0, self.x_pos + float(x)) self.y_pos = max(0.0, self.y_pos + float(y)) self.z_pos = max(0.0, self.z_pos + float(z)) @message(r'^randmove$') - def set_randmove(self): + def set_randmove(self) -> None: a1, b1, c1, a2, b2, c2 = self.table_limits self.x_pos = random.uniform(a1, a2) self.y_pos = random.uniform(b1, b2) self.z_pos = random.uniform(c1, c2) @message(r'^(-1|1|2|3)\s+getcaldone$') - def get_caldone(self, axis): + def get_caldone(self, axis) -> Optional[str]: if axis == "-1": a1, a2, a3 = self.getcaldone return f"{a1} {a2} {a3}" if axis == "1": - return self.getcaldone[0] + return f"{self.getcaldone[0]}" if axis == "2": - return self.getcaldone[0] + return f"{self.getcaldone[0]}" if axis == "3": - return self.getcaldone[0] + return f"{self.getcaldone[0]}" + return None @message(r'^(-1|1|2|3)\s+getaxis$') - def get_axis(self, axis): + def get_axis(self, axis) -> Optional[str]: if axis == "-1": a1, a2, a3 = self.getaxis return f"{a1} {a2} {a3}" if axis == "1": - return self.getaxis[0] + return f"{self.getaxis[0]}" if axis == "2": - return self.getaxis[1] + return f"{self.getaxis[1]}" if axis == "3": - return self.getaxis[2] + return f"{self.getaxis[2]}" + return None @message(r'^geterror|ge$') - def get_error(self): + def get_error(self) -> int: return self.geterror @message(r'^getmerror|gme$') - def get_merror(self): + def get_merror(self) -> int: return self.getmerror @message(r'^(0|1)\s+(?:joystick|j)$') - def set_joystick(self, value): + def set_joystick(self, value) -> None: self.joystick = bool(int(value)) @message(r'^getjoystick|gj$') - def get_joystick(self): + def get_joystick(self) -> str: return f"{self.joystick:d}" @message(r'^(-1|1|2|3)\s+getunit$') - def get_unit(self, axis): + def get_unit(self, axis) -> Optional[str]: if axis == "-1": return f"{self.x_unit} {self.y_unit} {self.z_unit} 1" if axis == "1": @@ -163,9 +164,10 @@ def get_unit(self, axis): return f"{self.y_unit}" if axis == "3": return f"{self.z_unit}" + return None @message(r'^(\d)\s+(1|2|3)\s+setunit$') - def set_unit(self, value, axis): + def set_unit(self, value, axis) -> None: if axis == "1": self.x_unit = int(value) if axis == "2": @@ -174,7 +176,7 @@ def set_unit(self, value, axis): self.z_unit = int(value) @message(r'^(1|2|3)\s+ncal$') - def set_ncal(self, axis): + def set_ncal(self, axis) -> None: if axis == "1": self.getcaldone[0] = 0x1 if axis == "2": @@ -183,7 +185,7 @@ def set_ncal(self, axis): self.getcaldone[2] = 0x1 @message(r'^(1|2|3)\s+nrm$') - def set_nrm(self, axis): + def set_nrm(self, axis) -> None: if axis == "1": self.getcaldone[0] |= 0x2 if axis == "2": diff --git a/src/comet/emulator/itk/hydra.py b/src/comet/emulator/itk/hydra.py index dfd2766..5bdf062 100644 --- a/src/comet/emulator/itk/hydra.py +++ b/src/comet/emulator/itk/hydra.py @@ -25,35 +25,34 @@ def __init__(self) -> None: self.manual_move: int = 0 @message(r'^identify$') - def get_identify(self): + def get_identify(self) -> str: return self.options.get("identity", self.IDENTITY) @message(r'^getversion|version$') - def get_version(self): - return float(self.options.get("version", self.VERSION)) # double + def get_version(self) -> float: + return float(self.options.get("version", self.VERSION)) # double! @message(r'^getmacadr$') - def get_macadr(self): + def get_macadr(self) -> str: return self.options.get("macaddr", self.MAC_ADDR) @message(r'^getserialno$') - def get_serialno(self): + def get_serialno(self) -> str: return self.options.get("serialno", self.SERIAL_NO) @message(r'^getproductid$') - def get_productid(self): + def get_productid(self) -> str: return "hydra" @message(r'^getcputemp$') - def get_cputemp(self): + def get_cputemp(self) -> float: return float(self.options.get("cputemp", 40.0)) @message(r'^reset$') - def set_reset(self): - ... + def set_reset(self) -> None: ... @message(r'^status|st$') - def get_status(self): + def get_status(self) -> int: status = 0 all_cal = int(all([value & 0x1 for value in self.calibrate.values()])) all_rm = int(all([value & 0x2 for value in self.calibrate.values()])) @@ -64,7 +63,7 @@ def get_status(self): return status @message(r'^(1|2)\s+(?:nstatus|nst|est|ast)$') - def get_nstatus(self, device): + def get_nstatus(self, device) -> int: status = 0 cal = int(self.calibrate[device] & 0x1 == 0x1) rm = int(self.calibrate[device] & 0x2 == 0x2) @@ -75,28 +74,28 @@ def get_nstatus(self, device): return status @message(r'^(1|2)\s+np$') - def get_np(self, device): + def get_np(self, device) -> float: return self.pos[device] @message(r'^([+-]?\d+(?:\.\d+)?)\s+([+-]?\d+(?:\.\d+)?)\s+m$') - def set_move(self, x, y): + def set_move(self, x, y) -> None: self.pos.update({"1": float(x), "2": float(y)}) @message(r'^([+-]?\d+(?:\.\d+)?)\s+([+-]?\d+(?:\.\d+)?)\s+r$') - def set_rmove(self, x, y): + def set_rmove(self, x, y) -> None: self.pos["1"] += float(x) self.pos["2"] += float(y) @message(r'^(1|2)\s+nrandmove$') - def set_nrandmove(self, device): + def set_nrandmove(self, device) -> None: self.pos[device] = random.uniform(0, 100) @message(r'^(1|2)\s+(?:ncalibrate|ncal)$') - def set_ncalibrate(self, device): + def set_ncalibrate(self, device) -> None: self.calibrate[device] = 0x1 @message(r'^(1|2)\s+(?:nrangemeasure|nrm)$') - def set_nrangemeasure(self, device): + def set_nrangemeasure(self, device) -> None: self.calibrate[device] |= 0x2 diff --git a/src/comet/emulator/keithley/k2400.py b/src/comet/emulator/keithley/k2400.py index b3fd7e2..5e920b9 100644 --- a/src/comet/emulator/keithley/k2400.py +++ b/src/comet/emulator/keithley/k2400.py @@ -1,5 +1,4 @@ import random -from typing import Dict, List, Set from comet.emulator import IEC60488Emulator, message, run from comet.emulator.utils import Error @@ -13,15 +12,15 @@ class K2400Emulator(IEC60488Emulator): def __init__(self) -> None: super().__init__() - self.error_queue: List[Error] = [] + self.error_queue: list[Error] = [] self.system_beeper_state: bool = True self.system_rsense: bool = False self.route_terminals: str = "FRON" self.output_state: bool = False self.source_function_mode: str = "VOLT" - self.source_level: Dict = {"VOLT": 0., "CURR": 0.} - self.source_range: Dict = {"VOLT": 0., "CURR": 0.} - self.source_range_auto: Dict = {"VOLT": True, "CURR": True} + self.source_level: dict[str, float] = {"VOLT": 0., "CURR": 0.} + self.source_range: dict[str, float] = {"VOLT": 0., "CURR": 0.} + self.source_range_auto: dict[str, bool] = {"VOLT": True, "CURR": True} self.source_voltage_protection_level: float = self.DEFAULT_VOLTAGE_PROTECTION_LEVEL self.sense_voltage_protection_level: float = 2.1e+1 self.sense_current_protection_level: float = 1.05e-5 @@ -36,7 +35,7 @@ def __init__(self) -> None: self.format_elements.update(["VOLT", "CURR", "RES", "TIME", "STAT"]) @message(r'^\*RST$') - def set_rst(self): + def set_rst(self) -> None: self.error_queue.clear() self.system_beeper_state = True self.system_rsense = False @@ -58,15 +57,15 @@ def set_rst(self): self.format_elements.update(["VOLT", "CURR", "RES", "TIME", "STAT"]) @message(r'^\*CLS$') - def set_cls(self): + def set_cls(self) -> None: self.error_queue.clear() @message(r'^:?SYST(?:em)?:ERR(?:or)?:COUN(?:t)?\?$') - def get_system_error_count(self): + def get_system_error_count(self) -> str: return format(len(self.error_queue), "d") @message(r'^:?SYST(?:em)?:ERR(?:or)?(?::NEXT)?\?$') - def get_system_error_next(self): + def get_system_error_next(self) -> str: if self.error_queue: error = self.error_queue.pop(0) else: @@ -76,41 +75,41 @@ def get_system_error_next(self): # Beeper @message(r'^:?SYST(?:em)?:BEEP(?:er)?(?::STAT(?:e)?)?\?$') - def get_system_beeper_state(self): - return int(self.system_beeper_state) + def get_system_beeper_state(self) -> str: + return format(self.system_beeper_state, "d") @message(r'^:?SYST(?:em)?:BEEP(?:er)?(?::STAT(?:e)?)? (OFF|ON|0|1)$') - def set_system_beeper_state(self, state): + def set_system_beeper_state(self, state) -> None: self.system_beeper_state = {"OFF": False, "ON": True, "0": False, "1": True}[state] # Remote sensing @message(r'^:?SYST(?:em)?:RSEN(?:se)?\?$') - def get_system_rsense(self): - return int(self.system_rsense) + def get_system_rsense(self) -> str: + return format(self.system_rsense, "d") @message(r'^:?SYST(?:em)?:RSEN(?:se)?\s+(OFF|ON|0|1)$') - def set_system_rsense(self, enabled): + def set_system_rsense(self, enabled) -> None: self.system_rsense = {'OFF': False, 'ON': True, '0': False, '1': True}[enabled] # Route terminal @message(r'^:?ROUT(?:e)?:TERM(?:inal)?\?$') - def get_route_terminals(self): + def get_route_terminals(self) -> str: return self.route_terminals @message(r'^:?ROUT(?:e)?:TERM(?:inal)? (FRON|REAR)$') - def set_route_terminals(self, terminal): + def set_route_terminals(self, terminal) -> None: self.route_terminals = terminal # Output state @message(r'^:?OUTP(?:ut)?(?::STAT(?:e)?)?\?$') - def get_output_state(self): + def get_output_state(self) -> str: return {False: '0', True: '1'}[self.output_state] @message(r'^:?OUTP(?:ut)?(?::STAT(?:e)?)? (.+)$') - def set_output_state(self, state): + def set_output_state(self, state) -> None: try: self.output_state = {"ON": True, "OFF": False, "0": False, "1": True}[state] except KeyError: @@ -119,11 +118,11 @@ def set_output_state(self, state): # Source function mode @message(r'^:?SOUR:FUNC(?::MODE)?\?$') - def get_source_function_mode(self): + def get_source_function_mode(self) -> str: return self.source_function_mode @message(r'^:?SOUR:FUNC(?::MODE)? (VOLT|CURR)$') - def set_source_function_mode(self, function): + def set_source_function_mode(self, function) -> None: try: self.source_function_mode = function except KeyError: @@ -132,11 +131,11 @@ def set_source_function_mode(self, function): # Source levels @message(r'^:?SOUR:(VOLT|CURR)(?::LEV)?\?$') - def get_source_level(self, function): + def get_source_level(self, function) -> str: return format(self.source_level[function], 'E') @message(r'^:?SOUR:(VOLT|CURR)(?::LEV)? (.+)$') - def set_source_level(self, function, level): + def set_source_level(self, function, level) -> None: try: self.source_level[function] = float(level) except ValueError: @@ -145,11 +144,11 @@ def set_source_level(self, function, level): # Source range levels @message(r'^:?SOUR:(VOLT|CURR):RANG\?$') - def get_source_range_level(self, function): + def get_source_range_level(self, function) -> str: return format(self.source_range[function], "E") @message(r'^:?SOUR:(VOLT|CURR):RANG (.+)$') - def set_source_range_level(self, function, level): + def set_source_range_level(self, function, level) -> None: try: self.source_range[function] = float(level) self.source_range_auto[function] = False @@ -159,11 +158,11 @@ def set_source_range_level(self, function, level): # Source auto ranges @message(r'^:?SOUR:(VOLT|CURR):RANG:AUTO\?$') - def get_source_range_auto(self, function): - return int(self.source_range_auto[function]) + def get_source_range_auto(self, function) -> str: + return format(self.source_range_auto[function], "d") @message(r'^:?SOUR:(VOLT|CURR):RANG:AUTO (.+)$') - def set_source_range_auto(self, function, state): + def set_source_range_auto(self, function, state) -> None: try: self.source_range_auto[function] = {"ON": True, "OFF": False, "0": False, "1": True}[state] except ValueError: @@ -172,11 +171,11 @@ def set_source_range_auto(self, function, state): # Source voltage limit @message(r'^:?SOUR:VOLT:PROT(?::LEV)?\?$') - def get_source_voltage_protection_level(self): + def get_source_voltage_protection_level(self) -> str: return format(self.source_voltage_protection_level, "E") @message(r'^:?SOUR:VOLT:PROT(?::LEV)? (.+)$') - def set_source_voltage_protection_level(self, level): + def set_source_voltage_protection_level(self, level) -> None: try: self.source_voltage_protection_level = float(level) except ValueError: @@ -185,105 +184,105 @@ def set_source_voltage_protection_level(self, level): # Source compliance @message(r'^(?::?SENS)?:VOLT:PROT(?::LEV)?\?$') - def get_sense_voltage_protection_level(self): + def get_sense_voltage_protection_level(self) -> str: return format(self.sense_voltage_protection_level, "E") @message(r'^(?::?SENS)?:VOLT:PROT(?::LEV)? (.+)$') - def set_sense_voltage_protection_level(self, level): + def set_sense_voltage_protection_level(self, level) -> None: try: self.sense_voltage_protection_level = float(level) except ValueError: self.error_queue.append(Error(101, "malformed command")) @message(r'^(?::?SENS)?:VOLT:PROT:TRIP\?$') - def get_sense_voltage_protection_tripped(self): + def get_sense_voltage_protection_tripped(self) -> str: return format(False, "d") # TODO @message(r'^(?::?SENS)?:CURR:PROT(?::LEV)?\?$') - def get_sense_current_protection_level(self): + def get_sense_current_protection_level(self) -> str: return format(self.sense_current_protection_level, "E") @message(r'^(?::?SENS)?:CURR:PROT(?::LEV)? (.+)$') - def set_sense_current_protection_level(self, level): + def set_sense_current_protection_level(self, level) -> None: try: self.sense_current_protection_level = float(level) except ValueError: self.error_queue.append(Error(101, "malformed command")) @message(r'^(?::?SENS)?:CURR:PROT:TRIP\?$') - def get_sense_current_protection_tripped(self): + def get_sense_current_protection_tripped(self) -> str: return format(False, "d") # TODO # Sense function @message(r'^(?::?SENS)?:FUNC(?::ON)?\?$') - def get_sense_function_on(self): + def get_sense_function_on(self) -> str: return format(self.sense_function) @message(r'^(?::?SENS)?:FUNC(?::ON)? \'(VOLT|CURR|RES|TIME|STAT)\'$') - def set_sense_function_on(self, value): + def set_sense_function_on(self, value) -> None: self.sense_function.add(value) # TODO @message(r'^(?::?SENS)?:FUNC(?::ON)? \'VOLT\',\s*\'CURR\'$') - def set_sense_function_on_2(self): + def set_sense_function_on_2(self) -> None: self.sense_function.add("VOLT") self.sense_function.add("CURR") # Concurrent function @message(r'^(?::?SENS)?:FUNC:CONC\?$') - def get_sense_function_concurrent(self): + def get_sense_function_concurrent(self) -> int: return int(self.sense_function_concurrent) @message(r'^(?::?SENS)?:FUNC:CONC (OFF|ON|0|1)$') - def set_sense_function_concurrent(self, state): + def set_sense_function_concurrent(self, state) -> None: self.sense_function_concurrent = {"OFF": False, "ON": True, "0": False, "1": True}[state] # Average @message(r'^(?::?SENS)?:AVER:TCON\?$') - def get_sense_average_tcontrol(self): + def get_sense_average_tcontrol(self) -> str: return self.sense_average_tcontrol @message(r'^(?::?SENS)?:AVER:TCON (REP|MOV)$') - def set_sense_average_tcontrol(self, state: str): + def set_sense_average_tcontrol(self, state: str) -> None: self.sense_average_tcontrol = state @message(r'^(?::?SENS)?:AVER:COUN\?$') - def get_sense_average_count(self): + def get_sense_average_count(self) -> int: return self.sense_average_count @message(r'^(?::?SENS)?:AVER:COUN (\d+)$') - def set_sense_average_count(self, count: str): + def set_sense_average_count(self, count: str) -> None: self.sense_average_count = int(count) @message(r'^(?::?SENS)?:AVER(?::STAT)?\?$') - def get_sense_average_state(self): + def get_sense_average_state(self) -> int: return int(self.sense_average_state) @message(r'^(?::?SENS)?:AVER(?::STAT)? (OFF|ON|0|1)$') - def set_sense_average_state(self, state): + def set_sense_average_state(self, state) -> None: self.sense_average_state = {"OFF": False, "ON": True, "0": False, "1": True}[state] # Integration time @message(r'^(?::?SENS)?:(?:VOLT|CURR|RES):NPLC\?$') - def get_sense_nplc(self): + def get_sense_nplc(self) -> str: return format(self.sense_nplc, "E") @message(r'^(?::?SENS)?:(?:VOLT|CURR|RES):NPLC (.+)$') - def set_sense_nplc(self, nplc: str): + def set_sense_nplc(self, nplc: str) -> None: self.sense_nplc = round(float(nplc), 2) # Format @message(r'^:?FORM:ELEM\?$') - def get_format_elements(self): + def get_format_elements(self) -> str: return format(self.format_elements) @message(r'^:?FORM:ELEM (.+)$') - def set_format_elements(self, elements): + def set_format_elements(self, elements) -> None: elements = [element.strip() for element in elements.split(",") if element.strip()] self.format_elements.clear() self.format_elements.update(elements) @@ -291,11 +290,10 @@ def set_format_elements(self, elements): # Measure @message(r'^:?INIT(?:iate)?$') - def set_initiate(self): - ... + def set_initiate(self) -> None: ... @message(r'^:?READ\?$') - def get_read(self): + def get_read(self) -> str: result = [] if "VOLT" in self.format_elements._values: curr_min = float(self.options.get("volt.min", self.source_level.get("VOLT"))) @@ -314,13 +312,13 @@ def get_read(self): return ",".join(result) @message(r'^:?FETC[H]?\?$') - def get_fetch(self): + def get_fetch(self) -> str: curr_min = float(self.options.get("curr.min", 1e6)) curr_max = float(self.options.get("curr.max", 1e7)) return format(random.uniform(curr_min, curr_max), "E") @message(r'^(.*)$') - def unknown_message(self, request): + def unknown_message(self, request) -> None: self.error_queue.append(Error(101, "malformed command")) @@ -330,7 +328,7 @@ class SenseFunction: ALIAS_VALUES = {"VOLT": "VOLT:DC", "CURR": "CURR:DC"} def __init__(self) -> None: - self._values: Set = set() + self._values: set[str] = set() def add(self, value) -> None: if value in self.ALIAS_VALUES: @@ -361,7 +359,7 @@ class FormatElements: ALLOWED_VALUES = ["VOLT", "CURR", "RES", "TIME", "STAT"] def __init__(self) -> None: - self._values: set = set() + self._values: set[str] = set() def add(self, value) -> None: if value in self.ALLOWED_VALUES: diff --git a/src/comet/emulator/keithley/k2470.py b/src/comet/emulator/keithley/k2470.py index bbc42b6..fc154fb 100644 --- a/src/comet/emulator/keithley/k2470.py +++ b/src/comet/emulator/keithley/k2470.py @@ -1,5 +1,4 @@ import random -from typing import Dict, List, Tuple from comet.emulator import IEC60488Emulator, message, run from comet.emulator.utils import tsp_print, tsp_assign, Error @@ -15,32 +14,32 @@ class K2470Emulator(IEC60488Emulator): def __init__(self) -> None: super().__init__() self.language: str = str(self.options.get("language", self.LANGUAGE)) - self.error_queue: List[Error] = [] + self.error_queue: list[Error] = [] self.route_terminals: str = "FRON" self.output_state: bool = False self.source_function_mode: str = "VOLT" - self.source_level: Dict = {"VOLT": 0., "CURR": 0.} - self.source_range: Dict = {"VOLT": 0., "CURR": 0.} - self.source_range_auto: Dict = {"VOLT": True, "CURR": True} + self.source_level: dict[str, float] = {"VOLT": 0., "CURR": 0.} + self.source_range: dict[str, float] = {"VOLT": 0., "CURR": 0.} + self.source_range_auto: dict[str, bool] = {"VOLT": True, "CURR": True} self.source_voltage_protection_level: float = self.DEFAULT_VOLTAGE_PROTECTION_LEVEL self.source_voltage_ilimit_level: float = 1.05e-4 self.source_current_vlimit_level: float = 2.1e-1 - self.sense_average_tcontrol: Dict = {"VOLT": "REP", "CURR": "REP"} - self.sense_average_count: Dict = {"VOLT": 10, "CURR": 10} - self.sense_average_state: Dict = {"VOLT": False, "CURR": False} + self.sense_average_tcontrol: dict[str, str] = {"VOLT": "REP", "CURR": "REP"} + self.sense_average_count: dict[str, int] = {"VOLT": 10, "CURR": 10} + self.sense_average_state: dict[str, bool] = {"VOLT": False, "CURR": False} self.sense_nplc: float = 1.0 self.system_breakdown_protection: str = "OFF" @property - def output_interlock_tripped(self): + def output_interlock_tripped(self) -> bool: return bool(self.options.get("interlock.tripped", True)) @message(r'^\*LANG\?$') - def get_lang(self): + def get_lang(self) -> str: return self.language @message(r'^\*RST$') - def set_rst(self): + def set_rst(self) -> None: self.error_queue.clear() self.route_terminals = "FRON" self.output_state = False @@ -58,11 +57,11 @@ def set_rst(self): self.system_breakdown_protection = "OFF" @message(r'^\*CLS$') - def set_cls(self): + def set_cls(self) -> None: self.error_queue.clear() @message(r'^:?SYST:ERR(?::NEXT)?\?$') - def get_system_error_next(self): + def get_system_error_next(self) -> str: if self.error_queue: error = self.error_queue.pop(0) else: @@ -70,48 +69,48 @@ def get_system_error_next(self): return f'{error.code}, "{error.message}"' @message(r'^:?SYST:BRE:PROT\?$') - def get_system_breakdown_protection(self): + def get_system_breakdown_protection(self) -> str: return self.system_breakdown_protection @message(r'^:?SYST:BRE:PROT (AUTO|OFF|ON)$') - def set_system_breakdown_protection(self, state): + def set_system_breakdown_protection(self, state) -> None: self.system_breakdown_protection = state # Route terminal @message(r'^:?ROUT:TERM\?$') - def get_route_terminals(self): + def get_route_terminals(self) -> str: return self.route_terminals @message(r'^:?ROUT:TERM (FRON|REAR)$') - def set_route_terminals(self, terminal): + def set_route_terminals(self, terminal) -> None: self.route_terminals = terminal # Output state @message(r'^:?OUTP(?::STAT)?\?$') - def get_output_state(self): + def get_output_state(self) -> str: return {False: "0", True: "1"}[self.output_state] @message(r'^:?OUTP(?::STAT)? (.+)$') - def set_output_state(self, state): + def set_output_state(self, state) -> None: try: self.output_state = {"ON": True, "OFF": False, "0": False, "1": True}[state] except KeyError: self.error_queue.append(Error(101, "malformed command")) @message(r'^:?OUTP:INT:TRIP\?$') - def get_output_interlock_tripped(self): + def get_output_interlock_tripped(self) -> str: return {False: "0", True: "1"}[self.output_interlock_tripped] # Source function mode @message(r'^:?SOUR:FUNC(?::MODE)?\?$') - def get_source_function_mode(self): + def get_source_function_mode(self) -> str: return self.source_function_mode @message(r'^:?SOUR:FUNC(?::MODE)? (VOLT|CURR)$') - def set_source_function_mode(self, function): + def set_source_function_mode(self, function) -> None: try: self.source_function_mode = function except KeyError: @@ -120,11 +119,11 @@ def set_source_function_mode(self, function): # Source levels @message(r'^:?SOUR:(VOLT|CURR)(?::LEV)?\?$') - def get_source_level(self, function): + def get_source_level(self, function) -> str: return format(self.source_level[function], "E") @message(r'^:?SOUR:(VOLT|CURR)(?::LEV)? (.+)$') - def set_source_level(self, function, level): + def set_source_level(self, function, level) -> None: try: self.source_level[function] = float(level) except ValueError: @@ -133,11 +132,11 @@ def set_source_level(self, function, level): # Source range levels @message(r'^:?SOUR:(VOLT|CURR):RANG\?$') - def get_source_range_level(self, function): + def get_source_range_level(self, function) -> str: return format(self.source_range[function], "E") @message(r'^:?SOUR:(VOLT|CURR):RANG (.+)$') - def set_source_range_level(self, function, level): + def set_source_range_level(self, function, level) -> None: try: self.source_range[function] = float(level) self.source_range_auto[function] = False @@ -147,11 +146,11 @@ def set_source_range_level(self, function, level): # Source auto ranges @message(r'^:?SOUR:(VOLT|CURR):RANG:AUTO\?$') - def get_source_range_auto(self, function): + def get_source_range_auto(self, function) -> int: return int(self.source_range_auto[function]) @message(r'^:?SOUR:(VOLT|CURR):RANG:AUTO (.+)$') - def set_source_range_auto(self, function, state): + def set_source_range_auto(self, function, state) -> None: try: self.source_range_auto[function] = {"ON": True, "OFF": False, "0": False, "1": True}[state] except ValueError: @@ -160,11 +159,11 @@ def set_source_range_auto(self, function, state): # Source voltage limit @message(r'^:?SOUR:VOLT:PROT(?::LEV)?\?$') - def get_source_voltage_protection_level(self): + def get_source_voltage_protection_level(self) -> str: return format(self.source_voltage_protection_level, "E") @message(r'^:?SOUR:VOLT:PROT(?::LEV)? (.+)$') - def set_source_voltage_protection_level(self, level): + def set_source_voltage_protection_level(self, level) -> None: try: self.source_voltage_protection_level = float(level) except ValueError: @@ -173,81 +172,81 @@ def set_source_voltage_protection_level(self, level): # Source compliance @message(r'^:?SOUR:VOLT:ILIM(?::LEV)?\?$') - def get_source_voltage_ilimit_level(self): + def get_source_voltage_ilimit_level(self) -> str: return format(self.source_voltage_ilimit_level, "E") @message(r'^:?SOUR:VOLT:ILIM(?::LEV)? (.+)$') - def set_source_voltage_ilimit_level(self, level): + def set_source_voltage_ilimit_level(self, level) -> None: try: self.source_voltage_ilimit_level = float(level) except ValueError: self.error_queue.append(Error(101, "malformed command")) @message(r'^:?SOUR:VOLT:ILIM(?::LEV)?:TRIP\?$') - def get_source_voltage_ilimit_level_tripped(self): + def get_source_voltage_ilimit_level_tripped(self) -> str: return format(False, "E") # TODO @message(r'^:?SOUR:CURR:VLIM(?::LEV)?\?$') - def get_source_current_vlimit_level(self): + def get_source_current_vlimit_level(self) -> str: return format(self.source_current_vlimit_level, "E") @message(r'^:?SOUR:CURR:VLIM(?::LEV)? (.+)$') - def set_source_current_vlimit_level(self, level): + def set_source_current_vlimit_level(self, level) -> None: try: self.source_current_vlimit_level = float(level) except ValueError: self.error_queue.append(Error(101, "malformed command")) @message(r'^:?SOUR:CURR:VLIM(?::LEV)?:TRIP\?$') - def get_source_current_vlimit_level_tripped(self): + def get_source_current_vlimit_level_tripped(self) -> str: return format(False, "E") # TODO # Average @message(r'^:?SENS:(VOLT|CURR):AVER:TCON\?$') - def get_sense_average_tcontrol(self, function: str): + def get_sense_average_tcontrol(self, function: str) -> str: return format(self.sense_average_tcontrol[function], "E") @message(r'^:?SENS:(VOLT|CURR):AVER:TCON (MOV|REP)$') - def set_sense_average_tcontrol(self, function: str, tcontrol: str): + def set_sense_average_tcontrol(self, function: str, tcontrol: str) -> None: self.sense_average_tcontrol[function] = tcontrol @message(r'^:?SENS:(VOLT|CURR):AVER:COUN[T]?\?$') - def get_sense_average_count(self, function: str): + def get_sense_average_count(self, function: str) -> str: return format(self.sense_average_count[function], "E") @message(r':?SENS:(VOLT|CURR):AVER:COUN[T]? (\d+)$') - def set_sense_average_count(self, function: str, count: str): + def set_sense_average_count(self, function: str, count: str) -> None: self.sense_average_count[function] = int(count) @message(r'^:?SENS:(VOLT|CURR):AVER:STAT[E]?\?$') - def get_sense_average_state(self, function: str): + def get_sense_average_state(self, function: str) -> str: return format(self.sense_average_state[function], "E") @message(r'^:?SENS:(VOLT|CURR):AVER:STAT[E]? (OFF|ON|0|1)$') - def set_sense_average_state(self, function: str, state: str): + def set_sense_average_state(self, function: str, state: str) -> None: self.sense_average_state[function] = {"OFF": False, "ON": True, "0": False, "1": True}[state] # Integration time @message(r'^(?::?SENS)?:(?:VOLT|CURR|RES):NPLC\?$') - def get_sense_nplc(self): + def get_sense_nplc(self) -> str: return format(self.sense_nplc, "E") @message(r'^(?::?SENS)?:(?:VOLT|CURR|RES):NPLC (.+)$') - def set_sense_nplc(self, nplc: str): + def set_sense_nplc(self, nplc: str) -> None: self.sense_nplc = round(float(nplc), 2) # Measure @message(r'^:?MEAS:VOLT\?$') - def get_measure_voltage(self): + def get_measure_voltage(self) -> str: volt_min = float(self.options.get("curr.min", 0)) volt_max = float(self.options.get("curr.max", 10)) return format(random.uniform(volt_min, volt_max), "E") @message(r'^:?MEAS:CURR\?$') - def get_measure_current(self): + def get_measure_current(self) -> str: curr_min = float(self.options.get("curr.min", 1e6)) curr_max = float(self.options.get("curr.max", 1e7)) return format(random.uniform(curr_min, curr_max), "E") @@ -255,34 +254,34 @@ def get_measure_current(self): # TSP @message(r'^reset\(\)$') - def write_reset(self): + def write_reset(self) -> None: self.error_queue.clear() @message(r'^clear\(\)$') - def write_clear(self): + def write_clear(self) -> None: self.error_queue.clear() @message(r'^errorqueue\.clear\(\)$') - def set_errorqueue_clear(self): + def set_errorqueue_clear(self) -> None: self.error_queue.clear() @message(tsp_print(r'errorqueue\.count')) - def get_errorqueue_count(self): + def get_errorqueue_count(self) -> int: return len(self.error_queue) @message(tsp_print(r'errorqueue\.next\(\)')) - def get_errorqueue_next(self): + def get_errorqueue_next(self) -> str: if self.error_queue: - code, message = self.error_queue.pop(0) - return f"{code}, \"{message}\", 0, 0" + error = self.error_queue.pop(0) + return f"{error.code}, \"{error.message}\", 0, 0" return "0, \"Queue is Empty\", 0, 0" @message(tsp_print(r'smu\.source\.output')) - def get_tsp_source_output(self): + def get_tsp_source_output(self) -> int: return {False: 0, True: 1}[self.smu_source_output] @message(tsp_assign(r'smu\.source\.output')) - def set_tsp_source_output(self, value): + def set_tsp_source_output(self, value) -> None: try: self.smu_source_output = { "smu.ON": True, "smu.OFF": False, @@ -292,7 +291,7 @@ def set_tsp_source_output(self, value): self.error_queue.append(Error(101, "malformed command")) @message(r'^.*$') - def unknown_message(self): + def unknown_message(self) -> None: self.error_queue.append(Error(101, "malformed command")) diff --git a/src/comet/emulator/keithley/k2657a.py b/src/comet/emulator/keithley/k2657a.py index 95aed9f..d160d9d 100644 --- a/src/comet/emulator/keithley/k2657a.py +++ b/src/comet/emulator/keithley/k2657a.py @@ -1,5 +1,4 @@ import random -from typing import Dict, List from comet.emulator import IEC60488Emulator, message, run from comet.emulator.utils import tsp_print, tsp_assign, Error @@ -11,14 +10,14 @@ class K2657AEmulator(IEC60488Emulator): def __init__(self) -> None: super().__init__() - self.error_queue: List[Error] = [] + self.error_queue: list[Error] = [] self.beeper_enable: bool = True self.smua_source_output: bool = False self.smua_source_function = "DCVOLTS" - self.smua_source_level: Dict = {"v": 0., "i": 0.} - self.smua_source_range: Dict = {"v": 0., "i": 0.} - self.smua_source_autorange: Dict = {"v": True, "i": True} - self.smua_source_limit: Dict = {"v": 0., "i": 0.} + self.smua_source_level: dict[str, float] = {"v": 0., "i": 0.} + self.smua_source_range: dict[str, float] = {"v": 0., "i": 0.} + self.smua_source_autorange: dict[str, bool] = {"v": True, "i": True} + self.smua_source_limit: dict[str, float] = {"v": 0., "i": 0.} self.smua_measure_filter_enable: bool = False self.smua_measure_filter_count: int = 1 self.smua_measure_filter_type: int = 1 @@ -42,23 +41,23 @@ def set_reset(self): self.source_protectv = 0. @message(r'^status.reset\(\)$') - def set_status_reset(self): + def set_status_reset(self) -> None: self.error_queue.clear() @message(r'^clear\(\)$') - def set_clear(self): + def set_clear(self) -> None: self.error_queue.clear() @message(r'^errorqueue\.clear\(\)$') - def set_errorqueue_clear(self): + def set_errorqueue_clear(self) -> None: self.error_queue.clear() @message(tsp_print(r'errorqueue\.count')) - def get_errorqueue_count(self): + def get_errorqueue_count(self) -> str: return format(len(self.error_queue), "d") @message(tsp_print(r'errorqueue\.next\(\)')) - def get_errorqueue_next(self): + def get_errorqueue_next(self) -> str: if self.error_queue: error = self.error_queue.pop(0) else: @@ -68,11 +67,11 @@ def get_errorqueue_next(self): # Beeper @message(tsp_print(r'beeper\.enabled')) - def get_beeper_enabled(self): + def get_beeper_enabled(self) -> str: return format(self.beeper_enable, "d") @message(tsp_assign(r'beeper\.enable')) - def set_beeper_enable(self, enable: str): + def set_beeper_enable(self, enable: str) -> None: try: self.beeper_enable = { "beeper.ON": True, "beeper.OFF": False, @@ -84,11 +83,11 @@ def set_beeper_enable(self, enable: str): # Source output @message(tsp_print(r'smua\.source\.output')) - def get_source_output(self): + def get_source_output(self) -> str: return format(self.smua_source_output, "E") @message(tsp_assign(r'smua\.source\.output')) - def set_source_output(self, state): + def set_source_output(self, state) -> None: try: self.smua_source_output = { "smua.OUTPUT_ON": True, "smua.OUTPUT_OFF": False, @@ -100,11 +99,11 @@ def set_source_output(self, state): # Source function @message(tsp_print(r'smua\.source\.func')) - def get_source_function(self): + def get_source_function(self) -> str: return format({"DCAMPS": 0, "DCVOLTS": 1}[self.smua_source_function], "E") @message(tsp_assign(r'smua\.source\.func')) - def set_source_function(self, function): + def set_source_function(self, function) -> None: try: self.smua_source_function = { "0": "DCAMPS", "smua.OUTPUT_DCAMPS": "DCAMPS", @@ -116,11 +115,11 @@ def set_source_function(self, function): # Source levels @message(tsp_print(r'smua\.source\.level([iv])')) - def get_source_level(self, function): + def get_source_level(self, function) -> str: return format(self.smua_source_level[function], "E") @message(tsp_assign(r'smua\.source\.level([iv])')) - def set_source_level(self, function, level): + def set_source_level(self, function, level) -> None: try: self.smua_source_level[function] = float(level) except ValueError: @@ -129,11 +128,11 @@ def set_source_level(self, function, level): # Source ranges @message(tsp_print(r'smua\.source\.range([iv])')) - def get_source_range(self, function): + def get_source_range(self, function) -> str: return format(self.smua_source_range[function], "E") @message(tsp_assign(r'smua\.source\.range([iv])')) - def set_source_range(self, function, level): + def set_source_range(self, function, level) -> None: try: self.smua_source_range[function] = float(level) except ValueError: @@ -142,11 +141,11 @@ def set_source_range(self, function, level): # Source autoranges @message(tsp_print(r'smua\.source\.autorange([iv])')) - def get_source_autorange(self, function): + def get_source_autorange(self, function) -> str: return format(self.smua_source_autorange[function], "E") @message(tsp_assign(r'smua\.source\.autorange([iv])')) - def set_source_autorange(self, function, state): + def set_source_autorange(self, function, state) -> None: try: self.smua_source_autorange[function] = { "0": False, "smua.AUTORANGE_OFF": False, @@ -158,11 +157,11 @@ def set_source_autorange(self, function, state): # Source voltage limit @message(tsp_print(r'smua\.source\.protectv')) - def get_source_protectv(self): + def get_source_protectv(self) -> str: return format(self.source_protectv, "E") @message(tsp_assign(r'smua\.source\.protectv')) - def set_source_protectv(self, level): + def set_source_protectv(self, level) -> None: try: self.source_protectv = float(level) except ValueError: @@ -171,38 +170,38 @@ def set_source_protectv(self, level): # Compliance @message(tsp_print(r'smua.source.compliance')) - def get_source_compliance(self): + def get_source_compliance(self) -> str: return "false" @message(tsp_print(r'smua\.source\.limit([iv])')) - def get_source_limit(self, function): + def get_source_limit(self, function) -> str: return format(self.smua_source_limit[function], "E") @message(tsp_assign(r'smua\.source\.limit([iv])')) - def set_source_limit(self, function, level): + def set_source_limit(self, function, level) -> None: try: self.smua_source_limit[function] = float(level) except ValueError: self.error_queue.append(Error(117, "malformed command")) @message(tsp_print(r'smua\.measure\.i\(\)')) - def get_measure_i(self): + def get_measure_i(self) -> str: curr_min = float(self.options.get("curr.min", 1e6)) curr_max = float(self.options.get("curr.max", 1e7)) return format(random.uniform(curr_min, curr_max), "E") @message(tsp_print(r'smua\.measure\.v\(\)')) - def get_measure_v(self): + def get_measure_v(self) -> str: return format(self.smua_source_level.get("v", 0) + random.uniform(-.25, +.25), "E") # Average @message(tsp_print(r'smua\.measure\.filter\.enable')) - def get_measure_filter_enable(self): + def get_measure_filter_enable(self) -> str: return format(self.smua_measure_filter_enable, "d") @message(tsp_assign(r'smua\.measure\.filter\.enable')) - def set_measure_filter_enable(self, enable: str): + def set_measure_filter_enable(self, enable: str) -> None: try: self.smua_measure_filter_enable = { "0": False, "smua.FILTER_OFF": False, @@ -212,22 +211,22 @@ def set_measure_filter_enable(self, enable: str): self.error_queue.append(Error(118, "malformed command")) @message(tsp_print(r'smua\.measure\.filter\.count')) - def get_measure_filter_count(self): + def get_measure_filter_count(self) -> str: return format(self.smua_measure_filter_count, "d") @message(tsp_assign(r'smua\.measure\.filter\.count')) - def set_measure_filter_count(self, count: str): + def set_measure_filter_count(self, count: str) -> None: try: self.smua_measure_filter_count = int(count) except KeyError: self.error_queue.append(Error(119, "malformed command")) @message(tsp_print(r'smua\.measure\.filter\.type')) - def get_measure_filter_type(self): + def get_measure_filter_type(self) -> str: return format(self.smua_measure_filter_type, "d") @message(tsp_assign(r'smua\.measure\.filter\.type')) - def set_measure_filter_type(self, enable: str): + def set_measure_filter_type(self, enable: str) -> None: try: self.smua_measure_filter_type = { "0": 0, "smua.FILTER_MOVING_AVG": 0, @@ -240,18 +239,18 @@ def set_measure_filter_type(self, enable: str): # Integration time @message(tsp_print(r'smua\.measure\.nplc')) - def get_measure_nplc(self): + def get_measure_nplc(self) -> str: return format(self.smua_measure_nplc, "E") @message(tsp_assign(r'smua\.measure\.nplc')) - def set_measure_nplc(self, nplc: str): + def set_measure_nplc(self, nplc: str) -> None: try: self.smua_measure_nplc = round(float(nplc), 3) except KeyError: self.error_queue.append(Error(120, "malformed command")) @message(r'^.*$') - def unknown_message(self): + def unknown_message(self) -> None: self.error_queue.append(Error(100, "malformed command")) diff --git a/src/comet/emulator/keithley/k2700.py b/src/comet/emulator/keithley/k2700.py index d403974..d66171b 100644 --- a/src/comet/emulator/keithley/k2700.py +++ b/src/comet/emulator/keithley/k2700.py @@ -1,6 +1,5 @@ import random import time -from typing import List from comet.emulator import IEC60488Emulator, message, run from comet.emulator.utils import Error @@ -15,13 +14,13 @@ def __init__(self) -> None: self.sense_voltage_average_tcontrol: str = "MOV" self.sense_voltage_average_count: int = 10 self.sense_voltage_average_state: bool = False - self.error_queue: List[Error] = [] + self.error_queue: list[Error] = [] self.system_beeper_state: bool = True self.trigger_delay_auto: bool = True self.trigger_delay: float = 0.001 @message(r'^\*RST$') - def set_rst(self): + def set_rst(self) -> None: self.sense_voltage_average_tcontrol = "MOV" self.sense_voltage_average_count = 10 self.sense_voltage_average_state = False @@ -31,35 +30,35 @@ def set_rst(self): self.trigger_delay = 0.001 @message(r'^\*CLS$') - def set_cls(self): + def set_cls(self) -> None: self.error_queue.clear() @message(r'^:?SENS:VOLT:AVER:TCON\?$') - def get_sense_average_tcontrol(self): + def get_sense_average_tcontrol(self) -> str: return self.sense_voltage_average_tcontrol @message(r'^:?SENS:VOLT:AVER:TCON\s+(REP|MOV)$') - def set_sense_average_tcontrol(self, name: str): + def set_sense_average_tcontrol(self, name: str) -> None: self.sense_voltage_average_tcontrol = name @message(r'^:?SENS:VOLT:AVER:COUN[T]?\?$') - def get_sense_average_count(self): + def get_sense_average_count(self) -> str: return format(self.sense_voltage_average_count, "d") @message(r'^:?SENS:VOLT:AVER:COUN[T]?\s+(\d+)$') - def set_sense_average_count(self, count: str): + def set_sense_average_count(self, count: str) -> None: self.sense_voltage_average_count = int(count) @message(r'^:?SENS:VOLT:AVER(?::STAT[E]?)?\?$') - def get_sense_voltage_average_state(self): + def get_sense_voltage_average_state(self) -> str: return format(self.sense_voltage_average_state, "d") @message(r'^:?SENS:VOLT:AVER(?::STAT[E]?)?\s+(OFF|ON|0|1)$') - def set_sense_voltage_average_state(self, value): + def set_sense_voltage_average_state(self, value) -> None: self.sense_voltage_average_state = {"0": False, "1": True, "OFF": False, "ON": True}[value] @message(r'^:?SYST:ERR\?$') - def get_system_error(self): + def get_system_error(self) -> str: if self.error_queue: error = self.error_queue.pop(0) else: @@ -67,23 +66,22 @@ def get_system_error(self): return f'{error.code}, "{error.message}"' @message(r'^:?SYST:BEEP(?::STAT)?\?$') - def get_beeper_state(self): + def get_beeper_state(self) -> str: return format(self.system_beeper_state, "d") @message(r'^:?SYST:BEEP(?::STAT)? (OFF|ON|0|1)$') - def set_beeper_state(self, value): + def set_beeper_state(self, value) -> None: self.system_beeper_state = {'0': False, '1': True, 'OFF': False, 'ON': True}[value] @message(r'^:?INIT(?::IMM)$') - def set_init(self): - ... + def set_init(self) -> None: ... @message(r'^:?READ\?$') - def get_read(self): + def get_read(self) -> None: self.get_fetch() @message(r'^:?FETC[H]?\?$') - def get_fetch(self): + def get_fetch(self) -> str: vdc = random.uniform(.00025, .001) time.sleep(random.uniform(.5, 1.0)) # rev B10 ;) return "{:E},+0.000,+0.000,+0.000,+0.000".format(vdc) @@ -91,26 +89,26 @@ def get_fetch(self): # Trigger @message(r':?TRIG:DEL:AUTO\?') - def get_trigger_delay_auto(self): + def get_trigger_delay_auto(self) -> str: return format(self.trigger_delay_auto, "d") @message(r':?TRIG:DEL:AUTO\s+(OFF|ON|0|1)') - def set_trigger_delay_auto(self, value): + def set_trigger_delay_auto(self, value) -> None: self.trigger_delay_auto = {'0': False, '1': True, 'OFF': False, 'ON': True}[value] @message(r':?TRIG:DEL\?') - def get_trigger_delay(self): + def get_trigger_delay(self) -> str: return format(self.trigger_delay, "E") @message(r':?TRIG:DEL\s+(.+)') - def set_trigger_delay(self, value): + def set_trigger_delay(self, value) -> None: try: self.trigger_delay = min(999999.999, max(0.001, float(value))) except ValueError: self.error_queue.append(Error(-113, "undefined header")) @message(r'^(.*)$') - def unknown_message(self, request): + def unknown_message(self, request) -> None: self.error_queue.append(Error(101, "malformed command")) diff --git a/src/comet/emulator/keithley/k6514.py b/src/comet/emulator/keithley/k6514.py index ec5f9bf..f16039b 100644 --- a/src/comet/emulator/keithley/k6514.py +++ b/src/comet/emulator/keithley/k6514.py @@ -1,6 +1,5 @@ import random import time -from typing import Dict, List from comet.emulator import IEC60488Emulator, message, run from comet.emulator.utils import Error @@ -12,7 +11,7 @@ class K6514Emulator(IEC60488Emulator): def __init__(self) -> None: super().__init__() - self.error_queue: List[Error] = [] + self.error_queue: list[Error] = [] self.zero_check: bool = False self.zero_correction: bool = False self.sense_function: str = "VOLT" @@ -24,7 +23,7 @@ def __init__(self) -> None: self.sense_nplc: float = 5.0 @message(r'^\*RST$') - def set_rst(self): + def set_rst(self) -> None: self.error_queue.clear() self.zero_check = False self.zero_correction = False @@ -34,18 +33,18 @@ def set_rst(self): self.sense_average_state = 0 self.sense_current_range = 2.1e-4 self.sense_current_range_auto = 1 - self.sense_nplc = 5. + self.sense_nplc = 5.0 @message(r'^\*CLS$') - def set_cls(self): + def set_cls(self) -> None: self.error_queue.clear() @message(r'^:?SYST:ERR:COUN\?$') - def get_system_error_count(self): + def get_system_error_count(self) -> str: return format(len(self.error_queue), "d") @message(r'^:?SYST:ERR(?::NEXT)?\?$') - def get_system_error_next(self): + def get_system_error_next(self) -> str: if self.error_queue: error = self.error_queue.pop(0) else: @@ -53,18 +52,17 @@ def get_system_error_next(self): return f'{error.code}, "{error.message}"' @message(r'^:?FORM:ELEM (READ)$') - def set_format_elements(self, value): - ... + def set_format_elements(self, value) -> None: ... @message(r'^:?FORM:ELEM\?$') - def get_format_elements(self): + def get_format_elements(self) -> str: return "READ" @message(r'^:?INIT$') - def set_init(self): + def set_init(self) -> None: time.sleep(random.uniform(.5, 1.0)) - def _reading(self): + def _reading(self) -> float: if self.sense_function == "CURR": curr_min = float(self.options.get("curr.min", 2.5e-10)) curr_max = float(self.options.get("curr.max", 2.5e-9)) @@ -76,108 +74,108 @@ def _reading(self): return 0 @message(r'^:?FETC[H]?\?$') - def get_fetch(self): + def get_fetch(self) -> str: return format(self._reading(), "E") @message(r'^:?READ\?$') - def get_read(self): + def get_read(self) -> str: time.sleep(random.uniform(.25, 1.0)) return format(self._reading(), "E") @message(r'^:?SYST:ZCH\s+(0|1|ON|OFF)$') - def set_zero_check(self, value): + def set_zero_check(self, value) -> None: self.zero_check = {"0": False, "1": True, "OFF": False, "ON": True}[value] @message(r'^:?SYST:ZCH\?$') - def get_zero_check(self): + def get_zero_check(self) -> str: return {False: "0", True: "1"}[self.zero_check] @message(r'^:?SYST:ZCOR\s+(0|1|ON|OFF)$') - def set_zero_correction(self, value): + def set_zero_correction(self, value) -> None: self.zero_correction = {"0": False, "1": True, "OFF": False, "ON": True}[value] @message(r'^:?SYST:ZCOR\?$') - def get_zero_correction(self): + def get_zero_correction(self) -> str: return {False: "0", True: "1"}[self.zero_correction] @message(r'^:?SENS:FUNC \'(VOLT|CURR|RES|CHAR)(?:\:DC)?\'$') - def set_sense_function(self, value: str): + def set_sense_function(self, value: str) -> None: self.sense_function = value @message(r'^:?SENS:FUNC\?$') - def get_sense_function(self): + def get_sense_function(self) -> str: return f"\"{self.sense_function}:DC\"" # Average @message(r'^(?::?SENS)?:AVER:TCON\?$') - def get_sense_average_tcontrol(self): + def get_sense_average_tcontrol(self) -> str: return self.sense_average_tcontrol @message(r'^(?::?SENS)?:AVER:TCON (REP|MOV)$') - def set_sense_average_tcontrol(self, state: str): + def set_sense_average_tcontrol(self, state: str) -> None: self.sense_average_tcontrol = state @message(r'^(?::?SENS)?:AVER:COUN\?$') - def get_sense_average_count(self): + def get_sense_average_count(self) -> int: return self.sense_average_count @message(r'^(?::?SENS)?:AVER:COUN (\d+)$') - def set_sense_average_count(self, count: str): + def set_sense_average_count(self, count: str) -> None: self.sense_average_count = int(count) @message(r'^(?::?SENS)?:AVER(?::STAT)?\?$') - def get_sense_average_state(self): + def get_sense_average_state(self) -> int: return int(self.sense_average_state) @message(r'^(?::?SENS)?:AVER(?::STAT)? (OFF|ON|0|1)$') - def set_sense_average_state(self, state: str): + def set_sense_average_state(self, state: str) -> None: self.sense_average_state = {"OFF": 0, "ON": 1, "0": 0, "1": 1}[state] # Current range @message(r'^(?::?SENS)?:CURR:RANG\?$') - def get_sense_current_range(self): + def get_sense_current_range(self) -> str: return format(self.sense_current_range, "E") @message(r'^(?::?SENS)?:CURR:RANG(?::UPP)?\s+(.+)$') - def set_sense_current_range(self, value: str): + def set_sense_current_range(self, value: str) -> None: try: self.sense_current_range = float(value) except Exception: self.error_queue.append(Error(102, "invalid header")) @message(r'^(?::?SENS)?:CURR:RANG:AUTO\?$') - def get_sense_current_range_auto(self): + def get_sense_current_range_auto(self) -> int: return self.sense_current_range_auto @message(r'^(?::?SENS)?:CURR:RANG:AUTO\s+(OFF|ON|0|1)$') - def set_sense_current_range_auto(self, state: str): + def set_sense_current_range_auto(self, state: str) -> None: self.sense_current_range_auto = {"OFF": 0, "ON": 1, "0": 0, "1": 1}[state] @message(r'^(?::?SENS)?:CURR:RANG:AUTO:ULIM\s+(.+)$') - def set_sense_current_range_auto_ulimit(self, value: str): + def set_sense_current_range_auto_ulimit(self, value: str) -> None: ... # TODO @message(r'^(?::?SENS)?:CURR:RANG:AUTO:LLIM\s+(.+)$') - def set_sense_current_range_auto_llimit(self, value: str): + def set_sense_current_range_auto_llimit(self, value: str) -> None: ... # TODO # NPLC (coupled commands) @message(r'^(?::?SENS)?:(:?CURR|VOLT|RES|CHAR):NPLC\?$') - def get_sense_nplc(self): - return self.sense_nplc + def get_sense_nplc(self) -> str: + return format(self.sense_nplc, "f") # TODO precision? @message(r'^(?::?SENS)?:(:?CURR|VOLT|RES|CHAR):NPLC\s+(.+)$') - def set_sense_nplc(self, mode: str, value: str): + def set_sense_nplc(self, mode: str, value: str) -> None: try: self.sense_nplc = max(0.01, min(10.0, float(value))) except Exception: self.error_queue.append(Error(102, "invalid header")) @message(r'^(.*)$') - def unknown_message(self, request): + def unknown_message(self, request) -> None: self.error_queue.append(Error(101, "malformed command")) diff --git a/src/comet/emulator/keithley/k6517b.py b/src/comet/emulator/keithley/k6517b.py index d06011b..7f55498 100644 --- a/src/comet/emulator/keithley/k6517b.py +++ b/src/comet/emulator/keithley/k6517b.py @@ -1,6 +1,5 @@ import random import time -from typing import List from comet.emulator import IEC60488Emulator, message, run from comet.emulator.utils import Error @@ -12,7 +11,7 @@ class K6517BEmulator(IEC60488Emulator): def __init__(self) -> None: super().__init__() - self.error_queue: List[Error] = [] + self.error_queue: list[Error] = [] self.zero_check: bool = False self.zero_correction: bool = False self.sense_function: str = "VOLT" @@ -24,9 +23,10 @@ def __init__(self) -> None: self.source_voltage_range: float = 100.0 self.source_voltage_mconnect: bool = False self.source_current_limit_state: bool = False + self.sense_nplc: float = 5.0 @message(r'^\*RST$') - def set_reset(self): + def set_reset(self) -> None: self.error_queue.clear() self.zero_check = False self.zero_correction = False @@ -39,17 +39,18 @@ def set_reset(self): self.source_voltage_range = 100.0 self.source_voltage_mconnect = False self.source_current_limit_state = False + self.sense_nplc = 5.0 @message(r'^\*CLS$') - def set_clear(self): + def set_clear(self) -> None: self.error_queue.clear() @message(r'^:?SYST:ERR:COUN\?$') - def get_system_error_count(self): + def get_system_error_count(self) -> str: return format(len(self.error_queue), "d") @message(r'^:?SYST:ERR(?::NEXT)?\?$') - def get_system_error_next(self): + def get_system_error_next(self) -> str: if self.error_queue: error = self.error_queue.pop(0) else: @@ -57,98 +58,96 @@ def get_system_error_next(self): return f'{error.code}, "{error.message}"' @message(r'^:?FORM:ELEM (READ)$') - def set_format_elements(self, value): - ... + def set_format_elements(self, value) -> None: ... @message(r'^:?FORM:ELEM\?$') - def get_format_elements(self): + def get_format_elements(self) -> str: return "READ" @message(r'^\*ESR\?$') - def get_esr(self): + def get_esr(self) -> str: return format(random.randint(0, 1)) @message(r'^:?SYST:ERR\?$') - def get_system_error(self): + def get_system_error(self) -> str: return '0, "no error"' @message(r'^:?SYST:ZCH\?$') - def get_system_zerocheck(self): + def get_system_zerocheck(self) -> str: return format(self.zero_check, "d") @message(r'^:?SYST:ZCH\s+(OFF|ON)$') - def set_system_zerocheck(self, value): + def set_system_zerocheck(self, value) -> None: self.zero_check = {"OFF": False, "ON": True}[value] @message(r'^:?SYST:ZCOR(?:STAT)?\s+(0|1|ON|OFF)$') - def set_zero_correction(self, value): + def set_zero_correction(self, value) -> None: self.zero_correction = {"0": False, "1": True, "OFF": False, "ON": True}[value] @message(r'^:?SYST:ZCOR(?:STAT)\?$') - def get_zero_correction(self): + def get_zero_correction(self) -> str: return {False: "0", True: "1"}[self.zero_correction] @message(r'^:?SENS:FUNC \'(VOLT|CURR|RES|CHAR)(?:\:DC)?\'$') - def set_sense_function(self, value: str): + def set_sense_function(self, value: str) -> None: self.sense_function = value @message(r'^:?SENS:FUNC\?$') - def get_sense_function(self): + def get_sense_function(self) -> str: return f'"{self.sense_function}:DC"' # Output @message(r'^:?OUTP(?::STAT)?\s+(0|1|ON|OFF)$') - def set_output_state(self, value): + def set_output_state(self, value) -> None: self.output_state = {"0": False, "1": True, "OFF": False, "ON": True}[value] @message(r'^:?OUTP(?::STAT)?\?$') - def get_output_state(self): + def get_output_state(self) -> str: return {False: "0", True: "1"}[self.output_state] # Source @message(r'^:?SOUR:VOLT(?::LEV(?::IMM(?::AMPL)?)?)?\s+(.+)$') - def set_source_voltage_level_immediate_amplitude(self, level): + def set_source_voltage_level_immediate_amplitude(self, level) -> None: try: self.source_voltage_level_immediate_amplitude = float(level) except ValueError: self.error_queue.append(Error(-171, "Invalid expression")) @message(r'^:?SOUR:VOLT(?::LEV(?::IMM(?::AMPL)?)?)?\?$') - def get_source_voltage_level_immediate_amplitude(self): + def get_source_voltage_level_immediate_amplitude(self) -> str: return format(self.source_voltage_level_immediate_amplitude, "E") @message(r'^:?SOUR:VOLT:RANG\s+(.+)$') - def set_source_voltage_range(self, level): + def set_source_voltage_range(self, level) -> None: try: self.source_voltage_range = 100.0 if float(level) <= 100.0 else 1000.0 except ValueError: self.error_queue.append(Error(-171, "Invalid expression")) @message(r'^:?SOUR:VOLT:RANG\?$') - def get_source_voltage_range(self): + def get_source_voltage_range(self) -> str: return format(self.source_voltage_range, "E") @message(r'^:?SOUR:CURR:LIM(?::STAT)?\?$') - def get_source_current_limit_state(self): + def get_source_current_limit_state(self) -> str: return {False: "0", True: "1"}[self.source_current_limit_state] @message(r'^:?SOUR:VOLT:MCON\s+(0|1|ON|OFF)$') - def set_source_voltage_mconnect(self, value): + def set_source_voltage_mconnect(self, value) -> None: self.source_voltage_mconnect = {"0": False, "1": True, "OFF": False, "ON": True}[value] @message(r'^:?SOUR:VOLT:MCON\?$') - def get_source_voltage_mconnect(self): + def get_source_voltage_mconnect(self) -> str: return {False: "0", True: "1"}[self.source_voltage_mconnect] # Measure @message(r'^:?INIT$') - def set_init(self): - ... + def set_init(self) -> None: ... - def _reading(self): + def _reading(self) -> float: if self.sense_function == "CURR": curr_min = float(self.options.get("curr.min", 2.5e-10)) curr_max = float(self.options.get("curr.max", 2.5e-9)) @@ -160,22 +159,22 @@ def _reading(self): return 0 @message(r'^:?READ\?$') - def get_read(self): + def get_read(self) -> str: time.sleep(0.25) return format(self._reading(), "E") @message(r'^:?FETC[H]?\?$') - def get_fetch(self): + def get_fetch(self) -> str: return format(self._reading(), "E") @message(r'^:?MEAS:CURR\?$') - def get_measure_current(self): + def get_measure_current(self) -> str: time.sleep(random.uniform(0.25, 1.0)) vdc = random.uniform(0.000025, 0.0001) return format(vdc, "E") @message(r'^:?MEAS:VOLT\?$') - def get_measure_voltage(self): + def get_measure_voltage(self) -> str: time.sleep(random.uniform(0.25, 1.0)) vdc = random.uniform(10.0, 100.0) return format(vdc, "E") @@ -183,73 +182,73 @@ def get_measure_voltage(self): # Average @message(r'^:?SENS:(VOLT|CURR):AVER:TCON\?$') - def get_sense_average_tcontrol(self, function: str): + def get_sense_average_tcontrol(self, function: str) -> str: return format(self.sense_average_tcontrol[function], "E") @message(r'^:?SENS:(VOLT|CURR):AVER:TCON (MOV|REP)$') - def set_sense_average_tcontrol(self, function: str, tcontrol: str): + def set_sense_average_tcontrol(self, function: str, tcontrol: str) -> None: self.sense_average_tcontrol[function] = tcontrol @message(r'^:?SENS:(VOLT|CURR):AVER:COUN[T]?\?$') - def get_sense_average_count(self, function: str): + def get_sense_average_count(self, function: str) -> str: return format(self.sense_average_count[function], "E") @message(r'^:?SENS:(VOLT|CURR):AVER:COUN[T]? (\d+)$') - def set_sense_average_count(self, function: str, count: str): + def set_sense_average_count(self, function: str, count: str) -> None: self.sense_average_count[function] = int(count) @message(r'^:?SENS:(VOLT|CURR):AVER:STAT[E]?\?$') - def get_sense_average_state(self, function: str): + def get_sense_average_state(self, function: str) -> str: return format(self.sense_average_state[function], "E") @message(r'^:?SENS:(VOLT|CURR):AVER:STAT[E]? (OFF|ON|0|1)$') - def set_sense_average_state(self, function: str, state: str): + def set_sense_average_state(self, function: str, state: str) -> None: self.sense_average_state[function] = {"OFF": 0, "ON": 1, "0": 0, "1": 1}[state] # Current range @message(r'^(?::?SENS)?:CURR:RANG\?$') - def get_sense_current_range(self): + def get_sense_current_range(self) -> str: return format(self.sense_current_range, "E") @message(r'^(?::?SENS)?:CURR:RANG(?::UPP)?\s+(.+)$') - def set_sense_current_range(self, value: str): + def set_sense_current_range(self, value: str) -> None: try: self.sense_current_range = float(value) except Exception: self.error_queue.append(Error(102, "invalid header")) @message(r'^(?::?SENS)?:CURR:RANG:AUTO\?$') - def get_sense_current_range_auto(self): + def get_sense_current_range_auto(self) -> int: return self.sense_current_range_auto @message(r'^(?::?SENS)?:CURR:RANG:AUTO\s+(OFF|ON|0|1)$') - def set_sense_current_range_auto(self, state: str): + def set_sense_current_range_auto(self, state: str) -> None: self.sense_current_range_auto = {"OFF": 0, "ON": 1, "0": 0, "1": 1}[state] @message(r'^(?::?SENS)?:CURR:RANG:AUTO:ULIM\s+(.+)$') - def set_sense_current_range_auto_ulimit(self, value: str): + def set_sense_current_range_auto_ulimit(self, value: str) -> None: ... # TODO @message(r'^(?::?SENS)?:CURR:RANG:AUTO:LLIM\s+(.+)$') - def set_sense_current_range_auto_llimit(self, value: str): + def set_sense_current_range_auto_llimit(self, value: str) -> None: ... # TODO # NPLC (coupled commands) @message(r'^(?::?SENS)?:(:?CURR|VOLT|RES|CHAR):NPLC\?$') - def get_sense_nplc(self): - return self.sense_nplc + def get_sense_nplc(self) -> str: + return format(self.sense_nplc, "f") # TODO precision? @message(r'^(?::?SENS)?:(:?CURR|VOLT|RES|CHAR):NPLC\s+(.+)$') - def set_sense_nplc(self, mode: str, value: str): + def set_sense_nplc(self, mode: str, value: str) -> None: try: self.sense_nplc = max(0.01, min(10.0, float(value))) except Exception: self.error_queue.append(Error(102, "invalid header")) @message(r'^(.*)$') - def unknown_message(self, request): + def unknown_message(self, request) -> None: self.error_queue.append(Error(101, "malformed command")) diff --git a/src/comet/emulator/keithley/k707b.py b/src/comet/emulator/keithley/k707b.py index a2170fd..b05cecf 100644 --- a/src/comet/emulator/keithley/k707b.py +++ b/src/comet/emulator/keithley/k707b.py @@ -1,5 +1,3 @@ -from typing import List, Set - from comet.emulator import IEC60488Emulator, message, run from comet.emulator.utils import tsp_print, Error from comet.utils import combine_matrix @@ -8,31 +6,31 @@ class K707BEmulator(IEC60488Emulator): IDENTITY: str = "Keithley Inc., Model 707B, 43768438, v1.0 (Emulator)" - CHANNELS = combine_matrix("1234", "ABCDEFGH", (format(i, "02d") for i in range(1, 13))) + CHANNELS: list[str] = combine_matrix("1234", "ABCDEFGH", (format(i, "02d") for i in range(1, 13))) def __init__(self) -> None: super().__init__() - self.error_queue: List[Error] = [] - self.closed_channels: Set[str] = set() + self.error_queue: list[Error] = [] + self.closed_channels: set[str] = set() @message(r'^reset\(\)|\*RST$') - def set_reset(self): + def set_reset(self) -> None: self.error_queue.clear() @message(r'^clear\(\)|\*CLS$') - def set_clear(self): + def set_clear(self) -> None: self.error_queue.clear() @message(r'errorqueue\.clear\(\)') - def set_errorqueue_clear(self): + def set_errorqueue_clear(self) -> None: self.error_queue.clear() @message(tsp_print(r'errorqueue\.count')) - def get_errorqueue_count(self): + def get_errorqueue_count(self) -> str: return format(len(self.error_queue), "d") @message(tsp_print(r'errorqueue\.next\(\)')) - def get_errorqueue_next(self): + def get_errorqueue_next(self) -> str: if self.error_queue: error = self.error_queue.pop(0) else: @@ -40,18 +38,18 @@ def get_errorqueue_next(self): return f"{error.code}, \"{error.message}\", 0, 0" @message(tsp_print(r'channel\.getclose\(([^\)]+)\)')) - def get_channel_getclose(self, channels): + def get_channel_getclose(self, channels) -> str: if not self.closed_channels: return "nil" return ";".join(sorted(self.closed_channels)) @message(r'channel\.close\(([^\)]+)\)') - def set_channel_close(self, channels): + def set_channel_close(self, channels) -> None: channels = channels.strip('"').split(',') self.closed_channels.update(channels) @message(r'channel\.open\(([^\)]+)\)') - def set_channel_open(self, channels): + def set_channel_open(self, channels) -> None: channels = channels.strip('"').split(',') if "allslots" in channels: self.closed_channels.clear() @@ -61,7 +59,7 @@ def set_channel_open(self, channels): self.closed_channels.remove(channel) @message(r'^(.*)$') - def unknown_message(self, v): + def unknown_message(self, v) -> None: self.error_queue.append(Error(101, "malformed command")) diff --git a/src/comet/emulator/keithley/k708b.py b/src/comet/emulator/keithley/k708b.py index 47d7628..cdb44b2 100644 --- a/src/comet/emulator/keithley/k708b.py +++ b/src/comet/emulator/keithley/k708b.py @@ -1,4 +1,4 @@ -from comet.emulator import message, run +from comet.emulator import run from comet.utils import combine_matrix from .k707b import K707BEmulator @@ -7,7 +7,7 @@ class K708BEmulator(K707BEmulator): IDENTITY: str = "Keithley Inc., Model 708B, 43768438, v1.0 (Emulator)" - CHANNELS = combine_matrix("1", "ABCDEFGH", "0", "12345678") + CHANNELS: list[str] = combine_matrix("1", "ABCDEFGH", "0", "12345678") if __name__ == "__main__": diff --git a/src/comet/emulator/keysight/e4980a.py b/src/comet/emulator/keysight/e4980a.py index efb522f..eb118b7 100644 --- a/src/comet/emulator/keysight/e4980a.py +++ b/src/comet/emulator/keysight/e4980a.py @@ -22,7 +22,7 @@ def __init__(self) -> None: self.bias_state: bool = False @message(r'^\*RST$') - def set_rst(self): + def set_rst(self) -> None: self.function_impedance_type = "CPD" self.correction_open_state = 0 self.correction_use = 0 @@ -87,7 +87,7 @@ def set_correction_length(self, length: str) -> None: self.correction_length = int(length) @message(r'^:?FETC[H]?(?:(?::IMP)?:FORM)?\?$') - def get_fetch(self): + def get_fetch(self) -> str: # TODO cp_min = float(self.options.get("cp.min", 2.5e-10)) cp_max = float(self.options.get("cp.max", 2.5e-9)) @@ -98,27 +98,27 @@ def get_fetch(self): return '{:E},{:E},{:+d}'.format(prim, sec, 0) @message(r'^:?BIAS:POL:CURR(\::LEV)?\?$') - def get_bias_polarity_current_level(self): + def get_bias_polarity_current_level(self) -> str: return format(random.random() / 1000., "E") @message(r'^:?BIAS:POL:VOLT(\::LEV)?\?$') - def get_bias_polarity_voltage_level(self): + def get_bias_polarity_voltage_level(self) -> str: return format(random.random() / 100., "E") @message(r'^:?BIAS:VOLT(?::LEV)?\?$') - def get_bias_voltage_level(self): + def get_bias_voltage_level(self) -> str: return format(self.bias_voltage_level, "E") @message(r'^:?BIAS:VOLT(?::LEV)?\s+(.+)$') - def set_bias_voltage_level(self, value): + def set_bias_voltage_level(self, value) -> None: self.bias_voltage_level = float(value) @message(r'^:?BIAS:STAT\?$') - def get_bias_state(self): + def get_bias_state(self) -> str: return format(self.bias_state, "d") @message(r'^:?BIAS:STAT\s+(0|1|ON|OFF)$') - def set_bias_state(self, value): + def set_bias_state(self, value) -> None: self.bias_state = {"0": False, "1": True, "OFF": False, "ON": True}[value] diff --git a/src/comet/emulator/marzhauser/tango.py b/src/comet/emulator/marzhauser/tango.py index 11edd58..e4530de 100644 --- a/src/comet/emulator/marzhauser/tango.py +++ b/src/comet/emulator/marzhauser/tango.py @@ -1,6 +1,6 @@ """TANGO emulator.""" -from typing import Dict +from typing import Optional from comet.emulator import Emulator, message, run @@ -14,10 +14,10 @@ class TangoEmulator(Emulator): def __init__(self) -> None: super().__init__() - self.position: Dict[str, float] = {"x": 0.0, "y": 0.0, "z": 0.0} - self.calst: Dict[str, int] = {"x": 3, "y": 3, "z": 3} - self.statusaxis: Dict[str, str] = {"x": "@", "y": "@", "z": "@"} - self.velocity: Dict[str, float] = {"x": 10.0, "y": 10.0, "z": 10.0} + self.position: dict[str, float] = {"x": 0.0, "y": 0.0, "z": 0.0} + self.calst: dict[str, int] = {"x": 3, "y": 3, "z": 3} + self.statusaxis: dict[str, str] = {"x": "@", "y": "@", "z": "@"} + self.velocity: dict[str, float] = {"x": 10.0, "y": 10.0, "z": 10.0} self.autostatus: bool = True # Controller informations @@ -41,32 +41,36 @@ def get_error(self) -> str: # Calibration @message(r'^\!?cal$') - def set_cal(self): + def set_cal(self) -> Optional[str]: self.calst["x"] |= 0x1 self.calst["y"] |= 0x1 self.calst["z"] |= 0x1 if self.autostatus: return "AAA-." + return None @message(r'^\!?cal (x|y|z)$') - def set_cal_xyz(self, axes): + def set_cal_xyz(self, axes) -> Optional[str]: self.calst[axes] |= 0x1 if self.autostatus: return "A" + return None @message(r'^\!?rm$') - def set_rm(self): + def set_rm(self) -> Optional[str]: self.calst["x"] |= 0x2 self.calst["y"] |= 0x2 self.calst["z"] |= 0x2 if self.autostatus: return "DDD-." + return None @message(r'^\!?rm (x|y|z)$') - def set_rm_xyz(self, axes): + def set_rm_xyz(self, axes) -> Optional[str]: self.calst[axes] &= 0x1 if self.autostatus: return "D" + return None @message(r'^\??calst$') def get_calst(self) -> str: @@ -83,87 +87,88 @@ def get_calst_xyz(self, axis) -> str: # Positioning @message(r'^\?pos$') - def get_pos(self): + def get_pos(self) -> str: x = self.position.get("x", 0) y = self.position.get("y", 0) z = self.position.get("z", 0) return f"{x:.3f} {y:.3f} {z:.3f}" @message(r'^\?pos (x|y|z)$') - def get_pos_xyz(self, axis): + def get_pos_xyz(self, axis) -> str: value = self.position.get(axis) return f"{value:.3f}" @message(r'^\!?moa ([^\sxyza]+) ([^\s]+) ([^\s]+)$') - def set_move_absolute(self, x, y, z): + def set_move_absolute(self, x, y, z) -> Optional[str]: self.position["x"] = float(x) self.position["y"] = float(y) self.position["z"] = float(z) if self.autostatus: return "@@@-." + return None @message(r'^\!?moa (x|y|z) ([^\s]+)$') - def set_move_absolute_xyz(self, axis, value): + def set_move_absolute_xyz(self, axis, value) -> Optional[str]: self.position[axis] = float(value) if self.autostatus: return "@@@-." + return None @message(r'^\!?mor ([^\sxyza]+) ([^\s]+) ([^\s]+)$') - def set_move_relative(self, x, y, z): + def set_move_relative(self, x, y, z) -> Optional[str]: self.position["x"] = float(x) self.position["y"] = float(y) self.position["z"] = float(z) if self.autostatus: return "@@@-." + return None @message(r'^\!?mor (x|y|z) ([^\s]+)$') - def set_move_relative_xyz(self, axis, value): + def set_move_relative_xyz(self, axis, value) -> Optional[str]: self.position[axis] = float(value) if self.autostatus: return "@@@-." + return None @message(r'^\?statusaxis$') - def get_statusaxis(self): + def get_statusaxis(self) -> str: x = self.statusaxis.get("x", "-") y = self.statusaxis.get("y", "-") z = self.statusaxis.get("z", "-") return f"{x}{y}{z}-.-" @message(r'^\?statusaxis (x|y|z)$') - def get_statusaxis_xyz(self, axis): + def get_statusaxis_xyz(self, axis) -> str: value = self.statusaxis.get(axis, "-") return f"{value}" @message(r'^\?vel$') - def get_vel(self): + def get_vel(self) -> str: x = self.velocity.get("x") y = self.velocity.get("y") z = self.velocity.get("z") return f"{x:.3f} {y:.3f} {z:.3f}" @message(r'^\?vel (x|y|z)$') - def get_vel_xyz(self, axis): + def get_vel_xyz(self, axis) -> str: value = self.velocity.get(axis) return f"{value:.3f}" @message(r'^!vel (x|y|z) ([^\s]+)$') - def set_vel_xyz(self, axis, value): + def set_vel_xyz(self, axis, value) -> str: self.velocity[axis]= float(value) return "@@@-." # System configuration @message(r'^save$') - def action_save(self): - ... + def action_save(self) -> None: ... @message(r'^restore$') - def action_restore(self): - ... + def action_restore(self) -> None: ... @message(r'^reset$') - def action_reset(self): - ... + def action_reset(self) -> None: ... if __name__ == "__main__": diff --git a/src/comet/emulator/rohde_schwarz/nge100.py b/src/comet/emulator/rohde_schwarz/nge100.py index 521dc5d..56cf278 100644 --- a/src/comet/emulator/rohde_schwarz/nge100.py +++ b/src/comet/emulator/rohde_schwarz/nge100.py @@ -1,6 +1,5 @@ """Rohde&Schwarz NGE100 power supply emulator""" -from typing import List import math from comet.emulator import Emulator @@ -16,23 +15,20 @@ class NGE100Emulator(Emulator): def __init__(self) -> None: super().__init__() - self.voltage_levels: List[float] = [0.0, 0.0, 0.0] - self.current_limits: List[float] = [0.0, 00.0, 0.0] - self.enabled_channels: List[bool] = [False, False, False] + self.voltage_levels: list[float] = [0.0, 0.0, 0.0] + self.current_limits: list[float] = [0.0, 00.0, 0.0] + self.enabled_channels: list[bool] = [False, False, False] self.selected_channel: int = 0 - self.resistances: List[float] = [1, 1e3, math.inf] # 1 Ohm, 1 kOhm, infinite + self.resistances: list[float] = [1, 1e3, math.inf] # 1 Ohm, 1 kOhm, infinite def get_voltage(self) -> float: - voltage_from_current_limit = ( self.current_limits[self.selected_channel] * self.resistances[self.selected_channel] ) - voltage_from_voltage_level = self.voltage_levels[self.selected_channel] - return min(voltage_from_current_limit, voltage_from_voltage_level) def get_current(self) -> float: @@ -41,7 +37,6 @@ def get_current(self) -> float: / self.resistances[self.selected_channel] ) current_from_current_limit = self.current_limits[self.selected_channel] - return min(current_from_voltage_level, current_from_current_limit) @message(r"^\*IDN\?$") @@ -64,29 +59,21 @@ def set_enabled(self, enabled: int) -> None: def get_enabled(self) -> str: return str(int(self.enabled_channels[self.selected_channel])) - @message( - r"(?:SOUR(?:ce)?:)?VOLT(?:age)?(?::LEV(?:el)?)?(?::IMM(?:ediate)?)?(?::AMPL(?:itude)?)? (\d+\.?\d*)$" - ) + @message(r"(?:SOUR(?:ce)?:)?VOLT(?:age)?(?::LEV(?:el)?)?(?::IMM(?:ediate)?)?(?::AMPL(?:itude)?)? (\d+\.?\d*)$") def set_voltage_level(self, voltage_level: float) -> None: voltage_level = min(max(0, float(voltage_level)), 32) self.voltage_levels[self.selected_channel] = voltage_level - @message( - r"(?:SOUR(?:ce)?:)?VOLT(?:age)?(?::LEV(?:el)?)?(?::IMM(?:ediate)?)?(?::AMPL(?:itude)?)?\?$" - ) + @message(r"(?:SOUR(?:ce)?:)?VOLT(?:age)?(?::LEV(?:el)?)?(?::IMM(?:ediate)?)?(?::AMPL(?:itude)?)?\?$") def get_voltage_level(self) -> str: return str(self.voltage_levels[self.selected_channel]) - @message( - r"(?:SOUR(?:ce)?:)?CURR(?:ent)?(?::LEV(?:el)?)?(?::IMM(?:ediate)?)?(?::AMPL(?:itude)?)? (\d+\.?\d*)$" - ) + @message(r"(?:SOUR(?:ce)?:)?CURR(?:ent)?(?::LEV(?:el)?)?(?::IMM(?:ediate)?)?(?::AMPL(?:itude)?)? (\d+\.?\d*)$") def set_current_limit(self, current_limit: float) -> None: current_limit = min(max(0, float(current_limit)), 3) self.current_limits[self.selected_channel] = current_limit - @message( - r"(?:SOUR(?:ce)?:)?CURR(?:ent)?(?::LEV(?:el)?)?(?::IMM(?:ediate)?)?(?::AMPL(?:itude)?)?\?$" - ) + @message(r"(?:SOUR(?:ce)?:)?CURR(?:ent)?(?::LEV(?:el)?)?(?::IMM(?:ediate)?)?(?::AMPL(?:itude)?)?\?$") def get_current_limit(self) -> str: return str(self.current_limits[self.selected_channel]) diff --git a/src/comet/emulator/rohde_schwarz/sma100b.py b/src/comet/emulator/rohde_schwarz/sma100b.py index fc7083d..8e357dc 100644 --- a/src/comet/emulator/rohde_schwarz/sma100b.py +++ b/src/comet/emulator/rohde_schwarz/sma100b.py @@ -1,7 +1,5 @@ """Rohde Schwarz SMA100B signal generator emulator""" -from typing import List - from comet.emulator import Emulator from comet.emulator import message, run from comet.emulator.utils import Error @@ -16,7 +14,7 @@ class SMA100BEmulator(Emulator): def __init__(self) -> None: super().__init__() - self.error_queue: List[Error] = [] + self.error_queue: list[Error] = [] self.frequency_mode: str = "FIXed" self.frequency: float = 1e10 @@ -24,20 +22,20 @@ def __init__(self) -> None: self.output: bool = False @message(r"^\*IDN\?$") - def identify(self): + def identify(self) -> str: return self.IDENTITY @message(r"^\*RST$") - def set_reset(self): + def set_reset(self) -> None: self.average_count = 100 self.wavelength = 370 @message(r"^\*CLS$") - def set_clear(self): + def set_clear(self) -> None: self.error_queue.clear() @message(r"^:?SYST(?:em)?:ERR(?::NEXT)?\?$") - def get_system_error_next(self): + def get_system_error_next(self) -> str: if self.error_queue: error = self.error_queue.pop(0) else: @@ -45,51 +43,43 @@ def get_system_error_next(self): return f'{error.code}, "{error.message}"' @message(r"^(?:SOUR(?:ce)?1)?:FREQ(?:uency)?:MODE\?$") - def get_frequency_mode(self): + def get_frequency_mode(self) -> str: return self.frequency_mode @message(r"^(?:SOUR(?:ce)?1)?:FREQ(?:uency)?:MODE (\w+)$") - def set_frequency_mode(self, mode): - print("setting new mode", mode) + def set_frequency_mode(self, mode) -> None: self.frequency_mode = mode @message(r"^(?:SOUR(?:ce)?1)?:FREQuency:(?:CW|FIX(?:ed)?)\?$") - def get_frequency(self): + def get_frequency(self) -> float: return self.frequency - @message( - r"^(?:SOUR(?:ce)?1)?:FREQuency:(?:CW|FIX(?:ed)?) ([\d.]+(?:[eE][+-]?\d+)?)$" - ) - def set_frequency(self, frequency): - + @message(r"^(?:SOUR(?:ce)?1)?:FREQuency:(?:CW|FIX(?:ed)?) ([\d.]+(?:[eE][+-]?\d+)?)$") + def set_frequency(self, frequency) -> None: frequency = float(frequency) if frequency < 8e3 or frequency > 12.75e9: self.error_queue.append(Error(222, "Parameter Data Out of Range")) - return - - self.frequency = frequency + else: + self.frequency = frequency @message(r"^(?:SOUR(?:ce)?1)?:POW(?:er)?:POW(?:er)?\?$") - def get_power(self): + def get_power(self) -> float: return self.power - @message( - r"^(?:SOUR(?:ce)?1)?:POW(?:er)?:POW(?:er)? ([+-]?[\d.]+(?:[eE][+-]?\d+)?)$" - ) - def set_power(self, power): - print(power) + @message(r"^(?:SOUR(?:ce)?1)?:POW(?:er)?:POW(?:er)? ([+-]?[\d.]+(?:[eE][+-]?\d+)?)$") + def set_power(self, power) -> None: power = float(power) if power < -145 or power > 40: self.error_queue.append(Error(222, "Parameter Data Out of Range")) - return - self.power = power + else: + self.power = power @message(r"^(?:SOUR(?:ce)?1:)?OUTP(?:ut)?:STAT(?:e)?\?$") - def get_output(self): + def get_output(self) -> str: return "1" if self.output else "0" @message(r"^(?:SOUR(?:ce)?1:)?OUTP(?:ut)?:STAT(?:e)? (ON|OFF)$") - def set_output(self, state): + def set_output(self, state) -> None: self.output = True if state == "ON" else False diff --git a/src/comet/emulator/tcpserver.py b/src/comet/emulator/tcpserver.py index f303d7a..927c040 100644 --- a/src/comet/emulator/tcpserver.py +++ b/src/comet/emulator/tcpserver.py @@ -2,32 +2,31 @@ import socketserver import threading import time -from typing import Callable, Iterable, List, Optional, Tuple, Union +from typing import Callable, Iterable, Optional, Union __all__ = ["TCPRequestHandler", "TCPServer", "TCPServerThread", "TCPServerContext"] -def split_data(data: str, terminator: str) -> List[str]: +def split_data(data: str, terminator: str) -> list[str]: if terminator: return data.split(terminator) return [data] class TCPRequestHandler(socketserver.BaseRequestHandler): - - def read_messages(self) -> Optional[List[str]]: + def read_messages(self) -> Optional[list[str]]: data = str(self.request.recv(4096), "ascii") if not data: return None self.server.context.logger.info("recv %s", bytes(data, "ascii")) # type: ignore - return [line for line in split_data(data, self.server.context.termination) if line] # type: ignore + termination = self.server.context.termination # type: ignore + return [line for line in split_data(data, termination) if line] def send_messages(self, response: Union[str, Iterable[str]]) -> None: + termination = self.server.context.termination # type: ignore if isinstance(response, (list, tuple)): - response = self.server.context.termination.join( # type: ignore - format(line) for line in response - ) - data = bytes(f"{response}{self.server.context.termination}", "ascii") # type: ignore + response = termination.join(format(line) for line in response) + data = bytes(f"{response}{termination}", "ascii") self.server.context.logger.info("send %s", data) # type: ignore self.request.sendall(data) @@ -43,7 +42,6 @@ def handle(self) -> None: class TCPServerContext: - def __init__(self, name: str, emulator: Callable, termination: str, request_delay: float) -> None: self.name: str = name self.emulator: Callable = emulator @@ -58,16 +56,14 @@ def __call__(self, request: str) -> Union[str, Iterable[str]]: class TCPServer(socketserver.TCPServer): + allow_reuse_address: bool = True - allow_reuse_address = True - - def __init__(self, address: Tuple[str, int], context: TCPServerContext) -> None: + def __init__(self, address: tuple[str, int], context: TCPServerContext) -> None: super().__init__(address, TCPRequestHandler) self.context: TCPServerContext = context class TCPServerThread(threading.Thread): - def __init__(self, server: TCPServer) -> None: super().__init__() self.server: TCPServer = server diff --git a/src/comet/emulator/thorlabs/pm100.py b/src/comet/emulator/thorlabs/pm100.py index b41e348..778fc8f 100644 --- a/src/comet/emulator/thorlabs/pm100.py +++ b/src/comet/emulator/thorlabs/pm100.py @@ -2,8 +2,6 @@ import random -from typing import List - from comet.emulator import Emulator from comet.emulator import message, run from comet.emulator.utils import Error @@ -18,26 +16,26 @@ class PM100Emulator(Emulator): def __init__(self) -> None: super().__init__() - self.error_queue: List[Error] = [] + self.error_queue: list[Error] = [] self.average_count: int = 100 self.wavelength: int = 370 @message(r"^\*IDN\?$") - def identify(self): + def identify(self) -> str: return self.IDENTITY @message(r"^\*RST$") - def set_reset(self): - self.average_count: int = 100 - self.wavelength: int = 370 + def set_reset(self) -> None: + self.average_count = 100 + self.wavelength = 370 @message(r"^\*CLS$") - def set_clear(self): + def set_clear(self) -> None: self.error_queue.clear() @message(r"^:?SYST:ERR(?::NEXT)?\?$") - def get_system_error_next(self): + def get_system_error_next(self) -> str: if self.error_queue: error = self.error_queue.pop(0) else: @@ -45,23 +43,23 @@ def get_system_error_next(self): return f'{error.code}, "{error.message}"' @message(r"^(?:SENS(?:e)?)?:AVER(?:age)?:COUN(?:t)?\?$") - def get_average_count(self): + def get_average_count(self) -> int: return self.average_count @message(r"^(?:SENS(?:e)?)?:AVER(?:age)?:COUN(?:t)? (\d+)$") - def set_average_count(self, average_count): + def set_average_count(self, average_count) -> None: self.average_count = average_count @message(r"^(?:SENS(?:e)?)?:CORR(?:ection)?:WAV(?:elength)?\?$") - def get_wavelength(self): + def get_wavelength(self) -> int: return self.wavelength @message(r"^(?:SENS(?:e)?)?:CORR(?:ection)?:WAV(?:elength)? (\d+)$") - def set_wavelength(self, wavelength): + def set_wavelength(self, wavelength) -> None: self.wavelength = wavelength @message(r"^MEAS(?:ure)?(?::SCAL(?:ar)?)?(?::POW(?:er)?)?") - def measure_power(self): + def measure_power(self) -> str: power = random.uniform(1e-9, 2e-9) return format(power, "E") diff --git a/src/comet/estimate.py b/src/comet/estimate.py index 12e771e..85d5f24 100644 --- a/src/comet/estimate.py +++ b/src/comet/estimate.py @@ -1,7 +1,6 @@ """Estimate remaining time.""" from datetime import datetime, timedelta -from typing import List, Optional, Tuple __all__ = ["Estimate"] @@ -20,7 +19,7 @@ class Estimate: def __init__(self, total: int) -> None: self._total: int = total - self._deltas: List[timedelta] = [] + self._deltas: list[timedelta] = [] self._start: datetime = datetime.now() self._prev: datetime = datetime.now() @@ -50,5 +49,5 @@ def remaining(self) -> timedelta: return max(timedelta(0), (self.average * self.total) - self.elapsed) @property - def progress(self) -> Tuple[int, int]: + def progress(self) -> tuple[int, int]: return self.passed, self.total diff --git a/src/comet/parameter.py b/src/comet/parameter.py index 14429e7..5c995dd 100644 --- a/src/comet/parameter.py +++ b/src/comet/parameter.py @@ -1,14 +1,14 @@ -from typing import Any, Dict, Optional, Type +from typing import Any, Optional, Type from .utils import to_unit __all__ = ["inspect_parameters", "Parameter", "ParameterBase"] ParameterBaseType = Type["ParameterBase"] -ParameterValues = Dict[str, Any] +ParameterValues = dict[str, Any] -def inspect_parameters(cls: ParameterBaseType) -> Dict[str, "Parameter"]: +def inspect_parameters(cls: ParameterBaseType) -> dict[str, "Parameter"]: """Retrun dictionary of assigned class parameters.""" parameters = {} for mro_cls in cls.__mro__: @@ -78,7 +78,7 @@ class ParameterBase: """Base class for parameters.""" def __init__(self, values: Optional[ParameterValues] = None) -> None: - self.__values: Dict[str, Any] = {} + self.__values: dict[str, Any] = {} self.update_parameters(values or {}) def __getattribute__(self, name): diff --git a/src/comet/utils.py b/src/comet/utils.py index dd4806d..a2b5df2 100644 --- a/src/comet/utils.py +++ b/src/comet/utils.py @@ -1,7 +1,7 @@ import datetime import re from math import log -from typing import Iterable, List, Tuple, Optional, Union +from typing import Iterable, Optional, Union from pint import UnitRegistry, Quantity @@ -29,7 +29,7 @@ def to_unit(value: Union[float, str, Quantity], unit: str) -> float: return (ureg(unit) * value).to(unit).m -def auto_scale(value: float) -> Tuple[float, str, str]: +def auto_scale(value: float) -> tuple[float, str, str]: scales = [ (1e24, "Y", "yotta"), (1e21, "Z", "zetta"), @@ -55,7 +55,7 @@ def auto_scale(value: float) -> Tuple[float, str, str]: return 1e0, "", "" -def combine_matrix(a: Iterable, b: Iterable, *args: Iterable) -> List[str]: +def combine_matrix(a: Iterable, b: Iterable, *args: Iterable) -> list[str]: c = ["".join((x, y)) for x in a for y in b] if args: return combine_matrix(c, *args) From 750d34e7f403de3f675124d713a30a0f994cf2f9 Mon Sep 17 00:00:00 2001 From: Bernhard Arnold Date: Thu, 12 Sep 2024 15:07:20 +0200 Subject: [PATCH 2/2] updated changelog --- changelog | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/changelog b/changelog index e13a7e4..651b2df 100644 --- a/changelog +++ b/changelog @@ -7,11 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [1.1.0] - 2024-09-11 +## [1.1.0] - 2024-09-12 ### Added -- Additional HEPHY EnvironBox commands for driver and emulator (#74). +- Missing type hints for static type checking (#82). - Generic base classes `PowerSupply` and `PowerSupplyChannel` and `LightSource`. +- Additional HEPHY EnvironBox commands for driver and emulator (#74). - Rhode&Schwarz NGE100 power supply (#77). - Photonic F3000 LED light source (#75). - Thorlabs PM100 USB optical power meter (#78).