@@ -15,8 +15,8 @@ class Filter(metaclass=ABCMeta):
1515 """
1616
1717 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 ] = {}
2020 self ._invert_result : Filter | None = None
2121
2222 @abstractmethod
@@ -40,7 +40,7 @@ def __and__(self, other: Filter) -> Filter:
4040 if other in self ._and_cache :
4141 return self ._and_cache [other ]
4242
43- result = _AndList ([self , other ])
43+ result = _AndList . create ([self , other ])
4444 self ._and_cache [other ] = result
4545 return result
4646
@@ -58,7 +58,7 @@ def __or__(self, other: Filter) -> Filter:
5858 if other in self ._or_cache :
5959 return self ._or_cache [other ]
6060
61- result = _OrList ([self , other ])
61+ result = _OrList . create ([self , other ])
6262 self ._or_cache [other ] = result
6363 return result
6464
@@ -86,20 +86,49 @@ def __bool__(self) -> None:
8686 )
8787
8888
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+
8997class _AndList (Filter ):
9098 """
9199 Result of &-operation between several filters.
92100 """
93101
94- def __init__ (self , filters : Iterable [Filter ]) -> None :
102+ def __init__ (self , filters : list [Filter ]) -> None :
95103 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 ] = []
97115
98116 for f in filters :
99117 if isinstance (f , _AndList ): # Turn nested _AndLists into one.
100- self . filters .extend (f .filters )
118+ filters_2 .extend (f .filters )
101119 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 )
103132
104133 def __call__ (self ) -> bool :
105134 return all (f () for f in self .filters )
@@ -113,15 +142,36 @@ class _OrList(Filter):
113142 Result of |-operation between several filters.
114143 """
115144
116- def __init__ (self , filters : Iterable [Filter ]) -> None :
145+ def __init__ (self , filters : list [Filter ]) -> None :
117146 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 ] = []
119158
120159 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 )
123162 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 )
125175
126176 def __call__ (self ) -> bool :
127177 return any (f () for f in self .filters )
0 commit comments