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 typing import Any 8 9from .probes import Probe 10 11 12class Matcher(object): 13 table_group_key = "table_group" 14 type_key = "type" 15 contains_key = "contains" 16 not_key = "not" 17 any_key = "any" 18 19 keywords = {contains_key, not_key, type_key, table_group_key, any_key} 20 21 def __init__(self, match_obj: dict, *, _type=None, table_group=None): 22 """ 23 table_group: required, which table that group belongs in 24 type: optional, the type of the metrics 25 26 All other fields are matched as exact matches, 27 except for `contains` which checks that that value 28 is in the associated array. 29 """ 30 self.table_group = table_group or match_obj.get(self.table_group_key) 31 self.type = _type or match_obj.get(self.type_key) 32 33 self.matcher = { 34 k: v 35 for k, v in match_obj.items() 36 if k not in {self.table_group_key, self.type_key} 37 } 38 39 def get_table_group(self): 40 return self.table_group 41 42 def matches(self, probe: Probe) -> bool: 43 # Not a match if the types don't match 44 if self.type and self.type != probe.get_type(): 45 return False 46 47 for k, v in self.matcher.items(): 48 probe_value = probe.get(k) 49 50 if not self._matches(v, probe_value): 51 return False 52 53 # Definitions are nested, check sub-fields (e.g. details) 54 if isinstance(v, dict): 55 for sub_k, sub_v in v.items(): 56 if sub_k not in self.keywords and not self._matches( 57 sub_v, probe_value[sub_k] 58 ): 59 return False 60 61 return True 62 63 def clone(self, new_type=None, new_table_group=None): 64 if new_table_group is None: 65 new_table_group = self.table_group 66 if new_type is None: 67 new_type = self.type 68 69 return Matcher(self.matcher, _type=new_type, table_group=new_table_group) 70 71 @staticmethod 72 def _matches(match_v: Any, probe_v: Any) -> bool: 73 if isinstance(probe_v, set): 74 probe_v = list(probe_v) 75 76 # Not a match if this key isn't in the probe definition 77 if probe_v is None: 78 return False 79 80 # Not a match if not an exact match of values (e.g. type=scalar vs. histogram) 81 if not isinstance(match_v, dict): 82 if match_v != probe_v: 83 return False 84 85 elif isinstance(match_v, dict): 86 # Not a match if probe_v doesn't contain expected value 87 if Matcher.contains_key in match_v: 88 if match_v[Matcher.contains_key] not in probe_v: 89 return False 90 91 # Not a match if matches the "not" value 92 if Matcher.not_key in match_v: 93 if match_v[Matcher.not_key] == probe_v: 94 return False 95 96 # Match if any of the listed values match 97 if Matcher.any_key in match_v: 98 return probe_v in match_v[Matcher.any_key] 99 return True
class
Matcher:
13class Matcher(object): 14 table_group_key = "table_group" 15 type_key = "type" 16 contains_key = "contains" 17 not_key = "not" 18 any_key = "any" 19 20 keywords = {contains_key, not_key, type_key, table_group_key, any_key} 21 22 def __init__(self, match_obj: dict, *, _type=None, table_group=None): 23 """ 24 table_group: required, which table that group belongs in 25 type: optional, the type of the metrics 26 27 All other fields are matched as exact matches, 28 except for `contains` which checks that that value 29 is in the associated array. 30 """ 31 self.table_group = table_group or match_obj.get(self.table_group_key) 32 self.type = _type or match_obj.get(self.type_key) 33 34 self.matcher = { 35 k: v 36 for k, v in match_obj.items() 37 if k not in {self.table_group_key, self.type_key} 38 } 39 40 def get_table_group(self): 41 return self.table_group 42 43 def matches(self, probe: Probe) -> bool: 44 # Not a match if the types don't match 45 if self.type and self.type != probe.get_type(): 46 return False 47 48 for k, v in self.matcher.items(): 49 probe_value = probe.get(k) 50 51 if not self._matches(v, probe_value): 52 return False 53 54 # Definitions are nested, check sub-fields (e.g. details) 55 if isinstance(v, dict): 56 for sub_k, sub_v in v.items(): 57 if sub_k not in self.keywords and not self._matches( 58 sub_v, probe_value[sub_k] 59 ): 60 return False 61 62 return True 63 64 def clone(self, new_type=None, new_table_group=None): 65 if new_table_group is None: 66 new_table_group = self.table_group 67 if new_type is None: 68 new_type = self.type 69 70 return Matcher(self.matcher, _type=new_type, table_group=new_table_group) 71 72 @staticmethod 73 def _matches(match_v: Any, probe_v: Any) -> bool: 74 if isinstance(probe_v, set): 75 probe_v = list(probe_v) 76 77 # Not a match if this key isn't in the probe definition 78 if probe_v is None: 79 return False 80 81 # Not a match if not an exact match of values (e.g. type=scalar vs. histogram) 82 if not isinstance(match_v, dict): 83 if match_v != probe_v: 84 return False 85 86 elif isinstance(match_v, dict): 87 # Not a match if probe_v doesn't contain expected value 88 if Matcher.contains_key in match_v: 89 if match_v[Matcher.contains_key] not in probe_v: 90 return False 91 92 # Not a match if matches the "not" value 93 if Matcher.not_key in match_v: 94 if match_v[Matcher.not_key] == probe_v: 95 return False 96 97 # Match if any of the listed values match 98 if Matcher.any_key in match_v: 99 return probe_v in match_v[Matcher.any_key] 100 return True
Matcher(match_obj: dict, *, _type=None, table_group=None)
22 def __init__(self, match_obj: dict, *, _type=None, table_group=None): 23 """ 24 table_group: required, which table that group belongs in 25 type: optional, the type of the metrics 26 27 All other fields are matched as exact matches, 28 except for `contains` which checks that that value 29 is in the associated array. 30 """ 31 self.table_group = table_group or match_obj.get(self.table_group_key) 32 self.type = _type or match_obj.get(self.type_key) 33 34 self.matcher = { 35 k: v 36 for k, v in match_obj.items() 37 if k not in {self.table_group_key, self.type_key} 38 }
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.
43 def matches(self, probe: Probe) -> bool: 44 # Not a match if the types don't match 45 if self.type and self.type != probe.get_type(): 46 return False 47 48 for k, v in self.matcher.items(): 49 probe_value = probe.get(k) 50 51 if not self._matches(v, probe_value): 52 return False 53 54 # Definitions are nested, check sub-fields (e.g. details) 55 if isinstance(v, dict): 56 for sub_k, sub_v in v.items(): 57 if sub_k not in self.keywords and not self._matches( 58 sub_v, probe_value[sub_k] 59 ): 60 return False 61 62 return True