Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 56 additions & 45 deletions deapi/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
Attributes,
Histogram,
PropertySpec,
PropertySpecifications,
PropertyType,
PropertyAllowableType,
MovieBufferStatus,
MovieBufferInfo,
DataType,
Expand Down Expand Up @@ -423,16 +426,18 @@ def get_property_spec(self, property_name: str):
)
def get_property_specifications(self, property_name):
"""
Get a list of allowed values for a property of the camera on DE-Server
Only works for DE-MC version greater or equal to 2.7.4
Get the specifications for a property of the camera on DE-Server
Only supported for DE-MC version 2.7.5 and above

Parameters
----------
property_name : str
The name of the property to get the allowed values for
The name of the property to get the specifications for
"""
t0 = self.GetTime()
values = False
if self.commandVersion < 13:
log.error("get_property_specifications is only supported for server version 2.7.5 and above.")
return None

command = self._addSingleCommand(
self.GET_PROPERTY_SPECIFICATIONS, property_name
)
Expand All @@ -442,48 +447,53 @@ def get_property_specifications(self, property_name):

values = self.__getParameters(response.acknowledge[0])

propSpec = PropertySpec()
propSpec.dataType = values[0]
propSpec.valueType = values[1]
propSpec.category = values[-4]
propSpec.options = list(values[2:-4])
propSpec.defaultValue = str(values[-3])
propSpec.currentValue = str(values[-2])
propSpec.readOnly = bool(values[-1])

optionsLength = len(propSpec.options)

if propSpec.valueType == "Range":
if optionsLength == 2:
rangeString = ""
for i in range(optionsLength):
if propSpec.dataType == "Integer":
rangeString += str(int(propSpec.options[i]))
else:
rangeString += str(propSpec.options[i])
if i == 0:
rangeString += str(" - ")

propSpec.options.append(rangeString)

if propSpec.valueType == "Set":
for i in range(optionsLength):
if propSpec.defaultValue == propSpec.options[i]:
if propSpec.defaultValue != "":
propSpec.options[i] = propSpec.defaultValue + str("*")
else:
emptyStringIndex = i
if propSpec.defaultValue == "":
propSpec.options.pop(emptyStringIndex)

if "allow_all" in propSpec.valueType:
propSpec.options = ""
elif propSpec.dataType == "String":
propSpec.options = str(list(map(lambda a: str(a), propSpec.options)))[1:-1]
if not values or len(values) == 0:
log.error(f"get_property_specifications({property_name}) failed, parameter size not matched.")
return None

prop_spec = PropertySpecifications()

param_id = 0
data_type = values[param_id]
param_id += 1
if data_type == "String":
prop_spec.prop_type = PropertyType.String
elif data_type == "Float":
prop_spec.prop_type = PropertyType.Float
elif data_type == "Integer":
prop_spec.prop_type = PropertyType.Integer
else:
propSpec.options = str(propSpec.options)[1:-1]
log.error(f"get_property_specifications({property_name}) failed, property type not matched.")
return None

prop_allowable_type = values[param_id]
param_id += 1

if prop_allowable_type == "Range":
prop_spec.prop_allowable_type = PropertyAllowableType.Range
if prop_spec.prop_type in (PropertyType.Float, PropertyType.Integer):
prop_spec.min_value = values[param_id]
param_id += 1
prop_spec.max_value = values[param_id]
param_id += 1
else:
log.error(f"get_property_specifications({property_name}) failed, cannot read the min/max value.")
return None
elif prop_allowable_type == "Set":
prop_spec.prop_allowable_type = PropertyAllowableType.Set
prop_spec.values = list(values[param_id:-4])
elif prop_allowable_type == "AllowAll":
prop_spec.prop_allowable_type = PropertyAllowableType.AllowAll
else:
log.error(f"get_property_specifications({property_name}) failed, unknown allowable type.")
return None

return propSpec
prop_spec.category = values[-4]
prop_spec.default_value = values[-3]
prop_spec.current_value = values[-2]
prop_spec.read_only = values[-1]

return prop_spec

