hfutils 0.3.6__tar.gz → 0.3.7__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 (69) hide show
  1. {hfutils-0.3.6/hfutils.egg-info → hfutils-0.3.7}/PKG-INFO +24 -23
  2. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/config/meta.py +1 -1
  3. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/entry/download.py +10 -1
  4. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/entry/index.py +5 -1
  5. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/entry/ls.py +4 -0
  6. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/entry/ls_repo.py +4 -0
  7. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/entry/upload.py +4 -0
  8. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/entry/whoami.py +4 -0
  9. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/operate/download.py +4 -1
  10. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/operate/validate.py +11 -3
  11. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/utils/__init__.py +1 -0
  12. hfutils-0.3.7/hfutils/utils/session.py +115 -0
  13. {hfutils-0.3.6 → hfutils-0.3.7/hfutils.egg-info}/PKG-INFO +24 -23
  14. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils.egg-info/SOURCES.txt +1 -0
  15. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils.egg-info/requires.txt +1 -0
  16. {hfutils-0.3.6 → hfutils-0.3.7}/requirements.txt +2 -1
  17. {hfutils-0.3.6 → hfutils-0.3.7}/LICENSE +0 -0
  18. {hfutils-0.3.6 → hfutils-0.3.7}/MANIFEST.in +0 -0
  19. {hfutils-0.3.6 → hfutils-0.3.7}/README.md +0 -0
  20. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/__init__.py +0 -0
  21. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/__main__.py +0 -0
  22. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/archive/__init__.py +0 -0
  23. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/archive/base.py +0 -0
  24. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/archive/rar.py +0 -0
  25. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/archive/sevenz.py +0 -0
  26. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/archive/tar.py +0 -0
  27. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/archive/zip.py +0 -0
  28. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/cache/__init__.py +0 -0
  29. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/cache/delete.py +0 -0
  30. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/config/__init__.py +0 -0
  31. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/entry/__init__.py +0 -0
  32. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/entry/base.py +0 -0
  33. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/entry/cli.py +0 -0
  34. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/entry/clone.py +0 -0
  35. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/entry/dispatch.py +0 -0
  36. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/entry/rollback.py +0 -0
  37. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/index/__init__.py +0 -0
  38. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/index/fetch.py +0 -0
  39. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/index/hash.py +0 -0
  40. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/index/local_fetch.py +0 -0
  41. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/index/make.py +0 -0
  42. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/index/validate.py +0 -0
  43. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/operate/__init__.py +0 -0
  44. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/operate/base.py +0 -0
  45. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/operate/upload.py +0 -0
  46. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/repository/__init__.py +0 -0
  47. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/repository/base.py +0 -0
  48. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/repository/clone.py +0 -0
  49. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/repository/rollback.py +0 -0
  50. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/utils/binary.py +0 -0
  51. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/utils/download.py +0 -0
  52. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/utils/irregular_repo.json +0 -0
  53. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/utils/logging.py +0 -0
  54. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/utils/number.py +0 -0
  55. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/utils/path.py +0 -0
  56. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/utils/temp.py +0 -0
  57. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/utils/tqdm_.py +0 -0
  58. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils/utils/walk.py +0 -0
  59. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils.egg-info/dependency_links.txt +0 -0
  60. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils.egg-info/entry_points.txt +0 -0
  61. {hfutils-0.3.6 → hfutils-0.3.7}/hfutils.egg-info/top_level.txt +0 -0
  62. {hfutils-0.3.6 → hfutils-0.3.7}/requirements-7z.txt +0 -0
  63. {hfutils-0.3.6 → hfutils-0.3.7}/requirements-build.txt +0 -0
  64. {hfutils-0.3.6 → hfutils-0.3.7}/requirements-doc.txt +0 -0
  65. {hfutils-0.3.6 → hfutils-0.3.7}/requirements-rar.txt +0 -0
  66. {hfutils-0.3.6 → hfutils-0.3.7}/requirements-test.txt +0 -0
  67. {hfutils-0.3.6 → hfutils-0.3.7}/requirements-transfer.txt +0 -0
  68. {hfutils-0.3.6 → hfutils-0.3.7}/setup.cfg +0 -0
  69. {hfutils-0.3.6 → hfutils-0.3.7}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hfutils
3
- Version: 0.3.6
3
+ Version: 0.3.7
4
4
  Summary: Useful utilities for huggingface
