Commit 5440d2bf authored by Jerome Carnis's avatar Jerome Carnis 🦊
Browse files

Merge branch 'picoscale' into 'master'

refactor DevicePicoscale implementation

See merge request !29
parents e3684fa6 a3566a62
Pipeline #28989 passed with stages
in 9 minutes and 8 seconds
......@@ -137,11 +137,13 @@ ATTR_FILEWRITER_STATUS = "Filewriter status"
ATTR_EIGERSTREAM_STATUS = "Eigerstream status"
ATTR_COLLIMATOR_STATUS = "Collimator status"
ATTR_POSITION_Z = "Position z"
ATTR_DEAD_PATH_CORRECTION = "Dead Path Correction"
ATTR_IMAGES_NUMBER = "Images number"
ATTR_EXTERNAL_TRIGGER = "External trigger"
ATTR_ACQUIRED_FRAMES = "Acquired frames"
ATTR_FRAME_NAME = "Frame name"
ATTR_FRAME_FILE = "Frame file"
ATTR_PRECISION_MODE = "Precision Mode"
ATTR_TRIGGERS_SP = "Triggers setpoint"
ATTR_TRIGGERS_GENERATED = "Triggers generated"
ATTR_LAST_TRIGGER_TYPE = "Last trigger type"
......
......@@ -26,6 +26,12 @@ from kamzik3.constants import *
from kamzik3.constants import SAVE_CHANGE
from kamzik3.snippets.snippetDataAccess import is_equal
PINT_ERRORS = (
pint.UndefinedUnitError,
pint.DefinitionSyntaxError,
AttributeError,
)
class SetFunction:
"""
......@@ -545,7 +551,7 @@ class Attribute(dict):
if self.numerical:
try:
return units.Quantity(self[VALUE], self[UNIT])
except (pint.UndefinedUnitError, AttributeError):
except PINT_ERRORS:
return units.Quantity(self[VALUE])
except TypeError:
return self[VALUE]
......@@ -561,7 +567,7 @@ class Attribute(dict):
if self.numerical:
try:
return units.Quantity(self[MIN], self[UNIT])
except (pint.UndefinedUnitError, AttributeError):
except PINT_ERRORS:
return units.Quantity(self[MIN])
except TypeError:
return self[MIN]
......@@ -577,7 +583,7 @@ class Attribute(dict):
if self.numerical:
try:
return units.Quantity(self[MAX], self[UNIT])
except (pint.UndefinedUnitError, AttributeError):
except PINT_ERRORS:
return units.Quantity(self[MAX])
except TypeError:
return self[MAX]
......@@ -594,7 +600,7 @@ class Attribute(dict):
if self.numerical:
try:
return units.Quantity(self[TOLERANCE][0], self[UNIT])
except (pint.UndefinedUnitError, AttributeError):
except PINT_ERRORS:
return units.Quantity(self[TOLERANCE][0])
except TypeError:
return self[TOLERANCE][0]
......@@ -611,7 +617,7 @@ class Attribute(dict):
if self.numerical:
try:
return units.Quantity(self[TOLERANCE][1], self[UNIT])
except (pint.UndefinedUnitError, AttributeError):
except PINT_ERRORS:
return units.Quantity(self[TOLERANCE][1])
except TypeError:
return self[TOLERANCE][1]
......@@ -627,7 +633,7 @@ class Attribute(dict):
if self.numerical:
try:
return units.Quantity(self[OFFSET], self[UNIT])
except (pint.UndefinedUnitError, AttributeError):
except PINT_ERRORS:
return units.Quantity(self[OFFSET])
except TypeError:
return self[OFFSET]
......@@ -643,7 +649,7 @@ class Attribute(dict):
if self.numerical:
try:
return units.Quantity(self[SETPOINT], self[UNIT])
except (pint.UndefinedUnitError, AttributeError):
except PINT_ERRORS:
return units.Quantity(self[SETPOINT])
except TypeError:
return self[SETPOINT]
......
......@@ -30,7 +30,7 @@ from kamzik3.snippets.snippetsControlLoops import (
)
from kamzik3.snippets.snippetsDecorators import expose_method
from kamzik3.snippets.snippetsGenerators import device_id_generator, token_generator
from kamzik3.snippets.snippetsUnits import convert_to_unit, device_units
from kamzik3.snippets.snippetsUnits import convert_to_unit
from kamzik3.snippets.snippetsYaml import YamlSerializable
if TYPE_CHECKING:
......@@ -1217,28 +1217,40 @@ class Device(Subject, YamlSerializable):
Always call this from handle_configuration method.
"""
if self.config:
for attribute, value in self.config.get("attributes", {}).items():
unit = self.get_attribute(attribute[:-1])[UNIT]
if unit in (None, "") or attribute[-1] == UNIT:
self.set_attribute(attribute, value)
else:
if isinstance(value, list):
set_value = []
for v in value:
try:
set_value.append(
device_units(self, list(attribute[:-1]), v).m
)
except (UndefinedUnitError, DimensionalityError):
set_value.append(v)
else:
self.config_filtered_attributes(
attributes=self.config.get("attributes", {})
)
def config_filtered_attributes(
self, attributes: Dict[Tuple[str, str], Any]
) -> None:
"""
Set attributes to desired values found in config.
The concept is similar to _config_attributes, except that this time the config
must be provided. This allows filtering some keys from the existing config and
more tailored behaviour in handle_configuration.
"""
for attribute, value in attributes.items():
unit = self.get_attribute(attribute[:-1])[UNIT]
if unit in (None, "") or attribute[-1] == UNIT:
self.set_attribute(attribute, value)
else:
if isinstance(value, list):
set_value = []
for v in value:
try:
set_value = device_units(
self, list(attribute[:-1]), value
).m
set_value.append(
self.to_device_unit(list(attribute[:-1]), v).m
)
except (UndefinedUnitError, DimensionalityError):
set_value = value
self.set_attribute(attribute, set_value)
set_value.append(v)
else:
try:
set_value = self.to_device_unit(list(attribute[:-1]), value).m
except (UndefinedUnitError, DimensionalityError):
set_value = value
self.set_attribute(attribute, set_value)
def _config_commands(self):
"""
......@@ -1380,12 +1392,14 @@ class Device(Subject, YamlSerializable):
return False
return True
def to_device_unit(self, attribute: str, value: Union[int, float, str]) -> Quantity:
def to_device_unit(
self, attribute: Union[List, Tuple, str], value: Union[int, float, str]
) -> Quantity:
"""
Convert a value to the unit of the corresponding attribute.
:param attribute: the name of the attribute whose unit should be used for the
conversion
conversion or a sequence [attribute_name, key_name] e.g. [ATTR_POSITION, UNIT]
:param value: the value to convert
:return: a pint Quantity with the unit of the attribute
"""
......
......@@ -8,7 +8,7 @@ import json
import pickle
import time
from threading import Thread, Event, RLock
from typing import Optional, Any
from typing import Any, Callable, Optional, Tuple, Union
import numpy as np
import zmq
......@@ -486,7 +486,9 @@ class DeviceClient(Device):
set_in_dict(self.attributes, attribute, value)
# pylint: disable=arguments-differ
def command(self, command, callback=None):
def command( # type: ignore
self, command: str, callback: Optional[Callable] = None, returning: bool = False
) -> Union[bool, str]:
"""
Execute raw command directly on devices.
......@@ -512,7 +514,12 @@ class DeviceClient(Device):
],
copy=False,
)
status, token, response = self.handle_server_response()
server_response = self.handle_server_response()
if server_response is None:
status = RESPONSE_ERROR
else:
status, token, response = server_response
if status == RESPONSE_OK:
if token and callback is not None:
self.set_callback(self.get_token(token), callback)
......@@ -568,7 +575,7 @@ class DeviceClient(Device):
self.handle_response_error("Method error: {}".format(e))
return False
def handle_server_response(self):
def handle_server_response(self) -> Optional[Tuple[str, str, str]]:
"""
This is crucial moment here.
......@@ -577,9 +584,7 @@ class DeviceClient(Device):
"""
message = self.socket.recv_multipart()
status, token, msg_type = message[:3]
if msg_type == MSG_JSON:
return status.decode(), token.decode(), message[3].decode()
elif msg_type == MSG_FILE:
if msg_type == MSG_JSON or msg_type == MSG_FILE:
return status.decode(), token.decode(), message[3].decode()
else:
return None
......
This diff is collapsed.
import pint
from math import inf
from PyQt5.QtCore import pyqtSlot
......@@ -53,7 +54,7 @@ class AttributeFloatWidget(AttributeWidget):
try:
set_value = value.to(self.unit)
except AttributeError:
except (AttributeError, pint.DefinitionSyntaxError):
set_value = units.Quantity(value)
self.on_numerical_value_set(set_value.m)
self.input_widget.setValue(set_value.m)
......@@ -104,10 +105,16 @@ class AttributeFloatWidget(AttributeWidget):
def on_numerical_value_set(self, value):
current_font_color = self.font_color
min_value, max_value = (
self.attribute.minimum().to(self.unit).m,
self.attribute.maximum().to(self.unit).m,
)
try:
min_value, max_value = (
self.attribute.minimum().to(self.unit).m,
self.attribute.maximum().to(self.unit).m,
)
except pint.DefinitionSyntaxError:
min_value, max_value = (
self.attribute.minimum(),
self.attribute.maximum(),
)
if min_value == -inf or max_value == inf:
if value <= min_value or value >= max_value:
self.font_color = "red"
......
import datetime
from logging import Logger
import math
from typing import Optional, TYPE_CHECKING, Union
from typing import List, Optional, Tuple, TYPE_CHECKING, Union
import warnings
from pint import DimensionalityError, Quantity, UndefinedUnitError
......@@ -133,14 +133,14 @@ def convert_to_unit(
def device_units(
device: "Device", attribute: str, value: Union[int, float, str]
device: "Device", attribute: Union[List, Tuple, str], value: Union[int, float, str]
) -> Quantity:
"""
Convert a value to the unit of the corresponding attribute.
:param device: the Device to which the attribute belongs
:param attribute: the name of the attribute whose unit should be used for the
conversion
conversion or a sequence [attribute_name, key_name] e.g. [ATTR_POSITION, UNIT]
:param value: the value to convert
:return: a pint Quantity with the unit of the attribute
"""
......
......@@ -27,7 +27,7 @@ setuptools.setup(
install_requires=[
"numpy>=1.16",
"pyzmq>=18.0",
"pint>=0.16.0",
"pint>=0.19.2",
"bidict>=0.18",
"pyqt5>=5.15.0",
"pyqtgraph>=0.11.0",
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment