huggingface-hub 1.0.0rc2__py3-none-any.whl → 1.0.0rc3__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.

Potentially problematic release.


This version of huggingface-hub might be problematic. Click here for more details.

Files changed (44) hide show
  1. huggingface_hub/__init__.py +4 -7
  2. huggingface_hub/_login.py +2 -2
  3. huggingface_hub/_snapshot_download.py +119 -21
  4. huggingface_hub/_upload_large_folder.py +1 -2
  5. huggingface_hub/cli/_cli_utils.py +12 -6
  6. huggingface_hub/cli/download.py +32 -7
  7. huggingface_hub/dataclasses.py +132 -3
  8. huggingface_hub/errors.py +4 -0
  9. huggingface_hub/file_download.py +216 -17
  10. huggingface_hub/hf_api.py +127 -14
  11. huggingface_hub/hf_file_system.py +38 -21
  12. huggingface_hub/inference/_client.py +3 -2
  13. huggingface_hub/inference/_generated/_async_client.py +3 -2
  14. huggingface_hub/inference/_generated/types/image_to_image.py +6 -2
  15. huggingface_hub/inference/_mcp/mcp_client.py +4 -3
  16. huggingface_hub/inference/_providers/__init__.py +5 -0
  17. huggingface_hub/inference/_providers/_common.py +1 -0
  18. huggingface_hub/inference/_providers/fal_ai.py +2 -0
  19. huggingface_hub/inference/_providers/zai_org.py +17 -0
  20. huggingface_hub/utils/__init__.py +1 -2
  21. huggingface_hub/utils/_cache_manager.py +1 -1
  22. huggingface_hub/utils/_http.py +10 -38
  23. huggingface_hub/utils/_validators.py +2 -2
  24. {huggingface_hub-1.0.0rc2.dist-info → huggingface_hub-1.0.0rc3.dist-info}/METADATA +1 -1
  25. {huggingface_hub-1.0.0rc2.dist-info → huggingface_hub-1.0.0rc3.dist-info}/RECORD +29 -43
  26. {huggingface_hub-1.0.0rc2.dist-info → huggingface_hub-1.0.0rc3.dist-info}/entry_points.txt +0 -1
  27. huggingface_hub/commands/__init__.py +0 -27
  28. huggingface_hub/commands/_cli_utils.py +0 -74
  29. huggingface_hub/commands/delete_cache.py +0 -476
  30. huggingface_hub/commands/download.py +0 -195
  31. huggingface_hub/commands/env.py +0 -39
  32. huggingface_hub/commands/huggingface_cli.py +0 -65
  33. huggingface_hub/commands/lfs.py +0 -200
  34. huggingface_hub/commands/repo.py +0 -151
  35. huggingface_hub/commands/repo_files.py +0 -132
  36. huggingface_hub/commands/scan_cache.py +0 -183
  37. huggingface_hub/commands/tag.py +0 -159
  38. huggingface_hub/commands/upload.py +0 -318
  39. huggingface_hub/commands/upload_large_folder.py +0 -131
  40. huggingface_hub/commands/user.py +0 -207
  41. huggingface_hub/commands/version.py +0 -40
  42. {huggingface_hub-1.0.0rc2.dist-info → huggingface_hub-1.0.0rc3.dist-info}/LICENSE +0 -0
  43. {huggingface_hub-1.0.0rc2.dist-info → huggingface_hub-1.0.0rc3.dist-info}/WHEEL +0 -0
  44. {huggingface_hub-1.0.0rc2.dist-info → huggingface_hub-1.0.0rc3.dist-info}/top_level.txt +0 -0
