Example #1
0
    def add_subtask(self, subtask):
        """Link a subtask to this parent task.

        This will cause stop() to block until the subtask has also
        finished.  Calling stop will not directly cancel the subtask.
        It is expected that your finalizer for this parent task will
        cancel or otherwise stop the subtask.

        Args:
            subtask (BackgroundTask): Another task that will be stopped
                when this task is stopped.
        """

        if self.stopped:
            raise InternalError(
                "Cannot add a subtask to a parent that is already stopped")

        if not isinstance(subtask, BackgroundTask):
            raise ArgumentError(
                "Subtasks must inherit from BackgroundTask, task={}".format(
                    subtask))

        # pylint:disable=protected-access;It is the same class as us so is equivalent to self access.
        if subtask._loop != self._loop:
            raise ArgumentError(
                "Subtasks must run in the same BackgroundEventLoop as their parent",
                subtask=subtask,
                parent=self)

        self.subtasks.append(subtask)
Example #2
0
def _create_resp_format(result_type, result_format):
    if result_type is not None and result_format is not None:
        raise ArgumentError("Both result_type and result_format specified",
                            result_format=result_format,
                            result_type=result_type)

    if result_format is not None:
        return result_format

    if result_type is None:
        return ""

    try:
        int_count, has_buffer = result_type
    except ValueError as err:
        raise ArgumentError(
            "Invalid value for result_type, must be tuple(int_count, has_buffer)",
            result_type=result_type) from err

    if has_buffer is False and int_count == 0:
        return ""

    if has_buffer is False:
        return "%dH" % int_count

    return "%dHV" % int_count
Example #3
0
    def __init__(self,
                 cor,
                 name=None,
                 finalizer=None,
                 stop_timeout=1.0,
                 loop=None):
        self._name = name
        self._finalizer = finalizer
        self._stop_timeout = stop_timeout
        self._logger = logging.getLogger(__name__)
        self.stopped = False

        if loop is None:
            loop = SharedLoop

        if not isinstance(loop, BackgroundEventLoop):
            raise ArgumentError(
                "A BackgroundTask must be created with a BackgroundEventLoop, loop={}"
                .format(loop))

        self._loop = loop

        self.subtasks = []
        if inspect.iscoroutine(cor):
            self.task = _create_task_threadsafe(cor, self._loop)
        elif inspect.iscoroutinefunction(cor):
            self.task = _create_task_threadsafe(cor(), self._loop)
        elif isinstance(cor, asyncio.Task):
            self.task = cor
        elif cor is None:
            self.task = None
        else:
            raise ArgumentError(
                "Unknown object passed to Background task: {}".format(cor))
Example #4
0
    def local_service(self, name_or_id):
        """Get the locally synced information for a service.

        Args:
            name_or_id (string or int): Either a short name for the service or
                a numeric id.

        Returns:
            ServiceState: the current state of the service synced locally
                at the time of the call.
        """

        with self._state_lock:
            if isinstance(name_or_id, int):
                if name_or_id not in self._name_map:
                    raise ArgumentError("Unknown ID used to look up service",
                                        id=name_or_id)

                name = self._name_map[name_or_id]
            else:
                name = name_or_id

            if name not in self.services:
                raise ArgumentError("Unknown service name", name=name)

            service = self.services[name]
            return copy(service)
Example #5
0
    def FromBinary(cls, record_data, record_count=1):
        """Create an UpdateRecord subclass from binary record data.

        This should be called with a binary record blob (NOT including the
        record type header) and it will decode it into a ReflashControllerRecord.

        Args:
            record_data (bytearray): The raw record data that we wish to parse
                into an UpdateRecord subclass NOT including its 8 byte record header.
            record_count (int): The number of records included in record_data.

        Raises:
            ArgumentError: If the record_data is malformed and cannot be parsed.

        Returns:
            ReflashControllerRecord: The decoded reflash tile record.
        """

        if len(record_data) < ReflashControllerRecord.RecordHeaderLength:
            raise ArgumentError(
                "Record was too short to contain a full reflash record header",
                length=len(record_data),
                header_length=ReflashControllerRecord.RecordHeaderLength)

        offset, data_length = struct.unpack_from("<LL", record_data)

        bindata = record_data[ReflashControllerRecord.RecordHeaderLength:]
        if len(bindata) != data_length:
            raise ArgumentError(
                "Embedded firmware length did not agree with actual length of embeded data",
                length=len(bindata),
                embedded_length=data_length)

        return ReflashControllerRecord(bindata, offset)
