koichi12 commited on
Commit
c7d1343
·
verified ·
1 Parent(s): d353357

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +7 -0
  2. .venv/lib/python3.11/site-packages/click/__init__.py +75 -0
  3. .venv/lib/python3.11/site-packages/click/__pycache__/__init__.cpython-311.pyc +0 -0
  4. .venv/lib/python3.11/site-packages/click/__pycache__/_compat.cpython-311.pyc +0 -0
  5. .venv/lib/python3.11/site-packages/click/__pycache__/_termui_impl.cpython-311.pyc +0 -0
  6. .venv/lib/python3.11/site-packages/click/__pycache__/_textwrap.cpython-311.pyc +0 -0
  7. .venv/lib/python3.11/site-packages/click/__pycache__/decorators.cpython-311.pyc +0 -0
  8. .venv/lib/python3.11/site-packages/click/__pycache__/exceptions.cpython-311.pyc +0 -0
  9. .venv/lib/python3.11/site-packages/click/__pycache__/globals.cpython-311.pyc +0 -0
  10. .venv/lib/python3.11/site-packages/click/__pycache__/shell_completion.cpython-311.pyc +0 -0
  11. .venv/lib/python3.11/site-packages/click/__pycache__/testing.cpython-311.pyc +0 -0
  12. .venv/lib/python3.11/site-packages/click/__pycache__/types.cpython-311.pyc +0 -0
  13. .venv/lib/python3.11/site-packages/click/__pycache__/utils.cpython-311.pyc +0 -0
  14. .venv/lib/python3.11/site-packages/click/_compat.py +623 -0
  15. .venv/lib/python3.11/site-packages/click/_textwrap.py +49 -0
  16. .venv/lib/python3.11/site-packages/click/_winconsole.py +279 -0
  17. .venv/lib/python3.11/site-packages/click/core.py +0 -0
  18. .venv/lib/python3.11/site-packages/click/exceptions.py +296 -0
  19. .venv/lib/python3.11/site-packages/click/formatting.py +301 -0
  20. .venv/lib/python3.11/site-packages/click/globals.py +67 -0
  21. .venv/lib/python3.11/site-packages/click/parser.py +531 -0
  22. .venv/lib/python3.11/site-packages/click/testing.py +483 -0
  23. .venv/lib/python3.11/site-packages/click/types.py +1093 -0
  24. .venv/lib/python3.11/site-packages/fsspec-2025.2.0.dist-info/INSTALLER +1 -0
  25. .venv/lib/python3.11/site-packages/fsspec-2025.2.0.dist-info/METADATA +278 -0
  26. .venv/lib/python3.11/site-packages/fsspec-2025.2.0.dist-info/RECORD +113 -0
  27. .venv/lib/python3.11/site-packages/fsspec-2025.2.0.dist-info/WHEEL +4 -0
  28. .venv/lib/python3.11/site-packages/fsspec-2025.2.0.dist-info/licenses/LICENSE +29 -0
  29. .venv/lib/python3.11/site-packages/importlib_metadata-8.6.1.dist-info/INSTALLER +1 -0
  30. .venv/lib/python3.11/site-packages/importlib_metadata-8.6.1.dist-info/LICENSE +202 -0
  31. .venv/lib/python3.11/site-packages/importlib_metadata-8.6.1.dist-info/METADATA +133 -0
  32. .venv/lib/python3.11/site-packages/importlib_metadata-8.6.1.dist-info/RECORD +31 -0
  33. .venv/lib/python3.11/site-packages/importlib_metadata-8.6.1.dist-info/WHEEL +5 -0
  34. .venv/lib/python3.11/site-packages/importlib_metadata-8.6.1.dist-info/top_level.txt +1 -0
  35. .venv/lib/python3.11/site-packages/oauth2client-4.1.3.dist-info/INSTALLER +1 -0
  36. .venv/lib/python3.11/site-packages/oauth2client-4.1.3.dist-info/METADATA +34 -0
  37. .venv/lib/python3.11/site-packages/oauth2client-4.1.3.dist-info/RECORD +71 -0
  38. .venv/lib/python3.11/site-packages/oauth2client-4.1.3.dist-info/WHEEL +6 -0
  39. .venv/lib/python3.11/site-packages/oauth2client-4.1.3.dist-info/top_level.txt +1 -0
  40. .venv/lib/python3.11/site-packages/opencv_python_headless.libs/libavformat-d296e685.so.59.27.100 +3 -0
  41. .venv/lib/python3.11/site-packages/opencv_python_headless.libs/libcrypto-8c1ab3ad.so.1.1 +3 -0
  42. .venv/lib/python3.11/site-packages/opencv_python_headless.libs/libpng16-ef62451c.so.16.44.0 +3 -0
  43. .venv/lib/python3.11/site-packages/opencv_python_headless.libs/libquadmath-96973f99.so.0.0.0 +3 -0
  44. .venv/lib/python3.11/site-packages/opencv_python_headless.libs/libswresample-3e7db482.so.4.7.100 +3 -0
  45. .venv/lib/python3.11/site-packages/opencv_python_headless.libs/libswscale-95ddd674.so.6.7.100 +3 -0
  46. .venv/lib/python3.11/site-packages/propcache/__init__.py +32 -0
  47. .venv/lib/python3.11/site-packages/propcache/__pycache__/__init__.cpython-311.pyc +0 -0
  48. .venv/lib/python3.11/site-packages/propcache/__pycache__/_helpers.cpython-311.pyc +0 -0
  49. .venv/lib/python3.11/site-packages/propcache/__pycache__/_helpers_py.cpython-311.pyc +0 -0
  50. .venv/lib/python3.11/site-packages/propcache/__pycache__/api.cpython-311.pyc +0 -0
.gitattributes CHANGED
@@ -252,3 +252,10 @@ tuning-competition-baseline/.venv/lib/python3.11/site-packages/torch/_inductor/_
252
  .venv/lib/python3.11/site-packages/torchvision.libs/libpng16.7f72a3c5.so.16 filter=lfs diff=lfs merge=lfs -text
253
  .venv/lib/python3.11/site-packages/msgspec/_core.cpython-311-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
254
  .venv/lib/python3.11/site-packages/vllm/_moe_C.abi3.so filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
252
  .venv/lib/python3.11/site-packages/torchvision.libs/libpng16.7f72a3c5.so.16 filter=lfs diff=lfs merge=lfs -text
253
  .venv/lib/python3.11/site-packages/msgspec/_core.cpython-311-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
254
  .venv/lib/python3.11/site-packages/vllm/_moe_C.abi3.so filter=lfs diff=lfs merge=lfs -text
