hfutils 0.3.9__tar.gz → 0.4.0__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 (74) hide show
  1. {hfutils-0.3.9/hfutils.egg-info → hfutils-0.4.0}/PKG-INFO +1 -1
  2. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/config/meta.py +1 -1
  3. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/entry/cli.py +2 -0
  4. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/entry/download.py +6 -2
  5. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/entry/ls.py +8 -61
  6. hfutils-0.4.0/hfutils/entry/tree.py +239 -0
  7. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/utils/__init__.py +3 -0
  8. hfutils-0.4.0/hfutils/utils/archive.py +157 -0
  9. hfutils-0.4.0/hfutils/utils/data.py +87 -0
  10. hfutils-0.4.0/hfutils/utils/model.py +140 -0
  11. hfutils-0.4.0/hfutils/utils/type_.py +121 -0
  12. {hfutils-0.3.9 → hfutils-0.4.0/hfutils.egg-info}/PKG-INFO +1 -1
  13. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils.egg-info/SOURCES.txt +5 -0
  14. {hfutils-0.3.9 → hfutils-0.4.0}/LICENSE +0 -0
  15. {hfutils-0.3.9 → hfutils-0.4.0}/MANIFEST.in +0 -0
  16. {hfutils-0.3.9 → hfutils-0.4.0}/README.md +0 -0
  17. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/__init__.py +0 -0
  18. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/__main__.py +0 -0
  19. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/archive/__init__.py +0 -0
  20. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/archive/base.py +0 -0
  21. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/archive/rar.py +0 -0
  22. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/archive/sevenz.py +0 -0
  23. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/archive/tar.py +0 -0
  24. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/archive/zip.py +0 -0
  25. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/cache/__init__.py +0 -0
  26. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/cache/delete.py +0 -0
  27. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/config/__init__.py +0 -0
  28. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/entry/__init__.py +0 -0
  29. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/entry/base.py +0 -0
  30. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/entry/clone.py +0 -0
  31. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/entry/dispatch.py +0 -0
  32. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/entry/index.py +0 -0
  33. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/entry/ls_repo.py +0 -0
  34. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/entry/rollback.py +0 -0
  35. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/entry/upload.py +0 -0
  36. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/entry/whoami.py +0 -0
  37. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/index/__init__.py +0 -0
  38. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/index/fetch.py +0 -0
  39. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/index/hash.py +0 -0
  40. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/index/local_fetch.py +0 -0
  41. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/index/make.py +0 -0
  42. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/index/validate.py +0 -0
  43. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/operate/__init__.py +0 -0
  44. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/operate/base.py +0 -0
  45. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/operate/download.py +0 -0
  46. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/operate/upload.py +0 -0
  47. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/operate/validate.py +0 -0
  48. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/repository/__init__.py +0 -0
  49. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/repository/base.py +0 -0
  50. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/repository/clone.py +0 -0
  51. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/repository/rollback.py +0 -0
  52. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/utils/binary.py +0 -0
  53. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/utils/download.py +0 -0
  54. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/utils/irregular_repo.json +0 -0
  55. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/utils/logging.py +0 -0
  56. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/utils/number.py +0 -0
  57. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/utils/path.py +0 -0
  58. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/utils/session.py +0 -0
  59. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/utils/temp.py +0 -0
  60. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/utils/tqdm_.py +0 -0
  61. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils/utils/walk.py +0 -0
  62. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils.egg-info/dependency_links.txt +0 -0
  63. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils.egg-info/entry_points.txt +0 -0
  64. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils.egg-info/requires.txt +0 -0
  65. {hfutils-0.3.9 → hfutils-0.4.0}/hfutils.egg-info/top_level.txt +0 -0
  66. {hfutils-0.3.9 → hfutils-0.4.0}/requirements-7z.txt +0 -0
  67. {hfutils-0.3.9 → hfutils-0.4.0}/requirements-build.txt +0 -0
  68. {hfutils-0.3.9 → hfutils-0.4.0}/requirements-doc.txt +0 -0
  69. {hfutils-0.3.9 → hfutils-0.4.0}/requirements-rar.txt +0 -0
  70. {hfutils-0.3.9 → hfutils-0.4.0}/requirements-test.txt +0 -0
  71. {hfutils-0.3.9 → hfutils-0.4.0}/requirements-transfer.txt +0 -0
  72. {hfutils-0.3.9 → hfutils-0.4.0}/requirements.txt +0 -0
  73. {hfutils-0.3.9 → hfutils-0.4.0}/setup.cfg +0 -0
  74. {hfutils-0.3.9 → hfutils-0.4.0}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hfutils
3
- Version: 0.3.9
3
+ Version: 0.4.0
4
4
  Summary: Useful utilities for huggingface
5
5
  Home-page: https://github.com/deepghs/hfutils
6
6
  Author: narugo1992
@@ -7,7 +7,7 @@ Overview:
7
7
  __TITLE__ = 'hfutils'
8
8
 
9
9
  #: Version of this project.
10
- __VERSION__ = '0.3.9'
10
+ __VERSION__ = '0.4.0'
11
11
 
12
12
  #: Short description of the project, will be included in ``setup.py``.
13
13
  __DESCRIPTION__ = 'Useful utilities for huggingface'
@@ -5,6 +5,7 @@ from .index import _add_index_subcommand
5
5
  from .ls import _add_ls_subcommand
6
6
  from .ls_repo import _add_ls_repo_subcommand
7
7
  from .rollback import _add_rollback_subcommand
8
+ from .tree import _add_tree_subcommand
8
9
  from .upload import _add_upload_subcommand
9
10
  from .whoami import _add_whoami_subcommand
10
11
 
@@ -17,6 +18,7 @@ _DECORATORS = [
17
18
  _add_index_subcommand,
18
19
  _add_rollback_subcommand,
19
20
  _add_clone_subcommand,
21
+ _add_tree_subcommand,
20
22
  ]
