hfutils 0.3.2__tar.gz → 0.3.4__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.2/hfutils.egg-info → hfutils-0.3.4}/PKG-INFO +2 -1
  2. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/config/meta.py +1 -1
  3. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/entry/download.py +11 -3
  4. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/operate/__init__.py +1 -1
  5. hfutils-0.3.4/hfutils/operate/base.py +267 -0
  6. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/operate/download.py +18 -6
  7. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/operate/upload.py +8 -1
  8. {hfutils-0.3.2 → hfutils-0.3.4/hfutils.egg-info}/PKG-INFO +2 -1
  9. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils.egg-info/requires.txt +1 -0
  10. {hfutils-0.3.2 → hfutils-0.3.4}/requirements.txt +2 -1
  11. hfutils-0.3.2/hfutils/operate/base.py +0 -135
  12. {hfutils-0.3.2 → hfutils-0.3.4}/LICENSE +0 -0
  13. {hfutils-0.3.2 → hfutils-0.3.4}/MANIFEST.in +0 -0
  14. {hfutils-0.3.2 → hfutils-0.3.4}/README.md +0 -0
  15. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/__init__.py +0 -0
  16. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/__main__.py +0 -0
  17. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/archive/__init__.py +0 -0
  18. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/archive/base.py +0 -0
  19. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/archive/rar.py +0 -0
  20. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/archive/sevenz.py +0 -0
  21. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/archive/tar.py +0 -0
  22. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/archive/zip.py +0 -0
  23. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/cache/__init__.py +0 -0
  24. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/cache/delete.py +0 -0
  25. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/config/__init__.py +0 -0
  26. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/entry/__init__.py +0 -0
  27. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/entry/base.py +0 -0
  28. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/entry/cli.py +0 -0
  29. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/entry/clone.py +0 -0
  30. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/entry/dispatch.py +0 -0
  31. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/entry/index.py +0 -0
  32. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/entry/ls.py +0 -0
  33. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/entry/ls_repo.py +0 -0
  34. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/entry/rollback.py +0 -0
  35. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/entry/upload.py +0 -0
  36. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/entry/whoami.py +0 -0
  37. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/index/__init__.py +0 -0
  38. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/index/fetch.py +0 -0
  39. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/index/hash.py +0 -0
  40. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/index/make.py +0 -0
  41. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/index/validate.py +0 -0
  42. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/operate/validate.py +0 -0
  43. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/repository/__init__.py +0 -0
  44. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/repository/base.py +0 -0
  45. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/repository/clone.py +0 -0
  46. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/repository/rollback.py +0 -0
  47. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/utils/__init__.py +0 -0
  48. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/utils/binary.py +0 -0
  49. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/utils/download.py +0 -0
  50. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/utils/irregular_repo.json +0 -0
  51. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/utils/logging.py +0 -0
  52. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/utils/number.py +0 -0
  53. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/utils/path.py +0 -0
  54. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/utils/temp.py +0 -0
  55. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/utils/tqdm_.py +0 -0
  56. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils/utils/walk.py +0 -0
  57. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils.egg-info/SOURCES.txt +0 -0
  58. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils.egg-info/dependency_links.txt +0 -0
  59. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils.egg-info/entry_points.txt +0 -0
  60. {hfutils-0.3.2 → hfutils-0.3.4}/hfutils.egg-info/top_level.txt +0 -0
  61. {hfutils-0.3.2 → hfutils-0.3.4}/requirements-7z.txt +0 -0
  62. {hfutils-0.3.2 → hfutils-0.3.4}/requirements-build.txt +0 -0
  63. {hfutils-0.3.2 → hfutils-0.3.4}/requirements-doc.txt +0 -0
  64. {hfutils-0.3.2 → hfutils-0.3.4}/requirements-rar.txt +0 -0
  65. {hfutils-0.3.2 → hfutils-0.3.4}/requirements-test.txt +0 -0
  66. {hfutils-0.3.2 → hfutils-0.3.4}/requirements-transfer.txt +0 -0
  67. {hfutils-0.3.2 → hfutils-0.3.4}/setup.cfg +0 -0
  68. {hfutils-0.3.2 → hfutils-0.3.4}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hfutils
3
- Version: 0.3.2
3
+ Version: 0.3.4
4
4
  Summary: Useful utilities for huggingface