@@ -1,318 +0,0 @@
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 with wildcard
34
- huggingface-cli upload my-cool-model "./model/training/*.safetensors"
35
-
36
- # Upload private dataset
37
- huggingface-cli upload Wauplin/my-cool-dataset ./data . --repo-type=dataset --private
38
-
39
- # Upload with token
40
- huggingface-cli upload Wauplin/my-cool-model --token=hf_****
41
-
42
- # Sync local Space with Hub (upload new files, delete removed files)
43
- huggingface-cli upload Wauplin/space-example --repo-type=space --exclude="/logs/*" --delete="*" --commit-message="Sync local Space with Hub"
44
-
45
- # Schedule commits every 30 minutes
46
- huggingface-cli upload Wauplin/my-cool-model --every=30
47
- """
48
-
49
- import os
50
- import time
51
- import warnings
52
- from argparse import Namespace, _SubParsersAction
53
- from typing import Optional
54
-
55
- from huggingface_hub import logging
56
- from huggingface_hub._commit_scheduler import CommitScheduler
57
- from huggingface_hub.commands import BaseHuggingfaceCLICommand
58
- from huggingface_hub.constants import HF_HUB_ENABLE_HF_TRANSFER
59
- from huggingface_hub.errors import RevisionNotFoundError
60
- from huggingface_hub.hf_api import HfApi
61
- from huggingface_hub.utils import disable_progress_bars, enable_progress_bars
62
- from huggingface_hub.utils._runtime import is_xet_available
63
-
64
- from ._cli_utils import show_deprecation_warning
65
-
66
-
67
- logger = logging.get_logger(__name__)
68
-
69
-
70
- class UploadCommand(BaseHuggingfaceCLICommand):
71
- @staticmethod
72
- def register_subcommand(parser: _SubParsersAction):
73
- upload_parser = parser.add_parser("upload", help="Upload a file or a folder to a repo on the Hub")
74
- upload_parser.add_argument(
75
- "repo_id", type=str, help="The ID of the repo to upload to (e.g. `username/repo-name`)."
76
- )
77
- upload_parser.add_argument(
78
- "local_path",
79
- nargs="?",
80
- help="Local path to the file or folder to upload. Wildcard patterns are supported. Defaults to current directory.",
81
- )
82
- upload_parser.add_argument(
83
- "path_in_repo",
84
- nargs="?",
85
- help="Path of the file or folder in the repo. Defaults to the relative path of the file or folder.",
86
- )
87
- upload_parser.add_argument(
88
- "--repo-type",
89
- choices=["model", "dataset", "space"],
90
- default="model",
91
- help="Type of the repo to upload to (e.g. `dataset`).",
92
- )
93
- upload_parser.add_argument(
94
- "--revision",
95
- type=str,
96
- help=(
97
- "An optional Git revision to push to. It can be a branch name or a PR reference. If revision does not"
98
- " exist and `--create-pr` is not set, a branch will be automatically created."
99
- ),
100
- )
101
- upload_parser.add_argument(
102
- "--private",
103
- action="store_true",
104
- help=(
105
- "Whether to create a private repo if repo doesn't exist on the Hub. Ignored if the repo already"
106
- " exists."
107
- ),
108
- )
109
- upload_parser.add_argument("--include", nargs="*", type=str, help="Glob patterns to match files to upload.")
110
- upload_parser.add_argument(
111
- "--exclude", nargs="*", type=str, help="Glob patterns to exclude from files to upload."
112
- )
113
- upload_parser.add_argument(
114
- "--delete",
115
- nargs="*",
116
- type=str,
117
- help="Glob patterns for file to be deleted from the repo while committing.",
118
- )
119
- upload_parser.add_argument(
120
- "--commit-message", type=str, help="The summary / title / first line of the generated commit."
121
- )
122
- upload_parser.add_argument("--commit-description", type=str, help="The description of the generated commit.")
123
- upload_parser.add_argument(
124
- "--create-pr", action="store_true", help="Whether to upload content as a new Pull Request."
125
- )
126
- upload_parser.add_argument(
127
- "--every",
128
- type=float,
129
- help="If set, a background job is scheduled to create commits every `every` minutes.",
130
- )
131
- upload_parser.add_argument(
132
- "--token", type=str, help="A User Access Token generated from https://huggingface.co/settings/tokens"
133
- )
134
- upload_parser.add_argument(
135
- "--quiet",
136
- action="store_true",
137
- help="If True, progress bars are disabled and only the path to the uploaded files is printed.",
138
- )
139
- upload_parser.set_defaults(func=UploadCommand)
140
-
141
- def __init__(self, args: Namespace) -> None:
142
- self.repo_id: str = args.repo_id
143
- self.repo_type: Optional[str] = args.repo_type
144
- self.revision: Optional[str] = args.revision
145
- self.private: bool = args.private
146
-
147
- self.include: Optional[list[str]] = args.include
148
- self.exclude: Optional[list[str]] = args.exclude
149
- self.delete: Optional[list[str]] = args.delete
150
-
151
- self.commit_message: Optional[str] = args.commit_message
152
- self.commit_description: Optional[str] = args.commit_description
153
- self.create_pr: bool = args.create_pr
154
- self.api: HfApi = HfApi(token=args.token, library_name="huggingface-cli")
155
- self.quiet: bool = args.quiet # disable warnings and progress bars
156
-
157
- # Check `--every` is valid
158
- if args.every is not None and args.every <= 0:
159
- raise ValueError(f"`every` must be a positive value (got '{args.every}')")
160
- self.every: Optional[float] = args.every
161
-
162
- # Resolve `local_path` and `path_in_repo`
163
- repo_name: str = args.repo_id.split("/")[-1] # e.g. "Wauplin/my-cool-model" => "my-cool-model"
164
- self.local_path: str
165
- self.path_in_repo: str
166
-
167
- if args.local_path is not None and any(c in args.local_path for c in ["*", "?", "["]):
168
- if args.include is not None:
169
- raise ValueError("Cannot set `--include` when passing a `local_path` containing a wildcard.")
170
- if args.path_in_repo is not None and args.path_in_repo != ".":
171
- raise ValueError("Cannot set `path_in_repo` when passing a `local_path` containing a wildcard.")
172
- self.local_path = "."
173
- self.include = args.local_path
174
- self.path_in_repo = "."
175
- elif args.local_path is None and os.path.isfile(repo_name):
176
- # Implicit case 1: user provided only a repo_id which happen to be a local file as well => upload it with same name
177
- self.local_path = repo_name
178
- self.path_in_repo = repo_name
179
- elif args.local_path is None and os.path.isdir(repo_name):
180
- # Implicit case 2: user provided only a repo_id which happen to be a local folder as well => upload it at root
181
- self.local_path = repo_name
182
- self.path_in_repo = "."
183
- elif args.local_path is None:
184
- # Implicit case 3: user provided only a repo_id that does not match a local file or folder
185
- # => the user must explicitly provide a local_path => raise exception
186
- raise ValueError(f"'{repo_name}' is not a local file or folder. Please set `local_path` explicitly.")
187
- elif args.path_in_repo is None and os.path.isfile(args.local_path):
188
- # Explicit local path to file, no path in repo => upload it at root with same name
189
- self.local_path = args.local_path
190
- self.path_in_repo = os.path.basename(args.local_path)
191
- elif args.path_in_repo is None:
192
- # Explicit local path to folder, no path in repo => upload at root
193
- self.local_path = args.local_path
194
- self.path_in_repo = "."
195
- else:
196
- # Finally, if both paths are explicit
197
- self.local_path = args.local_path
198
- self.path_in_repo = args.path_in_repo
199
-
200
- def run(self) -> None:
201
- show_deprecation_warning("huggingface-cli upload", "hf upload")
202
-
203
- if self.quiet:
204
- disable_progress_bars()
205
- with warnings.catch_warnings():
206
- warnings.simplefilter("ignore")
207
- print(self._upload())
208
- enable_progress_bars()
209
- else:
210
- logging.set_verbosity_info()
211
- print(self._upload())
212
- logging.set_verbosity_warning()
213
-
214
- def _upload(self) -> str:
215
- if os.path.isfile(self.local_path):
216
- if self.include is not None and len(self.include) > 0:
217
- warnings.warn("Ignoring `--include` since a single file is uploaded.")
218
- if self.exclude is not None and len(self.exclude) > 0:
219
- warnings.warn("Ignoring `--exclude` since a single file is uploaded.")
220
- if self.delete is not None and len(self.delete) > 0:
221
- warnings.warn("Ignoring `--delete` since a single file is uploaded.")
222
-
223
- if not is_xet_available() and not HF_HUB_ENABLE_HF_TRANSFER:
224
- logger.info(
225
- "Consider using `hf_transfer` for faster uploads. This solution comes with some limitations. See"
226
- " https://huggingface.co/docs/huggingface_hub/hf_transfer for more details."
227
- )
228
-
229
- # Schedule commits if `every` is set
230
- if self.every is not None:
231
- if os.path.isfile(self.local_path):
232
- # If file => watch entire folder + use allow_patterns
233
- folder_path = os.path.dirname(self.local_path)
234
- path_in_repo = (
235
- self.path_in_repo[: -len(self.local_path)] # remove filename from path_in_repo
236
- if self.path_in_repo.endswith(self.local_path)
237
- else self.path_in_repo
238
- )
239
- allow_patterns = [self.local_path]
240
- ignore_patterns = []
241
- else:
242
- folder_path = self.local_path
243
- path_in_repo = self.path_in_repo
244
- allow_patterns = self.include or []
245
- ignore_patterns = self.exclude or []
246
- if self.delete is not None and len(self.delete) > 0:
247
- warnings.warn("Ignoring `--delete` when uploading with scheduled commits.")
248
-
249
- scheduler = CommitScheduler(
250
- folder_path=folder_path,
251
- repo_id=self.repo_id,
252
- repo_type=self.repo_type,
253
- revision=self.revision,
254
- allow_patterns=allow_patterns,
255
- ignore_patterns=ignore_patterns,
256
- path_in_repo=path_in_repo,
257
- private=self.private,
258
- every=self.every,
259
- hf_api=self.api,
260
- )
261
- print(f"Scheduling commits every {self.every} minutes to {scheduler.repo_id}.")
262
- try: # Block main thread until KeyboardInterrupt
263
- while True:
264
- time.sleep(100)
265
- except KeyboardInterrupt:
266
- scheduler.stop()
267
- return "Stopped scheduled commits."
268
-
269
- # Otherwise, create repo and proceed with the upload
270
- if not os.path.isfile(self.local_path) and not os.path.isdir(self.local_path):
271
- raise FileNotFoundError(f"No such file or directory: '{self.local_path}'.")
272
- repo_id = self.api.create_repo(
273
- repo_id=self.repo_id,
274
- repo_type=self.repo_type,
275
- exist_ok=True,
276
- private=self.private,
277
- space_sdk="gradio" if self.repo_type == "space" else None,
278
- # ^ We don't want it to fail when uploading to a Space => let's set Gradio by default.
279
- # ^ I'd rather not add CLI args to set it explicitly as we already have `huggingface-cli repo create` for that.
280
- ).repo_id
281
-
282
- # Check if branch already exists and if not, create it
283
- if self.revision is not None and not self.create_pr:
284
- try:
285
- self.api.repo_info(repo_id=repo_id, repo_type=self.repo_type, revision=self.revision)
286
- except RevisionNotFoundError:
287
- logger.info(f"Branch '{self.revision}' not found. Creating it...")
288
- self.api.create_branch(repo_id=repo_id, repo_type=self.repo_type, branch=self.revision, exist_ok=True)
289
- # ^ `exist_ok=True` to avoid race concurrency issues
290
-
291
- # File-based upload
292
- if os.path.isfile(self.local_path):
293
- return self.api.upload_file(
294
- path_or_fileobj=self.local_path,
295
- path_in_repo=self.path_in_repo,
296
- repo_id=repo_id,
297
- repo_type=self.repo_type,
298
- revision=self.revision,
299
- commit_message=self.commit_message,
300
- commit_description=self.commit_description,
301
- create_pr=self.create_pr,
302
- )
303
-
304
- # Folder-based upload
305
- else:
306
- return self.api.upload_folder(
307
- folder_path=self.local_path,
308
- path_in_repo=self.path_in_repo,
309
- repo_id=repo_id,
310
- repo_type=self.repo_type,
311
- revision=self.revision,
312
- commit_message=self.commit_message,
313
- commit_description=self.commit_description,
314
- create_pr=self.create_pr,
315
- allow_patterns=self.include,
316
- ignore_patterns=self.exclude,
317
- delete_patterns=self.delete,
318
- )
@@ -1,131 +0,0 @@
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 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, show_deprecation_warning
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
- show_deprecation_warning("huggingface-cli upload-large-folder", "hf upload-large-folder")
90
-
91
- logging.set_verbosity_info()
92
-
93
- print(
94
- ANSI.yellow(
95
- "You are about to upload a large folder to the Hub using `huggingface-cli upload-large-folder`. "
96
- "This is a new feature so feedback is very welcome!\n"
97
- "\n"
98
- "A few things to keep in mind:\n"
99
- " - Repository limits still apply: https://huggingface.co/docs/hub/repositories-recommendations\n"
100
- " - Do not start several processes in parallel.\n"
101
- " - You can interrupt and resume the process at any time. "
102
- "The script will pick up where it left off except for partially uploaded files that would have to be entirely reuploaded.\n"
103
- " - Do not upload the same folder to several repositories. If you need to do so, you must delete the `./.cache/huggingface/` folder first.\n"
104
- "\n"
105
- f"Some temporary metadata will be stored under `{self.local_path}/.cache/huggingface`.\n"
106
- " - You must not modify those files manually.\n"
107
- " - You must not delete the `./.cache/huggingface/` folder while a process is running.\n"
108
- " - 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"
109
- "\n"
110
- "If the process output is too verbose, you can disable the progress bars with `--no-bars`. "
111
- "You can also entirely disable the status report with `--no-report`.\n"
112
- "\n"
113
- "For more details, run `huggingface-cli upload-large-folder --help` or check the documentation at "
114
- "https://huggingface.co/docs/huggingface_hub/guides/upload#upload-a-large-folder."
115
- )
116
- )
117
-
118
- if self.no_bars:
119
- disable_progress_bars()
120
-
121
- self.api.upload_large_folder(
122
- repo_id=self.repo_id,
123
- folder_path=self.local_path,
124
- repo_type=self.repo_type,
125
- revision=self.revision,
126
- private=self.private,
127
- allow_patterns=self.include,
128
- ignore_patterns=self.exclude,
129
- num_workers=self.num_workers,
130
- print_report=not self.no_report,
131
- )
@@ -1,207 +0,0 @@
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
-
33
- from argparse import _SubParsersAction
34
- from typing import Optional
35
-
36
- from huggingface_hub.commands import BaseHuggingfaceCLICommand
37
- from huggingface_hub.constants import ENDPOINT
38
- from huggingface_hub.errors import HfHubHTTPError
39
- from huggingface_hub.hf_api import HfApi
40
-
41
- from .._login import auth_list, auth_switch, login, logout
42
- from ..utils import get_stored_tokens, get_token, logging
43
- from ._cli_utils import ANSI, show_deprecation_warning
44
-
45
-
46
- logger = logging.get_logger(__name__)
47
-
48
- try:
49
- from InquirerPy import inquirer
50
- from InquirerPy.base.control import Choice
51
-
52
- _inquirer_py_available = True
53
- except ImportError:
54
- _inquirer_py_available = False
55
-
56
-
57
- class UserCommands(BaseHuggingfaceCLICommand):
58
- @staticmethod
59
- def register_subcommand(parser: _SubParsersAction):
60
- login_parser = parser.add_parser("login", help="Log in using a token from huggingface.co/settings/tokens")
61
- login_parser.add_argument(
62
- "--token",
63
- type=str,
64
- help="Token generated from https://huggingface.co/settings/tokens",
65
- )
66
- login_parser.add_argument(
67
- "--add-to-git-credential",
68
- action="store_true",
69
- help="Optional: Save token to git credential helper.",
70
- )
71
- login_parser.set_defaults(func=lambda args: LoginCommand(args))
72
- whoami_parser = parser.add_parser("whoami", help="Find out which huggingface.co account you are logged in as.")
73
- whoami_parser.set_defaults(func=lambda args: WhoamiCommand(args))
74
-
75
- logout_parser = parser.add_parser("logout", help="Log out")
76
- logout_parser.add_argument(
77
- "--token-name",
78
- type=str,
79
- help="Optional: Name of the access token to log out from.",
80
- )
81
- logout_parser.set_defaults(func=lambda args: LogoutCommand(args))
82
-
83
- auth_parser = parser.add_parser("auth", help="Other authentication related commands")
84
- auth_subparsers = auth_parser.add_subparsers(help="Authentication subcommands")
85
- auth_switch_parser = auth_subparsers.add_parser("switch", help="Switch between access tokens")
86
- auth_switch_parser.add_argument(
87
- "--token-name",
88
- type=str,
89
- help="Optional: Name of the access token to switch to.",
90
- )
91
- auth_switch_parser.add_argument(
92
- "--add-to-git-credential",
93
- action="store_true",
94
- help="Optional: Save token to git credential helper.",
95
- )
96
- auth_switch_parser.set_defaults(func=lambda args: AuthSwitchCommand(args))
97
- auth_list_parser = auth_subparsers.add_parser("list", help="List all stored access tokens")
98
- auth_list_parser.set_defaults(func=lambda args: AuthListCommand(args))
99
-
100
-
101
- class BaseUserCommand:
102
- def __init__(self, args):
103
- self.args = args
104
- self._api = HfApi()
105
-
106
-
107
- class LoginCommand(BaseUserCommand):
108
- def run(self):
109
- show_deprecation_warning("huggingface-cli login", "hf auth login")
110
-
111
- logging.set_verbosity_info()
112
- login(
113
- token=self.args.token,
114
- add_to_git_credential=self.args.add_to_git_credential,
115
- )
116
-
117
-
118
- class LogoutCommand(BaseUserCommand):
119
- def run(self):
120
- show_deprecation_warning("huggingface-cli logout", "hf auth logout")
121
-
122
- logging.set_verbosity_info()
123
- logout(token_name=self.args.token_name)
124
-
125
-
126
- class AuthSwitchCommand(BaseUserCommand):
127
- def run(self):
128
- show_deprecation_warning("huggingface-cli auth switch", "hf auth switch")
129
-
130
- logging.set_verbosity_info()
131
- token_name = self.args.token_name
132
- if token_name is None:
133
- token_name = self._select_token_name()
134
-
135
- if token_name is None:
136
- print("No token name provided. Aborting.")
137
- exit()
138
- auth_switch(token_name, add_to_git_credential=self.args.add_to_git_credential)
139
-
140
- def _select_token_name(self) -> Optional[str]:
141
- token_names = list(get_stored_tokens().keys())
142
-
143
- if not token_names:
144
- logger.error("No stored tokens found. Please login first.")
145
- return None
146
-
147
- if _inquirer_py_available:
148
- return self._select_token_name_tui(token_names)
149
- # if inquirer is not available, use a simpler terminal UI
150
- print("Available stored tokens:")
151
- for i, token_name in enumerate(token_names, 1):
152
- print(f"{i}. {token_name}")
153
- while True:
154
- try:
155
- choice = input("Enter the number of the token to switch to (or 'q' to quit): ")
156
- if choice.lower() == "q":
157
- return None
158
- index = int(choice) - 1
159
- if 0 <= index < len(token_names):
160
- return token_names[index]
161
- else:
162
- print("Invalid selection. Please try again.")
163
- except ValueError:
164
- print("Invalid input. Please enter a number or 'q' to quit.")
165
-
166
- def _select_token_name_tui(self, token_names: list[str]) -> Optional[str]:
167
- choices = [Choice(token_name, name=token_name) for token_name in token_names]
168
- try:
169
- return inquirer.select(
170
- message="Select a token to switch to:",
171
- choices=choices,
172
- default=None,
173
- ).execute()
174
- except KeyboardInterrupt:
175
- logger.info("Token selection cancelled.")
176
- return None
177
-
178
-
179
- class AuthListCommand(BaseUserCommand):
180
- def run(self):
181
- show_deprecation_warning("huggingface-cli auth list", "hf auth list")
182
-
183
- logging.set_verbosity_info()
184
- auth_list()
185
-
186
-
187
- class WhoamiCommand(BaseUserCommand):
188
- def run(self):
189
- show_deprecation_warning("huggingface-cli whoami", "hf auth whoami")
190
-
191
- token = get_token()
192
- if token is None:
193
- print("Not logged in")
194
- exit()
195
- try:
196
- info = self._api.whoami(token)
197
- print(info["name"])
198
- orgs = [org["name"] for org in info["orgs"]]
199
- if orgs:
200
- print(ANSI.bold("orgs: "), ",".join(orgs))
201
-
202
- if ENDPOINT != "https://huggingface.co":
203
- print(f"Authenticated through private endpoint: {ENDPOINT}")
204
- except HfHubHTTPError as e:
205
- print(e)
206
- print(ANSI.red(e.response.text))
207
- exit(1)