hfutils 0.3.4__tar.gz → 0.3.6__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.
Files changed (68) hide show
  1. {hfutils-0.3.4/hfutils.egg-info → hfutils-0.3.6}/PKG-INFO +23 -23
  2. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/config/meta.py +1 -1
  3. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/index/__init__.py +1 -0
  4. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/index/fetch.py +19 -9
  5. hfutils-0.3.6/hfutils/index/local_fetch.py +242 -0
  6. {hfutils-0.3.4 → hfutils-0.3.6/hfutils.egg-info}/PKG-INFO +23 -23
  7. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils.egg-info/SOURCES.txt +1 -0
  8. {hfutils-0.3.4 → hfutils-0.3.6}/LICENSE +0 -0
  9. {hfutils-0.3.4 → hfutils-0.3.6}/MANIFEST.in +0 -0
  10. {hfutils-0.3.4 → hfutils-0.3.6}/README.md +0 -0
  11. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/__init__.py +0 -0
  12. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/__main__.py +0 -0
  13. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/archive/__init__.py +0 -0
  14. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/archive/base.py +0 -0
  15. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/archive/rar.py +0 -0
  16. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/archive/sevenz.py +0 -0
  17. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/archive/tar.py +0 -0
  18. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/archive/zip.py +0 -0
  19. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/cache/__init__.py +0 -0
  20. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/cache/delete.py +0 -0
  21. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/config/__init__.py +0 -0
  22. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/entry/__init__.py +0 -0
  23. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/entry/base.py +0 -0
  24. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/entry/cli.py +0 -0
  25. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/entry/clone.py +0 -0
  26. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/entry/dispatch.py +0 -0
  27. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/entry/download.py +0 -0
  28. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/entry/index.py +0 -0
  29. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/entry/ls.py +0 -0
  30. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/entry/ls_repo.py +0 -0
  31. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/entry/rollback.py +0 -0
  32. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/entry/upload.py +0 -0
  33. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/entry/whoami.py +0 -0
  34. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/index/hash.py +0 -0
  35. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/index/make.py +0 -0
  36. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/index/validate.py +0 -0
  37. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/operate/__init__.py +0 -0
  38. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/operate/base.py +0 -0
  39. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/operate/download.py +0 -0
  40. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/operate/upload.py +0 -0
  41. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/operate/validate.py +0 -0
  42. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/repository/__init__.py +0 -0
  43. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/repository/base.py +0 -0
  44. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/repository/clone.py +0 -0
  45. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/repository/rollback.py +0 -0
  46. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/utils/__init__.py +0 -0
  47. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/utils/binary.py +0 -0
  48. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/utils/download.py +0 -0
  49. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/utils/irregular_repo.json +0 -0
  50. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/utils/logging.py +0 -0
  51. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/utils/number.py +0 -0
  52. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/utils/path.py +0 -0
  53. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/utils/temp.py +0 -0
  54. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/utils/tqdm_.py +0 -0
  55. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils/utils/walk.py +0 -0
  56. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils.egg-info/dependency_links.txt +0 -0
  57. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils.egg-info/entry_points.txt +0 -0
  58. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils.egg-info/requires.txt +0 -0
  59. {hfutils-0.3.4 → hfutils-0.3.6}/hfutils.egg-info/top_level.txt +0 -0
  60. {hfutils-0.3.4 → hfutils-0.3.6}/requirements-7z.txt +0 -0
  61. {hfutils-0.3.4 → hfutils-0.3.6}/requirements-build.txt +0 -0
  62. {hfutils-0.3.4 → hfutils-0.3.6}/requirements-doc.txt +0 -0
  63. {hfutils-0.3.4 → hfutils-0.3.6}/requirements-rar.txt +0 -0
  64. {hfutils-0.3.4 → hfutils-0.3.6}/requirements-test.txt +0 -0
  65. {hfutils-0.3.4 → hfutils-0.3.6}/requirements-transfer.txt +0 -0
  66. {hfutils-0.3.4 → hfutils-0.3.6}/requirements.txt +0 -0
  67. {hfutils-0.3.4 → hfutils-0.3.6}/setup.cfg +0 -0
  68. {hfutils-0.3.4 → hfutils-0.3.6}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hfutils
3
- Version: 0.3.4
3
+ Version: 0.3.6
4
4
  Summary: Useful utilities for huggingface
5
5
  Home-page: https://github.com/deepghs/hfutils
6
6
  Author: narugo1992
