mozilla_schema_generator.matcher

  1# -*- coding: utf-8 -*-
  2
  3# This Source Code Form is subject to the terms of the Mozilla Public
  4# License, v. 2.0. If a copy of the MPL was not distributed with this
  5# file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6
  7from copy import deepcopy
  8from typing import Any
  9
 10from .probes import Probe
 11
 12
 13class Matcher(object):
 14    table_group_key = "table_group"
 15    type_key = "type"
 16    contains_key = "contains"
 17    not_contains_key = "not_contains"
 18    not_key = "not"
 19    any_key = "any"
 20
 21    keywords = {
 22        contains_key,
 23        not_key,
 24        type_key,
 25        table_group_key,
 26        any_key,
 27        not_contains_key,
 28    }
 29
 30    def __init__(self, match_obj: dict, *, _type=None, table_group=None):
 31        """
 32        table_group: required, which table that group belongs in
 33        type: optional, the type of the metrics
 34
 35        All other fields are matched as exact matches,
 36        except for `contains` which checks that that value
 37        is in the associated array.
 38        """
 39        self.table_group = table_group or match_obj.get(self.table_group_key)
 40        self.type = _type or match_obj.get(self.type_key)
 41
 42        self.matcher = {
 43            k: v
 44            for k, v in match_obj.items()
 45            if k not in {self.table_group_key, self.type_key}
 46        }
 47
 48    def __repr__(self):
 49        return str(self.matcher)
 50
 51    def get_table_group(self):
 52        return self.table_group
 53
 54    def matches(self, probe: Probe) -> bool:
 55        # Not a match if the types don't match
 56        if self.type and self.type != probe.get_type():
 57            return False
 58
 59        for k, v in self.matcher.items():
 60            probe_value = probe.get(k)
 61
 62            if not self._matches(v, probe_value):
 63                return False
 64
 65            # Definitions are nested, check sub-fields (e.g. details)
 66            if isinstance(v, dict):
 67                for sub_k, sub_v in v.items():
 68                    if sub_k not in self.keywords and not self._matches(
 69                        sub_v, probe_value[sub_k]
 70                    ):
 71                        return False
 72
 73        return True
 74
 75    def clone(self, new_type=None, new_table_group=None):
 76        if new_table_group is None:
 77            new_table_group = self.table_group
 78        if new_type is None:
 79            new_type = self.type
 80
 81        return Matcher(
 82            deepcopy(self.matcher), _type=new_type, table_group=new_table_group
 83        )
 84
 85    @staticmethod
 86    def _matches(match_v: Any, probe_v: Any) -> bool:
 87        if isinstance(probe_v, set):
 88            probe_v = list(probe_v)
 89
 90        # Not a match if this key isn't in the probe definition
 91        if probe_v is None:
 92            return False
 93
 94        # Not a match if not an exact match of values (e.g. type=scalar vs. histogram)
 95        if not isinstance(match_v, dict):
 96            if match_v != probe_v:
 97                return False
 98
 99        elif isinstance(match_v, dict):
