Skip to content

Commit b7aa7e9

Browse files
committed
type_hint Context
Signed-off-by: Cristian Le <cristian.le@mpsd.mpg.de>
1 parent c7c6135 commit b7aa7e9

File tree

1 file changed

+51
-39
lines changed

1 file changed

+51
-39
lines changed

fmf/context.py

Lines changed: 51 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@
1616
See https://fmf.readthedocs.io/en/latest/modules.html#fmf.Tree.adjust
1717
"""
1818

19+
from __future__ import annotations
20+
1921
import re
22+
from collections.abc import Callable
2023

2124

2225
class CannotDecide(Exception):
@@ -34,7 +37,7 @@ class InvalidContext(Exception):
3437
class ContextValue:
3538
""" Value for dimension """
3639

37-
def __init__(self, origin):
40+
def __init__(self, origin: str | tuple[str, ...]):
3841
"""
3942
ContextValue("foo-1.2.3")
4043
ContextValue(["foo", "1", "2", "3"])
@@ -44,13 +47,13 @@ def __init__(self, origin):
4447
else:
4548
self._to_compare = self._split_to_version(origin)
4649

47-
def __eq__(self, other):
50+
def __eq__(self, other: ContextValue):
4851
if isinstance(other, self.__class__):
4952
return self._to_compare == other._to_compare
5053
else:
5154
return False
5255

53-
def __ne__(self, other):
56+
def __ne__(self, other: ContextValue):
5457
return not self.__eq__(other)
5558

5659
def __str__(self):
@@ -59,7 +62,11 @@ def __str__(self):
5962
def __repr__(self):
6063
return "{}({})".format(self.__class__.__name__, repr(self._to_compare))
6164

62-
def version_cmp(self, other, minor_mode=False, ordered=True):
65+
def version_cmp(
66+
self,
67+
other: ContextValue,
68+
minor_mode: bool = False,
69+
ordered: bool = True) -> int:
6370
"""
6471
Comparing two ContextValue objects
6572
@@ -138,7 +145,7 @@ def version_cmp(self, other, minor_mode=False, ordered=True):
138145
return -1 # other is larger (more pars)
139146

140147
@staticmethod
141-
def compare(first, second):
148+
def compare(first: str, second: str):
142149
""" compare two version parts """
143150
# Ideally use `from packaging import version` but we need older
144151
# python support too so very rough
@@ -155,7 +162,7 @@ def compare(first, second):
155162
(first_version < second_version))
156163

157164
@staticmethod
158-
def _split_to_version(text):
165+
def _split_to_version(text: str) -> tuple[str, ...]:
159166
"""
160167
Try to split text into name + version parts
161168
@@ -183,119 +190,121 @@ def __hash__(self):
183190

184191
class Context:
185192
""" Represents https://fmf.readthedocs.io/en/latest/context.html """
193+
186194
# Operators' definitions
187195

188-
def _op_defined(self, dimension_name, values):
196+
def _op_defined(self, dimension_name: str, values: list[ContextValue]):
189197
""" 'is defined' operator """
190198
return dimension_name in self._dimensions
191199

192-
def _op_not_defined(self, dimension_name, values):
200+
def _op_not_defined(self, dimension_name: str, values: list[ContextValue]):
193201
""" 'is not defined' operator """
194202
return dimension_name not in self._dimensions
195203

196-
def _op_eq(self, dimension_name, values):
204+
def _op_eq(self, dimension_name: str, values: list[ContextValue]):
197205
""" '=' operator """
198206

199-
def comparator(dimension_value, it_val):
207+
def comparator(dimension_value: ContextValue, it_val: ContextValue) -> bool:
200208
return dimension_value.version_cmp(it_val, ordered=False) == 0
201209

202210
return self._op_core(dimension_name, values, comparator)
203211

204-
def _op_not_eq(self, dimension_name, values):
212+
def _op_not_eq(self, dimension_name: str, values: list[ContextValue]):
205213
""" '!=' operator """
206214