Example #6
0
def _convert_to_bytearray(type_name, value):
    """Convert a typed value to a binary array"""

    int_types = {'uint8_t': 'B', 'int8_t': 'b', 'uint16_t': 'H', 'int16_t': 'h', 'uint32_t': 'L', 'int32_t': 'l'}

    type_name = type_name.lower()

    is_array = False
    if type_name[-2:] == '[]':
        if value[0] != '[' or value[-1] != ']':
            raise ArgumentError("Array value improperly formated, must be a stringified list")
        is_array = True
        type_name = type_name[:-2]

    if type_name not in int_types and type_name not in ['string', 'binary']:
        raise ArgumentError('Type must be a known integer type, integer type array, string', known_integers=int_types.keys(), actual_type=type_name)

    if type_name == 'string':
        #value should be passed as a string
        bytevalue = bytearray(value, 'utf-8')
    elif type_name == 'binary':
        bytevalue = bytearray(value)
    elif is_array:
        value = [int(n,0) for n in value[1:-1].split(',')]
        bytevalue = bytearray(struct.pack("<%s" % (int_types[type_name]*len(value)), *value))
    else:
        bytevalue = bytearray(struct.pack("<%s" % int_types[type_name], value))

    return bytevalue
Example #7
0
    def run(self):
        cloud = IOTileCloud()
        info = cloud.device_info(self._uuid)

        if self._sensorgraph is not None:
            if info['sg'] != self._sensorgraph:
                if not self._overwrite:
                    raise ArgumentError("Cloud has incorrect sensorgraph setting", \
                        cloud_sensorgraph=info['sg'], expect_sensorgraph=self._sensorgraph)
                else:
                    print("--> Updating cloud sensorgraph from %s to %s" % \
                        (info['sg'], self._sensorgraph))
                    cloud.set_sensorgraph(self._uuid,
                                          self._sensorgraph,
                                          app_tag=self._expected_app_tag)

        if self._device_template is not None:
            if info['template'] != self._device_template:
                if not self._overwrite:
                    raise ArgumentError("Cloud has incorrect device_template setting", \
                        cloud_device_template=info['template'], expect_device_template=self._device_template)
                else:
                    print("--> Updating cloud device template from %s to %s" % \
                        (info['template'], self._device_template))
                    cloud.set_device_template(self._uuid,
                                              self._device_template,
                                              os_tag=self._expected_os_tag)
Example #8
0
    def archive(self, output_path):
        """Archive this recipe and all associated files into a .ship archive.

        Args:
            output_path (str): The path where the .ship file should be saved.
        """

        if self.path is None:
            raise ArgumentError(
                "Cannot archive a recipe yet without a reference to its original yaml file in self.path"
            )

        outfile = zipfile.ZipFile(output_path, 'w', zipfile.ZIP_DEFLATED)

        outfile.write(self.path, arcname="recipe_script.yaml")

        written_files = set()

        for _factory, args, _resources, files in self.steps:
            for arg_name in files:
                file_path = args[arg_name]

                if file_path in written_files:
                    continue

                if os.path.basename(file_path) != file_path:
                    raise ArgumentError(
                        "Cannot archive a recipe yet that references file not in the same directory as the recipe"
                    )

                full_path = os.path.join(os.path.dirname(self.path), file_path)
                outfile.write(full_path, arcname=file_path)
                written_files.add(file_path)
Example #9
0
    def FromString(cls, desc):
        """Create a slot identifier from a string description.

        The string needs to be either:

        controller
        OR
        slot <X> where X is an integer that can be converted with int(X, 0)

        Args:
            desc (str): The string description of the slot

        Returns:
            SlotIdentifier
        """

        desc = str(desc)

        if desc == u'controller':
            return SlotIdentifier(controller=True)

        words = desc.split()
        if len(words) != 2 or words[0] != u'slot':
            raise ArgumentError(u"Illegal slot identifier", descriptor=desc)

        try:
            slot_id = int(words[1], 0)
        except ValueError:
            raise ArgumentError(u"Could not convert slot identifier to number",
                                descriptor=desc,
                                number=words[1])

        return SlotIdentifier(slot=slot_id)
