Example #1
0
 def add(self, items):
     """Add entry to global presubs list"""
     with _presub_lock:
         self.load_from_cloud()
         for entry in utils.ensure_listable(items):
             # add new entries, but only if they're unique
             if entry not in self.current:
                 self.current.append(entry)
         self.save_to_cloud()
Example #2
0
 def remove(self, items):
     """Remove entry from global presubs list"""
     with _presub_lock:
         self.load_from_cloud()
         for entry in utils.ensure_listable(items):
             # remove all matching entries
             while entry in self.current:
                 self.current.remove(entry)
         self.save_to_cloud()
Example #3
0
 def get_service_packages(self):
     """Get all service packages"""
     api = self._get_api(billing.DefaultApi)
     package_response = api.get_service_packages()
     packages = []
     for state in PACKAGE_STATES:
         # iterate states in order
         items = getattr(package_response, state) or []
         for item in ensure_listable(items):
             params = item.to_dict()
             params['state'] = state
             packages.append(ServicePackage(params))
     return packages
def expand_dict_as_keys(d):
    """Expands a dictionary into a list of immutables with cartesian product

    :param d: dictionary (of strings or lists)
    :returns: cartesian product of list parts
    """
    to_product = []
    for key, values in sorted(d.items()):
        # if we sort the inputs here, itertools.product will keep a stable sort order for us later
        key_values = sorted([(key, v) for v in utils.ensure_listable(values) if v is not None])
        if key_values:
            to_product.append(key_values)
    return list(itertools.product(*to_product))
Example #5
0
    def __init__(self,
                 device_id=None,
                 resource_path=None,
                 first_value=FirstValue.on_value_update,
                 **extra_filters):
        """Triggers when a resource's value changes

        .. warning:: This functionality is considered experimental;
           the interface may change in future releases

        :param device_id: device identifier, (or list thereof), optionally ending with wildcard *
        :param resource_path: resource path, (or list thereof), optionally ending with wildcard *
        :param first_value: mode for adjusting immediacy of subscribed values
        :param extra_filters: other local key-value filters
        """
        super(ResourceValues, self).__init__()

        self.device_ids = [
            str(d) for d in utils.ensure_listable(device_id) if d
        ]
        self.resource_paths = [
            str(p) for p in utils.ensure_listable(resource_path) if p
        ]
        # TODO(endpoint_type) support needs the endpoint_type or identifier in presub api response
        # self.endpoint_type

        self._immediacy = first_value
        self._presubscription_registry = None  # type: PreSubscriptionRegistry

        # for filtering inbound notifications (with wildcards)
        self._local_filters = {}

        # for configuring the router (which has no wildcard behaviour)
        self._route_seeds = {
            'channel': ChannelIdentifiers.notifications,
        }

        # turn our parameters into a presubscriptions-compatible list (one device id per entry)
        # note: pluralised 'resource_paths'
        self._sdk_presub_params = [{
            k: v
            for k, v in dict(device_id=d,
                             resource_paths=self.resource_paths).items() if v
        } for d in self.device_ids or [None]]

        # api sends back different field names on the notification channel so remap them before
        # putting them in the routing table
        for api_key_name, values in dict(ep=self.device_ids,
                                         path=self.resource_paths).items():
            has_wildcards = any(self._is_wildcard(v) for v in values if v)
            for to_validate in values:
                if to_validate is None:
                    continue
                if not self._validate_wildcard(to_validate):
                    raise ValueError(
                        'Wildcards can only be used at the end of values: "%s"'
                        % (to_validate, ))
                # local filters recreate behaviour of server-side wildcard filter, but are not
                # routable (can't look them up in a dictionary)
                # routable filters are for explicit key-value pairs
                if has_wildcards:
                    self._local_filters.setdefault(api_key_name,
                                                   []).append(to_validate)
                else:
                    self._route_seeds.setdefault(api_key_name,
                                                 []).append(to_validate)
        self._route_keys = expand_dict_as_keys(self._route_seeds)

        self._optional_filters = {}
        self._optional_filters.update(extra_filters)
        self._optional_filter_keys = expand_dict_as_keys(
            self._optional_filters)

        self.add_filter_function(self._wildcard_filter)