1#!/usr/bin/env python3
 2
 3from enum import Enum
 4
 5class NumTest:
 6    """Allow users to configure numerical tests, for filtering lists of items."""
 7
 8    class Test(Enum):
 9        """Basic comparisons used."""
10        ANY = '*'
11        GT = '>'
12        EQ = '='
13
14    def __init__(self, config):
15        if config is None or len(config) == 0:
16            self.test = NumTest.Test.ANY
17            self.param = None
18
19        elif config[0] == NumTest.Test.GT.value:
20            self.test = NumTest.Test.GT
21            self.param = int(config[1:])
22
23        elif config[0] == NumTest.Test.EQ.value:
24            self.test = NumTest.Test.EQ
25            self.param = int(config[1:])
26
27        else:
28            raise ValueError
29
30    def __str__(self):
31        if self.test is None:
32            return 'all'
33
34        else:
35            return '{test} {value}'.format(test=self.test.value, value=self.param)
36
37    def match(self, value):
38        """Return True if `value` matches ourselves."""
39        if self.test is NumTest.Test.ANY:
40            return True
41
42        elif self.test is NumTest.Test.GT and value > self.param:
43            return True
44
45        elif self.test is NumTest.Test.EQ and value == self.param:
46            return True
47
48        return False
49
50NumTest.Test.GT.long_name = 'greater than'
51NumTest.Test.EQ.long_name = 'equals'
52
53class StringTest:
54    """Allow users to test for string matches."""
55
56    class Test(Enum):
57        """Basic comparisons supported."""
58        ANY = '*'
59        EQ = '='
60        NEQ = ('!', '~')
61
62    def __init__(self, config):
63        if config is None or len(config) == 0:  # with no filters, match everything
64            self.test = StringTest.Test.ANY
65            self.param = None
66
67        elif config == '~':  # a single "~" means match any non-empty string
68            self.test = StringTest.Test.NEQ
69            self.param = ''
70
71        else:  # case-insensitive match only
72            self.test = StringTest.Test.EQ
73            self.param = config
74
75    def __str__(self):
76        return '{test} {value}'.format(test=self.test.value, value=self.param)
77
78    def matches(self, value):
79        """Return True if `value` is acceptable to us."""
80        if value is None:
81            value = ''
82
83        if self.test is StringTest.Test.ANY:
84            return True
85
86        elif self.test is StringTest.Test.NEQ:
87            return self.param != value
88
89        return self.param.lower() == value.lower()