@deprecated_argument(
name="propertyName", since="5.2.0", alternative="property_name"
Expand Down Expand Up @@ -3133,6 +3143,7 @@ def ParseChangedProperties(self, changedProperties, response):
SetCurrentCamera = set_current_camera
ListProperties = list_properties
GetPropertySpec = get_property_spec
GetPropertySpecifications = get_property_specifications
# PropertyValidValues = property_valid_values
GetProperty = get_property
SetProperty = set_property
Expand Down
83 changes: 83 additions & 0 deletions deapi/data_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,19 @@ class BinningMethod(IntEnum):
FOURIERCROP = 3


class PropertyType(IntEnum):
Undef = 0
String = 1
Float = 2
Integer = 3


class PropertyAllowableType(IntEnum):
Range = 0
Set = 1
AllowAll = 2


class Attributes:
"""Class to hold attributes for getting the result of an image acquisition

Expand Down Expand Up @@ -544,6 +557,7 @@ def __repr__(self):

class PropertySpec:
"""Class to hold the specification of a property in the DE API
Deprecated since DE-MC 2.7.4

Parameters
----------
Expand Down Expand Up @@ -600,6 +614,75 @@ def __repr__(self):
)


class PropertySpecifications:
"""Class to hold the specification of a property in the DE API

Parameters
----------
prop_type : str, optional
Type of the property
prop_allowable_type : str, optional
Allowable type of the property
min_value : float, optional
Minimum value of the property
max_value : float, optional
Maximum value of the property
values : list, optional
List of values for the property
default_value : str, optional
Default value of the property
current_value : str, optional
Current value of the property
read_only : bool, optional
Whether the property is read-only
"""

def __init__(
self,
prop_type: PropertyType = None,
prop_allowable_type: PropertyAllowableType = None,
min_value: float = None,
max_value: float = None,
values: list = None,
category: str = None,
default_value: str = None,
current_value: str = None,
read_only: bool = None,
):
self.prop_type = prop_type
self.prop_allowable_type = prop_allowable_type
self.min_value = min_value
self.max_value = max_value
self.values = values
self.category = category
self.default_value = default_value
self.current_value = current_value
self.read_only = read_only

prop_type = None # Undef | String | Float | Integer
prop_allowable_type = None # Range | Set | AllowAll
min_value = None # Minimum value for Range type
max_value = None # Maximum value for Range type
values = None # List of values for Set allowable type
category = None # "Alias" | "Advanced" | "Basic" | "Deprecated" | "Engineering" | Obsolete"
default_value = None # Default value
current_value = None # Current value
read_only = False # Read-only property

def __repr__(self):
return (
f"PropertySpecifications(prop_type={self.prop_type}, "
f"prop_allowable_type={self.prop_allowable_type}, "
f"min_value={self.min_value}, "
f"max_value={self.max_value}, "
f"values={self.values}, "
f"category={self.category}, "
f"default_value={self.default_value}, "
f"current_value={self.current_value}, "
f"read_only={self.read_only})"
)


class PropertyCollection:
"""Class to interact with collections of properties in the DE API

Expand Down
20 changes: 10 additions & 10 deletions deapi/tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from deapi import Client, Histogram
import pytest
from deapi.data_types import (
PropertySpec,
PropertySpecifications,
VirtualMask,
MovieBufferStatus,
ContrastStretchType,
Expand Down Expand Up @@ -172,23 +172,23 @@ def test_bin_property_set(self, client):

@pytest.mark.server
@pytest.mark.parametrize("bin_sw", [1, 2, 4])
def test_property_spec_set(self, client, bin_sw):
def test_property_specifications_set(self, client, bin_sw):
client.set_property("Hardware Binning X", 1)
client.set_property("Hardware Binning Y", 1)
client.set_property("Binning Y", bin_sw)
sp = client.get_property_spec("Binning Y")
assert isinstance(sp, PropertySpec)
assert sp.currentValue == str(bin_sw)
sp = client.get_property_specifications("Binning Y")
assert isinstance(sp, PropertySpecifications)
assert sp.current_value == str(bin_sw)
assert (
sp.options
== "'1*', '2', '4', '8', '16', '32', '64', '128', '256', '512', '1024'"
sp.values
== ['1', '2', '4', '8', '16', '32', '64', '128', '256', '512', '1024']
)
client.set_property("Hardware Binning X", 2)
client.set_property("Hardware Binning Y", 2)
sp = client.get_property_spec("Binning Y")
assert sp.currentValue == str(bin_sw)
sp = client.get_property_specifications("Binning Y")
assert sp.current_value == str(bin_sw)
assert (
sp.options == "'1*', '2', '4', '8', '16', '32', '64', '128', '256', '512'"
sp.values == ['1', '2', '4', '8', '16', '32', '64', '128', '256', '512']
)

@pytest.mark.parametrize("bin", [1, 2])
Expand Down
Loading