@@ -29,28 +29,6 @@ Requires-Dist: tzlocal
29
29
  Requires-Dist: natsort
30
30
  Requires-Dist: urlobject
31
31
  Requires-Dist: fsspec>=2024
32
- Provides-Extra: test
33
- Requires-Dist: coverage>=5; extra == "test"
34
- Requires-Dist: mock>=4.0.3; extra == "test"
35
- Requires-Dist: flake8~=3.5; extra == "test"
36
- Requires-Dist: testfixtures>=6.18.5; extra == "test"
37
- Requires-Dist: pytest~=6.2.5; extra == "test"
38
- Requires-Dist: pytest-cov~=3.0.0; extra == "test"
39
- Requires-Dist: pytest-mock~=3.6.1; extra == "test"
40
- Requires-Dist: pytest-xdist>=1.34.0; extra == "test"
41
- Requires-Dist: pytest-rerunfailures~=10.2; extra == "test"
42
- Requires-Dist: pytest-timeout~=2.0.2; extra == "test"
43
- Requires-Dist: pytest-benchmark~=3.4.0; extra == "test"
44
- Requires-Dist: easydict<2,>=1.7; extra == "test"
45
- Requires-Dist: testtools>=2; extra == "test"
46
- Requires-Dist: where>=1.0.2; extra == "test"
47
- Requires-Dist: responses>=0.20.0; extra == "test"
48
- Requires-Dist: natsort; extra == "test"
49
- Provides-Extra: 7z
50
- Requires-Dist: py7zr; extra == "7z"
51
- Provides-Extra: build
52
- Requires-Dist: pyinstaller<5,>=4.7; extra == "build"
53
- Requires-Dist: setuptools<70; extra == "build"
54
32
  Provides-Extra: doc
55
33
  Requires-Dist: Jinja2>=3.0.0; extra == "doc"
56
34
  Requires-Dist: sphinx>=3.2.0; extra == "doc"
@@ -71,8 +49,30 @@ Requires-Dist: ipykernel>=6.15; extra == "doc"
71
49
  Requires-Dist: py-cpuinfo>=8.0.0; extra == "doc"
72
50
  Requires-Dist: click>=7.0.0; extra == "doc"
73
51
  Requires-Dist: pandas; extra == "doc"
52
+ Provides-Extra: test
53
+ Requires-Dist: coverage>=5; extra == "test"
54
+ Requires-Dist: mock>=4.0.3; extra == "test"
55
+ Requires-Dist: flake8~=3.5; extra == "test"
56
+ Requires-Dist: testfixtures>=6.18.5; extra == "test"
57
+ Requires-Dist: pytest~=6.2.5; extra == "test"
58
+ Requires-Dist: pytest-cov~=3.0.0; extra == "test"
59
+ Requires-Dist: pytest-mock~=3.6.1; extra == "test"
60
+ Requires-Dist: pytest-xdist>=1.34.0; extra == "test"
61
+ Requires-Dist: pytest-rerunfailures~=10.2; extra == "test"
62
+ Requires-Dist: pytest-timeout~=2.0.2; extra == "test"
63
+ Requires-Dist: pytest-benchmark~=3.4.0; extra == "test"
64
+ Requires-Dist: easydict<2,>=1.7; extra == "test"
65
+ Requires-Dist: testtools>=2; extra == "test"
66
+ Requires-Dist: where>=1.0.2; extra == "test"
67
+ Requires-Dist: responses>=0.20.0; extra == "test"
68
+ Requires-Dist: natsort; extra == "test"
74
69
  Provides-Extra: transfer
75
70
  Requires-Dist: hf-transfer; extra == "transfer"
71
+ Provides-Extra: 7z
72
+ Requires-Dist: py7zr; extra == "7z"
73
+ Provides-Extra: build
74
+ Requires-Dist: pyinstaller<5,>=4.7; extra == "build"
75
+ Requires-Dist: setuptools<70; extra == "build"
76
76
  Provides-Extra: rar
77
77
  Requires-Dist: rarfile; extra == "rar"
78
78
 
@@ -7,7 +7,7 @@ Overview:
7
7
  __TITLE__ = 'hfutils'
8
8
 
9
9
  #: Version of this project.
10
- __VERSION__ = '0.3.4'
10
+ __VERSION__ = '0.3.6'
11
11
 
12
12
  #: Short description of the project, will be included in ``setup.py``.
13
13
  __DESCRIPTION__ = 'Useful utilities for huggingface'
