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.
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