Example #10
0
    def run(self):
        process = Popen(shlex.split(self._context),
                        stdout=PIPE,
                        stdin=PIPE,
                        stderr=STDOUT)
        out, err = process.communicate(
            input='\n'.join(self._commands).encode('utf-8'))
        if err is not None:
            raise ArgumentError("Output Errored",
                                errors=err,
                                commands=self._commands)

        out = out.decode('utf-8')

        #Split outputs and remove context strings
        outputs = [
            section.split(') ')[-1].strip() for section in out.split('\n(')
        ]
        return_strings = []

        for i in range(len(self._commands)):
            return_strings += [
                "Command: %s\nOutput: %s" % (self._commands[i], outputs[i])
            ]
            if self._expect is not None:
                expected_output = self._expect[i]
                if expected_output is not None:
                    if outputs[i] != expected_output:
                        raise ArgumentError("Unexpected output", command=self._commands[i], \
                            expected=expected_output, actual=outputs[i])
        print('\n'.join(return_strings))
Example #11
0
    def __init__(self, source, comparator, reference_value):
        source = str(source)
        if source not in [u'count', u'value']:
            raise ArgumentError(
                "Unknwon source for input trigger, should be count or value",
                source=source)

        self.use_count = False
        if source == u'count':
            self.use_count = True

        known_comps = {
            u'>': self._gt_comp,
            u'>=': self._ge_comp,
            u'<': self._lt_comp,
            u'<=': self._le_comp,
            u'==': self._eq_comp
        }

        comparator = str(comparator)
        if comparator not in known_comps:
            raise ArgumentError("Unkown comparison function for input trigger",
                                comparator=comparator)

        self.comp_function = known_comps[comparator]
        self.comp_string = comparator
        self.reference = reference_value
Example #12
0
def _pack_version(tag, version):
    if tag >= (1 << 20):
        raise ArgumentError(
            "The tag number is too high.  It must fit in 20-bits",
            max_tag=1 << 20,
            tag=tag)

    if "." not in version:
        raise ArgumentError("You must pass a version number in X.Y format",
                            version=version)

    major, _, minor = version.partition('.')
    try:
        major = int(major)
        minor = int(minor)
    except ValueError:
        raise ArgumentError(
            "Unable to convert version string into major and minor version numbers",
            version=version)

    if major < 0 or minor < 0 or major >= (1 << 6) or minor >= (1 << 6):
        raise ArgumentError(
            "Invalid version numbers that must be in the range [0, 63]",
            major=major,
            minor=minor,
            version_string=version)

    version_number = (major << 6) | minor
    combined_tag = (version_number << 20) | tag
    return combined_tag
Example #13
0
    def adjust_monitor(self, monitor_id, add_events=None, remove_events=None):
        """Adjust the events that this monitor wishes to receive

        Args:
            monitor_id (string): The exact string returned from a previous call to register_monitor
            add_events (iterable): A list of events to begin receiving
            remove_events (iterable): A list of events to stop receiving
        """

        dev_uuid, _, monitor_name = monitor_id.partition('/')

        if dev_uuid == '*':
            raise ArgumentError("You are not currently allowed to adjust a global monitor", monitor_id=monitor_id)

        dev_uuid = int(dev_uuid)
        if dev_uuid not in self.monitors or monitor_name not in self.monitors[dev_uuid]:
            raise ArgumentError("Could not find monitor by name", monitor_id=monitor_id)


        filters, callback = self.monitors[dev_uuid][monitor_name]

        if add_events is not None:
            filters.update(add_events)
        if remove_events is not None:
            filters.difference_update(remove_events)

        self.monitors[dev_uuid][monitor_name] = (filters, callback)
