Source code for secsgem.secs.variables.boolean

#####################################################################
# boolean.py
#
# (c) Copyright 2021, Benjamin Parzella. All rights reserved.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This software is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser General Public License for more details.
#####################################################################
"""SECS boolean variable type."""

from .base import Base


[docs]class Boolean(Base): """Secs type for boolean data.""" format_code = 0o11 text_code = "BOOLEAN" preferred_types = [bool] _true_strings = ["TRUE", "YES"] _false_strings = ["FALSE", "NO"] def __init__(self, value=None, count=-1): """ Initialize a boolean secs variable. :param value: initial value :type value: list/boolean :param count: number of items this value :type count: integer """ super().__init__() self.value = [] self.count = count if value is not None: self.set(value) def __repr__(self): """Generate textual representation for an object of this class.""" if len(self.value) == 0: return f"<{self.text_code}>" data = " ".join([str(value) for value in self.value]) return f"<{self.text_code} {data} >" def __len__(self): """Get the length.""" return len(self.value) def __getitem__(self, key): """Get an item using the indexer operator.""" return self.value[key] def __setitem__(self, key, item): """Set an item using the indexer operator.""" self.value[key] = item def __eq__(self, other): """Check equality with other object.""" if isinstance(other, Base): if other.is_dynamic: return other.value.value == self.value return other.value == self.value if isinstance(other, list): return other == self.value return [other] == self.value def __hash__(self): """Get data item for hashing.""" return hash(str(self.value)) def _check_single_item_support(self, value): if isinstance(value, bool): return True if isinstance(value, int): if 0 <= value <= 1: return True return False if isinstance(value, str): if value.upper() in self._true_strings or value.upper() in self._false_strings: return True return False return False
[docs] def supports_value(self, value) -> bool: """ Check if the current instance supports the provided value. :param value: value to test :type value: any """ if isinstance(value, (list, tuple)): return self._supports_value_list(value) if isinstance(value, bytearray): return self._supports_value_bytearray(value) return self._check_single_item_support(value)
def _supports_value_list(self, value) -> bool: if 0 < self.count < len(value): return False for item in value: if not self._check_single_item_support(item): return False return True def _supports_value_bytearray(self, value) -> bool: if 0 < self.count < len(value): return False for char in value: if not 0 <= char <= 1: return False return True def __convert_single_item(self, value): if isinstance(value, bool): return value if isinstance(value, int): if not 0 <= value <= 1: raise ValueError(f"Value {value} out of bounds") return bool(value) if isinstance(value, str): if value.upper() in self._true_strings: return True if value.upper() in self._false_strings: return False raise ValueError(f"Value {value} out of bounds") raise ValueError(f"Can't convert value {value}")
[docs] def set(self, value): """ Set the internal value to the provided value. :param value: new value :type value: list/boolean """ if isinstance(value, (list, tuple)): if 0 <= self.count < len(value): raise ValueError(f"Value longer than {self.count} chars") new_value = [] for item in value: new_value.append(self.__convert_single_item(item)) self.value = new_value elif isinstance(value, bytearray): if 0 <= self.count < len(value): raise ValueError(f"Value longer than {self.count} chars") new_value = [] for char in value: if not 0 <= char <= 1: raise ValueError(f"Value {char} out of bounds") new_value.append(char) self.value = new_value else: self.value = [self.__convert_single_item(value)]
[docs] def get(self): """ Return the internal value. :returns: internal value :rtype: list/boolean """ if len(self.value) == 1: return self.value[0] return self.value
[docs] def encode(self): """ Encode the value to secs data. :returns: encoded data bytes :rtype: string """ result = self.encode_item_header(len(self.value)) for value in self.value: if value: result += b"\1" else: result += b"\0" return result
[docs] def decode(self, data, start=0): """ Decode the secs byte data to the value. :param data: encoded data bytes :type data: string :param start: start position of value the data :type start: integer :returns: new start position :rtype: integer """ (text_pos, _, length) = self.decode_item_header(data, start) result = [] for _ in range(length): if bytearray(data)[text_pos] == 0: result.append(False) else: result.append(True) text_pos += 1 self.set(result) return text_pos