33
44from splitio .models .grammar .matchers .base import Matcher
55from splitio .models .grammar .matchers .string import Sanitizer
6+ from splitio .models .grammar .matchers .utils .utils import build_semver_or_none
67
7- _LOGGER = logging .getLogger (__name__ )
8-
9- def build_semver_or_none (version ):
10- try :
11- return Semver (version )
12- except (RuntimeError , ValueError ):
13- _LOGGER .error ("Invalid semver version: %s" , version )
14- return None
15-
16- class Semver (object ):
17- """Semver class."""
18-
19- _METADATA_DELIMITER = "+"
20- _PRE_RELEASE_DELIMITER = "-"
21- _VALUE_DELIMITER = "."
22-
23- def __init__ (self , version ):
24- """
25- Class Initializer
26-
27- :param version: raw version as read from splitChanges response.
28- :type version: str
29- """
30- self ._major = 0
31- self ._minor = 0
32- self ._patch = 0
33- self ._pre_release = []
34- self ._is_stable = False
35- self .version = ""
36- self ._metadata = ""
37- self ._parse (version )
38-
39-
40- def _parse (self , version ):
41- """
42- Parse the string in self.version to update the other internal variables
43- """
44- without_metadata = self ._extract_metadata (version )
45- index = without_metadata .find (self ._PRE_RELEASE_DELIMITER )
46- if index == - 1 :
47- self ._is_stable = True
48- else :
49- pre_release_data = without_metadata [index + 1 :]
50- if pre_release_data == "" :
51- raise RuntimeError ("Pre-release is empty despite delimiter exists: " + version )
52-
53- without_metadata = without_metadata [:index ]
54- for pre_digit in pre_release_data .split (self ._VALUE_DELIMITER ):
55- if pre_digit .isnumeric ():
56- pre_digit = str (int (pre_digit ))
57- self ._pre_release .append (pre_digit )
58-
59- self ._set_components (without_metadata )
60-
61- def _extract_metadata (self , version ):
62- """
63- Check if there is any metadata characters in self.version.
64-
65- :returns: The semver string without the metadata
66- :rtype: str
67- """
68- index = version .find (self ._METADATA_DELIMITER )
69- if index == - 1 :
70- return version
71-
72- self ._metadata = version [index + 1 :]
73- if self ._metadata == "" :
74- raise RuntimeError ("Metadata is empty despite delimiter exists: " + version )
75-
76- return version [:index ]
77-
78- def _set_components (self , version ):
79- """
80- Set the major, minor and patch internal variables based on string passed.
81-
82- :param version: raw version containing major.minor.patch numbers.
83- :type version: str
84- """
858
86- parts = version .split (self ._VALUE_DELIMITER )
87- if len (parts ) != 3 or not (parts [0 ].isnumeric () and parts [1 ].isnumeric () and parts [2 ].isnumeric ()):
88- raise RuntimeError ("Unable to convert to Semver, incorrect format: " + version )
89-
90- self ._major = int (parts [0 ])
91- self ._minor = int (parts [1 ])
92- self ._patch = int (parts [2 ])
93-
94- self .version = "{major}{DELIMITER}{minor}{DELIMITER}{patch}" .format (major = self ._major , DELIMITER = self ._VALUE_DELIMITER ,
95- minor = self ._minor , patch = self ._patch )
96- self .version += "{DELIMITER}{pre_release}" .format (DELIMITER = self ._PRE_RELEASE_DELIMITER ,
97- pre_release = '.' .join (self ._pre_release )) if len (self ._pre_release ) > 0 else ""
98- self .version += "{DELIMITER}{metadata}" .format (DELIMITER = self ._METADATA_DELIMITER , metadata = self ._metadata ) if self ._metadata != "" else ""
99-
100- def compare (self , to_compare ):
101- """
102- Compare the current Semver object to a given Semver object, return:
103- 0: if self == passed
104- 1: if self > passed
105- -1: if self < passed
106-
107- :param to_compare: a Semver object
108- :type to_compare: splitio.models.grammar.matchers.semver.Semver
109-
110- :returns: integer based on comparison
111- :rtype: int
112- """
113- if self .version == to_compare .version :
114- return 0
115-
116- # Compare major, minor, and patch versions numerically
117- result = self ._compare_vars (self ._major , to_compare ._major )
118- if result != 0 :
119- return result
120-
121- result = self ._compare_vars (self ._minor , to_compare ._minor )
122- if result != 0 :
123- return result
124-
125- result = self ._compare_vars (self ._patch , to_compare ._patch )
126- if result != 0 :
127- return result
128-
129- if not self ._is_stable and to_compare ._is_stable :
130- return - 1
131- elif self ._is_stable and not to_compare ._is_stable :
132- return 1
133-
134- # Compare pre-release versions lexically
135- min_length = min (len (self ._pre_release ), len (to_compare ._pre_release ))
136- for i in range (min_length ):
137- if self ._pre_release [i ] == to_compare ._pre_release [i ]:
138- continue
139-
140- if self ._pre_release [i ].isnumeric () and to_compare ._pre_release [i ].isnumeric ():
141- return self ._compare_vars (int (self ._pre_release [i ]), int (to_compare ._pre_release [i ]))
142-
143- return self ._compare_vars (self ._pre_release [i ], to_compare ._pre_release [i ])
144-
145- # Compare lengths of pre-release versions
146- return self ._compare_vars (len (self ._pre_release ), len (to_compare ._pre_release ))
9+ _LOGGER = logging .getLogger (__name__ )
14710
148- def _compare_vars (self , var1 , var2 ):
149- """
150- Compare 2 variables and return int as follows:
151- 0: if var1 == var2
152- 1: if var1 > var2
153- -1: if var1 < var2
154-
155- :param var1: any object accept ==, < or > operators
156- :type var1: str/int
157- :param var2: any object accept ==, < or > operators
158- :type var2: str/int
159-
160- :returns: integer based on comparison
161- :rtype: int
162- """
163- if var1 == var2 :
164- return 0
165- if var1 > var2 :
166- return 1
167- return - 1
16811
16912class EqualToSemverMatcher (Matcher ):
17013 """A matcher for Semver equal to."""
@@ -209,7 +52,7 @@ def _match(self, key, attributes=None, context=None):
20952
21053 def __str__ (self ):
21154 """Return string Representation."""
212- return 'equal semver {data}' . format ( data = self ._data )
55+ return f 'equal semver { self ._data } '
21356
21457 def _add_matcher_specific_properties_to_json (self ):
21558 """Add matcher specific properties to base dict before returning it."""
@@ -258,12 +101,13 @@ def _match(self, key, attributes=None, context=None):
258101
259102 def __str__ (self ):
260103 """Return string Representation."""
261- return 'greater than or equal to semver {data}' . format ( data = self ._data )
104+ return f 'greater than or equal to semver { self ._data } '
262105
263106 def _add_matcher_specific_properties_to_json (self ):
264107 """Add matcher specific properties to base dict before returning it."""
265108 return {'matcherType' : 'GREATER_THAN_OR_EQUAL_TO_SEMVER' , 'stringMatcherData' : self ._data }
266109
110+
267111class LessThanOrEqualToSemverMatcher (Matcher ):
268112 """A matcher for Semver less than or equal to."""
269113
@@ -307,12 +151,13 @@ def _match(self, key, attributes=None, context=None):
307151
308152 def __str__ (self ):
309153 """Return string Representation."""
310- return 'less than or equal to semver {data}' . format ( data = self ._data )
154+ return f 'less than or equal to semver { self ._data } '
311155
312156 def _add_matcher_specific_properties_to_json (self ):
313157 """Add matcher specific properties to base dict before returning it."""
314158 return {'matcherType' : 'LESS_THAN_OR_EQUAL_TO_SEMVER' , 'stringMatcherData' : self ._data }
315159
160+
316161class BetweenSemverMatcher (Matcher ):
317162 """A matcher for Semver between."""
318163
@@ -363,6 +208,7 @@ def _add_matcher_specific_properties_to_json(self):
363208 """Add matcher specific properties to base dict before returning it."""
364209 return {'matcherType' : 'BETWEEN_SEMVER' , 'betweenStringMatcherData' : self ._data }
365210
211+
366212class InListSemverMatcher (Matcher ):
367213 """A matcher for Semver in list."""
368214
@@ -374,8 +220,8 @@ def _build(self, raw_matcher):
374220 :type raw_matcher: dict
375221 """
376222 self ._data = raw_matcher ['whitelistMatcherData' ]['whitelist' ]
377- semver_list = [build_semver_or_none (item ) if item is not None else None for item in self ._data ]
378- self ._semver_list = frozenset ([item .version for item in semver_list ])
223+ semver_list = [build_semver_or_none (item ) for item in self ._data if item ]
224+ self ._semver_list = frozenset ([item .version for item in semver_list if item ])
379225
380226 def _match (self , key , attributes = None , context = None ):
381227 """
0 commit comments