29
29
import warnings
30
30
from functools import wraps , lru_cache
31
31
from itertools import count
32
- from typing import TYPE_CHECKING , Callable , Generic , Iterator , NamedTuple , TypeVar , TypedDict , overload
32
+ from typing import TYPE_CHECKING , Generic , Iterator , NamedTuple , TypeVar , TypedDict , overload
33
33
34
34
if TYPE_CHECKING : # pragma: no cover
35
35
from markdown import Markdown
38
38
_T = TypeVar ('_T' )
39
39
40
40
41
- def deprecated (message : str , stacklevel : int = 2 ):
42
- """
43
- Raise a [`DeprecationWarning`][] when wrapped function/method is called.
44
-
45
- Usage:
46
-
47
- ```python
48
- @deprecated("This method will be removed in version X; use Y instead.")
49
- def some_method():
50
- pass
51
- ```
52
- """
53
- def wrapper (func ):
54
- @wraps (func )
55
- def deprecated_func (* args , ** kwargs ):
56
- warnings .warn (
57
- f"'{ func .__name__ } ' is deprecated. { message } " ,
58
- category = DeprecationWarning ,
59
- stacklevel = stacklevel
60
- )
61
- return func (* args , ** kwargs )
62
- return deprecated_func
63
- return wrapper
64
-
65
-
66
- # TODO: Raise errors from list methods in the future.
67
- # Later, remove this class entirely and use a regular set.
68
- class _BlockLevelElements (list ):
69
- # This hybrid list/set container exists for backwards compatibility reasons,
70
- # to support using both the `BLOCK_LEVEL_ELEMENTS` global variable (soft-deprecated)
71
- # and the `Markdown.block_level_elements` instance attribute (preferred) as a list or a set.
72
- # When we stop supporting list methods on these objects, we can remove the container
73
- # as well as the `test_block_level_elements` test module.
74
-
75
- def __init__ (self , elements : list [str ], / ) -> None :
76
- self ._list = elements .copy ()
77
- self ._set = set (self ._list )
78
-
79
- @deprecated ("Using block level elements as a list is deprecated, use it as a set instead." )
80
- def __add__ (self , other : list [str ], / ) -> list [str ]:
81
- # Using `+` means user expects a list back.
82
- return self ._list + other
83
-
84
- def __and__ (self , other : set [str ], / ) -> set [str ]:
85
- # Using `&` means user expects a set back.
86
- return self ._set & other
87
-
88
- def __contains__ (self , item : str , / ) -> bool :
89
- return item in self ._set
90
-
91
- @deprecated ("Using block level elements as a list is deprecated, use it as a set instead." )
92
- def __delitem__ (self , index : int , / ) -> None :
93
- element = self ._list [index ]
94
- del self ._list [index ]
95
- # Only remove from set if absent from list.
96
- if element not in self ._list :
97
- self ._set .remove (element )
98
-
99
- @deprecated ("Using block level elements as a list is deprecated, use it as a set instead." )
100
- def __getitem__ (self , index : int , / ) -> str :
101
- return self ._list [index ]
102
-
103
- @deprecated ("Using block level elements as a list is deprecated, use it as a set instead." )
104
- def __iadd__ (self , other : list [str ], / ) -> set [str ]:
105
- # In-place addition should update both list and set.
106
- self ._list += other
107
- self ._set .update (set (other ))
108
- return self # type: ignore[return-value]
109
-
110
- def __iand__ (self , other : set [str ], / ) -> set [str ]:
111
- # In-place intersection should update both list and set.
112
- self ._set &= other
113
- # Elements were only removed.
114
- self ._list [:] = [element for element in self ._list if element in self ._set ]
115
- return self # type: ignore[return-value]
116
-
117
- def __ior__ (self , other : set [str ], / ) -> set [str ]:
118
- # In-place union should update both list and set.
119
- self ._set |= other
120
- # Elements were only added.
121
- self ._list .extend (element for element in sorted (self ._set - set (self ._list )))
122
- return self # type: ignore[return-value]
123
-
124
- def __iter__ (self ) -> Iterator [str ]:
125
- return iter (self ._list )
41
+ """
42
+ Constants you might want to modify
43
+ -----------------------------------------------------------------------------
44
+ """
126
45
127
- def __len__ (self ) -> int :
128
- # Length of the list, for backwards compatibility.
129
- # If used as a set, both lengths will be the same.
130
- return len (self ._list )
131
-
132
- def __or__ (self , value : set [str ], / ) -> set [str ]:
133
- # Using `|` means user expects a set back.
134
- return self ._set | value
135
-
136
- def __rand__ (self , value : set [str ], / ) -> set [str ]:
137
- # Using `&` means user expects a set back.
138
- return value & self ._set
139
-
140
- def __ror__ (self , value : set [str ], / ) -> set [str ]:
141
- # Using `|` means user expects a set back.
142
- return value | self ._set
143
-
144
- def __rsub__ (self , value : set [str ], / ) -> set [str ]:
145
- # Using `-` means user expects a set back.
146
- return value - self ._set
147
-
148
- def __rxor__ (self , value : set [str ], / ) -> set [str ]:
149
- # Using `^` means user expects a set back.
150
- return value ^ self ._set
151
-
152
- def __sub__ (self , value : set [str ], / ) -> set [str ]:
153
- # Using `-` means user expects a set back.
154
- return self ._set - value
155
-
156
- def __xor__ (self , value : set [str ], / ) -> set [str ]:
157
- # Using `^` means user expects a set back.
158
- return self ._set ^ value
159
-
160
- @deprecated ("Using block level elements as a list is deprecated, use it as a set instead." )
161
- def __reversed__ (self ) -> Iterator [str ]:
162
- return reversed (self ._list )
163
-
164
- @deprecated ("Using block level elements as a list is deprecated, use it as a set instead." )
165
- def __setitem__ (self , index : int , value : str , / ) -> None :
166
- # In-place item-setting should update both list and set.
167
- old = self ._list [index ]
168
- self ._list [index ] = value
169
- # Only remove from set if absent from list.
170
- if old not in self ._list :
171
- self ._set .discard (old )
172
- self ._set .add (value )
173
-
174
- def __str__ (self ) -> str :
175
- return str (self ._set )
176
-
177
- def add (self , element : str , / ) -> None :
178
- # In-place addition should update both list and set.
179
- self ._set .add (element )
180
- self ._list .append (element )
181
-
182
- @deprecated ("Using block level elements as a list is deprecated, use it as a set instead." )
183
- def append (self , element : str , / ) -> None :
184
- # In-place addition should update both list and set.
185
- self ._list .append (element )
186
- self ._set .add (element )
187
-
188
- def clear (self ) -> None :
189
- self ._list .clear ()
190
- self ._set .clear ()
191
-
192
- def copy (self ) -> _BlockLevelElements :
193
- # We're not sure yet whether the user wants to use it as a set or list.
194
- return _BlockLevelElements (self ._list )
195
-
196
- @deprecated ("Using block level elements as a list is deprecated, use it as a set instead." )
197
- def count (self , value : str , / ) -> int :
198
- # Count in list, for backwards compatibility.
199
- # If used as a set, both counts will be the same (1).
200
- return self ._list .count (value )
201
-
202
- def difference (self , * others : set [str ]) -> set [str ]:
203
- # User expects a set back.
204
- return self ._set .difference (* others )
205
-
206
- def difference_update (self , * others : set [str ]) -> None :
207
- # In-place difference should update both list and set.
208
- self ._set .difference_update (* others )
209
- # Elements were only removed.
210
- self ._list [:] = [element for element in self ._list if element in self ._set ]
211
-
212
- def discard (self , element : str , / ) -> None :
213
- # In-place discard should update both list and set.
214
- self ._set .discard (element )
215
- try :
216
- self ._list .remove (element )
217
- except ValueError :
218
- pass
219
-
220
- @deprecated ("Using block level elements as a list is deprecated, use it as a set instead." )
221
- def extend (self , elements : list [str ], / ) -> None :
222
- # In-place extension should update both list and set.
223
- self ._list .extend (elements )
224
- self ._set .update (elements )
225
-
226
- @deprecated ("Using block level elements as a list is deprecated, use it as a set instead." )
227
- def index (self , value , start : int = 0 , stop : int = sys .maxsize , / ):
228
- return self ._list .index (value , start , stop )
229
-
230
- @deprecated ("Using block level elements as a list is deprecated, use it as a set instead." )
231
- def insert (self , index : int , element : str , / ) -> None :
232
- # In-place insertion should update both list and set.
233
- self ._list .insert (index , element )
234
- self ._set .add (element )
235
-
236
- def intersection (self , * others : set [str ]) -> set [str ]:
237
- # User expects a set back.
238
- return self ._set .intersection (* others )
239
-
240
- def intersection_update (self , * others : set [str ]) -> None :
241
- # In-place intersection should update both list and set.
242
- self ._set .intersection_update (* others )
243
- # Elements were only removed.
244
- self ._list [:] = [element for element in self ._list if element in self ._set ]
245
-
246
- def isdisjoint (self , other : set [str ], / ) -> bool :
247
- return self ._set .isdisjoint (other )
248
-
249
- def issubset (self , other : set [str ], / ) -> bool :
250
- return self ._set .issubset (other )
251
-
252
- def issuperset (self , other : set [str ], / ) -> bool :
253
- return self ._set .issuperset (other )
254
-
255
- def pop (self , index : int | None = None , / ) -> str :
256
- # In-place pop should update both list and set.
257
- if index is None :
258
- index = - 1
259
- else :
260
- warnings .warn (
261
- "Using block level elements as a list is deprecated, use it as a set instead." ,
262
- DeprecationWarning ,
263
- )
264
- element = self ._list .pop (index )
265
- # Only remove from set if absent from list.
266
- if element not in self ._list :
267
- self ._set .remove (element )
268
- return element
269
-
270
- def remove (self , element : str , / ) -> None :
271
- # In-place removal should update both list and set.
272
- # We give precedence to set behavior, so we remove all occurrences from the list.
273
- while True :
274
- try :
275
- self ._list .remove (element )
276
- except ValueError :
277
- break
278
- self ._set .remove (element )
279
-
280
- @deprecated ("Using block level elements as a list is deprecated, use it as a set instead." )
281
- def reverse (self ) -> None :
282
- self ._list .reverse ()
283
-
284
- @deprecated ("Using block level elements as a list is deprecated, use it as a set instead." )
285
- def sort (self , / , * , key : Callable | None = None , reverse : bool = False ) -> None :
286
- self ._list .sort (key = key , reverse = reverse )
287
-
288
- def symmetric_difference (self , other : set [str ], / ) -> set [str ]:
289
- # User expects a set back.
290
- return self ._set .symmetric_difference (other )
291
-
292
- def symmetric_difference_update (self , other : set [str ], / ) -> None :
293
- # In-place symmetric difference should update both list and set.
294
- self ._set .symmetric_difference_update (other )
295
- # Elements were both removed and added.
296
- self ._list [:] = [element for element in self ._list if element in self ._set ]
297
- self ._list .extend (element for element in sorted (self ._set - set (self ._list )))
298
-
299
- def union (self , * others : set [str ]) -> set [str ]:
300
- # User expects a set back.
301
- return self ._set .union (* others )
302
-
303
- def update (self , * others : set [str ]) -> None :
304
- # In-place union should update both list and set.
305
- self ._set .update (* others )
306
- # Elements were only added.
307
- self ._list .extend (element for element in sorted (self ._set - set (self ._list )))
308
-
309
-
310
- # Constants you might want to modify
311
- # -----------------------------------------------------------------------------
312
46
313
- # Type it as `set[str]` to express our intent for it to be used as such.
314
- # We explicitly lie here, so that users running type checkers will get
315
- # warnings when they use the container as a list. This is a very effective
316
- # way of communicating the change, and deprecating list-like usage.
317
- BLOCK_LEVEL_ELEMENTS : set [str ] = _BlockLevelElements ([
47
+ BLOCK_LEVEL_ELEMENTS : list [str ] = [
318
48
# Elements which are invalid to wrap in a `<p>` tag.
319
49
# See https://w3c.github.io/html/grouping-content.html#the-p-element
320
50
'address' , 'article' , 'aside' , 'blockquote' , 'details' , 'div' , 'dl' ,
@@ -326,9 +56,9 @@ def update(self, *others: set[str]) -> None:
326
56
'math' , 'map' , 'noscript' , 'output' , 'object' , 'option' , 'progress' , 'script' ,
327
57
'style' , 'summary' , 'tbody' , 'td' , 'textarea' , 'tfoot' , 'th' , 'thead' , 'tr' , 'video' ,
328
58
'center'
329
- ]) # type: ignore[assignment]
59
+ ]
330
60
"""
331
- Set of HTML tags which get treated as block-level elements. Same as the `block_level_elements`
61
+ List of HTML tags which get treated as block-level elements. Same as the `block_level_elements`
332
62
attribute of the [`Markdown`][markdown.Markdown] class. Generally one should use the
333
63
attribute on the class. This remains for compatibility with older extensions.
334
64
"""
@@ -381,6 +111,31 @@ def get_installed_extensions():
381
111
return metadata .entry_points (group = 'markdown.extensions' )
382
112
383
113
114
+ def deprecated (message : str , stacklevel : int = 2 ):
115
+ """
116
+ Raise a [`DeprecationWarning`][] when wrapped function/method is called.
117
+
118
+ Usage:
119
+
120
+ ```python
121
+ @deprecated("This method will be removed in version X; use Y instead.")
122
+ def some_method():
123
+ pass
124
+ ```
125
+ """
126
+ def wrapper (func ):
127
+ @wraps (func )
128
+ def deprecated_func (* args , ** kwargs ):
129
+ warnings .warn (
130
+ f"'{ func .__name__ } ' is deprecated. { message } " ,
131
+ category = DeprecationWarning ,
132
+ stacklevel = stacklevel
133
+ )
134
+ return func (* args , ** kwargs )
135
+ return deprecated_func
136
+ return wrapper
137
+
138
+
384
139
def parseBoolValue (value : str | None , fail_on_errors : bool = True , preserve_none : bool = False ) -> bool | None :
385
140
"""Parses a string representing a boolean value. If parsing was successful,
386
141
returns `True` or `False`. If `preserve_none=True`, returns `True`, `False`,
0 commit comments