hfutils 0.3.8__tar.gz → 0.3.9__tar.gz
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.
- {hfutils-0.3.8/hfutils.egg-info → hfutils-0.3.9}/PKG-INFO +1 -1
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/config/meta.py +1 -1
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/operate/download.py +114 -61
- {hfutils-0.3.8 → hfutils-0.3.9/hfutils.egg-info}/PKG-INFO +1 -1
- {hfutils-0.3.8 → hfutils-0.3.9}/LICENSE +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/MANIFEST.in +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/README.md +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/__init__.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/__main__.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/archive/__init__.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/archive/base.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/archive/rar.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/archive/sevenz.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/archive/tar.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/archive/zip.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/cache/__init__.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/cache/delete.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/config/__init__.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/entry/__init__.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/entry/base.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/entry/cli.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/entry/clone.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/entry/dispatch.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/entry/download.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/entry/index.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/entry/ls.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/entry/ls_repo.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/entry/rollback.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/entry/upload.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/entry/whoami.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/index/__init__.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/index/fetch.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/index/hash.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/index/local_fetch.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/index/make.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/index/validate.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/operate/__init__.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/operate/base.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/operate/upload.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/operate/validate.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/repository/__init__.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/repository/base.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/repository/clone.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/repository/rollback.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/utils/__init__.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/utils/binary.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/utils/download.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/utils/irregular_repo.json +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/utils/logging.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/utils/number.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/utils/path.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/utils/session.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/utils/temp.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/utils/tqdm_.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils/utils/walk.py +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils.egg-info/SOURCES.txt +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils.egg-info/dependency_links.txt +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils.egg-info/entry_points.txt +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils.egg-info/requires.txt +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/hfutils.egg-info/top_level.txt +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/requirements-7z.txt +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/requirements-build.txt +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/requirements-doc.txt +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/requirements-rar.txt +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/requirements-test.txt +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/requirements-transfer.txt +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/requirements.txt +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/setup.cfg +0 -0
- {hfutils-0.3.8 → hfutils-0.3.9}/setup.py +0 -0
|
@@ -1,3 +1,27 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module provides functions for downloading files and directories from Hugging Face repositories.
|
|
3
|
+
|
|
4
|
+
It includes utilities for downloading individual files, archives, and entire directories,
|
|
5
|
+
with support for concurrent downloads, retries, and progress tracking.
|
|
6
|
+
|
|
7
|
+
The module interacts with the Hugging Face Hub API to fetch repository contents and
|
|
8
|
+
download files, handling various repository types and revisions.
|
|
9
|
+
|
|
10
|
+
Key features:
|
|
11
|
+
|
|
12
|
+
- Download individual files from Hugging Face repositories
|
|
13
|
+
- Download and extract archive files
|
|
14
|
+
- Download entire directories with pattern matching and ignore rules
|
|
15
|
+
- Concurrent downloads with configurable worker count
|
|
16
|
+
- Retry mechanism for failed downloads
|
|
17
|
+
- Progress tracking with tqdm
|
|
18
|
+
- Support for different repository types (dataset, model, space)
|
|
19
|
+
- Token-based authentication for accessing private repositories
|
|
20
|
+
|
|
21
|
+
This module is particularly useful for managing and synchronizing local copies of
|
|
22
|
+
Hugging Face repository contents, especially when dealing with large datasets or models.
|
|
23
|
+
"""
|
|
24
|
+
|
|
1
25
|
import logging
|
|
2
26
|
import os.path
|
|
3
27
|
import shutil
|
|
@@ -12,9 +36,50 @@ from ..archive import archive_unpack
|
|
|
12
36
|
from ..utils import tqdm, TemporaryDirectory, hf_normpath
|
|
13
37
|
|
|
14
38
|
|
|
39
|
+
def _raw_download_file(td: str, local_file: str, repo_id: str, file_in_repo: str,
|
|
40
|
+
repo_type: RepoTypeTyping = 'dataset', revision: str = 'main',
|
|
41
|
+
hf_token: Optional[str] = None):
|
|
42
|
+
"""
|
|
43
|
+
Download a file from a Hugging Face repository to a temporary directory and then move it to the final location.
|
|
44
|
+
|
|
45
|
+
This internal function handles the actual download process using the Hugging Face Hub client.
|
|
46
|
+
|
|
47
|
+
:param td: Temporary directory path.
|
|
48
|
+
:type td: str
|
|
49
|
+
:param local_file: The final local file path where the downloaded file will be moved.
|
|
50
|
+
:type local_file: str
|
|
51
|
+
:param repo_id: The identifier of the repository.
|
|
52
|
+
:type repo_id: str
|
|
53
|
+
:param file_in_repo: The file path within the repository.
|
|
54
|
+
:type file_in_repo: str
|
|
55
|
+
:param repo_type: The type of the repository ('dataset', 'model', 'space').
|
|
56
|
+
:type repo_type: RepoTypeTyping
|
|
57
|
+
:param revision: The revision of the repository (e.g., branch, tag, commit hash).
|
|
58
|
+
:type revision: str
|
|
59
|
+
:param hf_token: Hugging Face token for API client.
|
|
60
|
+
:type hf_token: str, optional
|
|
61
|
+
"""
|
|
62
|
+
hf_client = get_hf_client(hf_token=hf_token)
|
|
63
|
+
relative_filename = os.path.join(*file_in_repo.split("/"))
|
|
64
|
+
temp_path = os.path.join(td, relative_filename)
|
|
65
|
+
try:
|
|
66
|
+
hf_client.hf_hub_download(
|
|
67
|
+
repo_id=repo_id,
|
|
68
|
+
repo_type=repo_type,
|
|
69
|
+
filename=hf_normpath(file_in_repo),
|
|
70
|
+
revision=revision,
|
|
71
|
+
local_dir=td,
|
|
72
|
+
)
|
|
73
|
+
finally:
|
|
74
|
+
if os.path.exists(temp_path):
|
|
75
|
+
if os.path.dirname(local_file):
|
|
76
|
+
os.makedirs(os.path.dirname(local_file), exist_ok=True)
|
|
77
|
+
shutil.move(temp_path, local_file)
|
|
78
|
+
|
|
79
|
+
|
|
15
80
|
def download_file_to_file(local_file: str, repo_id: str, file_in_repo: str,
|
|
16
81
|
repo_type: RepoTypeTyping = 'dataset', revision: str = 'main',
|
|
17
|
-
|
|
82
|
+
hf_token: Optional[str] = None):
|
|
18
83
|
"""
|
|
19
84
|
Download a file from a Hugging Face repository and save it to a local file.
|
|
20
85
|
|
|
@@ -28,29 +93,19 @@ def download_file_to_file(local_file: str, repo_id: str, file_in_repo: str,
|
|
|
28
93
|
:type repo_type: RepoTypeTyping
|
|
29
94
|
:param revision: The revision of the repository (e.g., branch, tag, commit hash).
|
|
30
95
|
:type revision: str
|
|
31
|
-
:param resume_download: Resume the existing download.
|
|
32
|
-
:type resume_download: bool
|
|
33
96
|
:param hf_token: Huggingface token for API client, use ``HF_TOKEN`` variable if not assigned.
|
|
34
97
|
:type hf_token: str, optional
|
|
35
98
|
"""
|
|
36
|
-
hf_client = get_hf_client(hf_token)
|
|
37
|
-
relative_filename = os.path.join(*file_in_repo.split("/"))
|
|
38
99
|
with TemporaryDirectory() as td:
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
)
|
|
49
|
-
finally:
|
|
50
|
-
if os.path.exists(temp_path):
|
|
51
|
-
if os.path.dirname(local_file):
|
|
52
|
-
os.makedirs(os.path.dirname(local_file), exist_ok=True)
|
|
53
|
-
shutil.move(temp_path, local_file)
|
|
100
|
+
_raw_download_file(
|
|
101
|
+
td=td,
|
|
102
|
+
local_file=local_file,
|
|
103
|
+
repo_id=repo_id,
|
|
104
|
+
file_in_repo=file_in_repo,
|
|
105
|
+
repo_type=repo_type,
|
|
106
|
+
revision=revision,
|
|
107
|
+
hf_token=hf_token,
|
|
108
|
+
)
|
|
54
109
|
|
|
55
110
|
|
|
56
111
|
def download_archive_as_directory(local_directory: str, repo_id: str, file_in_repo: str,
|
|
@@ -84,7 +139,7 @@ def download_directory_as_directory(
|
|
|
84
139
|
local_directory: str, repo_id: str, dir_in_repo: str = '.', pattern: str = '**/*',
|
|
85
140
|
repo_type: RepoTypeTyping = 'dataset', revision: str = 'main',
|
|
86
141
|
silent: bool = False, ignore_patterns: List[str] = _IGNORE_PATTERN_UNSET,
|
|
87
|
-
|
|
142
|
+
max_workers: int = 8, max_retries: int = 5,
|
|
88
143
|
soft_mode_when_check: bool = False, hf_token: Optional[str] = None
|
|
89
144
|
):
|
|
90
145
|
"""
|
|
@@ -110,8 +165,6 @@ def download_directory_as_directory(
|
|
|
110
165
|
:type max_workers: int
|
|
111
166
|
:param max_retries: Max retry times when downloading. Default is ``5``.
|
|
112
167
|
:type max_retries: int
|
|
113
|
-
:param resume_download: Resume the existing download.
|
|
114
|
-
:type resume_download: bool
|
|
115
168
|
:param soft_mode_when_check: Just check the size of the expected file when enabled. Default is False.
|
|
116
169
|
:type soft_mode_when_check: bool
|
|
117
170
|
:param hf_token: Huggingface token for API client, use ``HF_TOKEN`` variable if not assigned.
|
|
@@ -129,46 +182,46 @@ def download_directory_as_directory(
|
|
|
129
182
|
progress = tqdm(files, silent=silent, desc=f'Downloading {dir_in_repo!r} ...')
|
|
130
183
|
|
|
131
184
|
def _download_one_file(rel_file):
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
185
|
+
with TemporaryDirectory() as td:
|
|
186
|
+
try:
|
|
187
|
+
dst_file = os.path.join(local_directory, rel_file)
|
|
188
|
+
file_in_repo = hf_normpath(f'{dir_in_repo}/{rel_file}')
|
|
189
|
+
if os.path.exists(dst_file) and is_local_file_ready(
|
|
190
|
+
repo_id=repo_id,
|
|
191
|
+
repo_type=repo_type,
|
|
192
|
+
local_file=dst_file,
|
|
193
|
+
file_in_repo=file_in_repo,
|
|
194
|
+
revision=revision,
|
|
195
|
+
hf_token=hf_token,
|
|
196
|
+
soft_mode=soft_mode_when_check,
|
|
197
|
+
):
|
|
198
|
+
logging.info(f'Local file {rel_file} is ready, download skipped.')
|
|
199
|
+
else:
|
|
200
|
+
tries = 0
|
|
201
|
+
while True:
|
|
202
|
+
try:
|
|
203
|
+
_raw_download_file(
|
|
204
|
+
td=td,
|
|
205
|
+
local_file=dst_file,
|
|
206
|
+
repo_id=repo_id,
|
|
207
|
+
file_in_repo=file_in_repo,
|
|
208
|
+
repo_type=repo_type,
|
|
209
|
+
revision=revision,
|
|
210
|
+
hf_token=hf_token,
|
|
211
|
+
)
|
|
212
|
+
except requests.exceptions.RequestException as err:
|
|
213
|
+
if tries < max_retries:
|
|
214
|
+
tries += 1
|
|
215
|
+
logging.warning(
|
|
216
|
+
f'Download {rel_file!r} failed, retry ({tries}/{max_retries}) - {err!r}.')
|
|
217
|
+
else:
|
|
218
|
+
raise
|
|
164
219
|
else:
|
|
165
|
-
|
|
166
|
-
else:
|
|
167
|
-
break
|
|
220
|
+
break
|
|
168
221
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
222
|
+
progress.update()
|
|
223
|
+
except Exception as err:
|
|
224
|
+
logging.exception(f'Unexpected error when downloading {rel_file!r} - {err!r}')
|
|
172
225
|
|
|
173
226
|
tp = ThreadPoolExecutor(max_workers=max_workers)
|
|
174
227
|
for file in files:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|