207-
def comparator(dimension_value, it_val):
215+
def comparator(dimension_value: ContextValue, it_val: ContextValue) -> bool:
208216
return dimension_value.version_cmp(it_val, ordered=False) != 0
209217

210218
return self._op_core(dimension_name, values, comparator)
211219

212-
def _op_minor_eq(self, dimension_name, values):
220+
def _op_minor_eq(self, dimension_name: str, values: list[ContextValue]):
213221
""" '~=' operator """
214222

215-
def comparator(dimension_value, it_val):
223+
def comparator(dimension_value: ContextValue, it_val: ContextValue) -> bool:
216224
return dimension_value.version_cmp(
217225
it_val, minor_mode=True, ordered=False) == 0
218226

219227
return self._op_core(dimension_name, values, comparator)
220228

221-
def _op_minor_not_eq(self, dimension_name, values):
229+
def _op_minor_not_eq(self, dimension_name: str, values: list[ContextValue]):
222230
""" '~!=' operator """
223231

224-
def comparator(dimension_value, it_val):
232+
def comparator(dimension_value: ContextValue, it_val: ContextValue) -> bool:
225233
return dimension_value.version_cmp(
226234
it_val, minor_mode=True, ordered=False) != 0
227235

228236
return self._op_core(dimension_name, values, comparator)
229237

230-
def _op_minor_less_or_eq(self, dimension_name, values):
238+
def _op_minor_less_or_eq(self, dimension_name: str, values: list[ContextValue]):
231239
""" '~<=' operator """
232240

233-
def comparator(dimension_value, it_val):
241+
def comparator(dimension_value: ContextValue, it_val: ContextValue) -> bool:
234242
return dimension_value.version_cmp(
235243
it_val, minor_mode=True, ordered=True) <= 0
236244

237245
return self._op_core(dimension_name, values, comparator)
238246

239-
def _op_minor_less(self, dimension_name, values):
247+
def _op_minor_less(self, dimension_name: str, values: list[ContextValue]):
240248
""" '~<' operator """
241249

242-
def comparator(dimension_value, it_val):
250+
def comparator(dimension_value: ContextValue, it_val: ContextValue) -> bool:
243251
return dimension_value.version_cmp(
244252
it_val, minor_mode=True, ordered=True) < 0
245253

246254
return self._op_core(dimension_name, values, comparator)
247255

248-
def _op_less(self, dimension_name, values):
256+
def _op_less(self, dimension_name: str, values: list[ContextValue]):
249257
""" '<' operator """
250258

251-
def comparator(dimension_value, it_val):
259+
def comparator(dimension_value: ContextValue, it_val: ContextValue) -> bool:
252260
return dimension_value.version_cmp(it_val, ordered=True) < 0
253261

254262
return self._op_core(dimension_name, values, comparator)
255263

256-
def _op_less_or_equal(self, dimension_name, values):
264+
def _op_less_or_equal(self, dimension_name: str, values: list[ContextValue]):
257265
""" '<=' operator """
258266

259-
def comparator(dimension_value, it_val):
267+
def comparator(dimension_value: ContextValue, it_val: ContextValue) -> bool:
260268
return dimension_value.version_cmp(it_val, ordered=True) <= 0
261269

262270
return self._op_core(dimension_name, values, comparator)
263271

264-
def _op_greater_or_equal(self, dimension_name, values):
272+
def _op_greater_or_equal(self, dimension_name: str, values: list[ContextValue]):
265273
""" '>=' operator """
266274

267-
def comparator(dimension_value, it_val):
275+
def comparator(dimension_value: ContextValue, it_val: ContextValue) -> bool:
268276
return dimension_value.version_cmp(it_val, ordered=True) >= 0
269277

270278
return self._op_core(dimension_name, values, comparator)
271279

272-
def _op_minor_greater_or_equal(self, dimension_name, values):
280+
def _op_minor_greater_or_equal(self, dimension_name: str, values: list[ContextValue]):
273281
""" '~>=' operator """
274282