@@ -1,4 +1,5 @@
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
+ from .local_fetch import tar_get_index, tar_file_info, tar_file_download, tar_file_size, tar_file_exists, tar_list_files
3
4
  from .make import tar_create_index, hf_tar_create_index, tar_get_index_info, hf_tar_create_from_directory
4
5
  from .validate import hf_tar_item_validate, hf_tar_validate
@@ -1,6 +1,8 @@
1
1
  import json
2
2
  import os.path
3
- from typing import Optional, Dict, Union
3
+ import threading
4
+ from collections import defaultdict
5
+ from typing import Optional, Dict, Union, List
4
6
 
5
7
  from huggingface_hub.file_download import http_get, hf_hub_url
6
8
  from huggingface_hub.utils import build_hf_headers
@@ -21,6 +23,9 @@ class ArchiveStandaloneFileHashNotMatch(Exception):
21
23
  """
22
24
 
23
25
 
26
+ _HF_TAR_IDX_LOCKS = defaultdict(threading.Lock)
27
+
28
+
24
29
  def hf_tar_get_index(repo_id: str, archive_in_repo: str,
25
30
  repo_type: RepoTypeTyping = 'dataset', revision: str = 'main',
26
31
  idx_repo_id: Optional[str] = None, idx_file_in_repo: Optional[str] = None,
@@ -83,20 +88,25 @@ def hf_tar_get_index(repo_id: str, archive_in_repo: str,
83
88
  hf_client = get_hf_client(hf_token)
84
89
  body, _ = os.path.splitext(archive_in_repo)
85
90
  default_index_file = f'{body}.json'
86
- with open(hf_client.hf_hub_download(
87
- repo_id=idx_repo_id or repo_id,
88
- repo_type=idx_repo_type or repo_type,
89
- filename=idx_file_in_repo or default_index_file,
90
- revision=idx_revision or revision,
91
- ), 'r') as f:
92
- return json.load(f)
91
+ f_repo_id = idx_repo_id or repo_id
92
+ f_repo_type = idx_repo_type or repo_type
93
+ f_filename = idx_file_in_repo or default_index_file
94
+ f_revision = idx_revision or revision
95
+ with _HF_TAR_IDX_LOCKS[(f_repo_id, f_repo_type, f_filename, f_revision)]:
96
+ with open(hf_client.hf_hub_download(
97
+ repo_id=f_repo_id,
98
+ repo_type=f_repo_type,
99
+ filename=f_filename,
100
+ revision=f_revision,
101
+ ), 'r') as f:
102
+ return json.load(f)
93
103
 
94
104
 
95
105
  def hf_tar_list_files(repo_id: str, archive_in_repo: str,
96
106
  repo_type: RepoTypeTyping = 'dataset', revision: str = 'main',
97
107
  idx_repo_id: Optional[str] = None, idx_file_in_repo: Optional[str] = None,
98
108
  idx_repo_type: Optional[RepoTypeTyping] = None, idx_revision: Optional[str] = None,
99
- hf_token: Optional[str] = None):
109
+ hf_token: Optional[str] = None) -> List[str]:
100
110
  """
101
111
  List files inside a tar archive file in a Hugging Face repository.
102
112
 