Example #14
0
    async def _write_ff_dump_cmd(self, start, length):
        start_bytes = start.to_bytes(4, byteorder='little')
        length_bytes = length.to_bytes(2, byteorder='little')

        cmd_id = 0
        read_cmd = struct.pack("B", cmd_id)
        await self.write_memory(ff_cfg.ff_addresses['command_id'], read_cmd, chunk_size=1)
        written_cmd, = await self.read_memory(ff_cfg.ff_addresses['command_id'], 1, chunk_size=1, join=False)

        if written_cmd != cmd_id:
            raise ArgumentError("FF dump command id was not successfully written.")
        else:
            logger.info("FF dump command id written was %s", hex(cmd_id))

        await self.write_memory(ff_cfg.ff_addresses['read_command_address'], start_bytes, chunk_size=1)
        written_start, = await self.read_memory(ff_cfg.ff_addresses['read_command_address'], 4, chunk_size=4, join=False)

        if written_start != start:
            raise ArgumentError("FF dump command address was not successfully written.")
        else:
            logger.info("FF dump command address written to %s", hex(start))

        await self.write_memory(ff_cfg.ff_addresses['read_command_length'], length_bytes, chunk_size=1)
        written_length, = await self.read_memory(ff_cfg.ff_addresses['read_command_length'], 2, chunk_size=2, join=False)

        if written_length != length:
            raise ArgumentError("ff dump command length was not successfully written.")
        else:
            logger.info("ff dump command length written to %d", length)
Example #15
0
    def _read_memory_blocking(self, start_address, length, chunk_size=4, join=True):
        if chunk_size not in (1, 2, 4):
            raise ArgumentError("Invalid chunk size specified in read_memory command", chunk_size=chunk_size)

        if length % chunk_size != 0:
            raise ArgumentError("You must specify a length that is an integer multiple of chunk_size", length=length, chunk_size=chunk_size)

        if start_address % chunk_size != 0:
            raise ArgumentError("You must specify a start address that is aligned to your chunk_size", start_address=start_address, chunk_size=chunk_size)

        word_length = length // chunk_size
        if chunk_size == 1:
            words = self._jlink.memory_read8(start_address, word_length)
            pack_size = "B"
        elif chunk_size == 2:
            words = self._jlink.memory_read16(start_address, word_length)
            pack_size = "H"
        elif chunk_size == 4:
            words = self._jlink.memory_read32(start_address, word_length)
            pack_size = "L"

        if join:
            return struct.pack("<%d%s" % (word_length, pack_size), *words)

        return words
Example #16
0
    def update_state(self, short_name, state):
        """Set the current state of a service.

        If the state is unchanged from a previous attempt, this routine does
        nothing.

        Args:
            short_name (string): The short name of the service
            state (int): The new stae of the service
        """

        if short_name not in self.services:
            raise ArgumentError("Service name is unknown", short_name=short_name)

        if state not in states.KNOWN_STATES:
            raise ArgumentError("Invalid service state", state=state)

        serv = self.services[short_name]['state']

        if serv.state == state:
            return

        update = {}
        update['old_status'] = serv.state
        update['new_status'] = state
        update['new_status_string'] = states.KNOWN_STATES[state]

        serv.state = state
        self._notify_update(short_name, 'state_change', update)
Example #17
0
def _parse_target(target):
    """Parse a binary targeting information structure.

    This function only supports extracting the slot number or controller from
    the target and will raise an ArgumentError if more complicated targeting
    is desired.

    Args:
        target (bytes): The binary targeting data blob.

    Returns:
        dict: The parsed targeting data
    """

    if len(target) != 8:
        raise ArgumentError("Invalid targeting data length",
                            expected=8,
                            length=len(target))
    slot, match_op = struct.unpack("<B6xB", target)

    if match_op == _MATCH_CONTROLLER:
        return {'controller': True, 'slot': 0}
    elif match_op == _MATCH_SLOT:
        return {'controller': False, 'slot': slot}

    raise ArgumentError("Unsupported complex targeting specified",
                        match_op=match_op)
Example #18
0
    def get_config(self, slot, config_id):
        """Get a config variable assignment previously set on this sensor graph.

        Args:
            slot (SlotIdentifier): The slot that we are setting this config variable
                on.
            config_id (int): The 16-bit config variable identifier.

        Returns:
            (str, str|int): Returns a tuple with the type of the config variable and
                the value that is being set.

        Raises:
            ArgumentError: If the config variable is not currently set on the specified
                slot.
        """

        if slot not in self.config_database:
            raise ArgumentError(
                "No config variables have been set on specified slot",
                slot=slot)

        if config_id not in self.config_database[slot]:
            raise ArgumentError(
                "Config variable has not been set on specified slot",
                slot=slot,
                config_id=config_id)

        return self.config_database[slot][config_id]
