JustinTX commited on
Commit
be7647c
·
verified ·
1 Parent(s): bbe73da

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. py311/lib/python3.11/site-packages/Levenshtein/StringMatcher.py +74 -0
  2. py311/lib/python3.11/site-packages/Levenshtein/__init__.py +550 -0
  3. py311/lib/python3.11/site-packages/Levenshtein/__init__.pyi +87 -0
  4. py311/lib/python3.11/site-packages/Levenshtein/py.typed +0 -0
  5. py311/lib/python3.11/site-packages/aiohappyeyeballs-2.6.1.dist-info/INSTALLER +1 -0
  6. py311/lib/python3.11/site-packages/aiohappyeyeballs-2.6.1.dist-info/LICENSE +279 -0
  7. py311/lib/python3.11/site-packages/aiohappyeyeballs-2.6.1.dist-info/METADATA +123 -0
  8. py311/lib/python3.11/site-packages/aiohappyeyeballs-2.6.1.dist-info/RECORD +12 -0
  9. py311/lib/python3.11/site-packages/aiohappyeyeballs-2.6.1.dist-info/REQUESTED +0 -0
  10. py311/lib/python3.11/site-packages/aiohappyeyeballs-2.6.1.dist-info/WHEEL +4 -0
  11. py311/lib/python3.11/site-packages/attr/__init__.py +104 -0
  12. py311/lib/python3.11/site-packages/attr/__init__.pyi +389 -0
  13. py311/lib/python3.11/site-packages/attr/__pycache__/__init__.cpython-311.pyc +0 -0
  14. py311/lib/python3.11/site-packages/attr/__pycache__/_cmp.cpython-311.pyc +0 -0
  15. py311/lib/python3.11/site-packages/attr/__pycache__/_compat.cpython-311.pyc +0 -0
  16. py311/lib/python3.11/site-packages/attr/__pycache__/_config.cpython-311.pyc +0 -0
  17. py311/lib/python3.11/site-packages/attr/__pycache__/_funcs.cpython-311.pyc +0 -0
  18. py311/lib/python3.11/site-packages/attr/__pycache__/_next_gen.cpython-311.pyc +0 -0
  19. py311/lib/python3.11/site-packages/attr/__pycache__/_version_info.cpython-311.pyc +0 -0
  20. py311/lib/python3.11/site-packages/attr/__pycache__/converters.cpython-311.pyc +0 -0
  21. py311/lib/python3.11/site-packages/attr/__pycache__/exceptions.cpython-311.pyc +0 -0
  22. py311/lib/python3.11/site-packages/attr/__pycache__/filters.cpython-311.pyc +0 -0
  23. py311/lib/python3.11/site-packages/attr/__pycache__/setters.cpython-311.pyc +0 -0
  24. py311/lib/python3.11/site-packages/attr/__pycache__/validators.cpython-311.pyc +0 -0
  25. py311/lib/python3.11/site-packages/attr/_cmp.py +160 -0
  26. py311/lib/python3.11/site-packages/attr/_cmp.pyi +13 -0
  27. py311/lib/python3.11/site-packages/attr/_compat.py +99 -0
  28. py311/lib/python3.11/site-packages/attr/_config.py +31 -0
  29. py311/lib/python3.11/site-packages/attr/_funcs.py +497 -0
  30. py311/lib/python3.11/site-packages/attr/_make.py +0 -0
  31. py311/lib/python3.11/site-packages/attr/_next_gen.py +674 -0
  32. py311/lib/python3.11/site-packages/attr/_typing_compat.pyi +15 -0
  33. py311/lib/python3.11/site-packages/attr/_version_info.py +89 -0
  34. py311/lib/python3.11/site-packages/attr/_version_info.pyi +9 -0
  35. py311/lib/python3.11/site-packages/attr/converters.py +162 -0
  36. py311/lib/python3.11/site-packages/attr/converters.pyi +19 -0
  37. py311/lib/python3.11/site-packages/attr/exceptions.py +95 -0
  38. py311/lib/python3.11/site-packages/attr/exceptions.pyi +17 -0
  39. py311/lib/python3.11/site-packages/attr/filters.py +72 -0
  40. py311/lib/python3.11/site-packages/attr/filters.pyi +6 -0
  41. py311/lib/python3.11/site-packages/attr/py.typed +0 -0
  42. py311/lib/python3.11/site-packages/attr/setters.py +79 -0
  43. py311/lib/python3.11/site-packages/attr/setters.pyi +20 -0
  44. py311/lib/python3.11/site-packages/attr/validators.py +748 -0
  45. py311/lib/python3.11/site-packages/attr/validators.pyi +140 -0
  46. py311/lib/python3.11/site-packages/attrs-25.4.0.dist-info/INSTALLER +1 -0
  47. py311/lib/python3.11/site-packages/attrs-25.4.0.dist-info/METADATA +235 -0
  48. py311/lib/python3.11/site-packages/attrs-25.4.0.dist-info/RECORD +37 -0
  49. py311/lib/python3.11/site-packages/attrs-25.4.0.dist-info/REQUESTED +0 -0
  50. py311/lib/python3.11/site-packages/attrs-25.4.0.dist-info/WHEEL +4 -0