@@ -0,0 +1,242 @@
1
+ """
2
+ This module provides utility functions for working with tar archives and their associated index files.
3
+ It includes functions for retrieving archive indexes, listing files, checking file existence,
4
+ getting file information, and downloading files from archives.
5
+
6
+ The module relies on a JSON-based index file that contains metadata about the files within the archive,
7
+ including their offsets, sizes, and optional SHA256 hashes.
8
+
9
+ Functions in this module are designed to work with both local archive files and their corresponding
10
+ index files, providing a convenient interface for archive manipulation and file extraction.
11
+ """
12
+
13
+ import json
14
+ import os
15
+ from typing import Optional, List
16
+
17
+
18
+ def tar_get_index(archive_file: str, idx_file: Optional[str] = None):
19
+ """
20
+ Retrieve the index data for a given tar archive file.
21
+
22
+ This function reads the JSON index file associated with the archive,
23
+ which contains metadata about the files within the archive.
24
+
25
+ :param archive_file: Path to the tar archive file.
26
+ :type archive_file: str
27
+ :param idx_file: Optional path to the index file. If not provided,
28
+ it will be inferred from the archive file name.
29
+ :type idx_file: Optional[str]
30
+
31
+ :return: The parsed JSON data from the index file.
32
+ :rtype: dict
33
+
34
+ :raises FileNotFoundError: If the index file is not found.
35
+ :raises json.JSONDecodeError: If the index file is not valid JSON.
36
+
37
+ :example:
38
+ >>> index_data = tar_get_index('my_archive.tar')
39
+ """
40
+ body, _ = os.path.splitext(archive_file)
41
+ default_index_file = f'{body}.json'
42
+ with open(idx_file or default_index_file, 'r') as f:
43
+ return json.load(f)
44
+
45
+
46
+ def tar_list_files(archive_file: str, idx_file: Optional[str] = None) -> List[str]:
47
+ """
48
+ List all files contained within the specified tar archive.
49
+
50
+ This function uses the archive's index file to retrieve the list of files
51
+ without actually reading the tar archive itself.
52
+
53
+ :param archive_file: Path to the tar archive file.
54
+ :type archive_file: str
55
+ :param idx_file: Optional path to the index file. If not provided,
56
+ it will be inferred from the archive file name.
57
+ :type idx_file: Optional[str]
58
+
59
+ :return: A list of file names contained in the archive.
60
+ :rtype: List[str]
61
+
62
+ :example:
63
+ >>> files = tar_list_files('my_archive.tar')
64
+ >>> for file in files:
65
+ >>> print(file)
66
+ """
67
+ index_data = tar_get_index(
68
+ archive_file=archive_file,
69
+ idx_file=idx_file,
70
+ )
71
+ return list(index_data['files'].keys())
72
+
73
+
74
+ def tar_file_exists(archive_file: str, file_in_archive: str, idx_file: Optional[str] = None) -> bool:
75
+ """
76
+ Check if a specific file exists within the tar archive.
77
+
78
+ This function uses the archive's index to check for file existence
79
+ without reading the entire archive.
80
+
81
+ :param archive_file: Path to the tar archive file.
82
+ :type archive_file: str
83
+ :param file_in_archive: The name of the file to check for in the archive.
84
+ :type file_in_archive: str
85
+ :param idx_file: Optional path to the index file. If not provided,
86
+ it will be inferred from the archive file name.
87
+ :type idx_file: Optional[str]
88
+
89
+ :return: True if the file exists in the archive, False otherwise.
90
+ :rtype: bool
91
+
92
+ :example:
93
+ >>> exists = tar_file_exists('my_archive.tar', 'path/to/file.txt')
94
+ >>> if exists:
95
+ >>> print("File exists in the archive")
96
+ """
97
+ from .fetch import _hf_files_process, _n_path
98
+ index = tar_get_index(
99
+ archive_file=archive_file,
100
+ idx_file=idx_file,
101
+ )
102
+ files = _hf_files_process(index['files'])
103
+ return _n_path(file_in_archive) in files
104
+
105
+
106
+ def tar_file_info(archive_file: str, file_in_archive: str, idx_file: Optional[str] = None) -> dict:
107
+ """
108
+ Retrieve information about a specific file within the tar archive.
109
+
110
+ This function returns a dictionary containing metadata about the specified file,
111
+ such as its size and offset within the archive.
112
+
113
+ :param archive_file: Path to the tar archive file.
114
+ :type archive_file: str
115
+ :param file_in_archive: The name of the file to get information for.
116
+ :type file_in_archive: str
117
+ :param idx_file: Optional path to the index file. If not provided,
118
+ it will be inferred from the archive file name.
119
+ :type idx_file: Optional[str]
120
+
121
+ :return: A dictionary containing file metadata.
122
+ :rtype: dict
123
+
124
+ :raises FileNotFoundError: If the specified file is not found in the archive.
125
+
126
+ :example:
127
+ >>> info = tar_file_info('my_archive.tar', 'path/to/file.txt')
128
+ >>> print(f"File size: {info['size']} bytes")
129
+ """
130
+ from .fetch import _hf_files_process, _n_path
131
+ index = tar_get_index(
132
+ archive_file=archive_file,
133
+ idx_file=idx_file,
134
+ )
135
+ files = _hf_files_process(index['files'])
136
+ if _n_path(file_in_archive) not in files:
137
+ raise FileNotFoundError(f'File {file_in_archive!r} not found '
138
+ f'in local archive {archive_file!r}.')
139
+ else:
140
+ return files[_n_path(file_in_archive)]
141
+
142
+
143
+ def tar_file_size(archive_file: str, file_in_archive: str, idx_file: Optional[str] = None) -> int:
144
+ """
145
+ Get the size of a specific file within the tar archive.
146
+
147
+ This function returns the size of the specified file in bytes.
148
+
149
+ :param archive_file: Path to the tar archive file.
150
+ :type archive_file: str
151
+ :param file_in_archive: The name of the file to get the size for.
152
+ :type file_in_archive: str
153
+ :param idx_file: Optional path to the index file. If not provided,
154
+ it will be inferred from the archive file name.
155
+ :type idx_file: Optional[str]
156
+
157
+ :return: The size of the file in bytes.
158
+ :rtype: int
159
+
160
+ :raises FileNotFoundError: If the specified file is not found in the archive.
161
+
162
+ :example:
163
+ >>> size = tar_file_size('my_archive.tar', 'path/to/file.txt')
164
+ >>> print(f"File size: {size} bytes")
165
+ """
166
+ return tar_file_info(
167
+ archive_file=archive_file,
168
+ file_in_archive=file_in_archive,
169
+ idx_file=idx_file,
170
+ )['size']
171
+
172
+
173
+ def tar_file_download(archive_file: str, file_in_archive: str, local_file: str,
174
+ idx_file: Optional[str] = None, chunk_size: int = 1 << 20):
175
+ """
176
+ Extract and download a specific file from the tar archive to a local file.
177
+
178
+ This function reads the specified file from the archive and writes it to a local file.
179
+ It also performs integrity checks to ensure the downloaded file is complete and matches
180
+ the expected hash (if provided in the index).
181
+
182
+ :param archive_file: Path to the tar archive file.
183
+ :type archive_file: str
184
+ :param file_in_archive: The name of the file to extract from the archive.
185
+ :type file_in_archive: str
186
+ :param local_file: The path where the extracted file should be saved.
187
+ :type local_file: str
188
+ :param idx_file: Optional path to the index file. If not provided,
189
+ it will be inferred from the archive file name.
190
+ :type idx_file: Optional[str]
191
+ :param chunk_size: The size of chunks to read and write, in bytes. Default is 1MB.
192
+ :type chunk_size: int
193
+
194
+ :raises FileNotFoundError: If the specified file is not found in the archive.
195
+ :raises ArchiveStandaloneFileIncompleteDownload: If the downloaded file size doesn't match the expected size.
196
+ :raises ArchiveStandaloneFileHashNotMatch: If the SHA256 hash of the downloaded file doesn't match the expected hash.
197
+
198
+ :example:
199
+ >>> tar_file_download('my_archive.tar', 'path/to/file.txt', 'local_file.txt')
200
+ """
201
+ from .fetch import _hf_files_process, _n_path, _f_sha256, \
202
+ ArchiveStandaloneFileIncompleteDownload, ArchiveStandaloneFileHashNotMatch
203
+
204
+ index = tar_get_index(
205
+ archive_file=archive_file,
206
+ idx_file=idx_file,
207
+ )
208
+ files = _hf_files_process(index['files'])
209
+ if _n_path(file_in_archive) not in files:
210
+ raise FileNotFoundError(f'File {file_in_archive!r} not found '
211
+ f'in local archive {archive_file!r}.')
212
+
213
+ info = files[_n_path(file_in_archive)]
214
+
215
+ if os.path.dirname(local_file):
216
+ os.makedirs(os.path.dirname(local_file), exist_ok=True)
217
+ try:
218
+ with open(local_file, 'wb') as wf:
219
+ if info['size'] > 0:
220
+ with open(archive_file, 'rb') as rf:
221
+ rf.seek(info['offset'])
222
+ tp = info['offset'] + info['size']
223
+ while rf.tell() < tp:
224
+ read_bytes = min(tp - rf.tell(), chunk_size)
225
+ wf.write(rf.read(read_bytes))
226
+
227
+ if os.path.getsize(local_file) != info['size']:
228
+ raise ArchiveStandaloneFileIncompleteDownload(
229
+ f'Expected size is {info["size"]}, but actually {os.path.getsize(local_file)} downloaded.'
230
+ )
231
+
232
+ if info.get('sha256'):
233
+ _sha256 = _f_sha256(local_file)
234
+ if _sha256 != info['sha256']:
235
+ raise ArchiveStandaloneFileHashNotMatch(
236
+ f'Expected hash is {info["sha256"]!r}, but actually {_sha256!r} found.'
237
+ )
238
+
239
+ except Exception:
240
+ if os.path.exists(local_file):
241
+ os.remove(local_file)
242
+ raise
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hfutils
3
- Version: 0.3.4
3
+ Version: 0.3.6
4
4
  Summary: Useful utilities for huggingface