Example #19
0
    def init_virtual_device_info(self, args):
        self.virtual_info['advertising_version'] = int(
            args.get('advertising_version', 1), 0)
        if self.virtual_info['advertising_version'] not in (1, 2):
            raise ArgumentError(
                "Invalid advertising version specified in args",
                supported=(1, 2),
                found=self.virtual_info['advertising_version'])

        self.virtual_info['reboot_count'] = int(args.get('reboot_count', 1), 0)
        if self.virtual_info['reboot_count'] <= 0:
            raise ArgumentError("Reboot count must be greater than 0.",
                                supported="> 0",
                                found=self.virtual_info['reboot_count'])

        self.virtual_info['mac_value'] = int(args.get('mac_value', 0), 0)
        if self.virtual_info['mac_value'] < 0 or self.virtual_info[
                'mac_value'] > 0xFFFFFFFF:
            raise ArgumentError("MAC value is limited to 32bits.",
                                supported="0 - 0xFFFFFFFF",
                                found=self.virtual_info['mac_value'])

        self.virtual_info['battery_voltage'] = float(
            args.get('battery_voltage', "3.14159"))
        if self.virtual_info['battery_voltage'] < 0 or self.virtual_info[
                'battery_voltage'] > 7.9:
            raise ArgumentError("Battery voltage is invalid",
                                supported="0 - 7.9",
                                found=self.virtual_info['battery_voltage'])
Example #20
0
def parse_size_name(type_name):
    """Calculate size and encoding from a type name.

    This method takes a C-style type string like uint8_t[10] and returns
    - the total size in bytes
    - the unit size of each member (if it's an array)
    - the scruct.{pack,unpack} format code for decoding the base type
    - whether it is an array.
    """

    if ' ' in type_name:
        raise ArgumentError("There should not be a space in config variable type specifier", specifier=type_name)

    variable = False
    count = 1
    base_type = type_name

    if type_name[-1] == ']':
        variable = True
        start_index = type_name.find('[')
        if start_index == -1:
            raise ArgumentError("Could not find matching [ for ] character", specifier=type_name)

        count = int(type_name[start_index+1:-1], 0)
        base_type = type_name[:start_index]

    matched_type = TYPE_CODES.get(base_type)
    if matched_type is None:
        raise ArgumentError("Could not find base type name", base_type=base_type, type_string=type_name)

    base_size = struct.calcsize("<%s" % matched_type)
    total_size = base_size*count

    return total_size, base_size, matched_type, variable
Example #21
0
    def _load_module_classes(cls, path, base_class):
        """Load a python module and return all classes that inherit from a given base."""

        folder, basename = os.path.split(path)
        basename, ext = os.path.splitext(basename)
        if ext not in (".py", ".pyc", ""):
            raise ArgumentError(
                "Attempted to load module is not a python package or module (.py or .pyc)",
                path=path)

        try:
            fileobj, pathname, description = imp.find_module(
                basename, [folder])

            #Don't load modules twice
            if basename in sys.modules:
                mod = sys.modules[basename]
            else:
                mod = imp.load_module(basename, fileobj, pathname, description)
        except ImportError as exc:
            cls.logger.exception(
                "Error importing module: %s looking for class %s", path,
                base_class)
            raise ArgumentError(
                "Could not import module in order to load external proxy modules",
                module_path=path,
                parent_directory=folder,
                module_name=basename,
                error=str(exc))

        # Find all classes in this module that inherit from the given base class
        return [
            x for x in itervalues(mod.__dict__) if inspect.isclass(x)
            and issubclass(x, base_class) and x != base_class
        ]
