Source code for exporters.filters.key_value_filters

import re
import six

from exporters.filters.base_filter import BaseFilter
from exporters.utils import nested_dict_value
from exporters.utils import dict_list
import operator


class InvalidOperator(ValueError):
    """
    Exception to be trown when an invalid operator is set in filter keys
    """


OPERATORS = {
    'in': lambda a, b: operator.contains(b, a),
    'contains': lambda a, b: b in a,
    '==': lambda a, b: a == b,
    're_match': lambda a, b: bool(re.match(b, u'%s' % a))
}

DEFAULT_OPERATOR = '=='


class KeyValueBaseFilter(BaseFilter):
    "Base class to key-value filters"

    supported_options = {
        'keys': {'type': dict_list},
        'nested_field_separator': {'type': six.string_types, 'default': '.'}
    }

    def __init__(self, *args, **kwargs):
        super(KeyValueBaseFilter, self).__init__(*args, **kwargs)
        self.keys = self.read_option('keys')
        self.nested_field_separator = self.read_option('nested_field_separator')
        self._validate_keys_operator()
        self.logger.info('{} has been initiated. Keys: {}'.format(
            self.__class__.__name__, self.keys))

    def _validate_keys_operator(self):
        for key in self.keys:
            op = key.get('operator')
            if op and op not in OPERATORS:
                raise InvalidOperator('{} operator not valid in key {}'.format(op, key))

    def filter(self, item):
        for key in self.keys:
            if self.nested_field_separator:
                nested_fields = key['name'].split(self.nested_field_separator)
                try:
                    value = nested_dict_value(item, nested_fields)
                except KeyError:
                    self.logger.debug('Missing path {} from item. Item dismissed'.format(
                            nested_fields))
                    return False
            else:
                value = item[key['name']]
            if not self._match_value(
                    value, key['value'], OPERATORS[key.get('operator', DEFAULT_OPERATOR)]):
                return False
        return True

    def _match_value(self, value_found, value_expected, op=None):
        """Return True if value found matches the expected.
        Should be overriden by derived classes implementing custom match.
        """
        raise NotImplementedError


[docs]class KeyValueFilter(KeyValueBaseFilter): """ Filter items depending on keys and values - keys (list) It is a list of dicts with the following structure: {"key": "value"}. The filter will delete those items that do not contain a key "key" or, if they do, that key is not the same as "value". """ def _match_value(self, found, expected, op): return op(found, expected)
[docs]class KeyValueRegexFilter(KeyValueBaseFilter): """ Filter items depending on keys and values using regular expressions - keys (list) It is a list of dicts with the following structure: {"key": "regex"}. The filter will delete those items that do not contain a key "key" or, if they do, that key value does not match "regex". """ def _match_value(self, found, expected, op): if found is None: return False return OPERATORS['re_match'](found, expected)