2929import warnings
3030from functools import wraps , lru_cache
3131from itertools import count
32- from typing import TYPE_CHECKING , Generic , Iterator , NamedTuple , TypeVar , TypedDict , overload
32+ from typing import TYPE_CHECKING , Callable , Generic , Iterator , NamedTuple , TypeVar , TypedDict , overload
3333
3434if TYPE_CHECKING : # pragma: no cover
3535 from markdown import Markdown
4747# TODO: Raise errors from list methods in the future.
4848# Later, remove this class entirely and use a regular set.
4949class _BlockLevelElements :
50- def __init__ (self , elements : list [str ]) -> None :
50+ def __init__ (self , elements : list [str ], / ) -> None :
5151 self ._list = elements .copy ()
5252 self ._set = set (self ._list )
5353
54- def __add__ (self , other : list [str ]) -> list [str ]:
54+ def __add__ (self , other : list [str ], / ) -> list [str ]:
5555 warnings .warn (
5656 "Using block level elements as a list is deprecated, use it as a set instead." ,
5757 DeprecationWarning ,
5858 )
5959 # Using `+` means user expects a list back.
6060 return self ._list + other
6161
62- def __and__ (self , other : set [str ]) -> set [str ]:
62+ def __and__ (self , other : set [str ], / ) -> set [str ]:
6363 # Using `&` means user expects a set back.
6464 return self ._set & other
6565
66- def __contains__ (self , item ) :
66+ def __contains__ (self , item : str , / ) -> bool :
6767 return item in self ._set
6868
69- def __delitem__ (self , key ) :
69+ def __delitem__ (self , key : int , / ) -> None :
7070 warnings .warn (
7171 "Using block level elements as a list is deprecated, use it as a set instead." ,
7272 DeprecationWarning ,
@@ -75,33 +75,36 @@ def __delitem__(self, key):
7575 del self ._list [key ]
7676 self ._set .remove (element )
7777
78- def __getitem__ (self , index ) :
78+ def __getitem__ (self , index : int , / ) -> str :
7979 warnings .warn (
8080 "Using block level elements as a list is deprecated, use it as a set instead." ,
8181 DeprecationWarning ,
8282 )
8383 return self ._list [index ]
8484
85- def __iadd__ (self , other : list [str ]) -> None :
85+ def __iadd__ (self , other : list [str ], / ) -> set [ str ] :
8686 warnings .warn (
8787 "Using block level elements as a list is deprecated, use it as a set instead." ,
8888 DeprecationWarning ,
8989 )
9090 # In-place addition should update both list and set.
9191 self ._list += other
9292 self ._set .update (set (other ))
93+ return self # type: ignore[return-value]
9394
94- def __iand__ (self , other : set [str ]) -> None :
95+ def __iand__ (self , other : set [str ], / ) -> set [ str ] :
9596 # In-place intersection should update both list and set.
9697 self ._list = [element for element in self ._list if element in other ]
9798 self ._set &= other
99+ return self # type: ignore[return-value]
98100
99- def __ior__ (self , other : set [str ]) -> None :
101+ def __ior__ (self , other : set [str ], / ) -> set [ str ] :
100102 # In-place union should update both list and set.
101103 for element in other :
102104 if element not in self ._set :
103105 self ._list .append (element )
104106 self ._set |= other
107+ return self # type: ignore[return-value]
105108
106109 def __iter__ (self ) -> Iterator [str ]:
107110 return iter (self ._list )
@@ -111,31 +114,31 @@ def __len__(self) -> int:
111114 # If used as a set, both lengths will be the same.
112115 return len (self ._list )
113116
114- def __or__ (self , value : set [str ]) -> set [str ]:
117+ def __or__ (self , value : set [str ], / ) -> set [str ]:
115118 # Using `|` means user expects a set back.
116119 return self ._set | value
117120
118- def __rand__ (self , value : set [str ]) -> set [str ]:
121+ def __rand__ (self , value : set [str ], / ) -> set [str ]:
119122 # Using `&` means user expects a set back.
120123 return value & self ._set
121124
122- def __ror__ (self , value : set [str ]) -> set [str ]:
125+ def __ror__ (self , value : set [str ], / ) -> set [str ]:
123126 # Using `|` means user expects a set back.
124127 return value | self ._set
125128
126- def __rsub__ (self , value : set [str ]) -> set [str ]:
129+ def __rsub__ (self , value : set [str ], / ) -> set [str ]:
127130 # Using `-` means user expects a set back.
128131 return value - self ._set
129132
130- def __rxor__ (self , value : set [str ]) -> set [str ]:
133+ def __rxor__ (self , value : set [str ], / ) -> set [str ]:
131134 # Using `^` means user expects a set back.
132135 return value ^ self ._set
133136
134- def __sub__ (self , value : set [str ]) -> set [str ]:
137+ def __sub__ (self , value : set [str ], / ) -> set [str ]:
135138 # Using `-` means user expects a set back.
136139 return self ._set - value
137140
138- def __xor__ (self , value : set [str ]) -> set [str ]:
141+ def __xor__ (self , value : set [str ], / ) -> set [str ]:
139142 # Using `^` means user expects a set back.
140143 return self ._set ^ value
141144
@@ -146,24 +149,26 @@ def __reversed__(self) -> Iterator[str]:
146149 )
147150 return reversed (self ._list )
148151
149- def __setitem__ (self , key : int , value : str ) -> None :
152+ def __setitem__ (self , key : int , value : str , / ) -> None :
150153 warnings .warn (
151154 "Using block level elements as a list is deprecated, use it as a set instead." ,
152155 DeprecationWarning ,
153156 )
154157 # In-place item-setting should update both list and set.
158+ old = self ._list [key ]
155159 self ._list [key ] = value
160+ self ._set .discard (old )
156161 self ._set .add (value )
157162
158163 def __str__ (self ) -> str :
159164 return str (self ._set )
160165
161- def add (self , element : str ) -> None :
166+ def add (self , element : str , / ) -> None :
162167 # In-place addition should update both list and set.
163168 self ._set .add (element )
164169 self ._list .append (element )
165170
166- def append (self , element : str ) -> None :
171+ def append (self , element : str , / ) -> None :
167172 warnings .warn (
168173 "Using block level elements as a list is deprecated, use it as a set instead." ,
169174 DeprecationWarning ,
@@ -180,7 +185,7 @@ def copy(self) -> _BlockLevelElements:
180185 # We're not sure yet whether the user wants to use it as a set or list.
181186 return _BlockLevelElements (self ._list )
182187
183- def count (self , value : str ) -> int :
188+ def count (self , value : str , / ) -> int :
184189 warnings .warn (
185190 "Using block level elements as a list is deprecated, use it as a set instead." ,
186191 DeprecationWarning ,
@@ -193,14 +198,13 @@ def difference(self, *others: set[str]) -> set[str]:
193198 # User expects a set back.
194199 return self ._set .difference (* others )
195200
196- def difference_update (self , * others ) -> None :
201+ def difference_update (self , * others : set [ str ] ) -> None :
197202 # In-place difference should update both list and set.
198203 self ._set .difference_update (* others )
199- for other in others :
200- for element in other :
201- self ._list .remove (element )
204+ self ._list .clear ()
205+ self ._list .extend (sorted (self ._set ))
202206
203- def discard (self , element : str ) -> None :
207+ def discard (self , element : str , / ) -> None :
204208 # In-place discard should update both list and set.
205209 self ._set .discard (element )
206210 while True :
@@ -209,13 +213,15 @@ def discard(self, element: str) -> None:
209213 except ValueError :
210214 break
211215
212- def extend (self , elements : list [str ]) -> None :
216+ def extend (self , elements : list [str ], / ) -> None :
213217 warnings .warn (
214218 "Using block level elements as a list is deprecated, use it as a set instead." ,
215219 DeprecationWarning ,
216220 )
217221 # In-place extension should update both list and set.
218- self ._list .extend (elements )
222+ for element in elements :
223+ if element not in self ._list :
224+ self ._list .append (element )
219225 self ._set .update (elements )
220226
221227 def index (self , value , start : int = 0 , stop : int = sys .maxsize , / ):
@@ -241,17 +247,16 @@ def intersection(self, *others: set[str]) -> set[str]:
241247 def intersection_update (self , * others : set [str ]) -> None :
242248 # In-place intersection should update both list and set.
243249 self ._set .intersection_update (* others )
244- for element in reversed (self ._list ):
245- if element not in self ._set :
246- self ._list .remove (element )
250+ self ._list .clear ()
251+ self ._list .extend (sorted (self ._set ))
247252
248- def isdisjoint (self , other : set [str ]) -> bool :
253+ def isdisjoint (self , other : set [str ], / ) -> bool :
249254 return self ._set .isdisjoint (other )
250255
251- def issubset (self , other : set [str ]) -> bool :
256+ def issubset (self , other : set [str ], / ) -> bool :
252257 return self ._set .issubset (other )
253258
254- def issuperset (self , other : set [str ]) -> bool :
259+ def issuperset (self , other : set [str ], / ) -> bool :
255260 return self ._set .issuperset (other )
256261
257262 def pop (self , index : int = - 1 , / ) -> str :
@@ -260,7 +265,7 @@ def pop(self, index: int = -1, /) -> str:
260265 self ._set .remove (element )
261266 return element
262267
263- def remove (self , element : str ) -> None :
268+ def remove (self , element : str , / ) -> None :
264269 # In-place removal should update both list and set.
265270 self ._list .remove (element )
266271 self ._set .remove (element )
@@ -272,25 +277,22 @@ def reverse(self) -> None:
272277 )
273278 self ._list .reverse ()
274279
275- def sort (self , / , * , key = None , reverse = False ) -> None :
280+ def sort (self , / , * , key : Callable | None = None , reverse : bool = False ) -> None :
276281 warnings .warn (
277282 "Using block level elements as a list is deprecated, use it as a set instead." ,
278283 DeprecationWarning ,
279284 )
280285 self ._list .sort (key = key , reverse = reverse )
281286
282- def symmetric_difference (self , other : set [str ]) -> set [str ]:
287+ def symmetric_difference (self , other : set [str ], / ) -> set [str ]:
283288 # User expects a set back.
284289 return self ._set .symmetric_difference (other )
285290
286- def symmetric_difference_update (self , other : set [str ]) -> None :
291+ def symmetric_difference_update (self , other : set [str ], / ) -> None :
287292 # In-place symmetric difference should update both list and set.
288293 self ._set .symmetric_difference_update (other )
289- for element in other :
290- if element in self ._set :
291- self ._list .remove (element )
292- else :
293- self ._list .append (element )
294+ self ._list .clear ()
295+ self ._list .extend (sorted (self ._set ))
294296
295297 def union (self , * others : set [str ]) -> set [str ]:
296298 # User expects a set back.
@@ -299,10 +301,8 @@ def union(self, *others: set[str]) -> set[str]:
299301 def update (self , * others : set [str ]) -> None :
300302 # In-place union should update both list and set.
301303 self ._set .update (* others )
302- for other in others :
303- for element in other :
304- if element not in self ._set :
305- self ._list .append (element )
304+ self ._list .clear ()
305+ self ._list .extend (sorted (self ._set ))
306306
307307
308308# Type it as `set[str]` to express our intent for it to be used as such.
0 commit comments