275-
def comparator(dimension_value, it_val):
283+
def comparator(dimension_value: ContextValue, it_val: ContextValue) -> bool:
276284
return dimension_value.version_cmp(
277285
it_val, minor_mode=True, ordered=True) >= 0
278286

279287
return self._op_core(dimension_name, values, comparator)
280288

281-
def _op_greater(self, dimension_name, values):
289+
def _op_greater(self, dimension_name: str, values: list[ContextValue]):
282290
""" '>' operator """
283291

284-
def comparator(dimension_value, it_val):
292+
def comparator(dimension_value: ContextValue, it_val: ContextValue) -> bool:
285293
return dimension_value.version_cmp(it_val, ordered=True) > 0
286294

287295
return self._op_core(dimension_name, values, comparator)
288296

289-
def _op_minor_greater(self, dimension_name, values):
297+
def _op_minor_greater(self, dimension_name: str, values: list[ContextValue]):
290298
""" '~>' operator """
291299

292-
def comparator(dimension_value, it_val):
300+
def comparator(dimension_value: ContextValue, it_val: ContextValue) -> bool:
293301
return dimension_value.version_cmp(
294302
it_val, minor_mode=True, ordered=True) > 0
295303

296304
return self._op_core(dimension_name, values, comparator)
297305

298-
def _op_core(self, dimension_name, values, comparator):
306+
def _op_core(self, dimension_name: str, values: list[ContextValue],
307+
comparator: Callable[[ContextValue, ContextValue], bool]):
299308
"""
300309
Evaluate value from dimension vs target values combination
301310
@@ -362,6 +371,7 @@ def _op_core(self, dimension_name, values, comparator):
362371

363372
# To split by 'or' operator
364373
re_or_split = re.compile(r'\bor\b')
374+
_dimensions: dict[str]
365375

366376
def __init__(self, *args, **kwargs):
367377
"""
@@ -393,8 +403,10 @@ def __init__(self, *args, **kwargs):
393403
[self.parse_value(val) for val in values]
394404
)
395405

406+
ExpressionType = tuple[str | None, str | bool, list[str] | None]
407+
396408
@staticmethod
397-
def parse_rule(rule):
409+
def parse_rule(rule: str | bool) -> list[list[ExpressionType]]:
398410
"""
399411
Parses rule into expressions
400412
@@ -437,12 +449,12 @@ def parse_rule(rule):
437449
return parsed_rule
438450

439451
@staticmethod
440-
def parse_value(value):
452+
def parse_value(value: str) -> ContextValue:
441453
""" Single place to convert to ContextValue """
442454
return ContextValue(str(value))
443455

444456
@staticmethod
445-
def split_rule_to_groups(rule):
457+
def split_rule_to_groups(rule: str) -> list[list[str]]:
446458
"""
447459
Split rule into nested lists, no real parsing
448460
@@ -467,7 +479,7 @@ def split_rule_to_groups(rule):
467479
return rule_parts
468480

469481
@staticmethod
470-
def split_expression(expression):
482+
def split_expression(expression: str) -> ExpressionType:
471483
"""
472484
Split expression to dimension name, operator and values
473485
@@ -500,7 +512,7 @@ def split_expression(expression):
500512
return (match.group(1), match.group(2), None)
501513
raise InvalidRule("Cannot parse expression '{}'.".format(expression))
502514

503-
def matches(self, rule):
515+
def matches(self, rule: str | bool) -> bool:
504516
"""
505517
Does the rule match the current Context?
506518
@@ -570,7 +582,7 @@ def matches(self, rule):
570582
else:
571583
raise CannotDecide() # It's up to callee how to treat this
572584

573-
def evaluate(self, expression):
585+
def evaluate(self, expression: ExpressionType) -> bool:
574586
dimension_name, operator, values = expression
575587
if isinstance(operator, bool):
576588
return operator

0 commit comments

Comments
 (0)