def determine_bitmask(self): """ Work out our bitmask value. if it's a callable and not an Enum class we call it with our packet to determine the bitmask. The bitmask must then be a subclass of enum.Enum And the bitmask must not have a member with the value zero """ bitmask = self.bitmask if type(bitmask) is not enum.EnumMeta and callable(self.bitmask): bitmask = bitmask(self.pkt) try: if not issubclass(bitmask, enum.Enum): raise ProgrammerError("Bitmask is not an enum! got {0}".format( repr(bitmask))) except TypeError: raise ProgrammerError("Bitmask is not an enum! got {0}".format( repr(bitmask))) for name, member in bitmask.__members__.items(): if member.value == 0: raise ProgrammerError( "A bitmask with a zero value item makes no sense: {0} in {1}" .format(name, repr(bitmask))) return bitmask
def __init__(self, determine_res_packet, adjust_expected_number): if not callable(determine_res_packet) or not callable( adjust_expected_number): raise ProgrammerError("Multi Options expects two callables") self.determine_res_packet = determine_res_packet self.adjust_expected_number = adjust_expected_number
def ChangeCleanCycle(*, enable, duration_s=0, duration=None, **kwargs): """ Returns a valid message that will either start or stop the cleaning (HEV) cycle of devices used against it. When a cycle is started, if the duration_s=0 or is not provided, the default duration will be used. For example: .. code-block:: python await target.send(ChangeCleanCycle(enable=True), ["d073d5000001", "d073d5000001"]) Options are: enable - boolean (required) Pass True to start a cleaning cycle or False to stop a cycle in progress duration_s - integer (optional) Only used if enable=True. Specifies the duration (in seconds) for the cleaning cycle. If not specified, the default duration will be used. Default duration can be set using target:set_clean_config and returned using target_get_clean_config """ if duration is not None: raise ProgrammerError("Duration needs to be specified as duration_s") return ForCapability(hev=LightMessages.SetHevCycle( enable=enable, duration_s=duration_s, ack_required=True, res_required=False, ))
def SetCleanConfig(*, indication, duration_s, duration=None, **kwargs): """ Returns a valid message that will set the default clean cycle configuration for the device. For example: .. code-block:: python await target.send(SetCleanConfig(indication=True), ["d073d5000001", "d073d5000001"]) The options are: indication - boolean - default False whether to run a short flashing indication at the end of the HEV cycle. duration_s - seconds - default 7200 seconds duration in seconds for a cleaning cycle, if no duration provided. """ if duration is not None: raise ProgrammerError("Duration needs to be specified as duration_s") return ForCapability(hev=LightMessages.SetHevCycleConfiguration( indication=bool(indication), duration_s=duration_s, ack_required=True, res_required=False, ))
def until(self, major, minor, *conditions, becomes): if any((ma, mi) >= (major, minor) and conditions == conds for ma, mi, _, conds in self.upgrades): raise ProgrammerError( "Each .until must be for a greater version number") self.upgrades.append((major, minor, becomes, conditions)) return self
def setup(self, pkt, enum, bitmask, unpacking=False, allow_float=False): self.pkt = pkt self.enum = enum self.bitmask = bitmask self.unpacking = unpacking self.allow_float = allow_float if self.enum and self.bitmask: raise ProgrammerError( "Sorry, can't specify enum and bitmask for the same type")
def setup(self): self.active = False self.packet_filter = Filter() self.final_future = None self.last_final_future = None if not hasattr(self, "io_source"): raise ProgrammerError( f"IO must have an io_source property: {self.__class__}")
def __getitem__(self, name): """Return a registered target template, or complain if one is not available under this name""" if not isinstance(name, str): raise ProgrammerError( f"Targets are key'd by their name but using {name}") if name in (None, sb.NotSpecified) or name not in self.registered: raise TargetNotFound(wanted=name, available=sorted(self.registered)) return self.registered[name]
def transform(self, pack_func, unpack_func): """Set a ``pack_func`` and ``unpack_func`` for transforming the value for use""" for f in (pack_func, unpack_func): if not callable(f): raise ProgrammerError( "Sorry, transform can only be given two callables") res = self.S(self.size_bits) res._transform = pack_func res._unpack_transform = unpack_func return res
def determine_enum(self): """ Work out our enum value. if it's a callable and not an Enum class we call it with our packet to determine the enum. The bitmask must then be a subclass of enum.Enum """ em = self.enum if type(em) is not enum.EnumMeta and callable(em): em = em(self.pkt) try: if not issubclass(em, enum.Enum): raise ProgrammerError("Enum is not an enum! got {0}".format( repr(em))) except TypeError: raise ProgrammerError("Enum is not an enum! got {0}".format( repr(em))) return em
def __new__(metaname, classname, baseclasses, attrs): groups = {} all_names = [] all_fields = [] field_types = [] format_types = [] name_to_group = {} fields = attrs.get("fields") if fields is None: for kls in baseclasses: if hasattr(kls, "Meta") and hasattr(kls.Meta, "original_fields"): fields = kls.Meta.original_fields if fields is None: msg = "PacketSpecMixin expects a fields attribute on the class or a PacketSpec parent" raise ProgrammerError("{0}\tcreating={1}".format(msg, classname)) if type(fields) is dict: msg = "PacketSpecMixin expect fields to be a list of tuples, not a dictionary" raise ProgrammerError("{0}\tcreating={1}".format(msg, classname)) for name, typ in fields: if isinstance(typ, str): typ = attrs[typ] if hasattr(typ, "Meta"): groups[name] = [] for n, _ in typ.Meta.field_types: groups[name].append(n) name_to_group[n] = name all_fields.extend(typ.Meta.field_types) all_names.extend(groups[name]) else: all_names.append(name) all_fields.append((name, typ)) format_types.append(typ) field_types.append((name, typ)) if len(set(all_names)) != len(all_names): raise ProgrammerError("Duplicated names!\t{0}".format( [name for name in all_names if all_names.count(name) > 1])) class MetaRepr(type): def __repr__(self): return "<type {0}.Meta>".format(classname) Meta = type.__new__( MetaRepr, "Meta", (), { "multi": None, "groups": groups, "all_names": all_names, "field_types": field_types, "format_types": format_types, "name_to_group": name_to_group, "all_field_types": all_fields, "original_fields": fields, "field_types_dict": dict(field_types), "all_field_types_dict": dict(all_fields), }, ) attrs["Meta"] = Meta def dflt(in_group): return Initial if in_group else sb.NotSpecified attrs["fields"] = [(name, partial(dflt, name in groups)) for name in (list(all_names) + list(groups.keys()))] kls = type.__new__(metaname, classname, baseclasses, attrs) already_attributes = [] for field in all_names: if hasattr(kls, field): already_attributes.append(field) if already_attributes: raise ProgrammerError( "Can't override attributes with fields\talready_attributes={0}" .format(sorted(already_attributes))) return kls
def value(self, cap): raise ProgrammerError( "CapabilityRange should only ever be present during definition time" )
def __init__(self, value): if not isinstance(value, tuple) or len(value) != 2: raise ProgrammerError( "Values in a capability range must be a tuple of two values") super().__init__(value)
def __init__(self, event=sb.NotSpecified): if event is sb.NotSpecified: raise ProgrammerError("Please use event.raise_stop() instead") self.event = event
def __init__(self, sender): if isinstance(sender, Target): raise ProgrammerError( "The Gatherer no longer takes in target instances. Please pass in a target.session result instead" ) self.sender = sender