5
5
  Home-page: https://github.com/deepghs/hfutils
6
6
  Author: narugo1992
@@ -28,6 +28,7 @@ Requires-Dist: click>=7
28
28
  Requires-Dist: tzlocal
29
29
  Requires-Dist: natsort
30
30
  Requires-Dist: urlobject
31
+ Requires-Dist: fsspec>=2024
31
32
  Provides-Extra: test
32
33
  Requires-Dist: coverage>=5; extra == "test"
33
34
  Requires-Dist: mock>=4.0.3; extra == "test"
@@ -7,7 +7,7 @@ Overview:
7
7
  __TITLE__ = 'hfutils'
8
8
 
9
9
  #: Version of this project.
10
- __VERSION__ = '0.3.2'
10
+ __VERSION__ = '0.3.4'
11
11
 
12
12
  #: Short description of the project, will be included in ``setup.py``.
13
13
  __DESCRIPTION__ = 'Useful utilities for huggingface'
@@ -47,12 +47,17 @@ def _add_download_subcommand(cli: click.Group) -> click.Group:
47
47
  help='Max threads to download.', show_default=True)
48
48
  @click.option('-p', '--password', 'password', type=str, default=None,
49
49
  help='Password for the archive file. Only applied when -a is used.', show_default=True)
50
+ @click.option('-w', '--wildcard', 'wildcard', type=str, default=None,
51
+ help='Wildcard for files to download. Only applied when -d is used.', show_default=True)
50
52
  @click.option('--tmpdir', 'tmpdir', type=str, default=None,
51
53
  help='Use custom temporary Directory.', show_default=True)
52
54
  @command_wrap()
53
- def download(repo_id: str, repo_type: RepoTypeTyping,
54
- file_in_repo: Optional[str], archive_in_repo: Optional[str], dir_in_repo: Optional[str],
55
- output_path: str, revision: str, max_workers: int, password: Optional[str], tmpdir: Optional[str]):
55
+ def download(
56
+ repo_id: str, repo_type: RepoTypeTyping,
57
+ file_in_repo: Optional[str], archive_in_repo: Optional[str], dir_in_repo: Optional[str],
58
+ output_path: str, revision: str, max_workers: int,
59
+ password: Optional[str], wildcard: Optional[str], tmpdir: Optional[str]
60
+ ):
56
61
  """
57
62
  Download data from HuggingFace repositories.
58
63
 
@@ -74,6 +79,8 @@ def _add_download_subcommand(cli: click.Group) -> click.Group:
74
79
  :type max_workers: int
75
80
  :param password: Password for the archive file. Only applied when -a is used.
76
81
  :type password: str, optional
82
+ :param wildcard: Wildcard for files to download. Only applied when -d is used.
83
+ :type password: str, optional
77
84
  :param tmpdir: Use custom temporary Directory.
78
85
  :type tmpdir: str, optional
79
86
  """
@@ -114,6 +121,7 @@ def _add_download_subcommand(cli: click.Group) -> click.Group:
114
121
  local_directory=output_path,
115
122
  repo_id=repo_id,
116
123
  dir_in_repo=dir_in_repo,
124
+ pattern=wildcard or '**/*',
117
125
  repo_type=repo_type,
118
126
  revision=revision,
119
127
  silent=False,
@@ -1,4 +1,4 @@
1
- from .base import get_hf_client, get_hf_fs, list_files_in_repository
1
+ from .base import get_hf_client, get_hf_fs, list_all_with_pattern, list_files_in_repository
2
2
  from .download import download_file_to_file, download_archive_as_directory, download_directory_as_directory
3
3
  from .upload import upload_file_to_file, upload_directory_as_archive, upload_directory_as_directory
4
4
  from .validate import is_local_file_ready
