koichi12 commited on
Commit
da4944c
·
verified ·
1 Parent(s): 0d81548

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. .venv/lib/python3.11/site-packages/huggingface_hub/commands/__init__.py +27 -0
  2. .venv/lib/python3.11/site-packages/huggingface_hub/commands/__pycache__/__init__.cpython-311.pyc +0 -0
  3. .venv/lib/python3.11/site-packages/huggingface_hub/commands/__pycache__/_cli_utils.cpython-311.pyc +0 -0
  4. .venv/lib/python3.11/site-packages/huggingface_hub/commands/__pycache__/delete_cache.cpython-311.pyc +0 -0
  5. .venv/lib/python3.11/site-packages/huggingface_hub/commands/__pycache__/download.cpython-311.pyc +0 -0
  6. .venv/lib/python3.11/site-packages/huggingface_hub/commands/__pycache__/env.cpython-311.pyc +0 -0
  7. .venv/lib/python3.11/site-packages/huggingface_hub/commands/__pycache__/huggingface_cli.cpython-311.pyc +0 -0
  8. .venv/lib/python3.11/site-packages/huggingface_hub/commands/__pycache__/lfs.cpython-311.pyc +0 -0
  9. .venv/lib/python3.11/site-packages/huggingface_hub/commands/__pycache__/repo_files.cpython-311.pyc +0 -0
  10. .venv/lib/python3.11/site-packages/huggingface_hub/commands/__pycache__/scan_cache.cpython-311.pyc +0 -0
  11. .venv/lib/python3.11/site-packages/huggingface_hub/commands/__pycache__/tag.cpython-311.pyc +0 -0
  12. .venv/lib/python3.11/site-packages/huggingface_hub/commands/__pycache__/upload.cpython-311.pyc +0 -0
  13. .venv/lib/python3.11/site-packages/huggingface_hub/commands/__pycache__/upload_large_folder.cpython-311.pyc +0 -0
  14. .venv/lib/python3.11/site-packages/huggingface_hub/commands/__pycache__/user.cpython-311.pyc +0 -0
  15. .venv/lib/python3.11/site-packages/huggingface_hub/commands/__pycache__/version.cpython-311.pyc +0 -0
  16. .venv/lib/python3.11/site-packages/huggingface_hub/commands/_cli_utils.py +69 -0
  17. .venv/lib/python3.11/site-packages/huggingface_hub/commands/delete_cache.py +428 -0
  18. .venv/lib/python3.11/site-packages/huggingface_hub/commands/download.py +200 -0
  19. .venv/lib/python3.11/site-packages/huggingface_hub/commands/env.py +36 -0
  20. .venv/lib/python3.11/site-packages/huggingface_hub/commands/huggingface_cli.py +61 -0
  21. .venv/lib/python3.11/site-packages/huggingface_hub/commands/lfs.py +200 -0
  22. .venv/lib/python3.11/site-packages/huggingface_hub/commands/repo_files.py +128 -0
  23. .venv/lib/python3.11/site-packages/huggingface_hub/commands/scan_cache.py +181 -0
  24. .venv/lib/python3.11/site-packages/huggingface_hub/commands/tag.py +159 -0
  25. .venv/lib/python3.11/site-packages/huggingface_hub/commands/upload.py +299 -0
  26. .venv/lib/python3.11/site-packages/huggingface_hub/commands/upload_large_folder.py +129 -0
  27. .venv/lib/python3.11/site-packages/huggingface_hub/commands/user.py +304 -0
  28. .venv/lib/python3.11/site-packages/huggingface_hub/commands/version.py +37 -0
  29. .venv/lib/python3.11/site-packages/huggingface_hub/serialization/__pycache__/__init__.cpython-311.pyc +0 -0
  30. .venv/lib/python3.11/site-packages/huggingface_hub/serialization/__pycache__/_base.cpython-311.pyc +0 -0
  31. .venv/lib/python3.11/site-packages/huggingface_hub/serialization/__pycache__/_tensorflow.cpython-311.pyc +0 -0
  32. .venv/lib/python3.11/site-packages/huggingface_hub/serialization/__pycache__/_torch.cpython-311.pyc +0 -0
  33. .venv/lib/python3.11/site-packages/huggingface_hub/utils/__init__.py +110 -0
  34. .venv/lib/python3.11/site-packages/huggingface_hub/utils/__pycache__/_chunk_utils.cpython-311.pyc +0 -0
  35. .venv/lib/python3.11/site-packages/huggingface_hub/utils/__pycache__/_fixes.cpython-311.pyc +0 -0
  36. .venv/lib/python3.11/site-packages/huggingface_hub/utils/__pycache__/_git_credential.cpython-311.pyc +0 -0
  37. .venv/lib/python3.11/site-packages/huggingface_hub/utils/__pycache__/_headers.cpython-311.pyc +0 -0
  38. .venv/lib/python3.11/site-packages/huggingface_hub/utils/__pycache__/_hf_folder.cpython-311.pyc +0 -0
  39. .venv/lib/python3.11/site-packages/huggingface_hub/utils/__pycache__/_http.cpython-311.pyc +0 -0
  40. .venv/lib/python3.11/site-packages/huggingface_hub/utils/__pycache__/_lfs.cpython-311.pyc +0 -0
  41. .venv/lib/python3.11/site-packages/huggingface_hub/utils/__pycache__/_pagination.cpython-311.pyc +0 -0
  42. .venv/lib/python3.11/site-packages/huggingface_hub/utils/__pycache__/_paths.cpython-311.pyc +0 -0
  43. .venv/lib/python3.11/site-packages/huggingface_hub/utils/__pycache__/_runtime.cpython-311.pyc +0 -0
  44. .venv/lib/python3.11/site-packages/huggingface_hub/utils/__pycache__/_safetensors.cpython-311.pyc +0 -0
  45. .venv/lib/python3.11/site-packages/huggingface_hub/utils/__pycache__/_subprocess.cpython-311.pyc +0 -0
  46. .venv/lib/python3.11/site-packages/huggingface_hub/utils/__pycache__/_telemetry.cpython-311.pyc +0 -0
  47. .venv/lib/python3.11/site-packages/huggingface_hub/utils/__pycache__/_typing.cpython-311.pyc +0 -0
  48. .venv/lib/python3.11/site-packages/huggingface_hub/utils/__pycache__/_validators.cpython-311.pyc +0 -0
  49. .venv/lib/python3.11/site-packages/huggingface_hub/utils/__pycache__/sha.cpython-311.pyc +0 -0
  50. .venv/lib/python3.11/site-packages/huggingface_hub/utils/_auth.py +214 -0
.venv/lib/python3.11/site-packages/huggingface_hub/commands/__init__.py ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2020 The HuggingFace Team. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from abc import ABC, abstractmethod
16
+ from argparse import _SubParsersAction
17
+
18
+
19
+ class BaseHuggingfaceCLICommand(ABC):
20
+ @staticmethod
21
+ @abstractmethod
22
+ def register_subcommand(parser: _SubParsersAction):
23
+ raise NotImplementedError()
24
+
25
+ @abstractmethod
26
+ def run(self):
27
+ raise NotImplementedError()
.venv/lib/python3.11/site-packages/huggingface_hub/commands/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (1.12 kB). View file
 
.venv/lib/python3.11/site-packages/huggingface_hub/commands/__pycache__/_cli_utils.cpython-311.pyc ADDED
Binary file (3.89 kB). View file
 
.venv/lib/python3.11/site-packages/huggingface_hub/commands/__pycache__/delete_cache.cpython-311.pyc ADDED
Binary file (20 kB). View file
 
.venv/lib/python3.11/site-packages/huggingface_hub/commands/__pycache__/download.cpython-311.pyc ADDED
Binary file (8.85 kB). View file
 
.venv/lib/python3.11/site-packages/huggingface_hub/commands/__pycache__/env.cpython-311.pyc ADDED
Binary file (1.63 kB). View file
 
.venv/lib/python3.11/site-packages/huggingface_hub/commands/__pycache__/huggingface_cli.cpython-311.pyc ADDED
Binary file (2.81 kB). View file
 
.venv/lib/python3.11/site-packages/huggingface_hub/commands/__pycache__/lfs.cpython-311.pyc ADDED
Binary file (9.6 kB). View file
 
.venv/lib/python3.11/site-packages/huggingface_hub/commands/__pycache__/repo_files.cpython-311.pyc ADDED
Binary file (5.87 kB). View file
 
.venv/lib/python3.11/site-packages/huggingface_hub/commands/__pycache__/scan_cache.cpython-311.pyc ADDED
Binary file (10.5 kB). View file
 
.venv/lib/python3.11/site-packages/huggingface_hub/commands/__pycache__/tag.cpython-311.pyc ADDED
Binary file (10.9 kB). View file
 
.venv/lib/python3.11/site-packages/huggingface_hub/commands/__pycache__/upload.cpython-311.pyc ADDED
Binary file (13.8 kB). View file
 
.venv/lib/python3.11/site-packages/huggingface_hub/commands/__pycache__/upload_large_folder.cpython-311.pyc ADDED
Binary file (6.84 kB). View file
 
.venv/lib/python3.11/site-packages/huggingface_hub/commands/__pycache__/user.cpython-311.pyc ADDED
Binary file (18 kB). View file
 
.venv/lib/python3.11/site-packages/huggingface_hub/commands/__pycache__/version.cpython-311.pyc ADDED
Binary file (1.7 kB). View file
 
