hfutils 0.3.7__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.7/hfutils.egg-info → hfutils-0.3.9}/PKG-INFO +1 -1
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/config/meta.py +1 -1
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/index/__init__.py +2 -1
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/index/make.py +59 -1
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/operate/download.py +114 -61
- {hfutils-0.3.7 → hfutils-0.3.9/hfutils.egg-info}/PKG-INFO +1 -1
- {hfutils-0.3.7 → hfutils-0.3.9}/LICENSE +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/MANIFEST.in +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/README.md +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/__init__.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/__main__.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/archive/__init__.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/archive/base.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/archive/rar.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/archive/sevenz.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/archive/tar.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/archive/zip.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/cache/__init__.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/cache/delete.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/config/__init__.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/entry/__init__.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/entry/base.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/entry/cli.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/entry/clone.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/entry/dispatch.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/entry/download.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/entry/index.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/entry/ls.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/entry/ls_repo.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/entry/rollback.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/entry/upload.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/entry/whoami.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/index/fetch.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/index/hash.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/index/local_fetch.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/index/validate.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/operate/__init__.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/operate/base.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/operate/upload.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/operate/validate.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/repository/__init__.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/repository/base.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/repository/clone.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/repository/rollback.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/utils/__init__.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/utils/binary.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/utils/download.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/utils/irregular_repo.json +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/utils/logging.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/utils/number.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/utils/path.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/utils/session.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/utils/temp.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/utils/tqdm_.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils/utils/walk.py +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils.egg-info/SOURCES.txt +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils.egg-info/dependency_links.txt +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils.egg-info/entry_points.txt +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils.egg-info/requires.txt +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/hfutils.egg-info/top_level.txt +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/requirements-7z.txt +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/requirements-build.txt +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/requirements-doc.txt +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/requirements-rar.txt +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/requirements-test.txt +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/requirements-transfer.txt +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/requirements.txt +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/setup.cfg +0 -0
- {hfutils-0.3.7 → hfutils-0.3.9}/setup.py +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from .fetch import hf_tar_list_files, hf_tar_file_download, hf_tar_get_index, hf_tar_file_exists, \
|
|
2
2
|
ArchiveStandaloneFileIncompleteDownload, ArchiveStandaloneFileHashNotMatch, hf_tar_file_size, hf_tar_file_info
|
|
3
3
|
from .local_fetch import tar_get_index, tar_file_info, tar_file_download, tar_file_size, tar_file_exists, tar_list_files
|
|
4
|
-
from .make import tar_create_index, hf_tar_create_index, tar_get_index_info, hf_tar_create_from_directory
|
|
4
|
+
from .make import tar_create_index, hf_tar_create_index, tar_get_index_info, hf_tar_create_from_directory, \
|
|
5
|
+
tar_create_index_for_directory
|
|
5
6
|
from .validate import hf_tar_item_validate, hf_tar_validate
|
|
@@ -1,3 +1,22 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module provides functionalities for handling and indexing TAR archive files, especially for use with
|
|
3
|
+
the Hugging Face ecosystem. It includes functions to create and retrieve index information of TAR archives,
|
|
4
|
+
which is crucial for efficient data retrieval and management in large datasets. The module also integrates
|
|
5
|
+
with Hugging Face's repository system, allowing for operations like uploading and downloading TAR files
|
|
6
|
+
and their indices.
|
|
7
|
+
|
|
8
|
+
Key functionalities include:
|
|
9
|
+
|
|
10
|
+
- Extracting index information from TAR files.
|
|
11
|
+
- Creating index files for TAR archives locally or in a directory.
|
|
12
|
+
- Integrating with Hugging Face repositories to manage TAR archives and their indices.
|
|
13
|
+
|
|
14
|
+
The module utilizes cryptographic hash functions for data integrity checks and supports operations on both local
|
|
15
|
+
and remote repositories. It is designed to work seamlessly with the Hugging Face platform, enabling users to
|
|
16
|
+
handle large datasets efficiently.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
import glob
|
|
1
20
|
import json
|
|
2
21
|
import logging
|
|
3
22
|
import os
|
|
@@ -47,7 +66,7 @@ def tar_get_index_info(src_tar_file, chunk_for_hash: int = 1 << 20, with_hash: b
|
|
|
47
66
|
logging.info(f'Indexing tar file {src_tar_file!r} ...')
|
|
48
67
|
files = {}
|
|
49
68
|
with tarfile.open(src_tar_file, mode='r|') as tar:
|
|
50
|
-
for tarinfo in tqdm(tar, desc='Indexing tar file ...', silent=silent):
|
|
69
|
+
for tarinfo in tqdm(tar, desc=f'Indexing tar file {src_tar_file!r} ...', silent=silent):
|
|
51
70
|
tarinfo: tarfile.TarInfo
|
|
52
71
|
if tarinfo.isreg():
|
|
53
72
|
info = {
|
|
@@ -90,11 +109,50 @@ def tar_create_index(src_tar_file, dst_index_file: Optional[str] = None,
|
|
|
90
109
|
"""
|
|
91
110
|
body, _ = os.path.splitext(src_tar_file)
|
|
92
111
|
dst_index_file = dst_index_file or f'{body}.json'
|
|
112
|
+
if os.path.dirname(dst_index_file):
|
|
113
|
+
os.makedirs(os.path.dirname(dst_index_file), exist_ok=True)
|
|
93
114
|
with open(dst_index_file, 'w') as f:
|
|
94
115
|
json.dump(tar_get_index_info(src_tar_file, chunk_for_hash, with_hash, silent), f)
|
|
95
116
|
return dst_index_file
|
|
96
117
|
|
|
97
118
|
|
|
119
|
+
def tar_create_index_for_directory(src_tar_directory: str, dst_index_directory: Optional[str] = None,
|
|
120
|
+
chunk_for_hash: int = 1 << 20, with_hash: bool = True, silent: bool = False):
|
|
121
|
+
"""
|
|
122
|
+
Create index files for all tar archives in a specified directory.
|
|
123
|
+
|
|
124
|
+
This function scans through the given directory to find all tar files, generates an index for each,
|
|
125
|
+
and saves these indices to the specified destination directory. If no destination directory is provided,
|
|
126
|
+
indices are saved in the same directory as the tar files.
|
|
127
|
+
|
|
128
|
+
:param src_tar_directory: The path to the directory containing tar files.
|
|
129
|
+
:type src_tar_directory: str
|
|
130
|
+
:param dst_index_directory: The path to the directory where index files will be saved, defaults to the same as src_tar_directory.
|
|
131
|
+
:type dst_index_directory: str, optional
|
|
132
|
+
:param chunk_for_hash: The chunk size for hashing, defaults to 1 << 20 (1 MB).
|
|
133
|
+
:type chunk_for_hash: int, optional
|
|
134
|
+
:param with_hash: Whether to include file hashes in the index, defaults to True.
|
|
135
|
+
:type with_hash: bool, optional
|
|
136
|
+
:param silent: Whether to suppress progress bars and logging messages, defaults to False.
|
|
137
|
+
:type silent: bool, optional
|
|
138
|
+
:return: The path to the directory where index files are saved.
|
|
139
|
+
:rtype: str
|
|
140
|
+
"""
|
|
141
|
+
dst_index_directory = dst_index_directory or src_tar_directory
|
|
142
|
+
for tar_file in tqdm(glob.glob(os.path.join(src_tar_directory, '**', '*.tar'), recursive=True), silent=silent):
|
|
143
|
+
p_idx_file = os.path.join(dst_index_directory, os.path.relpath(tar_file, src_tar_directory))
|
|
144
|
+
idx_body, _ = os.path.splitext(p_idx_file)
|
|
145
|
+
idx_file = f'{idx_body}.json'
|
|
146
|
+
tar_create_index(
|
|
147
|
+
src_tar_file=tar_file,
|
|
148
|
+
dst_index_file=idx_file,
|
|
149
|
+
chunk_for_hash=chunk_for_hash,
|
|
150
|
+
with_hash=with_hash,
|
|
151
|
+
silent=silent,
|
|
152
|
+
)
|
|
153
|
+
return dst_index_directory
|
|
154
|
+
|
|
155
|
+
|
|
98
156
|
def hf_tar_create_index(repo_id: str, archive_in_repo: str,
|
|
99
157
|
repo_type: RepoTypeTyping = 'dataset', revision: str = 'main',
|
|
100
158
|
idx_repo_id: Optional[str] = None, idx_file_in_repo: Optional[str] = None,
|
|
@@ -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
|