@@ -0,0 +1,267 @@
1
+ """
2
+ This module provides utilities for interacting with the Hugging Face Hub API and filesystem.
3
+ It includes functions for retrieving API clients, listing files in repositories, and handling
4
+ file patterns and ignore rules.
5
+
6
+ The module offers the following main functionalities:
7
+
8
+ 1. Retrieving Hugging Face API tokens and clients
9
+ 2. Accessing the Hugging Face filesystem
10
+ 3. Listing files in Hugging Face repositories with pattern matching and ignore rules
11
+ 4. Parsing and normalizing Hugging Face filesystem paths
12
+
13
+ These utilities are designed to simplify working with Hugging Face repositories, especially
14
+ when dealing with datasets, models, and spaces.
15
+ """
16
+
17
+ import fnmatch
18
+ import logging
19
+ import os
20
+ import re
21
+ from functools import lru_cache
22
+ from typing import Literal, List, Optional, Union, Iterator
23
+
24
+ from huggingface_hub import HfApi, HfFileSystem
25
+ from huggingface_hub.hf_api import RepoFolder, RepoFile
26
+ from huggingface_hub.utils import HfHubHTTPError
27
+
28
+ from ..utils import parse_hf_fs_path, hf_fs_path, tqdm, hf_normpath
29
+
30
+ RepoTypeTyping = Literal['dataset', 'model', 'space']
31
+ REPO_TYPES = ['dataset', 'model', 'space']
32
+
33
+
34
+ @lru_cache()
35
+ def _get_hf_token() -> Optional[str]:
36
+ """
37
+ Retrieve the Hugging Face token from the environment variable.
38
+
39
+ This function checks for the 'HF_TOKEN' environment variable and returns its value.
40
+ It is cached to avoid repeated environment variable lookups.
41
+
42
+ :return: The Hugging Face token if set, otherwise None.
43
+ :rtype: Optional[str]
44
+ """
45
+ return os.environ.get('HF_TOKEN')
46
+
47
+
48
+ @lru_cache()
49
+ def get_hf_client(hf_token: Optional[str] = None) -> HfApi:
50
+ """
51
+ Get the Hugging Face API client.
52
+
53
+ This function returns an instance of the Hugging Face API client. If a token is not provided,
54
+ it attempts to use the token from the environment variable.
55
+
56
+ :param hf_token: Hugging Face token for API client. If not provided, uses the 'HF_TOKEN' environment variable.
57
+ :type hf_token: Optional[str]
58
+
59
+ :return: An instance of the Hugging Face API client.
60
+ :rtype: HfApi
61
+
62
+ :example:
63
+
64
+ >>> client = get_hf_client()
65
+ >>> # Use client to interact with Hugging Face API
66
+ >>> client.list_repos(organization="huggingface")
67
+ """
68
+ return HfApi(token=hf_token or _get_hf_token())
69
+
70
+
71
+ @lru_cache()
72
+ def get_hf_fs(hf_token: Optional[str] = None) -> HfFileSystem:
73
+ """
74
+ Get the Hugging Face file system.
75
+
76
+ This function returns an instance of the Hugging Face file system. If a token is not provided,
77
+ it attempts to use the token from the environment variable. The file system is configured
78
+ not to use listings cache to ensure fresh results.
79
+
80
+ :param hf_token: Hugging Face token for API client. If not provided, uses the 'HF_TOKEN' environment variable.
81
+ :type hf_token: Optional[str]
82
+
83
+ :return: An instance of the Hugging Face file system.
84
+ :rtype: HfFileSystem
85
+
86
+ :example:
87
+
88
+ >>> fs = get_hf_fs()
89
+ >>> # Use fs to interact with Hugging Face file system
90
+ >>> fs.ls("dataset/example")
91
+ """
92
+ # use_listings_cache=False is necessary
93
+ # or the result of glob and ls will be cached, the unittest will down
94
+ return HfFileSystem(token=hf_token or _get_hf_token(), use_listings_cache=False)
95
+
96
+
97
+ _DEFAULT_IGNORE_PATTERNS = ['.git*']
98
+ _IGNORE_PATTERN_UNSET = object()
99
+
100
+
101
+ def _is_file_ignored(file_segments: List[str], ignore_patterns: List[str]) -> bool:
102
+ """
103
+ Check if a file should be ignored based on the given ignore patterns.
104
+
105
+ This function checks each segment of the file path against the provided ignore patterns.
106
+ If any segment matches any of the patterns, the file is considered ignored.
107
+
108
+ :param file_segments: The segments of the file path.
109
+ :type file_segments: List[str]
110
+ :param ignore_patterns: List of file patterns to ignore.
111
+ :type ignore_patterns: List[str]
112
+
113
+ :return: True if the file should be ignored, False otherwise.
114
+ :rtype: bool
115
+
116
+ :example:
117
+
118
+ >>> _is_file_ignored(['folder', 'file.txt'], ['.git*', '*.log'])
119
+ False
120
+ >>> _is_file_ignored(['folder', '.gitignore'], ['.git*', '*.log'])
121
+ True
122
+ """
123
+ for segment in file_segments:
124
+ for pattern in ignore_patterns:
125
+ if fnmatch.fnmatch(segment, pattern):
126
+ return True
127
+
128
+ return False
129
+
130
+
131
+ def list_all_with_pattern(
132
+ repo_id: str, pattern: str = '**/*', repo_type: RepoTypeTyping = 'dataset',
133
+ revision: str = 'main', startup_batch: int = 500, batch_factor: float = 0.8,
134
+ hf_token: Optional[str] = None, silent: bool = False
135
+ ) -> Iterator[Union[RepoFile, RepoFolder]]:
136
+ """
137
+ List all files and folders in a Hugging Face repository matching a given pattern.
138
+
139
+ This function retrieves information about files and folders in a repository that match
140
+ the specified pattern. It uses batching to handle large repositories efficiently.
141
+
142
+ :param repo_id: The identifier of the repository.
143
+ :type repo_id: str
144
+ :param pattern: Wildcard pattern to match files and folders. Default is `**/*` (all files and folders).
145
+ :type pattern: str
146
+ :param repo_type: The type of the repository ('dataset', 'model', 'space'). Default is 'dataset'.
147
+ :type repo_type: RepoTypeTyping
148
+ :param revision: The revision of the repository (e.g., branch, tag, commit hash). Default is 'main'.
149
+ :type revision: str
150
+ :param startup_batch: Initial batch size for retrieving path information. Default is 500.
151
+ :type startup_batch: int
152
+ :param batch_factor: Factor to reduce batch size if a request fails. Default is 0.8.
153
+ :type batch_factor: float
154
+ :param hf_token: Hugging Face token for API client. If not provided, uses the 'HF_TOKEN' environment variable.
155
+ :type hf_token: Optional[str]
156
+ :param silent: If True, suppresses progress bar. Default is False.
157
+ :type silent: bool
158
+
159
+ :return: An iterator of RepoFile and RepoFolder objects matching the pattern.
160
+ :rtype: Iterator[Union[RepoFile, RepoFolder]]
161
+
162
+ :raises HfHubHTTPError: If there's an error in the API request that's not related to batch size.
163
+
164
+ :example:
165
+
166
+ >>> for item in list_all_with_pattern("username/repo", pattern="*.txt"):
167
+ ... print(item.path)
168
+ """
169
+ hf_fs = get_hf_fs(hf_token=hf_token)
170
+ hf_client = get_hf_client(hf_token=hf_token)
171
+
172
+ try:
173
+ paths = [
174
+ parse_hf_fs_path(path).filename
175
+ for path in hf_fs.glob(hf_fs_path(
176
+ repo_id=repo_id,
177
+ repo_type=repo_type,
178
+ filename=pattern,
179
+ revision=revision,
180
+ ))
181
+ ]
182
+ except FileNotFoundError:
183
+ return
184
+
185
+ offset, batch_size = 0, startup_batch
186
+ progress = tqdm(total=len(paths), desc='Paths Info', silent=silent)
187
+ while offset < len(paths):
188
+ batch_paths = paths[offset:offset + batch_size]
189
+ try:
190
+ all_items = hf_client.get_paths_info(
191
+ repo_id=repo_id,
192
+ repo_type=repo_type,
193
+ paths=batch_paths,
194
+ revision=revision,
195
+ )
196
+ except HfHubHTTPError as err:
197
+ if err.response.status_code == 413:
198
+ new_batch_size = max(1, int(round(batch_size * batch_factor)))
199
+ logging.warning(f'Reducing batch size {batch_size} --> {new_batch_size} ...')
200
+ batch_size = new_batch_size
201
+ continue
202
+ raise
203
+ else:
204
+ progress.update(len(all_items))
205
+ offset += len(all_items)
206
+ yield from all_items
207
+
208
+
209
+ def list_files_in_repository(
210
+ repo_id: str, repo_type: RepoTypeTyping = 'dataset',
211
+ subdir: str = '', pattern: str = '**/*', revision: str = 'main',
212
+ ignore_patterns: List[str] = _IGNORE_PATTERN_UNSET,
213
+ hf_token: Optional[str] = None, silent: bool = False) -> List[str]:
214
+ """
215
+ List files in a Hugging Face repository based on the given parameters.
216
+
217
+ This function retrieves a list of file paths in a specified repository that match
218
+ the given pattern and are not ignored by the ignore patterns.
219
+
220
+ :param repo_id: The identifier of the repository.
221
+ :type repo_id: str
222
+ :param repo_type: The type of the repository ('dataset', 'model', 'space'). Default is 'dataset'.
223
+ :type repo_type: RepoTypeTyping
224
+ :param subdir: The subdirectory to list files from. Default is an empty string (root directory).
225
+ :type subdir: str
226
+ :param pattern: Wildcard pattern of the target files. Default is `**/*` (all files).
227
+ :type pattern: str
228
+ :param revision: The revision of the repository (e.g., branch, tag, commit hash). Default is 'main'.
229
+ :type revision: str
230
+ :param ignore_patterns: List of file patterns to ignore. If not set, uses default ignore patterns.
231
+ :type ignore_patterns: List[str]
232
+ :param hf_token: Hugging Face token for API client. If not provided, uses the 'HF_TOKEN' environment variable.
233
+ :type hf_token: Optional[str]
234
+ :param silent: If True, suppresses progress bar. Default is False.
235
+ :type silent: bool
236
+
237
+ :return: A list of file paths that match the criteria.
238
+ :rtype: List[str]
239
+
240
+ :example:
241
+
242
+ >>> files = list_files_in_repository("username/repo", pattern="*.txt", ignore_patterns=[".git*", "*.log"])
243
+ >>> print(files)
244
+ ['file1.txt', 'folder/file2.txt']
245
+ """
246
+ if ignore_patterns is _IGNORE_PATTERN_UNSET:
247
+ ignore_patterns = _DEFAULT_IGNORE_PATTERNS
248
+
249
+ if subdir and subdir != '.':
250
+ pattern = f'{subdir}/{pattern}'
251
+
252
+ result = []
253
+ for item in list_all_with_pattern(
254
+ repo_id=repo_id,
255
+ repo_type=repo_type,
256
+ revision=revision,
257
+ pattern=pattern,
258
+ hf_token=hf_token,
259
+ silent=silent,
260
+ ):
261
+ if isinstance(item, RepoFile):
262
+ path = hf_normpath(os.path.relpath(item.path, start=subdir or '.'))
263
+ segments = list(filter(bool, re.split(r'[\\/]+', path)))
264
+ if not _is_file_ignored(segments, ignore_patterns):
265
+ result.append(path)
266
+
267
+ return result
@@ -80,11 +80,13 @@ def download_archive_as_directory(local_directory: str, repo_id: str, file_in_re
80
80
  archive_unpack(archive_file, local_directory, password=password)
81
81
 
82
82
 
83
- def download_directory_as_directory(local_directory: str, repo_id: str, dir_in_repo: str = '.',
84
- repo_type: RepoTypeTyping = 'dataset', revision: str = 'main',
85
- silent: bool = False, ignore_patterns: List[str] = _IGNORE_PATTERN_UNSET,
86
- resume_download: bool = True, max_workers: int = 8, max_retries: int = 5,
87
- hf_token: Optional[str] = None):
83
+ def download_directory_as_directory(
84
+ local_directory: str, repo_id: str, dir_in_repo: str = '.', pattern: str = '**/*',
85
+ repo_type: RepoTypeTyping = 'dataset', revision: str = 'main',
86
+ silent: bool = False, ignore_patterns: List[str] = _IGNORE_PATTERN_UNSET,
87
+ resume_download: bool = True, max_workers: int = 8, max_retries: int = 5,
88
+ hf_token: Optional[str] = None
89
+ ):
88
90
  """
89
91
  Download all files in a directory from a Hugging Face repository to a local directory.
90
92
 
@@ -94,6 +96,8 @@ def download_directory_as_directory(local_directory: str, repo_id: str, dir_in_r
94
96
  :type repo_id: str
95
97
  :param dir_in_repo: The directory path within the repository.
96
98
  :type dir_in_repo: str
99
+ :param pattern: Patterns for filtering.
100
+ :type pattern: str
97
101
  :param repo_type: The type of the repository ('dataset', 'model', 'space').
98
102
  :type repo_type: RepoTypeTyping
99
103
  :param revision: The revision of the repository (e.g., branch, tag, commit hash).
@@ -111,7 +115,15 @@ def download_directory_as_directory(local_directory: str, repo_id: str, dir_in_r
111
115
  :param hf_token: Huggingface token for API client, use ``HF_TOKEN`` variable if not assigned.
112
116
  :type hf_token: str, optional
113
117
  """
114
- files = list_files_in_repository(repo_id, repo_type, dir_in_repo, revision, ignore_patterns, hf_token=hf_token)
118
+ files = list_files_in_repository(
119
+ repo_id=repo_id,
120
+ repo_type=repo_type,
121
+ subdir=dir_in_repo,
122
+ pattern=pattern,
123
+ revision=revision,
124
+ ignore_patterns=ignore_patterns,
125
+ hf_token=hf_token,
126
+ )
115
127
  progress = tqdm(files, silent=silent, desc=f'Downloading {dir_in_repo!r} ...')
116
128
 
117
129
  def _download_one_file(rel_file):
@@ -135,7 +135,14 @@ def upload_directory_as_directory(
135
135
  if clear:
136
136
  pre_exist_files = {
137
137
  tuple(file.split('/')) for file in
138
- list_files_in_repository(repo_id, repo_type, path_in_repo, revision, ignore_patterns, hf_token=hf_token)
138
+ list_files_in_repository(
139
+ repo_id=repo_id,
140
+ repo_type=repo_type,
141
+ subdir=path_in_repo,
142
+ revision=revision,
143
+ ignore_patterns=ignore_patterns,
144
+ hf_token=hf_token
145
+ )
139
146
  }
140
147
  else:
141
148
  pre_exist_files = set()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hfutils
3
- Version: 0.3.2
3
+ Version: 0.3.4
4
4
  Summary: Useful utilities for huggingface
5
5
  Home-page: https://github.com/deepghs/hfutils
6
6
  Author: narugo1992
@@ -28,6 +28,7 @@ Requires-Dist: click>=7
28
28
  Requires-Dist: tzlocal
29
29
  Requires-Dist: natsort
30
30
  Requires-Dist: urlobject
31
+ Requires-Dist: fsspec>=2024
31
32
  Provides-Extra: test
32
33
  Requires-Dist: coverage>=5; extra == "test"
33
34
  Requires-Dist: mock>=4.0.3; extra == "test"
@@ -6,6 +6,7 @@ click>=7
6
6
  tzlocal
7
7
  natsort
8
8
  urlobject
9
+ fsspec>=2024
9
10
 
10
11
  [7z]
11
12
  py7zr
@@ -5,4 +5,5 @@ requests
5
5
  click>=7
6
6
  tzlocal
7
7
  natsort
8
- urlobject
8
+ urlobject
9
+ fsspec>=2024
@@ -1,135 +0,0 @@
1
- import fnmatch
2
- import os
3
- from functools import lru_cache
4
- from typing import Literal, List, Optional
5
-
6
- from huggingface_hub import HfApi, HfFileSystem
7
-
8
- from hfutils.utils import parse_hf_fs_path
9
-
10
- RepoTypeTyping = Literal['dataset', 'model', 'space']
11
- REPO_TYPES = ['dataset', 'model', 'space']
12
-
13
-
14
- @lru_cache()
15
- def _get_hf_token() -> Optional[str]:
16
- """
17
- Retrieve the Hugging Face token from the environment variable.
18
-
19
- :return: The Hugging Face token.
20
- :rtype: Optional[str]
21
- """
22
- return os.environ.get('HF_TOKEN')
23
-
24
-
25
- @lru_cache()
26
- def get_hf_client(hf_token: Optional[str] = None) -> HfApi:
27
- """
28
- Get the Hugging Face API client.
29
-
30
- :param hf_token: Huggingface token for API client, use ``HF_TOKEN`` variable if not assigned.
31
- :type hf_token: str, optional
32
-
33
- :return: The Hugging Face API client.
34
- :rtype: HfApi
35
- """
36
- return HfApi(token=hf_token or _get_hf_token())
37
-
38
-
39
- @lru_cache()
40
- def get_hf_fs(hf_token: Optional[str] = None) -> HfFileSystem:
41
- """
42
- Get the Hugging Face file system.
43
-
44
- :param hf_token: Huggingface token for API client, use ``HF_TOKEN`` variable if not assigned.
45
- :type hf_token: str, optional
46
-
47
- :return: The Hugging Face file system.
48
- :rtype: HfFileSystem
49
- """
50
- # use_listings_cache=False is necessary
51
- # or the result of glob and ls will be cached, the unittest will down
52
- return HfFileSystem(token=hf_token or _get_hf_token(), use_listings_cache=False)
53
-
54
-
55
- _DEFAULT_IGNORE_PATTERNS = ['.git*']
56
- _IGNORE_PATTERN_UNSET = object()
57
-
58
-
59
- def _is_file_ignored(file_segments: List[str], ignore_patterns: List[str]) -> bool:
60
- """
61
- Check if a file should be ignored based on the given ignore patterns.
62
-
63
- :param file_segments: The segments of the file path.
64
- :type file_segments: List[str]
65
- :param ignore_patterns: List of file patterns to ignore.
66
- :type ignore_patterns: List[str]
67
-
68
- :return: True if the file should be ignored, False otherwise.
69
- :rtype: bool
70
- """
71
- for segment in file_segments:
72
- for pattern in ignore_patterns:
73
- if fnmatch.fnmatch(segment, pattern):
74
- return True
75
-
76
- return False
77
-
78
-
79
- def list_files_in_repository(repo_id: str, repo_type: RepoTypeTyping = 'dataset',
80
- subdir: str = '', revision: str = 'main',
81
- ignore_patterns: List[str] = _IGNORE_PATTERN_UNSET,
82
- hf_token: Optional[str] = None) -> List[str]:
83
- """
84
- List files in a Hugging Face repository based on the given parameters.
85
-
86
- :param repo_id: The identifier of the repository.
87
- :type repo_id: str
88
- :param repo_type: The type of the repository ('dataset', 'model', 'space').
89
- :type repo_type: RepoTypeTyping
90
- :param subdir: The subdirectory to list files from.
91
- :type subdir: str
92
- :param revision: The revision of the repository (e.g., branch, tag, commit hash).
93
- :type revision: str
94
- :param ignore_patterns: List of file patterns to ignore.
95
- :type ignore_patterns: List[str]
96
- :param hf_token: Huggingface token for API client, use ``HF_TOKEN`` variable if not assigned.
97
- :type hf_token: str, optional
98
-
99
- :return: A list of file paths.
100
- :rtype: List[str]
101
- """
102
- if ignore_patterns is _IGNORE_PATTERN_UNSET:
103
- ignore_patterns = _DEFAULT_IGNORE_PATTERNS
104
- hf_fs = get_hf_fs(hf_token)
105
- if repo_type == 'model':
106
- repo_root_path = repo_id
107
- elif repo_type == 'dataset':
108
- repo_root_path = f'datasets/{repo_id}'
109
- elif repo_type == 'space':
110
- repo_root_path = f'spaces/{repo_id}'
111
- else:
112
- raise ValueError(f'Invalid repo_type - {repo_type!r}.')
113
- if subdir and subdir != '.':
114
- repo_root_path = f'{repo_root_path}/{subdir}'
115
-
116
- try:
117
- _exist_files = [
118
- parse_hf_fs_path(file).filename
119
- for file in hf_fs.glob(f'{repo_root_path}/**', revision=revision)
120
- ]
121
- except FileNotFoundError:
122
- return []
123
- if subdir and subdir != '.':
124
- _exist_files = [os.path.relpath(file, subdir) for file in _exist_files]
125
-
126
- _exist_ps = sorted([(file, file.split('/')) for file in _exist_files], key=lambda x: x[1])
127
- retval = []
128
- for i, (file, segments) in enumerate(_exist_ps):
129
- if i < len(_exist_ps) - 1 and segments == _exist_ps[i + 1][1][:len(segments)]:
130
- continue
131
- if file != '.':
132
- if not _is_file_ignored(segments, ignore_patterns):
133
- retval.append('/'.join(segments))
134
-
135
- return retval
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