5
5
  Home-page: https://github.com/deepghs/hfutils
6
6
  Author: narugo1992
@@ -29,6 +29,29 @@ Requires-Dist: tzlocal
29
29
  Requires-Dist: natsort
30
30
  Requires-Dist: urlobject
31
31
  Requires-Dist: fsspec>=2024
32
+ Requires-Dist: random_user_agent
33
+ Provides-Extra: test
34
+ Requires-Dist: coverage>=5; extra == "test"
35
+ Requires-Dist: mock>=4.0.3; extra == "test"
36
+ Requires-Dist: flake8~=3.5; extra == "test"
37
+ Requires-Dist: testfixtures>=6.18.5; extra == "test"
38
+ Requires-Dist: pytest~=6.2.5; extra == "test"
39
+ Requires-Dist: pytest-cov~=3.0.0; extra == "test"
40
+ Requires-Dist: pytest-mock~=3.6.1; extra == "test"
41
+ Requires-Dist: pytest-xdist>=1.34.0; extra == "test"
42
+ Requires-Dist: pytest-rerunfailures~=10.2; extra == "test"
43
+ Requires-Dist: pytest-timeout~=2.0.2; extra == "test"
44
+ Requires-Dist: pytest-benchmark~=3.4.0; extra == "test"
45
+ Requires-Dist: easydict<2,>=1.7; extra == "test"
46
+ Requires-Dist: testtools>=2; extra == "test"
47
+ Requires-Dist: where>=1.0.2; extra == "test"
48
+ Requires-Dist: responses>=0.20.0; extra == "test"
49
+ Requires-Dist: natsort; extra == "test"
50
+ Provides-Extra: rar
51
+ Requires-Dist: rarfile; extra == "rar"
52
+ Provides-Extra: build
53
+ Requires-Dist: pyinstaller<5,>=4.7; extra == "build"
54
+ Requires-Dist: setuptools<70; extra == "build"
32
55
  Provides-Extra: doc
33
56
  Requires-Dist: Jinja2>=3.0.0; extra == "doc"
34
57
  Requires-Dist: sphinx>=3.2.0; extra == "doc"
@@ -49,32 +72,10 @@ Requires-Dist: ipykernel>=6.15; extra == "doc"
49
72
  Requires-Dist: py-cpuinfo>=8.0.0; extra == "doc"
50
73
  Requires-Dist: click>=7.0.0; extra == "doc"
51
74
  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"
69
75
  Provides-Extra: transfer
70
76
  Requires-Dist: hf-transfer; extra == "transfer"
71
77
  Provides-Extra: 7z
72
78
  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
- Provides-Extra: rar
77
- Requires-Dist: rarfile; extra == "rar"
78
79
 
79
80
  # hfutils
80
81
 
@@ -7,7 +7,7 @@ Overview:
7
7
  __TITLE__ = 'hfutils'
8
8
 
9
9
  #: Version of this project.
10
- __VERSION__ = '0.3.6'
10
+ __VERSION__ = '0.3.7'
11
11
 
12
12
  #: Short description of the project, will be included in ``setup.py``.
13
13
  __DESCRIPTION__ = 'Useful utilities for huggingface'
@@ -3,10 +3,12 @@ import warnings
3
3
  from typing import Optional
4
4
 
5
5
  import click
6
+ from huggingface_hub import configure_http_backend
6
7
 
7
8
  from .base import CONTEXT_SETTINGS, command_wrap, ClickErrorException
8
9
  from ..operate import download_file_to_file, download_archive_as_directory, download_directory_as_directory
9
10
  from ..operate.base import REPO_TYPES, RepoTypeTyping
11
+ from ..utils import get_requests_session
10
12
 
11
13
 
12
14
  class NoRemotePathAssignedWithDownload(ClickErrorException):
@@ -49,6 +51,8 @@ def _add_download_subcommand(cli: click.Group) -> click.Group:
49
51
  help='Password for the archive file. Only applied when -a is used.', show_default=True)
50
52
  @click.option('-w', '--wildcard', 'wildcard', type=str, default=None,
51
53
  help='Wildcard for files to download. Only applied when -d is used.', show_default=True)
