def __call__(self, *, names: list = None): if self._item is doors_params_error: raise FireError('Parameters may be used only for single door') if names is None: names = self._readable_params elif isinstance(names, str): names = (names, ) elif not isinstance(names, (list, tuple)): # Workaround of "Could not consume arg" message appearing # instead of exception message problem sys.stderr.write("ERROR: Names must be a name or list of parameters") raise FireError("Names must be a name or list of parameters") names = set(names) extra_names = names - set(self._readable_params) if extra_names: # Workaround of "Could not consume arg" message appearing # instead of exception message problem sys.stderr.write('ERROR: Unknown parameters were given: {}\n'.format(extra_names)) raise FireError('Unknown parameters were given: {}'.format(extra_names)) formatter = BaseFormatter.get_formatter(opt_io_format)( data_in, data_out, names ) converter = TypedFieldConverter(formatter, self._prop_types) converter.write_records( [{name: getattr(self._item, name) for name in sorted(names)}] )
def parse_array_index(opt_indexes: Optional[Union[int, str]]) -> Union[int, slice]: """ Parse index/range cli parameter and return appropriate int or slice >>> assert parse_array_index(None) == slice(None, None, None) >>> assert parse_array_index(1) == int(1) >>> assert parse_array_index('1-2') == slice(1, 2, None) Args: opt_indexes(Union[int, str], optional): index or range Returns: Union[int, slice]: int or slice suitable for sequences indexing """ if opt_indexes is None: return slice(None, None) if isinstance(opt_indexes, str): if not re.match(r'^\d-\d$', opt_indexes): raise FireError("Select range must contain numbers divided by dash, for example 0-3") pieces = opt_indexes.split('-') start = int(pieces.pop(0)) if pieces else None stop = int(pieces.pop(0) or 1000) + 1 if pieces else None return slice(start, stop) if isinstance(opt_indexes, int): if opt_indexes < 0: raise FireError("Select index must be a positive number") return opt_indexes raise FireError("Numbers must be list or int")
def validate_headers(self, input_headers: Union[set, KeysView]): headers = set(self._headers) extra = input_headers - headers if extra: raise FireError("Unknown fields in input: {}".format(extra)) missed = headers - input_headers if missed: raise FireError("Missed fields in input: {}".format(extra))
def write_raw(self, name: str): """Write raw data to a given table. ZKAccess device keeps table values as strings, many of these fields are encoded (some date fields, for instance). This command expects input data as it stores on a device, without applying any type convertions or decoding (like `table` command does). Args: name: table name. Possible values are: 'User', 'UserAuthorize', 'Holiday', 'Timezone', 'Transaction', 'FirstCard', 'MultiCard', 'InOutFun', 'TemplateV10' """ if name not in models_registry: raise FireError("Unknown table '{}', possible values are: {}".format( name, list(sorted(models_registry.keys())) )) table_cls = models_registry[name] formatter = BaseFormatter.get_formatter(opt_io_format)( data_in, data_out, table_cls.fields_mapping().values() ) converter = TextConverter(formatter) gen = self._zk.sdk.set_device_data(table_cls.table_name) gen.send(None) for record in converter.read_records(): gen.send(record) try: gen.send(None) except StopIteration: pass
def read_raw(self, name: str, *, buffer_size=32768): """Return raw data from a given table. ZKAccess device keeps table values as strings, many of these fields are encoded (some date fields, for instance). This command returns data as it stores on a device, without applying any type convertions or decoding, like `table` command does. This command works on low level. So, it accepts buffer size for storing a result. If you are observed that results are cut, its makes sense to increase buffer size. Args: name: table name. Possible values are: 'User', 'UserAuthorize', 'Holiday', 'Timezone', 'Transaction', 'FirstCard', 'MultiCard', 'InOutFun', 'TemplateV10' buffer_size: buffer size in bytes to store a result. Default is 32Kb """ if name not in models_registry: raise FireError("Unknown table '{}', possible values are: {}".format( name, list(sorted(models_registry.keys())) )) table_cls = models_registry[name] formatter = BaseFormatter.get_formatter(opt_io_format)( data_in, data_out, table_cls.fields_mapping().values() ) converter = TextConverter(formatter) converter.write_records( self._zk.sdk.get_device_data(table_cls.table_name, [], {}, buffer_size, False) )
def _validate_field_names(self, fields: Union[Set[str], KeysView], item: Mapping[str, Any]): # Check if field names are all exist in the model extra_fields = item.keys() - fields if extra_fields: raise FireError("Unknown fields of {} found in the input data: {}".format( self._model_cls.__name__, list(sorted(extra_fields)) ))
def _set_from_args(self, args: dict, converter): extra_names = args.keys() - set(self._readable_params) if extra_names: raise FireError('Unknown parameters were given: {}'.format(extra_names)) typed_items = converter.to_record_dict(args) for name, val in typed_items.items(): setattr(self._item, name, val)
def list(self): """List of all valid parameter names""" if self._item is doors_params_error: raise FireError('Parameters may be used only for single door') formatter = BaseFormatter.get_formatter(opt_io_format)( data_in, data_out, ['parameter_name'] ) converter = TextConverter(formatter) converter.write_records({'parameter_name': x} for x in sorted(self._readable_params))
def set(self, **parameters): """Set given parameters Args: parameters: Flags are parameters with values to be set. For example, `... parameters set --param1=value1 --param2=value2 ...` """ if self._item is doors_params_error: raise FireError('Parameters may be used only for single door') readonly_params = parameters.keys() & self._readonly_params if readonly_params: raise FireError('The following parameters are read-only: {}'.format(readonly_params)) formatter = BaseFormatter.get_formatter(opt_io_format)( data_in, data_out, parameters.keys() ) converter = TypedFieldConverter(formatter, self._prop_types) if parameters: self._set_from_args(parameters, converter) else: self._set_from_input(converter)
def connect(self, ip: str, *, model: str = 'ZK400') -> ZKCommand: """ Connect to a device with given ip. Args: ip (str): IP address of a device model (DeviceModels): device model. Possible values are: ZK100, ZK200, ZK400 """ model = device_models.get(model) if model is None: raise FireError( "Unknown device model '{}', possible values are: ZK100, ZK200, ZK400".format(model) ) if not ip: raise FireError('IP argument is required') connstr = 'protocol=TCP,ipaddress={},port=4370,timeout=4000,passwd='.format(ip) zkcmd = ZKCommand(ZKAccess(connstr, device_model=model, dllpath=self._dllpath)) return zkcmd
def __call__( self, *, format: str = 'ascii_table', file: str = None, dllpath: str = 'plcommpro.dll' ): if format not in io_formats: # Workaround of "Could not consume arg" message appearing # instead of exception message problem sys.stderr.write("ERROR: Unknown format '{}', available are: {}\n".format( format, list(sorted(io_formats.keys())) )) raise FireError("Unknown format '{}', available are: {}".format( format, list(sorted(io_formats.keys())) )) global opt_io_format opt_io_format = format self._file = None if file: d = os.path.dirname(file) if not os.path.isdir(d): # Workaround of "Could not consume arg" message appearing # instead of exception message problem sys.stderr.write("ERROR: Directory '{}' does not exist\n".format(d)) raise FireError("Directory {} does not exist".format(d)) self._file = open(file, 'r+') self._file.seek(0) global data_in global data_out data_in = self._file data_out = WriteFile(self._file) self._dllpath = dllpath return self
def _parse_value(self, field_name: str, value: str, field_datatype) -> Optional[Any]: if value == '': return None error_msg = '' try: if issubclass(field_datatype, Enum): error_msg = 'one of values: {}'.format( ','.join(x for x in dir(field_datatype) if not x.startswith('_')) ) return field_datatype[value] cast, error_msg = self._input_converters[field_datatype] return cast(value) except (ValueError, TypeError, KeyError): raise FireError( "Bad value of {}={} but must be: {}".format(field_name, value, error_msg) )
def table(self, name: str) -> Query: """ Make a query to a device table with given name Args: name: table name. Possible values are: 'User', 'UserAuthorize', 'Holiday', 'Timezone', 'Transaction', 'FirstCard', 'MultiCard', 'InOutFun', 'TemplateV10' """ if name not in models_registry: raise FireError("Unknown table '{}', possible values are: {}".format( name, list(sorted(models_registry.keys())) )) qs = self._zk.table(name) table_cls = qs._table_cls formatter = BaseFormatter.get_formatter(opt_io_format)( data_in, data_out, table_cls.fields_mapping().keys() ) return Query(qs, ModelConverter(formatter, table_cls))
def __init__( self, bg: str = "#EEE8D5", fg: str = "#484848", contrast_ratio: Optional[float] = None, saturation: float = 1, hues: Optional[Tuple[float, float, float, float, float, float]] = None, sample_rate: int = 256, ): try: # Cooking input. check_argument_types() bg = from_hex(bg) fg = from_hex(fg) if hues is None: hues = (0, 120, 60, 240, 300, 200) hues = (hue / 360 for hue in hues) if contrast_ratio is None: contrast_ratio = contrast(bg, fg) # Generating the palette. self.colors = [to_hex(*bg)] + [None] * 6 + [to_hex(*fg)] for hue, color in zip(hues, range(1, 7)): lightness_contrast = ( (lightness, contrast(bg, hls_to_rgb(hue, lightness, saturation))) for lightness in (x / (sample_rate - 1) for x in range(sample_rate))) # Filter out values of the opposite sign. lightness_contrast = filter( lambda p: (p[1] > 0) == (contrast_ratio > 0), lightness_contrast) best_lightness, best_contrast = min( lightness_contrast, key=lambda p: abs(p[1] - contrast_ratio)) self.colors[color] = to_hex( *hls_to_rgb(hue, best_lightness, saturation)) except Exception as e: raise FireError(str(e))
def get_formatter(io_format: str) -> 'Type[BaseFormatter]': if io_format not in io_formats: raise FireError("{} format(s) are only supported", sorted(io_formats.keys())) return io_formats[io_format]
def get_reader(self) -> Iterable[Mapping[str, str]]: raise FireError( 'You should to specify input data format, e.g. `pyzkaccess --format=csv ...`' )