Example #22
0
    def __init__(self,
                 selector,
                 dest_tile,
                 report_format,
                 automatic,
                 report_type=u'telegram',
                 with_other=None):
        report_format = str(report_format)
        report_type = str(report_type)

        if report_format not in DataStreamer.KnownFormats:
            raise ArgumentError(
                "Unknown report format in DataStreamer constructor",
                report_format=report_format,
                known_formats=DataStreamer.KnownFormats.keys())

        if report_type not in DataStreamer.KnownTypes:
            raise ArgumentError(
                "Unknown report type in DataStreamer constructor",
                report_type=report_type,
                known_types=DataStreamer.KnownTypes.keys())

        self.selector = selector
        self.dest = dest_tile
        self.format = report_format
        self.automatic = automatic
        self.report_type = report_type
        self.with_other = with_other
    def get_connection_id(self, conn_or_internal_id):
        """Get the connection id.

        Args:
            conn_or_internal_id (int, string): The external integer connection id or
                an internal string connection id

        Returns:
            int: The connection id associated with that connection

        Raises:
            ArgumentError: When the key is not found in the list of active connections
                or is invalid.
        """

        key = conn_or_internal_id
        if isinstance(key, str):
            table = self._int_connections
        elif isinstance(key, int):
            table = self._connections
        else:
            raise ArgumentError(
                "You must supply either an int connection id or a string internal id to _get_connection_state",
                id=key)

        try:
            data = table[key]
        except KeyError:
            raise ArgumentError("Could not find connection by id", id=key)

        return data['connection_id']
Example #24
0
    def local_service(self, name_or_id):
        """Get the locally synced information for a service.

        This method is safe to call outside of the background event loop
        without any race condition.  Internally it uses a thread-safe mutex to
        protect the local copies of supervisor data and ensure that it cannot
        change while this method is iterating over it.

        Args:
            name_or_id (string or int): Either a short name for the service or
                a numeric id.

        Returns:
            ServiceState: the current state of the service synced locally
                at the time of the call.
        """

        if not self._loop.inside_loop():
            self._state_lock.acquire()

        try:
            if isinstance(name_or_id, int):
                if name_or_id not in self._name_map:
                    raise ArgumentError("Unknown ID used to look up service",
                                        id=name_or_id)
                name = self._name_map[name_or_id]
            else:
                name = name_or_id
            if name not in self.services:
                raise ArgumentError("Unknown service name", name=name)

            return copy(self.services[name])
        finally:
            if not self._loop.inside_loop():
                self._state_lock.release()
Example #25
0
    def finish_async_rpc(self, address, rpc_id, *response):
        """Finish a previous asynchronous RPC.

        This method should be called by a peripheral tile that previously
        had an RPC called on it and chose to response asynchronously by
        raising ``AsynchronousRPCResponse`` in the RPC handler itself.

        The response passed to this function will be returned to the caller
        as if the RPC had returned it immediately.

        This method must only ever be called from a coroutine inside the
        emulation loop that is handling background work on behalf of a tile.

        Args:
            address (int): The tile address the RPC was called on.
            rpc_id (int): The ID of the RPC that was called.
            *response: The response that should be returned to the caller.

                This can either be a single bytes or bytearray object or a
                str object containing the format code followed by the required
                number of python objects that will then be packed using
                pack_rpc_payload(format, args).

                If you pass no additional response arguments then an
                empty response will be given.
        """

        self.verify_calling_thread(
            True,
            "All asynchronous rpcs must be finished from within the emulation loop"
        )

        if len(response) == 0:
            response_bytes = b''
        elif len(response) == 1:
            response_bytes = response[0]

            if not isinstance(response_bytes, (bytes, bytearray)):
                raise ArgumentError(
                    "When passing a binary response to finish_async_rpc, you must "
                    "pass a bytes or bytearray object",
                    response=response_bytes)
        else:
            resp_format = response[0]
            resp_args = response[1:]

            if not isinstance(resp_format, str):
                raise ArgumentError(
                    "When passing a formatted response to finish_async_rpc, you must "
                    "pass a str object with the format code as the first parameter after "
                    "the rpc id.",
                    resp_format=resp_format,
                    additional_args=resp_args)

            response_bytes = pack_rpc_payload(resp_format, resp_args)

        self._rpc_queue.finish_async_rpc(address, rpc_id, response_bytes)