54
+ @click.option('-s', '--soft_mode_when_check', 'soft_mode_when_check', is_flag=True, type=bool, default=False,
55
+ help='Just check the file size when validating the downloaded files.', show_default=True)
52
56
  @click.option('--tmpdir', 'tmpdir', type=str, default=None,
53
57
  help='Use custom temporary Directory.', show_default=True)
54
58
  @command_wrap()
@@ -56,7 +60,7 @@ def _add_download_subcommand(cli: click.Group) -> click.Group:
56
60
  repo_id: str, repo_type: RepoTypeTyping,
57
61
  file_in_repo: Optional[str], archive_in_repo: Optional[str], dir_in_repo: Optional[str],
58
62
  output_path: str, revision: str, max_workers: int,
59
- password: Optional[str], wildcard: Optional[str], tmpdir: Optional[str]
63
+ password: Optional[str], wildcard: Optional[str], soft_mode_when_check: bool, tmpdir: Optional[str]
60
64
  ):
61
65
  """
62
66
  Download data from HuggingFace repositories.
@@ -81,9 +85,13 @@ def _add_download_subcommand(cli: click.Group) -> click.Group:
81
85
  :type password: str, optional
82
86
  :param wildcard: Wildcard for files to download. Only applied when -d is used.
83
87
  :type password: str, optional
88
+ :param soft_mode_when_check: Just check the size of the expected file when enabled. Default is False.
89
+ :type soft_mode_when_check: bool
84
90
  :param tmpdir: Use custom temporary Directory.
85
91
  :type tmpdir: str, optional
86
92
  """
93
+ configure_http_backend(get_requests_session)
94
+
87
95
  if tmpdir:
88
96
  os.environ['TMPDIR'] = tmpdir
89
97
 
@@ -126,6 +134,7 @@ def _add_download_subcommand(cli: click.Group) -> click.Group:
126
134
  revision=revision,
127
135
  silent=False,
128
136
  max_workers=max_workers,
137
+ soft_mode_when_check=soft_mode_when_check,
129
138
  )
130
139
 
131
140
  else:
@@ -18,13 +18,15 @@ from typing import Optional
18
18
 
19
19
  import click
20
20
  from hbutils.string import plural_word
21
+ from huggingface_hub import configure_http_backend
21
22
 
22
23
  from .base import CONTEXT_SETTINGS
23
24
  from ..cache import delete_detached_cache
24
25
  from ..index import hf_tar_validate, tar_create_index
25
26
  from ..operate import get_hf_fs, download_file_to_file, upload_directory_as_directory
26
27
  from ..operate.base import REPO_TYPES, RepoTypeTyping, get_hf_client
27
- from ..utils import tqdm, hf_fs_path, parse_hf_fs_path, TemporaryDirectory, hf_normpath, ColoredFormatter
28
+ from ..utils import tqdm, hf_fs_path, parse_hf_fs_path, TemporaryDirectory, hf_normpath, ColoredFormatter, \
29
+ get_requests_session
28
30
 
29
31
 
30
32
  def _add_index_subcommand(cli: click.Group) -> click.Group:
@@ -86,6 +88,8 @@ def _add_index_subcommand(cli: click.Group) -> click.Group:
86
88
  This function is typically invoked through the CLI interface, like:
87
89
  $ python script.py index -r my_repo -x my_index_repo -t dataset -R main --min_upload_interval 120
88
90
  """
91
+ configure_http_backend(get_requests_session)
92
+
89
93
  logger = logging.getLogger()
90
94
  logger.setLevel(logging.INFO)
91
95
  console_handler = logging.StreamHandler()
@@ -5,10 +5,12 @@ from typing import Union, List
5
5
 
6
6
  import click
7
7
  import tzlocal
8
+ from huggingface_hub import configure_http_backend
8
9
  from huggingface_hub.hf_api import RepoFolder, RepoFile
9
10
 
10
11
  from .base import CONTEXT_SETTINGS
11
12
  from ..operate.base import REPO_TYPES, get_hf_client
13
+ from ..utils import get_requests_session
12
14
 
13
15
  mimetypes.add_type('image/webp', '.webp')
14
16
 
@@ -124,6 +126,8 @@ def _add_ls_subcommand(cli: click.Group) -> click.Group:
124
126
  :param show_detailed: Flag to indicate whether to show detailed file information.
125
127
  :type show_detailed: bool
126
128
  """
