@@ -15,8 +15,8 @@ class Filter(metaclass=ABCMeta):
15
15
"""
16
16
17
17
def __init__ (self ) -> None :
18
- self ._and_cache : dict [Filter , _AndList ] = {}
19
- self ._or_cache : dict [Filter , _OrList ] = {}
18
+ self ._and_cache : dict [Filter , Filter ] = {}
19
+ self ._or_cache : dict [Filter , Filter ] = {}
20
20
self ._invert_result : Filter | None = None
21
21
22
22
@abstractmethod
@@ -40,7 +40,7 @@ def __and__(self, other: Filter) -> Filter:
40
40
if other in self ._and_cache :
41
41
return self ._and_cache [other ]
42
42
43
- result = _AndList ([self , other ])
43
+ result = _AndList . create ([self , other ])
44
44
self ._and_cache [other ] = result
45
45
return result
46
46
@@ -58,7 +58,7 @@ def __or__(self, other: Filter) -> Filter:
58
58
if other in self ._or_cache :
59
59
return self ._or_cache [other ]
60
60
61
- result = _OrList ([self , other ])
61
+ result = _OrList . create ([self , other ])
62
62
self ._or_cache [other ] = result
63
63
return result
64
64
@@ -86,20 +86,49 @@ def __bool__(self) -> None:
86
86
)
87
87
88
88
89
+ def _remove_duplicates (filters : list [Filter ]) -> list [Filter ]:
90
+ result = []
91
+ for f in filters :
92
+ if f not in result :
93
+ result .append (f )
94
+ return result
95
+
96
+
89
97
class _AndList (Filter ):
90
98
"""
91
99
Result of &-operation between several filters.
92
100
"""
93
101
94
- def __init__ (self , filters : Iterable [Filter ]) -> None :
102
+ def __init__ (self , filters : list [Filter ]) -> None :
95
103
super ().__init__ ()
96
- self .filters : list [Filter ] = []
104
+ self .filters = filters
105
+
106
+ @classmethod
107
+ def create (cls , filters : Iterable [Filter ]) -> Filter :
108
+ """
109
+ Create a new filter by applying an `&` operator between them.
110
+
111
+ If there's only one unique filter in the given iterable, it will return
112
+ that one filter instead of an `_AndList`.
113
+ """
114
+ filters_2 : list [Filter ] = []
97
115
98
116
for f in filters :
99
117
if isinstance (f , _AndList ): # Turn nested _AndLists into one.
100
- self . filters .extend (f .filters )
118
+ filters_2 .extend (f .filters )
101
119
else :
102
- self .filters .append (f )
120
+ filters_2 .append (f )
121
+
122
+ # Remove duplicates. This could speed up execution, and doesn't make a
123
+ # difference for the evaluation.
124
+ filters = _remove_duplicates (filters_2 )
125
+
126
+ # If only one filter is left, return that without wrapping into an
127
+ # `_AndList`.
128
+ if len (filters ) == 1 :
129
+ return filters [0 ]
130
+
131
+ return cls (filters )
103
132
104
133
def __call__ (self ) -> bool :
105
134
return all (f () for f in self .filters )
@@ -113,15 +142,36 @@ class _OrList(Filter):
113
142
Result of |-operation between several filters.
114
143
"""
115
144
116
- def __init__ (self , filters : Iterable [Filter ]) -> None :
145
+ def __init__ (self , filters : list [Filter ]) -> None :
117
146
super ().__init__ ()
118
- self .filters : list [Filter ] = []
147
+ self .filters = filters
148
+
149
+ @classmethod
150
+ def create (cls , filters : Iterable [Filter ]) -> Filter :
151
+ """
152
+ Create a new filter by applying an `|` operator between them.
153
+
154
+ If there's only one unique filter in the given iterable, it will return
155
+ that one filter instead of an `_OrList`.
156
+ """
157
+ filters_2 : list [Filter ] = []
119
158
120
159
for f in filters :
121
- if isinstance (f , _OrList ): # Turn nested _OrLists into one.
122
- self . filters .extend (f .filters )
160
+ if isinstance (f , _OrList ): # Turn nested _AndLists into one.
161
+ filters_2 .extend (f .filters )
123
162
else :
124
- self .filters .append (f )
163
+ filters_2 .append (f )
164
+
165
+ # Remove duplicates. This could speed up execution, and doesn't make a
166
+ # difference for the evaluation.
167
+ filters = _remove_duplicates (filters_2 )
168
+
169
+ # If only one filter is left, return that without wrapping into an
170
+ # `_AndList`.
171
+ if len (filters ) == 1 :
172
+ return filters [0 ]
173
+
174
+ return cls (filters )
125
175
126
176
def __call__ (self ) -> bool :
127
177
return any (f () for f in self .filters )
0 commit comments