4
4
from __future__ import annotations
5
5
6
6
import logging
7
+ import re
7
8
8
9
from pathlib import Path
9
10
from yaml import safe_load
@@ -25,9 +26,10 @@ def __init__(self, quarantine_list=[]) -> None:
25
26
for quarantine_file in quarantine_list :
26
27
self .quarantine .extend (QuarantineData .load_data_from_yaml (quarantine_file ))
27
28
28
- def get_matched_quarantine (self , testname , platform , architecture ):
29
- qelem = self .quarantine .get_matched_quarantine (testname , platform , architecture )
29
+ def get_matched_quarantine (self , testname , platform , architecture , simulation ):
30
+ qelem = self .quarantine .get_matched_quarantine (testname , platform , architecture , simulation )
30
31
if qelem :
32
+ logger .debug ('%s quarantined with reason: %s' % (testname , qelem .comment ))
31
33
return qelem .comment
32
34
return None
33
35
@@ -37,18 +39,26 @@ class QuarantineElement:
37
39
scenarios : list [str ] = field (default_factory = list )
38
40
platforms : list [str ] = field (default_factory = list )
39
41
architectures : list [str ] = field (default_factory = list )
42
+ simulations : list [str ] = field (default_factory = list )
40
43
comment : str = 'under quarantine'
41
44
42
45
def __post_init__ (self ):
46
+ # If there is no entry in filters then take all possible values.
47
+ # To keep backward compatibility, 'all' keyword might be still used.
43
48
if 'all' in self .scenarios :
44
49
self .scenarios = []
45
50
if 'all' in self .platforms :
46
51
self .platforms = []
47
52
if 'all' in self .architectures :
48
53
self .architectures = []
49
- if not any ([self .scenarios , self .platforms , self .architectures ]):
50
- raise QuarantineException ("At least one of filters ('scenarios', 'platforms', "
51
- "'architectures') must be specified" )
54
+ if 'all' in self .simulations :
55
+ self .simulations = []
56
+ # However, at least one of the filters ('scenarios', platforms' ...)
57
+ # must be given (there is no sense to put all possible configuration
58
+ # into quarantine)
59
+ if not any ([self .scenarios , self .platforms , self .architectures , self .simulations ]):
60
+ raise QuarantineException ("At least one of filters ('scenarios', 'platforms' ...) "
61
+ "must be specified" )
52
62
53
63
54
64
@dataclass
@@ -58,48 +68,56 @@ class QuarantineData:
58
68
def __post_init__ (self ):
59
69
qelements = []
60
70
for qelem in self .qlist :
61
- qelements .append (QuarantineElement (** qelem ))
71
+ if isinstance (qelem , QuarantineElement ):
72
+ qelements .append (qelem )
73
+ else :
74
+ qelements .append (QuarantineElement (** qelem ))
62
75
self .qlist = qelements
63
76
64
77
@classmethod
65
78
def load_data_from_yaml (cls , filename : str | Path ) -> QuarantineData :
66
79
"""Load quarantine from yaml file."""
67
80
with open (filename , 'r' , encoding = 'UTF-8' ) as yaml_fd :
68
- qlist : list ( dict ) = safe_load (yaml_fd )
81
+ qlist_raw_data : list [ dict ] = safe_load (yaml_fd )
69
82
try :
70
- return cls (qlist )
83
+ return cls (qlist_raw_data )
71
84
72
85
except Exception as e :
73
86
logger .error (f'When loading { filename } received error: { e } ' )
74
87
raise QuarantineException ('Cannot load Quarantine data' ) from e
75
88
76
- def extend (self , qdata : QuarantineData ) -> list [ QuarantineElement ] :
89
+ def extend (self , qdata : QuarantineData ) -> None :
77
90
self .qlist .extend (qdata .qlist )
78
91
79
- def get_matched_quarantine (self , scenario : str , platform : str ,
80
- architecture : str ) -> QuarantineElement | None :
92
+ def get_matched_quarantine (self ,
93
+ scenario : str ,
94
+ platform : str ,
95
+ architecture : str ,
96
+ simulation : str ) -> QuarantineElement | None :
81
97
"""Return quarantine element if test is matched to quarantine rules"""
82
98
for qelem in self .qlist :
83
99
matched : bool = False
84
- if qelem .scenarios :
85
- if scenario in qelem .scenarios :
86
- matched = True
87
- else :
88
- matched = False
89
- continue
90
- if qelem .platforms :
91
- if platform in qelem .platforms :
92
- matched = True
93
- else :
94
- matched = False
95
- continue
96
- if qelem .architectures :
97
- if architecture in qelem .architectures :
98
- matched = True
99
- else :
100
- matched = False
101
- continue
100
+ if (qelem .scenarios
101
+ and (matched := _is_element_matched (scenario , qelem .scenarios )) is False ):
102
+ continue
103
+ if (qelem .platforms
104
+ and (matched := _is_element_matched (platform , qelem .platforms )) is False ):
105
+ continue
106
+ if (qelem .architectures
107
+ and (matched := _is_element_matched (architecture , qelem .architectures )) is False ):
108
+ continue
109
+ if (qelem .simulations
110
+ and (matched := _is_element_matched (simulation , qelem .simulations )) is False ):
111
+ continue
112
+
102
113
if matched :
103
114
return qelem
104
-
105
115
return None
116
+
117
+
118
+ def _is_element_matched (element : str , list_of_elements : list ) -> bool :
119
+ """Return True if given element is matching to any of elements from the list"""
120
+ for pattern in list_of_elements :
121
+ if re .fullmatch (pattern , element ):
122
+ return True
123
+ return False
0 commit comments