129
+ configure_http_backend(get_requests_session)
130
+
127
131
  hf_client = get_hf_client()
128
132
  items: List[ListItem] = []
129
133
  for item in hf_client.list_repo_tree(
@@ -2,10 +2,12 @@ import fnmatch
2
2
  from typing import Optional
3
3
 
4
4
  import click
5
+ from huggingface_hub import configure_http_backend
5
6
  from huggingface_hub.utils import LocalTokenNotFoundError
6
7
 
7
8
  from .base import CONTEXT_SETTINGS, ClickErrorException
8
9
  from ..operate.base import REPO_TYPES, get_hf_client
10
+ from ..utils import get_requests_session
9
11
 
10
12
 
11
13
  class NoLocalAuthentication(ClickErrorException):
@@ -46,6 +48,8 @@ def _add_ls_repo_subcommand(cli: click.Group) -> click.Group:
46
48
  :param pattern: Pattern of the repository names.
47
49
  :type pattern: str
48
50
  """
51
+ configure_http_backend(get_requests_session)
52
+
49
53
  hf_client = get_hf_client()
50
54
  if not author:
51
55
  try:
@@ -2,10 +2,12 @@ import warnings
2
2
  from typing import Optional
3
3
 
4
4
  import click
5
+ from huggingface_hub import configure_http_backend
5
6
 
6
7
  from .base import CONTEXT_SETTINGS, command_wrap, ClickErrorException
7
8
  from ..operate import upload_file_to_file, upload_directory_as_archive, upload_directory_as_directory
8
9
  from ..operate.base import REPO_TYPES, RepoTypeTyping, get_hf_client
10
+ from ..utils import get_requests_session
9
11
 
10
12
 
11
13
  class NoRemotePathAssignedWithUpload(ClickErrorException):
@@ -78,6 +80,8 @@ def _add_upload_subcommand(cli: click.Group) -> click.Group:
78
80
  :param public: Set public repository when created.
79
81
  :type public: bool
80
82
  """
83
+ configure_http_backend(get_requests_session)
84
+
81
85
  if not file_in_repo and not archive_in_repo and not dir_in_repo:
82
86
  raise NoRemotePathAssignedWithUpload('No remote path in repository assigned.\n'
83
87
  'One of the -f, -a, or -d option is required.')
@@ -1,9 +1,11 @@
1
1
  import click
2
2
  from hbutils.string import plural_word
3
+ from huggingface_hub import configure_http_backend
3
4
  from huggingface_hub.utils import LocalTokenNotFoundError
4
5
 
5
6
  from .base import CONTEXT_SETTINGS
6
7
  from ..operate.base import get_hf_client
8
+ from ..utils import get_requests_session
7
9
 
8
10
 
9
11
  def _add_whoami_subcommand(cli: click.Group) -> click.Group:
@@ -28,6 +30,8 @@ def _add_whoami_subcommand(cli: click.Group) -> click.Group:
28
30
  This function retrieves the current user's identification from the Hugging Face Hub API and displays it.
29
31
 
30
32
  """
33
+ configure_http_backend(get_requests_session)
34
+
31
35
  hf_client = get_hf_client()
32
36
  try:
33
37
  info = hf_client.whoami()
@@ -85,7 +85,7 @@ def download_directory_as_directory(
85
85
  repo_type: RepoTypeTyping = 'dataset', revision: str = 'main',
86
86
  silent: bool = False, ignore_patterns: List[str] = _IGNORE_PATTERN_UNSET,
87
87
  resume_download: bool = True, max_workers: int = 8, max_retries: int = 5,
88
- hf_token: Optional[str] = None
88
+ soft_mode_when_check: bool = False, hf_token: Optional[str] = None
89
89
  ):
90
90
  """
91
91
  Download all files in a directory from a Hugging Face repository to a local directory.
@@ -112,6 +112,8 @@ def download_directory_as_directory(
112
112
  :type max_retries: int
113
113
  :param resume_download: Resume the existing download.
114
114
  :type resume_download: bool
115
+ :param soft_mode_when_check: Just check the size of the expected file when enabled. Default is False.
116
+ :type soft_mode_when_check: bool
115
117
  :param hf_token: Huggingface token for API client, use ``HF_TOKEN`` variable if not assigned.
116
118
  :type hf_token: str, optional
117
119
  """
@@ -138,6 +140,7 @@ def download_directory_as_directory(
138
140
  file_in_repo=file_in_repo,
139
141
  revision=revision,
140
142
  hf_token=hf_token,
143
+ soft_mode=soft_mode_when_check,
141
144
  ):
142
145
  logging.info(f'Local file {rel_file} is ready, download skipped.')
143
146
  else:
@@ -9,7 +9,8 @@ from huggingface_hub.utils import EntryNotFoundError
9
9
  from .base import RepoTypeTyping, get_hf_client
10
10
 
11
11
 
12
- def _raw_check_local_file(repo_file: RepoFile, local_file: str, chunk_for_hash: int = 1 << 20) -> bool:
12
+ def _raw_check_local_file(repo_file: RepoFile, local_file: str, chunk_for_hash: int = 1 << 20,
13
+ soft_mode: bool = False) -> bool:
13
14
  """
14
15
  Checks if the local file matches the file on the Hugging Face Hub repository.
15
16
 
@@ -19,6 +20,8 @@ def _raw_check_local_file(repo_file: RepoFile, local_file: str, chunk_for_hash:
19
20
  :type local_file: str
20
21
  :param chunk_for_hash: The chunk size for calculating the hash. Default is 1 << 20.
21
22
  :type chunk_for_hash: int
23
+ :param soft_mode: Just check the size of the expected file when enabled. Default is False.
24
+ :type soft_mode: bool
22
25
  :return: True if the local file matches the file on the repository, False otherwise.
23
26
  :rtype: bool
24
27
  """
@@ -28,6 +31,9 @@ def _raw_check_local_file(repo_file: RepoFile, local_file: str, chunk_for_hash:
28
31
  f'the remote file {repo_file.path!r} ({repo_file.size}).')
29
32
  return False
30
33
 
34
+ if soft_mode:
35
+ return True
36
+
31
37
  if repo_file.lfs:
32
38
  sha = sha256()
33
39
  expected_hash = repo_file.lfs.sha256
@@ -54,7 +60,7 @@ def _raw_check_local_file(repo_file: RepoFile, local_file: str, chunk_for_hash:
54
60
 
55
61
  def is_local_file_ready(local_file: str, repo_id: str, file_in_repo: str,
56
62
  repo_type: RepoTypeTyping = 'dataset', revision: str = 'main',
57
- hf_token: Optional[str] = None) -> bool:
63
+ soft_mode: bool = False, hf_token: Optional[str] = None) -> bool:
58
64
  """
59
65
  Checks if the local file is ready by comparing it with the file on the Hugging Face Hub repository.
60
66
 
@@ -68,6 +74,8 @@ def is_local_file_ready(local_file: str, repo_id: str, file_in_repo: str,
68
74
  :type repo_type: RepoTypeTyping
69
75
  :param revision: The revision of the repository. Default is 'main'.
70
76
  :type revision: str
77
+ :param soft_mode: Just check the size of the expected file when enabled. Default is False.
78
+ :type soft_mode: bool
71
79
  :param hf_token: The Hugging Face API token. Default is None.
72
80
  :type hf_token: Optional[str]
73
81
  :return: True if the local file matches the file on the repository, False otherwise.
@@ -83,6 +91,6 @@ def is_local_file_ready(local_file: str, repo_id: str, file_in_repo: str,
83
91
  if len(infos) == 0:
84
92
  raise EntryNotFoundError(f'Entry {repo_type}s/{repo_id}/{file_in_repo} not found.')
85
93
  elif len(infos) == 1:
86
- return _raw_check_local_file(infos[0], local_file)
94
+ return _raw_check_local_file(infos[0], local_file, soft_mode=soft_mode)
87
95
  else:
88
96
  assert False, f'Should not reach here, multiple files with the same name found - {infos!r}' # pragma: no cover
@@ -3,6 +3,7 @@ from .download import download_file
3
3
  from .logging import ColoredFormatter
4
4
  from .number import number_to_tag
5
5
  from .path import hf_normpath, hf_fs_path, parse_hf_fs_path, HfFileSystemPath
6
+ from .session import TimeoutHTTPAdapter, get_requests_session, get_random_ua
6
7
  from .temp import TemporaryDirectory
7
8
  from .tqdm_ import tqdm
8
9
  from .walk import walk_files
@@ -0,0 +1,115 @@
1
+ """
2
+ This module provides functionality for creating and managing HTTP sessions with customizable retry logic,
3
+ timeout settings, and user-agent rotation using random user-agent generation. It is designed to help with
4
+ robust web scraping and API consumption by handling common HTTP errors and timeouts gracefully.
5
+
6
+ Main Features:
7
+
8
+ - Automatic retries on specified HTTP response status codes.
9
+ - Configurable request timeout.
10
+ - Rotating user-agent for each session to mimic different browsers and operating systems.
11
+ - Optional SSL verification.
12
+ """
13
+
14
+ from functools import lru_cache
15
+ from typing import Optional, Dict
16
+
17
+ import requests
18
+ from random_user_agent.params import SoftwareName, OperatingSystem
19
+ from random_user_agent.user_agent import UserAgent
20
+ from requests.adapters import HTTPAdapter, Retry
21
+
22
+ DEFAULT_TIMEOUT = 15 # seconds
23
+
24
+
25
+ class TimeoutHTTPAdapter(HTTPAdapter):
26
+ """
27
+ A custom HTTPAdapter that enforces a default timeout on all requests.
28
+
29
+ :param args: Variable length argument list for HTTPAdapter.
30
+ :param kwargs: Arbitrary keyword arguments. 'timeout' can be specified to set a custom timeout.
31
+ """
32
+
33
+ def __init__(self, *args, **kwargs):
34
+ self.timeout = DEFAULT_TIMEOUT
35
+ if "timeout" in kwargs:
36
+ self.timeout = kwargs["timeout"]
37
+ del kwargs["timeout"]
38
+ super().__init__(*args, **kwargs)
39
+
40
+ def send(self, request, **kwargs):
41
+ """
42
+ Sends the Request object, applying the timeout setting.
43
+
44
+ :param request: The Request object to send.
45
+ :type request: requests.PreparedRequest
46
+ :param kwargs: Keyword arguments that may contain 'timeout'.
47
+ :return: The response to the request.
48
+ """
49
+ timeout = kwargs.get("timeout")
50
+ if timeout is None:
51
+ kwargs["timeout"] = self.timeout
52
+ return super().send(request, **kwargs)
53
+
54
+
55
+ def get_requests_session(max_retries: int = 5, timeout: int = DEFAULT_TIMEOUT, verify: bool = True,
56
+ headers: Optional[Dict[str, str]] = None, session: Optional[requests.Session] = None) \
57
+ -> requests.Session:
58
+ """
59
+ Creates a requests session with retry logic, timeout settings, and random user-agent headers.
60
+
61
+ :param max_retries: Maximum number of retries on failed requests.
62
+ :type max_retries: int
63
+ :param timeout: Request timeout in seconds.
64
+ :type timeout: int
65
+ :param verify: Whether to verify SSL certificates.
66
+ :type verify: bool
67
+ :param headers: Additional headers to include in the requests.
68
+ :type headers: Optional[Dict[str, str]]
69
+ :param session: An existing requests.Session instance to use.
70
+ :type session: Optional[requests.Session]
71
+ :return: A configured requests.Session object.
72
+ :rtype: requests.Session
73
+ """
74
+ session = session or requests.session()
75
+ retries = Retry(
76
+ total=max_retries, backoff_factor=1,
77
+ status_forcelist=[408, 429, 500, 501, 502, 503, 504, 505, 506, 507, 509, 510, 511],
78
+ allowed_methods=["HEAD", "GET", "POST", "PUT", "DELETE", "OPTIONS", "TRACE"],
79
+ )
80
+ adapter = TimeoutHTTPAdapter(max_retries=retries, timeout=timeout, pool_connections=32, pool_maxsize=32)
81
+ session.mount('http://', adapter)
82
+ session.mount('https://', adapter)
83
+ session.headers.update({
84
+ "User-Agent": get_random_ua(),
85
+ **dict(headers or {}),
86
+ })
87
+ if not verify:
88
+ session.verify = False
89
+
90
+ return session
91
+
92
+
93
+ @lru_cache()
94
+ def _ua_pool():
95
+ """
96
+ Creates and caches a UserAgent rotator instance with a specified number of user agents.
97
+
98
+ :return: A UserAgent rotator instance.
99
+ :rtype: UserAgent
100
+ """
101
+ software_names = [SoftwareName.CHROME.value, SoftwareName.FIREFOX.value, SoftwareName.EDGE.value]
102
+ operating_systems = [OperatingSystem.WINDOWS.value, OperatingSystem.MACOS.value]
103
+
104
+ user_agent_rotator = UserAgent(software_names=software_names, operating_systems=operating_systems, limit=1000)
105
+ return user_agent_rotator
106
+
107
+
108
+ def get_random_ua():
109
+ """
110
+ Retrieves a random user agent string from the cached UserAgent rotator.
111
+
112
+ :return: A random user agent string.
113
+ :rtype: str
114
+ """
115
+ return _ua_pool().get_random_user_agent()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hfutils
3
- Version: 0.3.6
3
+ Version: 0.3.7
4
4
  Summary: Useful utilities for huggingface
5
5
  Home-page: https://github.com/deepghs/hfutils
6
6
  Author: narugo1992
@@ -29,6 +29,29 @@ Requires-Dist: tzlocal
29
29
  Requires-Dist: natsort
30
30
  Requires-Dist: urlobject
31
31
  Requires-Dist: fsspec>=2024
32
+ Requires-Dist: random_user_agent
33
+ Provides-Extra: test
34
+ Requires-Dist: coverage>=5; extra == "test"
35
+ Requires-Dist: mock>=4.0.3; extra == "test"
36
+ Requires-Dist: flake8~=3.5; extra == "test"
37
+ Requires-Dist: testfixtures>=6.18.5; extra == "test"
38
+ Requires-Dist: pytest~=6.2.5; extra == "test"
39
+ Requires-Dist: pytest-cov~=3.0.0; extra == "test"
40
+ Requires-Dist: pytest-mock~=3.6.1; extra == "test"
41
+ Requires-Dist: pytest-xdist>=1.34.0; extra == "test"
42
+ Requires-Dist: pytest-rerunfailures~=10.2; extra == "test"
43
+ Requires-Dist: pytest-timeout~=2.0.2; extra == "test"
44
+ Requires-Dist: pytest-benchmark~=3.4.0; extra == "test"
45
+ Requires-Dist: easydict<2,>=1.7; extra == "test"
46
+ Requires-Dist: testtools>=2; extra == "test"
47
+ Requires-Dist: where>=1.0.2; extra == "test"
48
+ Requires-Dist: responses>=0.20.0; extra == "test"
49
+ Requires-Dist: natsort; extra == "test"
50
+ Provides-Extra: rar
51
+ Requires-Dist: rarfile; extra == "rar"
52
+ Provides-Extra: build
53
+ Requires-Dist: pyinstaller<5,>=4.7; extra == "build"
54
+ Requires-Dist: setuptools<70; extra == "build"
32
55
  Provides-Extra: doc
33
56
  Requires-Dist: Jinja2>=3.0.0; extra == "doc"
34
57
  Requires-Dist: sphinx>=3.2.0; extra == "doc"
@@ -49,32 +72,10 @@ Requires-Dist: ipykernel>=6.15; extra == "doc"
49
72
  Requires-Dist: py-cpuinfo>=8.0.0; extra == "doc"
50
73
  Requires-Dist: click>=7.0.0; extra == "doc"
51
74
  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"
69
75
  Provides-Extra: transfer
70
76
  Requires-Dist: hf-transfer; extra == "transfer"
71
77
  Provides-Extra: 7z
72
78
  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
- Provides-Extra: rar
77
- Requires-Dist: rarfile; extra == "rar"
78
79
 
79
80
  # hfutils
80
81
 
@@ -61,6 +61,7 @@ hfutils/utils/irregular_repo.json
61
61
  hfutils/utils/logging.py
62
62
  hfutils/utils/number.py
63
63
  hfutils/utils/path.py
64
+ hfutils/utils/session.py
64
65
  hfutils/utils/temp.py
65
66
  hfutils/utils/tqdm_.py
66
67
  hfutils/utils/walk.py
@@ -7,6 +7,7 @@ tzlocal
7
7
  natsort
8
8
  urlobject
9
9
  fsspec>=2024
10
+ random_user_agent
10
11
 
11
12
  [7z]
12
13
  py7zr
@@ -6,4 +6,5 @@ click>=7
6
6
  tzlocal
7
7
  natsort
8
8
  urlobject
9
- fsspec>=2024
9
+ fsspec>=2024
10
+ random_user_agent
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