Example #26
0
    def load_extension(self,
                       path,
                       name_filter=None,
                       class_filter=None,
                       unique=False,
                       component=None):
        """Load a single python module extension.

        This function is similar to using the imp module directly to load a
        module and potentially inspecting the objects it declares to filter
        them by class.

        Args:
            path (str): The path to the python file to load
            name_filter (str): If passed, the basename of the module must match
                name or nothing is returned.
            class_filter (type): If passed, only instance of this class are returned.
            unique (bool): If True (default is False), there must be exactly one object
                found inside this extension that matches all of the other criteria.
            component (IOTile): The component that this extension comes from if it is
                loaded from an installed component.  This is used to properly import
                the extension as a submodule of the component's support package.

        Returns:
            list of (name, type): A list of the objects found at the extension path.

            If unique is True, then the list only contains a single entry and that
            entry will be directly returned.
        """

        import_name = None
        if component is not None:
            import_name = _ensure_package_loaded(path, component)

        name, ext = _try_load_module(path, import_name=import_name)

        if name_filter is not None and name != name_filter:
            return []

        found = [(name, x) for x in self._filter_subclasses(ext, class_filter)]
        found = [(name, x) for name, x in found
                 if self._filter_nonextensions(x)]

        if not unique:
            return found

        if len(found) > 1:
            raise ArgumentError(
                "Extension %s should have had exactly one instance of class %s, found %d"
                % (path, class_filter.__name__, len(found)),
                classes=found)
        elif len(found) == 0:
            raise ArgumentError("Extension %s had no instances of class %s" %
                                (path, class_filter.__name__))

        return found[0]
Example #27
0
    def allocate_stream(self, stream_type, stream_id=None, previous=None, attach=False):
        """Allocate a new stream of the given type.

        The stream is allocated with an incremental ID starting at
        StreamAllocator.StartingID.  The returned data stream can always
        be used to to attach a NodeInput to this stream, however the
        attach_stream() function should always be called first since this
        stream's output may need to be split and a logically equivalent
        stream used instead to satisfy a device specific constraint on the
        maximum number of outputs attached to a given stream.

        You can call allocate_stream on the same stream multiple times without
        issue.  Subsequent calls to allocate_stream are noops.

        Args:
            stream_type (int): A stream type specified in the DataStream class
                like DataStream.ConstantType
            stream_id (int): The ID we would like to use for this stream, if
                this is not specified, an ID is automatically allocated.
            previous (DataStream): If this stream was automatically derived from
                another stream, this parameter should be a link to the old
                stream.
            attach (bool): Call attach_stream immediately before returning.  Convenience
                routine for streams that should immediately be attached to something.

        Returns:
            DataStream: The allocated data stream.
        """

        if stream_type not in DataStream.TypeToString:
            raise ArgumentError("Unknown stream type in allocate_stream", stream_type=stream_type)

        if stream_id is not None and stream_id >= StreamAllocator.StartingID:
            raise ArgumentError("Attempted to explicitly allocate a stream id in the internally managed id range", stream_id=stream_id, started_id=StreamAllocator.StartingID)

        # If the stream id is not explicitly given, we need to manage and track it
        # from our autoallocate range
        if stream_id is None:
            if stream_type not in self._next_id:
                self._next_id[stream_type] = StreamAllocator.StartingID

            stream_id = self._next_id[stream_type]
            self._next_id[stream_type] += 1

        # Keep track of how many downstream nodes are attached to this stream so
        # that we know when we need to split it into two.
        stream = DataStream(stream_type, stream_id)

        if stream not in self._allocated_streams:
            self._allocated_streams[stream] = (stream, 0, previous)

        if attach:
            stream = self.attach_stream(stream)

        return stream
