huggingface-hub 0.13.4__py3-none-any.whl → 0.14.0.dev0__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 (40) hide show
  1. huggingface_hub/__init__.py +59 -5
  2. huggingface_hub/_commit_api.py +26 -71
  3. huggingface_hub/_login.py +16 -13
  4. huggingface_hub/_multi_commits.py +305 -0
  5. huggingface_hub/_snapshot_download.py +4 -0
  6. huggingface_hub/_space_api.py +6 -0
  7. huggingface_hub/_webhooks_payload.py +124 -0
  8. huggingface_hub/_webhooks_server.py +362 -0
  9. huggingface_hub/commands/lfs.py +3 -5
  10. huggingface_hub/commands/user.py +0 -3
  11. huggingface_hub/community.py +21 -0
  12. huggingface_hub/constants.py +3 -0
  13. huggingface_hub/file_download.py +25 -10
  14. huggingface_hub/hf_api.py +666 -139
  15. huggingface_hub/hf_file_system.py +441 -0
  16. huggingface_hub/hub_mixin.py +1 -1
  17. huggingface_hub/inference_api.py +2 -4
  18. huggingface_hub/keras_mixin.py +1 -1
  19. huggingface_hub/lfs.py +196 -176
  20. huggingface_hub/repocard.py +2 -2
  21. huggingface_hub/repository.py +1 -1
  22. huggingface_hub/templates/modelcard_template.md +1 -1
  23. huggingface_hub/utils/__init__.py +8 -11
  24. huggingface_hub/utils/_errors.py +4 -4
  25. huggingface_hub/utils/_experimental.py +65 -0
  26. huggingface_hub/utils/_git_credential.py +1 -80
  27. huggingface_hub/utils/_http.py +85 -2
  28. huggingface_hub/utils/_pagination.py +4 -3
  29. huggingface_hub/utils/_paths.py +2 -0
  30. huggingface_hub/utils/_runtime.py +12 -0
  31. huggingface_hub/utils/_subprocess.py +22 -0
  32. huggingface_hub/utils/_telemetry.py +2 -4
  33. huggingface_hub/utils/tqdm.py +23 -18
  34. {huggingface_hub-0.13.4.dist-info → huggingface_hub-0.14.0.dev0.dist-info}/METADATA +5 -1
  35. huggingface_hub-0.14.0.dev0.dist-info/RECORD +61 -0
  36. {huggingface_hub-0.13.4.dist-info → huggingface_hub-0.14.0.dev0.dist-info}/entry_points.txt +3 -0
  37. huggingface_hub-0.13.4.dist-info/RECORD +0 -56
  38. {huggingface_hub-0.13.4.dist-info → huggingface_hub-0.14.0.dev0.dist-info}/LICENSE +0 -0
  39. {huggingface_hub-0.13.4.dist-info → huggingface_hub-0.14.0.dev0.dist-info}/WHEEL +0 -0
  40. {huggingface_hub-0.13.4.dist-info → huggingface_hub-0.14.0.dev0.dist-info}/top_level.txt +0 -0
@@ -46,7 +46,7 @@ import sys
46
46
  from typing import TYPE_CHECKING
47
47
 
48
48
 
49
- __version__ = "0.13.4"
49
+ __version__ = "0.14.0.dev0"
50
50
 
51
51
  # Alphabetical order of definitions is ensured in tests
52
52
  # WARNING: any comment added in this dictionary definition will be lost when
@@ -58,6 +58,10 @@ _SUBMOD_ATTRS = {
58
58
  "logout",
59
59
  "notebook_login",
60
60
  ],
61
+ "_multi_commits": [
62
+ "MultiCommitException",
63
+ "plan_multi_commits",
64
+ ],
61
65
  "_snapshot_download": [
62
66
  "snapshot_download",
63
67
  ],
@@ -66,6 +70,21 @@ _SUBMOD_ATTRS = {
66
70
  "SpaceRuntime",
67
71
  "SpaceStage",
68
72
  ],