5
5
  Home-page: https://github.com/deepghs/hfutils
6
6
  Author: narugo1992
@@ -29,28 +29,6 @@ Requires-Dist: tzlocal
29
29
  Requires-Dist: natsort
30
30
  Requires-Dist: urlobject
31
31
  Requires-Dist: fsspec>=2024
32
- Provides-Extra: test
33
- Requires-Dist: coverage>=5; extra == "test"
34
- Requires-Dist: mock>=4.0.3; extra == "test"
35
- Requires-Dist: flake8~=3.5; extra == "test"
36
- Requires-Dist: testfixtures>=6.18.5; extra == "test"
37
- Requires-Dist: pytest~=6.2.5; extra == "test"
38
- Requires-Dist: pytest-cov~=3.0.0; extra == "test"
39
- Requires-Dist: pytest-mock~=3.6.1; extra == "test"
40
- Requires-Dist: pytest-xdist>=1.34.0; extra == "test"
41
- Requires-Dist: pytest-rerunfailures~=10.2; extra == "test"
42
- Requires-Dist: pytest-timeout~=2.0.2; extra == "test"
43
- Requires-Dist: pytest-benchmark~=3.4.0; extra == "test"
44
- Requires-Dist: easydict<2,>=1.7; extra == "test"
45
- Requires-Dist: testtools>=2; extra == "test"
46
- Requires-Dist: where>=1.0.2; extra == "test"
47
- Requires-Dist: responses>=0.20.0; extra == "test"
48
- Requires-Dist: natsort; extra == "test"
49
- Provides-Extra: 7z
50
- Requires-Dist: py7zr; extra == "7z"
51
- Provides-Extra: build
52
- Requires-Dist: pyinstaller<5,>=4.7; extra == "build"
53
- Requires-Dist: setuptools<70; extra == "build"
54
32
  Provides-Extra: doc