255
+ .venv/lib/python3.11/site-packages/opencv_python_headless.libs/libswscale-95ddd674.so.6.7.100 filter=lfs diff=lfs merge=lfs -text
256
+ .venv/lib/python3.11/site-packages/opencv_python_headless.libs/libavformat-d296e685.so.59.27.100 filter=lfs diff=lfs merge=lfs -text
257
+ .venv/lib/python3.11/site-packages/opencv_python_headless.libs/libpng16-ef62451c.so.16.44.0 filter=lfs diff=lfs merge=lfs -text
258
+ .venv/lib/python3.11/site-packages/opencv_python_headless.libs/libcrypto-8c1ab3ad.so.1.1 filter=lfs diff=lfs merge=lfs -text
259
+ .venv/lib/python3.11/site-packages/opencv_python_headless.libs/libswresample-3e7db482.so.4.7.100 filter=lfs diff=lfs merge=lfs -text
260
+ .venv/lib/python3.11/site-packages/opencv_python_headless.libs/libquadmath-96973f99.so.0.0.0 filter=lfs diff=lfs merge=lfs -text
261
+ .venv/lib/python3.11/site-packages/propcache/_helpers_c.cpython-311-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
.venv/lib/python3.11/site-packages/click/__init__.py ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Click is a simple Python module inspired by the stdlib optparse to make
3
+ writing command line scripts fun. Unlike other modules, it's based
4
+ around a simple API that does not come with too much magic and is
5
+ composable.
6
+ """
7
+
8
+ from .core import Argument as Argument
9
+ from .core import BaseCommand as BaseCommand
10
+ from .core import Command as Command
11
+ from .core import CommandCollection as CommandCollection
12
+ from .core import Context as Context
13
+ from .core import Group as Group
14
+ from .core import MultiCommand as MultiCommand
15
+ from .core import Option as Option
16
+ from .core import Parameter as Parameter
17
+ from .decorators import argument as argument
18
+ from .decorators import command as command
19
+ from .decorators import confirmation_option as confirmation_option
20
+ from .decorators import group as group
21
+ from .decorators import help_option as help_option
22
+ from .decorators import HelpOption as HelpOption
23
+ from .decorators import make_pass_decorator as make_pass_decorator
24
+ from .decorators import option as option
25
+ from .decorators import pass_context as pass_context
26
+ from .decorators import pass_obj as pass_obj
27
+ from .decorators import password_option as password_option
28
+ from .decorators import version_option as version_option
29
+ from .exceptions import Abort as Abort
30
+ from .exceptions import BadArgumentUsage as BadArgumentUsage
31
+ from .exceptions import BadOptionUsage as BadOptionUsage
32
+ from .exceptions import BadParameter as BadParameter
33
+ from .exceptions import ClickException as ClickException
34
+ from .exceptions import FileError as FileError
35
+ from .exceptions import MissingParameter as MissingParameter
36
+ from .exceptions import NoSuchOption as NoSuchOption
37
+ from .exceptions import UsageError as UsageError
38
+ from .formatting import HelpFormatter as HelpFormatter
39
+ from .formatting import wrap_text as wrap_text
40
+ from .globals import get_current_context as get_current_context
41
+ from .parser import OptionParser as OptionParser
42
+ from .termui import clear as clear
43
+ from .termui import confirm as confirm
44
+ from .termui import echo_via_pager as echo_via_pager
45
+ from .termui import edit as edit
46
+ from .termui import getchar as getchar
47
+ from .termui import launch as launch
48
+ from .termui import pause as pause
49
+ from .termui import progressbar as progressbar
50
+ from .termui import prompt as prompt
51
+ from .termui import secho as secho
52
+ from .termui import style as style
53
+ from .termui import unstyle as unstyle
54
+ from .types import BOOL as BOOL
55
+ from .types import Choice as Choice
56
+ from .types import DateTime as DateTime
57
+ from .types import File as File
58
+ from .types import FLOAT as FLOAT
59
+ from .types import FloatRange as FloatRange
60
+ from .types import INT as INT
61
+ from .types import IntRange as IntRange
62
+ from .types import ParamType as ParamType
63
+ from .types import Path as Path
64
+ from .types import STRING as STRING
65
+ from .types import Tuple as Tuple
66
+ from .types import UNPROCESSED as UNPROCESSED
67
+ from .types import UUID as UUID
68
+ from .utils import echo as echo
69
+ from .utils import format_filename as format_filename
70
+ from .utils import get_app_dir as get_app_dir
71
+ from .utils import get_binary_stream as get_binary_stream
72
+ from .utils import get_text_stream as get_text_stream
73
+ from .utils import open_file as open_file
74
+
75
+ __version__ = "8.1.8"
.venv/lib/python3.11/site-packages/click/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (3.72 kB). View file
 
.venv/lib/python3.11/site-packages/click/__pycache__/_compat.cpython-311.pyc ADDED
Binary file (28.7 kB). View file
 
.venv/lib/python3.11/site-packages/click/__pycache__/_termui_impl.cpython-311.pyc ADDED
Binary file (33.3 kB). View file
 
.venv/lib/python3.11/site-packages/click/__pycache__/_textwrap.cpython-311.pyc ADDED
Binary file (2.63 kB). View file
 
.venv/lib/python3.11/site-packages/click/__pycache__/decorators.cpython-311.pyc ADDED
Binary file (26.3 kB). View file
 
.venv/lib/python3.11/site-packages/click/__pycache__/exceptions.cpython-311.pyc ADDED
Binary file (16.3 kB). View file
 
.venv/lib/python3.11/site-packages/click/__pycache__/globals.cpython-311.pyc ADDED
Binary file (3.34 kB). View file
 
.venv/lib/python3.11/site-packages/click/__pycache__/shell_completion.cpython-311.pyc ADDED
Binary file (24.1 kB). View file
 
.venv/lib/python3.11/site-packages/click/__pycache__/testing.cpython-311.pyc ADDED
Binary file (26 kB). View file
 
.venv/lib/python3.11/site-packages/click/__pycache__/types.cpython-311.pyc ADDED
Binary file (53.7 kB). View file
 
.venv/lib/python3.11/site-packages/click/__pycache__/utils.cpython-311.pyc ADDED
Binary file (28 kB). View file
 
.venv/lib/python3.11/site-packages/click/_compat.py ADDED
@@ -0,0 +1,623 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import codecs
2
+ import io
3
+ import os
4
+ import re
5
+ import sys
6
+ import typing as t
7
+ from weakref import WeakKeyDictionary
8
+
9
+ CYGWIN = sys.platform.startswith("cygwin")
10
+ WIN = sys.platform.startswith("win")
11
+ auto_wrap_for_ansi: t.Optional[t.Callable[[t.TextIO], t.TextIO]] = None
12
+ _ansi_re = re.compile(r"\033\[[;?0-9]*[a-zA-Z]")
13
+
14
+
15
+ def _make_text_stream(
16
+ stream: t.BinaryIO,
17
+ encoding: t.Optional[str],
18
+ errors: t.Optional[str],
19
+ force_readable: bool = False,
20
+ force_writable: bool = False,
21
+ ) -> t.TextIO:
22
+ if encoding is None:
23
+ encoding = get_best_encoding(stream)
24
+ if errors is None:
25
+ errors = "replace"
26
+ return _NonClosingTextIOWrapper(
27
+ stream,
28
+ encoding,
29
+ errors,
30
+ line_buffering=True,
31
+ force_readable=force_readable,
32
+ force_writable=force_writable,
33
+ )
34
+
35
+
36
+ def is_ascii_encoding(encoding: str) -> bool:
37
+ """Checks if a given encoding is ascii."""
38
+ try:
39
+ return codecs.lookup(encoding).name == "ascii"
40
+ except LookupError:
41
+ return False
42
+
43
+
44
+ def get_best_encoding(stream: t.IO[t.Any]) -> str:
45
+ """Returns the default stream encoding if not found."""
46
+ rv = getattr(stream, "encoding", None) or sys.getdefaultencoding()
47
+ if is_ascii_encoding(rv):
48
+ return "utf-8"
49
+ return rv
50
+
51
+
52
+ class _NonClosingTextIOWrapper(io.TextIOWrapper):
53
+ def __init__(
54
+ self,
55
+ stream: t.BinaryIO,
56
+ encoding: t.Optional[str],
57
+ errors: t.Optional[str],
58
+ force_readable: bool = False,
59
+ force_writable: bool = False,
60
+ **extra: t.Any,
61
+ ) -> None:
62
+ self._stream = stream = t.cast(
63
+ t.BinaryIO, _FixupStream(stream, force_readable, force_writable)
64
+ )
65
+ super().__init__(stream, encoding, errors, **extra)
66
+
67
+ def __del__(self) -> None:
68
+ try:
69
+ self.detach()
70
+ except Exception:
71
+ pass
72
+
73
+ def isatty(self) -> bool:
74
+ # https://bitbucket.org/pypy/pypy/issue/1803
75
+ return self._stream.isatty()
76
+
77
+
78
+ class _FixupStream:
79
+ """The new io interface needs more from streams than streams
80
+ traditionally implement. As such, this fix-up code is necessary in
81
+ some circumstances.
82
+
83
+ The forcing of readable and writable flags are there because some tools
84
+ put badly patched objects on sys (one such offender are certain version
85
+ of jupyter notebook).
86
+ """
87
+
88
+ def __init__(
89
+ self,
90
+ stream: t.BinaryIO,
91
+ force_readable: bool = False,
92
+ force_writable: bool = False,
93
+ ):
94
+ self._stream = stream
95
+ self._force_readable = force_readable
96
+ self._force_writable = force_writable
97
+
98
+ def __getattr__(self, name: str) -> t.Any:
99
+ return getattr(self._stream, name)
100
+
101
+ def read1(self, size: int) -> bytes:
102
+ f = getattr(self._stream, "read1", None)
103
+
104
+ if f is not None:
105
+ return t.cast(bytes, f(size))
106
+
107
+ return self._stream.read(size)
108
+
109
+ def readable(self) -> bool:
110
+ if self._force_readable:
111
+ return True
112
+ x = getattr(self._stream, "readable", None)
113
+ if x is not None:
114
+ return t.cast(bool, x())
115
+ try:
116
+ self._stream.read(0)
117
+ except Exception:
118
+ return False
119
+ return True
120
+
121
+ def writable(self) -> bool:
122
+ if self._force_writable:
123
+ return True
124
+ x = getattr(self._stream, "writable", None)
125
+ if x is not None:
126
+ return t.cast(bool, x())
127
+ try:
128
+ self._stream.write("") # type: ignore
129
+ except Exception:
130
+ try:
131
+ self._stream.write(b"")
132
+ except Exception:
133
+ return False
134
+ return True
135
+
136
+ def seekable(self) -> bool:
137
+ x = getattr(self._stream, "seekable", None)
138
+ if x is not None:
139
+ return t.cast(bool, x())
140
+ try:
141
+ self._stream.seek(self._stream.tell())
142
+ except Exception:
143
+ return False
144
+ return True
145
+
146
+
147
+ def _is_binary_reader(stream: t.IO[t.Any], default: bool = False) -> bool:
148
+ try:
149
+ return isinstance(stream.read(0), bytes)
150
+ except Exception:
151
+ return default
152
+ # This happens in some cases where the stream was already
153
+ # closed. In this case, we assume the default.
154
+
155
+
156
+ def _is_binary_writer(stream: t.IO[t.Any], default: bool = False) -> bool:
157
+ try:
158
+ stream.write(b"")
159
+ except Exception:
160
+ try:
161
+ stream.write("")
162
+ return False
163
+ except Exception:
164
+ pass
165
+ return default
166
+ return True
167
+
168
+
169
+ def _find_binary_reader(stream: t.IO[t.Any]) -> t.Optional[t.BinaryIO]:
170
+ # We need to figure out if the given stream is already binary.
171
+ # This can happen because the official docs recommend detaching
172
+ # the streams to get binary streams. Some code might do this, so
173
+ # we need to deal with this case explicitly.
174
+ if _is_binary_reader(stream, False):
175
+ return t.cast(t.BinaryIO, stream)
176
+
177
+ buf = getattr(stream, "buffer", None)
178
+
179
+ # Same situation here; this time we assume that the buffer is
180
+ # actually binary in case it's closed.
181
+ if buf is not None and _is_binary_reader(buf, True):
182
+ return t.cast(t.BinaryIO, buf)
183
+
184
+ return None
185
+
186
+
187
+ def _find_binary_writer(stream: t.IO[t.Any]) -> t.Optional[t.BinaryIO]:
188
+ # We need to figure out if the given stream is already binary.
189
+ # This can happen because the official docs recommend detaching
190
+ # the streams to get binary streams. Some code might do this, so
191
+ # we need to deal with this case explicitly.
192
+ if _is_binary_writer(stream, False):
193
+ return t.cast(t.BinaryIO, stream)
194
+
195
+ buf = getattr(stream, "buffer", None)
196
+
197
+ # Same situation here; this time we assume that the buffer is
198
+ # actually binary in case it's closed.
199
+ if buf is not None and _is_binary_writer(buf, True):
200
+ return t.cast(t.BinaryIO, buf)
201
+
202
+ return None
203
+
204
+
205
+ def _stream_is_misconfigured(stream: t.TextIO) -> bool:
206
+ """A stream is misconfigured if its encoding is ASCII."""
207
+ # If the stream does not have an encoding set, we assume it's set
208
+ # to ASCII. This appears to happen in certain unittest
209
+ # environments. It's not quite clear what the correct behavior is
210
+ # but this at least will force Click to recover somehow.
211
+ return is_ascii_encoding(getattr(stream, "encoding", None) or "ascii")
212
+
213
+
214
+ def _is_compat_stream_attr(stream: t.TextIO, attr: str, value: t.Optional[str]) -> bool:
215
+ """A stream attribute is compatible if it is equal to the
216
+ desired value or the desired value is unset and the attribute
217
+ has a value.
218
+ """
219
+ stream_value = getattr(stream, attr, None)
220
+ return stream_value == value or (value is None and stream_value is not None)
221
+
222
+
223
+ def _is_compatible_text_stream(
224
+ stream: t.TextIO, encoding: t.Optional[str], errors: t.Optional[str]
225
+ ) -> bool:
226
+ """Check if a stream's encoding and errors attributes are
227
+ compatible with the desired values.
228
+ """
229
+ return _is_compat_stream_attr(
230
+ stream, "encoding", encoding
231
+ ) and _is_compat_stream_attr(stream, "errors", errors)
232
+
233
+
234
+ def _force_correct_text_stream(
235
+ text_stream: t.IO[t.Any],
236
+ encoding: t.Optional[str],
237
+ errors: t.Optional[str],
238
+ is_binary: t.Callable[[t.IO[t.Any], bool], bool],
239
+ find_binary: t.Callable[[t.IO[t.Any]], t.Optional[t.BinaryIO]],
240
+ force_readable: bool = False,
241
+ force_writable: bool = False,
242
+ ) -> t.TextIO:
243
+ if is_binary(text_stream, False):
244
+ binary_reader = t.cast(t.BinaryIO, text_stream)
245
+ else:
246
+ text_stream = t.cast(t.TextIO, text_stream)
247
+ # If the stream looks compatible, and won't default to a
248
+ # misconfigured ascii encoding, return it as-is.
249
+ if _is_compatible_text_stream(text_stream, encoding, errors) and not (
250
+ encoding is None and _stream_is_misconfigured(text_stream)
251
+ ):
252
+ return text_stream
253
+
254
+ # Otherwise, get the underlying binary reader.
255
+ possible_binary_reader = find_binary(text_stream)
256
+
257
+ # If that's not possible, silently use the original reader
258
+ # and get mojibake instead of exceptions.
259
+ if possible_binary_reader is None:
260
+ return text_stream
261
+
262
+ binary_reader = possible_binary_reader
263
+
264
+ # Default errors to replace instead of strict in order to get
265
+ # something that works.
266
+ if errors is None:
267
+ errors = "replace"
268
+
269
+ # Wrap the binary stream in a text stream with the correct
270
+ # encoding parameters.
271
+ return _make_text_stream(
272
+ binary_reader,
273
+ encoding,
274
+ errors,
275
+ force_readable=force_readable,
276
+ force_writable=force_writable,
277
+ )
278
+
279
+
280
+ def _force_correct_text_reader(
281
+ text_reader: t.IO[t.Any],
282
+ encoding: t.Optional[str],
283
+ errors: t.Optional[str],
284
+ force_readable: bool = False,
285
+ ) -> t.TextIO:
286
+ return _force_correct_text_stream(
287
+ text_reader,
288
+ encoding,
289
+ errors,
290
+ _is_binary_reader,
291
+ _find_binary_reader,
292
+ force_readable=force_readable,
293
+ )
294
+
295
+
296
+ def _force_correct_text_writer(
297
+ text_writer: t.IO[t.Any],
298
+ encoding: t.Optional[str],
299
+ errors: t.Optional[str],
300
+ force_writable: bool = False,
301
+ ) -> t.TextIO:
302
+ return _force_correct_text_stream(
303
+ text_writer,
304
+ encoding,
305
+ errors,
306
+ _is_binary_writer,
307
+ _find_binary_writer,
308
+ force_writable=force_writable,
309
+ )
310
+
311
+
312
+ def get_binary_stdin() -> t.BinaryIO:
313
+ reader = _find_binary_reader(sys.stdin)
314
+ if reader is None:
315
+ raise RuntimeError("Was not able to determine binary stream for sys.stdin.")
316
+ return reader
317
+
318
+
319
+ def get_binary_stdout() -> t.BinaryIO:
320
+ writer = _find_binary_writer(sys.stdout)
321
+ if writer is None:
322
+ raise RuntimeError("Was not able to determine binary stream for sys.stdout.")
323
+ return writer
324
+
325
+
326
+ def get_binary_stderr() -> t.BinaryIO:
327
+ writer = _find_binary_writer(sys.stderr)
328
+ if writer is None:
329
+ raise RuntimeError("Was not able to determine binary stream for sys.stderr.")
330
+ return writer
331
+
332
+
333
+ def get_text_stdin(
334
+ encoding: t.Optional[str] = None, errors: t.Optional[str] = None
335
+ ) -> t.TextIO:
336
+ rv = _get_windows_console_stream(sys.stdin, encoding, errors)
337
+ if rv is not None:
338
+ return rv
339
+ return _force_correct_text_reader(sys.stdin, encoding, errors, force_readable=True)
340
+
341
+
342
+ def get_text_stdout(
343
+ encoding: t.Optional[str] = None, errors: t.Optional[str] = None
344
+ ) -> t.TextIO:
345
+ rv = _get_windows_console_stream(sys.stdout, encoding, errors)
346
+ if rv is not None:
347
+ return rv
348
+ return _force_correct_text_writer(sys.stdout, encoding, errors, force_writable=True)
349
+
350
+
351
+ def get_text_stderr(
352
+ encoding: t.Optional[str] = None, errors: t.Optional[str] = None
353
+ ) -> t.TextIO:
354
+ rv = _get_windows_console_stream(sys.stderr, encoding, errors)
355
+ if rv is not None:
356
+ return rv
357
+ return _force_correct_text_writer(sys.stderr, encoding, errors, force_writable=True)
358
+
359
+
360
+ def _wrap_io_open(
361
+ file: t.Union[str, "os.PathLike[str]", int],
362
+ mode: str,
363
+ encoding: t.Optional[str],
364
+ errors: t.Optional[str],
365
+ ) -> t.IO[t.Any]:
366
+ """Handles not passing ``encoding`` and ``errors`` in binary mode."""
367
+ if "b" in mode:
368
+ return open(file, mode)
369
+
370
+ return open(file, mode, encoding=encoding, errors=errors)
371
+
372
+
373
+ def open_stream(
374
+ filename: "t.Union[str, os.PathLike[str]]",
375
+ mode: str = "r",
376
+ encoding: t.Optional[str] = None,
377
+ errors: t.Optional[str] = "strict",
378
+ atomic: bool = False,
379
+ ) -> t.Tuple[t.IO[t.Any], bool]:
380
+ binary = "b" in mode
381
+ filename = os.fspath(filename)
382
+
383
+ # Standard streams first. These are simple because they ignore the
384
+ # atomic flag. Use fsdecode to handle Path("-").
385
+ if os.fsdecode(filename) == "-":
386
+ if any(m in mode for m in ["w", "a", "x"]):
387
+ if binary:
388
+ return get_binary_stdout(), False
389
+ return get_text_stdout(encoding=encoding, errors=errors), False
390
+ if binary:
391
+ return get_binary_stdin(), False
392
+ return get_text_stdin(encoding=encoding, errors=errors), False
393
+
394
+ # Non-atomic writes directly go out through the regular open functions.
395
+ if not atomic:
396
+ return _wrap_io_open(filename, mode, encoding, errors), True
397
+
398
+ # Some usability stuff for atomic writes
399
+ if "a" in mode:
400
+ raise ValueError(
401
+ "Appending to an existing file is not supported, because that"
402
+ " would involve an expensive `copy`-operation to a temporary"
403
+ " file. Open the file in normal `w`-mode and copy explicitly"
404
+ " if that's what you're after."
405
+ )
406
+ if "x" in mode:
407
+ raise ValueError("Use the `overwrite`-parameter instead.")
408
+ if "w" not in mode:
409
+ raise ValueError("Atomic writes only make sense with `w`-mode.")
410
+
411
+ # Atomic writes are more complicated. They work by opening a file
412
+ # as a proxy in the same folder and then using the fdopen
413
+ # functionality to wrap it in a Python file. Then we wrap it in an
414
+ # atomic file that moves the file over on close.
415
+ import errno
416
+ import random
417
+
418
+ try:
419
+ perm: t.Optional[int] = os.stat(filename).st_mode
420
+ except OSError:
421
+ perm = None
422
+
423
+ flags = os.O_RDWR | os.O_CREAT | os.O_EXCL
424
+
425
+ if binary:
426
+ flags |= getattr(os, "O_BINARY", 0)
427
+
428
+ while True:
429
+ tmp_filename = os.path.join(
430
+ os.path.dirname(filename),
431
+ f".__atomic-write{random.randrange(1 << 32):08x}",
432
+ )
433
+ try:
434
+ fd = os.open(tmp_filename, flags, 0o666 if perm is None else perm)
435
+ break
436
+ except OSError as e:
437
+ if e.errno == errno.EEXIST or (
438
+ os.name == "nt"
439
+ and e.errno == errno.EACCES
440
+ and os.path.isdir(e.filename)
441
+ and os.access(e.filename, os.W_OK)
442
+ ):
443
+ continue
444
+ raise
445
+
446
+ if perm is not None:
447
+ os.chmod(tmp_filename, perm) # in case perm includes bits in umask
448
+
449
+ f = _wrap_io_open(fd, mode, encoding, errors)
450
+ af = _AtomicFile(f, tmp_filename, os.path.realpath(filename))
451
+ return t.cast(t.IO[t.Any], af), True
452
+
453
+
454
+ class _AtomicFile:
455
+ def __init__(self, f: t.IO[t.Any], tmp_filename: str, real_filename: str) -> None:
456
+ self._f = f
457
+ self._tmp_filename = tmp_filename
458
+ self._real_filename = real_filename
459
+ self.closed = False
460
+
461
+ @property
462
+ def name(self) -> str:
463
+ return self._real_filename
464
+
465
+ def close(self, delete: bool = False) -> None:
466
+ if self.closed:
467
+ return
468
+ self._f.close()
469
+ os.replace(self._tmp_filename, self._real_filename)
470
+ self.closed = True
471
+
472
+ def __getattr__(self, name: str) -> t.Any:
473
+ return getattr(self._f, name)
474
+
475
+ def __enter__(self) -> "_AtomicFile":
476
+ return self
477
+
478
+ def __exit__(self, exc_type: t.Optional[t.Type[BaseException]], *_: t.Any) -> None:
479
+ self.close(delete=exc_type is not None)
480
+
481
+ def __repr__(self) -> str:
482
+ return repr(self._f)
483
+
484
+
485
+ def strip_ansi(value: str) -> str:
486
+ return _ansi_re.sub("", value)
487
+
488
+
489
+ def _is_jupyter_kernel_output(stream: t.IO[t.Any]) -> bool:
490
+ while isinstance(stream, (_FixupStream, _NonClosingTextIOWrapper)):
491
+ stream = stream._stream
492
+
493
+ return stream.__class__.__module__.startswith("ipykernel.")
494
+
495
+
496
+ def should_strip_ansi(
497
+ stream: t.Optional[t.IO[t.Any]] = None, color: t.Optional[bool] = None
498
+ ) -> bool:
499
+ if color is None:
500
+ if stream is None:
501
+ stream = sys.stdin
502
+ return not isatty(stream) and not _is_jupyter_kernel_output(stream)
503
+ return not color
504
+
505
+
506
+ # On Windows, wrap the output streams with colorama to support ANSI
507
+ # color codes.
508
+ # NOTE: double check is needed so mypy does not analyze this on Linux
509
+ if sys.platform.startswith("win") and WIN:
510
+ from ._winconsole import _get_windows_console_stream
511
+
512
+ def _get_argv_encoding() -> str:
513
+ import locale
514
+
515
+ return locale.getpreferredencoding()
516
+
517
+ _ansi_stream_wrappers: t.MutableMapping[t.TextIO, t.TextIO] = WeakKeyDictionary()
518
+
519
+ def auto_wrap_for_ansi(
520
+ stream: t.TextIO, color: t.Optional[bool] = None
521
+ ) -> t.TextIO:
522
+ """Support ANSI color and style codes on Windows by wrapping a
523
+ stream with colorama.
524
+ """
525
+ try:
526
+ cached = _ansi_stream_wrappers.get(stream)
527
+ except Exception:
528
+ cached = None
529
+
530
+ if cached is not None:
531
+ return cached
532
+
533
+ import colorama
534
+
535
+ strip = should_strip_ansi(stream, color)
536
+ ansi_wrapper = colorama.AnsiToWin32(stream, strip=strip)
537
+ rv = t.cast(t.TextIO, ansi_wrapper.stream)
538
+ _write = rv.write
539
+
540
+ def _safe_write(s):
541
+ try:
542
+ return _write(s)
543
+ except BaseException:
544
+ ansi_wrapper.reset_all()
545
+ raise
546
+
547
+ rv.write = _safe_write
548
+
549
+ try:
550
+ _ansi_stream_wrappers[stream] = rv
551
+ except Exception:
552
+ pass
553
+
554
+ return rv
555
+
556
+ else:
557
+
558
+ def _get_argv_encoding() -> str:
559
+ return getattr(sys.stdin, "encoding", None) or sys.getfilesystemencoding()
560
+
561
+ def _get_windows_console_stream(
562
+ f: t.TextIO, encoding: t.Optional[str], errors: t.Optional[str]
563
+ ) -> t.Optional[t.TextIO]:
564
+ return None
565
+
566
+
567
+ def term_len(x: str) -> int:
568
+ return len(strip_ansi(x))
569
+
570
+
571
+ def isatty(stream: t.IO[t.Any]) -> bool:
572
+ try:
573
+ return stream.isatty()
574
+ except Exception:
575
+ return False
576
+
577
+
578
+ def _make_cached_stream_func(
579
+ src_func: t.Callable[[], t.Optional[t.TextIO]],
580
+ wrapper_func: t.Callable[[], t.TextIO],
581
+ ) -> t.Callable[[], t.Optional[t.TextIO]]:
582
+ cache: t.MutableMapping[t.TextIO, t.TextIO] = WeakKeyDictionary()
583
+
584
+ def func() -> t.Optional[t.TextIO]:
585
+ stream = src_func()
586
+
587
+ if stream is None:
588
+ return None
589
+
590
+ try:
591
+ rv = cache.get(stream)
592
+ except Exception:
593
+ rv = None
594
+ if rv is not None:
595
+ return rv
596
+ rv = wrapper_func()
597
+ try:
598
+ cache[stream] = rv
599
+ except Exception:
600
+ pass
601
+ return rv
602
+
603
+ return func
604
+
605
+
606
+ _default_text_stdin = _make_cached_stream_func(lambda: sys.stdin, get_text_stdin)
607
+ _default_text_stdout = _make_cached_stream_func(lambda: sys.stdout, get_text_stdout)
608
+ _default_text_stderr = _make_cached_stream_func(lambda: sys.stderr, get_text_stderr)
609
+
610
+
611
+ binary_streams: t.Mapping[str, t.Callable[[], t.BinaryIO]] = {
612
+ "stdin": get_binary_stdin,
613
+ "stdout": get_binary_stdout,
614
+ "stderr": get_binary_stderr,
615
+ }
616
+
617
+ text_streams: t.Mapping[
618
+ str, t.Callable[[t.Optional[str], t.Optional[str]], t.TextIO]
619
+ ] = {
620
+ "stdin": get_text_stdin,
621
+ "stdout": get_text_stdout,
622
+ "stderr": get_text_stderr,
623
+ }
.venv/lib/python3.11/site-packages/click/_textwrap.py ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import textwrap
2
+ import typing as t
3
+ from contextlib import contextmanager
4
+
5
+
6
+ class TextWrapper(textwrap.TextWrapper):
7
+ def _handle_long_word(
8
+ self,
9
+ reversed_chunks: t.List[str],
10
+ cur_line: t.List[str],
11
+ cur_len: int,
12
+ width: int,
13
+ ) -> None:
14
+ space_left = max(width - cur_len, 1)
15
+
16
+ if self.break_long_words:
17
+ last = reversed_chunks[-1]
18
+ cut = last[:space_left]
19
+ res = last[space_left:]
20
+ cur_line.append(cut)
21
+ reversed_chunks[-1] = res
22
+ elif not cur_line:
23
+ cur_line.append(reversed_chunks.pop())
24
+
25
+ @contextmanager
26
+ def extra_indent(self, indent: str) -> t.Iterator[None]:
27
+ old_initial_indent = self.initial_indent
28
+ old_subsequent_indent = self.subsequent_indent
29
+ self.initial_indent += indent
30
+ self.subsequent_indent += indent
31
+
32
+ try:
33
+ yield
34
+ finally:
35
+ self.initial_indent = old_initial_indent
36
+ self.subsequent_indent = old_subsequent_indent
37
+
38
+ def indent_only(self, text: str) -> str:
39
+ rv = []
40
+
41
+ for idx, line in enumerate(text.splitlines()):
42
+ indent = self.initial_indent
43
+
44
+ if idx > 0:
45
+ indent = self.subsequent_indent
46
+
47
+ rv.append(f"{indent}{line}")
48
+
49
+ return "\n".join(rv)
.venv/lib/python3.11/site-packages/click/_winconsole.py ADDED
@@ -0,0 +1,279 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # This module is based on the excellent work by Adam Bartoš who
2
+ # provided a lot of what went into the implementation here in
3
+ # the discussion to issue1602 in the Python bug tracker.
4
+ #
5
+ # There are some general differences in regards to how this works
6
+ # compared to the original patches as we do not need to patch
7
+ # the entire interpreter but just work in our little world of
8
+ # echo and prompt.
9
+ import io
10
+ import sys
11
+ import time
12
+ import typing as t
13
+ from ctypes import byref
14
+ from ctypes import c_char
15
+ from ctypes import c_char_p
16
+ from ctypes import c_int
17
+ from ctypes import c_ssize_t
18
+ from ctypes import c_ulong
19
+ from ctypes import c_void_p
20
+ from ctypes import POINTER
21
+ from ctypes import py_object
22
+ from ctypes import Structure
23
+ from ctypes.wintypes import DWORD
24
+ from ctypes.wintypes import HANDLE
25
+ from ctypes.wintypes import LPCWSTR
26
+ from ctypes.wintypes import LPWSTR
27
+
28
+ from ._compat import _NonClosingTextIOWrapper
29
+
30
+ assert sys.platform == "win32"
31
+ import msvcrt # noqa: E402
32
+ from ctypes import windll # noqa: E402
33
+ from ctypes import WINFUNCTYPE # noqa: E402
34
+
35
+ c_ssize_p = POINTER(c_ssize_t)
36
+
37
+ kernel32 = windll.kernel32
38
+ GetStdHandle = kernel32.GetStdHandle
39
+ ReadConsoleW = kernel32.ReadConsoleW
40
+ WriteConsoleW = kernel32.WriteConsoleW
41
+ GetConsoleMode = kernel32.GetConsoleMode
42
+ GetLastError = kernel32.GetLastError
43
+ GetCommandLineW = WINFUNCTYPE(LPWSTR)(("GetCommandLineW", windll.kernel32))
44
+ CommandLineToArgvW = WINFUNCTYPE(POINTER(LPWSTR), LPCWSTR, POINTER(c_int))(
45
+ ("CommandLineToArgvW", windll.shell32)
46
+ )
47
+ LocalFree = WINFUNCTYPE(c_void_p, c_void_p)(("LocalFree", windll.kernel32))
48
+
49
+ STDIN_HANDLE = GetStdHandle(-10)
50
+ STDOUT_HANDLE = GetStdHandle(-11)
51
+ STDERR_HANDLE = GetStdHandle(-12)
52
+
53
+ PyBUF_SIMPLE = 0
54
+ PyBUF_WRITABLE = 1
55
+
56
+ ERROR_SUCCESS = 0
57
+ ERROR_NOT_ENOUGH_MEMORY = 8
58
+ ERROR_OPERATION_ABORTED = 995
59
+
60
+ STDIN_FILENO = 0
61
+ STDOUT_FILENO = 1
62
+ STDERR_FILENO = 2
63
+
64
+ EOF = b"\x1a"
65
+ MAX_BYTES_WRITTEN = 32767
66
+
67
+ try:
68
+ from ctypes import pythonapi
69
+ except ImportError:
70
+ # On PyPy we cannot get buffers so our ability to operate here is
71
+ # severely limited.
72
+ get_buffer = None
73
+ else:
74
+
75
+ class Py_buffer(Structure):
76
+ _fields_ = [
77
+ ("buf", c_void_p),
78
+ ("obj", py_object),
79
+ ("len", c_ssize_t),
80
+ ("itemsize", c_ssize_t),
81
+ ("readonly", c_int),
82
+ ("ndim", c_int),
83
+ ("format", c_char_p),
84
+ ("shape", c_ssize_p),
85
+ ("strides", c_ssize_p),
86
+ ("suboffsets", c_ssize_p),
87
+ ("internal", c_void_p),
88
+ ]
89
+
90
+ PyObject_GetBuffer = pythonapi.PyObject_GetBuffer
91
+ PyBuffer_Release = pythonapi.PyBuffer_Release
92
+
93
+ def get_buffer(obj, writable=False):
94
+ buf = Py_buffer()
95
+ flags = PyBUF_WRITABLE if writable else PyBUF_SIMPLE
96
+ PyObject_GetBuffer(py_object(obj), byref(buf), flags)
97
+
98
+ try:
99
+ buffer_type = c_char * buf.len
100
+ return buffer_type.from_address(buf.buf)
101
+ finally:
102
+ PyBuffer_Release(byref(buf))
103
+
104
+
105
+ class _WindowsConsoleRawIOBase(io.RawIOBase):
106
+ def __init__(self, handle):
107
+ self.handle = handle
108
+
109
+ def isatty(self):
110
+ super().isatty()
111
+ return True
112
+
113
+
114
+ class _WindowsConsoleReader(_WindowsConsoleRawIOBase):
115
+ def readable(self):
116
+ return True
117
+
118
+ def readinto(self, b):
119
+ bytes_to_be_read = len(b)
120
+ if not bytes_to_be_read:
121
+ return 0
122
+ elif bytes_to_be_read % 2:
123
+ raise ValueError(
124
+ "cannot read odd number of bytes from UTF-16-LE encoded console"
125
+ )
126
+
127
+ buffer = get_buffer(b, writable=True)
128
+ code_units_to_be_read = bytes_to_be_read // 2
129
+ code_units_read = c_ulong()
130
+
131
+ rv = ReadConsoleW(
132
+ HANDLE(self.handle),
133
+ buffer,
134
+ code_units_to_be_read,
135
+ byref(code_units_read),
136
+ None,
137
+ )
138
+ if GetLastError() == ERROR_OPERATION_ABORTED:
139
+ # wait for KeyboardInterrupt
140
+ time.sleep(0.1)
141
+ if not rv:
142
+ raise OSError(f"Windows error: {GetLastError()}")
143
+
144
+ if buffer[0] == EOF:
145
+ return 0
146
+ return 2 * code_units_read.value
147
+
148
+
149
+ class _WindowsConsoleWriter(_WindowsConsoleRawIOBase):
150
+ def writable(self):
151
+ return True
152
+
153
+ @staticmethod
154
+ def _get_error_message(errno):
155
+ if errno == ERROR_SUCCESS:
156
+ return "ERROR_SUCCESS"
157
+ elif errno == ERROR_NOT_ENOUGH_MEMORY:
158
+ return "ERROR_NOT_ENOUGH_MEMORY"
159
+ return f"Windows error {errno}"
160
+
161
+ def write(self, b):
162
+ bytes_to_be_written = len(b)
163
+ buf = get_buffer(b)
164
+ code_units_to_be_written = min(bytes_to_be_written, MAX_BYTES_WRITTEN) // 2
165
+ code_units_written = c_ulong()
166
+
167
+ WriteConsoleW(
168
+ HANDLE(self.handle),
169
+ buf,
170
+ code_units_to_be_written,
171
+ byref(code_units_written),
172
+ None,
173
+ )
174
+ bytes_written = 2 * code_units_written.value
175
+
176
+ if bytes_written == 0 and bytes_to_be_written > 0:
177
+ raise OSError(self._get_error_message(GetLastError()))
178
+ return bytes_written
179
+
180
+
181
+ class ConsoleStream:
182
+ def __init__(self, text_stream: t.TextIO, byte_stream: t.BinaryIO) -> None:
183
+ self._text_stream = text_stream
184
+ self.buffer = byte_stream
185
+
186
+ @property
187
+ def name(self) -> str:
188
+ return self.buffer.name
189
+
190
+ def write(self, x: t.AnyStr) -> int:
191
+ if isinstance(x, str):
192
+ return self._text_stream.write(x)
193
+ try:
194
+ self.flush()
195
+ except Exception:
196
+ pass
197
+ return self.buffer.write(x)
198
+
199
+ def writelines(self, lines: t.Iterable[t.AnyStr]) -> None:
200
+ for line in lines:
201
+ self.write(line)
202
+
203
+ def __getattr__(self, name: str) -> t.Any:
204
+ return getattr(self._text_stream, name)
205
+
206
+ def isatty(self) -> bool:
207
+ return self.buffer.isatty()
208
+
209
+ def __repr__(self):
210
+ return f"<ConsoleStream name={self.name!r} encoding={self.encoding!r}>"
211
+
212
+
213
+ def _get_text_stdin(buffer_stream: t.BinaryIO) -> t.TextIO:
214
+ text_stream = _NonClosingTextIOWrapper(
215
+ io.BufferedReader(_WindowsConsoleReader(STDIN_HANDLE)),
216
+ "utf-16-le",
217
+ "strict",
218
+ line_buffering=True,
219
+ )
220
+ return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream))
221
+
222
+
223
+ def _get_text_stdout(buffer_stream: t.BinaryIO) -> t.TextIO:
224
+ text_stream = _NonClosingTextIOWrapper(
225
+ io.BufferedWriter(_WindowsConsoleWriter(STDOUT_HANDLE)),
226
+ "utf-16-le",
227
+ "strict",
228
+ line_buffering=True,
229
+ )
230
+ return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream))
231
+
232
+
233
+ def _get_text_stderr(buffer_stream: t.BinaryIO) -> t.TextIO:
234
+ text_stream = _NonClosingTextIOWrapper(
235
+ io.BufferedWriter(_WindowsConsoleWriter(STDERR_HANDLE)),
236
+ "utf-16-le",
237
+ "strict",
238
+ line_buffering=True,
239
+ )
240
+ return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream))
241
+
242
+
243
+ _stream_factories: t.Mapping[int, t.Callable[[t.BinaryIO], t.TextIO]] = {
244
+ 0: _get_text_stdin,
245
+ 1: _get_text_stdout,
246
+ 2: _get_text_stderr,
247
+ }
248
+
249
+
250
+ def _is_console(f: t.TextIO) -> bool:
251
+ if not hasattr(f, "fileno"):
252
+ return False
253
+
254
+ try:
255
+ fileno = f.fileno()
256
+ except (OSError, io.UnsupportedOperation):
257
+ return False
258
+
259
+ handle = msvcrt.get_osfhandle(fileno)
260
+ return bool(GetConsoleMode(handle, byref(DWORD())))
261
+
262
+
263
+ def _get_windows_console_stream(
264
+ f: t.TextIO, encoding: t.Optional[str], errors: t.Optional[str]
265
+ ) -> t.Optional[t.TextIO]:
266
+ if (
267
+ get_buffer is not None
268
+ and encoding in {"utf-16-le", None}
269
+ and errors in {"strict", None}
270
+ and _is_console(f)
271
+ ):
272
+ func = _stream_factories.get(f.fileno())
273
+ if func is not None:
274
+ b = getattr(f, "buffer", None)
275
+
276
+ if b is None:
277
+ return None
278
+
279
+ return func(b)
.venv/lib/python3.11/site-packages/click/core.py ADDED
The diff for this file is too large to render. See raw diff
 
.venv/lib/python3.11/site-packages/click/exceptions.py ADDED
@@ -0,0 +1,296 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import typing as t
2
+ from gettext import gettext as _
3
+ from gettext import ngettext
4
+
5
+ from ._compat import get_text_stderr
6
+ from .globals import resolve_color_default
7
+ from .utils import echo
8
+ from .utils import format_filename
9
+
10
+ if t.TYPE_CHECKING:
11
+ from .core import Command
12
+ from .core import Context
13
+ from .core import Parameter
14
+
15
+
16
+ def _join_param_hints(
17
+ param_hint: t.Optional[t.Union[t.Sequence[str], str]],
18
+ ) -> t.Optional[str]:
19
+ if param_hint is not None and not isinstance(param_hint, str):
20
+ return " / ".join(repr(x) for x in param_hint)
21
+
22
+ return param_hint
23
+
24
+
25
+ class ClickException(Exception):
26
+ """An exception that Click can handle and show to the user."""
27
+
28
+ #: The exit code for this exception.
29
+ exit_code = 1
30
+
31
+ def __init__(self, message: str) -> None:
32
+ super().__init__(message)
33
+ # The context will be removed by the time we print the message, so cache
34
+ # the color settings here to be used later on (in `show`)
35
+ self.show_color: t.Optional[bool] = resolve_color_default()
36
+ self.message = message
37
+
38
+ def format_message(self) -> str:
39
+ return self.message
40
+
41
+ def __str__(self) -> str:
42
+ return self.message
43
+
44
+ def show(self, file: t.Optional[t.IO[t.Any]] = None) -> None:
45
+ if file is None:
46
+ file = get_text_stderr()
47
+
48
+ echo(
49
+ _("Error: {message}").format(message=self.format_message()),
50
+ file=file,
51
+ color=self.show_color,
52
+ )
53
+
54
+
55
+ class UsageError(ClickException):
56
+ """An internal exception that signals a usage error. This typically
57
+ aborts any further handling.
58
+
59
+ :param message: the error message to display.
60
+ :param ctx: optionally the context that caused this error. Click will
61
+ fill in the context automatically in some situations.
62
+ """
63
+
64
+ exit_code = 2
65
+
66
+ def __init__(self, message: str, ctx: t.Optional["Context"] = None) -> None:
67
+ super().__init__(message)
68
+ self.ctx = ctx
69
+ self.cmd: t.Optional[Command] = self.ctx.command if self.ctx else None
70
+
71
+ def show(self, file: t.Optional[t.IO[t.Any]] = None) -> None:
72
+ if file is None:
73
+ file = get_text_stderr()
74
+ color = None
75
+ hint = ""
76
+ if (
77
+ self.ctx is not None
78
+ and self.ctx.command.get_help_option(self.ctx) is not None
79
+ ):
80
+ hint = _("Try '{command} {option}' for help.").format(
81
+ command=self.ctx.command_path, option=self.ctx.help_option_names[0]
82
+ )
83
+ hint = f"{hint}\n"
84
+ if self.ctx is not None:
85
+ color = self.ctx.color
86
+ echo(f"{self.ctx.get_usage()}\n{hint}", file=file, color=color)
87
+ echo(
88
+ _("Error: {message}").format(message=self.format_message()),
89
+ file=file,
90
+ color=color,
91
+ )
92
+
93
+
94
+ class BadParameter(UsageError):
95
+ """An exception that formats out a standardized error message for a
96
+ bad parameter. This is useful when thrown from a callback or type as
97
+ Click will attach contextual information to it (for instance, which
98
+ parameter it is).
99
+
100
+ .. versionadded:: 2.0
101
+
102
+ :param param: the parameter object that caused this error. This can
103
+ be left out, and Click will attach this info itself
104
+ if possible.
105
+ :param param_hint: a string that shows up as parameter name. This
106
+ can be used as alternative to `param` in cases
107
+ where custom validation should happen. If it is
108
+ a string it's used as such, if it's a list then
109
+ each item is quoted and separated.
110
+ """
111
+
112
+ def __init__(
113
+ self,
114
+ message: str,
115
+ ctx: t.Optional["Context"] = None,
116
+ param: t.Optional["Parameter"] = None,
117
+ param_hint: t.Optional[str] = None,
118
+ ) -> None:
119
+ super().__init__(message, ctx)
120
+ self.param = param
121
+ self.param_hint = param_hint
122
+
123
+ def format_message(self) -> str:
124
+ if self.param_hint is not None:
125
+ param_hint = self.param_hint
126
+ elif self.param is not None:
127
+ param_hint = self.param.get_error_hint(self.ctx) # type: ignore
128
+ else:
129
+ return _("Invalid value: {message}").format(message=self.message)
130
+
131
+ return _("Invalid value for {param_hint}: {message}").format(
132
+ param_hint=_join_param_hints(param_hint), message=self.message
133
+ )
134
+
135
+
136
+ class MissingParameter(BadParameter):
137
+ """Raised if click required an option or argument but it was not
138
+ provided when invoking the script.
139
+
140
+ .. versionadded:: 4.0
141
+
142
+ :param param_type: a string that indicates the type of the parameter.
143
+ The default is to inherit the parameter type from
144
+ the given `param`. Valid values are ``'parameter'``,
145
+ ``'option'`` or ``'argument'``.
146
+ """
147
+
148
+ def __init__(
149
+ self,
150
+ message: t.Optional[str] = None,
151
+ ctx: t.Optional["Context"] = None,
152
+ param: t.Optional["Parameter"] = None,
153
+ param_hint: t.Optional[str] = None,
154
+ param_type: t.Optional[str] = None,
155
+ ) -> None:
156
+ super().__init__(message or "", ctx, param, param_hint)
157
+ self.param_type = param_type
158
+
159
+ def format_message(self) -> str:
160
+ if self.param_hint is not None:
161
+ param_hint: t.Optional[str] = self.param_hint
162
+ elif self.param is not None:
163
+ param_hint = self.param.get_error_hint(self.ctx) # type: ignore
164
+ else:
165
+ param_hint = None
166
+
167
+ param_hint = _join_param_hints(param_hint)
168
+ param_hint = f" {param_hint}" if param_hint else ""
169
+
170
+ param_type = self.param_type
171
+ if param_type is None and self.param is not None:
172
+ param_type = self.param.param_type_name
173
+
174
+ msg = self.message
175
+ if self.param is not None:
176
+ msg_extra = self.param.type.get_missing_message(self.param)
177
+ if msg_extra:
178
+ if msg:
179
+ msg += f". {msg_extra}"
180
+ else:
181
+ msg = msg_extra
182
+
183
+ msg = f" {msg}" if msg else ""
184
+
185
+ # Translate param_type for known types.
186
+ if param_type == "argument":
187
+ missing = _("Missing argument")
188
+ elif param_type == "option":
189
+ missing = _("Missing option")
190
+ elif param_type == "parameter":
191
+ missing = _("Missing parameter")
192
+ else:
193
+ missing = _("Missing {param_type}").format(param_type=param_type)
194
+
195
+ return f"{missing}{param_hint}.{msg}"
196
+
197
+ def __str__(self) -> str:
198
+ if not self.message:
199
+ param_name = self.param.name if self.param else None
200
+ return _("Missing parameter: {param_name}").format(param_name=param_name)
201
+ else:
202
+ return self.message
203
+
204
+
205
+ class NoSuchOption(UsageError):
206
+ """Raised if click attempted to handle an option that does not
207
+ exist.
208
+
209
+ .. versionadded:: 4.0
210
+ """
211
+
212
+ def __init__(
213
+ self,
214
+ option_name: str,
215
+ message: t.Optional[str] = None,
216
+ possibilities: t.Optional[t.Sequence[str]] = None,
217
+ ctx: t.Optional["Context"] = None,
218
+ ) -> None:
219
+ if message is None:
220
+ message = _("No such option: {name}").format(name=option_name)
221
+
222
+ super().__init__(message, ctx)
223
+ self.option_name = option_name
224
+ self.possibilities = possibilities
225
+
226
+ def format_message(self) -> str:
227
+ if not self.possibilities:
228
+ return self.message
229
+
230
+ possibility_str = ", ".join(sorted(self.possibilities))
231
+ suggest = ngettext(
232
+ "Did you mean {possibility}?",
233
+ "(Possible options: {possibilities})",
234
+ len(self.possibilities),
235
+ ).format(possibility=possibility_str, possibilities=possibility_str)
236
+ return f"{self.message} {suggest}"
237
+
238
+
239
+ class BadOptionUsage(UsageError):
240
+ """Raised if an option is generally supplied but the use of the option
241
+ was incorrect. This is for instance raised if the number of arguments
242
+ for an option is not correct.
243
+
244
+ .. versionadded:: 4.0
245
+
246
+ :param option_name: the name of the option being used incorrectly.
247
+ """
248
+
249
+ def __init__(
250
+ self, option_name: str, message: str, ctx: t.Optional["Context"] = None
251
+ ) -> None:
252
+ super().__init__(message, ctx)
253
+ self.option_name = option_name
254
+
255
+
256
+ class BadArgumentUsage(UsageError):
257
+ """Raised if an argument is generally supplied but the use of the argument
258
+ was incorrect. This is for instance raised if the number of values
259
+ for an argument is not correct.
260
+
261
+ .. versionadded:: 6.0
262
+ """
263
+
264
+
265
+ class FileError(ClickException):
266
+ """Raised if a file cannot be opened."""
267
+
268
+ def __init__(self, filename: str, hint: t.Optional[str] = None) -> None:
269
+ if hint is None:
270
+ hint = _("unknown error")
271
+
272
+ super().__init__(hint)
273
+ self.ui_filename: str = format_filename(filename)
274
+ self.filename = filename
275
+
276
+ def format_message(self) -> str:
277
+ return _("Could not open file {filename!r}: {message}").format(
278
+ filename=self.ui_filename, message=self.message
279
+ )
280
+
281
+
282
+ class Abort(RuntimeError):
283
+ """An internal signalling exception that signals Click to abort."""
284
+
285
+
286
+ class Exit(RuntimeError):
287
+ """An exception that indicates that the application should exit with some
288
+ status code.
289
+
290
+ :param code: the status code to exit with.
291
+ """
292
+
293
+ __slots__ = ("exit_code",)
294
+
295
+ def __init__(self, code: int = 0) -> None:
296
+ self.exit_code: int = code
.venv/lib/python3.11/site-packages/click/formatting.py ADDED
@@ -0,0 +1,301 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import typing as t
2
+ from contextlib import contextmanager
3
+ from gettext import gettext as _
4
+
5
+ from ._compat import term_len
6
+ from .parser import split_opt
7
+
8
+ # Can force a width. This is used by the test system
9
+ FORCED_WIDTH: t.Optional[int] = None
10
+
11
+
12
+ def measure_table(rows: t.Iterable[t.Tuple[str, str]]) -> t.Tuple[int, ...]:
13
+ widths: t.Dict[int, int] = {}
14
+
15
+ for row in rows:
16
+ for idx, col in enumerate(row):
17
+ widths[idx] = max(widths.get(idx, 0), term_len(col))
18
+
19
+ return tuple(y for x, y in sorted(widths.items()))
20
+
21
+
22
+ def iter_rows(
23
+ rows: t.Iterable[t.Tuple[str, str]], col_count: int
24
+ ) -> t.Iterator[t.Tuple[str, ...]]:
25
+ for row in rows:
26
+ yield row + ("",) * (col_count - len(row))
27
+
28
+
29
+ def wrap_text(
30
+ text: str,
31
+ width: int = 78,
32
+ initial_indent: str = "",
33
+ subsequent_indent: str = "",
34
+ preserve_paragraphs: bool = False,
35
+ ) -> str:
36
+ """A helper function that intelligently wraps text. By default, it
37
+ assumes that it operates on a single paragraph of text but if the
38
+ `preserve_paragraphs` parameter is provided it will intelligently
39
+ handle paragraphs (defined by two empty lines).
40
+
41
+ If paragraphs are handled, a paragraph can be prefixed with an empty
42
+ line containing the ``\\b`` character (``\\x08``) to indicate that
43
+ no rewrapping should happen in that block.
44
+
45
+ :param text: the text that should be rewrapped.
46
+ :param width: the maximum width for the text.
47
+ :param initial_indent: the initial indent that should be placed on the
48
+ first line as a string.
49
+ :param subsequent_indent: the indent string that should be placed on
50
+ each consecutive line.
51
+ :param preserve_paragraphs: if this flag is set then the wrapping will
52
+ intelligently handle paragraphs.
53
+ """
54
+ from ._textwrap import TextWrapper
55
+
56
+ text = text.expandtabs()
57
+ wrapper = TextWrapper(
58
+ width,
59
+ initial_indent=initial_indent,
60
+ subsequent_indent=subsequent_indent,
61
+ replace_whitespace=False,
62
+ )
63
+ if not preserve_paragraphs:
64
+ return wrapper.fill(text)
65
+
66
+ p: t.List[t.Tuple[int, bool, str]] = []
67
+ buf: t.List[str] = []
68
+ indent = None
69
+
70
+ def _flush_par() -> None:
71
+ if not buf:
72
+ return
73
+ if buf[0].strip() == "\b":
74
+ p.append((indent or 0, True, "\n".join(buf[1:])))
75
+ else:
76
+ p.append((indent or 0, False, " ".join(buf)))
77
+ del buf[:]
78
+
79
+ for line in text.splitlines():
80
+ if not line:
81
+ _flush_par()
82
+ indent = None
83
+ else:
84
+ if indent is None:
85
+ orig_len = term_len(line)
86
+ line = line.lstrip()
87
+ indent = orig_len - term_len(line)
88
+ buf.append(line)
89
+ _flush_par()
90
+
91
+ rv = []
92
+ for indent, raw, text in p:
93
+ with wrapper.extra_indent(" " * indent):
94
+ if raw:
95
+ rv.append(wrapper.indent_only(text))
96
+ else:
97
+ rv.append(wrapper.fill(text))
98
+
99
+ return "\n\n".join(rv)
100
+
101
+
102
+ class HelpFormatter:
103
+ """This class helps with formatting text-based help pages. It's
104
+ usually just needed for very special internal cases, but it's also
105
+ exposed so that developers can write their own fancy outputs.
106
+
107
+ At present, it always writes into memory.
108
+
109
+ :param indent_increment: the additional increment for each level.
110
+ :param width: the width for the text. This defaults to the terminal
111
+ width clamped to a maximum of 78.
112
+ """
113
+
114
+ def __init__(
115
+ self,
116
+ indent_increment: int = 2,
117
+ width: t.Optional[int] = None,
118
+ max_width: t.Optional[int] = None,
119
+ ) -> None:
120
+ import shutil
121
+
122
+ self.indent_increment = indent_increment
123
+ if max_width is None:
124
+ max_width = 80
125
+ if width is None:
126
+ width = FORCED_WIDTH
127
+ if width is None:
128
+ width = max(min(shutil.get_terminal_size().columns, max_width) - 2, 50)
129
+ self.width = width
130
+ self.current_indent = 0
131
+ self.buffer: t.List[str] = []
132
+
133
+ def write(self, string: str) -> None:
134
+ """Writes a unicode string into the internal buffer."""
135
+ self.buffer.append(string)
136
+
137
+ def indent(self) -> None:
138
+ """Increases the indentation."""
139
+ self.current_indent += self.indent_increment
140
+
141
+ def dedent(self) -> None:
142
+ """Decreases the indentation."""
143
+ self.current_indent -= self.indent_increment
144
+
145
+ def write_usage(
146
+ self, prog: str, args: str = "", prefix: t.Optional[str] = None
147
+ ) -> None:
148
+ """Writes a usage line into the buffer.
149
+
150
+ :param prog: the program name.
151
+ :param args: whitespace separated list of arguments.
152
+ :param prefix: The prefix for the first line. Defaults to
153
+ ``"Usage: "``.
154
+ """
155
+ if prefix is None:
156
+ prefix = f"{_('Usage:')} "
157
+
158
+ usage_prefix = f"{prefix:>{self.current_indent}}{prog} "
159
+ text_width = self.width - self.current_indent
160
+
161
+ if text_width >= (term_len(usage_prefix) + 20):
162
+ # The arguments will fit to the right of the prefix.
163
+ indent = " " * term_len(usage_prefix)
164
+ self.write(
165
+ wrap_text(
166
+ args,
167
+ text_width,
168
+ initial_indent=usage_prefix,
169
+ subsequent_indent=indent,
170
+ )
171
+ )
172
+ else:
173
+ # The prefix is too long, put the arguments on the next line.
174
+ self.write(usage_prefix)
175
+ self.write("\n")
176
+ indent = " " * (max(self.current_indent, term_len(prefix)) + 4)
177
+ self.write(
178
+ wrap_text(
179
+ args, text_width, initial_indent=indent, subsequent_indent=indent
180
+ )
181
+ )
182
+
183
+ self.write("\n")
184
+
185
+ def write_heading(self, heading: str) -> None:
186
+ """Writes a heading into the buffer."""
187
+ self.write(f"{'':>{self.current_indent}}{heading}:\n")
188
+
189
+ def write_paragraph(self) -> None:
190
+ """Writes a paragraph into the buffer."""
191
+ if self.buffer:
192
+ self.write("\n")
193
+
194
+ def write_text(self, text: str) -> None:
195
+ """Writes re-indented text into the buffer. This rewraps and
196
+ preserves paragraphs.
197
+ """
198
+ indent = " " * self.current_indent
199
+ self.write(
200
+ wrap_text(
201
+ text,
202
+ self.width,
203
+ initial_indent=indent,
204
+ subsequent_indent=indent,
205
+ preserve_paragraphs=True,
206
+ )
207
+ )
208
+ self.write("\n")
209
+
210
+ def write_dl(
211
+ self,
212
+ rows: t.Sequence[t.Tuple[str, str]],
213
+ col_max: int = 30,
214
+ col_spacing: int = 2,
215
+ ) -> None:
216
+ """Writes a definition list into the buffer. This is how options
217
+ and commands are usually formatted.
218
+
219
+ :param rows: a list of two item tuples for the terms and values.
220
+ :param col_max: the maximum width of the first column.
221
+ :param col_spacing: the number of spaces between the first and
222
+ second column.
223
+ """
224
+ rows = list(rows)
225
+ widths = measure_table(rows)
226
+ if len(widths) != 2:
227
+ raise TypeError("Expected two columns for definition list")
228
+
229
+ first_col = min(widths[0], col_max) + col_spacing
230
+
231
+ for first, second in iter_rows(rows, len(widths)):
232
+ self.write(f"{'':>{self.current_indent}}{first}")
233
+ if not second:
234
+ self.write("\n")
235
+ continue
236
+ if term_len(first) <= first_col - col_spacing:
237
+ self.write(" " * (first_col - term_len(first)))
238
+ else:
239
+ self.write("\n")
240
+ self.write(" " * (first_col + self.current_indent))
241
+
242
+ text_width = max(self.width - first_col - 2, 10)
243
+ wrapped_text = wrap_text(second, text_width, preserve_paragraphs=True)
244
+ lines = wrapped_text.splitlines()
245
+
246
+ if lines:
247
+ self.write(f"{lines[0]}\n")
248
+
249
+ for line in lines[1:]:
250
+ self.write(f"{'':>{first_col + self.current_indent}}{line}\n")
251
+ else:
252
+ self.write("\n")
253
+
254
+ @contextmanager
255
+ def section(self, name: str) -> t.Iterator[None]:
256
+ """Helpful context manager that writes a paragraph, a heading,
257
+ and the indents.
258
+
259
+ :param name: the section name that is written as heading.
260
+ """
261
+ self.write_paragraph()
262
+ self.write_heading(name)
263
+ self.indent()
264
+ try:
265
+ yield
266
+ finally:
267
+ self.dedent()
268
+
269
+ @contextmanager
270
+ def indentation(self) -> t.Iterator[None]:
271
+ """A context manager that increases the indentation."""
272
+ self.indent()
273
+ try:
274
+ yield
275
+ finally:
276
+ self.dedent()
277
+
278
+ def getvalue(self) -> str:
279
+ """Returns the buffer contents."""
280
+ return "".join(self.buffer)
281
+
282
+
283
+ def join_options(options: t.Sequence[str]) -> t.Tuple[str, bool]:
284
+ """Given a list of option strings this joins them in the most appropriate
285
+ way and returns them in the form ``(formatted_string,
286
+ any_prefix_is_slash)`` where the second item in the tuple is a flag that
287
+ indicates if any of the option prefixes was a slash.
288
+ """
289
+ rv = []
290
+ any_prefix_is_slash = False
291
+
292
+ for opt in options:
293
+ prefix = split_opt(opt)[0]
294
+
295
+ if prefix == "/":
296
+ any_prefix_is_slash = True
297
+
298
+ rv.append((len(prefix), opt))
299
+
300
+ rv.sort(key=lambda x: x[0])
301
+ return ", ".join(x[1] for x in rv), any_prefix_is_slash
.venv/lib/python3.11/site-packages/click/globals.py ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import typing as t
2
+ from threading import local
3
+
4
+ if t.TYPE_CHECKING:
5
+ import typing_extensions as te
6
+
7
+ from .core import Context
8
+
9
+ _local = local()
10
+
11
+
12
+ @t.overload
13
+ def get_current_context(silent: "te.Literal[False]" = False) -> "Context": ...
14
+
15
+
16
+ @t.overload
17
+ def get_current_context(silent: bool = ...) -> t.Optional["Context"]: ...
18
+
19
+
20
+ def get_current_context(silent: bool = False) -> t.Optional["Context"]:
21
+ """Returns the current click context. This can be used as a way to
22
+ access the current context object from anywhere. This is a more implicit
23
+ alternative to the :func:`pass_context` decorator. This function is
24
+ primarily useful for helpers such as :func:`echo` which might be
25
+ interested in changing its behavior based on the current context.
26
+
27
+ To push the current context, :meth:`Context.scope` can be used.
28
+
29
+ .. versionadded:: 5.0
30
+
31
+ :param silent: if set to `True` the return value is `None` if no context
32
+ is available. The default behavior is to raise a
33
+ :exc:`RuntimeError`.
34
+ """
35
+ try:
36
+ return t.cast("Context", _local.stack[-1])
37
+ except (AttributeError, IndexError) as e:
38
+ if not silent:
39
+ raise RuntimeError("There is no active click context.") from e
40
+
41
+ return None
42
+
43
+
44
+ def push_context(ctx: "Context") -> None:
45
+ """Pushes a new context to the current stack."""
46
+ _local.__dict__.setdefault("stack", []).append(ctx)
47
+
48
+
49
+ def pop_context() -> None:
50
+ """Removes the top level from the stack."""
51
+ _local.stack.pop()
52
+
53
+
54
+ def resolve_color_default(color: t.Optional[bool] = None) -> t.Optional[bool]:
55
+ """Internal helper to get the default value of the color flag. If a
56
+ value is passed it's returned unchanged, otherwise it's looked up from
57
+ the current context.
58
+ """
59
+ if color is not None:
60
+ return color
61
+
62
+ ctx = get_current_context(silent=True)
63
+
64
+ if ctx is not None:
65
+ return ctx.color
66
+
67
+ return None
.venv/lib/python3.11/site-packages/click/parser.py ADDED
@@ -0,0 +1,531 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ This module started out as largely a copy paste from the stdlib's
3
+ optparse module with the features removed that we do not need from
4
+ optparse because we implement them in Click on a higher level (for
5
+ instance type handling, help formatting and a lot more).
6
+
7
+ The plan is to remove more and more from here over time.
8
+
9
+ The reason this is a different module and not optparse from the stdlib
10
+ is that there are differences in 2.x and 3.x about the error messages
11
+ generated and optparse in the stdlib uses gettext for no good reason
12
+ and might cause us issues.
13
+
14
+ Click uses parts of optparse written by Gregory P. Ward and maintained
15
+ by the Python Software Foundation. This is limited to code in parser.py.
16
+
17
+ Copyright 2001-2006 Gregory P. Ward. All rights reserved.
18
+ Copyright 2002-2006 Python Software Foundation. All rights reserved.
19
+ """
20
+
21
+ # This code uses parts of optparse written by Gregory P. Ward and
22
+ # maintained by the Python Software Foundation.
23
+ # Copyright 2001-2006 Gregory P. Ward
24
+ # Copyright 2002-2006 Python Software Foundation
25
+ import typing as t
26
+ from collections import deque
27
+ from gettext import gettext as _
28
+ from gettext import ngettext
29
+
30
+ from .exceptions import BadArgumentUsage
31
+ from .exceptions import BadOptionUsage
32
+ from .exceptions import NoSuchOption
33
+ from .exceptions import UsageError
34
+
35
+ if t.TYPE_CHECKING:
36
+ import typing_extensions as te
37
+
38
+ from .core import Argument as CoreArgument
39
+ from .core import Context
40
+ from .core import Option as CoreOption
41
+ from .core import Parameter as CoreParameter
42
+
43
+ V = t.TypeVar("V")
44
+
45
+ # Sentinel value that indicates an option was passed as a flag without a
46
+ # value but is not a flag option. Option.consume_value uses this to
47
+ # prompt or use the flag_value.
48
+ _flag_needs_value = object()
49
+
50
+
51
+ def _unpack_args(
52
+ args: t.Sequence[str], nargs_spec: t.Sequence[int]
53
+ ) -> t.Tuple[t.Sequence[t.Union[str, t.Sequence[t.Optional[str]], None]], t.List[str]]:
54
+ """Given an iterable of arguments and an iterable of nargs specifications,
55
+ it returns a tuple with all the unpacked arguments at the first index
56
+ and all remaining arguments as the second.
57
+
58
+ The nargs specification is the number of arguments that should be consumed
59
+ or `-1` to indicate that this position should eat up all the remainders.
60
+
61
+ Missing items are filled with `None`.
62
+ """
63
+ args = deque(args)
64
+ nargs_spec = deque(nargs_spec)
65
+ rv: t.List[t.Union[str, t.Tuple[t.Optional[str], ...], None]] = []
66
+ spos: t.Optional[int] = None
67
+
68
+ def _fetch(c: "te.Deque[V]") -> t.Optional[V]:
69
+ try:
70
+ if spos is None:
71
+ return c.popleft()
72
+ else:
73
+ return c.pop()
74
+ except IndexError:
75
+ return None
76
+
77
+ while nargs_spec:
78
+ nargs = _fetch(nargs_spec)
79
+
80
+ if nargs is None:
81
+ continue
82
+
83
+ if nargs == 1:
84
+ rv.append(_fetch(args))
85
+ elif nargs > 1:
86
+ x = [_fetch(args) for _ in range(nargs)]
87
+
88
+ # If we're reversed, we're pulling in the arguments in reverse,
89
+ # so we need to turn them around.
90
+ if spos is not None:
91
+ x.reverse()
92
+
93
+ rv.append(tuple(x))
94
+ elif nargs < 0:
95
+ if spos is not None:
96
+ raise TypeError("Cannot have two nargs < 0")
97
+
98
+ spos = len(rv)
99
+ rv.append(None)
100
+
101
+ # spos is the position of the wildcard (star). If it's not `None`,
102
+ # we fill it with the remainder.
103
+ if spos is not None:
104
+ rv[spos] = tuple(args)
105
+ args = []
106
+ rv[spos + 1 :] = reversed(rv[spos + 1 :])
107
+
108
+ return tuple(rv), list(args)
109
+
110
+
111
+ def split_opt(opt: str) -> t.Tuple[str, str]:
112
+ first = opt[:1]
113
+ if first.isalnum():
114
+ return "", opt
115
+ if opt[1:2] == first:
116
+ return opt[:2], opt[2:]
117
+ return first, opt[1:]
118
+
119
+
120
+ def normalize_opt(opt: str, ctx: t.Optional["Context"]) -> str:
121
+ if ctx is None or ctx.token_normalize_func is None:
122
+ return opt
123
+ prefix, opt = split_opt(opt)
124
+ return f"{prefix}{ctx.token_normalize_func(opt)}"
125
+
126
+
127
+ def split_arg_string(string: str) -> t.List[str]:
128
+ """Split an argument string as with :func:`shlex.split`, but don't
129
+ fail if the string is incomplete. Ignores a missing closing quote or
130
+ incomplete escape sequence and uses the partial token as-is.
131
+
132
+ .. code-block:: python
133
+
134
+ split_arg_string("example 'my file")
135
+ ["example", "my file"]
136
+
137
+ split_arg_string("example my\\")
138
+ ["example", "my"]
139
+
140
+ :param string: String to split.
141
+ """
142
+ import shlex
143
+
144
+ lex = shlex.shlex(string, posix=True)
145
+ lex.whitespace_split = True
146
+ lex.commenters = ""
147
+ out = []
148
+
149
+ try:
150
+ for token in lex:
151
+ out.append(token)
152
+ except ValueError:
153
+ # Raised when end-of-string is reached in an invalid state. Use
154
+ # the partial token as-is. The quote or escape character is in
155
+ # lex.state, not lex.token.
156
+ out.append(lex.token)
157
+
158
+ return out
159
+
160
+
161
+ class Option:
162
+ def __init__(
163
+ self,
164
+ obj: "CoreOption",
165
+ opts: t.Sequence[str],
166
+ dest: t.Optional[str],
167
+ action: t.Optional[str] = None,
168
+ nargs: int = 1,
169
+ const: t.Optional[t.Any] = None,
170
+ ):
171
+ self._short_opts = []
172
+ self._long_opts = []
173
+ self.prefixes: t.Set[str] = set()
174
+
175
+ for opt in opts:
176
+ prefix, value = split_opt(opt)
177
+ if not prefix:
178
+ raise ValueError(f"Invalid start character for option ({opt})")
179
+ self.prefixes.add(prefix[0])
180
+ if len(prefix) == 1 and len(value) == 1:
181
+ self._short_opts.append(opt)
182
+ else:
183
+ self._long_opts.append(opt)
184
+ self.prefixes.add(prefix)
185
+
186
+ if action is None:
187
+ action = "store"
188
+
189
+ self.dest = dest
190
+ self.action = action
191
+ self.nargs = nargs
192
+ self.const = const
193
+ self.obj = obj
194
+
195
+ @property
196
+ def takes_value(self) -> bool:
197
+ return self.action in ("store", "append")
198
+
199
+ def process(self, value: t.Any, state: "ParsingState") -> None:
200
+ if self.action == "store":
201
+ state.opts[self.dest] = value # type: ignore
202
+ elif self.action == "store_const":
203
+ state.opts[self.dest] = self.const # type: ignore
204
+ elif self.action == "append":
205
+ state.opts.setdefault(self.dest, []).append(value) # type: ignore
206
+ elif self.action == "append_const":
207
+ state.opts.setdefault(self.dest, []).append(self.const) # type: ignore
208
+ elif self.action == "count":
209
+ state.opts[self.dest] = state.opts.get(self.dest, 0) + 1 # type: ignore
210
+ else:
211
+ raise ValueError(f"unknown action '{self.action}'")
212
+ state.order.append(self.obj)
213
+
214
+
215
+ class Argument:
216
+ def __init__(self, obj: "CoreArgument", dest: t.Optional[str], nargs: int = 1):
217
+ self.dest = dest
218
+ self.nargs = nargs
219
+ self.obj = obj
220
+
221
+ def process(
222
+ self,
223
+ value: t.Union[t.Optional[str], t.Sequence[t.Optional[str]]],
224
+ state: "ParsingState",
225
+ ) -> None:
226
+ if self.nargs > 1:
227
+ assert value is not None
228
+ holes = sum(1 for x in value if x is None)
229
+ if holes == len(value):
230
+ value = None
231
+ elif holes != 0:
232
+ raise BadArgumentUsage(
233
+ _("Argument {name!r} takes {nargs} values.").format(
234
+ name=self.dest, nargs=self.nargs
235
+ )
236
+ )
237
+
238
+ if self.nargs == -1 and self.obj.envvar is not None and value == ():
239
+ # Replace empty tuple with None so that a value from the
240
+ # environment may be tried.
241
+ value = None
242
+
243
+ state.opts[self.dest] = value # type: ignore
244
+ state.order.append(self.obj)
245
+
246
+
247
+ class ParsingState:
248
+ def __init__(self, rargs: t.List[str]) -> None:
249
+ self.opts: t.Dict[str, t.Any] = {}
250
+ self.largs: t.List[str] = []
251
+ self.rargs = rargs
252
+ self.order: t.List[CoreParameter] = []
253
+
254
+
255
+ class OptionParser:
256
+ """The option parser is an internal class that is ultimately used to
257
+ parse options and arguments. It's modelled after optparse and brings
258
+ a similar but vastly simplified API. It should generally not be used
259
+ directly as the high level Click classes wrap it for you.
260
+
261
+ It's not nearly as extensible as optparse or argparse as it does not
262
+ implement features that are implemented on a higher level (such as
263
+ types or defaults).
264
+
265
+ :param ctx: optionally the :class:`~click.Context` where this parser
266
+ should go with.
267
+ """
268
+
269
+ def __init__(self, ctx: t.Optional["Context"] = None) -> None:
270
+ #: The :class:`~click.Context` for this parser. This might be
271
+ #: `None` for some advanced use cases.
272
+ self.ctx = ctx
273
+ #: This controls how the parser deals with interspersed arguments.
274
+ #: If this is set to `False`, the parser will stop on the first
275
+ #: non-option. Click uses this to implement nested subcommands
276
+ #: safely.
277
+ self.allow_interspersed_args: bool = True
278
+ #: This tells the parser how to deal with unknown options. By
279
+ #: default it will error out (which is sensible), but there is a
280
+ #: second mode where it will ignore it and continue processing
281
+ #: after shifting all the unknown options into the resulting args.
282
+ self.ignore_unknown_options: bool = False
283
+
284
+ if ctx is not None:
285
+ self.allow_interspersed_args = ctx.allow_interspersed_args
286
+ self.ignore_unknown_options = ctx.ignore_unknown_options
287
+
288
+ self._short_opt: t.Dict[str, Option] = {}
289
+ self._long_opt: t.Dict[str, Option] = {}
290
+ self._opt_prefixes = {"-", "--"}
291
+ self._args: t.List[Argument] = []
292
+
293
+ def add_option(
294
+ self,
295
+ obj: "CoreOption",
296
+ opts: t.Sequence[str],
297
+ dest: t.Optional[str],
298
+ action: t.Optional[str] = None,
299
+ nargs: int = 1,
300
+ const: t.Optional[t.Any] = None,
301
+ ) -> None:
302
+ """Adds a new option named `dest` to the parser. The destination
303
+ is not inferred (unlike with optparse) and needs to be explicitly
304
+ provided. Action can be any of ``store``, ``store_const``,
305
+ ``append``, ``append_const`` or ``count``.
306
+
307
+ The `obj` can be used to identify the option in the order list
308
+ that is returned from the parser.
309
+ """
310
+ opts = [normalize_opt(opt, self.ctx) for opt in opts]
311
+ option = Option(obj, opts, dest, action=action, nargs=nargs, const=const)
312
+ self._opt_prefixes.update(option.prefixes)
313
+ for opt in option._short_opts:
314
+ self._short_opt[opt] = option
315
+ for opt in option._long_opts:
316
+ self._long_opt[opt] = option
317
+
318
+ def add_argument(
319
+ self, obj: "CoreArgument", dest: t.Optional[str], nargs: int = 1
320
+ ) -> None:
321
+ """Adds a positional argument named `dest` to the parser.
322
+
323
+ The `obj` can be used to identify the option in the order list
324
+ that is returned from the parser.
325
+ """
326
+ self._args.append(Argument(obj, dest=dest, nargs=nargs))
327
+
328
+ def parse_args(
329
+ self, args: t.List[str]
330
+ ) -> t.Tuple[t.Dict[str, t.Any], t.List[str], t.List["CoreParameter"]]:
331
+ """Parses positional arguments and returns ``(values, args, order)``
332
+ for the parsed options and arguments as well as the leftover
333
+ arguments if there are any. The order is a list of objects as they
334
+ appear on the command line. If arguments appear multiple times they
335
+ will be memorized multiple times as well.
336
+ """
337
+ state = ParsingState(args)
338
+ try:
339
+ self._process_args_for_options(state)
340
+ self._process_args_for_args(state)
341
+ except UsageError:
342
+ if self.ctx is None or not self.ctx.resilient_parsing:
343
+ raise
344
+ return state.opts, state.largs, state.order
345
+
346
+ def _process_args_for_args(self, state: ParsingState) -> None:
347
+ pargs, args = _unpack_args(
348
+ state.largs + state.rargs, [x.nargs for x in self._args]
349
+ )
350
+
351
+ for idx, arg in enumerate(self._args):
352
+ arg.process(pargs[idx], state)
353
+
354
+ state.largs = args
355
+ state.rargs = []
356
+
357
+ def _process_args_for_options(self, state: ParsingState) -> None:
358
+ while state.rargs:
359
+ arg = state.rargs.pop(0)
360
+ arglen = len(arg)
361
+ # Double dashes always handled explicitly regardless of what
362
+ # prefixes are valid.
363
+ if arg == "--":
364
+ return
365
+ elif arg[:1] in self._opt_prefixes and arglen > 1:
366
+ self._process_opts(arg, state)
367
+ elif self.allow_interspersed_args:
368
+ state.largs.append(arg)
369
+ else:
370
+ state.rargs.insert(0, arg)
371
+ return
372
+
373
+ # Say this is the original argument list:
374
+ # [arg0, arg1, ..., arg(i-1), arg(i), arg(i+1), ..., arg(N-1)]
375
+ # ^
376
+ # (we are about to process arg(i)).
377
+ #
378
+ # Then rargs is [arg(i), ..., arg(N-1)] and largs is a *subset* of
379
+ # [arg0, ..., arg(i-1)] (any options and their arguments will have
380
+ # been removed from largs).
381
+ #
382
+ # The while loop will usually consume 1 or more arguments per pass.
383
+ # If it consumes 1 (eg. arg is an option that takes no arguments),
384
+ # then after _process_arg() is done the situation is:
385
+ #
386
+ # largs = subset of [arg0, ..., arg(i)]
387
+ # rargs = [arg(i+1), ..., arg(N-1)]
388
+ #
389
+ # If allow_interspersed_args is false, largs will always be
390
+ # *empty* -- still a subset of [arg0, ..., arg(i-1)], but
391
+ # not a very interesting subset!
392
+
393
+ def _match_long_opt(
394
+ self, opt: str, explicit_value: t.Optional[str], state: ParsingState
395
+ ) -> None:
396
+ if opt not in self._long_opt:
397
+ from difflib import get_close_matches
398
+
399
+ possibilities = get_close_matches(opt, self._long_opt)
400
+ raise NoSuchOption(opt, possibilities=possibilities, ctx=self.ctx)
401
+
402
+ option = self._long_opt[opt]
403
+ if option.takes_value:
404
+ # At this point it's safe to modify rargs by injecting the
405
+ # explicit value, because no exception is raised in this
406
+ # branch. This means that the inserted value will be fully
407
+ # consumed.
408
+ if explicit_value is not None:
409
+ state.rargs.insert(0, explicit_value)
410
+
411
+ value = self._get_value_from_state(opt, option, state)
412
+
413
+ elif explicit_value is not None:
414
+ raise BadOptionUsage(
415
+ opt, _("Option {name!r} does not take a value.").format(name=opt)
416
+ )
417
+
418
+ else:
419
+ value = None
420
+
421
+ option.process(value, state)
422
+
423
+ def _match_short_opt(self, arg: str, state: ParsingState) -> None:
424
+ stop = False
425
+ i = 1
426
+ prefix = arg[0]
427
+ unknown_options = []
428
+
429
+ for ch in arg[1:]:
430
+ opt = normalize_opt(f"{prefix}{ch}", self.ctx)
431
+ option = self._short_opt.get(opt)
432
+ i += 1
433
+
434
+ if not option:
435
+ if self.ignore_unknown_options:
436
+ unknown_options.append(ch)
437
+ continue
438
+ raise NoSuchOption(opt, ctx=self.ctx)
439
+ if option.takes_value:
440
+ # Any characters left in arg? Pretend they're the
441
+ # next arg, and stop consuming characters of arg.
442
+ if i < len(arg):
443
+ state.rargs.insert(0, arg[i:])
444
+ stop = True
445
+
446
+ value = self._get_value_from_state(opt, option, state)
447
+
448
+ else:
449
+ value = None
450
+
451
+ option.process(value, state)
452
+
453
+ if stop:
454
+ break
455
+
456
+ # If we got any unknown options we recombine the string of the
457
+ # remaining options and re-attach the prefix, then report that
458
+ # to the state as new larg. This way there is basic combinatorics
459
+ # that can be achieved while still ignoring unknown arguments.
460
+ if self.ignore_unknown_options and unknown_options:
461
+ state.largs.append(f"{prefix}{''.join(unknown_options)}")
462
+
463
+ def _get_value_from_state(
464
+ self, option_name: str, option: Option, state: ParsingState
465
+ ) -> t.Any:
466
+ nargs = option.nargs
467
+
468
+ if len(state.rargs) < nargs:
469
+ if option.obj._flag_needs_value:
470
+ # Option allows omitting the value.
471
+ value = _flag_needs_value
472
+ else:
473
+ raise BadOptionUsage(
474
+ option_name,
475
+ ngettext(
476
+ "Option {name!r} requires an argument.",
477
+ "Option {name!r} requires {nargs} arguments.",
478
+ nargs,
479
+ ).format(name=option_name, nargs=nargs),
480
+ )
481
+ elif nargs == 1:
482
+ next_rarg = state.rargs[0]
483
+
484
+ if (
485
+ option.obj._flag_needs_value
486
+ and isinstance(next_rarg, str)
487
+ and next_rarg[:1] in self._opt_prefixes
488
+ and len(next_rarg) > 1
489
+ ):
490
+ # The next arg looks like the start of an option, don't
491
+ # use it as the value if omitting the value is allowed.
492
+ value = _flag_needs_value
493
+ else:
494
+ value = state.rargs.pop(0)
495
+ else:
496
+ value = tuple(state.rargs[:nargs])
497
+ del state.rargs[:nargs]
498
+
499
+ return value
500
+
501
+ def _process_opts(self, arg: str, state: ParsingState) -> None:
502
+ explicit_value = None
503
+ # Long option handling happens in two parts. The first part is
504
+ # supporting explicitly attached values. In any case, we will try
505
+ # to long match the option first.
506
+ if "=" in arg:
507
+ long_opt, explicit_value = arg.split("=", 1)
508
+ else:
509
+ long_opt = arg
510
+ norm_long_opt = normalize_opt(long_opt, self.ctx)
511
+
512
+ # At this point we will match the (assumed) long option through
513
+ # the long option matching code. Note that this allows options
514
+ # like "-foo" to be matched as long options.
515
+ try:
516
+ self._match_long_opt(norm_long_opt, explicit_value, state)
517
+ except NoSuchOption:
518
+ # At this point the long option matching failed, and we need
519
+ # to try with short options. However there is a special rule
520
+ # which says, that if we have a two character options prefix
521
+ # (applies to "--foo" for instance), we do not dispatch to the
522
+ # short option code and will instead raise the no option
523
+ # error.
524
+ if arg[:2] not in self._opt_prefixes:
525
+ self._match_short_opt(arg, state)
526
+ return
527
+
528
+ if not self.ignore_unknown_options:
529
+ raise
530
+
531
+ state.largs.append(arg)
.venv/lib/python3.11/site-packages/click/testing.py ADDED
@@ -0,0 +1,483 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import contextlib
2
+ import io
3
+ import os
4
+ import shlex
5
+ import shutil
6
+ import sys
7
+ import tempfile
8
+ import typing as t
9
+ from types import TracebackType
10
+
11
+ from . import _compat
12
+ from . import formatting
13
+ from . import termui
14
+ from . import utils
15
+ from ._compat import _find_binary_reader
16
+
17
+ if t.TYPE_CHECKING:
18
+ from .core import BaseCommand
19
+
20
+
21
+ class EchoingStdin:
22
+ def __init__(self, input: t.BinaryIO, output: t.BinaryIO) -> None:
23
+ self._input = input
24
+ self._output = output
25
+ self._paused = False
26
+
27
+ def __getattr__(self, x: str) -> t.Any:
28
+ return getattr(self._input, x)
29
+
30
+ def _echo(self, rv: bytes) -> bytes:
31
+ if not self._paused:
32
+ self._output.write(rv)
33
+
34
+ return rv
35
+
36
+ def read(self, n: int = -1) -> bytes:
37
+ return self._echo(self._input.read(n))
38
+
39
+ def read1(self, n: int = -1) -> bytes:
40
+ return self._echo(self._input.read1(n)) # type: ignore
41
+
42
+ def readline(self, n: int = -1) -> bytes:
43
+ return self._echo(self._input.readline(n))
44
+
45
+ def readlines(self) -> t.List[bytes]:
46
+ return [self._echo(x) for x in self._input.readlines()]
47
+
48
+ def __iter__(self) -> t.Iterator[bytes]:
49
+ return iter(self._echo(x) for x in self._input)
50
+
51
+ def __repr__(self) -> str:
52
+ return repr(self._input)
53
+
54
+
55
+ @contextlib.contextmanager
56
+ def _pause_echo(stream: t.Optional[EchoingStdin]) -> t.Iterator[None]:
57
+ if stream is None:
58
+ yield
59
+ else:
60
+ stream._paused = True
61
+ yield
62
+ stream._paused = False
63
+
64
+
65
+ class _NamedTextIOWrapper(io.TextIOWrapper):
66
+ def __init__(
67
+ self, buffer: t.BinaryIO, name: str, mode: str, **kwargs: t.Any
68
+ ) -> None:
69
+ super().__init__(buffer, **kwargs)
70
+ self._name = name
71
+ self._mode = mode
72
+
73
+ @property
74
+ def name(self) -> str:
75
+ return self._name
76
+
77
+ @property
78
+ def mode(self) -> str:
79
+ return self._mode
80
+
81
+
82
+ def make_input_stream(
83
+ input: t.Optional[t.Union[str, bytes, t.IO[t.Any]]], charset: str
84
+ ) -> t.BinaryIO:
85
+ # Is already an input stream.
86
+ if hasattr(input, "read"):
87
+ rv = _find_binary_reader(t.cast(t.IO[t.Any], input))
88
+
89
+ if rv is not None:
90
+ return rv
91
+
92
+ raise TypeError("Could not find binary reader for input stream.")
93
+
94
+ if input is None:
95
+ input = b""
96
+ elif isinstance(input, str):
97
+ input = input.encode(charset)
98
+
99
+ return io.BytesIO(input)
100
+
101
+
102
+ class Result:
103
+ """Holds the captured result of an invoked CLI script."""
104
+
105
+ def __init__(
106
+ self,
107
+ runner: "CliRunner",
108
+ stdout_bytes: bytes,
109
+ stderr_bytes: t.Optional[bytes],
110
+ return_value: t.Any,
111
+ exit_code: int,
112
+ exception: t.Optional[BaseException],
113
+ exc_info: t.Optional[
114
+ t.Tuple[t.Type[BaseException], BaseException, TracebackType]
115
+ ] = None,
116
+ ):
117
+ #: The runner that created the result
118
+ self.runner = runner
119
+ #: The standard output as bytes.
120
+ self.stdout_bytes = stdout_bytes
121
+ #: The standard error as bytes, or None if not available
122
+ self.stderr_bytes = stderr_bytes
123
+ #: The value returned from the invoked command.
124
+ #:
125
+ #: .. versionadded:: 8.0
126
+ self.return_value = return_value
127
+ #: The exit code as integer.
128
+ self.exit_code = exit_code
129
+ #: The exception that happened if one did.
130
+ self.exception = exception
131
+ #: The traceback
132
+ self.exc_info = exc_info
133
+
134
+ @property
135
+ def output(self) -> str:
136
+ """The (standard) output as unicode string."""
137
+ return self.stdout
138
+
139
+ @property
140
+ def stdout(self) -> str:
141
+ """The standard output as unicode string."""
142
+ return self.stdout_bytes.decode(self.runner.charset, "replace").replace(
143
+ "\r\n", "\n"
144
+ )
145
+
146
+ @property
147
+ def stderr(self) -> str:
148
+ """The standard error as unicode string."""
149
+ if self.stderr_bytes is None:
150
+ raise ValueError("stderr not separately captured")
151
+ return self.stderr_bytes.decode(self.runner.charset, "replace").replace(
152
+ "\r\n", "\n"
153
+ )
154
+
155
+ def __repr__(self) -> str:
156
+ exc_str = repr(self.exception) if self.exception else "okay"
157
+ return f"<{type(self).__name__} {exc_str}>"
158
+
159
+
160
+ class CliRunner:
161
+ """The CLI runner provides functionality to invoke a Click command line
162
+ script for unittesting purposes in a isolated environment. This only
163
+ works in single-threaded systems without any concurrency as it changes the
164
+ global interpreter state.
165
+
166
+ :param charset: the character set for the input and output data.
167
+ :param env: a dictionary with environment variables for overriding.
168
+ :param echo_stdin: if this is set to `True`, then reading from stdin writes
169
+ to stdout. This is useful for showing examples in
170
+ some circumstances. Note that regular prompts
171
+ will automatically echo the input.
172
+ :param mix_stderr: if this is set to `False`, then stdout and stderr are
173
+ preserved as independent streams. This is useful for
174
+ Unix-philosophy apps that have predictable stdout and
175
+ noisy stderr, such that each may be measured
176
+ independently
177
+ """
178
+
179
+ def __init__(
180
+ self,
181
+ charset: str = "utf-8",
182
+ env: t.Optional[t.Mapping[str, t.Optional[str]]] = None,
183
+ echo_stdin: bool = False,
184
+ mix_stderr: bool = True,
185
+ ) -> None:
186
+ self.charset = charset
187
+ self.env: t.Mapping[str, t.Optional[str]] = env or {}
188
+ self.echo_stdin = echo_stdin
189
+ self.mix_stderr = mix_stderr
190
+
191
+ def get_default_prog_name(self, cli: "BaseCommand") -> str:
192
+ """Given a command object it will return the default program name
193
+ for it. The default is the `name` attribute or ``"root"`` if not
194
+ set.
195
+ """
196
+ return cli.name or "root"
197
+
198
+ def make_env(
199
+ self, overrides: t.Optional[t.Mapping[str, t.Optional[str]]] = None
200
+ ) -> t.Mapping[str, t.Optional[str]]:
201
+ """Returns the environment overrides for invoking a script."""
202
+ rv = dict(self.env)
203
+ if overrides:
204
+ rv.update(overrides)
205
+ return rv
206
+
207
+ @contextlib.contextmanager
208
+ def isolation(
209
+ self,
210
+ input: t.Optional[t.Union[str, bytes, t.IO[t.Any]]] = None,
211
+ env: t.Optional[t.Mapping[str, t.Optional[str]]] = None,
212
+ color: bool = False,
213
+ ) -> t.Iterator[t.Tuple[io.BytesIO, t.Optional[io.BytesIO]]]:
214
+ """A context manager that sets up the isolation for invoking of a
215
+ command line tool. This sets up stdin with the given input data
216
+ and `os.environ` with the overrides from the given dictionary.
217
+ This also rebinds some internals in Click to be mocked (like the
218
+ prompt functionality).
219
+
220
+ This is automatically done in the :meth:`invoke` method.
221
+
222
+ :param input: the input stream to put into sys.stdin.
223
+ :param env: the environment overrides as dictionary.
224
+ :param color: whether the output should contain color codes. The
225
+ application can still override this explicitly.
226
+
227
+ .. versionchanged:: 8.0
228
+ ``stderr`` is opened with ``errors="backslashreplace"``
229
+ instead of the default ``"strict"``.
230
+
231
+ .. versionchanged:: 4.0
232
+ Added the ``color`` parameter.
233
+ """
234
+ bytes_input = make_input_stream(input, self.charset)
235
+ echo_input = None
236
+
237
+ old_stdin = sys.stdin
238
+ old_stdout = sys.stdout
239
+ old_stderr = sys.stderr
240
+ old_forced_width = formatting.FORCED_WIDTH
241
+ formatting.FORCED_WIDTH = 80
242
+
243
+ env = self.make_env(env)
244
+
245
+ bytes_output = io.BytesIO()
246
+
247
+ if self.echo_stdin:
248
+ bytes_input = echo_input = t.cast(
249
+ t.BinaryIO, EchoingStdin(bytes_input, bytes_output)
250
+ )
251
+
252
+ sys.stdin = text_input = _NamedTextIOWrapper(
253
+ bytes_input, encoding=self.charset, name="<stdin>", mode="r"
254
+ )
255
+
256
+ if self.echo_stdin:
257
+ # Force unbuffered reads, otherwise TextIOWrapper reads a
258
+ # large chunk which is echoed early.
259
+ text_input._CHUNK_SIZE = 1 # type: ignore
260
+
261
+ sys.stdout = _NamedTextIOWrapper(
262
+ bytes_output, encoding=self.charset, name="<stdout>", mode="w"
263
+ )
264
+
265
+ bytes_error = None
266
+ if self.mix_stderr:
267
+ sys.stderr = sys.stdout
268
+ else:
269
+ bytes_error = io.BytesIO()
270
+ sys.stderr = _NamedTextIOWrapper(
271
+ bytes_error,
272
+ encoding=self.charset,
273
+ name="<stderr>",
274
+ mode="w",
275
+ errors="backslashreplace",
276
+ )
277
+
278
+ @_pause_echo(echo_input) # type: ignore
279
+ def visible_input(prompt: t.Optional[str] = None) -> str:
280
+ sys.stdout.write(prompt or "")
281
+ val = text_input.readline().rstrip("\r\n")
282
+ sys.stdout.write(f"{val}\n")
283
+ sys.stdout.flush()
284
+ return val
285
+
286
+ @_pause_echo(echo_input) # type: ignore
287
+ def hidden_input(prompt: t.Optional[str] = None) -> str:
288
+ sys.stdout.write(f"{prompt or ''}\n")
289
+ sys.stdout.flush()
290
+ return text_input.readline().rstrip("\r\n")
291
+
292
+ @_pause_echo(echo_input) # type: ignore
293
+ def _getchar(echo: bool) -> str:
294
+ char = sys.stdin.read(1)
295
+
296
+ if echo:
297
+ sys.stdout.write(char)
298
+
299
+ sys.stdout.flush()
300
+ return char
301
+
302
+ default_color = color
303
+
304
+ def should_strip_ansi(
305
+ stream: t.Optional[t.IO[t.Any]] = None, color: t.Optional[bool] = None
306
+ ) -> bool:
307
+ if color is None:
308
+ return not default_color
309
+ return not color
310
+
311
+ old_visible_prompt_func = termui.visible_prompt_func
312
+ old_hidden_prompt_func = termui.hidden_prompt_func
313
+ old__getchar_func = termui._getchar
314
+ old_should_strip_ansi = utils.should_strip_ansi # type: ignore
315
+ old__compat_should_strip_ansi = _compat.should_strip_ansi
316
+ termui.visible_prompt_func = visible_input
317
+ termui.hidden_prompt_func = hidden_input
318
+ termui._getchar = _getchar
319
+ utils.should_strip_ansi = should_strip_ansi # type: ignore
320
+ _compat.should_strip_ansi = should_strip_ansi
321
+
322
+ old_env = {}
323
+ try:
324
+ for key, value in env.items():
325
+ old_env[key] = os.environ.get(key)
326
+ if value is None:
327
+ try:
328
+ del os.environ[key]
329
+ except Exception:
330
+ pass
331
+ else:
332
+ os.environ[key] = value
333
+ yield (bytes_output, bytes_error)
334
+ finally:
335
+ for key, value in old_env.items():
336
+ if value is None:
337
+ try:
338
+ del os.environ[key]
339
+ except Exception:
340
+ pass
341
+ else:
342
+ os.environ[key] = value
343
+ sys.stdout = old_stdout
344
+ sys.stderr = old_stderr
345
+ sys.stdin = old_stdin
346
+ termui.visible_prompt_func = old_visible_prompt_func
347
+ termui.hidden_prompt_func = old_hidden_prompt_func
348
+ termui._getchar = old__getchar_func
349
+ utils.should_strip_ansi = old_should_strip_ansi # type: ignore
350
+ _compat.should_strip_ansi = old__compat_should_strip_ansi
351
+ formatting.FORCED_WIDTH = old_forced_width
352
+
353
+ def invoke(
354
+ self,
355
+ cli: "BaseCommand",
356
+ args: t.Optional[t.Union[str, t.Sequence[str]]] = None,
357
+ input: t.Optional[t.Union[str, bytes, t.IO[t.Any]]] = None,
358
+ env: t.Optional[t.Mapping[str, t.Optional[str]]] = None,
359
+ catch_exceptions: bool = True,
360
+ color: bool = False,
361
+ **extra: t.Any,
362
+ ) -> Result:
363
+ """Invokes a command in an isolated environment. The arguments are
364
+ forwarded directly to the command line script, the `extra` keyword
365
+ arguments are passed to the :meth:`~clickpkg.Command.main` function of
366
+ the command.
367
+
368
+ This returns a :class:`Result` object.
369
+
370
+ :param cli: the command to invoke
371
+ :param args: the arguments to invoke. It may be given as an iterable
372
+ or a string. When given as string it will be interpreted
373
+ as a Unix shell command. More details at
374
+ :func:`shlex.split`.
375
+ :param input: the input data for `sys.stdin`.
376
+ :param env: the environment overrides.
377
+ :param catch_exceptions: Whether to catch any other exceptions than
378
+ ``SystemExit``.
379
+ :param extra: the keyword arguments to pass to :meth:`main`.
380
+ :param color: whether the output should contain color codes. The
381
+ application can still override this explicitly.
382
+
383
+ .. versionchanged:: 8.0
384
+ The result object has the ``return_value`` attribute with
385
+ the value returned from the invoked command.
386
+
387
+ .. versionchanged:: 4.0
388
+ Added the ``color`` parameter.
389
+
390
+ .. versionchanged:: 3.0
391
+ Added the ``catch_exceptions`` parameter.
392
+
393
+ .. versionchanged:: 3.0
394
+ The result object has the ``exc_info`` attribute with the
395
+ traceback if available.
396
+ """
397
+ exc_info = None
398
+ with self.isolation(input=input, env=env, color=color) as outstreams:
399
+ return_value = None
400
+ exception: t.Optional[BaseException] = None
401
+ exit_code = 0
402
+
403
+ if isinstance(args, str):
404
+ args = shlex.split(args)
405
+
406
+ try:
407
+ prog_name = extra.pop("prog_name")
408
+ except KeyError:
409
+ prog_name = self.get_default_prog_name(cli)
410
+
411
+ try:
412
+ return_value = cli.main(args=args or (), prog_name=prog_name, **extra)
413
+ except SystemExit as e:
414
+ exc_info = sys.exc_info()
415
+ e_code = t.cast(t.Optional[t.Union[int, t.Any]], e.code)
416
+
417
+ if e_code is None:
418
+ e_code = 0
419
+
420
+ if e_code != 0:
421
+ exception = e
422
+
423
+ if not isinstance(e_code, int):
424
+ sys.stdout.write(str(e_code))
425
+ sys.stdout.write("\n")
426
+ e_code = 1
427
+
428
+ exit_code = e_code
429
+
430
+ except Exception as e:
431
+ if not catch_exceptions:
432
+ raise
433
+ exception = e
434
+ exit_code = 1
435
+ exc_info = sys.exc_info()
436
+ finally:
437
+ sys.stdout.flush()
438
+ stdout = outstreams[0].getvalue()
439
+ if self.mix_stderr:
440
+ stderr = None
441
+ else:
442
+ stderr = outstreams[1].getvalue() # type: ignore
443
+
444
+ return Result(
445
+ runner=self,
446
+ stdout_bytes=stdout,
447
+ stderr_bytes=stderr,
448
+ return_value=return_value,
449
+ exit_code=exit_code,
450
+ exception=exception,
451
+ exc_info=exc_info, # type: ignore
452
+ )
453
+
454
+ @contextlib.contextmanager
455
+ def isolated_filesystem(
456
+ self, temp_dir: t.Optional[t.Union[str, "os.PathLike[str]"]] = None
457
+ ) -> t.Iterator[str]:
458
+ """A context manager that creates a temporary directory and
459
+ changes the current working directory to it. This isolates tests
460
+ that affect the contents of the CWD to prevent them from
461
+ interfering with each other.
462
+
463
+ :param temp_dir: Create the temporary directory under this
464
+ directory. If given, the created directory is not removed
465
+ when exiting.
466
+
467
+ .. versionchanged:: 8.0
468
+ Added the ``temp_dir`` parameter.
469
+ """
470
+ cwd = os.getcwd()
471
+ dt = tempfile.mkdtemp(dir=temp_dir)
472
+ os.chdir(dt)
473
+
474
+ try:
475
+ yield dt
476
+ finally:
477
+ os.chdir(cwd)
478
+
479
+ if temp_dir is None:
480
+ try:
481
+ shutil.rmtree(dt)
482
+ except OSError:
483
+ pass
.venv/lib/python3.11/site-packages/click/types.py ADDED
@@ -0,0 +1,1093 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import stat
3
+ import sys
4
+ import typing as t
5
+ from datetime import datetime
6
+ from gettext import gettext as _
7
+ from gettext import ngettext
8
+
9
+ from ._compat import _get_argv_encoding
10
+ from ._compat import open_stream
11
+ from .exceptions import BadParameter
12
+ from .utils import format_filename
13
+ from .utils import LazyFile
14
+ from .utils import safecall
15
+
16
+ if t.TYPE_CHECKING:
17
+ import typing_extensions as te
18
+
19
+ from .core import Context
20
+ from .core import Parameter
21
+ from .shell_completion import CompletionItem
22
+
23
+
24
+ class ParamType:
25
+ """Represents the type of a parameter. Validates and converts values
26
+ from the command line or Python into the correct type.
27
+
28
+ To implement a custom type, subclass and implement at least the
29
+ following:
30
+
31
+ - The :attr:`name` class attribute must be set.
32
+ - Calling an instance of the type with ``None`` must return
33
+ ``None``. This is already implemented by default.
34
+ - :meth:`convert` must convert string values to the correct type.
35
+ - :meth:`convert` must accept values that are already the correct
36
+ type.
37
+ - It must be able to convert a value if the ``ctx`` and ``param``
38
+ arguments are ``None``. This can occur when converting prompt
39
+ input.
40
+ """
41
+
42
+ is_composite: t.ClassVar[bool] = False
43
+ arity: t.ClassVar[int] = 1
44
+
45
+ #: the descriptive name of this type
46
+ name: str
47
+
48
+ #: if a list of this type is expected and the value is pulled from a
49
+ #: string environment variable, this is what splits it up. `None`
50
+ #: means any whitespace. For all parameters the general rule is that
51
+ #: whitespace splits them up. The exception are paths and files which
52
+ #: are split by ``os.path.pathsep`` by default (":" on Unix and ";" on
53
+ #: Windows).
54
+ envvar_list_splitter: t.ClassVar[t.Optional[str]] = None
55
+
56
+ def to_info_dict(self) -> t.Dict[str, t.Any]:
57
+ """Gather information that could be useful for a tool generating
58
+ user-facing documentation.
59
+
60
+ Use :meth:`click.Context.to_info_dict` to traverse the entire
61
+ CLI structure.
62
+
63
+ .. versionadded:: 8.0
64
+ """
65
+ # The class name without the "ParamType" suffix.
66
+ param_type = type(self).__name__.partition("ParamType")[0]
67
+ param_type = param_type.partition("ParameterType")[0]
68
+
69
+ # Custom subclasses might not remember to set a name.
70
+ if hasattr(self, "name"):
71
+ name = self.name
72
+ else:
73
+ name = param_type
74
+
75
+ return {"param_type": param_type, "name": name}
76
+
77
+ def __call__(
78
+ self,
79
+ value: t.Any,
80
+ param: t.Optional["Parameter"] = None,
81
+ ctx: t.Optional["Context"] = None,
82
+ ) -> t.Any:
83
+ if value is not None:
84
+ return self.convert(value, param, ctx)
85
+
86
+ def get_metavar(self, param: "Parameter") -> t.Optional[str]:
87
+ """Returns the metavar default for this param if it provides one."""
88
+
89
+ def get_missing_message(self, param: "Parameter") -> t.Optional[str]:
90
+ """Optionally might return extra information about a missing
91
+ parameter.
92
+
93
+ .. versionadded:: 2.0
94
+ """
95
+
96
+ def convert(
97
+ self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"]
98
+ ) -> t.Any:
99
+ """Convert the value to the correct type. This is not called if
100
+ the value is ``None`` (the missing value).
101
+
102
+ This must accept string values from the command line, as well as
103
+ values that are already the correct type. It may also convert
104
+ other compatible types.
105
+
106
+ The ``param`` and ``ctx`` arguments may be ``None`` in certain
107
+ situations, such as when converting prompt input.
108
+
109
+ If the value cannot be converted, call :meth:`fail` with a
110
+ descriptive message.
111
+
112
+ :param value: The value to convert.
113
+ :param param: The parameter that is using this type to convert
114
+ its value. May be ``None``.
115
+ :param ctx: The current context that arrived at this value. May
116
+ be ``None``.
117
+ """
118
+ return value
119
+
120
+ def split_envvar_value(self, rv: str) -> t.Sequence[str]:
121
+ """Given a value from an environment variable this splits it up
122
+ into small chunks depending on the defined envvar list splitter.
123
+
124
+ If the splitter is set to `None`, which means that whitespace splits,
125
+ then leading and trailing whitespace is ignored. Otherwise, leading
126
+ and trailing splitters usually lead to empty items being included.
127
+ """
128
+ return (rv or "").split(self.envvar_list_splitter)
129
+
130
+ def fail(
131
+ self,
132
+ message: str,
133
+ param: t.Optional["Parameter"] = None,
134
+ ctx: t.Optional["Context"] = None,
135
+ ) -> "t.NoReturn":
136
+ """Helper method to fail with an invalid value message."""
137
+ raise BadParameter(message, ctx=ctx, param=param)
138
+
139
+ def shell_complete(
140
+ self, ctx: "Context", param: "Parameter", incomplete: str
141
+ ) -> t.List["CompletionItem"]:
142
+ """Return a list of
143
+ :class:`~click.shell_completion.CompletionItem` objects for the
144
+ incomplete value. Most types do not provide completions, but
145
+ some do, and this allows custom types to provide custom
146
+ completions as well.
147
+
148
+ :param ctx: Invocation context for this command.
149
+ :param param: The parameter that is requesting completion.
150
+ :param incomplete: Value being completed. May be empty.
151
+
152
+ .. versionadded:: 8.0
153
+ """
154
+ return []
155
+
156
+
157
+ class CompositeParamType(ParamType):
158
+ is_composite = True
159
+
160
+ @property
161
+ def arity(self) -> int: # type: ignore
162
+ raise NotImplementedError()
163
+
164
+
165
+ class FuncParamType(ParamType):
166
+ def __init__(self, func: t.Callable[[t.Any], t.Any]) -> None:
167
+ self.name: str = func.__name__
168
+ self.func = func
169
+
170
+ def to_info_dict(self) -> t.Dict[str, t.Any]:
171
+ info_dict = super().to_info_dict()
172
+ info_dict["func"] = self.func
173
+ return info_dict
174
+
175
+ def convert(
176
+ self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"]
177
+ ) -> t.Any:
178
+ try:
179
+ return self.func(value)
180
+ except ValueError:
181
+ try:
182
+ value = str(value)
183
+ except UnicodeError:
184
+ value = value.decode("utf-8", "replace")
185
+
186
+ self.fail(value, param, ctx)
187
+
188
+
189
+ class UnprocessedParamType(ParamType):
190
+ name = "text"
191
+
192
+ def convert(
193
+ self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"]
194
+ ) -> t.Any:
195
+ return value
196
+
197
+ def __repr__(self) -> str:
198
+ return "UNPROCESSED"
199
+
200
+
201
+ class StringParamType(ParamType):
202
+ name = "text"
203
+
204
+ def convert(
205
+ self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"]
206
+ ) -> t.Any:
207
+ if isinstance(value, bytes):
208
+ enc = _get_argv_encoding()
209
+ try:
210
+ value = value.decode(enc)
211
+ except UnicodeError:
212
+ fs_enc = sys.getfilesystemencoding()
213
+ if fs_enc != enc:
214
+ try:
215
+ value = value.decode(fs_enc)
216
+ except UnicodeError:
217
+ value = value.decode("utf-8", "replace")
218
+ else:
219
+ value = value.decode("utf-8", "replace")
220
+ return value
221
+ return str(value)
222
+
223
+ def __repr__(self) -> str:
224
+ return "STRING"
225
+
226
+
227
+ class Choice(ParamType):
228
+ """The choice type allows a value to be checked against a fixed set
229
+ of supported values. All of these values have to be strings.
230
+
231
+ You should only pass a list or tuple of choices. Other iterables
232
+ (like generators) may lead to surprising results.
233
+
234
+ The resulting value will always be one of the originally passed choices
235
+ regardless of ``case_sensitive`` or any ``ctx.token_normalize_func``
236
+ being specified.
237
+
238
+ See :ref:`choice-opts` for an example.
239
+
240
+ :param case_sensitive: Set to false to make choices case
241
+ insensitive. Defaults to true.
242
+ """
243
+
244
+ name = "choice"
245
+
246
+ def __init__(self, choices: t.Sequence[str], case_sensitive: bool = True) -> None:
247
+ self.choices = choices
248
+ self.case_sensitive = case_sensitive
249
+
250
+ def to_info_dict(self) -> t.Dict[str, t.Any]:
251
+ info_dict = super().to_info_dict()
252
+ info_dict["choices"] = self.choices
253
+ info_dict["case_sensitive"] = self.case_sensitive
254
+ return info_dict
255
+
256
+ def get_metavar(self, param: "Parameter") -> str:
257
+ choices_str = "|".join(self.choices)
258
+
259
+ # Use curly braces to indicate a required argument.
260
+ if param.required and param.param_type_name == "argument":
261
+ return f"{{{choices_str}}}"
262
+
263
+ # Use square braces to indicate an option or optional argument.
264
+ return f"[{choices_str}]"
265
+
266
+ def get_missing_message(self, param: "Parameter") -> str:
267
+ return _("Choose from:\n\t{choices}").format(choices=",\n\t".join(self.choices))
268
+
269
+ def convert(
270
+ self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"]
271
+ ) -> t.Any:
272
+ # Match through normalization and case sensitivity
273
+ # first do token_normalize_func, then lowercase
274
+ # preserve original `value` to produce an accurate message in
275
+ # `self.fail`
276
+ normed_value = value
277
+ normed_choices = {choice: choice for choice in self.choices}
278
+
279
+ if ctx is not None and ctx.token_normalize_func is not None:
280
+ normed_value = ctx.token_normalize_func(value)
281
+ normed_choices = {
282
+ ctx.token_normalize_func(normed_choice): original
283
+ for normed_choice, original in normed_choices.items()
284
+ }
285
+
286
+ if not self.case_sensitive:
287
+ normed_value = normed_value.casefold()
288
+ normed_choices = {
289
+ normed_choice.casefold(): original
290
+ for normed_choice, original in normed_choices.items()
291
+ }
292
+
293
+ if normed_value in normed_choices:
294
+ return normed_choices[normed_value]
295
+
296
+ choices_str = ", ".join(map(repr, self.choices))
297
+ self.fail(
298
+ ngettext(
299
+ "{value!r} is not {choice}.",
300
+ "{value!r} is not one of {choices}.",
301
+ len(self.choices),
302
+ ).format(value=value, choice=choices_str, choices=choices_str),
303
+ param,
304
+ ctx,
305
+ )
306
+
307
+ def __repr__(self) -> str:
308
+ return f"Choice({list(self.choices)})"
309
+
310
+ def shell_complete(
311
+ self, ctx: "Context", param: "Parameter", incomplete: str
312
+ ) -> t.List["CompletionItem"]:
313
+ """Complete choices that start with the incomplete value.
314
+
315
+ :param ctx: Invocation context for this command.
316
+ :param param: The parameter that is requesting completion.
317
+ :param incomplete: Value being completed. May be empty.
318
+
319
+ .. versionadded:: 8.0
320
+ """
321
+ from click.shell_completion import CompletionItem
322
+
323
+ str_choices = map(str, self.choices)
324
+
325
+ if self.case_sensitive:
326
+ matched = (c for c in str_choices if c.startswith(incomplete))
327
+ else:
328
+ incomplete = incomplete.lower()
329
+ matched = (c for c in str_choices if c.lower().startswith(incomplete))
330
+
331
+ return [CompletionItem(c) for c in matched]
332
+
333
+
334
+ class DateTime(ParamType):
335
+ """The DateTime type converts date strings into `datetime` objects.
336
+
337
+ The format strings which are checked are configurable, but default to some
338
+ common (non-timezone aware) ISO 8601 formats.
339
+
340
+ When specifying *DateTime* formats, you should only pass a list or a tuple.
341
+ Other iterables, like generators, may lead to surprising results.
342
+
343
+ The format strings are processed using ``datetime.strptime``, and this
344
+ consequently defines the format strings which are allowed.
345
+
346
+ Parsing is tried using each format, in order, and the first format which
347
+ parses successfully is used.
348
+
349
+ :param formats: A list or tuple of date format strings, in the order in
350
+ which they should be tried. Defaults to
351
+ ``'%Y-%m-%d'``, ``'%Y-%m-%dT%H:%M:%S'``,
352
+ ``'%Y-%m-%d %H:%M:%S'``.
353
+ """
354
+
355
+ name = "datetime"
356
+
357
+ def __init__(self, formats: t.Optional[t.Sequence[str]] = None):
358
+ self.formats: t.Sequence[str] = formats or [
359
+ "%Y-%m-%d",
360
+ "%Y-%m-%dT%H:%M:%S",
361
+ "%Y-%m-%d %H:%M:%S",
362
+ ]
363
+
364
+ def to_info_dict(self) -> t.Dict[str, t.Any]:
365
+ info_dict = super().to_info_dict()
366
+ info_dict["formats"] = self.formats
367
+ return info_dict
368
+
369
+ def get_metavar(self, param: "Parameter") -> str:
370
+ return f"[{'|'.join(self.formats)}]"
371
+
372
+ def _try_to_convert_date(self, value: t.Any, format: str) -> t.Optional[datetime]:
373
+ try:
374
+ return datetime.strptime(value, format)
375
+ except ValueError:
376
+ return None
377
+
378
+ def convert(
379
+ self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"]
380
+ ) -> t.Any:
381
+ if isinstance(value, datetime):
382
+ return value
383
+
384
+ for format in self.formats:
385
+ converted = self._try_to_convert_date(value, format)
386
+
387
+ if converted is not None:
388
+ return converted
389
+
390
+ formats_str = ", ".join(map(repr, self.formats))
391
+ self.fail(
392
+ ngettext(
393
+ "{value!r} does not match the format {format}.",
394
+ "{value!r} does not match the formats {formats}.",
395
+ len(self.formats),
396
+ ).format(value=value, format=formats_str, formats=formats_str),
397
+ param,
398
+ ctx,
399
+ )
400
+
401
+ def __repr__(self) -> str:
402
+ return "DateTime"
403
+
404
+
405
+ class _NumberParamTypeBase(ParamType):
406
+ _number_class: t.ClassVar[t.Type[t.Any]]
407
+
408
+ def convert(
409
+ self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"]
410
+ ) -> t.Any:
411
+ try:
412
+ return self._number_class(value)
413
+ except ValueError:
414
+ self.fail(
415
+ _("{value!r} is not a valid {number_type}.").format(
416
+ value=value, number_type=self.name
417
+ ),
418
+ param,
419
+ ctx,
420
+ )
421
+
422
+
423
+ class _NumberRangeBase(_NumberParamTypeBase):
424
+ def __init__(
425
+ self,
426
+ min: t.Optional[float] = None,
427
+ max: t.Optional[float] = None,
428
+ min_open: bool = False,
429
+ max_open: bool = False,
430
+ clamp: bool = False,
431
+ ) -> None:
432
+ self.min = min
433
+ self.max = max
434
+ self.min_open = min_open
435
+ self.max_open = max_open
436
+ self.clamp = clamp
437
+
438
+ def to_info_dict(self) -> t.Dict[str, t.Any]:
439
+ info_dict = super().to_info_dict()
440
+ info_dict.update(
441
+ min=self.min,
442
+ max=self.max,
443
+ min_open=self.min_open,
444
+ max_open=self.max_open,
445
+ clamp=self.clamp,
446
+ )
447
+ return info_dict
448
+
449
+ def convert(
450
+ self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"]
451
+ ) -> t.Any:
452
+ import operator
453
+
454
+ rv = super().convert(value, param, ctx)
455
+ lt_min: bool = self.min is not None and (
456
+ operator.le if self.min_open else operator.lt
457
+ )(rv, self.min)
458
+ gt_max: bool = self.max is not None and (
459
+ operator.ge if self.max_open else operator.gt
460
+ )(rv, self.max)
461
+
462
+ if self.clamp:
463
+ if lt_min:
464
+ return self._clamp(self.min, 1, self.min_open) # type: ignore
465
+
466
+ if gt_max:
467
+ return self._clamp(self.max, -1, self.max_open) # type: ignore
468
+
469
+ if lt_min or gt_max:
470
+ self.fail(
471
+ _("{value} is not in the range {range}.").format(
472
+ value=rv, range=self._describe_range()
473
+ ),
474
+ param,
475
+ ctx,
476
+ )
477
+
478
+ return rv
479
+
480
+ def _clamp(self, bound: float, dir: "te.Literal[1, -1]", open: bool) -> float:
481
+ """Find the valid value to clamp to bound in the given
482
+ direction.
483
+
484
+ :param bound: The boundary value.
485
+ :param dir: 1 or -1 indicating the direction to move.
486
+ :param open: If true, the range does not include the bound.
487
+ """
488
+ raise NotImplementedError
489
+
490
+ def _describe_range(self) -> str:
491
+ """Describe the range for use in help text."""
492
+ if self.min is None:
493
+ op = "<" if self.max_open else "<="
494
+ return f"x{op}{self.max}"
495
+
496
+ if self.max is None:
497
+ op = ">" if self.min_open else ">="
498
+ return f"x{op}{self.min}"
499
+
500
+ lop = "<" if self.min_open else "<="
501
+ rop = "<" if self.max_open else "<="
502
+ return f"{self.min}{lop}x{rop}{self.max}"
503
+
504
+ def __repr__(self) -> str:
505
+ clamp = " clamped" if self.clamp else ""
506
+ return f"<{type(self).__name__} {self._describe_range()}{clamp}>"
507
+
508
+
509
+ class IntParamType(_NumberParamTypeBase):
510
+ name = "integer"
511
+ _number_class = int
512
+
513
+ def __repr__(self) -> str:
514
+ return "INT"
515
+
516
+
517
+ class IntRange(_NumberRangeBase, IntParamType):
518
+ """Restrict an :data:`click.INT` value to a range of accepted
519
+ values. See :ref:`ranges`.
520
+
521
+ If ``min`` or ``max`` are not passed, any value is accepted in that
522
+ direction. If ``min_open`` or ``max_open`` are enabled, the
523
+ corresponding boundary is not included in the range.
524
+
525
+ If ``clamp`` is enabled, a value outside the range is clamped to the
526
+ boundary instead of failing.
527
+
528
+ .. versionchanged:: 8.0
529
+ Added the ``min_open`` and ``max_open`` parameters.
530
+ """
531
+
532
+ name = "integer range"
533
+
534
+ def _clamp( # type: ignore
535
+ self, bound: int, dir: "te.Literal[1, -1]", open: bool
536
+ ) -> int:
537
+ if not open:
538
+ return bound
539
+
540
+ return bound + dir
541
+
542
+
543
+ class FloatParamType(_NumberParamTypeBase):
544
+ name = "float"
545
+ _number_class = float
546
+
547
+ def __repr__(self) -> str:
548
+ return "FLOAT"
549
+
550
+
551
+ class FloatRange(_NumberRangeBase, FloatParamType):
552
+ """Restrict a :data:`click.FLOAT` value to a range of accepted
553
+ values. See :ref:`ranges`.
554
+
555
+ If ``min`` or ``max`` are not passed, any value is accepted in that
556
+ direction. If ``min_open`` or ``max_open`` are enabled, the
557
+ corresponding boundary is not included in the range.
558
+
559
+ If ``clamp`` is enabled, a value outside the range is clamped to the
560
+ boundary instead of failing. This is not supported if either
561
+ boundary is marked ``open``.
562
+
563
+ .. versionchanged:: 8.0
564
+ Added the ``min_open`` and ``max_open`` parameters.
565
+ """
566
+
567
+ name = "float range"
568
+
569
+ def __init__(
570
+ self,
571
+ min: t.Optional[float] = None,
572
+ max: t.Optional[float] = None,
573
+ min_open: bool = False,
574
+ max_open: bool = False,
575
+ clamp: bool = False,
576
+ ) -> None:
577
+ super().__init__(
578
+ min=min, max=max, min_open=min_open, max_open=max_open, clamp=clamp
579
+ )
580
+
581
+ if (min_open or max_open) and clamp:
582
+ raise TypeError("Clamping is not supported for open bounds.")
583
+
584
+ def _clamp(self, bound: float, dir: "te.Literal[1, -1]", open: bool) -> float:
585
+ if not open:
586
+ return bound
587
+
588
+ # Could use Python 3.9's math.nextafter here, but clamping an
589
+ # open float range doesn't seem to be particularly useful. It's
590
+ # left up to the user to write a callback to do it if needed.
591
+ raise RuntimeError("Clamping is not supported for open bounds.")
592
+
593
+
594
+ class BoolParamType(ParamType):
595
+ name = "boolean"
596
+
597
+ def convert(
598
+ self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"]
599
+ ) -> t.Any:
600
+ if value in {False, True}:
601
+ return bool(value)
602
+
603
+ norm = value.strip().lower()
604
+
605
+ if norm in {"1", "true", "t", "yes", "y", "on"}:
606
+ return True
607
+
608
+ if norm in {"0", "false", "f", "no", "n", "off"}:
609
+ return False
610
+
611
+ self.fail(
612
+ _("{value!r} is not a valid boolean.").format(value=value), param, ctx
613
+ )
614
+
615
+ def __repr__(self) -> str:
616
+ return "BOOL"
617
+
618
+
619
+ class UUIDParameterType(ParamType):
620
+ name = "uuid"
621
+
622
+ def convert(
623
+ self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"]
624
+ ) -> t.Any:
625
+ import uuid
626
+
627
+ if isinstance(value, uuid.UUID):
628
+ return value
629
+
630
+ value = value.strip()
631
+
632
+ try:
633
+ return uuid.UUID(value)
634
+ except ValueError:
635
+ self.fail(
636
+ _("{value!r} is not a valid UUID.").format(value=value), param, ctx
637
+ )
638
+
639
+ def __repr__(self) -> str:
640
+ return "UUID"
641
+
642
+
643
+ class File(ParamType):
644
+ """Declares a parameter to be a file for reading or writing. The file
645
+ is automatically closed once the context tears down (after the command
646
+ finished working).
647
+
648
+ Files can be opened for reading or writing. The special value ``-``
649
+ indicates stdin or stdout depending on the mode.
650
+
651
+ By default, the file is opened for reading text data, but it can also be
652
+ opened in binary mode or for writing. The encoding parameter can be used
653
+ to force a specific encoding.
654
+
655
+ The `lazy` flag controls if the file should be opened immediately or upon
656
+ first IO. The default is to be non-lazy for standard input and output
657
+ streams as well as files opened for reading, `lazy` otherwise. When opening a
658
+ file lazily for reading, it is still opened temporarily for validation, but
659
+ will not be held open until first IO. lazy is mainly useful when opening
660
+ for writing to avoid creating the file until it is needed.
661
+
662
+ Files can also be opened atomically in which case all writes go into a
663
+ separate file in the same folder and upon completion the file will
664
+ be moved over to the original location. This is useful if a file
665
+ regularly read by other users is modified.
666
+
667
+ See :ref:`file-args` for more information.
668
+
669
+ .. versionchanged:: 2.0
670
+ Added the ``atomic`` parameter.
671
+ """
672
+
673
+ name = "filename"
674
+ envvar_list_splitter: t.ClassVar[str] = os.path.pathsep
675
+
676
+ def __init__(
677
+ self,
678
+ mode: str = "r",
679
+ encoding: t.Optional[str] = None,
680
+ errors: t.Optional[str] = "strict",
681
+ lazy: t.Optional[bool] = None,
682
+ atomic: bool = False,
683
+ ) -> None:
684
+ self.mode = mode
685
+ self.encoding = encoding
686
+ self.errors = errors
687
+ self.lazy = lazy
688
+ self.atomic = atomic
689
+
690
+ def to_info_dict(self) -> t.Dict[str, t.Any]:
691
+ info_dict = super().to_info_dict()
692
+ info_dict.update(mode=self.mode, encoding=self.encoding)
693
+ return info_dict
694
+
695
+ def resolve_lazy_flag(self, value: "t.Union[str, os.PathLike[str]]") -> bool:
696
+ if self.lazy is not None:
697
+ return self.lazy
698
+ if os.fspath(value) == "-":
699
+ return False
700
+ elif "w" in self.mode:
701
+ return True
702
+ return False
703
+
704
+ def convert(
705
+ self,
706
+ value: t.Union[str, "os.PathLike[str]", t.IO[t.Any]],
707
+ param: t.Optional["Parameter"],
708
+ ctx: t.Optional["Context"],
709
+ ) -> t.IO[t.Any]:
710
+ if _is_file_like(value):
711
+ return value
712
+
713
+ value = t.cast("t.Union[str, os.PathLike[str]]", value)
714
+
715
+ try:
716
+ lazy = self.resolve_lazy_flag(value)
717
+
718
+ if lazy:
719
+ lf = LazyFile(
720
+ value, self.mode, self.encoding, self.errors, atomic=self.atomic
721
+ )
722
+
723
+ if ctx is not None:
724
+ ctx.call_on_close(lf.close_intelligently)
725
+
726
+ return t.cast(t.IO[t.Any], lf)
727
+
728
+ f, should_close = open_stream(
729
+ value, self.mode, self.encoding, self.errors, atomic=self.atomic
730
+ )
731
+
732
+ # If a context is provided, we automatically close the file
733
+ # at the end of the context execution (or flush out). If a
734
+ # context does not exist, it's the caller's responsibility to
735
+ # properly close the file. This for instance happens when the
736
+ # type is used with prompts.
737
+ if ctx is not None:
738
+ if should_close:
739
+ ctx.call_on_close(safecall(f.close))
740
+ else:
741
+ ctx.call_on_close(safecall(f.flush))
742
+
743
+ return f
744
+ except OSError as e:
745
+ self.fail(f"'{format_filename(value)}': {e.strerror}", param, ctx)
746
+
747
+ def shell_complete(
748
+ self, ctx: "Context", param: "Parameter", incomplete: str
749
+ ) -> t.List["CompletionItem"]:
750
+ """Return a special completion marker that tells the completion
751
+ system to use the shell to provide file path completions.
752
+
753
+ :param ctx: Invocation context for this command.
754
+ :param param: The parameter that is requesting completion.
755
+ :param incomplete: Value being completed. May be empty.
756
+
757
+ .. versionadded:: 8.0
758
+ """
759
+ from click.shell_completion import CompletionItem
760
+
761
+ return [CompletionItem(incomplete, type="file")]
762
+
763
+
764
+ def _is_file_like(value: t.Any) -> "te.TypeGuard[t.IO[t.Any]]":
765
+ return hasattr(value, "read") or hasattr(value, "write")
766
+
767
+
768
+ class Path(ParamType):
769
+ """The ``Path`` type is similar to the :class:`File` type, but
770
+ returns the filename instead of an open file. Various checks can be
771
+ enabled to validate the type of file and permissions.
772
+
773
+ :param exists: The file or directory needs to exist for the value to
774
+ be valid. If this is not set to ``True``, and the file does not
775
+ exist, then all further checks are silently skipped.
776
+ :param file_okay: Allow a file as a value.
777
+ :param dir_okay: Allow a directory as a value.
778
+ :param readable: if true, a readable check is performed.
779
+ :param writable: if true, a writable check is performed.
780
+ :param executable: if true, an executable check is performed.
781
+ :param resolve_path: Make the value absolute and resolve any
782
+ symlinks. A ``~`` is not expanded, as this is supposed to be
783
+ done by the shell only.
784
+ :param allow_dash: Allow a single dash as a value, which indicates
785
+ a standard stream (but does not open it). Use
786
+ :func:`~click.open_file` to handle opening this value.
787
+ :param path_type: Convert the incoming path value to this type. If
788
+ ``None``, keep Python's default, which is ``str``. Useful to
789
+ convert to :class:`pathlib.Path`.
790
+
791
+ .. versionchanged:: 8.1
792
+ Added the ``executable`` parameter.
793
+
794
+ .. versionchanged:: 8.0
795
+ Allow passing ``path_type=pathlib.Path``.
796
+
797
+ .. versionchanged:: 6.0
798
+ Added the ``allow_dash`` parameter.
799
+ """
800
+
801
+ envvar_list_splitter: t.ClassVar[str] = os.path.pathsep
802
+
803
+ def __init__(
804
+ self,
805
+ exists: bool = False,
806
+ file_okay: bool = True,
807
+ dir_okay: bool = True,
808
+ writable: bool = False,
809
+ readable: bool = True,
810
+ resolve_path: bool = False,
811
+ allow_dash: bool = False,
812
+ path_type: t.Optional[t.Type[t.Any]] = None,
813
+ executable: bool = False,
814
+ ):
815
+ self.exists = exists
816
+ self.file_okay = file_okay
817
+ self.dir_okay = dir_okay
818
+ self.readable = readable
819
+ self.writable = writable
820
+ self.executable = executable
821
+ self.resolve_path = resolve_path
822
+ self.allow_dash = allow_dash
823
+ self.type = path_type
824
+
825
+ if self.file_okay and not self.dir_okay:
826
+ self.name: str = _("file")
827
+ elif self.dir_okay and not self.file_okay:
828
+ self.name = _("directory")
829
+ else:
830
+ self.name = _("path")
831
+
832
+ def to_info_dict(self) -> t.Dict[str, t.Any]:
833
+ info_dict = super().to_info_dict()
834
+ info_dict.update(
835
+ exists=self.exists,
836
+ file_okay=self.file_okay,
837
+ dir_okay=self.dir_okay,
838
+ writable=self.writable,
839
+ readable=self.readable,
840
+ allow_dash=self.allow_dash,
841
+ )
842
+ return info_dict
843
+
844
+ def coerce_path_result(
845
+ self, value: "t.Union[str, os.PathLike[str]]"
846
+ ) -> "t.Union[str, bytes, os.PathLike[str]]":
847
+ if self.type is not None and not isinstance(value, self.type):
848
+ if self.type is str:
849
+ return os.fsdecode(value)
850
+ elif self.type is bytes:
851
+ return os.fsencode(value)
852
+ else:
853
+ return t.cast("os.PathLike[str]", self.type(value))
854
+
855
+ return value
856
+
857
+ def convert(
858
+ self,
859
+ value: "t.Union[str, os.PathLike[str]]",
860
+ param: t.Optional["Parameter"],
861
+ ctx: t.Optional["Context"],
862
+ ) -> "t.Union[str, bytes, os.PathLike[str]]":
863
+ rv = value
864
+
865
+ is_dash = self.file_okay and self.allow_dash and rv in (b"-", "-")
866
+
867
+ if not is_dash:
868
+ if self.resolve_path:
869
+ # os.path.realpath doesn't resolve symlinks on Windows
870
+ # until Python 3.8. Use pathlib for now.
871
+ import pathlib
872
+
873
+ rv = os.fsdecode(pathlib.Path(rv).resolve())
874
+
875
+ try:
876
+ st = os.stat(rv)
877
+ except OSError:
878
+ if not self.exists:
879
+ return self.coerce_path_result(rv)
880
+ self.fail(
881
+ _("{name} {filename!r} does not exist.").format(
882
+ name=self.name.title(), filename=format_filename(value)
883
+ ),
884
+ param,
885
+ ctx,
886
+ )
887
+
888
+ if not self.file_okay and stat.S_ISREG(st.st_mode):
889
+ self.fail(
890
+ _("{name} {filename!r} is a file.").format(
891
+ name=self.name.title(), filename=format_filename(value)
892
+ ),
893
+ param,
894
+ ctx,
895
+ )
896
+ if not self.dir_okay and stat.S_ISDIR(st.st_mode):
897
+ self.fail(
898
+ _("{name} {filename!r} is a directory.").format(
899
+ name=self.name.title(), filename=format_filename(value)
900
+ ),
901
+ param,
902
+ ctx,
903
+ )
904
+
905
+ if self.readable and not os.access(rv, os.R_OK):
906
+ self.fail(
907
+ _("{name} {filename!r} is not readable.").format(
908
+ name=self.name.title(), filename=format_filename(value)
909
+ ),
910
+ param,
911
+ ctx,
912
+ )
913
+
914
+ if self.writable and not os.access(rv, os.W_OK):
915
+ self.fail(
916
+ _("{name} {filename!r} is not writable.").format(
917
+ name=self.name.title(), filename=format_filename(value)
918
+ ),
919
+ param,
920
+ ctx,
921
+ )
922
+
923
+ if self.executable and not os.access(value, os.X_OK):
924
+ self.fail(
925
+ _("{name} {filename!r} is not executable.").format(
926
+ name=self.name.title(), filename=format_filename(value)
927
+ ),
928
+ param,
929
+ ctx,
930
+ )
931
+
932
+ return self.coerce_path_result(rv)
933
+
934
+ def shell_complete(
935
+ self, ctx: "Context", param: "Parameter", incomplete: str
936
+ ) -> t.List["CompletionItem"]:
937
+ """Return a special completion marker that tells the completion
938
+ system to use the shell to provide path completions for only
939
+ directories or any paths.
940
+
941
+ :param ctx: Invocation context for this command.
942
+ :param param: The parameter that is requesting completion.
943
+ :param incomplete: Value being completed. May be empty.
944
+
945
+ .. versionadded:: 8.0
946
+ """
947
+ from click.shell_completion import CompletionItem
948
+
949
+ type = "dir" if self.dir_okay and not self.file_okay else "file"
950
+ return [CompletionItem(incomplete, type=type)]
951
+
952
+
953
+ class Tuple(CompositeParamType):
954
+ """The default behavior of Click is to apply a type on a value directly.
955
+ This works well in most cases, except for when `nargs` is set to a fixed
956
+ count and different types should be used for different items. In this
957
+ case the :class:`Tuple` type can be used. This type can only be used
958
+ if `nargs` is set to a fixed number.
959
+
960
+ For more information see :ref:`tuple-type`.
961
+
962
+ This can be selected by using a Python tuple literal as a type.
963
+
964
+ :param types: a list of types that should be used for the tuple items.
965
+ """
966
+
967
+ def __init__(self, types: t.Sequence[t.Union[t.Type[t.Any], ParamType]]) -> None:
968
+ self.types: t.Sequence[ParamType] = [convert_type(ty) for ty in types]
969
+
970
+ def to_info_dict(self) -> t.Dict[str, t.Any]:
971
+ info_dict = super().to_info_dict()
972
+ info_dict["types"] = [t.to_info_dict() for t in self.types]
973
+ return info_dict
974
+
975
+ @property
976
+ def name(self) -> str: # type: ignore
977
+ return f"<{' '.join(ty.name for ty in self.types)}>"
978
+
979
+ @property
980
+ def arity(self) -> int: # type: ignore
981
+ return len(self.types)
982
+
983
+ def convert(
984
+ self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"]
985
+ ) -> t.Any:
986
+ len_type = len(self.types)
987
+ len_value = len(value)
988
+
989
+ if len_value != len_type:
990
+ self.fail(
991
+ ngettext(
992
+ "{len_type} values are required, but {len_value} was given.",
993
+ "{len_type} values are required, but {len_value} were given.",
994
+ len_value,
995
+ ).format(len_type=len_type, len_value=len_value),
996
+ param=param,
997
+ ctx=ctx,
998
+ )
999
+
1000
+ return tuple(ty(x, param, ctx) for ty, x in zip(self.types, value))
1001
+
1002
+
1003
+ def convert_type(ty: t.Optional[t.Any], default: t.Optional[t.Any] = None) -> ParamType:
1004
+ """Find the most appropriate :class:`ParamType` for the given Python
1005
+ type. If the type isn't provided, it can be inferred from a default
1006
+ value.
1007
+ """
1008
+ guessed_type = False
1009
+
1010
+ if ty is None and default is not None:
1011
+ if isinstance(default, (tuple, list)):
1012
+ # If the default is empty, ty will remain None and will
1013
+ # return STRING.
1014
+ if default:
1015
+ item = default[0]
1016
+
1017
+ # A tuple of tuples needs to detect the inner types.
1018
+ # Can't call convert recursively because that would
1019
+ # incorrectly unwind the tuple to a single type.
1020
+ if isinstance(item, (tuple, list)):
1021
+ ty = tuple(map(type, item))
1022
+ else:
1023
+ ty = type(item)
1024
+ else:
1025
+ ty = type(default)
1026
+
1027
+ guessed_type = True
1028
+
1029
+ if isinstance(ty, tuple):
1030
+ return Tuple(ty)
1031
+
1032
+ if isinstance(ty, ParamType):
1033
+ return ty
1034
+
1035
+ if ty is str or ty is None:
1036
+ return STRING
1037
+
1038
+ if ty is int:
1039
+ return INT
1040
+
1041
+ if ty is float:
1042
+ return FLOAT
1043
+
1044
+ if ty is bool:
1045
+ return BOOL
1046
+
1047
+ if guessed_type:
1048
+ return STRING
1049
+
1050
+ if __debug__:
1051
+ try:
1052
+ if issubclass(ty, ParamType):
1053
+ raise AssertionError(
1054
+ f"Attempted to use an uninstantiated parameter type ({ty})."
1055
+ )
1056
+ except TypeError:
1057
+ # ty is an instance (correct), so issubclass fails.
1058
+ pass
1059
+
1060
+ return FuncParamType(ty)
1061
+
1062
+
1063
+ #: A dummy parameter type that just does nothing. From a user's
1064
+ #: perspective this appears to just be the same as `STRING` but
1065
+ #: internally no string conversion takes place if the input was bytes.
1066
+ #: This is usually useful when working with file paths as they can
1067
+ #: appear in bytes and unicode.
1068
+ #:
1069
+ #: For path related uses the :class:`Path` type is a better choice but
1070
+ #: there are situations where an unprocessed type is useful which is why
1071
+ #: it is is provided.
1072
+ #:
1073
+ #: .. versionadded:: 4.0
1074
+ UNPROCESSED = UnprocessedParamType()
1075
+
1076
+ #: A unicode string parameter type which is the implicit default. This
1077
+ #: can also be selected by using ``str`` as type.
1078
+ STRING = StringParamType()
1079
+
1080
+ #: An integer parameter. This can also be selected by using ``int`` as
1081
+ #: type.
1082
+ INT = IntParamType()
1083
+
1084
+ #: A floating point value parameter. This can also be selected by using
1085
+ #: ``float`` as type.
1086
+ FLOAT = FloatParamType()
1087
+
1088
+ #: A boolean parameter. This is the default for boolean flags. This can
1089
+ #: also be selected by using ``bool`` as a type.
1090
+ BOOL = BoolParamType()
1091
+
1092
+ #: A UUID parameter.
1093
+ UUID = UUIDParameterType()
.venv/lib/python3.11/site-packages/fsspec-2025.2.0.dist-info/INSTALLER ADDED
@@ -0,0 +1 @@
 
 
1
+ pip
.venv/lib/python3.11/site-packages/fsspec-2025.2.0.dist-info/METADATA ADDED
@@ -0,0 +1,278 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Metadata-Version: 2.4
2
+ Name: fsspec
3
+ Version: 2025.2.0
4
+ Summary: File-system specification
5
+ Project-URL: Changelog, https://filesystem-spec.readthedocs.io/en/latest/changelog.html
6
+ Project-URL: Documentation, https://filesystem-spec.readthedocs.io/en/latest/
7
+ Project-URL: Homepage, https://github.com/fsspec/filesystem_spec
8
+ Maintainer-email: Martin Durant <mdurant@anaconda.com>
9
+ License: BSD 3-Clause License
10
+
11
+ Copyright (c) 2018, Martin Durant
12
+ All rights reserved.
13
+
14
+ Redistribution and use in source and binary forms, with or without
15
+ modification, are permitted provided that the following conditions are met:
16
+
17
+ * Redistributions of source code must retain the above copyright notice, this
18
+ list of conditions and the following disclaimer.
19
+
20
+ * Redistributions in binary form must reproduce the above copyright notice,
21
+ this list of conditions and the following disclaimer in the documentation
22
+ and/or other materials provided with the distribution.
23
+
24
+ * Neither the name of the copyright holder nor the names of its
25
+ contributors may be used to endorse or promote products derived from
26
+ this software without specific prior written permission.
27
+
28
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
29
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
31
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
32
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
34
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
35
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
36
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38
+ License-File: LICENSE
39
+ Keywords: file
40
+ Classifier: Development Status :: 4 - Beta
41
+ Classifier: Intended Audience :: Developers
42
+ Classifier: License :: OSI Approved :: BSD License
43
+ Classifier: Operating System :: OS Independent
44
+ Classifier: Programming Language :: Python :: 3.8
45
+ Classifier: Programming Language :: Python :: 3.9
46
+ Classifier: Programming Language :: Python :: 3.10
47
+ Classifier: Programming Language :: Python :: 3.11
48
+ Classifier: Programming Language :: Python :: 3.12
49
+ Classifier: Programming Language :: Python :: 3.13
50
+ Requires-Python: >=3.8
51
+ Provides-Extra: abfs
52
+ Requires-Dist: adlfs; extra == 'abfs'
53
+ Provides-Extra: adl
54
+ Requires-Dist: adlfs; extra == 'adl'
55
+ Provides-Extra: arrow
56
+ Requires-Dist: pyarrow>=1; extra == 'arrow'
57
+ Provides-Extra: dask
58
+ Requires-Dist: dask; extra == 'dask'
59
+ Requires-Dist: distributed; extra == 'dask'
60
+ Provides-Extra: dev
61
+ Requires-Dist: pre-commit; extra == 'dev'
62
+ Requires-Dist: ruff; extra == 'dev'
63
+ Provides-Extra: doc
64
+ Requires-Dist: numpydoc; extra == 'doc'
65
+ Requires-Dist: sphinx; extra == 'doc'
66
+ Requires-Dist: sphinx-design; extra == 'doc'
67
+ Requires-Dist: sphinx-rtd-theme; extra == 'doc'
68
+ Requires-Dist: yarl; extra == 'doc'
69
+ Provides-Extra: dropbox
70
+ Requires-Dist: dropbox; extra == 'dropbox'
71
+ Requires-Dist: dropboxdrivefs; extra == 'dropbox'
72
+ Requires-Dist: requests; extra == 'dropbox'
73
+ Provides-Extra: entrypoints
74
+ Provides-Extra: full
75
+ Requires-Dist: adlfs; extra == 'full'
76
+ Requires-Dist: aiohttp!=4.0.0a0,!=4.0.0a1; extra == 'full'
77
+ Requires-Dist: dask; extra == 'full'
78
+ Requires-Dist: distributed; extra == 'full'
79
+ Requires-Dist: dropbox; extra == 'full'
80
+ Requires-Dist: dropboxdrivefs; extra == 'full'
81
+ Requires-Dist: fusepy; extra == 'full'
82
+ Requires-Dist: gcsfs; extra == 'full'
83
+ Requires-Dist: libarchive-c; extra == 'full'
84
+ Requires-Dist: ocifs; extra == 'full'
85
+ Requires-Dist: panel; extra == 'full'
86
+ Requires-Dist: paramiko; extra == 'full'
87
+ Requires-Dist: pyarrow>=1; extra == 'full'
88
+ Requires-Dist: pygit2; extra == 'full'
89
+ Requires-Dist: requests; extra == 'full'
90
+ Requires-Dist: s3fs; extra == 'full'
91
+ Requires-Dist: smbprotocol; extra == 'full'
92
+ Requires-Dist: tqdm; extra == 'full'
93
+ Provides-Extra: fuse
94
+ Requires-Dist: fusepy; extra == 'fuse'
95
+ Provides-Extra: gcs
96
+ Requires-Dist: gcsfs; extra == 'gcs'
97
+ Provides-Extra: git
98
+ Requires-Dist: pygit2; extra == 'git'
99
+ Provides-Extra: github
100
+ Requires-Dist: requests; extra == 'github'
101
+ Provides-Extra: gs
102
+ Requires-Dist: gcsfs; extra == 'gs'
103
+ Provides-Extra: gui
104
+ Requires-Dist: panel; extra == 'gui'
105
+ Provides-Extra: hdfs
106
+ Requires-Dist: pyarrow>=1; extra == 'hdfs'
107
+ Provides-Extra: http
108
+ Requires-Dist: aiohttp!=4.0.0a0,!=4.0.0a1; extra == 'http'
109
+ Provides-Extra: libarchive
110
+ Requires-Dist: libarchive-c; extra == 'libarchive'
111
+ Provides-Extra: oci
112
+ Requires-Dist: ocifs; extra == 'oci'
113
+ Provides-Extra: s3
114
+ Requires-Dist: s3fs; extra == 's3'
115
+ Provides-Extra: sftp
116
+ Requires-Dist: paramiko; extra == 'sftp'
117
+ Provides-Extra: smb
118
+ Requires-Dist: smbprotocol; extra == 'smb'
119
+ Provides-Extra: ssh
120
+ Requires-Dist: paramiko; extra == 'ssh'
121
+ Provides-Extra: test
122
+ Requires-Dist: aiohttp!=4.0.0a0,!=4.0.0a1; extra == 'test'
123
+ Requires-Dist: numpy; extra == 'test'
124
+ Requires-Dist: pytest; extra == 'test'
125
+ Requires-Dist: pytest-asyncio!=0.22.0; extra == 'test'
126
+ Requires-Dist: pytest-benchmark; extra == 'test'
127
+ Requires-Dist: pytest-cov; extra == 'test'
128
+ Requires-Dist: pytest-mock; extra == 'test'
129
+ Requires-Dist: pytest-recording; extra == 'test'
130
+ Requires-Dist: pytest-rerunfailures; extra == 'test'
131
+ Requires-Dist: requests; extra == 'test'
132
+ Provides-Extra: test-downstream
133
+ Requires-Dist: aiobotocore<3.0.0,>=2.5.4; extra == 'test-downstream'
134
+ Requires-Dist: dask[dataframe,test]; extra == 'test-downstream'
135
+ Requires-Dist: moto[server]<5,>4; extra == 'test-downstream'
136
+ Requires-Dist: pytest-timeout; extra == 'test-downstream'
137
+ Requires-Dist: xarray; extra == 'test-downstream'
138
+ Provides-Extra: test-full
139
+ Requires-Dist: adlfs; extra == 'test-full'
140
+ Requires-Dist: aiohttp!=4.0.0a0,!=4.0.0a1; extra == 'test-full'
141
+ Requires-Dist: cloudpickle; extra == 'test-full'
142
+ Requires-Dist: dask; extra == 'test-full'
143
+ Requires-Dist: distributed; extra == 'test-full'
144
+ Requires-Dist: dropbox; extra == 'test-full'
145
+ Requires-Dist: dropboxdrivefs; extra == 'test-full'
146
+ Requires-Dist: fastparquet; extra == 'test-full'
147
+ Requires-Dist: fusepy; extra == 'test-full'
148
+ Requires-Dist: gcsfs; extra == 'test-full'
149
+ Requires-Dist: jinja2; extra == 'test-full'
150
+ Requires-Dist: kerchunk; extra == 'test-full'
151
+ Requires-Dist: libarchive-c; extra == 'test-full'
152
+ Requires-Dist: lz4; extra == 'test-full'
153
+ Requires-Dist: notebook; extra == 'test-full'
154
+ Requires-Dist: numpy; extra == 'test-full'
155
+ Requires-Dist: ocifs; extra == 'test-full'
156
+ Requires-Dist: pandas; extra == 'test-full'
157
+ Requires-Dist: panel; extra == 'test-full'
158
+ Requires-Dist: paramiko; extra == 'test-full'
159
+ Requires-Dist: pyarrow; extra == 'test-full'
160
+ Requires-Dist: pyarrow>=1; extra == 'test-full'
161
+ Requires-Dist: pyftpdlib; extra == 'test-full'
162
+ Requires-Dist: pygit2; extra == 'test-full'
163
+ Requires-Dist: pytest; extra == 'test-full'
164
+ Requires-Dist: pytest-asyncio!=0.22.0; extra == 'test-full'
165
+ Requires-Dist: pytest-benchmark; extra == 'test-full'
166
+ Requires-Dist: pytest-cov; extra == 'test-full'
167
+ Requires-Dist: pytest-mock; extra == 'test-full'
168
+ Requires-Dist: pytest-recording; extra == 'test-full'
169
+ Requires-Dist: pytest-rerunfailures; extra == 'test-full'
170
+ Requires-Dist: python-snappy; extra == 'test-full'
171
+ Requires-Dist: requests; extra == 'test-full'
172
+ Requires-Dist: smbprotocol; extra == 'test-full'
173
+ Requires-Dist: tqdm; extra == 'test-full'
174
+ Requires-Dist: urllib3; extra == 'test-full'
175
+ Requires-Dist: zarr; extra == 'test-full'
176
+ Requires-Dist: zstandard; extra == 'test-full'
177
+ Provides-Extra: tqdm
178
+ Requires-Dist: tqdm; extra == 'tqdm'
179
+ Description-Content-Type: text/markdown
180
+
181
+ # filesystem_spec
182
+
183
+ [![PyPI version](https://badge.fury.io/py/fsspec.svg)](https://pypi.python.org/pypi/fsspec/)
184
+ [![Anaconda-Server Badge](https://anaconda.org/conda-forge/fsspec/badges/version.svg)](https://anaconda.org/conda-forge/fsspec)
185
+ ![Build](https://github.com/fsspec/filesystem_spec/workflows/CI/badge.svg)
186
+ [![Docs](https://readthedocs.org/projects/filesystem-spec/badge/?version=latest)](https://filesystem-spec.readthedocs.io/en/latest/?badge=latest)
187
+
188
+ A specification for pythonic filesystems.
189
+
190
+ ## Install
191
+
192
+ ```bash
193
+ pip install fsspec
194
+ ```
195
+
196
+ would install the base fsspec. Various optionally supported features might require specification of custom
197
+ extra require, e.g. `pip install fsspec[ssh]` will install dependencies for `ssh` backends support.
198
+ Use `pip install fsspec[full]` for installation of all known extra dependencies.
199
+
200
+ Up-to-date package also provided through conda-forge distribution:
201
+
202
+ ```bash
203
+ conda install -c conda-forge fsspec
204
+ ```
205
+
206
+
207
+ ## Purpose
208
+
209
+ To produce a template or specification for a file-system interface, that specific implementations should follow,
210
+ so that applications making use of them can rely on a common behaviour and not have to worry about the specific
211
+ internal implementation decisions with any given backend. Many such implementations are included in this package,
212
+ or in sister projects such as `s3fs` and `gcsfs`.
213
+
214
+ In addition, if this is well-designed, then additional functionality, such as a key-value store or FUSE
215
+ mounting of the file-system implementation may be available for all implementations "for free".
216
+
217
+ ## Documentation
218
+
219
+ Please refer to [RTD](https://filesystem-spec.readthedocs.io/en/latest/?badge=latest)
220
+
221
+ ## Develop
222
+
223
+ fsspec uses GitHub Actions for CI. Environment files can be found
224
+ in the "ci/" directory. Note that the main environment is called "py38",
225
+ but it is expected that the version of python installed be adjustable at
226
+ CI runtime. For local use, pick a version suitable for you.
227
+
228
+ ```bash
229
+ # For a new environment (mamba / conda).
230
+ mamba create -n fsspec -c conda-forge python=3.9 -y
231
+ conda activate fsspec
232
+
233
+ # Standard dev install with docs and tests.
234
+ pip install -e ".[dev,doc,test]"
235
+
236
+ # Full tests except for downstream
237
+ pip install s3fs
238
+ pip uninstall s3fs
239
+ pip install -e .[dev,doc,test_full]
240
+ pip install s3fs --no-deps
241
+ pytest -v
242
+
243
+ # Downstream tests.
244
+ sh install_s3fs.sh
245
+ # Windows powershell.
246
+ install_s3fs.sh
247
+ ```
248
+
249
+ ### Testing
250
+
251
+ Tests can be run in the dev environment, if activated, via ``pytest fsspec``.
252
+
253
+ The full fsspec suite requires a system-level docker, docker-compose, and fuse
254
+ installation. If only making changes to one backend implementation, it is
255
+ not generally necessary to run all tests locally.
256
+
257
+ It is expected that contributors ensure that any change to fsspec does not
258
+ cause issues or regressions for either other fsspec-related packages such
259
+ as gcsfs and s3fs, nor for downstream users of fsspec. The "downstream" CI
260
+ run and corresponding environment file run a set of tests from the dask
261
+ test suite, and very minimal tests against pandas and zarr from the
262
+ test_downstream.py module in this repo.
263
+
264
+ ### Code Formatting
265
+
266
+ fsspec uses [Black](https://black.readthedocs.io/en/stable) to ensure
267
+ a consistent code format throughout the project.
268
+ Run ``black fsspec`` from the root of the filesystem_spec repository to
269
+ auto-format your code. Additionally, many editors have plugins that will apply
270
+ ``black`` as you edit files. ``black`` is included in the ``tox`` environments.
271
+
272
+ Optionally, you may wish to setup [pre-commit hooks](https://pre-commit.com) to
273
+ automatically run ``black`` when you make a git commit.
274
+ Run ``pre-commit install --install-hooks`` from the root of the
275
+ filesystem_spec repository to setup pre-commit hooks. ``black`` will now be run
276
+ before you commit, reformatting any changed files. You can format without
277
+ committing via ``pre-commit run`` or skip these checks with ``git commit
278
+ --no-verify``.
.venv/lib/python3.11/site-packages/fsspec-2025.2.0.dist-info/RECORD ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ fsspec-2025.2.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
2
+ fsspec-2025.2.0.dist-info/METADATA,sha256=GqrJBTBVJNmkbcEfTOamzq2KqYYbc9vRM0jpSWTZT04,11747
3
+ fsspec-2025.2.0.dist-info/RECORD,,
4
+ fsspec-2025.2.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
5
+ fsspec-2025.2.0.dist-info/licenses/LICENSE,sha256=LcNUls5TpzB5FcAIqESq1T53K0mzTN0ARFBnaRQH7JQ,1513
6
+ fsspec/__init__.py,sha256=l9MJaNNV2d4wKpCtMvXDr55n92DkdrAayGy3F9ICjzk,1998
7
+ fsspec/__pycache__/__init__.cpython-311.pyc,,
8
+ fsspec/__pycache__/_version.cpython-311.pyc,,
9
+ fsspec/__pycache__/archive.cpython-311.pyc,,
10
+ fsspec/__pycache__/asyn.cpython-311.pyc,,
11
+ fsspec/__pycache__/caching.cpython-311.pyc,,
12
+ fsspec/__pycache__/callbacks.cpython-311.pyc,,
13
+ fsspec/__pycache__/compression.cpython-311.pyc,,
14
+ fsspec/__pycache__/config.cpython-311.pyc,,
15
+ fsspec/__pycache__/conftest.cpython-311.pyc,,
16
+ fsspec/__pycache__/core.cpython-311.pyc,,
17
+ fsspec/__pycache__/dircache.cpython-311.pyc,,
18
+ fsspec/__pycache__/exceptions.cpython-311.pyc,,
19
+ fsspec/__pycache__/fuse.cpython-311.pyc,,
20
+ fsspec/__pycache__/generic.cpython-311.pyc,,
21
+ fsspec/__pycache__/gui.cpython-311.pyc,,
22
+ fsspec/__pycache__/json.cpython-311.pyc,,
23
+ fsspec/__pycache__/mapping.cpython-311.pyc,,
24
+ fsspec/__pycache__/parquet.cpython-311.pyc,,
25
+ fsspec/__pycache__/registry.cpython-311.pyc,,
26
+ fsspec/__pycache__/spec.cpython-311.pyc,,
27
+ fsspec/__pycache__/transaction.cpython-311.pyc,,
28
+ fsspec/__pycache__/utils.cpython-311.pyc,,
29
+ fsspec/_version.py,sha256=IE7d_vZlkju9WTb8xdQYMiqPyQOYnfC9HN9w8nHfkrY,417
30
+ fsspec/archive.py,sha256=vM6t_lgV6lBWbBYwpm3S4ofBQFQxUPr5KkDQrrQcQro,2411
31
+ fsspec/asyn.py,sha256=rsnCsFUmBZmKJqg9m-IDWInoQtE4wV0rGDZEXZwuU3c,36500
32
+ fsspec/caching.py,sha256=oHVy9zpy4Oqk5f1t3-Q31bbw0tsmfddGGKLJs__OdKA,32790
33
+ fsspec/callbacks.py,sha256=BDIwLzK6rr_0V5ch557fSzsivCElpdqhXr5dZ9Te-EE,9210
34
+ fsspec/compression.py,sha256=jCSUMJu-zSNyrusnHT0wKXgOd1tTJR6vM126i5SR5Zc,4865
35
+ fsspec/config.py,sha256=LF4Zmu1vhJW7Je9Q-cwkRc3xP7Rhyy7Xnwj26Z6sv2g,4279
36
+ fsspec/conftest.py,sha256=fVfx-NLrH_OZS1TIpYNoPzM7efEcMoL62reHOdYeFCA,1245
37
+ fsspec/core.py,sha256=bn-y3Mn9q8Gh3Ng_yAIDfIjyysQ95tuK78RlhlrqTb4,23828
38
+ fsspec/dircache.py,sha256=YzogWJrhEastHU7vWz-cJiJ7sdtLXFXhEpInGKd4EcM,2717
39
+ fsspec/exceptions.py,sha256=pauSLDMxzTJMOjvX1WEUK0cMyFkrFxpWJsyFywav7A8,331
40
+ fsspec/fuse.py,sha256=Q-3NOOyLqBfYa4Db5E19z_ZY36zzYHtIs1mOUasItBQ,10177
41
+ fsspec/generic.py,sha256=AFbo-mHBt5QJV1Aplg5CJuUiiJ4bNQhcKRuwkZJdWac,13761
42
+ fsspec/gui.py,sha256=xBnHL2-r0LVwhDAtnHoPpXts7jd4Z32peawCJiI-7lI,13975
43
+ fsspec/implementations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
44
+ fsspec/implementations/__pycache__/__init__.cpython-311.pyc,,
45
+ fsspec/implementations/__pycache__/arrow.cpython-311.pyc,,
46
+ fsspec/implementations/__pycache__/asyn_wrapper.cpython-311.pyc,,
47
+ fsspec/implementations/__pycache__/cache_mapper.cpython-311.pyc,,
48
+ fsspec/implementations/__pycache__/cache_metadata.cpython-311.pyc,,
49
+ fsspec/implementations/__pycache__/cached.cpython-311.pyc,,
50
+ fsspec/implementations/__pycache__/dask.cpython-311.pyc,,
51
+ fsspec/implementations/__pycache__/data.cpython-311.pyc,,
52
+ fsspec/implementations/__pycache__/dbfs.cpython-311.pyc,,
53
+ fsspec/implementations/__pycache__/dirfs.cpython-311.pyc,,
54
+ fsspec/implementations/__pycache__/ftp.cpython-311.pyc,,
55
+ fsspec/implementations/__pycache__/git.cpython-311.pyc,,
56
+ fsspec/implementations/__pycache__/github.cpython-311.pyc,,
57
+ fsspec/implementations/__pycache__/http.cpython-311.pyc,,
58
+ fsspec/implementations/__pycache__/jupyter.cpython-311.pyc,,
59
+ fsspec/implementations/__pycache__/libarchive.cpython-311.pyc,,
60
+ fsspec/implementations/__pycache__/local.cpython-311.pyc,,
61
+ fsspec/implementations/__pycache__/memory.cpython-311.pyc,,
62
+ fsspec/implementations/__pycache__/reference.cpython-311.pyc,,
63
+ fsspec/implementations/__pycache__/sftp.cpython-311.pyc,,
64
+ fsspec/implementations/__pycache__/smb.cpython-311.pyc,,
65
+ fsspec/implementations/__pycache__/tar.cpython-311.pyc,,
66
+ fsspec/implementations/__pycache__/webhdfs.cpython-311.pyc,,
67
+ fsspec/implementations/__pycache__/zip.cpython-311.pyc,,
68
+ fsspec/implementations/arrow.py,sha256=721Dikne_lV_0tlgk9jyKmHL6W-5MT0h2LKGvOYQTPI,8623
69
+ fsspec/implementations/asyn_wrapper.py,sha256=gmLy2voDAH9KRxhvd24UDPiOqX_NCK-3JY9rMX7R6Is,2935
70
+ fsspec/implementations/cache_mapper.py,sha256=W4wlxyPxZbSp9ItJ0pYRVBMh6bw9eFypgP6kUYuuiI4,2421
71
+ fsspec/implementations/cache_metadata.py,sha256=pcOJYcBQY5OaC7Yhw0F3wjg08QLYApGmoISCrbs59ks,8511
72
+ fsspec/implementations/cached.py,sha256=KA6c4jqrGeeg8WNPLsh8FkL3KeRAQtGLzKw18vSF1CI,32820
73
+ fsspec/implementations/dask.py,sha256=CXZbJzIVOhKV8ILcxuy3bTvcacCueAbyQxmvAkbPkrk,4466
74
+ fsspec/implementations/data.py,sha256=LDLczxRh8h7x39Zjrd-GgzdQHr78yYxDlrv2C9Uxb5E,1658
75
+ fsspec/implementations/dbfs.py,sha256=XwpotuS_ncz3XK1dkUteww9GnTja7HoY91c0m4GUfwI,15092
76
+ fsspec/implementations/dirfs.py,sha256=ymakitNNQ07tW76EShyw3rC9RvIDHl4gtuOhE_h1vUg,12032
77
+ fsspec/implementations/ftp.py,sha256=sorsczLp_2J3ukONsbZY-11sRZP6H5a3V7XXf6o6ip0,11936
78
+ fsspec/implementations/git.py,sha256=4SElW9U5d3k3_ITlvUAx59Yk7XLNRTqkGa2C3hCUkWM,3754
79
+ fsspec/implementations/github.py,sha256=eAn1kJ7VeWR6gVoVRLBYclF_rQDXSJU-xzMXpvPQWqs,8002
80
+ fsspec/implementations/http.py,sha256=d7G7_pRTMHouKE42lvRNHqB5u4XQi0dm4wb-6U_IiF4,29361
81
+ fsspec/implementations/jupyter.py,sha256=B2uj7OEm7yIk-vRSsO37_ND0t0EBvn4B-Su43ibN4Pg,3811
82
+ fsspec/implementations/libarchive.py,sha256=5_I2DiLXwQ1JC8x-K7jXu-tBwhO9dj7tFLnb0bTnVMQ,7102
83
+ fsspec/implementations/local.py,sha256=YvR9b2MndSQIHszAMUkFvN65eWVbIfoGJJjAeS43ZS4,15259
84
+ fsspec/implementations/memory.py,sha256=cLNrK9wk97sl4Tre9uVDXWj6mEHvvVVIgaVgNA5KVIg,10527
85
+ fsspec/implementations/reference.py,sha256=1VbyjAxq_8xHSQo2UV4ohuuoSAreB3OY4vjK05DnHsY,48646
86
+ fsspec/implementations/sftp.py,sha256=fMY9XZcmpjszQ2tCqO_TPaJesaeD_Dv7ptYzgUPGoO0,5631
87
+ fsspec/implementations/smb.py,sha256=5fhu8h06nOLBPh2c48aT7WBRqh9cEcbIwtyu06wTjec,15236
88
+ fsspec/implementations/tar.py,sha256=dam78Tp_CozybNqCY2JYgGBS3Uc9FuJUAT9oB0lolOs,4111
89
+ fsspec/implementations/webhdfs.py,sha256=G9wGywj7BkZk4Mu9zXu6HaDlEqX4F8Gw1i4k46CP_-o,16769
90
+ fsspec/implementations/zip.py,sha256=9LBMHPft2OutJl2Ft-r9u_z3GptLkc2n91ur2A3bCbg,6072
91
+ fsspec/json.py,sha256=65sQ0Y7mTj33u_Y4IId5up4abQ3bAel4E4QzbKMiQSg,3826
92
+ fsspec/mapping.py,sha256=m2ndB_gtRBXYmNJg0Ie1-BVR75TFleHmIQBzC-yWhjU,8343
93
+ fsspec/parquet.py,sha256=6ibAmG527L5JNFS0VO8BDNlxHdA3bVYqdByeiFgpUVM,19448
94
+ fsspec/registry.py,sha256=QFyMiUV6fnksETJuapNplf6YjkNRIdHSOyd95IqPZe8,11473
95
+ fsspec/spec.py,sha256=l7ZEbgLsnrFuS-yrGl9re6ia1Yts1_10RqGV_mT-5P8,76032
96
+ fsspec/tests/abstract/__init__.py,sha256=4xUJrv7gDgc85xAOz1p-V_K1hrsdMWTSa0rviALlJk8,10181
97
+ fsspec/tests/abstract/__pycache__/__init__.cpython-311.pyc,,
98
+ fsspec/tests/abstract/__pycache__/common.cpython-311.pyc,,
99
+ fsspec/tests/abstract/__pycache__/copy.cpython-311.pyc,,
100
+ fsspec/tests/abstract/__pycache__/get.cpython-311.pyc,,
101
+ fsspec/tests/abstract/__pycache__/mv.cpython-311.pyc,,
102
+ fsspec/tests/abstract/__pycache__/open.cpython-311.pyc,,
103
+ fsspec/tests/abstract/__pycache__/pipe.cpython-311.pyc,,
104
+ fsspec/tests/abstract/__pycache__/put.cpython-311.pyc,,
105
+ fsspec/tests/abstract/common.py,sha256=1GQwNo5AONzAnzZj0fWgn8NJPLXALehbsuGxS3FzWVU,4973
106
+ fsspec/tests/abstract/copy.py,sha256=gU5-d97U3RSde35Vp4RxPY4rWwL744HiSrJ8IBOp9-8,19967
107
+ fsspec/tests/abstract/get.py,sha256=vNR4HztvTR7Cj56AMo7_tx7TeYz1Jgr_2Wb8Lv-UiBY,20755
108
+ fsspec/tests/abstract/mv.py,sha256=k8eUEBIrRrGMsBY5OOaDXdGnQUKGwDIfQyduB6YD3Ns,1982
109
+ fsspec/tests/abstract/open.py,sha256=Fi2PBPYLbRqysF8cFm0rwnB41kMdQVYjq8cGyDXp3BU,329
110
+ fsspec/tests/abstract/pipe.py,sha256=LFzIrLCB5GLXf9rzFKJmE8AdG7LQ_h4bJo70r8FLPqM,402
111
+ fsspec/tests/abstract/put.py,sha256=7aih17OKB_IZZh1Mkq1eBDIjobhtMQmI8x-Pw-S_aZk,21201
112
+ fsspec/transaction.py,sha256=xliRG6U2Zf3khG4xcw9WiB-yAoqJSHEGK_VjHOdtgo0,2398
113
+ fsspec/utils.py,sha256=A11t25RnpiQ30RO6xeR0Qqlu3fGj8bnc40jg08tlYSI,22980
.venv/lib/python3.11/site-packages/fsspec-2025.2.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
.venv/lib/python3.11/site-packages/fsspec-2025.2.0.dist-info/licenses/LICENSE ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2018, Martin Durant
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ * Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+
12
+ * Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+
16
+ * Neither the name of the copyright holder nor the names of its
17
+ contributors may be used to endorse or promote products derived from
18
+ this software without specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.venv/lib/python3.11/site-packages/importlib_metadata-8.6.1.dist-info/INSTALLER ADDED
@@ -0,0 +1 @@
 
 
1
+ pip
.venv/lib/python3.11/site-packages/importlib_metadata-8.6.1.dist-info/LICENSE ADDED
@@ -0,0 +1,202 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright [yyyy] [name of copyright owner]
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
.venv/lib/python3.11/site-packages/importlib_metadata-8.6.1.dist-info/METADATA ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Metadata-Version: 2.2
2
+ Name: importlib_metadata
3
+ Version: 8.6.1
4
+ Summary: Read metadata from Python packages
5
+ Author-email: "Jason R. Coombs" <jaraco@jaraco.com>
6
+ Project-URL: Source, https://github.com/python/importlib_metadata
7
+ Classifier: Development Status :: 5 - Production/Stable
8
+ Classifier: Intended Audience :: Developers
9
+ Classifier: License :: OSI Approved :: Apache Software License
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3 :: Only
12
+ Requires-Python: >=3.9
13
+ Description-Content-Type: text/x-rst
14
+ License-File: LICENSE
15
+ Requires-Dist: zipp>=3.20
16
+ Requires-Dist: typing-extensions>=3.6.4; python_version < "3.8"
17
+ Provides-Extra: test
18
+ Requires-Dist: pytest!=8.1.*,>=6; extra == "test"
19
+ Requires-Dist: importlib_resources>=1.3; python_version < "3.9" and extra == "test"
20
+ Requires-Dist: packaging; extra == "test"
21
+ Requires-Dist: pyfakefs; extra == "test"
22
+ Requires-Dist: flufl.flake8; extra == "test"
23
+ Requires-Dist: pytest-perf>=0.9.2; extra == "test"
24
+ Requires-Dist: jaraco.test>=5.4; extra == "test"
25
+ Provides-Extra: doc
26
+ Requires-Dist: sphinx>=3.5; extra == "doc"
27
+ Requires-Dist: jaraco.packaging>=9.3; extra == "doc"
28
+ Requires-Dist: rst.linker>=1.9; extra == "doc"
29
+ Requires-Dist: furo; extra == "doc"
30
+ Requires-Dist: sphinx-lint; extra == "doc"
31
+ Requires-Dist: jaraco.tidelift>=1.4; extra == "doc"
32
+ Provides-Extra: perf
33
+ Requires-Dist: ipython; extra == "perf"
34
+ Provides-Extra: check
35
+ Requires-Dist: pytest-checkdocs>=2.4; extra == "check"
36
+ Requires-Dist: pytest-ruff>=0.2.1; sys_platform != "cygwin" and extra == "check"
37
+ Provides-Extra: cover
38
+ Requires-Dist: pytest-cov; extra == "cover"
39
+ Provides-Extra: enabler
40
+ Requires-Dist: pytest-enabler>=2.2; extra == "enabler"
41
+ Provides-Extra: type
42
+ Requires-Dist: pytest-mypy; extra == "type"
43
+
44
+ .. image:: https://img.shields.io/pypi/v/importlib_metadata.svg
45
+ :target: https://pypi.org/project/importlib_metadata
46
+
47
+ .. image:: https://img.shields.io/pypi/pyversions/importlib_metadata.svg
48
+
49
+ .. image:: https://github.com/python/importlib_metadata/actions/workflows/main.yml/badge.svg
50
+ :target: https://github.com/python/importlib_metadata/actions?query=workflow%3A%22tests%22
51
+ :alt: tests
52
+
53
+ .. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/badge/v2.json
54
+ :target: https://github.com/astral-sh/ruff
55
+ :alt: Ruff
56
+
57
+ .. image:: https://readthedocs.org/projects/importlib-metadata/badge/?version=latest
58
+ :target: https://importlib-metadata.readthedocs.io/en/latest/?badge=latest
59
+
60
+ .. image:: https://img.shields.io/badge/skeleton-2024-informational
61
+ :target: https://blog.jaraco.com/skeleton
62
+
63
+ .. image:: https://tidelift.com/badges/package/pypi/importlib-metadata
64
+ :target: https://tidelift.com/subscription/pkg/pypi-importlib-metadata?utm_source=pypi-importlib-metadata&utm_medium=readme
65
+
66
+ Library to access the metadata for a Python package.
67
+
68
+ This package supplies third-party access to the functionality of
69
+ `importlib.metadata <https://docs.python.org/3/library/importlib.metadata.html>`_
70
+ including improvements added to subsequent Python versions.
71
+
72
+
73
+ Compatibility
74
+ =============
75
+
76
+ New features are introduced in this third-party library and later merged
77
+ into CPython. The following table indicates which versions of this library
78
+ were contributed to different versions in the standard library:
79
+
80
+ .. list-table::
81
+ :header-rows: 1
82
+
83
+ * - importlib_metadata
84
+ - stdlib
85
+ * - 7.0
86
+ - 3.13
87
+ * - 6.5
88
+ - 3.12
89
+ * - 4.13
90
+ - 3.11
91
+ * - 4.6
92
+ - 3.10
93
+ * - 1.4
94
+ - 3.8
95
+
96
+
97
+ Usage
98
+ =====
99
+
100
+ See the `online documentation <https://importlib-metadata.readthedocs.io/>`_
101
+ for usage details.
102
+
103
+ `Finder authors
104
+ <https://docs.python.org/3/reference/import.html#finders-and-loaders>`_ can
105
+ also add support for custom package installers. See the above documentation
106
+ for details.
107
+
108
+
109
+ Caveats
110
+ =======
111
+
112
+ This project primarily supports third-party packages installed by PyPA
113
+ tools (or other conforming packages). It does not support:
114
+
115
+ - Packages in the stdlib.
116
+ - Packages installed without metadata.
117
+
118
+ Project details
119
+ ===============
120
+
121
+ * Project home: https://github.com/python/importlib_metadata
122
+ * Report bugs at: https://github.com/python/importlib_metadata/issues
123
+ * Code hosting: https://github.com/python/importlib_metadata
124
+ * Documentation: https://importlib-metadata.readthedocs.io/
125
+
126
+ For Enterprise
127
+ ==============
128
+
129
+ Available as part of the Tidelift Subscription.
130
+
131
+ This project and the maintainers of thousands of other packages are working with Tidelift to deliver one enterprise subscription that covers all of the open source you use.
132
+
133
+ `Learn more <https://tidelift.com/subscription/pkg/pypi-importlib-metadata?utm_source=pypi-importlib-metadata&utm_medium=referral&utm_campaign=github>`_.
.venv/lib/python3.11/site-packages/importlib_metadata-8.6.1.dist-info/RECORD ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ importlib_metadata-8.6.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
2
+ importlib_metadata-8.6.1.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
3
+ importlib_metadata-8.6.1.dist-info/METADATA,sha256=F24ATbamOm1kp40IQGodtMLWMrH-fVEksdySlZk_KAY,4738
4
+ importlib_metadata-8.6.1.dist-info/RECORD,,
5
+ importlib_metadata-8.6.1.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
6
+ importlib_metadata-8.6.1.dist-info/top_level.txt,sha256=CO3fD9yylANiXkrMo4qHLV_mqXL2sC5JFKgt1yWAT-A,19
7
+ importlib_metadata/__init__.py,sha256=-Sk7aVqfmzLecdjSOpLKo1P_PegQanR__HsMMyEq0PI,35853
8
+ importlib_metadata/__pycache__/__init__.cpython-311.pyc,,
9
+ importlib_metadata/__pycache__/_adapters.cpython-311.pyc,,
10
+ importlib_metadata/__pycache__/_collections.cpython-311.pyc,,
11
+ importlib_metadata/__pycache__/_compat.cpython-311.pyc,,
12
+ importlib_metadata/__pycache__/_functools.cpython-311.pyc,,
13
+ importlib_metadata/__pycache__/_itertools.cpython-311.pyc,,
14
+ importlib_metadata/__pycache__/_meta.cpython-311.pyc,,
15
+ importlib_metadata/__pycache__/_text.cpython-311.pyc,,
16
+ importlib_metadata/__pycache__/diagnose.cpython-311.pyc,,
17
+ importlib_metadata/_adapters.py,sha256=9Y3FAlZuoo8pOMVLnKXm5Xx6hKgsdUQOXF5SkiDGqWo,3784
18
+ importlib_metadata/_collections.py,sha256=CJ0OTCHIjWA0ZIVS4voORAsn2R4R2cQBEtPsZEJpASY,743
19
+ importlib_metadata/_compat.py,sha256=VC5ZDLlT-BcshauCShdFJvMNLntJJfZzNK1meGa-enw,1313
20
+ importlib_metadata/_functools.py,sha256=bSbAqC9-2niWM9364FYBx9GWtetnJEfo4mdLv8uMl7c,2895
21
+ importlib_metadata/_itertools.py,sha256=nMvp9SfHAQ_JYwK4L2i64lr3GRXGlYlikGTVzWbys_E,5351
22
+ importlib_metadata/_meta.py,sha256=JzuqMG4za5MoaBPCPv61c26fUBdQPZ4by3pbaQA_E_o,1823
23
+ importlib_metadata/_text.py,sha256=HCsFksZpJLeTP3NEk_ngrAeXVRRtTrtyh9eOABoRP4A,2166
24
+ importlib_metadata/compat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
+ importlib_metadata/compat/__pycache__/__init__.cpython-311.pyc,,
26
+ importlib_metadata/compat/__pycache__/py311.cpython-311.pyc,,
27
+ importlib_metadata/compat/__pycache__/py39.cpython-311.pyc,,
28
+ importlib_metadata/compat/py311.py,sha256=uqm-K-uohyj1042TH4a9Er_I5o7667DvulcD-gC_fSA,608
29
+ importlib_metadata/compat/py39.py,sha256=cPkMv6-0ilK-0Jw_Tkn0xYbOKJZc4WJKQHow0c2T44w,1102
30
+ importlib_metadata/diagnose.py,sha256=nkSRMiowlmkhLYhKhvCg9glmt_11Cox-EmLzEbqYTa8,379
31
+ importlib_metadata/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
.venv/lib/python3.11/site-packages/importlib_metadata-8.6.1.dist-info/WHEEL ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (75.8.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
.venv/lib/python3.11/site-packages/importlib_metadata-8.6.1.dist-info/top_level.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ importlib_metadata
.venv/lib/python3.11/site-packages/oauth2client-4.1.3.dist-info/INSTALLER ADDED
@@ -0,0 +1 @@
 
 
1
+ pip
.venv/lib/python3.11/site-packages/oauth2client-4.1.3.dist-info/METADATA ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Metadata-Version: 2.1
2
+ Name: oauth2client
3
+ Version: 4.1.3
4
+ Summary: OAuth 2.0 client library
5
+ Home-page: http://github.com/google/oauth2client/
6
+ Author: Google Inc.
7
+ Author-email: jonwayne+oauth2client@google.com
8
+ License: Apache 2.0
9
+ Keywords: google oauth 2.0 http client
10
+ Platform: UNKNOWN
11
+ Classifier: Programming Language :: Python :: 2
12
+ Classifier: Programming Language :: Python :: 2.7
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.4
15
+ Classifier: Programming Language :: Python :: 3.5
16
+ Classifier: Development Status :: 7 - Inactive
17
+ Classifier: Intended Audience :: Developers
18
+ Classifier: License :: OSI Approved :: Apache Software License
19
+ Classifier: Operating System :: POSIX
20
+ Classifier: Topic :: Internet :: WWW/HTTP
21
+ Requires-Dist: httplib2 (>=0.9.1)
22
+ Requires-Dist: pyasn1 (>=0.1.7)
23
+ Requires-Dist: pyasn1-modules (>=0.0.5)
24
+ Requires-Dist: rsa (>=3.1.4)
25
+ Requires-Dist: six (>=1.6.1)
26
+
27
+ oauth2client is a client library for OAuth 2.0.
28
+
29
+ Note: oauth2client is now deprecated. No more features will be added to the
30
+ libraries and the core team is turning down support. We recommend you use
31
+ `google-auth <https://google-auth.readthedocs.io>`__ and
32
+ `oauthlib <http://oauthlib.readthedocs.io/>`__.
33
+
34
+
.venv/lib/python3.11/site-packages/oauth2client-4.1.3.dist-info/RECORD ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ oauth2client-4.1.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
2
+ oauth2client-4.1.3.dist-info/METADATA,sha256=JZWZEBXJhRlFYMHmep-HdaeRsY1jWD35JiWPYzSGdF4,1247
3
+ oauth2client-4.1.3.dist-info/RECORD,,
4
+ oauth2client-4.1.3.dist-info/WHEEL,sha256=gduuPyBvFJQSQ0zdyxF7k0zynDXbIbvg5ZBHoXum5uk,110
5
+ oauth2client-4.1.3.dist-info/top_level.txt,sha256=omHPlSNz2suNBxXgtIrjYmhEGUmNTYAfPQ5lwQ69Nlc,13
6
+ oauth2client/__init__.py,sha256=TBa120J9aG9Gcu6t2PZYaitkua7M3k_vzkedK8ABJA0,1002
7
+ oauth2client/__pycache__/__init__.cpython-311.pyc,,
8
+ oauth2client/__pycache__/_helpers.cpython-311.pyc,,
9
+ oauth2client/__pycache__/_openssl_crypt.cpython-311.pyc,,
10
+ oauth2client/__pycache__/_pkce.cpython-311.pyc,,
11
+ oauth2client/__pycache__/_pure_python_crypt.cpython-311.pyc,,
12
+ oauth2client/__pycache__/_pycrypto_crypt.cpython-311.pyc,,
13
+ oauth2client/__pycache__/client.cpython-311.pyc,,
14
+ oauth2client/__pycache__/clientsecrets.cpython-311.pyc,,
15
+ oauth2client/__pycache__/crypt.cpython-311.pyc,,
16
+ oauth2client/__pycache__/file.cpython-311.pyc,,
17
+ oauth2client/__pycache__/service_account.cpython-311.pyc,,
18
+ oauth2client/__pycache__/tools.cpython-311.pyc,,
19
+ oauth2client/__pycache__/transport.cpython-311.pyc,,
20
+ oauth2client/_helpers.py,sha256=SamYkoAl9AJFpX4VDSFs36X69tdUmqzMwQAWuR-Khr8,10852
21
+ oauth2client/_openssl_crypt.py,sha256=SsdLrYE36SkJRpgyPl70cf9nQC2-HyBHJcEYSsG_tl8,4556
22
+ oauth2client/_pkce.py,sha256=XJaILUCZmTEI8wPBHQMRPo8NenOt2qYG4L7Dqrn57BI,2198
23
+ oauth2client/_pure_python_crypt.py,sha256=WllaU6FHNgqv9L_cGVmfcZbvgrnXn68O5buuvUrZx_w,6367
24
+ oauth2client/_pycrypto_crypt.py,sha256=hDYgYMc0Gh2rRA35C6YsQ16rYH_xhJaWBEEyJnfsvRo,4118
25
+ oauth2client/client.py,sha256=vguAS807amedrYxcdXaE3Y3FiuX9LdBXAavhjkQF1jE,83289
26
+ oauth2client/clientsecrets.py,sha256=ahMPXRucWfHbt7BdZynQrij_9HXy_tPBEfKfCKgjld8,5281
27
+ oauth2client/contrib/__init__.py,sha256=RgS87vH1KJhMUFArK1-bICLabNB6kcwM_Lx_mEkO45o,220
28
+ oauth2client/contrib/__pycache__/__init__.cpython-311.pyc,,
29
+ oauth2client/contrib/__pycache__/_appengine_ndb.cpython-311.pyc,,
30
+ oauth2client/contrib/__pycache__/_metadata.cpython-311.pyc,,
31
+ oauth2client/contrib/__pycache__/appengine.cpython-311.pyc,,
32
+ oauth2client/contrib/__pycache__/devshell.cpython-311.pyc,,
33
+ oauth2client/contrib/__pycache__/dictionary_storage.cpython-311.pyc,,
34
+ oauth2client/contrib/__pycache__/flask_util.cpython-311.pyc,,
35
+ oauth2client/contrib/__pycache__/gce.cpython-311.pyc,,
36
+ oauth2client/contrib/__pycache__/keyring_storage.cpython-311.pyc,,
37
+ oauth2client/contrib/__pycache__/multiprocess_file_storage.cpython-311.pyc,,
38
+ oauth2client/contrib/__pycache__/sqlalchemy.cpython-311.pyc,,
39
+ oauth2client/contrib/__pycache__/xsrfutil.cpython-311.pyc,,
40
+ oauth2client/contrib/_appengine_ndb.py,sha256=8l4erxmgtdK5mRrDu_NJaaWyU_o_fyvjFyCOPElvNtQ,5381
41
+ oauth2client/contrib/_metadata.py,sha256=Y-TwnItsOb1o2Abt1b3-yP5com3VrrUmwEeL-B3qUNs,4181
42
+ oauth2client/contrib/appengine.py,sha256=bPV7qY8GbK73qVVbOXVjumAI-K6img-C-dovWy8si9Q,33941
43
+ oauth2client/contrib/devshell.py,sha256=BdM3eX6nvR4J0cXb-nPx-VjrEqhQRlvNH1Z14R8gYgc,4991
44
+ oauth2client/contrib/dictionary_storage.py,sha256=TRxniVD5VzQUD0gUQ2fzyzlJAtMsaEoYOMkbZfklgqU,2278
45
+ oauth2client/contrib/django_util/__init__.py,sha256=HSuW5HW60Oty5uivnQ1KoRUD4g88NQCFsyYPOwOntNw,18152
46
+ oauth2client/contrib/django_util/__pycache__/__init__.cpython-311.pyc,,
47
+ oauth2client/contrib/django_util/__pycache__/apps.cpython-311.pyc,,
48
+ oauth2client/contrib/django_util/__pycache__/decorators.cpython-311.pyc,,
49
+ oauth2client/contrib/django_util/__pycache__/models.cpython-311.pyc,,
50
+ oauth2client/contrib/django_util/__pycache__/signals.cpython-311.pyc,,
51
+ oauth2client/contrib/django_util/__pycache__/site.cpython-311.pyc,,
52
+ oauth2client/contrib/django_util/__pycache__/storage.cpython-311.pyc,,
53
+ oauth2client/contrib/django_util/__pycache__/views.cpython-311.pyc,,
54
+ oauth2client/contrib/django_util/apps.py,sha256=S8wE_F8BJkyl0MKZfdB1wyIq39Zf4-rZwwCOhZR3k3E,1213
55
+ oauth2client/contrib/django_util/decorators.py,sha256=6caUSK4jvZz15jE2GL0XXC2o3zuRQoqEuup5KfvdRAw,5564
56
+ oauth2client/contrib/django_util/models.py,sha256=Q_bp__GHZNJ2tjIY8nuE4Z4bDE7O2JqAwiZtKLHZzrA,2742
57
+ oauth2client/contrib/django_util/signals.py,sha256=8RXmCgWXc9A5Se-ELQ-ny2uvCknBdQxB4fSpFo0ye70,1050
58
+ oauth2client/contrib/django_util/site.py,sha256=ywnit7c6MXN-MUhAB0T3IgLg0xa75dmrUGqke9zfJW8,960
59
+ oauth2client/contrib/django_util/storage.py,sha256=7XnyxjHydqEzBQUYhJRGzb0bqpmTS3b6iyF0wQODDCU,3070
60
+ oauth2client/contrib/django_util/views.py,sha256=lMlLk2yE6cs_O-OCiMxjyAGpdrAtnoajs6a1BUXN-U4,6785
61
+ oauth2client/contrib/flask_util.py,sha256=N9NhLOD7u4ZerJ1oOha8nj8uVZ_nNleqmndoTSvgd0M,19413
62
+ oauth2client/contrib/gce.py,sha256=lmcesVXQuiRk8LWg9wk9UsNpV_a4bmv1RVU3Q86MjK8,5431
63
+ oauth2client/contrib/keyring_storage.py,sha256=F4r96naObAPaJwrT_oZKCXu_b4GKBRASq21ND55EjrY,3091
64
+ oauth2client/contrib/multiprocess_file_storage.py,sha256=BIotaqL2rrruGIJbivZT1JG8Q_viL26RpFxL6b-ocUI,11679
65
+ oauth2client/contrib/sqlalchemy.py,sha256=nUHF369AFDth3a0G0MhovK1YSy7J1ETNioZrvVKbw_Q,5246
66
+ oauth2client/contrib/xsrfutil.py,sha256=KEQmQ29rkUkZldwVZ3QFfaX91prJOZLjvZP_PoygMBU,3470
67
+ oauth2client/crypt.py,sha256=7DjFdzNK4aeQ1FhXfwysf_iV6KVLnvVvMVIz6hckjoI,8447
68
+ oauth2client/file.py,sha256=YmIp9Ut4AVXHCKzZMzRoQHdk6unyCjfQcht_8brd4KU,2730
69
+ oauth2client/service_account.py,sha256=35g1easZKkx8kMcc7EJtRvR46JAz5WxyYJB7jNk4Tc0,28195
70
+ oauth2client/tools.py,sha256=8Oy5jSnvkLdxs88Xkoe7Nvy98536A7k0JYhDbE0yuNc,9069
71
+ oauth2client/transport.py,sha256=-RrkwCG1EtD6V68jMk_RhW2YMImjQXmPYRoJ3igKchY,10367
.venv/lib/python3.11/site-packages/oauth2client-4.1.3.dist-info/WHEEL ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ Wheel-Version: 1.0
2
+ Generator: bdist_wheel (0.31.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py2-none-any
5
+ Tag: py3-none-any
6
+
.venv/lib/python3.11/site-packages/oauth2client-4.1.3.dist-info/top_level.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ oauth2client
.venv/lib/python3.11/site-packages/opencv_python_headless.libs/libavformat-d296e685.so.59.27.100 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:71bbf605de259ea96b5cd8149c81a2cbb328d8a0c5e81389570177d508a3b4be
3
+ size 2571489
.venv/lib/python3.11/site-packages/opencv_python_headless.libs/libcrypto-8c1ab3ad.so.1.1 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d562e9ddc5621cad39f1d4a989fb233e6ebd59178b2a54fe06e8bc23a7389600
3
+ size 3481345
.venv/lib/python3.11/site-packages/opencv_python_headless.libs/libpng16-ef62451c.so.16.44.0 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:39e236462d06ff259b3d6b94eeda6c16311a139e5cc5a30a035f6ae8631d6319
3
+ size 1105201
.venv/lib/python3.11/site-packages/opencv_python_headless.libs/libquadmath-96973f99.so.0.0.0 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:934c22ded0e7d169c4d4678876c96051adf3d94545da962f60b41659b075da3b
3
+ size 247609
.venv/lib/python3.11/site-packages/opencv_python_headless.libs/libswresample-3e7db482.so.4.7.100 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e1870006793d8396a4aa7a6db3e228aa0a30ae4781a639787bc1dc78f76bc220
3
+ size 132417
.venv/lib/python3.11/site-packages/opencv_python_headless.libs/libswscale-95ddd674.so.6.7.100 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:72155ab5149130621f244a9c22259713208f25e0a5b295957479b9d3bc185be1
3
+ size 619945
.venv/lib/python3.11/site-packages/propcache/__init__.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """propcache: An accelerated property cache for Python classes."""
2
+
3
+ from typing import TYPE_CHECKING
4
+
5
+ _PUBLIC_API = ("cached_property", "under_cached_property")
6
+
7
+ __version__ = "0.2.1"
8
+ __all__ = ()
9
+
10
+ # Imports have moved to `propcache.api` in 0.2.0+.
11
+ # This module is now a facade for the API.
12
+ if TYPE_CHECKING:
13
+ from .api import cached_property as cached_property # noqa: F401
14
+ from .api import under_cached_property as under_cached_property # noqa: F401
15
+
16
+
17
+ def _import_facade(attr: str) -> object:
18
+ """Import the public API from the `api` module."""
19
+ if attr in _PUBLIC_API:
20
+ from . import api # pylint: disable=import-outside-toplevel
21
+
22
+ return getattr(api, attr)
23
+ raise AttributeError(f"module '{__package__}' has no attribute '{attr}'")
24
+
25
+
26
+ def _dir_facade() -> list[str]:
27
+ """Include the public API in the module's dir() output."""
28
+ return [*_PUBLIC_API, *globals().keys()]
29
+
30
+
31
+ __getattr__ = _import_facade
32
+ __dir__ = _dir_facade
.venv/lib/python3.11/site-packages/propcache/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (1.44 kB). View file
 
.venv/lib/python3.11/site-packages/propcache/__pycache__/_helpers.cpython-311.pyc ADDED
Binary file (1.2 kB). View file
 
.venv/lib/python3.11/site-packages/propcache/__pycache__/_helpers_py.cpython-311.pyc ADDED
Binary file (3.45 kB). View file
 
.venv/lib/python3.11/site-packages/propcache/__pycache__/api.cpython-311.pyc ADDED
Binary file (359 Bytes). View file