21
23
 
22
24
  cli = hfutilcli
@@ -7,7 +7,7 @@ from huggingface_hub import configure_http_backend
7
7
 
8
8
  from .base import CONTEXT_SETTINGS, command_wrap, ClickErrorException
9
9
  from ..operate import download_file_to_file, download_archive_as_directory, download_directory_as_directory
10
- from ..operate.base import REPO_TYPES, RepoTypeTyping
10
+ from ..operate.base import REPO_TYPES, RepoTypeTyping, _IGNORE_PATTERN_UNSET
11
11
  from ..utils import get_requests_session
12
12
 
13
13
 
@@ -55,12 +55,15 @@ def _add_download_subcommand(cli: click.Group) -> click.Group:
55
55
  help='Just check the file size when validating the downloaded files.', show_default=True)
56
56
  @click.option('--tmpdir', 'tmpdir', type=str, default=None,
57
57
  help='Use custom temporary Directory.', show_default=True)
58
+ @click.option('--all', 'show_all', is_flag=True, type=bool, default=False,
59
+ help='Show all files, including hidden files.', show_default=True)
58
60
  @command_wrap()
59
61
  def download(
60
62
  repo_id: str, repo_type: RepoTypeTyping,
61
63
  file_in_repo: Optional[str], archive_in_repo: Optional[str], dir_in_repo: Optional[str],
62
64
  output_path: str, revision: str, max_workers: int,
63
- password: Optional[str], wildcard: Optional[str], soft_mode_when_check: bool, tmpdir: Optional[str]
65
+ password: Optional[str], wildcard: Optional[str], soft_mode_when_check: bool, tmpdir: Optional[str],
66
+ show_all: bool = False,
64
67
  ):
