huggingface-hub 0.12.0rc0__py3-none-any.whl → 0.13.0rc0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- huggingface_hub/__init__.py +166 -126
- huggingface_hub/_commit_api.py +25 -51
- huggingface_hub/_login.py +4 -13
- huggingface_hub/_snapshot_download.py +45 -23
- huggingface_hub/_space_api.py +7 -0
- huggingface_hub/commands/delete_cache.py +13 -39
- huggingface_hub/commands/env.py +1 -3
- huggingface_hub/commands/huggingface_cli.py +1 -3
- huggingface_hub/commands/lfs.py +4 -8
- huggingface_hub/commands/scan_cache.py +5 -16
- huggingface_hub/commands/user.py +27 -45
- huggingface_hub/community.py +4 -4
- huggingface_hub/constants.py +22 -19
- huggingface_hub/fastai_utils.py +14 -23
- huggingface_hub/file_download.py +210 -121
- huggingface_hub/hf_api.py +500 -255
- huggingface_hub/hub_mixin.py +181 -176
- huggingface_hub/inference_api.py +4 -10
- huggingface_hub/keras_mixin.py +39 -71
- huggingface_hub/lfs.py +8 -24
- huggingface_hub/repocard.py +33 -48
- huggingface_hub/repocard_data.py +141 -30
- huggingface_hub/repository.py +41 -112
- huggingface_hub/templates/modelcard_template.md +39 -34
- huggingface_hub/utils/__init__.py +1 -0
- huggingface_hub/utils/_cache_assets.py +1 -4
- huggingface_hub/utils/_cache_manager.py +17 -39
- huggingface_hub/utils/_deprecation.py +8 -12
- huggingface_hub/utils/_errors.py +10 -57
- huggingface_hub/utils/_fixes.py +2 -6
- huggingface_hub/utils/_git_credential.py +5 -16
- huggingface_hub/utils/_headers.py +22 -11
- huggingface_hub/utils/_http.py +1 -4
- huggingface_hub/utils/_paths.py +5 -12
- huggingface_hub/utils/_runtime.py +2 -1
- huggingface_hub/utils/_telemetry.py +120 -0
- huggingface_hub/utils/_validators.py +5 -13
- huggingface_hub/utils/endpoint_helpers.py +1 -3
- huggingface_hub/utils/logging.py +10 -8
- {huggingface_hub-0.12.0rc0.dist-info → huggingface_hub-0.13.0rc0.dist-info}/METADATA +7 -14
- huggingface_hub-0.13.0rc0.dist-info/RECORD +56 -0
- huggingface_hub/py.typed +0 -0
- huggingface_hub-0.12.0rc0.dist-info/RECORD +0 -56
- {huggingface_hub-0.12.0rc0.dist-info → huggingface_hub-0.13.0rc0.dist-info}/LICENSE +0 -0
- {huggingface_hub-0.12.0rc0.dist-info → huggingface_hub-0.13.0rc0.dist-info}/WHEEL +0 -0
- {huggingface_hub-0.12.0rc0.dist-info → huggingface_hub-0.13.0rc0.dist-info}/entry_points.txt +0 -0
- {huggingface_hub-0.12.0rc0.dist-info → huggingface_hub-0.13.0rc0.dist-info}/top_level.txt +0 -0
|
@@ -13,9 +13,9 @@ from .constants import (
|
|
|
13
13
|
)
|
|
14
14
|
from .file_download import REGEX_COMMIT_HASH, hf_hub_download, repo_folder_name
|
|
15
15
|
from .hf_api import HfApi
|
|
16
|
-
from .utils import filter_repo_objects, logging
|
|
16
|
+
from .utils import filter_repo_objects, logging, validate_hf_hub_args
|
|
17
17
|
from .utils import tqdm as hf_tqdm
|
|
18
|
-
from .utils import
|
|
18
|
+
from .utils._typing import Literal
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
logger = logging.get_logger(__name__)
|
|
@@ -28,6 +28,8 @@ def snapshot_download(
|
|
|
28
28
|
revision: Optional[str] = None,
|
|
29
29
|
repo_type: Optional[str] = None,
|
|
30
30
|
cache_dir: Union[str, Path, None] = None,
|
|
31
|
+
local_dir: Union[str, Path, None] = None,
|
|
32
|
+
local_dir_use_symlinks: Union[bool, Literal["auto"]] = "auto",
|
|
31
33
|
library_name: Optional[str] = None,
|
|
32
34
|
library_version: Optional[str] = None,
|
|
33
35
|
user_agent: Optional[Union[Dict, str]] = None,
|
|
@@ -41,15 +43,30 @@ def snapshot_download(
|
|
|
41
43
|
max_workers: int = 8,
|
|
42
44
|
tqdm_class: Optional[base_tqdm] = None,
|
|
43
45
|
) -> str:
|
|
44
|
-
"""Download
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
46
|
+
"""Download repo files.
|
|
47
|
+
|
|
48
|
+
Download a whole snapshot of a repo's files at the specified revision. This is useful when you want all files from
|
|
49
|
+
a repo, because you don't know which ones you will need a priori. All files are nested inside a folder in order
|
|
50
|
+
to keep their actual filename relative to that folder. You can also filter which files to download using
|
|
51
|
+
`allow_patterns` and `ignore_patterns`.
|
|
52
|
+
|
|
53
|
+
If `local_dir` is provided, the file structure from the repo will be replicated in this location. You can configure
|
|
54
|
+
how you want to move those files:
|
|
55
|
+
- If `local_dir_use_symlinks="auto"` (default), files are downloaded and stored in the cache directory as blob
|
|
56
|
+
files. Small files (<5MB) are duplicated in `local_dir` while a symlink is created for bigger files. The goal
|
|
57
|
+
is to be able to manually edit and save small files without corrupting the cache while saving disk space for
|
|
58
|
+
binary files. The 5MB threshold can be configured with the `HF_HUB_LOCAL_DIR_AUTO_SYMLINK_THRESHOLD`
|
|
59
|
+
environment variable.
|
|
60
|
+
- If `local_dir_use_symlinks=True`, files are downloaded, stored in the cache directory and symlinked in `local_dir`.
|
|
61
|
+
This is optimal in term of disk usage but files must not be manually edited.
|
|
62
|
+
- If `local_dir_use_symlinks=False` and the blob files exist in the cache directory, they are duplicated in the
|
|
63
|
+
local dir. This means disk usage is not optimized.
|
|
64
|
+
- Finally, if `local_dir_use_symlinks=False` and the blob files do not exist in the cache directory, then the
|
|
65
|
+
files are downloaded and directly placed under `local_dir`. This means if you need to download them again later,
|
|
66
|
+
they will be re-downloaded entirely.
|
|
67
|
+
|
|
68
|
+
An alternative would be to clone the repo but this requires git and git-lfs to be installed and properly
|
|
69
|
+
configured. It is also not possible to filter which files to download when cloning a repository using git.
|
|
53
70
|
|
|
54
71
|
Args:
|
|
55
72
|
repo_id (`str`):
|
|
@@ -58,10 +75,18 @@ def snapshot_download(
|
|
|
58
75
|
An optional Git revision id which can be a branch name, a tag, or a
|
|
59
76
|
commit hash.
|
|
60
77
|
repo_type (`str`, *optional*):
|
|
61
|
-
Set to `"dataset"` or `"space"` if
|
|
62
|
-
`None` or `"model"` if
|
|
78
|
+
Set to `"dataset"` or `"space"` if downloading from a dataset or space,
|
|
79
|
+
`None` or `"model"` if downloading from a model. Default is `None`.
|
|
63
80
|
cache_dir (`str`, `Path`, *optional*):
|
|
64
81
|
Path to the folder where cached files are stored.
|
|
82
|
+
local_dir (`str` or `Path`, *optional*:
|
|
83
|
+
If provided, the downloaded files will be placed under this directory, either as symlinks (default) or
|
|
84
|
+
regular files (see description for more details).
|
|
85
|
+
local_dir_use_symlinks (`"auto"` or `bool`, defaults to `"auto"`):
|
|
86
|
+
To be used with `local_dir`. If set to "auto", the cache directory will be used and the file will be either
|
|
87
|
+
duplicated or symlinked to the local directory depending on its size. It set to `True`, a symlink will be
|
|
88
|
+
created, no matter the file size. If set to `False`, the file will either be duplicated from cache (if
|
|
89
|
+
already exists) or downloaded from the Hub and not cached. See description for more details.
|
|
65
90
|
library_name (`str`, *optional*):
|
|
66
91
|
The name of the library to which the object corresponds.
|
|
67
92
|
library_version (`str`, *optional*):
|
|
@@ -124,14 +149,9 @@ def snapshot_download(
|
|
|
124
149
|
if repo_type is None:
|
|
125
150
|
repo_type = "model"
|
|
126
151
|
if repo_type not in REPO_TYPES:
|
|
127
|
-
raise ValueError(
|
|
128
|
-
f"Invalid repo type: {repo_type}. Accepted repo types are:"
|
|
129
|
-
f" {str(REPO_TYPES)}"
|
|
130
|
-
)
|
|
152
|
+
raise ValueError(f"Invalid repo type: {repo_type}. Accepted repo types are: {str(REPO_TYPES)}")
|
|
131
153
|
|
|
132
|
-
storage_folder = os.path.join(
|
|
133
|
-
cache_dir, repo_folder_name(repo_id=repo_id, repo_type=repo_type)
|
|
134
|
-
)
|
|
154
|
+
storage_folder = os.path.join(cache_dir, repo_folder_name(repo_id=repo_id, repo_type=repo_type))
|
|
135
155
|
|
|
136
156
|
# if we have no internet connection we will look for an
|
|
137
157
|
# appropriate folder in the cache
|
|
@@ -166,9 +186,7 @@ def snapshot_download(
|
|
|
166
186
|
revision=revision,
|
|
167
187
|
token=token,
|
|
168
188
|
)
|
|
169
|
-
assert
|
|
170
|
-
repo_info.sha is not None
|
|
171
|
-
), "Repo info returned from server must have a revision sha."
|
|
189
|
+
assert repo_info.sha is not None, "Repo info returned from server must have a revision sha."
|
|
172
190
|
filtered_repo_files = list(
|
|
173
191
|
filter_repo_objects(
|
|
174
192
|
items=[f.rfilename for f in repo_info.siblings],
|
|
@@ -197,6 +215,8 @@ def snapshot_download(
|
|
|
197
215
|
repo_type=repo_type,
|
|
198
216
|
revision=commit_hash,
|
|
199
217
|
cache_dir=cache_dir,
|
|
218
|
+
local_dir=local_dir,
|
|
219
|
+
local_dir_use_symlinks=local_dir_use_symlinks,
|
|
200
220
|
library_name=library_name,
|
|
201
221
|
library_version=library_version,
|
|
202
222
|
user_agent=user_agent,
|
|
@@ -221,4 +241,6 @@ def snapshot_download(
|
|
|
221
241
|
tqdm_class=tqdm_class or hf_tqdm,
|
|
222
242
|
)
|
|
223
243
|
|
|
244
|
+
if local_dir is not None:
|
|
245
|
+
return str(os.path.realpath(local_dir))
|
|
224
246
|
return snapshot_folder
|
huggingface_hub/_space_api.py
CHANGED
|
@@ -39,6 +39,7 @@ class SpaceStage(str, Enum):
|
|
|
39
39
|
RUNTIME_ERROR = "RUNTIME_ERROR"
|
|
40
40
|
DELETING = "DELETING"
|
|
41
41
|
STOPPED = "STOPPED"
|
|
42
|
+
PAUSED = "PAUSED"
|
|
42
43
|
|
|
43
44
|
|
|
44
45
|
class SpaceHardware(str, Enum):
|
|
@@ -86,3 +87,9 @@ class SpaceRuntime:
|
|
|
86
87
|
hardware: Optional[SpaceHardware]
|
|
87
88
|
requested_hardware: Optional[SpaceHardware]
|
|
88
89
|
raw: Dict
|
|
90
|
+
|
|
91
|
+
def __init__(self, data: Dict) -> None:
|
|
92
|
+
self.stage = data["stage"]
|
|
93
|
+
self.hardware = data["hardware"]["current"]
|
|
94
|
+
self.requested_hardware = data["hardware"]["requested"]
|
|
95
|
+
self.raw = data
|
|
@@ -78,6 +78,7 @@ except ImportError:
|
|
|
78
78
|
|
|
79
79
|
def require_inquirer_py(fn: Callable) -> Callable:
|
|
80
80
|
"""Decorator to flag methods that require `InquirerPy`."""
|
|
81
|
+
|
|
81
82
|
# TODO: refactor this + imports in a unified pattern across codebase
|
|
82
83
|
@wraps(fn)
|
|
83
84
|
def _inner(*args, **kwargs):
|
|
@@ -100,17 +101,13 @@ _CANCEL_DELETION_STR = "CANCEL_DELETION"
|
|
|
100
101
|
class DeleteCacheCommand(BaseHuggingfaceCLICommand):
|
|
101
102
|
@staticmethod
|
|
102
103
|
def register_subcommand(parser: _SubParsersAction):
|
|
103
|
-
delete_cache_parser = parser.add_parser(
|
|
104
|
-
"delete-cache", help="Delete revisions from the cache directory."
|
|
105
|
-
)
|
|
104
|
+
delete_cache_parser = parser.add_parser("delete-cache", help="Delete revisions from the cache directory.")
|
|
106
105
|
|
|
107
106
|
delete_cache_parser.add_argument(
|
|
108
107
|
"--dir",
|
|
109
108
|
type=str,
|
|
110
109
|
default=None,
|
|
111
|
-
help=(
|
|
112
|
-
"cache directory (optional). Default to the default HuggingFace cache."
|
|
113
|
-
),
|
|
110
|
+
help="cache directory (optional). Default to the default HuggingFace cache.",
|
|
114
111
|
)
|
|
115
112
|
|
|
116
113
|
delete_cache_parser.add_argument(
|
|
@@ -141,10 +138,7 @@ class DeleteCacheCommand(BaseHuggingfaceCLICommand):
|
|
|
141
138
|
|
|
142
139
|
# If deletion is not cancelled
|
|
143
140
|
if len(selected_hashes) > 0 and _CANCEL_DELETION_STR not in selected_hashes:
|
|
144
|
-
confirm_message = (
|
|
145
|
-
_get_expectations_str(hf_cache_info, selected_hashes)
|
|
146
|
-
+ " Confirm deletion ?"
|
|
147
|
-
)
|
|
141
|
+
confirm_message = _get_expectations_str(hf_cache_info, selected_hashes) + " Confirm deletion ?"
|
|
148
142
|
|
|
149
143
|
# Confirm deletion
|
|
150
144
|
if self.disable_tui:
|
|
@@ -175,9 +169,7 @@ def _manual_review_tui(hf_cache_info: HFCacheInfo, preselected: List[str]) -> Li
|
|
|
175
169
|
Displays a multi-select menu in the terminal (TUI).
|
|
176
170
|
"""
|
|
177
171
|
# Define multiselect list
|
|
178
|
-
choices = _get_tui_choices_from_scan(
|
|
179
|
-
repos=hf_cache_info.repos, preselected=preselected
|
|
180
|
-
)
|
|
172
|
+
choices = _get_tui_choices_from_scan(repos=hf_cache_info.repos, preselected=preselected)
|
|
181
173
|
checkbox = inquirer.checkbox(
|
|
182
174
|
message="Select revisions to delete:",
|
|
183
175
|
choices=choices, # List of revisions with some pre-selection
|
|
@@ -187,15 +179,10 @@ def _manual_review_tui(hf_cache_info: HFCacheInfo, preselected: List[str]) -> Li
|
|
|
187
179
|
# deletion.
|
|
188
180
|
instruction=_get_expectations_str(
|
|
189
181
|
hf_cache_info,
|
|
190
|
-
selected_hashes=[
|
|
191
|
-
c.value for c in choices if isinstance(c, Choice) and c.enabled
|
|
192
|
-
],
|
|
182
|
+
selected_hashes=[c.value for c in choices if isinstance(c, Choice) and c.enabled],
|
|
193
183
|
),
|
|
194
184
|
# We use the long instruction to should keybindings instructions to the user
|
|
195
|
-
long_instruction=
|
|
196
|
-
"Press <space> to select, <enter> to validate and <ctrl+c> to quit"
|
|
197
|
-
" without modification."
|
|
198
|
-
),
|
|
185
|
+
long_instruction="Press <space> to select, <enter> to validate and <ctrl+c> to quit without modification.",
|
|
199
186
|
# Message that is displayed once the user validates its selection.
|
|
200
187
|
transformer=lambda result: f"{len(result)} revision(s) selected.",
|
|
201
188
|
)
|
|
@@ -207,11 +194,7 @@ def _manual_review_tui(hf_cache_info: HFCacheInfo, preselected: List[str]) -> Li
|
|
|
207
194
|
# a revision hash is selected/unselected.
|
|
208
195
|
checkbox._instruction = _get_expectations_str(
|
|
209
196
|
hf_cache_info,
|
|
210
|
-
selected_hashes=[
|
|
211
|
-
choice["value"]
|
|
212
|
-
for choice in checkbox.content_control.choices
|
|
213
|
-
if choice["enabled"]
|
|
214
|
-
],
|
|
197
|
+
selected_hashes=[choice["value"] for choice in checkbox.content_control.choices if choice["enabled"]],
|
|
215
198
|
)
|
|
216
199
|
|
|
217
200
|
checkbox.kb_func_lookup["toggle"].append({"func": _update_expectations})
|
|
@@ -229,9 +212,7 @@ def _ask_for_confirmation_tui(message: str, default: bool = True) -> bool:
|
|
|
229
212
|
return inquirer.confirm(message, default=default).execute()
|
|
230
213
|
|
|
231
214
|
|
|
232
|
-
def _get_tui_choices_from_scan(
|
|
233
|
-
repos: Iterable[CachedRepoInfo], preselected: List[str]
|
|
234
|
-
) -> List:
|
|
215
|
+
def _get_tui_choices_from_scan(repos: Iterable[CachedRepoInfo], preselected: List[str]) -> List:
|
|
235
216
|
"""Build a list of choices from the scanned repos.
|
|
236
217
|
|
|
237
218
|
Args:
|
|
@@ -282,9 +263,7 @@ def _get_tui_choices_from_scan(
|
|
|
282
263
|
return choices
|
|
283
264
|
|
|
284
265
|
|
|
285
|
-
def _manual_review_no_tui(
|
|
286
|
-
hf_cache_info: HFCacheInfo, preselected: List[str]
|
|
287
|
-
) -> List[str]:
|
|
266
|
+
def _manual_review_no_tui(hf_cache_info: HFCacheInfo, preselected: List[str]) -> List[str]:
|
|
288
267
|
"""Ask the user for a manual review of the revisions to delete.
|
|
289
268
|
|
|
290
269
|
Used when TUI is disabled. Manual review happens in a separate tmp file that the
|
|
@@ -317,7 +296,7 @@ def _manual_review_no_tui(
|
|
|
317
296
|
|
|
318
297
|
# 2. Prompt instructions to user.
|
|
319
298
|
instructions = f"""
|
|
320
|
-
TUI is disabled. In
|
|
299
|
+
TUI is disabled. In order to select which revisions you want to delete, please edit
|
|
321
300
|
the following file using the text editor of your choice. Instructions for manual
|
|
322
301
|
editing are located at the beginning of the file. Edit the file, save it and confirm
|
|
323
302
|
to continue.
|
|
@@ -357,9 +336,7 @@ def _ask_for_confirmation_no_tui(message: str, default: bool = True) -> bool:
|
|
|
357
336
|
print(f"Invalid input. Must be one of {ALL}")
|
|
358
337
|
|
|
359
338
|
|
|
360
|
-
def _get_expectations_str(
|
|
361
|
-
hf_cache_info: HFCacheInfo, selected_hashes: List[str]
|
|
362
|
-
) -> str:
|
|
339
|
+
def _get_expectations_str(hf_cache_info: HFCacheInfo, selected_hashes: List[str]) -> str:
|
|
363
340
|
"""Format a string to display to the user how much space would be saved.
|
|
364
341
|
|
|
365
342
|
Example:
|
|
@@ -371,10 +348,7 @@ def _get_expectations_str(
|
|
|
371
348
|
if _CANCEL_DELETION_STR in selected_hashes:
|
|
372
349
|
return "Nothing will be deleted."
|
|
373
350
|
strategy = hf_cache_info.delete_revisions(*selected_hashes)
|
|
374
|
-
return (
|
|
375
|
-
f"{len(selected_hashes)} revisions selected counting for"
|
|
376
|
-
f" {strategy.expected_freed_size_str}."
|
|
377
|
-
)
|
|
351
|
+
return f"{len(selected_hashes)} revisions selected counting for {strategy.expected_freed_size_str}."
|
|
378
352
|
|
|
379
353
|
|
|
380
354
|
def _read_manual_review_tmp_file(tmp_path: str) -> List[str]:
|
huggingface_hub/commands/env.py
CHANGED
|
@@ -28,9 +28,7 @@ class EnvironmentCommand(BaseHuggingfaceCLICommand):
|
|
|
28
28
|
|
|
29
29
|
@staticmethod
|
|
30
30
|
def register_subcommand(parser: _SubParsersAction):
|
|
31
|
-
env_parser = parser.add_parser(
|
|
32
|
-
"env", help="Print information about the environment."
|
|
33
|
-
)
|
|
31
|
+
env_parser = parser.add_parser("env", help="Print information about the environment.")
|
|
34
32
|
env_parser.set_defaults(func=EnvironmentCommand)
|
|
35
33
|
|
|
36
34
|
def run(self) -> None:
|
|
@@ -23,9 +23,7 @@ from huggingface_hub.commands.user import UserCommands
|
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
def main():
|
|
26
|
-
parser = ArgumentParser(
|
|
27
|
-
"huggingface-cli", usage="huggingface-cli <command> [<args>]"
|
|
28
|
-
)
|
|
26
|
+
parser = ArgumentParser("huggingface-cli", usage="huggingface-cli <command> [<args>]")
|
|
29
27
|
commands_parser = parser.add_subparsers(help="huggingface-cli command helpers")
|
|
30
28
|
|
|
31
29
|
# Register commands
|
huggingface_hub/commands/lfs.py
CHANGED
|
@@ -24,6 +24,7 @@ from argparse import _SubParsersAction
|
|
|
24
24
|
from typing import Dict, List, Optional
|
|
25
25
|
|
|
26
26
|
import requests
|
|
27
|
+
|
|
27
28
|
from huggingface_hub.commands import BaseHuggingfaceCLICommand
|
|
28
29
|
from huggingface_hub.lfs import LFS_MULTIPART_UPLOAD_COMMAND, SliceFileObj
|
|
29
30
|
|
|
@@ -60,9 +61,7 @@ class LfsCommands(BaseHuggingfaceCLICommand):
|
|
|
60
61
|
"lfs-enable-largefiles",
|
|
61
62
|
help="Configure your repository to enable upload of files > 5GB.",
|
|
62
63
|
)
|
|
63
|
-
enable_parser.add_argument(
|
|
64
|
-
"path", type=str, help="Local path to repository you want to configure."
|
|
65
|
-
)
|
|
64
|
+
enable_parser.add_argument("path", type=str, help="Local path to repository you want to configure.")
|
|
66
65
|
enable_parser.set_defaults(func=lambda args: LfsEnableCommand(args))
|
|
67
66
|
|
|
68
67
|
upload_parser = parser.add_parser(
|
|
@@ -87,8 +86,7 @@ class LfsEnableCommand:
|
|
|
87
86
|
cwd=local_path,
|
|
88
87
|
)
|
|
89
88
|
subprocess.run(
|
|
90
|
-
"git config lfs.customtransfer.multipart.args"
|
|
91
|
-
f" {LFS_MULTIPART_UPLOAD_COMMAND}".split(),
|
|
89
|
+
f"git config lfs.customtransfer.multipart.args {LFS_MULTIPART_UPLOAD_COMMAND}".split(),
|
|
92
90
|
check=True,
|
|
93
91
|
cwd=local_path,
|
|
94
92
|
)
|
|
@@ -126,9 +124,7 @@ class LfsUploadCommand:
|
|
|
126
124
|
# sends initiation data to the process over stdin.
|
|
127
125
|
# This tells the process useful information about the configuration.
|
|
128
126
|
init_msg = json.loads(sys.stdin.readline().strip())
|
|
129
|
-
if not (
|
|
130
|
-
init_msg.get("event") == "init" and init_msg.get("operation") == "upload"
|
|
131
|
-
):
|
|
127
|
+
if not (init_msg.get("event") == "init" and init_msg.get("operation") == "upload"):
|
|
132
128
|
write_msg({"error": {"code": 32, "message": "Wrong lfs init operation"}})
|
|
133
129
|
sys.exit(1)
|
|
134
130
|
|
|
@@ -32,18 +32,13 @@ from ._cli_utils import ANSI, tabulate
|
|
|
32
32
|
class ScanCacheCommand(BaseHuggingfaceCLICommand):
|
|
33
33
|
@staticmethod
|
|
34
34
|
def register_subcommand(parser: _SubParsersAction):
|
|
35
|
-
scan_cache_parser = parser.add_parser(
|
|
36
|
-
"scan-cache", help="Scan cache directory."
|
|
37
|
-
)
|
|
35
|
+
scan_cache_parser = parser.add_parser("scan-cache", help="Scan cache directory.")
|
|
38
36
|
|
|
39
37
|
scan_cache_parser.add_argument(
|
|
40
38
|
"--dir",
|
|
41
39
|
type=str,
|
|
42
40
|
default=None,
|
|
43
|
-
help=(
|
|
44
|
-
"cache directory to scan (optional). Default to the"
|
|
45
|
-
" default HuggingFace cache."
|
|
46
|
-
),
|
|
41
|
+
help="cache directory to scan (optional). Default to the default HuggingFace cache.",
|
|
47
42
|
)
|
|
48
43
|
scan_cache_parser.add_argument(
|
|
49
44
|
"-v",
|
|
@@ -98,9 +93,7 @@ class ScanCacheCommand(BaseHuggingfaceCLICommand):
|
|
|
98
93
|
", ".join(sorted(repo.refs)),
|
|
99
94
|
str(repo.repo_path),
|
|
100
95
|
]
|
|
101
|
-
for repo in sorted(
|
|
102
|
-
hf_cache_info.repos, key=lambda repo: repo.repo_path
|
|
103
|
-
)
|
|
96
|
+
for repo in sorted(hf_cache_info.repos, key=lambda repo: repo.repo_path)
|
|
104
97
|
],
|
|
105
98
|
headers=[
|
|
106
99
|
"REPO ID",
|
|
@@ -128,12 +121,8 @@ class ScanCacheCommand(BaseHuggingfaceCLICommand):
|
|
|
128
121
|
", ".join(sorted(revision.refs)),
|
|
129
122
|
str(revision.snapshot_path),
|
|
130
123
|
]
|
|
131
|
-
for repo in sorted(
|
|
132
|
-
|
|
133
|
-
)
|
|
134
|
-
for revision in sorted(
|
|
135
|
-
repo.revisions, key=lambda revision: revision.commit_hash
|
|
136
|
-
)
|
|
124
|
+
for repo in sorted(hf_cache_info.repos, key=lambda repo: repo.repo_path)
|
|
125
|
+
for revision in sorted(repo.revisions, key=lambda revision: revision.commit_hash)
|
|
137
126
|
],
|
|
138
127
|
headers=[
|
|
139
128
|
"REPO ID",
|
huggingface_hub/commands/user.py
CHANGED
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
import subprocess
|
|
15
15
|
from argparse import _SubParsersAction
|
|
16
16
|
|
|
17
|
+
from requests.exceptions import HTTPError
|
|
18
|
+
|
|
17
19
|
from huggingface_hub.commands import BaseHuggingfaceCLICommand
|
|
18
20
|
from huggingface_hub.constants import (
|
|
19
21
|
ENDPOINT,
|
|
@@ -22,21 +24,18 @@ from huggingface_hub.constants import (
|
|
|
22
24
|
SPACES_SDK_TYPES,
|
|
23
25
|
)
|
|
24
26
|
from huggingface_hub.hf_api import HfApi
|
|
25
|
-
from requests.exceptions import HTTPError
|
|
26
27
|
|
|
27
|
-
from .._login import ( # noqa: F401 # for backward compatibility
|
|
28
|
+
from .._login import ( # noqa: F401 # for backward compatibility # noqa: F401 # for backward compatibility
|
|
28
29
|
NOTEBOOK_LOGIN_PASSWORD_HTML,
|
|
29
30
|
NOTEBOOK_LOGIN_TOKEN_HTML_END,
|
|
30
31
|
NOTEBOOK_LOGIN_TOKEN_HTML_START,
|
|
31
|
-
)
|
|
32
|
-
from .._login import ( # noqa: F401 # for backward compatibility
|
|
33
|
-
_currently_setup_credential_helpers as currently_setup_credential_helpers,
|
|
34
|
-
)
|
|
35
|
-
from .._login import ( # noqa: F401 # for backward compatibility
|
|
36
32
|
login,
|
|
37
33
|
logout,
|
|
38
34
|
notebook_login,
|
|
39
35
|
)
|
|
36
|
+
from .._login import (
|
|
37
|
+
_currently_setup_credential_helpers as currently_setup_credential_helpers, # noqa: F401 # for backward compatibility
|
|
38
|
+
)
|
|
40
39
|
from ..utils import HfFolder
|
|
41
40
|
from ._cli_utils import ANSI
|
|
42
41
|
|
|
@@ -44,13 +43,19 @@ from ._cli_utils import ANSI
|
|
|
44
43
|
class UserCommands(BaseHuggingfaceCLICommand):
|
|
45
44
|
@staticmethod
|
|
46
45
|
def register_subcommand(parser: _SubParsersAction):
|
|
47
|
-
login_parser = parser.add_parser(
|
|
48
|
-
|
|
46
|
+
login_parser = parser.add_parser("login", help="Log in using a token from huggingface.co/settings/tokens")
|
|
47
|
+
login_parser.add_argument(
|
|
48
|
+
"--token",
|
|
49
|
+
type=str,
|
|
50
|
+
help="Token generated from https://huggingface.co/settings/tokens",
|
|
49
51
|
)
|
|
50
|
-
login_parser.
|
|
51
|
-
|
|
52
|
-
"
|
|
52
|
+
login_parser.add_argument(
|
|
53
|
+
"--add-to-git-credential",
|
|
54
|
+
action="store_true",
|
|
55
|
+
help="Optional: Save token to git credential helper.",
|
|
53
56
|
)
|
|
57
|
+
login_parser.set_defaults(func=lambda args: LoginCommand(args))
|
|
58
|
+
whoami_parser = parser.add_parser("whoami", help="Find out which huggingface.co account you are logged in as.")
|
|
54
59
|
whoami_parser.set_defaults(func=lambda args: WhoamiCommand(args))
|
|
55
60
|
logout_parser = parser.add_parser("logout", help="Log out")
|
|
56
61
|
logout_parser.set_defaults(func=lambda args: LogoutCommand(args))
|
|
@@ -58,43 +63,25 @@ class UserCommands(BaseHuggingfaceCLICommand):
|
|
|
58
63
|
# new system: git-based repo system
|
|
59
64
|
repo_parser = parser.add_parser(
|
|
60
65
|
"repo",
|
|
61
|
-
help=
|
|
62
|
-
"{create, ls-files} Commands to interact with your huggingface.co"
|
|
63
|
-
" repos."
|
|
64
|
-
),
|
|
65
|
-
)
|
|
66
|
-
repo_subparsers = repo_parser.add_subparsers(
|
|
67
|
-
help="huggingface.co repos related commands"
|
|
68
|
-
)
|
|
69
|
-
repo_create_parser = repo_subparsers.add_parser(
|
|
70
|
-
"create", help="Create a new repo on huggingface.co"
|
|
66
|
+
help="{create, ls-files} Commands to interact with your huggingface.co repos.",
|
|
71
67
|
)
|
|
68
|
+
repo_subparsers = repo_parser.add_subparsers(help="huggingface.co repos related commands")
|
|
69
|
+
repo_create_parser = repo_subparsers.add_parser("create", help="Create a new repo on huggingface.co")
|
|
72
70
|
repo_create_parser.add_argument(
|
|
73
71
|
"name",
|
|
74
72
|
type=str,
|
|
75
|
-
help=
|
|
76
|
-
"Name for your repo. Will be namespaced under your username to build"
|
|
77
|
-
" the repo id."
|
|
78
|
-
),
|
|
73
|
+
help="Name for your repo. Will be namespaced under your username to build the repo id.",
|
|
79
74
|
)
|
|
80
75
|
repo_create_parser.add_argument(
|
|
81
76
|
"--type",
|
|
82
77
|
type=str,
|
|
83
|
-
help=
|
|
84
|
-
'Optional: repo_type: set to "dataset" or "space" if creating a dataset'
|
|
85
|
-
" or space, default is model."
|
|
86
|
-
),
|
|
87
|
-
)
|
|
88
|
-
repo_create_parser.add_argument(
|
|
89
|
-
"--organization", type=str, help="Optional: organization namespace."
|
|
78
|
+
help='Optional: repo_type: set to "dataset" or "space" if creating a dataset or space, default is model.',
|
|
90
79
|
)
|
|
80
|
+
repo_create_parser.add_argument("--organization", type=str, help="Optional: organization namespace.")
|
|
91
81
|
repo_create_parser.add_argument(
|
|
92
82
|
"--space_sdk",
|
|
93
83
|
type=str,
|
|
94
|
-
help=
|
|
95
|
-
"Optional: Hugging Face Spaces SDK type. Required when --type is set to"
|
|
96
|
-
' "space".'
|
|
97
|
-
),
|
|
84
|
+
help='Optional: Hugging Face Spaces SDK type. Required when --type is set to "space".',
|
|
98
85
|
choices=SPACES_SDK_TYPES,
|
|
99
86
|
)
|
|
100
87
|
repo_create_parser.add_argument(
|
|
@@ -114,7 +101,7 @@ class BaseUserCommand:
|
|
|
114
101
|
|
|
115
102
|
class LoginCommand(BaseUserCommand):
|
|
116
103
|
def run(self):
|
|
117
|
-
login()
|
|
104
|
+
login(token=self.args.token, add_to_git_credential=self.args.add_to_git_credential)
|
|
118
105
|
|
|
119
106
|
|
|
120
107
|
class LogoutCommand(BaseUserCommand):
|
|
@@ -169,9 +156,7 @@ class RepoCreateCommand(BaseUserCommand):
|
|
|
169
156
|
print("")
|
|
170
157
|
|
|
171
158
|
user = self._api.whoami(token)["name"]
|
|
172
|
-
namespace =
|
|
173
|
-
self.args.organization if self.args.organization is not None else user
|
|
174
|
-
)
|
|
159
|
+
namespace = self.args.organization if self.args.organization is not None else user
|
|
175
160
|
|
|
176
161
|
repo_id = f"{namespace}/{self.args.name}"
|
|
177
162
|
|
|
@@ -204,9 +189,6 @@ class RepoCreateCommand(BaseUserCommand):
|
|
|
204
189
|
exit(1)
|
|
205
190
|
print("\nYour repo now lives at:")
|
|
206
191
|
print(f" {ANSI.bold(url)}")
|
|
207
|
-
print(
|
|
208
|
-
"\nYou can clone it locally with the command below,"
|
|
209
|
-
" and commit/push as usual."
|
|
210
|
-
)
|
|
192
|
+
print("\nYou can clone it locally with the command below, and commit/push as usual.")
|
|
211
193
|
print(f"\n git clone {url}")
|
|
212
194
|
print("")
|
huggingface_hub/community.py
CHANGED
|
@@ -44,7 +44,7 @@ class Discussion:
|
|
|
44
44
|
The username of the Discussion / Pull Request author.
|
|
45
45
|
Can be `"deleted"` if the user has been deleted since.
|
|
46
46
|
is_pull_request (`bool`):
|
|
47
|
-
|
|
47
|
+
Whether or not this is a Pull Request.
|
|
48
48
|
created_at (`datetime`):
|
|
49
49
|
The `datetime` of creation of the Discussion / Pull Request.
|
|
50
50
|
"""
|
|
@@ -96,7 +96,7 @@ class DiscussionWithDetails(Discussion):
|
|
|
96
96
|
The username of the Discussion / Pull Request author.
|
|
97
97
|
Can be `"deleted"` if the user has been deleted since.
|
|
98
98
|
is_pull_request (`bool`):
|
|
99
|
-
|
|
99
|
+
Whether or not this is a Pull Request.
|
|
100
100
|
created_at (`datetime`):
|
|
101
101
|
The `datetime` of creation of the Discussion / Pull Request.
|
|
102
102
|
events (`list` of [`DiscussionEvent`])
|
|
@@ -175,7 +175,7 @@ class DiscussionComment(DiscussionEvent):
|
|
|
175
175
|
content (`str`):
|
|
176
176
|
The raw markdown content of the comment. Mentions, links and images are not rendered.
|
|
177
177
|
edited (`bool`):
|
|
178
|
-
|
|
178
|
+
Whether or not this comment has been edited.
|
|
179
179
|
hidden (`bool`):
|
|
180
180
|
Whether or not this comment has been hidden.
|
|
181
181
|
"""
|
|
@@ -196,7 +196,7 @@ class DiscussionComment(DiscussionEvent):
|
|
|
196
196
|
|
|
197
197
|
@property
|
|
198
198
|
def last_edited_by(self) -> str:
|
|
199
|
-
"""The last edit
|
|
199
|
+
"""The last edit time, as a `datetime` object."""
|
|
200
200
|
return self._event["data"]["latest"].get("author", {}).get("name", "deleted")
|
|
201
201
|
|
|
202
202
|
@property
|
huggingface_hub/constants.py
CHANGED
|
@@ -15,10 +15,10 @@ def _is_true(value: Optional[str]) -> bool:
|
|
|
15
15
|
return value.upper() in ENV_VARS_TRUE_VALUES
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
def
|
|
18
|
+
def _as_int(value: Optional[str]) -> Optional[int]:
|
|
19
19
|
if value is None:
|
|
20
|
-
return
|
|
21
|
-
return value
|
|
20
|
+
return None
|
|
21
|
+
return int(value)
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
# Constants for file downloads
|
|
@@ -39,15 +39,15 @@ HUGGINGFACE_CO_URL_HOME = "https://huggingface.co/"
|
|
|
39
39
|
|
|
40
40
|
_staging_mode = _is_true(os.environ.get("HUGGINGFACE_CO_STAGING"))
|
|
41
41
|
|
|
42
|
-
ENDPOINT = os.getenv("HF_ENDPOINT") or (
|
|
43
|
-
"https://hub-ci.huggingface.co" if _staging_mode else "https://huggingface.co"
|
|
44
|
-
)
|
|
42
|
+
ENDPOINT = os.getenv("HF_ENDPOINT") or ("https://hub-ci.huggingface.co" if _staging_mode else "https://huggingface.co")
|
|
45
43
|
|
|
46
44
|
HUGGINGFACE_CO_URL_TEMPLATE = ENDPOINT + "/{repo_id}/resolve/{revision}/{filename}"
|
|
47
45
|
HUGGINGFACE_HEADER_X_REPO_COMMIT = "X-Repo-Commit"
|
|
48
46
|
HUGGINGFACE_HEADER_X_LINKED_ETAG = "X-Linked-Etag"
|
|
49
47
|
HUGGINGFACE_HEADER_X_LINKED_SIZE = "X-Linked-Size"
|
|
50
48
|
|
|
49
|
+
INFERENCE_ENDPOINT = os.environ.get("HF_INFERENCE_ENDPOINT", "https://api-inference.huggingface.co")
|
|
50
|
+
|
|
51
51
|
REPO_ID_SEPARATOR = "--"
|
|
52
52
|
# ^ this substring is not allowed in repo_ids on hf.co
|
|
53
53
|
# and is the canonical one we use for serialization of repo ids elsewhere.
|
|
@@ -83,11 +83,12 @@ default_cache_path = os.path.join(hf_cache_home, "hub")
|
|
|
83
83
|
default_assets_cache_path = os.path.join(hf_cache_home, "assets")
|
|
84
84
|
|
|
85
85
|
HUGGINGFACE_HUB_CACHE = os.getenv("HUGGINGFACE_HUB_CACHE", default_cache_path)
|
|
86
|
-
HUGGINGFACE_ASSETS_CACHE = os.getenv(
|
|
87
|
-
|
|
88
|
-
)
|
|
86
|
+
HUGGINGFACE_ASSETS_CACHE = os.getenv("HUGGINGFACE_ASSETS_CACHE", default_assets_cache_path)
|
|
87
|
+
|
|
88
|
+
HF_HUB_OFFLINE = _is_true(os.environ.get("HF_HUB_OFFLINE") or os.environ.get("TRANSFORMERS_OFFLINE"))
|
|
89
89
|
|
|
90
|
-
|
|
90
|
+
# Opt-out from telemetry requests
|
|
91
|
+
HF_HUB_DISABLE_TELEMETRY = _is_true(os.environ.get("HF_HUB_DISABLE_TELEMETRY") or os.environ.get("DISABLE_TELEMETRY"))
|
|
91
92
|
|
|
92
93
|
# In the past, token was stored in a hardcoded location
|
|
93
94
|
# `_OLD_HF_TOKEN_PATH` is deprecated and will be removed "at some point".
|
|
@@ -103,23 +104,25 @@ HF_TOKEN_PATH = os.path.join(hf_cache_home, "token")
|
|
|
103
104
|
# TL;DR: env variable has priority over code
|
|
104
105
|
__HF_HUB_DISABLE_PROGRESS_BARS = os.environ.get("HF_HUB_DISABLE_PROGRESS_BARS")
|
|
105
106
|
HF_HUB_DISABLE_PROGRESS_BARS: Optional[bool] = (
|
|
106
|
-
_is_true(__HF_HUB_DISABLE_PROGRESS_BARS)
|
|
107
|
-
if __HF_HUB_DISABLE_PROGRESS_BARS is not None
|
|
108
|
-
else None
|
|
107
|
+
_is_true(__HF_HUB_DISABLE_PROGRESS_BARS) if __HF_HUB_DISABLE_PROGRESS_BARS is not None else None
|
|
109
108
|
)
|
|
110
109
|
|
|
111
110
|
# Disable warning on machines that do not support symlinks (e.g. Windows non-developer)
|
|
112
|
-
HF_HUB_DISABLE_SYMLINKS_WARNING: bool = _is_true(
|
|
113
|
-
os.environ.get("HF_HUB_DISABLE_SYMLINKS_WARNING")
|
|
114
|
-
)
|
|
111
|
+
HF_HUB_DISABLE_SYMLINKS_WARNING: bool = _is_true(os.environ.get("HF_HUB_DISABLE_SYMLINKS_WARNING"))
|
|
115
112
|
|
|
116
113
|
# Disable sending the cached token by default is all HTTP requests to the Hub
|
|
117
|
-
HF_HUB_DISABLE_IMPLICIT_TOKEN: bool = _is_true(
|
|
118
|
-
os.environ.get("HF_HUB_DISABLE_IMPLICIT_TOKEN")
|
|
119
|
-
)
|
|
114
|
+
HF_HUB_DISABLE_IMPLICIT_TOKEN: bool = _is_true(os.environ.get("HF_HUB_DISABLE_IMPLICIT_TOKEN"))
|
|
120
115
|
|
|
121
116
|
# Enable fast-download using external dependency "hf_transfer"
|
|
122
117
|
# See:
|
|
123
118
|
# - https://pypi.org/project/hf-transfer/
|
|
124
119
|
# - https://github.com/huggingface/hf_transfer (private)
|
|
125
120
|
HF_HUB_ENABLE_HF_TRANSFER: bool = _is_true(os.environ.get("HF_HUB_ENABLE_HF_TRANSFER"))
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
# Used if download to `local_dir` and `local_dir_use_symlinks="auto"`
|
|
124
|
+
# Files smaller than 5MB are copy-pasted while bigger files are symlinked. The idea is to save disk-usage by symlinking
|
|
125
|
+
# huge files (i.e. LFS files most of the time) while allowing small files to be manually edited in local folder.
|
|
126
|
+
HF_HUB_LOCAL_DIR_AUTO_SYMLINK_THRESHOLD: int = (
|
|
127
|
+
_as_int(os.environ.get("HF_HUB_LOCAL_DIR_AUTO_SYMLINK_THRESHOLD")) or 5 * 1024 * 1024
|
|
128
|
+
)
|