py311/lib/python3.11/site-packages/Levenshtein/StringMatcher.py ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from warnings import warn
4
+
5
+ from Levenshtein import distance, editops, matching_blocks, opcodes, ratio
6
+
7
+
8
+ class StringMatcher:
9
+ """A SequenceMatcher-like class built on the top of Levenshtein"""
10
+
11
+ def _reset_cache(self):
12
+ self._ratio = self._distance = None
13
+ self._opcodes = self._editops = self._matching_blocks = None
14
+
15
+ def __init__(self, isjunk=None, seq1="", seq2="", autojunk=False):
16
+ if isjunk:
17
+ warn("isjunk NOT implemented, it will be ignored", stacklevel=1)
18
+ if autojunk:
19
+ warn("autojunk NOT implemented, it will be ignored", stacklevel=1)
20
+ self._str1, self._str2 = seq1, seq2
21
+ self._reset_cache()
22
+
23
+ def set_seqs(self, seq1, seq2):
24
+ self._str1, self._str2 = seq1, seq2
25
+ self._reset_cache()
26
+
27
+ def set_seq1(self, seq1):
28
+ self._str1 = seq1
29
+ self._reset_cache()
30
+
31
+ def set_seq2(self, seq2):
32
+ self._str2 = seq2
33
+ self._reset_cache()
34
+
35
+ def get_opcodes(self):
36
+ if not self._opcodes:
37
+ if self._editops:
38
+ self._opcodes = opcodes(self._editops, self._str1, self._str2)
39
+ else:
40
+ self._opcodes = opcodes(self._str1, self._str2)
41
+ return self._opcodes
42
+
43
+ def get_editops(self):
44
+ if not self._editops:
45
+ if self._opcodes:
46
+ self._editops = editops(self._opcodes, self._str1, self._str2)
47
+ else:
48
+ self._editops = editops(self._str1, self._str2)
49
+ return self._editops
50
+
51
+ def get_matching_blocks(self):
52
+ if not self._matching_blocks:
53
+ self._matching_blocks = matching_blocks(self.get_opcodes(), self._str1, self._str2)
54
+ return self._matching_blocks
55
+
56
+ def ratio(self):
57
+ if not self._ratio:
58
+ self._ratio = ratio(self._str1, self._str2)
59
+ return self._ratio
60
+
61
+ def quick_ratio(self):
62
+ # This is usually quick enough :o)
63
+ if not self._ratio:
64
+ self._ratio = ratio(self._str1, self._str2)
65
+ return self._ratio
66
+
67
+ def real_quick_ratio(self):
68
+ len1, len2 = len(self._str1), len(self._str2)
69
+ return 2.0 * min(len1, len2) / (len1 + len2)
70
+
71
+ def distance(self):
72
+ if not self._distance:
73
+ self._distance = distance(self._str1, self._str2)
74
+ return self._distance
py311/lib/python3.11/site-packages/Levenshtein/__init__.py ADDED
@@ -0,0 +1,550 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ A C extension module for fast computation of:
3
+ - Levenshtein (edit) distance and edit sequence manipulation
4
+ - string similarity
5
+ - approximate median strings, and generally string averaging
6
+ - string sequence and set similarity
7
+
8
+ Levenshtein has a some overlap with difflib (SequenceMatcher). It
9
+ supports only strings, not arbitrary sequence types, but on the
10
+ other hand it's much faster.
11
+
12
+ It supports both normal and Unicode strings, but can't mix them, all
13
+ arguments to a function (method) have to be of the same type (or its
14
+ subclasses).
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ __author__: str = "Max Bachmann"
20
+ __license__: str = "GPL"
21
+ __version__: str = "0.27.3"
22
+
23
+ import rapidfuzz.distance.Hamming as _Hamming
24
+ import rapidfuzz.distance.Indel as _Indel
25
+ import rapidfuzz.distance.Jaro as _Jaro
26
+ import rapidfuzz.distance.JaroWinkler as _JaroWinkler
27
+ import rapidfuzz.distance.Levenshtein as _Levenshtein
28
+ from rapidfuzz.distance import (
29
+ Editops as _Editops,
30
+ )
31
+ from rapidfuzz.distance import (
32
+ Opcodes as _Opcodes,
33
+ )
34
+
35
+ from Levenshtein.levenshtein_cpp import (
36
+ median,
37
+ median_improve,
38
+ quickmedian,
39
+ seqratio,
40
+ setmedian,
41
+ setratio,
42
+ )
43
+
44
+ __all__ = [
45
+ "quickmedian",
46
+ "median",
47
+ "median_improve",
48
+ "setmedian",
49
+ "setratio",
50
+ "seqratio",
51
+ "distance",
52
+ "ratio",
53
+ "hamming",
54
+ "jaro",
55
+ "jaro_winkler",
56
+ "editops",
57
+ "opcodes",
58
+ "matching_blocks",
59
+ "apply_edit",
60
+ "subtract_edit",
61
+ "inverse",
62
+ ]
63
+
64
+
65
+ def distance(s1, s2, *, weights=(1, 1, 1), processor=None, score_cutoff=None, score_hint=None):
66
+ """
67
+ Calculates the minimum number of insertions, deletions, and substitutions
68
+ required to change one sequence into the other according to Levenshtein with custom
69
+ costs for insertion, deletion and substitution
70
+
71
+ Parameters
72
+ ----------
73
+ s1 : Sequence[Hashable]
74
+ First string to compare.
75
+ s2 : Sequence[Hashable]
76
+ Second string to compare.
77
+ weights : Tuple[int, int, int] or None, optional
78
+ The weights for the three operations in the form
79
+ (insertion, deletion, substitution). Default is (1, 1, 1),
80
+ which gives all three operations a weight of 1.
81
+ processor: callable, optional
82
+ Optional callable that is used to preprocess the strings before
83
+ comparing them. Default is None, which deactivates this behaviour.
84
+ score_cutoff : int, optional
85
+ Maximum distance between s1 and s2, that is
86
+ considered as a result. If the distance is bigger than score_cutoff,
87
+ score_cutoff + 1 is returned instead. Default is None, which deactivates
88
+ this behaviour.
89
+ score_hint : int, optional
90
+ Expected distance between s1 and s2. This is used to select a
91
+ faster implementation. Default is None, which deactivates this behaviour.
92
+
93
+ Returns
94
+ -------
95
+ distance : int
96
+ distance between s1 and s2
97
+
98
+ Raises
99
+ ------
100
+ ValueError
101
+ If unsupported weights are provided a ValueError is thrown
102
+
103
+ Examples
104
+ --------
105
+ Find the Levenshtein distance between two strings:
106
+
107
+ >>> from Levenshtein import distance
108
+ >>> distance("lewenstein", "levenshtein")
109
+ 2
110
+
111
+ Setting a maximum distance allows the implementation to select
112
+ a more efficient implementation:
113
+
114
+ >>> distance("lewenstein", "levenshtein", score_cutoff=1)
115
+ 2
116
+
117
+ It is possible to select different weights by passing a `weight`
118
+ tuple.
119
+
120
+ >>> distance("lewenstein", "levenshtein", weights=(1,1,2))
121
+ 3
122
+ """
123
+ return _Levenshtein.distance(
124
+ s1,
125
+ s2,
126
+ weights=weights,
127
+ processor=processor,
128
+ score_cutoff=score_cutoff,
129
+ score_hint=score_hint,
130
+ )
131
+
132
+
133
+ def ratio(s1, s2, *, processor=None, score_cutoff=None):
134
+ """
135
+ Calculates a normalized indel similarity in the range [0, 1].
136
+ The indel distance calculates the minimum number of insertions and deletions
137
+ required to change one sequence into the other.
138
+
139
+ This is calculated as ``1 - (distance / (len1 + len2))``
140
+
141
+ Parameters
142
+ ----------
143
+ s1 : Sequence[Hashable]
144
+ First string to compare.
145
+ s2 : Sequence[Hashable]
146
+ Second string to compare.
147
+ processor: callable, optional
148
+ Optional callable that is used to preprocess the strings before
149
+ comparing them. Default is None, which deactivates this behaviour.
150
+ score_cutoff : float, optional
151
+ Optional argument for a score threshold as a float between 0 and 1.0.
152
+ For norm_sim < score_cutoff 0 is returned instead. Default is 0,
153
+ which deactivates this behaviour.
154
+
155
+ Returns
156
+ -------
157
+ norm_sim : float
158
+ normalized similarity between s1 and s2 as a float between 0 and 1.0
159
+
160
+ Examples
161
+ --------
162
+ Find the normalized Indel similarity between two strings:
163
+
164
+ >>> from Levenshtein import ratio
165
+ >>> ratio("lewenstein", "levenshtein")
166
+ 0.85714285714285
167
+
168
+ Setting a score_cutoff allows the implementation to select
169
+ a more efficient implementation:
170
+
171
+ >>> ratio("lewenstein", "levenshtein", score_cutoff=0.9)
172
+ 0.0
173
+
174
+ When a different processor is used s1 and s2 do not have to be strings
175
+
176
+ >>> ratio(["lewenstein"], ["levenshtein"], processor=lambda s: s[0])
177
+ 0.8571428571428572
178
+ """
179
+ return _Indel.normalized_similarity(s1, s2, processor=processor, score_cutoff=score_cutoff)
180
+
181
+
182
+ def hamming(s1, s2, *, pad=True, processor=None, score_cutoff=None):
183
+ """
184
+ Calculates the Hamming distance between two strings.
185
+ The hamming distance is defined as the number of positions
186
+ where the two strings differ. It describes the minimum
187
+ amount of substitutions required to transform s1 into s2.
188
+
189
+ Parameters
190
+ ----------
191
+ s1 : Sequence[Hashable]
192
+ First string to compare.
193
+ s2 : Sequence[Hashable]
194
+ Second string to compare.
195
+ pad : bool, optional
196
+ should strings be padded if there is a length difference.
197
+ If pad is False and strings have a different length
198
+ a ValueError is thrown instead. Default is True.
199
+ processor: callable, optional
200
+ Optional callable that is used to preprocess the strings before
201
+ comparing them. Default is None, which deactivates this behaviour.
202
+ score_cutoff : int or None, optional
203
+ Maximum distance between s1 and s2, that is
204
+ considered as a result. If the distance is bigger than score_cutoff,
205
+ score_cutoff + 1 is returned instead. Default is None, which deactivates
206
+ this behaviour.
207
+
208
+ Returns
209
+ -------
210
+ distance : int
211
+ distance between s1 and s2
212
+
213
+ Raises
214
+ ------
215
+ ValueError
216
+ If s1 and s2 have a different length
217
+ """
218
+ return _Hamming.distance(s1, s2, pad=pad, processor=processor, score_cutoff=score_cutoff)
219
+
220
+
221
+ def jaro(s1, s2, *, processor=None, score_cutoff=None) -> float:
222
+ """
223
+ Calculates the jaro similarity
224
+
225
+ Parameters
226
+ ----------
227
+ s1 : Sequence[Hashable]
228
+ First string to compare.
229
+ s2 : Sequence[Hashable]
230
+ Second string to compare.
231
+ processor: callable, optional
232
+ Optional callable that is used to preprocess the strings before
233
+ comparing them. Default is None, which deactivates this behaviour.
234
+ score_cutoff : float, optional
235
+ Optional argument for a score threshold as a float between 0 and 1.0.
236
+ For ratio < score_cutoff 0 is returned instead. Default is None,
237
+ which deactivates this behaviour.
238
+
239
+ Returns
240
+ -------
241
+ similarity : float
242
+ similarity between s1 and s2 as a float between 0 and 1.0
243
+ """
244
+ return _Jaro.similarity(s1, s2, processor=processor, score_cutoff=score_cutoff)
245
+
246
+
247
+ def jaro_winkler(s1, s2, *, prefix_weight=0.1, processor=None, score_cutoff=None) -> float:
248
+ """
249
+ Calculates the jaro winkler similarity
250
+
251
+ Parameters
252
+ ----------
253
+ s1 : Sequence[Hashable]
254
+ First string to compare.
255
+ s2 : Sequence[Hashable]
256
+ Second string to compare.
257
+ prefix_weight : float, optional
258
+ Weight used for the common prefix of the two strings.
259
+ Has to be between 0 and 0.25. Default is 0.1.
260
+ processor: callable, optional
261
+ Optional callable that is used to preprocess the strings before
262
+ comparing them. Default is None, which deactivates this behaviour.
263
+ score_cutoff : float, optional
264
+ Optional argument for a score threshold as a float between 0 and 1.0.
265
+ For ratio < score_cutoff 0 is returned instead. Default is None,
266
+ which deactivates this behaviour.
267
+
268
+ Returns
269
+ -------
270
+ similarity : float
271
+ similarity between s1 and s2 as a float between 0 and 1.0
272
+
273
+ Raises
274
+ ------
275
+ ValueError
276
+ If prefix_weight is invalid
277
+ """
278
+ return _JaroWinkler.similarity(
279
+ s1,
280
+ s2,
281
+ prefix_weight=prefix_weight,
282
+ processor=processor,
283
+ score_cutoff=score_cutoff,
284
+ )
285
+
286
+
287
+ # assign attributes to function. This allows rapidfuzz to call them more efficiently
288
+ # we can't directly copy the functions + replace the docstrings, since this leads to
289
+ # crashes on PyPy
290
+ distance._RF_OriginalScorer = distance
291
+ ratio._RF_OriginalScorer = ratio
292
+ hamming._RF_OriginalScorer = hamming
293
+ jaro._RF_OriginalScorer = jaro
294
+ jaro_winkler._RF_OriginalScorer = jaro_winkler
295
+
296
+ distance._RF_ScorerPy = _Levenshtein.distance._RF_ScorerPy
297
+ ratio._RF_ScorerPy = _Indel.normalized_similarity._RF_ScorerPy
298
+ hamming._RF_ScorerPy = _Hamming.distance._RF_ScorerPy
299
+ jaro._RF_ScorerPy = _Jaro.similarity._RF_ScorerPy
300
+ jaro_winkler._RF_ScorerPy = _JaroWinkler.similarity._RF_ScorerPy
301
+
302
+ if hasattr(_Levenshtein.distance, "_RF_Scorer"):
303
+ distance._RF_Scorer = _Levenshtein.distance._RF_Scorer
304
+ if hasattr(_Indel.normalized_similarity, "_RF_Scorer"):
305
+ ratio._RF_Scorer = _Indel.normalized_similarity._RF_Scorer
306
+ if hasattr(_Hamming.distance, "_RF_Scorer"):
307
+ hamming._RF_Scorer = _Hamming.distance._RF_Scorer
308
+ if hasattr(_Jaro.similarity, "_RF_Scorer"):
309
+ jaro._RF_Scorer = _Jaro.similarity._RF_Scorer
310
+ if hasattr(_JaroWinkler.similarity, "_RF_Scorer"):
311
+ jaro_winkler._RF_Scorer = _JaroWinkler.similarity._RF_Scorer
312
+
313
+
314
+ def editops(*args):
315
+ """
316
+ Find sequence of edit operations transforming one string to another.
317
+
318
+ editops(source_string, destination_string)
319
+ editops(edit_operations, source_length, destination_length)
320
+
321
+ The result is a list of triples (operation, spos, dpos), where
322
+ operation is one of 'equal', 'replace', 'insert', or 'delete'; spos
323
+ and dpos are position of characters in the first (source) and the
324
+ second (destination) strings. These are operations on single
325
+ characters. In fact the returned list doesn't contain the 'equal',
326
+ but all the related functions accept both lists with and without
327
+ 'equal's.
328
+
329
+ Examples
330
+ --------
331
+ >>> editops('spam', 'park')
332
+ [('delete', 0, 0), ('insert', 3, 2), ('replace', 3, 3)]
333
+
334
+ The alternate form editops(opcodes, source_string, destination_string)
335
+ can be used for conversion from opcodes (5-tuples) to editops (you can
336
+ pass strings or their lengths, it doesn't matter).
337
+ """
338
+ # convert: we were called (bops, s1, s2)
339
+ if len(args) == 3:
340
+ arg1, arg2, arg3 = args
341
+ len1 = arg2 if isinstance(arg2, int) else len(arg2)
342
+ len2 = arg3 if isinstance(arg3, int) else len(arg3)
343
+ return _Editops(arg1, len1, len2).as_list()
344
+
345
+ # find editops: we were called (s1, s2)
346
+ arg1, arg2 = args
347
+ return _Levenshtein.editops(arg1, arg2).as_list()
348
+
349
+
350
+ def opcodes(*args):
351
+ """
352
+ Find sequence of edit operations transforming one string to another.
353
+
354
+ opcodes(source_string, destination_string)
355
+ opcodes(edit_operations, source_length, destination_length)
356
+
357
+ The result is a list of 5-tuples with the same meaning as in
358
+ SequenceMatcher's get_opcodes() output. But since the algorithms
359
+ differ, the actual sequences from Levenshtein and SequenceMatcher
360
+ may differ too.
361
+
362
+ Examples
363
+ --------
364
+ >>> for x in opcodes('spam', 'park'):
365
+ ... print(x)
366
+ ...
367
+ ('delete', 0, 1, 0, 0)
368
+ ('equal', 1, 3, 0, 2)
369
+ ('insert', 3, 3, 2, 3)
370
+ ('replace', 3, 4, 3, 4)
371
+
372
+ The alternate form opcodes(editops, source_string, destination_string)
373
+ can be used for conversion from editops (triples) to opcodes (you can
374
+ pass strings or their lengths, it doesn't matter).
375
+ """
376
+ # convert: we were called (ops, s1, s2)
377
+ if len(args) == 3:
378
+ arg1, arg2, arg3 = args
379
+ len1 = arg2 if isinstance(arg2, int) else len(arg2)
380
+ len2 = arg3 if isinstance(arg3, int) else len(arg3)
381
+ return _Opcodes(arg1, len1, len2).as_list()
382
+
383
+ # find editops: we were called (s1, s2)
384
+ arg1, arg2 = args
385
+ return _Levenshtein.opcodes(arg1, arg2).as_list()
386
+
387
+
388
+ def matching_blocks(edit_operations, source_string, destination_string):
389
+ """
390
+ Find identical blocks in two strings.
391
+
392
+ Parameters
393
+ ----------
394
+ edit_operations : list[]
395
+ editops or opcodes created for the source and destination string
396
+ source_string : str | int
397
+ source string or the length of the source string
398
+ destination_string : str | int
399
+ destination string or the length of the destination string
400
+
401
+ Returns
402
+ -------
403
+ matching_blocks : list[]
404
+ List of triples with the same meaning as in SequenceMatcher's
405
+ get_matching_blocks() output.
406
+
407
+ Examples
408
+ --------
409
+ >>> a, b = 'spam', 'park'
410
+ >>> matching_blocks(editops(a, b), a, b)
411
+ [(1, 0, 2), (4, 4, 0)]
412
+ >>> matching_blocks(editops(a, b), len(a), len(b))
413
+ [(1, 0, 2), (4, 4, 0)]
414
+
415
+ The last zero-length block is not an error, but it's there for
416
+ compatibility with difflib which always emits it.
417
+
418
+ One can join the matching blocks to get two identical strings:
419
+
420
+ >>> a, b = 'dog kennels', 'mattresses'
421
+ >>> mb = matching_blocks(editops(a,b), a, b)
422
+ >>> ''.join([a[x[0]:x[0]+x[2]] for x in mb])
423
+ 'ees'
424
+ >>> ''.join([b[x[1]:x[1]+x[2]] for x in mb])
425
+ 'ees'
426
+ """
427
+ len1 = source_string if isinstance(source_string, int) else len(source_string)
428
+ len2 = destination_string if isinstance(destination_string, int) else len(destination_string)
429
+
430
+ if not edit_operations or len(edit_operations[0]) == 3:
431
+ return _Editops(edit_operations, len1, len2).as_matching_blocks()
432
+
433
+ return _Opcodes(edit_operations, len1, len2).as_matching_blocks()
434
+
435
+
436
+ def apply_edit(edit_operations, source_string, destination_string):
437
+ """
438
+ Apply a sequence of edit operations to a string.
439
+
440
+ apply_edit(edit_operations, source_string, destination_string)
441
+
442
+ In the case of editops, the sequence can be arbitrary ordered subset
443
+ of the edit sequence transforming source_string to destination_string.
444
+
445
+ Examples
446
+ --------
447
+ >>> e = editops('man', 'scotsman')
448
+ >>> apply_edit(e, 'man', 'scotsman')
449
+ 'scotsman'
450
+ >>> apply_edit(e[:3], 'man', 'scotsman')
451
+ 'scoman'
452
+
453
+ The other form of edit operations, opcodes, is not very suitable for
454
+ such a tricks, because it has to always span over complete strings,
455
+ subsets can be created by carefully replacing blocks with 'equal'
456
+ blocks, or by enlarging 'equal' block at the expense of other blocks
457
+ and adjusting the other blocks accordingly.
458
+
459
+ >>> a, b = 'spam and eggs', 'foo and bar'
460
+ >>> e = opcodes(a, b)
461
+ >>> apply_edit(inverse(e), b, a)
462
+ 'spam and eggs'
463
+ """
464
+ if len(edit_operations) == 0:
465
+ return source_string
466
+
467
+ len1 = len(source_string)
468
+ len2 = len(destination_string)
469
+
470
+ if len(edit_operations[0]) == 3:
471
+ return _Editops(edit_operations, len1, len2).apply(source_string, destination_string)
472
+
473
+ return _Opcodes(edit_operations, len1, len2).apply(source_string, destination_string)
474
+
475
+
476
+ def subtract_edit(edit_operations, subsequence):
477
+ """
478
+ Subtract an edit subsequence from a sequence.
479
+
480
+ subtract_edit(edit_operations, subsequence)
481
+
482
+ The result is equivalent to
483
+ editops(apply_edit(subsequence, s1, s2), s2), except that is
484
+ constructed directly from the edit operations. That is, if you apply
485
+ it to the result of subsequence application, you get the same final
486
+ string as from application complete edit_operations. It may be not
487
+ identical, though (in amibuous cases, like insertion of a character
488
+ next to the same character).
489
+
490
+ The subtracted subsequence must be an ordered subset of
491
+ edit_operations.
492
+
493
+ Note this function does not accept difflib-style opcodes as no one in
494
+ his right mind wants to create subsequences from them.
495
+
496
+ Examples
497
+ --------
498
+ >>> e = editops('man', 'scotsman')
499
+ >>> e1 = e[:3]
500
+ >>> bastard = apply_edit(e1, 'man', 'scotsman')
501
+ >>> bastard
502
+ 'scoman'
503
+ >>> apply_edit(subtract_edit(e, e1), bastard, 'scotsman')
504
+ 'scotsman'
505
+ """
506
+ str_len = 2**32
507
+ return (
508
+ _Editops(edit_operations, str_len, str_len)
509
+ .remove_subsequence(_Editops(subsequence, str_len, str_len))
510
+ .as_list()
511
+ )
512
+
513
+
514
+ def inverse(edit_operations):
515
+ """
516
+ Invert the sense of an edit operation sequence.
517
+
518
+ In other words, it returns a list of edit operations transforming the
519
+ second (destination) string to the first (source). It can be used
520
+ with both editops and opcodes.
521
+
522
+ Parameters
523
+ ----------
524
+ edit_operations : list[]
525
+ edit operations to invert
526
+
527
+ Returns
528
+ -------
529
+ edit_operations : list[]
530
+ inverted edit operations
531
+
532
+ Examples
533
+ --------
534
+ >>> editops('spam', 'park')
535
+ [('delete', 0, 0), ('insert', 3, 2), ('replace', 3, 3)]
536
+ >>> inverse(editops('spam', 'park'))
537
+ [('insert', 0, 0), ('delete', 2, 3), ('replace', 3, 3)]
538
+ """
539
+ if len(edit_operations) == 0:
540
+ return []
541
+
542
+ if len(edit_operations[0]) == 3:
543
+ len1 = edit_operations[-1][1] + 1
544
+ len2 = edit_operations[-1][2] + 1
545
+ return _Editops(edit_operations, len1, len2).inverse().as_list()
546
+
547
+ len1 = edit_operations[-1][2]
548
+ len2 = edit_operations[-1][4]
549
+
550
+ return _Opcodes(edit_operations, len1, len2).inverse().as_list()
py311/lib/python3.11/site-packages/Levenshtein/__init__.pyi ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Callable, Hashable, Sequence
4
+ from typing import overload
5
+
6
+ __author__: str
7
+ __license__: str
8
+ __version__: str
9
+
10
+ _EditopsList = list[tuple[str, int, int]]
11
+ _OpcodesList = list[tuple[str, int, int, int, int]]
12
+ _MatchingBlocks = list[tuple[int, int, int]]
13
+ _AnyEditops = _EditopsList | _OpcodesList
14
+
15
+ def inverse(edit_operations: list) -> list: ...
16
+ @overload
17
+ def editops(s1: Sequence[Hashable], s2: Sequence[Hashable]) -> _EditopsList: ...
18
+ @overload
19
+ def editops(
20
+ ops: _AnyEditops,
21
+ s1: Sequence[Hashable] | int,
22
+ s2: Sequence[Hashable] | int,
23
+ ) -> _EditopsList: ...
24
+ @overload
25
+ def opcodes(s1: Sequence[Hashable], s2: Sequence[Hashable]) -> _OpcodesList: ...
26
+ @overload
27
+ def opcodes(
28
+ ops: _AnyEditops,
29
+ s1: Sequence[Hashable] | int,
30
+ s2: Sequence[Hashable] | int,
31
+ ) -> _OpcodesList: ...
32
+ def matching_blocks(
33
+ edit_operations: _AnyEditops,
34
+ source_string: Sequence[Hashable] | int,
35
+ destination_string: Sequence[Hashable] | int,
36
+ ) -> _MatchingBlocks: ...
37
+ def subtract_edit(edit_operations: _EditopsList, subsequence: _EditopsList) -> _EditopsList: ...
38
+ def apply_edit(edit_operations: _AnyEditops, source_string: str, destination_string: str) -> str: ...
39
+ def median(strlist: list[str | bytes], wlist: list[float] | None = None) -> str: ...
40
+ def quickmedian(strlist: list[str | bytes], wlist: list[float] | None = None) -> str: ...
41
+ def median_improve(
42
+ string: str | bytes,
43
+ strlist: list[str | bytes],
44
+ wlist: list[float] | None = None,
45
+ ) -> str: ...
46
+ def setmedian(strlist: list[str | bytes], wlist: list[float] | None = None) -> str: ...
47
+ def setratio(strlist1: list[str | bytes], strlist2: list[str | bytes]) -> float: ...
48
+ def seqratio(strlist1: list[str | bytes], strlist2: list[str | bytes]) -> float: ...
49
+ def distance(
50
+ s1: Sequence[Hashable],
51
+ s2: Sequence[Hashable],
52
+ *,
53
+ weights: tuple[int, int, int] | None = (1, 1, 1),
54
+ processor: Callable[..., Sequence[Hashable]] | None = None,
55
+ score_cutoff: float | None = None,
56
+ score_hint: float | None = None,
57
+ ) -> int: ...
58
+ def ratio(
59
+ s1: Sequence[Hashable],
60
+ s2: Sequence[Hashable],
61
+ *,
62
+ processor: Callable[..., Sequence[Hashable]] | None = None,
63
+ score_cutoff: float | None = None,
64
+ ) -> float: ...
65
+ def hamming(
66
+ s1: Sequence[Hashable],
67
+ s2: Sequence[Hashable],
68
+ *,
69
+ pad: bool = True,
70
+ processor: Callable[..., Sequence[Hashable]] | None = None,
71
+ score_cutoff: float | None = None,
72
+ ) -> int: ...
73
+ def jaro(
74
+ s1: Sequence[Hashable],
75
+ s2: Sequence[Hashable],
76
+ *,
77
+ processor: Callable[..., Sequence[Hashable]] | None = None,
78
+ score_cutoff: float | None = None,
79
+ ) -> float: ...
80
+ def jaro_winkler(
81
+ s1: Sequence[Hashable],
82
+ s2: Sequence[Hashable],
83
+ *,
84
+ prefix_weight: float | None = 0.1,
85
+ processor: Callable[..., Sequence[Hashable]] | None = None,
86
+ score_cutoff: float | None = None,
87
+ ) -> float: ...
py311/lib/python3.11/site-packages/Levenshtein/py.typed ADDED
File without changes
py311/lib/python3.11/site-packages/aiohappyeyeballs-2.6.1.dist-info/INSTALLER ADDED
@@ -0,0 +1 @@
 
 
1
+ uv
py311/lib/python3.11/site-packages/aiohappyeyeballs-2.6.1.dist-info/LICENSE ADDED
@@ -0,0 +1,279 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ A. HISTORY OF THE SOFTWARE
2
+ ==========================
3
+
4
+ Python was created in the early 1990s by Guido van Rossum at Stichting
5
+ Mathematisch Centrum (CWI, see https://www.cwi.nl) in the Netherlands
6
+ as a successor of a language called ABC. Guido remains Python's
7
+ principal author, although it includes many contributions from others.
8
+
9
+ In 1995, Guido continued his work on Python at the Corporation for
10
+ National Research Initiatives (CNRI, see https://www.cnri.reston.va.us)
11
+ in Reston, Virginia where he released several versions of the
12
+ software.
13
+
14
+ In May 2000, Guido and the Python core development team moved to
15
+ BeOpen.com to form the BeOpen PythonLabs team. In October of the same
16
+ year, the PythonLabs team moved to Digital Creations, which became
17
+ Zope Corporation. In 2001, the Python Software Foundation (PSF, see
18
+ https://www.python.org/psf/) was formed, a non-profit organization
19
+ created specifically to own Python-related Intellectual Property.
20
+ Zope Corporation was a sponsoring member of the PSF.
21
+
22
+ All Python releases are Open Source (see https://opensource.org for
23
+ the Open Source Definition). Historically, most, but not all, Python
24
+ releases have also been GPL-compatible; the table below summarizes
25
+ the various releases.
26
+
27
+ Release Derived Year Owner GPL-
28
+ from compatible? (1)
29
+
30
+ 0.9.0 thru 1.2 1991-1995 CWI yes
31
+ 1.3 thru 1.5.2 1.2 1995-1999 CNRI yes
32
+ 1.6 1.5.2 2000 CNRI no
33
+ 2.0 1.6 2000 BeOpen.com no
34
+ 1.6.1 1.6 2001 CNRI yes (2)
35
+ 2.1 2.0+1.6.1 2001 PSF no
36
+ 2.0.1 2.0+1.6.1 2001 PSF yes
37
+ 2.1.1 2.1+2.0.1 2001 PSF yes
38
+ 2.1.2 2.1.1 2002 PSF yes
39
+ 2.1.3 2.1.2 2002 PSF yes
40
+ 2.2 and above 2.1.1 2001-now PSF yes
41
+
42
+ Footnotes:
43
+
44
+ (1) GPL-compatible doesn't mean that we're distributing Python under
45
+ the GPL. All Python licenses, unlike the GPL, let you distribute
46
+ a modified version without making your changes open source. The
47
+ GPL-compatible licenses make it possible to combine Python with
48
+ other software that is released under the GPL; the others don't.
49
+
50
+ (2) According to Richard Stallman, 1.6.1 is not GPL-compatible,
51
+ because its license has a choice of law clause. According to
52
+ CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1
53
+ is "not incompatible" with the GPL.
54
+
55
+ Thanks to the many outside volunteers who have worked under Guido's
56
+ direction to make these releases possible.
57
+
58
+
59
+ B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON
60
+ ===============================================================
61
+
62
+ Python software and documentation are licensed under the
63
+ Python Software Foundation License Version 2.
64
+
65
+ Starting with Python 3.8.6, examples, recipes, and other code in
66
+ the documentation are dual licensed under the PSF License Version 2
67
+ and the Zero-Clause BSD license.
68
+
69
+ Some software incorporated into Python is under different licenses.
70
+ The licenses are listed with code falling under that license.
71
+
72
+
73
+ PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
74
+ --------------------------------------------
75
+
76
+ 1. This LICENSE AGREEMENT is between the Python Software Foundation
77
+ ("PSF"), and the Individual or Organization ("Licensee") accessing and
78
+ otherwise using this software ("Python") in source or binary form and
79
+ its associated documentation.
80
+
81
+ 2. Subject to the terms and conditions of this License Agreement, PSF hereby
82
+ grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
83
+ analyze, test, perform and/or display publicly, prepare derivative works,
84
+ distribute, and otherwise use Python alone or in any derivative version,
85
+ provided, however, that PSF's License Agreement and PSF's notice of copyright,
86
+ i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
87
+ 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 Python Software Foundation;
88
+ All Rights Reserved" are retained in Python alone or in any derivative version
89
+ prepared by Licensee.
90
+
91
+ 3. In the event Licensee prepares a derivative work that is based on
92
+ or incorporates Python or any part thereof, and wants to make
93
+ the derivative work available to others as provided herein, then
94
+ Licensee hereby agrees to include in any such work a brief summary of
95
+ the changes made to Python.
96
+
97
+ 4. PSF is making Python available to Licensee on an "AS IS"
98
+ basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
99
+ IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
100
+ DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
101
+ FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
102
+ INFRINGE ANY THIRD PARTY RIGHTS.
103
+
104
+ 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
105
+ FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
106
+ A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
107
+ OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
108
+
109
+ 6. This License Agreement will automatically terminate upon a material
110
+ breach of its terms and conditions.
111
+
112
+ 7. Nothing in this License Agreement shall be deemed to create any
113
+ relationship of agency, partnership, or joint venture between PSF and
114
+ Licensee. This License Agreement does not grant permission to use PSF
115
+ trademarks or trade name in a trademark sense to endorse or promote
116
+ products or services of Licensee, or any third party.
117
+
118
+ 8. By copying, installing or otherwise using Python, Licensee
119
+ agrees to be bound by the terms and conditions of this License
120
+ Agreement.
121
+
122
+
123
+ BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0
124
+ -------------------------------------------
125
+
126
+ BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1
127
+
128
+ 1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an
129
+ office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the
130
+ Individual or Organization ("Licensee") accessing and otherwise using
131
+ this software in source or binary form and its associated
132
+ documentation ("the Software").
133
+
134
+ 2. Subject to the terms and conditions of this BeOpen Python License
135
+ Agreement, BeOpen hereby grants Licensee a non-exclusive,
136
+ royalty-free, world-wide license to reproduce, analyze, test, perform
137
+ and/or display publicly, prepare derivative works, distribute, and
138
+ otherwise use the Software alone or in any derivative version,
139
+ provided, however, that the BeOpen Python License is retained in the
140
+ Software, alone or in any derivative version prepared by Licensee.
141
+
142
+ 3. BeOpen is making the Software available to Licensee on an "AS IS"
143
+ basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
144
+ IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND
145
+ DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
146
+ FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT
147
+ INFRINGE ANY THIRD PARTY RIGHTS.
148
+
149
+ 4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE
150
+ SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS
151
+ AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY
152
+ DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
153
+
154
+ 5. This License Agreement will automatically terminate upon a material
155
+ breach of its terms and conditions.
156
+
157
+ 6. This License Agreement shall be governed by and interpreted in all
158
+ respects by the law of the State of California, excluding conflict of
159
+ law provisions. Nothing in this License Agreement shall be deemed to
160
+ create any relationship of agency, partnership, or joint venture
161
+ between BeOpen and Licensee. This License Agreement does not grant
162
+ permission to use BeOpen trademarks or trade names in a trademark
163
+ sense to endorse or promote products or services of Licensee, or any
164
+ third party. As an exception, the "BeOpen Python" logos available at
165
+ http://www.pythonlabs.com/logos.html may be used according to the
166
+ permissions granted on that web page.
167
+
168
+ 7. By copying, installing or otherwise using the software, Licensee
169
+ agrees to be bound by the terms and conditions of this License
170
+ Agreement.
171
+
172
+
173
+ CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1
174
+ ---------------------------------------
175
+
176
+ 1. This LICENSE AGREEMENT is between the Corporation for National
177
+ Research Initiatives, having an office at 1895 Preston White Drive,
178
+ Reston, VA 20191 ("CNRI"), and the Individual or Organization
179
+ ("Licensee") accessing and otherwise using Python 1.6.1 software in
180
+ source or binary form and its associated documentation.
181
+
182
+ 2. Subject to the terms and conditions of this License Agreement, CNRI
183
+ hereby grants Licensee a nonexclusive, royalty-free, world-wide
184
+ license to reproduce, analyze, test, perform and/or display publicly,
185
+ prepare derivative works, distribute, and otherwise use Python 1.6.1
186
+ alone or in any derivative version, provided, however, that CNRI's
187
+ License Agreement and CNRI's notice of copyright, i.e., "Copyright (c)
188
+ 1995-2001 Corporation for National Research Initiatives; All Rights
189
+ Reserved" are retained in Python 1.6.1 alone or in any derivative
190
+ version prepared by Licensee. Alternately, in lieu of CNRI's License
191
+ Agreement, Licensee may substitute the following text (omitting the
192
+ quotes): "Python 1.6.1 is made available subject to the terms and
193
+ conditions in CNRI's License Agreement. This Agreement together with
194
+ Python 1.6.1 may be located on the internet using the following
195
+ unique, persistent identifier (known as a handle): 1895.22/1013. This
196
+ Agreement may also be obtained from a proxy server on the internet
197
+ using the following URL: http://hdl.handle.net/1895.22/1013".
198
+
199
+ 3. In the event Licensee prepares a derivative work that is based on
200
+ or incorporates Python 1.6.1 or any part thereof, and wants to make
201
+ the derivative work available to others as provided herein, then
202
+ Licensee hereby agrees to include in any such work a brief summary of
203
+ the changes made to Python 1.6.1.
204
+
205
+ 4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS"
206
+ basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
207
+ IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND
208
+ DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
209
+ FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT
210
+ INFRINGE ANY THIRD PARTY RIGHTS.
211
+
212
+ 5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
213
+ 1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
214
+ A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1,
215
+ OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
216
+
217
+ 6. This License Agreement will automatically terminate upon a material
218
+ breach of its terms and conditions.
219
+
220
+ 7. This License Agreement shall be governed by the federal
221
+ intellectual property law of the United States, including without
222
+ limitation the federal copyright law, and, to the extent such
223
+ U.S. federal law does not apply, by the law of the Commonwealth of
224
+ Virginia, excluding Virginia's conflict of law provisions.
225
+ Notwithstanding the foregoing, with regard to derivative works based
226
+ on Python 1.6.1 that incorporate non-separable material that was
227
+ previously distributed under the GNU General Public License (GPL), the
228
+ law of the Commonwealth of Virginia shall govern this License
229
+ Agreement only as to issues arising under or with respect to
230
+ Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this
231
+ License Agreement shall be deemed to create any relationship of
232
+ agency, partnership, or joint venture between CNRI and Licensee. This
233
+ License Agreement does not grant permission to use CNRI trademarks or
234
+ trade name in a trademark sense to endorse or promote products or
235
+ services of Licensee, or any third party.
236
+
237
+ 8. By clicking on the "ACCEPT" button where indicated, or by copying,
238
+ installing or otherwise using Python 1.6.1, Licensee agrees to be
239
+ bound by the terms and conditions of this License Agreement.
240
+
241
+ ACCEPT
242
+
243
+
244
+ CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2
245
+ --------------------------------------------------
246
+
247
+ Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam,
248
+ The Netherlands. All rights reserved.
249
+
250
+ Permission to use, copy, modify, and distribute this software and its
251
+ documentation for any purpose and without fee is hereby granted,
252
+ provided that the above copyright notice appear in all copies and that
253
+ both that copyright notice and this permission notice appear in
254
+ supporting documentation, and that the name of Stichting Mathematisch
255
+ Centrum or CWI not be used in advertising or publicity pertaining to
256
+ distribution of the software without specific, written prior
257
+ permission.
258
+
259
+ STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
260
+ THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
261
+ FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
262
+ FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
263
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
264
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
265
+ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
266
+
267
+ ZERO-CLAUSE BSD LICENSE FOR CODE IN THE PYTHON DOCUMENTATION
268
+ ----------------------------------------------------------------------
269
+
270
+ Permission to use, copy, modify, and/or distribute this software for any
271
+ purpose with or without fee is hereby granted.
272
+
273
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
274
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
275
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
276
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
277
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
278
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
279
+ PERFORMANCE OF THIS SOFTWARE.
py311/lib/python3.11/site-packages/aiohappyeyeballs-2.6.1.dist-info/METADATA ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Metadata-Version: 2.3
2
+ Name: aiohappyeyeballs
3
+ Version: 2.6.1
4
+ Summary: Happy Eyeballs for asyncio
5
+ License: PSF-2.0
6
+ Author: J. Nick Koston
7
+ Author-email: nick@koston.org
8
+ Requires-Python: >=3.9
9
+ Classifier: Development Status :: 5 - Production/Stable
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Natural Language :: English
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Topic :: Software Development :: Libraries
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: License :: OSI Approved :: Python Software Foundation License
21
+ Project-URL: Bug Tracker, https://github.com/aio-libs/aiohappyeyeballs/issues
22
+ Project-URL: Changelog, https://github.com/aio-libs/aiohappyeyeballs/blob/main/CHANGELOG.md
23
+ Project-URL: Documentation, https://aiohappyeyeballs.readthedocs.io
24
+ Project-URL: Repository, https://github.com/aio-libs/aiohappyeyeballs
25
+ Description-Content-Type: text/markdown
26
+
27
+ # aiohappyeyeballs
28
+
29
+ <p align="center">
30
+ <a href="https://github.com/aio-libs/aiohappyeyeballs/actions/workflows/ci.yml?query=branch%3Amain">
31
+ <img src="https://img.shields.io/github/actions/workflow/status/aio-libs/aiohappyeyeballs/ci-cd.yml?branch=main&label=CI&logo=github&style=flat-square" alt="CI Status" >
32
+ </a>
33
+ <a href="https://aiohappyeyeballs.readthedocs.io">
34
+ <img src="https://img.shields.io/readthedocs/aiohappyeyeballs.svg?logo=read-the-docs&logoColor=fff&style=flat-square" alt="Documentation Status">
35
+ </a>
36
+ <a href="https://codecov.io/gh/aio-libs/aiohappyeyeballs">
37
+ <img src="https://img.shields.io/codecov/c/github/aio-libs/aiohappyeyeballs.svg?logo=codecov&logoColor=fff&style=flat-square" alt="Test coverage percentage">
38
+ </a>
39
+ </p>
40
+ <p align="center">
41
+ <a href="https://python-poetry.org/">
42
+ <img src="https://img.shields.io/badge/packaging-poetry-299bd7?style=flat-square&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAASCAYAAABrXO8xAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAJJSURBVHgBfZLPa1NBEMe/s7tNXoxW1KJQKaUHkXhQvHgW6UHQQ09CBS/6V3hKc/AP8CqCrUcpmop3Cx48eDB4yEECjVQrlZb80CRN8t6OM/teagVxYZi38+Yz853dJbzoMV3MM8cJUcLMSUKIE8AzQ2PieZzFxEJOHMOgMQQ+dUgSAckNXhapU/NMhDSWLs1B24A8sO1xrN4NECkcAC9ASkiIJc6k5TRiUDPhnyMMdhKc+Zx19l6SgyeW76BEONY9exVQMzKExGKwwPsCzza7KGSSWRWEQhyEaDXp6ZHEr416ygbiKYOd7TEWvvcQIeusHYMJGhTwF9y7sGnSwaWyFAiyoxzqW0PM/RjghPxF2pWReAowTEXnDh0xgcLs8l2YQmOrj3N7ByiqEoH0cARs4u78WgAVkoEDIDoOi3AkcLOHU60RIg5wC4ZuTC7FaHKQm8Hq1fQuSOBvX/sodmNJSB5geaF5CPIkUeecdMxieoRO5jz9bheL6/tXjrwCyX/UYBUcjCaWHljx1xiX6z9xEjkYAzbGVnB8pvLmyXm9ep+W8CmsSHQQY77Zx1zboxAV0w7ybMhQmfqdmmw3nEp1I0Z+FGO6M8LZdoyZnuzzBdjISicKRnpxzI9fPb+0oYXsNdyi+d3h9bm9MWYHFtPeIZfLwzmFDKy1ai3p+PDls1Llz4yyFpferxjnyjJDSEy9CaCx5m2cJPerq6Xm34eTrZt3PqxYO1XOwDYZrFlH1fWnpU38Y9HRze3lj0vOujZcXKuuXm3jP+s3KbZVra7y2EAAAAAASUVORK5CYII=" alt="Poetry">
43
+ </a>
44
+ <a href="https://github.com/astral-sh/ruff">
45
+ <img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json" alt="Ruff">
46
+ </a>
47
+ <a href="https://github.com/pre-commit/pre-commit">
48
+ <img src="https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white&style=flat-square" alt="pre-commit">
49
+ </a>
50
+ </p>
51
+ <p align="center">
52
+ <a href="https://pypi.org/project/aiohappyeyeballs/">
53
+ <img src="https://img.shields.io/pypi/v/aiohappyeyeballs.svg?logo=python&logoColor=fff&style=flat-square" alt="PyPI Version">
54
+ </a>
55
+ <img src="https://img.shields.io/pypi/pyversions/aiohappyeyeballs.svg?style=flat-square&logo=python&amp;logoColor=fff" alt="Supported Python versions">
56
+ <img src="https://img.shields.io/pypi/l/aiohappyeyeballs.svg?style=flat-square" alt="License">
57
+ </p>
58
+
59
+ ---
60
+
61
+ **Documentation**: <a href="https://aiohappyeyeballs.readthedocs.io" target="_blank">https://aiohappyeyeballs.readthedocs.io </a>
62
+
63
+ **Source Code**: <a href="https://github.com/aio-libs/aiohappyeyeballs" target="_blank">https://github.com/aio-libs/aiohappyeyeballs </a>
64
+
65
+ ---
66
+
67
+ [Happy Eyeballs](https://en.wikipedia.org/wiki/Happy_Eyeballs)
68
+ ([RFC 8305](https://www.rfc-editor.org/rfc/rfc8305.html))
69
+
70
+ ## Use case
71
+
72
+ This library exists to allow connecting with
73
+ [Happy Eyeballs](https://en.wikipedia.org/wiki/Happy_Eyeballs)
74
+ ([RFC 8305](https://www.rfc-editor.org/rfc/rfc8305.html))
75
+ when you
76
+ already have a list of addrinfo and not a DNS name.
77
+
78
+ The stdlib version of `loop.create_connection()`
79
+ will only work when you pass in an unresolved name which
80
+ is not a good fit when using DNS caching or resolving
81
+ names via another method such as `zeroconf`.
82
+
83
+ ## Installation
84
+
85
+ Install this via pip (or your favourite package manager):
86
+
87
+ `pip install aiohappyeyeballs`
88
+
89
+ ## License
90
+
91
+ [aiohappyeyeballs is licensed under the same terms as cpython itself.](https://github.com/python/cpython/blob/main/LICENSE)
92
+
93
+ ## Example usage
94
+
95
+ ```python
96
+
97
+ addr_infos = await loop.getaddrinfo("example.org", 80)
98
+
99
+ socket = await start_connection(addr_infos)
100
+ socket = await start_connection(addr_infos, local_addr_infos=local_addr_infos, happy_eyeballs_delay=0.2)
101
+
102
+ transport, protocol = await loop.create_connection(
103
+ MyProtocol, sock=socket, ...)
104
+
105
+ # Remove the first address for each family from addr_info
106
+ pop_addr_infos_interleave(addr_info, 1)
107
+
108
+ # Remove all matching address from addr_info
109
+ remove_addr_infos(addr_info, "dead::beef::")
110
+
111
+ # Convert a local_addr to local_addr_infos
112
+ local_addr_infos = addr_to_addr_infos(("127.0.0.1",0))
113
+ ```
114
+
115
+ ## Credits
116
+
117
+ This package contains code from cpython and is licensed under the same terms as cpython itself.
118
+
119
+ This package was created with
120
+ [Copier](https://copier.readthedocs.io/) and the
121
+ [browniebroke/pypackage-template](https://github.com/browniebroke/pypackage-template)
122
+ project template.
123
+
py311/lib/python3.11/site-packages/aiohappyeyeballs-2.6.1.dist-info/RECORD ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ aiohappyeyeballs-2.6.1.dist-info/INSTALLER,sha256=5hhM4Q4mYTT9z6QB6PGpUAW81PGNFrYrdXMj4oM_6ak,2
2
+ aiohappyeyeballs-2.6.1.dist-info/LICENSE,sha256=Oy-B_iHRgcSZxZolbI4ZaEVdZonSaaqFNzv7avQdo78,13936
3
+ aiohappyeyeballs-2.6.1.dist-info/METADATA,sha256=NSXlhJwAfi380eEjAo7BQ4P_TVal9xi0qkyZWibMsVM,5915
4
+ aiohappyeyeballs-2.6.1.dist-info/RECORD,,
5
+ aiohappyeyeballs-2.6.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ aiohappyeyeballs-2.6.1.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
7
+ aiohappyeyeballs/__init__.py,sha256=x7kktHEtaD9quBcWDJPuLeKyjuVAI-Jj14S9B_5hcTs,361
8
+ aiohappyeyeballs/_staggered.py,sha256=edfVowFx-P-ywJjIEF3MdPtEMVODujV6CeMYr65otac,6900
9
+ aiohappyeyeballs/impl.py,sha256=Dlcm2mTJ28ucrGnxkb_fo9CZzLAkOOBizOt7dreBbXE,9681
10
+ aiohappyeyeballs/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
+ aiohappyeyeballs/types.py,sha256=YZJIAnyoV4Dz0WFtlaf_OyE4EW7Xus1z7aIfNI6tDDQ,425
12
+ aiohappyeyeballs/utils.py,sha256=on9GxIR0LhEfZu8P6Twi9hepX9zDanuZM20MWsb3xlQ,3028
py311/lib/python3.11/site-packages/aiohappyeyeballs-2.6.1.dist-info/REQUESTED ADDED
File without changes
py311/lib/python3.11/site-packages/aiohappyeyeballs-2.6.1.dist-info/WHEEL ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ Wheel-Version: 1.0
2
+ Generator: poetry-core 2.1.1
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
py311/lib/python3.11/site-packages/attr/__init__.py ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: MIT
2
+
3
+ """
4
+ Classes Without Boilerplate
5
+ """
6
+
7
+ from functools import partial
8
+ from typing import Callable, Literal, Protocol
9
+
10
+ from . import converters, exceptions, filters, setters, validators
11
+ from ._cmp import cmp_using
12
+ from ._config import get_run_validators, set_run_validators
13
+ from ._funcs import asdict, assoc, astuple, has, resolve_types
14
+ from ._make import (
15
+ NOTHING,
16
+ Attribute,
17
+ Converter,
18
+ Factory,
19
+ _Nothing,
20
+ attrib,
21
+ attrs,
22
+ evolve,
23
+ fields,
24
+ fields_dict,
25
+ make_class,
26
+ validate,
27
+ )
28
+ from ._next_gen import define, field, frozen, mutable
29
+ from ._version_info import VersionInfo
30
+
31
+
32
+ s = attributes = attrs
33
+ ib = attr = attrib
34
+ dataclass = partial(attrs, auto_attribs=True) # happy Easter ;)
35
+
36
+
37
+ class AttrsInstance(Protocol):
38
+ pass
39
+
40
+
41
+ NothingType = Literal[_Nothing.NOTHING]
42
+
43
+ __all__ = [
44
+ "NOTHING",
45
+ "Attribute",
46
+ "AttrsInstance",
47
+ "Converter",
48
+ "Factory",
49
+ "NothingType",
50
+ "asdict",
51
+ "assoc",
52
+ "astuple",
53
+ "attr",
54
+ "attrib",
55
+ "attributes",
56
+ "attrs",
57
+ "cmp_using",
58
+ "converters",
59
+ "define",
60
+ "evolve",
61
+ "exceptions",
62
+ "field",
63
+ "fields",
64
+ "fields_dict",
65
+ "filters",
66
+ "frozen",
67
+ "get_run_validators",
68
+ "has",
69
+ "ib",
70
+ "make_class",
71
+ "mutable",
72
+ "resolve_types",
73
+ "s",
74
+ "set_run_validators",
75
+ "setters",
76
+ "validate",
77
+ "validators",
78
+ ]
79
+
80
+
81
+ def _make_getattr(mod_name: str) -> Callable:
82
+ """
83
+ Create a metadata proxy for packaging information that uses *mod_name* in
84
+ its warnings and errors.
85
+ """
86
+
87
+ def __getattr__(name: str) -> str:
88
+ if name not in ("__version__", "__version_info__"):
89
+ msg = f"module {mod_name} has no attribute {name}"
90
+ raise AttributeError(msg)
91
+
92
+ from importlib.metadata import metadata
93
+
94
+ meta = metadata("attrs")
95
+
96
+ if name == "__version_info__":
97
+ return VersionInfo._from_version_string(meta["version"])
98
+
99
+ return meta["version"]
100
+
101
+ return __getattr__
102
+
103
+
104
+ __getattr__ = _make_getattr(__name__)
py311/lib/python3.11/site-packages/attr/__init__.pyi ADDED
@@ -0,0 +1,389 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import enum
2
+ import sys
3
+
4
+ from typing import (
5
+ Any,
6
+ Callable,
7
+ Generic,
8
+ Literal,
9
+ Mapping,
10
+ Protocol,
11
+ Sequence,
12
+ TypeVar,
13
+ overload,
14
+ )
15
+
16
+ # `import X as X` is required to make these public
17
+ from . import converters as converters
18
+ from . import exceptions as exceptions
19
+ from . import filters as filters
20
+ from . import setters as setters
21
+ from . import validators as validators
22
+ from ._cmp import cmp_using as cmp_using
23
+ from ._typing_compat import AttrsInstance_
24
+ from ._version_info import VersionInfo
25
+ from attrs import (
26
+ define as define,
27
+ field as field,
28
+ mutable as mutable,
29
+ frozen as frozen,
30
+ _EqOrderType,
31
+ _ValidatorType,
32
+ _ConverterType,
33
+ _ReprArgType,
34
+ _OnSetAttrType,
35
+ _OnSetAttrArgType,
36
+ _FieldTransformer,
37
+ _ValidatorArgType,
38
+ )
39
+
40
+ if sys.version_info >= (3, 10):
41
+ from typing import TypeGuard, TypeAlias
42
+ else:
43
+ from typing_extensions import TypeGuard, TypeAlias
44
+
45
+ if sys.version_info >= (3, 11):
46
+ from typing import dataclass_transform
47
+ else:
48
+ from typing_extensions import dataclass_transform
49
+
50
+ __version__: str
51
+ __version_info__: VersionInfo
52
+ __title__: str
53
+ __description__: str
54
+ __url__: str
55
+ __uri__: str
56
+ __author__: str
57
+ __email__: str
58
+ __license__: str
59
+ __copyright__: str
60
+
61
+ _T = TypeVar("_T")
62
+ _C = TypeVar("_C", bound=type)
63
+
64
+ _FilterType = Callable[["Attribute[_T]", _T], bool]
65
+
66
+ # We subclass this here to keep the protocol's qualified name clean.
67
+ class AttrsInstance(AttrsInstance_, Protocol):
68
+ pass
69
+
70
+ _A = TypeVar("_A", bound=type[AttrsInstance])
71
+
72
+ class _Nothing(enum.Enum):
73
+ NOTHING = enum.auto()
74
+
75
+ NOTHING = _Nothing.NOTHING
76
+ NothingType: TypeAlias = Literal[_Nothing.NOTHING]
77
+
78
+ # NOTE: Factory lies about its return type to make this possible:
79
+ # `x: List[int] # = Factory(list)`
80
+ # Work around mypy issue #4554 in the common case by using an overload.
81
+
82
+ @overload
83
+ def Factory(factory: Callable[[], _T]) -> _T: ...
84
+ @overload
85
+ def Factory(
86
+ factory: Callable[[Any], _T],
87
+ takes_self: Literal[True],
88
+ ) -> _T: ...
89
+ @overload
90
+ def Factory(
91
+ factory: Callable[[], _T],
92
+ takes_self: Literal[False],
93
+ ) -> _T: ...
94
+
95
+ In = TypeVar("In")
96
+ Out = TypeVar("Out")
97
+
98
+ class Converter(Generic[In, Out]):
99
+ @overload
100
+ def __init__(self, converter: Callable[[In], Out]) -> None: ...
101
+ @overload
102
+ def __init__(
103
+ self,
104
+ converter: Callable[[In, AttrsInstance, Attribute], Out],
105
+ *,
106
+ takes_self: Literal[True],
107
+ takes_field: Literal[True],
108
+ ) -> None: ...
109
+ @overload
110
+ def __init__(
111
+ self,
112
+ converter: Callable[[In, Attribute], Out],
113
+ *,
114
+ takes_field: Literal[True],
115
+ ) -> None: ...
116
+ @overload
117
+ def __init__(
118
+ self,
119
+ converter: Callable[[In, AttrsInstance], Out],
120
+ *,
121
+ takes_self: Literal[True],
122
+ ) -> None: ...
123
+
124
+ class Attribute(Generic[_T]):
125
+ name: str
126
+ default: _T | None
127
+ validator: _ValidatorType[_T] | None
128
+ repr: _ReprArgType
129
+ cmp: _EqOrderType
130
+ eq: _EqOrderType
131
+ order: _EqOrderType
132
+ hash: bool | None
133
+ init: bool
134
+ converter: Converter | None
135
+ metadata: dict[Any, Any]
136
+ type: type[_T] | None
137
+ kw_only: bool
138
+ on_setattr: _OnSetAttrType
139
+ alias: str | None
140
+
141
+ def evolve(self, **changes: Any) -> "Attribute[Any]": ...
142
+
143
+ # NOTE: We had several choices for the annotation to use for type arg:
144
+ # 1) Type[_T]
145
+ # - Pros: Handles simple cases correctly
146
+ # - Cons: Might produce less informative errors in the case of conflicting
147
+ # TypeVars e.g. `attr.ib(default='bad', type=int)`
148
+ # 2) Callable[..., _T]
149
+ # - Pros: Better error messages than #1 for conflicting TypeVars
150
+ # - Cons: Terrible error messages for validator checks.
151
+ # e.g. attr.ib(type=int, validator=validate_str)
152
+ # -> error: Cannot infer function type argument
153
+ # 3) type (and do all of the work in the mypy plugin)
154
+ # - Pros: Simple here, and we could customize the plugin with our own errors.
155
+ # - Cons: Would need to write mypy plugin code to handle all the cases.
156
+ # We chose option #1.
157
+
158
+ # `attr` lies about its return type to make the following possible:
159
+ # attr() -> Any
160
+ # attr(8) -> int
161
+ # attr(validator=<some callable>) -> Whatever the callable expects.
162
+ # This makes this type of assignments possible:
163
+ # x: int = attr(8)
164
+ #
165
+ # This form catches explicit None or no default but with no other arguments
166
+ # returns Any.
167
+ @overload
168
+ def attrib(
169
+ default: None = ...,
170
+ validator: None = ...,
171
+ repr: _ReprArgType = ...,
172
+ cmp: _EqOrderType | None = ...,
173
+ hash: bool | None = ...,
174
+ init: bool = ...,
175
+ metadata: Mapping[Any, Any] | None = ...,
176
+ type: None = ...,
177
+ converter: None = ...,
178
+ factory: None = ...,
179
+ kw_only: bool | None = ...,
180
+ eq: _EqOrderType | None = ...,
181
+ order: _EqOrderType | None = ...,
182
+ on_setattr: _OnSetAttrArgType | None = ...,
183
+ alias: str | None = ...,
184
+ ) -> Any: ...
185
+
186
+ # This form catches an explicit None or no default and infers the type from the
187
+ # other arguments.
188
+ @overload
189
+ def attrib(
190
+ default: None = ...,
191
+ validator: _ValidatorArgType[_T] | None = ...,
192
+ repr: _ReprArgType = ...,
193
+ cmp: _EqOrderType | None = ...,
194
+ hash: bool | None = ...,
195
+ init: bool = ...,
196
+ metadata: Mapping[Any, Any] | None = ...,
197
+ type: type[_T] | None = ...,
198
+ converter: _ConverterType
199
+ | list[_ConverterType]
200
+ | tuple[_ConverterType]
201
+ | None = ...,
202
+ factory: Callable[[], _T] | None = ...,
203
+ kw_only: bool | None = ...,
204
+ eq: _EqOrderType | None = ...,
205
+ order: _EqOrderType | None = ...,
206
+ on_setattr: _OnSetAttrArgType | None = ...,
207
+ alias: str | None = ...,
208
+ ) -> _T: ...
209
+
210
+ # This form catches an explicit default argument.
211
+ @overload
212
+ def attrib(
213
+ default: _T,
214
+ validator: _ValidatorArgType[_T] | None = ...,
215
+ repr: _ReprArgType = ...,
216
+ cmp: _EqOrderType | None = ...,
217
+ hash: bool | None = ...,
218
+ init: bool = ...,
219
+ metadata: Mapping[Any, Any] | None = ...,
220
+ type: type[_T] | None = ...,
221
+ converter: _ConverterType
222
+ | list[_ConverterType]
223
+ | tuple[_ConverterType]
224
+ | None = ...,
225
+ factory: Callable[[], _T] | None = ...,
226
+ kw_only: bool | None = ...,
227
+ eq: _EqOrderType | None = ...,
228
+ order: _EqOrderType | None = ...,
229
+ on_setattr: _OnSetAttrArgType | None = ...,
230
+ alias: str | None = ...,
231
+ ) -> _T: ...
232
+
233
+ # This form covers type=non-Type: e.g. forward references (str), Any
234
+ @overload
235
+ def attrib(
236
+ default: _T | None = ...,
237
+ validator: _ValidatorArgType[_T] | None = ...,
238
+ repr: _ReprArgType = ...,
239
+ cmp: _EqOrderType | None = ...,
240
+ hash: bool | None = ...,
241
+ init: bool = ...,
242
+ metadata: Mapping[Any, Any] | None = ...,
243
+ type: object = ...,
244
+ converter: _ConverterType
245
+ | list[_ConverterType]
246
+ | tuple[_ConverterType]
247
+ | None = ...,
248
+ factory: Callable[[], _T] | None = ...,
249
+ kw_only: bool | None = ...,
250
+ eq: _EqOrderType | None = ...,
251
+ order: _EqOrderType | None = ...,
252
+ on_setattr: _OnSetAttrArgType | None = ...,
253
+ alias: str | None = ...,
254
+ ) -> Any: ...
255
+ @overload
256
+ @dataclass_transform(order_default=True, field_specifiers=(attrib, field))
257
+ def attrs(
258
+ maybe_cls: _C,
259
+ these: dict[str, Any] | None = ...,
260
+ repr_ns: str | None = ...,
261
+ repr: bool = ...,
262
+ cmp: _EqOrderType | None = ...,
263
+ hash: bool | None = ...,
264
+ init: bool = ...,
265
+ slots: bool = ...,
266
+ frozen: bool = ...,
267
+ weakref_slot: bool = ...,
268
+ str: bool = ...,
269
+ auto_attribs: bool = ...,
270
+ kw_only: bool = ...,
271
+ cache_hash: bool = ...,
272
+ auto_exc: bool = ...,
273
+ eq: _EqOrderType | None = ...,
274
+ order: _EqOrderType | None = ...,
275
+ auto_detect: bool = ...,
276
+ collect_by_mro: bool = ...,
277
+ getstate_setstate: bool | None = ...,
278
+ on_setattr: _OnSetAttrArgType | None = ...,
279
+ field_transformer: _FieldTransformer | None = ...,
280
+ match_args: bool = ...,
281
+ unsafe_hash: bool | None = ...,
282
+ ) -> _C: ...
283
+ @overload
284
+ @dataclass_transform(order_default=True, field_specifiers=(attrib, field))
285
+ def attrs(
286
+ maybe_cls: None = ...,
287
+ these: dict[str, Any] | None = ...,
288
+ repr_ns: str | None = ...,
289
+ repr: bool = ...,
290
+ cmp: _EqOrderType | None = ...,
291
+ hash: bool | None = ...,
292
+ init: bool = ...,
293
+ slots: bool = ...,
294
+ frozen: bool = ...,
295
+ weakref_slot: bool = ...,
296
+ str: bool = ...,
297
+ auto_attribs: bool = ...,
298
+ kw_only: bool = ...,
299
+ cache_hash: bool = ...,
300
+ auto_exc: bool = ...,
301
+ eq: _EqOrderType | None = ...,
302
+ order: _EqOrderType | None = ...,
303
+ auto_detect: bool = ...,
304
+ collect_by_mro: bool = ...,
305
+ getstate_setstate: bool | None = ...,
306
+ on_setattr: _OnSetAttrArgType | None = ...,
307
+ field_transformer: _FieldTransformer | None = ...,
308
+ match_args: bool = ...,
309
+ unsafe_hash: bool | None = ...,
310
+ ) -> Callable[[_C], _C]: ...
311
+ def fields(cls: type[AttrsInstance]) -> Any: ...
312
+ def fields_dict(cls: type[AttrsInstance]) -> dict[str, Attribute[Any]]: ...
313
+ def validate(inst: AttrsInstance) -> None: ...
314
+ def resolve_types(
315
+ cls: _A,
316
+ globalns: dict[str, Any] | None = ...,
317
+ localns: dict[str, Any] | None = ...,
318
+ attribs: list[Attribute[Any]] | None = ...,
319
+ include_extras: bool = ...,
320
+ ) -> _A: ...
321
+
322
+ # TODO: add support for returning a proper attrs class from the mypy plugin
323
+ # we use Any instead of _CountingAttr so that e.g. `make_class('Foo',
324
+ # [attr.ib()])` is valid
325
+ def make_class(
326
+ name: str,
327
+ attrs: list[str] | tuple[str, ...] | dict[str, Any],
328
+ bases: tuple[type, ...] = ...,
329
+ class_body: dict[str, Any] | None = ...,
330
+ repr_ns: str | None = ...,
331
+ repr: bool = ...,
332
+ cmp: _EqOrderType | None = ...,
333
+ hash: bool | None = ...,
334
+ init: bool = ...,
335
+ slots: bool = ...,
336
+ frozen: bool = ...,
337
+ weakref_slot: bool = ...,
338
+ str: bool = ...,
339
+ auto_attribs: bool = ...,
340
+ kw_only: bool = ...,
341
+ cache_hash: bool = ...,
342
+ auto_exc: bool = ...,
343
+ eq: _EqOrderType | None = ...,
344
+ order: _EqOrderType | None = ...,
345
+ collect_by_mro: bool = ...,
346
+ on_setattr: _OnSetAttrArgType | None = ...,
347
+ field_transformer: _FieldTransformer | None = ...,
348
+ ) -> type: ...
349
+
350
+ # _funcs --
351
+
352
+ # TODO: add support for returning TypedDict from the mypy plugin
353
+ # FIXME: asdict/astuple do not honor their factory args. Waiting on one of
354
+ # these:
355
+ # https://github.com/python/mypy/issues/4236
356
+ # https://github.com/python/typing/issues/253
357
+ # XXX: remember to fix attrs.asdict/astuple too!
358
+ def asdict(
359
+ inst: AttrsInstance,
360
+ recurse: bool = ...,
361
+ filter: _FilterType[Any] | None = ...,
362
+ dict_factory: type[Mapping[Any, Any]] = ...,
363
+ retain_collection_types: bool = ...,
364
+ value_serializer: Callable[[type, Attribute[Any], Any], Any] | None = ...,
365
+ tuple_keys: bool | None = ...,
366
+ ) -> dict[str, Any]: ...
367
+
368
+ # TODO: add support for returning NamedTuple from the mypy plugin
369
+ def astuple(
370
+ inst: AttrsInstance,
371
+ recurse: bool = ...,
372
+ filter: _FilterType[Any] | None = ...,
373
+ tuple_factory: type[Sequence[Any]] = ...,
374
+ retain_collection_types: bool = ...,
375
+ ) -> tuple[Any, ...]: ...
376
+ def has(cls: type) -> TypeGuard[type[AttrsInstance]]: ...
377
+ def assoc(inst: _T, **changes: Any) -> _T: ...
378
+ def evolve(inst: _T, **changes: Any) -> _T: ...
379
+
380
+ # _config --
381
+
382
+ def set_run_validators(run: bool) -> None: ...
383
+ def get_run_validators() -> bool: ...
384
+
385
+ # aliases --
386
+
387
+ s = attributes = attrs
388
+ ib = attr = attrib
389
+ dataclass = attrs # Technically, partial(attrs, auto_attribs=True) ;)
py311/lib/python3.11/site-packages/attr/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (3.12 kB). View file
 
py311/lib/python3.11/site-packages/attr/__pycache__/_cmp.cpython-311.pyc ADDED
Binary file (5.37 kB). View file
 
py311/lib/python3.11/site-packages/attr/__pycache__/_compat.cpython-311.pyc ADDED
Binary file (3.74 kB). View file
 
py311/lib/python3.11/site-packages/attr/__pycache__/_config.cpython-311.pyc ADDED
Binary file (1.18 kB). View file
 
py311/lib/python3.11/site-packages/attr/__pycache__/_funcs.cpython-311.pyc ADDED
Binary file (15.8 kB). View file
 
py311/lib/python3.11/site-packages/attr/__pycache__/_next_gen.cpython-311.pyc ADDED
Binary file (27 kB). View file
 
py311/lib/python3.11/site-packages/attr/__pycache__/_version_info.cpython-311.pyc ADDED
Binary file (3.9 kB). View file
 
py311/lib/python3.11/site-packages/attr/__pycache__/converters.cpython-311.pyc ADDED
Binary file (5.04 kB). View file
 
py311/lib/python3.11/site-packages/attr/__pycache__/exceptions.cpython-311.pyc ADDED
Binary file (4.16 kB). View file
 
py311/lib/python3.11/site-packages/attr/__pycache__/filters.cpython-311.pyc ADDED
Binary file (3.19 kB). View file
 
py311/lib/python3.11/site-packages/attr/__pycache__/setters.cpython-311.pyc ADDED
Binary file (2.08 kB). View file
 
py311/lib/python3.11/site-packages/attr/__pycache__/validators.cpython-311.pyc ADDED
Binary file (29.9 kB). View file
 
py311/lib/python3.11/site-packages/attr/_cmp.py ADDED
@@ -0,0 +1,160 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: MIT
2
+
3
+
4
+ import functools
5
+ import types
6
+
7
+ from ._make import __ne__
8
+
9
+
10
+ _operation_names = {"eq": "==", "lt": "<", "le": "<=", "gt": ">", "ge": ">="}
11
+
12
+
13
+ def cmp_using(
14
+ eq=None,
15
+ lt=None,
16
+ le=None,
17
+ gt=None,
18
+ ge=None,
19
+ require_same_type=True,
20
+ class_name="Comparable",
21
+ ):
22
+ """
23
+ Create a class that can be passed into `attrs.field`'s ``eq``, ``order``,
24
+ and ``cmp`` arguments to customize field comparison.
25
+
26
+ The resulting class will have a full set of ordering methods if at least
27
+ one of ``{lt, le, gt, ge}`` and ``eq`` are provided.
28
+
29
+ Args:
30
+ eq (typing.Callable | None):
31
+ Callable used to evaluate equality of two objects.
32
+
33
+ lt (typing.Callable | None):
34
+ Callable used to evaluate whether one object is less than another
35
+ object.
36
+
37
+ le (typing.Callable | None):
38
+ Callable used to evaluate whether one object is less than or equal
39
+ to another object.
40
+
41
+ gt (typing.Callable | None):
42
+ Callable used to evaluate whether one object is greater than
43
+ another object.
44
+
45
+ ge (typing.Callable | None):
46
+ Callable used to evaluate whether one object is greater than or
47
+ equal to another object.
48
+
49
+ require_same_type (bool):
50
+ When `True`, equality and ordering methods will return
51
+ `NotImplemented` if objects are not of the same type.
52
+
53
+ class_name (str | None): Name of class. Defaults to "Comparable".
54
+
55
+ See `comparison` for more details.
56
+
57
+ .. versionadded:: 21.1.0
58
+ """
59
+
60
+ body = {
61
+ "__slots__": ["value"],
62
+ "__init__": _make_init(),
63
+ "_requirements": [],
64
+ "_is_comparable_to": _is_comparable_to,
65
+ }
66
+
67
+ # Add operations.
68
+ num_order_functions = 0
69
+ has_eq_function = False
70
+
71
+ if eq is not None:
72
+ has_eq_function = True
73
+ body["__eq__"] = _make_operator("eq", eq)
74
+ body["__ne__"] = __ne__
75
+
76
+ if lt is not None:
77
+ num_order_functions += 1
78
+ body["__lt__"] = _make_operator("lt", lt)
79
+
80
+ if le is not None:
81
+ num_order_functions += 1
82
+ body["__le__"] = _make_operator("le", le)
83
+
84
+ if gt is not None:
85
+ num_order_functions += 1
86
+ body["__gt__"] = _make_operator("gt", gt)
87
+
88
+ if ge is not None:
89
+ num_order_functions += 1
90
+ body["__ge__"] = _make_operator("ge", ge)
91
+
92
+ type_ = types.new_class(
93
+ class_name, (object,), {}, lambda ns: ns.update(body)
94
+ )
95
+
96
+ # Add same type requirement.
97
+ if require_same_type:
98
+ type_._requirements.append(_check_same_type)
99
+
100
+ # Add total ordering if at least one operation was defined.
101
+ if 0 < num_order_functions < 4:
102
+ if not has_eq_function:
103
+ # functools.total_ordering requires __eq__ to be defined,
104
+ # so raise early error here to keep a nice stack.
105
+ msg = "eq must be define is order to complete ordering from lt, le, gt, ge."
106
+ raise ValueError(msg)
107
+ type_ = functools.total_ordering(type_)
108
+
109
+ return type_
110
+
111
+
112
+ def _make_init():
113
+ """
114
+ Create __init__ method.
115
+ """
116
+
117
+ def __init__(self, value):
118
+ """
119
+ Initialize object with *value*.
120
+ """
121
+ self.value = value
122
+
123
+ return __init__
124
+
125
+
126
+ def _make_operator(name, func):
127
+ """
128
+ Create operator method.
129
+ """
130
+
131
+ def method(self, other):
132
+ if not self._is_comparable_to(other):
133
+ return NotImplemented
134
+
135
+ result = func(self.value, other.value)
136
+ if result is NotImplemented:
137
+ return NotImplemented
138
+
139
+ return result
140
+
141
+ method.__name__ = f"__{name}__"
142
+ method.__doc__ = (
143
+ f"Return a {_operation_names[name]} b. Computed by attrs."
144
+ )
145
+
146
+ return method
147
+
148
+
149
+ def _is_comparable_to(self, other):
150
+ """
151
+ Check whether `other` is comparable to `self`.
152
+ """
153
+ return all(func(self, other) for func in self._requirements)
154
+
155
+
156
+ def _check_same_type(self, other):
157
+ """
158
+ Return True if *self* and *other* are of the same type, False otherwise.
159
+ """
160
+ return other.value.__class__ is self.value.__class__
py311/lib/python3.11/site-packages/attr/_cmp.pyi ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Any, Callable
2
+
3
+ _CompareWithType = Callable[[Any, Any], bool]
4
+
5
+ def cmp_using(
6
+ eq: _CompareWithType | None = ...,
7
+ lt: _CompareWithType | None = ...,
8
+ le: _CompareWithType | None = ...,
9
+ gt: _CompareWithType | None = ...,
10
+ ge: _CompareWithType | None = ...,
11
+ require_same_type: bool = ...,
12
+ class_name: str = ...,
13
+ ) -> type: ...
py311/lib/python3.11/site-packages/attr/_compat.py ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: MIT
2
+
3
+ import inspect
4
+ import platform
5
+ import sys
6
+ import threading
7
+
8
+ from collections.abc import Mapping, Sequence # noqa: F401
9
+ from typing import _GenericAlias
10
+
11
+
12
+ PYPY = platform.python_implementation() == "PyPy"
13
+ PY_3_10_PLUS = sys.version_info[:2] >= (3, 10)
14
+ PY_3_11_PLUS = sys.version_info[:2] >= (3, 11)
15
+ PY_3_12_PLUS = sys.version_info[:2] >= (3, 12)
16
+ PY_3_13_PLUS = sys.version_info[:2] >= (3, 13)
17
+ PY_3_14_PLUS = sys.version_info[:2] >= (3, 14)
18
+
19
+
20
+ if PY_3_14_PLUS:
21
+ import annotationlib
22
+
23
+ # We request forward-ref annotations to not break in the presence of
24
+ # forward references.
25
+
26
+ def _get_annotations(cls):
27
+ return annotationlib.get_annotations(
28
+ cls, format=annotationlib.Format.FORWARDREF
29
+ )
30
+
31
+ else:
32
+
33
+ def _get_annotations(cls):
34
+ """
35
+ Get annotations for *cls*.
36
+ """
37
+ return cls.__dict__.get("__annotations__", {})
38
+
39
+
40
+ class _AnnotationExtractor:
41
+ """
42
+ Extract type annotations from a callable, returning None whenever there
43
+ is none.
44
+ """
45
+
46
+ __slots__ = ["sig"]
47
+
48
+ def __init__(self, callable):
49
+ try:
50
+ self.sig = inspect.signature(callable)
51
+ except (ValueError, TypeError): # inspect failed
52
+ self.sig = None
53
+
54
+ def get_first_param_type(self):
55
+ """
56
+ Return the type annotation of the first argument if it's not empty.
57
+ """
58
+ if not self.sig:
59
+ return None
60
+
61
+ params = list(self.sig.parameters.values())
62
+ if params and params[0].annotation is not inspect.Parameter.empty:
63
+ return params[0].annotation
64
+
65
+ return None
66
+
67
+ def get_return_type(self):
68
+ """
69
+ Return the return type if it's not empty.
70
+ """
71
+ if (
72
+ self.sig
73
+ and self.sig.return_annotation is not inspect.Signature.empty
74
+ ):
75
+ return self.sig.return_annotation
76
+
77
+ return None
78
+
79
+
80
+ # Thread-local global to track attrs instances which are already being repr'd.
81
+ # This is needed because there is no other (thread-safe) way to pass info
82
+ # about the instances that are already being repr'd through the call stack
83
+ # in order to ensure we don't perform infinite recursion.
84
+ #
85
+ # For instance, if an instance contains a dict which contains that instance,
86
+ # we need to know that we're already repr'ing the outside instance from within
87
+ # the dict's repr() call.
88
+ #
89
+ # This lives here rather than in _make.py so that the functions in _make.py
90
+ # don't have a direct reference to the thread-local in their globals dict.
91
+ # If they have such a reference, it breaks cloudpickle.
92
+ repr_context = threading.local()
93
+
94
+
95
+ def get_generic_base(cl):
96
+ """If this is a generic class (A[str]), return the generic base for it."""
97
+ if cl.__class__ is _GenericAlias:
98
+ return cl.__origin__
99
+ return None
py311/lib/python3.11/site-packages/attr/_config.py ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: MIT
2
+
3
+ __all__ = ["get_run_validators", "set_run_validators"]
4
+
5
+ _run_validators = True
6
+
7
+
8
+ def set_run_validators(run):
9
+ """
10
+ Set whether or not validators are run. By default, they are run.
11
+
12
+ .. deprecated:: 21.3.0 It will not be removed, but it also will not be
13
+ moved to new ``attrs`` namespace. Use `attrs.validators.set_disabled()`
14
+ instead.
15
+ """
16
+ if not isinstance(run, bool):
17
+ msg = "'run' must be bool."
18
+ raise TypeError(msg)
19
+ global _run_validators
20
+ _run_validators = run
21
+
22
+
23
+ def get_run_validators():
24
+ """
25
+ Return whether or not validators are run.
26
+
27
+ .. deprecated:: 21.3.0 It will not be removed, but it also will not be
28
+ moved to new ``attrs`` namespace. Use `attrs.validators.get_disabled()`
29
+ instead.
30
+ """
31
+ return _run_validators
py311/lib/python3.11/site-packages/attr/_funcs.py ADDED
@@ -0,0 +1,497 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: MIT
2
+
3
+
4
+ import copy
5
+
6
+ from ._compat import get_generic_base
7
+ from ._make import _OBJ_SETATTR, NOTHING, fields
8
+ from .exceptions import AttrsAttributeNotFoundError
9
+
10
+
11
+ _ATOMIC_TYPES = frozenset(
12
+ {
13
+ type(None),
14
+ bool,
15
+ int,
16
+ float,
17
+ str,
18
+ complex,
19
+ bytes,
20
+ type(...),
21
+ type,
22
+ range,
23
+ property,
24
+ }
25
+ )
26
+
27
+
28
+ def asdict(
29
+ inst,
30
+ recurse=True,
31
+ filter=None,
32
+ dict_factory=dict,
33
+ retain_collection_types=False,
34
+ value_serializer=None,
35
+ ):
36
+ """
37
+ Return the *attrs* attribute values of *inst* as a dict.
38
+
39
+ Optionally recurse into other *attrs*-decorated classes.
40
+
41
+ Args:
42
+ inst: Instance of an *attrs*-decorated class.
43
+
44
+ recurse (bool): Recurse into classes that are also *attrs*-decorated.
45
+
46
+ filter (~typing.Callable):
47
+ A callable whose return code determines whether an attribute or
48
+ element is included (`True`) or dropped (`False`). Is called with
49
+ the `attrs.Attribute` as the first argument and the value as the
50
+ second argument.
51
+
52
+ dict_factory (~typing.Callable):
53
+ A callable to produce dictionaries from. For example, to produce
54
+ ordered dictionaries instead of normal Python dictionaries, pass in
55
+ ``collections.OrderedDict``.
56
+
57
+ retain_collection_types (bool):
58
+ Do not convert to `list` when encountering an attribute whose type
59
+ is `tuple` or `set`. Only meaningful if *recurse* is `True`.
60
+
61
+ value_serializer (typing.Callable | None):
62
+ A hook that is called for every attribute or dict key/value. It
63
+ receives the current instance, field and value and must return the
64
+ (updated) value. The hook is run *after* the optional *filter* has
65
+ been applied.
66
+
67
+ Returns:
68
+ Return type of *dict_factory*.
69
+
70
+ Raises:
71
+ attrs.exceptions.NotAnAttrsClassError:
72
+ If *cls* is not an *attrs* class.
73
+
74
+ .. versionadded:: 16.0.0 *dict_factory*
75
+ .. versionadded:: 16.1.0 *retain_collection_types*
76
+ .. versionadded:: 20.3.0 *value_serializer*
77
+ .. versionadded:: 21.3.0
78
+ If a dict has a collection for a key, it is serialized as a tuple.
79
+ """
80
+ attrs = fields(inst.__class__)
81
+ rv = dict_factory()
82
+ for a in attrs:
83
+ v = getattr(inst, a.name)
84
+ if filter is not None and not filter(a, v):
85
+ continue
86
+
87
+ if value_serializer is not None:
88
+ v = value_serializer(inst, a, v)
89
+
90
+ if recurse is True:
91
+ value_type = type(v)
92
+ if value_type in _ATOMIC_TYPES:
93
+ rv[a.name] = v
94
+ elif has(value_type):
95
+ rv[a.name] = asdict(
96
+ v,
97
+ recurse=True,
98
+ filter=filter,
99
+ dict_factory=dict_factory,
100
+ retain_collection_types=retain_collection_types,
101
+ value_serializer=value_serializer,
102
+ )
103
+ elif issubclass(value_type, (tuple, list, set, frozenset)):
104
+ cf = value_type if retain_collection_types is True else list
105
+ items = [
106
+ _asdict_anything(
107
+ i,
108
+ is_key=False,
109
+ filter=filter,
110
+ dict_factory=dict_factory,
111
+ retain_collection_types=retain_collection_types,
112
+ value_serializer=value_serializer,
113
+ )
114
+ for i in v
115
+ ]
116
+ try:
117
+ rv[a.name] = cf(items)
118
+ except TypeError:
119
+ if not issubclass(cf, tuple):
120
+ raise
121
+ # Workaround for TypeError: cf.__new__() missing 1 required
122
+ # positional argument (which appears, for a namedturle)
123
+ rv[a.name] = cf(*items)
124
+ elif issubclass(value_type, dict):
125
+ df = dict_factory
126
+ rv[a.name] = df(
127
+ (
128
+ _asdict_anything(
129
+ kk,
130
+ is_key=True,
131
+ filter=filter,
132
+ dict_factory=df,
133
+ retain_collection_types=retain_collection_types,
134
+ value_serializer=value_serializer,
135
+ ),
136
+ _asdict_anything(
137
+ vv,
138
+ is_key=False,
139
+ filter=filter,
140
+ dict_factory=df,
141
+ retain_collection_types=retain_collection_types,
142
+ value_serializer=value_serializer,
143
+ ),
144
+ )
145
+ for kk, vv in v.items()
146
+ )
147
+ else:
148
+ rv[a.name] = v
149
+ else:
150
+ rv[a.name] = v
151
+ return rv
152
+
153
+
154
+ def _asdict_anything(
155
+ val,
156
+ is_key,
157
+ filter,
158
+ dict_factory,
159
+ retain_collection_types,
160
+ value_serializer,
161
+ ):
162
+ """
163
+ ``asdict`` only works on attrs instances, this works on anything.
164
+ """
165
+ val_type = type(val)
166
+ if val_type in _ATOMIC_TYPES:
167
+ rv = val
168
+ if value_serializer is not None:
169
+ rv = value_serializer(None, None, rv)
170
+ elif getattr(val_type, "__attrs_attrs__", None) is not None:
171
+ # Attrs class.
172
+ rv = asdict(
173
+ val,
174
+ recurse=True,
175
+ filter=filter,
176
+ dict_factory=dict_factory,
177
+ retain_collection_types=retain_collection_types,
178
+ value_serializer=value_serializer,
179
+ )
180
+ elif issubclass(val_type, (tuple, list, set, frozenset)):
181
+ if retain_collection_types is True:
182
+ cf = val.__class__
183
+ elif is_key:
184
+ cf = tuple
185
+ else:
186
+ cf = list
187
+
188
+ rv = cf(
189
+ [
190
+ _asdict_anything(
191
+ i,
192
+ is_key=False,
193
+ filter=filter,
194
+ dict_factory=dict_factory,
195
+ retain_collection_types=retain_collection_types,
196
+ value_serializer=value_serializer,
197
+ )
198
+ for i in val
199
+ ]
200
+ )
201
+ elif issubclass(val_type, dict):
202
+ df = dict_factory
203
+ rv = df(
204
+ (
205
+ _asdict_anything(
206
+ kk,
207
+ is_key=True,
208
+ filter=filter,
209
+ dict_factory=df,
210
+ retain_collection_types=retain_collection_types,
211
+ value_serializer=value_serializer,
212
+ ),
213
+ _asdict_anything(
214
+ vv,
215
+ is_key=False,
216
+ filter=filter,
217
+ dict_factory=df,
218
+ retain_collection_types=retain_collection_types,
219
+ value_serializer=value_serializer,
220
+ ),
221
+ )
222
+ for kk, vv in val.items()
223
+ )
224
+ else:
225
+ rv = val
226
+ if value_serializer is not None:
227
+ rv = value_serializer(None, None, rv)
228
+
229
+ return rv
230
+
231
+
232
+ def astuple(
233
+ inst,
234
+ recurse=True,
235
+ filter=None,
236
+ tuple_factory=tuple,
237
+ retain_collection_types=False,
238
+ ):
239
+ """
240
+ Return the *attrs* attribute values of *inst* as a tuple.
241
+
242
+ Optionally recurse into other *attrs*-decorated classes.
243
+
244
+ Args:
245
+ inst: Instance of an *attrs*-decorated class.
246
+
247
+ recurse (bool):
248
+ Recurse into classes that are also *attrs*-decorated.
249
+
250
+ filter (~typing.Callable):
251
+ A callable whose return code determines whether an attribute or
252
+ element is included (`True`) or dropped (`False`). Is called with
253
+ the `attrs.Attribute` as the first argument and the value as the
254
+ second argument.
255
+
256
+ tuple_factory (~typing.Callable):
257
+ A callable to produce tuples from. For example, to produce lists
258
+ instead of tuples.
259
+
260
+ retain_collection_types (bool):
261
+ Do not convert to `list` or `dict` when encountering an attribute
262
+ which type is `tuple`, `dict` or `set`. Only meaningful if
263
+ *recurse* is `True`.
264
+
265
+ Returns:
266
+ Return type of *tuple_factory*
267
+
268
+ Raises:
269
+ attrs.exceptions.NotAnAttrsClassError:
270
+ If *cls* is not an *attrs* class.
271
+
272
+ .. versionadded:: 16.2.0
273
+ """
274
+ attrs = fields(inst.__class__)
275
+ rv = []
276
+ retain = retain_collection_types # Very long. :/
277
+ for a in attrs:
278
+ v = getattr(inst, a.name)
279
+ if filter is not None and not filter(a, v):
280
+ continue
281
+ value_type = type(v)
282
+ if recurse is True:
283
+ if value_type in _ATOMIC_TYPES:
284
+ rv.append(v)
285
+ elif has(value_type):
286
+ rv.append(
287
+ astuple(
288
+ v,
289
+ recurse=True,
290
+ filter=filter,
291
+ tuple_factory=tuple_factory,
292
+ retain_collection_types=retain,
293
+ )
294
+ )
295
+ elif issubclass(value_type, (tuple, list, set, frozenset)):
296
+ cf = v.__class__ if retain is True else list
297
+ items = [
298
+ (
299
+ astuple(
300
+ j,
301
+ recurse=True,
302
+ filter=filter,
303
+ tuple_factory=tuple_factory,
304
+ retain_collection_types=retain,
305
+ )
306
+ if has(j.__class__)
307
+ else j
308
+ )
309
+ for j in v
310
+ ]
311
+ try:
312
+ rv.append(cf(items))
313
+ except TypeError:
314
+ if not issubclass(cf, tuple):
315
+ raise
316
+ # Workaround for TypeError: cf.__new__() missing 1 required
317
+ # positional argument (which appears, for a namedturle)
318
+ rv.append(cf(*items))
319
+ elif issubclass(value_type, dict):
320
+ df = value_type if retain is True else dict
321
+ rv.append(
322
+ df(
323
+ (
324
+ (
325
+ astuple(
326
+ kk,
327
+ tuple_factory=tuple_factory,
328
+ retain_collection_types=retain,
329
+ )
330
+ if has(kk.__class__)
331
+ else kk
332
+ ),
333
+ (
334
+ astuple(
335
+ vv,
336
+ tuple_factory=tuple_factory,
337
+ retain_collection_types=retain,
338
+ )
339
+ if has(vv.__class__)
340
+ else vv
341
+ ),
342
+ )
343
+ for kk, vv in v.items()
344
+ )
345
+ )
346
+ else:
347
+ rv.append(v)
348
+ else:
349
+ rv.append(v)
350
+
351
+ return rv if tuple_factory is list else tuple_factory(rv)
352
+
353
+
354
+ def has(cls):
355
+ """
356
+ Check whether *cls* is a class with *attrs* attributes.
357
+
358
+ Args:
359
+ cls (type): Class to introspect.
360
+
361
+ Raises:
362
+ TypeError: If *cls* is not a class.
363
+
364
+ Returns:
365
+ bool:
366
+ """
367
+ attrs = getattr(cls, "__attrs_attrs__", None)
368
+ if attrs is not None:
369
+ return True
370
+
371
+ # No attrs, maybe it's a specialized generic (A[str])?
372
+ generic_base = get_generic_base(cls)
373
+ if generic_base is not None:
374
+ generic_attrs = getattr(generic_base, "__attrs_attrs__", None)
375
+ if generic_attrs is not None:
376
+ # Stick it on here for speed next time.
377
+ cls.__attrs_attrs__ = generic_attrs
378
+ return generic_attrs is not None
379
+ return False
380
+
381
+
382
+ def assoc(inst, **changes):
383
+ """
384
+ Copy *inst* and apply *changes*.
385
+
386
+ This is different from `evolve` that applies the changes to the arguments
387
+ that create the new instance.
388
+
389
+ `evolve`'s behavior is preferable, but there are `edge cases`_ where it
390
+ doesn't work. Therefore `assoc` is deprecated, but will not be removed.
391
+
392
+ .. _`edge cases`: https://github.com/python-attrs/attrs/issues/251
393
+
394
+ Args:
395
+ inst: Instance of a class with *attrs* attributes.
396
+
397
+ changes: Keyword changes in the new copy.
398
+
399
+ Returns:
400
+ A copy of inst with *changes* incorporated.
401
+
402
+ Raises:
403
+ attrs.exceptions.AttrsAttributeNotFoundError:
404
+ If *attr_name* couldn't be found on *cls*.
405
+
406
+ attrs.exceptions.NotAnAttrsClassError:
407
+ If *cls* is not an *attrs* class.
408
+
409
+ .. deprecated:: 17.1.0
410
+ Use `attrs.evolve` instead if you can. This function will not be
411
+ removed du to the slightly different approach compared to
412
+ `attrs.evolve`, though.
413
+ """
414
+ new = copy.copy(inst)
415
+ attrs = fields(inst.__class__)
416
+ for k, v in changes.items():
417
+ a = getattr(attrs, k, NOTHING)
418
+ if a is NOTHING:
419
+ msg = f"{k} is not an attrs attribute on {new.__class__}."
420
+ raise AttrsAttributeNotFoundError(msg)
421
+ _OBJ_SETATTR(new, k, v)
422
+ return new
423
+
424
+
425
+ def resolve_types(
426
+ cls, globalns=None, localns=None, attribs=None, include_extras=True
427
+ ):
428
+ """
429
+ Resolve any strings and forward annotations in type annotations.
430
+
431
+ This is only required if you need concrete types in :class:`Attribute`'s
432
+ *type* field. In other words, you don't need to resolve your types if you
433
+ only use them for static type checking.
434
+
435
+ With no arguments, names will be looked up in the module in which the class
436
+ was created. If this is not what you want, for example, if the name only
437
+ exists inside a method, you may pass *globalns* or *localns* to specify
438
+ other dictionaries in which to look up these names. See the docs of
439
+ `typing.get_type_hints` for more details.
440
+
441
+ Args:
442
+ cls (type): Class to resolve.
443
+
444
+ globalns (dict | None): Dictionary containing global variables.
445
+
446
+ localns (dict | None): Dictionary containing local variables.
447
+
448
+ attribs (list | None):
449
+ List of attribs for the given class. This is necessary when calling
450
+ from inside a ``field_transformer`` since *cls* is not an *attrs*
451
+ class yet.
452
+
453
+ include_extras (bool):
454
+ Resolve more accurately, if possible. Pass ``include_extras`` to
455
+ ``typing.get_hints``, if supported by the typing module. On
456
+ supported Python versions (3.9+), this resolves the types more
457
+ accurately.
458
+
459
+ Raises:
460
+ TypeError: If *cls* is not a class.
461
+
462
+ attrs.exceptions.NotAnAttrsClassError:
463
+ If *cls* is not an *attrs* class and you didn't pass any attribs.
464
+
465
+ NameError: If types cannot be resolved because of missing variables.
466
+
467
+ Returns:
468
+ *cls* so you can use this function also as a class decorator. Please
469
+ note that you have to apply it **after** `attrs.define`. That means the
470
+ decorator has to come in the line **before** `attrs.define`.
471
+
472
+ .. versionadded:: 20.1.0
473
+ .. versionadded:: 21.1.0 *attribs*
474
+ .. versionadded:: 23.1.0 *include_extras*
475
+ """
476
+ # Since calling get_type_hints is expensive we cache whether we've
477
+ # done it already.
478
+ if getattr(cls, "__attrs_types_resolved__", None) != cls:
479
+ import typing
480
+
481
+ kwargs = {
482
+ "globalns": globalns,
483
+ "localns": localns,
484
+ "include_extras": include_extras,
485
+ }
486
+
487
+ hints = typing.get_type_hints(cls, **kwargs)
488
+ for field in fields(cls) if attribs is None else attribs:
489
+ if field.name in hints:
490
+ # Since fields have been frozen we must work around it.
491
+ _OBJ_SETATTR(field, "type", hints[field.name])
492
+ # We store the class we resolved so that subclasses know they haven't
493
+ # been resolved.
494
+ cls.__attrs_types_resolved__ = cls
495
+
496
+ # Return the class so you can use it as a decorator too.
497
+ return cls
py311/lib/python3.11/site-packages/attr/_make.py ADDED
The diff for this file is too large to render. See raw diff
 
py311/lib/python3.11/site-packages/attr/_next_gen.py ADDED
@@ -0,0 +1,674 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: MIT
2
+
3
+ """
4
+ These are keyword-only APIs that call `attr.s` and `attr.ib` with different
5
+ default values.
6
+ """
7
+
8
+ from functools import partial
9
+
10
+ from . import setters
11
+ from ._funcs import asdict as _asdict
12
+ from ._funcs import astuple as _astuple
13
+ from ._make import (
14
+ _DEFAULT_ON_SETATTR,
15
+ NOTHING,
16
+ _frozen_setattrs,
17
+ attrib,
18
+ attrs,
19
+ )
20
+ from .exceptions import NotAnAttrsClassError, UnannotatedAttributeError
21
+
22
+
23
+ def define(
24
+ maybe_cls=None,
25
+ *,
26
+ these=None,
27
+ repr=None,
28
+ unsafe_hash=None,
29
+ hash=None,
30
+ init=None,
31
+ slots=True,
32
+ frozen=False,
33
+ weakref_slot=True,
34
+ str=False,
35
+ auto_attribs=None,
36
+ kw_only=False,
37
+ cache_hash=False,
38
+ auto_exc=True,
39
+ eq=None,
40
+ order=False,
41
+ auto_detect=True,
42
+ getstate_setstate=None,
43
+ on_setattr=None,
44
+ field_transformer=None,
45
+ match_args=True,
46
+ force_kw_only=False,
47
+ ):
48
+ r"""
49
+ A class decorator that adds :term:`dunder methods` according to
50
+ :term:`fields <field>` specified using :doc:`type annotations <types>`,
51
+ `field()` calls, or the *these* argument.
52
+
53
+ Since *attrs* patches or replaces an existing class, you cannot use
54
+ `object.__init_subclass__` with *attrs* classes, because it runs too early.
55
+ As a replacement, you can define ``__attrs_init_subclass__`` on your class.
56
+ It will be called by *attrs* classes that subclass it after they're
57
+ created. See also :ref:`init-subclass`.
58
+
59
+ Args:
60
+ slots (bool):
61
+ Create a :term:`slotted class <slotted classes>` that's more
62
+ memory-efficient. Slotted classes are generally superior to the
63
+ default dict classes, but have some gotchas you should know about,
64
+ so we encourage you to read the :term:`glossary entry <slotted
65
+ classes>`.
66
+
67
+ auto_detect (bool):
68
+ Instead of setting the *init*, *repr*, *eq*, and *hash* arguments
69
+ explicitly, assume they are set to True **unless any** of the
70
+ involved methods for one of the arguments is implemented in the
71
+ *current* class (meaning, it is *not* inherited from some base
72
+ class).
73
+
74
+ So, for example by implementing ``__eq__`` on a class yourself,
75
+ *attrs* will deduce ``eq=False`` and will create *neither*
76
+ ``__eq__`` *nor* ``__ne__`` (but Python classes come with a
77
+ sensible ``__ne__`` by default, so it *should* be enough to only
78
+ implement ``__eq__`` in most cases).
79
+
80
+ Passing :data:`True` or :data:`False` to *init*, *repr*, *eq*, or *hash*
81
+ overrides whatever *auto_detect* would determine.
82
+
83
+ auto_exc (bool):
84
+ If the class subclasses `BaseException` (which implicitly includes
85
+ any subclass of any exception), the following happens to behave
86
+ like a well-behaved Python exception class:
87
+
88
+ - the values for *eq*, *order*, and *hash* are ignored and the
89
+ instances compare and hash by the instance's ids [#]_ ,
90
+ - all attributes that are either passed into ``__init__`` or have a
91
+ default value are additionally available as a tuple in the
92
+ ``args`` attribute,
93
+ - the value of *str* is ignored leaving ``__str__`` to base
94
+ classes.
95
+
96
+ .. [#]
97
+ Note that *attrs* will *not* remove existing implementations of
98
+ ``__hash__`` or the equality methods. It just won't add own
99
+ ones.
100
+
101
+ on_setattr (~typing.Callable | list[~typing.Callable] | None | ~typing.Literal[attrs.setters.NO_OP]):
102
+ A callable that is run whenever the user attempts to set an
103
+ attribute (either by assignment like ``i.x = 42`` or by using
104
+ `setattr` like ``setattr(i, "x", 42)``). It receives the same
105
+ arguments as validators: the instance, the attribute that is being
106
+ modified, and the new value.
107
+
108
+ If no exception is raised, the attribute is set to the return value
109
+ of the callable.
110
+
111
+ If a list of callables is passed, they're automatically wrapped in
112
+ an `attrs.setters.pipe`.
113
+
114
+ If left None, the default behavior is to run converters and
115
+ validators whenever an attribute is set.
116
+
117
+ init (bool):
118
+ Create a ``__init__`` method that initializes the *attrs*
119
+ attributes. Leading underscores are stripped for the argument name,
120
+ unless an alias is set on the attribute.
121
+
122
+ .. seealso::
123
+ `init` shows advanced ways to customize the generated
124
+ ``__init__`` method, including executing code before and after.
125
+
126
+ repr(bool):
127
+ Create a ``__repr__`` method with a human readable representation
128
+ of *attrs* attributes.
129
+
130
+ str (bool):
131
+ Create a ``__str__`` method that is identical to ``__repr__``. This
132
+ is usually not necessary except for `Exception`\ s.
133
+
134
+ eq (bool | None):
135
+ If True or None (default), add ``__eq__`` and ``__ne__`` methods
136
+ that check two instances for equality.
137
+
138
+ .. seealso::
139
+ `comparison` describes how to customize the comparison behavior
140
+ going as far comparing NumPy arrays.
141
+
142
+ order (bool | None):
143
+ If True, add ``__lt__``, ``__le__``, ``__gt__``, and ``__ge__``
144
+ methods that behave like *eq* above and allow instances to be
145
+ ordered.
146
+
147
+ They compare the instances as if they were tuples of their *attrs*
148
+ attributes if and only if the types of both classes are
149
+ *identical*.
150
+
151
+ If `None` mirror value of *eq*.
152
+
153
+ .. seealso:: `comparison`
154
+
155
+ unsafe_hash (bool | None):
156
+ If None (default), the ``__hash__`` method is generated according
157
+ how *eq* and *frozen* are set.
158
+
159
+ 1. If *both* are True, *attrs* will generate a ``__hash__`` for
160
+ you.
161
+ 2. If *eq* is True and *frozen* is False, ``__hash__`` will be set
162
+ to None, marking it unhashable (which it is).
163
+ 3. If *eq* is False, ``__hash__`` will be left untouched meaning
164
+ the ``__hash__`` method of the base class will be used. If the
165
+ base class is `object`, this means it will fall back to id-based
166
+ hashing.
167
+
168
+ Although not recommended, you can decide for yourself and force
169
+ *attrs* to create one (for example, if the class is immutable even
170
+ though you didn't freeze it programmatically) by passing True or
171
+ not. Both of these cases are rather special and should be used
172
+ carefully.
173
+
174
+ .. seealso::
175
+
176
+ - Our documentation on `hashing`,
177
+ - Python's documentation on `object.__hash__`,
178
+ - and the `GitHub issue that led to the default \ behavior
179
+ <https://github.com/python-attrs/attrs/issues/136>`_ for more
180
+ details.
181
+
182
+ hash (bool | None):
183
+ Deprecated alias for *unsafe_hash*. *unsafe_hash* takes precedence.
184
+
185
+ cache_hash (bool):
186
+ Ensure that the object's hash code is computed only once and stored
187
+ on the object. If this is set to True, hashing must be either
188
+ explicitly or implicitly enabled for this class. If the hash code
189
+ is cached, avoid any reassignments of fields involved in hash code
190
+ computation or mutations of the objects those fields point to after
191
+ object creation. If such changes occur, the behavior of the
192
+ object's hash code is undefined.
193
+
194
+ frozen (bool):
195
+ Make instances immutable after initialization. If someone attempts
196
+ to modify a frozen instance, `attrs.exceptions.FrozenInstanceError`
197
+ is raised.
198
+
199
+ .. note::
200
+
201
+ 1. This is achieved by installing a custom ``__setattr__``
202
+ method on your class, so you can't implement your own.
203
+
204
+ 2. True immutability is impossible in Python.
205
+
206
+ 3. This *does* have a minor a runtime performance `impact
207
+ <how-frozen>` when initializing new instances. In other
208
+ words: ``__init__`` is slightly slower with ``frozen=True``.
209
+
210
+ 4. If a class is frozen, you cannot modify ``self`` in
211
+ ``__attrs_post_init__`` or a self-written ``__init__``. You
212
+ can circumvent that limitation by using
213
+ ``object.__setattr__(self, "attribute_name", value)``.
214
+
215
+ 5. Subclasses of a frozen class are frozen too.
216
+
217
+ kw_only (bool):
218
+ Make attributes keyword-only in the generated ``__init__`` (if
219
+ *init* is False, this parameter is ignored). Attributes that
220
+ explicitly set ``kw_only=False`` are not affected; base class
221
+ attributes are also not affected.
222
+
223
+ Also see *force_kw_only*.
224
+
225
+ weakref_slot (bool):
226
+ Make instances weak-referenceable. This has no effect unless
227
+ *slots* is True.
228
+
229
+ field_transformer (~typing.Callable | None):
230
+ A function that is called with the original class object and all
231
+ fields right before *attrs* finalizes the class. You can use this,
232
+ for example, to automatically add converters or validators to
233
+ fields based on their types.
234
+
235
+ .. seealso:: `transform-fields`
236
+
237
+ match_args (bool):
238
+ If True (default), set ``__match_args__`` on the class to support
239
+ :pep:`634` (*Structural Pattern Matching*). It is a tuple of all
240
+ non-keyword-only ``__init__`` parameter names on Python 3.10 and
241
+ later. Ignored on older Python versions.
242
+
243
+ collect_by_mro (bool):
244
+ If True, *attrs* collects attributes from base classes correctly
245
+ according to the `method resolution order
246
+ <https://docs.python.org/3/howto/mro.html>`_. If False, *attrs*
247
+ will mimic the (wrong) behavior of `dataclasses` and :pep:`681`.
248
+
249
+ See also `issue #428
250
+ <https://github.com/python-attrs/attrs/issues/428>`_.
251
+
252
+ force_kw_only (bool):
253
+ A back-compat flag for restoring pre-25.4.0 behavior. If True and
254
+ ``kw_only=True``, all attributes are made keyword-only, including
255
+ base class attributes, and those set to ``kw_only=False`` at the
256
+ attribute level. Defaults to False.
257
+
258
+ See also `issue #980
259
+ <https://github.com/python-attrs/attrs/issues/980>`_.
260
+
261
+ getstate_setstate (bool | None):
262
+ .. note::
263
+
264
+ This is usually only interesting for slotted classes and you
265
+ should probably just set *auto_detect* to True.
266
+
267
+ If True, ``__getstate__`` and ``__setstate__`` are generated and
268
+ attached to the class. This is necessary for slotted classes to be
269
+ pickleable. If left None, it's True by default for slotted classes
270
+ and False for dict classes.
271
+
272
+ If *auto_detect* is True, and *getstate_setstate* is left None, and
273
+ **either** ``__getstate__`` or ``__setstate__`` is detected
274
+ directly on the class (meaning: not inherited), it is set to False
275
+ (this is usually what you want).
276
+
277
+ auto_attribs (bool | None):
278
+ If True, look at type annotations to determine which attributes to
279
+ use, like `dataclasses`. If False, it will only look for explicit
280
+ :func:`field` class attributes, like classic *attrs*.
281
+
282
+ If left None, it will guess:
283
+
284
+ 1. If any attributes are annotated and no unannotated
285
+ `attrs.field`\ s are found, it assumes *auto_attribs=True*.
286
+ 2. Otherwise it assumes *auto_attribs=False* and tries to collect
287
+ `attrs.field`\ s.
288
+
289
+ If *attrs* decides to look at type annotations, **all** fields
290
+ **must** be annotated. If *attrs* encounters a field that is set to
291
+ a :func:`field` / `attr.ib` but lacks a type annotation, an
292
+ `attrs.exceptions.UnannotatedAttributeError` is raised. Use
293
+ ``field_name: typing.Any = field(...)`` if you don't want to set a
294
+ type.
295
+
296
+ .. warning::
297
+
298
+ For features that use the attribute name to create decorators
299
+ (for example, :ref:`validators <validators>`), you still *must*
300
+ assign :func:`field` / `attr.ib` to them. Otherwise Python will
301
+ either not find the name or try to use the default value to
302
+ call, for example, ``validator`` on it.
303
+
304
+ Attributes annotated as `typing.ClassVar`, and attributes that are
305
+ neither annotated nor set to an `field()` are **ignored**.
306
+
307
+ these (dict[str, object]):
308
+ A dictionary of name to the (private) return value of `field()`
309
+ mappings. This is useful to avoid the definition of your attributes
310
+ within the class body because you can't (for example, if you want
311
+ to add ``__repr__`` methods to Django models) or don't want to.
312
+
313
+ If *these* is not `None`, *attrs* will *not* search the class body
314
+ for attributes and will *not* remove any attributes from it.
315
+
316
+ The order is deduced from the order of the attributes inside
317
+ *these*.
318
+
319
+ Arguably, this is a rather obscure feature.
320
+
321
+ .. versionadded:: 20.1.0
322
+ .. versionchanged:: 21.3.0 Converters are also run ``on_setattr``.
323
+ .. versionadded:: 22.2.0
324
+ *unsafe_hash* as an alias for *hash* (for :pep:`681` compliance).
325
+ .. versionchanged:: 24.1.0
326
+ Instances are not compared as tuples of attributes anymore, but using a
327
+ big ``and`` condition. This is faster and has more correct behavior for
328
+ uncomparable values like `math.nan`.
329
+ .. versionadded:: 24.1.0
330
+ If a class has an *inherited* classmethod called
331
+ ``__attrs_init_subclass__``, it is executed after the class is created.
332
+ .. deprecated:: 24.1.0 *hash* is deprecated in favor of *unsafe_hash*.
333
+ .. versionadded:: 24.3.0
334
+ Unless already present, a ``__replace__`` method is automatically
335
+ created for `copy.replace` (Python 3.13+ only).
336
+ .. versionchanged:: 25.4.0
337
+ *kw_only* now only applies to attributes defined in the current class,
338
+ and respects attribute-level ``kw_only=False`` settings.
339
+ .. versionadded:: 25.4.0
340
+ Added *force_kw_only* to go back to the previous *kw_only* behavior.
341
+
342
+ .. note::
343
+
344
+ The main differences to the classic `attr.s` are:
345
+
346
+ - Automatically detect whether or not *auto_attribs* should be `True`
347
+ (c.f. *auto_attribs* parameter).
348
+ - Converters and validators run when attributes are set by default --
349
+ if *frozen* is `False`.
350
+ - *slots=True*
351
+
352
+ Usually, this has only upsides and few visible effects in everyday
353
+ programming. But it *can* lead to some surprising behaviors, so
354
+ please make sure to read :term:`slotted classes`.
355
+
356
+ - *auto_exc=True*
357
+ - *auto_detect=True*
358
+ - *order=False*
359
+ - *force_kw_only=False*
360
+ - Some options that were only relevant on Python 2 or were kept around
361
+ for backwards-compatibility have been removed.
362
+
363
+ """
364
+
365
+ def do_it(cls, auto_attribs):
366
+ return attrs(
367
+ maybe_cls=cls,
368
+ these=these,
369
+ repr=repr,
370
+ hash=hash,
371
+ unsafe_hash=unsafe_hash,
372
+ init=init,
373
+ slots=slots,
374
+ frozen=frozen,
375
+ weakref_slot=weakref_slot,
376
+ str=str,
377
+ auto_attribs=auto_attribs,
378
+ kw_only=kw_only,
379
+ cache_hash=cache_hash,
380
+ auto_exc=auto_exc,
381
+ eq=eq,
382
+ order=order,
383
+ auto_detect=auto_detect,
384
+ collect_by_mro=True,
385
+ getstate_setstate=getstate_setstate,
386
+ on_setattr=on_setattr,
387
+ field_transformer=field_transformer,
388
+ match_args=match_args,
389
+ force_kw_only=force_kw_only,
390
+ )
391
+
392
+ def wrap(cls):
393
+ """
394
+ Making this a wrapper ensures this code runs during class creation.
395
+
396
+ We also ensure that frozen-ness of classes is inherited.
397
+ """
398
+ nonlocal frozen, on_setattr
399
+
400
+ had_on_setattr = on_setattr not in (None, setters.NO_OP)
401
+
402
+ # By default, mutable classes convert & validate on setattr.
403
+ if frozen is False and on_setattr is None:
404
+ on_setattr = _DEFAULT_ON_SETATTR
405
+
406
+ # However, if we subclass a frozen class, we inherit the immutability
407
+ # and disable on_setattr.
408
+ for base_cls in cls.__bases__:
409
+ if base_cls.__setattr__ is _frozen_setattrs:
410
+ if had_on_setattr:
411
+ msg = "Frozen classes can't use on_setattr (frozen-ness was inherited)."
412
+ raise ValueError(msg)
413
+
414
+ on_setattr = setters.NO_OP
415
+ break
416
+
417
+ if auto_attribs is not None:
418
+ return do_it(cls, auto_attribs)
419
+
420
+ try:
421
+ return do_it(cls, True)
422
+ except UnannotatedAttributeError:
423
+ return do_it(cls, False)
424
+
425
+ # maybe_cls's type depends on the usage of the decorator. It's a class
426
+ # if it's used as `@attrs` but `None` if used as `@attrs()`.
427
+ if maybe_cls is None:
428
+ return wrap
429
+
430
+ return wrap(maybe_cls)
431
+
432
+
433
+ mutable = define
434
+ frozen = partial(define, frozen=True, on_setattr=None)
435
+
436
+
437
+ def field(
438
+ *,
439
+ default=NOTHING,
440
+ validator=None,
441
+ repr=True,
442
+ hash=None,
443
+ init=True,
444
+ metadata=None,
445
+ type=None,
446
+ converter=None,
447
+ factory=None,
448
+ kw_only=None,
449
+ eq=None,
450
+ order=None,
451
+ on_setattr=None,
452
+ alias=None,
453
+ ):
454
+ """
455
+ Create a new :term:`field` / :term:`attribute` on a class.
456
+
457
+ .. warning::
458
+
459
+ Does **nothing** unless the class is also decorated with
460
+ `attrs.define` (or similar)!
461
+
462
+ Args:
463
+ default:
464
+ A value that is used if an *attrs*-generated ``__init__`` is used
465
+ and no value is passed while instantiating or the attribute is
466
+ excluded using ``init=False``.
467
+
468
+ If the value is an instance of `attrs.Factory`, its callable will
469
+ be used to construct a new value (useful for mutable data types
470
+ like lists or dicts).
471
+
472
+ If a default is not set (or set manually to `attrs.NOTHING`), a
473
+ value *must* be supplied when instantiating; otherwise a
474
+ `TypeError` will be raised.
475
+
476
+ .. seealso:: `defaults`
477
+
478
+ factory (~typing.Callable):
479
+ Syntactic sugar for ``default=attr.Factory(factory)``.
480
+
481
+ validator (~typing.Callable | list[~typing.Callable]):
482
+ Callable that is called by *attrs*-generated ``__init__`` methods
483
+ after the instance has been initialized. They receive the
484
+ initialized instance, the :func:`~attrs.Attribute`, and the passed
485
+ value.
486
+
487
+ The return value is *not* inspected so the validator has to throw
488
+ an exception itself.
489
+
490
+ If a `list` is passed, its items are treated as validators and must
491
+ all pass.
492
+
493
+ Validators can be globally disabled and re-enabled using
494
+ `attrs.validators.get_disabled` / `attrs.validators.set_disabled`.
495
+
496
+ The validator can also be set using decorator notation as shown
497
+ below.
498
+
499
+ .. seealso:: :ref:`validators`
500
+
501
+ repr (bool | ~typing.Callable):
502
+ Include this attribute in the generated ``__repr__`` method. If
503
+ True, include the attribute; if False, omit it. By default, the
504
+ built-in ``repr()`` function is used. To override how the attribute
505
+ value is formatted, pass a ``callable`` that takes a single value
506
+ and returns a string. Note that the resulting string is used as-is,
507
+ which means it will be used directly *instead* of calling
508
+ ``repr()`` (the default).
509
+
510
+ eq (bool | ~typing.Callable):
511
+ If True (default), include this attribute in the generated
512
+ ``__eq__`` and ``__ne__`` methods that check two instances for
513
+ equality. To override how the attribute value is compared, pass a
514
+ callable that takes a single value and returns the value to be
515
+ compared.
516
+
517
+ .. seealso:: `comparison`
518
+
519
+ order (bool | ~typing.Callable):
520
+ If True (default), include this attributes in the generated
521
+ ``__lt__``, ``__le__``, ``__gt__`` and ``__ge__`` methods. To
522
+ override how the attribute value is ordered, pass a callable that
523
+ takes a single value and returns the value to be ordered.
524
+
525
+ .. seealso:: `comparison`
526
+
527
+ hash (bool | None):
528
+ Include this attribute in the generated ``__hash__`` method. If
529
+ None (default), mirror *eq*'s value. This is the correct behavior
530
+ according the Python spec. Setting this value to anything else
531
+ than None is *discouraged*.
532
+
533
+ .. seealso:: `hashing`
534
+
535
+ init (bool):
536
+ Include this attribute in the generated ``__init__`` method.
537
+
538
+ It is possible to set this to False and set a default value. In
539
+ that case this attributed is unconditionally initialized with the
540
+ specified default value or factory.
541
+
542
+ .. seealso:: `init`
543
+
544
+ converter (typing.Callable | Converter):
545
+ A callable that is called by *attrs*-generated ``__init__`` methods
546
+ to convert attribute's value to the desired format.
547
+
548
+ If a vanilla callable is passed, it is given the passed-in value as
549
+ the only positional argument. It is possible to receive additional
550
+ arguments by wrapping the callable in a `Converter`.
551
+
552
+ Either way, the returned value will be used as the new value of the
553
+ attribute. The value is converted before being passed to the
554
+ validator, if any.
555
+
556
+ .. seealso:: :ref:`converters`
557
+
558
+ metadata (dict | None):
559
+ An arbitrary mapping, to be used by third-party code.
560
+
561
+ .. seealso:: `extending-metadata`.
562
+
563
+ type (type):
564
+ The type of the attribute. Nowadays, the preferred method to
565
+ specify the type is using a variable annotation (see :pep:`526`).
566
+ This argument is provided for backwards-compatibility and for usage
567
+ with `make_class`. Regardless of the approach used, the type will
568
+ be stored on ``Attribute.type``.
569
+
570
+ Please note that *attrs* doesn't do anything with this metadata by
571
+ itself. You can use it as part of your own code or for `static type
572
+ checking <types>`.
573
+
574
+ kw_only (bool | None):
575
+ Make this attribute keyword-only in the generated ``__init__`` (if
576
+ *init* is False, this parameter is ignored). If None (default),
577
+ mirror the setting from `attrs.define`.
578
+
579
+ on_setattr (~typing.Callable | list[~typing.Callable] | None | ~typing.Literal[attrs.setters.NO_OP]):
580
+ Allows to overwrite the *on_setattr* setting from `attr.s`. If left
581
+ None, the *on_setattr* value from `attr.s` is used. Set to
582
+ `attrs.setters.NO_OP` to run **no** `setattr` hooks for this
583
+ attribute -- regardless of the setting in `define()`.
584
+
585
+ alias (str | None):
586
+ Override this attribute's parameter name in the generated
587
+ ``__init__`` method. If left None, default to ``name`` stripped
588
+ of leading underscores. See `private-attributes`.
589
+
590
+ .. versionadded:: 20.1.0
591
+ .. versionchanged:: 21.1.0
592
+ *eq*, *order*, and *cmp* also accept a custom callable
593
+ .. versionadded:: 22.2.0 *alias*
594
+ .. versionadded:: 23.1.0
595
+ The *type* parameter has been re-added; mostly for `attrs.make_class`.
596
+ Please note that type checkers ignore this metadata.
597
+ .. versionchanged:: 25.4.0
598
+ *kw_only* can now be None, and its default is also changed from False to
599
+ None.
600
+
601
+ .. seealso::
602
+
603
+ `attr.ib`
604
+ """
605
+ return attrib(
606
+ default=default,
607
+ validator=validator,
608
+ repr=repr,
609
+ hash=hash,
610
+ init=init,
611
+ metadata=metadata,
612
+ type=type,
613
+ converter=converter,
614
+ factory=factory,
615
+ kw_only=kw_only,
616
+ eq=eq,
617
+ order=order,
618
+ on_setattr=on_setattr,
619
+ alias=alias,
620
+ )
621
+
622
+
623
+ def asdict(inst, *, recurse=True, filter=None, value_serializer=None):
624
+ """
625
+ Same as `attr.asdict`, except that collections types are always retained
626
+ and dict is always used as *dict_factory*.
627
+
628
+ .. versionadded:: 21.3.0
629
+ """
630
+ return _asdict(
631
+ inst=inst,
632
+ recurse=recurse,
633
+ filter=filter,
634
+ value_serializer=value_serializer,
635
+ retain_collection_types=True,
636
+ )
637
+
638
+
639
+ def astuple(inst, *, recurse=True, filter=None):
640
+ """
641
+ Same as `attr.astuple`, except that collections types are always retained
642
+ and `tuple` is always used as the *tuple_factory*.
643
+
644
+ .. versionadded:: 21.3.0
645
+ """
646
+ return _astuple(
647
+ inst=inst, recurse=recurse, filter=filter, retain_collection_types=True
648
+ )
649
+
650
+
651
+ def inspect(cls):
652
+ """
653
+ Inspect the class and return its effective build parameters.
654
+
655
+ Warning:
656
+ This feature is currently **experimental** and is not covered by our
657
+ strict backwards-compatibility guarantees.
658
+
659
+ Args:
660
+ cls: The *attrs*-decorated class to inspect.
661
+
662
+ Returns:
663
+ The effective build parameters of the class.
664
+
665
+ Raises:
666
+ NotAnAttrsClassError: If the class is not an *attrs*-decorated class.
667
+
668
+ .. versionadded:: 25.4.0
669
+ """
670
+ try:
671
+ return cls.__dict__["__attrs_props__"]
672
+ except KeyError:
673
+ msg = f"{cls!r} is not an attrs-decorated class."
674
+ raise NotAnAttrsClassError(msg) from None
py311/lib/python3.11/site-packages/attr/_typing_compat.pyi ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Any, ClassVar, Protocol
2
+
3
+ # MYPY is a special constant in mypy which works the same way as `TYPE_CHECKING`.
4
+ MYPY = False
5
+
6
+ if MYPY:
7
+ # A protocol to be able to statically accept an attrs class.
8
+ class AttrsInstance_(Protocol):
9
+ __attrs_attrs__: ClassVar[Any]
10
+
11
+ else:
12
+ # For type checkers without plug-in support use an empty protocol that
13
+ # will (hopefully) be combined into a union.
14
+ class AttrsInstance_(Protocol):
15
+ pass
py311/lib/python3.11/site-packages/attr/_version_info.py ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: MIT
2
+
3
+
4
+ from functools import total_ordering
5
+
6
+ from ._funcs import astuple
7
+ from ._make import attrib, attrs
8
+
9
+
10
+ @total_ordering
11
+ @attrs(eq=False, order=False, slots=True, frozen=True)
12
+ class VersionInfo:
13
+ """
14
+ A version object that can be compared to tuple of length 1--4:
15
+
16
+ >>> attr.VersionInfo(19, 1, 0, "final") <= (19, 2)
17
+ True
18
+ >>> attr.VersionInfo(19, 1, 0, "final") < (19, 1, 1)
19
+ True
20
+ >>> vi = attr.VersionInfo(19, 2, 0, "final")
21
+ >>> vi < (19, 1, 1)
22
+ False
23
+ >>> vi < (19,)
24
+ False
25
+ >>> vi == (19, 2,)
26
+ True
27
+ >>> vi == (19, 2, 1)
28
+ False
29
+
30
+ .. versionadded:: 19.2
31
+ """
32
+
33
+ year = attrib(type=int)
34
+ minor = attrib(type=int)
35
+ micro = attrib(type=int)
36
+ releaselevel = attrib(type=str)
37
+
38
+ @classmethod
39
+ def _from_version_string(cls, s):
40
+ """
41
+ Parse *s* and return a _VersionInfo.
42
+ """
43
+ v = s.split(".")
44
+ if len(v) == 3:
45
+ v.append("final")
46
+
47
+ return cls(
48
+ year=int(v[0]), minor=int(v[1]), micro=int(v[2]), releaselevel=v[3]
49
+ )
50
+
51
+ def _ensure_tuple(self, other):
52
+ """
53
+ Ensure *other* is a tuple of a valid length.
54
+
55
+ Returns a possibly transformed *other* and ourselves as a tuple of
56
+ the same length as *other*.
57
+ """
58
+
59
+ if self.__class__ is other.__class__:
60
+ other = astuple(other)
61
+
62
+ if not isinstance(other, tuple):
63
+ raise NotImplementedError
64
+
65
+ if not (1 <= len(other) <= 4):
66
+ raise NotImplementedError
67
+
68
+ return astuple(self)[: len(other)], other
69
+
70
+ def __eq__(self, other):
71
+ try:
72
+ us, them = self._ensure_tuple(other)
73
+ except NotImplementedError:
74
+ return NotImplemented
75
+
76
+ return us == them
77
+
78
+ def __lt__(self, other):
79
+ try:
80
+ us, them = self._ensure_tuple(other)
81
+ except NotImplementedError:
82
+ return NotImplemented
83
+
84
+ # Since alphabetically "dev0" < "final" < "post1" < "post2", we don't
85
+ # have to do anything special with releaselevel for now.
86
+ return us < them
87
+
88
+ def __hash__(self):
89
+ return hash((self.year, self.minor, self.micro, self.releaselevel))
py311/lib/python3.11/site-packages/attr/_version_info.pyi ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ class VersionInfo:
2
+ @property
3
+ def year(self) -> int: ...
4
+ @property
5
+ def minor(self) -> int: ...
6
+ @property
7
+ def micro(self) -> int: ...
8
+ @property
9
+ def releaselevel(self) -> str: ...
py311/lib/python3.11/site-packages/attr/converters.py ADDED
@@ -0,0 +1,162 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: MIT
2
+
3
+ """
4
+ Commonly useful converters.
5
+ """
6
+
7
+ import typing
8
+
9
+ from ._compat import _AnnotationExtractor
10
+ from ._make import NOTHING, Converter, Factory, pipe
11
+
12
+
13
+ __all__ = [
14
+ "default_if_none",
15
+ "optional",
16
+ "pipe",
17
+ "to_bool",
18
+ ]
19
+
20
+
21
+ def optional(converter):
22
+ """
23
+ A converter that allows an attribute to be optional. An optional attribute
24
+ is one which can be set to `None`.
25
+
26
+ Type annotations will be inferred from the wrapped converter's, if it has
27
+ any.
28
+
29
+ Args:
30
+ converter (typing.Callable):
31
+ the converter that is used for non-`None` values.
32
+
33
+ .. versionadded:: 17.1.0
34
+ """
35
+
36
+ if isinstance(converter, Converter):
37
+
38
+ def optional_converter(val, inst, field):
39
+ if val is None:
40
+ return None
41
+ return converter(val, inst, field)
42
+
43
+ else:
44
+
45
+ def optional_converter(val):
46
+ if val is None:
47
+ return None
48
+ return converter(val)
49
+
50
+ xtr = _AnnotationExtractor(converter)
51
+
52
+ t = xtr.get_first_param_type()
53
+ if t:
54
+ optional_converter.__annotations__["val"] = typing.Optional[t]
55
+
56
+ rt = xtr.get_return_type()
57
+ if rt:
58
+ optional_converter.__annotations__["return"] = typing.Optional[rt]
59
+
60
+ if isinstance(converter, Converter):
61
+ return Converter(optional_converter, takes_self=True, takes_field=True)
62
+
63
+ return optional_converter
64
+
65
+
66
+ def default_if_none(default=NOTHING, factory=None):
67
+ """
68
+ A converter that allows to replace `None` values by *default* or the result
69
+ of *factory*.
70
+
71
+ Args:
72
+ default:
73
+ Value to be used if `None` is passed. Passing an instance of
74
+ `attrs.Factory` is supported, however the ``takes_self`` option is
75
+ *not*.
76
+
77
+ factory (typing.Callable):
78
+ A callable that takes no parameters whose result is used if `None`
79
+ is passed.
80
+
81
+ Raises:
82
+ TypeError: If **neither** *default* or *factory* is passed.
83
+
84
+ TypeError: If **both** *default* and *factory* are passed.
85
+
86
+ ValueError:
87
+ If an instance of `attrs.Factory` is passed with
88
+ ``takes_self=True``.
89
+
90
+ .. versionadded:: 18.2.0
91
+ """
92
+ if default is NOTHING and factory is None:
93
+ msg = "Must pass either `default` or `factory`."
94
+ raise TypeError(msg)
95
+
96
+ if default is not NOTHING and factory is not None:
97
+ msg = "Must pass either `default` or `factory` but not both."
98
+ raise TypeError(msg)
99
+
100
+ if factory is not None:
101
+ default = Factory(factory)
102
+
103
+ if isinstance(default, Factory):
104
+ if default.takes_self:
105
+ msg = "`takes_self` is not supported by default_if_none."
106
+ raise ValueError(msg)
107
+
108
+ def default_if_none_converter(val):
109
+ if val is not None:
110
+ return val
111
+
112
+ return default.factory()
113
+
114
+ else:
115
+
116
+ def default_if_none_converter(val):
117
+ if val is not None:
118
+ return val
119
+
120
+ return default
121
+
122
+ return default_if_none_converter
123
+
124
+
125
+ def to_bool(val):
126
+ """
127
+ Convert "boolean" strings (for example, from environment variables) to real
128
+ booleans.
129
+
130
+ Values mapping to `True`:
131
+
132
+ - ``True``
133
+ - ``"true"`` / ``"t"``
134
+ - ``"yes"`` / ``"y"``
135
+ - ``"on"``
136
+ - ``"1"``
137
+ - ``1``
138
+
139
+ Values mapping to `False`:
140
+
141
+ - ``False``
142
+ - ``"false"`` / ``"f"``
143
+ - ``"no"`` / ``"n"``
144
+ - ``"off"``
145
+ - ``"0"``
146
+ - ``0``
147
+
148
+ Raises:
149
+ ValueError: For any other value.
150
+
151
+ .. versionadded:: 21.3.0
152
+ """
153
+ if isinstance(val, str):
154
+ val = val.lower()
155
+
156
+ if val in (True, "true", "t", "yes", "y", "on", "1", 1):
157
+ return True
158
+ if val in (False, "false", "f", "no", "n", "off", "0", 0):
159
+ return False
160
+
161
+ msg = f"Cannot convert value to bool: {val!r}"
162
+ raise ValueError(msg)
py311/lib/python3.11/site-packages/attr/converters.pyi ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Callable, Any, overload
2
+
3
+ from attrs import _ConverterType, _CallableConverterType
4
+
5
+ @overload
6
+ def pipe(*validators: _CallableConverterType) -> _CallableConverterType: ...
7
+ @overload
8
+ def pipe(*validators: _ConverterType) -> _ConverterType: ...
9
+ @overload
10
+ def optional(converter: _CallableConverterType) -> _CallableConverterType: ...
11
+ @overload
12
+ def optional(converter: _ConverterType) -> _ConverterType: ...
13
+ @overload
14
+ def default_if_none(default: Any) -> _CallableConverterType: ...
15
+ @overload
16
+ def default_if_none(
17
+ *, factory: Callable[[], Any]
18
+ ) -> _CallableConverterType: ...
19
+ def to_bool(val: str | int | bool) -> bool: ...
py311/lib/python3.11/site-packages/attr/exceptions.py ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: MIT
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import ClassVar
6
+
7
+
8
+ class FrozenError(AttributeError):
9
+ """
10
+ A frozen/immutable instance or attribute have been attempted to be
11
+ modified.
12
+
13
+ It mirrors the behavior of ``namedtuples`` by using the same error message
14
+ and subclassing `AttributeError`.
15
+
16
+ .. versionadded:: 20.1.0
17
+ """
18
+
19
+ msg = "can't set attribute"
20
+ args: ClassVar[tuple[str]] = [msg]
21
+
22
+
23
+ class FrozenInstanceError(FrozenError):
24
+ """
25
+ A frozen instance has been attempted to be modified.
26
+
27
+ .. versionadded:: 16.1.0
28
+ """
29
+
30
+
31
+ class FrozenAttributeError(FrozenError):
32
+ """
33
+ A frozen attribute has been attempted to be modified.
34
+
35
+ .. versionadded:: 20.1.0
36
+ """
37
+
38
+
39
+ class AttrsAttributeNotFoundError(ValueError):
40
+ """
41
+ An *attrs* function couldn't find an attribute that the user asked for.
42
+
43
+ .. versionadded:: 16.2.0
44
+ """
45
+
46
+
47
+ class NotAnAttrsClassError(ValueError):
48
+ """
49
+ A non-*attrs* class has been passed into an *attrs* function.
50
+
51
+ .. versionadded:: 16.2.0
52
+ """
53
+
54
+
55
+ class DefaultAlreadySetError(RuntimeError):
56
+ """
57
+ A default has been set when defining the field and is attempted to be reset
58
+ using the decorator.
59
+
60
+ .. versionadded:: 17.1.0
61
+ """
62
+
63
+
64
+ class UnannotatedAttributeError(RuntimeError):
65
+ """
66
+ A class with ``auto_attribs=True`` has a field without a type annotation.
67
+
68
+ .. versionadded:: 17.3.0
69
+ """
70
+
71
+
72
+ class PythonTooOldError(RuntimeError):
73
+ """
74
+ It was attempted to use an *attrs* feature that requires a newer Python
75
+ version.
76
+
77
+ .. versionadded:: 18.2.0
78
+ """
79
+
80
+
81
+ class NotCallableError(TypeError):
82
+ """
83
+ A field requiring a callable has been set with a value that is not
84
+ callable.
85
+
86
+ .. versionadded:: 19.2.0
87
+ """
88
+
89
+ def __init__(self, msg, value):
90
+ super(TypeError, self).__init__(msg, value)
91
+ self.msg = msg
92
+ self.value = value
93
+
94
+ def __str__(self):
95
+ return str(self.msg)
py311/lib/python3.11/site-packages/attr/exceptions.pyi ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Any
2
+
3
+ class FrozenError(AttributeError):
4
+ msg: str = ...
5
+
6
+ class FrozenInstanceError(FrozenError): ...
7
+ class FrozenAttributeError(FrozenError): ...
8
+ class AttrsAttributeNotFoundError(ValueError): ...
9
+ class NotAnAttrsClassError(ValueError): ...
10
+ class DefaultAlreadySetError(RuntimeError): ...
11
+ class UnannotatedAttributeError(RuntimeError): ...
12
+ class PythonTooOldError(RuntimeError): ...
13
+
14
+ class NotCallableError(TypeError):
15
+ msg: str = ...
16
+ value: Any = ...
17
+ def __init__(self, msg: str, value: Any) -> None: ...
py311/lib/python3.11/site-packages/attr/filters.py ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: MIT
2
+
3
+ """
4
+ Commonly useful filters for `attrs.asdict` and `attrs.astuple`.
5
+ """
6
+
7
+ from ._make import Attribute
8
+
9
+
10
+ def _split_what(what):
11
+ """
12
+ Returns a tuple of `frozenset`s of classes and attributes.
13
+ """
14
+ return (
15
+ frozenset(cls for cls in what if isinstance(cls, type)),
16
+ frozenset(cls for cls in what if isinstance(cls, str)),
17
+ frozenset(cls for cls in what if isinstance(cls, Attribute)),
18
+ )
19
+
20
+
21
+ def include(*what):
22
+ """
23
+ Create a filter that only allows *what*.
24
+
25
+ Args:
26
+ what (list[type, str, attrs.Attribute]):
27
+ What to include. Can be a type, a name, or an attribute.
28
+
29
+ Returns:
30
+ Callable:
31
+ A callable that can be passed to `attrs.asdict`'s and
32
+ `attrs.astuple`'s *filter* argument.
33
+
34
+ .. versionchanged:: 23.1.0 Accept strings with field names.
35
+ """
36
+ cls, names, attrs = _split_what(what)
37
+
38
+ def include_(attribute, value):
39
+ return (
40
+ value.__class__ in cls
41
+ or attribute.name in names
42
+ or attribute in attrs
43
+ )
44
+
45
+ return include_
46
+
47
+
48
+ def exclude(*what):
49
+ """
50
+ Create a filter that does **not** allow *what*.
51
+
52
+ Args:
53
+ what (list[type, str, attrs.Attribute]):
54
+ What to exclude. Can be a type, a name, or an attribute.
55
+
56
+ Returns:
57
+ Callable:
58
+ A callable that can be passed to `attrs.asdict`'s and
59
+ `attrs.astuple`'s *filter* argument.
60
+
61
+ .. versionchanged:: 23.3.0 Accept field name string as input argument
62
+ """
63
+ cls, names, attrs = _split_what(what)
64
+
65
+ def exclude_(attribute, value):
66
+ return not (
67
+ value.__class__ in cls
68
+ or attribute.name in names
69
+ or attribute in attrs
70
+ )
71
+
72
+ return exclude_
py311/lib/python3.11/site-packages/attr/filters.pyi ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ from typing import Any
2
+
3
+ from . import Attribute, _FilterType
4
+
5
+ def include(*what: type | str | Attribute[Any]) -> _FilterType[Any]: ...
6
+ def exclude(*what: type | str | Attribute[Any]) -> _FilterType[Any]: ...
py311/lib/python3.11/site-packages/attr/py.typed ADDED
File without changes
py311/lib/python3.11/site-packages/attr/setters.py ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: MIT
2
+
3
+ """
4
+ Commonly used hooks for on_setattr.
5
+ """
6
+
7
+ from . import _config
8
+ from .exceptions import FrozenAttributeError
9
+
10
+
11
+ def pipe(*setters):
12
+ """
13
+ Run all *setters* and return the return value of the last one.
14
+
15
+ .. versionadded:: 20.1.0
16
+ """
17
+
18
+ def wrapped_pipe(instance, attrib, new_value):
19
+ rv = new_value
20
+
21
+ for setter in setters:
22
+ rv = setter(instance, attrib, rv)
23
+
24
+ return rv
25
+
26
+ return wrapped_pipe
27
+
28
+
29
+ def frozen(_, __, ___):
30
+ """
31
+ Prevent an attribute to be modified.
32
+
33
+ .. versionadded:: 20.1.0
34
+ """
35
+ raise FrozenAttributeError
36
+
37
+
38
+ def validate(instance, attrib, new_value):
39
+ """
40
+ Run *attrib*'s validator on *new_value* if it has one.
41
+
42
+ .. versionadded:: 20.1.0
43
+ """
44
+ if _config._run_validators is False:
45
+ return new_value
46
+
47
+ v = attrib.validator
48
+ if not v:
49
+ return new_value
50
+
51
+ v(instance, attrib, new_value)
52
+
53
+ return new_value
54
+
55
+
56
+ def convert(instance, attrib, new_value):
57
+ """
58
+ Run *attrib*'s converter -- if it has one -- on *new_value* and return the
59
+ result.
60
+
61
+ .. versionadded:: 20.1.0
62
+ """
63
+ c = attrib.converter
64
+ if c:
65
+ # This can be removed once we drop 3.8 and use attrs.Converter instead.
66
+ from ._make import Converter
67
+
68
+ if not isinstance(c, Converter):
69
+ return c(new_value)
70
+
71
+ return c(new_value, instance, attrib)
72
+
73
+ return new_value
74
+
75
+
76
+ # Sentinel for disabling class-wide *on_setattr* hooks for certain attributes.
77
+ # Sphinx's autodata stopped working, so the docstring is inlined in the API
78
+ # docs.
79
+ NO_OP = object()
py311/lib/python3.11/site-packages/attr/setters.pyi ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Any, NewType, NoReturn, TypeVar
2
+
3
+ from . import Attribute
4
+ from attrs import _OnSetAttrType
5
+
6
+ _T = TypeVar("_T")
7
+
8
+ def frozen(
9
+ instance: Any, attribute: Attribute[Any], new_value: Any
10
+ ) -> NoReturn: ...
11
+ def pipe(*setters: _OnSetAttrType) -> _OnSetAttrType: ...
12
+ def validate(instance: Any, attribute: Attribute[_T], new_value: _T) -> _T: ...
13
+
14
+ # convert is allowed to return Any, because they can be chained using pipe.
15
+ def convert(
16
+ instance: Any, attribute: Attribute[Any], new_value: Any
17
+ ) -> Any: ...
18
+
19
+ _NoOpType = NewType("_NoOpType", object)
20
+ NO_OP: _NoOpType
py311/lib/python3.11/site-packages/attr/validators.py ADDED
@@ -0,0 +1,748 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: MIT
2
+
3
+ """
4
+ Commonly useful validators.
5
+ """
6
+
7
+ import operator
8
+ import re
9
+
10
+ from contextlib import contextmanager
11
+ from re import Pattern
12
+
13
+ from ._config import get_run_validators, set_run_validators
14
+ from ._make import _AndValidator, and_, attrib, attrs
15
+ from .converters import default_if_none
16
+ from .exceptions import NotCallableError
17
+
18
+
19
+ __all__ = [
20
+ "and_",
21
+ "deep_iterable",
22
+ "deep_mapping",
23
+ "disabled",
24
+ "ge",
25
+ "get_disabled",
26
+ "gt",
27
+ "in_",
28
+ "instance_of",
29
+ "is_callable",
30
+ "le",
31
+ "lt",
32
+ "matches_re",
33
+ "max_len",
34
+ "min_len",
35
+ "not_",
36
+ "optional",
37
+ "or_",
38
+ "set_disabled",
39
+ ]
40
+
41
+
42
+ def set_disabled(disabled):
43
+ """
44
+ Globally disable or enable running validators.
45
+
46
+ By default, they are run.
47
+
48
+ Args:
49
+ disabled (bool): If `True`, disable running all validators.
50
+
51
+ .. warning::
52
+
53
+ This function is not thread-safe!
54
+
55
+ .. versionadded:: 21.3.0
56
+ """
57
+ set_run_validators(not disabled)
58
+
59
+
60
+ def get_disabled():
61
+ """
62
+ Return a bool indicating whether validators are currently disabled or not.
63
+
64
+ Returns:
65
+ bool:`True` if validators are currently disabled.
66
+
67
+ .. versionadded:: 21.3.0
68
+ """
69
+ return not get_run_validators()
70
+
71
+
72
+ @contextmanager
73
+ def disabled():
74
+ """
75
+ Context manager that disables running validators within its context.
76
+
77
+ .. warning::
78
+
79
+ This context manager is not thread-safe!
80
+
81
+ .. versionadded:: 21.3.0
82
+ """
83
+ set_run_validators(False)
84
+ try:
85
+ yield
86
+ finally:
87
+ set_run_validators(True)
88
+
89
+
90
+ @attrs(repr=False, slots=True, unsafe_hash=True)
91
+ class _InstanceOfValidator:
92
+ type = attrib()
93
+
94
+ def __call__(self, inst, attr, value):
95
+ """
96
+ We use a callable class to be able to change the ``__repr__``.
97
+ """
98
+ if not isinstance(value, self.type):
99
+ msg = f"'{attr.name}' must be {self.type!r} (got {value!r} that is a {value.__class__!r})."
100
+ raise TypeError(
101
+ msg,
102
+ attr,
103
+ self.type,
104
+ value,
105
+ )
106
+
107
+ def __repr__(self):
108
+ return f"<instance_of validator for type {self.type!r}>"
109
+
110
+
111
+ def instance_of(type):
112
+ """
113
+ A validator that raises a `TypeError` if the initializer is called with a
114
+ wrong type for this particular attribute (checks are performed using
115
+ `isinstance` therefore it's also valid to pass a tuple of types).
116
+
117
+ Args:
118
+ type (type | tuple[type]): The type to check for.
119
+
120
+ Raises:
121
+ TypeError:
122
+ With a human readable error message, the attribute (of type
123
+ `attrs.Attribute`), the expected type, and the value it got.
124
+ """
125
+ return _InstanceOfValidator(type)
126
+
127
+
128
+ @attrs(repr=False, frozen=True, slots=True)
129
+ class _MatchesReValidator:
130
+ pattern = attrib()
131
+ match_func = attrib()
132
+
133
+ def __call__(self, inst, attr, value):
134
+ """
135
+ We use a callable class to be able to change the ``__repr__``.
136
+ """
137
+ if not self.match_func(value):
138
+ msg = f"'{attr.name}' must match regex {self.pattern.pattern!r} ({value!r} doesn't)"
139
+ raise ValueError(
140
+ msg,
141
+ attr,
142
+ self.pattern,
143
+ value,
144
+ )
145
+
146
+ def __repr__(self):
147
+ return f"<matches_re validator for pattern {self.pattern!r}>"
148
+
149
+
150
+ def matches_re(regex, flags=0, func=None):
151
+ r"""
152
+ A validator that raises `ValueError` if the initializer is called with a
153
+ string that doesn't match *regex*.
154
+
155
+ Args:
156
+ regex (str, re.Pattern):
157
+ A regex string or precompiled pattern to match against
158
+
159
+ flags (int):
160
+ Flags that will be passed to the underlying re function (default 0)
161
+
162
+ func (typing.Callable):
163
+ Which underlying `re` function to call. Valid options are
164
+ `re.fullmatch`, `re.search`, and `re.match`; the default `None`
165
+ means `re.fullmatch`. For performance reasons, the pattern is
166
+ always precompiled using `re.compile`.
167
+
168
+ .. versionadded:: 19.2.0
169
+ .. versionchanged:: 21.3.0 *regex* can be a pre-compiled pattern.
170
+ """
171
+ valid_funcs = (re.fullmatch, None, re.search, re.match)
172
+ if func not in valid_funcs:
173
+ msg = "'func' must be one of {}.".format(
174
+ ", ".join(
175
+ sorted((e and e.__name__) or "None" for e in set(valid_funcs))
176
+ )
177
+ )
178
+ raise ValueError(msg)
179
+
180
+ if isinstance(regex, Pattern):
181
+ if flags:
182
+ msg = "'flags' can only be used with a string pattern; pass flags to re.compile() instead"
183
+ raise TypeError(msg)
184
+ pattern = regex
185
+ else:
186
+ pattern = re.compile(regex, flags)
187
+
188
+ if func is re.match:
189
+ match_func = pattern.match
190
+ elif func is re.search:
191
+ match_func = pattern.search
192
+ else:
193
+ match_func = pattern.fullmatch
194
+
195
+ return _MatchesReValidator(pattern, match_func)
196
+
197
+
198
+ @attrs(repr=False, slots=True, unsafe_hash=True)
199
+ class _OptionalValidator:
200
+ validator = attrib()
201
+
202
+ def __call__(self, inst, attr, value):
203
+ if value is None:
204
+ return
205
+
206
+ self.validator(inst, attr, value)
207
+
208
+ def __repr__(self):
209
+ return f"<optional validator for {self.validator!r} or None>"
210
+
211
+
212
+ def optional(validator):
213
+ """
214
+ A validator that makes an attribute optional. An optional attribute is one
215
+ which can be set to `None` in addition to satisfying the requirements of
216
+ the sub-validator.
217
+
218
+ Args:
219
+ validator
220
+ (typing.Callable | tuple[typing.Callable] | list[typing.Callable]):
221
+ A validator (or validators) that is used for non-`None` values.
222
+
223
+ .. versionadded:: 15.1.0
224
+ .. versionchanged:: 17.1.0 *validator* can be a list of validators.
225
+ .. versionchanged:: 23.1.0 *validator* can also be a tuple of validators.
226
+ """
227
+ if isinstance(validator, (list, tuple)):
228
+ return _OptionalValidator(_AndValidator(validator))
229
+
230
+ return _OptionalValidator(validator)
231
+
232
+
233
+ @attrs(repr=False, slots=True, unsafe_hash=True)
234
+ class _InValidator:
235
+ options = attrib()
236
+ _original_options = attrib(hash=False)
237
+
238
+ def __call__(self, inst, attr, value):
239
+ try:
240
+ in_options = value in self.options
241
+ except TypeError: # e.g. `1 in "abc"`
242
+ in_options = False
243
+
244
+ if not in_options:
245
+ msg = f"'{attr.name}' must be in {self._original_options!r} (got {value!r})"
246
+ raise ValueError(
247
+ msg,
248
+ attr,
249
+ self._original_options,
250
+ value,
251
+ )
252
+
253
+ def __repr__(self):
254
+ return f"<in_ validator with options {self._original_options!r}>"
255
+
256
+
257
+ def in_(options):
258
+ """
259
+ A validator that raises a `ValueError` if the initializer is called with a
260
+ value that does not belong in the *options* provided.
261
+
262
+ The check is performed using ``value in options``, so *options* has to
263
+ support that operation.
264
+
265
+ To keep the validator hashable, dicts, lists, and sets are transparently
266
+ transformed into a `tuple`.
267
+
268
+ Args:
269
+ options: Allowed options.
270
+
271
+ Raises:
272
+ ValueError:
273
+ With a human readable error message, the attribute (of type
274
+ `attrs.Attribute`), the expected options, and the value it got.
275
+
276
+ .. versionadded:: 17.1.0
277
+ .. versionchanged:: 22.1.0
278
+ The ValueError was incomplete until now and only contained the human
279
+ readable error message. Now it contains all the information that has
280
+ been promised since 17.1.0.
281
+ .. versionchanged:: 24.1.0
282
+ *options* that are a list, dict, or a set are now transformed into a
283
+ tuple to keep the validator hashable.
284
+ """
285
+ repr_options = options
286
+ if isinstance(options, (list, dict, set)):
287
+ options = tuple(options)
288
+
289
+ return _InValidator(options, repr_options)
290
+
291
+
292
+ @attrs(repr=False, slots=False, unsafe_hash=True)
293
+ class _IsCallableValidator:
294
+ def __call__(self, inst, attr, value):
295
+ """
296
+ We use a callable class to be able to change the ``__repr__``.
297
+ """
298
+ if not callable(value):
299
+ message = (
300
+ "'{name}' must be callable "
301
+ "(got {value!r} that is a {actual!r})."
302
+ )
303
+ raise NotCallableError(
304
+ msg=message.format(
305
+ name=attr.name, value=value, actual=value.__class__
306
+ ),
307
+ value=value,
308
+ )
309
+
310
+ def __repr__(self):
311
+ return "<is_callable validator>"
312
+
313
+
314
+ def is_callable():
315
+ """
316
+ A validator that raises a `attrs.exceptions.NotCallableError` if the
317
+ initializer is called with a value for this particular attribute that is
318
+ not callable.
319
+
320
+ .. versionadded:: 19.1.0
321
+
322
+ Raises:
323
+ attrs.exceptions.NotCallableError:
324
+ With a human readable error message containing the attribute
325
+ (`attrs.Attribute`) name, and the value it got.
326
+ """
327
+ return _IsCallableValidator()
328
+
329
+
330
+ @attrs(repr=False, slots=True, unsafe_hash=True)
331
+ class _DeepIterable:
332
+ member_validator = attrib(validator=is_callable())
333
+ iterable_validator = attrib(
334
+ default=None, validator=optional(is_callable())
335
+ )
336
+
337
+ def __call__(self, inst, attr, value):
338
+ """
339
+ We use a callable class to be able to change the ``__repr__``.
340
+ """
341
+ if self.iterable_validator is not None:
342
+ self.iterable_validator(inst, attr, value)
343
+
344
+ for member in value:
345
+ self.member_validator(inst, attr, member)
346
+
347
+ def __repr__(self):
348
+ iterable_identifier = (
349
+ ""
350
+ if self.iterable_validator is None
351
+ else f" {self.iterable_validator!r}"
352
+ )
353
+ return (
354
+ f"<deep_iterable validator for{iterable_identifier}"
355
+ f" iterables of {self.member_validator!r}>"
356
+ )
357
+
358
+
359
+ def deep_iterable(member_validator, iterable_validator=None):
360
+ """
361
+ A validator that performs deep validation of an iterable.
362
+
363
+ Args:
364
+ member_validator: Validator(s) to apply to iterable members.
365
+
366
+ iterable_validator:
367
+ Validator(s) to apply to iterable itself (optional).
368
+
369
+ Raises
370
+ TypeError: if any sub-validators fail
371
+
372
+ .. versionadded:: 19.1.0
373
+
374
+ .. versionchanged:: 25.4.0
375
+ *member_validator* and *iterable_validator* can now be a list or tuple
376
+ of validators.
377
+ """
378
+ if isinstance(member_validator, (list, tuple)):
379
+ member_validator = and_(*member_validator)
380
+ if isinstance(iterable_validator, (list, tuple)):
381
+ iterable_validator = and_(*iterable_validator)
382
+ return _DeepIterable(member_validator, iterable_validator)
383
+
384
+
385
+ @attrs(repr=False, slots=True, unsafe_hash=True)
386
+ class _DeepMapping:
387
+ key_validator = attrib(validator=optional(is_callable()))
388
+ value_validator = attrib(validator=optional(is_callable()))
389
+ mapping_validator = attrib(validator=optional(is_callable()))
390
+
391
+ def __call__(self, inst, attr, value):
392
+ """
393
+ We use a callable class to be able to change the ``__repr__``.
394
+ """
395
+ if self.mapping_validator is not None:
396
+ self.mapping_validator(inst, attr, value)
397
+
398
+ for key in value:
399
+ if self.key_validator is not None:
400
+ self.key_validator(inst, attr, key)
401
+ if self.value_validator is not None:
402
+ self.value_validator(inst, attr, value[key])
403
+
404
+ def __repr__(self):
405
+ return f"<deep_mapping validator for objects mapping {self.key_validator!r} to {self.value_validator!r}>"
406
+
407
+
408
+ def deep_mapping(
409
+ key_validator=None, value_validator=None, mapping_validator=None
410
+ ):
411
+ """
412
+ A validator that performs deep validation of a dictionary.
413
+
414
+ All validators are optional, but at least one of *key_validator* or
415
+ *value_validator* must be provided.
416
+
417
+ Args:
418
+ key_validator: Validator(s) to apply to dictionary keys.
419
+
420
+ value_validator: Validator(s) to apply to dictionary values.
421
+
422
+ mapping_validator:
423
+ Validator(s) to apply to top-level mapping attribute.
424
+
425
+ .. versionadded:: 19.1.0
426
+
427
+ .. versionchanged:: 25.4.0
428
+ *key_validator* and *value_validator* are now optional, but at least one
429
+ of them must be provided.
430
+
431
+ .. versionchanged:: 25.4.0
432
+ *key_validator*, *value_validator*, and *mapping_validator* can now be a
433
+ list or tuple of validators.
434
+
435
+ Raises:
436
+ TypeError: If any sub-validator fails on validation.
437
+
438
+ ValueError:
439
+ If neither *key_validator* nor *value_validator* is provided on
440
+ instantiation.
441
+ """
442
+ if key_validator is None and value_validator is None:
443
+ msg = (
444
+ "At least one of key_validator or value_validator must be provided"
445
+ )
446
+ raise ValueError(msg)
447
+
448
+ if isinstance(key_validator, (list, tuple)):
449
+ key_validator = and_(*key_validator)
450
+ if isinstance(value_validator, (list, tuple)):
451
+ value_validator = and_(*value_validator)
452
+ if isinstance(mapping_validator, (list, tuple)):
453
+ mapping_validator = and_(*mapping_validator)
454
+
455
+ return _DeepMapping(key_validator, value_validator, mapping_validator)
456
+
457
+
458
+ @attrs(repr=False, frozen=True, slots=True)
459
+ class _NumberValidator:
460
+ bound = attrib()
461
+ compare_op = attrib()
462
+ compare_func = attrib()
463
+
464
+ def __call__(self, inst, attr, value):
465
+ """
466
+ We use a callable class to be able to change the ``__repr__``.
467
+ """
468
+ if not self.compare_func(value, self.bound):
469
+ msg = f"'{attr.name}' must be {self.compare_op} {self.bound}: {value}"
470
+ raise ValueError(msg)
471
+
472
+ def __repr__(self):
473
+ return f"<Validator for x {self.compare_op} {self.bound}>"
474
+
475
+
476
+ def lt(val):
477
+ """
478
+ A validator that raises `ValueError` if the initializer is called with a
479
+ number larger or equal to *val*.
480
+
481
+ The validator uses `operator.lt` to compare the values.
482
+
483
+ Args:
484
+ val: Exclusive upper bound for values.
485
+
486
+ .. versionadded:: 21.3.0
487
+ """
488
+ return _NumberValidator(val, "<", operator.lt)
489
+
490
+
491
+ def le(val):
492
+ """
493
+ A validator that raises `ValueError` if the initializer is called with a
494
+ number greater than *val*.
495
+
496
+ The validator uses `operator.le` to compare the values.
497
+
498
+ Args:
499
+ val: Inclusive upper bound for values.
500
+
501
+ .. versionadded:: 21.3.0
502
+ """
503
+ return _NumberValidator(val, "<=", operator.le)
504
+
505
+
506
+ def ge(val):
507
+ """
508
+ A validator that raises `ValueError` if the initializer is called with a
509
+ number smaller than *val*.
510
+
511
+ The validator uses `operator.ge` to compare the values.
512
+
513
+ Args:
514
+ val: Inclusive lower bound for values
515
+
516
+ .. versionadded:: 21.3.0
517
+ """
518
+ return _NumberValidator(val, ">=", operator.ge)
519
+
520
+
521
+ def gt(val):
522
+ """
523
+ A validator that raises `ValueError` if the initializer is called with a
524
+ number smaller or equal to *val*.
525
+
526
+ The validator uses `operator.gt` to compare the values.
527
+
528
+ Args:
529
+ val: Exclusive lower bound for values
530
+
531
+ .. versionadded:: 21.3.0
532
+ """
533
+ return _NumberValidator(val, ">", operator.gt)
534
+
535
+
536
+ @attrs(repr=False, frozen=True, slots=True)
537
+ class _MaxLengthValidator:
538
+ max_length = attrib()
539
+
540
+ def __call__(self, inst, attr, value):
541
+ """
542
+ We use a callable class to be able to change the ``__repr__``.
543
+ """
544
+ if len(value) > self.max_length:
545
+ msg = f"Length of '{attr.name}' must be <= {self.max_length}: {len(value)}"
546
+ raise ValueError(msg)
547
+
548
+ def __repr__(self):
549
+ return f"<max_len validator for {self.max_length}>"
550
+
551
+
552
+ def max_len(length):
553
+ """
554
+ A validator that raises `ValueError` if the initializer is called
555
+ with a string or iterable that is longer than *length*.
556
+
557
+ Args:
558
+ length (int): Maximum length of the string or iterable
559
+
560
+ .. versionadded:: 21.3.0
561
+ """
562
+ return _MaxLengthValidator(length)
563
+
564
+
565
+ @attrs(repr=False, frozen=True, slots=True)
566
+ class _MinLengthValidator:
567
+ min_length = attrib()
568
+
569
+ def __call__(self, inst, attr, value):
570
+ """
571
+ We use a callable class to be able to change the ``__repr__``.
572
+ """
573
+ if len(value) < self.min_length:
574
+ msg = f"Length of '{attr.name}' must be >= {self.min_length}: {len(value)}"
575
+ raise ValueError(msg)
576
+
577
+ def __repr__(self):
578
+ return f"<min_len validator for {self.min_length}>"
579
+
580
+
581
+ def min_len(length):
582
+ """
583
+ A validator that raises `ValueError` if the initializer is called
584
+ with a string or iterable that is shorter than *length*.
585
+
586
+ Args:
587
+ length (int): Minimum length of the string or iterable
588
+
589
+ .. versionadded:: 22.1.0
590
+ """
591
+ return _MinLengthValidator(length)
592
+
593
+
594
+ @attrs(repr=False, slots=True, unsafe_hash=True)
595
+ class _SubclassOfValidator:
596
+ type = attrib()
597
+
598
+ def __call__(self, inst, attr, value):
599
+ """
600
+ We use a callable class to be able to change the ``__repr__``.
601
+ """
602
+ if not issubclass(value, self.type):
603
+ msg = f"'{attr.name}' must be a subclass of {self.type!r} (got {value!r})."
604
+ raise TypeError(
605
+ msg,
606
+ attr,
607
+ self.type,
608
+ value,
609
+ )
610
+
611
+ def __repr__(self):
612
+ return f"<subclass_of validator for type {self.type!r}>"
613
+
614
+
615
+ def _subclass_of(type):
616
+ """
617
+ A validator that raises a `TypeError` if the initializer is called with a
618
+ wrong type for this particular attribute (checks are performed using
619
+ `issubclass` therefore it's also valid to pass a tuple of types).
620
+
621
+ Args:
622
+ type (type | tuple[type, ...]): The type(s) to check for.
623
+
624
+ Raises:
625
+ TypeError:
626
+ With a human readable error message, the attribute (of type
627
+ `attrs.Attribute`), the expected type, and the value it got.
628
+ """
629
+ return _SubclassOfValidator(type)
630
+
631
+
632
+ @attrs(repr=False, slots=True, unsafe_hash=True)
633
+ class _NotValidator:
634
+ validator = attrib()
635
+ msg = attrib(
636
+ converter=default_if_none(
637
+ "not_ validator child '{validator!r}' "
638
+ "did not raise a captured error"
639
+ )
640
+ )
641
+ exc_types = attrib(
642
+ validator=deep_iterable(
643
+ member_validator=_subclass_of(Exception),
644
+ iterable_validator=instance_of(tuple),
645
+ ),
646
+ )
647
+
648
+ def __call__(self, inst, attr, value):
649
+ try:
650
+ self.validator(inst, attr, value)
651
+ except self.exc_types:
652
+ pass # suppress error to invert validity
653
+ else:
654
+ raise ValueError(
655
+ self.msg.format(
656
+ validator=self.validator,
657
+ exc_types=self.exc_types,
658
+ ),
659
+ attr,
660
+ self.validator,
661
+ value,
662
+ self.exc_types,
663
+ )
664
+
665
+ def __repr__(self):
666
+ return f"<not_ validator wrapping {self.validator!r}, capturing {self.exc_types!r}>"
667
+
668
+
669
+ def not_(validator, *, msg=None, exc_types=(ValueError, TypeError)):
670
+ """
671
+ A validator that wraps and logically 'inverts' the validator passed to it.
672
+ It will raise a `ValueError` if the provided validator *doesn't* raise a
673
+ `ValueError` or `TypeError` (by default), and will suppress the exception
674
+ if the provided validator *does*.
675
+
676
+ Intended to be used with existing validators to compose logic without
677
+ needing to create inverted variants, for example, ``not_(in_(...))``.
678
+
679
+ Args:
680
+ validator: A validator to be logically inverted.
681
+
682
+ msg (str):
683
+ Message to raise if validator fails. Formatted with keys
684
+ ``exc_types`` and ``validator``.
685
+
686
+ exc_types (tuple[type, ...]):
687
+ Exception type(s) to capture. Other types raised by child
688
+ validators will not be intercepted and pass through.
689
+
690
+ Raises:
691
+ ValueError:
692
+ With a human readable error message, the attribute (of type
693
+ `attrs.Attribute`), the validator that failed to raise an
694
+ exception, the value it got, and the expected exception types.
695
+
696
+ .. versionadded:: 22.2.0
697
+ """
698
+ try:
699
+ exc_types = tuple(exc_types)
700
+ except TypeError:
701
+ exc_types = (exc_types,)
702
+ return _NotValidator(validator, msg, exc_types)
703
+
704
+
705
+ @attrs(repr=False, slots=True, unsafe_hash=True)
706
+ class _OrValidator:
707
+ validators = attrib()
708
+
709
+ def __call__(self, inst, attr, value):
710
+ for v in self.validators:
711
+ try:
712
+ v(inst, attr, value)
713
+ except Exception: # noqa: BLE001, PERF203, S112
714
+ continue
715
+ else:
716
+ return
717
+
718
+ msg = f"None of {self.validators!r} satisfied for value {value!r}"
719
+ raise ValueError(msg)
720
+
721
+ def __repr__(self):
722
+ return f"<or validator wrapping {self.validators!r}>"
723
+
724
+
725
+ def or_(*validators):
726
+ """
727
+ A validator that composes multiple validators into one.
728
+
729
+ When called on a value, it runs all wrapped validators until one of them is
730
+ satisfied.
731
+
732
+ Args:
733
+ validators (~collections.abc.Iterable[typing.Callable]):
734
+ Arbitrary number of validators.
735
+
736
+ Raises:
737
+ ValueError:
738
+ If no validator is satisfied. Raised with a human-readable error
739
+ message listing all the wrapped validators and the value that
740
+ failed all of them.
741
+
742
+ .. versionadded:: 24.1.0
743
+ """
744
+ vals = []
745
+ for v in validators:
746
+ vals.extend(v.validators if isinstance(v, _OrValidator) else [v])
747
+
748
+ return _OrValidator(tuple(vals))
py311/lib/python3.11/site-packages/attr/validators.pyi ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from types import UnionType
2
+ from typing import (
3
+ Any,
4
+ AnyStr,
5
+ Callable,
6
+ Container,
7
+ ContextManager,
8
+ Iterable,
9
+ Mapping,
10
+ Match,
11
+ Pattern,
12
+ TypeVar,
13
+ overload,
14
+ )
15
+
16
+ from attrs import _ValidatorType
17
+ from attrs import _ValidatorArgType
18
+
19
+ _T = TypeVar("_T")
20
+ _T1 = TypeVar("_T1")
21
+ _T2 = TypeVar("_T2")
22
+ _T3 = TypeVar("_T3")
23
+ _T4 = TypeVar("_T4")
24
+ _T5 = TypeVar("_T5")
25
+ _T6 = TypeVar("_T6")
26
+ _I = TypeVar("_I", bound=Iterable)
27
+ _K = TypeVar("_K")
28
+ _V = TypeVar("_V")
29
+ _M = TypeVar("_M", bound=Mapping)
30
+
31
+ def set_disabled(run: bool) -> None: ...
32
+ def get_disabled() -> bool: ...
33
+ def disabled() -> ContextManager[None]: ...
34
+
35
+ # To be more precise on instance_of use some overloads.
36
+ # If there are more than 3 items in the tuple then we fall back to Any
37
+ @overload
38
+ def instance_of(type: type[_T]) -> _ValidatorType[_T]: ...
39
+ @overload
40
+ def instance_of(type: tuple[type[_T]]) -> _ValidatorType[_T]: ...
41
+ @overload
42
+ def instance_of(
43
+ type: tuple[type[_T1], type[_T2]],
44
+ ) -> _ValidatorType[_T1 | _T2]: ...
45
+ @overload
46
+ def instance_of(
47
+ type: tuple[type[_T1], type[_T2], type[_T3]],
48
+ ) -> _ValidatorType[_T1 | _T2 | _T3]: ...
49
+ @overload
50
+ def instance_of(type: tuple[type, ...]) -> _ValidatorType[Any]: ...
51
+ @overload
52
+ def instance_of(type: UnionType) -> _ValidatorType[Any]: ...
53
+ def optional(
54
+ validator: (
55
+ _ValidatorType[_T]
56
+ | list[_ValidatorType[_T]]
57
+ | tuple[_ValidatorType[_T]]
58
+ ),
59
+ ) -> _ValidatorType[_T | None]: ...
60
+ def in_(options: Container[_T]) -> _ValidatorType[_T]: ...
61
+ def and_(*validators: _ValidatorType[_T]) -> _ValidatorType[_T]: ...
62
+ def matches_re(
63
+ regex: Pattern[AnyStr] | AnyStr,
64
+ flags: int = ...,
65
+ func: Callable[[AnyStr, AnyStr, int], Match[AnyStr] | None] | None = ...,
66
+ ) -> _ValidatorType[AnyStr]: ...
67
+ def deep_iterable(
68
+ member_validator: _ValidatorArgType[_T],
69
+ iterable_validator: _ValidatorArgType[_I] | None = ...,
70
+ ) -> _ValidatorType[_I]: ...
71
+ @overload
72
+ def deep_mapping(
73
+ key_validator: _ValidatorArgType[_K],
74
+ value_validator: _ValidatorArgType[_V] | None = ...,
75
+ mapping_validator: _ValidatorArgType[_M] | None = ...,
76
+ ) -> _ValidatorType[_M]: ...
77
+ @overload
78
+ def deep_mapping(
79
+ key_validator: _ValidatorArgType[_K] | None = ...,
80
+ value_validator: _ValidatorArgType[_V] = ...,
81
+ mapping_validator: _ValidatorArgType[_M] | None = ...,
82
+ ) -> _ValidatorType[_M]: ...
83
+ def is_callable() -> _ValidatorType[_T]: ...
84
+ def lt(val: _T) -> _ValidatorType[_T]: ...
85
+ def le(val: _T) -> _ValidatorType[_T]: ...
86
+ def ge(val: _T) -> _ValidatorType[_T]: ...
87
+ def gt(val: _T) -> _ValidatorType[_T]: ...
88
+ def max_len(length: int) -> _ValidatorType[_T]: ...
89
+ def min_len(length: int) -> _ValidatorType[_T]: ...
90
+ def not_(
91
+ validator: _ValidatorType[_T],
92
+ *,
93
+ msg: str | None = None,
94
+ exc_types: type[Exception] | Iterable[type[Exception]] = ...,
95
+ ) -> _ValidatorType[_T]: ...
96
+ @overload
97
+ def or_(
98
+ __v1: _ValidatorType[_T1],
99
+ __v2: _ValidatorType[_T2],
100
+ ) -> _ValidatorType[_T1 | _T2]: ...
101
+ @overload
102
+ def or_(
103
+ __v1: _ValidatorType[_T1],
104
+ __v2: _ValidatorType[_T2],
105
+ __v3: _ValidatorType[_T3],
106
+ ) -> _ValidatorType[_T1 | _T2 | _T3]: ...
107
+ @overload
108
+ def or_(
109
+ __v1: _ValidatorType[_T1],
110
+ __v2: _ValidatorType[_T2],
111
+ __v3: _ValidatorType[_T3],
112
+ __v4: _ValidatorType[_T4],
113
+ ) -> _ValidatorType[_T1 | _T2 | _T3 | _T4]: ...
114
+ @overload
115
+ def or_(
116
+ __v1: _ValidatorType[_T1],
117
+ __v2: _ValidatorType[_T2],
118
+ __v3: _ValidatorType[_T3],
119
+ __v4: _ValidatorType[_T4],
120
+ __v5: _ValidatorType[_T5],
121
+ ) -> _ValidatorType[_T1 | _T2 | _T3 | _T4 | _T5]: ...
122
+ @overload
123
+ def or_(
124
+ __v1: _ValidatorType[_T1],
125
+ __v2: _ValidatorType[_T2],
126
+ __v3: _ValidatorType[_T3],
127
+ __v4: _ValidatorType[_T4],
128
+ __v5: _ValidatorType[_T5],
129
+ __v6: _ValidatorType[_T6],
130
+ ) -> _ValidatorType[_T1 | _T2 | _T3 | _T4 | _T5 | _T6]: ...
131
+ @overload
132
+ def or_(
133
+ __v1: _ValidatorType[Any],
134
+ __v2: _ValidatorType[Any],
135
+ __v3: _ValidatorType[Any],
136
+ __v4: _ValidatorType[Any],
137
+ __v5: _ValidatorType[Any],
138
+ __v6: _ValidatorType[Any],
139
+ *validators: _ValidatorType[Any],
140
+ ) -> _ValidatorType[Any]: ...
py311/lib/python3.11/site-packages/attrs-25.4.0.dist-info/INSTALLER ADDED
@@ -0,0 +1 @@
 
 
1
+ uv
py311/lib/python3.11/site-packages/attrs-25.4.0.dist-info/METADATA ADDED
@@ -0,0 +1,235 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Metadata-Version: 2.4
2
+ Name: attrs
3
+ Version: 25.4.0
4
+ Summary: Classes Without Boilerplate
5
+ Project-URL: Documentation, https://www.attrs.org/
6
+ Project-URL: Changelog, https://www.attrs.org/en/stable/changelog.html
7
+ Project-URL: GitHub, https://github.com/python-attrs/attrs
8
+ Project-URL: Funding, https://github.com/sponsors/hynek
9
+ Project-URL: Tidelift, https://tidelift.com/subscription/pkg/pypi-attrs?utm_source=pypi-attrs&utm_medium=pypi
10
+ Author-email: Hynek Schlawack <hs@ox.cx>
11
+ License-Expression: MIT
12
+ License-File: LICENSE
13
+ Keywords: attribute,boilerplate,class
14
+ Classifier: Development Status :: 5 - Production/Stable
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Programming Language :: Python :: Implementation :: CPython
22
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
23
+ Classifier: Typing :: Typed
24
+ Requires-Python: >=3.9
25
+ Description-Content-Type: text/markdown
26
+
27
+ <p align="center">
28
+ <a href="https://www.attrs.org/">
29
+ <img src="https://raw.githubusercontent.com/python-attrs/attrs/main/docs/_static/attrs_logo.svg" width="35%" alt="attrs" />
30
+ </a>
31
+ </p>
32
+
33
+
34
+ *attrs* is the Python package that will bring back the **joy** of **writing classes** by relieving you from the drudgery of implementing object protocols (aka [dunder methods](https://www.attrs.org/en/latest/glossary.html#term-dunder-methods)).
35
+ Trusted by NASA for [Mars missions since 2020](https://github.com/readme/featured/nasa-ingenuity-helicopter)!
36
+
37
+ Its main goal is to help you to write **concise** and **correct** software without slowing down your code.
38
+
39
+
40
+ ## Sponsors
41
+
42
+ *attrs* would not be possible without our [amazing sponsors](https://github.com/sponsors/hynek).
43
+ Especially those generously supporting us at the *The Organization* tier and higher:
44
+
45
+ <!-- sponsor-break-begin -->
46
+
47
+ <p align="center">
48
+
49
+ <!-- [[[cog
50
+ import pathlib, tomllib
51
+
52
+ for sponsor in tomllib.loads(pathlib.Path("pyproject.toml").read_text())["tool"]["sponcon"]["sponsors"]:
53
+ print(f'<a href="{sponsor["url"]}"><img title="{sponsor["title"]}" src="https://www.attrs.org/en/25.4.0/_static/sponsors/{sponsor["img"]}" width="190" /></a>')
54
+ ]]] -->
55
+ <a href="https://www.variomedia.de/"><img title="Variomedia AG" src="https://www.attrs.org/en/25.4.0/_static/sponsors/Variomedia.svg" width="190" /></a>
56
+ <a href="https://tidelift.com/?utm_source=lifter&utm_medium=referral&utm_campaign=hynek"><img title="Tidelift" src="https://www.attrs.org/en/25.4.0/_static/sponsors/Tidelift.svg" width="190" /></a>
57
+ <a href="https://privacy-solutions.org/"><img title="Privacy Solutions" src="https://www.attrs.org/en/25.4.0/_static/sponsors/Privacy-Solutions.svg" width="190" /></a>
58
+ <a href="https://filepreviews.io/"><img title="FilePreviews" src="https://www.attrs.org/en/25.4.0/_static/sponsors/FilePreviews.svg" width="190" /></a>
59
+ <a href="https://polar.sh/"><img title="Polar" src="https://www.attrs.org/en/25.4.0/_static/sponsors/Polar.svg" width="190" /></a>
60
+ <!-- [[[end]]] -->
61
+
62
+ </p>
63
+
64
+ <!-- sponsor-break-end -->
65
+
66
+ <p align="center">
67
+ <strong>Please consider <a href="https://github.com/sponsors/hynek">joining them</a> to help make <em>attrs</em>’s maintenance more sustainable!</strong>
68
+ </p>
69
+
70
+ <!-- teaser-end -->
71
+
72
+ ## Example
73
+
74
+ *attrs* gives you a class decorator and a way to declaratively define the attributes on that class:
75
+
76
+ <!-- code-begin -->
77
+
78
+ ```pycon
79
+ >>> from attrs import asdict, define, make_class, Factory
80
+
81
+ >>> @define
82
+ ... class SomeClass:
83
+ ... a_number: int = 42
84
+ ... list_of_numbers: list[int] = Factory(list)
85
+ ...
86
+ ... def hard_math(self, another_number):
87
+ ... return self.a_number + sum(self.list_of_numbers) * another_number
88
+
89
+
90
+ >>> sc = SomeClass(1, [1, 2, 3])
91
+ >>> sc
92
+ SomeClass(a_number=1, list_of_numbers=[1, 2, 3])
93
+
94
+ >>> sc.hard_math(3)
95
+ 19
96
+ >>> sc == SomeClass(1, [1, 2, 3])
97
+ True
98
+ >>> sc != SomeClass(2, [3, 2, 1])
99
+ True
100
+
101
+ >>> asdict(sc)
102
+ {'a_number': 1, 'list_of_numbers': [1, 2, 3]}
103
+
104
+ >>> SomeClass()
105
+ SomeClass(a_number=42, list_of_numbers=[])
106
+
107
+ >>> C = make_class("C", ["a", "b"])
108
+ >>> C("foo", "bar")
109
+ C(a='foo', b='bar')
110
+ ```
111
+
112
+ After *declaring* your attributes, *attrs* gives you:
113
+
114
+ - a concise and explicit overview of the class's attributes,
115
+ - a nice human-readable `__repr__`,
116
+ - equality-checking methods,
117
+ - an initializer,
118
+ - and much more,
119
+
120
+ *without* writing dull boilerplate code again and again and *without* runtime performance penalties.
121
+
122
+ ---
123
+
124
+ This example uses *attrs*'s modern APIs that have been introduced in version 20.1.0, and the *attrs* package import name that has been added in version 21.3.0.
125
+ The classic APIs (`@attr.s`, `attr.ib`, plus their serious-business aliases) and the `attr` package import name will remain **indefinitely**.
126
+
127
+ Check out [*On The Core API Names*](https://www.attrs.org/en/latest/names.html) for an in-depth explanation!
128
+
129
+
130
+ ### Hate Type Annotations!?
131
+
132
+ No problem!
133
+ Types are entirely **optional** with *attrs*.
134
+ Simply assign `attrs.field()` to the attributes instead of annotating them with types:
135
+
136
+ ```python
137
+ from attrs import define, field
138
+
139
+ @define
140
+ class SomeClass:
141
+ a_number = field(default=42)
142
+ list_of_numbers = field(factory=list)
143
+ ```
144
+
145
+
146
+ ## Data Classes
147
+
148
+ On the tin, *attrs* might remind you of `dataclasses` (and indeed, `dataclasses` [are a descendant](https://hynek.me/articles/import-attrs/) of *attrs*).
149
+ In practice it does a lot more and is more flexible.
150
+ For instance, it allows you to define [special handling of NumPy arrays for equality checks](https://www.attrs.org/en/stable/comparison.html#customization), allows more ways to [plug into the initialization process](https://www.attrs.org/en/stable/init.html#hooking-yourself-into-initialization), has a replacement for `__init_subclass__`, and allows for stepping through the generated methods using a debugger.
151
+
152
+ For more details, please refer to our [comparison page](https://www.attrs.org/en/stable/why.html#data-classes), but generally speaking, we are more likely to commit crimes against nature to make things work that one would expect to work, but that are quite complicated in practice.
153
+
154
+
155
+ ## Project Information
156
+
157
+ - [**Changelog**](https://www.attrs.org/en/stable/changelog.html)
158
+ - [**Documentation**](https://www.attrs.org/)
159
+ - [**PyPI**](https://pypi.org/project/attrs/)
160
+ - [**Source Code**](https://github.com/python-attrs/attrs)
161
+ - [**Contributing**](https://github.com/python-attrs/attrs/blob/main/.github/CONTRIBUTING.md)
162
+ - [**Third-party Extensions**](https://github.com/python-attrs/attrs/wiki/Extensions-to-attrs)
163
+ - **Get Help**: use the `python-attrs` tag on [Stack Overflow](https://stackoverflow.com/questions/tagged/python-attrs)
164
+
165
+
166
+ ### *attrs* for Enterprise
167
+
168
+ Available as part of the [Tidelift Subscription](https://tidelift.com/?utm_source=lifter&utm_medium=referral&utm_campaign=hynek).
169
+
170
+ The maintainers of *attrs* and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications.
171
+ Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use.
172
+
173
+ ## Release Information
174
+
175
+ ### Backwards-incompatible Changes
176
+
177
+ - Class-level `kw_only=True` behavior is now consistent with `dataclasses`.
178
+
179
+ Previously, a class that sets `kw_only=True` makes all attributes keyword-only, including those from base classes.
180
+ If an attribute sets `kw_only=False`, that setting is ignored, and it is still made keyword-only.
181
+
182
+ Now, only the attributes defined in that class that doesn't explicitly set `kw_only=False` are made keyword-only.
183
+
184
+ This shouldn't be a problem for most users, unless you have a pattern like this:
185
+
186
+ ```python
187
+ @attrs.define(kw_only=True)
188
+ class Base:
189
+ a: int
190
+ b: int = attrs.field(default=1, kw_only=False)
191
+
192
+ @attrs.define
193
+ class Subclass(Base):
194
+ c: int
195
+ ```
196
+
197
+ Here, we have a `kw_only=True` *attrs* class (`Base`) with an attribute that sets `kw_only=False` and has a default (`Base.b`), and then create a subclass (`Subclass`) with required arguments (`Subclass.c`).
198
+ Previously this would work, since it would make `Base.b` keyword-only, but now this fails since `Base.b` is positional, and we have a required positional argument (`Subclass.c`) following another argument with defaults.
199
+ [#1457](https://github.com/python-attrs/attrs/issues/1457)
200
+
201
+
202
+ ### Changes
203
+
204
+ - Values passed to the `__init__()` method of `attrs` classes are now correctly passed to `__attrs_pre_init__()` instead of their default values (in cases where *kw_only* was not specified).
205
+ [#1427](https://github.com/python-attrs/attrs/issues/1427)
206
+ - Added support for Python 3.14 and [PEP 749](https://peps.python.org/pep-0749/).
207
+ [#1446](https://github.com/python-attrs/attrs/issues/1446),
208
+ [#1451](https://github.com/python-attrs/attrs/issues/1451)
209
+ - `attrs.validators.deep_mapping()` now allows to leave out either *key_validator* xor *value_validator*.
210
+ [#1448](https://github.com/python-attrs/attrs/issues/1448)
211
+ - `attrs.validators.deep_iterator()` and `attrs.validators.deep_mapping()` now accept lists and tuples for all validators and wrap them into a `attrs.validators.and_()`.
212
+ [#1449](https://github.com/python-attrs/attrs/issues/1449)
213
+ - Added a new **experimental** way to inspect classes:
214
+
215
+ `attrs.inspect(cls)` returns the _effective_ class-wide parameters that were used by *attrs* to construct the class.
216
+
217
+ The returned class is the same data structure that *attrs* uses internally to decide how to construct the final class.
218
+ [#1454](https://github.com/python-attrs/attrs/issues/1454)
219
+ - Fixed annotations for `attrs.field(converter=...)`.
220
+ Previously, a `tuple` of converters was only accepted if it had exactly one element.
221
+ [#1461](https://github.com/python-attrs/attrs/issues/1461)
222
+ - The performance of `attrs.asdict()` has been improved by 45��260%.
223
+ [#1463](https://github.com/python-attrs/attrs/issues/1463)
224
+ - The performance of `attrs.astuple()` has been improved by 49–270%.
225
+ [#1469](https://github.com/python-attrs/attrs/issues/1469)
226
+ - The type annotation for `attrs.validators.or_()` now allows for different types of validators.
227
+
228
+ This was only an issue on Pyright.
229
+ [#1474](https://github.com/python-attrs/attrs/issues/1474)
230
+
231
+
232
+
233
+ ---
234
+
235
+ [Full changelog →](https://www.attrs.org/en/stable/changelog.html)
py311/lib/python3.11/site-packages/attrs-25.4.0.dist-info/RECORD ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ attr/__init__.py,sha256=fOYIvt1eGSqQre4uCS3sJWKZ0mwAuC8UD6qba5OS9_U,2057
2
+ attr/__init__.pyi,sha256=IZkzIjvtbRqDWGkDBIF9dd12FgDa379JYq3GHnVOvFQ,11309
3
+ attr/_cmp.py,sha256=3Nn1TjxllUYiX_nJoVnEkXoDk0hM1DYKj5DE7GZe4i0,4117
4
+ attr/_cmp.pyi,sha256=U-_RU_UZOyPUEQzXE6RMYQQcjkZRY25wTH99sN0s7MM,368
5
+ attr/_compat.py,sha256=x0g7iEUOnBVJC72zyFCgb1eKqyxS-7f2LGnNyZ_r95s,2829
6
+ attr/_config.py,sha256=dGq3xR6fgZEF6UBt_L0T-eUHIB4i43kRmH0P28sJVw8,843
7
+ attr/_funcs.py,sha256=Ix5IETTfz5F01F-12MF_CSFomIn2h8b67EVVz2gCtBE,16479
8
+ attr/_make.py,sha256=NRJDGS8syg2h3YNflVNoK2FwR3CpdSZxx8M6lacwljA,104141
9
+ attr/_next_gen.py,sha256=BQtCUlzwg2gWHTYXBQvrEYBnzBUrDvO57u0Py6UCPhc,26274
10
+ attr/_typing_compat.pyi,sha256=XDP54TUn-ZKhD62TOQebmzrwFyomhUCoGRpclb6alRA,469
11
+ attr/_version_info.py,sha256=w4R-FYC3NK_kMkGUWJlYP4cVAlH9HRaC-um3fcjYkHM,2222
12
+ attr/_version_info.pyi,sha256=x_M3L3WuB7r_ULXAWjx959udKQ4HLB8l-hsc1FDGNvk,209
13
+ attr/converters.py,sha256=GlDeOzPeTFgeBBLbj9G57Ez5lAk68uhSALRYJ_exe84,3861
14
+ attr/converters.pyi,sha256=orU2bff-VjQa2kMDyvnMQV73oJT2WRyQuw4ZR1ym1bE,643
15
+ attr/exceptions.py,sha256=HRFq4iybmv7-DcZwyjl6M1euM2YeJVK_hFxuaBGAngI,1977
16
+ attr/exceptions.pyi,sha256=zZq8bCUnKAy9mDtBEw42ZhPhAUIHoTKedDQInJD883M,539
17
+ attr/filters.py,sha256=ZBiKWLp3R0LfCZsq7X11pn9WX8NslS2wXM4jsnLOGc8,1795
18
+ attr/filters.pyi,sha256=3J5BG-dTxltBk1_-RuNRUHrv2qu1v8v4aDNAQ7_mifA,208
19
+ attr/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
+ attr/setters.py,sha256=5-dcT63GQK35ONEzSgfXCkbB7pPkaR-qv15mm4PVSzQ,1617
21
+ attr/setters.pyi,sha256=NnVkaFU1BB4JB8E4JuXyrzTUgvtMpj8p3wBdJY7uix4,584
22
+ attr/validators.py,sha256=1BnYGTuYvSucGEI4ju-RPNJteVzG0ZlfWpJiWoSFHQ8,21458
23
+ attr/validators.pyi,sha256=ftmW3m4KJ3pQcIXAj-BejT7BY4ZfqrC1G-5W7XvoPds,4082
24
+ attrs-25.4.0.dist-info/INSTALLER,sha256=5hhM4Q4mYTT9z6QB6PGpUAW81PGNFrYrdXMj4oM_6ak,2
25
+ attrs-25.4.0.dist-info/METADATA,sha256=2Rerxj7agcMRxiwdkt6lC2guqHAmkGKCH13nWWK7ZoQ,10473
26
+ attrs-25.4.0.dist-info/RECORD,,
27
+ attrs-25.4.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
+ attrs-25.4.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
29
+ attrs-25.4.0.dist-info/licenses/LICENSE,sha256=iCEVyV38KvHutnFPjsbVy8q_Znyv-HKfQkINpj9xTp8,1109
30
+ attrs/__init__.py,sha256=RxaAZNwYiEh-fcvHLZNpQ_DWKni73M_jxEPEftiq1Zc,1183
31
+ attrs/__init__.pyi,sha256=2gV79g9UxJppGSM48hAZJ6h_MHb70dZoJL31ZNJeZYI,9416
32
+ attrs/converters.py,sha256=8kQljrVwfSTRu8INwEk8SI0eGrzmWftsT7rM0EqyohM,76
33
+ attrs/exceptions.py,sha256=ACCCmg19-vDFaDPY9vFl199SPXCQMN_bENs4DALjzms,76
34
+ attrs/filters.py,sha256=VOUMZug9uEU6dUuA0dF1jInUK0PL3fLgP0VBS5d-CDE,73
35
+ attrs/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
+ attrs/setters.py,sha256=eL1YidYQV3T2h9_SYIZSZR1FAcHGb1TuCTy0E0Lv2SU,73
37
+ attrs/validators.py,sha256=xcy6wD5TtTkdCG1f4XWbocPSO0faBjk5IfVJfP6SUj0,76
py311/lib/python3.11/site-packages/attrs-25.4.0.dist-info/REQUESTED ADDED
File without changes
py311/lib/python3.11/site-packages/attrs-25.4.0.dist-info/WHEEL ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.27.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any