100            # Not a match if probe_v doesn't contain expected value
101            if Matcher.contains_key in match_v:
102                if match_v[Matcher.contains_key] not in probe_v:
103                    return False
104
105            # Not a match if probe_v contain value
106            if Matcher.not_contains_key in match_v:
107                if match_v[Matcher.not_contains_key] in probe_v:
108                    return False
109
110            # Not a match if matches the "not" value
111            if Matcher.not_key in match_v:
112                if match_v[Matcher.not_key] == probe_v:
113                    return False
114
115            # Match if any of the listed values match
116            if Matcher.any_key in match_v:
117                return probe_v in match_v[Matcher.any_key]
118        return True
class Matcher:
 14class Matcher(object):
 15    table_group_key = "table_group"
 16    type_key = "type"
 17    contains_key = "contains"
 18    not_contains_key = "not_contains"
 19    not_key = "not"
 20    any_key = "any"
 21
 22    keywords = {
 23        contains_key,
 24        not_key,
 25        type_key,
 26        table_group_key,
 27        any_key,
 28        not_contains_key,
 29    }
 30
 31    def __init__(self, match_obj: dict, *, _type=None, table_group=None):
 32        """
 33        table_group: required, which table that group belongs in
 34        type: optional, the type of the metrics
 35
 36        All other fields are matched as exact matches,
 37        except for `contains` which checks that that value
 38        is in the associated array.
 39        """
 40        self.table_group = table_group or match_obj.get(self.table_group_key)
 41        self.type = _type or match_obj.get(self.type_key)
 42
 43        self.matcher = {
 44            k: v
 45            for k, v in match_obj.items()
 46            if k not in {self.table_group_key, self.type_key}
 47        }
 48
 49    def __repr__(self):
 50        return str(self.matcher)
 51
 52    def get_table_group(self):
 53        return self.table_group
 54
 55    def matches(self, probe: Probe) -> bool:
 56        # Not a match if the types don't match
 57        if self.type and self.type != probe.get_type():
 58            return False
 59
 60        for k, v in self.matcher.items():
 61            probe_value = probe.get(k)
 62
 63            if not self._matches(v, probe_value):
 64                return False
 65
 66            # Definitions are nested, check sub-fields (e.g. details)
 67            if isinstance(v, dict):
 68                for sub_k, sub_v in v.items():
 69                    if sub_k not in self.keywords and not self._matches(
 70                        sub_v, probe_value[sub_k]
 71                    ):
 72                        return False
 73
 74        return True
 75
 76    def clone(self, new_type=None, new_table_group=None):
 77        if new_table_group is None:
 78            new_table_group = self.table_group
 79        if new_type is None:
 80            new_type = self.type
 81
 82        return Matcher(
 83            deepcopy(self.matcher), _type=new_type, table_group=new_table_group
 84        )
 85
 86    @staticmethod
 87    def _matches(match_v: Any, probe_v: Any) -> bool:
 88        if isinstance(probe_v, set):
 89            probe_v = list(probe_v)
 90
 91        # Not a match if this key isn't in the probe definition
 92        if probe_v is None:
 93            return False
 94
 95        # Not a match if not an exact match of values (e.g. type=scalar vs. histogram)
 96        if not isinstance(match_v, dict):
 97            if match_v != probe_v:
 98                return False
 99
100        elif isinstance(match_v, dict):
101            # Not a match if probe_v doesn't contain expected value
102            if Matcher.contains_key in match_v:
103                if match_v[Matcher.contains_key] not in probe_v:
104                    return False
105
106            # Not a match if probe_v contain value
107            if Matcher.not_contains_key in match_v:
108                if match_v[Matcher.not_contains_key] in probe_v:
109                    return False
110
111            # Not a match if matches the "not" value
112            if Matcher.not_key in match_v:
113                if match_v[Matcher.not_key] == probe_v:
114                    return False
115
116            # Match if any of the listed values match
117            if Matcher.any_key in match_v:
118                return probe_v in match_v[Matcher.any_key]
119        return True
Matcher(match_obj: dict, *, _type=None, table_group=None)
31    def __init__(self, match_obj: dict, *, _type=None, table_group=None):
32        """
33        table_group: required, which table that group belongs in
34        type: optional, the type of the metrics
35
36        All other fields are matched as exact matches,
37        except for `contains` which checks that that value
38        is in the associated array.
39        """
40        self.table_group = table_group or match_obj.get(self.table_group_key)
41        self.type = _type or match_obj.get(self.type_key)
42
43        self.matcher = {
44            k: v
45            for k, v in match_obj.items()
46            if k not in {self.table_group_key, self.type_key}
47        }

table_group: required, which table that group belongs in type: optional, the type of the metrics

All other fields are matched as exact matches, except for contains which checks that that value is in the associated array.

table_group_key = 'table_group'
type_key = 'type'
contains_key = 'contains'
not_contains_key = 'not_contains'
not_key = 'not'
any_key = 'any'
keywords = {'type', 'not', 'table_group', 'contains', 'not_contains', 'any'}
table_group
type
matcher
def get_table_group(self):
52    def get_table_group(self):
53        return self.table_group
def matches(self, probe: mozilla_schema_generator.probes.Probe) -> bool:
55    def matches(self, probe: Probe) -> bool:
56        # Not a match if the types don't match
57        if self.type and self.type != probe.get_type():
58            return False
59
60        for k, v in self.matcher.items():
61            probe_value = probe.get(k)
62
63            if not self._matches(v, probe_value):
64                return False
65
66            # Definitions are nested, check sub-fields (e.g. details)
67            if isinstance(v, dict):
68                for sub_k, sub_v in v.items():
69                    if sub_k not in self.keywords and not self._matches(
70                        sub_v, probe_value[sub_k]
71                    ):
72                        return False
73
74        return True
def clone(self, new_type=None, new_table_group=None):
76    def clone(self, new_type=None, new_table_group=None):
77        if new_table_group is None:
78            new_table_group = self.table_group
79        if new_type is None:
80            new_type = self.type
81
82        return Matcher(
83            deepcopy(self.matcher), _type=new_type, table_group=new_table_group
84        )