55
33
  Requires-Dist: Jinja2>=3.0.0; extra == "doc"
56
34
  Requires-Dist: sphinx>=3.2.0; extra == "doc"
@@ -71,8 +49,30 @@ Requires-Dist: ipykernel>=6.15; extra == "doc"
71
49
  Requires-Dist: py-cpuinfo>=8.0.0; extra == "doc"
72
50
  Requires-Dist: click>=7.0.0; extra == "doc"
73
51
  Requires-Dist: pandas; extra == "doc"
52
+ Provides-Extra: test
53
+ Requires-Dist: coverage>=5; extra == "test"
54
+ Requires-Dist: mock>=4.0.3; extra == "test"
55
+ Requires-Dist: flake8~=3.5; extra == "test"
56
+ Requires-Dist: testfixtures>=6.18.5; extra == "test"
57
+ Requires-Dist: pytest~=6.2.5; extra == "test"
58
+ Requires-Dist: pytest-cov~=3.0.0; extra == "test"
59
+ Requires-Dist: pytest-mock~=3.6.1; extra == "test"
60
+ Requires-Dist: pytest-xdist>=1.34.0; extra == "test"
61
+ Requires-Dist: pytest-rerunfailures~=10.2; extra == "test"
62
+ Requires-Dist: pytest-timeout~=2.0.2; extra == "test"
63
+ Requires-Dist: pytest-benchmark~=3.4.0; extra == "test"
64
+ Requires-Dist: easydict<2,>=1.7; extra == "test"
65
+ Requires-Dist: testtools>=2; extra == "test"
66
+ Requires-Dist: where>=1.0.2; extra == "test"
67
+ Requires-Dist: responses>=0.20.0; extra == "test"
68
+ Requires-Dist: natsort; extra == "test"
74
69
  Provides-Extra: transfer
75
70
  Requires-Dist: hf-transfer; extra == "transfer"
71
+ Provides-Extra: 7z
72
+ Requires-Dist: py7zr; extra == "7z"
73
+ Provides-Extra: build
74
+ Requires-Dist: pyinstaller<5,>=4.7; extra == "build"
75
+ Requires-Dist: setuptools<70; extra == "build"
76
76
  Provides-Extra: rar
77
77
  Requires-Dist: rarfile; extra == "rar"
78
78
 
@@ -42,6 +42,7 @@ hfutils/entry/whoami.py
42
42
  hfutils/index/__init__.py
43
43
  hfutils/index/fetch.py
44
44
  hfutils/index/hash.py
45
+ hfutils/index/local_fetch.py
45
46
  hfutils/index/make.py
46
47
  hfutils/index/validate.py
47
48
  hfutils/operate/__init__.py
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