Example #28
0
    def LoadFromFile(cls, script_path):
        """Import a virtual tile from a file rather than an installed module

        script_path must point to a python file ending in .py that contains exactly one
        VirtualTile class definition.  That class is loaded and executed as if it
        were installed.

        To facilitate development, if there is a proxy object defined in the same
        file, it is also added to the HardwareManager proxy registry so that it
        can be found and used with the device.

        Args:
            script_path (string): The path to the script to load

        Returns:
            VirtualTile: A subclass of VirtualTile that was loaded from script_path
        """

        search_dir, filename = os.path.split(script_path)
        if search_dir == '':
            search_dir = './'

        if filename == '' or not os.path.exists(script_path):
            raise ArgumentError("Could not find script to load virtual tile",
                                path=script_path)

        module_name, ext = os.path.splitext(filename)
        if ext != '.py':
            raise ArgumentError("Script did not end with .py",
                                filename=filename)

        try:
            file_obj = None
            file_obj, pathname, desc = imp.find_module(module_name,
                                                       [search_dir])
            mod = imp.load_module(module_name, file_obj, pathname, desc)
        finally:
            if file_obj is not None:
                file_obj.close()

        devs = [
            x for x in itervalues(mod.__dict__) if inspect.isclass(x)
            and issubclass(x, VirtualTile) and x != VirtualTile
        ]
        if len(devs) == 0:
            raise ArgumentError(
                "No VirtualTiles subclasses were defined in script",
                path=script_path)
        elif len(devs) > 1:
            raise ArgumentError(
                "More than one VirtualTiles subclass was defined in script",
                path=script_path,
                tiles=devs)

        return devs[0]
Example #29
0
    def FromString(cls, string_rep):
        """Create a DataStreamSelector from a string.

        The format of the string should either be:

        all <type>
        OR
        <type> <id>

        Where type is [system] <stream type>, with <stream type>
        defined as in DataStream

        Args:
            rep (str): The string representation to convert to a DataStreamSelector
        """

        rep = str(string_rep)

        rep = rep.replace(u'node', '')
        rep = rep.replace(u'nodes', '')

        if rep.startswith(u'all'):
            parts = rep.split()

            spec_string = u''

            if len(parts) == 3:
                spec_string = parts[1]
                stream_type = parts[2]
            elif len(parts) == 2:
                stream_type = parts[1]
            else:
                raise ArgumentError("Invalid wildcard stream selector", string_rep=string_rep)

            try:
                # Remove pluralization that can come with e.g. 'all system outputs'
                if stream_type.endswith(u's'):
                    stream_type = stream_type[:-1]

                stream_type = DataStream.StringToType[stream_type]
            except KeyError:
                raise ArgumentError("Invalid stream type given", stream_type=stream_type, known_types=DataStream.StringToType.keys())

            stream_spec = DataStreamSelector.SpecifierNames.get(spec_string, None)
            if stream_spec is None:
                raise ArgumentError("Invalid stream specifier given (should be system, user, combined or blank)", string_rep=string_rep, spec_string=spec_string)

            return DataStreamSelector(stream_type, None, stream_spec)

        # If we're not matching a wildcard stream type, then the match is exactly
        # the same as a DataStream identifier, so use that to match it.

        stream = DataStream.FromString(rep)
        return DataStreamSelector.FromStream(stream)
Example #30
0
    def upload_report(self, report):
        """Upload an IOTile report to the cloud.

        This function currently supports uploading the following kinds of
        reports:
            SignedListReport
            FlexibleDictionaryReport

        If you pass an instance of IndividualReadingReport, an exception will
        be thrown because IOTile.cloud does not support receiving individual
        readings.  Those are only for local use.

        The filename of the uploaded report will have an extension set based
        on the type of report that you are uploading.

        Args:
            report (IOTileReport): The report that you want to upload.  This should
                not be an IndividualReadingReport.

        Returns:
            int: The number of new readings that were accepted by the cloud as novel.
        """

        if isinstance(report, IndividualReadingReport):
            raise ArgumentError(
                "You cannot upload IndividualReadingReport objects to iotile.cloud",
                report=report)

        if isinstance(report, SignedListReport):
            file_ext = ".bin"
        elif isinstance(report, FlexibleDictionaryReport):
            file_ext = ".mp"
        else:
            raise ArgumentError(
                "Unknown report format passed to upload_report",
                classname=report.__class__.__name__,
                report=report)

        timestamp = '{}'.format(report.received_time.isoformat())
        payload = {'file': ("report" + file_ext, BytesIO(report.encode()))}

        resource = self.api.streamer.report

        headers = {}
        authorization_str = '{0} {1}'.format(self.token_type, self.token)
        headers['Authorization'] = authorization_str

        resp = self.api.session.post(resource.url(),
                                     files=payload,
                                     headers=headers,
                                     params={'timestamp': timestamp})

        count = resource._process_response(resp)['count']
        return count