73
+ "_webhooks_payload": [
74
+ "WebhookPayload",
75
+ "WebhookPayloadComment",
76
+ "WebhookPayloadDiscussion",
77
+ "WebhookPayloadDiscussionChanges",
78
+ "WebhookPayloadEvent",
79
+ "WebhookPayloadMovedTo",
80
+ "WebhookPayloadRepo",
81
+ "WebhookPayloadUrl",
82
+ "WebhookPayloadWebhook",
83
+ ],
84
+ "_webhooks_server": [
85
+ "WebhooksServer",
86
+ "webhook_endpoint",
87
+ ],
69
88
  "community": [
70
89
  "Discussion",
71
90
  "DiscussionComment",
@@ -119,6 +138,7 @@ _SUBMOD_ATTRS = {
119
138
  "comment_discussion",
120
139
  "create_branch",
121
140
  "create_commit",
141
+ "create_commits_on_pr",
122
142
  "create_discussion",
123
143
  "create_pull_request",
124
144
  "create_repo",
@@ -140,6 +160,7 @@ _SUBMOD_ATTRS = {
140
160
  "get_space_runtime",
141
161
  "like",
142
162
  "list_datasets",
163
+ "list_files_info",
143
164
  "list_liked_repos",
144
165
  "list_metrics",
145
166
  "list_models",
@@ -155,15 +176,19 @@ _SUBMOD_ATTRS = {
155
176
  "repo_type_and_id_from_hf_id",
156
177
  "request_space_hardware",
157
178
  "restart_space",
158
- "set_access_token",
179
+ "set_space_sleep_time",
159
180
  "space_info",
160
181
  "unlike",
161
- "unset_access_token",
162
182
  "update_repo_visibility",
163
183
  "upload_file",
164
184
  "upload_folder",
165
185
  "whoami",
166
186
  ],
187
+ "hf_file_system": [
188
+ "HfFileSystem",
189
+ "HfFileSystemFile",
190
+ "HfFileSystemResolvedPath",
191
+ ],
167
192
  "hub_mixin": [
168
193
  "ModelHubMixin",
169
194
  "PyTorchModelHubMixin",
@@ -207,7 +232,9 @@ _SUBMOD_ATTRS = {
207
232
  "HFCacheInfo",
208
233
  "HfFolder",
209
234
  "cached_assets_path",
235
+ "configure_http_backend",
210
236
  "dump_environment_info",
237
+ "get_session",
211
238
  "logging",
212
239
  "scan_cache_dir",
213
240
  ],
@@ -319,12 +346,31 @@ if TYPE_CHECKING: # pragma: no cover
319
346
  logout, # noqa: F401
320
347
  notebook_login, # noqa: F401
321
348
  )
349
+ from ._multi_commits import (
350
+ MultiCommitException, # noqa: F401
351
+ plan_multi_commits, # noqa: F401
352
+ )
322
353
  from ._snapshot_download import snapshot_download # noqa: F401
323
354
  from ._space_api import (
324
355
  SpaceHardware, # noqa: F401
325
356
  SpaceRuntime, # noqa: F401
326
357
  SpaceStage, # noqa: F401
327
358
  )
359
+ from ._webhooks_payload import (
360
+ WebhookPayload, # noqa: F401
361
+ WebhookPayloadComment, # noqa: F401
362
+ WebhookPayloadDiscussion, # noqa: F401
363
+ WebhookPayloadDiscussionChanges, # noqa: F401
364
+ WebhookPayloadEvent, # noqa: F401
365
+ WebhookPayloadMovedTo, # noqa: F401
366
+ WebhookPayloadRepo, # noqa: F401
367
+ WebhookPayloadUrl, # noqa: F401
368
+ WebhookPayloadWebhook, # noqa: F401
369
+ )
370
+ from ._webhooks_server import (
371
+ WebhooksServer, # noqa: F401
372
+ webhook_endpoint, # noqa: F401
373
+ )
328
374
  from .community import (
329
375
  Discussion, # noqa: F401
330
376
  DiscussionComment, # noqa: F401
@@ -378,6 +424,7 @@ if TYPE_CHECKING: # pragma: no cover
378
424
  comment_discussion, # noqa: F401
379
425
  create_branch, # noqa: F401
380
426
  create_commit, # noqa: F401
427
+ create_commits_on_pr, # noqa: F401
381
428
  create_discussion, # noqa: F401
382
429
  create_pull_request, # noqa: F401
383
430
  create_repo, # noqa: F401
@@ -399,6 +446,7 @@ if TYPE_CHECKING: # pragma: no cover
399
446
  get_space_runtime, # noqa: F401
400
447
  like, # noqa: F401
401
448
  list_datasets, # noqa: F401
449
+ list_files_info, # noqa: F401
402
450
  list_liked_repos, # noqa: F401
403
451
  list_metrics, # noqa: F401
404
452
  list_models, # noqa: F401
@@ -414,15 +462,19 @@ if TYPE_CHECKING: # pragma: no cover
414
462
  repo_type_and_id_from_hf_id, # noqa: F401
415
463
  request_space_hardware, # noqa: F401
416
464
  restart_space, # noqa: F401
417
- set_access_token, # noqa: F401
465
+ set_space_sleep_time, # noqa: F401
418
466
  space_info, # noqa: F401
419
467
  unlike, # noqa: F401
420
- unset_access_token, # noqa: F401
421
468
  update_repo_visibility, # noqa: F401
422
469
  upload_file, # noqa: F401
423
470
  upload_folder, # noqa: F401
424
471
  whoami, # noqa: F401
425
472
  )
473
+ from .hf_file_system import (
474
+ HfFileSystem, # noqa: F401
475
+ HfFileSystemFile, # noqa: F401
476
+ HfFileSystemResolvedPath, # noqa: F401
477
+ )
426
478
  from .hub_mixin import (
427
479
  ModelHubMixin, # noqa: F401
428
480
  PyTorchModelHubMixin, # noqa: F401
@@ -462,7 +514,9 @@ if TYPE_CHECKING: # pragma: no cover
462
514
  HFCacheInfo, # noqa: F401
463
515
  HfFolder, # noqa: F401
464
516
  cached_assets_path, # noqa: F401
517
+ configure_http_backend, # noqa: F401
465
518
  dump_environment_info, # noqa: F401
519
+ get_session, # noqa: F401
466
520
  logging, # noqa: F401
467
521
  scan_cache_dir, # noqa: F401
468
522
  )
@@ -11,11 +11,12 @@ from dataclasses import dataclass, field
11
11
  from pathlib import Path, PurePosixPath
12
12
  from typing import Any, BinaryIO, Dict, Iterable, Iterator, List, Optional, Union
13
13
 
14
- import requests
15
14
  from tqdm.contrib.concurrent import thread_map
16
15
 
17
- from .constants import ENDPOINT
18
- from .lfs import UploadInfo, _validate_batch_actions, lfs_upload, post_lfs_batch_info
16
+ from huggingface_hub import get_session
17
+
18
+ from .constants import ENDPOINT, HF_HUB_ENABLE_HF_TRANSFER
19
+ from .lfs import UploadInfo, lfs_upload, post_lfs_batch_info
19
20
  from .utils import (
20
21
  build_hf_headers,
21
22
  chunk_iterable,
@@ -25,7 +26,6 @@ from .utils import (
25
26
  validate_hf_hub_args,
26
27
  )
27
28
  from .utils import tqdm as hf_tqdm
28
- from .utils._deprecation import _deprecate_method
29
29
  from .utils._typing import Literal
30
30
 
31
31
 
@@ -130,14 +130,6 @@ class CommitOperationAdd:
130
130
  else:
131
131
  self.upload_info = UploadInfo.from_fileobj(self.path_or_fileobj)
132
132
 
133
- @_deprecate_method(version="0.14", message="Operation is validated at initialization.")
134
- def validate(self) -> None:
135
- pass
136
-
137
- @_deprecate_method(version="0.14", message="Use `upload_info` property instead.")
138
- def _upload_info(self) -> UploadInfo:
139
- return self.upload_info
140
-
141
133
  @contextmanager
142
134
  def as_file(self, with_tqdm: bool = False) -> Iterator[BinaryIO]:
143
135
  """
@@ -206,6 +198,11 @@ def _validate_path_in_repo(path_in_repo: str) -> str:
206
198
  raise ValueError(f"Invalid `path_in_repo` in CommitOperation: '{path_in_repo}'")
207
199
  if path_in_repo.startswith("./"):
208
200
  path_in_repo = path_in_repo[2:]
201
+ if any(part == ".git" for part in path_in_repo.split("/")):
202
+ raise ValueError(
203
+ "Invalid `path_in_repo` in CommitOperation: cannot update files under a '.git/' folder (path:"
204
+ f" '{path_in_repo}')."
205
+ )
209
206
  return path_in_repo
210
207
 
211
208
 
@@ -338,64 +335,28 @@ def upload_lfs_files(
338
335
  return
339
336
 
340
337
  # Step 3: upload files concurrently according to these instructions
341
- def _inner_upload_lfs_object(batch_action):
338
+ def _wrapped_lfs_upload(batch_action) -> None:
342
339
  try:
343
340
  operation = oid2addop[batch_action["oid"]]
344
- return _upload_lfs_object(operation=operation, lfs_batch_action=batch_action, token=token)
341
+ lfs_upload(operation=operation, lfs_batch_action=batch_action, token=token)
345
342
  except Exception as exc:
346
343
  raise RuntimeError(f"Error while uploading '{operation.path_in_repo}' to the Hub.") from exc
347
344
 
348
- logger.debug(
349
- f"Uploading {len(filtered_actions)} LFS files to the Hub using up to {num_threads} threads concurrently"
350
- )
351
- thread_map(
352
- _inner_upload_lfs_object,
353
- filtered_actions,
354
- desc=f"Upload {len(filtered_actions)} LFS files",
355
- max_workers=num_threads,
356
- tqdm_class=hf_tqdm,
357
- )
358
-
359
-
360
- def _upload_lfs_object(operation: CommitOperationAdd, lfs_batch_action: dict, token: Optional[str]):
361
- """
362
- Handles uploading a given object to the Hub with the LFS protocol.
363
-
364
- Defers to [`~utils.lfs.lfs_upload`] for the actual upload logic.
365
-
366
- Can be a No-op if the content of the file is already present on the hub
367
- large file storage.
368
-
369
- Args:
370
- operation (`CommitOperationAdd`):
371
- The add operation triggering this upload
372
- lfs_batch_action (`dict`):
373
- Upload instructions from the LFS batch endpoint for this object.
374
- See [`~utils.lfs.post_lfs_batch_info`] for more details.
375
- token (`str`, *optional*):
376
- A [user access token](https://hf.co/settings/tokens) to authenticate requests against the Hub
377
-
378
- Raises: `ValueError` if `lfs_batch_action` is improperly formatted
379
- """
380
- _validate_batch_actions(lfs_batch_action)
381
- upload_info = operation.upload_info
382
- actions = lfs_batch_action.get("actions")
383
- if actions is None:
384
- # The file was already uploaded
385
- logger.debug(f"Content of file {operation.path_in_repo} is already present upstream - skipping upload")
386
- return
387
- upload_action = lfs_batch_action["actions"].get("upload")
388
- verify_action = lfs_batch_action["actions"].get("verify")
389
- with operation.as_file(with_tqdm=True) as fileobj:
390
- logger.debug(f"Uploading {operation.path_in_repo} as LFS file...")
391
- lfs_upload(
392
- fileobj=fileobj,
393
- upload_action=upload_action,
394
- verify_action=verify_action,
395
- upload_info=upload_info,
396
- token=token,
345
+ if HF_HUB_ENABLE_HF_TRANSFER:
346
+ logger.debug(f"Uploading {len(filtered_actions)} LFS files to the Hub using `hf_transfer`.")
347
+ for action in filtered_actions:
348
+ _wrapped_lfs_upload(action)
349
+ else:
350
+ logger.debug(
351
+ f"Uploading {len(filtered_actions)} LFS files to the Hub using up to {num_threads} threads concurrently"
352
+ )
353
+ thread_map(
354
+ _wrapped_lfs_upload,
355
+ filtered_actions,
356
+ desc=f"Upload {len(filtered_actions)} LFS files",
357
+ max_workers=num_threads,
358
+ tqdm_class=hf_tqdm,
397
359
  )
398
- logger.debug(f"{operation.path_in_repo}: Upload successful")
399
360
 
400
361
 
401
362
  def _validate_preupload_info(preupload_info: dict):
@@ -468,7 +429,7 @@ def fetch_upload_modes(
468
429
  ]
469
430
  }
470
431
 
471
- resp = requests.post(
432
+ resp = get_session().post(
472
433
  f"{endpoint}/api/{repo_type}s/{repo_id}/preupload/{revision}",
473
434
  json=payload,
474
435
  headers=headers,
@@ -478,17 +439,11 @@ def fetch_upload_modes(
478
439
  preupload_info = _validate_preupload_info(resp.json())
479
440
  upload_modes.update(**{file["path"]: file["uploadMode"] for file in preupload_info["files"]})
480
441
 
481
- # If a file is empty, it is most likely a mistake.
482
- # => a warning message is triggered to warn the user.
483
- # => except if `.gitkeep` as it is a legit use case for an empty file.
484
- #
485
442
  # Empty files cannot be uploaded as LFS (S3 would fail with a 501 Not Implemented)
486
443
  # => empty files are uploaded as "regular" to still allow users to commit them.
487
444
  for addition in additions:
488
445
  if addition.upload_info.size == 0:
489
446
  path = addition.path_in_repo
490
- if not path.endswith(".gitkeep"):
491
- warnings.warn(f"About to commit an empty file: '{path}'. Are you sure this is intended?")
492
447
  upload_modes[path] = "regular"
493
448
 
494
449
  return upload_modes
huggingface_hub/_login.py CHANGED
@@ -15,13 +15,14 @@
15
15
  import os
16
16
  import subprocess
17
17
  from getpass import getpass
18
- from typing import List, Optional
18
+ from typing import Optional
19
19
 
20
20
  from .commands._cli_utils import ANSI
21
21
  from .commands.delete_cache import _ask_for_confirmation_no_tui
22
22
  from .hf_api import HfApi
23
23
  from .utils import (
24
24
  HfFolder,
25
+ capture_output,
25
26
  is_google_colab,
26
27
  is_notebook,
27
28
  list_credential_helpers,
@@ -30,7 +31,6 @@ from .utils import (
30
31
  set_git_credential,
31
32
  unset_git_credential,
32
33
  )
33
- from .utils._deprecation import _deprecate_method
34
34
 
35
35
 
36
36
  logger = logging.get_logger(__name__)
@@ -127,7 +127,7 @@ def interpreter_login() -> None:
127
127
  _|_|_|_| _| _| _| _|_| _| _|_| _| _| _| _| _| _|_| _|_|_| _|_|_|_| _| _|_|_|
128
128
  _| _| _| _| _| _| _| _| _| _| _|_| _| _| _| _| _| _| _|
129
129
  _| _| _|_| _|_|_| _|_|_| _|_|_| _| _| _|_|_| _| _| _| _|_|_| _|_|_|_|
130
- """) # docstyle-ignore
130
+ """)
131
131
  if HfFolder.get_token() is not None:
132
132
  print(
133
133
  " A token is already saved on your machine. Run `huggingface-cli"
@@ -181,7 +181,7 @@ def notebook_login() -> None:
181
181
  """
182
182
  try:
183
183
  import ipywidgets.widgets as widgets # type: ignore
184
- from IPython.display import clear_output, display # type: ignore
184
+ from IPython.display import display # type: ignore
185
185
  except ImportError:
186
186
  raise ImportError(
187
187
  "The `notebook_login` function can only be used in a notebook (Jupyter or"
@@ -212,8 +212,16 @@ def notebook_login() -> None:
212
212
  add_to_git_credential = git_checkbox_widget.value
213
213
  # Erase token and clear value to make sure it's not saved in the notebook.
214
214
  token_widget.value = ""
215
- clear_output()
216
- _login(token, add_to_git_credential=add_to_git_credential)
215
+ # Hide inputs
216
+ login_token_widget.children = [widgets.Label("Connecting...")]
217
+ try:
218
+ with capture_output() as captured:
219
+ _login(token, add_to_git_credential=add_to_git_credential)
220
+ message = captured.getvalue()
221
+ except Exception as error:
222
+ message = str(error)
223
+ # Print result (success message or error)
224
+ login_token_widget.children = [widgets.Label(line) for line in message.split("\n") if line.strip()]
217
225
 
218
226
  token_finish_button.on_click(login_token_event)
219
227
 
@@ -236,13 +244,13 @@ def _login(token: str, add_to_git_credential: bool) -> None:
236
244
  set_git_credential(token)
237
245
  print(
238
246
  "Your token has been saved in your configured git credential helpers"
239
- f" ({','.join(list_credential_helpers())})."
247
+ + f" ({','.join(list_credential_helpers())})."
240
248
  )
241
249
  else:
242
250
  print("Token has not been saved to git credential helper.")
243
251
 
244
252
  HfFolder.save_token(token)
245
- print("Your token has been saved to", HfFolder.path_token)
253
+ print(f"Your token has been saved to {HfFolder.path_token}")
246
254
  print("Login successful")
247
255
 
248
256
 
@@ -293,8 +301,3 @@ def _set_store_as_git_credential_helper_globally() -> None:
293
301
  run_subprocess("git config --global credential.helper store")
294
302
  except subprocess.CalledProcessError as exc:
295
303
  raise EnvironmentError(exc.stderr)
296
-
297
-
298
- @_deprecate_method(version="0.14", message="Please use `list_credential_helpers` instead.")
299
- def _currently_setup_credential_helpers(directory: Optional[str] = None) -> List[str]:
300
- return list_credential_helpers(directory)