Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- py311/lib/python3.11/site-packages/Levenshtein/StringMatcher.py +74 -0
- py311/lib/python3.11/site-packages/Levenshtein/__init__.py +550 -0
- py311/lib/python3.11/site-packages/Levenshtein/__init__.pyi +87 -0
- py311/lib/python3.11/site-packages/Levenshtein/py.typed +0 -0
- py311/lib/python3.11/site-packages/aiohappyeyeballs-2.6.1.dist-info/INSTALLER +1 -0
- py311/lib/python3.11/site-packages/aiohappyeyeballs-2.6.1.dist-info/LICENSE +279 -0
- py311/lib/python3.11/site-packages/aiohappyeyeballs-2.6.1.dist-info/METADATA +123 -0
- py311/lib/python3.11/site-packages/aiohappyeyeballs-2.6.1.dist-info/RECORD +12 -0
- py311/lib/python3.11/site-packages/aiohappyeyeballs-2.6.1.dist-info/REQUESTED +0 -0
- py311/lib/python3.11/site-packages/aiohappyeyeballs-2.6.1.dist-info/WHEEL +4 -0
- py311/lib/python3.11/site-packages/attr/__init__.py +104 -0
- py311/lib/python3.11/site-packages/attr/__init__.pyi +389 -0
- py311/lib/python3.11/site-packages/attr/__pycache__/__init__.cpython-311.pyc +0 -0
- py311/lib/python3.11/site-packages/attr/__pycache__/_cmp.cpython-311.pyc +0 -0
- py311/lib/python3.11/site-packages/attr/__pycache__/_compat.cpython-311.pyc +0 -0
- py311/lib/python3.11/site-packages/attr/__pycache__/_config.cpython-311.pyc +0 -0
- py311/lib/python3.11/site-packages/attr/__pycache__/_funcs.cpython-311.pyc +0 -0
- py311/lib/python3.11/site-packages/attr/__pycache__/_next_gen.cpython-311.pyc +0 -0
- py311/lib/python3.11/site-packages/attr/__pycache__/_version_info.cpython-311.pyc +0 -0
- py311/lib/python3.11/site-packages/attr/__pycache__/converters.cpython-311.pyc +0 -0
- py311/lib/python3.11/site-packages/attr/__pycache__/exceptions.cpython-311.pyc +0 -0
- py311/lib/python3.11/site-packages/attr/__pycache__/filters.cpython-311.pyc +0 -0
- py311/lib/python3.11/site-packages/attr/__pycache__/setters.cpython-311.pyc +0 -0
- py311/lib/python3.11/site-packages/attr/__pycache__/validators.cpython-311.pyc +0 -0
- py311/lib/python3.11/site-packages/attr/_cmp.py +160 -0
- py311/lib/python3.11/site-packages/attr/_cmp.pyi +13 -0
- py311/lib/python3.11/site-packages/attr/_compat.py +99 -0
- py311/lib/python3.11/site-packages/attr/_config.py +31 -0
- py311/lib/python3.11/site-packages/attr/_funcs.py +497 -0
- py311/lib/python3.11/site-packages/attr/_make.py +0 -0
- py311/lib/python3.11/site-packages/attr/_next_gen.py +674 -0
- py311/lib/python3.11/site-packages/attr/_typing_compat.pyi +15 -0
- py311/lib/python3.11/site-packages/attr/_version_info.py +89 -0
- py311/lib/python3.11/site-packages/attr/_version_info.pyi +9 -0
- py311/lib/python3.11/site-packages/attr/converters.py +162 -0
- py311/lib/python3.11/site-packages/attr/converters.pyi +19 -0
- py311/lib/python3.11/site-packages/attr/exceptions.py +95 -0
- py311/lib/python3.11/site-packages/attr/exceptions.pyi +17 -0
- py311/lib/python3.11/site-packages/attr/filters.py +72 -0
- py311/lib/python3.11/site-packages/attr/filters.pyi +6 -0
- py311/lib/python3.11/site-packages/attr/py.typed +0 -0
- py311/lib/python3.11/site-packages/attr/setters.py +79 -0
- py311/lib/python3.11/site-packages/attr/setters.pyi +20 -0
- py311/lib/python3.11/site-packages/attr/validators.py +748 -0
- py311/lib/python3.11/site-packages/attr/validators.pyi +140 -0
- py311/lib/python3.11/site-packages/attrs-25.4.0.dist-info/INSTALLER +1 -0
- py311/lib/python3.11/site-packages/attrs-25.4.0.dist-info/METADATA +235 -0
- py311/lib/python3.11/site-packages/attrs-25.4.0.dist-info/RECORD +37 -0
- py311/lib/python3.11/site-packages/attrs-25.4.0.dist-info/REQUESTED +0 -0
- 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&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
|