65
68
  """
66
69
  Download data from HuggingFace repositories.
@@ -135,6 +138,7 @@ def _add_download_subcommand(cli: click.Group) -> click.Group:
135
138
  silent=False,
136
139
  max_workers=max_workers,
137
140
  soft_mode_when_check=soft_mode_when_check,
141
+ ignore_patterns=_IGNORE_PATTERN_UNSET if not show_all else [],
138
142
  )
139
143
 
140
144
  else:
@@ -1,6 +1,5 @@
1
- import mimetypes
2
1
  import os.path
3
- from enum import Enum, unique
2
+ import os.path
4
3
  from typing import Union, List
5
4
 
6
5
  import click
@@ -10,46 +9,7 @@ from huggingface_hub.hf_api import RepoFolder, RepoFile
10
9
 
11
10
  from .base import CONTEXT_SETTINGS
12
11
  from ..operate.base import REPO_TYPES, get_hf_client
13
- from ..utils import get_requests_session
14
-
15
- mimetypes.add_type('image/webp', '.webp')
16
-
17
-
18
- @unique
19
- class ListItemType(Enum):
20
- """
21
- Enum class representing different types of list items.
22
- """
23
-
24
- FILE = 0x1
25
- FOLDER = 0x2
26
- IMAGE = 0x3
27
- ARCHIVE = 0x4
28
- MODEL = 0x5
29
- DATA = 0x6
30
-
31
- @property
32
- def render_color(self):
33
- """
34
- Get the render color based on the item type.
35
-
36
- :return: The render color for the item type.
37
- :rtype: str
38
- """
39
- if self == self.FILE:
40
- return None
41
- elif self == self.FOLDER:
42
- return 'blue'
43
- elif self == self.IMAGE:
44
- return 'magenta'
45
- elif self == self.ARCHIVE:
46
- return 'red'
47
- elif self == self.MODEL:
48
- return 'green'
49
- elif self == self.DATA:
50
- return 'yellow'
51
- else:
52
- raise ValueError(f'Unknown type - {self!r}') # pragma: no cover
12
+ from ..utils import get_requests_session, FileItemType, get_file_type
53
13
 
54
14
 
55
15
  class ListItem:
@@ -66,22 +26,9 @@ class ListItem:
66
26
  self.item = item
67
27
  self.base_dir = base_dir
68
28
  if isinstance(item, RepoFolder):
69
- self.type = ListItemType.FOLDER
29
+ self.type = FileItemType.FOLDER
70
30
  else:
71
- mimetype, _ = mimetypes.guess_type(item.path)
72
- _, ext = os.path.splitext(item.path)
73
- self.type = ListItemType.FILE
74
- if ext in {'.ckpt', '.pt', '.safetensors', '.onnx', '.model', '.h5', '.mlmodel',
75
- '.ftz', '.pb', '.pth', '.tflite'}:
76
- self.type = ListItemType.MODEL
77
- elif ext in {'.json', '.csv', '.tsv', '.arrow', '.bin', '.msgpack', '.npy', '.npz',
78
- '.parquet', '.pickle', '.pkl', '.wasm'}:
79
- self.type = ListItemType.DATA
80
- elif mimetype:
81
- if 'image' in mimetype:
82
- self.type = ListItemType.IMAGE
83
- elif mimetype.split('/', maxsplit=1)[-1] in {'zip', 'rar', 'x-tar', 'x-7z-compressed'}:
84
- self.type = ListItemType.ARCHIVE
31
+ self.type = get_file_type(item.path)
85
32
 
86
33
 
87
34
  def _add_ls_subcommand(cli: click.Group) -> click.Group:
@@ -154,7 +101,7 @@ def _add_ls_subcommand(cli: click.Group) -> click.Group:
154
101
  max_size_length = 0
155
102
  max_commit_info_length = 0
156
103
  for item in items:
157
- if item.type == ListItemType.FOLDER:
104
+ if item.type == FileItemType.FOLDER:
158
105
  size_text = '-'
159
106
  else:
160
107
  size_text = str(item.item.size)
@@ -164,8 +111,8 @@ def _add_ls_subcommand(cli: click.Group) -> click.Group:
164
111
  max_commit_info_length = max(max_commit_info_length, len(commit_text))
165
112
 
166
113
  for item in items:
167
- print('d' if item.type == ListItemType.FOLDER else '-', end='')
168
- print('L' if item.type != ListItemType.FOLDER and item.item.lfs else '-', end='')
114
+ print('d' if item.type == FileItemType.FOLDER else '-', end='')
115
+ print('L' if item.type != FileItemType.FOLDER and item.item.lfs else '-', end='')
169
116
 
170
117
  commit_text = (item.item.last_commit.title or '').splitlines(keepends=False)[0]
171
118
  print(
@@ -174,7 +121,7 @@ def _add_ls_subcommand(cli: click.Group) -> click.Group:
174
121
  end=''
175
122
  )
176
123
 
177
- if item.type == ListItemType.FOLDER:
124
+ if item.type == FileItemType.FOLDER:
178
125
  size_text = '-'
179
126
  else:
180
127
  size_text = str(item.item.size)
@@ -0,0 +1,239 @@
1
+ """
2
+ This module provides functionality for listing and displaying files from a HuggingFace repository in a tree-like structure.
3
+
4
+ It includes functions for parsing repository paths, retrieving file information, and formatting the output as a tree.
5
+ The module also defines a CLI command for easy interaction with the tree functionality.
6
+
7
+ Key components:
8
+
9
+ - TreeItem: A dataclass representing an item (file or folder) in the tree structure.
10
+ - _get_tree: Function to retrieve the tree structure of files in a HuggingFace repository.
11
+ - _add_tree_subcommand: Function to add the 'tree' subcommand to a Click CLI group.
12
+
13
+ Usage:
14
+ This module is typically used as part of a larger CLI application for interacting with HuggingFace repositories.
15
+ The 'tree' command can be used to visualize the structure of files in a repository.
16
+ """
17
+
18
+ import dataclasses
19
+ import os
20
+ import re
21
+ from typing import Optional, List, Union
22
+
23
+ import click
24
+ from hbutils.string import format_tree
25
+ from huggingface_hub import configure_http_backend
26
+ from huggingface_hub.hf_api import RepoFile
27
+ from natsort import natsorted
28
+
29
+ from .base import CONTEXT_SETTINGS
30
+ from ..operate.base import REPO_TYPES, list_files_in_repository, RepoTypeTyping, get_hf_client
31
+ from ..utils import get_requests_session, hf_normpath, get_file_type, hf_fs_path, FileItemType
32
+
33
+
34
+ @dataclasses.dataclass
35
+ class TreeItem:
36
+ """
37
+ Represents an item (file or folder) in the tree structure.
38
+
39
+ :param name: The name of the item.
40
+ :type name: str
41
+ :param type_: The type of the item (file or folder).
42
+ :type type_: FileItemType
43
+ :param children: List of child items if this is a folder.
44
+ :type children: Optional[List[TreeItem]]
45
+ :param exist: Whether the item exists in the repository.
46
+ :type exist: bool
47
+
48
+ :ivar name: The name of the item.
49
+ :ivar type_: The type of the item.
50
+ :ivar children: List of child items.
51
+ :ivar exist: Existence status of the item.
52
+ """
53
+
54
+ name: str
55
+ type_: FileItemType
56
+ children: Optional[List['TreeItem']]
57
+ exist: bool = True
58
+
59
+ def get_name(self):
60
+ """
61
+ Get the formatted name of the item for display.
62
+
63
+ :return: Formatted name string with color and strike-through if applicable.
64
+ :rtype: str
65
+ """
66
+ return click.style(
67
+ self.name,
68
+ fg=self.type_.render_color if self.exist else None,
69
+ strikethrough=not self.exist,
70
+ ) + ('' if self.exist else ' <NOT EXIST>')
71
+
72
+ def get_children(self):
73
+ """
74
+ Get the children of this item if it's a folder.
75
+
76
+ :return: List of child items if folder, empty list otherwise.
77
+ :rtype: List[TreeItem]
78
+ """
79
+ return self.children if self.type_ == FileItemType.FOLDER else []
80
+
81
+
82
+ def _get_tree(repo_id: str, repo_type: RepoTypeTyping, dir_in_repo: str,
83
+ revision: Optional[str] = None, show_all: bool = False) -> TreeItem:
84
+ """
85
+ Retrieve the tree structure of files in a HuggingFace repository.
86
+
87
+ :param repo_id: The ID of the repository.
88
+ :type repo_id: str
89
+ :param repo_type: The type of the repository.
90
+ :type repo_type: RepoTypeTyping
91
+ :param dir_in_repo: The directory in the repository to start from.
92
+ :type dir_in_repo: str
93
+ :param revision: The revision of the repository to use.
94
+ :type revision: Optional[str]
95
+ :param show_all: Whether to show hidden files.
96
+ :type show_all: bool
97
+
98
+ :return: The root TreeItem representing the directory structure.
99
+ :rtype: TreeItem
100
+ """
101
+ root = {}
102
+ for filepath in list_files_in_repository(
103
+ repo_id=repo_id,
104
+ repo_type=repo_type,
105
+ subdir=dir_in_repo,
106
+ revision=revision,
107
+ ignore_patterns=[],
108
+ ):
109
+ filename = hf_normpath(os.path.relpath(filepath, dir_in_repo))
110
+ segments = re.split(r'[\\/]+', filename)
111
+ if any(segment.startswith('.') and segment != '.' for segment in segments) and not show_all:
112
+ continue
113
+
114
+ current_node = root
115
+ for i, segment in enumerate(segments):
116
+ if segment not in current_node:
117
+ if i == (len(segments) - 1):
118
+ current_node[segment] = get_file_type(segment)
119
+ else:
120
+ current_node[segment] = {}
121
+ current_node = current_node[segment]
122
+
123
+ root_name = hf_fs_path(
124
+ repo_id=repo_id,
125
+ repo_type=repo_type,
126
+ filename=dir_in_repo,
127
+ revision=revision,
128
+ )
129
+
130
+ def _recursion(cur_node: Union[dict, FileItemType], parent_name: str, is_exist: bool = False):
131
+ if isinstance(cur_node, dict):
132
+ return TreeItem(
133
+ name=parent_name,
134
+ type_=FileItemType.FOLDER,
135
+ children=[
136
+ _recursion(cur_node=value, parent_name=name, is_exist=is_exist)
137
+ for name, value in natsorted(cur_node.items())
138
+ ],
139
+ exist=is_exist,
140
+ )
141
+ else:
142
+ return TreeItem(
143
+ name=parent_name,
144
+ type_=cur_node,
145
+ children=[],
146
+ exist=is_exist,
147
+ )
148
+
149
+ exist = True
150
+ if not root:
151
+ hf_client = get_hf_client()
152
+ paths = hf_client.get_paths_info(
153
+ repo_id=repo_id,
154
+ repo_type=repo_type,
155
+ revision=revision,
156
+ paths=[dir_in_repo],
157
+ )
158
+ if len(paths) == 0:
159
+ exist = False
160
+ elif len(paths) == 1:
161
+ pathobj = paths[0]
162
+ if isinstance(pathobj, RepoFile): # the subdir is a file
163
+ root = get_file_type(dir_in_repo)
164
+ else:
165
+ assert len(paths) == 1, \
166
+ f'Multiple path {dir_in_repo!r} found in repo {root_name!r}, ' \
167
+ f'this must be caused by HuggingFace API.' # pragma: no cover
168
+
169
+ return _recursion(
170
+ cur_node=root,
171
+ parent_name=root_name,
172
+ is_exist=exist,
173
+ )
174
+
175
+
176
+ def _add_tree_subcommand(cli: click.Group) -> click.Group:
177
+ """
178
+ Add the 'tree' subcommand to a Click CLI group.
179
+
180
+ This function defines a new 'tree' command that lists files from a HuggingFace repository
181
+ in a tree-like structure.
182
+
183
+ :param cli: The Click CLI group to add the command to.
184
+ :type cli: click.Group
185
+
186
+ :return: The modified CLI group with the 'tree' command added.
187
+ :rtype: click.Group
188
+
189
+ Usage:
190
+ This function is typically called when setting up a CLI application:
191
+
192
+ cli = click.Group()
193
+ cli = _add_tree_subcommand(cli)
194
+ """
195
+
196
+ @cli.command('tree', help='List files as a tree from HuggingFace repository.\n\n'
197
+ 'Set environment $HF_TOKEN to use your own access token.',
198
+ context_settings=CONTEXT_SETTINGS)
199
+ @click.option('-r', '--repository', 'repo_id', type=str, required=True,
200
+ help='Repository to download from.')
201
+ @click.option('-t', '--type', 'repo_type', type=click.Choice(REPO_TYPES), default='dataset',
202
+ help='Type of the HuggingFace repository.', show_default=True)
203
+ @click.option('-d', '--directory', 'dir_in_repo', type=str, default=None,
204
+ help='Directory in repository to download the full directory tree.')
205
+ @click.option('-R', '--revision', 'revision', type=str, default='main',
206
+ help='Revision of repository.', show_default=True)
207
+ @click.option('-a', '--all', 'show_all', is_flag=True, type=bool, default=False,
208
+ help='Show all files, including hidden files.', show_default=True)
209
+ def tree(repo_id: str, repo_type: RepoTypeTyping, dir_in_repo, revision: str, show_all: bool):
210
+ """
211
+ List files as a tree from a HuggingFace repository in a tree-like structure.
212
+
213
+ :param repo_id: The ID of the repository.
214
+ :type repo_id: str
215
+ :param repo_type: The type of the repository.
216
+ :type repo_type: RepoTypeTyping
217
+ :param dir_in_repo: The directory in the repository to start from.
218
+ :type dir_in_repo: str
219
+ :param revision: The revision of the repository to use.
220
+ :type revision: str
221
+ :param show_all: Whether to show hidden files.
222
+ :type show_all: bool
223
+ """
224
+ configure_http_backend(get_requests_session)
225
+
226
+ _tree = _get_tree(
227
+ repo_id=repo_id,
228
+ repo_type=repo_type,
229
+ dir_in_repo=dir_in_repo or '.',
230
+ revision=revision,
231
+ show_all=show_all,
232
+ )
233
+ print(format_tree(
234
+ _tree,
235
+ format_node=TreeItem.get_name,
236
+ get_children=TreeItem.get_children,
237
+ ))
238
+
239
+ return cli
@@ -1,4 +1,6 @@
1
+ from .archive import is_archive_or_compressed
1
2
  from .binary import is_binary_file
3
+ from .data import is_data_file
2
4
  from .download import download_file
3
5
  from .logging import ColoredFormatter
4
6
  from .number import number_to_tag
@@ -6,4 +8,5 @@ from .path import hf_normpath, hf_fs_path, parse_hf_fs_path, HfFileSystemPath
6
8
  from .session import TimeoutHTTPAdapter, get_requests_session, get_random_ua
7
9
  from .temp import TemporaryDirectory
8
10
  from .tqdm_ import tqdm
11
+ from .type_ import FileItemType, get_file_type
9
12
  from .walk import walk_files
@@ -0,0 +1,157 @@
1
+ """
2
+ This module provides functionality for identifying archive and compressed files based on their filenames.
3
+
4
+ It includes a comprehensive list of known archive and compressed file extensions, as well as patterns for
5
+ identifying split archives and other generic compressed file formats. The main
6
+ function :func:`is_archive_or_compressed` can be used to determine if a given filename
7
+ represents an archive or compressed file.
8
+
9
+ The module is useful for file handling operations where it's necessary to distinguish between regular files
10
+ and archives or compressed files.
11
+ """
12
+
13
+ import os.path
14
+ import re
15
+ from typing import Union
16
+
17
+ _ARCHIVE_KNOWN_EXTS = {
18
+ '.tar', # Tape Archive
19
+ '.rar', # Roshal Archive
20
+ '.rar5', # RAR version 5
21
+ '.zip', # ZIP archive
22
+ '.7z', # 7-Zip archive
23
+ '.7zip', # Alternative extension for 7-Zip
24
+ '.gz', # Gzip compressed file
25
+ '.bz2', # Bzip2 compressed file
26
+ '.xz', # XZ compressed file
27
+ '.ace', # ACE archive
28
+ '.lz', # Lzip compressed file
29
+ '.lzma', # LZMA compressed file
30
+ '.z', # Compress (Unix) file
31
+ '.cab', # Microsoft Cabinet file
32
+ '.arj', # ARJ archive
33
+ '.iso', # ISO disk image
34
+ '.lzh', # LZH archive
35
+ '.sit', # StuffIt archive
36
+ '.sitx', # StuffIt X archive
37
+ '.sea', # Self-Extracting Archive
38
+ '.alz', # ALZip archive
39
+ '.egg', # Python Egg
40
+ '.whl', # Python Wheel
41
+ '.deb', # Debian package
42
+ '.rpm', # Red Hat Package Manager
43
+ '.pkg', # macOS Installer Package
44
+ '.dmg', # Apple Disk Image
45
+ '.msi', # Microsoft Installer
46
+ '.tgz', # Gzipped tar archive
47
+ '.tbz2', # Bzip2 compressed tar archive
48
+ '.lzw', # LZW compressed file
49
+ '.rz', # RZip compressed file
50
+ '.lzo', # Lempel-Ziv-Oberhumer compressed file
51
+ '.zst', # Zstandard compressed file
52
+ '.tar.gz', # Gzipped tar archive
53
+ '.tar.bz2', # Bzip2 compressed tar archive
54
+ '.tar.xz', # XZ compressed tar archive
55
+ '.tar.lz', # Lzip compressed tar archive
56
+ '.tar.lzma', # LZMA compressed tar archive
57
+ '.zipx', # Extended ZIP archive
58
+ '.arc', # ARC archive
59
+ '.ark', # ARC archive (alternative extension)
60
+ '.lha', # LHA archive
61
+ '.zoo', # ZOO archive
62
+ '.gca', # GCA archive
63
+ '.uc2', # UC2 archive
64
+ '.uha', # UHarc archive
65
+ '.war', # Web Application Archive
66
+ '.ear', # Enterprise Application aRchive
67
+ '.sar', # SAR archive
68
+ '.jar', # Java Archive
69
+ '.apk', # Android Package Kit
70
+ '.xpi', # XPInstall (Mozilla browser extension)
71
+ '.snap', # Snap package (Ubuntu)
72
+ '.appimage', # AppImage package
73
+ '.squashfs', # Squashfs filesystem
74
+ '.cpio', # CPIO archive
75
+ '.shar', # Shell archive
76
+ '.lbr', # LBR archive
77
+ '.mar', # Mozilla Archive
78
+ '.sbx', # Sandbox file
79
+ '.qcow2', # QEMU Copy On Write 2
80
+ '.vdi', # VirtualBox Disk Image
81
+ '.vhd', # Virtual Hard Disk
82
+ '.vmdk', # Virtual Machine Disk
83
+ '.ova', # Open Virtual Appliance
84
+ '.xar', # eXtensible ARchive
85
+ '.mpq', # MoPaQ archive (Blizzard games)
86
+ }
87
+
88
+ # Additional generic patterns
89
+ _EXTERNAL_PATTERNS = [
90
+ r'\.tar(?:\.(?:gz|bz2|xz|lz|lzma|Z))?$', # Tar and compressed tar archives
91
+ r'\.t\.(?:gz|bz2|xz|lz|lzma|Z)$', # Compressed files with .t.XX extension
92
+ r'\.(?:zip|z)$', # ZIP archives and Z compressed files
93
+ r'\.rar$', # RAR archives
94
+ r'\.7z$', # 7-Zip archives
95
+ r'\.(?:ar|a)$', # AR archives
96
+ r'\.(?:lz|lzma?)$', # LZ and LZMA compressed files
97
+ r'\.gz(?:ip)?$', # Gzip compressed files
98
+ r'\.bz(?:ip)?2?$', # Bzip and Bzip2 compressed files
99
+ r'\.(?:xz|lzh|lha)$', # XZ, LZH, and LHA archives
100
+ r'\.(?:iso|img|dmg|pkg|msi)$', # Disk images and installers
101
+ r'\.(?:deb|rpm|apk|ipa)$', # Package formats
102
+ ]
103
+
104
+ _ARCHIVE_SPLIT_PATTERNS = [
105
+ r'^(.+\.(?:zip|rar|7z|tar|tar\.gz|tar\.bz2|tar\.xz))\.\d+$', # Split archives (e.g., .zip.001)
106
+ r'^(.+\.t)\.[a-z0-9]{2,4}$', # Split archives with .t.XX extension
107
+ r'^(.+\.part\d+)\.rar$', # Split RAR archives
108
+ r'^(.+)\.r\d{2}$', # Old-style split RAR archives
109
+ ]
110
+
111
+
112
+ def is_archive_or_compressed(filename: Union[str, os.PathLike]) -> bool:
113
+ """
114
+ Determine if the given filename represents an archive or compressed file.
115
+
116
+ This function checks the filename against a list of known archive and compressed file extensions,
117
+ as well as patterns for split archives and other generic compressed file formats.
118
+
119
+ :param filename: The name of the file to check. Can be a string or a path-like object.
120
+ :type filename: Union[str, os.PathLike]
121
+
122
+ :return: True if the filename represents an archive or compressed file, False otherwise.
123
+ :rtype: bool
124
+
125
+ :raises TypeError: If the filename is not a string or path-like object.
126
+
127
+ Usage:
128
+ >>> is_archive_or_compressed('example.zip')
129
+ True
130
+ >>> is_archive_or_compressed('document.txt')
131
+ False
132
+ >>> is_archive_or_compressed('archive.tar.gz')
133
+ True
134
+ >>> is_archive_or_compressed('split_archive.zip.001')
135
+ True
136
+ """
137
+ if not isinstance(filename, (str, os.PathLike)):
138
+ raise TypeError(f'Unknown file name type - {filename!r}')
139
+ filename = os.path.basename(os.path.normcase(str(filename)))
140
+
141
+ # Check for known extensions
142
+ for ext in _ARCHIVE_KNOWN_EXTS:
143
+ if filename.lower().endswith(ext):
144
+ return True
145
+
146
+ # Check for split archives
147
+ for pattern in _ARCHIVE_SPLIT_PATTERNS:
148
+ match = re.match(pattern, filename.lower())
149
+ if match:
150
+ return True
151
+
152
+ # Check for external patterns
153
+ for pattern in _EXTERNAL_PATTERNS:
154
+ if re.search(pattern, filename.lower()):
155
+ return True
156
+
157
+ return False
@@ -0,0 +1,87 @@
1
+ """
2
+ This module provides functionality for identifying data files based on their file extensions.
3
+
4
+ It includes a comprehensive set of data file extensions and a function to check if a given
5
+ filename corresponds to a known data file format. This can be useful in various data processing
6
+ and file handling scenarios where it's necessary to distinguish data files from other types of files.
7
+ """
8
+
9
+ import os
10
+ from typing import Union
11
+
12
+ _DATA_EXTS = {
13
+ '.json', # JavaScript Object Notation
14
+ '.csv', # Comma-Separated Values
15
+ '.tsv', # Tab-Separated Values
16
+ '.arrow', # Apache Arrow file format
17
+ '.feather', # Feather file format (fast, language-agnostic columnar format)
18
+ '.parquet', # Apache Parquet file format
19
+ '.avro', # Apache Avro file format
20
+ '.orc', # Optimized Row Columnar file format
21
+ '.npy', # NumPy array file
22
+ '.npz', # NumPy compressed archive file
23
+ '.hdf5', # Hierarchical Data Format version 5
24
+ '.h5', # Alternative extension for HDF5
25
+ '.mat', # MATLAB file format
26
+ '.sav', # SPSS data file
27
+ '.dta', # Stata data file
28
+ '.sas7bdat', # SAS data file
29
+ '.xpt', # SAS transport file
30
+ '.xlsx', # Microsoft Excel Open XML Spreadsheet
31
+ '.xls', # Microsoft Excel Binary File Format
32
+ '.ods', # OpenDocument Spreadsheet
33
+ '.db', # Generic database file
34
+ '.sqlite', # SQLite database file
35
+ '.mdb', # Microsoft Access database file
36
+ '.accdb', # Microsoft Access database file (newer version)
37
+ '.dbf', # dBase database file
38
+ '.ftr', # Feather file format (alternative extension)
39
+ '.geojson', # GeoJSON file (for geographical data)
40
+ '.shp', # Shapefile (for geographical data)
41
+ '.kml', # Keyhole Markup Language (for geographical data)
42
+ '.gpx', # GPS Exchange Format
43
+ '.nc', # NetCDF (Network Common Data Form) file
44
+ '.grib', # GRIdded Binary or General Regularly-distributed Information in Binary form
45
+ '.hdf', # Hierarchical Data Format (older version)
46
+ '.zarr', # Zarr array storage format
47
+ '.bin', # Generic Binary File
48
+ '.pickle', # Pickle dumped file
49
+ '.pkl', # Shortcut of .pickle
50
+ '.wasm', # WASM
51
+ }
52
+
53
+
54
+ def is_data_file(filename: Union[str, os.PathLike]) -> bool:
55
+ """
56
+ Determine if a given filename corresponds to a known data file format.
57
+
58
+ This function checks if the file extension of the provided filename matches
59
+ any of the known data file extensions defined in the `_DATA_EXTS` set.
60
+
61
+ :param filename: The name of the file to check. Can be a string or a path-like object.
62
+ :type filename: Union[str, os.PathLike]
63
+
64
+ :return: True if the file extension matches a known data file format, False otherwise.
65
+ :rtype: bool
66
+
67
+ :raises TypeError: If the provided filename is not a string or path-like object.
68
+
69
+ Usage:
70
+ >>> is_data_file('data.csv')
71
+ True
72
+ >>> is_data_file('script.py')
73
+ False
74
+ >>> is_data_file(Path('/path/to/data.json'))
75
+ True
76
+
77
+ .. note::
78
+ The function is case-insensitive and works with both file names and full paths.
79
+ It normalizes the filename and extracts only the extension for comparison.
80
+ """
81
+ if not isinstance(filename, (str, os.PathLike)):
82
+ raise TypeError(f'Unknown file name type - {filename!r}')
83
+
84
+ # Normalize the filename and get the extension
85
+ filename = os.path.basename(os.path.normcase(str(filename)))
86
+ _, ext = os.path.splitext(filename.lower())
87
+ return ext in _DATA_EXTS
@@ -0,0 +1,140 @@
1
+ """
2
+ This module provides functionality for identifying model files based on their extensions and naming patterns.
3
+
4
+ It includes a comprehensive list of model file extensions, patterns for sharded model files, and specific patterns
5
+ for Hugging Face model files. The main function, :func:`is_model_file`, determines whether a given filename corresponds
6
+ to a model file based on these predefined patterns and extensions.
7
+
8
+ This module can be useful in various scenarios, such as:
9
+
10
+ - Automated model file detection in directories
11
+ - Validation of uploaded files in machine learning platforms
12
+ - Preprocessing steps in model loading pipelines
13
+
14
+ Usage:
15
+ .. code:: python
16
+
17
+ from model_file_identifier import is_model_file
18
+
19
+ filename = "model.pt"
20
+ if is_model_file(filename):
21
+ print(f"{filename} is a model file")
22
+ else:
23
+ print(f"{filename} is not a model file")
24
+ """
25
+
26
+ import os
27
+ import re
28
+ from typing import Union
29
+
30
+ _MODEL_EXTS = {
31
+ '.ckpt', # Checkpoint file
32
+ '.pt', # PyTorch model file
33
+ '.pth', # PyTorch model file (alternative extension)
34
+ '.safetensors', # SafeTensors model file
35
+ '.onnx', # Open Neural Network Exchange model file
36
+ '.model', # Generic model file
37
+ '.h5', # Hierarchical Data Format version 5
38
+ '.hdf5', # Hierarchical Data Format version 5 (alternative extension)
39
+ '.mlmodel', # Core ML model file
40
+ '.ftz', # FastText model file
41
+ '.pb', # Protocol Buffer file (often used for TensorFlow models)
42
+ '.tflite', # TensorFlow Lite model file
43
+ '.pkl', # Pickle file (often used for scikit-learn models)
44
+ '.joblib', # Joblib file (often used for scikit-learn models)
45
+ '.bin', # Binary file (generic)
46
+ '.meta', # Meta file (often associated with TensorFlow checkpoints)
47
+ '.params', # Parameters file (often used in MXNet)
48
+ '.pdparams', # PaddlePaddle parameters file
49
+ '.pdmodel', # PaddlePaddle model file
50
+ '.ot', # OpenVINO model file
51
+ '.nnet', # Neural network file
52
+ '.dnn', # Deep neural network file
53
+ '.mar', # MXNet Archive
54
+ '.tf', # TensorFlow SavedModel file
55
+ '.keras', # Keras model file
56
+ '.weights', # Weights file (generic)
57
+ '.pmml', # Predictive Model Markup Language file
58
+ '.gguf', # GGUF (GPT-Generated Unified Format) file
59
+ '.ggml', # GGML (GPT-Generated Model Language) file
60
+ '.q4_0', # 4-bit quantized model (type 0)
61
+ '.q4_1', # 4-bit quantized model (type 1)
62
+ '.q5_0', # 5-bit quantized model (type 0)
63
+ '.q5_1', # 5-bit quantized model (type 1)
64
+ '.q8_0', # 8-bit quantized model
65
+ '.qnt', # Quantized model (generic)
66
+ '.int8', # 8-bit integer quantized model
67
+ '.fp16', # 16-bit floating point model
68
+ '.bk', # Backup file (often used for model checkpoints)
69
+ '.engine', # TensorRT engine file
70
+ '.plan', # TensorRT plan file
71
+ '.trt', # TensorRT model file
72
+ '.torchscript', # TorchScript model file
73
+ '.pdiparams', # PaddlePaddle inference parameters file
74
+ '.pdopt', # PaddlePaddle optimizer file
75
+ '.nb', # Neural network binary file
76
+ '.mnn', # MNN (Mobile Neural Network) model file
77
+ '.ncnn', # NCNN model file
78
+ '.om', # CANN (Compute Architecture for Neural Networks) offline model
79
+ '.rknn', # Rockchip Neural Network model file
80
+ '.xmodel', # Vitis AI model file
81
+ '.kmodel', # Kendryte model file
82
+ }
83
+
84
+ _MODEL_SHARD_PATTERNS = [
85
+ r'.*-\d{5}-of-\d{5}', # Pattern for sharded files like "model-00001-of-00005"
86
+ r'.*\.bin\.\d+', # Pattern for binary shards like "model.bin.1"
87
+ r'.*\.part\.\d+', # Pattern for part files like "model.part.0"
88
+ r'.*_part_\d+', # Alternative pattern for part files like "model_part_0"
89
+ r'.*-shard\d+', # Pattern for shard files like "model-shard1"
90
+ ]
91
+
92
+ _HF_MODEL_PATTERNS = [
93
+ r'pytorch_model.*\.bin', # Hugging Face PyTorch model file
94
+ r'tf_model.*\.h5', # Hugging Face TensorFlow model file
95
+ r'model.*\.ckpt', # Hugging Face checkpoint file
96
+ r'flax_model.*\.msgpack', # Hugging Face Flax model file
97
+ r'.*\.safetensors', # SafeTensors file (often used in Hugging Face models)
98
+ ]
99
+
100
+
101
+ def is_model_file(filename: Union[str, os.PathLike]) -> bool:
102
+ """
103
+ Determine if a given filename corresponds to a model file.
104
+
105
+ This function checks if the provided filename matches any of the known model file extensions
106
+ or patterns, including sharded model files and Hugging Face specific patterns.
107
+
108
+ :param filename: The name of the file to check. Can be a full path or just the filename.
109
+ :type filename: Union[str, os.PathLike]
110
+
111
+ :return: True if the filename corresponds to a model file, False otherwise.
112
+ :rtype: bool
113
+
114
+ :raises TypeError: If the filename is not a string or os.PathLike object.
115
+
116
+ Usage:
117
+ >>> is_model_file("model.pt")
118
+ True
119
+ >>> is_model_file("data.csv")
120
+ False
121
+ >>> is_model_file("model-00001-of-00005")
122
+ True
123
+ >>> is_model_file("pytorch_model.bin")
124
+ True
125
+
126
+ .. note::
127
+ This function is case-insensitive and works with both file names and full paths.
128
+ """
129
+ if not isinstance(filename, (str, os.PathLike)):
130
+ raise TypeError(f'Unknown file name type - {filename!r}')
131
+ filename = os.path.basename(os.path.normcase(str(filename)))
132
+
133
+ if any(filename.lower().endswith(ext) for ext in _MODEL_EXTS):
134
+ return True
135
+ if any(re.match(pattern, filename.lower()) for pattern in _MODEL_SHARD_PATTERNS):
136
+ return True
137
+ if any(re.match(pattern, filename.lower()) for pattern in _HF_MODEL_PATTERNS):
138
+ return True
139
+
140
+ return False
@@ -0,0 +1,121 @@
1
+ """
2
+ This module provides functionality for determining file types and managing list item types.
3
+
4
+ It includes an enumeration class for different types of list items, and a function to determine
5
+ the type of a given file. The module also adds support for the WebP image format.
6
+
7
+ The module uses the ``mimetypes`` library for MIME type detection and imports custom functions
8
+ for identifying archive, model, and data files.
9
+ """
10
+
11
+ import mimetypes
12
+ import os
13
+ from enum import Enum, unique
14
+ from typing import Union
15
+
16
+ from .archive import is_archive_or_compressed
17
+ from .data import is_data_file
18
+ from .model import is_model_file
19
+
20
+ mimetypes.add_type('image/webp', '.webp')
21
+
22
+
23
+ @unique
24
+ class FileItemType(Enum):
25
+ """
26
+ Enum class representing different types of list items.
27
+
28
+ This enumeration defines various file and folder types that can be encountered
29
+ in a file system or list of items. Each type is associated with a unique integer value.
30
+
31
+ Usage:
32
+ >>> item_type = FileItemType.FILE
33
+ >>> print(item_type)
34
+ FileItemType.FILE
35
+ >>> print(item_type.value)
36
+ 1
37
+ """
38
+
39
+ FILE = 0x1
40
+ FOLDER = 0x2
41
+ IMAGE = 0x3
42
+ ARCHIVE = 0x4
43
+ MODEL = 0x5
44
+ DATA = 0x6
45
+
46
+ @property
47
+ def render_color(self):
48
+ """
49
+ Get the render color based on the item type.
50
+
51
+ This property returns a color string associated with each item type,
52
+ which can be used for rendering or display purposes.
53
+
54
+ :return: The render color for the item type.
55
+ :rtype: str or None
56
+
57
+ :raises ValueError: If an unknown item type is encountered.
58
+
59
+ Usage:
60
+ >>> item_type = FileItemType.FOLDER
61
+ >>> print(item_type.render_color)
62
+ blue
63
+ """
64
+ if self == FileItemType.FILE:
65
+ return None
66
+ elif self == FileItemType.FOLDER:
67
+ return 'blue'
68
+ elif self == FileItemType.IMAGE:
69
+ return 'magenta'
70
+ elif self == FileItemType.ARCHIVE:
71
+ return 'red'
72
+ elif self == FileItemType.MODEL:
73
+ return 'green'
74
+ elif self == FileItemType.DATA:
75
+ return 'yellow'
76
+ else:
77
+ raise ValueError(f'Unknown type - {self!r}') # pragma: no cover
78
+
79
+
80
+ def get_file_type(filename: Union[str, os.PathLike]) -> FileItemType:
81
+ """
82
+ Determine the type of a given file.
83
+
84
+ This function analyzes the provided filename and returns the corresponding FileItemType.
85
+ It uses various methods to determine the file type, including checking for archives,
86
+ model files, data files, and image files based on MIME types.
87
+
88
+ :param filename: The name or path of the file to analyze.
89
+ :type filename: Union[str, os.PathLike]
90
+
91
+ :return: The determined FileItemType for the given file.
92
+ :rtype: FileItemType
93
+
94
+ :raises TypeError: If the provided filename is not a string or PathLike object.
95
+
96
+ Usage:
97
+ >>> file_type = get_file_type('image.jpg')
98
+ >>> print(file_type)
99
+ FileItemType.IMAGE
100
+
101
+ >>> file_type = get_file_type('data.csv')
102
+ >>> print(file_type)
103
+ FileItemType.DATA
104
+ """
105
+ if not isinstance(filename, (str, os.PathLike)):
106
+ raise TypeError(f'Unknown file name type - {filename!r}')
107
+ filename = os.path.basename(os.path.normcase(str(filename)))
108
+
109
+ mimetype, _ = mimetypes.guess_type(filename)
110
+ type_ = FileItemType.FILE
111
+ if is_archive_or_compressed(filename):
112
+ type_ = FileItemType.ARCHIVE
113
+ elif is_model_file(filename):
114
+ type_ = FileItemType.MODEL
115
+ elif is_data_file(filename):
116
+ type_ = FileItemType.DATA
117
+ elif mimetype:
118
+ if 'image' in mimetype:
119
+ type_ = FileItemType.IMAGE
120
+
121
+ return type_
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hfutils
3
- Version: 0.3.9
3
+ Version: 0.4.0
4
4
  Summary: Useful utilities for huggingface
5
5
  Home-page: https://github.com/deepghs/hfutils
6
6
  Author: narugo1992
@@ -37,6 +37,7 @@ hfutils/entry/index.py
37
37
  hfutils/entry/ls.py
38
38
  hfutils/entry/ls_repo.py
39
39
  hfutils/entry/rollback.py
40
+ hfutils/entry/tree.py
40
41
  hfutils/entry/upload.py
41
42
  hfutils/entry/whoami.py
42
43
  hfutils/index/__init__.py
@@ -55,13 +56,17 @@ hfutils/repository/base.py
55
56
  hfutils/repository/clone.py
56
57
  hfutils/repository/rollback.py
57
58
  hfutils/utils/__init__.py
59
+ hfutils/utils/archive.py
58
60
  hfutils/utils/binary.py
61
+ hfutils/utils/data.py
59
62
  hfutils/utils/download.py
60
63
  hfutils/utils/irregular_repo.json
61
64
  hfutils/utils/logging.py
65
+ hfutils/utils/model.py
62
66
  hfutils/utils/number.py
63
67
  hfutils/utils/path.py
64
68
  hfutils/utils/session.py
65
69
  hfutils/utils/temp.py
66
70
  hfutils/utils/tqdm_.py
71
+ hfutils/utils/type_.py
67
72
  hfutils/utils/walk.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