.venv/lib/python3.11/site-packages/huggingface_hub/commands/_cli_utils.py ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2022 The HuggingFace Team. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ """Contains a utility for good-looking prints."""
15
+
16
+ import os
17
+ from typing import List, Union
18
+
19
+
20
+ class ANSI:
21
+ """
22
+ Helper for en.wikipedia.org/wiki/ANSI_escape_code
23
+ """
24
+
25
+ _bold = "\u001b[1m"
26
+ _gray = "\u001b[90m"
27
+ _red = "\u001b[31m"
28
+ _reset = "\u001b[0m"
29
+ _yellow = "\u001b[33m"
30
+
31
+ @classmethod
32
+ def bold(cls, s: str) -> str:
33
+ return cls._format(s, cls._bold)
34
+
35
+ @classmethod
36
+ def gray(cls, s: str) -> str:
37
+ return cls._format(s, cls._gray)
38
+
39
+ @classmethod
40
+ def red(cls, s: str) -> str:
41
+ return cls._format(s, cls._bold + cls._red)
42
+
43
+ @classmethod
44
+ def yellow(cls, s: str) -> str:
45
+ return cls._format(s, cls._yellow)
46
+
47
+ @classmethod
48
+ def _format(cls, s: str, code: str) -> str:
49
+ if os.environ.get("NO_COLOR"):
50
+ # See https://no-color.org/
51
+ return s
52
+ return f"{code}{s}{cls._reset}"
53
+
54
+
55
+ def tabulate(rows: List[List[Union[str, int]]], headers: List[str]) -> str:
56
+ """
57
+ Inspired by:
58
+
59
+ - stackoverflow.com/a/8356620/593036
60
+ - stackoverflow.com/questions/9535954/printing-lists-as-tabular-data
61
+ """
62
+ col_widths = [max(len(str(x)) for x in col) for col in zip(*rows, headers)]
63
+ row_format = ("{{:{}}} " * len(headers)).format(*col_widths)
64
+ lines = []
65
+ lines.append(row_format.format(*headers))
66
+ lines.append(row_format.format(*["-" * w for w in col_widths]))
67
+ for row in rows:
68
+ lines.append(row_format.format(*row))
69
+ return "\n".join(lines)
.venv/lib/python3.11/site-packages/huggingface_hub/commands/delete_cache.py ADDED
@@ -0,0 +1,428 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding=utf-8
2
+ # Copyright 2022-present, the HuggingFace Inc. team.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ """Contains command to delete some revisions from the HF cache directory.
16
+
17
+ Usage:
18
+ huggingface-cli delete-cache
19
+ huggingface-cli delete-cache --disable-tui
20
+ huggingface-cli delete-cache --dir ~/.cache/huggingface/hub
21
+
22
+ NOTE:
23
+ This command is based on `InquirerPy` to build the multiselect menu in the terminal.
24
+ This dependency has to be installed with `pip install huggingface_hub[cli]`. Since
25
+ we want to avoid as much as possible cross-platform issues, I chose a library that
26
+ is built on top of `python-prompt-toolkit` which seems to be a reference in terminal
27
+ GUI (actively maintained on both Unix and Windows, 7.9k stars).
28
+
29
+ For the moment, the TUI feature is in beta.
30
+
31
+ See:
32
+ - https://github.com/kazhala/InquirerPy
33
+ - https://inquirerpy.readthedocs.io/en/latest/
34
+ - https://github.com/prompt-toolkit/python-prompt-toolkit
35
+
36
+ Other solutions could have been:
37
+ - `simple_term_menu`: would be good as well for our use case but some issues suggest
38
+ that Windows is less supported.
39
+ See: https://github.com/IngoMeyer441/simple-term-menu
40
+ - `PyInquirer`: very similar to `InquirerPy` but older and not maintained anymore.
41
+ In particular, no support of Python3.10.
42
+ See: https://github.com/CITGuru/PyInquirer
43
+ - `pick` (or `pickpack`): easy to use and flexible but built on top of Python's
44
+ standard library `curses` that is specific to Unix (not implemented on Windows).
45
+ See https://github.com/wong2/pick and https://github.com/anafvana/pickpack.
46
+ - `inquirer`: lot of traction (700 stars) but explicitly states "experimental
47
+ support of Windows". Not built on top of `python-prompt-toolkit`.
48
+ See https://github.com/magmax/python-inquirer
49
+
50
+ TODO: add support for `huggingface-cli delete-cache aaaaaa bbbbbb cccccc (...)` ?
51
+ TODO: add "--keep-last" arg to delete revisions that are not on `main` ref
52
+ TODO: add "--filter" arg to filter repositories by name ?
53
+ TODO: add "--sort" arg to sort by size ?
54
+ TODO: add "--limit" arg to limit to X repos ?
55
+ TODO: add "-y" arg for immediate deletion ?
56
+ See discussions in https://github.com/huggingface/huggingface_hub/issues/1025.
57
+ """
58
+
59
+ import os
60
+ from argparse import Namespace, _SubParsersAction
61
+ from functools import wraps
62
+ from tempfile import mkstemp
63
+ from typing import Any, Callable, Iterable, List, Optional, Union
64
+
65
+ from ..utils import CachedRepoInfo, CachedRevisionInfo, HFCacheInfo, scan_cache_dir
66
+ from . import BaseHuggingfaceCLICommand
67
+ from ._cli_utils import ANSI
68
+
69
+
70
+ try:
71
+ from InquirerPy import inquirer
72
+ from InquirerPy.base.control import Choice
73
+ from InquirerPy.separator import Separator
74
+
75
+ _inquirer_py_available = True
76
+ except ImportError:
77
+ _inquirer_py_available = False
78
+
79
+
80
+ def require_inquirer_py(fn: Callable) -> Callable:
81
+ """Decorator to flag methods that require `InquirerPy`."""
82
+
83
+ # TODO: refactor this + imports in a unified pattern across codebase
84
+ @wraps(fn)
85
+ def _inner(*args, **kwargs):
86
+ if not _inquirer_py_available:
87
+ raise ImportError(
88
+ "The `delete-cache` command requires extra dependencies to work with"
89
+ " the TUI.\nPlease run `pip install huggingface_hub[cli]` to install"
90
+ " them.\nOtherwise, disable TUI using the `--disable-tui` flag."
91
+ )
92
+
93
+ return fn(*args, **kwargs)
94
+
95
+ return _inner
96
+
97
+
98
+ # Possibility for the user to cancel deletion
99
+ _CANCEL_DELETION_STR = "CANCEL_DELETION"
100
+
101
+
102
+ class DeleteCacheCommand(BaseHuggingfaceCLICommand):
103
+ @staticmethod
104
+ def register_subcommand(parser: _SubParsersAction):
105
+ delete_cache_parser = parser.add_parser("delete-cache", help="Delete revisions from the cache directory.")
106
+
107
+ delete_cache_parser.add_argument(
108
+ "--dir",
109
+ type=str,
110
+ default=None,
111
+ help="cache directory (optional). Default to the default HuggingFace cache.",
112
+ )
113
+
114
+ delete_cache_parser.add_argument(
115
+ "--disable-tui",
116
+ action="store_true",
117
+ help=(
118
+ "Disable Terminal User Interface (TUI) mode. Useful if your"
119
+ " platform/terminal doesn't support the multiselect menu."
120
+ ),
121
+ )
122
+
123
+ delete_cache_parser.set_defaults(func=DeleteCacheCommand)
124
+
125
+ def __init__(self, args: Namespace) -> None:
126
+ self.cache_dir: Optional[str] = args.dir
127
+ self.disable_tui: bool = args.disable_tui
128
+
129
+ def run(self):
130
+ """Run `delete-cache` command with or without TUI."""
131
+ # Scan cache directory
132
+ hf_cache_info = scan_cache_dir(self.cache_dir)
133
+
134
+ # Manual review from the user
135
+ if self.disable_tui:
136
+ selected_hashes = _manual_review_no_tui(hf_cache_info, preselected=[])
137
+ else:
138
+ selected_hashes = _manual_review_tui(hf_cache_info, preselected=[])
139
+
140
+ # If deletion is not cancelled
141
+ if len(selected_hashes) > 0 and _CANCEL_DELETION_STR not in selected_hashes:
142
+ confirm_message = _get_expectations_str(hf_cache_info, selected_hashes) + " Confirm deletion ?"
143
+
144
+ # Confirm deletion
145
+ if self.disable_tui:
146
+ confirmed = _ask_for_confirmation_no_tui(confirm_message)
147
+ else:
148
+ confirmed = _ask_for_confirmation_tui(confirm_message)
149
+
150
+ # Deletion is confirmed
151
+ if confirmed:
152
+ strategy = hf_cache_info.delete_revisions(*selected_hashes)
153
+ print("Start deletion.")
154
+ strategy.execute()
155
+ print(
156
+ f"Done. Deleted {len(strategy.repos)} repo(s) and"
157
+ f" {len(strategy.snapshots)} revision(s) for a total of"
158
+ f" {strategy.expected_freed_size_str}."
159
+ )
160
+ return
161
+
162
+ # Deletion is cancelled
163
+ print("Deletion is cancelled. Do nothing.")
164
+
165
+
166
+ @require_inquirer_py
167
+ def _manual_review_tui(hf_cache_info: HFCacheInfo, preselected: List[str]) -> List[str]:
168
+ """Ask the user for a manual review of the revisions to delete.
169
+
170
+ Displays a multi-select menu in the terminal (TUI).
171
+ """
172
+ # Define multiselect list
173
+ choices = _get_tui_choices_from_scan(repos=hf_cache_info.repos, preselected=preselected)
174
+ checkbox = inquirer.checkbox(
175
+ message="Select revisions to delete:",
176
+ choices=choices, # List of revisions with some pre-selection
177
+ cycle=False, # No loop between top and bottom
178
+ height=100, # Large list if possible
179
+ # We use the instruction to display to the user the expected effect of the
180
+ # deletion.
181
+ instruction=_get_expectations_str(
182
+ hf_cache_info,
183
+ selected_hashes=[c.value for c in choices if isinstance(c, Choice) and c.enabled],
184
+ ),
185
+ # We use the long instruction to should keybindings instructions to the user
186
+ long_instruction="Press <space> to select, <enter> to validate and <ctrl+c> to quit without modification.",
187
+ # Message that is displayed once the user validates its selection.
188
+ transformer=lambda result: f"{len(result)} revision(s) selected.",
189
+ )
190
+
191
+ # Add a callback to update the information line when a revision is
192
+ # selected/unselected
193
+ def _update_expectations(_) -> None:
194
+ # Hacky way to dynamically set an instruction message to the checkbox when
195
+ # a revision hash is selected/unselected.
196
+ checkbox._instruction = _get_expectations_str(
197
+ hf_cache_info,
198
+ selected_hashes=[choice["value"] for choice in checkbox.content_control.choices if choice["enabled"]],
199
+ )
200
+
201
+ checkbox.kb_func_lookup["toggle"].append({"func": _update_expectations})
202
+
203
+ # Finally display the form to the user.
204
+ try:
205
+ return checkbox.execute()
206
+ except KeyboardInterrupt:
207
+ return [] # Quit without deletion
208
+
209
+
210
+ @require_inquirer_py
211
+ def _ask_for_confirmation_tui(message: str, default: bool = True) -> bool:
212
+ """Ask for confirmation using Inquirer."""
213
+ return inquirer.confirm(message, default=default).execute()
214
+
215
+
216
+ def _get_tui_choices_from_scan(repos: Iterable[CachedRepoInfo], preselected: List[str]) -> List:
217
+ """Build a list of choices from the scanned repos.
218
+
219
+ Args:
220
+ repos (*Iterable[`CachedRepoInfo`]*):
221
+ List of scanned repos on which we want to delete revisions.
222
+ preselected (*List[`str`]*):
223
+ List of revision hashes that will be preselected.
224
+
225
+ Return:
226
+ The list of choices to pass to `inquirer.checkbox`.
227
+ """
228
+ choices: List[Union[Choice, Separator]] = []
229
+
230
+ # First choice is to cancel the deletion. If selected, nothing will be deleted,
231
+ # no matter the other selected items.
232
+ choices.append(
233
+ Choice(
234
+ _CANCEL_DELETION_STR,
235
+ name="None of the following (if selected, nothing will be deleted).",
236
+ enabled=False,
237
+ )
238
+ )
239
+
240
+ # Display a separator per repo and a Choice for each revisions of the repo
241
+ for repo in sorted(repos, key=_repo_sorting_order):
242
+ # Repo as separator
243
+ choices.append(
244
+ Separator(
245
+ f"\n{repo.repo_type.capitalize()} {repo.repo_id} ({repo.size_on_disk_str},"
246
+ f" used {repo.last_accessed_str})"
247
+ )
248
+ )
249
+ for revision in sorted(repo.revisions, key=_revision_sorting_order):
250
+ # Revision as choice
251
+ choices.append(
252
+ Choice(
253
+ revision.commit_hash,
254
+ name=(
255
+ f"{revision.commit_hash[:8]}:"
256
+ f" {', '.join(sorted(revision.refs)) or '(detached)'} #"
257
+ f" modified {revision.last_modified_str}"
258
+ ),
259
+ enabled=revision.commit_hash in preselected,
260
+ )
261
+ )
262
+
263
+ # Return choices
264
+ return choices
265
+
266
+
267
+ def _manual_review_no_tui(hf_cache_info: HFCacheInfo, preselected: List[str]) -> List[str]:
268
+ """Ask the user for a manual review of the revisions to delete.
269
+
270
+ Used when TUI is disabled. Manual review happens in a separate tmp file that the
271
+ user can manually edit.
272
+ """
273
+ # 1. Generate temporary file with delete commands.
274
+ fd, tmp_path = mkstemp(suffix=".txt") # suffix to make it easier to find by editors
275
+ os.close(fd)
276
+
277
+ lines = []
278
+ for repo in sorted(hf_cache_info.repos, key=_repo_sorting_order):
279
+ lines.append(
280
+ f"\n# {repo.repo_type.capitalize()} {repo.repo_id} ({repo.size_on_disk_str},"
281
+ f" used {repo.last_accessed_str})"
282
+ )
283
+ for revision in sorted(repo.revisions, key=_revision_sorting_order):
284
+ lines.append(
285
+ # Deselect by prepending a '#'
286
+ f"{'' if revision.commit_hash in preselected else '#'} "
287
+ f" {revision.commit_hash} # Refs:"
288
+ # Print `refs` as comment on same line
289
+ f" {', '.join(sorted(revision.refs)) or '(detached)'} # modified"
290
+ # Print `last_modified` as comment on same line
291
+ f" {revision.last_modified_str}"
292
+ )
293
+
294
+ with open(tmp_path, "w") as f:
295
+ f.write(_MANUAL_REVIEW_NO_TUI_INSTRUCTIONS)
296
+ f.write("\n".join(lines))
297
+
298
+ # 2. Prompt instructions to user.
299
+ instructions = f"""
300
+ TUI is disabled. In order to select which revisions you want to delete, please edit
301
+ the following file using the text editor of your choice. Instructions for manual
302
+ editing are located at the beginning of the file. Edit the file, save it and confirm
303
+ to continue.
304
+ File to edit: {ANSI.bold(tmp_path)}
305
+ """
306
+ print("\n".join(line.strip() for line in instructions.strip().split("\n")))
307
+
308
+ # 3. Wait for user confirmation.
309
+ while True:
310
+ selected_hashes = _read_manual_review_tmp_file(tmp_path)
311
+ if _ask_for_confirmation_no_tui(
312
+ _get_expectations_str(hf_cache_info, selected_hashes) + " Continue ?",
313
+ default=False,
314
+ ):
315
+ break
316
+
317
+ # 4. Return selected_hashes
318
+ os.remove(tmp_path)
319
+ return selected_hashes
320
+
321
+
322
+ def _ask_for_confirmation_no_tui(message: str, default: bool = True) -> bool:
323
+ """Ask for confirmation using pure-python."""
324
+ YES = ("y", "yes", "1")
325
+ NO = ("n", "no", "0")
326
+ DEFAULT = ""
327
+ ALL = YES + NO + (DEFAULT,)
328
+ full_message = message + (" (Y/n) " if default else " (y/N) ")
329
+ while True:
330
+ answer = input(full_message).lower()
331
+ if answer == DEFAULT:
332
+ return default
333
+ if answer in YES:
334
+ return True
335
+ if answer in NO:
336
+ return False
337
+ print(f"Invalid input. Must be one of {ALL}")
338
+
339
+
340
+ def _get_expectations_str(hf_cache_info: HFCacheInfo, selected_hashes: List[str]) -> str:
341
+ """Format a string to display to the user how much space would be saved.
342
+
343
+ Example:
344
+ ```
345
+ >>> _get_expectations_str(hf_cache_info, selected_hashes)
346
+ '7 revisions selected counting for 4.3G.'
347
+ ```
348
+ """
349
+ if _CANCEL_DELETION_STR in selected_hashes:
350
+ return "Nothing will be deleted."
351
+ strategy = hf_cache_info.delete_revisions(*selected_hashes)
352
+ return f"{len(selected_hashes)} revisions selected counting for {strategy.expected_freed_size_str}."
353
+
354
+
355
+ def _read_manual_review_tmp_file(tmp_path: str) -> List[str]:
356
+ """Read the manually reviewed instruction file and return a list of revision hash.
357
+
358
+ Example:
359
+ ```txt
360
+ # This is the tmp file content
361
+ ###
362
+
363
+ # Commented out line
364
+ 123456789 # revision hash
365
+
366
+ # Something else
367
+ # a_newer_hash # 2 days ago
368
+ an_older_hash # 3 days ago
369
+ ```
370
+
371
+ ```py
372
+ >>> _read_manual_review_tmp_file(tmp_path)
373
+ ['123456789', 'an_older_hash']
374
+ ```
375
+ """
376
+ with open(tmp_path) as f:
377
+ content = f.read()
378
+
379
+ # Split lines
380
+ lines = [line.strip() for line in content.split("\n")]
381
+
382
+ # Filter commented lines
383
+ selected_lines = [line for line in lines if not line.startswith("#")]
384
+
385
+ # Select only before comment
386
+ selected_hashes = [line.split("#")[0].strip() for line in selected_lines]
387
+
388
+ # Return revision hashes
389
+ return [hash for hash in selected_hashes if len(hash) > 0]
390
+
391
+
392
+ _MANUAL_REVIEW_NO_TUI_INSTRUCTIONS = f"""
393
+ # INSTRUCTIONS
394
+ # ------------
395
+ # This is a temporary file created by running `huggingface-cli delete-cache` with the
396
+ # `--disable-tui` option. It contains a set of revisions that can be deleted from your
397
+ # local cache directory.
398
+ #
399
+ # Please manually review the revisions you want to delete:
400
+ # - Revision hashes can be commented out with '#'.
401
+ # - Only non-commented revisions in this file will be deleted.
402
+ # - Revision hashes that are removed from this file are ignored as well.
403
+ # - If `{_CANCEL_DELETION_STR}` line is uncommented, the all cache deletion is cancelled and
404
+ # no changes will be applied.
405
+ #
406
+ # Once you've manually reviewed this file, please confirm deletion in the terminal. This
407
+ # file will be automatically removed once done.
408
+ # ------------
409
+
410
+ # KILL SWITCH
411
+ # ------------
412
+ # Un-comment following line to completely cancel the deletion process
413
+ # {_CANCEL_DELETION_STR}
414
+ # ------------
415
+
416
+ # REVISIONS
417
+ # ------------
418
+ """.strip()
419
+
420
+
421
+ def _repo_sorting_order(repo: CachedRepoInfo) -> Any:
422
+ # First split by Dataset/Model, then sort by last accessed (oldest first)
423
+ return (repo.repo_type, repo.last_accessed)
424
+
425
+
426
+ def _revision_sorting_order(revision: CachedRevisionInfo) -> Any:
427
+ # Sort by last modified (oldest first)
428
+ return revision.last_modified
.venv/lib/python3.11/site-packages/huggingface_hub/commands/download.py ADDED
@@ -0,0 +1,200 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding=utf-8
2
+ # Copyright 2023-present, the HuggingFace Inc. team.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ """Contains command to download files from the Hub with the CLI.
16
+
17
+ Usage:
18
+ huggingface-cli download --help
19
+
20
+ # Download file
21
+ huggingface-cli download gpt2 config.json
22
+
23
+ # Download entire repo
24
+ huggingface-cli download fffiloni/zeroscope --repo-type=space --revision=refs/pr/78
25
+
26
+ # Download repo with filters
27
+ huggingface-cli download gpt2 --include="*.safetensors"
28
+
29
+ # Download with token
30
+ huggingface-cli download Wauplin/private-model --token=hf_***
31
+
32
+ # Download quietly (no progress bar, no warnings, only the returned path)
33
+ huggingface-cli download gpt2 config.json --quiet
34
+
35
+ # Download to local dir
36
+ huggingface-cli download gpt2 --local-dir=./models/gpt2
37
+ """
38
+
39
+ import warnings
40
+ from argparse import Namespace, _SubParsersAction
41
+ from typing import List, Optional
42
+
43
+ from huggingface_hub import logging
44
+ from huggingface_hub._snapshot_download import snapshot_download
45
+ from huggingface_hub.commands import BaseHuggingfaceCLICommand
46
+ from huggingface_hub.file_download import hf_hub_download
47
+ from huggingface_hub.utils import disable_progress_bars, enable_progress_bars
48
+
49
+
50
+ logger = logging.get_logger(__name__)
51
+
52
+
53
+ class DownloadCommand(BaseHuggingfaceCLICommand):
54
+ @staticmethod
55
+ def register_subcommand(parser: _SubParsersAction):
56
+ download_parser = parser.add_parser("download", help="Download files from the Hub")
57
+ download_parser.add_argument(
58
+ "repo_id", type=str, help="ID of the repo to download from (e.g. `username/repo-name`)."
59
+ )
60
+ download_parser.add_argument(
61
+ "filenames", type=str, nargs="*", help="Files to download (e.g. `config.json`, `data/metadata.jsonl`)."
62
+ )
63
+ download_parser.add_argument(
64
+ "--repo-type",
65
+ choices=["model", "dataset", "space"],
66
+ default="model",
67
+ help="Type of repo to download from (defaults to 'model').",
68
+ )
69
+ download_parser.add_argument(
70
+ "--revision",
71
+ type=str,
72
+ help="An optional Git revision id which can be a branch name, a tag, or a commit hash.",
73
+ )
74
+ download_parser.add_argument(
75
+ "--include", nargs="*", type=str, help="Glob patterns to match files to download."
76
+ )
77
+ download_parser.add_argument(
78
+ "--exclude", nargs="*", type=str, help="Glob patterns to exclude from files to download."
79
+ )
80
+ download_parser.add_argument(
81
+ "--cache-dir", type=str, help="Path to the directory where to save the downloaded files."
82
+ )
83
+ download_parser.add_argument(
84
+ "--local-dir",
85
+ type=str,
86
+ help=(
87
+ "If set, the downloaded file will be placed under this directory. Check out"
88
+ " https://huggingface.co/docs/huggingface_hub/guides/download#download-files-to-local-folder for more"
89
+ " details."
90
+ ),
91
+ )
92
+ download_parser.add_argument(
93
+ "--local-dir-use-symlinks",
94
+ choices=["auto", "True", "False"],
95
+ help=("Deprecated and ignored. Downloading to a local directory does not use symlinks anymore."),
96
+ )
97
+ download_parser.add_argument(
98
+ "--force-download",
99
+ action="store_true",
100
+ help="If True, the files will be downloaded even if they are already cached.",
101
+ )
102
+ download_parser.add_argument(
103
+ "--resume-download",
104
+ action="store_true",
105
+ help="Deprecated and ignored. Downloading a file to local dir always attempts to resume previously interrupted downloads (unless hf-transfer is enabled).",
106
+ )
107
+ download_parser.add_argument(
108
+ "--token", type=str, help="A User Access Token generated from https://huggingface.co/settings/tokens"
109
+ )
110
+ download_parser.add_argument(
111
+ "--quiet",
112
+ action="store_true",
113
+ help="If True, progress bars are disabled and only the path to the download files is printed.",
114
+ )
115
+ download_parser.add_argument(
116
+ "--max-workers",
117
+ type=int,
118
+ default=8,
119
+ help="Maximum number of workers to use for downloading files. Default is 8.",
120
+ )
121
+ download_parser.set_defaults(func=DownloadCommand)
122
+
123
+ def __init__(self, args: Namespace) -> None:
124
+ self.token = args.token
125
+ self.repo_id: str = args.repo_id
126
+ self.filenames: List[str] = args.filenames
127
+ self.repo_type: str = args.repo_type
128
+ self.revision: Optional[str] = args.revision
129
+ self.include: Optional[List[str]] = args.include
130
+ self.exclude: Optional[List[str]] = args.exclude
131
+ self.cache_dir: Optional[str] = args.cache_dir
132
+ self.local_dir: Optional[str] = args.local_dir
133
+ self.force_download: bool = args.force_download
134
+ self.resume_download: Optional[bool] = args.resume_download or None
135
+ self.quiet: bool = args.quiet
136
+ self.max_workers: int = args.max_workers
137
+
138
+ if args.local_dir_use_symlinks is not None:
139
+ warnings.warn(
140
+ "Ignoring --local-dir-use-symlinks. Downloading to a local directory does not use symlinks anymore.",
141
+ FutureWarning,
142
+ )
143
+
144
+ def run(self) -> None:
145
+ if self.quiet:
146
+ disable_progress_bars()
147
+ with warnings.catch_warnings():
148
+ warnings.simplefilter("ignore")
149
+ print(self._download()) # Print path to downloaded files
150
+ enable_progress_bars()
151
+ else:
152
+ logging.set_verbosity_info()
153
+ print(self._download()) # Print path to downloaded files
154
+ logging.set_verbosity_warning()
155
+
156
+ def _download(self) -> str:
157
+ # Warn user if patterns are ignored
158
+ if len(self.filenames) > 0:
159
+ if self.include is not None and len(self.include) > 0:
160
+ warnings.warn("Ignoring `--include` since filenames have being explicitly set.")
161
+ if self.exclude is not None and len(self.exclude) > 0:
162
+ warnings.warn("Ignoring `--exclude` since filenames have being explicitly set.")
163
+
164
+ # Single file to download: use `hf_hub_download`
165
+ if len(self.filenames) == 1:
166
+ return hf_hub_download(
167
+ repo_id=self.repo_id,
168
+ repo_type=self.repo_type,
169
+ revision=self.revision,
170
+ filename=self.filenames[0],
171
+ cache_dir=self.cache_dir,
172
+ resume_download=self.resume_download,
173
+ force_download=self.force_download,
174
+ token=self.token,
175
+ local_dir=self.local_dir,
176
+ library_name="huggingface-cli",
177
+ )
178
+
179
+ # Otherwise: use `snapshot_download` to ensure all files comes from same revision
180
+ elif len(self.filenames) == 0:
181
+ allow_patterns = self.include
182
+ ignore_patterns = self.exclude
183
+ else:
184
+ allow_patterns = self.filenames
185
+ ignore_patterns = None
186
+
187
+ return snapshot_download(
188
+ repo_id=self.repo_id,
189
+ repo_type=self.repo_type,
190
+ revision=self.revision,
191
+ allow_patterns=allow_patterns,
192
+ ignore_patterns=ignore_patterns,
193
+ resume_download=self.resume_download,
194
+ force_download=self.force_download,
195
+ cache_dir=self.cache_dir,
196
+ token=self.token,
197
+ local_dir=self.local_dir,
198
+ library_name="huggingface-cli",
199
+ max_workers=self.max_workers,
200
+ )
.venv/lib/python3.11/site-packages/huggingface_hub/commands/env.py ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2022 The HuggingFace Team. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ """Contains command to print information about the environment.
15
+
16
+ Usage:
17
+ huggingface-cli env
18
+ """
19
+
20
+ from argparse import _SubParsersAction
21
+
22
+ from ..utils import dump_environment_info
23
+ from . import BaseHuggingfaceCLICommand
24
+
25
+
26
+ class EnvironmentCommand(BaseHuggingfaceCLICommand):
27
+ def __init__(self, args):
28
+ self.args = args
29
+
30
+ @staticmethod
31
+ def register_subcommand(parser: _SubParsersAction):
32
+ env_parser = parser.add_parser("env", help="Print information about the environment.")
33
+ env_parser.set_defaults(func=EnvironmentCommand)
34
+
35
+ def run(self) -> None:
36
+ dump_environment_info()
.venv/lib/python3.11/site-packages/huggingface_hub/commands/huggingface_cli.py ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2020 The HuggingFace Team. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from argparse import ArgumentParser
16
+
17
+ from huggingface_hub.commands.delete_cache import DeleteCacheCommand
18
+ from huggingface_hub.commands.download import DownloadCommand
19
+ from huggingface_hub.commands.env import EnvironmentCommand
20
+ from huggingface_hub.commands.lfs import LfsCommands
21
+ from huggingface_hub.commands.repo_files import RepoFilesCommand
22
+ from huggingface_hub.commands.scan_cache import ScanCacheCommand
23
+ from huggingface_hub.commands.tag import TagCommands
24
+ from huggingface_hub.commands.upload import UploadCommand
25
+ from huggingface_hub.commands.upload_large_folder import UploadLargeFolderCommand
26
+ from huggingface_hub.commands.user import UserCommands
27
+ from huggingface_hub.commands.version import VersionCommand
28
+
29
+
30
+ def main():
31
+ parser = ArgumentParser("huggingface-cli", usage="huggingface-cli <command> [<args>]")
32
+ commands_parser = parser.add_subparsers(help="huggingface-cli command helpers")
33
+
34
+ # Register commands
35
+ DownloadCommand.register_subcommand(commands_parser)
36
+ UploadCommand.register_subcommand(commands_parser)
37
+ RepoFilesCommand.register_subcommand(commands_parser)
38
+ EnvironmentCommand.register_subcommand(commands_parser)
39
+ UserCommands.register_subcommand(commands_parser)
40
+ LfsCommands.register_subcommand(commands_parser)
41
+ ScanCacheCommand.register_subcommand(commands_parser)
42
+ DeleteCacheCommand.register_subcommand(commands_parser)
43
+ TagCommands.register_subcommand(commands_parser)
44
+ VersionCommand.register_subcommand(commands_parser)
45
+
46
+ # Experimental
47
+ UploadLargeFolderCommand.register_subcommand(commands_parser)
48
+
49
+ # Let's go
50
+ args = parser.parse_args()
51
+ if not hasattr(args, "func"):
52
+ parser.print_help()
53
+ exit(1)
54
+
55
+ # Run
56
+ service = args.func(args)
57
+ service.run()
58
+
59
+
60
+ if __name__ == "__main__":
61
+ main()
.venv/lib/python3.11/site-packages/huggingface_hub/commands/lfs.py ADDED
@@ -0,0 +1,200 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Implementation of a custom transfer agent for the transfer type "multipart" for
3
+ git-lfs.
4
+
5
+ Inspired by:
6
+ github.com/cbartz/git-lfs-swift-transfer-agent/blob/master/git_lfs_swift_transfer.py
7
+
8
+ Spec is: github.com/git-lfs/git-lfs/blob/master/docs/custom-transfers.md
9
+
10
+
11
+ To launch debugger while developing:
12
+
13
+ ``` [lfs "customtransfer.multipart"]
14
+ path = /path/to/huggingface_hub/.env/bin/python args = -m debugpy --listen 5678
15
+ --wait-for-client
16
+ /path/to/huggingface_hub/src/huggingface_hub/commands/huggingface_cli.py
17
+ lfs-multipart-upload ```"""
18
+
19
+ import json
20
+ import os
21
+ import subprocess
22
+ import sys
23
+ from argparse import _SubParsersAction
24
+ from typing import Dict, List, Optional
25
+
26
+ from huggingface_hub.commands import BaseHuggingfaceCLICommand
27
+ from huggingface_hub.lfs import LFS_MULTIPART_UPLOAD_COMMAND
28
+
29
+ from ..utils import get_session, hf_raise_for_status, logging
30
+ from ..utils._lfs import SliceFileObj
31
+
32
+
33
+ logger = logging.get_logger(__name__)
34
+
35
+
36
+ class LfsCommands(BaseHuggingfaceCLICommand):
37
+ """
38
+ Implementation of a custom transfer agent for the transfer type "multipart"
39
+ for git-lfs. This lets users upload large files >5GB 🔥. Spec for LFS custom
40
+ transfer agent is:
41
+ https://github.com/git-lfs/git-lfs/blob/master/docs/custom-transfers.md
42
+
43
+ This introduces two commands to the CLI:
44
+
45
+ 1. $ huggingface-cli lfs-enable-largefiles
46
+
47
+ This should be executed once for each model repo that contains a model file
48
+ >5GB. It's documented in the error message you get if you just try to git
49
+ push a 5GB file without having enabled it before.
50
+
51
+ 2. $ huggingface-cli lfs-multipart-upload
52
+
53
+ This command is called by lfs directly and is not meant to be called by the
54
+ user.
55
+ """
56
+
57
+ @staticmethod
58
+ def register_subcommand(parser: _SubParsersAction):
59
+ enable_parser = parser.add_parser(
60
+ "lfs-enable-largefiles", help="Configure your repository to enable upload of files > 5GB."
61
+ )
62
+ enable_parser.add_argument("path", type=str, help="Local path to repository you want to configure.")
63
+ enable_parser.set_defaults(func=lambda args: LfsEnableCommand(args))
64
+
65
+ # Command will get called by git-lfs, do not call it directly.
66
+ upload_parser = parser.add_parser(LFS_MULTIPART_UPLOAD_COMMAND, add_help=False)
67
+ upload_parser.set_defaults(func=lambda args: LfsUploadCommand(args))
68
+
69
+
70
+ class LfsEnableCommand:
71
+ def __init__(self, args):
72
+ self.args = args
73
+
74
+ def run(self):
75
+ local_path = os.path.abspath(self.args.path)
76
+ if not os.path.isdir(local_path):
77
+ print("This does not look like a valid git repo.")
78
+ exit(1)
79
+ subprocess.run(
80
+ "git config lfs.customtransfer.multipart.path huggingface-cli".split(),
81
+ check=True,
82
+ cwd=local_path,
83
+ )
84
+ subprocess.run(
85
+ f"git config lfs.customtransfer.multipart.args {LFS_MULTIPART_UPLOAD_COMMAND}".split(),
86
+ check=True,
87
+ cwd=local_path,
88
+ )
89
+ print("Local repo set up for largefiles")
90
+
91
+
92
+ def write_msg(msg: Dict):
93
+ """Write out the message in Line delimited JSON."""
94
+ msg_str = json.dumps(msg) + "\n"
95
+ sys.stdout.write(msg_str)
96
+ sys.stdout.flush()
97
+
98
+
99
+ def read_msg() -> Optional[Dict]:
100
+ """Read Line delimited JSON from stdin."""
101
+ msg = json.loads(sys.stdin.readline().strip())
102
+
103
+ if "terminate" in (msg.get("type"), msg.get("event")):
104
+ # terminate message received
105
+ return None
106
+
107
+ if msg.get("event") not in ("download", "upload"):
108
+ logger.critical("Received unexpected message")
109
+ sys.exit(1)
110
+
111
+ return msg
112
+
113
+
114
+ class LfsUploadCommand:
115
+ def __init__(self, args) -> None:
116
+ self.args = args
117
+
118
+ def run(self) -> None:
119
+ # Immediately after invoking a custom transfer process, git-lfs
120
+ # sends initiation data to the process over stdin.
121
+ # This tells the process useful information about the configuration.
122
+ init_msg = json.loads(sys.stdin.readline().strip())
123
+ if not (init_msg.get("event") == "init" and init_msg.get("operation") == "upload"):
124
+ write_msg({"error": {"code": 32, "message": "Wrong lfs init operation"}})
125
+ sys.exit(1)
126
+
127
+ # The transfer process should use the information it needs from the
128
+ # initiation structure, and also perform any one-off setup tasks it
129
+ # needs to do. It should then respond on stdout with a simple empty
130
+ # confirmation structure, as follows:
131
+ write_msg({})
132
+
133
+ # After the initiation exchange, git-lfs will send any number of
134
+ # transfer requests to the stdin of the transfer process, in a serial sequence.
135
+ while True:
136
+ msg = read_msg()
137
+ if msg is None:
138
+ # When all transfers have been processed, git-lfs will send
139
+ # a terminate event to the stdin of the transfer process.
140
+ # On receiving this message the transfer process should
141
+ # clean up and terminate. No response is expected.
142
+ sys.exit(0)
143
+
144
+ oid = msg["oid"]
145
+ filepath = msg["path"]
146
+ completion_url = msg["action"]["href"]
147
+ header = msg["action"]["header"]
148
+ chunk_size = int(header.pop("chunk_size"))
149
+ presigned_urls: List[str] = list(header.values())
150
+
151
+ # Send a "started" progress event to allow other workers to start.
152
+ # Otherwise they're delayed until first "progress" event is reported,
153
+ # i.e. after the first 5GB by default (!)
154
+ write_msg(
155
+ {
156
+ "event": "progress",
157
+ "oid": oid,
158
+ "bytesSoFar": 1,
159
+ "bytesSinceLast": 0,
160
+ }
161
+ )
162
+
163
+ parts = []
164
+ with open(filepath, "rb") as file:
165
+ for i, presigned_url in enumerate(presigned_urls):
166
+ with SliceFileObj(
167
+ file,
168
+ seek_from=i * chunk_size,
169
+ read_limit=chunk_size,
170
+ ) as data:
171
+ r = get_session().put(presigned_url, data=data)
172
+ hf_raise_for_status(r)
173
+ parts.append(
174
+ {
175
+ "etag": r.headers.get("etag"),
176
+ "partNumber": i + 1,
177
+ }
178
+ )
179
+ # In order to support progress reporting while data is uploading / downloading,
180
+ # the transfer process should post messages to stdout
181
+ write_msg(
182
+ {
183
+ "event": "progress",
184
+ "oid": oid,
185
+ "bytesSoFar": (i + 1) * chunk_size,
186
+ "bytesSinceLast": chunk_size,
187
+ }
188
+ )
189
+ # Not precise but that's ok.
190
+
191
+ r = get_session().post(
192
+ completion_url,
193
+ json={
194
+ "oid": oid,
195
+ "parts": parts,
196
+ },
197
+ )
198
+ hf_raise_for_status(r)
199
+
200
+ write_msg({"event": "complete", "oid": oid})
.venv/lib/python3.11/site-packages/huggingface_hub/commands/repo_files.py ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding=utf-8
2
+ # Copyright 2023-present, the HuggingFace Inc. team.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ """Contains command to update or delete files in a repository using the CLI.
16
+
17
+ Usage:
18
+ # delete all
19
+ huggingface-cli repo-files <repo_id> delete "*"
20
+
21
+ # delete single file
22
+ huggingface-cli repo-files <repo_id> delete file.txt
23
+
24
+ # delete single folder
25
+ huggingface-cli repo-files <repo_id> delete folder/
26
+
27
+ # delete multiple
28
+ huggingface-cli repo-files <repo_id> delete file.txt folder/ file2.txt
29
+
30
+ # delete multiple patterns
31
+ huggingface-cli repo-files <repo_id> delete file.txt "*.json" "folder/*.parquet"
32
+
33
+ # delete from different revision / repo-type
34
+ huggingface-cli repo-files <repo_id> delete file.txt --revision=refs/pr/1 --repo-type=dataset
35
+ """
36
+
37
+ from argparse import _SubParsersAction
38
+ from typing import List, Optional
39
+
40
+ from huggingface_hub import logging
41
+ from huggingface_hub.commands import BaseHuggingfaceCLICommand
42
+ from huggingface_hub.hf_api import HfApi
43
+
44
+
45
+ logger = logging.get_logger(__name__)
46
+
47
+
48
+ class DeleteFilesSubCommand:
49
+ def __init__(self, args) -> None:
50
+ self.args = args
51
+ self.repo_id: str = args.repo_id
52
+ self.repo_type: Optional[str] = args.repo_type
53
+ self.revision: Optional[str] = args.revision
54
+ self.api: HfApi = HfApi(token=args.token, library_name="huggingface-cli")
55
+ self.patterns: List[str] = args.patterns
56
+ self.commit_message: Optional[str] = args.commit_message
57
+ self.commit_description: Optional[str] = args.commit_description
58
+ self.create_pr: bool = args.create_pr
59
+ self.token: Optional[str] = args.token
60
+
61
+ def run(self) -> None:
62
+ logging.set_verbosity_info()
63
+ url = self.api.delete_files(
64
+ delete_patterns=self.patterns,
65
+ repo_id=self.repo_id,
66
+ repo_type=self.repo_type,
67
+ revision=self.revision,
68
+ commit_message=self.commit_message,
69
+ commit_description=self.commit_description,
70
+ create_pr=self.create_pr,
71
+ )
72
+ print(f"Files correctly deleted from repo. Commit: {url}.")
73
+ logging.set_verbosity_warning()
74
+
75
+
76
+ class RepoFilesCommand(BaseHuggingfaceCLICommand):
77
+ @staticmethod
78
+ def register_subcommand(parser: _SubParsersAction):
79
+ repo_files_parser = parser.add_parser("repo-files", help="Manage files in a repo on the Hub")
80
+ repo_files_parser.add_argument(
81
+ "repo_id", type=str, help="The ID of the repo to manage (e.g. `username/repo-name`)."
82
+ )
83
+ repo_files_subparsers = repo_files_parser.add_subparsers(
84
+ help="Action to execute against the files.",
85
+ required=True,
86
+ )
87
+ delete_subparser = repo_files_subparsers.add_parser(
88
+ "delete",
89
+ help="Delete files from a repo on the Hub",
90
+ )
91
+ delete_subparser.set_defaults(func=lambda args: DeleteFilesSubCommand(args))
92
+ delete_subparser.add_argument(
93
+ "patterns",
94
+ nargs="+",
95
+ type=str,
96
+ help="Glob patterns to match files to delete.",
97
+ )
98
+ delete_subparser.add_argument(
99
+ "--repo-type",
100
+ choices=["model", "dataset", "space"],
101
+ default="model",
102
+ help="Type of the repo to upload to (e.g. `dataset`).",
103
+ )
104
+ delete_subparser.add_argument(
105
+ "--revision",
106
+ type=str,
107
+ help=(
108
+ "An optional Git revision to push to. It can be a branch name "
109
+ "or a PR reference. If revision does not"
110
+ " exist and `--create-pr` is not set, a branch will be automatically created."
111
+ ),
112
+ )
113
+ delete_subparser.add_argument(
114
+ "--commit-message", type=str, help="The summary / title / first line of the generated commit."
115
+ )
116
+ delete_subparser.add_argument(
117
+ "--commit-description", type=str, help="The description of the generated commit."
118
+ )
119
+ delete_subparser.add_argument(
120
+ "--create-pr", action="store_true", help="Whether to create a new Pull Request for these changes."
121
+ )
122
+ repo_files_parser.add_argument(
123
+ "--token",
124
+ type=str,
125
+ help="A User Access Token generated from https://huggingface.co/settings/tokens",
126
+ )
127
+
128
+ repo_files_parser.set_defaults(func=RepoFilesCommand)
.venv/lib/python3.11/site-packages/huggingface_hub/commands/scan_cache.py ADDED
@@ -0,0 +1,181 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding=utf-8
2
+ # Copyright 2022-present, the HuggingFace Inc. team.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ """Contains command to scan the HF cache directory.
16
+
17
+ Usage:
18
+ huggingface-cli scan-cache
19
+ huggingface-cli scan-cache -v
20
+ huggingface-cli scan-cache -vvv
21
+ huggingface-cli scan-cache --dir ~/.cache/huggingface/hub
22
+ """
23
+
24
+ import time
25
+ from argparse import Namespace, _SubParsersAction
26
+ from typing import Optional
27
+
28
+ from ..utils import CacheNotFound, HFCacheInfo, scan_cache_dir
29
+ from . import BaseHuggingfaceCLICommand
30
+ from ._cli_utils import ANSI, tabulate
31
+
32
+
33
+ class ScanCacheCommand(BaseHuggingfaceCLICommand):
34
+ @staticmethod
35
+ def register_subcommand(parser: _SubParsersAction):
36
+ scan_cache_parser = parser.add_parser("scan-cache", help="Scan cache directory.")
37
+
38
+ scan_cache_parser.add_argument(
39
+ "--dir",
40
+ type=str,
41
+ default=None,
42
+ help="cache directory to scan (optional). Default to the default HuggingFace cache.",
43
+ )
44
+ scan_cache_parser.add_argument(
45
+ "-v",
46
+ "--verbose",
47
+ action="count",
48
+ default=0,
49
+ help="show a more verbose output",
50
+ )
51
+ scan_cache_parser.set_defaults(func=ScanCacheCommand)
52
+
53
+ def __init__(self, args: Namespace) -> None:
54
+ self.verbosity: int = args.verbose
55
+ self.cache_dir: Optional[str] = args.dir
56
+
57
+ def run(self):
58
+ try:
59
+ t0 = time.time()
60
+ hf_cache_info = scan_cache_dir(self.cache_dir)
61
+ t1 = time.time()
62
+ except CacheNotFound as exc:
63
+ cache_dir = exc.cache_dir
64
+ print(f"Cache directory not found: {cache_dir}")
65
+ return
66
+
67
+ self._print_hf_cache_info_as_table(hf_cache_info)
68
+
69
+ print(
70
+ f"\nDone in {round(t1 - t0, 1)}s. Scanned {len(hf_cache_info.repos)} repo(s)"
71
+ f" for a total of {ANSI.red(hf_cache_info.size_on_disk_str)}."
72
+ )
73
+ if len(hf_cache_info.warnings) > 0:
74
+ message = f"Got {len(hf_cache_info.warnings)} warning(s) while scanning."
75
+ if self.verbosity >= 3:
76
+ print(ANSI.gray(message))
77
+ for warning in hf_cache_info.warnings:
78
+ print(ANSI.gray(warning))
79
+ else:
80
+ print(ANSI.gray(message + " Use -vvv to print details."))
81
+
82
+ def _print_hf_cache_info_as_table(self, hf_cache_info: HFCacheInfo) -> None:
83
+ print(get_table(hf_cache_info, verbosity=self.verbosity))
84
+
85
+
86
+ def get_table(hf_cache_info: HFCacheInfo, *, verbosity: int = 0) -> str:
87
+ """Generate a table from the [`HFCacheInfo`] object.
88
+
89
+ Pass `verbosity=0` to get a table with a single row per repo, with columns
90
+ "repo_id", "repo_type", "size_on_disk", "nb_files", "last_accessed", "last_modified", "refs", "local_path".
91
+
92
+ Pass `verbosity=1` to get a table with a row per repo and revision (thus multiple rows can appear for a single repo), with columns
93
+ "repo_id", "repo_type", "revision", "size_on_disk", "nb_files", "last_modified", "refs", "local_path".
94
+
95
+ Example:
96
+ ```py
97
+ >>> from huggingface_hub.utils import scan_cache_dir
98
+ >>> from huggingface_hub.commands.scan_cache import get_table
99
+
100
+ >>> hf_cache_info = scan_cache_dir()
101
+ HFCacheInfo(...)
102
+
103
+ >>> print(get_table(hf_cache_info, verbosity=0))
104
+ REPO ID REPO TYPE SIZE ON DISK NB FILES LAST_ACCESSED LAST_MODIFIED REFS LOCAL PATH
105
+ --------------------------------------------------- --------- ------------ -------- ------------- ------------- ---- --------------------------------------------------------------------------------------------------
106
+ roberta-base model 2.7M 5 1 day ago 1 week ago main C:\\Users\\admin\\.cache\\huggingface\\hub\\models--roberta-base
107
+ suno/bark model 8.8K 1 1 week ago 1 week ago main C:\\Users\\admin\\.cache\\huggingface\\hub\\models--suno--bark
108
+ t5-base model 893.8M 4 4 days ago 7 months ago main C:\\Users\\admin\\.cache\\huggingface\\hub\\models--t5-base
109
+ t5-large model 3.0G 4 5 weeks ago 5 months ago main C:\\Users\\admin\\.cache\\huggingface\\hub\\models--t5-large
110
+
111
+ >>> print(get_table(hf_cache_info, verbosity=1))
112
+ REPO ID REPO TYPE REVISION SIZE ON DISK NB FILES LAST_MODIFIED REFS LOCAL PATH
113
+ --------------------------------------------------- --------- ---------------------------------------- ------------ -------- ------------- ---- -----------------------------------------------------------------------------------------------------------------------------------------------------
114
+ roberta-base model e2da8e2f811d1448a5b465c236feacd80ffbac7b 2.7M 5 1 week ago main C:\\Users\\admin\\.cache\\huggingface\\hub\\models--roberta-base\\snapshots\\e2da8e2f811d1448a5b465c236feacd80ffbac7b
115
+ suno/bark model 70a8a7d34168586dc5d028fa9666aceade177992 8.8K 1 1 week ago main C:\\Users\\admin\\.cache\\huggingface\\hub\\models--suno--bark\\snapshots\\70a8a7d34168586dc5d028fa9666aceade177992
116
+ t5-base model a9723ea7f1b39c1eae772870f3b547bf6ef7e6c1 893.8M 4 7 months ago main C:\\Users\\admin\\.cache\\huggingface\\hub\\models--t5-base\\snapshots\\a9723ea7f1b39c1eae772870f3b547bf6ef7e6c1
117
+ t5-large model 150ebc2c4b72291e770f58e6057481c8d2ed331a 3.0G 4 5 months ago main C:\\Users\\admin\\.cache\\huggingface\\hub\\models--t5-large\\snapshots\\150ebc2c4b72291e770f58e6057481c8d2ed331a ```
118
+ ```
119
+
120
+ Args:
121
+ hf_cache_info ([`HFCacheInfo`]):
122
+ The HFCacheInfo object to print.
123
+ verbosity (`int`, *optional*):
124
+ The verbosity level. Defaults to 0.
125
+
126
+ Returns:
127
+ `str`: The table as a string.
128
+ """
129
+ if verbosity == 0:
130
+ return tabulate(
131
+ rows=[
132
+ [
133
+ repo.repo_id,
134
+ repo.repo_type,
135
+ "{:>12}".format(repo.size_on_disk_str),
136
+ repo.nb_files,
137
+ repo.last_accessed_str,
138
+ repo.last_modified_str,
139
+ ", ".join(sorted(repo.refs)),
140
+ str(repo.repo_path),
141
+ ]
142
+ for repo in sorted(hf_cache_info.repos, key=lambda repo: repo.repo_path)
143
+ ],
144
+ headers=[
145
+ "REPO ID",
146
+ "REPO TYPE",
147
+ "SIZE ON DISK",
148
+ "NB FILES",
149
+ "LAST_ACCESSED",
150
+ "LAST_MODIFIED",
151
+ "REFS",
152
+ "LOCAL PATH",
153
+ ],
154
+ )
155
+ else:
156
+ return tabulate(
157
+ rows=[
158
+ [
159
+ repo.repo_id,
160
+ repo.repo_type,
161
+ revision.commit_hash,
162
+ "{:>12}".format(revision.size_on_disk_str),
163
+ revision.nb_files,
164
+ revision.last_modified_str,
165
+ ", ".join(sorted(revision.refs)),
166
+ str(revision.snapshot_path),
167
+ ]
168
+ for repo in sorted(hf_cache_info.repos, key=lambda repo: repo.repo_path)
169
+ for revision in sorted(repo.revisions, key=lambda revision: revision.commit_hash)
170
+ ],
171
+ headers=[
172
+ "REPO ID",
173
+ "REPO TYPE",
174
+ "REVISION",
175
+ "SIZE ON DISK",
176
+ "NB FILES",
177
+ "LAST_MODIFIED",
178
+ "REFS",
179
+ "LOCAL PATH",
180
+ ],
181
+ )
.venv/lib/python3.11/site-packages/huggingface_hub/commands/tag.py ADDED
@@ -0,0 +1,159 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding=utf-8
2
+ # Copyright 2024-present, the HuggingFace Inc. team.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ """Contains commands to perform tag management with the CLI.
17
+
18
+ Usage Examples:
19
+ - Create a tag:
20
+ $ huggingface-cli tag user/my-model 1.0 --message "First release"
21
+ $ huggingface-cli tag user/my-model 1.0 -m "First release" --revision develop
22
+ $ huggingface-cli tag user/my-dataset 1.0 -m "First release" --repo-type dataset
23
+ $ huggingface-cli tag user/my-space 1.0
24
+ - List all tags:
25
+ $ huggingface-cli tag -l user/my-model
26
+ $ huggingface-cli tag --list user/my-dataset --repo-type dataset
27
+ - Delete a tag:
28
+ $ huggingface-cli tag -d user/my-model 1.0
29
+ $ huggingface-cli tag --delete user/my-dataset 1.0 --repo-type dataset
30
+ $ huggingface-cli tag -d user/my-space 1.0 -y
31
+ """
32
+
33
+ from argparse import Namespace, _SubParsersAction
34
+
35
+ from requests.exceptions import HTTPError
36
+
37
+ from huggingface_hub.commands import BaseHuggingfaceCLICommand
38
+ from huggingface_hub.constants import (
39
+ REPO_TYPES,
40
+ )
41
+ from huggingface_hub.hf_api import HfApi
42
+
43
+ from ..errors import HfHubHTTPError, RepositoryNotFoundError, RevisionNotFoundError
44
+ from ._cli_utils import ANSI
45
+
46
+
47
+ class TagCommands(BaseHuggingfaceCLICommand):
48
+ @staticmethod
49
+ def register_subcommand(parser: _SubParsersAction):
50
+ tag_parser = parser.add_parser("tag", help="(create, list, delete) tags for a repo in the hub")
51
+
52
+ tag_parser.add_argument("repo_id", type=str, help="The ID of the repo to tag (e.g. `username/repo-name`).")
53
+ tag_parser.add_argument("tag", nargs="?", type=str, help="The name of the tag for creation or deletion.")
54
+ tag_parser.add_argument("-m", "--message", type=str, help="The description of the tag to create.")
55
+ tag_parser.add_argument("--revision", type=str, help="The git revision to tag.")
56
+ tag_parser.add_argument(
57
+ "--token", type=str, help="A User Access Token generated from https://huggingface.co/settings/tokens."
58
+ )
59
+ tag_parser.add_argument(
60
+ "--repo-type",
61
+ choices=["model", "dataset", "space"],
62
+ default="model",
63
+ help="Set the type of repository (model, dataset, or space).",
64
+ )
65
+ tag_parser.add_argument("-y", "--yes", action="store_true", help="Answer Yes to prompts automatically.")
66
+
67
+ tag_parser.add_argument("-l", "--list", action="store_true", help="List tags for a repository.")
68
+ tag_parser.add_argument("-d", "--delete", action="store_true", help="Delete a tag for a repository.")
69
+
70
+ tag_parser.set_defaults(func=lambda args: handle_commands(args))
71
+
72
+
73
+ def handle_commands(args: Namespace):
74
+ if args.list:
75
+ return TagListCommand(args)
76
+ elif args.delete:
77
+ return TagDeleteCommand(args)
78
+ else:
79
+ return TagCreateCommand(args)
80
+
81
+
82
+ class TagCommand:
83
+ def __init__(self, args: Namespace):
84
+ self.args = args
85
+ self.api = HfApi(token=self.args.token)
86
+ self.repo_id = self.args.repo_id
87
+ self.repo_type = self.args.repo_type
88
+ if self.repo_type not in REPO_TYPES:
89
+ print("Invalid repo --repo-type")
90
+ exit(1)
91
+
92
+
93
+ class TagCreateCommand(TagCommand):
94
+ def run(self):
95
+ print(f"You are about to create tag {ANSI.bold(self.args.tag)} on {self.repo_type} {ANSI.bold(self.repo_id)}")
96
+
97
+ try:
98
+ self.api.create_tag(
99
+ repo_id=self.repo_id,
100
+ tag=self.args.tag,
101
+ tag_message=self.args.message,
102
+ revision=self.args.revision,
103
+ repo_type=self.repo_type,
104
+ )
105
+ except RepositoryNotFoundError:
106
+ print(f"{self.repo_type.capitalize()} {ANSI.bold(self.repo_id)} not found.")
107
+ exit(1)
108
+ except RevisionNotFoundError:
109
+ print(f"Revision {ANSI.bold(self.args.revision)} not found.")
110
+ exit(1)
111
+ except HfHubHTTPError as e:
112
+ if e.response.status_code == 409:
113
+ print(f"Tag {ANSI.bold(self.args.tag)} already exists on {ANSI.bold(self.repo_id)}")
114
+ exit(1)
115
+ raise e
116
+
117
+ print(f"Tag {ANSI.bold(self.args.tag)} created on {ANSI.bold(self.repo_id)}")
118
+
119
+
120
+ class TagListCommand(TagCommand):
121
+ def run(self):
122
+ try:
123
+ refs = self.api.list_repo_refs(
124
+ repo_id=self.repo_id,
125
+ repo_type=self.repo_type,
126
+ )
127
+ except RepositoryNotFoundError:
128
+ print(f"{self.repo_type.capitalize()} {ANSI.bold(self.repo_id)} not found.")
129
+ exit(1)
130
+ except HTTPError as e:
131
+ print(e)
132
+ print(ANSI.red(e.response.text))
133
+ exit(1)
134
+ if len(refs.tags) == 0:
135
+ print("No tags found")
136
+ exit(0)
137
+ print(f"Tags for {self.repo_type} {ANSI.bold(self.repo_id)}:")
138
+ for tag in refs.tags:
139
+ print(tag.name)
140
+
141
+
142
+ class TagDeleteCommand(TagCommand):
143
+ def run(self):
144
+ print(f"You are about to delete tag {ANSI.bold(self.args.tag)} on {self.repo_type} {ANSI.bold(self.repo_id)}")
145
+
146
+ if not self.args.yes:
147
+ choice = input("Proceed? [Y/n] ").lower()
148
+ if choice not in ("", "y", "yes"):
149
+ print("Abort")
150
+ exit()
151
+ try:
152
+ self.api.delete_tag(repo_id=self.repo_id, tag=self.args.tag, repo_type=self.repo_type)
153
+ except RepositoryNotFoundError:
154
+ print(f"{self.repo_type.capitalize()} {ANSI.bold(self.repo_id)} not found.")
155
+ exit(1)
156
+ except RevisionNotFoundError:
157
+ print(f"Tag {ANSI.bold(self.args.tag)} not found on {ANSI.bold(self.repo_id)}")
158
+ exit(1)
159
+ print(f"Tag {ANSI.bold(self.args.tag)} deleted on {ANSI.bold(self.repo_id)}")
.venv/lib/python3.11/site-packages/huggingface_hub/commands/upload.py ADDED
@@ -0,0 +1,299 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding=utf-8
2
+ # Copyright 2023-present, the HuggingFace Inc. team.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ """Contains command to upload a repo or file with the CLI.
16
+
17
+ Usage:
18
+ # Upload file (implicit)
19
+ huggingface-cli upload my-cool-model ./my-cool-model.safetensors
20
+
21
+ # Upload file (explicit)
22
+ huggingface-cli upload my-cool-model ./my-cool-model.safetensors model.safetensors
23
+
24
+ # Upload directory (implicit). If `my-cool-model/` is a directory it will be uploaded, otherwise an exception is raised.
25
+ huggingface-cli upload my-cool-model
26
+
27
+ # Upload directory (explicit)
28
+ huggingface-cli upload my-cool-model ./models/my-cool-model .
29
+
30
+ # Upload filtered directory (example: tensorboard logs except for the last run)
31
+ huggingface-cli upload my-cool-model ./model/training /logs --include "*.tfevents.*" --exclude "*20230905*"
32
+
33
+ # Upload private dataset
34
+ huggingface-cli upload Wauplin/my-cool-dataset ./data . --repo-type=dataset --private
35
+
36
+ # Upload with token
37
+ huggingface-cli upload Wauplin/my-cool-model --token=hf_****
38
+
39
+ # Sync local Space with Hub (upload new files, delete removed files)
40
+ huggingface-cli upload Wauplin/space-example --repo-type=space --exclude="/logs/*" --delete="*" --commit-message="Sync local Space with Hub"
41
+
42
+ # Schedule commits every 30 minutes
43
+ huggingface-cli upload Wauplin/my-cool-model --every=30
44
+ """
45
+
46
+ import os
47
+ import time
48
+ import warnings
49
+ from argparse import Namespace, _SubParsersAction
50
+ from typing import List, Optional
51
+
52
+ from huggingface_hub import logging
53
+ from huggingface_hub._commit_scheduler import CommitScheduler
54
+ from huggingface_hub.commands import BaseHuggingfaceCLICommand
55
+ from huggingface_hub.constants import HF_HUB_ENABLE_HF_TRANSFER
56
+ from huggingface_hub.errors import RevisionNotFoundError
57
+ from huggingface_hub.hf_api import HfApi
58
+ from huggingface_hub.utils import disable_progress_bars, enable_progress_bars
59
+
60
+
61
+ logger = logging.get_logger(__name__)
62
+
63
+
64
+ class UploadCommand(BaseHuggingfaceCLICommand):
65
+ @staticmethod
66
+ def register_subcommand(parser: _SubParsersAction):
67
+ upload_parser = parser.add_parser("upload", help="Upload a file or a folder to a repo on the Hub")
68
+ upload_parser.add_argument(
69
+ "repo_id", type=str, help="The ID of the repo to upload to (e.g. `username/repo-name`)."
70
+ )
71
+ upload_parser.add_argument(
72
+ "local_path", nargs="?", help="Local path to the file or folder to upload. Defaults to current directory."
73
+ )
74
+ upload_parser.add_argument(
75
+ "path_in_repo",
76
+ nargs="?",
77
+ help="Path of the file or folder in the repo. Defaults to the relative path of the file or folder.",
78
+ )
79
+ upload_parser.add_argument(
80
+ "--repo-type",
81
+ choices=["model", "dataset", "space"],
82
+ default="model",
83
+ help="Type of the repo to upload to (e.g. `dataset`).",
84
+ )
85
+ upload_parser.add_argument(
86
+ "--revision",
87
+ type=str,
88
+ help=(
89
+ "An optional Git revision to push to. It can be a branch name or a PR reference. If revision does not"
90
+ " exist and `--create-pr` is not set, a branch will be automatically created."
91
+ ),
92
+ )
93
+ upload_parser.add_argument(
94
+ "--private",
95
+ action="store_true",
96
+ help=(
97
+ "Whether to create a private repo if repo doesn't exist on the Hub. Ignored if the repo already"
98
+ " exists."
99
+ ),
100
+ )
101
+ upload_parser.add_argument("--include", nargs="*", type=str, help="Glob patterns to match files to upload.")
102
+ upload_parser.add_argument(
103
+ "--exclude", nargs="*", type=str, help="Glob patterns to exclude from files to upload."
104
+ )
105
+ upload_parser.add_argument(
106
+ "--delete",
107
+ nargs="*",
108
+ type=str,
109
+ help="Glob patterns for file to be deleted from the repo while committing.",
110
+ )
111
+ upload_parser.add_argument(
112
+ "--commit-message", type=str, help="The summary / title / first line of the generated commit."
113
+ )
114
+ upload_parser.add_argument("--commit-description", type=str, help="The description of the generated commit.")
115
+ upload_parser.add_argument(
116
+ "--create-pr", action="store_true", help="Whether to upload content as a new Pull Request."
117
+ )
118
+ upload_parser.add_argument(
119
+ "--every",
120
+ type=float,
121
+ help="If set, a background job is scheduled to create commits every `every` minutes.",
122
+ )
123
+ upload_parser.add_argument(
124
+ "--token", type=str, help="A User Access Token generated from https://huggingface.co/settings/tokens"
125
+ )
126
+ upload_parser.add_argument(
127
+ "--quiet",
128
+ action="store_true",
129
+ help="If True, progress bars are disabled and only the path to the uploaded files is printed.",
130
+ )
131
+ upload_parser.set_defaults(func=UploadCommand)
132
+
133
+ def __init__(self, args: Namespace) -> None:
134
+ self.repo_id: str = args.repo_id
135
+ self.repo_type: Optional[str] = args.repo_type
136
+ self.revision: Optional[str] = args.revision
137
+ self.private: bool = args.private
138
+
139
+ self.include: Optional[List[str]] = args.include
140
+ self.exclude: Optional[List[str]] = args.exclude
141
+ self.delete: Optional[List[str]] = args.delete
142
+
143
+ self.commit_message: Optional[str] = args.commit_message
144
+ self.commit_description: Optional[str] = args.commit_description
145
+ self.create_pr: bool = args.create_pr
146
+ self.api: HfApi = HfApi(token=args.token, library_name="huggingface-cli")
147
+ self.quiet: bool = args.quiet # disable warnings and progress bars
148
+
149
+ # Check `--every` is valid
150
+ if args.every is not None and args.every <= 0:
151
+ raise ValueError(f"`every` must be a positive value (got '{args.every}')")
152
+ self.every: Optional[float] = args.every
153
+
154
+ # Resolve `local_path` and `path_in_repo`
155
+ repo_name: str = args.repo_id.split("/")[-1] # e.g. "Wauplin/my-cool-model" => "my-cool-model"
156
+ self.local_path: str
157
+ self.path_in_repo: str
158
+ if args.local_path is None and os.path.isfile(repo_name):
159
+ # Implicit case 1: user provided only a repo_id which happen to be a local file as well => upload it with same name
160
+ self.local_path = repo_name
161
+ self.path_in_repo = repo_name
162
+ elif args.local_path is None and os.path.isdir(repo_name):
163
+ # Implicit case 2: user provided only a repo_id which happen to be a local folder as well => upload it at root
164
+ self.local_path = repo_name
165
+ self.path_in_repo = "."
166
+ elif args.local_path is None:
167
+ # Implicit case 3: user provided only a repo_id that does not match a local file or folder
168
+ # => the user must explicitly provide a local_path => raise exception
169
+ raise ValueError(f"'{repo_name}' is not a local file or folder. Please set `local_path` explicitly.")
170
+ elif args.path_in_repo is None and os.path.isfile(args.local_path):
171
+ # Explicit local path to file, no path in repo => upload it at root with same name
172
+ self.local_path = args.local_path
173
+ self.path_in_repo = os.path.basename(args.local_path)
174
+ elif args.path_in_repo is None:
175
+ # Explicit local path to folder, no path in repo => upload at root
176
+ self.local_path = args.local_path
177
+ self.path_in_repo = "."
178
+ else:
179
+ # Finally, if both paths are explicit
180
+ self.local_path = args.local_path
181
+ self.path_in_repo = args.path_in_repo
182
+
183
+ def run(self) -> None:
184
+ if self.quiet:
185
+ disable_progress_bars()
186
+ with warnings.catch_warnings():
187
+ warnings.simplefilter("ignore")
188
+ print(self._upload())
189
+ enable_progress_bars()
190
+ else:
191
+ logging.set_verbosity_info()
192
+ print(self._upload())
193
+ logging.set_verbosity_warning()
194
+
195
+ def _upload(self) -> str:
196
+ if os.path.isfile(self.local_path):
197
+ if self.include is not None and len(self.include) > 0:
198
+ warnings.warn("Ignoring `--include` since a single file is uploaded.")
199
+ if self.exclude is not None and len(self.exclude) > 0:
200
+ warnings.warn("Ignoring `--exclude` since a single file is uploaded.")
201
+ if self.delete is not None and len(self.delete) > 0:
202
+ warnings.warn("Ignoring `--delete` since a single file is uploaded.")
203
+
204
+ if not HF_HUB_ENABLE_HF_TRANSFER:
205
+ logger.info(
206
+ "Consider using `hf_transfer` for faster uploads. This solution comes with some limitations. See"
207
+ " https://huggingface.co/docs/huggingface_hub/hf_transfer for more details."
208
+ )
209
+
210
+ # Schedule commits if `every` is set
211
+ if self.every is not None:
212
+ if os.path.isfile(self.local_path):
213
+ # If file => watch entire folder + use allow_patterns
214
+ folder_path = os.path.dirname(self.local_path)
215
+ path_in_repo = (
216
+ self.path_in_repo[: -len(self.local_path)] # remove filename from path_in_repo
217
+ if self.path_in_repo.endswith(self.local_path)
218
+ else self.path_in_repo
219
+ )
220
+ allow_patterns = [self.local_path]
221
+ ignore_patterns = []
222
+ else:
223
+ folder_path = self.local_path
224
+ path_in_repo = self.path_in_repo
225
+ allow_patterns = self.include or []
226
+ ignore_patterns = self.exclude or []
227
+ if self.delete is not None and len(self.delete) > 0:
228
+ warnings.warn("Ignoring `--delete` when uploading with scheduled commits.")
229
+
230
+ scheduler = CommitScheduler(
231
+ folder_path=folder_path,
232
+ repo_id=self.repo_id,
233
+ repo_type=self.repo_type,
234
+ revision=self.revision,
235
+ allow_patterns=allow_patterns,
236
+ ignore_patterns=ignore_patterns,
237
+ path_in_repo=path_in_repo,
238
+ private=self.private,
239
+ every=self.every,
240
+ hf_api=self.api,
241
+ )
242
+ print(f"Scheduling commits every {self.every} minutes to {scheduler.repo_id}.")
243
+ try: # Block main thread until KeyboardInterrupt
244
+ while True:
245
+ time.sleep(100)
246
+ except KeyboardInterrupt:
247
+ scheduler.stop()
248
+ return "Stopped scheduled commits."
249
+
250
+ # Otherwise, create repo and proceed with the upload
251
+ if not os.path.isfile(self.local_path) and not os.path.isdir(self.local_path):
252
+ raise FileNotFoundError(f"No such file or directory: '{self.local_path}'.")
253
+ repo_id = self.api.create_repo(
254
+ repo_id=self.repo_id,
255
+ repo_type=self.repo_type,
256
+ exist_ok=True,
257
+ private=self.private,
258
+ space_sdk="gradio" if self.repo_type == "space" else None,
259
+ # ^ We don't want it to fail when uploading to a Space => let's set Gradio by default.
260
+ # ^ I'd rather not add CLI args to set it explicitly as we already have `huggingface-cli repo create` for that.
261
+ ).repo_id
262
+
263
+ # Check if branch already exists and if not, create it
264
+ if self.revision is not None and not self.create_pr:
265
+ try:
266
+ self.api.repo_info(repo_id=repo_id, repo_type=self.repo_type, revision=self.revision)
267
+ except RevisionNotFoundError:
268
+ logger.info(f"Branch '{self.revision}' not found. Creating it...")
269
+ self.api.create_branch(repo_id=repo_id, repo_type=self.repo_type, branch=self.revision, exist_ok=True)
270
+ # ^ `exist_ok=True` to avoid race concurrency issues
271
+
272
+ # File-based upload
273
+ if os.path.isfile(self.local_path):
274
+ return self.api.upload_file(
275
+ path_or_fileobj=self.local_path,
276
+ path_in_repo=self.path_in_repo,
277
+ repo_id=repo_id,
278
+ repo_type=self.repo_type,
279
+ revision=self.revision,
280
+ commit_message=self.commit_message,
281
+ commit_description=self.commit_description,
282
+ create_pr=self.create_pr,
283
+ )
284
+
285
+ # Folder-based upload
286
+ else:
287
+ return self.api.upload_folder(
288
+ folder_path=self.local_path,
289
+ path_in_repo=self.path_in_repo,
290
+ repo_id=repo_id,
291
+ repo_type=self.repo_type,
292
+ revision=self.revision,
293
+ commit_message=self.commit_message,
294
+ commit_description=self.commit_description,
295
+ create_pr=self.create_pr,
296
+ allow_patterns=self.include,
297
+ ignore_patterns=self.exclude,
298
+ delete_patterns=self.delete,
299
+ )
.venv/lib/python3.11/site-packages/huggingface_hub/commands/upload_large_folder.py ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding=utf-8
2
+ # Copyright 2023-present, the HuggingFace Inc. team.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ """Contains command to upload a large folder with the CLI."""
16
+
17
+ import os
18
+ from argparse import Namespace, _SubParsersAction
19
+ from typing import List, Optional
20
+
21
+ from huggingface_hub import logging
22
+ from huggingface_hub.commands import BaseHuggingfaceCLICommand
23
+ from huggingface_hub.hf_api import HfApi
24
+ from huggingface_hub.utils import disable_progress_bars
25
+
26
+ from ._cli_utils import ANSI
27
+
28
+
29
+ logger = logging.get_logger(__name__)
30
+
31
+
32
+ class UploadLargeFolderCommand(BaseHuggingfaceCLICommand):
33
+ @staticmethod
34
+ def register_subcommand(parser: _SubParsersAction):
35
+ subparser = parser.add_parser("upload-large-folder", help="Upload a large folder to a repo on the Hub")
36
+ subparser.add_argument(
37
+ "repo_id", type=str, help="The ID of the repo to upload to (e.g. `username/repo-name`)."
38
+ )
39
+ subparser.add_argument("local_path", type=str, help="Local path to the file or folder to upload.")
40
+ subparser.add_argument(
41
+ "--repo-type",
42
+ choices=["model", "dataset", "space"],
43
+ help="Type of the repo to upload to (e.g. `dataset`).",
44
+ )
45
+ subparser.add_argument(
46
+ "--revision",
47
+ type=str,
48
+ help=("An optional Git revision to push to. It can be a branch name or a PR reference."),
49
+ )
50
+ subparser.add_argument(
51
+ "--private",
52
+ action="store_true",
53
+ help=(
54
+ "Whether to create a private repo if repo doesn't exist on the Hub. Ignored if the repo already exists."
55
+ ),
56
+ )
57
+ subparser.add_argument("--include", nargs="*", type=str, help="Glob patterns to match files to upload.")
58
+ subparser.add_argument("--exclude", nargs="*", type=str, help="Glob patterns to exclude from files to upload.")
59
+ subparser.add_argument(
60
+ "--token", type=str, help="A User Access Token generated from https://huggingface.co/settings/tokens"
61
+ )
62
+ subparser.add_argument(
63
+ "--num-workers", type=int, help="Number of workers to use to hash, upload and commit files."
64
+ )
65
+ subparser.add_argument("--no-report", action="store_true", help="Whether to disable regular status report.")
66
+ subparser.add_argument("--no-bars", action="store_true", help="Whether to disable progress bars.")
67
+ subparser.set_defaults(func=UploadLargeFolderCommand)
68
+
69
+ def __init__(self, args: Namespace) -> None:
70
+ self.repo_id: str = args.repo_id
71
+ self.local_path: str = args.local_path
72
+ self.repo_type: str = args.repo_type
73
+ self.revision: Optional[str] = args.revision
74
+ self.private: bool = args.private
75
+
76
+ self.include: Optional[List[str]] = args.include
77
+ self.exclude: Optional[List[str]] = args.exclude
78
+
79
+ self.api: HfApi = HfApi(token=args.token, library_name="huggingface-cli")
80
+
81
+ self.num_workers: Optional[int] = args.num_workers
82
+ self.no_report: bool = args.no_report
83
+ self.no_bars: bool = args.no_bars
84
+
85
+ if not os.path.isdir(self.local_path):
86
+ raise ValueError("Large upload is only supported for folders.")
87
+
88
+ def run(self) -> None:
89
+ logging.set_verbosity_info()
90
+
91
+ print(
92
+ ANSI.yellow(
93
+ "You are about to upload a large folder to the Hub using `huggingface-cli upload-large-folder`. "
94
+ "This is a new feature so feedback is very welcome!\n"
95
+ "\n"
96
+ "A few things to keep in mind:\n"
97
+ " - Repository limits still apply: https://huggingface.co/docs/hub/repositories-recommendations\n"
98
+ " - Do not start several processes in parallel.\n"
99
+ " - You can interrupt and resume the process at any time. "
100
+ "The script will pick up where it left off except for partially uploaded files that would have to be entirely reuploaded.\n"
101
+ " - Do not upload the same folder to several repositories. If you need to do so, you must delete the `./.cache/huggingface/` folder first.\n"
102
+ "\n"
103
+ f"Some temporary metadata will be stored under `{self.local_path}/.cache/huggingface`.\n"
104
+ " - You must not modify those files manually.\n"
105
+ " - You must not delete the `./.cache/huggingface/` folder while a process is running.\n"
106
+ " - You can delete the `./.cache/huggingface/` folder to reinitialize the upload state when process is not running. Files will have to be hashed and preuploaded again, except for already committed files.\n"
107
+ "\n"
108
+ "If the process output is too verbose, you can disable the progress bars with `--no-bars`. "
109
+ "You can also entirely disable the status report with `--no-report`.\n"
110
+ "\n"
111
+ "For more details, run `huggingface-cli upload-large-folder --help` or check the documentation at "
112
+ "https://huggingface.co/docs/huggingface_hub/guides/upload#upload-a-large-folder."
113
+ )
114
+ )
115
+
116
+ if self.no_bars:
117
+ disable_progress_bars()
118
+
119
+ self.api.upload_large_folder(
120
+ repo_id=self.repo_id,
121
+ folder_path=self.local_path,
122
+ repo_type=self.repo_type,
123
+ revision=self.revision,
124
+ private=self.private,
125
+ allow_patterns=self.include,
126
+ ignore_patterns=self.exclude,
127
+ num_workers=self.num_workers,
128
+ print_report=not self.no_report,
129
+ )
.venv/lib/python3.11/site-packages/huggingface_hub/commands/user.py ADDED
@@ -0,0 +1,304 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2020 The HuggingFace Team. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ """Contains commands to authenticate to the Hugging Face Hub and interact with your repositories.
15
+
16
+ Usage:
17
+ # login and save token locally.
18
+ huggingface-cli login --token=hf_*** --add-to-git-credential
19
+
20
+ # switch between tokens
21
+ huggingface-cli auth switch
22
+
23
+ # list all tokens
24
+ huggingface-cli auth list
25
+
26
+ # logout from a specific token, if no token-name is provided, all tokens will be deleted from your machine.
27
+ huggingface-cli logout --token-name=your_token_name
28
+
29
+ # find out which huggingface.co account you are logged in as
30
+ huggingface-cli whoami
31
+
32
+ # create a new dataset repo on the Hub
33
+ huggingface-cli repo create mydataset --type=dataset
34
+
35
+ """
36
+
37
+ import subprocess
38
+ from argparse import _SubParsersAction
39
+ from typing import List, Optional
40
+
41
+ from requests.exceptions import HTTPError
42
+
43
+ from huggingface_hub.commands import BaseHuggingfaceCLICommand
44
+ from huggingface_hub.constants import ENDPOINT, REPO_TYPES, REPO_TYPES_URL_PREFIXES, SPACES_SDK_TYPES
45
+ from huggingface_hub.hf_api import HfApi
46
+
47
+ from .._login import ( # noqa: F401 # for backward compatibility # noqa: F401 # for backward compatibility
48
+ NOTEBOOK_LOGIN_PASSWORD_HTML,
49
+ NOTEBOOK_LOGIN_TOKEN_HTML_END,
50
+ NOTEBOOK_LOGIN_TOKEN_HTML_START,
51
+ auth_list,
52
+ auth_switch,
53
+ login,
54
+ logout,
55
+ notebook_login,
56
+ )
57
+ from ..utils import get_stored_tokens, get_token, logging
58
+ from ._cli_utils import ANSI
59
+
60
+
61
+ logger = logging.get_logger(__name__)
62
+
63
+ try:
64
+ from InquirerPy import inquirer
65
+ from InquirerPy.base.control import Choice
66
+
67
+ _inquirer_py_available = True
68
+ except ImportError:
69
+ _inquirer_py_available = False
70
+
71
+
72
+ class UserCommands(BaseHuggingfaceCLICommand):
73
+ @staticmethod
74
+ def register_subcommand(parser: _SubParsersAction):
75
+ login_parser = parser.add_parser("login", help="Log in using a token from huggingface.co/settings/tokens")
76
+ login_parser.add_argument(
77
+ "--token",
78
+ type=str,
79
+ help="Token generated from https://huggingface.co/settings/tokens",
80
+ )
81
+ login_parser.add_argument(
82
+ "--add-to-git-credential",
83
+ action="store_true",
84
+ help="Optional: Save token to git credential helper.",
85
+ )
86
+ login_parser.set_defaults(func=lambda args: LoginCommand(args))
87
+ whoami_parser = parser.add_parser("whoami", help="Find out which huggingface.co account you are logged in as.")
88
+ whoami_parser.set_defaults(func=lambda args: WhoamiCommand(args))
89
+
90
+ logout_parser = parser.add_parser("logout", help="Log out")
91
+ logout_parser.add_argument(
92
+ "--token-name",
93
+ type=str,
94
+ help="Optional: Name of the access token to log out from.",
95
+ )
96
+ logout_parser.set_defaults(func=lambda args: LogoutCommand(args))
97
+
98
+ auth_parser = parser.add_parser("auth", help="Other authentication related commands")
99
+ auth_subparsers = auth_parser.add_subparsers(help="Authentication subcommands")
100
+ auth_switch_parser = auth_subparsers.add_parser("switch", help="Switch between access tokens")
101
+ auth_switch_parser.add_argument(
102
+ "--token-name",
103
+ type=str,
104
+ help="Optional: Name of the access token to switch to.",
105
+ )
106
+ auth_switch_parser.add_argument(
107
+ "--add-to-git-credential",
108
+ action="store_true",
109
+ help="Optional: Save token to git credential helper.",
110
+ )
111
+ auth_switch_parser.set_defaults(func=lambda args: AuthSwitchCommand(args))
112
+ auth_list_parser = auth_subparsers.add_parser("list", help="List all stored access tokens")
113
+ auth_list_parser.set_defaults(func=lambda args: AuthListCommand(args))
114
+ # new system: git-based repo system
115
+ repo_parser = parser.add_parser("repo", help="{create} Commands to interact with your huggingface.co repos.")
116
+ repo_subparsers = repo_parser.add_subparsers(help="huggingface.co repos related commands")
117
+ repo_create_parser = repo_subparsers.add_parser("create", help="Create a new repo on huggingface.co")
118
+ repo_create_parser.add_argument(
119
+ "name",
120
+ type=str,
121
+ help="Name for your repo. Will be namespaced under your username to build the repo id.",
122
+ )
123
+ repo_create_parser.add_argument(
124
+ "--type",
125
+ type=str,
126
+ help='Optional: repo_type: set to "dataset" or "space" if creating a dataset or space, default is model.',
127
+ )
128
+ repo_create_parser.add_argument("--organization", type=str, help="Optional: organization namespace.")
129
+ repo_create_parser.add_argument(
130
+ "--space_sdk",
131
+ type=str,
132
+ help='Optional: Hugging Face Spaces SDK type. Required when --type is set to "space".',
133
+ choices=SPACES_SDK_TYPES,
134
+ )
135
+ repo_create_parser.add_argument(
136
+ "-y",
137
+ "--yes",
138
+ action="store_true",
139
+ help="Optional: answer Yes to the prompt",
140
+ )
141
+ repo_create_parser.set_defaults(func=lambda args: RepoCreateCommand(args))
142
+
143
+
144
+ class BaseUserCommand:
145
+ def __init__(self, args):
146
+ self.args = args
147
+ self._api = HfApi()
148
+
149
+
150
+ class LoginCommand(BaseUserCommand):
151
+ def run(self):
152
+ logging.set_verbosity_info()
153
+ login(
154
+ token=self.args.token,
155
+ add_to_git_credential=self.args.add_to_git_credential,
156
+ )
157
+
158
+
159
+ class LogoutCommand(BaseUserCommand):
160
+ def run(self):
161
+ logging.set_verbosity_info()
162
+ logout(token_name=self.args.token_name)
163
+
164
+
165
+ class AuthSwitchCommand(BaseUserCommand):
166
+ def run(self):
167
+ logging.set_verbosity_info()
168
+ token_name = self.args.token_name
169
+ if token_name is None:
170
+ token_name = self._select_token_name()
171
+
172
+ if token_name is None:
173
+ print("No token name provided. Aborting.")
174
+ exit()
175
+ auth_switch(token_name, add_to_git_credential=self.args.add_to_git_credential)
176
+
177
+ def _select_token_name(self) -> Optional[str]:
178
+ token_names = list(get_stored_tokens().keys())
179
+
180
+ if not token_names:
181
+ logger.error("No stored tokens found. Please login first.")
182
+ return None
183
+
184
+ if _inquirer_py_available:
185
+ return self._select_token_name_tui(token_names)
186
+ # if inquirer is not available, use a simpler terminal UI
187
+ print("Available stored tokens:")
188
+ for i, token_name in enumerate(token_names, 1):
189
+ print(f"{i}. {token_name}")
190
+ while True:
191
+ try:
192
+ choice = input("Enter the number of the token to switch to (or 'q' to quit): ")
193
+ if choice.lower() == "q":
194
+ return None
195
+ index = int(choice) - 1
196
+ if 0 <= index < len(token_names):
197
+ return token_names[index]
198
+ else:
199
+ print("Invalid selection. Please try again.")
200
+ except ValueError:
201
+ print("Invalid input. Please enter a number or 'q' to quit.")
202
+
203
+ def _select_token_name_tui(self, token_names: List[str]) -> Optional[str]:
204
+ choices = [Choice(token_name, name=token_name) for token_name in token_names]
205
+ try:
206
+ return inquirer.select(
207
+ message="Select a token to switch to:",
208
+ choices=choices,
209
+ default=None,
210
+ ).execute()
211
+ except KeyboardInterrupt:
212
+ logger.info("Token selection cancelled.")
213
+ return None
214
+
215
+
216
+ class AuthListCommand(BaseUserCommand):
217
+ def run(self):
218
+ logging.set_verbosity_info()
219
+ auth_list()
220
+
221
+
222
+ class WhoamiCommand(BaseUserCommand):
223
+ def run(self):
224
+ token = get_token()
225
+ if token is None:
226
+ print("Not logged in")
227
+ exit()
228
+ try:
229
+ info = self._api.whoami(token)
230
+ print(info["name"])
231
+ orgs = [org["name"] for org in info["orgs"]]
232
+ if orgs:
233
+ print(ANSI.bold("orgs: "), ",".join(orgs))
234
+
235
+ if ENDPOINT != "https://huggingface.co":
236
+ print(f"Authenticated through private endpoint: {ENDPOINT}")
237
+ except HTTPError as e:
238
+ print(e)
239
+ print(ANSI.red(e.response.text))
240
+ exit(1)
241
+
242
+
243
+ class RepoCreateCommand(BaseUserCommand):
244
+ def run(self):
245
+ token = get_token()
246
+ if token is None:
247
+ print("Not logged in")
248
+ exit(1)
249
+ try:
250
+ stdout = subprocess.check_output(["git", "--version"]).decode("utf-8")
251
+ print(ANSI.gray(stdout.strip()))
252
+ except FileNotFoundError:
253
+ print("Looks like you do not have git installed, please install.")
254
+
255
+ try:
256
+ stdout = subprocess.check_output(["git-lfs", "--version"]).decode("utf-8")
257
+ print(ANSI.gray(stdout.strip()))
258
+ except FileNotFoundError:
259
+ print(
260
+ ANSI.red(
261
+ "Looks like you do not have git-lfs installed, please install."
262
+ " You can install from https://git-lfs.github.com/."
263
+ " Then run `git lfs install` (you only have to do this once)."
264
+ )
265
+ )
266
+ print("")
267
+
268
+ user = self._api.whoami(token)["name"]
269
+ namespace = self.args.organization if self.args.organization is not None else user
270
+
271
+ repo_id = f"{namespace}/{self.args.name}"
272
+
273
+ if self.args.type not in REPO_TYPES:
274
+ print("Invalid repo --type")
275
+ exit(1)
276
+
277
+ if self.args.type in REPO_TYPES_URL_PREFIXES:
278
+ prefixed_repo_id = REPO_TYPES_URL_PREFIXES[self.args.type] + repo_id
279
+ else:
280
+ prefixed_repo_id = repo_id
281
+
282
+ print(f"You are about to create {ANSI.bold(prefixed_repo_id)}")
283
+
284
+ if not self.args.yes:
285
+ choice = input("Proceed? [Y/n] ").lower()
286
+ if not (choice == "" or choice == "y" or choice == "yes"):
287
+ print("Abort")
288
+ exit()
289
+ try:
290
+ url = self._api.create_repo(
291
+ repo_id=repo_id,
292
+ token=token,
293
+ repo_type=self.args.type,
294
+ space_sdk=self.args.space_sdk,
295
+ )
296
+ except HTTPError as e:
297
+ print(e)
298
+ print(ANSI.red(e.response.text))
299
+ exit(1)
300
+ print("\nYour repo now lives at:")
301
+ print(f" {ANSI.bold(url)}")
302
+ print("\nYou can clone it locally with the command below, and commit/push as usual.")
303
+ print(f"\n git clone {url}")
304
+ print("")
.venv/lib/python3.11/site-packages/huggingface_hub/commands/version.py ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2022 The HuggingFace Team. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ """Contains command to print information about the version.
15
+
16
+ Usage:
17
+ huggingface-cli version
18
+ """
19
+
20
+ from argparse import _SubParsersAction
21
+
22
+ from huggingface_hub import __version__
23
+
24
+ from . import BaseHuggingfaceCLICommand
25
+
26
+
27
+ class VersionCommand(BaseHuggingfaceCLICommand):
28
+ def __init__(self, args):
29
+ self.args = args
30
+
31
+ @staticmethod
32
+ def register_subcommand(parser: _SubParsersAction):
33
+ version_parser = parser.add_parser("version", help="Print information about the huggingface-cli version.")
34
+ version_parser.set_defaults(func=VersionCommand)
35
+
36
+ def run(self) -> None:
37
+ print(f"huggingface_hub version: {__version__}")
.venv/lib/python3.11/site-packages/huggingface_hub/serialization/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (836 Bytes). View file
 
.venv/lib/python3.11/site-packages/huggingface_hub/serialization/__pycache__/_base.cpython-311.pyc ADDED
Binary file (8.25 kB). View file
 
.venv/lib/python3.11/site-packages/huggingface_hub/serialization/__pycache__/_tensorflow.cpython-311.pyc ADDED
Binary file (3.9 kB). View file
 
.venv/lib/python3.11/site-packages/huggingface_hub/serialization/__pycache__/_torch.cpython-311.pyc ADDED
Binary file (50.3 kB). View file
 
.venv/lib/python3.11/site-packages/huggingface_hub/utils/__init__.py ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding=utf-8
2
+ # Copyright 2021 The HuggingFace Inc. team. All rights reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License
15
+
16
+ # ruff: noqa: F401
17
+
18
+ from huggingface_hub.errors import (
19
+ BadRequestError,
20
+ CacheNotFound,
21
+ CorruptedCacheException,
22
+ DisabledRepoError,
23
+ EntryNotFoundError,
24
+ FileMetadataError,
25
+ GatedRepoError,
26
+ HfHubHTTPError,
27
+ HFValidationError,
28
+ LocalEntryNotFoundError,
29
+ LocalTokenNotFoundError,
30
+ NotASafetensorsRepoError,
31
+ OfflineModeIsEnabled,
32
+ RepositoryNotFoundError,
33
+ RevisionNotFoundError,
34
+ SafetensorsParsingError,
35
+ )
36
+
37
+ from . import tqdm as _tqdm # _tqdm is the module
38
+ from ._auth import get_stored_tokens, get_token
39
+ from ._cache_assets import cached_assets_path
40
+ from ._cache_manager import (
41
+ CachedFileInfo,
42
+ CachedRepoInfo,
43
+ CachedRevisionInfo,
44
+ DeleteCacheStrategy,
45
+ HFCacheInfo,
46
+ scan_cache_dir,
47
+ )
48
+ from ._chunk_utils import chunk_iterable
49
+ from ._datetime import parse_datetime
50
+ from ._experimental import experimental
51
+ from ._fixes import SoftTemporaryDirectory, WeakFileLock, yaml_dump
52
+ from ._git_credential import list_credential_helpers, set_git_credential, unset_git_credential
53
+ from ._headers import build_hf_headers, get_token_to_send
54
+ from ._hf_folder import HfFolder
55
+ from ._http import (
56
+ configure_http_backend,
57
+ fix_hf_endpoint_in_url,
58
+ get_session,
59
+ hf_raise_for_status,
60
+ http_backoff,
61
+ reset_sessions,
62
+ )
63
+ from ._pagination import paginate
64
+ from ._paths import DEFAULT_IGNORE_PATTERNS, FORBIDDEN_FOLDERS, filter_repo_objects
65
+ from ._runtime import (
66
+ dump_environment_info,
67
+ get_aiohttp_version,
68
+ get_fastai_version,
69
+ get_fastapi_version,
70
+ get_fastcore_version,
71
+ get_gradio_version,
72
+ get_graphviz_version,
73
+ get_hf_hub_version,
74
+ get_hf_transfer_version,
75
+ get_jinja_version,
76
+ get_numpy_version,
77
+ get_pillow_version,
78
+ get_pydantic_version,
79
+ get_pydot_version,
80
+ get_python_version,
81
+ get_tensorboard_version,
82
+ get_tf_version,
83
+ get_torch_version,
84
+ is_aiohttp_available,
85
+ is_colab_enterprise,
86
+ is_fastai_available,
87
+ is_fastapi_available,
88
+ is_fastcore_available,
89
+ is_google_colab,
90
+ is_gradio_available,
91
+ is_graphviz_available,
92
+ is_hf_transfer_available,
93
+ is_jinja_available,
94
+ is_notebook,
95
+ is_numpy_available,
96
+ is_package_available,
97
+ is_pillow_available,
98
+ is_pydantic_available,
99
+ is_pydot_available,
100
+ is_safetensors_available,
101
+ is_tensorboard_available,
102
+ is_tf_available,
103
+ is_torch_available,
104
+ )
105
+ from ._safetensors import SafetensorsFileMetadata, SafetensorsRepoMetadata, TensorInfo
106
+ from ._subprocess import capture_output, run_interactive_subprocess, run_subprocess
107
+ from ._telemetry import send_telemetry
108
+ from ._typing import is_jsonable, is_simple_optional_type, unwrap_simple_optional_type
109
+ from ._validators import smoothly_deprecate_use_auth_token, validate_hf_hub_args, validate_repo_id
110
+ from .tqdm import are_progress_bars_disabled, disable_progress_bars, enable_progress_bars, tqdm, tqdm_stream_file
.venv/lib/python3.11/site-packages/huggingface_hub/utils/__pycache__/_chunk_utils.cpython-311.pyc ADDED
Binary file (2.23 kB). View file
 
.venv/lib/python3.11/site-packages/huggingface_hub/utils/__pycache__/_fixes.cpython-311.pyc ADDED
Binary file (6.41 kB). View file
 
.venv/lib/python3.11/site-packages/huggingface_hub/utils/__pycache__/_git_credential.cpython-311.pyc ADDED
Binary file (5.68 kB). View file
 
.venv/lib/python3.11/site-packages/huggingface_hub/utils/__pycache__/_headers.cpython-311.pyc ADDED
Binary file (9.56 kB). View file
 
.venv/lib/python3.11/site-packages/huggingface_hub/utils/__pycache__/_hf_folder.cpython-311.pyc ADDED
Binary file (4.01 kB). View file
 
.venv/lib/python3.11/site-packages/huggingface_hub/utils/__pycache__/_http.cpython-311.pyc ADDED
Binary file (24.8 kB). View file
 
.venv/lib/python3.11/site-packages/huggingface_hub/utils/__pycache__/_lfs.cpython-311.pyc ADDED
Binary file (5.46 kB). View file
 
.venv/lib/python3.11/site-packages/huggingface_hub/utils/__pycache__/_pagination.cpython-311.pyc ADDED
Binary file (2.25 kB). View file
 
.venv/lib/python3.11/site-packages/huggingface_hub/utils/__pycache__/_paths.cpython-311.pyc ADDED
Binary file (5.89 kB). View file
 
.venv/lib/python3.11/site-packages/huggingface_hub/utils/__pycache__/_runtime.cpython-311.pyc ADDED
Binary file (15 kB). View file
 
.venv/lib/python3.11/site-packages/huggingface_hub/utils/__pycache__/_safetensors.cpython-311.pyc ADDED
Binary file (6.55 kB). View file
 
.venv/lib/python3.11/site-packages/huggingface_hub/utils/__pycache__/_subprocess.cpython-311.pyc ADDED
Binary file (5.4 kB). View file
 
.venv/lib/python3.11/site-packages/huggingface_hub/utils/__pycache__/_telemetry.cpython-311.pyc ADDED
Binary file (6.36 kB). View file
 
.venv/lib/python3.11/site-packages/huggingface_hub/utils/__pycache__/_typing.cpython-311.pyc ADDED
Binary file (3.97 kB). View file
 
.venv/lib/python3.11/site-packages/huggingface_hub/utils/__pycache__/_validators.cpython-311.pyc ADDED
Binary file (9.42 kB). View file
 
.venv/lib/python3.11/site-packages/huggingface_hub/utils/__pycache__/sha.cpython-311.pyc ADDED
Binary file (2.93 kB). View file
 
.venv/lib/python3.11/site-packages/huggingface_hub/utils/_auth.py ADDED
@@ -0,0 +1,214 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2023 The HuggingFace Team. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ """Contains an helper to get the token from machine (env variable, secret or config file)."""
15
+
16
+ import configparser
17
+ import logging
18
+ import os
19
+ import warnings
20
+ from pathlib import Path
21
+ from threading import Lock
22
+ from typing import Dict, Optional
23
+
24
+ from .. import constants
25
+ from ._runtime import is_colab_enterprise, is_google_colab
26
+
27
+
28
+ _IS_GOOGLE_COLAB_CHECKED = False
29
+ _GOOGLE_COLAB_SECRET_LOCK = Lock()
30
+ _GOOGLE_COLAB_SECRET: Optional[str] = None
31
+
32
+ logger = logging.getLogger(__name__)
33
+
34
+
35
+ def get_token() -> Optional[str]:
36
+ """
37
+ Get token if user is logged in.
38
+
39
+ Note: in most cases, you should use [`huggingface_hub.utils.build_hf_headers`] instead. This method is only useful
40
+ if you want to retrieve the token for other purposes than sending an HTTP request.
41
+
42
+ Token is retrieved in priority from the `HF_TOKEN` environment variable. Otherwise, we read the token file located
43
+ in the Hugging Face home folder. Returns None if user is not logged in. To log in, use [`login`] or
44
+ `huggingface-cli login`.
45
+
46
+ Returns:
47
+ `str` or `None`: The token, `None` if it doesn't exist.
48
+ """
49
+ return _get_token_from_google_colab() or _get_token_from_environment() or _get_token_from_file()
50
+
51
+
52
+ def _get_token_from_google_colab() -> Optional[str]:
53
+ """Get token from Google Colab secrets vault using `google.colab.userdata.get(...)`.
54
+
55
+ Token is read from the vault only once per session and then stored in a global variable to avoid re-requesting
56
+ access to the vault.
57
+ """
58
+ # If it's not a Google Colab or it's Colab Enterprise, fallback to environment variable or token file authentication
59
+ if not is_google_colab() or is_colab_enterprise():
60
+ return None
61
+
62
+ # `google.colab.userdata` is not thread-safe
63
+ # This can lead to a deadlock if multiple threads try to access it at the same time
64
+ # (typically when using `snapshot_download`)
65
+ # => use a lock
66
+ # See https://github.com/huggingface/huggingface_hub/issues/1952 for more details.
67
+ with _GOOGLE_COLAB_SECRET_LOCK:
68
+ global _GOOGLE_COLAB_SECRET
69
+ global _IS_GOOGLE_COLAB_CHECKED
70
+
71
+ if _IS_GOOGLE_COLAB_CHECKED: # request access only once
72
+ return _GOOGLE_COLAB_SECRET
73
+
74
+ try:
75
+ from google.colab import userdata # type: ignore
76
+ from google.colab.errors import Error as ColabError # type: ignore
77
+ except ImportError:
78
+ return None
79
+
80
+ try:
81
+ token = userdata.get("HF_TOKEN")
82
+ _GOOGLE_COLAB_SECRET = _clean_token(token)
83
+ except userdata.NotebookAccessError:
84
+ # Means the user has a secret call `HF_TOKEN` and got a popup "please grand access to HF_TOKEN" and refused it
85
+ # => warn user but ignore error => do not re-request access to user
86
+ warnings.warn(
87
+ "\nAccess to the secret `HF_TOKEN` has not been granted on this notebook."
88
+ "\nYou will not be requested again."
89
+ "\nPlease restart the session if you want to be prompted again."
90
+ )
91
+ _GOOGLE_COLAB_SECRET = None
92
+ except userdata.SecretNotFoundError:
93
+ # Means the user did not define a `HF_TOKEN` secret => warn
94
+ warnings.warn(
95
+ "\nThe secret `HF_TOKEN` does not exist in your Colab secrets."
96
+ "\nTo authenticate with the Hugging Face Hub, create a token in your settings tab "
97
+ "(https://huggingface.co/settings/tokens), set it as secret in your Google Colab and restart your session."
98
+ "\nYou will be able to reuse this secret in all of your notebooks."
99
+ "\nPlease note that authentication is recommended but still optional to access public models or datasets."
100
+ )
101
+ _GOOGLE_COLAB_SECRET = None
102
+ except ColabError as e:
103
+ # Something happen but we don't know what => recommend to open a GitHub issue
104
+ warnings.warn(
105
+ f"\nError while fetching `HF_TOKEN` secret value from your vault: '{str(e)}'."
106
+ "\nYou are not authenticated with the Hugging Face Hub in this notebook."
107
+ "\nIf the error persists, please let us know by opening an issue on GitHub "
108
+ "(https://github.com/huggingface/huggingface_hub/issues/new)."
109
+ )
110
+ _GOOGLE_COLAB_SECRET = None
111
+
112
+ _IS_GOOGLE_COLAB_CHECKED = True
113
+ return _GOOGLE_COLAB_SECRET
114
+
115
+
116
+ def _get_token_from_environment() -> Optional[str]:
117
+ # `HF_TOKEN` has priority (keep `HUGGING_FACE_HUB_TOKEN` for backward compatibility)
118
+ return _clean_token(os.environ.get("HF_TOKEN") or os.environ.get("HUGGING_FACE_HUB_TOKEN"))
119
+
120
+
121
+ def _get_token_from_file() -> Optional[str]:
122
+ try:
123
+ return _clean_token(Path(constants.HF_TOKEN_PATH).read_text())
124
+ except FileNotFoundError:
125
+ return None
126
+
127
+
128
+ def get_stored_tokens() -> Dict[str, str]:
129
+ """
130
+ Returns the parsed INI file containing the access tokens.
131
+ The file is located at `HF_STORED_TOKENS_PATH`, defaulting to `~/.cache/huggingface/stored_tokens`.
132
+ If the file does not exist, an empty dictionary is returned.
133
+
134
+ Returns: `Dict[str, str]`
135
+ Key is the token name and value is the token.
136
+ """
137
+ tokens_path = Path(constants.HF_STORED_TOKENS_PATH)
138
+ if not tokens_path.exists():
139
+ stored_tokens = {}
140
+ config = configparser.ConfigParser()
141
+ try:
142
+ config.read(tokens_path)
143
+ stored_tokens = {token_name: config.get(token_name, "hf_token") for token_name in config.sections()}
144
+ except configparser.Error as e:
145
+ logger.error(f"Error parsing stored tokens file: {e}")
146
+ stored_tokens = {}
147
+ return stored_tokens
148
+
149
+
150
+ def _save_stored_tokens(stored_tokens: Dict[str, str]) -> None:
151
+ """
152
+ Saves the given configuration to the stored tokens file.
153
+
154
+ Args:
155
+ stored_tokens (`Dict[str, str]`):
156
+ The stored tokens to save. Key is the token name and value is the token.
157
+ """
158
+ stored_tokens_path = Path(constants.HF_STORED_TOKENS_PATH)
159
+
160
+ # Write the stored tokens into an INI file
161
+ config = configparser.ConfigParser()
162
+ for token_name in sorted(stored_tokens.keys()):
163
+ config.add_section(token_name)
164
+ config.set(token_name, "hf_token", stored_tokens[token_name])
165
+
166
+ stored_tokens_path.parent.mkdir(parents=True, exist_ok=True)
167
+ with stored_tokens_path.open("w") as config_file:
168
+ config.write(config_file)
169
+
170
+
171
+ def _get_token_by_name(token_name: str) -> Optional[str]:
172
+ """
173
+ Get the token by name.
174
+
175
+ Args:
176
+ token_name (`str`):
177
+ The name of the token to get.
178
+
179
+ Returns:
180
+ `str` or `None`: The token, `None` if it doesn't exist.
181
+
182
+ """
183
+ stored_tokens = get_stored_tokens()
184
+ if token_name not in stored_tokens:
185
+ return None
186
+ return _clean_token(stored_tokens[token_name])
187
+
188
+
189
+ def _save_token(token: str, token_name: str) -> None:
190
+ """
191
+ Save the given token.
192
+
193
+ If the stored tokens file does not exist, it will be created.
194
+ Args:
195
+ token (`str`):
196
+ The token to save.
197
+ token_name (`str`):
198
+ The name of the token.
199
+ """
200
+ tokens_path = Path(constants.HF_STORED_TOKENS_PATH)
201
+ stored_tokens = get_stored_tokens()
202
+ stored_tokens[token_name] = token
203
+ _save_stored_tokens(stored_tokens)
204
+ logger.info(f"The token `{token_name}` has been saved to {tokens_path}")
205
+
206
+
207
+ def _clean_token(token: Optional[str]) -> Optional[str]:
208
+ """Clean token by removing trailing and leading spaces and newlines.
209
+
210
+ If token is an empty string, return None.
211
+ """
212
+ if token is None:
213
+ return None
214
+ return token.replace("\r", "").replace("\n", "").strip() or None