not-pegasus commited on
Commit
b90379c
·
verified ·
1 Parent(s): 8ac5b3e

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. env/lib/python3.13/site-packages/fsspec-2025.12.0.dist-info/INSTALLER +1 -0
  2. env/lib/python3.13/site-packages/fsspec-2025.12.0.dist-info/METADATA +256 -0
  3. env/lib/python3.13/site-packages/fsspec-2025.12.0.dist-info/RECORD +119 -0
  4. env/lib/python3.13/site-packages/fsspec-2025.12.0.dist-info/WHEEL +4 -0
  5. env/lib/python3.13/site-packages/hf_xet/__init__.py +5 -0
  6. env/lib/python3.13/site-packages/huggingface_hub-1.2.1.dist-info/INSTALLER +1 -0
  7. env/lib/python3.13/site-packages/huggingface_hub-1.2.1.dist-info/METADATA +320 -0
  8. env/lib/python3.13/site-packages/huggingface_hub-1.2.1.dist-info/RECORD +307 -0
  9. env/lib/python3.13/site-packages/huggingface_hub-1.2.1.dist-info/REQUESTED +0 -0
  10. env/lib/python3.13/site-packages/huggingface_hub-1.2.1.dist-info/WHEEL +5 -0
  11. env/lib/python3.13/site-packages/huggingface_hub-1.2.1.dist-info/entry_points.txt +6 -0
  12. env/lib/python3.13/site-packages/huggingface_hub-1.2.1.dist-info/top_level.txt +1 -0
  13. env/lib/python3.13/site-packages/huggingface_hub/__init__.py +1560 -0
  14. env/lib/python3.13/site-packages/huggingface_hub/_commit_api.py +966 -0
  15. env/lib/python3.13/site-packages/huggingface_hub/_commit_scheduler.py +353 -0
  16. env/lib/python3.13/site-packages/huggingface_hub/_inference_endpoints.py +418 -0
  17. env/lib/python3.13/site-packages/huggingface_hub/_jobs_api.py +301 -0
  18. env/lib/python3.13/site-packages/huggingface_hub/_local_folder.py +447 -0
  19. env/lib/python3.13/site-packages/huggingface_hub/_oauth.py +460 -0
  20. env/lib/python3.13/site-packages/huggingface_hub/_snapshot_download.py +465 -0
  21. env/lib/python3.13/site-packages/huggingface_hub/_space_api.py +168 -0
  22. env/lib/python3.13/site-packages/huggingface_hub/_tensorboard_logger.py +190 -0
  23. env/lib/python3.13/site-packages/huggingface_hub/_webhooks_payload.py +137 -0
  24. env/lib/python3.13/site-packages/huggingface_hub/community.py +363 -0
  25. env/lib/python3.13/site-packages/huggingface_hub/constants.py +279 -0
  26. env/lib/python3.13/site-packages/huggingface_hub/errors.py +404 -0
  27. env/lib/python3.13/site-packages/huggingface_hub/fastai_utils.py +414 -0
  28. env/lib/python3.13/site-packages/huggingface_hub/file_download.py +1958 -0
  29. env/lib/python3.13/site-packages/huggingface_hub/hf_api.py +0 -0
  30. env/lib/python3.13/site-packages/huggingface_hub/hub_mixin.py +831 -0
  31. env/lib/python3.13/site-packages/huggingface_hub/lfs.py +393 -0
  32. env/lib/python3.13/site-packages/huggingface_hub/py.typed +0 -0
  33. env/lib/python3.13/site-packages/huggingface_hub/repocard_data.py +770 -0
  34. env/lib/python3.13/site-packages/idna/__init__.py +45 -0
  35. env/lib/python3.13/site-packages/idna/codec.py +122 -0
  36. env/lib/python3.13/site-packages/idna/compat.py +15 -0
  37. env/lib/python3.13/site-packages/idna/core.py +437 -0
  38. env/lib/python3.13/site-packages/idna/idnadata.py +4309 -0
  39. env/lib/python3.13/site-packages/idna/intranges.py +57 -0
  40. env/lib/python3.13/site-packages/idna/package_data.py +1 -0
  41. env/lib/python3.13/site-packages/idna/py.typed +0 -0
  42. env/lib/python3.13/site-packages/idna/uts46data.py +0 -0
  43. env/lib/python3.13/site-packages/pip/__init__.py +13 -0
  44. env/lib/python3.13/site-packages/pip/__main__.py +24 -0
  45. env/lib/python3.13/site-packages/pip/__pip-runner__.py +50 -0
  46. env/lib/python3.13/site-packages/pip/py.typed +4 -0
  47. env/lib/python3.13/site-packages/pyyaml-6.0.3.dist-info/INSTALLER +1 -0
  48. env/lib/python3.13/site-packages/pyyaml-6.0.3.dist-info/METADATA +59 -0
  49. env/lib/python3.13/site-packages/pyyaml-6.0.3.dist-info/RECORD +43 -0
  50. env/lib/python3.13/site-packages/pyyaml-6.0.3.dist-info/WHEEL +7 -0
env/lib/python3.13/site-packages/fsspec-2025.12.0.dist-info/INSTALLER ADDED
@@ -0,0 +1 @@
 
 
1
+ pip
env/lib/python3.13/site-packages/fsspec-2025.12.0.dist-info/METADATA ADDED
@@ -0,0 +1,256 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Metadata-Version: 2.4
2
+ Name: fsspec
3
+ Version: 2025.12.0
4
+ Summary: File-system specification
5
+ Project-URL: Changelog, https://filesystem-spec.readthedocs.io/en/latest/changelog.html
6
+ Project-URL: Documentation, https://filesystem-spec.readthedocs.io/en/latest/
7
+ Project-URL: Homepage, https://github.com/fsspec/filesystem_spec
8
+ Maintainer-email: Martin Durant <mdurant@anaconda.com>
9
+ License-Expression: BSD-3-Clause
10
+ License-File: LICENSE
11
+ Keywords: file
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
20
+ Requires-Python: >=3.10
21
+ Provides-Extra: abfs
22
+ Requires-Dist: adlfs; extra == 'abfs'
23
+ Provides-Extra: adl
24
+ Requires-Dist: adlfs; extra == 'adl'
25
+ Provides-Extra: arrow
26
+ Requires-Dist: pyarrow>=1; extra == 'arrow'
27
+ Provides-Extra: dask
28
+ Requires-Dist: dask; extra == 'dask'
29
+ Requires-Dist: distributed; extra == 'dask'
30
+ Provides-Extra: dev
31
+ Requires-Dist: pre-commit; extra == 'dev'
32
+ Requires-Dist: ruff>=0.5; extra == 'dev'
33
+ Provides-Extra: doc
34
+ Requires-Dist: numpydoc; extra == 'doc'
35
+ Requires-Dist: sphinx; extra == 'doc'
36
+ Requires-Dist: sphinx-design; extra == 'doc'
37
+ Requires-Dist: sphinx-rtd-theme; extra == 'doc'
38
+ Requires-Dist: yarl; extra == 'doc'
39
+ Provides-Extra: dropbox
40
+ Requires-Dist: dropbox; extra == 'dropbox'
41
+ Requires-Dist: dropboxdrivefs; extra == 'dropbox'
42
+ Requires-Dist: requests; extra == 'dropbox'
43
+ Provides-Extra: entrypoints
44
+ Provides-Extra: full
45
+ Requires-Dist: adlfs; extra == 'full'
46
+ Requires-Dist: aiohttp!=4.0.0a0,!=4.0.0a1; extra == 'full'
47
+ Requires-Dist: dask; extra == 'full'
48
+ Requires-Dist: distributed; extra == 'full'
49
+ Requires-Dist: dropbox; extra == 'full'
50
+ Requires-Dist: dropboxdrivefs; extra == 'full'
51
+ Requires-Dist: fusepy; extra == 'full'
52
+ Requires-Dist: gcsfs; extra == 'full'
53
+ Requires-Dist: libarchive-c; extra == 'full'
54
+ Requires-Dist: ocifs; extra == 'full'
55
+ Requires-Dist: panel; extra == 'full'
56
+ Requires-Dist: paramiko; extra == 'full'
57
+ Requires-Dist: pyarrow>=1; extra == 'full'
58
+ Requires-Dist: pygit2; extra == 'full'
59
+ Requires-Dist: requests; extra == 'full'
60
+ Requires-Dist: s3fs; extra == 'full'
61
+ Requires-Dist: smbprotocol; extra == 'full'
62
+ Requires-Dist: tqdm; extra == 'full'
63
+ Provides-Extra: fuse
64
+ Requires-Dist: fusepy; extra == 'fuse'
65
+ Provides-Extra: gcs
66
+ Requires-Dist: gcsfs; extra == 'gcs'
67
+ Provides-Extra: git
68
+ Requires-Dist: pygit2; extra == 'git'
69
+ Provides-Extra: github
70
+ Requires-Dist: requests; extra == 'github'
71
+ Provides-Extra: gs
72
+ Requires-Dist: gcsfs; extra == 'gs'
73
+ Provides-Extra: gui
74
+ Requires-Dist: panel; extra == 'gui'
75
+ Provides-Extra: hdfs
76
+ Requires-Dist: pyarrow>=1; extra == 'hdfs'
77
+ Provides-Extra: http
78
+ Requires-Dist: aiohttp!=4.0.0a0,!=4.0.0a1; extra == 'http'
79
+ Provides-Extra: libarchive
80
+ Requires-Dist: libarchive-c; extra == 'libarchive'
81
+ Provides-Extra: oci
82
+ Requires-Dist: ocifs; extra == 'oci'
83
+ Provides-Extra: s3
84
+ Requires-Dist: s3fs; extra == 's3'
85
+ Provides-Extra: sftp
86
+ Requires-Dist: paramiko; extra == 'sftp'
87
+ Provides-Extra: smb
88
+ Requires-Dist: smbprotocol; extra == 'smb'
89
+ Provides-Extra: ssh
90
+ Requires-Dist: paramiko; extra == 'ssh'
91
+ Provides-Extra: test
92
+ Requires-Dist: aiohttp!=4.0.0a0,!=4.0.0a1; extra == 'test'
93
+ Requires-Dist: numpy; extra == 'test'
94
+ Requires-Dist: pytest; extra == 'test'
95
+ Requires-Dist: pytest-asyncio!=0.22.0; extra == 'test'
96
+ Requires-Dist: pytest-benchmark; extra == 'test'
97
+ Requires-Dist: pytest-cov; extra == 'test'
98
+ Requires-Dist: pytest-mock; extra == 'test'
99
+ Requires-Dist: pytest-recording; extra == 'test'
100
+ Requires-Dist: pytest-rerunfailures; extra == 'test'
101
+ Requires-Dist: requests; extra == 'test'
102
+ Provides-Extra: test-downstream
103
+ Requires-Dist: aiobotocore<3.0.0,>=2.5.4; extra == 'test-downstream'
104
+ Requires-Dist: dask[dataframe,test]; extra == 'test-downstream'
105
+ Requires-Dist: moto[server]<5,>4; extra == 'test-downstream'
106
+ Requires-Dist: pytest-timeout; extra == 'test-downstream'
107
+ Requires-Dist: xarray; extra == 'test-downstream'
108
+ Provides-Extra: test-full
109
+ Requires-Dist: adlfs; extra == 'test-full'
110
+ Requires-Dist: aiohttp!=4.0.0a0,!=4.0.0a1; extra == 'test-full'
111
+ Requires-Dist: cloudpickle; extra == 'test-full'
112
+ Requires-Dist: dask; extra == 'test-full'
113
+ Requires-Dist: distributed; extra == 'test-full'
114
+ Requires-Dist: dropbox; extra == 'test-full'
115
+ Requires-Dist: dropboxdrivefs; extra == 'test-full'
116
+ Requires-Dist: fastparquet; extra == 'test-full'
117
+ Requires-Dist: fusepy; extra == 'test-full'
118
+ Requires-Dist: gcsfs; extra == 'test-full'
119
+ Requires-Dist: jinja2; extra == 'test-full'
120
+ Requires-Dist: kerchunk; extra == 'test-full'
121
+ Requires-Dist: libarchive-c; extra == 'test-full'
122
+ Requires-Dist: lz4; extra == 'test-full'
123
+ Requires-Dist: notebook; extra == 'test-full'
124
+ Requires-Dist: numpy; extra == 'test-full'
125
+ Requires-Dist: ocifs; extra == 'test-full'
126
+ Requires-Dist: pandas; extra == 'test-full'
127
+ Requires-Dist: panel; extra == 'test-full'
128
+ Requires-Dist: paramiko; extra == 'test-full'
129
+ Requires-Dist: pyarrow; extra == 'test-full'
130
+ Requires-Dist: pyarrow>=1; extra == 'test-full'
131
+ Requires-Dist: pyftpdlib; extra == 'test-full'
132
+ Requires-Dist: pygit2; extra == 'test-full'
133
+ Requires-Dist: pytest; extra == 'test-full'
134
+ Requires-Dist: pytest-asyncio!=0.22.0; extra == 'test-full'
135
+ Requires-Dist: pytest-benchmark; extra == 'test-full'
136
+ Requires-Dist: pytest-cov; extra == 'test-full'
137
+ Requires-Dist: pytest-mock; extra == 'test-full'
138
+ Requires-Dist: pytest-recording; extra == 'test-full'
139
+ Requires-Dist: pytest-rerunfailures; extra == 'test-full'
140
+ Requires-Dist: python-snappy; extra == 'test-full'
141
+ Requires-Dist: requests; extra == 'test-full'
142
+ Requires-Dist: smbprotocol; extra == 'test-full'
143
+ Requires-Dist: tqdm; extra == 'test-full'
144
+ Requires-Dist: urllib3; extra == 'test-full'
145
+ Requires-Dist: zarr; extra == 'test-full'
146
+ Requires-Dist: zstandard; (python_version < '3.14') and extra == 'test-full'
147
+ Provides-Extra: tqdm
148
+ Requires-Dist: tqdm; extra == 'tqdm'
149
+ Description-Content-Type: text/markdown
150
+
151
+ # filesystem_spec
152
+
153
+ [![PyPI version](https://badge.fury.io/py/fsspec.svg)](https://pypi.python.org/pypi/fsspec/)
154
+ [![Anaconda-Server Badge](https://anaconda.org/conda-forge/fsspec/badges/version.svg)](https://anaconda.org/conda-forge/fsspec)
155
+ ![Build](https://github.com/fsspec/filesystem_spec/workflows/CI/badge.svg)
156
+ [![Docs](https://readthedocs.org/projects/filesystem-spec/badge/?version=latest)](https://filesystem-spec.readthedocs.io/en/latest/?badge=latest)
157
+
158
+ A specification for pythonic filesystems.
159
+
160
+ ## Install
161
+
162
+ ```bash
163
+ pip install fsspec
164
+ ```
165
+
166
+ would install the base fsspec. Various optionally supported features might require specification of custom
167
+ extra require, e.g. `pip install fsspec[ssh]` will install dependencies for `ssh` backends support.
168
+ Use `pip install fsspec[full]` for installation of all known extra dependencies.
169
+
170
+ Up-to-date package also provided through conda-forge distribution:
171
+
172
+ ```bash
173
+ conda install -c conda-forge fsspec
174
+ ```
175
+
176
+
177
+ ## Purpose
178
+
179
+ To produce a template or specification for a file-system interface, that specific implementations should follow,
180
+ so that applications making use of them can rely on a common behaviour and not have to worry about the specific
181
+ internal implementation decisions with any given backend. Many such implementations are included in this package,
182
+ or in sister projects such as `s3fs` and `gcsfs`.
183
+
184
+ In addition, if this is well-designed, then additional functionality, such as a key-value store or FUSE
185
+ mounting of the file-system implementation may be available for all implementations "for free".
186
+
187
+ ## Documentation
188
+
189
+ Please refer to [RTD](https://filesystem-spec.readthedocs.io/en/latest/?badge=latest)
190
+
191
+ ## Develop
192
+
193
+ fsspec uses GitHub Actions for CI. Environment files can be found
194
+ in the "ci/" directory. Note that the main environment is called "py38",
195
+ but it is expected that the version of python installed be adjustable at
196
+ CI runtime. For local use, pick a version suitable for you.
197
+
198
+ ```bash
199
+ # For a new environment (mamba / conda).
200
+ mamba create -n fsspec -c conda-forge python=3.10 -y
201
+ conda activate fsspec
202
+
203
+ # Standard dev install with docs and tests.
204
+ pip install -e ".[dev,doc,test]"
205
+
206
+ # Full tests except for downstream
207
+ pip install s3fs
208
+ pip uninstall s3fs
209
+ pip install -e .[dev,doc,test_full]
210
+ pip install s3fs --no-deps
211
+ pytest -v
212
+
213
+ # Downstream tests.
214
+ sh install_s3fs.sh
215
+ # Windows powershell.
216
+ install_s3fs.sh
217
+ ```
218
+
219
+ ### Testing
220
+
221
+ Tests can be run in the dev environment, if activated, via ``pytest fsspec``.
222
+
223
+ The full fsspec suite requires a system-level docker, docker-compose, and fuse
224
+ installation. If only making changes to one backend implementation, it is
225
+ not generally necessary to run all tests locally.
226
+
227
+ It is expected that contributors ensure that any change to fsspec does not
228
+ cause issues or regressions for either other fsspec-related packages such
229
+ as gcsfs and s3fs, nor for downstream users of fsspec. The "downstream" CI
230
+ run and corresponding environment file run a set of tests from the dask
231
+ test suite, and very minimal tests against pandas and zarr from the
232
+ test_downstream.py module in this repo.
233
+
234
+ ### Code Formatting
235
+
236
+ fsspec uses [Black](https://black.readthedocs.io/en/stable) to ensure
237
+ a consistent code format throughout the project.
238
+ Run ``black fsspec`` from the root of the filesystem_spec repository to
239
+ auto-format your code. Additionally, many editors have plugins that will apply
240
+ ``black`` as you edit files. ``black`` is included in the ``tox`` environments.
241
+
242
+ Optionally, you may wish to setup [pre-commit hooks](https://pre-commit.com) to
243
+ automatically run ``black`` when you make a git commit.
244
+ Run ``pre-commit install --install-hooks`` from the root of the
245
+ filesystem_spec repository to setup pre-commit hooks. ``black`` will now be run
246
+ before you commit, reformatting any changed files. You can format without
247
+ committing via ``pre-commit run`` or skip these checks with ``git commit
248
+ --no-verify``.
249
+
250
+ ## Support
251
+
252
+ Work on this repository is supported in part by:
253
+
254
+ "Anaconda, Inc. - Advancing AI through open source."
255
+
256
+ <a href="https://anaconda.com/"><img src="https://camo.githubusercontent.com/b8555ef2222598ed37ce38ac86955febbd25de7619931bb7dd3c58432181d3b6/68747470733a2f2f626565776172652e6f72672f636f6d6d756e6974792f6d656d626572732f616e61636f6e64612f616e61636f6e64612d6c617267652e706e67" alt="anaconda logo" width="40%"/></a>
env/lib/python3.13/site-packages/fsspec-2025.12.0.dist-info/RECORD ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ fsspec-2025.12.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
2
+ fsspec-2025.12.0.dist-info/METADATA,sha256=Fm2bIMio0NYy1EdMfxgGq4OE2kE5nt1qZDaDYbOuC0M,10401
3
+ fsspec-2025.12.0.dist-info/RECORD,,
4
+ fsspec-2025.12.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
5
+ fsspec-2025.12.0.dist-info/licenses/LICENSE,sha256=LcNUls5TpzB5FcAIqESq1T53K0mzTN0ARFBnaRQH7JQ,1513
6
+ fsspec/__init__.py,sha256=L7qwNBU1iMNQd8Of87HYSNFT9gWlNMSESaJC8fY0AaQ,2053
7
+ fsspec/__pycache__/__init__.cpython-313.pyc,,
8
+ fsspec/__pycache__/_version.cpython-313.pyc,,
9
+ fsspec/__pycache__/archive.cpython-313.pyc,,
10
+ fsspec/__pycache__/asyn.cpython-313.pyc,,
11
+ fsspec/__pycache__/caching.cpython-313.pyc,,
12
+ fsspec/__pycache__/callbacks.cpython-313.pyc,,
13
+ fsspec/__pycache__/compression.cpython-313.pyc,,
14
+ fsspec/__pycache__/config.cpython-313.pyc,,
15
+ fsspec/__pycache__/conftest.cpython-313.pyc,,
16
+ fsspec/__pycache__/core.cpython-313.pyc,,
17
+ fsspec/__pycache__/dircache.cpython-313.pyc,,
18
+ fsspec/__pycache__/exceptions.cpython-313.pyc,,
19
+ fsspec/__pycache__/fuse.cpython-313.pyc,,
20
+ fsspec/__pycache__/generic.cpython-313.pyc,,
21
+ fsspec/__pycache__/gui.cpython-313.pyc,,
22
+ fsspec/__pycache__/json.cpython-313.pyc,,
23
+ fsspec/__pycache__/mapping.cpython-313.pyc,,
24
+ fsspec/__pycache__/parquet.cpython-313.pyc,,
25
+ fsspec/__pycache__/registry.cpython-313.pyc,,
26
+ fsspec/__pycache__/spec.cpython-313.pyc,,
27
+ fsspec/__pycache__/transaction.cpython-313.pyc,,
28
+ fsspec/__pycache__/utils.cpython-313.pyc,,
29
+ fsspec/_version.py,sha256=u_WCUBrOC78o9bqe-21i1S8FKT43ei4dqyL4oKUga9g,712
30
+ fsspec/archive.py,sha256=vM6t_lgV6lBWbBYwpm3S4ofBQFQxUPr5KkDQrrQcQro,2411
31
+ fsspec/asyn.py,sha256=LP_OicTWXmKHe31wBoYs2MrrNf8rmlhjVeGg5AqvVy8,36630
32
+ fsspec/caching.py,sha256=B2xeDz9-VDgr_dDeVOTNRq3vaS9zVUe0nxtOBgsrjUk,34260
33
+ fsspec/callbacks.py,sha256=BDIwLzK6rr_0V5ch557fSzsivCElpdqhXr5dZ9Te-EE,9210
34
+ fsspec/compression.py,sha256=gBK2MV_oTFVW2XDq8bZVbYQKYrl6JDUou6_-kyvmxuk,5086
35
+ fsspec/config.py,sha256=LF4Zmu1vhJW7Je9Q-cwkRc3xP7Rhyy7Xnwj26Z6sv2g,4279
36
+ fsspec/conftest.py,sha256=uWfm_Qs5alPRxOhRpDfQ0-1jqSJ54pni4y96IxOREXM,3446
37
+ fsspec/core.py,sha256=lc7XSnZU6_C6xljp7Z_xEGN3V7704hbeQLkxvPP0wds,24173
38
+ fsspec/dircache.py,sha256=YzogWJrhEastHU7vWz-cJiJ7sdtLXFXhEpInGKd4EcM,2717
39
+ fsspec/exceptions.py,sha256=pauSLDMxzTJMOjvX1WEUK0cMyFkrFxpWJsyFywav7A8,331
40
+ fsspec/fuse.py,sha256=Q-3NOOyLqBfYa4Db5E19z_ZY36zzYHtIs1mOUasItBQ,10177
41
+ fsspec/generic.py,sha256=9QHQYMNb-8w8-eYuIqShcTjO_LeHXFoQTyt8J5oEq5Q,13482
42
+ fsspec/gui.py,sha256=CQ7QsrTpaDlWSLNOpwNoJc7khOcYXIZxmrAJN9bHWQU,14002
43
+ fsspec/implementations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
44
+ fsspec/implementations/__pycache__/__init__.cpython-313.pyc,,
45
+ fsspec/implementations/__pycache__/arrow.cpython-313.pyc,,
46
+ fsspec/implementations/__pycache__/asyn_wrapper.cpython-313.pyc,,
47
+ fsspec/implementations/__pycache__/cache_mapper.cpython-313.pyc,,
48
+ fsspec/implementations/__pycache__/cache_metadata.cpython-313.pyc,,
49
+ fsspec/implementations/__pycache__/cached.cpython-313.pyc,,
50
+ fsspec/implementations/__pycache__/chained.cpython-313.pyc,,
51
+ fsspec/implementations/__pycache__/dask.cpython-313.pyc,,
52
+ fsspec/implementations/__pycache__/data.cpython-313.pyc,,
53
+ fsspec/implementations/__pycache__/dbfs.cpython-313.pyc,,
54
+ fsspec/implementations/__pycache__/dirfs.cpython-313.pyc,,
55
+ fsspec/implementations/__pycache__/ftp.cpython-313.pyc,,
56
+ fsspec/implementations/__pycache__/gist.cpython-313.pyc,,
57
+ fsspec/implementations/__pycache__/git.cpython-313.pyc,,
58
+ fsspec/implementations/__pycache__/github.cpython-313.pyc,,
59
+ fsspec/implementations/__pycache__/http.cpython-313.pyc,,
60
+ fsspec/implementations/__pycache__/http_sync.cpython-313.pyc,,
61
+ fsspec/implementations/__pycache__/jupyter.cpython-313.pyc,,
62
+ fsspec/implementations/__pycache__/libarchive.cpython-313.pyc,,
63
+ fsspec/implementations/__pycache__/local.cpython-313.pyc,,
64
+ fsspec/implementations/__pycache__/memory.cpython-313.pyc,,
65
+ fsspec/implementations/__pycache__/reference.cpython-313.pyc,,
66
+ fsspec/implementations/__pycache__/sftp.cpython-313.pyc,,
67
+ fsspec/implementations/__pycache__/smb.cpython-313.pyc,,
68
+ fsspec/implementations/__pycache__/tar.cpython-313.pyc,,
69
+ fsspec/implementations/__pycache__/webhdfs.cpython-313.pyc,,
70
+ fsspec/implementations/__pycache__/zip.cpython-313.pyc,,
71
+ fsspec/implementations/arrow.py,sha256=6BaSEBZ4nb8UuY6NsyFevGzXcdJWamt3qEHjMe2S-W8,8831
72
+ fsspec/implementations/asyn_wrapper.py,sha256=3lfJkGs6D_AwRBdxTSYlL-RCVdaXBZ9Itys2P5o5Si0,3738
73
+ fsspec/implementations/cache_mapper.py,sha256=W4wlxyPxZbSp9ItJ0pYRVBMh6bw9eFypgP6kUYuuiI4,2421
74
+ fsspec/implementations/cache_metadata.py,sha256=ipIe4S8nlU_M9oRJkvTqr-b0tcbXVZsxH3GxaelaNOY,8502
75
+ fsspec/implementations/cached.py,sha256=gp1eaM2X7ix2eGRDaC8rtTuO0icK6hbz3yDXh9YdB0E,35392
76
+ fsspec/implementations/chained.py,sha256=iGivpNaHUFjB_ea0-HAPhcmm6CL8qnDf270PSj7JwuE,680
77
+ fsspec/implementations/dask.py,sha256=CXZbJzIVOhKV8ILcxuy3bTvcacCueAbyQxmvAkbPkrk,4466
78
+ fsspec/implementations/data.py,sha256=IhOGDkacYp5gkl9jhEu4msQfZPb0gS5Q_ml7Mbr6dgQ,1627
79
+ fsspec/implementations/dbfs.py,sha256=1cvvC6KBWOb8pBVpc01xavVbEPXO1xsgZvPD7H73M9k,16217
80
+ fsspec/implementations/dirfs.py,sha256=VNj6gPMfmmLPK4wxbtxt7mUqW7xkh2XDgMmEmSK_E1c,12166
81
+ fsspec/implementations/ftp.py,sha256=bzL_TgH77nMMtTMewRGkbq4iObSHGu7YoMRCXBH4nrc,11639
82
+ fsspec/implementations/gist.py,sha256=Y6jTDrE-wuTwvpPyAQDuuOMBGxlajafKWoB1_yX6jdY,8528
83
+ fsspec/implementations/git.py,sha256=qBDWMz5LNllPqVjr5jf_1FuNha4P5lyQI3IlhYg-wUE,3731
84
+ fsspec/implementations/github.py,sha256=aCsZL8UvXZgdkcB1RUs3DdLeNrjLKcFsFYeQFDWbBFo,11653
85
+ fsspec/implementations/http.py,sha256=-AV5qeNpBWqnsmgnIO9Ily9B6--SR4sQJ7G4cBHarGE,30675
86
+ fsspec/implementations/http_sync.py,sha256=UmBqd938ebwVjYgVtzg-ysG3ZoGhIJw0wFtQAfxV3Aw,30332
87
+ fsspec/implementations/jupyter.py,sha256=q1PlQ66AAswGFyr8MFKWyobaV2YekMWRtqENBDQtD28,4002
88
+ fsspec/implementations/libarchive.py,sha256=SpIA1F-zf7kb2-VYUVuhMrXTBOhBxUXKgEW1RaAdDoA,7098
89
+ fsspec/implementations/local.py,sha256=DQeK7jRGv4_mJAweLKALO5WzIIkjXxZ_jRvwQ_xadSA,16936
90
+ fsspec/implementations/memory.py,sha256=TDdLtSPWXxZKrrVGwmc3uS3oK_2mlcVTk2BiqR8IeII,10507
91
+ fsspec/implementations/reference.py,sha256=xSUpB8o_QFAZiVJE2dt78QZMCUMLo5TaJ27e5DwDAfg,48814
92
+ fsspec/implementations/sftp.py,sha256=L9pZOa6eLUWfJNtxkxeG2YI96SQwrM5Hj6ocyUZXUbg,5923
93
+ fsspec/implementations/smb.py,sha256=5fhu8h06nOLBPh2c48aT7WBRqh9cEcbIwtyu06wTjec,15236
94
+ fsspec/implementations/tar.py,sha256=dam78Tp_CozybNqCY2JYgGBS3Uc9FuJUAT9oB0lolOs,4111
95
+ fsspec/implementations/webhdfs.py,sha256=PUgZM9HbVPAeW4u4B-rWl8wTcKKpPhwZO7xcINDmTNQ,16779
96
+ fsspec/implementations/zip.py,sha256=9LBMHPft2OutJl2Ft-r9u_z3GptLkc2n91ur2A3bCbg,6072
97
+ fsspec/json.py,sha256=4EBZ-xOmRiyxmIqPIwxmDImosRQ7io7qBM2xjJPsEE4,3768
98
+ fsspec/mapping.py,sha256=m2ndB_gtRBXYmNJg0Ie1-BVR75TFleHmIQBzC-yWhjU,8343
99
+ fsspec/parquet.py,sha256=vpOuoxg0y0iS2yoiXeAUcWB0n-wct2x2L6Vmn_O-hRQ,20668
100
+ fsspec/registry.py,sha256=Kvv7NEqvIDhI2PXoYmwi4Z9RHAjrLMhGRu3m492801s,12157
101
+ fsspec/spec.py,sha256=Ym-Ust6LRjHgbhrmvNqwOBZxoVnaw3g3xHXMZGHx_xg,77692
102
+ fsspec/tests/abstract/__init__.py,sha256=4xUJrv7gDgc85xAOz1p-V_K1hrsdMWTSa0rviALlJk8,10181
103
+ fsspec/tests/abstract/__pycache__/__init__.cpython-313.pyc,,
104
+ fsspec/tests/abstract/__pycache__/common.cpython-313.pyc,,
105
+ fsspec/tests/abstract/__pycache__/copy.cpython-313.pyc,,
106
+ fsspec/tests/abstract/__pycache__/get.cpython-313.pyc,,
107
+ fsspec/tests/abstract/__pycache__/mv.cpython-313.pyc,,
108
+ fsspec/tests/abstract/__pycache__/open.cpython-313.pyc,,
109
+ fsspec/tests/abstract/__pycache__/pipe.cpython-313.pyc,,
110
+ fsspec/tests/abstract/__pycache__/put.cpython-313.pyc,,
111
+ fsspec/tests/abstract/common.py,sha256=1GQwNo5AONzAnzZj0fWgn8NJPLXALehbsuGxS3FzWVU,4973
112
+ fsspec/tests/abstract/copy.py,sha256=gU5-d97U3RSde35Vp4RxPY4rWwL744HiSrJ8IBOp9-8,19967
113
+ fsspec/tests/abstract/get.py,sha256=vNR4HztvTR7Cj56AMo7_tx7TeYz1Jgr_2Wb8Lv-UiBY,20755
114
+ fsspec/tests/abstract/mv.py,sha256=k8eUEBIrRrGMsBY5OOaDXdGnQUKGwDIfQyduB6YD3Ns,1982
115
+ fsspec/tests/abstract/open.py,sha256=Fi2PBPYLbRqysF8cFm0rwnB41kMdQVYjq8cGyDXp3BU,329
116
+ fsspec/tests/abstract/pipe.py,sha256=LFzIrLCB5GLXf9rzFKJmE8AdG7LQ_h4bJo70r8FLPqM,402
117
+ fsspec/tests/abstract/put.py,sha256=7aih17OKB_IZZh1Mkq1eBDIjobhtMQmI8x-Pw-S_aZk,21201
118
+ fsspec/transaction.py,sha256=xliRG6U2Zf3khG4xcw9WiB-yAoqJSHEGK_VjHOdtgo0,2398
119
+ fsspec/utils.py,sha256=5DOxB_eE-wNHwrc6zp3h-oMp5mCLw4tsQZqqPTjLDmM,23136
env/lib/python3.13/site-packages/fsspec-2025.12.0.dist-info/WHEEL ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.28.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
env/lib/python3.13/site-packages/hf_xet/__init__.py ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ from .hf_xet import *
2
+
3
+ __doc__ = hf_xet.__doc__
4
+ if hasattr(hf_xet, "__all__"):
5
+ __all__ = hf_xet.__all__
env/lib/python3.13/site-packages/huggingface_hub-1.2.1.dist-info/INSTALLER ADDED
@@ -0,0 +1 @@
 
 
1
+ pip
env/lib/python3.13/site-packages/huggingface_hub-1.2.1.dist-info/METADATA ADDED
@@ -0,0 +1,320 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Metadata-Version: 2.4
2
+ Name: huggingface_hub
3
+ Version: 1.2.1
4
+ Summary: Client library to download and publish models, datasets and other repos on the huggingface.co hub
5
+ Home-page: https://github.com/huggingface/huggingface_hub
6
+ Author: Hugging Face, Inc.
7
+ Author-email: julien@huggingface.co
8
+ License: Apache
9
+ Keywords: model-hub machine-learning models natural-language-processing deep-learning pytorch pretrained-models
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Intended Audience :: Education
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: License :: OSI Approved :: Apache Software License
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3 :: Only
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Programming Language :: Python :: 3.14
23
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
24
+ Requires-Python: >=3.9.0
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+ Requires-Dist: filelock
28
+ Requires-Dist: fsspec>=2023.5.0
29
+ Requires-Dist: hf-xet<2.0.0,>=1.2.0; platform_machine == "x86_64" or platform_machine == "amd64" or platform_machine == "AMD64" or platform_machine == "arm64" or platform_machine == "aarch64"
30
+ Requires-Dist: httpx<1,>=0.23.0
31
+ Requires-Dist: packaging>=20.9
32
+ Requires-Dist: pyyaml>=5.1
33
+ Requires-Dist: shellingham
34
+ Requires-Dist: tqdm>=4.42.1
35
+ Requires-Dist: typer-slim
36
+ Requires-Dist: typing-extensions>=3.7.4.3
37
+ Provides-Extra: oauth
38
+ Requires-Dist: authlib>=1.3.2; extra == "oauth"
39
+ Requires-Dist: fastapi; extra == "oauth"
40
+ Requires-Dist: httpx; extra == "oauth"
41
+ Requires-Dist: itsdangerous; extra == "oauth"
42
+ Provides-Extra: torch
43
+ Requires-Dist: torch; extra == "torch"
44
+ Requires-Dist: safetensors[torch]; extra == "torch"
45
+ Provides-Extra: fastai
46
+ Requires-Dist: toml; extra == "fastai"
47
+ Requires-Dist: fastai>=2.4; extra == "fastai"
48
+ Requires-Dist: fastcore>=1.3.27; extra == "fastai"
49
+ Provides-Extra: hf-xet
50
+ Requires-Dist: hf-xet<2.0.0,>=1.1.3; extra == "hf-xet"
51
+ Provides-Extra: mcp
52
+ Requires-Dist: mcp>=1.8.0; extra == "mcp"
53
+ Provides-Extra: testing
54
+ Requires-Dist: authlib>=1.3.2; extra == "testing"
55
+ Requires-Dist: fastapi; extra == "testing"
56
+ Requires-Dist: httpx; extra == "testing"
57
+ Requires-Dist: itsdangerous; extra == "testing"
58
+ Requires-Dist: jedi; extra == "testing"
59
+ Requires-Dist: Jinja2; extra == "testing"
60
+ Requires-Dist: pytest>=8.4.2; extra == "testing"
61
+ Requires-Dist: pytest-cov; extra == "testing"
62
+ Requires-Dist: pytest-env; extra == "testing"
63
+ Requires-Dist: pytest-xdist; extra == "testing"
64
+ Requires-Dist: pytest-vcr; extra == "testing"
65
+ Requires-Dist: pytest-asyncio; extra == "testing"
66
+ Requires-Dist: pytest-rerunfailures<16.0; extra == "testing"
67
+ Requires-Dist: pytest-mock; extra == "testing"
68
+ Requires-Dist: urllib3<2.0; extra == "testing"
69
+ Requires-Dist: soundfile; extra == "testing"
70
+ Requires-Dist: Pillow; extra == "testing"
71
+ Requires-Dist: numpy; extra == "testing"
72
+ Requires-Dist: fastapi; extra == "testing"
73
+ Provides-Extra: typing
74
+ Requires-Dist: typing-extensions>=4.8.0; extra == "typing"
75
+ Requires-Dist: types-PyYAML; extra == "typing"
76
+ Requires-Dist: types-simplejson; extra == "typing"
77
+ Requires-Dist: types-toml; extra == "typing"
78
+ Requires-Dist: types-tqdm; extra == "typing"
79
+ Requires-Dist: types-urllib3; extra == "typing"
80
+ Provides-Extra: quality
81
+ Requires-Dist: ruff>=0.9.0; extra == "quality"
82
+ Requires-Dist: mypy==1.15.0; extra == "quality"
83
+ Requires-Dist: libcst>=1.4.0; extra == "quality"
84
+ Requires-Dist: ty; extra == "quality"
85
+ Provides-Extra: all
86
+ Requires-Dist: authlib>=1.3.2; extra == "all"
87
+ Requires-Dist: fastapi; extra == "all"
88
+ Requires-Dist: httpx; extra == "all"
89
+ Requires-Dist: itsdangerous; extra == "all"
90
+ Requires-Dist: jedi; extra == "all"
91
+ Requires-Dist: Jinja2; extra == "all"
92
+ Requires-Dist: pytest>=8.4.2; extra == "all"
93
+ Requires-Dist: pytest-cov; extra == "all"
94
+ Requires-Dist: pytest-env; extra == "all"
95
+ Requires-Dist: pytest-xdist; extra == "all"
96
+ Requires-Dist: pytest-vcr; extra == "all"
97
+ Requires-Dist: pytest-asyncio; extra == "all"
98
+ Requires-Dist: pytest-rerunfailures<16.0; extra == "all"
99
+ Requires-Dist: pytest-mock; extra == "all"
100
+ Requires-Dist: urllib3<2.0; extra == "all"
101
+ Requires-Dist: soundfile; extra == "all"
102
+ Requires-Dist: Pillow; extra == "all"
103
+ Requires-Dist: numpy; extra == "all"
104
+ Requires-Dist: fastapi; extra == "all"
105
+ Requires-Dist: ruff>=0.9.0; extra == "all"
106
+ Requires-Dist: mypy==1.15.0; extra == "all"
107
+ Requires-Dist: libcst>=1.4.0; extra == "all"
108
+ Requires-Dist: ty; extra == "all"
109
+ Requires-Dist: typing-extensions>=4.8.0; extra == "all"
110
+ Requires-Dist: types-PyYAML; extra == "all"
111
+ Requires-Dist: types-simplejson; extra == "all"
112
+ Requires-Dist: types-toml; extra == "all"
113
+ Requires-Dist: types-tqdm; extra == "all"
114
+ Requires-Dist: types-urllib3; extra == "all"
115
+ Provides-Extra: dev
116
+ Requires-Dist: authlib>=1.3.2; extra == "dev"
117
+ Requires-Dist: fastapi; extra == "dev"
118
+ Requires-Dist: httpx; extra == "dev"
119
+ Requires-Dist: itsdangerous; extra == "dev"
120
+ Requires-Dist: jedi; extra == "dev"
121
+ Requires-Dist: Jinja2; extra == "dev"
122
+ Requires-Dist: pytest>=8.4.2; extra == "dev"
123
+ Requires-Dist: pytest-cov; extra == "dev"
124
+ Requires-Dist: pytest-env; extra == "dev"
125
+ Requires-Dist: pytest-xdist; extra == "dev"
126
+ Requires-Dist: pytest-vcr; extra == "dev"
127
+ Requires-Dist: pytest-asyncio; extra == "dev"
128
+ Requires-Dist: pytest-rerunfailures<16.0; extra == "dev"
129
+ Requires-Dist: pytest-mock; extra == "dev"
130
+ Requires-Dist: urllib3<2.0; extra == "dev"
131
+ Requires-Dist: soundfile; extra == "dev"
132
+ Requires-Dist: Pillow; extra == "dev"
133
+ Requires-Dist: numpy; extra == "dev"
134
+ Requires-Dist: fastapi; extra == "dev"
135
+ Requires-Dist: ruff>=0.9.0; extra == "dev"
136
+ Requires-Dist: mypy==1.15.0; extra == "dev"
137
+ Requires-Dist: libcst>=1.4.0; extra == "dev"
138
+ Requires-Dist: ty; extra == "dev"
139
+ Requires-Dist: typing-extensions>=4.8.0; extra == "dev"
140
+ Requires-Dist: types-PyYAML; extra == "dev"
141
+ Requires-Dist: types-simplejson; extra == "dev"
142
+ Requires-Dist: types-toml; extra == "dev"
143
+ Requires-Dist: types-tqdm; extra == "dev"
144
+ Requires-Dist: types-urllib3; extra == "dev"
145
+ Dynamic: author
146
+ Dynamic: author-email
147
+ Dynamic: classifier
148
+ Dynamic: description
149
+ Dynamic: description-content-type
150
+ Dynamic: home-page
151
+ Dynamic: keywords
152
+ Dynamic: license
153
+ Dynamic: license-file
154
+ Dynamic: provides-extra
155
+ Dynamic: requires-dist
156
+ Dynamic: requires-python
157
+ Dynamic: summary
158
+
159
+ <p align="center">
160
+ <picture>
161
+ <source media="(prefers-color-scheme: dark)" srcset="https://huggingface.co/datasets/huggingface/documentation-images/raw/main/huggingface_hub-dark.svg">
162
+ <source media="(prefers-color-scheme: light)" srcset="https://huggingface.co/datasets/huggingface/documentation-images/raw/main/huggingface_hub.svg">
163
+ <img alt="huggingface_hub library logo" src="https://huggingface.co/datasets/huggingface/documentation-images/raw/main/huggingface_hub.svg" width="352" height="59" style="max-width: 100%;">
164
+ </picture>
165
+ <br/>
166
+ <br/>
167
+ </p>
168
+
169
+ <p align="center">
170
+ <i>The official Python client for the Huggingface Hub.</i>
171
+ </p>
172
+
173
+ <p align="center">
174
+ <a href="https://huggingface.co/docs/huggingface_hub/en/index"><img alt="Documentation" src="https://img.shields.io/website/http/huggingface.co/docs/huggingface_hub/index.svg?down_color=red&down_message=offline&up_message=online&label=doc"></a>
175
+ <a href="https://github.com/huggingface/huggingface_hub/releases"><img alt="GitHub release" src="https://img.shields.io/github/release/huggingface/huggingface_hub.svg"></a>
176
+ <a href="https://github.com/huggingface/huggingface_hub"><img alt="PyPi version" src="https://img.shields.io/pypi/pyversions/huggingface_hub.svg"></a>
177
+ <a href="https://pypi.org/project/huggingface-hub"><img alt="PyPI - Downloads" src="https://img.shields.io/pypi/dm/huggingface_hub"></a>
178
+ <a href="https://codecov.io/gh/huggingface/huggingface_hub"><img alt="Code coverage" src="https://codecov.io/gh/huggingface/huggingface_hub/branch/main/graph/badge.svg?token=RXP95LE2XL"></a>
179
+ </p>
180
+
181
+ <h4 align="center">
182
+ <p>
183
+ <b>English</b> |
184
+ <a href="https://github.com/huggingface/huggingface_hub/blob/main/i18n/README_de.md">Deutsch</a> |
185
+ <a href="https://github.com/huggingface/huggingface_hub/blob/main/i18n/README_fr.md">Français</a> |
186
+ <a href="https://github.com/huggingface/huggingface_hub/blob/main/i18n/README_hi.md">हिंदी</a> |
187
+ <a href="https://github.com/huggingface/huggingface_hub/blob/main/i18n/README_ko.md">한국어</a> |
188
+ <a href="https://github.com/huggingface/huggingface_hub/blob/main/i18n/README_cn.md">中文 (简体)</a>
189
+ <p>
190
+ </h4>
191
+
192
+ ---
193
+
194
+ **Documentation**: <a href="https://hf.co/docs/huggingface_hub" target="_blank">https://hf.co/docs/huggingface_hub</a>
195
+
196
+ **Source Code**: <a href="https://github.com/huggingface/huggingface_hub" target="_blank">https://github.com/huggingface/huggingface_hub</a>
197
+
198
+ ---
199
+
200
+ ## Welcome to the huggingface_hub library
201
+
202
+ The `huggingface_hub` library allows you to interact with the [Hugging Face Hub](https://huggingface.co/), a platform democratizing open-source Machine Learning for creators and collaborators. Discover pre-trained models and datasets for your projects or play with the thousands of machine learning apps hosted on the Hub. You can also create and share your own models, datasets and demos with the community. The `huggingface_hub` library provides a simple way to do all these things with Python.
203
+
204
+ ## Key features
205
+
206
+ - [Download files](https://huggingface.co/docs/huggingface_hub/en/guides/download) from the Hub.
207
+ - [Upload files](https://huggingface.co/docs/huggingface_hub/en/guides/upload) to the Hub.
208
+ - [Manage your repositories](https://huggingface.co/docs/huggingface_hub/en/guides/repository).
209
+ - [Run Inference](https://huggingface.co/docs/huggingface_hub/en/guides/inference) on deployed models.
210
+ - [Search](https://huggingface.co/docs/huggingface_hub/en/guides/search) for models, datasets and Spaces.
211
+ - [Share Model Cards](https://huggingface.co/docs/huggingface_hub/en/guides/model-cards) to document your models.
212
+ - [Engage with the community](https://huggingface.co/docs/huggingface_hub/en/guides/community) through PRs and comments.
213
+
214
+ ## Installation
215
+
216
+ Install the `huggingface_hub` package with [pip](https://pypi.org/project/huggingface-hub/):
217
+
218
+ ```bash
219
+ pip install huggingface_hub
220
+ ```
221
+
222
+ If you prefer, you can also install it with [conda](https://huggingface.co/docs/huggingface_hub/en/installation#install-with-conda).
223
+
224
+ In order to keep the package minimal by default, `huggingface_hub` comes with optional dependencies useful for some use cases. For example, if you want to use the MCP module, run:
225
+
226
+ ```bash
227
+ pip install "huggingface_hub[mcp]"
228
+ ```
229
+
230
+ To learn more installation and optional dependencies, check out the [installation guide](https://huggingface.co/docs/huggingface_hub/en/installation).
231
+
232
+ ## Quick start
233
+
234
+ ### Download files
235
+
236
+ Download a single file
237
+
238
+ ```py
239
+ from huggingface_hub import hf_hub_download
240
+
241
+ hf_hub_download(repo_id="tiiuae/falcon-7b-instruct", filename="config.json")
242
+ ```
243
+
244
+ Or an entire repository
245
+
246
+ ```py
247
+ from huggingface_hub import snapshot_download
248
+
249
+ snapshot_download("stabilityai/stable-diffusion-2-1")
250
+ ```
251
+
252
+ Files will be downloaded in a local cache folder. More details in [this guide](https://huggingface.co/docs/huggingface_hub/en/guides/manage-cache).
253
+
254
+ ### Login
255
+
256
+ The Hugging Face Hub uses tokens to authenticate applications (see [docs](https://huggingface.co/docs/hub/security-tokens)). To log in your machine, run the following CLI:
257
+
258
+ ```bash
259
+ hf auth login
260
+ # or using an environment variable
261
+ hf auth login --token $HUGGINGFACE_TOKEN
262
+ ```
263
+
264
+ ### Create a repository
265
+
266
+ ```py
267
+ from huggingface_hub import create_repo
268
+
269
+ create_repo(repo_id="super-cool-model")
270
+ ```
271
+
272
+ ### Upload files
273
+
274
+ Upload a single file
275
+
276
+ ```py
277
+ from huggingface_hub import upload_file
278
+
279
+ upload_file(
280
+ path_or_fileobj="/home/lysandre/dummy-test/README.md",
281
+ path_in_repo="README.md",
282
+ repo_id="lysandre/test-model",
283
+ )
284
+ ```
285
+
286
+ Or an entire folder
287
+
288
+ ```py
289
+ from huggingface_hub import upload_folder
290
+
291
+ upload_folder(
292
+ folder_path="/path/to/local/space",
293
+ repo_id="username/my-cool-space",
294
+ repo_type="space",
295
+ )
296
+ ```
297
+
298
+ For details in the [upload guide](https://huggingface.co/docs/huggingface_hub/en/guides/upload).
299
+
300
+ ## Integrating to the Hub.
301
+
302
+ We're partnering with cool open source ML libraries to provide free model hosting and versioning. You can find the existing integrations [here](https://huggingface.co/docs/hub/libraries).
303
+
304
+ The advantages are:
305
+
306
+ - Free model or dataset hosting for libraries and their users.
307
+ - Built-in file versioning, even with very large files, thanks to a git-based approach.
308
+ - In-browser widgets to play with the uploaded models.
309
+ - Anyone can upload a new model for your library, they just need to add the corresponding tag for the model to be discoverable.
310
+ - Fast downloads! We use Cloudfront (a CDN) to geo-replicate downloads so they're blazing fast from anywhere on the globe.
311
+ - Usage stats and more features to come.
312
+
313
+ If you would like to integrate your library, feel free to open an issue to begin the discussion. We wrote a [step-by-step guide](https://huggingface.co/docs/hub/adding-a-library) with ❤️ showing how to do this integration.
314
+
315
+ ## Contributions (feature requests, bugs, etc.) are super welcome 💙💚💛💜🧡❤️
316
+
317
+ Everyone is welcome to contribute, and we value everybody's contribution. Code is not the only way to help the community.
318
+ Answering questions, helping others, reaching out and improving the documentations are immensely valuable to the community.
319
+ We wrote a [contribution guide](https://github.com/huggingface/huggingface_hub/blob/main/CONTRIBUTING.md) to summarize
320
+ how to get started to contribute to this repository.
env/lib/python3.13/site-packages/huggingface_hub-1.2.1.dist-info/RECORD ADDED
@@ -0,0 +1,307 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ../../../bin/hf,sha256=PqjimA7s1Q8AvyAr6wVvcx-Pv06r9DYNm9IGwCZBECg,270
2
+ ../../../bin/tiny-agents,sha256=QppnsPE9VkFszkWSxL4-tDq6lbPK8J7m9B6MMfLbLWo,280
3
+ huggingface_hub-1.2.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
4
+ huggingface_hub-1.2.1.dist-info/METADATA,sha256=vYJ-x9FTGzaVdO4iaPyWMRFItcXe3jLlVPKc7uMEHjI,13856
5
+ huggingface_hub-1.2.1.dist-info/RECORD,,
6
+ huggingface_hub-1.2.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ huggingface_hub-1.2.1.dist-info/WHEEL,sha256=SmOxYU7pzNKBqASvQJ7DjX3XGUF92lrGhMb3R6_iiqI,91
8
+ huggingface_hub-1.2.1.dist-info/entry_points.txt,sha256=j3KnOggx2dIP7NUkPyYgXdRnLxd94aHmqJ8J6tEZwY8,154
9
+ huggingface_hub-1.2.1.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
10
+ huggingface_hub-1.2.1.dist-info/top_level.txt,sha256=8KzlQJAY4miUvjAssOAJodqKOw3harNzuiwGQ9qLSSk,16
11
+ huggingface_hub/__init__.py,sha256=z3hJ7HEvxxHcaP5SHISsGi_z2VAhrQYMh1zReY-sp5I,52852
12
+ huggingface_hub/__pycache__/__init__.cpython-313.pyc,,
13
+ huggingface_hub/__pycache__/_commit_api.cpython-313.pyc,,
14
+ huggingface_hub/__pycache__/_commit_scheduler.cpython-313.pyc,,
15
+ huggingface_hub/__pycache__/_inference_endpoints.cpython-313.pyc,,
16
+ huggingface_hub/__pycache__/_jobs_api.cpython-313.pyc,,
17
+ huggingface_hub/__pycache__/_local_folder.cpython-313.pyc,,
18
+ huggingface_hub/__pycache__/_login.cpython-313.pyc,,
19
+ huggingface_hub/__pycache__/_oauth.cpython-313.pyc,,
20
+ huggingface_hub/__pycache__/_snapshot_download.cpython-313.pyc,,
21
+ huggingface_hub/__pycache__/_space_api.cpython-313.pyc,,
22
+ huggingface_hub/__pycache__/_tensorboard_logger.cpython-313.pyc,,
23
+ huggingface_hub/__pycache__/_upload_large_folder.cpython-313.pyc,,
24
+ huggingface_hub/__pycache__/_webhooks_payload.cpython-313.pyc,,
25
+ huggingface_hub/__pycache__/_webhooks_server.cpython-313.pyc,,
26
+ huggingface_hub/__pycache__/community.cpython-313.pyc,,
27
+ huggingface_hub/__pycache__/constants.cpython-313.pyc,,
28
+ huggingface_hub/__pycache__/dataclasses.cpython-313.pyc,,
29
+ huggingface_hub/__pycache__/errors.cpython-313.pyc,,
30
+ huggingface_hub/__pycache__/fastai_utils.cpython-313.pyc,,
31
+ huggingface_hub/__pycache__/file_download.cpython-313.pyc,,
32
+ huggingface_hub/__pycache__/hf_api.cpython-313.pyc,,
33
+ huggingface_hub/__pycache__/hf_file_system.cpython-313.pyc,,
34
+ huggingface_hub/__pycache__/hub_mixin.cpython-313.pyc,,
35
+ huggingface_hub/__pycache__/lfs.cpython-313.pyc,,
36
+ huggingface_hub/__pycache__/repocard.cpython-313.pyc,,
37
+ huggingface_hub/__pycache__/repocard_data.cpython-313.pyc,,
38
+ huggingface_hub/_commit_api.py,sha256=tc1vhwKwIzFZefUjQOGTdlEL0bFla2fW_dW76YxfKKs,40651
39
+ huggingface_hub/_commit_scheduler.py,sha256=tqcdWVGJRIxGQtkFHs_AgBdN9ztUjOQSuAhfMAr1ieM,14751
40
+ huggingface_hub/_inference_endpoints.py,sha256=UHWmeZdmwyHRDkfpChvYpLL-onwjNubjzhR9xZEmDqY,17722
41
+ huggingface_hub/_jobs_api.py,sha256=BelnQPFWSH80-SJm8OGrZy8s1mwm8PmCGbV82sZ11xs,10871
42
+ huggingface_hub/_local_folder.py,sha256=gVG89_stPbxsQpkYh6YCXhhgfvhHFavP4uKmGkHjEzY,17305
43
+ huggingface_hub/_login.py,sha256=Me2o4B1qovbcXNKlHaakUrxho1XtPPSV7DD1sn2apEA,18971
44
+ huggingface_hub/_oauth.py,sha256=Pvu5zi733W7ZofFpzET1ZJjTJeg3JkdlW1TBc0WgBjU,18695
45
+ huggingface_hub/_snapshot_download.py,sha256=YQnl_fp3UiqMJf1Z-HYNHgiwm4QOeChQduQgXomiWA8,20595
46
+ huggingface_hub/_space_api.py,sha256=x3g73UhCyz4HEQIGjy7RTKUMO6j8VERpMD9RR-j9cEM,5464
47
+ huggingface_hub/_tensorboard_logger.py,sha256=3TocVxxSIioqxOkI6p1N4plnWfAizfdU456V0-K10Bs,8414
48
+ huggingface_hub/_upload_large_folder.py,sha256=CdtkQQPwURUGtpwZ_xzkrpAHCAEOJi458sIFayQ4oLQ,29554
49
+ huggingface_hub/_webhooks_payload.py,sha256=qCZjBa5dhssg_O0yzgzxPyMpwAxLG96I4qen_HIk0Qc,3611
50
+ huggingface_hub/_webhooks_server.py,sha256=-trDDzwsFHuE0IIwxWJLtfq9D35k8AVas-UAMSn3qxc,15668
51
+ huggingface_hub/cli/__init__.py,sha256=A4zmzuHD2OHjQ5zmdfcnsj0JeCzHVPtpzh-wCjInugA,606
52
+ huggingface_hub/cli/__pycache__/__init__.cpython-313.pyc,,
53
+ huggingface_hub/cli/__pycache__/_cli_utils.cpython-313.pyc,,
54
+ huggingface_hub/cli/__pycache__/auth.cpython-313.pyc,,
55
+ huggingface_hub/cli/__pycache__/cache.cpython-313.pyc,,
56
+ huggingface_hub/cli/__pycache__/download.cpython-313.pyc,,
57
+ huggingface_hub/cli/__pycache__/hf.cpython-313.pyc,,
58
+ huggingface_hub/cli/__pycache__/inference_endpoints.cpython-313.pyc,,
59
+ huggingface_hub/cli/__pycache__/jobs.cpython-313.pyc,,
60
+ huggingface_hub/cli/__pycache__/lfs.cpython-313.pyc,,
61
+ huggingface_hub/cli/__pycache__/repo.cpython-313.pyc,,
62
+ huggingface_hub/cli/__pycache__/repo_files.cpython-313.pyc,,
63
+ huggingface_hub/cli/__pycache__/system.cpython-313.pyc,,
64
+ huggingface_hub/cli/__pycache__/upload.cpython-313.pyc,,
65
+ huggingface_hub/cli/__pycache__/upload_large_folder.cpython-313.pyc,,
66
+ huggingface_hub/cli/_cli_utils.py,sha256=9ZtCiUgjKfII7d8Zg3PWN6k40Vec91vH9zF_EsBZiSs,5492
67
+ huggingface_hub/cli/auth.py,sha256=tJcKzQz8_pl0FFl8a-tNjxpK4AFfA38L4oztcXVdcSY,4515
68
+ huggingface_hub/cli/cache.py,sha256=v_2ssqCj3CLqFbD-nKK6BhGSCpgHzowrO4VvkSKU4k8,29168
69
+ huggingface_hub/cli/download.py,sha256=h9dUa91e1nOTmIcgtxyNE0ZGz6ZSrKu4nnlJsYp2HWg,6532
70
+ huggingface_hub/cli/hf.py,sha256=-ZfZnBMGYgIGZj7bf_juokmufqwpEnfLUiFABr5Y66w,2479
71
+ huggingface_hub/cli/inference_endpoints.py,sha256=-NNOdZkJyRuNls12b6SwYrR7-4Jc2qe73TQLfIrEEWY,12839
72
+ huggingface_hub/cli/jobs.py,sha256=HgxxxDRaCHH62eBpihzf1SakevM3OWewPiIzWjFkYLw,23871
73
+ huggingface_hub/cli/lfs.py,sha256=UJI5nBbrt_a-lm5uU88gxD6hVu8xyQav-zBxLTv3Wzo,5895
74
+ huggingface_hub/cli/repo.py,sha256=kAHyiYQap5gVNY8kPmub4s7X9mGsn8vFJNIIzSeIOD4,9709
75
+ huggingface_hub/cli/repo_files.py,sha256=6d5GsLsCjqSKTSbJqCHnrRxB9kXj-yLRAtcVbQkQNMo,2799
76
+ huggingface_hub/cli/system.py,sha256=bEIXmK3qz4qIej1lv1LMCxnXEN9zZnwdl42g4mV_1nQ,982
77
+ huggingface_hub/cli/upload.py,sha256=Dpu-syLR6J52U2HM8bJbjAk5PNA2gxAYagjKoRTNSZs,11383
78
+ huggingface_hub/cli/upload_large_folder.py,sha256=xQuloimQT0PQH6r5urRpLv8M9I99yAWSGM-sbkG2pu8,4470
79
+ huggingface_hub/community.py,sha256=FACeqlP7OgR2vLLJ0IN4cfglBiEGbyTafJ0cXfsjgnQ,12359
80
+ huggingface_hub/constants.py,sha256=V9dJXjYbO2tDQuiGmTGNl34QL8-h5DEi0JxJm7aR5Hw,10303
81
+ huggingface_hub/dataclasses.py,sha256=NSCRD_I9MrGUdea0-ep0fqVQtlWhIB1jvUOd_6aKrsY,22342
82
+ huggingface_hub/errors.py,sha256=8x8c4_VDG5cE21b6sRSjuTDD77bLaFO0xB8dejQjlS4,11919
83
+ huggingface_hub/fastai_utils.py,sha256=0joRPBUccjFALLCfhQLyD_K8qxGvQiLThKJClwej_JQ,16657
84
+ huggingface_hub/file_download.py,sha256=S4kOzCb5Cn-P1HvRYGFzOPm5VY7entYUQp5oIYyofpA,82880
85
+ huggingface_hub/hf_api.py,sha256=PaNel2xtIVlT9PmB7wMnwcH9Eiv8I36B--KhqUUWLo4,488151
86
+ huggingface_hub/hf_file_system.py,sha256=ye-mYdMdTJ7Sj2XBKciL3co3P7ooeUBas9BrsO-1sOE,53649
87
+ huggingface_hub/hub_mixin.py,sha256=9VkPWMmxKr2PhyeGiaHxiUgs65DOhPCZQT_ZfOkaUhE,37092
88
+ huggingface_hub/inference/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
89
+ huggingface_hub/inference/__pycache__/__init__.cpython-313.pyc,,
90
+ huggingface_hub/inference/__pycache__/_client.cpython-313.pyc,,
91
+ huggingface_hub/inference/__pycache__/_common.cpython-313.pyc,,
92
+ huggingface_hub/inference/_client.py,sha256=91FUhHmNfa6DgsHHhKxnOufTaE3hoGHYE9VNFAliMxE,158060
93
+ huggingface_hub/inference/_common.py,sha256=GrQXvwwQsG2Ow2tpjlp1WdRN-AvQYJlzW0eeTfSOJ64,15074
94
+ huggingface_hub/inference/_generated/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
95
+ huggingface_hub/inference/_generated/__pycache__/__init__.cpython-313.pyc,,
96
+ huggingface_hub/inference/_generated/__pycache__/_async_client.cpython-313.pyc,,
97
+ huggingface_hub/inference/_generated/_async_client.py,sha256=-u1yRjHIzu9nv3mWk1v0amxdGw3Eg4n_ooF3BZBn_Ao,161270
98
+ huggingface_hub/inference/_generated/types/__init__.py,sha256=9WvrGQ8aThtKSNzZF06j-CIE2ZuItne8FFnea1p1u38,6557
99
+ huggingface_hub/inference/_generated/types/__pycache__/__init__.cpython-313.pyc,,
100
+ huggingface_hub/inference/_generated/types/__pycache__/audio_classification.cpython-313.pyc,,
101
+ huggingface_hub/inference/_generated/types/__pycache__/audio_to_audio.cpython-313.pyc,,
102
+ huggingface_hub/inference/_generated/types/__pycache__/automatic_speech_recognition.cpython-313.pyc,,
103
+ huggingface_hub/inference/_generated/types/__pycache__/base.cpython-313.pyc,,
104
+ huggingface_hub/inference/_generated/types/__pycache__/chat_completion.cpython-313.pyc,,
105
+ huggingface_hub/inference/_generated/types/__pycache__/depth_estimation.cpython-313.pyc,,
106
+ huggingface_hub/inference/_generated/types/__pycache__/document_question_answering.cpython-313.pyc,,
107
+ huggingface_hub/inference/_generated/types/__pycache__/feature_extraction.cpython-313.pyc,,
108
+ huggingface_hub/inference/_generated/types/__pycache__/fill_mask.cpython-313.pyc,,
109
+ huggingface_hub/inference/_generated/types/__pycache__/image_classification.cpython-313.pyc,,
110
+ huggingface_hub/inference/_generated/types/__pycache__/image_segmentation.cpython-313.pyc,,
111
+ huggingface_hub/inference/_generated/types/__pycache__/image_to_image.cpython-313.pyc,,
112
+ huggingface_hub/inference/_generated/types/__pycache__/image_to_text.cpython-313.pyc,,
113
+ huggingface_hub/inference/_generated/types/__pycache__/image_to_video.cpython-313.pyc,,
114
+ huggingface_hub/inference/_generated/types/__pycache__/object_detection.cpython-313.pyc,,
115
+ huggingface_hub/inference/_generated/types/__pycache__/question_answering.cpython-313.pyc,,
116
+ huggingface_hub/inference/_generated/types/__pycache__/sentence_similarity.cpython-313.pyc,,
117
+ huggingface_hub/inference/_generated/types/__pycache__/summarization.cpython-313.pyc,,
118
+ huggingface_hub/inference/_generated/types/__pycache__/table_question_answering.cpython-313.pyc,,
119
+ huggingface_hub/inference/_generated/types/__pycache__/text2text_generation.cpython-313.pyc,,
120
+ huggingface_hub/inference/_generated/types/__pycache__/text_classification.cpython-313.pyc,,
121
+ huggingface_hub/inference/_generated/types/__pycache__/text_generation.cpython-313.pyc,,
122
+ huggingface_hub/inference/_generated/types/__pycache__/text_to_audio.cpython-313.pyc,,
123
+ huggingface_hub/inference/_generated/types/__pycache__/text_to_image.cpython-313.pyc,,
124
+ huggingface_hub/inference/_generated/types/__pycache__/text_to_speech.cpython-313.pyc,,
125
+ huggingface_hub/inference/_generated/types/__pycache__/text_to_video.cpython-313.pyc,,
126
+ huggingface_hub/inference/_generated/types/__pycache__/token_classification.cpython-313.pyc,,
127
+ huggingface_hub/inference/_generated/types/__pycache__/translation.cpython-313.pyc,,
128
+ huggingface_hub/inference/_generated/types/__pycache__/video_classification.cpython-313.pyc,,
129
+ huggingface_hub/inference/_generated/types/__pycache__/visual_question_answering.cpython-313.pyc,,
130
+ huggingface_hub/inference/_generated/types/__pycache__/zero_shot_classification.cpython-313.pyc,,
131
+ huggingface_hub/inference/_generated/types/__pycache__/zero_shot_image_classification.cpython-313.pyc,,
132
+ huggingface_hub/inference/_generated/types/__pycache__/zero_shot_object_detection.cpython-313.pyc,,
133
+ huggingface_hub/inference/_generated/types/audio_classification.py,sha256=Jg3mzfGhCSH6CfvVvgJSiFpkz6v4nNA0G4LJXacEgNc,1573
134
+ huggingface_hub/inference/_generated/types/audio_to_audio.py,sha256=2Ep4WkePL7oJwcp5nRJqApwviumGHbft9HhXE9XLHj4,891
135
+ huggingface_hub/inference/_generated/types/automatic_speech_recognition.py,sha256=FyViZkZqd0oo7Raqo48HESMAXHSnJap9HRWsKCi8Xz4,5509
136
+ huggingface_hub/inference/_generated/types/base.py,sha256=9sGEyvytJureiYimTb-pFIxG7jLe6okKzPamZuSiZyc,6896
137
+ huggingface_hub/inference/_generated/types/chat_completion.py,sha256=3-pAyko3ozXSsvE_nFl4wtALf3z5DVQSLjtAD-2tUe4,11242
138
+ huggingface_hub/inference/_generated/types/depth_estimation.py,sha256=c7IA81gZp5xIHol-7wlvy8V8UE--O1XF9rahauLVuoY,923
139
+ huggingface_hub/inference/_generated/types/document_question_answering.py,sha256=aJ_dC3pVLTHombqX3UwIFhKN_mFzpw4m89sfB2J488E,3196
140
+ huggingface_hub/inference/_generated/types/feature_extraction.py,sha256=xlo6LffaPlvickke537wAbTwbvjao82gnyWeUl1-WVs,1531
141
+ huggingface_hub/inference/_generated/types/fill_mask.py,sha256=E-dU2bmHlso1cei_ju_LQtYVvDZEqAM1-walZkMPa74,1702
142
+ huggingface_hub/inference/_generated/types/image_classification.py,sha256=A-Y024o8723_n8mGVos4TwdAkVL62McGeL1iIo4VzNs,1585
143
+ huggingface_hub/inference/_generated/types/image_segmentation.py,sha256=vrkI4SuP1Iq_iLXc-2pQhYY3SHN4gzvFBoZqbUHxU7o,1950
144
+ huggingface_hub/inference/_generated/types/image_to_image.py,sha256=snvGbmCdqchxGef25MceD7LSKAmVkIgnoX5t71rdlAQ,2290
145
+ huggingface_hub/inference/_generated/types/image_to_text.py,sha256=OaFEBAfgT-fOVzJ7xVermGf7VODhrc9-Jg38WrM7-2o,4810
146
+ huggingface_hub/inference/_generated/types/image_to_video.py,sha256=bC-L_cNsDhk4s_IdSiprJ9d1NeMGePLcUp7UPpco21w,2240
147
+ huggingface_hub/inference/_generated/types/object_detection.py,sha256=VuFlb1281qTXoSgJDmquGz-VNfEZLo2H0Rh_F6MF6ts,2000
148
+ huggingface_hub/inference/_generated/types/question_answering.py,sha256=zw38a9_9l2k1ifYZefjkioqZ4asfSRM9M4nU3gSCmAQ,2898
149
+ huggingface_hub/inference/_generated/types/sentence_similarity.py,sha256=5mDdTop4w6CpS-SulA03UVq5lBbzHuNMe8IQsTmAUPQ,1040
150
+ huggingface_hub/inference/_generated/types/summarization.py,sha256=eMJvNJmxdImVXLLMADmyDeB1YhJbN3Qd_fC6lPB7mTM,1481
151
+ huggingface_hub/inference/_generated/types/table_question_answering.py,sha256=SbgRCeEopJ0ig0U-q-Ft58kzD4aKfn1Dzu46r1g5z28,2281
152
+ huggingface_hub/inference/_generated/types/text2text_generation.py,sha256=S9as2uJKqCmRht_dFGws-KwQwEq1hD6w3gSLiGTMERI,1603
153
+ huggingface_hub/inference/_generated/types/text_classification.py,sha256=FarAjygLEfPofLfKeabzJ7PKEBItlHGoUNUOzyLRpL4,1445
154
+ huggingface_hub/inference/_generated/types/text_generation.py,sha256=g9pLc5XrWc1Ir0nmQ4xTa4ZauKHIJ9Pr7yM1FmZkX0Y,5916
155
+ huggingface_hub/inference/_generated/types/text_to_audio.py,sha256=1HR9Q6s9MXqtKGTvHPLGVMum5-eg7O-Pgv6Nd0v8_HU,4741
156
+ huggingface_hub/inference/_generated/types/text_to_image.py,sha256=sGGi1Fa0n5Pmd6G3I-F2SBJcJ1M7Gmqnng6sfi0AVzs,1903
157
+ huggingface_hub/inference/_generated/types/text_to_speech.py,sha256=ROFuR32ijROCeqbv81Jos0lmaA8SRWyIUsWrdD4yWow,4760
158
+ huggingface_hub/inference/_generated/types/text_to_video.py,sha256=xjC9Vp3eovuKEk7qhIeeC8VNJG8W0Kr8PEnOwOC1Ga4,1784
159
+ huggingface_hub/inference/_generated/types/token_classification.py,sha256=bpRwy_1knC11auZaeoVrCyYWBwyJLLKeiS-ypNkDTT8,1909
160
+ huggingface_hub/inference/_generated/types/translation.py,sha256=jfeWNGkZInGTOWP-Tq2dl1rGa8xuUQvZ40PxuOrsBpE,1757
161
+ huggingface_hub/inference/_generated/types/video_classification.py,sha256=TyydjQw2NRLK9sDGzJUVnkDeo848ebmCx588Ur8I9q0,1680
162
+ huggingface_hub/inference/_generated/types/visual_question_answering.py,sha256=AWrQ6qo4gZa3PGedaNpzDFqx5yOYyjhnUB6iuZEj_uo,1673
163
+ huggingface_hub/inference/_generated/types/zero_shot_classification.py,sha256=-PRiAdpXN0wxRrSVe3z8byEvuxcNby89mASU9CbfVzU,1732
164
+ huggingface_hub/inference/_generated/types/zero_shot_image_classification.py,sha256=1alzatw0RA88YUuHfrhRWQ5-Fix-iO3KcxfJV3WQB50,1481
165
+ huggingface_hub/inference/_generated/types/zero_shot_object_detection.py,sha256=sjdpVUN5zW9aYBymLVUs6i5HVk2qkUBO9ysEjHmsXVM,1605
166
+ huggingface_hub/inference/_mcp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
167
+ huggingface_hub/inference/_mcp/__pycache__/__init__.cpython-313.pyc,,
168
+ huggingface_hub/inference/_mcp/__pycache__/_cli_hacks.cpython-313.pyc,,
169
+ huggingface_hub/inference/_mcp/__pycache__/agent.cpython-313.pyc,,
170
+ huggingface_hub/inference/_mcp/__pycache__/cli.cpython-313.pyc,,
171
+ huggingface_hub/inference/_mcp/__pycache__/constants.cpython-313.pyc,,
172
+ huggingface_hub/inference/_mcp/__pycache__/mcp_client.cpython-313.pyc,,
173
+ huggingface_hub/inference/_mcp/__pycache__/types.cpython-313.pyc,,
174
+ huggingface_hub/inference/_mcp/__pycache__/utils.cpython-313.pyc,,
175
+ huggingface_hub/inference/_mcp/_cli_hacks.py,sha256=KX9HZJPa1p8ngY3mtYGGlVUXfg4vYbbBRs-8HLToP04,3284
176
+ huggingface_hub/inference/_mcp/agent.py,sha256=ufIzMGHore5n252hV5GZPM0ouDXIl6tv5Jl_5gHXnbg,4250
177
+ huggingface_hub/inference/_mcp/cli.py,sha256=BUw-ZINYw3xQpqMpP0NMQ8sur-lebQTcp7KuzCAIJPo,9811
178
+ huggingface_hub/inference/_mcp/constants.py,sha256=Ws8BujjgZWb5kPAVm4GLE_Rqse63MszHp863EWwoPCI,2487
179
+ huggingface_hub/inference/_mcp/mcp_client.py,sha256=dGp8PhN6aVw4bDnuSySFSiguHUiz-nzhgv89CVdO7pI,17243
180
+ huggingface_hub/inference/_mcp/types.py,sha256=yHNfPsM9MhD06oeKdkbmrBsW-3WhUeqA26fyfRfx_bk,929
181
+ huggingface_hub/inference/_mcp/utils.py,sha256=GI-jVl4AoGTQkpyUIyFmk1YF13bIABbq7hOLHWizBTI,4245
182
+ huggingface_hub/inference/_providers/__init__.py,sha256=yV2dL4ld59d-39FfnmpNU0fsQyBbzOX10bWdfRBXMc8,10269
183
+ huggingface_hub/inference/_providers/__pycache__/__init__.cpython-313.pyc,,
184
+ huggingface_hub/inference/_providers/__pycache__/_common.cpython-313.pyc,,
185
+ huggingface_hub/inference/_providers/__pycache__/black_forest_labs.cpython-313.pyc,,
186
+ huggingface_hub/inference/_providers/__pycache__/cerebras.cpython-313.pyc,,
187
+ huggingface_hub/inference/_providers/__pycache__/clarifai.cpython-313.pyc,,
188
+ huggingface_hub/inference/_providers/__pycache__/cohere.cpython-313.pyc,,
189
+ huggingface_hub/inference/_providers/__pycache__/fal_ai.cpython-313.pyc,,
190
+ huggingface_hub/inference/_providers/__pycache__/featherless_ai.cpython-313.pyc,,
191
+ huggingface_hub/inference/_providers/__pycache__/fireworks_ai.cpython-313.pyc,,
192
+ huggingface_hub/inference/_providers/__pycache__/groq.cpython-313.pyc,,
193
+ huggingface_hub/inference/_providers/__pycache__/hf_inference.cpython-313.pyc,,
194
+ huggingface_hub/inference/_providers/__pycache__/hyperbolic.cpython-313.pyc,,
195
+ huggingface_hub/inference/_providers/__pycache__/nebius.cpython-313.pyc,,
196
+ huggingface_hub/inference/_providers/__pycache__/novita.cpython-313.pyc,,
197
+ huggingface_hub/inference/_providers/__pycache__/nscale.cpython-313.pyc,,
198
+ huggingface_hub/inference/_providers/__pycache__/openai.cpython-313.pyc,,
199
+ huggingface_hub/inference/_providers/__pycache__/ovhcloud.cpython-313.pyc,,
200
+ huggingface_hub/inference/_providers/__pycache__/publicai.cpython-313.pyc,,
201
+ huggingface_hub/inference/_providers/__pycache__/replicate.cpython-313.pyc,,
202
+ huggingface_hub/inference/_providers/__pycache__/sambanova.cpython-313.pyc,,
203
+ huggingface_hub/inference/_providers/__pycache__/scaleway.cpython-313.pyc,,
204
+ huggingface_hub/inference/_providers/__pycache__/together.cpython-313.pyc,,
205
+ huggingface_hub/inference/_providers/__pycache__/wavespeed.cpython-313.pyc,,
206
+ huggingface_hub/inference/_providers/__pycache__/zai_org.cpython-313.pyc,,
207
+ huggingface_hub/inference/_providers/_common.py,sha256=fMs5721C0QyUpjQw7bzcNetqS0_oJ37gqceG4iCf7wo,13859
208
+ huggingface_hub/inference/_providers/black_forest_labs.py,sha256=vkjK_-4epSJa2-fLnbcXFzPAgQsGKhykKwd9Np-V2iw,2846
209
+ huggingface_hub/inference/_providers/cerebras.py,sha256=QOJ-1U-os7uE7p6eUnn_P_APq-yQhx28be7c3Tq2EuA,210
210
+ huggingface_hub/inference/_providers/clarifai.py,sha256=1cEXQwhGk4DRKiPCQUa5y-L6okTo4781EImQC8yJVOw,380
211
+ huggingface_hub/inference/_providers/cohere.py,sha256=GqUyCR4j6Re-_27ItwQF2p89Yya4e__EWDP9hTSs9w0,1247
212
+ huggingface_hub/inference/_providers/fal_ai.py,sha256=eQN_mXZY5eIoBifvEL8nPJMrtfcQOiIUhrmqdCFtLmA,11776
213
+ huggingface_hub/inference/_providers/featherless_ai.py,sha256=SceM3VsgzDSaCnzVxTFK6JepHaGStptdLlwrX-zsM2g,1376
214
+ huggingface_hub/inference/_providers/fireworks_ai.py,sha256=YfxC8wMU38qpv6xFc5HnHf6qK4x64nt-iwEDTip4C_U,1209
215
+ huggingface_hub/inference/_providers/groq.py,sha256=JTk2JV4ZOlaohho7zLAFQtk92kGVsPmLJ1hmzcwsqvQ,315
216
+ huggingface_hub/inference/_providers/hf_inference.py,sha256=dp15WQQNdbIJhLiRvH3PA651xdf7OjMx3R_1bjKqLxw,9534
217
+ huggingface_hub/inference/_providers/hyperbolic.py,sha256=LiAAiW7diy-ctrDKNYO_2N4Ght9wnvvD7hMo2NYbsNg,1979
218
+ huggingface_hub/inference/_providers/nebius.py,sha256=NQDJoNbFd9FPBA5yWTb_C42NoMeV8edpZCTRoXqtDOM,3574
219
+ huggingface_hub/inference/_providers/novita.py,sha256=AN4csxwKbRvNiaK87o9xVp9krL6mHPk6iv5iat87skA,2508
220
+ huggingface_hub/inference/_providers/nscale.py,sha256=RkyvmYtQbs2RPenF_pxDPMUMZM_botT21zqfVe2hT5Y,1796
221
+ huggingface_hub/inference/_providers/openai.py,sha256=GCVYeNdjWIgpQQ7E_Xv8IebmdhTi0S6WfFosz3nLtps,1089
222
+ huggingface_hub/inference/_providers/ovhcloud.py,sha256=tdmymlkbddMJKV7NRZ-tH2wymbLPFDTqUSXpWJUXyDQ,314
223
+ huggingface_hub/inference/_providers/publicai.py,sha256=1I2W6rORloB5QHSvky4njZO2XKLTwA-kPdNoauoT5rg,210
224
+ huggingface_hub/inference/_providers/replicate.py,sha256=Ug149-om44qC9VGyxJcpiMpIiG7QuNc80YbS6h7Gihg,5843
225
+ huggingface_hub/inference/_providers/sambanova.py,sha256=t-J89tab8wut62jXSXl7pAK5mCrovwdgtvbDYK1DHis,2031
226
+ huggingface_hub/inference/_providers/scaleway.py,sha256=Jy81kXWbXCHBpx6xmyzdEfXGSyhUfjKOLHuDSvhHWGo,1209
227
+ huggingface_hub/inference/_providers/together.py,sha256=q32zFvXhmRogWXMSaEFVYS8m9blXI_oy7KPdeal7Wwg,3433
228
+ huggingface_hub/inference/_providers/wavespeed.py,sha256=908rHLPhrbbdmR4EDfkH58N8gg8zcoYy0bvHALbnGoU,5060
229
+ huggingface_hub/inference/_providers/zai_org.py,sha256=plGzMZuLrChZvgpS3CCPqI6ImotZZxNLgfxnR7v6tw8,646
230
+ huggingface_hub/lfs.py,sha256=_yqqEl3xbzWufgBBJ-vtPx-LUiuZBJpT9AQ9iX0VJ0c,14060
231
+ huggingface_hub/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
232
+ huggingface_hub/repocard.py,sha256=eGgvokul8iiCXYuPdrGGyiq6r0YZy_bA91p0SNdmkqw,34973
233
+ huggingface_hub/repocard_data.py,sha256=awhSsLRPrcFM9CurB9mrY40H1bE15yzoXDTVL60yD1U,34079
234
+ huggingface_hub/serialization/__init__.py,sha256=jCiw_vVQYW52gwVfWiqgocf2Q19kGTQlRGVpf-4SLP8,963
235
+ huggingface_hub/serialization/__pycache__/__init__.cpython-313.pyc,,
236
+ huggingface_hub/serialization/__pycache__/_base.cpython-313.pyc,,
237
+ huggingface_hub/serialization/__pycache__/_dduf.cpython-313.pyc,,
238
+ huggingface_hub/serialization/__pycache__/_torch.cpython-313.pyc,,
239
+ huggingface_hub/serialization/_base.py,sha256=9HZ0W6r77rsUVk5g51_-uglb5KSfHIBMC5YIsVG0woU,8175
240
+ huggingface_hub/serialization/_dduf.py,sha256=KpfM8D9w3UcAM0hhwYdnM8byIiZMUKQnTl25Wb1hHiw,15410
241
+ huggingface_hub/serialization/_torch.py,sha256=__M4aP9zuCJp9TAJLr0r-26LuSao2cofzeo2MPSe-VI,45124
242
+ huggingface_hub/templates/datasetcard_template.md,sha256=W-EMqR6wndbrnZorkVv56URWPG49l7MATGeI015kTvs,5503
243
+ huggingface_hub/templates/modelcard_template.md,sha256=4AqArS3cqdtbit5Bo-DhjcnDFR-pza5hErLLTPM4Yuc,6870
244
+ huggingface_hub/utils/__init__.py,sha256=w7O2buBzUW1akdF9G-t8nbaEkQuDEQLelH685d8Zjow,3894
245
+ huggingface_hub/utils/__pycache__/__init__.cpython-313.pyc,,
246
+ huggingface_hub/utils/__pycache__/_auth.cpython-313.pyc,,
247
+ huggingface_hub/utils/__pycache__/_cache_assets.cpython-313.pyc,,
248
+ huggingface_hub/utils/__pycache__/_cache_manager.cpython-313.pyc,,
249
+ huggingface_hub/utils/__pycache__/_chunk_utils.cpython-313.pyc,,
250
+ huggingface_hub/utils/__pycache__/_datetime.cpython-313.pyc,,
251
+ huggingface_hub/utils/__pycache__/_deprecation.cpython-313.pyc,,
252
+ huggingface_hub/utils/__pycache__/_dotenv.cpython-313.pyc,,
253
+ huggingface_hub/utils/__pycache__/_experimental.cpython-313.pyc,,
254
+ huggingface_hub/utils/__pycache__/_fixes.cpython-313.pyc,,
255
+ huggingface_hub/utils/__pycache__/_git_credential.cpython-313.pyc,,
256
+ huggingface_hub/utils/__pycache__/_headers.cpython-313.pyc,,
257
+ huggingface_hub/utils/__pycache__/_http.cpython-313.pyc,,
258
+ huggingface_hub/utils/__pycache__/_lfs.cpython-313.pyc,,
259
+ huggingface_hub/utils/__pycache__/_pagination.cpython-313.pyc,,
260
+ huggingface_hub/utils/__pycache__/_parsing.cpython-313.pyc,,
261
+ huggingface_hub/utils/__pycache__/_paths.cpython-313.pyc,,
262
+ huggingface_hub/utils/__pycache__/_runtime.cpython-313.pyc,,
263
+ huggingface_hub/utils/__pycache__/_safetensors.cpython-313.pyc,,
264
+ huggingface_hub/utils/__pycache__/_subprocess.cpython-313.pyc,,
265
+ huggingface_hub/utils/__pycache__/_telemetry.cpython-313.pyc,,
266
+ huggingface_hub/utils/__pycache__/_terminal.cpython-313.pyc,,
267
+ huggingface_hub/utils/__pycache__/_typing.cpython-313.pyc,,
268
+ huggingface_hub/utils/__pycache__/_validators.cpython-313.pyc,,
269
+ huggingface_hub/utils/__pycache__/_verification.cpython-313.pyc,,
270
+ huggingface_hub/utils/__pycache__/_xet.cpython-313.pyc,,
271
+ huggingface_hub/utils/__pycache__/_xet_progress_reporting.cpython-313.pyc,,
272
+ huggingface_hub/utils/__pycache__/endpoint_helpers.cpython-313.pyc,,
273
+ huggingface_hub/utils/__pycache__/insecure_hashlib.cpython-313.pyc,,
274
+ huggingface_hub/utils/__pycache__/logging.cpython-313.pyc,,
275
+ huggingface_hub/utils/__pycache__/sha.cpython-313.pyc,,
276
+ huggingface_hub/utils/__pycache__/tqdm.cpython-313.pyc,,
277
+ huggingface_hub/utils/_auth.py,sha256=dtJXLgad9jyH33b3YOGFqbjV8Fi0PPR9GnBxgJqfKK4,8279
278
+ huggingface_hub/utils/_cache_assets.py,sha256=GAefejvj4ZAY1aJ4agyuR-1_IqYo-xznjXA_QYcEQGI,5736
279
+ huggingface_hub/utils/_cache_manager.py,sha256=1Yb3s4jIXudAV1H2nD7mmxi3CcUel8dCmXB06RiexLk,32991
280
+ huggingface_hub/utils/_chunk_utils.py,sha256=MH7-6FwCDZ8noV6dGRytCOJGSfcZmDBvsvVotdI8TvQ,2109
281
+ huggingface_hub/utils/_datetime.py,sha256=kCS5jaKV25kOncX1xujbXsz5iDLcjLcLw85semGNzxQ,2770
282
+ huggingface_hub/utils/_deprecation.py,sha256=4tWi3vBSdvnhA0z_Op-tkAQ0xrJ4TUb0HbPhMiXUnOs,4872
283
+ huggingface_hub/utils/_dotenv.py,sha256=2LLdzpA-LzLxO15GLb9WKT5IGrTurIRmFPrMX1yDzsU,2011
284
+ huggingface_hub/utils/_experimental.py,sha256=3-c8irbn9sJr2CwWbzhGkIrdXKg8_x7BifhHFy32ei8,2470
285
+ huggingface_hub/utils/_fixes.py,sha256=xQZzfwLqZV8-gNcw9mrZ-M1acA6NZHszI_-cSZIWN-U,3978
286
+ huggingface_hub/utils/_git_credential.py,sha256=gdQbYZyKEynpqLmtr8lSnCrfPTBzdFdmODmHIgivr4k,4612
287
+ huggingface_hub/utils/_headers.py,sha256=k_ApvA8fJGHc0yNp2IFY8wySM9MQ5UZEpjr1g-fpRJ4,8060
288
+ huggingface_hub/utils/_http.py,sha256=LUiP5V9uF0GqQaT6LgKcMnpnXC7D8Fe7TeeUxDH7jcU,37337
289
+ huggingface_hub/utils/_lfs.py,sha256=EC0Oz6Wiwl8foRNkUOzrETXzAWlbgpnpxo5a410ovFY,3957
290
+ huggingface_hub/utils/_pagination.py,sha256=-6HUYjkSXXy-l0z4iRUBkdW1R_Pv7p6h2Z78HEFEC14,1851
291
+ huggingface_hub/utils/_parsing.py,sha256=T6UCjUh0h731A0Jh-eH5RWcqVQ5m0IyMcXHl5G2YNUs,3021
292
+ huggingface_hub/utils/_paths.py,sha256=WCR2WbqDJLdNlU4XZNXXNmGct3OiDwPesGYrq41T2wE,5036
293
+ huggingface_hub/utils/_runtime.py,sha256=YIbpExk5dxRXGbdwUjTJDBNnZIwo6_5xi4ZjVOPI6Vg,12595
294
+ huggingface_hub/utils/_safetensors.py,sha256=2_xbCsDPsCwR1tyBjJ5MoOHsX4ksocjzc4jS7oGe7_s,4439
295
+ huggingface_hub/utils/_subprocess.py,sha256=9qDWT1a2QF2TmXOQJDlPK6LwzYl9XjXeRadQPn15U14,4612
296
+ huggingface_hub/utils/_telemetry.py,sha256=hlVBh85Cp10Kl4mqIlJLDyGzlrEKCJnqWvNEip7stwo,4884
297
+ huggingface_hub/utils/_terminal.py,sha256=6iiPQfqjkNCo3GfBDAFu1NfGRaZO4AFTYapQDTwNCjs,2354
298
+ huggingface_hub/utils/_typing.py,sha256=cC9p6E8hG2LId8sFWJ9H-cpQozv3asuoww_XiA1-XWI,3617
299
+ huggingface_hub/utils/_validators.py,sha256=A3BkXbpX4KnUD2WFsYOgkXnYdpLiXXG8KbyNdq0qz78,8346
300
+ huggingface_hub/utils/_verification.py,sha256=KoAGX5YzdBT0DwqBcDW7QtzCdWiXOgsxJw9r0THyr4M,5496
301
+ huggingface_hub/utils/_xet.py,sha256=cVPjHSYL13qNuhr1T1DOyERy30WJJa-SonsAuwy1j8Q,8896
302
+ huggingface_hub/utils/_xet_progress_reporting.py,sha256=bxwanhLxigDASflFZVt7S8eENIviguyVg1Q9vFtmDf8,6169
303
+ huggingface_hub/utils/endpoint_helpers.py,sha256=9VtIAlxQ5H_4y30sjCAgbu7XCqAtNLC7aRYxaNn0hLI,2366
304
+ huggingface_hub/utils/insecure_hashlib.py,sha256=z3dVUFvdBZ8kQI_8Vzvvlr3ims-EBiY-SYPdnzIKOkw,1008
305
+ huggingface_hub/utils/logging.py,sha256=N6NXaCcbPbZSF-Oe-TY3ZnmkpmdFVyTOV8ASo-yVXLE,4916
306
+ huggingface_hub/utils/sha.py,sha256=OFnNGCba0sNcT2gUwaVCJnldxlltrHHe0DS_PCpV3C4,2134
307
+ huggingface_hub/utils/tqdm.py,sha256=lhdAR-4zn9cablCDS6240-O2vb4bdTfTbjUW684QWI4,10757
env/lib/python3.13/site-packages/huggingface_hub-1.2.1.dist-info/REQUESTED ADDED
File without changes
env/lib/python3.13/site-packages/huggingface_hub-1.2.1.dist-info/WHEEL ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (79.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
env/lib/python3.13/site-packages/huggingface_hub-1.2.1.dist-info/entry_points.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ [console_scripts]
2
+ hf = huggingface_hub.cli.hf:main
3
+ tiny-agents = huggingface_hub.inference._mcp.cli:app
4
+
5
+ [fsspec.specs]
6
+ hf = huggingface_hub.HfFileSystem
env/lib/python3.13/site-packages/huggingface_hub-1.2.1.dist-info/top_level.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ huggingface_hub
env/lib/python3.13/site-packages/huggingface_hub/__init__.py ADDED
@@ -0,0 +1,1560 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2020 The HuggingFace Team. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # ***********
16
+ # `huggingface_hub` init has 2 modes:
17
+ # - Normal usage:
18
+ # If imported to use it, all modules and functions are lazy-loaded. This means
19
+ # they exist at top level in module but are imported only the first time they are
20
+ # used. This way, `from huggingface_hub import something` will import `something`
21
+ # quickly without the hassle of importing all the features from `huggingface_hub`.
22
+ # - Static check:
23
+ # If statically analyzed, all modules and functions are loaded normally. This way
24
+ # static typing check works properly as well as autocomplete in text editors and
25
+ # IDEs.
26
+ #
27
+ # The static model imports are done inside the `if TYPE_CHECKING:` statement at
28
+ # the bottom of this file. Since module/functions imports are duplicated, it is
29
+ # mandatory to make sure to add them twice when adding one. This is checked in the
30
+ # `make quality` command.
31
+ #
32
+ # To update the static imports, please run the following command and commit the changes.
33
+ # ```
34
+ # # Use script
35
+ # python utils/check_static_imports.py --update-file
36
+ #
37
+ # # Or run style on codebase
38
+ # make style
39
+ # ```
40
+ #
41
+ # ***********
42
+ # Lazy loader vendored from https://github.com/scientific-python/lazy_loader
43
+ import importlib
44
+ import os
45
+ import sys
46
+ from typing import TYPE_CHECKING
47
+
48
+
49
+ __version__ = "1.2.1"
50
+
51
+ # Alphabetical order of definitions is ensured in tests
52
+ # WARNING: any comment added in this dictionary definition will be lost when
53
+ # re-generating the file !
54
+ _SUBMOD_ATTRS = {
55
+ "_commit_scheduler": [
56
+ "CommitScheduler",
57
+ ],
58
+ "_inference_endpoints": [
59
+ "InferenceEndpoint",
60
+ "InferenceEndpointError",
61
+ "InferenceEndpointStatus",
62
+ "InferenceEndpointTimeoutError",
63
+ "InferenceEndpointType",
64
+ ],
65
+ "_jobs_api": [
66
+ "JobInfo",
67
+ "JobOwner",
68
+ "JobStage",
69
+ "JobStatus",
70
+ ],
71
+ "_login": [
72
+ "auth_list",
73
+ "auth_switch",
74
+ "interpreter_login",
75
+ "login",
76
+ "logout",
77
+ "notebook_login",
78
+ ],
79
+ "_oauth": [
80
+ "OAuthInfo",
81
+ "OAuthOrgInfo",
82
+ "OAuthUserInfo",
83
+ "attach_huggingface_oauth",
84
+ "parse_huggingface_oauth",
85
+ ],
86
+ "_snapshot_download": [
87
+ "snapshot_download",
88
+ ],
89
+ "_space_api": [
90
+ "SpaceHardware",
91
+ "SpaceRuntime",
92
+ "SpaceStage",
93
+ "SpaceStorage",
94
+ "SpaceVariable",
95
+ ],
96
+ "_tensorboard_logger": [
97
+ "HFSummaryWriter",
98
+ ],
99
+ "_webhooks_payload": [
100
+ "WebhookPayload",
101
+ "WebhookPayloadComment",
102
+ "WebhookPayloadDiscussion",
103
+ "WebhookPayloadDiscussionChanges",
104
+ "WebhookPayloadEvent",
105
+ "WebhookPayloadMovedTo",
106
+ "WebhookPayloadRepo",
107
+ "WebhookPayloadUrl",
108
+ "WebhookPayloadWebhook",
109
+ ],
110
+ "_webhooks_server": [
111
+ "WebhooksServer",
112
+ "webhook_endpoint",
113
+ ],
114
+ "cli._cli_utils": [
115
+ "typer_factory",
116
+ ],
117
+ "community": [
118
+ "Discussion",
119
+ "DiscussionComment",
120
+ "DiscussionCommit",
121
+ "DiscussionEvent",
122
+ "DiscussionStatusChange",
123
+ "DiscussionTitleChange",
124
+ "DiscussionWithDetails",
125
+ ],
126
+ "constants": [
127
+ "CONFIG_NAME",
128
+ "FLAX_WEIGHTS_NAME",
129
+ "HUGGINGFACE_CO_URL_HOME",
130
+ "HUGGINGFACE_CO_URL_TEMPLATE",
131
+ "PYTORCH_WEIGHTS_NAME",
132
+ "REPO_TYPE_DATASET",
133
+ "REPO_TYPE_MODEL",
134
+ "REPO_TYPE_SPACE",
135
+ "TF2_WEIGHTS_NAME",
136
+ "TF_WEIGHTS_NAME",
137
+ "is_offline_mode",
138
+ ],
139
+ "fastai_utils": [
140
+ "_save_pretrained_fastai",
141
+ "from_pretrained_fastai",
142
+ "push_to_hub_fastai",
143
+ ],
144
+ "file_download": [
145
+ "DryRunFileInfo",
146
+ "HfFileMetadata",
147
+ "_CACHED_NO_EXIST",
148
+ "get_hf_file_metadata",
149
+ "hf_hub_download",
150
+ "hf_hub_url",
151
+ "try_to_load_from_cache",
152
+ ],
153
+ "hf_api": [
154
+ "Collection",
155
+ "CollectionItem",
156
+ "CommitInfo",
157
+ "CommitOperation",
158
+ "CommitOperationAdd",
159
+ "CommitOperationCopy",
160
+ "CommitOperationDelete",
161
+ "DatasetInfo",
162
+ "GitCommitInfo",
163
+ "GitRefInfo",
164
+ "GitRefs",
165
+ "HfApi",
166
+ "ModelInfo",
167
+ "Organization",
168
+ "RepoFile",
169
+ "RepoFolder",
170
+ "RepoUrl",
171
+ "SpaceInfo",
172
+ "User",
173
+ "UserLikes",
174
+ "WebhookInfo",
175
+ "WebhookWatchedItem",
176
+ "accept_access_request",
177
+ "add_collection_item",
178
+ "add_space_secret",
179
+ "add_space_variable",
180
+ "auth_check",
181
+ "cancel_access_request",
182
+ "cancel_job",
183
+ "change_discussion_status",
184
+ "comment_discussion",
185
+ "create_branch",
186
+ "create_collection",
187
+ "create_commit",
188
+ "create_discussion",
189
+ "create_inference_endpoint",
190
+ "create_inference_endpoint_from_catalog",
191
+ "create_pull_request",
192
+ "create_repo",
193
+ "create_scheduled_job",
194
+ "create_scheduled_uv_job",
195
+ "create_tag",
196
+ "create_webhook",
197
+ "dataset_info",
198
+ "delete_branch",
199
+ "delete_collection",
200
+ "delete_collection_item",
201
+ "delete_file",
202
+ "delete_folder",
203
+ "delete_inference_endpoint",
204
+ "delete_repo",
205
+ "delete_scheduled_job",
206
+ "delete_space_secret",
207
+ "delete_space_storage",
208
+ "delete_space_variable",
209
+ "delete_tag",
210
+ "delete_webhook",
211
+ "disable_webhook",
212
+ "duplicate_space",
213
+ "edit_discussion_comment",
214
+ "enable_webhook",
215
+ "fetch_job_logs",
216
+ "file_exists",
217
+ "get_collection",
218
+ "get_dataset_tags",
219
+ "get_discussion_details",
220
+ "get_full_repo_name",
221
+ "get_inference_endpoint",
222
+ "get_model_tags",
223
+ "get_organization_overview",
224
+ "get_paths_info",
225
+ "get_repo_discussions",
226
+ "get_safetensors_metadata",
227
+ "get_space_runtime",
228
+ "get_space_variables",
229
+ "get_user_overview",
230
+ "get_webhook",
231
+ "grant_access",
232
+ "inspect_job",
233
+ "inspect_scheduled_job",
234
+ "list_accepted_access_requests",
235
+ "list_collections",
236
+ "list_daily_papers",
237
+ "list_datasets",
238
+ "list_inference_catalog",
239
+ "list_inference_endpoints",
240
+ "list_jobs",
241
+ "list_lfs_files",
242
+ "list_liked_repos",
243
+ "list_models",
244
+ "list_organization_followers",
245
+ "list_organization_members",
246
+ "list_papers",
247
+ "list_pending_access_requests",
248
+ "list_rejected_access_requests",
249
+ "list_repo_commits",
250
+ "list_repo_files",
251
+ "list_repo_likers",
252
+ "list_repo_refs",
253
+ "list_repo_tree",
254
+ "list_spaces",
255
+ "list_user_followers",
256
+ "list_user_following",
257
+ "list_webhooks",
258
+ "merge_pull_request",
259
+ "model_info",
260
+ "move_repo",
261
+ "paper_info",
262
+ "parse_safetensors_file_metadata",
263
+ "pause_inference_endpoint",
264
+ "pause_space",
265
+ "permanently_delete_lfs_files",
266
+ "preupload_lfs_files",
267
+ "reject_access_request",
268
+ "rename_discussion",
269
+ "repo_exists",
270
+ "repo_info",
271
+ "repo_type_and_id_from_hf_id",
272
+ "request_space_hardware",
273
+ "request_space_storage",
274
+ "restart_space",
275
+ "resume_inference_endpoint",
276
+ "resume_scheduled_job",
277
+ "revision_exists",
278
+ "run_as_future",
279
+ "run_job",
280
+ "run_uv_job",
281
+ "scale_to_zero_inference_endpoint",
282
+ "set_space_sleep_time",
283
+ "space_info",
284
+ "super_squash_history",
285
+ "suspend_scheduled_job",
286
+ "unlike",
287
+ "update_collection_item",
288
+ "update_collection_metadata",
289
+ "update_inference_endpoint",
290
+ "update_repo_settings",
291
+ "update_webhook",
292
+ "upload_file",
293
+ "upload_folder",
294
+ "upload_large_folder",
295
+ "verify_repo_checksums",
296
+ "whoami",
297
+ ],
298
+ "hf_file_system": [
299
+ "HfFileSystem",
300
+ "HfFileSystemFile",
301
+ "HfFileSystemResolvedPath",
302
+ "HfFileSystemStreamFile",
303
+ "hffs",
304
+ ],
305
+ "hub_mixin": [
306
+ "ModelHubMixin",
307
+ "PyTorchModelHubMixin",
308
+ ],
309
+ "inference._client": [
310
+ "InferenceClient",
311
+ "InferenceTimeoutError",
312
+ ],
313
+ "inference._generated._async_client": [
314
+ "AsyncInferenceClient",
315
+ ],
316
+ "inference._generated.types": [
317
+ "AudioClassificationInput",
318
+ "AudioClassificationOutputElement",
319
+ "AudioClassificationOutputTransform",
320
+ "AudioClassificationParameters",
321
+ "AudioToAudioInput",
322
+ "AudioToAudioOutputElement",
323
+ "AutomaticSpeechRecognitionEarlyStoppingEnum",
324
+ "AutomaticSpeechRecognitionGenerationParameters",
325
+ "AutomaticSpeechRecognitionInput",
326
+ "AutomaticSpeechRecognitionOutput",
327
+ "AutomaticSpeechRecognitionOutputChunk",
328
+ "AutomaticSpeechRecognitionParameters",
329
+ "ChatCompletionInput",
330
+ "ChatCompletionInputFunctionDefinition",
331
+ "ChatCompletionInputFunctionName",
332
+ "ChatCompletionInputGrammarType",
333
+ "ChatCompletionInputJSONSchema",
334
+ "ChatCompletionInputMessage",
335
+ "ChatCompletionInputMessageChunk",
336
+ "ChatCompletionInputMessageChunkType",
337
+ "ChatCompletionInputResponseFormatJSONObject",
338
+ "ChatCompletionInputResponseFormatJSONSchema",
339
+ "ChatCompletionInputResponseFormatText",
340
+ "ChatCompletionInputStreamOptions",
341
+ "ChatCompletionInputTool",
342
+ "ChatCompletionInputToolCall",
343
+ "ChatCompletionInputToolChoiceClass",
344
+ "ChatCompletionInputToolChoiceEnum",
345
+ "ChatCompletionInputURL",
346
+ "ChatCompletionOutput",
347
+ "ChatCompletionOutputComplete",
348
+ "ChatCompletionOutputFunctionDefinition",
349
+ "ChatCompletionOutputLogprob",
350
+ "ChatCompletionOutputLogprobs",
351
+ "ChatCompletionOutputMessage",
352
+ "ChatCompletionOutputToolCall",
353
+ "ChatCompletionOutputTopLogprob",
354
+ "ChatCompletionOutputUsage",
355
+ "ChatCompletionStreamOutput",
356
+ "ChatCompletionStreamOutputChoice",
357
+ "ChatCompletionStreamOutputDelta",
358
+ "ChatCompletionStreamOutputDeltaToolCall",
359
+ "ChatCompletionStreamOutputFunction",
360
+ "ChatCompletionStreamOutputLogprob",
361
+ "ChatCompletionStreamOutputLogprobs",
362
+ "ChatCompletionStreamOutputTopLogprob",
363
+ "ChatCompletionStreamOutputUsage",
364
+ "DepthEstimationInput",
365
+ "DepthEstimationOutput",
366
+ "DocumentQuestionAnsweringInput",
367
+ "DocumentQuestionAnsweringInputData",
368
+ "DocumentQuestionAnsweringOutputElement",
369
+ "DocumentQuestionAnsweringParameters",
370
+ "FeatureExtractionInput",
371
+ "FeatureExtractionInputTruncationDirection",
372
+ "FillMaskInput",
373
+ "FillMaskOutputElement",
374
+ "FillMaskParameters",
375
+ "ImageClassificationInput",
376
+ "ImageClassificationOutputElement",
377
+ "ImageClassificationOutputTransform",
378
+ "ImageClassificationParameters",
379
+ "ImageSegmentationInput",
380
+ "ImageSegmentationOutputElement",
381
+ "ImageSegmentationParameters",
382
+ "ImageSegmentationSubtask",
383
+ "ImageToImageInput",
384
+ "ImageToImageOutput",
385
+ "ImageToImageParameters",
386
+ "ImageToImageTargetSize",
387
+ "ImageToTextEarlyStoppingEnum",
388
+ "ImageToTextGenerationParameters",
389
+ "ImageToTextInput",
390
+ "ImageToTextOutput",
391
+ "ImageToTextParameters",
392
+ "ImageToVideoInput",
393
+ "ImageToVideoOutput",
394
+ "ImageToVideoParameters",
395
+ "ImageToVideoTargetSize",
396
+ "ObjectDetectionBoundingBox",
397
+ "ObjectDetectionInput",
398
+ "ObjectDetectionOutputElement",
399
+ "ObjectDetectionParameters",
400
+ "Padding",
401
+ "QuestionAnsweringInput",
402
+ "QuestionAnsweringInputData",
403
+ "QuestionAnsweringOutputElement",
404
+ "QuestionAnsweringParameters",
405
+ "SentenceSimilarityInput",
406
+ "SentenceSimilarityInputData",
407
+ "SummarizationInput",
408
+ "SummarizationOutput",
409
+ "SummarizationParameters",
410
+ "SummarizationTruncationStrategy",
411
+ "TableQuestionAnsweringInput",
412
+ "TableQuestionAnsweringInputData",
413
+ "TableQuestionAnsweringOutputElement",
414
+ "TableQuestionAnsweringParameters",
415
+ "Text2TextGenerationInput",
416
+ "Text2TextGenerationOutput",
417
+ "Text2TextGenerationParameters",
418
+ "Text2TextGenerationTruncationStrategy",
419
+ "TextClassificationInput",
420
+ "TextClassificationOutputElement",
421
+ "TextClassificationOutputTransform",
422
+ "TextClassificationParameters",
423
+ "TextGenerationInput",
424
+ "TextGenerationInputGenerateParameters",
425
+ "TextGenerationInputGrammarType",
426
+ "TextGenerationOutput",
427
+ "TextGenerationOutputBestOfSequence",
428
+ "TextGenerationOutputDetails",
429
+ "TextGenerationOutputFinishReason",
430
+ "TextGenerationOutputPrefillToken",
431
+ "TextGenerationOutputToken",
432
+ "TextGenerationStreamOutput",
433
+ "TextGenerationStreamOutputStreamDetails",
434
+ "TextGenerationStreamOutputToken",
435
+ "TextToAudioEarlyStoppingEnum",
436
+ "TextToAudioGenerationParameters",
437
+ "TextToAudioInput",
438
+ "TextToAudioOutput",
439
+ "TextToAudioParameters",
440
+ "TextToImageInput",
441
+ "TextToImageOutput",
442
+ "TextToImageParameters",
443
+ "TextToSpeechEarlyStoppingEnum",
444
+ "TextToSpeechGenerationParameters",
445
+ "TextToSpeechInput",
446
+ "TextToSpeechOutput",
447
+ "TextToSpeechParameters",
448
+ "TextToVideoInput",
449
+ "TextToVideoOutput",
450
+ "TextToVideoParameters",
451
+ "TokenClassificationAggregationStrategy",
452
+ "TokenClassificationInput",
453
+ "TokenClassificationOutputElement",
454
+ "TokenClassificationParameters",
455
+ "TranslationInput",
456
+ "TranslationOutput",
457
+ "TranslationParameters",
458
+ "TranslationTruncationStrategy",
459
+ "TypeEnum",
460
+ "VideoClassificationInput",
461
+ "VideoClassificationOutputElement",
462
+ "VideoClassificationOutputTransform",
463
+ "VideoClassificationParameters",
464
+ "VisualQuestionAnsweringInput",
465
+ "VisualQuestionAnsweringInputData",
466
+ "VisualQuestionAnsweringOutputElement",
467
+ "VisualQuestionAnsweringParameters",
468
+ "ZeroShotClassificationInput",
469
+ "ZeroShotClassificationOutputElement",
470
+ "ZeroShotClassificationParameters",
471
+ "ZeroShotImageClassificationInput",
472
+ "ZeroShotImageClassificationOutputElement",
473
+ "ZeroShotImageClassificationParameters",
474
+ "ZeroShotObjectDetectionBoundingBox",
475
+ "ZeroShotObjectDetectionInput",
476
+ "ZeroShotObjectDetectionOutputElement",
477
+ "ZeroShotObjectDetectionParameters",
478
+ ],
479
+ "inference._mcp.agent": [
480
+ "Agent",
481
+ ],
482
+ "inference._mcp.mcp_client": [
483
+ "MCPClient",
484
+ ],
485
+ "repocard": [
486
+ "DatasetCard",
487
+ "ModelCard",
488
+ "RepoCard",
489
+ "SpaceCard",
490
+ "metadata_eval_result",
491
+ "metadata_load",
492
+ "metadata_save",
493
+ "metadata_update",
494
+ ],
495
+ "repocard_data": [
496
+ "CardData",
497
+ "DatasetCardData",
498
+ "EvalResult",
499
+ "ModelCardData",
500
+ "SpaceCardData",
501
+ ],
502
+ "serialization": [
503
+ "StateDictSplit",
504
+ "get_torch_storage_id",
505
+ "get_torch_storage_size",
506
+ "load_state_dict_from_file",
507
+ "load_torch_model",
508
+ "save_torch_model",
509
+ "save_torch_state_dict",
510
+ "split_state_dict_into_shards_factory",
511
+ "split_torch_state_dict_into_shards",
512
+ ],
513
+ "serialization._dduf": [
514
+ "DDUFEntry",
515
+ "export_entries_as_dduf",
516
+ "export_folder_as_dduf",
517
+ "read_dduf_file",
518
+ ],
519
+ "utils": [
520
+ "ASYNC_CLIENT_FACTORY_T",
521
+ "CLIENT_FACTORY_T",
522
+ "CacheNotFound",
523
+ "CachedFileInfo",
524
+ "CachedRepoInfo",
525
+ "CachedRevisionInfo",
526
+ "CorruptedCacheException",
527
+ "DeleteCacheStrategy",
528
+ "HFCacheInfo",
529
+ "cached_assets_path",
530
+ "close_session",
531
+ "dump_environment_info",
532
+ "get_async_session",
533
+ "get_session",
534
+ "get_token",
535
+ "hf_raise_for_status",
536
+ "logging",
537
+ "scan_cache_dir",
538
+ "set_async_client_factory",
539
+ "set_client_factory",
540
+ ],
541
+ }
542
+
543
+ # WARNING: __all__ is generated automatically, Any manual edit will be lost when re-generating this file !
544
+ #
545
+ # To update the static imports, please run the following command and commit the changes.
546
+ # ```
547
+ # # Use script
548
+ # python utils/check_all_variable.py --update
549
+ #
550
+ # # Or run style on codebase
551
+ # make style
552
+ # ```
553
+
554
+ __all__ = [
555
+ "ASYNC_CLIENT_FACTORY_T",
556
+ "Agent",
557
+ "AsyncInferenceClient",
558
+ "AudioClassificationInput",
559
+ "AudioClassificationOutputElement",
560
+ "AudioClassificationOutputTransform",
561
+ "AudioClassificationParameters",
562
+ "AudioToAudioInput",
563
+ "AudioToAudioOutputElement",
564
+ "AutomaticSpeechRecognitionEarlyStoppingEnum",
565
+ "AutomaticSpeechRecognitionGenerationParameters",
566
+ "AutomaticSpeechRecognitionInput",
567
+ "AutomaticSpeechRecognitionOutput",
568
+ "AutomaticSpeechRecognitionOutputChunk",
569
+ "AutomaticSpeechRecognitionParameters",
570
+ "CLIENT_FACTORY_T",
571
+ "CONFIG_NAME",
572
+ "CacheNotFound",
573
+ "CachedFileInfo",
574
+ "CachedRepoInfo",
575
+ "CachedRevisionInfo",
576
+ "CardData",
577
+ "ChatCompletionInput",
578
+ "ChatCompletionInputFunctionDefinition",
579
+ "ChatCompletionInputFunctionName",
580
+ "ChatCompletionInputGrammarType",
581
+ "ChatCompletionInputJSONSchema",
582
+ "ChatCompletionInputMessage",
583
+ "ChatCompletionInputMessageChunk",
584
+ "ChatCompletionInputMessageChunkType",
585
+ "ChatCompletionInputResponseFormatJSONObject",
586
+ "ChatCompletionInputResponseFormatJSONSchema",
587
+ "ChatCompletionInputResponseFormatText",
588
+ "ChatCompletionInputStreamOptions",
589
+ "ChatCompletionInputTool",
590
+ "ChatCompletionInputToolCall",
591
+ "ChatCompletionInputToolChoiceClass",
592
+ "ChatCompletionInputToolChoiceEnum",
593
+ "ChatCompletionInputURL",
594
+ "ChatCompletionOutput",
595
+ "ChatCompletionOutputComplete",
596
+ "ChatCompletionOutputFunctionDefinition",
597
+ "ChatCompletionOutputLogprob",
598
+ "ChatCompletionOutputLogprobs",
599
+ "ChatCompletionOutputMessage",
600
+ "ChatCompletionOutputToolCall",
601
+ "ChatCompletionOutputTopLogprob",
602
+ "ChatCompletionOutputUsage",
603
+ "ChatCompletionStreamOutput",
604
+ "ChatCompletionStreamOutputChoice",
605
+ "ChatCompletionStreamOutputDelta",
606
+ "ChatCompletionStreamOutputDeltaToolCall",
607
+ "ChatCompletionStreamOutputFunction",
608
+ "ChatCompletionStreamOutputLogprob",
609
+ "ChatCompletionStreamOutputLogprobs",
610
+ "ChatCompletionStreamOutputTopLogprob",
611
+ "ChatCompletionStreamOutputUsage",
612
+ "Collection",
613
+ "CollectionItem",
614
+ "CommitInfo",
615
+ "CommitOperation",
616
+ "CommitOperationAdd",
617
+ "CommitOperationCopy",
618
+ "CommitOperationDelete",
619
+ "CommitScheduler",
620
+ "CorruptedCacheException",
621
+ "DDUFEntry",
622
+ "DatasetCard",
623
+ "DatasetCardData",
624
+ "DatasetInfo",
625
+ "DeleteCacheStrategy",
626
+ "DepthEstimationInput",
627
+ "DepthEstimationOutput",
628
+ "Discussion",
629
+ "DiscussionComment",
630
+ "DiscussionCommit",
631
+ "DiscussionEvent",
632
+ "DiscussionStatusChange",
633
+ "DiscussionTitleChange",
634
+ "DiscussionWithDetails",
635
+ "DocumentQuestionAnsweringInput",
636
+ "DocumentQuestionAnsweringInputData",
637
+ "DocumentQuestionAnsweringOutputElement",
638
+ "DocumentQuestionAnsweringParameters",
639
+ "DryRunFileInfo",
640
+ "EvalResult",
641
+ "FLAX_WEIGHTS_NAME",
642
+ "FeatureExtractionInput",
643
+ "FeatureExtractionInputTruncationDirection",
644
+ "FillMaskInput",
645
+ "FillMaskOutputElement",
646
+ "FillMaskParameters",
647
+ "GitCommitInfo",
648
+ "GitRefInfo",
649
+ "GitRefs",
650
+ "HFCacheInfo",
651
+ "HFSummaryWriter",
652
+ "HUGGINGFACE_CO_URL_HOME",
653
+ "HUGGINGFACE_CO_URL_TEMPLATE",
654
+ "HfApi",
655
+ "HfFileMetadata",
656
+ "HfFileSystem",
657
+ "HfFileSystemFile",
658
+ "HfFileSystemResolvedPath",
659
+ "HfFileSystemStreamFile",
660
+ "ImageClassificationInput",
661
+ "ImageClassificationOutputElement",
662
+ "ImageClassificationOutputTransform",
663
+ "ImageClassificationParameters",
664
+ "ImageSegmentationInput",
665
+ "ImageSegmentationOutputElement",
666
+ "ImageSegmentationParameters",
667
+ "ImageSegmentationSubtask",
668
+ "ImageToImageInput",
669
+ "ImageToImageOutput",
670
+ "ImageToImageParameters",
671
+ "ImageToImageTargetSize",
672
+ "ImageToTextEarlyStoppingEnum",
673
+ "ImageToTextGenerationParameters",
674
+ "ImageToTextInput",
675
+ "ImageToTextOutput",
676
+ "ImageToTextParameters",
677
+ "ImageToVideoInput",
678
+ "ImageToVideoOutput",
679
+ "ImageToVideoParameters",
680
+ "ImageToVideoTargetSize",
681
+ "InferenceClient",
682
+ "InferenceEndpoint",
683
+ "InferenceEndpointError",
684
+ "InferenceEndpointStatus",
685
+ "InferenceEndpointTimeoutError",
686
+ "InferenceEndpointType",
687
+ "InferenceTimeoutError",
688
+ "JobInfo",
689
+ "JobOwner",
690
+ "JobStage",
691
+ "JobStatus",
692
+ "MCPClient",
693
+ "ModelCard",
694
+ "ModelCardData",
695
+ "ModelHubMixin",
696
+ "ModelInfo",
697
+ "OAuthInfo",
698
+ "OAuthOrgInfo",
699
+ "OAuthUserInfo",
700
+ "ObjectDetectionBoundingBox",
701
+ "ObjectDetectionInput",
702
+ "ObjectDetectionOutputElement",
703
+ "ObjectDetectionParameters",
704
+ "Organization",
705
+ "PYTORCH_WEIGHTS_NAME",
706
+ "Padding",
707
+ "PyTorchModelHubMixin",
708
+ "QuestionAnsweringInput",
709
+ "QuestionAnsweringInputData",
710
+ "QuestionAnsweringOutputElement",
711
+ "QuestionAnsweringParameters",
712
+ "REPO_TYPE_DATASET",
713
+ "REPO_TYPE_MODEL",
714
+ "REPO_TYPE_SPACE",
715
+ "RepoCard",
716
+ "RepoFile",
717
+ "RepoFolder",
718
+ "RepoUrl",
719
+ "SentenceSimilarityInput",
720
+ "SentenceSimilarityInputData",
721
+ "SpaceCard",
722
+ "SpaceCardData",
723
+ "SpaceHardware",
724
+ "SpaceInfo",
725
+ "SpaceRuntime",
726
+ "SpaceStage",
727
+ "SpaceStorage",
728
+ "SpaceVariable",
729
+ "StateDictSplit",
730
+ "SummarizationInput",
731
+ "SummarizationOutput",
732
+ "SummarizationParameters",
733
+ "SummarizationTruncationStrategy",
734
+ "TF2_WEIGHTS_NAME",
735
+ "TF_WEIGHTS_NAME",
736
+ "TableQuestionAnsweringInput",
737
+ "TableQuestionAnsweringInputData",
738
+ "TableQuestionAnsweringOutputElement",
739
+ "TableQuestionAnsweringParameters",
740
+ "Text2TextGenerationInput",
741
+ "Text2TextGenerationOutput",
742
+ "Text2TextGenerationParameters",
743
+ "Text2TextGenerationTruncationStrategy",
744
+ "TextClassificationInput",
745
+ "TextClassificationOutputElement",
746
+ "TextClassificationOutputTransform",
747
+ "TextClassificationParameters",
748
+ "TextGenerationInput",
749
+ "TextGenerationInputGenerateParameters",
750
+ "TextGenerationInputGrammarType",
751
+ "TextGenerationOutput",
752
+ "TextGenerationOutputBestOfSequence",
753
+ "TextGenerationOutputDetails",
754
+ "TextGenerationOutputFinishReason",
755
+ "TextGenerationOutputPrefillToken",
756
+ "TextGenerationOutputToken",
757
+ "TextGenerationStreamOutput",
758
+ "TextGenerationStreamOutputStreamDetails",
759
+ "TextGenerationStreamOutputToken",
760
+ "TextToAudioEarlyStoppingEnum",
761
+ "TextToAudioGenerationParameters",
762
+ "TextToAudioInput",
763
+ "TextToAudioOutput",
764
+ "TextToAudioParameters",
765
+ "TextToImageInput",
766
+ "TextToImageOutput",
767
+ "TextToImageParameters",
768
+ "TextToSpeechEarlyStoppingEnum",
769
+ "TextToSpeechGenerationParameters",
770
+ "TextToSpeechInput",
771
+ "TextToSpeechOutput",
772
+ "TextToSpeechParameters",
773
+ "TextToVideoInput",
774
+ "TextToVideoOutput",
775
+ "TextToVideoParameters",
776
+ "TokenClassificationAggregationStrategy",
777
+ "TokenClassificationInput",
778
+ "TokenClassificationOutputElement",
779
+ "TokenClassificationParameters",
780
+ "TranslationInput",
781
+ "TranslationOutput",
782
+ "TranslationParameters",
783
+ "TranslationTruncationStrategy",
784
+ "TypeEnum",
785
+ "User",
786
+ "UserLikes",
787
+ "VideoClassificationInput",
788
+ "VideoClassificationOutputElement",
789
+ "VideoClassificationOutputTransform",
790
+ "VideoClassificationParameters",
791
+ "VisualQuestionAnsweringInput",
792
+ "VisualQuestionAnsweringInputData",
793
+ "VisualQuestionAnsweringOutputElement",
794
+ "VisualQuestionAnsweringParameters",
795
+ "WebhookInfo",
796
+ "WebhookPayload",
797
+ "WebhookPayloadComment",
798
+ "WebhookPayloadDiscussion",
799
+ "WebhookPayloadDiscussionChanges",
800
+ "WebhookPayloadEvent",
801
+ "WebhookPayloadMovedTo",
802
+ "WebhookPayloadRepo",
803
+ "WebhookPayloadUrl",
804
+ "WebhookPayloadWebhook",
805
+ "WebhookWatchedItem",
806
+ "WebhooksServer",
807
+ "ZeroShotClassificationInput",
808
+ "ZeroShotClassificationOutputElement",
809
+ "ZeroShotClassificationParameters",
810
+ "ZeroShotImageClassificationInput",
811
+ "ZeroShotImageClassificationOutputElement",
812
+ "ZeroShotImageClassificationParameters",
813
+ "ZeroShotObjectDetectionBoundingBox",
814
+ "ZeroShotObjectDetectionInput",
815
+ "ZeroShotObjectDetectionOutputElement",
816
+ "ZeroShotObjectDetectionParameters",
817
+ "_CACHED_NO_EXIST",
818
+ "_save_pretrained_fastai",
819
+ "accept_access_request",
820
+ "add_collection_item",
821
+ "add_space_secret",
822
+ "add_space_variable",
823
+ "attach_huggingface_oauth",
824
+ "auth_check",
825
+ "auth_list",
826
+ "auth_switch",
827
+ "cached_assets_path",
828
+ "cancel_access_request",
829
+ "cancel_job",
830
+ "change_discussion_status",
831
+ "close_session",
832
+ "comment_discussion",
833
+ "create_branch",
834
+ "create_collection",
835
+ "create_commit",
836
+ "create_discussion",
837
+ "create_inference_endpoint",
838
+ "create_inference_endpoint_from_catalog",
839
+ "create_pull_request",
840
+ "create_repo",
841
+ "create_scheduled_job",
842
+ "create_scheduled_uv_job",
843
+ "create_tag",
844
+ "create_webhook",
845
+ "dataset_info",
846
+ "delete_branch",
847
+ "delete_collection",
848
+ "delete_collection_item",
849
+ "delete_file",
850
+ "delete_folder",
851
+ "delete_inference_endpoint",
852
+ "delete_repo",
853
+ "delete_scheduled_job",
854
+ "delete_space_secret",
855
+ "delete_space_storage",
856
+ "delete_space_variable",
857
+ "delete_tag",
858
+ "delete_webhook",
859
+ "disable_webhook",
860
+ "dump_environment_info",
861
+ "duplicate_space",
862
+ "edit_discussion_comment",
863
+ "enable_webhook",
864
+ "export_entries_as_dduf",
865
+ "export_folder_as_dduf",
866
+ "fetch_job_logs",
867
+ "file_exists",
868
+ "from_pretrained_fastai",
869
+ "get_async_session",
870
+ "get_collection",
871
+ "get_dataset_tags",
872
+ "get_discussion_details",
873
+ "get_full_repo_name",
874
+ "get_hf_file_metadata",
875
+ "get_inference_endpoint",
876
+ "get_model_tags",
877
+ "get_organization_overview",
878
+ "get_paths_info",
879
+ "get_repo_discussions",
880
+ "get_safetensors_metadata",
881
+ "get_session",
882
+ "get_space_runtime",
883
+ "get_space_variables",
884
+ "get_token",
885
+ "get_torch_storage_id",
886
+ "get_torch_storage_size",
887
+ "get_user_overview",
888
+ "get_webhook",
889
+ "grant_access",
890
+ "hf_hub_download",
891
+ "hf_hub_url",
892
+ "hf_raise_for_status",
893
+ "hffs",
894
+ "inspect_job",
895
+ "inspect_scheduled_job",
896
+ "interpreter_login",
897
+ "is_offline_mode",
898
+ "list_accepted_access_requests",
899
+ "list_collections",
900
+ "list_daily_papers",
901
+ "list_datasets",
902
+ "list_inference_catalog",
903
+ "list_inference_endpoints",
904
+ "list_jobs",
905
+ "list_lfs_files",
906
+ "list_liked_repos",
907
+ "list_models",
908
+ "list_organization_followers",
909
+ "list_organization_members",
910
+ "list_papers",
911
+ "list_pending_access_requests",
912
+ "list_rejected_access_requests",
913
+ "list_repo_commits",
914
+ "list_repo_files",
915
+ "list_repo_likers",
916
+ "list_repo_refs",
917
+ "list_repo_tree",
918
+ "list_spaces",
919
+ "list_user_followers",
920
+ "list_user_following",
921
+ "list_webhooks",
922
+ "load_state_dict_from_file",
923
+ "load_torch_model",
924
+ "logging",
925
+ "login",
926
+ "logout",
927
+ "merge_pull_request",
928
+ "metadata_eval_result",
929
+ "metadata_load",
930
+ "metadata_save",
931
+ "metadata_update",
932
+ "model_info",
933
+ "move_repo",
934
+ "notebook_login",
935
+ "paper_info",
936
+ "parse_huggingface_oauth",
937
+ "parse_safetensors_file_metadata",
938
+ "pause_inference_endpoint",
939
+ "pause_space",
940
+ "permanently_delete_lfs_files",
941
+ "preupload_lfs_files",
942
+ "push_to_hub_fastai",
943
+ "read_dduf_file",
944
+ "reject_access_request",
945
+ "rename_discussion",
946
+ "repo_exists",
947
+ "repo_info",
948
+ "repo_type_and_id_from_hf_id",
949
+ "request_space_hardware",
950
+ "request_space_storage",
951
+ "restart_space",
952
+ "resume_inference_endpoint",
953
+ "resume_scheduled_job",
954
+ "revision_exists",
955
+ "run_as_future",
956
+ "run_job",
957
+ "run_uv_job",
958
+ "save_torch_model",
959
+ "save_torch_state_dict",
960
+ "scale_to_zero_inference_endpoint",
961
+ "scan_cache_dir",
962
+ "set_async_client_factory",
963
+ "set_client_factory",
964
+ "set_space_sleep_time",
965
+ "snapshot_download",
966
+ "space_info",
967
+ "split_state_dict_into_shards_factory",
968
+ "split_torch_state_dict_into_shards",
969
+ "super_squash_history",
970
+ "suspend_scheduled_job",
971
+ "try_to_load_from_cache",
972
+ "typer_factory",
973
+ "unlike",
974
+ "update_collection_item",
975
+ "update_collection_metadata",
976
+ "update_inference_endpoint",
977
+ "update_repo_settings",
978
+ "update_webhook",
979
+ "upload_file",
980
+ "upload_folder",
981
+ "upload_large_folder",
982
+ "verify_repo_checksums",
983
+ "webhook_endpoint",
984
+ "whoami",
985
+ ]
986
+
987
+
988
+ def _attach(package_name, submodules=None, submod_attrs=None):
989
+ """Attach lazily loaded submodules, functions, or other attributes.
990
+
991
+ Typically, modules import submodules and attributes as follows:
992
+
993
+ ```py
994
+ import mysubmodule
995
+ import anothersubmodule
996
+
997
+ from .foo import someattr
998
+ ```
999
+
1000
+ The idea is to replace a package's `__getattr__`, `__dir__`, such that all imports
1001
+ work exactly the way they would with normal imports, except that the import occurs
1002
+ upon first use.
1003
+
1004
+ The typical way to call this function, replacing the above imports, is:
1005
+
1006
+ ```python
1007
+ __getattr__, __dir__ = lazy.attach(
1008
+ __name__,
1009
+ ['mysubmodule', 'anothersubmodule'],
1010
+ {'foo': ['someattr']}
1011
+ )
1012
+ ```
1013
+ This functionality requires Python 3.7 or higher.
1014
+
1015
+ Args:
1016
+ package_name (`str`):
1017
+ Typically use `__name__`.
1018
+ submodules (`set`):
1019
+ List of submodules to attach.
1020
+ submod_attrs (`dict`):
1021
+ Dictionary of submodule -> list of attributes / functions.
1022
+ These attributes are imported as they are used.
1023
+
1024
+ Returns:
1025
+ __getattr__, __dir__, __all__
1026
+
1027
+ """
1028
+ if submod_attrs is None:
1029
+ submod_attrs = {}
1030
+
1031
+ if submodules is None:
1032
+ submodules = set()
1033
+ else:
1034
+ submodules = set(submodules)
1035
+
1036
+ attr_to_modules = {attr: mod for mod, attrs in submod_attrs.items() for attr in attrs}
1037
+
1038
+ def __getattr__(name):
1039
+ if name in submodules:
1040
+ try:
1041
+ return importlib.import_module(f"{package_name}.{name}")
1042
+ except Exception as e:
1043
+ print(f"Error importing {package_name}.{name}: {e}")
1044
+ raise
1045
+ elif name in attr_to_modules:
1046
+ submod_path = f"{package_name}.{attr_to_modules[name]}"
1047
+ try:
1048
+ submod = importlib.import_module(submod_path)
1049
+ except Exception as e:
1050
+ print(f"Error importing {submod_path}: {e}")
1051
+ raise
1052
+ attr = getattr(submod, name)
1053
+
1054
+ # If the attribute lives in a file (module) with the same
1055
+ # name as the attribute, ensure that the attribute and *not*
1056
+ # the module is accessible on the package.
1057
+ if name == attr_to_modules[name]:
1058
+ pkg = sys.modules[package_name]
1059
+ pkg.__dict__[name] = attr
1060
+
1061
+ return attr
1062
+ else:
1063
+ raise AttributeError(f"No {package_name} attribute {name}")
1064
+
1065
+ def __dir__():
1066
+ return __all__
1067
+
1068
+ return __getattr__, __dir__
1069
+
1070
+
1071
+ __getattr__, __dir__ = _attach(__name__, submodules=[], submod_attrs=_SUBMOD_ATTRS)
1072
+
1073
+ if os.environ.get("EAGER_IMPORT", ""):
1074
+ for attr in __all__:
1075
+ __getattr__(attr)
1076
+
1077
+ # WARNING: any content below this statement is generated automatically. Any manual edit
1078
+ # will be lost when re-generating this file !
1079
+ #
1080
+ # To update the static imports, please run the following command and commit the changes.
1081
+ # ```
1082
+ # # Use script
1083
+ # python utils/check_static_imports.py --update
1084
+ #
1085
+ # # Or run style on codebase
1086
+ # make style
1087
+ # ```
1088
+ if TYPE_CHECKING: # pragma: no cover
1089
+ from ._commit_scheduler import CommitScheduler # noqa: F401
1090
+ from ._inference_endpoints import (
1091
+ InferenceEndpoint, # noqa: F401
1092
+ InferenceEndpointError, # noqa: F401
1093
+ InferenceEndpointStatus, # noqa: F401
1094
+ InferenceEndpointTimeoutError, # noqa: F401
1095
+ InferenceEndpointType, # noqa: F401
1096
+ )
1097
+ from ._jobs_api import (
1098
+ JobInfo, # noqa: F401
1099
+ JobOwner, # noqa: F401
1100
+ JobStage, # noqa: F401
1101
+ JobStatus, # noqa: F401
1102
+ )
1103
+ from ._login import (
1104
+ auth_list, # noqa: F401
1105
+ auth_switch, # noqa: F401
1106
+ interpreter_login, # noqa: F401
1107
+ login, # noqa: F401
1108
+ logout, # noqa: F401
1109
+ notebook_login, # noqa: F401
1110
+ )
1111
+ from ._oauth import (
1112
+ OAuthInfo, # noqa: F401
1113
+ OAuthOrgInfo, # noqa: F401
1114
+ OAuthUserInfo, # noqa: F401
1115
+ attach_huggingface_oauth, # noqa: F401
1116
+ parse_huggingface_oauth, # noqa: F401
1117
+ )
1118
+ from ._snapshot_download import snapshot_download # noqa: F401
1119
+ from ._space_api import (
1120
+ SpaceHardware, # noqa: F401
1121
+ SpaceRuntime, # noqa: F401
1122
+ SpaceStage, # noqa: F401
1123
+ SpaceStorage, # noqa: F401
1124
+ SpaceVariable, # noqa: F401
1125
+ )
1126
+ from ._tensorboard_logger import HFSummaryWriter # noqa: F401
1127
+ from ._webhooks_payload import (
1128
+ WebhookPayload, # noqa: F401
1129
+ WebhookPayloadComment, # noqa: F401
1130
+ WebhookPayloadDiscussion, # noqa: F401
1131
+ WebhookPayloadDiscussionChanges, # noqa: F401
1132
+ WebhookPayloadEvent, # noqa: F401
1133
+ WebhookPayloadMovedTo, # noqa: F401
1134
+ WebhookPayloadRepo, # noqa: F401
1135
+ WebhookPayloadUrl, # noqa: F401
1136
+ WebhookPayloadWebhook, # noqa: F401
1137
+ )
1138
+ from ._webhooks_server import (
1139
+ WebhooksServer, # noqa: F401
1140
+ webhook_endpoint, # noqa: F401
1141
+ )
1142
+ from .cli._cli_utils import typer_factory # noqa: F401
1143
+ from .community import (
1144
+ Discussion, # noqa: F401
1145
+ DiscussionComment, # noqa: F401
1146
+ DiscussionCommit, # noqa: F401
1147
+ DiscussionEvent, # noqa: F401
1148
+ DiscussionStatusChange, # noqa: F401
1149
+ DiscussionTitleChange, # noqa: F401
1150
+ DiscussionWithDetails, # noqa: F401
1151
+ )
1152
+ from .constants import (
1153
+ CONFIG_NAME, # noqa: F401
1154
+ FLAX_WEIGHTS_NAME, # noqa: F401
1155
+ HUGGINGFACE_CO_URL_HOME, # noqa: F401
1156
+ HUGGINGFACE_CO_URL_TEMPLATE, # noqa: F401
1157
+ PYTORCH_WEIGHTS_NAME, # noqa: F401
1158
+ REPO_TYPE_DATASET, # noqa: F401
1159
+ REPO_TYPE_MODEL, # noqa: F401
1160
+ REPO_TYPE_SPACE, # noqa: F401
1161
+ TF2_WEIGHTS_NAME, # noqa: F401
1162
+ TF_WEIGHTS_NAME, # noqa: F401
1163
+ is_offline_mode, # noqa: F401
1164
+ )
1165
+ from .fastai_utils import (
1166
+ _save_pretrained_fastai, # noqa: F401
1167
+ from_pretrained_fastai, # noqa: F401
1168
+ push_to_hub_fastai, # noqa: F401
1169
+ )
1170
+ from .file_download import (
1171
+ _CACHED_NO_EXIST, # noqa: F401
1172
+ DryRunFileInfo, # noqa: F401
1173
+ HfFileMetadata, # noqa: F401
1174
+ get_hf_file_metadata, # noqa: F401
1175
+ hf_hub_download, # noqa: F401
1176
+ hf_hub_url, # noqa: F401
1177
+ try_to_load_from_cache, # noqa: F401
1178
+ )
1179
+ from .hf_api import (
1180
+ Collection, # noqa: F401
1181
+ CollectionItem, # noqa: F401
1182
+ CommitInfo, # noqa: F401
1183
+ CommitOperation, # noqa: F401
1184
+ CommitOperationAdd, # noqa: F401
1185
+ CommitOperationCopy, # noqa: F401
1186
+ CommitOperationDelete, # noqa: F401
1187
+ DatasetInfo, # noqa: F401
1188
+ GitCommitInfo, # noqa: F401
1189
+ GitRefInfo, # noqa: F401
1190
+ GitRefs, # noqa: F401
1191
+ HfApi, # noqa: F401
1192
+ ModelInfo, # noqa: F401
1193
+ Organization, # noqa: F401
1194
+ RepoFile, # noqa: F401
1195
+ RepoFolder, # noqa: F401
1196
+ RepoUrl, # noqa: F401
1197
+ SpaceInfo, # noqa: F401
1198
+ User, # noqa: F401
1199
+ UserLikes, # noqa: F401
1200
+ WebhookInfo, # noqa: F401
1201
+ WebhookWatchedItem, # noqa: F401
1202
+ accept_access_request, # noqa: F401
1203
+ add_collection_item, # noqa: F401
1204
+ add_space_secret, # noqa: F401
1205
+ add_space_variable, # noqa: F401
1206
+ auth_check, # noqa: F401
1207
+ cancel_access_request, # noqa: F401
1208
+ cancel_job, # noqa: F401
1209
+ change_discussion_status, # noqa: F401
1210
+ comment_discussion, # noqa: F401
1211
+ create_branch, # noqa: F401
1212
+ create_collection, # noqa: F401
1213
+ create_commit, # noqa: F401
1214
+ create_discussion, # noqa: F401
1215
+ create_inference_endpoint, # noqa: F401
1216
+ create_inference_endpoint_from_catalog, # noqa: F401
1217
+ create_pull_request, # noqa: F401
1218
+ create_repo, # noqa: F401
1219
+ create_scheduled_job, # noqa: F401
1220
+ create_scheduled_uv_job, # noqa: F401
1221
+ create_tag, # noqa: F401
1222
+ create_webhook, # noqa: F401
1223
+ dataset_info, # noqa: F401
1224
+ delete_branch, # noqa: F401
1225
+ delete_collection, # noqa: F401
1226
+ delete_collection_item, # noqa: F401
1227
+ delete_file, # noqa: F401
1228
+ delete_folder, # noqa: F401
1229
+ delete_inference_endpoint, # noqa: F401
1230
+ delete_repo, # noqa: F401
1231
+ delete_scheduled_job, # noqa: F401
1232
+ delete_space_secret, # noqa: F401
1233
+ delete_space_storage, # noqa: F401
1234
+ delete_space_variable, # noqa: F401
1235
+ delete_tag, # noqa: F401
1236
+ delete_webhook, # noqa: F401
1237
+ disable_webhook, # noqa: F401
1238
+ duplicate_space, # noqa: F401
1239
+ edit_discussion_comment, # noqa: F401
1240
+ enable_webhook, # noqa: F401
1241
+ fetch_job_logs, # noqa: F401
1242
+ file_exists, # noqa: F401
1243
+ get_collection, # noqa: F401
1244
+ get_dataset_tags, # noqa: F401
1245
+ get_discussion_details, # noqa: F401
1246
+ get_full_repo_name, # noqa: F401
1247
+ get_inference_endpoint, # noqa: F401
1248
+ get_model_tags, # noqa: F401
1249
+ get_organization_overview, # noqa: F401
1250
+ get_paths_info, # noqa: F401
1251
+ get_repo_discussions, # noqa: F401
1252
+ get_safetensors_metadata, # noqa: F401
1253
+ get_space_runtime, # noqa: F401
1254
+ get_space_variables, # noqa: F401
1255
+ get_user_overview, # noqa: F401
1256
+ get_webhook, # noqa: F401
1257
+ grant_access, # noqa: F401
1258
+ inspect_job, # noqa: F401
1259
+ inspect_scheduled_job, # noqa: F401
1260
+ list_accepted_access_requests, # noqa: F401
1261
+ list_collections, # noqa: F401
1262
+ list_daily_papers, # noqa: F401
1263
+ list_datasets, # noqa: F401
1264
+ list_inference_catalog, # noqa: F401
1265
+ list_inference_endpoints, # noqa: F401
1266
+ list_jobs, # noqa: F401
1267
+ list_lfs_files, # noqa: F401
1268
+ list_liked_repos, # noqa: F401
1269
+ list_models, # noqa: F401
1270
+ list_organization_followers, # noqa: F401
1271
+ list_organization_members, # noqa: F401
1272
+ list_papers, # noqa: F401
1273
+ list_pending_access_requests, # noqa: F401
1274
+ list_rejected_access_requests, # noqa: F401
1275
+ list_repo_commits, # noqa: F401
1276
+ list_repo_files, # noqa: F401
1277
+ list_repo_likers, # noqa: F401
1278
+ list_repo_refs, # noqa: F401
1279
+ list_repo_tree, # noqa: F401
1280
+ list_spaces, # noqa: F401
1281
+ list_user_followers, # noqa: F401
1282
+ list_user_following, # noqa: F401
1283
+ list_webhooks, # noqa: F401
1284
+ merge_pull_request, # noqa: F401
1285
+ model_info, # noqa: F401
1286
+ move_repo, # noqa: F401
1287
+ paper_info, # noqa: F401
1288
+ parse_safetensors_file_metadata, # noqa: F401
1289
+ pause_inference_endpoint, # noqa: F401
1290
+ pause_space, # noqa: F401
1291
+ permanently_delete_lfs_files, # noqa: F401
1292
+ preupload_lfs_files, # noqa: F401
1293
+ reject_access_request, # noqa: F401
1294
+ rename_discussion, # noqa: F401
1295
+ repo_exists, # noqa: F401
1296
+ repo_info, # noqa: F401
1297
+ repo_type_and_id_from_hf_id, # noqa: F401
1298
+ request_space_hardware, # noqa: F401
1299
+ request_space_storage, # noqa: F401
1300
+ restart_space, # noqa: F401
1301
+ resume_inference_endpoint, # noqa: F401
1302
+ resume_scheduled_job, # noqa: F401
1303
+ revision_exists, # noqa: F401
1304
+ run_as_future, # noqa: F401
1305
+ run_job, # noqa: F401
1306
+ run_uv_job, # noqa: F401
1307
+ scale_to_zero_inference_endpoint, # noqa: F401
1308
+ set_space_sleep_time, # noqa: F401
1309
+ space_info, # noqa: F401
1310
+ super_squash_history, # noqa: F401
1311
+ suspend_scheduled_job, # noqa: F401
1312
+ unlike, # noqa: F401
1313
+ update_collection_item, # noqa: F401
1314
+ update_collection_metadata, # noqa: F401
1315
+ update_inference_endpoint, # noqa: F401
1316
+ update_repo_settings, # noqa: F401
1317
+ update_webhook, # noqa: F401
1318
+ upload_file, # noqa: F401
1319
+ upload_folder, # noqa: F401
1320
+ upload_large_folder, # noqa: F401
1321
+ verify_repo_checksums, # noqa: F401
1322
+ whoami, # noqa: F401
1323
+ )
1324
+ from .hf_file_system import (
1325
+ HfFileSystem, # noqa: F401
1326
+ HfFileSystemFile, # noqa: F401
1327
+ HfFileSystemResolvedPath, # noqa: F401
1328
+ HfFileSystemStreamFile, # noqa: F401
1329
+ hffs, # noqa: F401
1330
+ )
1331
+ from .hub_mixin import (
1332
+ ModelHubMixin, # noqa: F401
1333
+ PyTorchModelHubMixin, # noqa: F401
1334
+ )
1335
+ from .inference._client import (
1336
+ InferenceClient, # noqa: F401
1337
+ InferenceTimeoutError, # noqa: F401
1338
+ )
1339
+ from .inference._generated._async_client import AsyncInferenceClient # noqa: F401
1340
+ from .inference._generated.types import (
1341
+ AudioClassificationInput, # noqa: F401
1342
+ AudioClassificationOutputElement, # noqa: F401
1343
+ AudioClassificationOutputTransform, # noqa: F401
1344
+ AudioClassificationParameters, # noqa: F401
1345
+ AudioToAudioInput, # noqa: F401
1346
+ AudioToAudioOutputElement, # noqa: F401
1347
+ AutomaticSpeechRecognitionEarlyStoppingEnum, # noqa: F401
1348
+ AutomaticSpeechRecognitionGenerationParameters, # noqa: F401
1349
+ AutomaticSpeechRecognitionInput, # noqa: F401
1350
+ AutomaticSpeechRecognitionOutput, # noqa: F401
1351
+ AutomaticSpeechRecognitionOutputChunk, # noqa: F401
1352
+ AutomaticSpeechRecognitionParameters, # noqa: F401
1353
+ ChatCompletionInput, # noqa: F401
1354
+ ChatCompletionInputFunctionDefinition, # noqa: F401
1355
+ ChatCompletionInputFunctionName, # noqa: F401
1356
+ ChatCompletionInputGrammarType, # noqa: F401
1357
+ ChatCompletionInputJSONSchema, # noqa: F401
1358
+ ChatCompletionInputMessage, # noqa: F401
1359
+ ChatCompletionInputMessageChunk, # noqa: F401
1360
+ ChatCompletionInputMessageChunkType, # noqa: F401
1361
+ ChatCompletionInputResponseFormatJSONObject, # noqa: F401
1362
+ ChatCompletionInputResponseFormatJSONSchema, # noqa: F401
1363
+ ChatCompletionInputResponseFormatText, # noqa: F401
1364
+ ChatCompletionInputStreamOptions, # noqa: F401
1365
+ ChatCompletionInputTool, # noqa: F401
1366
+ ChatCompletionInputToolCall, # noqa: F401
1367
+ ChatCompletionInputToolChoiceClass, # noqa: F401
1368
+ ChatCompletionInputToolChoiceEnum, # noqa: F401
1369
+ ChatCompletionInputURL, # noqa: F401
1370
+ ChatCompletionOutput, # noqa: F401
1371
+ ChatCompletionOutputComplete, # noqa: F401
1372
+ ChatCompletionOutputFunctionDefinition, # noqa: F401
1373
+ ChatCompletionOutputLogprob, # noqa: F401
1374
+ ChatCompletionOutputLogprobs, # noqa: F401
1375
+ ChatCompletionOutputMessage, # noqa: F401
1376
+ ChatCompletionOutputToolCall, # noqa: F401
1377
+ ChatCompletionOutputTopLogprob, # noqa: F401
1378
+ ChatCompletionOutputUsage, # noqa: F401
1379
+ ChatCompletionStreamOutput, # noqa: F401
1380
+ ChatCompletionStreamOutputChoice, # noqa: F401
1381
+ ChatCompletionStreamOutputDelta, # noqa: F401
1382
+ ChatCompletionStreamOutputDeltaToolCall, # noqa: F401
1383
+ ChatCompletionStreamOutputFunction, # noqa: F401
1384
+ ChatCompletionStreamOutputLogprob, # noqa: F401
1385
+ ChatCompletionStreamOutputLogprobs, # noqa: F401
1386
+ ChatCompletionStreamOutputTopLogprob, # noqa: F401
1387
+ ChatCompletionStreamOutputUsage, # noqa: F401
1388
+ DepthEstimationInput, # noqa: F401
1389
+ DepthEstimationOutput, # noqa: F401
1390
+ DocumentQuestionAnsweringInput, # noqa: F401
1391
+ DocumentQuestionAnsweringInputData, # noqa: F401
1392
+ DocumentQuestionAnsweringOutputElement, # noqa: F401
1393
+ DocumentQuestionAnsweringParameters, # noqa: F401
1394
+ FeatureExtractionInput, # noqa: F401
1395
+ FeatureExtractionInputTruncationDirection, # noqa: F401
1396
+ FillMaskInput, # noqa: F401
1397
+ FillMaskOutputElement, # noqa: F401
1398
+ FillMaskParameters, # noqa: F401
1399
+ ImageClassificationInput, # noqa: F401
1400
+ ImageClassificationOutputElement, # noqa: F401
1401
+ ImageClassificationOutputTransform, # noqa: F401
1402
+ ImageClassificationParameters, # noqa: F401
1403
+ ImageSegmentationInput, # noqa: F401
1404
+ ImageSegmentationOutputElement, # noqa: F401
1405
+ ImageSegmentationParameters, # noqa: F401
1406
+ ImageSegmentationSubtask, # noqa: F401
1407
+ ImageToImageInput, # noqa: F401
1408
+ ImageToImageOutput, # noqa: F401
1409
+ ImageToImageParameters, # noqa: F401
1410
+ ImageToImageTargetSize, # noqa: F401
1411
+ ImageToTextEarlyStoppingEnum, # noqa: F401
1412
+ ImageToTextGenerationParameters, # noqa: F401
1413
+ ImageToTextInput, # noqa: F401
1414
+ ImageToTextOutput, # noqa: F401
1415
+ ImageToTextParameters, # noqa: F401
1416
+ ImageToVideoInput, # noqa: F401
1417
+ ImageToVideoOutput, # noqa: F401
1418
+ ImageToVideoParameters, # noqa: F401
1419
+ ImageToVideoTargetSize, # noqa: F401
1420
+ ObjectDetectionBoundingBox, # noqa: F401
1421
+ ObjectDetectionInput, # noqa: F401
1422
+ ObjectDetectionOutputElement, # noqa: F401
1423
+ ObjectDetectionParameters, # noqa: F401
1424
+ Padding, # noqa: F401
1425
+ QuestionAnsweringInput, # noqa: F401
1426
+ QuestionAnsweringInputData, # noqa: F401
1427
+ QuestionAnsweringOutputElement, # noqa: F401
1428
+ QuestionAnsweringParameters, # noqa: F401
1429
+ SentenceSimilarityInput, # noqa: F401
1430
+ SentenceSimilarityInputData, # noqa: F401
1431
+ SummarizationInput, # noqa: F401
1432
+ SummarizationOutput, # noqa: F401
1433
+ SummarizationParameters, # noqa: F401
1434
+ SummarizationTruncationStrategy, # noqa: F401
1435
+ TableQuestionAnsweringInput, # noqa: F401
1436
+ TableQuestionAnsweringInputData, # noqa: F401
1437
+ TableQuestionAnsweringOutputElement, # noqa: F401
1438
+ TableQuestionAnsweringParameters, # noqa: F401
1439
+ Text2TextGenerationInput, # noqa: F401
1440
+ Text2TextGenerationOutput, # noqa: F401
1441
+ Text2TextGenerationParameters, # noqa: F401
1442
+ Text2TextGenerationTruncationStrategy, # noqa: F401
1443
+ TextClassificationInput, # noqa: F401
1444
+ TextClassificationOutputElement, # noqa: F401
1445
+ TextClassificationOutputTransform, # noqa: F401
1446
+ TextClassificationParameters, # noqa: F401
1447
+ TextGenerationInput, # noqa: F401
1448
+ TextGenerationInputGenerateParameters, # noqa: F401
1449
+ TextGenerationInputGrammarType, # noqa: F401
1450
+ TextGenerationOutput, # noqa: F401
1451
+ TextGenerationOutputBestOfSequence, # noqa: F401
1452
+ TextGenerationOutputDetails, # noqa: F401
1453
+ TextGenerationOutputFinishReason, # noqa: F401
1454
+ TextGenerationOutputPrefillToken, # noqa: F401
1455
+ TextGenerationOutputToken, # noqa: F401
1456
+ TextGenerationStreamOutput, # noqa: F401
1457
+ TextGenerationStreamOutputStreamDetails, # noqa: F401
1458
+ TextGenerationStreamOutputToken, # noqa: F401
1459
+ TextToAudioEarlyStoppingEnum, # noqa: F401
1460
+ TextToAudioGenerationParameters, # noqa: F401
1461
+ TextToAudioInput, # noqa: F401
1462
+ TextToAudioOutput, # noqa: F401
1463
+ TextToAudioParameters, # noqa: F401
1464
+ TextToImageInput, # noqa: F401
1465
+ TextToImageOutput, # noqa: F401
1466
+ TextToImageParameters, # noqa: F401
1467
+ TextToSpeechEarlyStoppingEnum, # noqa: F401
1468
+ TextToSpeechGenerationParameters, # noqa: F401
1469
+ TextToSpeechInput, # noqa: F401
1470
+ TextToSpeechOutput, # noqa: F401
1471
+ TextToSpeechParameters, # noqa: F401
1472
+ TextToVideoInput, # noqa: F401
1473
+ TextToVideoOutput, # noqa: F401
1474
+ TextToVideoParameters, # noqa: F401
1475
+ TokenClassificationAggregationStrategy, # noqa: F401
1476
+ TokenClassificationInput, # noqa: F401
1477
+ TokenClassificationOutputElement, # noqa: F401
1478
+ TokenClassificationParameters, # noqa: F401
1479
+ TranslationInput, # noqa: F401
1480
+ TranslationOutput, # noqa: F401
1481
+ TranslationParameters, # noqa: F401
1482
+ TranslationTruncationStrategy, # noqa: F401
1483
+ TypeEnum, # noqa: F401
1484
+ VideoClassificationInput, # noqa: F401
1485
+ VideoClassificationOutputElement, # noqa: F401
1486
+ VideoClassificationOutputTransform, # noqa: F401
1487
+ VideoClassificationParameters, # noqa: F401
1488
+ VisualQuestionAnsweringInput, # noqa: F401
1489
+ VisualQuestionAnsweringInputData, # noqa: F401
1490
+ VisualQuestionAnsweringOutputElement, # noqa: F401
1491
+ VisualQuestionAnsweringParameters, # noqa: F401
1492
+ ZeroShotClassificationInput, # noqa: F401
1493
+ ZeroShotClassificationOutputElement, # noqa: F401
1494
+ ZeroShotClassificationParameters, # noqa: F401
1495
+ ZeroShotImageClassificationInput, # noqa: F401
1496
+ ZeroShotImageClassificationOutputElement, # noqa: F401
1497
+ ZeroShotImageClassificationParameters, # noqa: F401
1498
+ ZeroShotObjectDetectionBoundingBox, # noqa: F401
1499
+ ZeroShotObjectDetectionInput, # noqa: F401
1500
+ ZeroShotObjectDetectionOutputElement, # noqa: F401
1501
+ ZeroShotObjectDetectionParameters, # noqa: F401
1502
+ )
1503
+ from .inference._mcp.agent import Agent # noqa: F401
1504
+ from .inference._mcp.mcp_client import MCPClient # noqa: F401
1505
+ from .repocard import (
1506
+ DatasetCard, # noqa: F401
1507
+ ModelCard, # noqa: F401
1508
+ RepoCard, # noqa: F401
1509
+ SpaceCard, # noqa: F401
1510
+ metadata_eval_result, # noqa: F401
1511
+ metadata_load, # noqa: F401
1512
+ metadata_save, # noqa: F401
1513
+ metadata_update, # noqa: F401
1514
+ )
1515
+ from .repocard_data import (
1516
+ CardData, # noqa: F401
1517
+ DatasetCardData, # noqa: F401
1518
+ EvalResult, # noqa: F401
1519
+ ModelCardData, # noqa: F401
1520
+ SpaceCardData, # noqa: F401
1521
+ )
1522
+ from .serialization import (
1523
+ StateDictSplit, # noqa: F401
1524
+ get_torch_storage_id, # noqa: F401
1525
+ get_torch_storage_size, # noqa: F401
1526
+ load_state_dict_from_file, # noqa: F401
1527
+ load_torch_model, # noqa: F401
1528
+ save_torch_model, # noqa: F401
1529
+ save_torch_state_dict, # noqa: F401
1530
+ split_state_dict_into_shards_factory, # noqa: F401
1531
+ split_torch_state_dict_into_shards, # noqa: F401
1532
+ )
1533
+ from .serialization._dduf import (
1534
+ DDUFEntry, # noqa: F401
1535
+ export_entries_as_dduf, # noqa: F401
1536
+ export_folder_as_dduf, # noqa: F401
1537
+ read_dduf_file, # noqa: F401
1538
+ )
1539
+ from .utils import (
1540
+ ASYNC_CLIENT_FACTORY_T, # noqa: F401
1541
+ CLIENT_FACTORY_T, # noqa: F401
1542
+ CachedFileInfo, # noqa: F401
1543
+ CachedRepoInfo, # noqa: F401
1544
+ CachedRevisionInfo, # noqa: F401
1545
+ CacheNotFound, # noqa: F401
1546
+ CorruptedCacheException, # noqa: F401
1547
+ DeleteCacheStrategy, # noqa: F401
1548
+ HFCacheInfo, # noqa: F401
1549
+ cached_assets_path, # noqa: F401
1550
+ close_session, # noqa: F401
1551
+ dump_environment_info, # noqa: F401
1552
+ get_async_session, # noqa: F401
1553
+ get_session, # noqa: F401
1554
+ get_token, # noqa: F401
1555
+ hf_raise_for_status, # noqa: F401
1556
+ logging, # noqa: F401
1557
+ scan_cache_dir, # noqa: F401
1558
+ set_async_client_factory, # noqa: F401
1559
+ set_client_factory, # noqa: F401
1560
+ )
env/lib/python3.13/site-packages/huggingface_hub/_commit_api.py ADDED
@@ -0,0 +1,966 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Type definitions and utilities for the `create_commit` API
3
+ """
4
+
5
+ import base64
6
+ import io
7
+ import os
8
+ import warnings
9
+ from collections import defaultdict
10
+ from contextlib import contextmanager
11
+ from dataclasses import dataclass, field
12
+ from itertools import groupby
13
+ from pathlib import Path, PurePosixPath
14
+ from typing import TYPE_CHECKING, Any, BinaryIO, Iterable, Iterator, Literal, Optional, Union
15
+
16
+ from tqdm.contrib.concurrent import thread_map
17
+
18
+ from . import constants
19
+ from .errors import EntryNotFoundError, HfHubHTTPError, XetAuthorizationError, XetRefreshTokenError
20
+ from .file_download import hf_hub_url
21
+ from .lfs import UploadInfo, lfs_upload, post_lfs_batch_info
22
+ from .utils import (
23
+ FORBIDDEN_FOLDERS,
24
+ XetTokenType,
25
+ are_progress_bars_disabled,
26
+ chunk_iterable,
27
+ fetch_xet_connection_info_from_repo_info,
28
+ get_session,
29
+ hf_raise_for_status,
30
+ http_backoff,
31
+ logging,
32
+ sha,
33
+ tqdm_stream_file,
34
+ validate_hf_hub_args,
35
+ )
36
+ from .utils import tqdm as hf_tqdm
37
+ from .utils._runtime import is_xet_available
38
+
39
+
40
+ if TYPE_CHECKING:
41
+ from .hf_api import RepoFile
42
+
43
+
44
+ logger = logging.get_logger(__name__)
45
+
46
+
47
+ UploadMode = Literal["lfs", "regular"]
48
+
49
+ # Max is 1,000 per request on the Hub for HfApi.get_paths_info
50
+ # Otherwise we get:
51
+ # HfHubHTTPError: 413 Client Error: Payload Too Large for url: https://huggingface.co/api/datasets/xxx (Request ID: xxx)\n\ntoo many parameters
52
+ # See https://github.com/huggingface/huggingface_hub/issues/1503
53
+ FETCH_LFS_BATCH_SIZE = 500
54
+
55
+ UPLOAD_BATCH_MAX_NUM_FILES = 256
56
+
57
+
58
+ @dataclass
59
+ class CommitOperationDelete:
60
+ """
61
+ Data structure holding necessary info to delete a file or a folder from a repository
62
+ on the Hub.
63
+
64
+ Args:
65
+ path_in_repo (`str`):
66
+ Relative filepath in the repo, for example: `"checkpoints/1fec34a/weights.bin"`
67
+ for a file or `"checkpoints/1fec34a/"` for a folder.
68
+ is_folder (`bool` or `Literal["auto"]`, *optional*)
69
+ Whether the Delete Operation applies to a folder or not. If "auto", the path
70
+ type (file or folder) is guessed automatically by looking if path ends with
71
+ a "/" (folder) or not (file). To explicitly set the path type, you can set
72
+ `is_folder=True` or `is_folder=False`.
73
+ """
74
+
75
+ path_in_repo: str
76
+ is_folder: Union[bool, Literal["auto"]] = "auto"
77
+
78
+ def __post_init__(self):
79
+ self.path_in_repo = _validate_path_in_repo(self.path_in_repo)
80
+
81
+ if self.is_folder == "auto":
82
+ self.is_folder = self.path_in_repo.endswith("/")
83
+ if not isinstance(self.is_folder, bool):
84
+ raise ValueError(
85
+ f"Wrong value for `is_folder`. Must be one of [`True`, `False`, `'auto'`]. Got '{self.is_folder}'."
86
+ )
87
+
88
+
89
+ @dataclass
90
+ class CommitOperationCopy:
91
+ """
92
+ Data structure holding necessary info to copy a file in a repository on the Hub.
93
+
94
+ Limitations:
95
+ - Only LFS files can be copied. To copy a regular file, you need to download it locally and re-upload it
96
+ - Cross-repository copies are not supported.
97
+
98
+ Note: you can combine a [`CommitOperationCopy`] and a [`CommitOperationDelete`] to rename an LFS file on the Hub.
99
+
100
+ Args:
101
+ src_path_in_repo (`str`):
102
+ Relative filepath in the repo of the file to be copied, e.g. `"checkpoints/1fec34a/weights.bin"`.
103
+ path_in_repo (`str`):
104
+ Relative filepath in the repo where to copy the file, e.g. `"checkpoints/1fec34a/weights_copy.bin"`.
105
+ src_revision (`str`, *optional*):
106
+ The git revision of the file to be copied. Can be any valid git revision.
107
+ Default to the target commit revision.
108
+ """
109
+
110
+ src_path_in_repo: str
111
+ path_in_repo: str
112
+ src_revision: Optional[str] = None
113
+ # set to the OID of the file to be copied if it has already been uploaded
114
+ # useful to determine if a commit will be empty or not.
115
+ _src_oid: Optional[str] = None
116
+ # set to the OID of the file to copy to if it has already been uploaded
117
+ # useful to determine if a commit will be empty or not.
118
+ _dest_oid: Optional[str] = None
119
+
120
+ def __post_init__(self):
121
+ self.src_path_in_repo = _validate_path_in_repo(self.src_path_in_repo)
122
+ self.path_in_repo = _validate_path_in_repo(self.path_in_repo)
123
+
124
+
125
+ @dataclass
126
+ class CommitOperationAdd:
127
+ """
128
+ Data structure holding necessary info to upload a file to a repository on the Hub.
129
+
130
+ Args:
131
+ path_in_repo (`str`):
132
+ Relative filepath in the repo, for example: `"checkpoints/1fec34a/weights.bin"`
133
+ path_or_fileobj (`str`, `Path`, `bytes`, or `BinaryIO`):
134
+ Either:
135
+ - a path to a local file (as `str` or `pathlib.Path`) to upload
136
+ - a buffer of bytes (`bytes`) holding the content of the file to upload
137
+ - a "file object" (subclass of `io.BufferedIOBase`), typically obtained
138
+ with `open(path, "rb")`. It must support `seek()` and `tell()` methods.
139
+
140
+ Raises:
141
+ [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError)
142
+ If `path_or_fileobj` is not one of `str`, `Path`, `bytes` or `io.BufferedIOBase`.
143
+ [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError)
144
+ If `path_or_fileobj` is a `str` or `Path` but not a path to an existing file.
145
+ [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError)
146
+ If `path_or_fileobj` is a `io.BufferedIOBase` but it doesn't support both
147
+ `seek()` and `tell()`.
148
+ """
149
+
150
+ path_in_repo: str
151
+ path_or_fileobj: Union[str, Path, bytes, BinaryIO]
152
+ upload_info: UploadInfo = field(init=False, repr=False)
153
+
154
+ # Internal attributes
155
+
156
+ # set to "lfs" or "regular" once known
157
+ _upload_mode: Optional[UploadMode] = field(init=False, repr=False, default=None)
158
+
159
+ # set to True if .gitignore rules prevent the file from being uploaded as LFS
160
+ # (server-side check)
161
+ _should_ignore: Optional[bool] = field(init=False, repr=False, default=None)
162
+
163
+ # set to the remote OID of the file if it has already been uploaded
164
+ # useful to determine if a commit will be empty or not
165
+ _remote_oid: Optional[str] = field(init=False, repr=False, default=None)
166
+
167
+ # set to True once the file has been uploaded as LFS
168
+ _is_uploaded: bool = field(init=False, repr=False, default=False)
169
+
170
+ # set to True once the file has been committed
171
+ _is_committed: bool = field(init=False, repr=False, default=False)
172
+
173
+ def __post_init__(self) -> None:
174
+ """Validates `path_or_fileobj` and compute `upload_info`."""
175
+ self.path_in_repo = _validate_path_in_repo(self.path_in_repo)
176
+
177
+ # Validate `path_or_fileobj` value
178
+ if isinstance(self.path_or_fileobj, Path):
179
+ self.path_or_fileobj = str(self.path_or_fileobj)
180
+ if isinstance(self.path_or_fileobj, str):
181
+ path_or_fileobj = os.path.normpath(os.path.expanduser(self.path_or_fileobj))
182
+ if not os.path.isfile(path_or_fileobj):
183
+ raise ValueError(f"Provided path: '{path_or_fileobj}' is not a file on the local file system")
184
+ elif not isinstance(self.path_or_fileobj, (io.BufferedIOBase, bytes)):
185
+ # ^^ Inspired from: https://stackoverflow.com/questions/44584829/how-to-determine-if-file-is-opened-in-binary-or-text-mode
186
+ raise ValueError(
187
+ "path_or_fileobj must be either an instance of str, bytes or"
188
+ " io.BufferedIOBase. If you passed a file-like object, make sure it is"
189
+ " in binary mode."
190
+ )
191
+ if isinstance(self.path_or_fileobj, io.BufferedIOBase):
192
+ try:
193
+ self.path_or_fileobj.tell()
194
+ self.path_or_fileobj.seek(0, os.SEEK_CUR)
195
+ except (OSError, AttributeError) as exc:
196
+ raise ValueError(
197
+ "path_or_fileobj is a file-like object but does not implement seek() and tell()"
198
+ ) from exc
199
+
200
+ # Compute "upload_info" attribute
201
+ if isinstance(self.path_or_fileobj, str):
202
+ self.upload_info = UploadInfo.from_path(self.path_or_fileobj)
203
+ elif isinstance(self.path_or_fileobj, bytes):
204
+ self.upload_info = UploadInfo.from_bytes(self.path_or_fileobj)
205
+ else:
206
+ self.upload_info = UploadInfo.from_fileobj(self.path_or_fileobj)
207
+
208
+ @contextmanager
209
+ def as_file(self, with_tqdm: bool = False) -> Iterator[BinaryIO]:
210
+ """
211
+ A context manager that yields a file-like object allowing to read the underlying
212
+ data behind `path_or_fileobj`.
213
+
214
+ Args:
215
+ with_tqdm (`bool`, *optional*, defaults to `False`):
216
+ If True, iterating over the file object will display a progress bar. Only
217
+ works if the file-like object is a path to a file. Pure bytes and buffers
218
+ are not supported.
219
+
220
+ Example:
221
+
222
+ ```python
223
+ >>> operation = CommitOperationAdd(
224
+ ... path_in_repo="remote/dir/weights.h5",
225
+ ... path_or_fileobj="./local/weights.h5",
226
+ ... )
227
+ CommitOperationAdd(path_in_repo='remote/dir/weights.h5', path_or_fileobj='./local/weights.h5')
228
+
229
+ >>> with operation.as_file() as file:
230
+ ... content = file.read()
231
+
232
+ >>> with operation.as_file(with_tqdm=True) as file:
233
+ ... while True:
234
+ ... data = file.read(1024)
235
+ ... if not data:
236
+ ... break
237
+ config.json: 100%|█████████████████████████| 8.19k/8.19k [00:02<00:00, 3.72kB/s]
238
+
239
+ >>> with operation.as_file(with_tqdm=True) as file:
240
+ ... httpx.put(..., data=file)
241
+ config.json: 100%|█████████████████████████| 8.19k/8.19k [00:02<00:00, 3.72kB/s]
242
+ ```
243
+ """
244
+ if isinstance(self.path_or_fileobj, str) or isinstance(self.path_or_fileobj, Path):
245
+ if with_tqdm:
246
+ with tqdm_stream_file(self.path_or_fileobj) as file:
247
+ yield file
248
+ else:
249
+ with open(self.path_or_fileobj, "rb") as file:
250
+ yield file
251
+ elif isinstance(self.path_or_fileobj, bytes):
252
+ yield io.BytesIO(self.path_or_fileobj)
253
+ elif isinstance(self.path_or_fileobj, io.BufferedIOBase):
254
+ prev_pos = self.path_or_fileobj.tell()
255
+ yield self.path_or_fileobj
256
+ self.path_or_fileobj.seek(prev_pos, io.SEEK_SET)
257
+
258
+ def b64content(self) -> bytes:
259
+ """
260
+ The base64-encoded content of `path_or_fileobj`
261
+
262
+ Returns: `bytes`
263
+ """
264
+ with self.as_file() as file:
265
+ return base64.b64encode(file.read())
266
+
267
+ @property
268
+ def _local_oid(self) -> Optional[str]:
269
+ """Return the OID of the local file.
270
+
271
+ This OID is then compared to `self._remote_oid` to check if the file has changed compared to the remote one.
272
+ If the file did not change, we won't upload it again to prevent empty commits.
273
+
274
+ For LFS files, the OID corresponds to the SHA256 of the file content (used a LFS ref).
275
+ For regular files, the OID corresponds to the SHA1 of the file content.
276
+ Note: this is slightly different to git OID computation since the oid of an LFS file is usually the git-SHA1 of the
277
+ pointer file content (not the actual file content). However, using the SHA256 is enough to detect changes
278
+ and more convenient client-side.
279
+ """
280
+ if self._upload_mode is None:
281
+ return None
282
+ elif self._upload_mode == "lfs":
283
+ return self.upload_info.sha256.hex()
284
+ else:
285
+ # Regular file => compute sha1
286
+ # => no need to read by chunk since the file is guaranteed to be <=5MB.
287
+ with self.as_file() as file:
288
+ return sha.git_hash(file.read())
289
+
290
+
291
+ def _validate_path_in_repo(path_in_repo: str) -> str:
292
+ # Validate `path_in_repo` value to prevent a server-side issue
293
+ if path_in_repo.startswith("/"):
294
+ path_in_repo = path_in_repo[1:]
295
+ if path_in_repo == "." or path_in_repo == ".." or path_in_repo.startswith("../"):
296
+ raise ValueError(f"Invalid `path_in_repo` in CommitOperation: '{path_in_repo}'")
297
+ if path_in_repo.startswith("./"):
298
+ path_in_repo = path_in_repo[2:]
299
+ for forbidden in FORBIDDEN_FOLDERS:
300
+ if any(part == forbidden for part in path_in_repo.split("/")):
301
+ raise ValueError(
302
+ f"Invalid `path_in_repo` in CommitOperation: cannot update files under a '{forbidden}/' folder (path:"
303
+ f" '{path_in_repo}')."
304
+ )
305
+ return path_in_repo
306
+
307
+
308
+ CommitOperation = Union[CommitOperationAdd, CommitOperationCopy, CommitOperationDelete]
309
+
310
+
311
+ def _warn_on_overwriting_operations(operations: list[CommitOperation]) -> None:
312
+ """
313
+ Warn user when a list of operations is expected to overwrite itself in a single
314
+ commit.
315
+
316
+ Rules:
317
+ - If a filepath is updated by multiple `CommitOperationAdd` operations, a warning
318
+ message is triggered.
319
+ - If a filepath is updated at least once by a `CommitOperationAdd` and then deleted
320
+ by a `CommitOperationDelete`, a warning is triggered.
321
+ - If a `CommitOperationDelete` deletes a filepath that is then updated by a
322
+ `CommitOperationAdd`, no warning is triggered. This is usually useless (no need to
323
+ delete before upload) but can happen if a user deletes an entire folder and then
324
+ add new files to it.
325
+ """
326
+ nb_additions_per_path: dict[str, int] = defaultdict(int)
327
+ for operation in operations:
328
+ path_in_repo = operation.path_in_repo
329
+ if isinstance(operation, CommitOperationAdd):
330
+ if nb_additions_per_path[path_in_repo] > 0:
331
+ warnings.warn(
332
+ "About to update multiple times the same file in the same commit:"
333
+ f" '{path_in_repo}'. This can cause undesired inconsistencies in"
334
+ " your repo."
335
+ )
336
+ nb_additions_per_path[path_in_repo] += 1
337
+ for parent in PurePosixPath(path_in_repo).parents:
338
+ # Also keep track of number of updated files per folder
339
+ # => warns if deleting a folder overwrite some contained files
340
+ nb_additions_per_path[str(parent)] += 1
341
+ if isinstance(operation, CommitOperationDelete):
342
+ if nb_additions_per_path[str(PurePosixPath(path_in_repo))] > 0:
343
+ if operation.is_folder:
344
+ warnings.warn(
345
+ "About to delete a folder containing files that have just been"
346
+ f" updated within the same commit: '{path_in_repo}'. This can"
347
+ " cause undesired inconsistencies in your repo."
348
+ )
349
+ else:
350
+ warnings.warn(
351
+ "About to delete a file that have just been updated within the"
352
+ f" same commit: '{path_in_repo}'. This can cause undesired"
353
+ " inconsistencies in your repo."
354
+ )
355
+
356
+
357
+ @validate_hf_hub_args
358
+ def _upload_files(
359
+ *,
360
+ additions: list[CommitOperationAdd],
361
+ repo_type: str,
362
+ repo_id: str,
363
+ headers: dict[str, str],
364
+ endpoint: Optional[str] = None,
365
+ num_threads: int = 5,
366
+ revision: Optional[str] = None,
367
+ create_pr: Optional[bool] = None,
368
+ ):
369
+ """
370
+ Negotiates per-file transfer (LFS vs Xet) and uploads in batches.
371
+ """
372
+ xet_additions: list[CommitOperationAdd] = []
373
+ lfs_actions: list[dict[str, Any]] = []
374
+ lfs_oid2addop: dict[str, CommitOperationAdd] = {}
375
+
376
+ for chunk in chunk_iterable(additions, chunk_size=UPLOAD_BATCH_MAX_NUM_FILES):
377
+ chunk_list = [op for op in chunk]
378
+
379
+ transfers: list[str] = ["basic", "multipart"]
380
+ has_buffered_io_data = any(isinstance(op.path_or_fileobj, io.BufferedIOBase) for op in chunk_list)
381
+ if is_xet_available():
382
+ if not has_buffered_io_data:
383
+ transfers.append("xet")
384
+ else:
385
+ logger.warning(
386
+ "Uploading files as a binary IO buffer is not supported by Xet Storage. "
387
+ "Falling back to HTTP upload."
388
+ )
389
+
390
+ actions_chunk, errors_chunk, chosen_transfer = post_lfs_batch_info(
391
+ upload_infos=[op.upload_info for op in chunk_list],
392
+ repo_id=repo_id,
393
+ repo_type=repo_type,
394
+ revision=revision,
395
+ endpoint=endpoint,
396
+ headers=headers,
397
+ token=None, # already passed in 'headers'
398
+ transfers=transfers,
399
+ )
400
+ if errors_chunk:
401
+ message = "\n".join(
402
+ [
403
+ f"Encountered error for file with OID {err.get('oid')}: `{err.get('error', {}).get('message')}"
404
+ for err in errors_chunk
405
+ ]
406
+ )
407
+ raise ValueError(f"LFS batch API returned errors:\n{message}")
408
+
409
+ # If server returns a transfer we didn't offer (e.g "xet" while uploading from BytesIO),
410
+ # fall back to LFS for this chunk.
411
+ if chosen_transfer == "xet" and ("xet" in transfers):
412
+ xet_additions.extend(chunk_list)
413
+ else:
414
+ lfs_actions.extend(actions_chunk)
415
+ for op in chunk_list:
416
+ lfs_oid2addop[op.upload_info.sha256.hex()] = op
417
+
418
+ if len(lfs_actions) > 0:
419
+ _upload_lfs_files(
420
+ actions=lfs_actions,
421
+ oid2addop=lfs_oid2addop,
422
+ headers=headers,
423
+ endpoint=endpoint,
424
+ num_threads=num_threads,
425
+ )
426
+
427
+ if len(xet_additions) > 0:
428
+ _upload_xet_files(
429
+ additions=xet_additions,
430
+ repo_type=repo_type,
431
+ repo_id=repo_id,
432
+ headers=headers,
433
+ endpoint=endpoint,
434
+ revision=revision,
435
+ create_pr=create_pr,
436
+ )
437
+
438
+
439
+ @validate_hf_hub_args
440
+ def _upload_lfs_files(
441
+ *,
442
+ actions: list[dict[str, Any]],
443
+ oid2addop: dict[str, CommitOperationAdd],
444
+ headers: dict[str, str],
445
+ endpoint: Optional[str] = None,
446
+ num_threads: int = 5,
447
+ ):
448
+ """
449
+ Uploads the content of `additions` to the Hub using the large file storage protocol.
450
+
451
+ Relevant external documentation:
452
+ - LFS Batch API: https://github.com/git-lfs/git-lfs/blob/main/docs/api/batch.md
453
+
454
+ Args:
455
+ actions (`list[dict[str, Any]]`):
456
+ LFS batch actions returned by the server.
457
+ oid2addop (`dict[str, CommitOperationAdd]`):
458
+ A dictionary mapping the OID of the file to the corresponding `CommitOperationAdd` object.
459
+ headers (`dict[str, str]`):
460
+ Headers to use for the request, including authorization headers and user agent.
461
+ endpoint (`str`, *optional*):
462
+ The endpoint to use for the request. Defaults to `constants.ENDPOINT`.
463
+ num_threads (`int`, *optional*):
464
+ The number of concurrent threads to use when uploading. Defaults to 5.
465
+
466
+ Raises:
467
+ [`EnvironmentError`](https://docs.python.org/3/library/exceptions.html#EnvironmentError)
468
+ If an upload failed for any reason
469
+ [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError)
470
+ Type of the repo to upload to: `"model"`, `"dataset"` or `"space"`.
471
+ repo_id (`str`):
472
+ A namespace (user or an organization) and a repo name separated
473
+ by a `/`.
474
+ headers (`dict[str, str]`):
475
+ Headers to use for the request, including authorization headers and user agent.
476
+ num_threads (`int`, *optional*):
477
+ The number of concurrent threads to use when uploading. Defaults to 5.
478
+ revision (`str`, *optional*):
479
+ The git revision to upload to.
480
+
481
+ Raises:
482
+ [`EnvironmentError`](https://docs.python.org/3/library/exceptions.html#EnvironmentError)
483
+ If an upload failed for any reason
484
+ [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError)
485
+ If the server returns malformed responses
486
+ [`HfHubHTTPError`]
487
+ If the LFS batch endpoint returned an HTTP error.
488
+ """
489
+ # Filter out files already present upstream
490
+ filtered_actions = []
491
+ for action in actions:
492
+ if action.get("actions") is None:
493
+ logger.debug(
494
+ f"Content of file {oid2addop[action['oid']].path_in_repo} is already present upstream - skipping upload."
495
+ )
496
+ else:
497
+ filtered_actions.append(action)
498
+
499
+ # Upload according to server-provided actions
500
+ def _wrapped_lfs_upload(batch_action) -> None:
501
+ try:
502
+ operation = oid2addop[batch_action["oid"]]
503
+ lfs_upload(operation=operation, lfs_batch_action=batch_action, headers=headers, endpoint=endpoint)
504
+ except Exception as exc:
505
+ raise RuntimeError(f"Error while uploading '{operation.path_in_repo}' to the Hub.") from exc
506
+
507
+ if len(filtered_actions) == 1:
508
+ logger.debug("Uploading 1 LFS file to the Hub")
509
+ _wrapped_lfs_upload(filtered_actions[0])
510
+ else:
511
+ logger.debug(
512
+ f"Uploading {len(filtered_actions)} LFS files to the Hub using up to {num_threads} threads concurrently"
513
+ )
514
+ thread_map(
515
+ _wrapped_lfs_upload,
516
+ filtered_actions,
517
+ desc=f"Upload {len(filtered_actions)} LFS files",
518
+ max_workers=num_threads,
519
+ tqdm_class=hf_tqdm,
520
+ )
521
+
522
+
523
+ @validate_hf_hub_args
524
+ def _upload_xet_files(
525
+ *,
526
+ additions: list[CommitOperationAdd],
527
+ repo_type: str,
528
+ repo_id: str,
529
+ headers: dict[str, str],
530
+ endpoint: Optional[str] = None,
531
+ revision: Optional[str] = None,
532
+ create_pr: Optional[bool] = None,
533
+ ):
534
+ """
535
+ Uploads the content of `additions` to the Hub using the xet storage protocol.
536
+ This chunks the files and deduplicates the chunks before uploading them to xetcas storage.
537
+
538
+ Args:
539
+ additions (`` of `CommitOperationAdd`):
540
+ The files to be uploaded.
541
+ repo_type (`str`):
542
+ Type of the repo to upload to: `"model"`, `"dataset"` or `"space"`.
543
+ repo_id (`str`):
544
+ A namespace (user or an organization) and a repo name separated
545
+ by a `/`.
546
+ headers (`dict[str, str]`):
547
+ Headers to use for the request, including authorization headers and user agent.
548
+ endpoint: (`str`, *optional*):
549
+ The endpoint to use for the xetcas service. Defaults to `constants.ENDPOINT`.
550
+ revision (`str`, *optional*):
551
+ The git revision to upload to.
552
+ create_pr (`bool`, *optional*):
553
+ Whether or not to create a Pull Request with that commit.
554
+
555
+ Raises:
556
+ [`EnvironmentError`](https://docs.python.org/3/library/exceptions.html#EnvironmentError)
557
+ If an upload failed for any reason.
558
+ [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError)
559
+ If the server returns malformed responses or if the user is unauthorized to upload to xet storage.
560
+ [`HfHubHTTPError`]
561
+ If the LFS batch endpoint returned an HTTP error.
562
+
563
+ **How it works:**
564
+ The file download system uses Xet storage, which is a content-addressable storage system that breaks files into chunks
565
+ for efficient storage and transfer.
566
+
567
+ `hf_xet.upload_files` manages uploading files by:
568
+ - Taking a list of file paths to upload
569
+ - Breaking files into smaller chunks for efficient storage
570
+ - Avoiding duplicate storage by recognizing identical chunks across files
571
+ - Connecting to a storage server (CAS server) that manages these chunks
572
+
573
+ The upload process works like this:
574
+ 1. Create a local folder at ~/.cache/huggingface/xet/chunk-cache to store file chunks for reuse.
575
+ 2. Process files in parallel (up to 8 files at once):
576
+ 2.1. Read the file content.
577
+ 2.2. Split the file content into smaller chunks based on content patterns: each chunk gets a unique ID based on what's in it.
578
+ 2.3. For each chunk:
579
+ - Check if it already exists in storage.
580
+ - Skip uploading chunks that already exist.
581
+ 2.4. Group chunks into larger blocks for efficient transfer.
582
+ 2.5. Upload these blocks to the storage server.
583
+ 2.6. Create and upload information about how the file is structured.
584
+ 3. Return reference files that contain information about the uploaded files, which can be used later to download them.
585
+ """
586
+ if len(additions) == 0:
587
+ return
588
+
589
+ # at this point, we know that hf_xet is installed
590
+ from hf_xet import upload_bytes, upload_files
591
+
592
+ from .utils._xet_progress_reporting import XetProgressReporter
593
+
594
+ try:
595
+ xet_connection_info = fetch_xet_connection_info_from_repo_info(
596
+ token_type=XetTokenType.WRITE,
597
+ repo_id=repo_id,
598
+ repo_type=repo_type,
599
+ revision=revision,
600
+ headers=headers,
601
+ endpoint=endpoint,
602
+ params={"create_pr": "1"} if create_pr else None,
603
+ )
604
+ except HfHubHTTPError as e:
605
+ if e.response.status_code == 401:
606
+ raise XetAuthorizationError(
607
+ f"You are unauthorized to upload to xet storage for {repo_type}/{repo_id}. "
608
+ f"Please check that you have configured your access token with write access to the repo."
609
+ ) from e
610
+ raise
611
+
612
+ xet_endpoint = xet_connection_info.endpoint
613
+ access_token_info = (xet_connection_info.access_token, xet_connection_info.expiration_unix_epoch)
614
+
615
+ def token_refresher() -> tuple[str, int]:
616
+ new_xet_connection = fetch_xet_connection_info_from_repo_info(
617
+ token_type=XetTokenType.WRITE,
618
+ repo_id=repo_id,
619
+ repo_type=repo_type,
620
+ revision=revision,
621
+ headers=headers,
622
+ endpoint=endpoint,
623
+ params={"create_pr": "1"} if create_pr else None,
624
+ )
625
+ if new_xet_connection is None:
626
+ raise XetRefreshTokenError("Failed to refresh xet token")
627
+ return new_xet_connection.access_token, new_xet_connection.expiration_unix_epoch
628
+
629
+ if not are_progress_bars_disabled():
630
+ progress = XetProgressReporter()
631
+ progress_callback = progress.update_progress
632
+ else:
633
+ progress, progress_callback = None, None
634
+
635
+ try:
636
+ all_bytes_ops = [op for op in additions if isinstance(op.path_or_fileobj, bytes)]
637
+ all_paths_ops = [op for op in additions if isinstance(op.path_or_fileobj, (str, Path))]
638
+
639
+ if len(all_paths_ops) > 0:
640
+ all_paths = [str(op.path_or_fileobj) for op in all_paths_ops]
641
+ upload_files(
642
+ all_paths,
643
+ xet_endpoint,
644
+ access_token_info,
645
+ token_refresher,
646
+ progress_callback,
647
+ repo_type,
648
+ )
649
+
650
+ if len(all_bytes_ops) > 0:
651
+ all_bytes = [op.path_or_fileobj for op in all_bytes_ops]
652
+ upload_bytes(
653
+ all_bytes,
654
+ xet_endpoint,
655
+ access_token_info,
656
+ token_refresher,
657
+ progress_callback,
658
+ repo_type,
659
+ )
660
+
661
+ finally:
662
+ if progress is not None:
663
+ progress.close(False)
664
+
665
+ return
666
+
667
+
668
+ def _validate_preupload_info(preupload_info: dict):
669
+ files = preupload_info.get("files")
670
+ if not isinstance(files, list):
671
+ raise ValueError("preupload_info is improperly formatted")
672
+ for file_info in files:
673
+ if not (
674
+ isinstance(file_info, dict)
675
+ and isinstance(file_info.get("path"), str)
676
+ and isinstance(file_info.get("uploadMode"), str)
677
+ and (file_info["uploadMode"] in ("lfs", "regular"))
678
+ ):
679
+ raise ValueError("preupload_info is improperly formatted:")
680
+ return preupload_info
681
+
682
+
683
+ @validate_hf_hub_args
684
+ def _fetch_upload_modes(
685
+ additions: Iterable[CommitOperationAdd],
686
+ repo_type: str,
687
+ repo_id: str,
688
+ headers: dict[str, str],
689
+ revision: str,
690
+ endpoint: Optional[str] = None,
691
+ create_pr: bool = False,
692
+ gitignore_content: Optional[str] = None,
693
+ ) -> None:
694
+ """
695
+ Requests the Hub "preupload" endpoint to determine whether each input file should be uploaded as a regular git blob,
696
+ as a git LFS blob, or as a XET file. Input `additions` are mutated in-place with the upload mode.
697
+
698
+ Args:
699
+ additions (`Iterable` of :class:`CommitOperationAdd`):
700
+ Iterable of :class:`CommitOperationAdd` describing the files to
701
+ upload to the Hub.
702
+ repo_type (`str`):
703
+ Type of the repo to upload to: `"model"`, `"dataset"` or `"space"`.
704
+ repo_id (`str`):
705
+ A namespace (user or an organization) and a repo name separated
706
+ by a `/`.
707
+ headers (`dict[str, str]`):
708
+ Headers to use for the request, including authorization headers and user agent.
709
+ revision (`str`):
710
+ The git revision to upload the files to. Can be any valid git revision.
711
+ gitignore_content (`str`, *optional*):
712
+ The content of the `.gitignore` file to know which files should be ignored. The order of priority
713
+ is to first check if `gitignore_content` is passed, then check if the `.gitignore` file is present
714
+ in the list of files to commit and finally default to the `.gitignore` file already hosted on the Hub
715
+ (if any).
716
+ Raises:
717
+ [`~utils.HfHubHTTPError`]
718
+ If the Hub API returned an error.
719
+ [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError)
720
+ If the Hub API response is improperly formatted.
721
+ """
722
+ endpoint = endpoint if endpoint is not None else constants.ENDPOINT
723
+
724
+ # Fetch upload mode (LFS or regular) chunk by chunk.
725
+ upload_modes: dict[str, UploadMode] = {}
726
+ should_ignore_info: dict[str, bool] = {}
727
+ oid_info: dict[str, Optional[str]] = {}
728
+
729
+ for chunk in chunk_iterable(additions, 256):
730
+ payload: dict = {
731
+ "files": [
732
+ {
733
+ "path": op.path_in_repo,
734
+ "sample": base64.b64encode(op.upload_info.sample).decode("ascii"),
735
+ "size": op.upload_info.size,
736
+ }
737
+ for op in chunk
738
+ ]
739
+ }
740
+ if gitignore_content is not None:
741
+ payload["gitIgnore"] = gitignore_content
742
+
743
+ resp = http_backoff(
744
+ "POST",
745
+ f"{endpoint}/api/{repo_type}s/{repo_id}/preupload/{revision}",
746
+ json=payload,
747
+ headers=headers,
748
+ params={"create_pr": "1"} if create_pr else None,
749
+ )
750
+ hf_raise_for_status(resp)
751
+ preupload_info = _validate_preupload_info(resp.json())
752
+ upload_modes.update(**{file["path"]: file["uploadMode"] for file in preupload_info["files"]})
753
+ should_ignore_info.update(**{file["path"]: file["shouldIgnore"] for file in preupload_info["files"]})
754
+ oid_info.update(**{file["path"]: file.get("oid") for file in preupload_info["files"]})
755
+
756
+ # Set upload mode for each addition operation
757
+ for addition in additions:
758
+ addition._upload_mode = upload_modes[addition.path_in_repo]
759
+ addition._should_ignore = should_ignore_info[addition.path_in_repo]
760
+ addition._remote_oid = oid_info[addition.path_in_repo]
761
+
762
+ # Empty files cannot be uploaded as LFS (S3 would fail with a 501 Not Implemented)
763
+ # => empty files are uploaded as "regular" to still allow users to commit them.
764
+ for addition in additions:
765
+ if addition.upload_info.size == 0:
766
+ addition._upload_mode = "regular"
767
+
768
+
769
+ @validate_hf_hub_args
770
+ def _fetch_files_to_copy(
771
+ copies: Iterable[CommitOperationCopy],
772
+ repo_type: str,
773
+ repo_id: str,
774
+ headers: dict[str, str],
775
+ revision: str,
776
+ endpoint: Optional[str] = None,
777
+ ) -> dict[tuple[str, Optional[str]], Union["RepoFile", bytes]]:
778
+ """
779
+ Fetch information about the files to copy.
780
+
781
+ For LFS files, we only need their metadata (file size and sha256) while for regular files
782
+ we need to download the raw content from the Hub.
783
+
784
+ Args:
785
+ copies (`Iterable` of :class:`CommitOperationCopy`):
786
+ Iterable of :class:`CommitOperationCopy` describing the files to
787
+ copy on the Hub.
788
+ repo_type (`str`):
789
+ Type of the repo to upload to: `"model"`, `"dataset"` or `"space"`.
790
+ repo_id (`str`):
791
+ A namespace (user or an organization) and a repo name separated
792
+ by a `/`.
793
+ headers (`dict[str, str]`):
794
+ Headers to use for the request, including authorization headers and user agent.
795
+ revision (`str`):
796
+ The git revision to upload the files to. Can be any valid git revision.
797
+
798
+ Returns: `dict[tuple[str, Optional[str]], Union[RepoFile, bytes]]]`
799
+ Key is the file path and revision of the file to copy.
800
+ Value is the raw content as bytes (for regular files) or the file information as a RepoFile (for LFS files).
801
+
802
+ Raises:
803
+ [`~utils.HfHubHTTPError`]
804
+ If the Hub API returned an error.
805
+ [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError)
806
+ If the Hub API response is improperly formatted.
807
+ """
808
+ from .hf_api import HfApi, RepoFolder
809
+
810
+ hf_api = HfApi(endpoint=endpoint, headers=headers)
811
+ files_to_copy: dict[tuple[str, Optional[str]], Union["RepoFile", bytes]] = {}
812
+ # Store (path, revision) -> oid mapping
813
+ oid_info: dict[tuple[str, Optional[str]], Optional[str]] = {}
814
+ # 1. Fetch OIDs for destination paths in batches.
815
+ dest_paths = [op.path_in_repo for op in copies]
816
+ for offset in range(0, len(dest_paths), FETCH_LFS_BATCH_SIZE):
817
+ dest_repo_files = hf_api.get_paths_info(
818
+ repo_id=repo_id,
819
+ paths=dest_paths[offset : offset + FETCH_LFS_BATCH_SIZE],
820
+ revision=revision,
821
+ repo_type=repo_type,
822
+ )
823
+ for file in dest_repo_files:
824
+ if not isinstance(file, RepoFolder):
825
+ oid_info[(file.path, revision)] = file.blob_id
826
+
827
+ # 2. Group by source revision and fetch source file info in batches.
828
+ for src_revision, operations in groupby(copies, key=lambda op: op.src_revision):
829
+ operations = list(operations) # type: ignore
830
+ src_paths = [op.src_path_in_repo for op in operations]
831
+ for offset in range(0, len(src_paths), FETCH_LFS_BATCH_SIZE):
832
+ src_repo_files = hf_api.get_paths_info(
833
+ repo_id=repo_id,
834
+ paths=src_paths[offset : offset + FETCH_LFS_BATCH_SIZE],
835
+ revision=src_revision or revision,
836
+ repo_type=repo_type,
837
+ )
838
+
839
+ for src_repo_file in src_repo_files:
840
+ if isinstance(src_repo_file, RepoFolder):
841
+ raise NotImplementedError("Copying a folder is not implemented.")
842
+ oid_info[(src_repo_file.path, src_revision)] = src_repo_file.blob_id
843
+ # If it's an LFS file, store the RepoFile object. Otherwise, download raw bytes.
844
+ if src_repo_file.lfs:
845
+ files_to_copy[(src_repo_file.path, src_revision)] = src_repo_file
846
+ else:
847
+ # TODO: (optimization) download regular files to copy concurrently
848
+ url = hf_hub_url(
849
+ endpoint=endpoint,
850
+ repo_type=repo_type,
851
+ repo_id=repo_id,
852
+ revision=src_revision or revision,
853
+ filename=src_repo_file.path,
854
+ )
855
+ response = get_session().get(url, headers=headers)
856
+ hf_raise_for_status(response)
857
+ files_to_copy[(src_repo_file.path, src_revision)] = response.content
858
+ # 3. Ensure all operations found a corresponding file in the Hub
859
+ # and track src/dest OIDs for each operation.
860
+ for operation in operations:
861
+ if (operation.src_path_in_repo, src_revision) not in files_to_copy:
862
+ raise EntryNotFoundError(
863
+ f"Cannot copy {operation.src_path_in_repo} at revision "
864
+ f"{src_revision or revision}: file is missing on repo."
865
+ )
866
+ operation._src_oid = oid_info.get((operation.src_path_in_repo, operation.src_revision))
867
+ operation._dest_oid = oid_info.get((operation.path_in_repo, revision))
868
+ return files_to_copy
869
+
870
+
871
+ def _prepare_commit_payload(
872
+ operations: Iterable[CommitOperation],
873
+ files_to_copy: dict[tuple[str, Optional[str]], Union["RepoFile", bytes]],
874
+ commit_message: str,
875
+ commit_description: Optional[str] = None,
876
+ parent_commit: Optional[str] = None,
877
+ ) -> Iterable[dict[str, Any]]:
878
+ """
879
+ Builds the payload to POST to the `/commit` API of the Hub.
880
+
881
+ Payload is returned as an iterator so that it can be streamed as a ndjson in the
882
+ POST request.
883
+
884
+ For more information, see:
885
+ - https://github.com/huggingface/huggingface_hub/issues/1085#issuecomment-1265208073
886
+ - http://ndjson.org/
887
+ """
888
+ commit_description = commit_description if commit_description is not None else ""
889
+
890
+ # 1. Send a header item with the commit metadata
891
+ header_value = {"summary": commit_message, "description": commit_description}
892
+ if parent_commit is not None:
893
+ header_value["parentCommit"] = parent_commit
894
+ yield {"key": "header", "value": header_value}
895
+
896
+ nb_ignored_files = 0
897
+
898
+ # 2. Send operations, one per line
899
+ for operation in operations:
900
+ # Skip ignored files
901
+ if isinstance(operation, CommitOperationAdd) and operation._should_ignore:
902
+ logger.debug(f"Skipping file '{operation.path_in_repo}' in commit (ignored by gitignore file).")
903
+ nb_ignored_files += 1
904
+ continue
905
+
906
+ # 2.a. Case adding a regular file
907
+ if isinstance(operation, CommitOperationAdd) and operation._upload_mode == "regular":
908
+ yield {
909
+ "key": "file",
910
+ "value": {
911
+ "content": operation.b64content().decode(),
912
+ "path": operation.path_in_repo,
913
+ "encoding": "base64",
914
+ },
915
+ }
916
+ # 2.b. Case adding an LFS file
917
+ elif isinstance(operation, CommitOperationAdd) and operation._upload_mode == "lfs":
918
+ yield {
919
+ "key": "lfsFile",
920
+ "value": {
921
+ "path": operation.path_in_repo,
922
+ "algo": "sha256",
923
+ "oid": operation.upload_info.sha256.hex(),
924
+ "size": operation.upload_info.size,
925
+ },
926
+ }
927
+ # 2.c. Case deleting a file or folder
928
+ elif isinstance(operation, CommitOperationDelete):
929
+ yield {
930
+ "key": "deletedFolder" if operation.is_folder else "deletedFile",
931
+ "value": {"path": operation.path_in_repo},
932
+ }
933
+ # 2.d. Case copying a file or folder
934
+ elif isinstance(operation, CommitOperationCopy):
935
+ file_to_copy = files_to_copy[(operation.src_path_in_repo, operation.src_revision)]
936
+ if isinstance(file_to_copy, bytes):
937
+ yield {
938
+ "key": "file",
939
+ "value": {
940
+ "content": base64.b64encode(file_to_copy).decode(),
941
+ "path": operation.path_in_repo,
942
+ "encoding": "base64",
943
+ },
944
+ }
945
+ elif file_to_copy.lfs:
946
+ yield {
947
+ "key": "lfsFile",
948
+ "value": {
949
+ "path": operation.path_in_repo,
950
+ "algo": "sha256",
951
+ "oid": file_to_copy.lfs.sha256,
952
+ },
953
+ }
954
+ else:
955
+ raise ValueError(
956
+ "Malformed files_to_copy (should be raw file content as bytes or RepoFile objects with LFS info."
957
+ )
958
+ # 2.e. Never expected to happen
959
+ else:
960
+ raise ValueError(
961
+ f"Unknown operation to commit. Operation: {operation}. Upload mode:"
962
+ f" {getattr(operation, '_upload_mode', None)}"
963
+ )
964
+
965
+ if nb_ignored_files > 0:
966
+ logger.info(f"Skipped {nb_ignored_files} file(s) in commit (ignored by gitignore file).")
env/lib/python3.13/site-packages/huggingface_hub/_commit_scheduler.py ADDED
@@ -0,0 +1,353 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import atexit
2
+ import logging
3
+ import os
4
+ import time
5
+ from concurrent.futures import Future
6
+ from dataclasses import dataclass
7
+ from io import SEEK_END, SEEK_SET, BytesIO
8
+ from pathlib import Path
9
+ from threading import Lock, Thread
10
+ from typing import Optional, Union
11
+
12
+ from .hf_api import DEFAULT_IGNORE_PATTERNS, CommitInfo, CommitOperationAdd, HfApi
13
+ from .utils import filter_repo_objects
14
+
15
+
16
+ logger = logging.getLogger(__name__)
17
+
18
+
19
+ @dataclass(frozen=True)
20
+ class _FileToUpload:
21
+ """Temporary dataclass to store info about files to upload. Not meant to be used directly."""
22
+
23
+ local_path: Path
24
+ path_in_repo: str
25
+ size_limit: int
26
+ last_modified: float
27
+
28
+
29
+ class CommitScheduler:
30
+ """
31
+ Scheduler to upload a local folder to the Hub at regular intervals (e.g. push to hub every 5 minutes).
32
+
33
+ The recommended way to use the scheduler is to use it as a context manager. This ensures that the scheduler is
34
+ properly stopped and the last commit is triggered when the script ends. The scheduler can also be stopped manually
35
+ with the `stop` method. Checkout the [upload guide](https://huggingface.co/docs/huggingface_hub/guides/upload#scheduled-uploads)
36
+ to learn more about how to use it.
37
+
38
+ Args:
39
+ repo_id (`str`):
40
+ The id of the repo to commit to.
41
+ folder_path (`str` or `Path`):
42
+ Path to the local folder to upload regularly.
43
+ every (`int` or `float`, *optional*):
44
+ The number of minutes between each commit. Defaults to 5 minutes.
45
+ path_in_repo (`str`, *optional*):
46
+ Relative path of the directory in the repo, for example: `"checkpoints/"`. Defaults to the root folder
47
+ of the repository.
48
+ repo_type (`str`, *optional*):
49
+ The type of the repo to commit to. Defaults to `model`.
50
+ revision (`str`, *optional*):
51
+ The revision of the repo to commit to. Defaults to `main`.
52
+ private (`bool`, *optional*):
53
+ Whether to make the repo private. If `None` (default), the repo will be public unless the organization's default is private. This value is ignored if the repo already exists.
54
+ token (`str`, *optional*):
55
+ The token to use to commit to the repo. Defaults to the token saved on the machine.
56
+ allow_patterns (`list[str]` or `str`, *optional*):
57
+ If provided, only files matching at least one pattern are uploaded.
58
+ ignore_patterns (`list[str]` or `str`, *optional*):
59
+ If provided, files matching any of the patterns are not uploaded.
60
+ squash_history (`bool`, *optional*):
61
+ Whether to squash the history of the repo after each commit. Defaults to `False`. Squashing commits is
62
+ useful to avoid degraded performances on the repo when it grows too large.
63
+ hf_api (`HfApi`, *optional*):
64
+ The [`HfApi`] client to use to commit to the Hub. Can be set with custom settings (user agent, token,...).
65
+
66
+ Example:
67
+ ```py
68
+ >>> from pathlib import Path
69
+ >>> from huggingface_hub import CommitScheduler
70
+
71
+ # Scheduler uploads every 10 minutes
72
+ >>> csv_path = Path("watched_folder/data.csv")
73
+ >>> CommitScheduler(repo_id="test_scheduler", repo_type="dataset", folder_path=csv_path.parent, every=10)
74
+
75
+ >>> with csv_path.open("a") as f:
76
+ ... f.write("first line")
77
+
78
+ # Some time later (...)
79
+ >>> with csv_path.open("a") as f:
80
+ ... f.write("second line")
81
+ ```
82
+
83
+ Example using a context manager:
84
+ ```py
85
+ >>> from pathlib import Path
86
+ >>> from huggingface_hub import CommitScheduler
87
+
88
+ >>> with CommitScheduler(repo_id="test_scheduler", repo_type="dataset", folder_path="watched_folder", every=10) as scheduler:
89
+ ... csv_path = Path("watched_folder/data.csv")
90
+ ... with csv_path.open("a") as f:
91
+ ... f.write("first line")
92
+ ... (...)
93
+ ... with csv_path.open("a") as f:
94
+ ... f.write("second line")
95
+
96
+ # Scheduler is now stopped and last commit have been triggered
97
+ ```
98
+ """
99
+
100
+ def __init__(
101
+ self,
102
+ *,
103
+ repo_id: str,
104
+ folder_path: Union[str, Path],
105
+ every: Union[int, float] = 5,
106
+ path_in_repo: Optional[str] = None,
107
+ repo_type: Optional[str] = None,
108
+ revision: Optional[str] = None,
109
+ private: Optional[bool] = None,
110
+ token: Optional[str] = None,
111
+ allow_patterns: Optional[Union[list[str], str]] = None,
112
+ ignore_patterns: Optional[Union[list[str], str]] = None,
113
+ squash_history: bool = False,
114
+ hf_api: Optional["HfApi"] = None,
115
+ ) -> None:
116
+ self.api = hf_api or HfApi(token=token)
117
+
118
+ # Folder
119
+ self.folder_path = Path(folder_path).expanduser().resolve()
120
+ self.path_in_repo = path_in_repo or ""
121
+ self.allow_patterns = allow_patterns
122
+
123
+ if ignore_patterns is None:
124
+ ignore_patterns = []
125
+ elif isinstance(ignore_patterns, str):
126
+ ignore_patterns = [ignore_patterns]
127
+ self.ignore_patterns = ignore_patterns + DEFAULT_IGNORE_PATTERNS
128
+
129
+ if self.folder_path.is_file():
130
+ raise ValueError(f"'folder_path' must be a directory, not a file: '{self.folder_path}'.")
131
+ self.folder_path.mkdir(parents=True, exist_ok=True)
132
+
133
+ # Repository
134
+ repo_url = self.api.create_repo(repo_id=repo_id, private=private, repo_type=repo_type, exist_ok=True)
135
+ self.repo_id = repo_url.repo_id
136
+ self.repo_type = repo_type
137
+ self.revision = revision
138
+ self.token = token
139
+
140
+ # Keep track of already uploaded files
141
+ self.last_uploaded: dict[Path, float] = {} # key is local path, value is timestamp
142
+
143
+ # Scheduler
144
+ if not every > 0:
145
+ raise ValueError(f"'every' must be a positive integer, not '{every}'.")
146
+ self.lock = Lock()
147
+ self.every = every
148
+ self.squash_history = squash_history
149
+
150
+ logger.info(f"Scheduled job to push '{self.folder_path}' to '{self.repo_id}' every {self.every} minutes.")
151
+ self._scheduler_thread = Thread(target=self._run_scheduler, daemon=True)
152
+ self._scheduler_thread.start()
153
+ atexit.register(self._push_to_hub)
154
+
155
+ self.__stopped = False
156
+
157
+ def stop(self) -> None:
158
+ """Stop the scheduler.
159
+
160
+ A stopped scheduler cannot be restarted. Mostly for tests purposes.
161
+ """
162
+ self.__stopped = True
163
+
164
+ def __enter__(self) -> "CommitScheduler":
165
+ return self
166
+
167
+ def __exit__(self, exc_type, exc_value, traceback) -> None:
168
+ # Upload last changes before exiting
169
+ self.trigger().result()
170
+ self.stop()
171
+ return
172
+
173
+ def _run_scheduler(self) -> None:
174
+ """Dumb thread waiting between each scheduled push to Hub."""
175
+ while True:
176
+ self.last_future = self.trigger()
177
+ time.sleep(self.every * 60)
178
+ if self.__stopped:
179
+ break
180
+
181
+ def trigger(self) -> Future:
182
+ """Trigger a `push_to_hub` and return a future.
183
+
184
+ This method is automatically called every `every` minutes. You can also call it manually to trigger a commit
185
+ immediately, without waiting for the next scheduled commit.
186
+ """
187
+ return self.api.run_as_future(self._push_to_hub)
188
+
189
+ def _push_to_hub(self) -> Optional[CommitInfo]:
190
+ if self.__stopped: # If stopped, already scheduled commits are ignored
191
+ return None
192
+
193
+ logger.info("(Background) scheduled commit triggered.")
194
+ try:
195
+ value = self.push_to_hub()
196
+ if self.squash_history:
197
+ logger.info("(Background) squashing repo history.")
198
+ self.api.super_squash_history(repo_id=self.repo_id, repo_type=self.repo_type, branch=self.revision)
199
+ return value
200
+ except Exception as e:
201
+ logger.error(f"Error while pushing to Hub: {e}") # Depending on the setup, error might be silenced
202
+ raise
203
+
204
+ def push_to_hub(self) -> Optional[CommitInfo]:
205
+ """
206
+ Push folder to the Hub and return the commit info.
207
+
208
+ > [!WARNING]
209
+ > This method is not meant to be called directly. It is run in the background by the scheduler, respecting a
210
+ > queue mechanism to avoid concurrent commits. Making a direct call to the method might lead to concurrency
211
+ > issues.
212
+
213
+ The default behavior of `push_to_hub` is to assume an append-only folder. It lists all files in the folder and
214
+ uploads only changed files. If no changes are found, the method returns without committing anything. If you want
215
+ to change this behavior, you can inherit from [`CommitScheduler`] and override this method. This can be useful
216
+ for example to compress data together in a single file before committing. For more details and examples, check
217
+ out our [integration guide](https://huggingface.co/docs/huggingface_hub/main/en/guides/upload#scheduled-uploads).
218
+ """
219
+ # Check files to upload (with lock)
220
+ with self.lock:
221
+ logger.debug("Listing files to upload for scheduled commit.")
222
+
223
+ # List files from folder (taken from `_prepare_upload_folder_additions`)
224
+ relpath_to_abspath = {
225
+ path.relative_to(self.folder_path).as_posix(): path
226
+ for path in sorted(self.folder_path.glob("**/*")) # sorted to be deterministic
227
+ if path.is_file()
228
+ }
229
+ prefix = f"{self.path_in_repo.strip('/')}/" if self.path_in_repo else ""
230
+
231
+ # Filter with pattern + filter out unchanged files + retrieve current file size
232
+ files_to_upload: list[_FileToUpload] = []
233
+ for relpath in filter_repo_objects(
234
+ relpath_to_abspath.keys(), allow_patterns=self.allow_patterns, ignore_patterns=self.ignore_patterns
235
+ ):
236
+ local_path = relpath_to_abspath[relpath]
237
+ stat = local_path.stat()
238
+ if self.last_uploaded.get(local_path) is None or self.last_uploaded[local_path] != stat.st_mtime:
239
+ files_to_upload.append(
240
+ _FileToUpload(
241
+ local_path=local_path,
242
+ path_in_repo=prefix + relpath,
243
+ size_limit=stat.st_size,
244
+ last_modified=stat.st_mtime,
245
+ )
246
+ )
247
+
248
+ # Return if nothing to upload
249
+ if len(files_to_upload) == 0:
250
+ logger.debug("Dropping schedule commit: no changed file to upload.")
251
+ return None
252
+
253
+ # Convert `_FileToUpload` as `CommitOperationAdd` (=> compute file shas + limit to file size)
254
+ logger.debug("Removing unchanged files since previous scheduled commit.")
255
+ add_operations = [
256
+ CommitOperationAdd(
257
+ # Cap the file to its current size, even if the user append data to it while a scheduled commit is happening
258
+ path_or_fileobj=PartialFileIO(file_to_upload.local_path, size_limit=file_to_upload.size_limit),
259
+ path_in_repo=file_to_upload.path_in_repo,
260
+ )
261
+ for file_to_upload in files_to_upload
262
+ ]
263
+
264
+ # Upload files (append mode expected - no need for lock)
265
+ logger.debug("Uploading files for scheduled commit.")
266
+ commit_info = self.api.create_commit(
267
+ repo_id=self.repo_id,
268
+ repo_type=self.repo_type,
269
+ operations=add_operations,
270
+ commit_message="Scheduled Commit",
271
+ revision=self.revision,
272
+ )
273
+
274
+ # Successful commit: keep track of the latest "last_modified" for each file
275
+ for file in files_to_upload:
276
+ self.last_uploaded[file.local_path] = file.last_modified
277
+ return commit_info
278
+
279
+
280
+ class PartialFileIO(BytesIO):
281
+ """A file-like object that reads only the first part of a file.
282
+
283
+ Useful to upload a file to the Hub when the user might still be appending data to it. Only the first part of the
284
+ file is uploaded (i.e. the part that was available when the filesystem was first scanned).
285
+
286
+ In practice, only used internally by the CommitScheduler to regularly push a folder to the Hub with minimal
287
+ disturbance for the user. The object is passed to `CommitOperationAdd`.
288
+
289
+ Only supports `read`, `tell` and `seek` methods.
290
+
291
+ Args:
292
+ file_path (`str` or `Path`):
293
+ Path to the file to read.
294
+ size_limit (`int`):
295
+ The maximum number of bytes to read from the file. If the file is larger than this, only the first part
296
+ will be read (and uploaded).
297
+ """
298
+
299
+ def __init__(self, file_path: Union[str, Path], size_limit: int) -> None:
300
+ self._file_path = Path(file_path)
301
+ self._file = self._file_path.open("rb")
302
+ self._size_limit = min(size_limit, os.fstat(self._file.fileno()).st_size)
303
+
304
+ def __del__(self) -> None:
305
+ self._file.close()
306
+ return super().__del__()
307
+
308
+ def __repr__(self) -> str:
309
+ return f"<PartialFileIO file_path={self._file_path} size_limit={self._size_limit}>"
310
+
311
+ def __len__(self) -> int:
312
+ return self._size_limit
313
+
314
+ def __getattribute__(self, name: str):
315
+ if name.startswith("_") or name in ("read", "tell", "seek", "fileno"): # only 4 public methods supported
316
+ return super().__getattribute__(name)
317
+ raise NotImplementedError(f"PartialFileIO does not support '{name}'.")
318
+
319
+ def fileno(self):
320
+ raise AttributeError("PartialFileIO does not have a fileno.")
321
+
322
+ def tell(self) -> int:
323
+ """Return the current file position."""
324
+ return self._file.tell()
325
+
326
+ def seek(self, __offset: int, __whence: int = SEEK_SET) -> int:
327
+ """Change the stream position to the given offset.
328
+
329
+ Behavior is the same as a regular file, except that the position is capped to the size limit.
330
+ """
331
+ if __whence == SEEK_END:
332
+ # SEEK_END => set from the truncated end
333
+ __offset = len(self) + __offset
334
+ __whence = SEEK_SET
335
+
336
+ pos = self._file.seek(__offset, __whence)
337
+ if pos > self._size_limit:
338
+ return self._file.seek(self._size_limit)
339
+ return pos
340
+
341
+ def read(self, __size: Optional[int] = -1) -> bytes:
342
+ """Read at most `__size` bytes from the file.
343
+
344
+ Behavior is the same as a regular file, except that it is capped to the size limit.
345
+ """
346
+ current = self._file.tell()
347
+ if __size is None or __size < 0:
348
+ # Read until file limit
349
+ truncated_size = self._size_limit - current
350
+ else:
351
+ # Read until file limit or __size
352
+ truncated_size = min(__size, self._size_limit - current)
353
+ return self._file.read(truncated_size)
env/lib/python3.13/site-packages/huggingface_hub/_inference_endpoints.py ADDED
@@ -0,0 +1,418 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import time
2
+ from dataclasses import dataclass, field
3
+ from datetime import datetime
4
+ from enum import Enum
5
+ from typing import TYPE_CHECKING, Optional, Union
6
+
7
+ from huggingface_hub.errors import InferenceEndpointError, InferenceEndpointTimeoutError
8
+
9
+ from .utils import get_session, logging, parse_datetime
10
+
11
+
12
+ if TYPE_CHECKING:
13
+ from .hf_api import HfApi
14
+ from .inference._client import InferenceClient
15
+ from .inference._generated._async_client import AsyncInferenceClient
16
+
17
+ logger = logging.get_logger(__name__)
18
+
19
+
20
+ class InferenceEndpointStatus(str, Enum):
21
+ PENDING = "pending"
22
+ INITIALIZING = "initializing"
23
+ UPDATING = "updating"
24
+ UPDATE_FAILED = "updateFailed"
25
+ RUNNING = "running"
26
+ PAUSED = "paused"
27
+ FAILED = "failed"
28
+ SCALED_TO_ZERO = "scaledToZero"
29
+
30
+
31
+ class InferenceEndpointType(str, Enum):
32
+ PUBlIC = "public"
33
+ PROTECTED = "protected"
34
+ PRIVATE = "private"
35
+
36
+
37
+ class InferenceEndpointScalingMetric(str, Enum):
38
+ PENDING_REQUESTS = "pendingRequests"
39
+ HARDWARE_USAGE = "hardwareUsage"
40
+
41
+
42
+ @dataclass
43
+ class InferenceEndpoint:
44
+ """
45
+ Contains information about a deployed Inference Endpoint.
46
+
47
+ Args:
48
+ name (`str`):
49
+ The unique name of the Inference Endpoint.
50
+ namespace (`str`):
51
+ The namespace where the Inference Endpoint is located.
52
+ repository (`str`):
53
+ The name of the model repository deployed on this Inference Endpoint.
54
+ status ([`InferenceEndpointStatus`]):
55
+ The current status of the Inference Endpoint.
56
+ url (`str`, *optional*):
57
+ The URL of the Inference Endpoint, if available. Only a deployed Inference Endpoint will have a URL.
58
+ framework (`str`):
59
+ The machine learning framework used for the model.
60
+ revision (`str`):
61
+ The specific model revision deployed on the Inference Endpoint.
62
+ task (`str`):
63
+ The task associated with the deployed model.
64
+ created_at (`datetime.datetime`):
65
+ The timestamp when the Inference Endpoint was created.
66
+ updated_at (`datetime.datetime`):
67
+ The timestamp of the last update of the Inference Endpoint.
68
+ type ([`InferenceEndpointType`]):
69
+ The type of the Inference Endpoint (public, protected, private).
70
+ raw (`dict`):
71
+ The raw dictionary data returned from the API.
72
+ token (`str` or `bool`, *optional*):
73
+ Authentication token for the Inference Endpoint, if set when requesting the API. Will default to the
74
+ locally saved token if not provided. Pass `token=False` if you don't want to send your token to the server.
75
+
76
+ Example:
77
+ ```python
78
+ >>> from huggingface_hub import get_inference_endpoint
79
+ >>> endpoint = get_inference_endpoint("my-text-to-image")
80
+ >>> endpoint
81
+ InferenceEndpoint(name='my-text-to-image', ...)
82
+
83
+ # Get status
84
+ >>> endpoint.status
85
+ 'running'
86
+ >>> endpoint.url
87
+ 'https://my-text-to-image.region.vendor.endpoints.huggingface.cloud'
88
+
89
+ # Run inference
90
+ >>> endpoint.client.text_to_image(...)
91
+
92
+ # Pause endpoint to save $$$
93
+ >>> endpoint.pause()
94
+
95
+ # ...
96
+ # Resume and wait for deployment
97
+ >>> endpoint.resume()
98
+ >>> endpoint.wait()
99
+ >>> endpoint.client.text_to_image(...)
100
+ ```
101
+ """
102
+
103
+ # Field in __repr__
104
+ name: str = field(init=False)
105
+ namespace: str
106
+ repository: str = field(init=False)
107
+ status: InferenceEndpointStatus = field(init=False)
108
+ health_route: str = field(init=False)
109
+ url: Optional[str] = field(init=False)
110
+
111
+ # Other fields
112
+ framework: str = field(repr=False, init=False)
113
+ revision: str = field(repr=False, init=False)
114
+ task: str = field(repr=False, init=False)
115
+ created_at: datetime = field(repr=False, init=False)
116
+ updated_at: datetime = field(repr=False, init=False)
117
+ type: InferenceEndpointType = field(repr=False, init=False)
118
+
119
+ # Raw dict from the API
120
+ raw: dict = field(repr=False)
121
+
122
+ # Internal fields
123
+ _token: Union[str, bool, None] = field(repr=False, compare=False)
124
+ _api: "HfApi" = field(repr=False, compare=False)
125
+
126
+ @classmethod
127
+ def from_raw(
128
+ cls, raw: dict, namespace: str, token: Union[str, bool, None] = None, api: Optional["HfApi"] = None
129
+ ) -> "InferenceEndpoint":
130
+ """Initialize object from raw dictionary."""
131
+ if api is None:
132
+ from .hf_api import HfApi
133
+
134
+ api = HfApi()
135
+ if token is None:
136
+ token = api.token
137
+
138
+ # All other fields are populated in __post_init__
139
+ return cls(raw=raw, namespace=namespace, _token=token, _api=api)
140
+
141
+ def __post_init__(self) -> None:
142
+ """Populate fields from raw dictionary."""
143
+ self._populate_from_raw()
144
+
145
+ @property
146
+ def client(self) -> "InferenceClient":
147
+ """Returns a client to make predictions on this Inference Endpoint.
148
+
149
+ Returns:
150
+ [`InferenceClient`]: an inference client pointing to the deployed endpoint.
151
+
152
+ Raises:
153
+ [`InferenceEndpointError`]: If the Inference Endpoint is not yet deployed.
154
+ """
155
+ if self.url is None:
156
+ raise InferenceEndpointError(
157
+ "Cannot create a client for this Inference Endpoint as it is not yet deployed. "
158
+ "Please wait for the Inference Endpoint to be deployed using `endpoint.wait()` and try again."
159
+ )
160
+ from .inference._client import InferenceClient
161
+
162
+ return InferenceClient(
163
+ model=self.url,
164
+ token=self._token, # type: ignore[arg-type] # boolean token shouldn't be possible. In practice it's ok.
165
+ )
166
+
167
+ @property
168
+ def async_client(self) -> "AsyncInferenceClient":
169
+ """Returns a client to make predictions on this Inference Endpoint.
170
+
171
+ Returns:
172
+ [`AsyncInferenceClient`]: an asyncio-compatible inference client pointing to the deployed endpoint.
173
+
174
+ Raises:
175
+ [`InferenceEndpointError`]: If the Inference Endpoint is not yet deployed.
176
+ """
177
+ if self.url is None:
178
+ raise InferenceEndpointError(
179
+ "Cannot create a client for this Inference Endpoint as it is not yet deployed. "
180
+ "Please wait for the Inference Endpoint to be deployed using `endpoint.wait()` and try again."
181
+ )
182
+ from .inference._generated._async_client import AsyncInferenceClient
183
+
184
+ return AsyncInferenceClient(
185
+ model=self.url,
186
+ token=self._token, # type: ignore[arg-type] # boolean token shouldn't be possible. In practice it's ok.
187
+ )
188
+
189
+ def wait(self, timeout: Optional[int] = None, refresh_every: int = 5) -> "InferenceEndpoint":
190
+ """Wait for the Inference Endpoint to be deployed.
191
+
192
+ Information from the server will be fetched every 1s. If the Inference Endpoint is not deployed after `timeout`
193
+ seconds, a [`InferenceEndpointTimeoutError`] will be raised. The [`InferenceEndpoint`] will be mutated in place with the latest
194
+ data.
195
+
196
+ Args:
197
+ timeout (`int`, *optional*):
198
+ The maximum time to wait for the Inference Endpoint to be deployed, in seconds. If `None`, will wait
199
+ indefinitely.
200
+ refresh_every (`int`, *optional*):
201
+ The time to wait between each fetch of the Inference Endpoint status, in seconds. Defaults to 5s.
202
+
203
+ Returns:
204
+ [`InferenceEndpoint`]: the same Inference Endpoint, mutated in place with the latest data.
205
+
206
+ Raises:
207
+ [`InferenceEndpointError`]
208
+ If the Inference Endpoint ended up in a failed state.
209
+ [`InferenceEndpointTimeoutError`]
210
+ If the Inference Endpoint is not deployed after `timeout` seconds.
211
+ """
212
+ if timeout is not None and timeout < 0:
213
+ raise ValueError("`timeout` cannot be negative.")
214
+ if refresh_every <= 0:
215
+ raise ValueError("`refresh_every` must be positive.")
216
+
217
+ start = time.time()
218
+ while True:
219
+ if self.status == InferenceEndpointStatus.FAILED:
220
+ raise InferenceEndpointError(
221
+ f"Inference Endpoint {self.name} failed to deploy. Please check the logs for more information."
222
+ )
223
+ if self.status == InferenceEndpointStatus.UPDATE_FAILED:
224
+ raise InferenceEndpointError(
225
+ f"Inference Endpoint {self.name} failed to update. Please check the logs for more information."
226
+ )
227
+ if self.status == InferenceEndpointStatus.RUNNING and self.url is not None:
228
+ # Verify the endpoint is actually reachable
229
+ _health_url = f"{self.url.rstrip('/')}/{self.health_route.lstrip('/')}"
230
+ response = get_session().get(_health_url, headers=self._api._build_hf_headers(token=self._token))
231
+ if response.status_code == 200:
232
+ logger.info("Inference Endpoint is ready to be used.")
233
+ return self
234
+
235
+ if timeout is not None:
236
+ if time.time() - start > timeout:
237
+ raise InferenceEndpointTimeoutError("Timeout while waiting for Inference Endpoint to be deployed.")
238
+ logger.info(f"Inference Endpoint is not deployed yet ({self.status}). Waiting {refresh_every}s...")
239
+ time.sleep(refresh_every)
240
+ self.fetch()
241
+
242
+ def fetch(self) -> "InferenceEndpoint":
243
+ """Fetch latest information about the Inference Endpoint.
244
+
245
+ Returns:
246
+ [`InferenceEndpoint`]: the same Inference Endpoint, mutated in place with the latest data.
247
+ """
248
+ obj = self._api.get_inference_endpoint(name=self.name, namespace=self.namespace, token=self._token) # type: ignore [arg-type]
249
+ self.raw = obj.raw
250
+ self._populate_from_raw()
251
+ return self
252
+
253
+ def update(
254
+ self,
255
+ *,
256
+ # Compute update
257
+ accelerator: Optional[str] = None,
258
+ instance_size: Optional[str] = None,
259
+ instance_type: Optional[str] = None,
260
+ min_replica: Optional[int] = None,
261
+ max_replica: Optional[int] = None,
262
+ scale_to_zero_timeout: Optional[int] = None,
263
+ # Model update
264
+ repository: Optional[str] = None,
265
+ framework: Optional[str] = None,
266
+ revision: Optional[str] = None,
267
+ task: Optional[str] = None,
268
+ custom_image: Optional[dict] = None,
269
+ secrets: Optional[dict[str, str]] = None,
270
+ ) -> "InferenceEndpoint":
271
+ """Update the Inference Endpoint.
272
+
273
+ This method allows the update of either the compute configuration, the deployed model, or both. All arguments are
274
+ optional but at least one must be provided.
275
+
276
+ This is an alias for [`HfApi.update_inference_endpoint`]. The current object is mutated in place with the
277
+ latest data from the server.
278
+
279
+ Args:
280
+ accelerator (`str`, *optional*):
281
+ The hardware accelerator to be used for inference (e.g. `"cpu"`).
282
+ instance_size (`str`, *optional*):
283
+ The size or type of the instance to be used for hosting the model (e.g. `"x4"`).
284
+ instance_type (`str`, *optional*):
285
+ The cloud instance type where the Inference Endpoint will be deployed (e.g. `"intel-icl"`).
286
+ min_replica (`int`, *optional*):
287
+ The minimum number of replicas (instances) to keep running for the Inference Endpoint.
288
+ max_replica (`int`, *optional*):
289
+ The maximum number of replicas (instances) to scale to for the Inference Endpoint.
290
+ scale_to_zero_timeout (`int`, *optional*):
291
+ The duration in minutes before an inactive endpoint is scaled to zero.
292
+
293
+ repository (`str`, *optional*):
294
+ The name of the model repository associated with the Inference Endpoint (e.g. `"gpt2"`).
295
+ framework (`str`, *optional*):
296
+ The machine learning framework used for the model (e.g. `"custom"`).
297
+ revision (`str`, *optional*):
298
+ The specific model revision to deploy on the Inference Endpoint (e.g. `"6c0e6080953db56375760c0471a8c5f2929baf11"`).
299
+ task (`str`, *optional*):
300
+ The task on which to deploy the model (e.g. `"text-classification"`).
301
+ custom_image (`dict`, *optional*):
302
+ A custom Docker image to use for the Inference Endpoint. This is useful if you want to deploy an
303
+ Inference Endpoint running on the `text-generation-inference` (TGI) framework (see examples).
304
+ secrets (`dict[str, str]`, *optional*):
305
+ Secret values to inject in the container environment.
306
+ Returns:
307
+ [`InferenceEndpoint`]: the same Inference Endpoint, mutated in place with the latest data.
308
+ """
309
+ # Make API call
310
+ obj = self._api.update_inference_endpoint(
311
+ name=self.name,
312
+ namespace=self.namespace,
313
+ accelerator=accelerator,
314
+ instance_size=instance_size,
315
+ instance_type=instance_type,
316
+ min_replica=min_replica,
317
+ max_replica=max_replica,
318
+ scale_to_zero_timeout=scale_to_zero_timeout,
319
+ repository=repository,
320
+ framework=framework,
321
+ revision=revision,
322
+ task=task,
323
+ custom_image=custom_image,
324
+ secrets=secrets,
325
+ token=self._token, # type: ignore [arg-type]
326
+ )
327
+
328
+ # Mutate current object
329
+ self.raw = obj.raw
330
+ self._populate_from_raw()
331
+ return self
332
+
333
+ def pause(self) -> "InferenceEndpoint":
334
+ """Pause the Inference Endpoint.
335
+
336
+ A paused Inference Endpoint will not be charged. It can be resumed at any time using [`InferenceEndpoint.resume`].
337
+ This is different from scaling the Inference Endpoint to zero with [`InferenceEndpoint.scale_to_zero`], which
338
+ would be automatically restarted when a request is made to it.
339
+
340
+ This is an alias for [`HfApi.pause_inference_endpoint`]. The current object is mutated in place with the
341
+ latest data from the server.
342
+
343
+ Returns:
344
+ [`InferenceEndpoint`]: the same Inference Endpoint, mutated in place with the latest data.
345
+ """
346
+ obj = self._api.pause_inference_endpoint(name=self.name, namespace=self.namespace, token=self._token) # type: ignore [arg-type]
347
+ self.raw = obj.raw
348
+ self._populate_from_raw()
349
+ return self
350
+
351
+ def resume(self, running_ok: bool = True) -> "InferenceEndpoint":
352
+ """Resume the Inference Endpoint.
353
+
354
+ This is an alias for [`HfApi.resume_inference_endpoint`]. The current object is mutated in place with the
355
+ latest data from the server.
356
+
357
+ Args:
358
+ running_ok (`bool`, *optional*):
359
+ If `True`, the method will not raise an error if the Inference Endpoint is already running. Defaults to
360
+ `True`.
361
+
362
+ Returns:
363
+ [`InferenceEndpoint`]: the same Inference Endpoint, mutated in place with the latest data.
364
+ """
365
+ obj = self._api.resume_inference_endpoint(
366
+ name=self.name, namespace=self.namespace, running_ok=running_ok, token=self._token
367
+ ) # type: ignore [arg-type]
368
+ self.raw = obj.raw
369
+ self._populate_from_raw()
370
+ return self
371
+
372
+ def scale_to_zero(self) -> "InferenceEndpoint":
373
+ """Scale Inference Endpoint to zero.
374
+
375
+ An Inference Endpoint scaled to zero will not be charged. It will be resumed on the next request to it, with a
376
+ cold start delay. This is different from pausing the Inference Endpoint with [`InferenceEndpoint.pause`], which
377
+ would require a manual resume with [`InferenceEndpoint.resume`].
378
+
379
+ This is an alias for [`HfApi.scale_to_zero_inference_endpoint`]. The current object is mutated in place with the
380
+ latest data from the server.
381
+
382
+ Returns:
383
+ [`InferenceEndpoint`]: the same Inference Endpoint, mutated in place with the latest data.
384
+ """
385
+ obj = self._api.scale_to_zero_inference_endpoint(name=self.name, namespace=self.namespace, token=self._token) # type: ignore [arg-type]
386
+ self.raw = obj.raw
387
+ self._populate_from_raw()
388
+ return self
389
+
390
+ def delete(self) -> None:
391
+ """Delete the Inference Endpoint.
392
+
393
+ This operation is not reversible. If you don't want to be charged for an Inference Endpoint, it is preferable
394
+ to pause it with [`InferenceEndpoint.pause`] or scale it to zero with [`InferenceEndpoint.scale_to_zero`].
395
+
396
+ This is an alias for [`HfApi.delete_inference_endpoint`].
397
+ """
398
+ self._api.delete_inference_endpoint(name=self.name, namespace=self.namespace, token=self._token) # type: ignore [arg-type]
399
+
400
+ def _populate_from_raw(self) -> None:
401
+ """Populate fields from raw dictionary.
402
+
403
+ Called in __post_init__ + each time the Inference Endpoint is updated.
404
+ """
405
+ # Repr fields
406
+ self.name = self.raw["name"]
407
+ self.repository = self.raw["model"]["repository"]
408
+ self.status = self.raw["status"]["state"]
409
+ self.url = self.raw["status"].get("url")
410
+ self.health_route = self.raw["healthRoute"]
411
+
412
+ # Other fields
413
+ self.framework = self.raw["model"]["framework"]
414
+ self.revision = self.raw["model"]["revision"]
415
+ self.task = self.raw["model"]["task"]
416
+ self.created_at = parse_datetime(self.raw["status"]["createdAt"])
417
+ self.updated_at = parse_datetime(self.raw["status"]["updatedAt"])
418
+ self.type = self.raw["type"]
env/lib/python3.13/site-packages/huggingface_hub/_jobs_api.py ADDED
@@ -0,0 +1,301 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding=utf-8
2
+ # Copyright 2025-present, the HuggingFace Inc. team.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ from dataclasses import dataclass
16
+ from datetime import datetime
17
+ from enum import Enum
18
+ from typing import Any, Optional, Union
19
+
20
+ from huggingface_hub import constants
21
+ from huggingface_hub._space_api import SpaceHardware
22
+ from huggingface_hub.utils._datetime import parse_datetime
23
+
24
+
25
+ class JobStage(str, Enum):
26
+ """
27
+ Enumeration of possible stage of a Job on the Hub.
28
+
29
+ Value can be compared to a string:
30
+ ```py
31
+ assert JobStage.COMPLETED == "COMPLETED"
32
+ ```
33
+ Possible values are: `COMPLETED`, `CANCELED`, `ERROR`, `DELETED`, `RUNNING`.
34
+ Taken from https://github.com/huggingface/moon-landing/blob/main/server/job_types/JobInfo.ts#L61 (private url).
35
+ """
36
+
37
+ # Copied from moon-landing > server > lib > Job.ts
38
+ COMPLETED = "COMPLETED"
39
+ CANCELED = "CANCELED"
40
+ ERROR = "ERROR"
41
+ DELETED = "DELETED"
42
+ RUNNING = "RUNNING"
43
+
44
+
45
+ @dataclass
46
+ class JobStatus:
47
+ stage: JobStage
48
+ message: Optional[str]
49
+
50
+
51
+ @dataclass
52
+ class JobOwner:
53
+ id: str
54
+ name: str
55
+ type: str
56
+
57
+
58
+ @dataclass
59
+ class JobInfo:
60
+ """
61
+ Contains information about a Job.
62
+
63
+ Args:
64
+ id (`str`):
65
+ Job ID.
66
+ created_at (`datetime` or `None`):
67
+ When the Job was created.
68
+ docker_image (`str` or `None`):
69
+ The Docker image from Docker Hub used for the Job.
70
+ Can be None if space_id is present instead.
71
+ space_id (`str` or `None`):
72
+ The Docker image from Hugging Face Spaces used for the Job.
73
+ Can be None if docker_image is present instead.
74
+ command (`list[str]` or `None`):
75
+ Command of the Job, e.g. `["python", "-c", "print('hello world')"]`
76
+ arguments (`list[str]` or `None`):
77
+ Arguments passed to the command
78
+ environment (`dict[str]` or `None`):
79
+ Environment variables of the Job as a dictionary.
80
+ secrets (`dict[str]` or `None`):
81
+ Secret environment variables of the Job (encrypted).
82
+ flavor (`str` or `None`):
83
+ Flavor for the hardware, as in Hugging Face Spaces. See [`SpaceHardware`] for possible values.
84
+ E.g. `"cpu-basic"`.
85
+ status: (`JobStatus` or `None`):
86
+ Status of the Job, e.g. `JobStatus(stage="RUNNING", message=None)`
87
+ See [`JobStage`] for possible stage values.
88
+ owner: (`JobOwner` or `None`):
89
+ Owner of the Job, e.g. `JobOwner(id="5e9ecfc04957053f60648a3e", name="lhoestq", type="user")`
90
+
91
+ Example:
92
+
93
+ ```python
94
+ >>> from huggingface_hub import run_job
95
+ >>> job = run_job(
96
+ ... image="python:3.12",
97
+ ... command=["python", "-c", "print('Hello from the cloud!')"]
98
+ ... )
99
+ >>> job
100
+ JobInfo(id='687fb701029421ae5549d998', created_at=datetime.datetime(2025, 7, 22, 16, 6, 25, 79000, tzinfo=datetime.timezone.utc), docker_image='python:3.12', space_id=None, command=['python', '-c', "print('Hello from the cloud!')"], arguments=[], environment={}, secrets={}, flavor='cpu-basic', status=JobStatus(stage='RUNNING', message=None), owner=JobOwner(id='5e9ecfc04957053f60648a3e', name='lhoestq', type='user'), endpoint='https://huggingface.co', url='https://huggingface.co/jobs/lhoestq/687fb701029421ae5549d998')
101
+ >>> job.id
102
+ '687fb701029421ae5549d998'
103
+ >>> job.url
104
+ 'https://huggingface.co/jobs/lhoestq/687fb701029421ae5549d998'
105
+ >>> job.status.stage
106
+ 'RUNNING'
107
+ ```
108
+ """
109
+
110
+ id: str
111
+ created_at: Optional[datetime]
112
+ docker_image: Optional[str]
113
+ space_id: Optional[str]
114
+ command: Optional[list[str]]
115
+ arguments: Optional[list[str]]
116
+ environment: Optional[dict[str, Any]]
117
+ secrets: Optional[dict[str, Any]]
118
+ flavor: Optional[SpaceHardware]
119
+ status: JobStatus
120
+ owner: JobOwner
121
+
122
+ # Inferred fields
123
+ endpoint: str
124
+ url: str
125
+
126
+ def __init__(self, **kwargs) -> None:
127
+ self.id = kwargs["id"]
128
+ created_at = kwargs.get("createdAt") or kwargs.get("created_at")
129
+ self.created_at = parse_datetime(created_at) if created_at else None
130
+ self.docker_image = kwargs.get("dockerImage") or kwargs.get("docker_image")
131
+ self.space_id = kwargs.get("spaceId") or kwargs.get("space_id")
132
+ owner = kwargs.get("owner", {})
133
+ self.owner = JobOwner(id=owner["id"], name=owner["name"], type=owner["type"])
134
+ self.command = kwargs.get("command")
135
+ self.arguments = kwargs.get("arguments")
136
+ self.environment = kwargs.get("environment")
137
+ self.secrets = kwargs.get("secrets")
138
+ self.flavor = kwargs.get("flavor")
139
+ status = kwargs.get("status", {})
140
+ self.status = JobStatus(stage=status["stage"], message=status.get("message"))
141
+
142
+ # Inferred fields
143
+ self.endpoint = kwargs.get("endpoint", constants.ENDPOINT)
144
+ self.url = f"{self.endpoint}/jobs/{self.owner.name}/{self.id}"
145
+
146
+
147
+ @dataclass
148
+ class JobSpec:
149
+ docker_image: Optional[str]
150
+ space_id: Optional[str]
151
+ command: Optional[list[str]]
152
+ arguments: Optional[list[str]]
153
+ environment: Optional[dict[str, Any]]
154
+ secrets: Optional[dict[str, Any]]
155
+ flavor: Optional[SpaceHardware]
156
+ timeout: Optional[int]
157
+ tags: Optional[list[str]]
158
+ arch: Optional[str]
159
+
160
+ def __init__(self, **kwargs) -> None:
161
+ self.docker_image = kwargs.get("dockerImage") or kwargs.get("docker_image")
162
+ self.space_id = kwargs.get("spaceId") or kwargs.get("space_id")
163
+ self.command = kwargs.get("command")
164
+ self.arguments = kwargs.get("arguments")
165
+ self.environment = kwargs.get("environment")
166
+ self.secrets = kwargs.get("secrets")
167
+ self.flavor = kwargs.get("flavor")
168
+ self.timeout = kwargs.get("timeout")
169
+ self.tags = kwargs.get("tags")
170
+ self.arch = kwargs.get("arch")
171
+
172
+
173
+ @dataclass
174
+ class LastJobInfo:
175
+ id: str
176
+ at: datetime
177
+
178
+ def __init__(self, **kwargs) -> None:
179
+ self.id = kwargs["id"]
180
+ self.at = parse_datetime(kwargs["at"])
181
+
182
+
183
+ @dataclass
184
+ class ScheduledJobStatus:
185
+ last_job: Optional[LastJobInfo]
186
+ next_job_run_at: Optional[datetime]
187
+
188
+ def __init__(self, **kwargs) -> None:
189
+ last_job = kwargs.get("lastJob") or kwargs.get("last_job")
190
+ self.last_job = LastJobInfo(**last_job) if last_job else None
191
+ next_job_run_at = kwargs.get("nextJobRunAt") or kwargs.get("next_job_run_at")
192
+ self.next_job_run_at = parse_datetime(str(next_job_run_at)) if next_job_run_at else None
193
+
194
+
195
+ @dataclass
196
+ class ScheduledJobInfo:
197
+ """
198
+ Contains information about a Job.
199
+
200
+ Args:
201
+ id (`str`):
202
+ Scheduled Job ID.
203
+ created_at (`datetime` or `None`):
204
+ When the scheduled Job was created.
205
+ tags (`list[str]` or `None`):
206
+ The tags of the scheduled Job.
207
+ schedule (`str` or `None`):
208
+ One of "@annually", "@yearly", "@monthly", "@weekly", "@daily", "@hourly", or a
209
+ CRON schedule expression (e.g., '0 9 * * 1' for 9 AM every Monday).
210
+ suspend (`bool` or `None`):
211
+ Whether the scheduled job is suspended (paused).
212
+ concurrency (`bool` or `None`):
213
+ Whether multiple instances of this Job can run concurrently.
214
+ status (`ScheduledJobStatus` or `None`):
215
+ Status of the scheduled Job.
216
+ owner: (`JobOwner` or `None`):
217
+ Owner of the scheduled Job, e.g. `JobOwner(id="5e9ecfc04957053f60648a3e", name="lhoestq", type="user")`
218
+ job_spec: (`JobSpec` or `None`):
219
+ Specifications of the Job.
220
+
221
+ Example:
222
+
223
+ ```python
224
+ >>> from huggingface_hub import run_job
225
+ >>> scheduled_job = create_scheduled_job(
226
+ ... image="python:3.12",
227
+ ... command=["python", "-c", "print('Hello from the cloud!')"],
228
+ ... schedule="@hourly",
229
+ ... )
230
+ >>> scheduled_job.id
231
+ '687fb701029421ae5549d999'
232
+ >>> scheduled_job.status.next_job_run_at
233
+ datetime.datetime(2025, 7, 22, 17, 6, 25, 79000, tzinfo=datetime.timezone.utc)
234
+ ```
235
+ """
236
+
237
+ id: str
238
+ created_at: Optional[datetime]
239
+ job_spec: JobSpec
240
+ schedule: Optional[str]
241
+ suspend: Optional[bool]
242
+ concurrency: Optional[bool]
243
+ status: ScheduledJobStatus
244
+ owner: JobOwner
245
+
246
+ def __init__(self, **kwargs) -> None:
247
+ self.id = kwargs["id"]
248
+ created_at = kwargs.get("createdAt") or kwargs.get("created_at")
249
+ self.created_at = parse_datetime(created_at) if created_at else None
250
+ self.job_spec = JobSpec(**(kwargs.get("job_spec") or kwargs.get("jobSpec", {})))
251
+ self.schedule = kwargs.get("schedule")
252
+ self.suspend = kwargs.get("suspend")
253
+ self.concurrency = kwargs.get("concurrency")
254
+ status = kwargs.get("status", {})
255
+ self.status = ScheduledJobStatus(
256
+ last_job=status.get("last_job") or status.get("lastJob"),
257
+ next_job_run_at=status.get("next_job_run_at") or status.get("nextJobRunAt"),
258
+ )
259
+ owner = kwargs.get("owner", {})
260
+ self.owner = JobOwner(id=owner["id"], name=owner["name"], type=owner["type"])
261
+
262
+
263
+ def _create_job_spec(
264
+ *,
265
+ image: str,
266
+ command: list[str],
267
+ env: Optional[dict[str, Any]],
268
+ secrets: Optional[dict[str, Any]],
269
+ flavor: Optional[SpaceHardware],
270
+ timeout: Optional[Union[int, float, str]],
271
+ ) -> dict[str, Any]:
272
+ # prepare job spec to send to HF Jobs API
273
+ job_spec: dict[str, Any] = {
274
+ "command": command,
275
+ "arguments": [],
276
+ "environment": env or {},
277
+ "flavor": flavor or SpaceHardware.CPU_BASIC,
278
+ }
279
+ # secrets are optional
280
+ if secrets:
281
+ job_spec["secrets"] = secrets
282
+ # timeout is optional
283
+ if timeout:
284
+ time_units_factors = {"s": 1, "m": 60, "h": 3600, "d": 3600 * 24}
285
+ if isinstance(timeout, str) and timeout[-1] in time_units_factors:
286
+ job_spec["timeoutSeconds"] = int(float(timeout[:-1]) * time_units_factors[timeout[-1]])
287
+ else:
288
+ job_spec["timeoutSeconds"] = int(timeout)
289
+ # input is either from docker hub or from HF spaces
290
+ for prefix in (
291
+ "https://huggingface.co/spaces/",
292
+ "https://hf.co/spaces/",
293
+ "huggingface.co/spaces/",
294
+ "hf.co/spaces/",
295
+ ):
296
+ if image.startswith(prefix):
297
+ job_spec["spaceId"] = image[len(prefix) :]
298
+ break
299
+ else:
300
+ job_spec["dockerImage"] = image
301
+ return job_spec
env/lib/python3.13/site-packages/huggingface_hub/_local_folder.py ADDED
@@ -0,0 +1,447 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding=utf-8
2
+ # Copyright 2024-present, the HuggingFace Inc. team.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ """Contains utilities to handle the `../.cache/huggingface` folder in local directories.
16
+
17
+ First discussed in https://github.com/huggingface/huggingface_hub/issues/1738 to store
18
+ download metadata when downloading files from the hub to a local directory (without
19
+ using the cache).
20
+
21
+ ./.cache/huggingface folder structure:
22
+ [4.0K] data
23
+ ├── [4.0K] .cache
24
+ │ └── [4.0K] huggingface
25
+ │ └── [4.0K] download
26
+ │ ├── [ 16] file.parquet.metadata
27
+ │ ├── [ 16] file.txt.metadata
28
+ │ └── [4.0K] folder
29
+ │ └── [ 16] file.parquet.metadata
30
+
31
+ ├── [6.5G] file.parquet
32
+ ├── [1.5K] file.txt
33
+ └── [4.0K] folder
34
+ └── [ 16] file.parquet
35
+
36
+
37
+ Download metadata file structure:
38
+ ```
39
+ # file.txt.metadata
40
+ 11c5a3d5811f50298f278a704980280950aedb10
41
+ a16a55fda99d2f2e7b69cce5cf93ff4ad3049930
42
+ 1712656091.123
43
+
44
+ # file.parquet.metadata
45
+ 11c5a3d5811f50298f278a704980280950aedb10
46
+ 7c5d3f4b8b76583b422fcb9189ad6c89d5d97a094541ce8932dce3ecabde1421
47
+ 1712656091.123
48
+ }
49
+ ```
50
+ """
51
+
52
+ import base64
53
+ import hashlib
54
+ import logging
55
+ import os
56
+ import time
57
+ from dataclasses import dataclass
58
+ from pathlib import Path
59
+ from typing import Optional
60
+
61
+ from .utils import WeakFileLock
62
+
63
+
64
+ logger = logging.getLogger(__name__)
65
+
66
+
67
+ @dataclass
68
+ class LocalDownloadFilePaths:
69
+ """
70
+ Paths to the files related to a download process in a local dir.
71
+
72
+ Returned by [`get_local_download_paths`].
73
+
74
+ Attributes:
75
+ file_path (`Path`):
76
+ Path where the file will be saved.
77
+ lock_path (`Path`):
78
+ Path to the lock file used to ensure atomicity when reading/writing metadata.
79
+ metadata_path (`Path`):
80
+ Path to the metadata file.
81
+ """
82
+
83
+ file_path: Path
84
+ lock_path: Path
85
+ metadata_path: Path
86
+
87
+ def incomplete_path(self, etag: str) -> Path:
88
+ """Return the path where a file will be temporarily downloaded before being moved to `file_path`."""
89
+ path = self.metadata_path.parent / f"{_short_hash(self.metadata_path.name)}.{etag}.incomplete"
90
+ resolved_path = str(path.resolve())
91
+ # Some Windows versions do not allow for paths longer than 255 characters.
92
+ # In this case, we must specify it as an extended path by using the "\\?\" prefix.
93
+ if os.name == "nt" and len(resolved_path) > 255 and not resolved_path.startswith("\\\\?\\"):
94
+ path = Path("\\\\?\\" + resolved_path)
95
+ return path
96
+
97
+
98
+ @dataclass(frozen=True)
99
+ class LocalUploadFilePaths:
100
+ """
101
+ Paths to the files related to an upload process in a local dir.
102
+
103
+ Returned by [`get_local_upload_paths`].
104
+
105
+ Attributes:
106
+ path_in_repo (`str`):
107
+ Path of the file in the repo.
108
+ file_path (`Path`):
109
+ Path where the file will be saved.
110
+ lock_path (`Path`):
111
+ Path to the lock file used to ensure atomicity when reading/writing metadata.
112
+ metadata_path (`Path`):
113
+ Path to the metadata file.
114
+ """
115
+
116
+ path_in_repo: str
117
+ file_path: Path
118
+ lock_path: Path
119
+ metadata_path: Path
120
+
121
+
122
+ @dataclass
123
+ class LocalDownloadFileMetadata:
124
+ """
125
+ Metadata about a file in the local directory related to a download process.
126
+
127
+ Attributes:
128
+ filename (`str`):
129
+ Path of the file in the repo.
130
+ commit_hash (`str`):
131
+ Commit hash of the file in the repo.
132
+ etag (`str`):
133
+ ETag of the file in the repo. Used to check if the file has changed.
134
+ For LFS files, this is the sha256 of the file. For regular files, it corresponds to the git hash.
135
+ timestamp (`int`):
136
+ Unix timestamp of when the metadata was saved i.e. when the metadata was accurate.
137
+ """
138
+
139
+ filename: str
140
+ commit_hash: str
141
+ etag: str
142
+ timestamp: float
143
+
144
+
145
+ @dataclass
146
+ class LocalUploadFileMetadata:
147
+ """
148
+ Metadata about a file in the local directory related to an upload process.
149
+ """
150
+
151
+ size: int
152
+
153
+ # Default values correspond to "we don't know yet"
154
+ timestamp: Optional[float] = None
155
+ should_ignore: Optional[bool] = None
156
+ sha256: Optional[str] = None
157
+ upload_mode: Optional[str] = None
158
+ remote_oid: Optional[str] = None
159
+ is_uploaded: bool = False
160
+ is_committed: bool = False
161
+
162
+ def save(self, paths: LocalUploadFilePaths) -> None:
163
+ """Save the metadata to disk."""
164
+ with WeakFileLock(paths.lock_path):
165
+ with paths.metadata_path.open("w") as f:
166
+ new_timestamp = time.time()
167
+ f.write(str(new_timestamp) + "\n")
168
+
169
+ f.write(str(self.size)) # never None
170
+ f.write("\n")
171
+
172
+ if self.should_ignore is not None:
173
+ f.write(str(int(self.should_ignore)))
174
+ f.write("\n")
175
+
176
+ if self.sha256 is not None:
177
+ f.write(self.sha256)
178
+ f.write("\n")
179
+
180
+ if self.upload_mode is not None:
181
+ f.write(self.upload_mode)
182
+ f.write("\n")
183
+
184
+ if self.remote_oid is not None:
185
+ f.write(self.remote_oid)
186
+ f.write("\n")
187
+
188
+ f.write(str(int(self.is_uploaded)) + "\n")
189
+ f.write(str(int(self.is_committed)) + "\n")
190
+
191
+ self.timestamp = new_timestamp
192
+
193
+
194
+ def get_local_download_paths(local_dir: Path, filename: str) -> LocalDownloadFilePaths:
195
+ """Compute paths to the files related to a download process.
196
+
197
+ Folders containing the paths are all guaranteed to exist.
198
+
199
+ Args:
200
+ local_dir (`Path`):
201
+ Path to the local directory in which files are downloaded.
202
+ filename (`str`):
203
+ Path of the file in the repo.
204
+
205
+ Return:
206
+ [`LocalDownloadFilePaths`]: the paths to the files (file_path, lock_path, metadata_path, incomplete_path).
207
+ """
208
+ # filename is the path in the Hub repository (separated by '/')
209
+ # make sure to have a cross-platform transcription
210
+ sanitized_filename = os.path.join(*filename.split("/"))
211
+ if os.name == "nt":
212
+ if sanitized_filename.startswith("..\\") or "\\..\\" in sanitized_filename:
213
+ raise ValueError(
214
+ f"Invalid filename: cannot handle filename '{sanitized_filename}' on Windows. Please ask the repository"
215
+ " owner to rename this file."
216
+ )
217
+ file_path = local_dir / sanitized_filename
218
+ metadata_path = _huggingface_dir(local_dir) / "download" / f"{sanitized_filename}.metadata"
219
+ lock_path = metadata_path.with_suffix(".lock")
220
+
221
+ # Some Windows versions do not allow for paths longer than 255 characters.
222
+ # In this case, we must specify it as an extended path by using the "\\?\" prefix
223
+ if os.name == "nt":
224
+ if not str(local_dir).startswith("\\\\?\\") and len(os.path.abspath(lock_path)) > 255:
225
+ file_path = Path("\\\\?\\" + os.path.abspath(file_path))
226
+ lock_path = Path("\\\\?\\" + os.path.abspath(lock_path))
227
+ metadata_path = Path("\\\\?\\" + os.path.abspath(metadata_path))
228
+
229
+ file_path.parent.mkdir(parents=True, exist_ok=True)
230
+ metadata_path.parent.mkdir(parents=True, exist_ok=True)
231
+ return LocalDownloadFilePaths(file_path=file_path, lock_path=lock_path, metadata_path=metadata_path)
232
+
233
+
234
+ def get_local_upload_paths(local_dir: Path, filename: str) -> LocalUploadFilePaths:
235
+ """Compute paths to the files related to an upload process.
236
+
237
+ Folders containing the paths are all guaranteed to exist.
238
+
239
+ Args:
240
+ local_dir (`Path`):
241
+ Path to the local directory that is uploaded.
242
+ filename (`str`):
243
+ Path of the file in the repo.
244
+
245
+ Return:
246
+ [`LocalUploadFilePaths`]: the paths to the files (file_path, lock_path, metadata_path).
247
+ """
248
+ # filename is the path in the Hub repository (separated by '/')
249
+ # make sure to have a cross-platform transcription
250
+ sanitized_filename = os.path.join(*filename.split("/"))
251
+ if os.name == "nt":
252
+ if sanitized_filename.startswith("..\\") or "\\..\\" in sanitized_filename:
253
+ raise ValueError(
254
+ f"Invalid filename: cannot handle filename '{sanitized_filename}' on Windows. Please ask the repository"
255
+ " owner to rename this file."
256
+ )
257
+ file_path = local_dir / sanitized_filename
258
+ metadata_path = _huggingface_dir(local_dir) / "upload" / f"{sanitized_filename}.metadata"
259
+ lock_path = metadata_path.with_suffix(".lock")
260
+
261
+ # Some Windows versions do not allow for paths longer than 255 characters.
262
+ # In this case, we must specify it as an extended path by using the "\\?\" prefix
263
+ if os.name == "nt":
264
+ if not str(local_dir).startswith("\\\\?\\") and len(os.path.abspath(lock_path)) > 255:
265
+ file_path = Path("\\\\?\\" + os.path.abspath(file_path))
266
+ lock_path = Path("\\\\?\\" + os.path.abspath(lock_path))
267
+ metadata_path = Path("\\\\?\\" + os.path.abspath(metadata_path))
268
+
269
+ file_path.parent.mkdir(parents=True, exist_ok=True)
270
+ metadata_path.parent.mkdir(parents=True, exist_ok=True)
271
+ return LocalUploadFilePaths(
272
+ path_in_repo=filename, file_path=file_path, lock_path=lock_path, metadata_path=metadata_path
273
+ )
274
+
275
+
276
+ def read_download_metadata(local_dir: Path, filename: str) -> Optional[LocalDownloadFileMetadata]:
277
+ """Read metadata about a file in the local directory related to a download process.
278
+
279
+ Args:
280
+ local_dir (`Path`):
281
+ Path to the local directory in which files are downloaded.
282
+ filename (`str`):
283
+ Path of the file in the repo.
284
+
285
+ Return:
286
+ `[LocalDownloadFileMetadata]` or `None`: the metadata if it exists, `None` otherwise.
287
+ """
288
+ paths = get_local_download_paths(local_dir, filename)
289
+ with WeakFileLock(paths.lock_path):
290
+ if paths.metadata_path.exists():
291
+ try:
292
+ with paths.metadata_path.open() as f:
293
+ commit_hash = f.readline().strip()
294
+ etag = f.readline().strip()
295
+ timestamp = float(f.readline().strip())
296
+ metadata = LocalDownloadFileMetadata(
297
+ filename=filename,
298
+ commit_hash=commit_hash,
299
+ etag=etag,
300
+ timestamp=timestamp,
301
+ )
302
+ except Exception as e:
303
+ # remove the metadata file if it is corrupted / not the right format
304
+ logger.warning(
305
+ f"Invalid metadata file {paths.metadata_path}: {e}. Removing it from disk and continue."
306
+ )
307
+ try:
308
+ paths.metadata_path.unlink()
309
+ except Exception as e:
310
+ logger.warning(f"Could not remove corrupted metadata file {paths.metadata_path}: {e}")
311
+
312
+ try:
313
+ # check if the file exists and hasn't been modified since the metadata was saved
314
+ stat = paths.file_path.stat()
315
+ if (
316
+ stat.st_mtime - 1 <= metadata.timestamp
317
+ ): # allow 1s difference as stat.st_mtime might not be precise
318
+ return metadata
319
+ logger.info(f"Ignored metadata for '{filename}' (outdated). Will re-compute hash.")
320
+ except FileNotFoundError:
321
+ # file does not exist => metadata is outdated
322
+ return None
323
+ return None
324
+
325
+
326
+ def read_upload_metadata(local_dir: Path, filename: str) -> LocalUploadFileMetadata:
327
+ """Read metadata about a file in the local directory related to an upload process.
328
+
329
+ TODO: factorize logic with `read_download_metadata`.
330
+
331
+ Args:
332
+ local_dir (`Path`):
333
+ Path to the local directory in which files are downloaded.
334
+ filename (`str`):
335
+ Path of the file in the repo.
336
+
337
+ Return:
338
+ `[LocalUploadFileMetadata]` or `None`: the metadata if it exists, `None` otherwise.
339
+ """
340
+ paths = get_local_upload_paths(local_dir, filename)
341
+ with WeakFileLock(paths.lock_path):
342
+ if paths.metadata_path.exists():
343
+ try:
344
+ with paths.metadata_path.open() as f:
345
+ timestamp = float(f.readline().strip())
346
+
347
+ size = int(f.readline().strip()) # never None
348
+
349
+ _should_ignore = f.readline().strip()
350
+ should_ignore = None if _should_ignore == "" else bool(int(_should_ignore))
351
+
352
+ _sha256 = f.readline().strip()
353
+ sha256 = None if _sha256 == "" else _sha256
354
+
355
+ _upload_mode = f.readline().strip()
356
+ upload_mode = None if _upload_mode == "" else _upload_mode
357
+ if upload_mode not in (None, "regular", "lfs"):
358
+ raise ValueError(f"Invalid upload mode in metadata {paths.path_in_repo}: {upload_mode}")
359
+
360
+ _remote_oid = f.readline().strip()
361
+ remote_oid = None if _remote_oid == "" else _remote_oid
362
+
363
+ is_uploaded = bool(int(f.readline().strip()))
364
+ is_committed = bool(int(f.readline().strip()))
365
+
366
+ metadata = LocalUploadFileMetadata(
367
+ timestamp=timestamp,
368
+ size=size,
369
+ should_ignore=should_ignore,
370
+ sha256=sha256,
371
+ upload_mode=upload_mode,
372
+ remote_oid=remote_oid,
373
+ is_uploaded=is_uploaded,
374
+ is_committed=is_committed,
375
+ )
376
+ except Exception as e:
377
+ # remove the metadata file if it is corrupted / not the right format
378
+ logger.warning(
379
+ f"Invalid metadata file {paths.metadata_path}: {e}. Removing it from disk and continue."
380
+ )
381
+ try:
382
+ paths.metadata_path.unlink()
383
+ except Exception as e:
384
+ logger.warning(f"Could not remove corrupted metadata file {paths.metadata_path}: {e}")
385
+
386
+ # TODO: can we do better?
387
+ if (
388
+ metadata.timestamp is not None
389
+ and metadata.is_uploaded # file was uploaded
390
+ and not metadata.is_committed # but not committed
391
+ and time.time() - metadata.timestamp > 20 * 3600 # and it's been more than 20 hours
392
+ ): # => we consider it as garbage-collected by S3
393
+ metadata.is_uploaded = False
394
+
395
+ # check if the file exists and hasn't been modified since the metadata was saved
396
+ try:
397
+ if metadata.timestamp is not None and paths.file_path.stat().st_mtime <= metadata.timestamp:
398
+ return metadata
399
+ logger.info(f"Ignored metadata for '{filename}' (outdated). Will re-compute hash.")
400
+ except FileNotFoundError:
401
+ # file does not exist => metadata is outdated
402
+ pass
403
+
404
+ # empty metadata => we don't know anything expect its size
405
+ return LocalUploadFileMetadata(size=paths.file_path.stat().st_size)
406
+
407
+
408
+ def write_download_metadata(local_dir: Path, filename: str, commit_hash: str, etag: str) -> None:
409
+ """Write metadata about a file in the local directory related to a download process.
410
+
411
+ Args:
412
+ local_dir (`Path`):
413
+ Path to the local directory in which files are downloaded.
414
+ """
415
+ paths = get_local_download_paths(local_dir, filename)
416
+ with WeakFileLock(paths.lock_path):
417
+ with paths.metadata_path.open("w") as f:
418
+ f.write(f"{commit_hash}\n{etag}\n{time.time()}\n")
419
+
420
+
421
+ def _huggingface_dir(local_dir: Path) -> Path:
422
+ """Return the path to the `.cache/huggingface` directory in a local directory."""
423
+ # Wrap in lru_cache to avoid overwriting the .gitignore file if called multiple times
424
+ path = local_dir / ".cache" / "huggingface"
425
+ path.mkdir(exist_ok=True, parents=True)
426
+
427
+ # Create a .gitignore file in the .cache/huggingface directory if it doesn't exist
428
+ # Should be thread-safe enough like this.
429
+ gitignore = path / ".gitignore"
430
+ gitignore_lock = path / ".gitignore.lock"
431
+ if not gitignore.exists():
432
+ try:
433
+ with WeakFileLock(gitignore_lock, timeout=0.1):
434
+ gitignore.write_text("*")
435
+ except IndexError:
436
+ pass
437
+ except OSError: # TimeoutError, FileNotFoundError, PermissionError, etc.
438
+ pass
439
+ try:
440
+ gitignore_lock.unlink()
441
+ except OSError:
442
+ pass
443
+ return path
444
+
445
+
446
+ def _short_hash(filename: str) -> str:
447
+ return base64.urlsafe_b64encode(hashlib.sha1(filename.encode()).digest()).decode()
env/lib/python3.13/site-packages/huggingface_hub/_oauth.py ADDED
@@ -0,0 +1,460 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import datetime
2
+ import hashlib
3
+ import logging
4
+ import os
5
+ import time
6
+ import urllib.parse
7
+ import warnings
8
+ from dataclasses import dataclass
9
+ from typing import TYPE_CHECKING, Literal, Optional, Union
10
+
11
+ from . import constants
12
+ from .hf_api import whoami
13
+ from .utils import experimental, get_token
14
+
15
+
16
+ logger = logging.getLogger(__name__)
17
+
18
+ if TYPE_CHECKING:
19
+ import fastapi
20
+
21
+
22
+ @dataclass
23
+ class OAuthOrgInfo:
24
+ """
25
+ Information about an organization linked to a user logged in with OAuth.
26
+
27
+ Attributes:
28
+ sub (`str`):
29
+ Unique identifier for the org. OpenID Connect field.
30
+ name (`str`):
31
+ The org's full name. OpenID Connect field.
32
+ preferred_username (`str`):
33
+ The org's username. OpenID Connect field.
34
+ picture (`str`):
35
+ The org's profile picture URL. OpenID Connect field.
36
+ is_enterprise (`bool`):
37
+ Whether the org is an enterprise org. Hugging Face field.
38
+ can_pay (`Optional[bool]`, *optional*):
39
+ Whether the org has a payment method set up. Hugging Face field.
40
+ role_in_org (`Optional[str]`, *optional*):
41
+ The user's role in the org. Hugging Face field.
42
+ security_restrictions (`Optional[list[Literal["ip", "token-policy", "mfa", "sso"]]]`, *optional*):
43
+ Array of security restrictions that the user hasn't completed for this org. Possible values: "ip", "token-policy", "mfa", "sso". Hugging Face field.
44
+ """
45
+
46
+ sub: str
47
+ name: str
48
+ preferred_username: str
49
+ picture: str
50
+ is_enterprise: bool
51
+ can_pay: Optional[bool] = None
52
+ role_in_org: Optional[str] = None
53
+ security_restrictions: Optional[list[Literal["ip", "token-policy", "mfa", "sso"]]] = None
54
+
55
+
56
+ @dataclass
57
+ class OAuthUserInfo:
58
+ """
59
+ Information about a user logged in with OAuth.
60
+
61
+ Attributes:
62
+ sub (`str`):
63
+ Unique identifier for the user, even in case of rename. OpenID Connect field.
64
+ name (`str`):
65
+ The user's full name. OpenID Connect field.
66
+ preferred_username (`str`):
67
+ The user's username. OpenID Connect field.
68
+ email_verified (`Optional[bool]`, *optional*):
69
+ Indicates if the user's email is verified. OpenID Connect field.
70
+ email (`Optional[str]`, *optional*):
71
+ The user's email address. OpenID Connect field.
72
+ picture (`str`):
73
+ The user's profile picture URL. OpenID Connect field.
74
+ profile (`str`):
75
+ The user's profile URL. OpenID Connect field.
76
+ website (`Optional[str]`, *optional*):
77
+ The user's website URL. OpenID Connect field.
78
+ is_pro (`bool`):
79
+ Whether the user is a pro user. Hugging Face field.
80
+ can_pay (`Optional[bool]`, *optional*):
81
+ Whether the user has a payment method set up. Hugging Face field.
82
+ orgs (`Optional[list[OrgInfo]]`, *optional*):
83
+ List of organizations the user is part of. Hugging Face field.
84
+ """
85
+
86
+ sub: str
87
+ name: str
88
+ preferred_username: str
89
+ email_verified: Optional[bool]
90
+ email: Optional[str]
91
+ picture: str
92
+ profile: str
93
+ website: Optional[str]
94
+ is_pro: bool
95
+ can_pay: Optional[bool]
96
+ orgs: Optional[list[OAuthOrgInfo]]
97
+
98
+
99
+ @dataclass
100
+ class OAuthInfo:
101
+ """
102
+ Information about the OAuth login.
103
+
104
+ Attributes:
105
+ access_token (`str`):
106
+ The access token.
107
+ access_token_expires_at (`datetime.datetime`):
108
+ The expiration date of the access token.
109
+ user_info ([`OAuthUserInfo`]):
110
+ The user information.
111
+ state (`str`, *optional*):
112
+ State passed to the OAuth provider in the original request to the OAuth provider.
113
+ scope (`str`):
114
+ Granted scope.
115
+ """
116
+
117
+ access_token: str
118
+ access_token_expires_at: datetime.datetime
119
+ user_info: OAuthUserInfo
120
+ state: Optional[str]
121
+ scope: str
122
+
123
+
124
+ @experimental
125
+ def attach_huggingface_oauth(app: "fastapi.FastAPI", route_prefix: str = "/"):
126
+ """
127
+ Add OAuth endpoints to a FastAPI app to enable OAuth login with Hugging Face.
128
+
129
+ How to use:
130
+ - Call this method on your FastAPI app to add the OAuth endpoints.
131
+ - Inside your route handlers, call `parse_huggingface_oauth(request)` to retrieve the OAuth info.
132
+ - If user is logged in, an [`OAuthInfo`] object is returned with the user's info. If not, `None` is returned.
133
+ - In your app, make sure to add links to `/oauth/huggingface/login` and `/oauth/huggingface/logout` for the user to log in and out.
134
+
135
+ Example:
136
+ ```py
137
+ from huggingface_hub import attach_huggingface_oauth, parse_huggingface_oauth
138
+
139
+ # Create a FastAPI app
140
+ app = FastAPI()
141
+
142
+ # Add OAuth endpoints to the FastAPI app
143
+ attach_huggingface_oauth(app)
144
+
145
+ # Add a route that greets the user if they are logged in
146
+ @app.get("/")
147
+ def greet_json(request: Request):
148
+ # Retrieve the OAuth info from the request
149
+ oauth_info = parse_huggingface_oauth(request) # e.g. OAuthInfo dataclass
150
+ if oauth_info is None:
151
+ return {"msg": "Not logged in!"}
152
+ return {"msg": f"Hello, {oauth_info.user_info.preferred_username}!"}
153
+ ```
154
+ """
155
+ # TODO: handle generic case (handling OAuth in a non-Space environment with custom dev values) (low priority)
156
+
157
+ # Add SessionMiddleware to the FastAPI app to store the OAuth info in the session.
158
+ # Session Middleware requires a secret key to sign the cookies. Let's use a hash
159
+ # of the OAuth secret key to make it unique to the Space + updated in case OAuth
160
+ # config gets updated. When ran locally, we use an empty string as a secret key.
161
+ try:
162
+ from starlette.middleware.sessions import SessionMiddleware
163
+ except ImportError as e:
164
+ raise ImportError(
165
+ "Cannot initialize OAuth to due a missing library. Please run `pip install huggingface_hub[oauth]` or add "
166
+ "`huggingface_hub[oauth]` to your requirements.txt file in order to install the required dependencies."
167
+ ) from e
168
+ session_secret = (constants.OAUTH_CLIENT_SECRET or "") + "-v1"
169
+ app.add_middleware(
170
+ SessionMiddleware, # type: ignore[arg-type]
171
+ secret_key=hashlib.sha256(session_secret.encode()).hexdigest(),
172
+ same_site="none",
173
+ https_only=True,
174
+ ) # type: ignore
175
+
176
+ # Add OAuth endpoints to the FastAPI app:
177
+ # - {route_prefix}/oauth/huggingface/login
178
+ # - {route_prefix}/oauth/huggingface/callback
179
+ # - {route_prefix}/oauth/huggingface/logout
180
+ # If the app is running in a Space, OAuth is enabled normally.
181
+ # Otherwise, we mock the endpoints to make the user log in with a fake user profile - without any calls to hf.co.
182
+ route_prefix = route_prefix.strip("/")
183
+ if os.getenv("SPACE_ID") is not None:
184
+ logger.info("OAuth is enabled in the Space. Adding OAuth routes.")
185
+ _add_oauth_routes(app, route_prefix=route_prefix)
186
+ else:
187
+ logger.info("App is not running in a Space. Adding mocked OAuth routes.")
188
+ _add_mocked_oauth_routes(app, route_prefix=route_prefix)
189
+
190
+
191
+ def parse_huggingface_oauth(request: "fastapi.Request") -> Optional[OAuthInfo]:
192
+ """
193
+ Returns the information from a logged-in user as a [`OAuthInfo`] object.
194
+
195
+ For flexibility and future-proofing, this method is very lax in its parsing and does not raise errors.
196
+ Missing fields are set to `None` without a warning.
197
+
198
+ Return `None`, if the user is not logged in (no info in session cookie).
199
+
200
+ See [`attach_huggingface_oauth`] for an example on how to use this method.
201
+ """
202
+ if "oauth_info" not in request.session:
203
+ logger.debug("No OAuth info in session.")
204
+ return None
205
+
206
+ logger.debug("Parsing OAuth info from session.")
207
+ oauth_data = request.session["oauth_info"]
208
+ user_data = oauth_data.get("userinfo", {})
209
+ orgs_data = user_data.get("orgs", [])
210
+
211
+ orgs = (
212
+ [
213
+ OAuthOrgInfo(
214
+ sub=org.get("sub"),
215
+ name=org.get("name"),
216
+ preferred_username=org.get("preferred_username"),
217
+ picture=org.get("picture"),
218
+ is_enterprise=org.get("isEnterprise"),
219
+ can_pay=org.get("canPay"),
220
+ role_in_org=org.get("roleInOrg"),
221
+ security_restrictions=org.get("securityRestrictions"),
222
+ )
223
+ for org in orgs_data
224
+ ]
225
+ if orgs_data
226
+ else None
227
+ )
228
+
229
+ user_info = OAuthUserInfo(
230
+ sub=user_data.get("sub"),
231
+ name=user_data.get("name"),
232
+ preferred_username=user_data.get("preferred_username"),
233
+ email_verified=user_data.get("email_verified"),
234
+ email=user_data.get("email"),
235
+ picture=user_data.get("picture"),
236
+ profile=user_data.get("profile"),
237
+ website=user_data.get("website"),
238
+ is_pro=user_data.get("isPro"),
239
+ can_pay=user_data.get("canPay"),
240
+ orgs=orgs,
241
+ )
242
+
243
+ return OAuthInfo(
244
+ access_token=oauth_data.get("access_token"),
245
+ access_token_expires_at=datetime.datetime.fromtimestamp(oauth_data.get("expires_at")),
246
+ user_info=user_info,
247
+ state=oauth_data.get("state"),
248
+ scope=oauth_data.get("scope"),
249
+ )
250
+
251
+
252
+ def _add_oauth_routes(app: "fastapi.FastAPI", route_prefix: str) -> None:
253
+ """Add OAuth routes to the FastAPI app (login, callback handler and logout)."""
254
+ try:
255
+ import fastapi
256
+ from authlib.integrations.base_client.errors import MismatchingStateError
257
+ from authlib.integrations.starlette_client import OAuth
258
+ from fastapi.responses import RedirectResponse
259
+ except ImportError as e:
260
+ raise ImportError(
261
+ "Cannot initialize OAuth to due a missing library. Please run `pip install huggingface_hub[oauth]` or add "
262
+ "`huggingface_hub[oauth]` to your requirements.txt file."
263
+ ) from e
264
+
265
+ # Check environment variables
266
+ msg = (
267
+ "OAuth is required but '{}' environment variable is not set. Make sure you've enabled OAuth in your Space by"
268
+ " setting `hf_oauth: true` in the Space metadata."
269
+ )
270
+ if constants.OAUTH_CLIENT_ID is None:
271
+ raise ValueError(msg.format("OAUTH_CLIENT_ID"))
272
+ if constants.OAUTH_CLIENT_SECRET is None:
273
+ raise ValueError(msg.format("OAUTH_CLIENT_SECRET"))
274
+ if constants.OAUTH_SCOPES is None:
275
+ raise ValueError(msg.format("OAUTH_SCOPES"))
276
+ if constants.OPENID_PROVIDER_URL is None:
277
+ raise ValueError(msg.format("OPENID_PROVIDER_URL"))
278
+
279
+ # Register OAuth server
280
+ oauth = OAuth()
281
+ oauth.register(
282
+ name="huggingface",
283
+ client_id=constants.OAUTH_CLIENT_ID,
284
+ client_secret=constants.OAUTH_CLIENT_SECRET,
285
+ client_kwargs={"scope": constants.OAUTH_SCOPES},
286
+ server_metadata_url=constants.OPENID_PROVIDER_URL + "/.well-known/openid-configuration",
287
+ )
288
+
289
+ login_uri, callback_uri, logout_uri = _get_oauth_uris(route_prefix)
290
+
291
+ # Register OAuth endpoints
292
+ @app.get(login_uri)
293
+ async def oauth_login(request: fastapi.Request) -> RedirectResponse:
294
+ """Endpoint that redirects to HF OAuth page."""
295
+ redirect_uri = _generate_redirect_uri(request)
296
+ return await oauth.huggingface.authorize_redirect(request, redirect_uri) # type: ignore
297
+
298
+ @app.get(callback_uri)
299
+ async def oauth_redirect_callback(request: fastapi.Request) -> RedirectResponse:
300
+ """Endpoint that handles the OAuth callback."""
301
+ try:
302
+ oauth_info = await oauth.huggingface.authorize_access_token(request) # type: ignore
303
+ except MismatchingStateError:
304
+ # Parse query params
305
+ nb_redirects = int(request.query_params.get("_nb_redirects", 0))
306
+ target_url = request.query_params.get("_target_url")
307
+
308
+ # Build redirect URI with the same query params as before and bump nb_redirects count
309
+ query_params: dict[str, Union[int, str]] = {"_nb_redirects": nb_redirects + 1}
310
+ if target_url:
311
+ query_params["_target_url"] = target_url
312
+
313
+ redirect_uri = f"{login_uri}?{urllib.parse.urlencode(query_params)}"
314
+
315
+ # If the user is redirected more than 3 times, it is very likely that the cookie is not working properly.
316
+ # (e.g. browser is blocking third-party cookies in iframe). In this case, redirect the user in the
317
+ # non-iframe view.
318
+ if nb_redirects > constants.OAUTH_MAX_REDIRECTS:
319
+ host = os.environ.get("SPACE_HOST")
320
+ if host is None: # cannot happen in a Space
321
+ raise RuntimeError(
322
+ "App is not running in a Space (SPACE_HOST environment variable is not set). Cannot redirect to non-iframe view."
323
+ ) from None
324
+ host_url = "https://" + host.rstrip("/")
325
+ return RedirectResponse(host_url + redirect_uri)
326
+
327
+ # Redirect the user to the login page again
328
+ return RedirectResponse(redirect_uri)
329
+
330
+ # OAuth login worked => store the user info in the session and redirect
331
+ logger.debug("Successfully logged in with OAuth. Storing user info in session.")
332
+ request.session["oauth_info"] = oauth_info
333
+ return RedirectResponse(_get_redirect_target(request))
334
+
335
+ @app.get(logout_uri)
336
+ async def oauth_logout(request: fastapi.Request) -> RedirectResponse:
337
+ """Endpoint that logs out the user (e.g. delete info from cookie session)."""
338
+ logger.debug("Logged out with OAuth. Removing user info from session.")
339
+ request.session.pop("oauth_info", None)
340
+ return RedirectResponse(_get_redirect_target(request))
341
+
342
+
343
+ def _add_mocked_oauth_routes(app: "fastapi.FastAPI", route_prefix: str = "/") -> None:
344
+ """Add fake oauth routes if app is run locally and OAuth is enabled.
345
+
346
+ Using OAuth will have the same behavior as in a Space but instead of authenticating with HF, a mocked user profile
347
+ is added to the session.
348
+ """
349
+ try:
350
+ import fastapi
351
+ from fastapi.responses import RedirectResponse
352
+ from starlette.datastructures import URL
353
+ except ImportError as e:
354
+ raise ImportError(
355
+ "Cannot initialize OAuth to due a missing library. Please run `pip install huggingface_hub[oauth]` or add "
356
+ "`huggingface_hub[oauth]` to your requirements.txt file."
357
+ ) from e
358
+
359
+ warnings.warn(
360
+ "OAuth is not supported outside of a Space environment. To help you debug your app locally, the oauth endpoints"
361
+ " are mocked to return your profile and token. To make it work, your machine must be logged in to Huggingface."
362
+ )
363
+ mocked_oauth_info = _get_mocked_oauth_info()
364
+
365
+ login_uri, callback_uri, logout_uri = _get_oauth_uris(route_prefix)
366
+
367
+ # Define OAuth routes
368
+ @app.get(login_uri)
369
+ async def oauth_login(request: fastapi.Request) -> RedirectResponse:
370
+ """Fake endpoint that redirects to HF OAuth page."""
371
+ # Define target (where to redirect after login)
372
+ redirect_uri = _generate_redirect_uri(request)
373
+ return RedirectResponse(callback_uri + "?" + urllib.parse.urlencode({"_target_url": redirect_uri}))
374
+
375
+ @app.get(callback_uri)
376
+ async def oauth_redirect_callback(request: fastapi.Request) -> RedirectResponse:
377
+ """Endpoint that handles the OAuth callback."""
378
+ request.session["oauth_info"] = mocked_oauth_info
379
+ return RedirectResponse(_get_redirect_target(request))
380
+
381
+ @app.get(logout_uri)
382
+ async def oauth_logout(request: fastapi.Request) -> RedirectResponse:
383
+ """Endpoint that logs out the user (e.g. delete cookie session)."""
384
+ request.session.pop("oauth_info", None)
385
+ logout_url = URL("/").include_query_params(**request.query_params)
386
+ return RedirectResponse(url=logout_url, status_code=302) # see https://github.com/gradio-app/gradio/pull/9659
387
+
388
+
389
+ def _generate_redirect_uri(request: "fastapi.Request") -> str:
390
+ if "_target_url" in request.query_params:
391
+ # if `_target_url` already in query params => respect it
392
+ target = request.query_params["_target_url"]
393
+ else:
394
+ # otherwise => keep query params
395
+ target = "/?" + urllib.parse.urlencode(request.query_params)
396
+
397
+ redirect_uri = request.url_for("oauth_redirect_callback").include_query_params(_target_url=target)
398
+ redirect_uri_as_str = str(redirect_uri)
399
+ if redirect_uri.netloc.endswith(".hf.space"):
400
+ # In Space, FastAPI redirect as http but we want https
401
+ redirect_uri_as_str = redirect_uri_as_str.replace("http://", "https://")
402
+ return redirect_uri_as_str
403
+
404
+
405
+ def _get_redirect_target(request: "fastapi.Request", default_target: str = "/") -> str:
406
+ return request.query_params.get("_target_url", default_target)
407
+
408
+
409
+ def _get_mocked_oauth_info() -> dict:
410
+ token = get_token()
411
+ if token is None:
412
+ raise ValueError(
413
+ "Your machine must be logged in to HF to debug an OAuth app locally. Please"
414
+ " run `hf auth login` or set `HF_TOKEN` as environment variable "
415
+ "with one of your access token. You can generate a new token in your "
416
+ "settings page (https://huggingface.co/settings/tokens)."
417
+ )
418
+
419
+ user = whoami()
420
+ if user["type"] != "user":
421
+ raise ValueError(
422
+ "Your machine is not logged in with a personal account. Please use a "
423
+ "personal access token. You can generate a new token in your settings page"
424
+ " (https://huggingface.co/settings/tokens)."
425
+ )
426
+
427
+ return {
428
+ "access_token": token,
429
+ "token_type": "bearer",
430
+ "expires_in": 8 * 60 * 60, # 8 hours
431
+ "id_token": "FOOBAR",
432
+ "scope": "openid profile",
433
+ "refresh_token": "hf_oauth__refresh_token",
434
+ "expires_at": int(time.time()) + 8 * 60 * 60, # 8 hours
435
+ "userinfo": {
436
+ "sub": "0123456789",
437
+ "name": user["fullname"],
438
+ "preferred_username": user["name"],
439
+ "profile": f"https://huggingface.co/{user['name']}",
440
+ "picture": user["avatarUrl"],
441
+ "website": "",
442
+ "aud": "00000000-0000-0000-0000-000000000000",
443
+ "auth_time": 1691672844,
444
+ "nonce": "aaaaaaaaaaaaaaaaaaa",
445
+ "iat": 1691672844,
446
+ "exp": 1691676444,
447
+ "iss": "https://huggingface.co",
448
+ },
449
+ }
450
+
451
+
452
+ def _get_oauth_uris(route_prefix: str = "/") -> tuple[str, str, str]:
453
+ route_prefix = route_prefix.strip("/")
454
+ if route_prefix:
455
+ route_prefix = f"/{route_prefix}"
456
+ return (
457
+ f"{route_prefix}/oauth/huggingface/login",
458
+ f"{route_prefix}/oauth/huggingface/callback",
459
+ f"{route_prefix}/oauth/huggingface/logout",
460
+ )
env/lib/python3.13/site-packages/huggingface_hub/_snapshot_download.py ADDED
@@ -0,0 +1,465 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from pathlib import Path
3
+ from typing import Iterable, List, Literal, Optional, Union, overload
4
+
5
+ import httpx
6
+ from tqdm.auto import tqdm as base_tqdm
7
+ from tqdm.contrib.concurrent import thread_map
8
+
9
+ from . import constants
10
+ from .errors import (
11
+ DryRunError,
12
+ GatedRepoError,
13
+ HfHubHTTPError,
14
+ LocalEntryNotFoundError,
15
+ RepositoryNotFoundError,
16
+ RevisionNotFoundError,
17
+ )
18
+ from .file_download import REGEX_COMMIT_HASH, DryRunFileInfo, hf_hub_download, repo_folder_name
19
+ from .hf_api import DatasetInfo, HfApi, ModelInfo, RepoFile, SpaceInfo
20
+ from .utils import OfflineModeIsEnabled, filter_repo_objects, is_tqdm_disabled, logging, validate_hf_hub_args
21
+ from .utils import tqdm as hf_tqdm
22
+
23
+
24
+ logger = logging.get_logger(__name__)
25
+
26
+ LARGE_REPO_THRESHOLD = 1000 # After this limit, we don't consider `repo_info.siblings` to be reliable enough
27
+
28
+
29
+ @overload
30
+ def snapshot_download(
31
+ repo_id: str,
32
+ *,
33
+ repo_type: Optional[str] = None,
34
+ revision: Optional[str] = None,
35
+ cache_dir: Union[str, Path, None] = None,
36
+ local_dir: Union[str, Path, None] = None,
37
+ library_name: Optional[str] = None,
38
+ library_version: Optional[str] = None,
39
+ user_agent: Optional[Union[dict, str]] = None,
40
+ etag_timeout: float = constants.DEFAULT_ETAG_TIMEOUT,
41
+ force_download: bool = False,
42
+ token: Optional[Union[bool, str]] = None,
43
+ local_files_only: bool = False,
44
+ allow_patterns: Optional[Union[list[str], str]] = None,
45
+ ignore_patterns: Optional[Union[list[str], str]] = None,
46
+ max_workers: int = 8,
47
+ tqdm_class: Optional[type[base_tqdm]] = None,
48
+ headers: Optional[dict[str, str]] = None,
49
+ endpoint: Optional[str] = None,
50
+ dry_run: Literal[False] = False,
51
+ ) -> str: ...
52
+
53
+
54
+ @overload
55
+ def snapshot_download(
56
+ repo_id: str,
57
+ *,
58
+ repo_type: Optional[str] = None,
59
+ revision: Optional[str] = None,
60
+ cache_dir: Union[str, Path, None] = None,
61
+ local_dir: Union[str, Path, None] = None,
62
+ library_name: Optional[str] = None,
63
+ library_version: Optional[str] = None,
64
+ user_agent: Optional[Union[dict, str]] = None,
65
+ etag_timeout: float = constants.DEFAULT_ETAG_TIMEOUT,
66
+ force_download: bool = False,
67
+ token: Optional[Union[bool, str]] = None,
68
+ local_files_only: bool = False,
69
+ allow_patterns: Optional[Union[list[str], str]] = None,
70
+ ignore_patterns: Optional[Union[list[str], str]] = None,
71
+ max_workers: int = 8,
72
+ tqdm_class: Optional[type[base_tqdm]] = None,
73
+ headers: Optional[dict[str, str]] = None,
74
+ endpoint: Optional[str] = None,
75
+ dry_run: Literal[True] = True,
76
+ ) -> list[DryRunFileInfo]: ...
77
+
78
+
79
+ @overload
80
+ def snapshot_download(
81
+ repo_id: str,
82
+ *,
83
+ repo_type: Optional[str] = None,
84
+ revision: Optional[str] = None,
85
+ cache_dir: Union[str, Path, None] = None,
86
+ local_dir: Union[str, Path, None] = None,
87
+ library_name: Optional[str] = None,
88
+ library_version: Optional[str] = None,
89
+ user_agent: Optional[Union[dict, str]] = None,
90
+ etag_timeout: float = constants.DEFAULT_ETAG_TIMEOUT,
91
+ force_download: bool = False,
92
+ token: Optional[Union[bool, str]] = None,
93
+ local_files_only: bool = False,
94
+ allow_patterns: Optional[Union[list[str], str]] = None,
95
+ ignore_patterns: Optional[Union[list[str], str]] = None,
96
+ max_workers: int = 8,
97
+ tqdm_class: Optional[type[base_tqdm]] = None,
98
+ headers: Optional[dict[str, str]] = None,
99
+ endpoint: Optional[str] = None,
100
+ dry_run: bool = False,
101
+ ) -> Union[str, list[DryRunFileInfo]]: ...
102
+
103
+
104
+ @validate_hf_hub_args
105
+ def snapshot_download(
106
+ repo_id: str,
107
+ *,
108
+ repo_type: Optional[str] = None,
109
+ revision: Optional[str] = None,
110
+ cache_dir: Union[str, Path, None] = None,
111
+ local_dir: Union[str, Path, None] = None,
112
+ library_name: Optional[str] = None,
113
+ library_version: Optional[str] = None,
114
+ user_agent: Optional[Union[dict, str]] = None,
115
+ etag_timeout: float = constants.DEFAULT_ETAG_TIMEOUT,
116
+ force_download: bool = False,
117
+ token: Optional[Union[bool, str]] = None,
118
+ local_files_only: bool = False,
119
+ allow_patterns: Optional[Union[list[str], str]] = None,
120
+ ignore_patterns: Optional[Union[list[str], str]] = None,
121
+ max_workers: int = 8,
122
+ tqdm_class: Optional[type[base_tqdm]] = None,
123
+ headers: Optional[dict[str, str]] = None,
124
+ endpoint: Optional[str] = None,
125
+ dry_run: bool = False,
126
+ ) -> Union[str, list[DryRunFileInfo]]:
127
+ """Download repo files.
128
+
129
+ Download a whole snapshot of a repo's files at the specified revision. This is useful when you want all files from
130
+ a repo, because you don't know which ones you will need a priori. All files are nested inside a folder in order
131
+ to keep their actual filename relative to that folder. You can also filter which files to download using
132
+ `allow_patterns` and `ignore_patterns`.
133
+
134
+ If `local_dir` is provided, the file structure from the repo will be replicated in this location. When using this
135
+ option, the `cache_dir` will not be used and a `.cache/huggingface/` folder will be created at the root of `local_dir`
136
+ to store some metadata related to the downloaded files. While this mechanism is not as robust as the main
137
+ cache-system, it's optimized for regularly pulling the latest version of a repository.
138
+
139
+ An alternative would be to clone the repo but this requires git and git-lfs to be installed and properly
140
+ configured. It is also not possible to filter which files to download when cloning a repository using git.
141
+
142
+ Args:
143
+ repo_id (`str`):
144
+ A user or an organization name and a repo name separated by a `/`.
145
+ repo_type (`str`, *optional*):
146
+ Set to `"dataset"` or `"space"` if downloading from a dataset or space,
147
+ `None` or `"model"` if downloading from a model. Default is `None`.
148
+ revision (`str`, *optional*):
149
+ An optional Git revision id which can be a branch name, a tag, or a
150
+ commit hash.
151
+ cache_dir (`str`, `Path`, *optional*):
152
+ Path to the folder where cached files are stored.
153
+ local_dir (`str` or `Path`, *optional*):
154
+ If provided, the downloaded files will be placed under this directory.
155
+ library_name (`str`, *optional*):
156
+ The name of the library to which the object corresponds.
157
+ library_version (`str`, *optional*):
158
+ The version of the library.
159
+ user_agent (`str`, `dict`, *optional*):
160
+ The user-agent info in the form of a dictionary or a string.
161
+ etag_timeout (`float`, *optional*, defaults to `10`):
162
+ When fetching ETag, how many seconds to wait for the server to send
163
+ data before giving up which is passed to `httpx.request`.
164
+ force_download (`bool`, *optional*, defaults to `False`):
165
+ Whether the file should be downloaded even if it already exists in the local cache.
166
+ token (`str`, `bool`, *optional*):
167
+ A token to be used for the download.
168
+ - If `True`, the token is read from the HuggingFace config
169
+ folder.
170
+ - If a string, it's used as the authentication token.
171
+ headers (`dict`, *optional*):
172
+ Additional headers to include in the request. Those headers take precedence over the others.
173
+ local_files_only (`bool`, *optional*, defaults to `False`):
174
+ If `True`, avoid downloading the file and return the path to the
175
+ local cached file if it exists.
176
+ allow_patterns (`list[str]` or `str`, *optional*):
177
+ If provided, only files matching at least one pattern are downloaded.
178
+ ignore_patterns (`list[str]` or `str`, *optional*):
179
+ If provided, files matching any of the patterns are not downloaded.
180
+ max_workers (`int`, *optional*):
181
+ Number of concurrent threads to download files (1 thread = 1 file download).
182
+ Defaults to 8.
183
+ tqdm_class (`tqdm`, *optional*):
184
+ If provided, overwrites the default behavior for the progress bar. Passed
185
+ argument must inherit from `tqdm.auto.tqdm` or at least mimic its behavior.
186
+ Note that the `tqdm_class` is not passed to each individual download.
187
+ Defaults to the custom HF progress bar that can be disabled by setting
188
+ `HF_HUB_DISABLE_PROGRESS_BARS` environment variable.
189
+ dry_run (`bool`, *optional*, defaults to `False`):
190
+ If `True`, perform a dry run without actually downloading the files. Returns a list of
191
+ [`DryRunFileInfo`] objects containing information about what would be downloaded.
192
+
193
+ Returns:
194
+ `str` or list of [`DryRunFileInfo`]:
195
+ - If `dry_run=False`: Local snapshot path.
196
+ - If `dry_run=True`: A list of [`DryRunFileInfo`] objects containing download information.
197
+
198
+ Raises:
199
+ [`~utils.RepositoryNotFoundError`]
200
+ If the repository to download from cannot be found. This may be because it doesn't exist,
201
+ or because it is set to `private` and you do not have access.
202
+ [`~utils.RevisionNotFoundError`]
203
+ If the revision to download from cannot be found.
204
+ [`EnvironmentError`](https://docs.python.org/3/library/exceptions.html#EnvironmentError)
205
+ If `token=True` and the token cannot be found.
206
+ [`OSError`](https://docs.python.org/3/library/exceptions.html#OSError) if
207
+ ETag cannot be determined.
208
+ [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError)
209
+ if some parameter value is invalid.
210
+ """
211
+ if cache_dir is None:
212
+ cache_dir = constants.HF_HUB_CACHE
213
+ if revision is None:
214
+ revision = constants.DEFAULT_REVISION
215
+ if isinstance(cache_dir, Path):
216
+ cache_dir = str(cache_dir)
217
+
218
+ if repo_type is None:
219
+ repo_type = "model"
220
+ if repo_type not in constants.REPO_TYPES:
221
+ raise ValueError(f"Invalid repo type: {repo_type}. Accepted repo types are: {str(constants.REPO_TYPES)}")
222
+
223
+ storage_folder = os.path.join(cache_dir, repo_folder_name(repo_id=repo_id, repo_type=repo_type))
224
+
225
+ api = HfApi(
226
+ library_name=library_name,
227
+ library_version=library_version,
228
+ user_agent=user_agent,
229
+ endpoint=endpoint,
230
+ headers=headers,
231
+ token=token,
232
+ )
233
+
234
+ repo_info: Union[ModelInfo, DatasetInfo, SpaceInfo, None] = None
235
+ api_call_error: Optional[Exception] = None
236
+ if not local_files_only:
237
+ # try/except logic to handle different errors => taken from `hf_hub_download`
238
+ try:
239
+ # if we have internet connection we want to list files to download
240
+ repo_info = api.repo_info(repo_id=repo_id, repo_type=repo_type, revision=revision)
241
+ except httpx.ProxyError:
242
+ # Actually raise on proxy error
243
+ raise
244
+ except (httpx.ConnectError, httpx.TimeoutException, OfflineModeIsEnabled) as error:
245
+ # Internet connection is down
246
+ # => will try to use local files only
247
+ api_call_error = error
248
+ pass
249
+ except RevisionNotFoundError:
250
+ # The repo was found but the revision doesn't exist on the Hub (never existed or got deleted)
251
+ raise
252
+ except HfHubHTTPError as error:
253
+ # Multiple reasons for an http error:
254
+ # - Repository is private and invalid/missing token sent
255
+ # - Repository is gated and invalid/missing token sent
256
+ # - Hub is down (error 500 or 504)
257
+ # => let's switch to 'local_files_only=True' to check if the files are already cached.
258
+ # (if it's not the case, the error will be re-raised)
259
+ api_call_error = error
260
+ pass
261
+
262
+ # At this stage, if `repo_info` is None it means either:
263
+ # - internet connection is down
264
+ # - internet connection is deactivated (local_files_only=True or HF_HUB_OFFLINE=True)
265
+ # - repo is private/gated and invalid/missing token sent
266
+ # - Hub is down
267
+ # => let's look if we can find the appropriate folder in the cache:
268
+ # - if the specified revision is a commit hash, look inside "snapshots".
269
+ # - f the specified revision is a branch or tag, look inside "refs".
270
+ # => if local_dir is not None, we will return the path to the local folder if it exists.
271
+ if repo_info is None:
272
+ if dry_run:
273
+ raise DryRunError(
274
+ "Dry run cannot be performed as the repository cannot be accessed. Please check your internet connection or authentication token."
275
+ ) from api_call_error
276
+
277
+ # Try to get which commit hash corresponds to the specified revision
278
+ commit_hash = None
279
+ if REGEX_COMMIT_HASH.match(revision):
280
+ commit_hash = revision
281
+ else:
282
+ ref_path = os.path.join(storage_folder, "refs", revision)
283
+ if os.path.exists(ref_path):
284
+ # retrieve commit_hash from refs file
285
+ with open(ref_path) as f:
286
+ commit_hash = f.read()
287
+
288
+ # Try to locate snapshot folder for this commit hash
289
+ if commit_hash is not None and local_dir is None:
290
+ snapshot_folder = os.path.join(storage_folder, "snapshots", commit_hash)
291
+ if os.path.exists(snapshot_folder):
292
+ # Snapshot folder exists => let's return it
293
+ # (but we can't check if all the files are actually there)
294
+ return snapshot_folder
295
+
296
+ # If local_dir is not None, return it if it exists and is not empty
297
+ if local_dir is not None:
298
+ local_dir = Path(local_dir)
299
+ if local_dir.is_dir() and any(local_dir.iterdir()):
300
+ logger.warning(
301
+ f"Returning existing local_dir `{local_dir}` as remote repo cannot be accessed in `snapshot_download` ({api_call_error})."
302
+ )
303
+ return str(local_dir.resolve())
304
+ # If we couldn't find the appropriate folder on disk, raise an error.
305
+ if local_files_only:
306
+ raise LocalEntryNotFoundError(
307
+ "Cannot find an appropriate cached snapshot folder for the specified revision on the local disk and "
308
+ "outgoing traffic has been disabled. To enable repo look-ups and downloads online, pass "
309
+ "'local_files_only=False' as input."
310
+ )
311
+ elif isinstance(api_call_error, OfflineModeIsEnabled):
312
+ raise LocalEntryNotFoundError(
313
+ "Cannot find an appropriate cached snapshot folder for the specified revision on the local disk and "
314
+ "outgoing traffic has been disabled. To enable repo look-ups and downloads online, set "
315
+ "'HF_HUB_OFFLINE=0' as environment variable."
316
+ ) from api_call_error
317
+ elif isinstance(api_call_error, (RepositoryNotFoundError, GatedRepoError)) or (
318
+ isinstance(api_call_error, HfHubHTTPError) and api_call_error.response.status_code == 401
319
+ ):
320
+ # Repo not found, gated, or specific authentication error => let's raise the actual error
321
+ raise api_call_error
322
+ else:
323
+ # Otherwise: most likely a connection issue or Hub downtime => let's warn the user
324
+ raise LocalEntryNotFoundError(
325
+ "An error happened while trying to locate the files on the Hub and we cannot find the appropriate"
326
+ " snapshot folder for the specified revision on the local disk. Please check your internet connection"
327
+ " and try again."
328
+ ) from api_call_error
329
+
330
+ # At this stage, internet connection is up and running
331
+ # => let's download the files!
332
+ assert repo_info.sha is not None, "Repo info returned from server must have a revision sha."
333
+
334
+ # Corner case: on very large repos, the siblings list in `repo_info` might not contain all files.
335
+ # In that case, we need to use the `list_repo_tree` method to prevent caching issues.
336
+ repo_files: Iterable[str] = [f.rfilename for f in repo_info.siblings] if repo_info.siblings is not None else []
337
+ unreliable_nb_files = (
338
+ repo_info.siblings is None or len(repo_info.siblings) == 0 or len(repo_info.siblings) > LARGE_REPO_THRESHOLD
339
+ )
340
+ if unreliable_nb_files:
341
+ logger.info(
342
+ "Number of files in the repo is unreliable. Using `list_repo_tree` to ensure all files are listed."
343
+ )
344
+ repo_files = (
345
+ f.rfilename
346
+ for f in api.list_repo_tree(repo_id=repo_id, recursive=True, revision=revision, repo_type=repo_type)
347
+ if isinstance(f, RepoFile)
348
+ )
349
+
350
+ filtered_repo_files: Iterable[str] = filter_repo_objects(
351
+ items=repo_files,
352
+ allow_patterns=allow_patterns,
353
+ ignore_patterns=ignore_patterns,
354
+ )
355
+
356
+ if not unreliable_nb_files:
357
+ filtered_repo_files = list(filtered_repo_files)
358
+ tqdm_desc = f"Fetching {len(filtered_repo_files)} files"
359
+ else:
360
+ tqdm_desc = "Fetching ... files"
361
+ if dry_run:
362
+ tqdm_desc = "[dry-run] " + tqdm_desc
363
+
364
+ commit_hash = repo_info.sha
365
+ snapshot_folder = os.path.join(storage_folder, "snapshots", commit_hash)
366
+ # if passed revision is not identical to commit_hash
367
+ # then revision has to be a branch name or tag name.
368
+ # In that case store a ref.
369
+ if revision != commit_hash:
370
+ ref_path = os.path.join(storage_folder, "refs", revision)
371
+ try:
372
+ os.makedirs(os.path.dirname(ref_path), exist_ok=True)
373
+ with open(ref_path, "w") as f:
374
+ f.write(commit_hash)
375
+ except OSError as e:
376
+ logger.warning(f"Ignored error while writing commit hash to {ref_path}: {e}.")
377
+
378
+ results: List[Union[str, DryRunFileInfo]] = []
379
+
380
+ # User can use its own tqdm class or the default one from `huggingface_hub.utils`
381
+ tqdm_class = tqdm_class or hf_tqdm
382
+
383
+ # Create a progress bar for the bytes downloaded
384
+ # This progress bar is shared across threads/files and gets updated each time we fetch
385
+ # metadata for a file.
386
+ bytes_progress = tqdm_class(
387
+ desc="Downloading (incomplete total...)",
388
+ disable=is_tqdm_disabled(log_level=logger.getEffectiveLevel()),
389
+ total=0,
390
+ initial=0,
391
+ unit="B",
392
+ unit_scale=True,
393
+ name="huggingface_hub.snapshot_download",
394
+ )
395
+
396
+ class _AggregatedTqdm:
397
+ """Fake tqdm object to aggregate progress into the parent `bytes_progress` bar.
398
+
399
+ In practice the `_AggregatedTqdm` object won't be displayed, it's just used to update
400
+ the `bytes_progress` bar from each thread/file download.
401
+ """
402
+
403
+ def __init__(self, *args, **kwargs):
404
+ # Adjust the total of the parent progress bar
405
+ total = kwargs.pop("total", None)
406
+ if total is not None:
407
+ bytes_progress.total += total
408
+ bytes_progress.refresh()
409
+
410
+ # Adjust initial of the parent progress bar
411
+ initial = kwargs.pop("initial", 0)
412
+ if initial:
413
+ bytes_progress.update(initial)
414
+
415
+ def __enter__(self):
416
+ return self
417
+
418
+ def __exit__(self, exc_type, exc_value, traceback):
419
+ pass
420
+
421
+ def update(self, n: Optional[Union[int, float]] = 1) -> None:
422
+ bytes_progress.update(n)
423
+
424
+ # we pass the commit_hash to hf_hub_download
425
+ # so no network call happens if we already
426
+ # have the file locally.
427
+ def _inner_hf_hub_download(repo_file: str) -> None:
428
+ results.append(
429
+ hf_hub_download( # type: ignore
430
+ repo_id,
431
+ filename=repo_file,
432
+ repo_type=repo_type,
433
+ revision=commit_hash,
434
+ endpoint=endpoint,
435
+ cache_dir=cache_dir,
436
+ local_dir=local_dir,
437
+ library_name=library_name,
438
+ library_version=library_version,
439
+ user_agent=user_agent,
440
+ etag_timeout=etag_timeout,
441
+ force_download=force_download,
442
+ token=token,
443
+ headers=headers,
444
+ tqdm_class=_AggregatedTqdm, # type: ignore
445
+ dry_run=dry_run,
446
+ )
447
+ )
448
+
449
+ thread_map(
450
+ _inner_hf_hub_download,
451
+ filtered_repo_files,
452
+ desc=tqdm_desc,
453
+ max_workers=max_workers,
454
+ tqdm_class=tqdm_class,
455
+ )
456
+
457
+ bytes_progress.set_description("Download complete")
458
+
459
+ if dry_run:
460
+ assert all(isinstance(r, DryRunFileInfo) for r in results)
461
+ return results # type: ignore
462
+
463
+ if local_dir is not None:
464
+ return str(os.path.realpath(local_dir))
465
+ return snapshot_folder
env/lib/python3.13/site-packages/huggingface_hub/_space_api.py ADDED
@@ -0,0 +1,168 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding=utf-8
2
+ # Copyright 2019-present, the HuggingFace Inc. team.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ from dataclasses import dataclass
16
+ from datetime import datetime
17
+ from enum import Enum
18
+ from typing import Optional
19
+
20
+ from huggingface_hub.utils import parse_datetime
21
+
22
+
23
+ class SpaceStage(str, Enum):
24
+ """
25
+ Enumeration of possible stage of a Space on the Hub.
26
+
27
+ Value can be compared to a string:
28
+ ```py
29
+ assert SpaceStage.BUILDING == "BUILDING"
30
+ ```
31
+
32
+ Taken from https://github.com/huggingface/moon-landing/blob/main/server/repo_types/SpaceInfo.ts#L61 (private url).
33
+ """
34
+
35
+ # Copied from moon-landing > server > repo_types > SpaceInfo.ts (private repo)
36
+ NO_APP_FILE = "NO_APP_FILE"
37
+ CONFIG_ERROR = "CONFIG_ERROR"
38
+ BUILDING = "BUILDING"
39
+ BUILD_ERROR = "BUILD_ERROR"
40
+ RUNNING = "RUNNING"
41
+ RUNNING_BUILDING = "RUNNING_BUILDING"
42
+ RUNTIME_ERROR = "RUNTIME_ERROR"
43
+ DELETING = "DELETING"
44
+ STOPPED = "STOPPED"
45
+ PAUSED = "PAUSED"
46
+
47
+
48
+ class SpaceHardware(str, Enum):
49
+ """
50
+ Enumeration of hardwares available to run your Space on the Hub.
51
+
52
+ Value can be compared to a string:
53
+ ```py
54
+ assert SpaceHardware.CPU_BASIC == "cpu-basic"
55
+ ```
56
+
57
+ Taken from https://github.com/huggingface-internal/moon-landing/blob/main/server/repo_types/SpaceHardwareFlavor.ts (private url).
58
+ """
59
+
60
+ # CPU
61
+ CPU_BASIC = "cpu-basic"
62
+ CPU_UPGRADE = "cpu-upgrade"
63
+ CPU_XL = "cpu-xl"
64
+
65
+ # ZeroGPU
66
+ ZERO_A10G = "zero-a10g"
67
+
68
+ # GPU
69
+ T4_SMALL = "t4-small"
70
+ T4_MEDIUM = "t4-medium"
71
+ L4X1 = "l4x1"
72
+ L4X4 = "l4x4"
73
+ L40SX1 = "l40sx1"
74
+ L40SX4 = "l40sx4"
75
+ L40SX8 = "l40sx8"
76
+ A10G_SMALL = "a10g-small"
77
+ A10G_LARGE = "a10g-large"
78
+ A10G_LARGEX2 = "a10g-largex2"
79
+ A10G_LARGEX4 = "a10g-largex4"
80
+ A100_LARGE = "a100-large"
81
+ H100 = "h100"
82
+ H100X8 = "h100x8"
83
+
84
+
85
+ class SpaceStorage(str, Enum):
86
+ """
87
+ Enumeration of persistent storage available for your Space on the Hub.
88
+
89
+ Value can be compared to a string:
90
+ ```py
91
+ assert SpaceStorage.SMALL == "small"
92
+ ```
93
+
94
+ Taken from https://github.com/huggingface/moon-landing/blob/main/server/repo_types/SpaceHardwareFlavor.ts#L24 (private url).
95
+ """
96
+
97
+ SMALL = "small"
98
+ MEDIUM = "medium"
99
+ LARGE = "large"
100
+
101
+
102
+ @dataclass
103
+ class SpaceRuntime:
104
+ """
105
+ Contains information about the current runtime of a Space.
106
+
107
+ Args:
108
+ stage (`str`):
109
+ Current stage of the space. Example: RUNNING.
110
+ hardware (`str` or `None`):
111
+ Current hardware of the space. Example: "cpu-basic". Can be `None` if Space
112
+ is `BUILDING` for the first time.
113
+ requested_hardware (`str` or `None`):
114
+ Requested hardware. Can be different from `hardware` especially if the request
115
+ has just been made. Example: "t4-medium". Can be `None` if no hardware has
116
+ been requested yet.
117
+ sleep_time (`int` or `None`):
118
+ Number of seconds the Space will be kept alive after the last request. By default (if value is `None`), the
119
+ Space will never go to sleep if it's running on an upgraded hardware, while it will go to sleep after 48
120
+ hours on a free 'cpu-basic' hardware. For more details, see https://huggingface.co/docs/hub/spaces-gpus#sleep-time.
121
+ raw (`dict`):
122
+ Raw response from the server. Contains more information about the Space
123
+ runtime like number of replicas, number of cpu, memory size,...
124
+ """
125
+
126
+ stage: SpaceStage
127
+ hardware: Optional[SpaceHardware]
128
+ requested_hardware: Optional[SpaceHardware]
129
+ sleep_time: Optional[int]
130
+ storage: Optional[SpaceStorage]
131
+ raw: dict
132
+
133
+ def __init__(self, data: dict) -> None:
134
+ self.stage = data["stage"]
135
+ self.hardware = data.get("hardware", {}).get("current")
136
+ self.requested_hardware = data.get("hardware", {}).get("requested")
137
+ self.sleep_time = data.get("gcTimeout")
138
+ self.storage = data.get("storage")
139
+ self.raw = data
140
+
141
+
142
+ @dataclass
143
+ class SpaceVariable:
144
+ """
145
+ Contains information about the current variables of a Space.
146
+
147
+ Args:
148
+ key (`str`):
149
+ Variable key. Example: `"MODEL_REPO_ID"`
150
+ value (`str`):
151
+ Variable value. Example: `"the_model_repo_id"`.
152
+ description (`str` or None):
153
+ Description of the variable. Example: `"Model Repo ID of the implemented model"`.
154
+ updatedAt (`datetime` or None):
155
+ datetime of the last update of the variable (if the variable has been updated at least once).
156
+ """
157
+
158
+ key: str
159
+ value: str
160
+ description: Optional[str]
161
+ updated_at: Optional[datetime]
162
+
163
+ def __init__(self, key: str, values: dict) -> None:
164
+ self.key = key
165
+ self.value = values["value"]
166
+ self.description = values.get("description")
167
+ updated_at = values.get("updatedAt")
168
+ self.updated_at = parse_datetime(updated_at) if updated_at is not None else None
env/lib/python3.13/site-packages/huggingface_hub/_tensorboard_logger.py ADDED
@@ -0,0 +1,190 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2023 The HuggingFace Team. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ """Contains a logger to push training logs to the Hub, using Tensorboard."""
15
+
16
+ from pathlib import Path
17
+ from typing import Optional, Union
18
+
19
+ from ._commit_scheduler import CommitScheduler
20
+ from .errors import EntryNotFoundError
21
+ from .repocard import ModelCard
22
+ from .utils import experimental
23
+
24
+
25
+ # Depending on user's setup, SummaryWriter can come either from 'tensorboardX'
26
+ # or from 'torch.utils.tensorboard'. Both are compatible so let's try to load
27
+ # from either of them.
28
+ try:
29
+ from tensorboardX import SummaryWriter as _RuntimeSummaryWriter
30
+
31
+ is_summary_writer_available = True
32
+ except ImportError:
33
+ try:
34
+ from torch.utils.tensorboard import SummaryWriter as _RuntimeSummaryWriter
35
+
36
+ is_summary_writer_available = True
37
+ except ImportError:
38
+ # Dummy class to avoid failing at import. Will raise on instance creation.
39
+ class _DummySummaryWriter:
40
+ pass
41
+
42
+ _RuntimeSummaryWriter = _DummySummaryWriter # type: ignore[assignment]
43
+ is_summary_writer_available = False
44
+
45
+
46
+ class HFSummaryWriter(_RuntimeSummaryWriter):
47
+ """
48
+ Wrapper around the tensorboard's `SummaryWriter` to push training logs to the Hub.
49
+
50
+ Data is logged locally and then pushed to the Hub asynchronously. Pushing data to the Hub is done in a separate
51
+ thread to avoid blocking the training script. In particular, if the upload fails for any reason (e.g. a connection
52
+ issue), the main script will not be interrupted. Data is automatically pushed to the Hub every `commit_every`
53
+ minutes (default to every 5 minutes).
54
+
55
+ > [!WARNING]
56
+ > `HFSummaryWriter` is experimental. Its API is subject to change in the future without prior notice.
57
+
58
+ Args:
59
+ repo_id (`str`):
60
+ The id of the repo to which the logs will be pushed.
61
+ logdir (`str`, *optional*):
62
+ The directory where the logs will be written. If not specified, a local directory will be created by the
63
+ underlying `SummaryWriter` object.
64
+ commit_every (`int` or `float`, *optional*):
65
+ The frequency (in minutes) at which the logs will be pushed to the Hub. Defaults to 5 minutes.
66
+ squash_history (`bool`, *optional*):
67
+ Whether to squash the history of the repo after each commit. Defaults to `False`. Squashing commits is
68
+ useful to avoid degraded performances on the repo when it grows too large.
69
+ repo_type (`str`, *optional*):
70
+ The type of the repo to which the logs will be pushed. Defaults to "model".
71
+ repo_revision (`str`, *optional*):
72
+ The revision of the repo to which the logs will be pushed. Defaults to "main".
73
+ repo_private (`bool`, *optional*):
74
+ Whether to make the repo private. If `None` (default), the repo will be public unless the organization's default is private. This value is ignored if the repo already exists.
75
+ path_in_repo (`str`, *optional*):
76
+ The path to the folder in the repo where the logs will be pushed. Defaults to "tensorboard/".
77
+ repo_allow_patterns (`list[str]` or `str`, *optional*):
78
+ A list of patterns to include in the upload. Defaults to `"*.tfevents.*"`. Check out the
79
+ [upload guide](https://huggingface.co/docs/huggingface_hub/guides/upload#upload-a-folder) for more details.
80
+ repo_ignore_patterns (`list[str]` or `str`, *optional*):
81
+ A list of patterns to exclude in the upload. Check out the
82
+ [upload guide](https://huggingface.co/docs/huggingface_hub/guides/upload#upload-a-folder) for more details.
83
+ token (`str`, *optional*):
84
+ Authentication token. Will default to the stored token. See https://huggingface.co/settings/token for more
85
+ details
86
+ kwargs:
87
+ Additional keyword arguments passed to `SummaryWriter`.
88
+
89
+ Examples:
90
+ ```diff
91
+ # Taken from https://pytorch.org/docs/stable/tensorboard.html
92
+ - from torch.utils.tensorboard import SummaryWriter
93
+ + from huggingface_hub import HFSummaryWriter
94
+
95
+ import numpy as np
96
+
97
+ - writer = SummaryWriter()
98
+ + writer = HFSummaryWriter(repo_id="username/my-trained-model")
99
+
100
+ for n_iter in range(100):
101
+ writer.add_scalar('Loss/train', np.random.random(), n_iter)
102
+ writer.add_scalar('Loss/test', np.random.random(), n_iter)
103
+ writer.add_scalar('Accuracy/train', np.random.random(), n_iter)
104
+ writer.add_scalar('Accuracy/test', np.random.random(), n_iter)
105
+ ```
106
+
107
+ ```py
108
+ >>> from huggingface_hub import HFSummaryWriter
109
+
110
+ # Logs are automatically pushed every 15 minutes (5 by default) + when exiting the context manager
111
+ >>> with HFSummaryWriter(repo_id="test_hf_logger", commit_every=15) as logger:
112
+ ... logger.add_scalar("a", 1)
113
+ ... logger.add_scalar("b", 2)
114
+ ```
115
+ """
116
+
117
+ @experimental
118
+ def __new__(cls, *args, **kwargs) -> "HFSummaryWriter":
119
+ if not is_summary_writer_available:
120
+ raise ImportError(
121
+ "You must have `tensorboard` installed to use `HFSummaryWriter`. Please run `pip install --upgrade"
122
+ " tensorboardX` first."
123
+ )
124
+ return super().__new__(cls)
125
+
126
+ def __init__(
127
+ self,
128
+ repo_id: str,
129
+ *,
130
+ logdir: Optional[str] = None,
131
+ commit_every: Union[int, float] = 5,
132
+ squash_history: bool = False,
133
+ repo_type: Optional[str] = None,
134
+ repo_revision: Optional[str] = None,
135
+ repo_private: Optional[bool] = None,
136
+ path_in_repo: Optional[str] = "tensorboard",
137
+ repo_allow_patterns: Optional[Union[list[str], str]] = "*.tfevents.*",
138
+ repo_ignore_patterns: Optional[Union[list[str], str]] = None,
139
+ token: Optional[str] = None,
140
+ **kwargs,
141
+ ):
142
+ # Initialize SummaryWriter
143
+ super().__init__(logdir=logdir, **kwargs)
144
+
145
+ # Check logdir has been correctly initialized and fail early otherwise. In practice, SummaryWriter takes care of it.
146
+ if not isinstance(self.logdir, str):
147
+ raise ValueError(f"`self.logdir` must be a string. Got '{self.logdir}' of type {type(self.logdir)}.")
148
+
149
+ # Append logdir name to `path_in_repo`
150
+ if path_in_repo is None or path_in_repo == "":
151
+ path_in_repo = Path(self.logdir).name
152
+ else:
153
+ path_in_repo = path_in_repo.strip("/") + "/" + Path(self.logdir).name
154
+
155
+ # Initialize scheduler
156
+ self.scheduler = CommitScheduler(
157
+ folder_path=self.logdir,
158
+ path_in_repo=path_in_repo,
159
+ repo_id=repo_id,
160
+ repo_type=repo_type,
161
+ revision=repo_revision,
162
+ private=repo_private,
163
+ token=token,
164
+ allow_patterns=repo_allow_patterns,
165
+ ignore_patterns=repo_ignore_patterns,
166
+ every=commit_every,
167
+ squash_history=squash_history,
168
+ )
169
+
170
+ # Exposing some high-level info at root level
171
+ self.repo_id = self.scheduler.repo_id
172
+ self.repo_type = self.scheduler.repo_type
173
+ self.repo_revision = self.scheduler.revision
174
+
175
+ # Add `hf-summary-writer` tag to the model card metadata
176
+ try:
177
+ card = ModelCard.load(repo_id_or_path=self.repo_id, repo_type=self.repo_type)
178
+ except EntryNotFoundError:
179
+ card = ModelCard("")
180
+ tags = card.data.get("tags", [])
181
+ if "hf-summary-writer" not in tags:
182
+ tags.append("hf-summary-writer")
183
+ card.data["tags"] = tags
184
+ card.push_to_hub(repo_id=self.repo_id, repo_type=self.repo_type)
185
+
186
+ def __exit__(self, exc_type, exc_val, exc_tb):
187
+ """Push to hub in a non-blocking way when exiting the logger's context manager."""
188
+ super().__exit__(exc_type, exc_val, exc_tb)
189
+ future = self.scheduler.trigger()
190
+ future.result()
env/lib/python3.13/site-packages/huggingface_hub/_webhooks_payload.py ADDED
@@ -0,0 +1,137 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding=utf-8
2
+ # Copyright 2023-present, the HuggingFace Inc. team.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ """Contains data structures to parse the webhooks payload."""
16
+
17
+ from typing import Literal, Optional
18
+
19
+ from .utils import is_pydantic_available
20
+
21
+
22
+ if is_pydantic_available():
23
+ from pydantic import BaseModel
24
+ else:
25
+ # Define a dummy BaseModel to avoid import errors when pydantic is not installed
26
+ # Import error will be raised when trying to use the class
27
+
28
+ class BaseModel: # type: ignore [no-redef]
29
+ def __init__(self, *args, **kwargs) -> None:
30
+ raise ImportError(
31
+ "You must have `pydantic` installed to use `WebhookPayload`. This is an optional dependency that"
32
+ " should be installed separately. Please run `pip install --upgrade pydantic` and retry."
33
+ )
34
+
35
+
36
+ # This is an adaptation of the ReportV3 interface implemented in moon-landing. V0, V1 and V2 have been ignored as they
37
+ # are not in used anymore. To keep in sync when format is updated in
38
+ # https://github.com/huggingface/moon-landing/blob/main/server/lib/HFWebhooks.ts (internal link).
39
+
40
+
41
+ WebhookEvent_T = Literal[
42
+ "create",
43
+ "delete",
44
+ "move",
45
+ "update",
46
+ ]
47
+ RepoChangeEvent_T = Literal[
48
+ "add",
49
+ "move",
50
+ "remove",
51
+ "update",
52
+ ]
53
+ RepoType_T = Literal[
54
+ "dataset",
55
+ "model",
56
+ "space",
57
+ ]
58
+ DiscussionStatus_T = Literal[
59
+ "closed",
60
+ "draft",
61
+ "open",
62
+ "merged",
63
+ ]
64
+ SupportedWebhookVersion = Literal[3]
65
+
66
+
67
+ class ObjectId(BaseModel):
68
+ id: str
69
+
70
+
71
+ class WebhookPayloadUrl(BaseModel):
72
+ web: str
73
+ api: Optional[str] = None
74
+
75
+
76
+ class WebhookPayloadMovedTo(BaseModel):
77
+ name: str
78
+ owner: ObjectId
79
+
80
+
81
+ class WebhookPayloadWebhook(ObjectId):
82
+ version: SupportedWebhookVersion
83
+
84
+
85
+ class WebhookPayloadEvent(BaseModel):
86
+ action: WebhookEvent_T
87
+ scope: str
88
+
89
+
90
+ class WebhookPayloadDiscussionChanges(BaseModel):
91
+ base: str
92
+ mergeCommitId: Optional[str] = None
93
+
94
+
95
+ class WebhookPayloadComment(ObjectId):
96
+ author: ObjectId
97
+ hidden: bool
98
+ content: Optional[str] = None
99
+ url: WebhookPayloadUrl
100
+
101
+
102
+ class WebhookPayloadDiscussion(ObjectId):
103
+ num: int
104
+ author: ObjectId
105
+ url: WebhookPayloadUrl
106
+ title: str
107
+ isPullRequest: bool
108
+ status: DiscussionStatus_T
109
+ changes: Optional[WebhookPayloadDiscussionChanges] = None
110
+ pinned: Optional[bool] = None
111
+
112
+
113
+ class WebhookPayloadRepo(ObjectId):
114
+ owner: ObjectId
115
+ head_sha: Optional[str] = None
116
+ name: str
117
+ private: bool
118
+ subdomain: Optional[str] = None
119
+ tags: Optional[list[str]] = None
120
+ type: Literal["dataset", "model", "space"]
121
+ url: WebhookPayloadUrl
122
+
123
+
124
+ class WebhookPayloadUpdatedRef(BaseModel):
125
+ ref: str
126
+ oldSha: Optional[str] = None
127
+ newSha: Optional[str] = None
128
+
129
+
130
+ class WebhookPayload(BaseModel):
131
+ event: WebhookPayloadEvent
132
+ repo: WebhookPayloadRepo
133
+ discussion: Optional[WebhookPayloadDiscussion] = None
134
+ comment: Optional[WebhookPayloadComment] = None
135
+ webhook: WebhookPayloadWebhook
136
+ movedTo: Optional[WebhookPayloadMovedTo] = None
137
+ updatedRefs: Optional[list[WebhookPayloadUpdatedRef]] = None
env/lib/python3.13/site-packages/huggingface_hub/community.py ADDED
@@ -0,0 +1,363 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Data structures to interact with Discussions and Pull Requests on the Hub.
3
+
4
+ See [the Discussions and Pull Requests guide](https://huggingface.co/docs/hub/repositories-pull-requests-discussions)
5
+ for more information on Pull Requests, Discussions, and the community tab.
6
+ """
7
+
8
+ from dataclasses import dataclass
9
+ from datetime import datetime
10
+ from typing import Literal, Optional, TypedDict, Union
11
+
12
+ from . import constants
13
+ from .utils import parse_datetime
14
+
15
+
16
+ DiscussionStatus = Literal["open", "closed", "merged", "draft"]
17
+
18
+
19
+ @dataclass
20
+ class Discussion:
21
+ """
22
+ A Discussion or Pull Request on the Hub.
23
+
24
+ This dataclass is not intended to be instantiated directly.
25
+
26
+ Attributes:
27
+ title (`str`):
28
+ The title of the Discussion / Pull Request
29
+ status (`str`):
30
+ The status of the Discussion / Pull Request.
31
+ It must be one of:
32
+ * `"open"`
33
+ * `"closed"`
34
+ * `"merged"` (only for Pull Requests )
35
+ * `"draft"` (only for Pull Requests )
36
+ num (`int`):
37
+ The number of the Discussion / Pull Request.
38
+ repo_id (`str`):
39
+ The id (`"{namespace}/{repo_name}"`) of the repo on which
40
+ the Discussion / Pull Request was open.
41
+ repo_type (`str`):
42
+ The type of the repo on which the Discussion / Pull Request was open.
43
+ Possible values are: `"model"`, `"dataset"`, `"space"`.
44
+ author (`str`):
45
+ The username of the Discussion / Pull Request author.
46
+ Can be `"deleted"` if the user has been deleted since.
47
+ is_pull_request (`bool`):
48
+ Whether or not this is a Pull Request.
49
+ created_at (`datetime`):
50
+ The `datetime` of creation of the Discussion / Pull Request.
51
+ endpoint (`str`):
52
+ Endpoint of the Hub. Default is https://huggingface.co.
53
+ git_reference (`str`, *optional*):
54
+ (property) Git reference to which changes can be pushed if this is a Pull Request, `None` otherwise.
55
+ url (`str`):
56
+ (property) URL of the discussion on the Hub.
57
+ """
58
+
59
+ title: str
60
+ status: DiscussionStatus
61
+ num: int
62
+ repo_id: str
63
+ repo_type: str
64
+ author: str
65
+ is_pull_request: bool
66
+ created_at: datetime
67
+ endpoint: str
68
+
69
+ @property
70
+ def git_reference(self) -> Optional[str]:
71
+ """
72
+ If this is a Pull Request , returns the git reference to which changes can be pushed.
73
+ Returns `None` otherwise.
74
+ """
75
+ if self.is_pull_request:
76
+ return f"refs/pr/{self.num}"
77
+ return None
78
+
79
+ @property
80
+ def url(self) -> str:
81
+ """Returns the URL of the discussion on the Hub."""
82
+ if self.repo_type is None or self.repo_type == constants.REPO_TYPE_MODEL:
83
+ return f"{self.endpoint}/{self.repo_id}/discussions/{self.num}"
84
+ return f"{self.endpoint}/{self.repo_type}s/{self.repo_id}/discussions/{self.num}"
85
+
86
+
87
+ @dataclass
88
+ class DiscussionWithDetails(Discussion):
89
+ """
90
+ Subclass of [`Discussion`].
91
+
92
+ Attributes:
93
+ title (`str`):
94
+ The title of the Discussion / Pull Request
95
+ status (`str`):
96
+ The status of the Discussion / Pull Request.
97
+ It can be one of:
98
+ * `"open"`
99
+ * `"closed"`
100
+ * `"merged"` (only for Pull Requests )
101
+ * `"draft"` (only for Pull Requests )
102
+ num (`int`):
103
+ The number of the Discussion / Pull Request.
104
+ repo_id (`str`):
105
+ The id (`"{namespace}/{repo_name}"`) of the repo on which
106
+ the Discussion / Pull Request was open.
107
+ repo_type (`str`):
108
+ The type of the repo on which the Discussion / Pull Request was open.
109
+ Possible values are: `"model"`, `"dataset"`, `"space"`.
110
+ author (`str`):
111
+ The username of the Discussion / Pull Request author.
112
+ Can be `"deleted"` if the user has been deleted since.
113
+ is_pull_request (`bool`):
114
+ Whether or not this is a Pull Request.
115
+ created_at (`datetime`):
116
+ The `datetime` of creation of the Discussion / Pull Request.
117
+ events (`list` of [`DiscussionEvent`])
118
+ The list of [`DiscussionEvents`] in this Discussion or Pull Request.
119
+ conflicting_files (`Union[list[str], bool, None]`, *optional*):
120
+ A list of conflicting files if this is a Pull Request.
121
+ `None` if `self.is_pull_request` is `False`.
122
+ `True` if there are conflicting files but the list can't be retrieved.
123
+ target_branch (`str`, *optional*):
124
+ The branch into which changes are to be merged if this is a
125
+ Pull Request . `None` if `self.is_pull_request` is `False`.
126
+ merge_commit_oid (`str`, *optional*):
127
+ If this is a merged Pull Request , this is set to the OID / SHA of
128
+ the merge commit, `None` otherwise.
129
+ diff (`str`, *optional*):
130
+ The git diff if this is a Pull Request , `None` otherwise.
131
+ endpoint (`str`):
132
+ Endpoint of the Hub. Default is https://huggingface.co.
133
+ git_reference (`str`, *optional*):
134
+ (property) Git reference to which changes can be pushed if this is a Pull Request, `None` otherwise.
135
+ url (`str`):
136
+ (property) URL of the discussion on the Hub.
137
+ """
138
+
139
+ events: list["DiscussionEvent"]
140
+ conflicting_files: Union[list[str], bool, None]
141
+ target_branch: Optional[str]
142
+ merge_commit_oid: Optional[str]
143
+ diff: Optional[str]
144
+
145
+
146
+ class DiscussionEventArgs(TypedDict):
147
+ id: str
148
+ type: str
149
+ created_at: datetime
150
+ author: str
151
+ _event: dict
152
+
153
+
154
+ @dataclass
155
+ class DiscussionEvent:
156
+ """
157
+ An event in a Discussion or Pull Request.
158
+
159
+ Use concrete classes:
160
+ * [`DiscussionComment`]
161
+ * [`DiscussionStatusChange`]
162
+ * [`DiscussionCommit`]
163
+ * [`DiscussionTitleChange`]
164
+
165
+ Attributes:
166
+ id (`str`):
167
+ The ID of the event. An hexadecimal string.
168
+ type (`str`):
169
+ The type of the event.
170
+ created_at (`datetime`):
171
+ A [`datetime`](https://docs.python.org/3/library/datetime.html?highlight=datetime#datetime.datetime)
172
+ object holding the creation timestamp for the event.
173
+ author (`str`):
174
+ The username of the Discussion / Pull Request author.
175
+ Can be `"deleted"` if the user has been deleted since.
176
+ """
177
+
178
+ id: str
179
+ type: str
180
+ created_at: datetime
181
+ author: str
182
+
183
+ _event: dict
184
+ """Stores the original event data, in case we need to access it later."""
185
+
186
+
187
+ @dataclass
188
+ class DiscussionComment(DiscussionEvent):
189
+ """A comment in a Discussion / Pull Request.
190
+
191
+ Subclass of [`DiscussionEvent`].
192
+
193
+
194
+ Attributes:
195
+ id (`str`):
196
+ The ID of the event. An hexadecimal string.
197
+ type (`str`):
198
+ The type of the event.
199
+ created_at (`datetime`):
200
+ A [`datetime`](https://docs.python.org/3/library/datetime.html?highlight=datetime#datetime.datetime)
201
+ object holding the creation timestamp for the event.
202
+ author (`str`):
203
+ The username of the Discussion / Pull Request author.
204
+ Can be `"deleted"` if the user has been deleted since.
205
+ content (`str`):
206
+ The raw markdown content of the comment. Mentions, links and images are not rendered.
207
+ edited (`bool`):
208
+ Whether or not this comment has been edited.
209
+ hidden (`bool`):
210
+ Whether or not this comment has been hidden.
211
+ """
212
+
213
+ content: str
214
+ edited: bool
215
+ hidden: bool
216
+
217
+ @property
218
+ def rendered(self) -> str:
219
+ """The rendered comment, as a HTML string"""
220
+ return self._event["data"]["latest"]["html"]
221
+
222
+ @property
223
+ def last_edited_at(self) -> datetime:
224
+ """The last edit time, as a `datetime` object."""
225
+ return parse_datetime(self._event["data"]["latest"]["updatedAt"])
226
+
227
+ @property
228
+ def last_edited_by(self) -> str:
229
+ """The last edit time, as a `datetime` object."""
230
+ return self._event["data"]["latest"].get("author", {}).get("name", "deleted")
231
+
232
+ @property
233
+ def edit_history(self) -> list[dict]:
234
+ """The edit history of the comment"""
235
+ return self._event["data"]["history"]
236
+
237
+ @property
238
+ def number_of_edits(self) -> int:
239
+ return len(self.edit_history)
240
+
241
+
242
+ @dataclass
243
+ class DiscussionStatusChange(DiscussionEvent):
244
+ """A change of status in a Discussion / Pull Request.
245
+
246
+ Subclass of [`DiscussionEvent`].
247
+
248
+ Attributes:
249
+ id (`str`):
250
+ The ID of the event. An hexadecimal string.
251
+ type (`str`):
252
+ The type of the event.
253
+ created_at (`datetime`):
254
+ A [`datetime`](https://docs.python.org/3/library/datetime.html?highlight=datetime#datetime.datetime)
255
+ object holding the creation timestamp for the event.
256
+ author (`str`):
257
+ The username of the Discussion / Pull Request author.
258
+ Can be `"deleted"` if the user has been deleted since.
259
+ new_status (`str`):
260
+ The status of the Discussion / Pull Request after the change.
261
+ It can be one of:
262
+ * `"open"`
263
+ * `"closed"`
264
+ * `"merged"` (only for Pull Requests )
265
+ """
266
+
267
+ new_status: str
268
+
269
+
270
+ @dataclass
271
+ class DiscussionCommit(DiscussionEvent):
272
+ """A commit in a Pull Request.
273
+
274
+ Subclass of [`DiscussionEvent`].
275
+
276
+ Attributes:
277
+ id (`str`):
278
+ The ID of the event. An hexadecimal string.
279
+ type (`str`):
280
+ The type of the event.
281
+ created_at (`datetime`):
282
+ A [`datetime`](https://docs.python.org/3/library/datetime.html?highlight=datetime#datetime.datetime)
283
+ object holding the creation timestamp for the event.
284
+ author (`str`):
285
+ The username of the Discussion / Pull Request author.
286
+ Can be `"deleted"` if the user has been deleted since.
287
+ summary (`str`):
288
+ The summary of the commit.
289
+ oid (`str`):
290
+ The OID / SHA of the commit, as a hexadecimal string.
291
+ """
292
+
293
+ summary: str
294
+ oid: str
295
+
296
+
297
+ @dataclass
298
+ class DiscussionTitleChange(DiscussionEvent):
299
+ """A rename event in a Discussion / Pull Request.
300
+
301
+ Subclass of [`DiscussionEvent`].
302
+
303
+ Attributes:
304
+ id (`str`):
305
+ The ID of the event. An hexadecimal string.
306
+ type (`str`):
307
+ The type of the event.
308
+ created_at (`datetime`):
309
+ A [`datetime`](https://docs.python.org/3/library/datetime.html?highlight=datetime#datetime.datetime)
310
+ object holding the creation timestamp for the event.
311
+ author (`str`):
312
+ The username of the Discussion / Pull Request author.
313
+ Can be `"deleted"` if the user has been deleted since.
314
+ old_title (`str`):
315
+ The previous title for the Discussion / Pull Request.
316
+ new_title (`str`):
317
+ The new title.
318
+ """
319
+
320
+ old_title: str
321
+ new_title: str
322
+
323
+
324
+ def deserialize_event(event: dict) -> DiscussionEvent:
325
+ """Instantiates a [`DiscussionEvent`] from a dict"""
326
+ event_id: str = event["id"]
327
+ event_type: str = event["type"]
328
+ created_at = parse_datetime(event["createdAt"])
329
+
330
+ common_args: DiscussionEventArgs = {
331
+ "id": event_id,
332
+ "type": event_type,
333
+ "created_at": created_at,
334
+ "author": event.get("author", {}).get("name", "deleted"),
335
+ "_event": event,
336
+ }
337
+
338
+ if event_type == "comment":
339
+ return DiscussionComment(
340
+ **common_args,
341
+ edited=event["data"]["edited"],
342
+ hidden=event["data"]["hidden"],
343
+ content=event["data"]["latest"]["raw"],
344
+ )
345
+ if event_type == "status-change":
346
+ return DiscussionStatusChange(
347
+ **common_args,
348
+ new_status=event["data"]["status"],
349
+ )
350
+ if event_type == "commit":
351
+ return DiscussionCommit(
352
+ **common_args,
353
+ summary=event["data"]["subject"],
354
+ oid=event["data"]["oid"],
355
+ )
356
+ if event_type == "title-change":
357
+ return DiscussionTitleChange(
358
+ **common_args,
359
+ old_title=event["data"]["from"],
360
+ new_title=event["data"]["to"],
361
+ )
362
+
363
+ return DiscussionEvent(**common_args)
env/lib/python3.13/site-packages/huggingface_hub/constants.py ADDED
@@ -0,0 +1,279 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import re
3
+ import typing
4
+ from typing import Literal, Optional
5
+
6
+
7
+ # Possible values for env variables
8
+
9
+
10
+ ENV_VARS_TRUE_VALUES = {"1", "ON", "YES", "TRUE"}
11
+ ENV_VARS_TRUE_AND_AUTO_VALUES = ENV_VARS_TRUE_VALUES.union({"AUTO"})
12
+
13
+
14
+ def _is_true(value: Optional[str]) -> bool:
15
+ if value is None:
16
+ return False
17
+ return value.upper() in ENV_VARS_TRUE_VALUES
18
+
19
+
20
+ def _as_int(value: Optional[str]) -> Optional[int]:
21
+ if value is None:
22
+ return None
23
+ return int(value)
24
+
25
+
26
+ # Constants for file downloads
27
+
28
+ PYTORCH_WEIGHTS_NAME = "pytorch_model.bin"
29
+ TF2_WEIGHTS_NAME = "tf_model.h5"
30
+ TF_WEIGHTS_NAME = "model.ckpt"
31
+ FLAX_WEIGHTS_NAME = "flax_model.msgpack"
32
+ CONFIG_NAME = "config.json"
33
+ REPOCARD_NAME = "README.md"
34
+ DEFAULT_ETAG_TIMEOUT = 10
35
+ DEFAULT_DOWNLOAD_TIMEOUT = 10
36
+ DEFAULT_REQUEST_TIMEOUT = 10
37
+ DOWNLOAD_CHUNK_SIZE = 10 * 1024 * 1024
38
+ MAX_HTTP_DOWNLOAD_SIZE = 50 * 1000 * 1000 * 1000 # 50 GB
39
+
40
+ # Constants for serialization
41
+
42
+ PYTORCH_WEIGHTS_FILE_PATTERN = "pytorch_model{suffix}.bin" # Unsafe pickle: use safetensors instead
43
+ SAFETENSORS_WEIGHTS_FILE_PATTERN = "model{suffix}.safetensors"
44
+ TF2_WEIGHTS_FILE_PATTERN = "tf_model{suffix}.h5"
45
+
46
+ # Constants for safetensors repos
47
+
48
+ SAFETENSORS_SINGLE_FILE = "model.safetensors"
49
+ SAFETENSORS_INDEX_FILE = "model.safetensors.index.json"
50
+ SAFETENSORS_MAX_HEADER_LENGTH = 25_000_000
51
+
52
+ # Timeout of aquiring file lock and logging the attempt
53
+ FILELOCK_LOG_EVERY_SECONDS = 10
54
+
55
+ # Git-related constants
56
+
57
+ DEFAULT_REVISION = "main"
58
+ REGEX_COMMIT_OID = re.compile(r"[A-Fa-f0-9]{5,40}")
59
+
60
+ HUGGINGFACE_CO_URL_HOME = "https://huggingface.co/"
61
+
62
+ _staging_mode = _is_true(os.environ.get("HUGGINGFACE_CO_STAGING"))
63
+
64
+ _HF_DEFAULT_ENDPOINT = "https://huggingface.co"
65
+ _HF_DEFAULT_STAGING_ENDPOINT = "https://hub-ci.huggingface.co"
66
+ ENDPOINT = os.getenv("HF_ENDPOINT", _HF_DEFAULT_ENDPOINT).rstrip("/")
67
+ HUGGINGFACE_CO_URL_TEMPLATE = ENDPOINT + "/{repo_id}/resolve/{revision}/{filename}"
68
+
69
+ if _staging_mode:
70
+ ENDPOINT = _HF_DEFAULT_STAGING_ENDPOINT
71
+ HUGGINGFACE_CO_URL_TEMPLATE = _HF_DEFAULT_STAGING_ENDPOINT + "/{repo_id}/resolve/{revision}/{filename}"
72
+
73
+ HUGGINGFACE_HEADER_X_REPO_COMMIT = "X-Repo-Commit"
74
+ HUGGINGFACE_HEADER_X_LINKED_ETAG = "X-Linked-Etag"
75
+ HUGGINGFACE_HEADER_X_LINKED_SIZE = "X-Linked-Size"
76
+ HUGGINGFACE_HEADER_X_BILL_TO = "X-HF-Bill-To"
77
+
78
+ INFERENCE_ENDPOINT = os.environ.get("HF_INFERENCE_ENDPOINT", "https://api-inference.huggingface.co")
79
+
80
+ # See https://huggingface.co/docs/inference-endpoints/index
81
+ INFERENCE_ENDPOINTS_ENDPOINT = "https://api.endpoints.huggingface.cloud/v2"
82
+ INFERENCE_CATALOG_ENDPOINT = "https://endpoints.huggingface.co/api/catalog"
83
+
84
+ # See https://api.endpoints.huggingface.cloud/#post-/v2/endpoint/-namespace-
85
+ INFERENCE_ENDPOINT_IMAGE_KEYS = [
86
+ "custom",
87
+ "huggingface",
88
+ "huggingfaceNeuron",
89
+ "llamacpp",
90
+ "tei",
91
+ "tgi",
92
+ "tgiNeuron",
93
+ ]
94
+
95
+ # Proxy for third-party providers
96
+ INFERENCE_PROXY_TEMPLATE = "https://router.huggingface.co/{provider}"
97
+
98
+ REPO_ID_SEPARATOR = "--"
99
+ # ^ this substring is not allowed in repo_ids on hf.co
100
+ # and is the canonical one we use for serialization of repo ids elsewhere.
101
+
102
+
103
+ REPO_TYPE_DATASET = "dataset"
104
+ REPO_TYPE_SPACE = "space"
105
+ REPO_TYPE_MODEL = "model"
106
+ REPO_TYPES = [None, REPO_TYPE_MODEL, REPO_TYPE_DATASET, REPO_TYPE_SPACE]
107
+ SPACES_SDK_TYPES = ["gradio", "streamlit", "docker", "static"]
108
+
109
+ REPO_TYPES_URL_PREFIXES = {
110
+ REPO_TYPE_DATASET: "datasets/",
111
+ REPO_TYPE_SPACE: "spaces/",
112
+ }
113
+ REPO_TYPES_MAPPING = {
114
+ "datasets": REPO_TYPE_DATASET,
115
+ "spaces": REPO_TYPE_SPACE,
116
+ "models": REPO_TYPE_MODEL,
117
+ }
118
+
119
+ DiscussionTypeFilter = Literal["all", "discussion", "pull_request"]
120
+ DISCUSSION_TYPES: tuple[DiscussionTypeFilter, ...] = typing.get_args(DiscussionTypeFilter)
121
+ DiscussionStatusFilter = Literal["all", "open", "closed"]
122
+ DISCUSSION_STATUS: tuple[DiscussionTypeFilter, ...] = typing.get_args(DiscussionStatusFilter)
123
+
124
+ # Webhook subscription types
125
+ WEBHOOK_DOMAIN_T = Literal["repo", "discussions"]
126
+
127
+ # default cache
128
+ default_home = os.path.join(os.path.expanduser("~"), ".cache")
129
+ HF_HOME = os.path.expandvars(
130
+ os.path.expanduser(
131
+ os.getenv(
132
+ "HF_HOME",
133
+ os.path.join(os.getenv("XDG_CACHE_HOME", default_home), "huggingface"),
134
+ )
135
+ )
136
+ )
137
+
138
+ default_cache_path = os.path.join(HF_HOME, "hub")
139
+ default_assets_cache_path = os.path.join(HF_HOME, "assets")
140
+
141
+ # Legacy env variables
142
+ HUGGINGFACE_HUB_CACHE = os.getenv("HUGGINGFACE_HUB_CACHE", default_cache_path)
143
+ HUGGINGFACE_ASSETS_CACHE = os.getenv("HUGGINGFACE_ASSETS_CACHE", default_assets_cache_path)
144
+
145
+ # New env variables
146
+ HF_HUB_CACHE = os.path.expandvars(
147
+ os.path.expanduser(
148
+ os.getenv(
149
+ "HF_HUB_CACHE",
150
+ HUGGINGFACE_HUB_CACHE,
151
+ )
152
+ )
153
+ )
154
+ HF_ASSETS_CACHE = os.path.expandvars(
155
+ os.path.expanduser(
156
+ os.getenv(
157
+ "HF_ASSETS_CACHE",
158
+ HUGGINGFACE_ASSETS_CACHE,
159
+ )
160
+ )
161
+ )
162
+
163
+ HF_HUB_OFFLINE = _is_true(os.environ.get("HF_HUB_OFFLINE") or os.environ.get("TRANSFORMERS_OFFLINE"))
164
+
165
+
166
+ def is_offline_mode() -> bool:
167
+ """Returns whether we are in offline mode for the Hub.
168
+
169
+ When offline mode is enabled, all HTTP requests made with `get_session` will raise an `OfflineModeIsEnabled` exception.
170
+
171
+ Example:
172
+ ```py
173
+ from huggingface_hub import is_offline_mode
174
+
175
+ def list_files(repo_id: str):
176
+ if is_offline_mode():
177
+ ... # list files from local cache (degraded experience but still functional)
178
+ else:
179
+ ... # list files from Hub (complete experience)
180
+ ```
181
+ """
182
+ return HF_HUB_OFFLINE
183
+
184
+
185
+ # File created to mark that the version check has been done.
186
+ # Check is performed once per 24 hours at most.
187
+ CHECK_FOR_UPDATE_DONE_PATH = os.path.join(HF_HOME, ".check_for_update_done")
188
+
189
+ # If set, log level will be set to DEBUG and all requests made to the Hub will be logged
190
+ # as curl commands for reproducibility.
191
+ HF_DEBUG = _is_true(os.environ.get("HF_DEBUG"))
192
+
193
+ # Opt-out from telemetry requests
194
+ HF_HUB_DISABLE_TELEMETRY = (
195
+ _is_true(os.environ.get("HF_HUB_DISABLE_TELEMETRY")) # HF-specific env variable
196
+ or _is_true(os.environ.get("DISABLE_TELEMETRY"))
197
+ or _is_true(os.environ.get("DO_NOT_TRACK")) # https://consoledonottrack.com/
198
+ )
199
+
200
+ HF_TOKEN_PATH = os.path.expandvars(
201
+ os.path.expanduser(
202
+ os.getenv(
203
+ "HF_TOKEN_PATH",
204
+ os.path.join(HF_HOME, "token"),
205
+ )
206
+ )
207
+ )
208
+ HF_STORED_TOKENS_PATH = os.path.join(os.path.dirname(HF_TOKEN_PATH), "stored_tokens")
209
+
210
+ if _staging_mode:
211
+ # In staging mode, we use a different cache to ensure we don't mix up production and staging data or tokens
212
+ # In practice in `huggingface_hub` tests, we monkeypatch these values with temporary directories. The following
213
+ # lines are only used in third-party libraries tests (e.g. `transformers`, `diffusers`, etc.).
214
+ _staging_home = os.path.join(os.path.expanduser("~"), ".cache", "huggingface_staging")
215
+ HUGGINGFACE_HUB_CACHE = os.path.join(_staging_home, "hub")
216
+ HF_TOKEN_PATH = os.path.join(_staging_home, "token")
217
+
218
+ # Here, `True` will disable progress bars globally without possibility of enabling it
219
+ # programmatically. `False` will enable them without possibility of disabling them.
220
+ # If environment variable is not set (None), then the user is free to enable/disable
221
+ # them programmatically.
222
+ # TL;DR: env variable has priority over code
223
+ __HF_HUB_DISABLE_PROGRESS_BARS = os.environ.get("HF_HUB_DISABLE_PROGRESS_BARS")
224
+ HF_HUB_DISABLE_PROGRESS_BARS: Optional[bool] = (
225
+ _is_true(__HF_HUB_DISABLE_PROGRESS_BARS) if __HF_HUB_DISABLE_PROGRESS_BARS is not None else None
226
+ )
227
+
228
+ # Disable warning on machines that do not support symlinks (e.g. Windows non-developer)
229
+ HF_HUB_DISABLE_SYMLINKS_WARNING: bool = _is_true(os.environ.get("HF_HUB_DISABLE_SYMLINKS_WARNING"))
230
+
231
+ # Disable warning when using experimental features
232
+ HF_HUB_DISABLE_EXPERIMENTAL_WARNING: bool = _is_true(os.environ.get("HF_HUB_DISABLE_EXPERIMENTAL_WARNING"))
233
+
234
+ # Disable sending the cached token by default is all HTTP requests to the Hub
235
+ HF_HUB_DISABLE_IMPLICIT_TOKEN: bool = _is_true(os.environ.get("HF_HUB_DISABLE_IMPLICIT_TOKEN"))
236
+
237
+ HF_XET_HIGH_PERFORMANCE: bool = _is_true(os.environ.get("HF_XET_HIGH_PERFORMANCE"))
238
+
239
+ # hf_transfer is not used anymore. Let's warn user is case they set the env variable
240
+ if _is_true(os.environ.get("HF_HUB_ENABLE_HF_TRANSFER")) and not HF_XET_HIGH_PERFORMANCE:
241
+ import warnings
242
+
243
+ warnings.warn(
244
+ "The `HF_HUB_ENABLE_HF_TRANSFER` environment variable is deprecated as 'hf_transfer' is not used anymore. "
245
+ "Please use `HF_XET_HIGH_PERFORMANCE` instead to enable high performance transfer with Xet. "
246
+ "Visit https://huggingface.co/docs/huggingface_hub/package_reference/environment_variables#hfxethighperformance for more details.",
247
+ DeprecationWarning,
248
+ )
249
+
250
+ # Used to override the etag timeout on a system level
251
+ HF_HUB_ETAG_TIMEOUT: int = _as_int(os.environ.get("HF_HUB_ETAG_TIMEOUT")) or DEFAULT_ETAG_TIMEOUT
252
+
253
+ # Used to override the get request timeout on a system level
254
+ HF_HUB_DOWNLOAD_TIMEOUT: int = _as_int(os.environ.get("HF_HUB_DOWNLOAD_TIMEOUT")) or DEFAULT_DOWNLOAD_TIMEOUT
255
+
256
+ # Allows to add information about the requester in the user-agent (e.g. partner name)
257
+ HF_HUB_USER_AGENT_ORIGIN: Optional[str] = os.environ.get("HF_HUB_USER_AGENT_ORIGIN")
258
+
259
+ # If OAuth didn't work after 2 redirects, there's likely a third-party cookie issue in the Space iframe view.
260
+ # In this case, we redirect the user to the non-iframe view.
261
+ OAUTH_MAX_REDIRECTS = 2
262
+
263
+ # OAuth-related environment variables injected by the Space
264
+ OAUTH_CLIENT_ID = os.environ.get("OAUTH_CLIENT_ID")
265
+ OAUTH_CLIENT_SECRET = os.environ.get("OAUTH_CLIENT_SECRET")
266
+ OAUTH_SCOPES = os.environ.get("OAUTH_SCOPES")
267
+ OPENID_PROVIDER_URL = os.environ.get("OPENID_PROVIDER_URL")
268
+
269
+ # Xet constants
270
+ HUGGINGFACE_HEADER_X_XET_ENDPOINT = "X-Xet-Cas-Url"
271
+ HUGGINGFACE_HEADER_X_XET_ACCESS_TOKEN = "X-Xet-Access-Token"
272
+ HUGGINGFACE_HEADER_X_XET_EXPIRATION = "X-Xet-Token-Expiration"
273
+ HUGGINGFACE_HEADER_X_XET_HASH = "X-Xet-Hash"
274
+ HUGGINGFACE_HEADER_X_XET_REFRESH_ROUTE = "X-Xet-Refresh-Route"
275
+ HUGGINGFACE_HEADER_LINK_XET_AUTH_KEY = "xet-auth"
276
+
277
+ default_xet_cache_path = os.path.join(HF_HOME, "xet")
278
+ HF_XET_CACHE = os.getenv("HF_XET_CACHE", default_xet_cache_path)
279
+ HF_HUB_DISABLE_XET: bool = _is_true(os.environ.get("HF_HUB_DISABLE_XET"))
env/lib/python3.13/site-packages/huggingface_hub/errors.py ADDED
@@ -0,0 +1,404 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Contains all custom errors."""
2
+
3
+ from pathlib import Path
4
+ from typing import Optional, Union
5
+
6
+ from httpx import HTTPError, Response
7
+
8
+
9
+ # CACHE ERRORS
10
+
11
+
12
+ class CacheNotFound(Exception):
13
+ """Exception thrown when the Huggingface cache is not found."""
14
+
15
+ cache_dir: Union[str, Path]
16
+
17
+ def __init__(self, msg: str, cache_dir: Union[str, Path], *args, **kwargs):
18
+ super().__init__(msg, *args, **kwargs)
19
+ self.cache_dir = cache_dir
20
+
21
+
22
+ class CorruptedCacheException(Exception):
23
+ """Exception for any unexpected structure in the Huggingface cache-system."""
24
+
25
+
26
+ # HEADERS ERRORS
27
+
28
+
29
+ class LocalTokenNotFoundError(EnvironmentError):
30
+ """Raised if local token is required but not found."""
31
+
32
+
33
+ # HTTP ERRORS
34
+
35
+
36
+ class OfflineModeIsEnabled(ConnectionError):
37
+ """Raised when a request is made but `HF_HUB_OFFLINE=1` is set as environment variable."""
38
+
39
+
40
+ class HfHubHTTPError(HTTPError, OSError):
41
+ """
42
+ HTTPError to inherit from for any custom HTTP Error raised in HF Hub.
43
+
44
+ Any HTTPError is converted at least into a `HfHubHTTPError`. If some information is
45
+ sent back by the server, it will be added to the error message.
46
+
47
+ Added details:
48
+ - Request id from "X-Request-Id" header if exists. If not, fallback to "X-Amzn-Trace-Id" header if exists.
49
+ - Server error message from the header "X-Error-Message".
50
+ - Server error message if we can found one in the response body.
51
+
52
+ Example:
53
+ ```py
54
+ import httpx
55
+ from huggingface_hub.utils import get_session, hf_raise_for_status, HfHubHTTPError
56
+
57
+ response = get_session().post(...)
58
+ try:
59
+ hf_raise_for_status(response)
60
+ except HfHubHTTPError as e:
61
+ print(str(e)) # formatted message
62
+ e.request_id, e.server_message # details returned by server
63
+
64
+ # Complete the error message with additional information once it's raised
65
+ e.append_to_message("\n`create_commit` expects the repository to exist.")
66
+ raise
67
+ ```
68
+ """
69
+
70
+ def __init__(
71
+ self,
72
+ message: str,
73
+ *,
74
+ response: Response,
75
+ server_message: Optional[str] = None,
76
+ ):
77
+ self.request_id = response.headers.get("x-request-id") or response.headers.get("X-Amzn-Trace-Id")
78
+ self.server_message = server_message
79
+ self.response = response
80
+ self.request = response.request
81
+ super().__init__(message)
82
+
83
+ def append_to_message(self, additional_message: str) -> None:
84
+ """Append additional information to the `HfHubHTTPError` initial message."""
85
+ self.args = (self.args[0] + additional_message,) + self.args[1:]
86
+
87
+ @classmethod
88
+ def _reconstruct_hf_hub_http_error(
89
+ cls, message: str, response: Response, server_message: Optional[str]
90
+ ) -> "HfHubHTTPError":
91
+ return cls(message, response=response, server_message=server_message)
92
+
93
+ def __reduce_ex__(self, protocol):
94
+ """Fix pickling of Exception subclass with kwargs. We need to override __reduce_ex__ of the parent class"""
95
+ return (self.__class__._reconstruct_hf_hub_http_error, (str(self), self.response, self.server_message))
96
+
97
+
98
+ # INFERENCE CLIENT ERRORS
99
+
100
+
101
+ class InferenceTimeoutError(HTTPError, TimeoutError):
102
+ """Error raised when a model is unavailable or the request times out."""
103
+
104
+
105
+ # INFERENCE ENDPOINT ERRORS
106
+
107
+
108
+ class InferenceEndpointError(Exception):
109
+ """Generic exception when dealing with Inference Endpoints."""
110
+
111
+
112
+ class InferenceEndpointTimeoutError(InferenceEndpointError, TimeoutError):
113
+ """Exception for timeouts while waiting for Inference Endpoint."""
114
+
115
+
116
+ # SAFETENSORS ERRORS
117
+
118
+
119
+ class SafetensorsParsingError(Exception):
120
+ """Raised when failing to parse a safetensors file metadata.
121
+
122
+ This can be the case if the file is not a safetensors file or does not respect the specification.
123
+ """
124
+
125
+
126
+ class NotASafetensorsRepoError(Exception):
127
+ """Raised when a repo is not a Safetensors repo i.e. doesn't have either a `model.safetensors` or a
128
+ `model.safetensors.index.json` file.
129
+ """
130
+
131
+
132
+ # TEXT GENERATION ERRORS
133
+
134
+
135
+ class TextGenerationError(HTTPError):
136
+ """Generic error raised if text-generation went wrong."""
137
+
138
+
139
+ # Text Generation Inference Errors
140
+ class ValidationError(TextGenerationError):
141
+ """Server-side validation error."""
142
+
143
+
144
+ class GenerationError(TextGenerationError):
145
+ pass
146
+
147
+
148
+ class OverloadedError(TextGenerationError):
149
+ pass
150
+
151
+
152
+ class IncompleteGenerationError(TextGenerationError):
153
+ pass
154
+
155
+
156
+ class UnknownError(TextGenerationError):
157
+ pass
158
+
159
+
160
+ # VALIDATION ERRORS
161
+
162
+
163
+ class HFValidationError(ValueError):
164
+ """Generic exception thrown by `huggingface_hub` validators.
165
+
166
+ Inherits from [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError).
167
+ """
168
+
169
+
170
+ # FILE METADATA ERRORS
171
+
172
+
173
+ class DryRunError(OSError):
174
+ """Error triggered when a dry run is requested but cannot be performed (e.g. invalid repo)."""
175
+
176
+
177
+ class FileMetadataError(OSError):
178
+ """Error triggered when the metadata of a file on the Hub cannot be retrieved (missing ETag or commit_hash).
179
+
180
+ Inherits from `OSError` for backward compatibility.
181
+ """
182
+
183
+
184
+ # REPOSITORY ERRORS
185
+
186
+
187
+ class RepositoryNotFoundError(HfHubHTTPError):
188
+ """
189
+ Raised when trying to access a hf.co URL with an invalid repository name, or
190
+ with a private repo name the user does not have access to.
191
+
192
+ Example:
193
+
194
+ ```py
195
+ >>> from huggingface_hub import model_info
196
+ >>> model_info("<non_existent_repository>")
197
+ (...)
198
+ huggingface_hub.errors.RepositoryNotFoundError: 401 Client Error. (Request ID: PvMw_VjBMjVdMz53WKIzP)
199
+
200
+ Repository Not Found for url: https://huggingface.co/api/models/%3Cnon_existent_repository%3E.
201
+ Please make sure you specified the correct `repo_id` and `repo_type`.
202
+ If the repo is private, make sure you are authenticated.
203
+ Invalid username or password.
204
+ ```
205
+ """
206
+
207
+
208
+ class GatedRepoError(RepositoryNotFoundError):
209
+ """
210
+ Raised when trying to access a gated repository for which the user is not on the
211
+ authorized list.
212
+
213
+ Note: derives from `RepositoryNotFoundError` to ensure backward compatibility.
214
+
215
+ Example:
216
+
217
+ ```py
218
+ >>> from huggingface_hub import model_info
219
+ >>> model_info("<gated_repository>")
220
+ (...)
221
+ huggingface_hub.errors.GatedRepoError: 403 Client Error. (Request ID: ViT1Bf7O_026LGSQuVqfa)
222
+
223
+ Cannot access gated repo for url https://huggingface.co/api/models/ardent-figment/gated-model.
224
+ Access to model ardent-figment/gated-model is restricted and you are not in the authorized list.
225
+ Visit https://huggingface.co/ardent-figment/gated-model to ask for access.
226
+ ```
227
+ """
228
+
229
+
230
+ class DisabledRepoError(HfHubHTTPError):
231
+ """
232
+ Raised when trying to access a repository that has been disabled by its author.
233
+
234
+ Example:
235
+
236
+ ```py
237
+ >>> from huggingface_hub import dataset_info
238
+ >>> dataset_info("laion/laion-art")
239
+ (...)
240
+ huggingface_hub.errors.DisabledRepoError: 403 Client Error. (Request ID: Root=1-659fc3fa-3031673e0f92c71a2260dbe2;bc6f4dfb-b30a-4862-af0a-5cfe827610d8)
241
+
242
+ Cannot access repository for url https://huggingface.co/api/datasets/laion/laion-art.
243
+ Access to this resource is disabled.
244
+ ```
245
+ """
246
+
247
+
248
+ # REVISION ERROR
249
+
250
+
251
+ class RevisionNotFoundError(HfHubHTTPError):
252
+ """
253
+ Raised when trying to access a hf.co URL with a valid repository but an invalid
254
+ revision.
255
+
256
+ Example:
257
+
258
+ ```py
259
+ >>> from huggingface_hub import hf_hub_download
260
+ >>> hf_hub_download('bert-base-cased', 'config.json', revision='<non-existent-revision>')
261
+ (...)
262
+ huggingface_hub.errors.RevisionNotFoundError: 404 Client Error. (Request ID: Mwhe_c3Kt650GcdKEFomX)
263
+
264
+ Revision Not Found for url: https://huggingface.co/bert-base-cased/resolve/%3Cnon-existent-revision%3E/config.json.
265
+ ```
266
+ """
267
+
268
+
269
+ # ENTRY ERRORS
270
+ class EntryNotFoundError(Exception):
271
+ """
272
+ Raised when entry not found, either locally or remotely.
273
+
274
+ Example:
275
+
276
+ ```py
277
+ >>> from huggingface_hub import hf_hub_download
278
+ >>> hf_hub_download('bert-base-cased', '<non-existent-file>')
279
+ (...)
280
+ huggingface_hub.errors.RemoteEntryNotFoundError (...)
281
+ >>> hf_hub_download('bert-base-cased', '<non-existent-file>', local_files_only=True)
282
+ (...)
283
+ huggingface_hub.utils.errors.LocalEntryNotFoundError (...)
284
+ ```
285
+ """
286
+
287
+
288
+ class RemoteEntryNotFoundError(HfHubHTTPError, EntryNotFoundError):
289
+ """
290
+ Raised when trying to access a hf.co URL with a valid repository and revision
291
+ but an invalid filename.
292
+
293
+ Example:
294
+
295
+ ```py
296
+ >>> from huggingface_hub import hf_hub_download
297
+ >>> hf_hub_download('bert-base-cased', '<non-existent-file>')
298
+ (...)
299
+ huggingface_hub.errors.EntryNotFoundError: 404 Client Error. (Request ID: 53pNl6M0MxsnG5Sw8JA6x)
300
+
301
+ Entry Not Found for url: https://huggingface.co/bert-base-cased/resolve/main/%3Cnon-existent-file%3E.
302
+ ```
303
+ """
304
+
305
+
306
+ class LocalEntryNotFoundError(FileNotFoundError, EntryNotFoundError):
307
+ """
308
+ Raised when trying to access a file or snapshot that is not on the disk when network is
309
+ disabled or unavailable (connection issue). The entry may exist on the Hub.
310
+
311
+ Example:
312
+
313
+ ```py
314
+ >>> from huggingface_hub import hf_hub_download
315
+ >>> hf_hub_download('bert-base-cased', '<non-cached-file>', local_files_only=True)
316
+ (...)
317
+ huggingface_hub.errors.LocalEntryNotFoundError: Cannot find the requested files in the disk cache and outgoing traffic has been disabled. To enable hf.co look-ups and downloads online, set 'local_files_only' to False.
318
+ ```
319
+ """
320
+
321
+ def __init__(self, message: str):
322
+ super().__init__(message)
323
+
324
+
325
+ # REQUEST ERROR
326
+ class BadRequestError(HfHubHTTPError, ValueError):
327
+ """
328
+ Raised by `hf_raise_for_status` when the server returns a HTTP 400 error.
329
+
330
+ Example:
331
+
332
+ ```py
333
+ >>> resp = httpx.post("hf.co/api/check", ...)
334
+ >>> hf_raise_for_status(resp, endpoint_name="check")
335
+ huggingface_hub.errors.BadRequestError: Bad request for check endpoint: {details} (Request ID: XXX)
336
+ ```
337
+ """
338
+
339
+
340
+ # DDUF file format ERROR
341
+
342
+
343
+ class DDUFError(Exception):
344
+ """Base exception for errors related to the DDUF format."""
345
+
346
+
347
+ class DDUFCorruptedFileError(DDUFError):
348
+ """Exception thrown when the DDUF file is corrupted."""
349
+
350
+
351
+ class DDUFExportError(DDUFError):
352
+ """Base exception for errors during DDUF export."""
353
+
354
+
355
+ class DDUFInvalidEntryNameError(DDUFExportError):
356
+ """Exception thrown when the entry name is invalid."""
357
+
358
+
359
+ # STRICT DATACLASSES ERRORS
360
+
361
+
362
+ class StrictDataclassError(Exception):
363
+ """Base exception for strict dataclasses."""
364
+
365
+
366
+ class StrictDataclassDefinitionError(StrictDataclassError):
367
+ """Exception thrown when a strict dataclass is defined incorrectly."""
368
+
369
+
370
+ class StrictDataclassFieldValidationError(StrictDataclassError):
371
+ """Exception thrown when a strict dataclass fails validation for a given field."""
372
+
373
+ def __init__(self, field: str, cause: Exception):
374
+ error_message = f"Validation error for field '{field}':"
375
+ error_message += f"\n {cause.__class__.__name__}: {cause}"
376
+ super().__init__(error_message)
377
+
378
+
379
+ class StrictDataclassClassValidationError(StrictDataclassError):
380
+ """Exception thrown when a strict dataclass fails validation on a class validator."""
381
+
382
+ def __init__(self, validator: str, cause: Exception):
383
+ error_message = f"Class validation error for validator '{validator}':"
384
+ error_message += f"\n {cause.__class__.__name__}: {cause}"
385
+ super().__init__(error_message)
386
+
387
+
388
+ # XET ERRORS
389
+
390
+
391
+ class XetError(Exception):
392
+ """Base exception for errors related to Xet Storage."""
393
+
394
+
395
+ class XetAuthorizationError(XetError):
396
+ """Exception thrown when the user does not have the right authorization to use Xet Storage."""
397
+
398
+
399
+ class XetRefreshTokenError(XetError):
400
+ """Exception thrown when the refresh token is invalid."""
401
+
402
+
403
+ class XetDownloadError(Exception):
404
+ """Exception thrown when the download from Xet Storage fails."""
env/lib/python3.13/site-packages/huggingface_hub/fastai_utils.py ADDED
@@ -0,0 +1,414 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import os
3
+ from pathlib import Path
4
+ from pickle import DEFAULT_PROTOCOL, PicklingError
5
+ from typing import Any, Optional, Union
6
+
7
+ from packaging import version
8
+
9
+ from huggingface_hub import constants, snapshot_download
10
+ from huggingface_hub.hf_api import HfApi
11
+ from huggingface_hub.utils import (
12
+ SoftTemporaryDirectory,
13
+ get_fastai_version,
14
+ get_fastcore_version,
15
+ get_python_version,
16
+ )
17
+
18
+ from .utils import logging, validate_hf_hub_args
19
+
20
+
21
+ logger = logging.get_logger(__name__)
22
+
23
+
24
+ def _check_fastai_fastcore_versions(
25
+ fastai_min_version: str = "2.4",
26
+ fastcore_min_version: str = "1.3.27",
27
+ ):
28
+ """
29
+ Checks that the installed fastai and fastcore versions are compatible for pickle serialization.
30
+
31
+ Args:
32
+ fastai_min_version (`str`, *optional*):
33
+ The minimum fastai version supported.
34
+ fastcore_min_version (`str`, *optional*):
35
+ The minimum fastcore version supported.
36
+
37
+ > [!TIP]
38
+ > Raises the following error:
39
+ >
40
+ > - [`ImportError`](https://docs.python.org/3/library/exceptions.html#ImportError)
41
+ > if the fastai or fastcore libraries are not available or are of an invalid version.
42
+ """
43
+
44
+ if (get_fastcore_version() or get_fastai_version()) == "N/A":
45
+ raise ImportError(
46
+ f"fastai>={fastai_min_version} and fastcore>={fastcore_min_version} are"
47
+ f" required. Currently using fastai=={get_fastai_version()} and"
48
+ f" fastcore=={get_fastcore_version()}."
49
+ )
50
+
51
+ current_fastai_version = version.Version(get_fastai_version())
52
+ current_fastcore_version = version.Version(get_fastcore_version())
53
+
54
+ if current_fastai_version < version.Version(fastai_min_version):
55
+ raise ImportError(
56
+ "`push_to_hub_fastai` and `from_pretrained_fastai` require a"
57
+ f" fastai>={fastai_min_version} version, but you are using fastai version"
58
+ f" {get_fastai_version()} which is incompatible. Upgrade with `pip install"
59
+ " fastai==2.5.6`."
60
+ )
61
+
62
+ if current_fastcore_version < version.Version(fastcore_min_version):
63
+ raise ImportError(
64
+ "`push_to_hub_fastai` and `from_pretrained_fastai` require a"
65
+ f" fastcore>={fastcore_min_version} version, but you are using fastcore"
66
+ f" version {get_fastcore_version()} which is incompatible. Upgrade with"
67
+ " `pip install fastcore==1.3.27`."
68
+ )
69
+
70
+
71
+ def _check_fastai_fastcore_pyproject_versions(
72
+ storage_folder: str,
73
+ fastai_min_version: str = "2.4",
74
+ fastcore_min_version: str = "1.3.27",
75
+ ):
76
+ """
77
+ Checks that the `pyproject.toml` file in the directory `storage_folder` has fastai and fastcore versions
78
+ that are compatible with `from_pretrained_fastai` and `push_to_hub_fastai`. If `pyproject.toml` does not exist
79
+ or does not contain versions for fastai and fastcore, then it logs a warning.
80
+
81
+ Args:
82
+ storage_folder (`str`):
83
+ Folder to look for the `pyproject.toml` file.
84
+ fastai_min_version (`str`, *optional*):
85
+ The minimum fastai version supported.
86
+ fastcore_min_version (`str`, *optional*):
87
+ The minimum fastcore version supported.
88
+
89
+ > [!TIP]
90
+ > Raises the following errors:
91
+ >
92
+ > - [`ImportError`](https://docs.python.org/3/library/exceptions.html#ImportError)
93
+ > if the `toml` module is not installed.
94
+ > - [`ImportError`](https://docs.python.org/3/library/exceptions.html#ImportError)
95
+ > if the `pyproject.toml` indicates a lower than minimum supported version of fastai or fastcore.
96
+ """
97
+
98
+ try:
99
+ import toml
100
+ except ModuleNotFoundError:
101
+ raise ImportError(
102
+ "`push_to_hub_fastai` and `from_pretrained_fastai` require the toml module."
103
+ " Install it with `pip install toml`."
104
+ )
105
+
106
+ # Checks that a `pyproject.toml`, with `build-system` and `requires` sections, exists in the repository. If so, get a list of required packages.
107
+ if not os.path.isfile(f"{storage_folder}/pyproject.toml"):
108
+ logger.warning(
109
+ "There is no `pyproject.toml` in the repository that contains the fastai"
110
+ " `Learner`. The `pyproject.toml` would allow us to verify that your fastai"
111
+ " and fastcore versions are compatible with those of the model you want to"
112
+ " load."
113
+ )
114
+ return
115
+ pyproject_toml = toml.load(f"{storage_folder}/pyproject.toml")
116
+
117
+ if "build-system" not in pyproject_toml.keys():
118
+ logger.warning(
119
+ "There is no `build-system` section in the pyproject.toml of the repository"
120
+ " that contains the fastai `Learner`. The `build-system` would allow us to"
121
+ " verify that your fastai and fastcore versions are compatible with those"
122
+ " of the model you want to load."
123
+ )
124
+ return
125
+ build_system_toml = pyproject_toml["build-system"]
126
+
127
+ if "requires" not in build_system_toml.keys():
128
+ logger.warning(
129
+ "There is no `requires` section in the pyproject.toml of the repository"
130
+ " that contains the fastai `Learner`. The `requires` would allow us to"
131
+ " verify that your fastai and fastcore versions are compatible with those"
132
+ " of the model you want to load."
133
+ )
134
+ return
135
+ package_versions = build_system_toml["requires"]
136
+
137
+ # Extracts contains fastai and fastcore versions from `pyproject.toml` if available.
138
+ # If the package is specified but not the version (e.g. "fastai" instead of "fastai=2.4"), the default versions are the highest.
139
+ fastai_packages = [pck for pck in package_versions if pck.startswith("fastai")]
140
+ if len(fastai_packages) == 0:
141
+ logger.warning("The repository does not have a fastai version specified in the `pyproject.toml`.")
142
+ # fastai_version is an empty string if not specified
143
+ else:
144
+ fastai_version = str(fastai_packages[0]).partition("=")[2]
145
+ if fastai_version != "" and version.Version(fastai_version) < version.Version(fastai_min_version):
146
+ raise ImportError(
147
+ "`from_pretrained_fastai` requires"
148
+ f" fastai>={fastai_min_version} version but the model to load uses"
149
+ f" {fastai_version} which is incompatible."
150
+ )
151
+
152
+ fastcore_packages = [pck for pck in package_versions if pck.startswith("fastcore")]
153
+ if len(fastcore_packages) == 0:
154
+ logger.warning("The repository does not have a fastcore version specified in the `pyproject.toml`.")
155
+ # fastcore_version is an empty string if not specified
156
+ else:
157
+ fastcore_version = str(fastcore_packages[0]).partition("=")[2]
158
+ if fastcore_version != "" and version.Version(fastcore_version) < version.Version(fastcore_min_version):
159
+ raise ImportError(
160
+ "`from_pretrained_fastai` requires"
161
+ f" fastcore>={fastcore_min_version} version, but you are using fastcore"
162
+ f" version {fastcore_version} which is incompatible."
163
+ )
164
+
165
+
166
+ README_TEMPLATE = """---
167
+ tags:
168
+ - fastai
169
+ ---
170
+
171
+ # Amazing!
172
+
173
+ 🥳 Congratulations on hosting your fastai model on the Hugging Face Hub!
174
+
175
+ # Some next steps
176
+ 1. Fill out this model card with more information (see the template below and the [documentation here](https://huggingface.co/docs/hub/model-repos))!
177
+
178
+ 2. Create a demo in Gradio or Streamlit using 🤗 Spaces ([documentation here](https://huggingface.co/docs/hub/spaces)).
179
+
180
+ 3. Join the fastai community on the [Fastai Discord](https://discord.com/invite/YKrxeNn)!
181
+
182
+ Greetings fellow fastlearner 🤝! Don't forget to delete this content from your model card.
183
+
184
+
185
+ ---
186
+
187
+
188
+ # Model card
189
+
190
+ ## Model description
191
+ More information needed
192
+
193
+ ## Intended uses & limitations
194
+ More information needed
195
+
196
+ ## Training and evaluation data
197
+ More information needed
198
+ """
199
+
200
+ PYPROJECT_TEMPLATE = f"""[build-system]
201
+ requires = ["setuptools>=40.8.0", "wheel", "python={get_python_version()}", "fastai={get_fastai_version()}", "fastcore={get_fastcore_version()}"]
202
+ build-backend = "setuptools.build_meta:__legacy__"
203
+ """
204
+
205
+
206
+ def _create_model_card(repo_dir: Path):
207
+ """
208
+ Creates a model card for the repository.
209
+
210
+ Args:
211
+ repo_dir (`Path`):
212
+ Directory where model card is created.
213
+ """
214
+ readme_path = repo_dir / "README.md"
215
+
216
+ if not readme_path.exists():
217
+ with readme_path.open("w", encoding="utf-8") as f:
218
+ f.write(README_TEMPLATE)
219
+
220
+
221
+ def _create_model_pyproject(repo_dir: Path):
222
+ """
223
+ Creates a `pyproject.toml` for the repository.
224
+
225
+ Args:
226
+ repo_dir (`Path`):
227
+ Directory where `pyproject.toml` is created.
228
+ """
229
+ pyproject_path = repo_dir / "pyproject.toml"
230
+
231
+ if not pyproject_path.exists():
232
+ with pyproject_path.open("w", encoding="utf-8") as f:
233
+ f.write(PYPROJECT_TEMPLATE)
234
+
235
+
236
+ def _save_pretrained_fastai(
237
+ learner,
238
+ save_directory: Union[str, Path],
239
+ config: Optional[dict[str, Any]] = None,
240
+ ):
241
+ """
242
+ Saves a fastai learner to `save_directory` in pickle format using the default pickle protocol for the version of python used.
243
+
244
+ Args:
245
+ learner (`Learner`):
246
+ The `fastai.Learner` you'd like to save.
247
+ save_directory (`str` or `Path`):
248
+ Specific directory in which you want to save the fastai learner.
249
+ config (`dict`, *optional*):
250
+ Configuration object. Will be uploaded as a .json file. Example: 'https://huggingface.co/espejelomar/fastai-pet-breeds-classification/blob/main/config.json'.
251
+
252
+ > [!TIP]
253
+ > Raises the following error:
254
+ >
255
+ > - [`RuntimeError`](https://docs.python.org/3/library/exceptions.html#RuntimeError)
256
+ > if the config file provided is not a dictionary.
257
+ """
258
+ _check_fastai_fastcore_versions()
259
+
260
+ os.makedirs(save_directory, exist_ok=True)
261
+
262
+ # if the user provides config then we update it with the fastai and fastcore versions in CONFIG_TEMPLATE.
263
+ if config is not None:
264
+ if not isinstance(config, dict):
265
+ raise RuntimeError(f"Provided config should be a dict. Got: '{type(config)}'")
266
+ path = os.path.join(save_directory, constants.CONFIG_NAME)
267
+ with open(path, "w") as f:
268
+ json.dump(config, f)
269
+
270
+ _create_model_card(Path(save_directory))
271
+ _create_model_pyproject(Path(save_directory))
272
+
273
+ # learner.export saves the model in `self.path`.
274
+ learner.path = Path(save_directory)
275
+ os.makedirs(save_directory, exist_ok=True)
276
+ try:
277
+ learner.export(
278
+ fname="model.pkl",
279
+ pickle_protocol=DEFAULT_PROTOCOL,
280
+ )
281
+ except PicklingError:
282
+ raise PicklingError(
283
+ "You are using a lambda function, i.e., an anonymous function. `pickle`"
284
+ " cannot pickle function objects and requires that all functions have"
285
+ " names. One possible solution is to name the function."
286
+ )
287
+
288
+
289
+ @validate_hf_hub_args
290
+ def from_pretrained_fastai(
291
+ repo_id: str,
292
+ revision: Optional[str] = None,
293
+ ):
294
+ """
295
+ Load pretrained fastai model from the Hub or from a local directory.
296
+
297
+ Args:
298
+ repo_id (`str`):
299
+ The location where the pickled fastai.Learner is. It can be either of the two:
300
+ - Hosted on the Hugging Face Hub. E.g.: 'espejelomar/fatai-pet-breeds-classification' or 'distilgpt2'.
301
+ You can add a `revision` by appending `@` at the end of `repo_id`. E.g.: `dbmdz/bert-base-german-cased@main`.
302
+ Revision is the specific model version to use. Since we use a git-based system for storing models and other
303
+ artifacts on the Hugging Face Hub, it can be a branch name, a tag name, or a commit id.
304
+ - Hosted locally. `repo_id` would be a directory containing the pickle and a pyproject.toml
305
+ indicating the fastai and fastcore versions used to build the `fastai.Learner`. E.g.: `./my_model_directory/`.
306
+ revision (`str`, *optional*):
307
+ Revision at which the repo's files are downloaded. See documentation of `snapshot_download`.
308
+
309
+ Returns:
310
+ The `fastai.Learner` model in the `repo_id` repo.
311
+ """
312
+ _check_fastai_fastcore_versions()
313
+
314
+ # Load the `repo_id` repo.
315
+ # `snapshot_download` returns the folder where the model was stored.
316
+ # `cache_dir` will be the default '/root/.cache/huggingface/hub'
317
+ if not os.path.isdir(repo_id):
318
+ storage_folder = snapshot_download(
319
+ repo_id=repo_id,
320
+ revision=revision,
321
+ library_name="fastai",
322
+ library_version=get_fastai_version(),
323
+ )
324
+ else:
325
+ storage_folder = repo_id
326
+
327
+ _check_fastai_fastcore_pyproject_versions(storage_folder)
328
+
329
+ from fastai.learner import load_learner # type: ignore
330
+
331
+ return load_learner(os.path.join(storage_folder, "model.pkl"))
332
+
333
+
334
+ @validate_hf_hub_args
335
+ def push_to_hub_fastai(
336
+ learner,
337
+ *,
338
+ repo_id: str,
339
+ commit_message: str = "Push FastAI model using huggingface_hub.",
340
+ private: Optional[bool] = None,
341
+ token: Optional[str] = None,
342
+ config: Optional[dict] = None,
343
+ branch: Optional[str] = None,
344
+ create_pr: Optional[bool] = None,
345
+ allow_patterns: Optional[Union[list[str], str]] = None,
346
+ ignore_patterns: Optional[Union[list[str], str]] = None,
347
+ delete_patterns: Optional[Union[list[str], str]] = None,
348
+ api_endpoint: Optional[str] = None,
349
+ ):
350
+ """
351
+ Upload learner checkpoint files to the Hub.
352
+
353
+ Use `allow_patterns` and `ignore_patterns` to precisely filter which files should be pushed to the hub. Use
354
+ `delete_patterns` to delete existing remote files in the same commit. See [`upload_folder`] reference for more
355
+ details.
356
+
357
+ Args:
358
+ learner (`Learner`):
359
+ The `fastai.Learner' you'd like to push to the Hub.
360
+ repo_id (`str`):
361
+ The repository id for your model in Hub in the format of "namespace/repo_name". The namespace can be your individual account or an organization to which you have write access (for example, 'stanfordnlp/stanza-de').
362
+ commit_message (`str`, *optional*):
363
+ Message to commit while pushing. Will default to :obj:`"add model"`.
364
+ private (`bool`, *optional*):
365
+ Whether or not the repository created should be private.
366
+ If `None` (default), will default to been public except if the organization's default is private.
367
+ token (`str`, *optional*):
368
+ The Hugging Face account token to use as HTTP bearer authorization for remote files. If :obj:`None`, the token will be asked by a prompt.
369
+ config (`dict`, *optional*):
370
+ Configuration object to be saved alongside the model weights.
371
+ branch (`str`, *optional*):
372
+ The git branch on which to push the model. This defaults to
373
+ the default branch as specified in your repository, which
374
+ defaults to `"main"`.
375
+ create_pr (`boolean`, *optional*):
376
+ Whether or not to create a Pull Request from `branch` with that commit.
377
+ Defaults to `False`.
378
+ api_endpoint (`str`, *optional*):
379
+ The API endpoint to use when pushing the model to the hub.
380
+ allow_patterns (`list[str]` or `str`, *optional*):
381
+ If provided, only files matching at least one pattern are pushed.
382
+ ignore_patterns (`list[str]` or `str`, *optional*):
383
+ If provided, files matching any of the patterns are not pushed.
384
+ delete_patterns (`list[str]` or `str`, *optional*):
385
+ If provided, remote files matching any of the patterns will be deleted from the repo.
386
+
387
+ Returns:
388
+ The url of the commit of your model in the given repository.
389
+
390
+ > [!TIP]
391
+ > Raises the following error:
392
+ >
393
+ > - [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError)
394
+ > if the user is not log on to the Hugging Face Hub.
395
+ """
396
+ _check_fastai_fastcore_versions()
397
+ api = HfApi(endpoint=api_endpoint)
398
+ repo_id = api.create_repo(repo_id=repo_id, token=token, private=private, exist_ok=True).repo_id
399
+
400
+ # Push the files to the repo in a single commit
401
+ with SoftTemporaryDirectory() as tmp:
402
+ saved_path = Path(tmp) / repo_id
403
+ _save_pretrained_fastai(learner, saved_path, config=config)
404
+ return api.upload_folder(
405
+ repo_id=repo_id,
406
+ token=token,
407
+ folder_path=saved_path,
408
+ commit_message=commit_message,
409
+ revision=branch,
410
+ create_pr=create_pr,
411
+ allow_patterns=allow_patterns,
412
+ ignore_patterns=ignore_patterns,
413
+ delete_patterns=delete_patterns,
414
+ )
env/lib/python3.13/site-packages/huggingface_hub/file_download.py ADDED
@@ -0,0 +1,1958 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import copy
2
+ import errno
3
+ import os
4
+ import re
5
+ import shutil
6
+ import stat
7
+ import time
8
+ import uuid
9
+ import warnings
10
+ from dataclasses import dataclass
11
+ from pathlib import Path
12
+ from typing import Any, BinaryIO, Literal, NoReturn, Optional, Union, overload
13
+ from urllib.parse import quote, urlparse
14
+
15
+ import httpx
16
+ from tqdm.auto import tqdm as base_tqdm
17
+
18
+ from . import constants
19
+ from ._local_folder import get_local_download_paths, read_download_metadata, write_download_metadata
20
+ from .errors import (
21
+ FileMetadataError,
22
+ GatedRepoError,
23
+ HfHubHTTPError,
24
+ LocalEntryNotFoundError,
25
+ RemoteEntryNotFoundError,
26
+ RepositoryNotFoundError,
27
+ RevisionNotFoundError,
28
+ )
29
+ from .utils import (
30
+ OfflineModeIsEnabled,
31
+ SoftTemporaryDirectory,
32
+ WeakFileLock,
33
+ XetFileData,
34
+ build_hf_headers,
35
+ hf_raise_for_status,
36
+ logging,
37
+ parse_xet_file_data_from_response,
38
+ refresh_xet_connection_info,
39
+ tqdm,
40
+ validate_hf_hub_args,
41
+ )
42
+ from .utils._http import (
43
+ _DEFAULT_RETRY_ON_EXCEPTIONS,
44
+ _DEFAULT_RETRY_ON_STATUS_CODES,
45
+ _adjust_range_header,
46
+ http_backoff,
47
+ http_stream_backoff,
48
+ )
49
+ from .utils._runtime import is_xet_available
50
+ from .utils._typing import HTTP_METHOD_T
51
+ from .utils.sha import sha_fileobj
52
+ from .utils.tqdm import _get_progress_bar_context
53
+
54
+
55
+ logger = logging.get_logger(__name__)
56
+
57
+ # Return value when trying to load a file from cache but the file does not exist in the distant repo.
58
+ _CACHED_NO_EXIST = object()
59
+ _CACHED_NO_EXIST_T = Any
60
+
61
+ # Regex to get filename from a "Content-Disposition" header for CDN-served files
62
+ HEADER_FILENAME_PATTERN = re.compile(r'filename="(?P<filename>.*?)";')
63
+
64
+ # Regex to check if the revision IS directly a commit_hash
65
+ REGEX_COMMIT_HASH = re.compile(r"^[0-9a-f]{40}$")
66
+
67
+ # Regex to check if the file etag IS a valid sha256
68
+ REGEX_SHA256 = re.compile(r"^[0-9a-f]{64}$")
69
+
70
+ _are_symlinks_supported_in_dir: dict[str, bool] = {}
71
+
72
+ # Internal retry timeout for metadata fetch when no local file exists
73
+ _ETAG_RETRY_TIMEOUT = 60
74
+
75
+
76
+ def are_symlinks_supported(cache_dir: Union[str, Path, None] = None) -> bool:
77
+ """Return whether the symlinks are supported on the machine.
78
+
79
+ Since symlinks support can change depending on the mounted disk, we need to check
80
+ on the precise cache folder. By default, the default HF cache directory is checked.
81
+
82
+ Args:
83
+ cache_dir (`str`, `Path`, *optional*):
84
+ Path to the folder where cached files are stored.
85
+
86
+ Returns: [bool] Whether symlinks are supported in the directory.
87
+ """
88
+ # Defaults to HF cache
89
+ if cache_dir is None:
90
+ cache_dir = constants.HF_HUB_CACHE
91
+ cache_dir = str(Path(cache_dir).expanduser().resolve()) # make it unique
92
+
93
+ # Check symlink compatibility only once (per cache directory) at first time use
94
+ if cache_dir not in _are_symlinks_supported_in_dir:
95
+ _are_symlinks_supported_in_dir[cache_dir] = True
96
+
97
+ os.makedirs(cache_dir, exist_ok=True)
98
+ with SoftTemporaryDirectory(dir=cache_dir) as tmpdir:
99
+ src_path = Path(tmpdir) / "dummy_file_src"
100
+ src_path.touch()
101
+ dst_path = Path(tmpdir) / "dummy_file_dst"
102
+
103
+ # Relative source path as in `_create_symlink``
104
+ relative_src = os.path.relpath(src_path, start=os.path.dirname(dst_path))
105
+ try:
106
+ os.symlink(relative_src, dst_path)
107
+ except OSError:
108
+ # Likely running on Windows
109
+ _are_symlinks_supported_in_dir[cache_dir] = False
110
+
111
+ if not constants.HF_HUB_DISABLE_SYMLINKS_WARNING:
112
+ message = (
113
+ "`huggingface_hub` cache-system uses symlinks by default to"
114
+ " efficiently store duplicated files but your machine does not"
115
+ f" support them in {cache_dir}. Caching files will still work"
116
+ " but in a degraded version that might require more space on"
117
+ " your disk. This warning can be disabled by setting the"
118
+ " `HF_HUB_DISABLE_SYMLINKS_WARNING` environment variable. For"
119
+ " more details, see"
120
+ " https://huggingface.co/docs/huggingface_hub/how-to-cache#limitations."
121
+ )
122
+ if os.name == "nt":
123
+ message += (
124
+ "\nTo support symlinks on Windows, you either need to"
125
+ " activate Developer Mode or to run Python as an"
126
+ " administrator. In order to activate developer mode,"
127
+ " see this article:"
128
+ " https://docs.microsoft.com/en-us/windows/apps/get-started/enable-your-device-for-development"
129
+ )
130
+ warnings.warn(message)
131
+
132
+ return _are_symlinks_supported_in_dir[cache_dir]
133
+
134
+
135
+ @dataclass(frozen=True)
136
+ class HfFileMetadata:
137
+ """Data structure containing information about a file versioned on the Hub.
138
+
139
+ Returned by [`get_hf_file_metadata`] based on a URL.
140
+
141
+ Args:
142
+ commit_hash (`str`, *optional*):
143
+ The commit_hash related to the file.
144
+ etag (`str`, *optional*):
145
+ Etag of the file on the server.
146
+ location (`str`):
147
+ Location where to download the file. Can be a Hub url or not (CDN).
148
+ size (`size`):
149
+ Size of the file. In case of an LFS file, contains the size of the actual
150
+ LFS file, not the pointer.
151
+ xet_file_data (`XetFileData`, *optional*):
152
+ Xet information for the file. This is only set if the file is stored using Xet storage.
153
+ """
154
+
155
+ commit_hash: Optional[str]
156
+ etag: Optional[str]
157
+ location: str
158
+ size: Optional[int]
159
+ xet_file_data: Optional[XetFileData]
160
+
161
+
162
+ @dataclass
163
+ class DryRunFileInfo:
164
+ """Information returned when performing a dry run of a file download.
165
+
166
+ Returned by [`hf_hub_download`] when `dry_run=True`.
167
+
168
+ Args:
169
+ commit_hash (`str`):
170
+ The commit_hash related to the file.
171
+ file_size (`int`):
172
+ Size of the file. In case of an LFS file, contains the size of the actual LFS file, not the pointer.
173
+ filename (`str`):
174
+ Name of the file in the repo.
175
+ is_cached (`bool`):
176
+ Whether the file is already cached locally.
177
+ will_download (`bool`):
178
+ Whether the file will be downloaded if `hf_hub_download` is called with `dry_run=False`.
179
+ In practice, will_download is `True` if the file is not cached or if `force_download=True`.
180
+ """
181
+
182
+ commit_hash: str
183
+ file_size: int
184
+ filename: str
185
+ local_path: str
186
+ is_cached: bool
187
+ will_download: bool
188
+
189
+
190
+ @validate_hf_hub_args
191
+ def hf_hub_url(
192
+ repo_id: str,
193
+ filename: str,
194
+ *,
195
+ subfolder: Optional[str] = None,
196
+ repo_type: Optional[str] = None,
197
+ revision: Optional[str] = None,
198
+ endpoint: Optional[str] = None,
199
+ ) -> str:
200
+ """Construct the URL of a file from the given information.
201
+
202
+ The resolved address can either be a huggingface.co-hosted url, or a link to
203
+ Cloudfront (a Content Delivery Network, or CDN) for large files which are
204
+ more than a few MBs.
205
+
206
+ Args:
207
+ repo_id (`str`):
208
+ A namespace (user or an organization) name and a repo name separated
209
+ by a `/`.
210
+ filename (`str`):
211
+ The name of the file in the repo.
212
+ subfolder (`str`, *optional*):
213
+ An optional value corresponding to a folder inside the repo.
214
+ repo_type (`str`, *optional*):
215
+ Set to `"dataset"` or `"space"` if downloading from a dataset or space,
216
+ `None` or `"model"` if downloading from a model. Default is `None`.
217
+ revision (`str`, *optional*):
218
+ An optional Git revision id which can be a branch name, a tag, or a
219
+ commit hash.
220
+
221
+ Example:
222
+
223
+ ```python
224
+ >>> from huggingface_hub import hf_hub_url
225
+
226
+ >>> hf_hub_url(
227
+ ... repo_id="julien-c/EsperBERTo-small", filename="pytorch_model.bin"
228
+ ... )
229
+ 'https://huggingface.co/julien-c/EsperBERTo-small/resolve/main/pytorch_model.bin'
230
+ ```
231
+
232
+ > [!TIP]
233
+ > Notes:
234
+ >
235
+ > Cloudfront is replicated over the globe so downloads are way faster for
236
+ > the end user (and it also lowers our bandwidth costs).
237
+ >
238
+ > Cloudfront aggressively caches files by default (default TTL is 24
239
+ > hours), however this is not an issue here because we implement a
240
+ > git-based versioning system on huggingface.co, which means that we store
241
+ > the files on S3/Cloudfront in a content-addressable way (i.e., the file
242
+ > name is its hash). Using content-addressable filenames means cache can't
243
+ > ever be stale.
244
+ >
245
+ > In terms of client-side caching from this library, we base our caching
246
+ > on the objects' entity tag (`ETag`), which is an identifier of a
247
+ > specific version of a resource [1]_. An object's ETag is: its git-sha1
248
+ > if stored in git, or its sha256 if stored in git-lfs.
249
+
250
+ References:
251
+
252
+ - [1] https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag
253
+ """
254
+ if subfolder == "":
255
+ subfolder = None
256
+ if subfolder is not None:
257
+ filename = f"{subfolder}/{filename}"
258
+
259
+ if repo_type not in constants.REPO_TYPES:
260
+ raise ValueError("Invalid repo type")
261
+
262
+ if repo_type in constants.REPO_TYPES_URL_PREFIXES:
263
+ repo_id = constants.REPO_TYPES_URL_PREFIXES[repo_type] + repo_id
264
+
265
+ if revision is None:
266
+ revision = constants.DEFAULT_REVISION
267
+ url = constants.HUGGINGFACE_CO_URL_TEMPLATE.format(
268
+ repo_id=repo_id, revision=quote(revision, safe=""), filename=quote(filename)
269
+ )
270
+ # Update endpoint if provided
271
+ if endpoint is not None and url.startswith(constants.ENDPOINT):
272
+ url = endpoint + url[len(constants.ENDPOINT) :]
273
+ return url
274
+
275
+
276
+ def _httpx_follow_relative_redirects(
277
+ method: HTTP_METHOD_T, url: str, *, retry_on_errors: bool = False, **httpx_kwargs
278
+ ) -> httpx.Response:
279
+ """Perform an HTTP request with backoff and follow relative redirects only.
280
+
281
+ This is useful to follow a redirection to a renamed repository without following redirection to a CDN.
282
+
283
+ A backoff mechanism retries the HTTP call on errors (429, 5xx, timeout, network errors).
284
+
285
+ Args:
286
+ method (`str`):
287
+ HTTP method, such as 'GET' or 'HEAD'.
288
+ url (`str`):
289
+ The URL of the resource to fetch.
290
+ retry_on_errors (`bool`, *optional*, defaults to `False`):
291
+ Whether to retry on errors. If False, no retry is performed (fast fallback to local cache).
292
+ If True, uses default retry behavior (429, 5xx, timeout, network errors).
293
+ **httpx_kwargs (`dict`, *optional*):
294
+ Params to pass to `httpx.request`.
295
+ """
296
+ # if `retry_on_errors=False`, disable all retries for fast fallback to cache
297
+ no_retry_kwargs: dict[str, Any] = (
298
+ {} if retry_on_errors else {"retry_on_exceptions": (), "retry_on_status_codes": ()}
299
+ )
300
+
301
+ while True:
302
+ response = http_backoff(
303
+ method=method,
304
+ url=url,
305
+ **httpx_kwargs,
306
+ follow_redirects=False,
307
+ **no_retry_kwargs,
308
+ )
309
+ hf_raise_for_status(response)
310
+
311
+ # Check if response is a relative redirect
312
+ if 300 <= response.status_code <= 399:
313
+ parsed_target = urlparse(response.headers["Location"])
314
+ if parsed_target.netloc == "":
315
+ # Relative redirect -> update URL and retry
316
+ url = urlparse(url)._replace(path=parsed_target.path).geturl()
317
+ continue
318
+
319
+ # Break if no relative redirect
320
+ break
321
+
322
+ return response
323
+
324
+
325
+ def _get_file_length_from_http_response(response: httpx.Response) -> Optional[int]:
326
+ """
327
+ Get the length of the file from the HTTP response headers.
328
+
329
+ This function extracts the file size from the HTTP response headers, either from the
330
+ `Content-Range` or `Content-Length` header, if available (in that order).
331
+
332
+ Args:
333
+ response (`httpx.Response`):
334
+ The HTTP response object.
335
+
336
+ Returns:
337
+ `int` or `None`: The length of the file in bytes, or None if not available.
338
+ """
339
+
340
+ # If HTTP response contains compressed body (e.g. gzip), the `Content-Length` header will
341
+ # contain the length of the compressed body, not the uncompressed file size.
342
+ # And at the start of transmission there's no way to know the uncompressed file size for gzip,
343
+ # thus we return None in that case.
344
+ content_encoding = response.headers.get("Content-Encoding", "identity").lower()
345
+ if content_encoding != "identity":
346
+ # gzip/br/deflate/zstd etc
347
+ return None
348
+
349
+ content_range = response.headers.get("Content-Range")
350
+ if content_range is not None:
351
+ return int(content_range.rsplit("/")[-1])
352
+
353
+ content_length = response.headers.get("Content-Length")
354
+ if content_length is not None:
355
+ return int(content_length)
356
+
357
+ return None
358
+
359
+
360
+ @validate_hf_hub_args
361
+ def http_get(
362
+ url: str,
363
+ temp_file: BinaryIO,
364
+ *,
365
+ resume_size: int = 0,
366
+ headers: Optional[dict[str, Any]] = None,
367
+ expected_size: Optional[int] = None,
368
+ displayed_filename: Optional[str] = None,
369
+ tqdm_class: Optional[type[base_tqdm]] = None,
370
+ _nb_retries: int = 5,
371
+ _tqdm_bar: Optional[tqdm] = None,
372
+ ) -> None:
373
+ """
374
+ Download a remote file. Do not gobble up errors, and will return errors tailored to the Hugging Face Hub.
375
+
376
+ If ConnectionError (SSLError) or ReadTimeout happen while streaming data from the server, it is most likely a
377
+ transient error (network outage?). We log a warning message and try to resume the download a few times before
378
+ giving up. The method gives up after 5 attempts if no new data has being received from the server.
379
+
380
+ Args:
381
+ url (`str`):
382
+ The URL of the file to download.
383
+ temp_file (`BinaryIO`):
384
+ The file-like object where to save the file.
385
+ resume_size (`int`, *optional*):
386
+ The number of bytes already downloaded. If set to 0 (default), the whole file is download. If set to a
387
+ positive number, the download will resume at the given position.
388
+ headers (`dict`, *optional*):
389
+ Dictionary of HTTP Headers to send with the request.
390
+ expected_size (`int`, *optional*):
391
+ The expected size of the file to download. If set, the download will raise an error if the size of the
392
+ received content is different from the expected one.
393
+ displayed_filename (`str`, *optional*):
394
+ The filename of the file that is being downloaded. Value is used only to display a nice progress bar. If
395
+ not set, the filename is guessed from the URL or the `Content-Disposition` header.
396
+ """
397
+ if expected_size is not None and resume_size == expected_size:
398
+ # If the file is already fully downloaded, we don't need to download it again.
399
+ return
400
+
401
+ initial_headers = headers
402
+ headers = copy.deepcopy(headers) or {}
403
+ if resume_size > 0:
404
+ headers["Range"] = _adjust_range_header(headers.get("Range"), resume_size)
405
+ elif expected_size and expected_size > constants.MAX_HTTP_DOWNLOAD_SIZE:
406
+ # Any files over 50GB will not be available through basic http requests.
407
+ raise ValueError(
408
+ "The file is too large to be downloaded using the regular download method. "
409
+ " Install `hf_xet` with `pip install hf_xet` for xet-powered downloads."
410
+ )
411
+
412
+ with http_stream_backoff(
413
+ method="GET",
414
+ url=url,
415
+ headers=headers,
416
+ timeout=constants.HF_HUB_DOWNLOAD_TIMEOUT,
417
+ retry_on_exceptions=(),
418
+ retry_on_status_codes=(429,),
419
+ ) as response:
420
+ hf_raise_for_status(response)
421
+ total: Optional[int] = _get_file_length_from_http_response(response)
422
+
423
+ if displayed_filename is None:
424
+ displayed_filename = url
425
+ content_disposition = response.headers.get("Content-Disposition")
426
+ if content_disposition is not None:
427
+ match = HEADER_FILENAME_PATTERN.search(content_disposition)
428
+ if match is not None:
429
+ # Means file is on CDN
430
+ displayed_filename = match.groupdict()["filename"]
431
+
432
+ # Truncate filename if too long to display
433
+ if len(displayed_filename) > 40:
434
+ displayed_filename = f"(…){displayed_filename[-40:]}"
435
+
436
+ consistency_error_message = (
437
+ f"Consistency check failed: file should be of size {expected_size} but has size"
438
+ f" {{actual_size}} ({displayed_filename}).\nThis is usually due to network issues while downloading the file."
439
+ " Please retry with `force_download=True`."
440
+ )
441
+ progress_cm = _get_progress_bar_context(
442
+ desc=displayed_filename,
443
+ log_level=logger.getEffectiveLevel(),
444
+ total=total,
445
+ initial=resume_size,
446
+ name="huggingface_hub.http_get",
447
+ tqdm_class=tqdm_class,
448
+ _tqdm_bar=_tqdm_bar,
449
+ )
450
+
451
+ with progress_cm as progress:
452
+ new_resume_size = resume_size
453
+ try:
454
+ for chunk in response.iter_bytes(chunk_size=constants.DOWNLOAD_CHUNK_SIZE):
455
+ if chunk: # filter out keep-alive new chunks
456
+ progress.update(len(chunk))
457
+ temp_file.write(chunk)
458
+ new_resume_size += len(chunk)
459
+ # Some data has been downloaded from the server so we reset the number of retries.
460
+ _nb_retries = 5
461
+ except (httpx.ConnectError, httpx.TimeoutException) as e:
462
+ # If ConnectionError (SSLError) or ReadTimeout happen while streaming data from the server, it is most likely
463
+ # a transient error (network outage?). We log a warning message and try to resume the download a few times
464
+ # before giving up. Tre retry mechanism is basic but should be enough in most cases.
465
+ if _nb_retries <= 0:
466
+ logger.warning("Error while downloading from %s: %s\nMax retries exceeded.", url, str(e))
467
+ raise
468
+ logger.warning("Error while downloading from %s: %s\nTrying to resume download...", url, str(e))
469
+ time.sleep(1)
470
+ return http_get(
471
+ url=url,
472
+ temp_file=temp_file,
473
+ resume_size=new_resume_size,
474
+ headers=initial_headers,
475
+ expected_size=expected_size,
476
+ tqdm_class=tqdm_class,
477
+ _nb_retries=_nb_retries - 1,
478
+ _tqdm_bar=_tqdm_bar,
479
+ )
480
+
481
+ if expected_size is not None and expected_size != temp_file.tell():
482
+ raise EnvironmentError(
483
+ consistency_error_message.format(
484
+ actual_size=temp_file.tell(),
485
+ )
486
+ )
487
+
488
+
489
+ def xet_get(
490
+ *,
491
+ incomplete_path: Path,
492
+ xet_file_data: XetFileData,
493
+ headers: dict[str, str],
494
+ expected_size: Optional[int] = None,
495
+ displayed_filename: Optional[str] = None,
496
+ tqdm_class: Optional[type[base_tqdm]] = None,
497
+ _tqdm_bar: Optional[tqdm] = None,
498
+ ) -> None:
499
+ """
500
+ Download a file using Xet storage service.
501
+
502
+ Args:
503
+ incomplete_path (`Path`):
504
+ The path to the file to download.
505
+ xet_file_data (`XetFileData`):
506
+ The file metadata needed to make the request to the xet storage service.
507
+ headers (`dict[str, str]`):
508
+ The headers to send to the xet storage service.
509
+ expected_size (`int`, *optional*):
510
+ The expected size of the file to download. If set, the download will raise an error if the size of the
511
+ received content is different from the expected one.
512
+ displayed_filename (`str`, *optional*):
513
+ The filename of the file that is being downloaded. Value is used only to display a nice progress bar. If
514
+ not set, the filename is guessed from the URL or the `Content-Disposition` header.
515
+
516
+ **How it works:**
517
+ The file download system uses Xet storage, which is a content-addressable storage system that breaks files into chunks
518
+ for efficient storage and transfer.
519
+
520
+ `hf_xet.download_files` manages downloading files by:
521
+ - Taking a list of files to download (each with its unique content hash)
522
+ - Connecting to a storage server (CAS server) that knows how files are chunked
523
+ - Using authentication to ensure secure access
524
+ - Providing progress updates during download
525
+
526
+ Authentication works by regularly refreshing access tokens through `refresh_xet_connection_info` to maintain a valid
527
+ connection to the storage server.
528
+
529
+ The download process works like this:
530
+ 1. Create a local cache folder at `~/.cache/huggingface/xet/chunk-cache` to store reusable file chunks
531
+ 2. Download files in parallel:
532
+ 2.1. Prepare to write the file to disk
533
+ 2.2. Ask the server "how is this file split into chunks?" using the file's unique hash
534
+ The server responds with:
535
+ - Which chunks make up the complete file
536
+ - Where each chunk can be downloaded from
537
+ 2.3. For each needed chunk:
538
+ - Checks if we already have it in our local cache
539
+ - If not, download it from cloud storage (S3)
540
+ - Save it to cache for future use
541
+ - Assemble the chunks in order to recreate the original file
542
+
543
+ """
544
+ try:
545
+ from hf_xet import PyXetDownloadInfo, download_files # type: ignore[no-redef]
546
+ except ImportError:
547
+ raise ValueError(
548
+ "To use optimized download using Xet storage, you need to install the hf_xet package. "
549
+ 'Try `pip install "huggingface_hub[hf_xet]"` or `pip install hf_xet`.'
550
+ )
551
+
552
+ connection_info = refresh_xet_connection_info(file_data=xet_file_data, headers=headers)
553
+
554
+ def token_refresher() -> tuple[str, int]:
555
+ connection_info = refresh_xet_connection_info(file_data=xet_file_data, headers=headers)
556
+ if connection_info is None:
557
+ raise ValueError("Failed to refresh token using xet metadata.")
558
+ return connection_info.access_token, connection_info.expiration_unix_epoch
559
+
560
+ xet_download_info = [
561
+ PyXetDownloadInfo(
562
+ destination_path=str(incomplete_path.absolute()), hash=xet_file_data.file_hash, file_size=expected_size
563
+ )
564
+ ]
565
+
566
+ if not displayed_filename:
567
+ displayed_filename = incomplete_path.name
568
+
569
+ # Truncate filename if too long to display
570
+ if len(displayed_filename) > 40:
571
+ displayed_filename = f"{displayed_filename[:40]}(…)"
572
+
573
+ progress_cm = _get_progress_bar_context(
574
+ desc=displayed_filename,
575
+ log_level=logger.getEffectiveLevel(),
576
+ total=expected_size,
577
+ initial=0,
578
+ name="huggingface_hub.xet_get",
579
+ tqdm_class=tqdm_class,
580
+ _tqdm_bar=_tqdm_bar,
581
+ )
582
+
583
+ with progress_cm as progress:
584
+
585
+ def progress_updater(progress_bytes: float):
586
+ progress.update(progress_bytes)
587
+
588
+ download_files(
589
+ xet_download_info,
590
+ endpoint=connection_info.endpoint,
591
+ token_info=(connection_info.access_token, connection_info.expiration_unix_epoch),
592
+ token_refresher=token_refresher,
593
+ progress_updater=[progress_updater],
594
+ )
595
+
596
+
597
+ def _normalize_etag(etag: Optional[str]) -> Optional[str]:
598
+ """Normalize ETag HTTP header, so it can be used to create nice filepaths.
599
+
600
+ The HTTP spec allows two forms of ETag:
601
+ ETag: W/"<etag_value>"
602
+ ETag: "<etag_value>"
603
+
604
+ For now, we only expect the second form from the server, but we want to be future-proof so we support both. For
605
+ more context, see `TestNormalizeEtag` tests and https://github.com/huggingface/huggingface_hub/pull/1428.
606
+
607
+ Args:
608
+ etag (`str`, *optional*): HTTP header
609
+
610
+ Returns:
611
+ `str` or `None`: string that can be used as a nice directory name.
612
+ Returns `None` if input is None.
613
+ """
614
+ if etag is None:
615
+ return None
616
+ return etag.lstrip("W/").strip('"')
617
+
618
+
619
+ def _create_relative_symlink(src: str, dst: str, new_blob: bool = False) -> None:
620
+ """Alias method used in `transformers` conversion script."""
621
+ return _create_symlink(src=src, dst=dst, new_blob=new_blob)
622
+
623
+
624
+ def _create_symlink(src: str, dst: str, new_blob: bool = False) -> None:
625
+ """Create a symbolic link named dst pointing to src.
626
+
627
+ By default, it will try to create a symlink using a relative path. Relative paths have 2 advantages:
628
+ - If the cache_folder is moved (example: back-up on a shared drive), relative paths within the cache folder will
629
+ not break.
630
+ - Relative paths seems to be better handled on Windows. Issue was reported 3 times in less than a week when
631
+ changing from relative to absolute paths. See https://github.com/huggingface/huggingface_hub/issues/1398,
632
+ https://github.com/huggingface/diffusers/issues/2729 and https://github.com/huggingface/transformers/pull/22228.
633
+ NOTE: The issue with absolute paths doesn't happen on admin mode.
634
+ When creating a symlink from the cache to a local folder, it is possible that a relative path cannot be created.
635
+ This happens when paths are not on the same volume. In that case, we use absolute paths.
636
+
637
+
638
+ The result layout looks something like
639
+ └── [ 128] snapshots
640
+ ├── [ 128] 2439f60ef33a0d46d85da5001d52aeda5b00ce9f
641
+ │ ├── [ 52] README.md -> ../../../blobs/d7edf6bd2a681fb0175f7735299831ee1b22b812
642
+ │ └── [ 76] pytorch_model.bin -> ../../../blobs/403450e234d65943a7dcf7e05a771ce3c92faa84dd07db4ac20f592037a1e4bd
643
+
644
+ If symlinks cannot be created on this platform (most likely to be Windows), the workaround is to avoid symlinks by
645
+ having the actual file in `dst`. If it is a new file (`new_blob=True`), we move it to `dst`. If it is not a new file
646
+ (`new_blob=False`), we don't know if the blob file is already referenced elsewhere. To avoid breaking existing
647
+ cache, the file is duplicated on the disk.
648
+
649
+ In case symlinks are not supported, a warning message is displayed to the user once when loading `huggingface_hub`.
650
+ The warning message can be disabled with the `DISABLE_SYMLINKS_WARNING` environment variable.
651
+ """
652
+ try:
653
+ os.remove(dst)
654
+ except OSError:
655
+ pass
656
+
657
+ abs_src = os.path.abspath(os.path.expanduser(src))
658
+ abs_dst = os.path.abspath(os.path.expanduser(dst))
659
+ abs_dst_folder = os.path.dirname(abs_dst)
660
+
661
+ # Use relative_dst in priority
662
+ try:
663
+ relative_src = os.path.relpath(abs_src, abs_dst_folder)
664
+ except ValueError:
665
+ # Raised on Windows if src and dst are not on the same volume. This is the case when creating a symlink to a
666
+ # local_dir instead of within the cache directory.
667
+ # See https://docs.python.org/3/library/os.path.html#os.path.relpath
668
+ relative_src = None
669
+
670
+ try:
671
+ commonpath = os.path.commonpath([abs_src, abs_dst])
672
+ _support_symlinks = are_symlinks_supported(commonpath)
673
+ except ValueError:
674
+ # Raised if src and dst are not on the same volume. Symlinks will still work on Linux/Macos.
675
+ # See https://docs.python.org/3/library/os.path.html#os.path.commonpath
676
+ _support_symlinks = os.name != "nt"
677
+ except PermissionError:
678
+ # Permission error means src and dst are not in the same volume (e.g. destination path has been provided
679
+ # by the user via `local_dir`. Let's test symlink support there)
680
+ _support_symlinks = are_symlinks_supported(abs_dst_folder)
681
+ except OSError as e:
682
+ # OS error (errno=30) means that the commonpath is readonly on Linux/MacOS.
683
+ if e.errno == errno.EROFS:
684
+ _support_symlinks = are_symlinks_supported(abs_dst_folder)
685
+ else:
686
+ raise
687
+
688
+ # Symlinks are supported => let's create a symlink.
689
+ if _support_symlinks:
690
+ src_rel_or_abs = relative_src or abs_src
691
+ logger.debug(f"Creating pointer from {src_rel_or_abs} to {abs_dst}")
692
+ try:
693
+ os.symlink(src_rel_or_abs, abs_dst)
694
+ return
695
+ except FileExistsError:
696
+ if os.path.islink(abs_dst) and os.path.realpath(abs_dst) == os.path.realpath(abs_src):
697
+ # `abs_dst` already exists and is a symlink to the `abs_src` blob. It is most likely that the file has
698
+ # been cached twice concurrently (exactly between `os.remove` and `os.symlink`). Do nothing.
699
+ return
700
+ else:
701
+ # Very unlikely to happen. Means a file `dst` has been created exactly between `os.remove` and
702
+ # `os.symlink` and is not a symlink to the `abs_src` blob file. Raise exception.
703
+ raise
704
+ except PermissionError:
705
+ # Permission error means src and dst are not in the same volume (e.g. download to local dir) and symlink
706
+ # is supported on both volumes but not between them. Let's just make a hard copy in that case.
707
+ pass
708
+
709
+ # Symlinks are not supported => let's move or copy the file.
710
+ if new_blob:
711
+ logger.debug(f"Symlink not supported. Moving file from {abs_src} to {abs_dst}")
712
+ shutil.move(abs_src, abs_dst, copy_function=_copy_no_matter_what)
713
+ else:
714
+ logger.debug(f"Symlink not supported. Copying file from {abs_src} to {abs_dst}")
715
+ shutil.copyfile(abs_src, abs_dst)
716
+
717
+
718
+ def _cache_commit_hash_for_specific_revision(storage_folder: str, revision: str, commit_hash: str) -> None:
719
+ """Cache reference between a revision (tag, branch or truncated commit hash) and the corresponding commit hash.
720
+
721
+ Does nothing if `revision` is already a proper `commit_hash` or reference is already cached.
722
+ """
723
+ if revision != commit_hash:
724
+ ref_path = Path(storage_folder) / "refs" / revision
725
+ ref_path.parent.mkdir(parents=True, exist_ok=True)
726
+ if not ref_path.exists() or commit_hash != ref_path.read_text():
727
+ # Update ref only if has been updated. Could cause useless error in case
728
+ # repo is already cached and user doesn't have write access to cache folder.
729
+ # See https://github.com/huggingface/huggingface_hub/issues/1216.
730
+ ref_path.write_text(commit_hash)
731
+
732
+
733
+ @validate_hf_hub_args
734
+ def repo_folder_name(*, repo_id: str, repo_type: str) -> str:
735
+ """Return a serialized version of a hf.co repo name and type, safe for disk storage
736
+ as a single non-nested folder.
737
+
738
+ Example: models--julien-c--EsperBERTo-small
739
+ """
740
+ # remove all `/` occurrences to correctly convert repo to directory name
741
+ parts = [f"{repo_type}s", *repo_id.split("/")]
742
+ return constants.REPO_ID_SEPARATOR.join(parts)
743
+
744
+
745
+ def _check_disk_space(expected_size: int, target_dir: Union[str, Path]) -> None:
746
+ """Check disk usage and log a warning if there is not enough disk space to download the file.
747
+
748
+ Args:
749
+ expected_size (`int`):
750
+ The expected size of the file in bytes.
751
+ target_dir (`str`):
752
+ The directory where the file will be stored after downloading.
753
+ """
754
+
755
+ target_dir = Path(target_dir) # format as `Path`
756
+ for path in [target_dir] + list(target_dir.parents): # first check target_dir, then each parents one by one
757
+ try:
758
+ target_dir_free = shutil.disk_usage(path).free
759
+ if target_dir_free < expected_size:
760
+ warnings.warn(
761
+ "Not enough free disk space to download the file. "
762
+ f"The expected file size is: {expected_size / 1e6:.2f} MB. "
763
+ f"The target location {target_dir} only has {target_dir_free / 1e6:.2f} MB free disk space."
764
+ )
765
+ return
766
+ except OSError: # raise on anything: file does not exist or space disk cannot be checked
767
+ pass
768
+
769
+
770
+ @overload
771
+ def hf_hub_download(
772
+ repo_id: str,
773
+ filename: str,
774
+ *,
775
+ subfolder: Optional[str] = None,
776
+ repo_type: Optional[str] = None,
777
+ revision: Optional[str] = None,
778
+ library_name: Optional[str] = None,
779
+ library_version: Optional[str] = None,
780
+ cache_dir: Union[str, Path, None] = None,
781
+ local_dir: Union[str, Path, None] = None,
782
+ user_agent: Union[dict, str, None] = None,
783
+ force_download: bool = False,
784
+ etag_timeout: float = constants.DEFAULT_ETAG_TIMEOUT,
785
+ token: Union[bool, str, None] = None,
786
+ local_files_only: bool = False,
787
+ headers: Optional[dict[str, str]] = None,
788
+ endpoint: Optional[str] = None,
789
+ tqdm_class: Optional[type[base_tqdm]] = None,
790
+ dry_run: Literal[False] = False,
791
+ ) -> str: ...
792
+
793
+
794
+ @overload
795
+ def hf_hub_download(
796
+ repo_id: str,
797
+ filename: str,
798
+ *,
799
+ subfolder: Optional[str] = None,
800
+ repo_type: Optional[str] = None,
801
+ revision: Optional[str] = None,
802
+ library_name: Optional[str] = None,
803
+ library_version: Optional[str] = None,
804
+ cache_dir: Union[str, Path, None] = None,
805
+ local_dir: Union[str, Path, None] = None,
806
+ user_agent: Union[dict, str, None] = None,
807
+ force_download: bool = False,
808
+ etag_timeout: float = constants.DEFAULT_ETAG_TIMEOUT,
809
+ token: Union[bool, str, None] = None,
810
+ local_files_only: bool = False,
811
+ headers: Optional[dict[str, str]] = None,
812
+ endpoint: Optional[str] = None,
813
+ tqdm_class: Optional[type[base_tqdm]] = None,
814
+ dry_run: Literal[True] = True,
815
+ ) -> DryRunFileInfo: ...
816
+
817
+
818
+ @overload
819
+ def hf_hub_download(
820
+ repo_id: str,
821
+ filename: str,
822
+ *,
823
+ subfolder: Optional[str] = None,
824
+ repo_type: Optional[str] = None,
825
+ revision: Optional[str] = None,
826
+ library_name: Optional[str] = None,
827
+ library_version: Optional[str] = None,
828
+ cache_dir: Union[str, Path, None] = None,
829
+ local_dir: Union[str, Path, None] = None,
830
+ user_agent: Union[dict, str, None] = None,
831
+ force_download: bool = False,
832
+ etag_timeout: float = constants.DEFAULT_ETAG_TIMEOUT,
833
+ token: Union[bool, str, None] = None,
834
+ local_files_only: bool = False,
835
+ headers: Optional[dict[str, str]] = None,
836
+ endpoint: Optional[str] = None,
837
+ tqdm_class: Optional[type[base_tqdm]] = None,
838
+ dry_run: bool = False,
839
+ ) -> Union[str, DryRunFileInfo]: ...
840
+
841
+
842
+ @validate_hf_hub_args
843
+ def hf_hub_download(
844
+ repo_id: str,
845
+ filename: str,
846
+ *,
847
+ subfolder: Optional[str] = None,
848
+ repo_type: Optional[str] = None,
849
+ revision: Optional[str] = None,
850
+ library_name: Optional[str] = None,
851
+ library_version: Optional[str] = None,
852
+ cache_dir: Union[str, Path, None] = None,
853
+ local_dir: Union[str, Path, None] = None,
854
+ user_agent: Union[dict, str, None] = None,
855
+ force_download: bool = False,
856
+ etag_timeout: float = constants.DEFAULT_ETAG_TIMEOUT,
857
+ token: Union[bool, str, None] = None,
858
+ local_files_only: bool = False,
859
+ headers: Optional[dict[str, str]] = None,
860
+ endpoint: Optional[str] = None,
861
+ tqdm_class: Optional[type[base_tqdm]] = None,
862
+ dry_run: bool = False,
863
+ ) -> Union[str, DryRunFileInfo]:
864
+ """Download a given file if it's not already present in the local cache.
865
+
866
+ The new cache file layout looks like this:
867
+ - The cache directory contains one subfolder per repo_id (namespaced by repo type)
868
+ - inside each repo folder:
869
+ - refs is a list of the latest known revision => commit_hash pairs
870
+ - blobs contains the actual file blobs (identified by their git-sha or sha256, depending on
871
+ whether they're LFS files or not)
872
+ - snapshots contains one subfolder per commit, each "commit" contains the subset of the files
873
+ that have been resolved at that particular commit. Each filename is a symlink to the blob
874
+ at that particular commit.
875
+
876
+ ```
877
+ [ 96] .
878
+ └── [ 160] models--julien-c--EsperBERTo-small
879
+ ├── [ 160] blobs
880
+ │ ├── [321M] 403450e234d65943a7dcf7e05a771ce3c92faa84dd07db4ac20f592037a1e4bd
881
+ │ ├── [ 398] 7cb18dc9bafbfcf74629a4b760af1b160957a83e
882
+ │ └── [1.4K] d7edf6bd2a681fb0175f7735299831ee1b22b812
883
+ ├── [ 96] refs
884
+ │ └── [ 40] main
885
+ └── [ 128] snapshots
886
+ ├── [ 128] 2439f60ef33a0d46d85da5001d52aeda5b00ce9f
887
+ │ ├── [ 52] README.md -> ../../blobs/d7edf6bd2a681fb0175f7735299831ee1b22b812
888
+ │ └── [ 76] pytorch_model.bin -> ../../blobs/403450e234d65943a7dcf7e05a771ce3c92faa84dd07db4ac20f592037a1e4bd
889
+ └── [ 128] bbc77c8132af1cc5cf678da3f1ddf2de43606d48
890
+ ├── [ 52] README.md -> ../../blobs/7cb18dc9bafbfcf74629a4b760af1b160957a83e
891
+ └── [ 76] pytorch_model.bin -> ../../blobs/403450e234d65943a7dcf7e05a771ce3c92faa84dd07db4ac20f592037a1e4bd
892
+ ```
893
+
894
+ If `local_dir` is provided, the file structure from the repo will be replicated in this location. When using this
895
+ option, the `cache_dir` will not be used and a `.cache/huggingface/` folder will be created at the root of `local_dir`
896
+ to store some metadata related to the downloaded files. While this mechanism is not as robust as the main
897
+ cache-system, it's optimized for regularly pulling the latest version of a repository.
898
+
899
+ Args:
900
+ repo_id (`str`):
901
+ A user or an organization name and a repo name separated by a `/`.
902
+ filename (`str`):
903
+ The name of the file in the repo.
904
+ subfolder (`str`, *optional*):
905
+ An optional value corresponding to a folder inside the model repo.
906
+ repo_type (`str`, *optional*):
907
+ Set to `"dataset"` or `"space"` if downloading from a dataset or space,
908
+ `None` or `"model"` if downloading from a model. Default is `None`.
909
+ revision (`str`, *optional*):
910
+ An optional Git revision id which can be a branch name, a tag, or a
911
+ commit hash.
912
+ library_name (`str`, *optional*):
913
+ The name of the library to which the object corresponds.
914
+ library_version (`str`, *optional*):
915
+ The version of the library.
916
+ cache_dir (`str`, `Path`, *optional*):
917
+ Path to the folder where cached files are stored.
918
+ local_dir (`str` or `Path`, *optional*):
919
+ If provided, the downloaded file will be placed under this directory.
920
+ user_agent (`dict`, `str`, *optional*):
921
+ The user-agent info in the form of a dictionary or a string.
922
+ force_download (`bool`, *optional*, defaults to `False`):
923
+ Whether the file should be downloaded even if it already exists in
924
+ the local cache.
925
+ etag_timeout (`float`, *optional*, defaults to `10`):
926
+ When fetching ETag, how many seconds to wait for the server to send
927
+ data before giving up which is passed to `requests.request`.
928
+ token (`str`, `bool`, *optional*):
929
+ A token to be used for the download.
930
+ - If `True`, the token is read from the HuggingFace config
931
+ folder.
932
+ - If a string, it's used as the authentication token.
933
+ local_files_only (`bool`, *optional*, defaults to `False`):
934
+ If `True`, avoid downloading the file and return the path to the
935
+ local cached file if it exists.
936
+ headers (`dict`, *optional*):
937
+ Additional headers to be sent with the request.
938
+ tqdm_class (`tqdm`, *optional*):
939
+ If provided, overwrites the default behavior for the progress bar. Passed
940
+ argument must inherit from `tqdm.auto.tqdm` or at least mimic its behavior.
941
+ Defaults to the custom HF progress bar that can be disabled by setting
942
+ `HF_HUB_DISABLE_PROGRESS_BARS` environment variable.
943
+ dry_run (`bool`, *optional*, defaults to `False`):
944
+ If `True`, perform a dry run without actually downloading the file. Returns a
945
+ [`DryRunFileInfo`] object containing information about what would be downloaded.
946
+
947
+ Returns:
948
+ `str` or [`DryRunFileInfo`]:
949
+ - If `dry_run=False`: Local path of file or if networking is off, last version of file cached on disk.
950
+ - If `dry_run=True`: A [`DryRunFileInfo`] object containing download information.
951
+
952
+ Raises:
953
+ [`~utils.RepositoryNotFoundError`]
954
+ If the repository to download from cannot be found. This may be because it doesn't exist,
955
+ or because it is set to `private` and you do not have access.
956
+ [`~utils.RevisionNotFoundError`]
957
+ If the revision to download from cannot be found.
958
+ [`~utils.RemoteEntryNotFoundError`]
959
+ If the file to download cannot be found.
960
+ [`~utils.LocalEntryNotFoundError`]
961
+ If network is disabled or unavailable and file is not found in cache.
962
+ [`EnvironmentError`](https://docs.python.org/3/library/exceptions.html#EnvironmentError)
963
+ If `token=True` but the token cannot be found.
964
+ [`OSError`](https://docs.python.org/3/library/exceptions.html#OSError)
965
+ If ETag cannot be determined.
966
+ [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError)
967
+ If some parameter value is invalid.
968
+
969
+ """
970
+ if constants.HF_HUB_ETAG_TIMEOUT != constants.DEFAULT_ETAG_TIMEOUT:
971
+ # Respect environment variable above user value
972
+ etag_timeout = constants.HF_HUB_ETAG_TIMEOUT
973
+
974
+ if cache_dir is None:
975
+ cache_dir = constants.HF_HUB_CACHE
976
+ if revision is None:
977
+ revision = constants.DEFAULT_REVISION
978
+ if isinstance(cache_dir, Path):
979
+ cache_dir = str(cache_dir)
980
+ if isinstance(local_dir, Path):
981
+ local_dir = str(local_dir)
982
+
983
+ if subfolder == "":
984
+ subfolder = None
985
+ if subfolder is not None:
986
+ # This is used to create a URL, and not a local path, hence the forward slash.
987
+ filename = f"{subfolder}/{filename}"
988
+
989
+ if repo_type is None:
990
+ repo_type = "model"
991
+ if repo_type not in constants.REPO_TYPES:
992
+ raise ValueError(f"Invalid repo type: {repo_type}. Accepted repo types are: {str(constants.REPO_TYPES)}")
993
+
994
+ hf_headers = build_hf_headers(
995
+ token=token,
996
+ library_name=library_name,
997
+ library_version=library_version,
998
+ user_agent=user_agent,
999
+ headers=headers,
1000
+ )
1001
+
1002
+ if local_dir is not None:
1003
+ return _hf_hub_download_to_local_dir(
1004
+ # Destination
1005
+ local_dir=local_dir,
1006
+ # File info
1007
+ repo_id=repo_id,
1008
+ repo_type=repo_type,
1009
+ filename=filename,
1010
+ revision=revision,
1011
+ # HTTP info
1012
+ endpoint=endpoint,
1013
+ etag_timeout=etag_timeout,
1014
+ headers=hf_headers,
1015
+ token=token,
1016
+ # Additional options
1017
+ cache_dir=cache_dir,
1018
+ force_download=force_download,
1019
+ local_files_only=local_files_only,
1020
+ tqdm_class=tqdm_class,
1021
+ dry_run=dry_run,
1022
+ )
1023
+ else:
1024
+ return _hf_hub_download_to_cache_dir(
1025
+ # Destination
1026
+ cache_dir=cache_dir,
1027
+ # File info
1028
+ repo_id=repo_id,
1029
+ filename=filename,
1030
+ repo_type=repo_type,
1031
+ revision=revision,
1032
+ # HTTP info
1033
+ endpoint=endpoint,
1034
+ etag_timeout=etag_timeout,
1035
+ headers=hf_headers,
1036
+ token=token,
1037
+ # Additional options
1038
+ local_files_only=local_files_only,
1039
+ force_download=force_download,
1040
+ tqdm_class=tqdm_class,
1041
+ dry_run=dry_run,
1042
+ )
1043
+
1044
+
1045
+ def _hf_hub_download_to_cache_dir(
1046
+ *,
1047
+ # Destination
1048
+ cache_dir: str,
1049
+ # File info
1050
+ repo_id: str,
1051
+ filename: str,
1052
+ repo_type: str,
1053
+ revision: str,
1054
+ # HTTP info
1055
+ endpoint: Optional[str],
1056
+ etag_timeout: float,
1057
+ headers: dict[str, str],
1058
+ token: Optional[Union[bool, str]],
1059
+ # Additional options
1060
+ local_files_only: bool,
1061
+ force_download: bool,
1062
+ tqdm_class: Optional[type[base_tqdm]],
1063
+ dry_run: bool,
1064
+ ) -> Union[str, DryRunFileInfo]:
1065
+ """Download a given file to a cache folder, if not already present.
1066
+
1067
+ Method should not be called directly. Please use `hf_hub_download` instead.
1068
+ """
1069
+ locks_dir = os.path.join(cache_dir, ".locks")
1070
+ storage_folder = os.path.join(cache_dir, repo_folder_name(repo_id=repo_id, repo_type=repo_type))
1071
+
1072
+ # cross-platform transcription of filename, to be used as a local file path.
1073
+ relative_filename = os.path.join(*filename.split("/"))
1074
+ if os.name == "nt":
1075
+ if relative_filename.startswith("..\\") or "\\..\\" in relative_filename:
1076
+ raise ValueError(
1077
+ f"Invalid filename: cannot handle filename '{relative_filename}' on Windows. Please ask the repository"
1078
+ " owner to rename this file."
1079
+ )
1080
+
1081
+ # if user provides a commit_hash and they already have the file on disk, shortcut everything.
1082
+ if REGEX_COMMIT_HASH.match(revision):
1083
+ pointer_path = _get_pointer_path(storage_folder, revision, relative_filename)
1084
+ if os.path.exists(pointer_path):
1085
+ if dry_run:
1086
+ return DryRunFileInfo(
1087
+ commit_hash=revision,
1088
+ file_size=os.path.getsize(pointer_path),
1089
+ filename=filename,
1090
+ is_cached=True,
1091
+ local_path=pointer_path,
1092
+ will_download=force_download,
1093
+ )
1094
+ if not force_download:
1095
+ return pointer_path
1096
+
1097
+ # Try to get metadata (etag, commit_hash, url, size) from the server.
1098
+ # If we can't, a HEAD request error is returned.
1099
+ (url_to_download, etag, commit_hash, expected_size, xet_file_data, head_call_error) = _get_metadata_or_catch_error(
1100
+ repo_id=repo_id,
1101
+ filename=filename,
1102
+ repo_type=repo_type,
1103
+ revision=revision,
1104
+ endpoint=endpoint,
1105
+ etag_timeout=etag_timeout,
1106
+ headers=headers,
1107
+ token=token,
1108
+ local_files_only=local_files_only,
1109
+ storage_folder=storage_folder,
1110
+ relative_filename=relative_filename,
1111
+ )
1112
+
1113
+ # etag can be None for several reasons:
1114
+ # 1. we passed local_files_only.
1115
+ # 2. we don't have a connection
1116
+ # 3. Hub is down (HTTP 500, 503, 504)
1117
+ # 4. repo is not found -for example private or gated- and invalid/missing token sent
1118
+ # 5. Hub is blocked by a firewall or proxy is not set correctly.
1119
+ # => Try to get the last downloaded one from the specified revision.
1120
+ #
1121
+ # If the specified revision is a commit hash, look inside "snapshots".
1122
+ # If the specified revision is a branch or tag, look inside "refs".
1123
+ if head_call_error is not None:
1124
+ # Couldn't make a HEAD call => let's try to find a local file
1125
+ if not force_download:
1126
+ commit_hash = None
1127
+ if REGEX_COMMIT_HASH.match(revision):
1128
+ commit_hash = revision
1129
+ else:
1130
+ ref_path = os.path.join(storage_folder, "refs", revision)
1131
+ if os.path.isfile(ref_path):
1132
+ with open(ref_path) as f:
1133
+ commit_hash = f.read()
1134
+
1135
+ # Return pointer file if exists
1136
+ if commit_hash is not None:
1137
+ pointer_path = _get_pointer_path(storage_folder, commit_hash, relative_filename)
1138
+ if os.path.exists(pointer_path):
1139
+ if dry_run:
1140
+ return DryRunFileInfo(
1141
+ commit_hash=commit_hash,
1142
+ file_size=os.path.getsize(pointer_path),
1143
+ filename=filename,
1144
+ is_cached=True,
1145
+ local_path=pointer_path,
1146
+ will_download=force_download,
1147
+ )
1148
+ if not force_download:
1149
+ return pointer_path
1150
+
1151
+ if isinstance(head_call_error, _DEFAULT_RETRY_ON_EXCEPTIONS) or (
1152
+ isinstance(head_call_error, HfHubHTTPError)
1153
+ and head_call_error.response.status_code in _DEFAULT_RETRY_ON_STATUS_CODES
1154
+ ):
1155
+ logger.info("No local file found. Retrying..")
1156
+ (url_to_download, etag, commit_hash, expected_size, xet_file_data, head_call_error) = (
1157
+ _get_metadata_or_catch_error(
1158
+ repo_id=repo_id,
1159
+ filename=filename,
1160
+ repo_type=repo_type,
1161
+ revision=revision,
1162
+ endpoint=endpoint,
1163
+ etag_timeout=_ETAG_RETRY_TIMEOUT,
1164
+ headers=headers,
1165
+ token=token,
1166
+ local_files_only=local_files_only,
1167
+ storage_folder=storage_folder,
1168
+ relative_filename=relative_filename,
1169
+ retry_on_errors=True,
1170
+ )
1171
+ )
1172
+
1173
+ # If still error, raise
1174
+ if head_call_error is not None:
1175
+ _raise_on_head_call_error(head_call_error, force_download, local_files_only)
1176
+
1177
+ # From now on, etag, commit_hash, url and size are not None.
1178
+ assert etag is not None, "etag must have been retrieved from server"
1179
+ assert commit_hash is not None, "commit_hash must have been retrieved from server"
1180
+ assert url_to_download is not None, "file location must have been retrieved from server"
1181
+ assert expected_size is not None, "expected_size must have been retrieved from server"
1182
+ blob_path = os.path.join(storage_folder, "blobs", etag)
1183
+ pointer_path = _get_pointer_path(storage_folder, commit_hash, relative_filename)
1184
+
1185
+ if dry_run:
1186
+ is_cached = os.path.exists(pointer_path) or os.path.exists(blob_path)
1187
+ return DryRunFileInfo(
1188
+ commit_hash=commit_hash,
1189
+ file_size=expected_size,
1190
+ filename=filename,
1191
+ is_cached=is_cached,
1192
+ local_path=pointer_path,
1193
+ will_download=force_download or not is_cached,
1194
+ )
1195
+
1196
+ os.makedirs(os.path.dirname(blob_path), exist_ok=True)
1197
+ os.makedirs(os.path.dirname(pointer_path), exist_ok=True)
1198
+
1199
+ # if passed revision is not identical to commit_hash
1200
+ # then revision has to be a branch name or tag name.
1201
+ # In that case store a ref.
1202
+ _cache_commit_hash_for_specific_revision(storage_folder, revision, commit_hash)
1203
+
1204
+ # Prevent parallel downloads of the same file with a lock.
1205
+ # etag could be duplicated across repos,
1206
+ lock_path = os.path.join(locks_dir, repo_folder_name(repo_id=repo_id, repo_type=repo_type), f"{etag}.lock")
1207
+
1208
+ # Some Windows versions do not allow for paths longer than 255 characters.
1209
+ # In this case, we must specify it as an extended path by using the "\\?\" prefix.
1210
+ if (
1211
+ os.name == "nt"
1212
+ and len(os.path.abspath(lock_path)) > 255
1213
+ and not os.path.abspath(lock_path).startswith("\\\\?\\")
1214
+ ):
1215
+ lock_path = "\\\\?\\" + os.path.abspath(lock_path)
1216
+
1217
+ if (
1218
+ os.name == "nt"
1219
+ and len(os.path.abspath(blob_path)) > 255
1220
+ and not os.path.abspath(blob_path).startswith("\\\\?\\")
1221
+ ):
1222
+ blob_path = "\\\\?\\" + os.path.abspath(blob_path)
1223
+
1224
+ Path(lock_path).parent.mkdir(parents=True, exist_ok=True)
1225
+
1226
+ # pointer already exists -> immediate return
1227
+ if not force_download and os.path.exists(pointer_path):
1228
+ return pointer_path
1229
+
1230
+ # Blob exists but pointer must be (safely) created -> take the lock
1231
+ if not force_download and os.path.exists(blob_path):
1232
+ with WeakFileLock(lock_path):
1233
+ if not os.path.exists(pointer_path):
1234
+ _create_symlink(blob_path, pointer_path, new_blob=False)
1235
+ return pointer_path
1236
+
1237
+ # Local file doesn't exist or etag isn't a match => retrieve file from remote (or cache)
1238
+
1239
+ with WeakFileLock(lock_path):
1240
+ _download_to_tmp_and_move(
1241
+ incomplete_path=Path(blob_path + ".incomplete"),
1242
+ destination_path=Path(blob_path),
1243
+ url_to_download=url_to_download,
1244
+ headers=headers,
1245
+ expected_size=expected_size,
1246
+ filename=filename,
1247
+ force_download=force_download,
1248
+ etag=etag,
1249
+ xet_file_data=xet_file_data,
1250
+ tqdm_class=tqdm_class,
1251
+ )
1252
+ if not os.path.exists(pointer_path):
1253
+ _create_symlink(blob_path, pointer_path, new_blob=True)
1254
+
1255
+ return pointer_path
1256
+
1257
+
1258
+ def _hf_hub_download_to_local_dir(
1259
+ *,
1260
+ # Destination
1261
+ local_dir: Union[str, Path],
1262
+ # File info
1263
+ repo_id: str,
1264
+ repo_type: str,
1265
+ filename: str,
1266
+ revision: str,
1267
+ # HTTP info
1268
+ endpoint: Optional[str],
1269
+ etag_timeout: float,
1270
+ headers: dict[str, str],
1271
+ token: Union[bool, str, None],
1272
+ # Additional options
1273
+ cache_dir: str,
1274
+ force_download: bool,
1275
+ local_files_only: bool,
1276
+ tqdm_class: Optional[type[base_tqdm]],
1277
+ dry_run: bool,
1278
+ ) -> Union[str, DryRunFileInfo]:
1279
+ """Download a given file to a local folder, if not already present.
1280
+
1281
+ Method should not be called directly. Please use `hf_hub_download` instead.
1282
+ """
1283
+ # Some Windows versions do not allow for paths longer than 255 characters.
1284
+ # In this case, we must specify it as an extended path by using the "\\?\" prefix.
1285
+ if os.name == "nt" and len(os.path.abspath(local_dir)) > 255:
1286
+ local_dir = "\\\\?\\" + os.path.abspath(local_dir)
1287
+ local_dir = Path(local_dir)
1288
+ paths = get_local_download_paths(local_dir=local_dir, filename=filename)
1289
+ local_metadata = read_download_metadata(local_dir=local_dir, filename=filename)
1290
+
1291
+ # Local file exists + metadata exists + commit_hash matches => return file
1292
+ if (
1293
+ REGEX_COMMIT_HASH.match(revision)
1294
+ and paths.file_path.is_file()
1295
+ and local_metadata is not None
1296
+ and local_metadata.commit_hash == revision
1297
+ ):
1298
+ local_file = str(paths.file_path)
1299
+ if dry_run:
1300
+ return DryRunFileInfo(
1301
+ commit_hash=revision,
1302
+ file_size=os.path.getsize(local_file),
1303
+ filename=filename,
1304
+ is_cached=True,
1305
+ local_path=local_file,
1306
+ will_download=force_download,
1307
+ )
1308
+ if not force_download:
1309
+ return local_file
1310
+
1311
+ # Local file doesn't exist or commit_hash doesn't match => we need the etag
1312
+ (url_to_download, etag, commit_hash, expected_size, xet_file_data, head_call_error) = _get_metadata_or_catch_error(
1313
+ repo_id=repo_id,
1314
+ filename=filename,
1315
+ repo_type=repo_type,
1316
+ revision=revision,
1317
+ endpoint=endpoint,
1318
+ etag_timeout=etag_timeout,
1319
+ headers=headers,
1320
+ token=token,
1321
+ local_files_only=local_files_only,
1322
+ )
1323
+
1324
+ if head_call_error is not None:
1325
+ # No HEAD call but local file exists => default to local file
1326
+ if paths.file_path.is_file():
1327
+ if dry_run or not force_download:
1328
+ logger.warning(
1329
+ f"Couldn't access the Hub to check for update but local file already exists. Defaulting to existing file. (error: {head_call_error})"
1330
+ )
1331
+ local_path = str(paths.file_path)
1332
+ if dry_run and local_metadata is not None:
1333
+ return DryRunFileInfo(
1334
+ commit_hash=local_metadata.commit_hash,
1335
+ file_size=os.path.getsize(local_path),
1336
+ filename=filename,
1337
+ is_cached=True,
1338
+ local_path=local_path,
1339
+ will_download=force_download,
1340
+ )
1341
+ if not force_download:
1342
+ return local_path
1343
+ elif not force_download:
1344
+ if isinstance(head_call_error, _DEFAULT_RETRY_ON_EXCEPTIONS) or (
1345
+ isinstance(head_call_error, HfHubHTTPError)
1346
+ and head_call_error.response.status_code in _DEFAULT_RETRY_ON_STATUS_CODES
1347
+ ):
1348
+ logger.info("No local file found. Retrying..")
1349
+ (url_to_download, etag, commit_hash, expected_size, xet_file_data, head_call_error) = (
1350
+ _get_metadata_or_catch_error(
1351
+ repo_id=repo_id,
1352
+ filename=filename,
1353
+ repo_type=repo_type,
1354
+ revision=revision,
1355
+ endpoint=endpoint,
1356
+ etag_timeout=_ETAG_RETRY_TIMEOUT,
1357
+ headers=headers,
1358
+ token=token,
1359
+ local_files_only=local_files_only,
1360
+ retry_on_errors=True,
1361
+ )
1362
+ )
1363
+
1364
+ # If still error, raise
1365
+ if head_call_error is not None:
1366
+ _raise_on_head_call_error(head_call_error, force_download, local_files_only)
1367
+
1368
+ # From now on, etag, commit_hash, url and size are not None.
1369
+ assert etag is not None, "etag must have been retrieved from server"
1370
+ assert commit_hash is not None, "commit_hash must have been retrieved from server"
1371
+ assert url_to_download is not None, "file location must have been retrieved from server"
1372
+ assert expected_size is not None, "expected_size must have been retrieved from server"
1373
+
1374
+ # Local file exists => check if it's up-to-date
1375
+ if not force_download and paths.file_path.is_file():
1376
+ # etag matches => update metadata and return file
1377
+ if local_metadata is not None and local_metadata.etag == etag:
1378
+ write_download_metadata(local_dir=local_dir, filename=filename, commit_hash=commit_hash, etag=etag)
1379
+ if dry_run:
1380
+ return DryRunFileInfo(
1381
+ commit_hash=commit_hash,
1382
+ file_size=expected_size,
1383
+ filename=filename,
1384
+ is_cached=True,
1385
+ local_path=str(paths.file_path),
1386
+ will_download=False,
1387
+ )
1388
+ return str(paths.file_path)
1389
+
1390
+ # metadata is outdated + etag is a sha256
1391
+ # => means it's an LFS file (large)
1392
+ # => let's compute local hash and compare
1393
+ # => if match, update metadata and return file
1394
+ if local_metadata is None and REGEX_SHA256.match(etag) is not None:
1395
+ with open(paths.file_path, "rb") as f:
1396
+ file_hash = sha_fileobj(f).hex()
1397
+ if file_hash == etag:
1398
+ write_download_metadata(local_dir=local_dir, filename=filename, commit_hash=commit_hash, etag=etag)
1399
+ if dry_run:
1400
+ return DryRunFileInfo(
1401
+ commit_hash=commit_hash,
1402
+ file_size=expected_size,
1403
+ filename=filename,
1404
+ is_cached=True,
1405
+ local_path=str(paths.file_path),
1406
+ will_download=False,
1407
+ )
1408
+ return str(paths.file_path)
1409
+
1410
+ # Local file doesn't exist or etag isn't a match => retrieve file from remote (or cache)
1411
+
1412
+ # If we are lucky enough, the file is already in the cache => copy it
1413
+ if not force_download:
1414
+ cached_path = try_to_load_from_cache(
1415
+ repo_id=repo_id,
1416
+ filename=filename,
1417
+ cache_dir=cache_dir,
1418
+ revision=commit_hash,
1419
+ repo_type=repo_type,
1420
+ )
1421
+ if isinstance(cached_path, str):
1422
+ with WeakFileLock(paths.lock_path):
1423
+ paths.file_path.parent.mkdir(parents=True, exist_ok=True)
1424
+ shutil.copyfile(cached_path, paths.file_path)
1425
+ write_download_metadata(local_dir=local_dir, filename=filename, commit_hash=commit_hash, etag=etag)
1426
+ if dry_run:
1427
+ return DryRunFileInfo(
1428
+ commit_hash=commit_hash,
1429
+ file_size=expected_size,
1430
+ filename=filename,
1431
+ is_cached=True,
1432
+ local_path=str(paths.file_path),
1433
+ will_download=False,
1434
+ )
1435
+ return str(paths.file_path)
1436
+
1437
+ if dry_run:
1438
+ is_cached = paths.file_path.is_file()
1439
+ return DryRunFileInfo(
1440
+ commit_hash=commit_hash,
1441
+ file_size=expected_size,
1442
+ filename=filename,
1443
+ is_cached=is_cached,
1444
+ local_path=str(paths.file_path),
1445
+ will_download=force_download or not is_cached,
1446
+ )
1447
+
1448
+ # Otherwise, let's download the file!
1449
+ with WeakFileLock(paths.lock_path):
1450
+ paths.file_path.unlink(missing_ok=True) # delete outdated file first
1451
+ _download_to_tmp_and_move(
1452
+ incomplete_path=paths.incomplete_path(etag),
1453
+ destination_path=paths.file_path,
1454
+ url_to_download=url_to_download,
1455
+ headers=headers,
1456
+ expected_size=expected_size,
1457
+ filename=filename,
1458
+ force_download=force_download,
1459
+ etag=etag,
1460
+ xet_file_data=xet_file_data,
1461
+ tqdm_class=tqdm_class,
1462
+ )
1463
+
1464
+ write_download_metadata(local_dir=local_dir, filename=filename, commit_hash=commit_hash, etag=etag)
1465
+ return str(paths.file_path)
1466
+
1467
+
1468
+ @validate_hf_hub_args
1469
+ def try_to_load_from_cache(
1470
+ repo_id: str,
1471
+ filename: str,
1472
+ cache_dir: Union[str, Path, None] = None,
1473
+ revision: Optional[str] = None,
1474
+ repo_type: Optional[str] = None,
1475
+ ) -> Union[str, _CACHED_NO_EXIST_T, None]:
1476
+ """
1477
+ Explores the cache to return the latest cached file for a given revision if found.
1478
+
1479
+ This function will not raise any exception if the file in not cached.
1480
+
1481
+ Args:
1482
+ cache_dir (`str` or `os.PathLike`):
1483
+ The folder where the cached files lie.
1484
+ repo_id (`str`):
1485
+ The ID of the repo on huggingface.co.
1486
+ filename (`str`):
1487
+ The filename to look for inside `repo_id`.
1488
+ revision (`str`, *optional*):
1489
+ The specific model version to use. Will default to `"main"` if it's not provided and no `commit_hash` is
1490
+ provided either.
1491
+ repo_type (`str`, *optional*):
1492
+ The type of the repository. Will default to `"model"`.
1493
+
1494
+ Returns:
1495
+ `Optional[str]` or `_CACHED_NO_EXIST`:
1496
+ Will return `None` if the file was not cached. Otherwise:
1497
+ - The exact path to the cached file if it's found in the cache
1498
+ - A special value `_CACHED_NO_EXIST` if the file does not exist at the given commit hash and this fact was
1499
+ cached.
1500
+
1501
+ Example:
1502
+
1503
+ ```python
1504
+ from huggingface_hub import try_to_load_from_cache, _CACHED_NO_EXIST
1505
+
1506
+ filepath = try_to_load_from_cache()
1507
+ if isinstance(filepath, str):
1508
+ # file exists and is cached
1509
+ ...
1510
+ elif filepath is _CACHED_NO_EXIST:
1511
+ # non-existence of file is cached
1512
+ ...
1513
+ else:
1514
+ # file is not cached
1515
+ ...
1516
+ ```
1517
+ """
1518
+ if revision is None:
1519
+ revision = "main"
1520
+ if repo_type is None:
1521
+ repo_type = "model"
1522
+ if repo_type not in constants.REPO_TYPES:
1523
+ raise ValueError(f"Invalid repo type: {repo_type}. Accepted repo types are: {str(constants.REPO_TYPES)}")
1524
+ if cache_dir is None:
1525
+ cache_dir = constants.HF_HUB_CACHE
1526
+
1527
+ object_id = repo_id.replace("/", "--")
1528
+ repo_cache = os.path.join(cache_dir, f"{repo_type}s--{object_id}")
1529
+ if not os.path.isdir(repo_cache):
1530
+ # No cache for this model
1531
+ return None
1532
+
1533
+ refs_dir = os.path.join(repo_cache, "refs")
1534
+ snapshots_dir = os.path.join(repo_cache, "snapshots")
1535
+ no_exist_dir = os.path.join(repo_cache, ".no_exist")
1536
+
1537
+ # Resolve refs (for instance to convert main to the associated commit sha)
1538
+ if os.path.isdir(refs_dir):
1539
+ revision_file = os.path.join(refs_dir, revision)
1540
+ if os.path.isfile(revision_file):
1541
+ with open(revision_file) as f:
1542
+ revision = f.read()
1543
+
1544
+ # Check if file is cached as "no_exist"
1545
+ if os.path.isfile(os.path.join(no_exist_dir, revision, filename)):
1546
+ return _CACHED_NO_EXIST
1547
+
1548
+ # Check if revision folder exists
1549
+ if not os.path.exists(snapshots_dir):
1550
+ return None
1551
+ cached_shas = os.listdir(snapshots_dir)
1552
+ if revision not in cached_shas:
1553
+ # No cache for this revision and we won't try to return a random revision
1554
+ return None
1555
+
1556
+ # Check if file exists in cache
1557
+ cached_file = os.path.join(snapshots_dir, revision, filename)
1558
+ return cached_file if os.path.isfile(cached_file) else None
1559
+
1560
+
1561
+ @validate_hf_hub_args
1562
+ def get_hf_file_metadata(
1563
+ url: str,
1564
+ token: Union[bool, str, None] = None,
1565
+ timeout: Optional[float] = constants.HF_HUB_ETAG_TIMEOUT,
1566
+ library_name: Optional[str] = None,
1567
+ library_version: Optional[str] = None,
1568
+ user_agent: Union[dict, str, None] = None,
1569
+ headers: Optional[dict[str, str]] = None,
1570
+ endpoint: Optional[str] = None,
1571
+ retry_on_errors: bool = False,
1572
+ ) -> HfFileMetadata:
1573
+ """Fetch metadata of a file versioned on the Hub for a given url.
1574
+
1575
+ Args:
1576
+ url (`str`):
1577
+ File url, for example returned by [`hf_hub_url`].
1578
+ token (`str` or `bool`, *optional*):
1579
+ A token to be used for the download.
1580
+ - If `True`, the token is read from the HuggingFace config
1581
+ folder.
1582
+ - If `False` or `None`, no token is provided.
1583
+ - If a string, it's used as the authentication token.
1584
+ timeout (`float`, *optional*, defaults to 10):
1585
+ How many seconds to wait for the server to send metadata before giving up.
1586
+ library_name (`str`, *optional*):
1587
+ The name of the library to which the object corresponds.
1588
+ library_version (`str`, *optional*):
1589
+ The version of the library.
1590
+ user_agent (`dict`, `str`, *optional*):
1591
+ The user-agent info in the form of a dictionary or a string.
1592
+ headers (`dict`, *optional*):
1593
+ Additional headers to be sent with the request.
1594
+ endpoint (`str`, *optional*):
1595
+ Endpoint of the Hub. Defaults to <https://huggingface.co>.
1596
+ retry_on_errors (`bool`, *optional*, defaults to `False`):
1597
+ Whether to retry on errors (429, 5xx, timeout, network errors).
1598
+ If False, no retry for fast fallback to local cache.
1599
+
1600
+ Returns:
1601
+ A [`HfFileMetadata`] object containing metadata such as location, etag, size and
1602
+ commit_hash.
1603
+ """
1604
+ hf_headers = build_hf_headers(
1605
+ token=token,
1606
+ library_name=library_name,
1607
+ library_version=library_version,
1608
+ user_agent=user_agent,
1609
+ headers=headers,
1610
+ )
1611
+ hf_headers["Accept-Encoding"] = "identity" # prevent any compression => we want to know the real size of the file
1612
+
1613
+ # Retrieve metadata
1614
+ response = _httpx_follow_relative_redirects(
1615
+ method="HEAD", url=url, headers=hf_headers, timeout=timeout, retry_on_errors=retry_on_errors
1616
+ )
1617
+ hf_raise_for_status(response)
1618
+
1619
+ # Return
1620
+ return HfFileMetadata(
1621
+ commit_hash=response.headers.get(constants.HUGGINGFACE_HEADER_X_REPO_COMMIT),
1622
+ # We favor a custom header indicating the etag of the linked resource, and we fall back to the regular etag header.
1623
+ etag=_normalize_etag(
1624
+ response.headers.get(constants.HUGGINGFACE_HEADER_X_LINKED_ETAG) or response.headers.get("ETag")
1625
+ ),
1626
+ # Either from response headers (if redirected) or defaults to request url
1627
+ # Do not use directly `url` as we might have followed relative redirects.
1628
+ location=response.headers.get("Location") or str(response.request.url), # type: ignore
1629
+ size=_int_or_none(
1630
+ response.headers.get(constants.HUGGINGFACE_HEADER_X_LINKED_SIZE) or response.headers.get("Content-Length")
1631
+ ),
1632
+ xet_file_data=parse_xet_file_data_from_response(response, endpoint=endpoint), # type: ignore
1633
+ )
1634
+
1635
+
1636
+ def _get_metadata_or_catch_error(
1637
+ *,
1638
+ repo_id: str,
1639
+ filename: str,
1640
+ repo_type: str,
1641
+ revision: str,
1642
+ endpoint: Optional[str],
1643
+ etag_timeout: Optional[float],
1644
+ headers: dict[str, str], # mutated inplace!
1645
+ token: Union[bool, str, None],
1646
+ local_files_only: bool,
1647
+ relative_filename: Optional[str] = None, # only used to store `.no_exists` in cache
1648
+ storage_folder: Optional[str] = None, # only used to store `.no_exists` in cache
1649
+ retry_on_errors: bool = False,
1650
+ ) -> Union[
1651
+ # Either an exception is caught and returned
1652
+ tuple[None, None, None, None, None, Exception],
1653
+ # Or the metadata is returned as
1654
+ # `(url_to_download, etag, commit_hash, expected_size, xet_file_data, None)`
1655
+ tuple[str, str, str, int, Optional[XetFileData], None],
1656
+ ]:
1657
+ """Get metadata for a file on the Hub, safely handling network issues.
1658
+
1659
+ Returns either the etag, commit_hash and expected size of the file, or the error
1660
+ raised while fetching the metadata.
1661
+
1662
+ NOTE: This function mutates `headers` inplace! It removes the `authorization` header
1663
+ if the file is a LFS blob and the domain of the url is different from the
1664
+ domain of the location (typically an S3 bucket).
1665
+ """
1666
+ if local_files_only:
1667
+ return (
1668
+ None,
1669
+ None,
1670
+ None,
1671
+ None,
1672
+ None,
1673
+ OfflineModeIsEnabled(
1674
+ f"Cannot access file since 'local_files_only=True' as been set. (repo_id: {repo_id}, repo_type: {repo_type}, revision: {revision}, filename: {filename})"
1675
+ ),
1676
+ )
1677
+
1678
+ url = hf_hub_url(repo_id, filename, repo_type=repo_type, revision=revision, endpoint=endpoint)
1679
+ url_to_download: str = url
1680
+ etag: Optional[str] = None
1681
+ commit_hash: Optional[str] = None
1682
+ expected_size: Optional[int] = None
1683
+ head_error_call: Optional[Exception] = None
1684
+ xet_file_data: Optional[XetFileData] = None
1685
+
1686
+ # Try to get metadata from the server.
1687
+ # Do not raise yet if the file is not found or not accessible.
1688
+ if not local_files_only:
1689
+ try:
1690
+ try:
1691
+ metadata = get_hf_file_metadata(
1692
+ url=url,
1693
+ timeout=etag_timeout,
1694
+ headers=headers,
1695
+ token=token,
1696
+ endpoint=endpoint,
1697
+ retry_on_errors=retry_on_errors,
1698
+ )
1699
+ except RemoteEntryNotFoundError as http_error:
1700
+ if storage_folder is not None and relative_filename is not None:
1701
+ # Cache the non-existence of the file
1702
+ commit_hash = http_error.response.headers.get(constants.HUGGINGFACE_HEADER_X_REPO_COMMIT)
1703
+ if commit_hash is not None:
1704
+ no_exist_file_path = Path(storage_folder) / ".no_exist" / commit_hash / relative_filename
1705
+ try:
1706
+ no_exist_file_path.parent.mkdir(parents=True, exist_ok=True)
1707
+ no_exist_file_path.touch()
1708
+ except OSError as e:
1709
+ logger.error(
1710
+ f"Could not cache non-existence of file. Will ignore error and continue. Error: {e}"
1711
+ )
1712
+ _cache_commit_hash_for_specific_revision(storage_folder, revision, commit_hash)
1713
+ raise
1714
+
1715
+ # Commit hash must exist
1716
+ commit_hash = metadata.commit_hash
1717
+ if commit_hash is None:
1718
+ raise FileMetadataError(
1719
+ "Distant resource does not seem to be on huggingface.co. It is possible that a configuration issue"
1720
+ " prevents you from downloading resources from https://huggingface.co. Please check your firewall"
1721
+ " and proxy settings and make sure your SSL certificates are updated."
1722
+ )
1723
+
1724
+ # Etag must exist
1725
+ # If we don't have any of those, raise an error.
1726
+ etag = metadata.etag
1727
+ if etag is None:
1728
+ raise FileMetadataError(
1729
+ "Distant resource does not have an ETag, we won't be able to reliably ensure reproducibility."
1730
+ )
1731
+
1732
+ # Size must exist
1733
+ expected_size = metadata.size
1734
+ if expected_size is None:
1735
+ raise FileMetadataError("Distant resource does not have a Content-Length.")
1736
+
1737
+ xet_file_data = metadata.xet_file_data
1738
+
1739
+ # In case of a redirect, save an extra redirect on the request.get call,
1740
+ # and ensure we download the exact atomic version even if it changed
1741
+ # between the HEAD and the GET (unlikely, but hey).
1742
+ #
1743
+ # If url domain is different => we are downloading from a CDN => url is signed => don't send auth
1744
+ # If url domain is the same => redirect due to repo rename AND downloading a regular file => keep auth
1745
+ if xet_file_data is None and url != metadata.location:
1746
+ url_to_download = metadata.location
1747
+ if urlparse(url).netloc != urlparse(metadata.location).netloc:
1748
+ # Remove authorization header when downloading a LFS blob
1749
+ headers.pop("authorization", None)
1750
+ except httpx.ProxyError:
1751
+ # Actually raise on proxy error
1752
+ raise
1753
+ except (httpx.ConnectError, httpx.TimeoutException, OfflineModeIsEnabled) as error:
1754
+ # Otherwise, our Internet connection is down.
1755
+ # etag is None
1756
+ head_error_call = error
1757
+ except (RevisionNotFoundError, RemoteEntryNotFoundError):
1758
+ # The repo was found but the revision or entry doesn't exist on the Hub (never existed or got deleted)
1759
+ raise
1760
+ except HfHubHTTPError as error:
1761
+ # Multiple reasons for an http error:
1762
+ # - Repository is private and invalid/missing token sent
1763
+ # - Repository is gated and invalid/missing token sent
1764
+ # - Hub is down (error 500 or 504)
1765
+ # => let's switch to 'local_files_only=True' to check if the files are already cached.
1766
+ # (if it's not the case, the error will be re-raised)
1767
+ head_error_call = error
1768
+ except FileMetadataError as error:
1769
+ # Multiple reasons for a FileMetadataError:
1770
+ # - Wrong network configuration (proxy, firewall, SSL certificates)
1771
+ # - Inconsistency on the Hub
1772
+ # => let's switch to 'local_files_only=True' to check if the files are already cached.
1773
+ # (if it's not the case, the error will be re-raised)
1774
+ head_error_call = error
1775
+
1776
+ if not (local_files_only or etag is not None or head_error_call is not None):
1777
+ raise RuntimeError("etag is empty due to uncovered problems")
1778
+
1779
+ return (url_to_download, etag, commit_hash, expected_size, xet_file_data, head_error_call) # type: ignore [return-value]
1780
+
1781
+
1782
+ def _raise_on_head_call_error(head_call_error: Exception, force_download: bool, local_files_only: bool) -> NoReturn:
1783
+ """Raise an appropriate error when the HEAD call failed and we cannot locate a local file."""
1784
+ # No head call => we cannot force download.
1785
+ if force_download:
1786
+ if local_files_only:
1787
+ raise ValueError("Cannot pass 'force_download=True' and 'local_files_only=True' at the same time.")
1788
+ elif isinstance(head_call_error, OfflineModeIsEnabled):
1789
+ raise ValueError("Cannot pass 'force_download=True' when offline mode is enabled.") from head_call_error
1790
+ else:
1791
+ raise ValueError("Force download failed due to the above error.") from head_call_error
1792
+
1793
+ # No head call + couldn't find an appropriate file on disk => raise an error.
1794
+ if local_files_only:
1795
+ raise LocalEntryNotFoundError(
1796
+ "Cannot find the requested files in the disk cache and outgoing traffic has been disabled. To enable"
1797
+ " hf.co look-ups and downloads online, set 'local_files_only' to False."
1798
+ )
1799
+ elif isinstance(head_call_error, (RepositoryNotFoundError, GatedRepoError)) or (
1800
+ isinstance(head_call_error, HfHubHTTPError) and head_call_error.response.status_code == 401
1801
+ ):
1802
+ # Repo not found or gated => let's raise the actual error
1803
+ # Unauthorized => likely a token issue => let's raise the actual error
1804
+ raise head_call_error
1805
+ else:
1806
+ # Otherwise: most likely a connection issue or Hub downtime => let's warn the user
1807
+ raise LocalEntryNotFoundError(
1808
+ "An error happened while trying to locate the file on the Hub and we cannot find the requested files"
1809
+ " in the local cache. Please check your connection and try again or make sure your Internet connection"
1810
+ " is on."
1811
+ ) from head_call_error
1812
+
1813
+
1814
+ def _download_to_tmp_and_move(
1815
+ incomplete_path: Path,
1816
+ destination_path: Path,
1817
+ url_to_download: str,
1818
+ headers: dict[str, str],
1819
+ expected_size: Optional[int],
1820
+ filename: str,
1821
+ force_download: bool,
1822
+ etag: Optional[str],
1823
+ xet_file_data: Optional[XetFileData],
1824
+ tqdm_class: Optional[type[base_tqdm]] = None,
1825
+ ) -> None:
1826
+ """Download content from a URL to a destination path.
1827
+
1828
+ Internal logic:
1829
+ - return early if file is already downloaded
1830
+ - resume download if possible (from incomplete file)
1831
+ - do not resume download if `force_download=True`
1832
+ - check disk space before downloading
1833
+ - download content to a temporary file
1834
+ - set correct permissions on temporary file
1835
+ - move the temporary file to the destination path
1836
+
1837
+ Both `incomplete_path` and `destination_path` must be on the same volume to avoid a local copy.
1838
+ """
1839
+ if destination_path.exists() and not force_download:
1840
+ # Do nothing if already exists (except if force_download=True)
1841
+ return
1842
+
1843
+ if incomplete_path.exists() and force_download:
1844
+ # By default, we will try to resume the download if possible.
1845
+ # However, if the user has set `force_download=True`, then we should
1846
+ # not resume the download => delete the incomplete file.
1847
+ logger.debug(f"Removing incomplete file '{incomplete_path}' (force_download=True)")
1848
+ incomplete_path.unlink(missing_ok=True)
1849
+
1850
+ with incomplete_path.open("ab") as f:
1851
+ resume_size = f.tell()
1852
+ message = f"Downloading '{filename}' to '{incomplete_path}'"
1853
+ if resume_size > 0 and expected_size is not None:
1854
+ message += f" (resume from {resume_size}/{expected_size})"
1855
+ logger.debug(message)
1856
+
1857
+ if expected_size is not None: # might be None if HTTP header not set correctly
1858
+ # Check disk space in both tmp and destination path
1859
+ _check_disk_space(expected_size, incomplete_path.parent)
1860
+ _check_disk_space(expected_size, destination_path.parent)
1861
+
1862
+ if xet_file_data is not None and is_xet_available():
1863
+ logger.debug("Xet Storage is enabled for this repo. Downloading file from Xet Storage..")
1864
+ xet_get(
1865
+ incomplete_path=incomplete_path,
1866
+ xet_file_data=xet_file_data,
1867
+ headers=headers,
1868
+ expected_size=expected_size,
1869
+ displayed_filename=filename,
1870
+ tqdm_class=tqdm_class,
1871
+ )
1872
+ else:
1873
+ if xet_file_data is not None and not constants.HF_HUB_DISABLE_XET:
1874
+ logger.warning(
1875
+ "Xet Storage is enabled for this repo, but the 'hf_xet' package is not installed. "
1876
+ "Falling back to regular HTTP download. "
1877
+ "For better performance, install the package with: `pip install huggingface_hub[hf_xet]` or `pip install hf_xet`"
1878
+ )
1879
+
1880
+ http_get(
1881
+ url_to_download,
1882
+ f,
1883
+ resume_size=resume_size,
1884
+ headers=headers,
1885
+ expected_size=expected_size,
1886
+ tqdm_class=tqdm_class,
1887
+ )
1888
+
1889
+ logger.debug(f"Download complete. Moving file to {destination_path}")
1890
+ _chmod_and_move(incomplete_path, destination_path)
1891
+
1892
+
1893
+ def _int_or_none(value: Optional[str]) -> Optional[int]:
1894
+ try:
1895
+ return int(value) # type: ignore
1896
+ except (TypeError, ValueError):
1897
+ return None
1898
+
1899
+
1900
+ def _chmod_and_move(src: Path, dst: Path) -> None:
1901
+ """Set correct permission before moving a blob from tmp directory to cache dir.
1902
+
1903
+ Do not take into account the `umask` from the process as there is no convenient way
1904
+ to get it that is thread-safe.
1905
+
1906
+ See:
1907
+ - About umask: https://docs.python.org/3/library/os.html#os.umask
1908
+ - Thread-safety: https://stackoverflow.com/a/70343066
1909
+ - About solution: https://github.com/huggingface/huggingface_hub/pull/1220#issuecomment-1326211591
1910
+ - Fix issue: https://github.com/huggingface/huggingface_hub/issues/1141
1911
+ - Fix issue: https://github.com/huggingface/huggingface_hub/issues/1215
1912
+ """
1913
+ # Get umask by creating a temporary file in the cached repo folder.
1914
+ tmp_file = dst.parent.parent / f"tmp_{uuid.uuid4()}"
1915
+ try:
1916
+ tmp_file.touch()
1917
+ cache_dir_mode = Path(tmp_file).stat().st_mode
1918
+ os.chmod(str(src), stat.S_IMODE(cache_dir_mode))
1919
+ except OSError as e:
1920
+ logger.warning(
1921
+ f"Could not set the permissions on the file '{src}'. Error: {e}.\nContinuing without setting permissions."
1922
+ )
1923
+ finally:
1924
+ try:
1925
+ tmp_file.unlink()
1926
+ except OSError:
1927
+ # fails if `tmp_file.touch()` failed => do nothing
1928
+ # See https://github.com/huggingface/huggingface_hub/issues/2359
1929
+ pass
1930
+
1931
+ shutil.move(str(src), str(dst), copy_function=_copy_no_matter_what)
1932
+
1933
+
1934
+ def _copy_no_matter_what(src: str, dst: str) -> None:
1935
+ """Copy file from src to dst.
1936
+
1937
+ If `shutil.copy2` fails, fallback to `shutil.copyfile`.
1938
+ """
1939
+ try:
1940
+ # Copy file with metadata and permission
1941
+ # Can fail e.g. if dst is an S3 mount
1942
+ shutil.copy2(src, dst)
1943
+ except OSError:
1944
+ # Copy only file content
1945
+ shutil.copyfile(src, dst)
1946
+
1947
+
1948
+ def _get_pointer_path(storage_folder: str, revision: str, relative_filename: str) -> str:
1949
+ # Using `os.path.abspath` instead of `Path.resolve()` to avoid resolving symlinks
1950
+ snapshot_path = os.path.join(storage_folder, "snapshots")
1951
+ pointer_path = os.path.join(snapshot_path, revision, relative_filename)
1952
+ if Path(os.path.abspath(snapshot_path)) not in Path(os.path.abspath(pointer_path)).parents:
1953
+ raise ValueError(
1954
+ "Invalid pointer path: cannot create pointer path in snapshot folder if"
1955
+ f" `storage_folder='{storage_folder}'`, `revision='{revision}'` and"
1956
+ f" `relative_filename='{relative_filename}'`."
1957
+ )
1958
+ return pointer_path
env/lib/python3.13/site-packages/huggingface_hub/hf_api.py ADDED
The diff for this file is too large to render. See raw diff
 
env/lib/python3.13/site-packages/huggingface_hub/hub_mixin.py ADDED
@@ -0,0 +1,831 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import inspect
2
+ import json
3
+ import os
4
+ from dataclasses import Field, asdict, dataclass, is_dataclass
5
+ from pathlib import Path
6
+ from typing import Any, Callable, ClassVar, Optional, Protocol, Type, TypeVar, Union
7
+
8
+ import packaging.version
9
+
10
+ from . import constants
11
+ from .errors import EntryNotFoundError, HfHubHTTPError
12
+ from .file_download import hf_hub_download
13
+ from .hf_api import HfApi
14
+ from .repocard import ModelCard, ModelCardData
15
+ from .utils import (
16
+ SoftTemporaryDirectory,
17
+ is_jsonable,
18
+ is_safetensors_available,
19
+ is_simple_optional_type,
20
+ is_torch_available,
21
+ logging,
22
+ unwrap_simple_optional_type,
23
+ validate_hf_hub_args,
24
+ )
25
+
26
+
27
+ if is_torch_available():
28
+ import torch # type: ignore
29
+
30
+ if is_safetensors_available():
31
+ import safetensors
32
+ from safetensors.torch import load_model as load_model_as_safetensor
33
+ from safetensors.torch import save_model as save_model_as_safetensor
34
+
35
+
36
+ logger = logging.get_logger(__name__)
37
+
38
+
39
+ # Type alias for dataclass instances, copied from https://github.com/python/typeshed/blob/9f28171658b9ca6c32a7cb93fbb99fc92b17858b/stdlib/_typeshed/__init__.pyi#L349
40
+ class DataclassInstance(Protocol):
41
+ __dataclass_fields__: ClassVar[dict[str, Field]]
42
+
43
+
44
+ # Generic variable that is either ModelHubMixin or a subclass thereof
45
+ T = TypeVar("T", bound="ModelHubMixin")
46
+ # Generic variable to represent an args type
47
+ ARGS_T = TypeVar("ARGS_T")
48
+ ENCODER_T = Callable[[ARGS_T], Any]
49
+ DECODER_T = Callable[[Any], ARGS_T]
50
+ CODER_T = tuple[ENCODER_T, DECODER_T]
51
+
52
+
53
+ DEFAULT_MODEL_CARD = """
54
+ ---
55
+ # For reference on model card metadata, see the spec: https://github.com/huggingface/hub-docs/blob/main/modelcard.md?plain=1
56
+ # Doc / guide: https://huggingface.co/docs/hub/model-cards
57
+ {{ card_data }}
58
+ ---
59
+
60
+ This model has been pushed to the Hub using the [PytorchModelHubMixin](https://huggingface.co/docs/huggingface_hub/package_reference/mixins#huggingface_hub.PyTorchModelHubMixin) integration:
61
+ - Code: {{ repo_url | default("[More Information Needed]", true) }}
62
+ - Paper: {{ paper_url | default("[More Information Needed]", true) }}
63
+ - Docs: {{ docs_url | default("[More Information Needed]", true) }}
64
+ """
65
+
66
+
67
+ @dataclass
68
+ class MixinInfo:
69
+ model_card_template: str
70
+ model_card_data: ModelCardData
71
+ docs_url: Optional[str] = None
72
+ paper_url: Optional[str] = None
73
+ repo_url: Optional[str] = None
74
+
75
+
76
+ class ModelHubMixin:
77
+ """
78
+ A generic mixin to integrate ANY machine learning framework with the Hub.
79
+
80
+ To integrate your framework, your model class must inherit from this class. Custom logic for saving/loading models
81
+ have to be overwritten in [`_from_pretrained`] and [`_save_pretrained`]. [`PyTorchModelHubMixin`] is a good example
82
+ of mixin integration with the Hub. Check out our [integration guide](../guides/integrations) for more instructions.
83
+
84
+ When inheriting from [`ModelHubMixin`], you can define class-level attributes. These attributes are not passed to
85
+ `__init__` but to the class definition itself. This is useful to define metadata about the library integrating
86
+ [`ModelHubMixin`].
87
+
88
+ For more details on how to integrate the mixin with your library, checkout the [integration guide](../guides/integrations).
89
+
90
+ Args:
91
+ repo_url (`str`, *optional*):
92
+ URL of the library repository. Used to generate model card.
93
+ paper_url (`str`, *optional*):
94
+ URL of the library paper. Used to generate model card.
95
+ docs_url (`str`, *optional*):
96
+ URL of the library documentation. Used to generate model card.
97
+ model_card_template (`str`, *optional*):
98
+ Template of the model card. Used to generate model card. Defaults to a generic template.
99
+ language (`str` or `list[str]`, *optional*):
100
+ Language supported by the library. Used to generate model card.
101
+ library_name (`str`, *optional*):
102
+ Name of the library integrating ModelHubMixin. Used to generate model card.
103
+ license (`str`, *optional*):
104
+ License of the library integrating ModelHubMixin. Used to generate model card.
105
+ E.g: "apache-2.0"
106
+ license_name (`str`, *optional*):
107
+ Name of the library integrating ModelHubMixin. Used to generate model card.
108
+ Only used if `license` is set to `other`.
109
+ E.g: "coqui-public-model-license".
110
+ license_link (`str`, *optional*):
111
+ URL to the license of the library integrating ModelHubMixin. Used to generate model card.
112
+ Only used if `license` is set to `other` and `license_name` is set.
113
+ E.g: "https://coqui.ai/cpml".
114
+ pipeline_tag (`str`, *optional*):
115
+ Tag of the pipeline. Used to generate model card. E.g. "text-classification".
116
+ tags (`list[str]`, *optional*):
117
+ Tags to be added to the model card. Used to generate model card. E.g. ["computer-vision"]
118
+ coders (`dict[Type, tuple[Callable, Callable]]`, *optional*):
119
+ Dictionary of custom types and their encoders/decoders. Used to encode/decode arguments that are not
120
+ jsonable by default. E.g. dataclasses, argparse.Namespace, OmegaConf, etc.
121
+
122
+ Example:
123
+
124
+ ```python
125
+ >>> from huggingface_hub import ModelHubMixin
126
+
127
+ # Inherit from ModelHubMixin
128
+ >>> class MyCustomModel(
129
+ ... ModelHubMixin,
130
+ ... library_name="my-library",
131
+ ... tags=["computer-vision"],
132
+ ... repo_url="https://github.com/huggingface/my-cool-library",
133
+ ... paper_url="https://arxiv.org/abs/2304.12244",
134
+ ... docs_url="https://huggingface.co/docs/my-cool-library",
135
+ ... # ^ optional metadata to generate model card
136
+ ... ):
137
+ ... def __init__(self, size: int = 512, device: str = "cpu"):
138
+ ... # define how to initialize your model
139
+ ... super().__init__()
140
+ ... ...
141
+ ...
142
+ ... def _save_pretrained(self, save_directory: Path) -> None:
143
+ ... # define how to serialize your model
144
+ ... ...
145
+ ...
146
+ ... @classmethod
147
+ ... def from_pretrained(
148
+ ... cls: type[T],
149
+ ... pretrained_model_name_or_path: Union[str, Path],
150
+ ... *,
151
+ ... force_download: bool = False,
152
+ ... token: Optional[Union[str, bool]] = None,
153
+ ... cache_dir: Optional[Union[str, Path]] = None,
154
+ ... local_files_only: bool = False,
155
+ ... revision: Optional[str] = None,
156
+ ... **model_kwargs,
157
+ ... ) -> T:
158
+ ... # define how to deserialize your model
159
+ ... ...
160
+
161
+ >>> model = MyCustomModel(size=256, device="gpu")
162
+
163
+ # Save model weights to local directory
164
+ >>> model.save_pretrained("my-awesome-model")
165
+
166
+ # Push model weights to the Hub
167
+ >>> model.push_to_hub("my-awesome-model")
168
+
169
+ # Download and initialize weights from the Hub
170
+ >>> reloaded_model = MyCustomModel.from_pretrained("username/my-awesome-model")
171
+ >>> reloaded_model.size
172
+ 256
173
+
174
+ # Model card has been correctly populated
175
+ >>> from huggingface_hub import ModelCard
176
+ >>> card = ModelCard.load("username/my-awesome-model")
177
+ >>> card.data.tags
178
+ ["x-custom-tag", "pytorch_model_hub_mixin", "model_hub_mixin"]
179
+ >>> card.data.library_name
180
+ "my-library"
181
+ ```
182
+ """
183
+
184
+ _hub_mixin_config: Optional[Union[dict, DataclassInstance]] = None
185
+ # ^ optional config attribute automatically set in `from_pretrained`
186
+ _hub_mixin_info: MixinInfo
187
+ # ^ information about the library integrating ModelHubMixin (used to generate model card)
188
+ _hub_mixin_inject_config: bool # whether `_from_pretrained` expects `config` or not
189
+ _hub_mixin_init_parameters: dict[str, inspect.Parameter] # __init__ parameters
190
+ _hub_mixin_jsonable_default_values: dict[str, Any] # default values for __init__ parameters
191
+ _hub_mixin_jsonable_custom_types: tuple[Type, ...] # custom types that can be encoded/decoded
192
+ _hub_mixin_coders: dict[Type, CODER_T] # encoders/decoders for custom types
193
+ # ^ internal values to handle config
194
+
195
+ def __init_subclass__(
196
+ cls,
197
+ *,
198
+ # Generic info for model card
199
+ repo_url: Optional[str] = None,
200
+ paper_url: Optional[str] = None,
201
+ docs_url: Optional[str] = None,
202
+ # Model card template
203
+ model_card_template: str = DEFAULT_MODEL_CARD,
204
+ # Model card metadata
205
+ language: Optional[list[str]] = None,
206
+ library_name: Optional[str] = None,
207
+ license: Optional[str] = None,
208
+ license_name: Optional[str] = None,
209
+ license_link: Optional[str] = None,
210
+ pipeline_tag: Optional[str] = None,
211
+ tags: Optional[list[str]] = None,
212
+ # How to encode/decode arguments with custom type into a JSON config?
213
+ coders: Optional[
214
+ dict[Type, CODER_T]
215
+ # Key is a type.
216
+ # Value is a tuple (encoder, decoder).
217
+ # Example: {MyCustomType: (lambda x: x.value, lambda data: MyCustomType(data))}
218
+ ] = None,
219
+ ) -> None:
220
+ """Inspect __init__ signature only once when subclassing + handle modelcard."""
221
+ super().__init_subclass__()
222
+
223
+ # Will be reused when creating modelcard
224
+ tags = tags or []
225
+ tags.append("model_hub_mixin")
226
+
227
+ # Initialize MixinInfo if not existent
228
+ info = MixinInfo(model_card_template=model_card_template, model_card_data=ModelCardData())
229
+
230
+ # If parent class has a MixinInfo, inherit from it as a copy
231
+ if hasattr(cls, "_hub_mixin_info"):
232
+ # Inherit model card template from parent class if not explicitly set
233
+ if model_card_template == DEFAULT_MODEL_CARD:
234
+ info.model_card_template = cls._hub_mixin_info.model_card_template
235
+
236
+ # Inherit from parent model card data
237
+ info.model_card_data = ModelCardData(**cls._hub_mixin_info.model_card_data.to_dict())
238
+
239
+ # Inherit other info
240
+ info.docs_url = cls._hub_mixin_info.docs_url
241
+ info.paper_url = cls._hub_mixin_info.paper_url
242
+ info.repo_url = cls._hub_mixin_info.repo_url
243
+ cls._hub_mixin_info = info
244
+
245
+ # Update MixinInfo with metadata
246
+ if model_card_template is not None and model_card_template != DEFAULT_MODEL_CARD:
247
+ info.model_card_template = model_card_template
248
+ if repo_url is not None:
249
+ info.repo_url = repo_url
250
+ if paper_url is not None:
251
+ info.paper_url = paper_url
252
+ if docs_url is not None:
253
+ info.docs_url = docs_url
254
+ if language is not None:
255
+ info.model_card_data.language = language
256
+ if library_name is not None:
257
+ info.model_card_data.library_name = library_name
258
+ if license is not None:
259
+ info.model_card_data.license = license
260
+ if license_name is not None:
261
+ info.model_card_data.license_name = license_name
262
+ if license_link is not None:
263
+ info.model_card_data.license_link = license_link
264
+ if pipeline_tag is not None:
265
+ info.model_card_data.pipeline_tag = pipeline_tag
266
+ if tags is not None:
267
+ normalized_tags = list(tags)
268
+ if info.model_card_data.tags is not None:
269
+ info.model_card_data.tags.extend(normalized_tags)
270
+ else:
271
+ info.model_card_data.tags = normalized_tags
272
+
273
+ if info.model_card_data.tags is not None:
274
+ info.model_card_data.tags = sorted(set(info.model_card_data.tags))
275
+
276
+ # Handle encoders/decoders for args
277
+ cls._hub_mixin_coders = coders or {}
278
+ cls._hub_mixin_jsonable_custom_types = tuple(cls._hub_mixin_coders.keys())
279
+
280
+ # Inspect __init__ signature to handle config
281
+ cls._hub_mixin_init_parameters = dict(inspect.signature(cls.__init__).parameters)
282
+ cls._hub_mixin_jsonable_default_values = {
283
+ param.name: cls._encode_arg(param.default)
284
+ for param in cls._hub_mixin_init_parameters.values()
285
+ if param.default is not inspect.Parameter.empty and cls._is_jsonable(param.default)
286
+ }
287
+ cls._hub_mixin_inject_config = "config" in inspect.signature(cls._from_pretrained).parameters
288
+
289
+ def __new__(cls: type[T], *args, **kwargs) -> T:
290
+ """Create a new instance of the class and handle config.
291
+
292
+ 3 cases:
293
+ - If `self._hub_mixin_config` is already set, do nothing.
294
+ - If `config` is passed as a dataclass, set it as `self._hub_mixin_config`.
295
+ - Otherwise, build `self._hub_mixin_config` from default values and passed values.
296
+ """
297
+ instance = super().__new__(cls)
298
+
299
+ # If `config` is already set, return early
300
+ if instance._hub_mixin_config is not None:
301
+ return instance
302
+
303
+ # Infer passed values
304
+ passed_values = {
305
+ **{
306
+ key: value
307
+ for key, value in zip(
308
+ # [1:] to skip `self` parameter
309
+ list(cls._hub_mixin_init_parameters)[1:],
310
+ args,
311
+ )
312
+ },
313
+ **kwargs,
314
+ }
315
+
316
+ # If config passed as dataclass => set it and return early
317
+ if is_dataclass(passed_values.get("config")):
318
+ instance._hub_mixin_config = passed_values["config"]
319
+ return instance
320
+
321
+ # Otherwise, build config from default + passed values
322
+ init_config = {
323
+ # default values
324
+ **cls._hub_mixin_jsonable_default_values,
325
+ # passed values
326
+ **{
327
+ key: cls._encode_arg(value) # Encode custom types as jsonable value
328
+ for key, value in passed_values.items()
329
+ if instance._is_jsonable(value) # Only if jsonable or we have a custom encoder
330
+ },
331
+ }
332
+ passed_config = init_config.pop("config", {})
333
+
334
+ # Populate `init_config` with provided config
335
+ if isinstance(passed_config, dict):
336
+ init_config.update(passed_config)
337
+
338
+ # Set `config` attribute and return
339
+ if init_config != {}:
340
+ instance._hub_mixin_config = init_config
341
+ return instance
342
+
343
+ @classmethod
344
+ def _is_jsonable(cls, value: Any) -> bool:
345
+ """Check if a value is JSON serializable."""
346
+ if is_dataclass(value):
347
+ return True
348
+ if isinstance(value, cls._hub_mixin_jsonable_custom_types):
349
+ return True
350
+ return is_jsonable(value)
351
+
352
+ @classmethod
353
+ def _encode_arg(cls, arg: Any) -> Any:
354
+ """Encode an argument into a JSON serializable format."""
355
+ if is_dataclass(arg):
356
+ return asdict(arg) # type: ignore[arg-type]
357
+ for type_, (encoder, _) in cls._hub_mixin_coders.items():
358
+ if isinstance(arg, type_):
359
+ if arg is None:
360
+ return None
361
+ return encoder(arg)
362
+ return arg
363
+
364
+ @classmethod
365
+ def _decode_arg(cls, expected_type: type[ARGS_T], value: Any) -> Optional[ARGS_T]:
366
+ """Decode a JSON serializable value into an argument."""
367
+ if is_simple_optional_type(expected_type):
368
+ if value is None:
369
+ return None
370
+ expected_type = unwrap_simple_optional_type(expected_type) # type: ignore[assignment]
371
+ # Dataclass => handle it
372
+ if is_dataclass(expected_type):
373
+ return _load_dataclass(expected_type, value) # type: ignore[return-value]
374
+ # Otherwise => check custom decoders
375
+ for type_, (_, decoder) in cls._hub_mixin_coders.items():
376
+ if inspect.isclass(expected_type) and issubclass(expected_type, type_):
377
+ return decoder(value)
378
+ # Otherwise => don't decode
379
+ return value
380
+
381
+ def save_pretrained(
382
+ self,
383
+ save_directory: Union[str, Path],
384
+ *,
385
+ config: Optional[Union[dict, DataclassInstance]] = None,
386
+ repo_id: Optional[str] = None,
387
+ push_to_hub: bool = False,
388
+ model_card_kwargs: Optional[dict[str, Any]] = None,
389
+ **push_to_hub_kwargs,
390
+ ) -> Optional[str]:
391
+ """
392
+ Save weights in local directory.
393
+
394
+ Args:
395
+ save_directory (`str` or `Path`):
396
+ Path to directory in which the model weights and configuration will be saved.
397
+ config (`dict` or `DataclassInstance`, *optional*):
398
+ Model configuration specified as a key/value dictionary or a dataclass instance.
399
+ push_to_hub (`bool`, *optional*, defaults to `False`):
400
+ Whether or not to push your model to the Huggingface Hub after saving it.
401
+ repo_id (`str`, *optional*):
402
+ ID of your repository on the Hub. Used only if `push_to_hub=True`. Will default to the folder name if
403
+ not provided.
404
+ model_card_kwargs (`dict[str, Any]`, *optional*):
405
+ Additional arguments passed to the model card template to customize the model card.
406
+ push_to_hub_kwargs:
407
+ Additional key word arguments passed along to the [`~ModelHubMixin.push_to_hub`] method.
408
+ Returns:
409
+ `str` or `None`: url of the commit on the Hub if `push_to_hub=True`, `None` otherwise.
410
+ """
411
+ save_directory = Path(save_directory)
412
+ save_directory.mkdir(parents=True, exist_ok=True)
413
+
414
+ # Remove config.json if already exists. After `_save_pretrained` we don't want to overwrite config.json
415
+ # as it might have been saved by the custom `_save_pretrained` already. However we do want to overwrite
416
+ # an existing config.json if it was not saved by `_save_pretrained`.
417
+ config_path = save_directory / constants.CONFIG_NAME
418
+ config_path.unlink(missing_ok=True)
419
+
420
+ # save model weights/files (framework-specific)
421
+ self._save_pretrained(save_directory)
422
+
423
+ # save config (if provided and if not serialized yet in `_save_pretrained`)
424
+ if config is None:
425
+ config = self._hub_mixin_config
426
+ if config is not None:
427
+ if is_dataclass(config):
428
+ config = asdict(config) # type: ignore[arg-type]
429
+ if not config_path.exists():
430
+ config_str = json.dumps(config, sort_keys=True, indent=2)
431
+ config_path.write_text(config_str)
432
+
433
+ # save model card
434
+ model_card_path = save_directory / "README.md"
435
+ model_card_kwargs = model_card_kwargs if model_card_kwargs is not None else {}
436
+ if not model_card_path.exists(): # do not overwrite if already exists
437
+ self.generate_model_card(**model_card_kwargs).save(save_directory / "README.md")
438
+
439
+ # push to the Hub if required
440
+ if push_to_hub:
441
+ kwargs = push_to_hub_kwargs.copy() # soft-copy to avoid mutating input
442
+ if config is not None: # kwarg for `push_to_hub`
443
+ kwargs["config"] = config
444
+ if repo_id is None:
445
+ repo_id = save_directory.name # Defaults to `save_directory` name
446
+ return self.push_to_hub(repo_id=repo_id, model_card_kwargs=model_card_kwargs, **kwargs)
447
+ return None
448
+
449
+ def _save_pretrained(self, save_directory: Path) -> None:
450
+ """
451
+ Overwrite this method in subclass to define how to save your model.
452
+ Check out our [integration guide](../guides/integrations) for instructions.
453
+
454
+ Args:
455
+ save_directory (`str` or `Path`):
456
+ Path to directory in which the model weights and configuration will be saved.
457
+ """
458
+ raise NotImplementedError
459
+
460
+ @classmethod
461
+ @validate_hf_hub_args
462
+ def from_pretrained(
463
+ cls: type[T],
464
+ pretrained_model_name_or_path: Union[str, Path],
465
+ *,
466
+ force_download: bool = False,
467
+ token: Optional[Union[str, bool]] = None,
468
+ cache_dir: Optional[Union[str, Path]] = None,
469
+ local_files_only: bool = False,
470
+ revision: Optional[str] = None,
471
+ **model_kwargs,
472
+ ) -> T:
473
+ """
474
+ Download a model from the Huggingface Hub and instantiate it.
475
+
476
+ Args:
477
+ pretrained_model_name_or_path (`str`, `Path`):
478
+ - Either the `model_id` (string) of a model hosted on the Hub, e.g. `bigscience/bloom`.
479
+ - Or a path to a `directory` containing model weights saved using
480
+ [`~transformers.PreTrainedModel.save_pretrained`], e.g., `../path/to/my_model_directory/`.
481
+ revision (`str`, *optional*):
482
+ Revision of the model on the Hub. Can be a branch name, a git tag or any commit id.
483
+ Defaults to the latest commit on `main` branch.
484
+ force_download (`bool`, *optional*, defaults to `False`):
485
+ Whether to force (re-)downloading the model weights and configuration files from the Hub, overriding
486
+ the existing cache.
487
+ token (`str` or `bool`, *optional*):
488
+ The token to use as HTTP bearer authorization for remote files. By default, it will use the token
489
+ cached when running `hf auth login`.
490
+ cache_dir (`str`, `Path`, *optional*):
491
+ Path to the folder where cached files are stored.
492
+ local_files_only (`bool`, *optional*, defaults to `False`):
493
+ If `True`, avoid downloading the file and return the path to the local cached file if it exists.
494
+ model_kwargs (`dict`, *optional*):
495
+ Additional kwargs to pass to the model during initialization.
496
+ """
497
+ model_id = str(pretrained_model_name_or_path)
498
+ config_file: Optional[str] = None
499
+ if os.path.isdir(model_id):
500
+ if constants.CONFIG_NAME in os.listdir(model_id):
501
+ config_file = os.path.join(model_id, constants.CONFIG_NAME)
502
+ else:
503
+ logger.warning(f"{constants.CONFIG_NAME} not found in {Path(model_id).resolve()}")
504
+ else:
505
+ try:
506
+ config_file = hf_hub_download(
507
+ repo_id=model_id,
508
+ filename=constants.CONFIG_NAME,
509
+ revision=revision,
510
+ cache_dir=cache_dir,
511
+ force_download=force_download,
512
+ token=token,
513
+ local_files_only=local_files_only,
514
+ )
515
+ except HfHubHTTPError as e:
516
+ logger.info(f"{constants.CONFIG_NAME} not found on the HuggingFace Hub: {str(e)}")
517
+
518
+ # Read config
519
+ config = None
520
+ if config_file is not None:
521
+ with open(config_file, "r", encoding="utf-8") as f:
522
+ config = json.load(f)
523
+
524
+ # Decode custom types in config
525
+ for key, value in config.items():
526
+ if key in cls._hub_mixin_init_parameters:
527
+ expected_type = cls._hub_mixin_init_parameters[key].annotation
528
+ if expected_type is not inspect.Parameter.empty:
529
+ config[key] = cls._decode_arg(expected_type, value)
530
+
531
+ # Populate model_kwargs from config
532
+ for param in cls._hub_mixin_init_parameters.values():
533
+ if param.name not in model_kwargs and param.name in config:
534
+ model_kwargs[param.name] = config[param.name]
535
+
536
+ # Check if `config` argument was passed at init
537
+ if "config" in cls._hub_mixin_init_parameters and "config" not in model_kwargs:
538
+ # Decode `config` argument if it was passed
539
+ config_annotation = cls._hub_mixin_init_parameters["config"].annotation
540
+ config = cls._decode_arg(config_annotation, config)
541
+
542
+ # Forward config to model initialization
543
+ model_kwargs["config"] = config
544
+
545
+ # Inject config if `**kwargs` are expected
546
+ if is_dataclass(cls):
547
+ for key in cls.__dataclass_fields__:
548
+ if key not in model_kwargs and key in config:
549
+ model_kwargs[key] = config[key]
550
+ elif any(param.kind == inspect.Parameter.VAR_KEYWORD for param in cls._hub_mixin_init_parameters.values()):
551
+ for key, value in config.items(): # type: ignore[union-attr]
552
+ if key not in model_kwargs:
553
+ model_kwargs[key] = value
554
+
555
+ # Finally, also inject if `_from_pretrained` expects it
556
+ if cls._hub_mixin_inject_config and "config" not in model_kwargs:
557
+ model_kwargs["config"] = config
558
+
559
+ instance = cls._from_pretrained(
560
+ model_id=str(model_id),
561
+ revision=revision,
562
+ cache_dir=cache_dir,
563
+ force_download=force_download,
564
+ local_files_only=local_files_only,
565
+ token=token,
566
+ **model_kwargs,
567
+ )
568
+
569
+ # Implicitly set the config as instance attribute if not already set by the class
570
+ # This way `config` will be available when calling `save_pretrained` or `push_to_hub`.
571
+ if config is not None and (getattr(instance, "_hub_mixin_config", None) in (None, {})):
572
+ instance._hub_mixin_config = config
573
+
574
+ return instance
575
+
576
+ @classmethod
577
+ def _from_pretrained(
578
+ cls: type[T],
579
+ *,
580
+ model_id: str,
581
+ revision: Optional[str],
582
+ cache_dir: Optional[Union[str, Path]],
583
+ force_download: bool,
584
+ local_files_only: bool,
585
+ token: Optional[Union[str, bool]],
586
+ **model_kwargs,
587
+ ) -> T:
588
+ """Overwrite this method in subclass to define how to load your model from pretrained.
589
+
590
+ Use [`hf_hub_download`] or [`snapshot_download`] to download files from the Hub before loading them. Most
591
+ args taken as input can be directly passed to those 2 methods. If needed, you can add more arguments to this
592
+ method using "model_kwargs". For example [`PyTorchModelHubMixin._from_pretrained`] takes as input a `map_location`
593
+ parameter to set on which device the model should be loaded.
594
+
595
+ Check out our [integration guide](../guides/integrations) for more instructions.
596
+
597
+ Args:
598
+ model_id (`str`):
599
+ ID of the model to load from the Huggingface Hub (e.g. `bigscience/bloom`).
600
+ revision (`str`, *optional*):
601
+ Revision of the model on the Hub. Can be a branch name, a git tag or any commit id. Defaults to the
602
+ latest commit on `main` branch.
603
+ force_download (`bool`, *optional*, defaults to `False`):
604
+ Whether to force (re-)downloading the model weights and configuration files from the Hub, overriding
605
+ the existing cache.
606
+ token (`str` or `bool`, *optional*):
607
+ The token to use as HTTP bearer authorization for remote files. By default, it will use the token
608
+ cached when running `hf auth login`.
609
+ cache_dir (`str`, `Path`, *optional*):
610
+ Path to the folder where cached files are stored.
611
+ local_files_only (`bool`, *optional*, defaults to `False`):
612
+ If `True`, avoid downloading the file and return the path to the local cached file if it exists.
613
+ model_kwargs:
614
+ Additional keyword arguments passed along to the [`~ModelHubMixin._from_pretrained`] method.
615
+ """
616
+ raise NotImplementedError
617
+
618
+ @validate_hf_hub_args
619
+ def push_to_hub(
620
+ self,
621
+ repo_id: str,
622
+ *,
623
+ config: Optional[Union[dict, DataclassInstance]] = None,
624
+ commit_message: str = "Push model using huggingface_hub.",
625
+ private: Optional[bool] = None,
626
+ token: Optional[str] = None,
627
+ branch: Optional[str] = None,
628
+ create_pr: Optional[bool] = None,
629
+ allow_patterns: Optional[Union[list[str], str]] = None,
630
+ ignore_patterns: Optional[Union[list[str], str]] = None,
631
+ delete_patterns: Optional[Union[list[str], str]] = None,
632
+ model_card_kwargs: Optional[dict[str, Any]] = None,
633
+ ) -> str:
634
+ """
635
+ Upload model checkpoint to the Hub.
636
+
637
+ Use `allow_patterns` and `ignore_patterns` to precisely filter which files should be pushed to the hub. Use
638
+ `delete_patterns` to delete existing remote files in the same commit. See [`upload_folder`] reference for more
639
+ details.
640
+
641
+ Args:
642
+ repo_id (`str`):
643
+ ID of the repository to push to (example: `"username/my-model"`).
644
+ config (`dict` or `DataclassInstance`, *optional*):
645
+ Model configuration specified as a key/value dictionary or a dataclass instance.
646
+ commit_message (`str`, *optional*):
647
+ Message to commit while pushing.
648
+ private (`bool`, *optional*):
649
+ Whether the repository created should be private.
650
+ If `None` (default), the repo will be public unless the organization's default is private.
651
+ token (`str`, *optional*):
652
+ The token to use as HTTP bearer authorization for remote files. By default, it will use the token
653
+ cached when running `hf auth login`.
654
+ branch (`str`, *optional*):
655
+ The git branch on which to push the model. This defaults to `"main"`.
656
+ create_pr (`boolean`, *optional*):
657
+ Whether or not to create a Pull Request from `branch` with that commit. Defaults to `False`.
658
+ allow_patterns (`list[str]` or `str`, *optional*):
659
+ If provided, only files matching at least one pattern are pushed.
660
+ ignore_patterns (`list[str]` or `str`, *optional*):
661
+ If provided, files matching any of the patterns are not pushed.
662
+ delete_patterns (`list[str]` or `str`, *optional*):
663
+ If provided, remote files matching any of the patterns will be deleted from the repo.
664
+ model_card_kwargs (`dict[str, Any]`, *optional*):
665
+ Additional arguments passed to the model card template to customize the model card.
666
+
667
+ Returns:
668
+ The url of the commit of your model in the given repository.
669
+ """
670
+ api = HfApi(token=token)
671
+ repo_id = api.create_repo(repo_id=repo_id, private=private, exist_ok=True).repo_id
672
+
673
+ # Push the files to the repo in a single commit
674
+ with SoftTemporaryDirectory() as tmp:
675
+ saved_path = Path(tmp) / repo_id
676
+ self.save_pretrained(saved_path, config=config, model_card_kwargs=model_card_kwargs)
677
+ return api.upload_folder(
678
+ repo_id=repo_id,
679
+ repo_type="model",
680
+ folder_path=saved_path,
681
+ commit_message=commit_message,
682
+ revision=branch,
683
+ create_pr=create_pr,
684
+ allow_patterns=allow_patterns,
685
+ ignore_patterns=ignore_patterns,
686
+ delete_patterns=delete_patterns,
687
+ )
688
+
689
+ def generate_model_card(self, *args, **kwargs) -> ModelCard:
690
+ card = ModelCard.from_template(
691
+ card_data=self._hub_mixin_info.model_card_data,
692
+ template_str=self._hub_mixin_info.model_card_template,
693
+ repo_url=self._hub_mixin_info.repo_url,
694
+ paper_url=self._hub_mixin_info.paper_url,
695
+ docs_url=self._hub_mixin_info.docs_url,
696
+ **kwargs,
697
+ )
698
+ return card
699
+
700
+
701
+ class PyTorchModelHubMixin(ModelHubMixin):
702
+ """
703
+ Implementation of [`ModelHubMixin`] to provide model Hub upload/download capabilities to PyTorch models. The model
704
+ is set in evaluation mode by default using `model.eval()` (dropout modules are deactivated). To train the model,
705
+ you should first set it back in training mode with `model.train()`.
706
+
707
+ See [`ModelHubMixin`] for more details on how to use the mixin.
708
+
709
+ Example:
710
+
711
+ ```python
712
+ >>> import torch
713
+ >>> import torch.nn as nn
714
+ >>> from huggingface_hub import PyTorchModelHubMixin
715
+
716
+ >>> class MyModel(
717
+ ... nn.Module,
718
+ ... PyTorchModelHubMixin,
719
+ ... library_name="keras-nlp",
720
+ ... repo_url="https://github.com/keras-team/keras-nlp",
721
+ ... paper_url="https://arxiv.org/abs/2304.12244",
722
+ ... docs_url="https://keras.io/keras_nlp/",
723
+ ... # ^ optional metadata to generate model card
724
+ ... ):
725
+ ... def __init__(self, hidden_size: int = 512, vocab_size: int = 30000, output_size: int = 4):
726
+ ... super().__init__()
727
+ ... self.param = nn.Parameter(torch.rand(hidden_size, vocab_size))
728
+ ... self.linear = nn.Linear(output_size, vocab_size)
729
+
730
+ ... def forward(self, x):
731
+ ... return self.linear(x + self.param)
732
+ >>> model = MyModel(hidden_size=256)
733
+
734
+ # Save model weights to local directory
735
+ >>> model.save_pretrained("my-awesome-model")
736
+
737
+ # Push model weights to the Hub
738
+ >>> model.push_to_hub("my-awesome-model")
739
+
740
+ # Download and initialize weights from the Hub
741
+ >>> model = MyModel.from_pretrained("username/my-awesome-model")
742
+ >>> model.hidden_size
743
+ 256
744
+ ```
745
+ """
746
+
747
+ def __init_subclass__(cls, *args, tags: Optional[list[str]] = None, **kwargs) -> None:
748
+ tags = tags or []
749
+ tags.append("pytorch_model_hub_mixin")
750
+ kwargs["tags"] = tags
751
+ return super().__init_subclass__(*args, **kwargs)
752
+
753
+ def _save_pretrained(self, save_directory: Path) -> None:
754
+ """Save weights from a Pytorch model to a local directory."""
755
+ model_to_save = self.module if hasattr(self, "module") else self # type: ignore
756
+ save_model_as_safetensor(model_to_save, str(save_directory / constants.SAFETENSORS_SINGLE_FILE)) # type: ignore [arg-type]
757
+
758
+ @classmethod
759
+ def _from_pretrained(
760
+ cls,
761
+ *,
762
+ model_id: str,
763
+ revision: Optional[str],
764
+ cache_dir: Optional[Union[str, Path]],
765
+ force_download: bool,
766
+ local_files_only: bool,
767
+ token: Union[str, bool, None],
768
+ map_location: str = "cpu",
769
+ strict: bool = False,
770
+ **model_kwargs,
771
+ ):
772
+ """Load Pytorch pretrained weights and return the loaded model."""
773
+ model = cls(**model_kwargs)
774
+ if os.path.isdir(model_id):
775
+ print("Loading weights from local directory")
776
+ model_file = os.path.join(model_id, constants.SAFETENSORS_SINGLE_FILE)
777
+ return cls._load_as_safetensor(model, model_file, map_location, strict)
778
+ else:
779
+ try:
780
+ model_file = hf_hub_download(
781
+ repo_id=model_id,
782
+ filename=constants.SAFETENSORS_SINGLE_FILE,
783
+ revision=revision,
784
+ cache_dir=cache_dir,
785
+ force_download=force_download,
786
+ token=token,
787
+ local_files_only=local_files_only,
788
+ )
789
+ return cls._load_as_safetensor(model, model_file, map_location, strict)
790
+ except EntryNotFoundError:
791
+ model_file = hf_hub_download(
792
+ repo_id=model_id,
793
+ filename=constants.PYTORCH_WEIGHTS_NAME,
794
+ revision=revision,
795
+ cache_dir=cache_dir,
796
+ force_download=force_download,
797
+ token=token,
798
+ local_files_only=local_files_only,
799
+ )
800
+ return cls._load_as_pickle(model, model_file, map_location, strict)
801
+
802
+ @classmethod
803
+ def _load_as_pickle(cls, model: T, model_file: str, map_location: str, strict: bool) -> T:
804
+ state_dict = torch.load(model_file, map_location=torch.device(map_location), weights_only=True)
805
+ model.load_state_dict(state_dict, strict=strict) # type: ignore
806
+ model.eval() # type: ignore
807
+ return model
808
+
809
+ @classmethod
810
+ def _load_as_safetensor(cls, model: T, model_file: str, map_location: str, strict: bool) -> T:
811
+ if packaging.version.parse(safetensors.__version__) < packaging.version.parse("0.4.3"): # type: ignore [attr-defined]
812
+ load_model_as_safetensor(model, model_file, strict=strict) # type: ignore [arg-type]
813
+ if map_location != "cpu":
814
+ logger.warning(
815
+ "Loading model weights on other devices than 'cpu' is not supported natively in your version of safetensors."
816
+ " This means that the model is loaded on 'cpu' first and then copied to the device."
817
+ " This leads to a slower loading time."
818
+ " Please update safetensors to version 0.4.3 or above for improved performance."
819
+ )
820
+ model.to(map_location) # type: ignore [attr-defined]
821
+ else:
822
+ safetensors.torch.load_model(model, model_file, strict=strict, device=map_location) # type: ignore [arg-type]
823
+ return model
824
+
825
+
826
+ def _load_dataclass(datacls: type[DataclassInstance], data: dict) -> DataclassInstance:
827
+ """Load a dataclass instance from a dictionary.
828
+
829
+ Fields not expected by the dataclass are ignored.
830
+ """
831
+ return datacls(**{k: v for k, v in data.items() if k in datacls.__dataclass_fields__})
env/lib/python3.13/site-packages/huggingface_hub/lfs.py ADDED
@@ -0,0 +1,393 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding=utf-8
2
+ # Copyright 2019-present, the HuggingFace Inc. team.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ """Git LFS related type definitions and utilities"""
16
+
17
+ import io
18
+ import re
19
+ from dataclasses import dataclass
20
+ from math import ceil
21
+ from os.path import getsize
22
+ from typing import TYPE_CHECKING, BinaryIO, Iterable, Optional, TypedDict
23
+ from urllib.parse import unquote
24
+
25
+ from huggingface_hub import constants
26
+
27
+ from .utils import (
28
+ build_hf_headers,
29
+ fix_hf_endpoint_in_url,
30
+ get_session,
31
+ hf_raise_for_status,
32
+ http_backoff,
33
+ logging,
34
+ validate_hf_hub_args,
35
+ )
36
+ from .utils._lfs import SliceFileObj
37
+ from .utils.sha import sha256, sha_fileobj
38
+
39
+
40
+ if TYPE_CHECKING:
41
+ from ._commit_api import CommitOperationAdd
42
+
43
+ logger = logging.get_logger(__name__)
44
+
45
+ OID_REGEX = re.compile(r"^[0-9a-f]{40}$")
46
+
47
+ LFS_MULTIPART_UPLOAD_COMMAND = "lfs-multipart-upload"
48
+
49
+ LFS_HEADERS = {
50
+ "Accept": "application/vnd.git-lfs+json",
51
+ "Content-Type": "application/vnd.git-lfs+json",
52
+ }
53
+
54
+
55
+ @dataclass
56
+ class UploadInfo:
57
+ """
58
+ Dataclass holding required information to determine whether a blob
59
+ should be uploaded to the hub using the LFS protocol or the regular protocol
60
+
61
+ Args:
62
+ sha256 (`bytes`):
63
+ SHA256 hash of the blob
64
+ size (`int`):
65
+ Size in bytes of the blob
66
+ sample (`bytes`):
67
+ First 512 bytes of the blob
68
+ """
69
+
70
+ sha256: bytes
71
+ size: int
72
+ sample: bytes
73
+
74
+ @classmethod
75
+ def from_path(cls, path: str):
76
+ size = getsize(path)
77
+ with io.open(path, "rb") as file:
78
+ sample = file.peek(512)[:512]
79
+ sha = sha_fileobj(file)
80
+ return cls(size=size, sha256=sha, sample=sample)
81
+
82
+ @classmethod
83
+ def from_bytes(cls, data: bytes):
84
+ sha = sha256(data).digest()
85
+ return cls(size=len(data), sample=data[:512], sha256=sha)
86
+
87
+ @classmethod
88
+ def from_fileobj(cls, fileobj: BinaryIO):
89
+ sample = fileobj.read(512)
90
+ fileobj.seek(0, io.SEEK_SET)
91
+ sha = sha_fileobj(fileobj)
92
+ size = fileobj.tell()
93
+ fileobj.seek(0, io.SEEK_SET)
94
+ return cls(size=size, sha256=sha, sample=sample)
95
+
96
+
97
+ @validate_hf_hub_args
98
+ def post_lfs_batch_info(
99
+ upload_infos: Iterable[UploadInfo],
100
+ token: Optional[str],
101
+ repo_type: str,
102
+ repo_id: str,
103
+ revision: Optional[str] = None,
104
+ endpoint: Optional[str] = None,
105
+ headers: Optional[dict[str, str]] = None,
106
+ transfers: Optional[list[str]] = None,
107
+ ) -> tuple[list[dict], list[dict], Optional[str]]:
108
+ """
109
+ Requests the LFS batch endpoint to retrieve upload instructions
110
+
111
+ Learn more: https://github.com/git-lfs/git-lfs/blob/main/docs/api/batch.md
112
+
113
+ Args:
114
+ upload_infos (`Iterable` of `UploadInfo`):
115
+ `UploadInfo` for the files that are being uploaded, typically obtained
116
+ from `CommitOperationAdd.upload_info`
117
+ repo_type (`str`):
118
+ Type of the repo to upload to: `"model"`, `"dataset"` or `"space"`.
119
+ repo_id (`str`):
120
+ A namespace (user or an organization) and a repo name separated
121
+ by a `/`.
122
+ revision (`str`, *optional*):
123
+ The git revision to upload to.
124
+ headers (`dict`, *optional*):
125
+ Additional headers to include in the request
126
+ transfers (`list`, *optional*):
127
+ List of transfer methods to use. Defaults to ["basic", "multipart"].
128
+
129
+ Returns:
130
+ `LfsBatchInfo`: 3-tuple:
131
+ - First element is the list of upload instructions from the server
132
+ - Second element is a list of errors, if any
133
+ - Third element is the chosen transfer adapter if provided by the server (e.g. "basic", "multipart", "xet")
134
+
135
+ Raises:
136
+ [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError)
137
+ If an argument is invalid or the server response is malformed.
138
+ [`HfHubHTTPError`]
139
+ If the server returned an error.
140
+ """
141
+ endpoint = endpoint if endpoint is not None else constants.ENDPOINT
142
+ url_prefix = ""
143
+ if repo_type in constants.REPO_TYPES_URL_PREFIXES:
144
+ url_prefix = constants.REPO_TYPES_URL_PREFIXES[repo_type]
145
+ batch_url = f"{endpoint}/{url_prefix}{repo_id}.git/info/lfs/objects/batch"
146
+ payload: dict = {
147
+ "operation": "upload",
148
+ "transfers": transfers if transfers is not None else ["basic", "multipart"],
149
+ "objects": [
150
+ {
151
+ "oid": upload.sha256.hex(),
152
+ "size": upload.size,
153
+ }
154
+ for upload in upload_infos
155
+ ],
156
+ "hash_algo": "sha256",
157
+ }
158
+ if revision is not None:
159
+ payload["ref"] = {"name": unquote(revision)} # revision has been previously 'quoted'
160
+
161
+ headers = {
162
+ **LFS_HEADERS,
163
+ **build_hf_headers(token=token),
164
+ **(headers or {}),
165
+ }
166
+ resp = get_session().post(batch_url, headers=headers, json=payload)
167
+ hf_raise_for_status(resp)
168
+ batch_info = resp.json()
169
+
170
+ objects = batch_info.get("objects", None)
171
+ if not isinstance(objects, list):
172
+ raise ValueError("Malformed response from server")
173
+
174
+ chosen_transfer = batch_info.get("transfer")
175
+ chosen_transfer = chosen_transfer if isinstance(chosen_transfer, str) else None
176
+
177
+ return (
178
+ [_validate_batch_actions(obj) for obj in objects if "error" not in obj],
179
+ [_validate_batch_error(obj) for obj in objects if "error" in obj],
180
+ chosen_transfer,
181
+ )
182
+
183
+
184
+ class PayloadPartT(TypedDict):
185
+ partNumber: int
186
+ etag: str
187
+
188
+
189
+ class CompletionPayloadT(TypedDict):
190
+ """Payload that will be sent to the Hub when uploading multi-part."""
191
+
192
+ oid: str
193
+ parts: list[PayloadPartT]
194
+
195
+
196
+ def lfs_upload(
197
+ operation: "CommitOperationAdd",
198
+ lfs_batch_action: dict,
199
+ token: Optional[str] = None,
200
+ headers: Optional[dict[str, str]] = None,
201
+ endpoint: Optional[str] = None,
202
+ ) -> None:
203
+ """
204
+ Handles uploading a given object to the Hub with the LFS protocol.
205
+
206
+ Can be a No-op if the content of the file is already present on the hub large file storage.
207
+
208
+ Args:
209
+ operation (`CommitOperationAdd`):
210
+ The add operation triggering this upload.
211
+ lfs_batch_action (`dict`):
212
+ Upload instructions from the LFS batch endpoint for this object. See [`~utils.lfs.post_lfs_batch_info`] for
213
+ more details.
214
+ headers (`dict`, *optional*):
215
+ Headers to include in the request, including authentication and user agent headers.
216
+
217
+ Raises:
218
+ [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError)
219
+ If `lfs_batch_action` is improperly formatted
220
+ [`HfHubHTTPError`]
221
+ If the upload resulted in an error
222
+ """
223
+ # 0. If LFS file is already present, skip upload
224
+ _validate_batch_actions(lfs_batch_action)
225
+ actions = lfs_batch_action.get("actions")
226
+ if actions is None:
227
+ # The file was already uploaded
228
+ logger.debug(f"Content of file {operation.path_in_repo} is already present upstream - skipping upload")
229
+ return
230
+
231
+ # 1. Validate server response (check required keys in dict)
232
+ upload_action = lfs_batch_action["actions"]["upload"]
233
+ _validate_lfs_action(upload_action)
234
+ verify_action = lfs_batch_action["actions"].get("verify")
235
+ if verify_action is not None:
236
+ _validate_lfs_action(verify_action)
237
+
238
+ # 2. Upload file (either single part or multi-part)
239
+ header = upload_action.get("header", {})
240
+ chunk_size = header.get("chunk_size")
241
+ upload_url = fix_hf_endpoint_in_url(upload_action["href"], endpoint=endpoint)
242
+ if chunk_size is not None:
243
+ try:
244
+ chunk_size = int(chunk_size)
245
+ except (ValueError, TypeError):
246
+ raise ValueError(
247
+ f"Malformed response from LFS batch endpoint: `chunk_size` should be an integer. Got '{chunk_size}'."
248
+ )
249
+ _upload_multi_part(operation=operation, header=header, chunk_size=chunk_size, upload_url=upload_url)
250
+ else:
251
+ _upload_single_part(operation=operation, upload_url=upload_url)
252
+
253
+ # 3. Verify upload went well
254
+ if verify_action is not None:
255
+ _validate_lfs_action(verify_action)
256
+ verify_url = fix_hf_endpoint_in_url(verify_action["href"], endpoint)
257
+ verify_resp = get_session().post(
258
+ verify_url,
259
+ headers=build_hf_headers(token=token, headers=headers),
260
+ json={"oid": operation.upload_info.sha256.hex(), "size": operation.upload_info.size},
261
+ )
262
+ hf_raise_for_status(verify_resp)
263
+ logger.debug(f"{operation.path_in_repo}: Upload successful")
264
+
265
+
266
+ def _validate_lfs_action(lfs_action: dict):
267
+ """validates response from the LFS batch endpoint"""
268
+ if not (
269
+ isinstance(lfs_action.get("href"), str)
270
+ and (lfs_action.get("header") is None or isinstance(lfs_action.get("header"), dict))
271
+ ):
272
+ raise ValueError("lfs_action is improperly formatted")
273
+ return lfs_action
274
+
275
+
276
+ def _validate_batch_actions(lfs_batch_actions: dict):
277
+ """validates response from the LFS batch endpoint"""
278
+ if not (isinstance(lfs_batch_actions.get("oid"), str) and isinstance(lfs_batch_actions.get("size"), int)):
279
+ raise ValueError("lfs_batch_actions is improperly formatted")
280
+
281
+ upload_action = lfs_batch_actions.get("actions", {}).get("upload")
282
+ verify_action = lfs_batch_actions.get("actions", {}).get("verify")
283
+ if upload_action is not None:
284
+ _validate_lfs_action(upload_action)
285
+ if verify_action is not None:
286
+ _validate_lfs_action(verify_action)
287
+ return lfs_batch_actions
288
+
289
+
290
+ def _validate_batch_error(lfs_batch_error: dict):
291
+ """validates response from the LFS batch endpoint"""
292
+ if not (isinstance(lfs_batch_error.get("oid"), str) and isinstance(lfs_batch_error.get("size"), int)):
293
+ raise ValueError("lfs_batch_error is improperly formatted")
294
+ error_info = lfs_batch_error.get("error")
295
+ if not (
296
+ isinstance(error_info, dict)
297
+ and isinstance(error_info.get("message"), str)
298
+ and isinstance(error_info.get("code"), int)
299
+ ):
300
+ raise ValueError("lfs_batch_error is improperly formatted")
301
+ return lfs_batch_error
302
+
303
+
304
+ def _upload_single_part(operation: "CommitOperationAdd", upload_url: str) -> None:
305
+ """
306
+ Uploads `fileobj` as a single PUT HTTP request (basic LFS transfer protocol)
307
+
308
+ Args:
309
+ upload_url (`str`):
310
+ The URL to PUT the file to.
311
+ fileobj:
312
+ The file-like object holding the data to upload.
313
+
314
+ Raises:
315
+ [`HfHubHTTPError`]
316
+ If the upload resulted in an error.
317
+ """
318
+ with operation.as_file(with_tqdm=True) as fileobj:
319
+ # S3 might raise a transient 500 error -> let's retry if that happens
320
+ response = http_backoff("PUT", upload_url, data=fileobj)
321
+ hf_raise_for_status(response)
322
+
323
+
324
+ def _upload_multi_part(operation: "CommitOperationAdd", header: dict, chunk_size: int, upload_url: str) -> None:
325
+ """
326
+ Uploads file using HF multipart LFS transfer protocol.
327
+ """
328
+ # 1. Get upload URLs for each part
329
+ sorted_parts_urls = _get_sorted_parts_urls(header=header, upload_info=operation.upload_info, chunk_size=chunk_size)
330
+
331
+ # 2. Upload parts (pure Python)
332
+ response_headers = _upload_parts_iteratively(
333
+ operation=operation, sorted_parts_urls=sorted_parts_urls, chunk_size=chunk_size
334
+ )
335
+
336
+ # 3. Send completion request
337
+ completion_res = get_session().post(
338
+ upload_url,
339
+ json=_get_completion_payload(response_headers, operation.upload_info.sha256.hex()),
340
+ headers=LFS_HEADERS,
341
+ )
342
+ hf_raise_for_status(completion_res)
343
+
344
+
345
+ def _get_sorted_parts_urls(header: dict, upload_info: UploadInfo, chunk_size: int) -> list[str]:
346
+ sorted_part_upload_urls = [
347
+ upload_url
348
+ for _, upload_url in sorted(
349
+ [
350
+ (int(part_num, 10), upload_url)
351
+ for part_num, upload_url in header.items()
352
+ if part_num.isdigit() and len(part_num) > 0
353
+ ],
354
+ key=lambda t: t[0],
355
+ )
356
+ ]
357
+ num_parts = len(sorted_part_upload_urls)
358
+ if num_parts != ceil(upload_info.size / chunk_size):
359
+ raise ValueError("Invalid server response to upload large LFS file")
360
+ return sorted_part_upload_urls
361
+
362
+
363
+ def _get_completion_payload(response_headers: list[dict], oid: str) -> CompletionPayloadT:
364
+ parts: list[PayloadPartT] = []
365
+ for part_number, header in enumerate(response_headers):
366
+ etag = header.get("etag")
367
+ if etag is None or etag == "":
368
+ raise ValueError(f"Invalid etag (`{etag}`) returned for part {part_number + 1}")
369
+ parts.append(
370
+ {
371
+ "partNumber": part_number + 1,
372
+ "etag": etag,
373
+ }
374
+ )
375
+ return {"oid": oid, "parts": parts}
376
+
377
+
378
+ def _upload_parts_iteratively(
379
+ operation: "CommitOperationAdd", sorted_parts_urls: list[str], chunk_size: int
380
+ ) -> list[dict]:
381
+ headers = []
382
+ with operation.as_file(with_tqdm=True) as fileobj:
383
+ for part_idx, part_upload_url in enumerate(sorted_parts_urls):
384
+ with SliceFileObj(
385
+ fileobj,
386
+ seek_from=chunk_size * part_idx,
387
+ read_limit=chunk_size,
388
+ ) as fileobj_slice:
389
+ # S3 might raise a transient 500 error -> let's retry if that happens
390
+ part_upload_res = http_backoff("PUT", part_upload_url, data=fileobj_slice)
391
+ hf_raise_for_status(part_upload_res)
392
+ headers.append(part_upload_res.headers)
393
+ return headers # type: ignore
env/lib/python3.13/site-packages/huggingface_hub/py.typed ADDED
File without changes
env/lib/python3.13/site-packages/huggingface_hub/repocard_data.py ADDED
@@ -0,0 +1,770 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import copy
2
+ from collections import defaultdict
3
+ from dataclasses import dataclass
4
+ from typing import Any, Optional, Union
5
+
6
+ from huggingface_hub.utils import logging, yaml_dump
7
+
8
+
9
+ logger = logging.get_logger(__name__)
10
+
11
+
12
+ @dataclass
13
+ class EvalResult:
14
+ """
15
+ Flattened representation of individual evaluation results found in model-index of Model Cards.
16
+
17
+ For more information on the model-index spec, see https://github.com/huggingface/hub-docs/blob/main/modelcard.md?plain=1.
18
+
19
+ Args:
20
+ task_type (`str`):
21
+ The task identifier. Example: "image-classification".
22
+ dataset_type (`str`):
23
+ The dataset identifier. Example: "common_voice". Use dataset id from https://hf.co/datasets.
24
+ dataset_name (`str`):
25
+ A pretty name for the dataset. Example: "Common Voice (French)".
26
+ metric_type (`str`):
27
+ The metric identifier. Example: "wer". Use metric id from https://hf.co/metrics.
28
+ metric_value (`Any`):
29
+ The metric value. Example: 0.9 or "20.0 ± 1.2".
30
+ task_name (`str`, *optional*):
31
+ A pretty name for the task. Example: "Speech Recognition".
32
+ dataset_config (`str`, *optional*):
33
+ The name of the dataset configuration used in `load_dataset()`.
34
+ Example: fr in `load_dataset("common_voice", "fr")`. See the `datasets` docs for more info:
35
+ https://hf.co/docs/datasets/package_reference/loading_methods#datasets.load_dataset.name
36
+ dataset_split (`str`, *optional*):
37
+ The split used in `load_dataset()`. Example: "test".
38
+ dataset_revision (`str`, *optional*):
39
+ The revision (AKA Git Sha) of the dataset used in `load_dataset()`.
40
+ Example: 5503434ddd753f426f4b38109466949a1217c2bb
41
+ dataset_args (`dict[str, Any]`, *optional*):
42
+ The arguments passed during `Metric.compute()`. Example for `bleu`: `{"max_order": 4}`
43
+ metric_name (`str`, *optional*):
44
+ A pretty name for the metric. Example: "Test WER".
45
+ metric_config (`str`, *optional*):
46
+ The name of the metric configuration used in `load_metric()`.
47
+ Example: bleurt-large-512 in `load_metric("bleurt", "bleurt-large-512")`.
48
+ See the `datasets` docs for more info: https://huggingface.co/docs/datasets/v2.1.0/en/loading#load-configurations
49
+ metric_args (`dict[str, Any]`, *optional*):
50
+ The arguments passed during `Metric.compute()`. Example for `bleu`: max_order: 4
51
+ verified (`bool`, *optional*):
52
+ Indicates whether the metrics originate from Hugging Face's [evaluation service](https://huggingface.co/spaces/autoevaluate/model-evaluator) or not. Automatically computed by Hugging Face, do not set.
53
+ verify_token (`str`, *optional*):
54
+ A JSON Web Token that is used to verify whether the metrics originate from Hugging Face's [evaluation service](https://huggingface.co/spaces/autoevaluate/model-evaluator) or not.
55
+ source_name (`str`, *optional*):
56
+ The name of the source of the evaluation result. Example: "Open LLM Leaderboard".
57
+ source_url (`str`, *optional*):
58
+ The URL of the source of the evaluation result. Example: "https://huggingface.co/spaces/open-llm-leaderboard/open_llm_leaderboard".
59
+ """
60
+
61
+ # Required
62
+
63
+ # The task identifier
64
+ # Example: automatic-speech-recognition
65
+ task_type: str
66
+
67
+ # The dataset identifier
68
+ # Example: common_voice. Use dataset id from https://hf.co/datasets
69
+ dataset_type: str
70
+
71
+ # A pretty name for the dataset.
72
+ # Example: Common Voice (French)
73
+ dataset_name: str
74
+
75
+ # The metric identifier
76
+ # Example: wer. Use metric id from https://hf.co/metrics
77
+ metric_type: str
78
+
79
+ # Value of the metric.
80
+ # Example: 20.0 or "20.0 ± 1.2"
81
+ metric_value: Any
82
+
83
+ # Optional
84
+
85
+ # A pretty name for the task.
86
+ # Example: Speech Recognition
87
+ task_name: Optional[str] = None
88
+
89
+ # The name of the dataset configuration used in `load_dataset()`.
90
+ # Example: fr in `load_dataset("common_voice", "fr")`.
91
+ # See the `datasets` docs for more info:
92
+ # https://huggingface.co/docs/datasets/package_reference/loading_methods#datasets.load_dataset.name
93
+ dataset_config: Optional[str] = None
94
+
95
+ # The split used in `load_dataset()`.
96
+ # Example: test
97
+ dataset_split: Optional[str] = None
98
+
99
+ # The revision (AKA Git Sha) of the dataset used in `load_dataset()`.
100
+ # Example: 5503434ddd753f426f4b38109466949a1217c2bb
101
+ dataset_revision: Optional[str] = None
102
+
103
+ # The arguments passed during `Metric.compute()`.
104
+ # Example for `bleu`: max_order: 4
105
+ dataset_args: Optional[dict[str, Any]] = None
106
+
107
+ # A pretty name for the metric.
108
+ # Example: Test WER
109
+ metric_name: Optional[str] = None
110
+
111
+ # The name of the metric configuration used in `load_metric()`.
112
+ # Example: bleurt-large-512 in `load_metric("bleurt", "bleurt-large-512")`.
113
+ # See the `datasets` docs for more info: https://huggingface.co/docs/datasets/v2.1.0/en/loading#load-configurations
114
+ metric_config: Optional[str] = None
115
+
116
+ # The arguments passed during `Metric.compute()`.
117
+ # Example for `bleu`: max_order: 4
118
+ metric_args: Optional[dict[str, Any]] = None
119
+
120
+ # Indicates whether the metrics originate from Hugging Face's [evaluation service](https://huggingface.co/spaces/autoevaluate/model-evaluator) or not. Automatically computed by Hugging Face, do not set.
121
+ verified: Optional[bool] = None
122
+
123
+ # A JSON Web Token that is used to verify whether the metrics originate from Hugging Face's [evaluation service](https://huggingface.co/spaces/autoevaluate/model-evaluator) or not.
124
+ verify_token: Optional[str] = None
125
+
126
+ # The name of the source of the evaluation result.
127
+ # Example: Open LLM Leaderboard
128
+ source_name: Optional[str] = None
129
+
130
+ # The URL of the source of the evaluation result.
131
+ # Example: https://huggingface.co/spaces/open-llm-leaderboard/open_llm_leaderboard
132
+ source_url: Optional[str] = None
133
+
134
+ @property
135
+ def unique_identifier(self) -> tuple:
136
+ """Returns a tuple that uniquely identifies this evaluation."""
137
+ return (
138
+ self.task_type,
139
+ self.dataset_type,
140
+ self.dataset_config,
141
+ self.dataset_split,
142
+ self.dataset_revision,
143
+ )
144
+
145
+ def is_equal_except_value(self, other: "EvalResult") -> bool:
146
+ """
147
+ Return True if `self` and `other` describe exactly the same metric but with a
148
+ different value.
149
+ """
150
+ for key, _ in self.__dict__.items():
151
+ if key == "metric_value":
152
+ continue
153
+ # For metrics computed by Hugging Face's evaluation service, `verify_token` is derived from `metric_value`,
154
+ # so we exclude it here in the comparison.
155
+ if key != "verify_token" and getattr(self, key) != getattr(other, key):
156
+ return False
157
+ return True
158
+
159
+ def __post_init__(self) -> None:
160
+ if self.source_name is not None and self.source_url is None:
161
+ raise ValueError("If `source_name` is provided, `source_url` must also be provided.")
162
+
163
+
164
+ @dataclass
165
+ class CardData:
166
+ """Structure containing metadata from a RepoCard.
167
+
168
+ [`CardData`] is the parent class of [`ModelCardData`] and [`DatasetCardData`].
169
+
170
+ Metadata can be exported as a dictionary or YAML. Export can be customized to alter the representation of the data
171
+ (example: flatten evaluation results). `CardData` behaves as a dictionary (can get, pop, set values) but do not
172
+ inherit from `dict` to allow this export step.
173
+ """
174
+
175
+ def __init__(self, ignore_metadata_errors: bool = False, **kwargs):
176
+ self.__dict__.update(kwargs)
177
+
178
+ def to_dict(self):
179
+ """Converts CardData to a dict.
180
+
181
+ Returns:
182
+ `dict`: CardData represented as a dictionary ready to be dumped to a YAML
183
+ block for inclusion in a README.md file.
184
+ """
185
+
186
+ data_dict = copy.deepcopy(self.__dict__)
187
+ self._to_dict(data_dict)
188
+ return {key: value for key, value in data_dict.items() if value is not None}
189
+
190
+ def _to_dict(self, data_dict):
191
+ """Use this method in child classes to alter the dict representation of the data. Alter the dict in-place.
192
+
193
+ Args:
194
+ data_dict (`dict`): The raw dict representation of the card data.
195
+ """
196
+ pass
197
+
198
+ def to_yaml(self, line_break=None, original_order: Optional[list[str]] = None) -> str:
199
+ """Dumps CardData to a YAML block for inclusion in a README.md file.
200
+
201
+ Args:
202
+ line_break (str, *optional*):
203
+ The line break to use when dumping to yaml.
204
+
205
+ Returns:
206
+ `str`: CardData represented as a YAML block.
207
+ """
208
+ if original_order:
209
+ self.__dict__ = {
210
+ k: self.__dict__[k]
211
+ for k in original_order + list(set(self.__dict__.keys()) - set(original_order))
212
+ if k in self.__dict__
213
+ }
214
+ return yaml_dump(self.to_dict(), sort_keys=False, line_break=line_break).strip()
215
+
216
+ def __repr__(self):
217
+ return repr(self.__dict__)
218
+
219
+ def __str__(self):
220
+ return self.to_yaml()
221
+
222
+ def get(self, key: str, default: Any = None) -> Any:
223
+ """Get value for a given metadata key."""
224
+ value = self.__dict__.get(key)
225
+ return default if value is None else value
226
+
227
+ def pop(self, key: str, default: Any = None) -> Any:
228
+ """Pop value for a given metadata key."""
229
+ return self.__dict__.pop(key, default)
230
+
231
+ def __getitem__(self, key: str) -> Any:
232
+ """Get value for a given metadata key."""
233
+ return self.__dict__[key]
234
+
235
+ def __setitem__(self, key: str, value: Any) -> None:
236
+ """Set value for a given metadata key."""
237
+ self.__dict__[key] = value
238
+
239
+ def __contains__(self, key: str) -> bool:
240
+ """Check if a given metadata key is set."""
241
+ return key in self.__dict__
242
+
243
+ def __len__(self) -> int:
244
+ """Return the number of metadata keys set."""
245
+ return len(self.__dict__)
246
+
247
+
248
+ def _validate_eval_results(
249
+ eval_results: Optional[Union[EvalResult, list[EvalResult]]],
250
+ model_name: Optional[str],
251
+ ) -> list[EvalResult]:
252
+ if eval_results is None:
253
+ return []
254
+ if isinstance(eval_results, EvalResult):
255
+ eval_results = [eval_results]
256
+ if not isinstance(eval_results, list) or not all(isinstance(r, EvalResult) for r in eval_results):
257
+ raise ValueError(
258
+ f"`eval_results` should be of type `EvalResult` or a list of `EvalResult`, got {type(eval_results)}."
259
+ )
260
+ if model_name is None:
261
+ raise ValueError("Passing `eval_results` requires `model_name` to be set.")
262
+ return eval_results
263
+
264
+
265
+ class ModelCardData(CardData):
266
+ """Model Card Metadata that is used by Hugging Face Hub when included at the top of your README.md
267
+
268
+ Args:
269
+ base_model (`str` or `list[str]`, *optional*):
270
+ The identifier of the base model from which the model derives. This is applicable for example if your model is a
271
+ fine-tune or adapter of an existing model. The value must be the ID of a model on the Hub (or a list of IDs
272
+ if your model derives from multiple models). Defaults to None.
273
+ datasets (`Union[str, list[str]]`, *optional*):
274
+ Dataset or list of datasets that were used to train this model. Should be a dataset ID
275
+ found on https://hf.co/datasets. Defaults to None.
276
+ eval_results (`Union[list[EvalResult], EvalResult]`, *optional*):
277
+ List of `huggingface_hub.EvalResult` that define evaluation results of the model. If provided,
278
+ `model_name` is used to as a name on PapersWithCode's leaderboards. Defaults to `None`.
279
+ language (`Union[str, list[str]]`, *optional*):
280
+ Language of model's training data or metadata. It must be an ISO 639-1, 639-2 or
281
+ 639-3 code (two/three letters), or a special value like "code", "multilingual". Defaults to `None`.
282
+ library_name (`str`, *optional*):
283
+ Name of library used by this model. Example: keras or any library from
284
+ https://github.com/huggingface/huggingface.js/blob/main/packages/tasks/src/model-libraries.ts.
285
+ Defaults to None.
286
+ license (`str`, *optional*):
287
+ License of this model. Example: apache-2.0 or any license from
288
+ https://huggingface.co/docs/hub/repositories-licenses. Defaults to None.
289
+ license_name (`str`, *optional*):
290
+ Name of the license of this model. Defaults to None. To be used in conjunction with `license_link`.
291
+ Common licenses (Apache-2.0, MIT, CC-BY-SA-4.0) do not need a name. In that case, use `license` instead.
292
+ license_link (`str`, *optional*):
293
+ Link to the license of this model. Defaults to None. To be used in conjunction with `license_name`.
294
+ Common licenses (Apache-2.0, MIT, CC-BY-SA-4.0) do not need a link. In that case, use `license` instead.
295
+ metrics (`list[str]`, *optional*):
296
+ List of metrics used to evaluate this model. Should be a metric name that can be found
297
+ at https://hf.co/metrics. Example: 'accuracy'. Defaults to None.
298
+ model_name (`str`, *optional*):
299
+ A name for this model. It is used along with
300
+ `eval_results` to construct the `model-index` within the card's metadata. The name
301
+ you supply here is what will be used on PapersWithCode's leaderboards. If None is provided
302
+ then the repo name is used as a default. Defaults to None.
303
+ pipeline_tag (`str`, *optional*):
304
+ The pipeline tag associated with the model. Example: "text-classification".
305
+ tags (`list[str]`, *optional*):
306
+ List of tags to add to your model that can be used when filtering on the Hugging
307
+ Face Hub. Defaults to None.
308
+ ignore_metadata_errors (`str`):
309
+ If True, errors while parsing the metadata section will be ignored. Some information might be lost during
310
+ the process. Use it at your own risk.
311
+ kwargs (`dict`, *optional*):
312
+ Additional metadata that will be added to the model card. Defaults to None.
313
+
314
+ Example:
315
+ ```python
316
+ >>> from huggingface_hub import ModelCardData
317
+ >>> card_data = ModelCardData(
318
+ ... language="en",
319
+ ... license="mit",
320
+ ... library_name="timm",
321
+ ... tags=['image-classification', 'resnet'],
322
+ ... )
323
+ >>> card_data.to_dict()
324
+ {'language': 'en', 'license': 'mit', 'library_name': 'timm', 'tags': ['image-classification', 'resnet']}
325
+
326
+ ```
327
+ """
328
+
329
+ def __init__(
330
+ self,
331
+ *,
332
+ base_model: Optional[Union[str, list[str]]] = None,
333
+ datasets: Optional[Union[str, list[str]]] = None,
334
+ eval_results: Optional[list[EvalResult]] = None,
335
+ language: Optional[Union[str, list[str]]] = None,
336
+ library_name: Optional[str] = None,
337
+ license: Optional[str] = None,
338
+ license_name: Optional[str] = None,
339
+ license_link: Optional[str] = None,
340
+ metrics: Optional[list[str]] = None,
341
+ model_name: Optional[str] = None,
342
+ pipeline_tag: Optional[str] = None,
343
+ tags: Optional[list[str]] = None,
344
+ ignore_metadata_errors: bool = False,
345
+ **kwargs,
346
+ ):
347
+ self.base_model = base_model
348
+ self.datasets = datasets
349
+ self.eval_results = eval_results
350
+ self.language = language
351
+ self.library_name = library_name
352
+ self.license = license
353
+ self.license_name = license_name
354
+ self.license_link = license_link
355
+ self.metrics = metrics
356
+ self.model_name = model_name
357
+ self.pipeline_tag = pipeline_tag
358
+ self.tags = _to_unique_list(tags)
359
+
360
+ model_index = kwargs.pop("model-index", None)
361
+ if model_index:
362
+ try:
363
+ model_name, eval_results = model_index_to_eval_results(model_index)
364
+ self.model_name = model_name
365
+ self.eval_results = eval_results
366
+ except (KeyError, TypeError) as error:
367
+ if ignore_metadata_errors:
368
+ logger.warning("Invalid model-index. Not loading eval results into CardData.")
369
+ else:
370
+ raise ValueError(
371
+ f"Invalid `model_index` in metadata cannot be parsed: {error.__class__} {error}. Pass"
372
+ " `ignore_metadata_errors=True` to ignore this error while loading a Model Card. Warning:"
373
+ " some information will be lost. Use it at your own risk."
374
+ )
375
+
376
+ super().__init__(**kwargs)
377
+
378
+ if self.eval_results:
379
+ try:
380
+ self.eval_results = _validate_eval_results(self.eval_results, self.model_name)
381
+ except Exception as e:
382
+ if ignore_metadata_errors:
383
+ logger.warning(f"Failed to validate eval_results: {e}. Not loading eval results into CardData.")
384
+ else:
385
+ raise ValueError(f"Failed to validate eval_results: {e}") from e
386
+
387
+ def _to_dict(self, data_dict):
388
+ """Format the internal data dict. In this case, we convert eval results to a valid model index"""
389
+ if self.eval_results is not None:
390
+ data_dict["model-index"] = eval_results_to_model_index(self.model_name, self.eval_results) # type: ignore
391
+ del data_dict["eval_results"], data_dict["model_name"]
392
+
393
+
394
+ class DatasetCardData(CardData):
395
+ """Dataset Card Metadata that is used by Hugging Face Hub when included at the top of your README.md
396
+
397
+ Args:
398
+ language (`list[str]`, *optional*):
399
+ Language of dataset's data or metadata. It must be an ISO 639-1, 639-2 or
400
+ 639-3 code (two/three letters), or a special value like "code", "multilingual".
401
+ license (`Union[str, list[str]]`, *optional*):
402
+ License(s) of this dataset. Example: apache-2.0 or any license from
403
+ https://huggingface.co/docs/hub/repositories-licenses.
404
+ annotations_creators (`Union[str, list[str]]`, *optional*):
405
+ How the annotations for the dataset were created.
406
+ Options are: 'found', 'crowdsourced', 'expert-generated', 'machine-generated', 'no-annotation', 'other'.
407
+ language_creators (`Union[str, list[str]]`, *optional*):
408
+ How the text-based data in the dataset was created.
409
+ Options are: 'found', 'crowdsourced', 'expert-generated', 'machine-generated', 'other'
410
+ multilinguality (`Union[str, list[str]]`, *optional*):
411
+ Whether the dataset is multilingual.
412
+ Options are: 'monolingual', 'multilingual', 'translation', 'other'.
413
+ size_categories (`Union[str, list[str]]`, *optional*):
414
+ The number of examples in the dataset. Options are: 'n<1K', '1K<n<10K', '10K<n<100K',
415
+ '100K<n<1M', '1M<n<10M', '10M<n<100M', '100M<n<1B', '1B<n<10B', '10B<n<100B', '100B<n<1T', 'n>1T', and 'other'.
416
+ source_datasets (`list[str]]`, *optional*):
417
+ Indicates whether the dataset is an original dataset or extended from another existing dataset.
418
+ Options are: 'original' and 'extended'.
419
+ task_categories (`Union[str, list[str]]`, *optional*):
420
+ What categories of task does the dataset support?
421
+ task_ids (`Union[str, list[str]]`, *optional*):
422
+ What specific tasks does the dataset support?
423
+ paperswithcode_id (`str`, *optional*):
424
+ ID of the dataset on PapersWithCode.
425
+ pretty_name (`str`, *optional*):
426
+ A more human-readable name for the dataset. (ex. "Cats vs. Dogs")
427
+ train_eval_index (`dict`, *optional*):
428
+ A dictionary that describes the necessary spec for doing evaluation on the Hub.
429
+ If not provided, it will be gathered from the 'train-eval-index' key of the kwargs.
430
+ config_names (`Union[str, list[str]]`, *optional*):
431
+ A list of the available dataset configs for the dataset.
432
+ """
433
+
434
+ def __init__(
435
+ self,
436
+ *,
437
+ language: Optional[Union[str, list[str]]] = None,
438
+ license: Optional[Union[str, list[str]]] = None,
439
+ annotations_creators: Optional[Union[str, list[str]]] = None,
440
+ language_creators: Optional[Union[str, list[str]]] = None,
441
+ multilinguality: Optional[Union[str, list[str]]] = None,
442
+ size_categories: Optional[Union[str, list[str]]] = None,
443
+ source_datasets: Optional[list[str]] = None,
444
+ task_categories: Optional[Union[str, list[str]]] = None,
445
+ task_ids: Optional[Union[str, list[str]]] = None,
446
+ paperswithcode_id: Optional[str] = None,
447
+ pretty_name: Optional[str] = None,
448
+ train_eval_index: Optional[dict] = None,
449
+ config_names: Optional[Union[str, list[str]]] = None,
450
+ ignore_metadata_errors: bool = False,
451
+ **kwargs,
452
+ ):
453
+ self.annotations_creators = annotations_creators
454
+ self.language_creators = language_creators
455
+ self.language = language
456
+ self.license = license
457
+ self.multilinguality = multilinguality
458
+ self.size_categories = size_categories
459
+ self.source_datasets = source_datasets
460
+ self.task_categories = task_categories
461
+ self.task_ids = task_ids
462
+ self.paperswithcode_id = paperswithcode_id
463
+ self.pretty_name = pretty_name
464
+ self.config_names = config_names
465
+
466
+ # TODO - maybe handle this similarly to EvalResult?
467
+ self.train_eval_index = train_eval_index or kwargs.pop("train-eval-index", None)
468
+ super().__init__(**kwargs)
469
+
470
+ def _to_dict(self, data_dict):
471
+ data_dict["train-eval-index"] = data_dict.pop("train_eval_index")
472
+
473
+
474
+ class SpaceCardData(CardData):
475
+ """Space Card Metadata that is used by Hugging Face Hub when included at the top of your README.md
476
+
477
+ To get an exhaustive reference of Spaces configuration, please visit https://huggingface.co/docs/hub/spaces-config-reference#spaces-configuration-reference.
478
+
479
+ Args:
480
+ title (`str`, *optional*)
481
+ Title of the Space.
482
+ sdk (`str`, *optional*)
483
+ SDK of the Space (one of `gradio`, `streamlit`, `docker`, or `static`).
484
+ sdk_version (`str`, *optional*)
485
+ Version of the used SDK (if Gradio/Streamlit sdk).
486
+ python_version (`str`, *optional*)
487
+ Python version used in the Space (if Gradio/Streamlit sdk).
488
+ app_file (`str`, *optional*)
489
+ Path to your main application file (which contains either gradio or streamlit Python code, or static html code).
490
+ Path is relative to the root of the repository.
491
+ app_port (`str`, *optional*)
492
+ Port on which your application is running. Used only if sdk is `docker`.
493
+ license (`str`, *optional*)
494
+ License of this model. Example: apache-2.0 or any license from
495
+ https://huggingface.co/docs/hub/repositories-licenses.
496
+ duplicated_from (`str`, *optional*)
497
+ ID of the original Space if this is a duplicated Space.
498
+ models (list[`str`], *optional*)
499
+ List of models related to this Space. Should be a dataset ID found on https://hf.co/models.
500
+ datasets (`list[str]`, *optional*)
501
+ List of datasets related to this Space. Should be a dataset ID found on https://hf.co/datasets.
502
+ tags (`list[str]`, *optional*)
503
+ List of tags to add to your Space that can be used when filtering on the Hub.
504
+ ignore_metadata_errors (`str`):
505
+ If True, errors while parsing the metadata section will be ignored. Some information might be lost during
506
+ the process. Use it at your own risk.
507
+ kwargs (`dict`, *optional*):
508
+ Additional metadata that will be added to the space card.
509
+
510
+ Example:
511
+ ```python
512
+ >>> from huggingface_hub import SpaceCardData
513
+ >>> card_data = SpaceCardData(
514
+ ... title="Dreambooth Training",
515
+ ... license="mit",
516
+ ... sdk="gradio",
517
+ ... duplicated_from="multimodalart/dreambooth-training"
518
+ ... )
519
+ >>> card_data.to_dict()
520
+ {'title': 'Dreambooth Training', 'sdk': 'gradio', 'license': 'mit', 'duplicated_from': 'multimodalart/dreambooth-training'}
521
+ ```
522
+ """
523
+
524
+ def __init__(
525
+ self,
526
+ *,
527
+ title: Optional[str] = None,
528
+ sdk: Optional[str] = None,
529
+ sdk_version: Optional[str] = None,
530
+ python_version: Optional[str] = None,
531
+ app_file: Optional[str] = None,
532
+ app_port: Optional[int] = None,
533
+ license: Optional[str] = None,
534
+ duplicated_from: Optional[str] = None,
535
+ models: Optional[list[str]] = None,
536
+ datasets: Optional[list[str]] = None,
537
+ tags: Optional[list[str]] = None,
538
+ ignore_metadata_errors: bool = False,
539
+ **kwargs,
540
+ ):
541
+ self.title = title
542
+ self.sdk = sdk
543
+ self.sdk_version = sdk_version
544
+ self.python_version = python_version
545
+ self.app_file = app_file
546
+ self.app_port = app_port
547
+ self.license = license
548
+ self.duplicated_from = duplicated_from
549
+ self.models = models
550
+ self.datasets = datasets
551
+ self.tags = _to_unique_list(tags)
552
+ super().__init__(**kwargs)
553
+
554
+
555
+ def model_index_to_eval_results(model_index: list[dict[str, Any]]) -> tuple[str, list[EvalResult]]:
556
+ """Takes in a model index and returns the model name and a list of `huggingface_hub.EvalResult` objects.
557
+
558
+ A detailed spec of the model index can be found here:
559
+ https://github.com/huggingface/hub-docs/blob/main/modelcard.md?plain=1
560
+
561
+ Args:
562
+ model_index (`list[dict[str, Any]]`):
563
+ A model index data structure, likely coming from a README.md file on the
564
+ Hugging Face Hub.
565
+
566
+ Returns:
567
+ model_name (`str`):
568
+ The name of the model as found in the model index. This is used as the
569
+ identifier for the model on leaderboards like PapersWithCode.
570
+ eval_results (`list[EvalResult]`):
571
+ A list of `huggingface_hub.EvalResult` objects containing the metrics
572
+ reported in the provided model_index.
573
+
574
+ Example:
575
+ ```python
576
+ >>> from huggingface_hub.repocard_data import model_index_to_eval_results
577
+ >>> # Define a minimal model index
578
+ >>> model_index = [
579
+ ... {
580
+ ... "name": "my-cool-model",
581
+ ... "results": [
582
+ ... {
583
+ ... "task": {
584
+ ... "type": "image-classification"
585
+ ... },
586
+ ... "dataset": {
587
+ ... "type": "beans",
588
+ ... "name": "Beans"
589
+ ... },
590
+ ... "metrics": [
591
+ ... {
592
+ ... "type": "accuracy",
593
+ ... "value": 0.9
594
+ ... }
595
+ ... ]
596
+ ... }
597
+ ... ]
598
+ ... }
599
+ ... ]
600
+ >>> model_name, eval_results = model_index_to_eval_results(model_index)
601
+ >>> model_name
602
+ 'my-cool-model'
603
+ >>> eval_results[0].task_type
604
+ 'image-classification'
605
+ >>> eval_results[0].metric_type
606
+ 'accuracy'
607
+
608
+ ```
609
+ """
610
+
611
+ eval_results = []
612
+ for elem in model_index:
613
+ name = elem["name"]
614
+ results = elem["results"]
615
+ for result in results:
616
+ task_type = result["task"]["type"]
617
+ task_name = result["task"].get("name")
618
+ dataset_type = result["dataset"]["type"]
619
+ dataset_name = result["dataset"]["name"]
620
+ dataset_config = result["dataset"].get("config")
621
+ dataset_split = result["dataset"].get("split")
622
+ dataset_revision = result["dataset"].get("revision")
623
+ dataset_args = result["dataset"].get("args")
624
+ source_name = result.get("source", {}).get("name")
625
+ source_url = result.get("source", {}).get("url")
626
+
627
+ for metric in result["metrics"]:
628
+ metric_type = metric["type"]
629
+ metric_value = metric["value"]
630
+ metric_name = metric.get("name")
631
+ metric_args = metric.get("args")
632
+ metric_config = metric.get("config")
633
+ verified = metric.get("verified")
634
+ verify_token = metric.get("verifyToken")
635
+
636
+ eval_result = EvalResult(
637
+ task_type=task_type, # Required
638
+ dataset_type=dataset_type, # Required
639
+ dataset_name=dataset_name, # Required
640
+ metric_type=metric_type, # Required
641
+ metric_value=metric_value, # Required
642
+ task_name=task_name,
643
+ dataset_config=dataset_config,
644
+ dataset_split=dataset_split,
645
+ dataset_revision=dataset_revision,
646
+ dataset_args=dataset_args,
647
+ metric_name=metric_name,
648
+ metric_args=metric_args,
649
+ metric_config=metric_config,
650
+ verified=verified,
651
+ verify_token=verify_token,
652
+ source_name=source_name,
653
+ source_url=source_url,
654
+ )
655
+ eval_results.append(eval_result)
656
+ return name, eval_results
657
+
658
+
659
+ def _remove_none(obj):
660
+ """
661
+ Recursively remove `None` values from a dict. Borrowed from: https://stackoverflow.com/a/20558778
662
+ """
663
+ if isinstance(obj, (list, tuple, set)):
664
+ return type(obj)(_remove_none(x) for x in obj if x is not None)
665
+ elif isinstance(obj, dict):
666
+ return type(obj)((_remove_none(k), _remove_none(v)) for k, v in obj.items() if k is not None and v is not None)
667
+ else:
668
+ return obj
669
+
670
+
671
+ def eval_results_to_model_index(model_name: str, eval_results: list[EvalResult]) -> list[dict[str, Any]]:
672
+ """Takes in given model name and list of `huggingface_hub.EvalResult` and returns a
673
+ valid model-index that will be compatible with the format expected by the
674
+ Hugging Face Hub.
675
+
676
+ Args:
677
+ model_name (`str`):
678
+ Name of the model (ex. "my-cool-model"). This is used as the identifier
679
+ for the model on leaderboards like PapersWithCode.
680
+ eval_results (`list[EvalResult]`):
681
+ List of `huggingface_hub.EvalResult` objects containing the metrics to be
682
+ reported in the model-index.
683
+
684
+ Returns:
685
+ model_index (`list[dict[str, Any]]`): The eval_results converted to a model-index.
686
+
687
+ Example:
688
+ ```python
689
+ >>> from huggingface_hub.repocard_data import eval_results_to_model_index, EvalResult
690
+ >>> # Define minimal eval_results
691
+ >>> eval_results = [
692
+ ... EvalResult(
693
+ ... task_type="image-classification", # Required
694
+ ... dataset_type="beans", # Required
695
+ ... dataset_name="Beans", # Required
696
+ ... metric_type="accuracy", # Required
697
+ ... metric_value=0.9, # Required
698
+ ... )
699
+ ... ]
700
+ >>> eval_results_to_model_index("my-cool-model", eval_results)
701
+ [{'name': 'my-cool-model', 'results': [{'task': {'type': 'image-classification'}, 'dataset': {'name': 'Beans', 'type': 'beans'}, 'metrics': [{'type': 'accuracy', 'value': 0.9}]}]}]
702
+
703
+ ```
704
+ """
705
+
706
+ # Metrics are reported on a unique task-and-dataset basis.
707
+ # Here, we make a map of those pairs and the associated EvalResults.
708
+ task_and_ds_types_map: dict[Any, list[EvalResult]] = defaultdict(list)
709
+ for eval_result in eval_results:
710
+ task_and_ds_types_map[eval_result.unique_identifier].append(eval_result)
711
+
712
+ # Use the map from above to generate the model index data.
713
+ model_index_data = []
714
+ for results in task_and_ds_types_map.values():
715
+ # All items from `results` share same metadata
716
+ sample_result = results[0]
717
+ data = {
718
+ "task": {
719
+ "type": sample_result.task_type,
720
+ "name": sample_result.task_name,
721
+ },
722
+ "dataset": {
723
+ "name": sample_result.dataset_name,
724
+ "type": sample_result.dataset_type,
725
+ "config": sample_result.dataset_config,
726
+ "split": sample_result.dataset_split,
727
+ "revision": sample_result.dataset_revision,
728
+ "args": sample_result.dataset_args,
729
+ },
730
+ "metrics": [
731
+ {
732
+ "type": result.metric_type,
733
+ "value": result.metric_value,
734
+ "name": result.metric_name,
735
+ "config": result.metric_config,
736
+ "args": result.metric_args,
737
+ "verified": result.verified,
738
+ "verifyToken": result.verify_token,
739
+ }
740
+ for result in results
741
+ ],
742
+ }
743
+ if sample_result.source_url is not None:
744
+ source = {
745
+ "url": sample_result.source_url,
746
+ }
747
+ if sample_result.source_name is not None:
748
+ source["name"] = sample_result.source_name
749
+ data["source"] = source
750
+ model_index_data.append(data)
751
+
752
+ # TODO - Check if there cases where this list is longer than one?
753
+ # Finally, the model index itself is list of dicts.
754
+ model_index = [
755
+ {
756
+ "name": model_name,
757
+ "results": model_index_data,
758
+ }
759
+ ]
760
+ return _remove_none(model_index)
761
+
762
+
763
+ def _to_unique_list(tags: Optional[list[str]]) -> Optional[list[str]]:
764
+ if tags is None:
765
+ return tags
766
+ unique_tags = [] # make tags unique + keep order explicitly
767
+ for tag in tags:
768
+ if tag not in unique_tags:
769
+ unique_tags.append(tag)
770
+ return unique_tags
env/lib/python3.13/site-packages/idna/__init__.py ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from .core import (
2
+ IDNABidiError,
3
+ IDNAError,
4
+ InvalidCodepoint,
5
+ InvalidCodepointContext,
6
+ alabel,
7
+ check_bidi,
8
+ check_hyphen_ok,
9
+ check_initial_combiner,
10
+ check_label,
11
+ check_nfc,
12
+ decode,
13
+ encode,
14
+ ulabel,
15
+ uts46_remap,
16
+ valid_contextj,
17
+ valid_contexto,
18
+ valid_label_length,
19
+ valid_string_length,
20
+ )
21
+ from .intranges import intranges_contain
22
+ from .package_data import __version__
23
+
24
+ __all__ = [
25
+ "__version__",
26
+ "IDNABidiError",
27
+ "IDNAError",
28
+ "InvalidCodepoint",
29
+ "InvalidCodepointContext",
30
+ "alabel",
31
+ "check_bidi",
32
+ "check_hyphen_ok",
33
+ "check_initial_combiner",
34
+ "check_label",
35
+ "check_nfc",
36
+ "decode",
37
+ "encode",
38
+ "intranges_contain",
39
+ "ulabel",
40
+ "uts46_remap",
41
+ "valid_contextj",
42
+ "valid_contexto",
43
+ "valid_label_length",
44
+ "valid_string_length",
45
+ ]
env/lib/python3.13/site-packages/idna/codec.py ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import codecs
2
+ import re
3
+ from typing import Any, Optional, Tuple
4
+
5
+ from .core import IDNAError, alabel, decode, encode, ulabel
6
+
7
+ _unicode_dots_re = re.compile("[\u002e\u3002\uff0e\uff61]")
8
+
9
+
10
+ class Codec(codecs.Codec):
11
+ def encode(self, data: str, errors: str = "strict") -> Tuple[bytes, int]:
12
+ if errors != "strict":
13
+ raise IDNAError('Unsupported error handling "{}"'.format(errors))
14
+
15
+ if not data:
16
+ return b"", 0
17
+
18
+ return encode(data), len(data)
19
+
20
+ def decode(self, data: bytes, errors: str = "strict") -> Tuple[str, int]:
21
+ if errors != "strict":
22
+ raise IDNAError('Unsupported error handling "{}"'.format(errors))
23
+
24
+ if not data:
25
+ return "", 0
26
+
27
+ return decode(data), len(data)
28
+
29
+
30
+ class IncrementalEncoder(codecs.BufferedIncrementalEncoder):
31
+ def _buffer_encode(self, data: str, errors: str, final: bool) -> Tuple[bytes, int]:
32
+ if errors != "strict":
33
+ raise IDNAError('Unsupported error handling "{}"'.format(errors))
34
+
35
+ if not data:
36
+ return b"", 0
37
+
38
+ labels = _unicode_dots_re.split(data)
39
+ trailing_dot = b""
40
+ if labels:
41
+ if not labels[-1]:
42
+ trailing_dot = b"."
43
+ del labels[-1]
44
+ elif not final:
45
+ # Keep potentially unfinished label until the next call
46
+ del labels[-1]
47
+ if labels:
48
+ trailing_dot = b"."
49
+
50
+ result = []
51
+ size = 0
52
+ for label in labels:
53
+ result.append(alabel(label))
54
+ if size:
55
+ size += 1
56
+ size += len(label)
57
+
58
+ # Join with U+002E
59
+ result_bytes = b".".join(result) + trailing_dot
60
+ size += len(trailing_dot)
61
+ return result_bytes, size
62
+
63
+
64
+ class IncrementalDecoder(codecs.BufferedIncrementalDecoder):
65
+ def _buffer_decode(self, data: Any, errors: str, final: bool) -> Tuple[str, int]:
66
+ if errors != "strict":
67
+ raise IDNAError('Unsupported error handling "{}"'.format(errors))
68
+
69
+ if not data:
70
+ return ("", 0)
71
+
72
+ if not isinstance(data, str):
73
+ data = str(data, "ascii")
74
+
75
+ labels = _unicode_dots_re.split(data)
76
+ trailing_dot = ""
77
+ if labels:
78
+ if not labels[-1]:
79
+ trailing_dot = "."
80
+ del labels[-1]
81
+ elif not final:
82
+ # Keep potentially unfinished label until the next call
83
+ del labels[-1]
84
+ if labels:
85
+ trailing_dot = "."
86
+
87
+ result = []
88
+ size = 0
89
+ for label in labels:
90
+ result.append(ulabel(label))
91
+ if size:
92
+ size += 1
93
+ size += len(label)
94
+
95
+ result_str = ".".join(result) + trailing_dot
96
+ size += len(trailing_dot)
97
+ return (result_str, size)
98
+
99
+
100
+ class StreamWriter(Codec, codecs.StreamWriter):
101
+ pass
102
+
103
+
104
+ class StreamReader(Codec, codecs.StreamReader):
105
+ pass
106
+
107
+
108
+ def search_function(name: str) -> Optional[codecs.CodecInfo]:
109
+ if name != "idna2008":
110
+ return None
111
+ return codecs.CodecInfo(
112
+ name=name,
113
+ encode=Codec().encode,
114
+ decode=Codec().decode, # type: ignore
115
+ incrementalencoder=IncrementalEncoder,
116
+ incrementaldecoder=IncrementalDecoder,
117
+ streamwriter=StreamWriter,
118
+ streamreader=StreamReader,
119
+ )
120
+
121
+
122
+ codecs.register(search_function)
env/lib/python3.13/site-packages/idna/compat.py ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Any, Union
2
+
3
+ from .core import decode, encode
4
+
5
+
6
+ def ToASCII(label: str) -> bytes:
7
+ return encode(label)
8
+
9
+
10
+ def ToUnicode(label: Union[bytes, bytearray]) -> str:
11
+ return decode(label)
12
+
13
+
14
+ def nameprep(s: Any) -> None:
15
+ raise NotImplementedError("IDNA 2008 does not utilise nameprep protocol")
env/lib/python3.13/site-packages/idna/core.py ADDED
@@ -0,0 +1,437 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import bisect
2
+ import re
3
+ import unicodedata
4
+ from typing import Optional, Union
5
+
6
+ from . import idnadata
7
+ from .intranges import intranges_contain
8
+
9
+ _virama_combining_class = 9
10
+ _alabel_prefix = b"xn--"
11
+ _unicode_dots_re = re.compile("[\u002e\u3002\uff0e\uff61]")
12
+
13
+
14
+ class IDNAError(UnicodeError):
15
+ """Base exception for all IDNA-encoding related problems"""
16
+
17
+ pass
18
+
19
+
20
+ class IDNABidiError(IDNAError):
21
+ """Exception when bidirectional requirements are not satisfied"""
22
+
23
+ pass
24
+
25
+
26
+ class InvalidCodepoint(IDNAError):
27
+ """Exception when a disallowed or unallocated codepoint is used"""
28
+
29
+ pass
30
+
31
+
32
+ class InvalidCodepointContext(IDNAError):
33
+ """Exception when the codepoint is not valid in the context it is used"""
34
+
35
+ pass
36
+
37
+
38
+ def _combining_class(cp: int) -> int:
39
+ v = unicodedata.combining(chr(cp))
40
+ if v == 0:
41
+ if not unicodedata.name(chr(cp)):
42
+ raise ValueError("Unknown character in unicodedata")
43
+ return v
44
+
45
+
46
+ def _is_script(cp: str, script: str) -> bool:
47
+ return intranges_contain(ord(cp), idnadata.scripts[script])
48
+
49
+
50
+ def _punycode(s: str) -> bytes:
51
+ return s.encode("punycode")
52
+
53
+
54
+ def _unot(s: int) -> str:
55
+ return "U+{:04X}".format(s)
56
+
57
+
58
+ def valid_label_length(label: Union[bytes, str]) -> bool:
59
+ if len(label) > 63:
60
+ return False
61
+ return True
62
+
63
+
64
+ def valid_string_length(label: Union[bytes, str], trailing_dot: bool) -> bool:
65
+ if len(label) > (254 if trailing_dot else 253):
66
+ return False
67
+ return True
68
+
69
+
70
+ def check_bidi(label: str, check_ltr: bool = False) -> bool:
71
+ # Bidi rules should only be applied if string contains RTL characters
72
+ bidi_label = False
73
+ for idx, cp in enumerate(label, 1):
74
+ direction = unicodedata.bidirectional(cp)
75
+ if direction == "":
76
+ # String likely comes from a newer version of Unicode
77
+ raise IDNABidiError("Unknown directionality in label {} at position {}".format(repr(label), idx))
78
+ if direction in ["R", "AL", "AN"]:
79
+ bidi_label = True
80
+ if not bidi_label and not check_ltr:
81
+ return True
82
+
83
+ # Bidi rule 1
84
+ direction = unicodedata.bidirectional(label[0])
85
+ if direction in ["R", "AL"]:
86
+ rtl = True
87
+ elif direction == "L":
88
+ rtl = False
89
+ else:
90
+ raise IDNABidiError("First codepoint in label {} must be directionality L, R or AL".format(repr(label)))
91
+
92
+ valid_ending = False
93
+ number_type: Optional[str] = None
94
+ for idx, cp in enumerate(label, 1):
95
+ direction = unicodedata.bidirectional(cp)
96
+
97
+ if rtl:
98
+ # Bidi rule 2
99
+ if direction not in [
100
+ "R",
101
+ "AL",
102
+ "AN",
103
+ "EN",
104
+ "ES",
105
+ "CS",
106
+ "ET",
107
+ "ON",
108
+ "BN",
109
+ "NSM",
110
+ ]:
111
+ raise IDNABidiError("Invalid direction for codepoint at position {} in a right-to-left label".format(idx))
112
+ # Bidi rule 3
113
+ if direction in ["R", "AL", "EN", "AN"]:
114
+ valid_ending = True
115
+ elif direction != "NSM":
116
+ valid_ending = False
117
+ # Bidi rule 4
118
+ if direction in ["AN", "EN"]:
119
+ if not number_type:
120
+ number_type = direction
121
+ else:
122
+ if number_type != direction:
123
+ raise IDNABidiError("Can not mix numeral types in a right-to-left label")
124
+ else:
125
+ # Bidi rule 5
126
+ if direction not in ["L", "EN", "ES", "CS", "ET", "ON", "BN", "NSM"]:
127
+ raise IDNABidiError("Invalid direction for codepoint at position {} in a left-to-right label".format(idx))
128
+ # Bidi rule 6
129
+ if direction in ["L", "EN"]:
130
+ valid_ending = True
131
+ elif direction != "NSM":
132
+ valid_ending = False
133
+
134
+ if not valid_ending:
135
+ raise IDNABidiError("Label ends with illegal codepoint directionality")
136
+
137
+ return True
138
+
139
+
140
+ def check_initial_combiner(label: str) -> bool:
141
+ if unicodedata.category(label[0])[0] == "M":
142
+ raise IDNAError("Label begins with an illegal combining character")
143
+ return True
144
+
145
+
146
+ def check_hyphen_ok(label: str) -> bool:
147
+ if label[2:4] == "--":
148
+ raise IDNAError("Label has disallowed hyphens in 3rd and 4th position")
149
+ if label[0] == "-" or label[-1] == "-":
150
+ raise IDNAError("Label must not start or end with a hyphen")
151
+ return True
152
+
153
+
154
+ def check_nfc(label: str) -> None:
155
+ if unicodedata.normalize("NFC", label) != label:
156
+ raise IDNAError("Label must be in Normalization Form C")
157
+
158
+
159
+ def valid_contextj(label: str, pos: int) -> bool:
160
+ cp_value = ord(label[pos])
161
+
162
+ if cp_value == 0x200C:
163
+ if pos > 0:
164
+ if _combining_class(ord(label[pos - 1])) == _virama_combining_class:
165
+ return True
166
+
167
+ ok = False
168
+ for i in range(pos - 1, -1, -1):
169
+ joining_type = idnadata.joining_types.get(ord(label[i]))
170
+ if joining_type == ord("T"):
171
+ continue
172
+ elif joining_type in [ord("L"), ord("D")]:
173
+ ok = True
174
+ break
175
+ else:
176
+ break
177
+
178
+ if not ok:
179
+ return False
180
+
181
+ ok = False
182
+ for i in range(pos + 1, len(label)):
183
+ joining_type = idnadata.joining_types.get(ord(label[i]))
184
+ if joining_type == ord("T"):
185
+ continue
186
+ elif joining_type in [ord("R"), ord("D")]:
187
+ ok = True
188
+ break
189
+ else:
190
+ break
191
+ return ok
192
+
193
+ if cp_value == 0x200D:
194
+ if pos > 0:
195
+ if _combining_class(ord(label[pos - 1])) == _virama_combining_class:
196
+ return True
197
+ return False
198
+
199
+ else:
200
+ return False
201
+
202
+
203
+ def valid_contexto(label: str, pos: int, exception: bool = False) -> bool:
204
+ cp_value = ord(label[pos])
205
+
206
+ if cp_value == 0x00B7:
207
+ if 0 < pos < len(label) - 1:
208
+ if ord(label[pos - 1]) == 0x006C and ord(label[pos + 1]) == 0x006C:
209
+ return True
210
+ return False
211
+
212
+ elif cp_value == 0x0375:
213
+ if pos < len(label) - 1 and len(label) > 1:
214
+ return _is_script(label[pos + 1], "Greek")
215
+ return False
216
+
217
+ elif cp_value == 0x05F3 or cp_value == 0x05F4:
218
+ if pos > 0:
219
+ return _is_script(label[pos - 1], "Hebrew")
220
+ return False
221
+
222
+ elif cp_value == 0x30FB:
223
+ for cp in label:
224
+ if cp == "\u30fb":
225
+ continue
226
+ if _is_script(cp, "Hiragana") or _is_script(cp, "Katakana") or _is_script(cp, "Han"):
227
+ return True
228
+ return False
229
+
230
+ elif 0x660 <= cp_value <= 0x669:
231
+ for cp in label:
232
+ if 0x6F0 <= ord(cp) <= 0x06F9:
233
+ return False
234
+ return True
235
+
236
+ elif 0x6F0 <= cp_value <= 0x6F9:
237
+ for cp in label:
238
+ if 0x660 <= ord(cp) <= 0x0669:
239
+ return False
240
+ return True
241
+
242
+ return False
243
+
244
+
245
+ def check_label(label: Union[str, bytes, bytearray]) -> None:
246
+ if isinstance(label, (bytes, bytearray)):
247
+ label = label.decode("utf-8")
248
+ if len(label) == 0:
249
+ raise IDNAError("Empty Label")
250
+
251
+ check_nfc(label)
252
+ check_hyphen_ok(label)
253
+ check_initial_combiner(label)
254
+
255
+ for pos, cp in enumerate(label):
256
+ cp_value = ord(cp)
257
+ if intranges_contain(cp_value, idnadata.codepoint_classes["PVALID"]):
258
+ continue
259
+ elif intranges_contain(cp_value, idnadata.codepoint_classes["CONTEXTJ"]):
260
+ try:
261
+ if not valid_contextj(label, pos):
262
+ raise InvalidCodepointContext(
263
+ "Joiner {} not allowed at position {} in {}".format(_unot(cp_value), pos + 1, repr(label))
264
+ )
265
+ except ValueError:
266
+ raise IDNAError(
267
+ "Unknown codepoint adjacent to joiner {} at position {} in {}".format(
268
+ _unot(cp_value), pos + 1, repr(label)
269
+ )
270
+ )
271
+ elif intranges_contain(cp_value, idnadata.codepoint_classes["CONTEXTO"]):
272
+ if not valid_contexto(label, pos):
273
+ raise InvalidCodepointContext(
274
+ "Codepoint {} not allowed at position {} in {}".format(_unot(cp_value), pos + 1, repr(label))
275
+ )
276
+ else:
277
+ raise InvalidCodepoint(
278
+ "Codepoint {} at position {} of {} not allowed".format(_unot(cp_value), pos + 1, repr(label))
279
+ )
280
+
281
+ check_bidi(label)
282
+
283
+
284
+ def alabel(label: str) -> bytes:
285
+ try:
286
+ label_bytes = label.encode("ascii")
287
+ ulabel(label_bytes)
288
+ if not valid_label_length(label_bytes):
289
+ raise IDNAError("Label too long")
290
+ return label_bytes
291
+ except UnicodeEncodeError:
292
+ pass
293
+
294
+ check_label(label)
295
+ label_bytes = _alabel_prefix + _punycode(label)
296
+
297
+ if not valid_label_length(label_bytes):
298
+ raise IDNAError("Label too long")
299
+
300
+ return label_bytes
301
+
302
+
303
+ def ulabel(label: Union[str, bytes, bytearray]) -> str:
304
+ if not isinstance(label, (bytes, bytearray)):
305
+ try:
306
+ label_bytes = label.encode("ascii")
307
+ except UnicodeEncodeError:
308
+ check_label(label)
309
+ return label
310
+ else:
311
+ label_bytes = bytes(label)
312
+
313
+ label_bytes = label_bytes.lower()
314
+ if label_bytes.startswith(_alabel_prefix):
315
+ label_bytes = label_bytes[len(_alabel_prefix) :]
316
+ if not label_bytes:
317
+ raise IDNAError("Malformed A-label, no Punycode eligible content found")
318
+ if label_bytes.decode("ascii")[-1] == "-":
319
+ raise IDNAError("A-label must not end with a hyphen")
320
+ else:
321
+ check_label(label_bytes)
322
+ return label_bytes.decode("ascii")
323
+
324
+ try:
325
+ label = label_bytes.decode("punycode")
326
+ except UnicodeError:
327
+ raise IDNAError("Invalid A-label")
328
+ check_label(label)
329
+ return label
330
+
331
+
332
+ def uts46_remap(domain: str, std3_rules: bool = True, transitional: bool = False) -> str:
333
+ """Re-map the characters in the string according to UTS46 processing."""
334
+ from .uts46data import uts46data
335
+
336
+ output = ""
337
+
338
+ for pos, char in enumerate(domain):
339
+ code_point = ord(char)
340
+ try:
341
+ uts46row = uts46data[code_point if code_point < 256 else bisect.bisect_left(uts46data, (code_point, "Z")) - 1]
342
+ status = uts46row[1]
343
+ replacement: Optional[str] = None
344
+ if len(uts46row) == 3:
345
+ replacement = uts46row[2]
346
+ if (
347
+ status == "V"
348
+ or (status == "D" and not transitional)
349
+ or (status == "3" and not std3_rules and replacement is None)
350
+ ):
351
+ output += char
352
+ elif replacement is not None and (
353
+ status == "M" or (status == "3" and not std3_rules) or (status == "D" and transitional)
354
+ ):
355
+ output += replacement
356
+ elif status != "I":
357
+ raise IndexError()
358
+ except IndexError:
359
+ raise InvalidCodepoint(
360
+ "Codepoint {} not allowed at position {} in {}".format(_unot(code_point), pos + 1, repr(domain))
361
+ )
362
+
363
+ return unicodedata.normalize("NFC", output)
364
+
365
+
366
+ def encode(
367
+ s: Union[str, bytes, bytearray],
368
+ strict: bool = False,
369
+ uts46: bool = False,
370
+ std3_rules: bool = False,
371
+ transitional: bool = False,
372
+ ) -> bytes:
373
+ if not isinstance(s, str):
374
+ try:
375
+ s = str(s, "ascii")
376
+ except UnicodeDecodeError:
377
+ raise IDNAError("should pass a unicode string to the function rather than a byte string.")
378
+ if uts46:
379
+ s = uts46_remap(s, std3_rules, transitional)
380
+ trailing_dot = False
381
+ result = []
382
+ if strict:
383
+ labels = s.split(".")
384
+ else:
385
+ labels = _unicode_dots_re.split(s)
386
+ if not labels or labels == [""]:
387
+ raise IDNAError("Empty domain")
388
+ if labels[-1] == "":
389
+ del labels[-1]
390
+ trailing_dot = True
391
+ for label in labels:
392
+ s = alabel(label)
393
+ if s:
394
+ result.append(s)
395
+ else:
396
+ raise IDNAError("Empty label")
397
+ if trailing_dot:
398
+ result.append(b"")
399
+ s = b".".join(result)
400
+ if not valid_string_length(s, trailing_dot):
401
+ raise IDNAError("Domain too long")
402
+ return s
403
+
404
+
405
+ def decode(
406
+ s: Union[str, bytes, bytearray],
407
+ strict: bool = False,
408
+ uts46: bool = False,
409
+ std3_rules: bool = False,
410
+ ) -> str:
411
+ try:
412
+ if not isinstance(s, str):
413
+ s = str(s, "ascii")
414
+ except UnicodeDecodeError:
415
+ raise IDNAError("Invalid ASCII in A-label")
416
+ if uts46:
417
+ s = uts46_remap(s, std3_rules, False)
418
+ trailing_dot = False
419
+ result = []
420
+ if not strict:
421
+ labels = _unicode_dots_re.split(s)
422
+ else:
423
+ labels = s.split(".")
424
+ if not labels or labels == [""]:
425
+ raise IDNAError("Empty domain")
426
+ if not labels[-1]:
427
+ del labels[-1]
428
+ trailing_dot = True
429
+ for label in labels:
430
+ s = ulabel(label)
431
+ if s:
432
+ result.append(s)
433
+ else:
434
+ raise IDNAError("Empty label")
435
+ if trailing_dot:
436
+ result.append("")
437
+ return ".".join(result)
env/lib/python3.13/site-packages/idna/idnadata.py ADDED
@@ -0,0 +1,4309 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # This file is automatically generated by tools/idna-data
2
+
3
+ __version__ = "16.0.0"
4
+
5
+ scripts = {
6
+ "Greek": (
7
+ 0x37000000374,
8
+ 0x37500000378,
9
+ 0x37A0000037E,
10
+ 0x37F00000380,
11
+ 0x38400000385,
12
+ 0x38600000387,
13
+ 0x3880000038B,
14
+ 0x38C0000038D,
15
+ 0x38E000003A2,
16
+ 0x3A3000003E2,
17
+ 0x3F000000400,
18
+ 0x1D2600001D2B,
19
+ 0x1D5D00001D62,
20
+ 0x1D6600001D6B,
21
+ 0x1DBF00001DC0,
22
+ 0x1F0000001F16,
23
+ 0x1F1800001F1E,
24
+ 0x1F2000001F46,
25
+ 0x1F4800001F4E,
26
+ 0x1F5000001F58,
27
+ 0x1F5900001F5A,
28
+ 0x1F5B00001F5C,
29
+ 0x1F5D00001F5E,
30
+ 0x1F5F00001F7E,
31
+ 0x1F8000001FB5,
32
+ 0x1FB600001FC5,
33
+ 0x1FC600001FD4,
34
+ 0x1FD600001FDC,
35
+ 0x1FDD00001FF0,
36
+ 0x1FF200001FF5,
37
+ 0x1FF600001FFF,
38
+ 0x212600002127,
39
+ 0xAB650000AB66,
40
+ 0x101400001018F,
41
+ 0x101A0000101A1,
42
+ 0x1D2000001D246,
43
+ ),
44
+ "Han": (
45
+ 0x2E8000002E9A,
46
+ 0x2E9B00002EF4,
47
+ 0x2F0000002FD6,
48
+ 0x300500003006,
49
+ 0x300700003008,
50
+ 0x30210000302A,
51
+ 0x30380000303C,
52
+ 0x340000004DC0,
53
+ 0x4E000000A000,
54
+ 0xF9000000FA6E,
55
+ 0xFA700000FADA,
56
+ 0x16FE200016FE4,
57
+ 0x16FF000016FF2,
58
+ 0x200000002A6E0,
59
+ 0x2A7000002B73A,
60
+ 0x2B7400002B81E,
61
+ 0x2B8200002CEA2,
62
+ 0x2CEB00002EBE1,
63
+ 0x2EBF00002EE5E,
64
+ 0x2F8000002FA1E,
65
+ 0x300000003134B,
66
+ 0x31350000323B0,
67
+ ),
68
+ "Hebrew": (
69
+ 0x591000005C8,
70
+ 0x5D0000005EB,
71
+ 0x5EF000005F5,
72
+ 0xFB1D0000FB37,
73
+ 0xFB380000FB3D,
74
+ 0xFB3E0000FB3F,
75
+ 0xFB400000FB42,
76
+ 0xFB430000FB45,
77
+ 0xFB460000FB50,
78
+ ),
79
+ "Hiragana": (
80
+ 0x304100003097,
81
+ 0x309D000030A0,
82
+ 0x1B0010001B120,
83
+ 0x1B1320001B133,
84
+ 0x1B1500001B153,
85
+ 0x1F2000001F201,
86
+ ),
87
+ "Katakana": (
88
+ 0x30A1000030FB,
89
+ 0x30FD00003100,
90
+ 0x31F000003200,
91
+ 0x32D0000032FF,
92
+ 0x330000003358,
93
+ 0xFF660000FF70,
94
+ 0xFF710000FF9E,
95
+ 0x1AFF00001AFF4,
96
+ 0x1AFF50001AFFC,
97
+ 0x1AFFD0001AFFF,
98
+ 0x1B0000001B001,
99
+ 0x1B1200001B123,
100
+ 0x1B1550001B156,
101
+ 0x1B1640001B168,
102
+ ),
103
+ }
104
+ joining_types = {
105
+ 0xAD: 84,
106
+ 0x300: 84,
107
+ 0x301: 84,
108
+ 0x302: 84,
109
+ 0x303: 84,
110
+ 0x304: 84,
111
+ 0x305: 84,
112
+ 0x306: 84,
113
+ 0x307: 84,
114
+ 0x308: 84,
115
+ 0x309: 84,
116
+ 0x30A: 84,
117
+ 0x30B: 84,
118
+ 0x30C: 84,
119
+ 0x30D: 84,
120
+ 0x30E: 84,
121
+ 0x30F: 84,
122
+ 0x310: 84,
123
+ 0x311: 84,
124
+ 0x312: 84,
125
+ 0x313: 84,
126
+ 0x314: 84,
127
+ 0x315: 84,
128
+ 0x316: 84,
129
+ 0x317: 84,
130
+ 0x318: 84,
131
+ 0x319: 84,
132
+ 0x31A: 84,
133
+ 0x31B: 84,
134
+ 0x31C: 84,
135
+ 0x31D: 84,
136
+ 0x31E: 84,
137
+ 0x31F: 84,
138
+ 0x320: 84,
139
+ 0x321: 84,
140
+ 0x322: 84,
141
+ 0x323: 84,
142
+ 0x324: 84,
143
+ 0x325: 84,
144
+ 0x326: 84,
145
+ 0x327: 84,
146
+ 0x328: 84,
147
+ 0x329: 84,
148
+ 0x32A: 84,
149
+ 0x32B: 84,
150
+ 0x32C: 84,
151
+ 0x32D: 84,
152
+ 0x32E: 84,
153
+ 0x32F: 84,
154
+ 0x330: 84,
155
+ 0x331: 84,
156
+ 0x332: 84,
157
+ 0x333: 84,
158
+ 0x334: 84,
159
+ 0x335: 84,
160
+ 0x336: 84,
161
+ 0x337: 84,
162
+ 0x338: 84,
163
+ 0x339: 84,
164
+ 0x33A: 84,
165
+ 0x33B: 84,
166
+ 0x33C: 84,
167
+ 0x33D: 84,
168
+ 0x33E: 84,
169
+ 0x33F: 84,
170
+ 0x340: 84,
171
+ 0x341: 84,
172
+ 0x342: 84,
173
+ 0x343: 84,
174
+ 0x344: 84,
175
+ 0x345: 84,
176
+ 0x346: 84,
177
+ 0x347: 84,
178
+ 0x348: 84,
179
+ 0x349: 84,
180
+ 0x34A: 84,
181
+ 0x34B: 84,
182
+ 0x34C: 84,
183
+ 0x34D: 84,
184
+ 0x34E: 84,
185
+ 0x34F: 84,
186
+ 0x350: 84,
187
+ 0x351: 84,
188
+ 0x352: 84,
189
+ 0x353: 84,
190
+ 0x354: 84,
191
+ 0x355: 84,
192
+ 0x356: 84,
193
+ 0x357: 84,
194
+ 0x358: 84,
195
+ 0x359: 84,
196
+ 0x35A: 84,
197
+ 0x35B: 84,
198
+ 0x35C: 84,
199
+ 0x35D: 84,
200
+ 0x35E: 84,
201
+ 0x35F: 84,
202
+ 0x360: 84,
203
+ 0x361: 84,
204
+ 0x362: 84,
205
+ 0x363: 84,
206
+ 0x364: 84,
207
+ 0x365: 84,
208
+ 0x366: 84,
209
+ 0x367: 84,
210
+ 0x368: 84,
211
+ 0x369: 84,
212
+ 0x36A: 84,
213
+ 0x36B: 84,
214
+ 0x36C: 84,
215
+ 0x36D: 84,
216
+ 0x36E: 84,
217
+ 0x36F: 84,
218
+ 0x483: 84,
219
+ 0x484: 84,
220
+ 0x485: 84,
221
+ 0x486: 84,
222
+ 0x487: 84,
223
+ 0x488: 84,
224
+ 0x489: 84,
225
+ 0x591: 84,
226
+ 0x592: 84,
227
+ 0x593: 84,
228
+ 0x594: 84,
229
+ 0x595: 84,
230
+ 0x596: 84,
231
+ 0x597: 84,
232
+ 0x598: 84,
233
+ 0x599: 84,
234
+ 0x59A: 84,
235
+ 0x59B: 84,
236
+ 0x59C: 84,
237
+ 0x59D: 84,
238
+ 0x59E: 84,
239
+ 0x59F: 84,
240
+ 0x5A0: 84,
241
+ 0x5A1: 84,
242
+ 0x5A2: 84,
243
+ 0x5A3: 84,
244
+ 0x5A4: 84,
245
+ 0x5A5: 84,
246
+ 0x5A6: 84,
247
+ 0x5A7: 84,
248
+ 0x5A8: 84,
249
+ 0x5A9: 84,
250
+ 0x5AA: 84,
251
+ 0x5AB: 84,
252
+ 0x5AC: 84,
253
+ 0x5AD: 84,
254
+ 0x5AE: 84,
255
+ 0x5AF: 84,
256
+ 0x5B0: 84,
257
+ 0x5B1: 84,
258
+ 0x5B2: 84,
259
+ 0x5B3: 84,
260
+ 0x5B4: 84,
261
+ 0x5B5: 84,
262
+ 0x5B6: 84,
263
+ 0x5B7: 84,
264
+ 0x5B8: 84,
265
+ 0x5B9: 84,
266
+ 0x5BA: 84,
267
+ 0x5BB: 84,
268
+ 0x5BC: 84,
269
+ 0x5BD: 84,
270
+ 0x5BF: 84,
271
+ 0x5C1: 84,
272
+ 0x5C2: 84,
273
+ 0x5C4: 84,
274
+ 0x5C5: 84,
275
+ 0x5C7: 84,
276
+ 0x610: 84,
277
+ 0x611: 84,
278
+ 0x612: 84,
279
+ 0x613: 84,
280
+ 0x614: 84,
281
+ 0x615: 84,
282
+ 0x616: 84,
283
+ 0x617: 84,
284
+ 0x618: 84,
285
+ 0x619: 84,
286
+ 0x61A: 84,
287
+ 0x61C: 84,
288
+ 0x620: 68,
289
+ 0x622: 82,
290
+ 0x623: 82,
291
+ 0x624: 82,
292
+ 0x625: 82,
293
+ 0x626: 68,
294
+ 0x627: 82,
295
+ 0x628: 68,
296
+ 0x629: 82,
297
+ 0x62A: 68,
298
+ 0x62B: 68,
299
+ 0x62C: 68,
300
+ 0x62D: 68,
301
+ 0x62E: 68,
302
+ 0x62F: 82,
303
+ 0x630: 82,
304
+ 0x631: 82,
305
+ 0x632: 82,
306
+ 0x633: 68,
307
+ 0x634: 68,
308
+ 0x635: 68,
309
+ 0x636: 68,
310
+ 0x637: 68,
311
+ 0x638: 68,
312
+ 0x639: 68,
313
+ 0x63A: 68,
314
+ 0x63B: 68,
315
+ 0x63C: 68,
316
+ 0x63D: 68,
317
+ 0x63E: 68,
318
+ 0x63F: 68,
319
+ 0x640: 67,
320
+ 0x641: 68,
321
+ 0x642: 68,
322
+ 0x643: 68,
323
+ 0x644: 68,
324
+ 0x645: 68,
325
+ 0x646: 68,
326
+ 0x647: 68,
327
+ 0x648: 82,
328
+ 0x649: 68,
329
+ 0x64A: 68,
330
+ 0x64B: 84,
331
+ 0x64C: 84,
332
+ 0x64D: 84,
333
+ 0x64E: 84,
334
+ 0x64F: 84,
335
+ 0x650: 84,
336
+ 0x651: 84,
337
+ 0x652: 84,
338
+ 0x653: 84,
339
+ 0x654: 84,
340
+ 0x655: 84,
341
+ 0x656: 84,
342
+ 0x657: 84,
343
+ 0x658: 84,
344
+ 0x659: 84,
345
+ 0x65A: 84,
346
+ 0x65B: 84,
347
+ 0x65C: 84,
348
+ 0x65D: 84,
349
+ 0x65E: 84,
350
+ 0x65F: 84,
351
+ 0x66E: 68,
352
+ 0x66F: 68,
353
+ 0x670: 84,
354
+ 0x671: 82,
355
+ 0x672: 82,
356
+ 0x673: 82,
357
+ 0x675: 82,
358
+ 0x676: 82,
359
+ 0x677: 82,
360
+ 0x678: 68,
361
+ 0x679: 68,
362
+ 0x67A: 68,
363
+ 0x67B: 68,
364
+ 0x67C: 68,
365
+ 0x67D: 68,
366
+ 0x67E: 68,
367
+ 0x67F: 68,
368
+ 0x680: 68,
369
+ 0x681: 68,
370
+ 0x682: 68,
371
+ 0x683: 68,
372
+ 0x684: 68,
373
+ 0x685: 68,
374
+ 0x686: 68,
375
+ 0x687: 68,
376
+ 0x688: 82,
377
+ 0x689: 82,
378
+ 0x68A: 82,
379
+ 0x68B: 82,
380
+ 0x68C: 82,
381
+ 0x68D: 82,
382
+ 0x68E: 82,
383
+ 0x68F: 82,
384
+ 0x690: 82,
385
+ 0x691: 82,
386
+ 0x692: 82,
387
+ 0x693: 82,
388
+ 0x694: 82,
389
+ 0x695: 82,
390
+ 0x696: 82,
391
+ 0x697: 82,
392
+ 0x698: 82,
393
+ 0x699: 82,
394
+ 0x69A: 68,
395
+ 0x69B: 68,
396
+ 0x69C: 68,
397
+ 0x69D: 68,
398
+ 0x69E: 68,
399
+ 0x69F: 68,
400
+ 0x6A0: 68,
401
+ 0x6A1: 68,
402
+ 0x6A2: 68,
403
+ 0x6A3: 68,
404
+ 0x6A4: 68,
405
+ 0x6A5: 68,
406
+ 0x6A6: 68,
407
+ 0x6A7: 68,
408
+ 0x6A8: 68,
409
+ 0x6A9: 68,
410
+ 0x6AA: 68,
411
+ 0x6AB: 68,
412
+ 0x6AC: 68,
413
+ 0x6AD: 68,
414
+ 0x6AE: 68,
415
+ 0x6AF: 68,
416
+ 0x6B0: 68,
417
+ 0x6B1: 68,
418
+ 0x6B2: 68,
419
+ 0x6B3: 68,
420
+ 0x6B4: 68,
421
+ 0x6B5: 68,
422
+ 0x6B6: 68,
423
+ 0x6B7: 68,
424
+ 0x6B8: 68,
425
+ 0x6B9: 68,
426
+ 0x6BA: 68,
427
+ 0x6BB: 68,
428
+ 0x6BC: 68,
429
+ 0x6BD: 68,
430
+ 0x6BE: 68,
431
+ 0x6BF: 68,
432
+ 0x6C0: 82,
433
+ 0x6C1: 68,
434
+ 0x6C2: 68,
435
+ 0x6C3: 82,
436
+ 0x6C4: 82,
437
+ 0x6C5: 82,
438
+ 0x6C6: 82,
439
+ 0x6C7: 82,
440
+ 0x6C8: 82,
441
+ 0x6C9: 82,
442
+ 0x6CA: 82,
443
+ 0x6CB: 82,
444
+ 0x6CC: 68,
445
+ 0x6CD: 82,
446
+ 0x6CE: 68,
447
+ 0x6CF: 82,
448
+ 0x6D0: 68,
449
+ 0x6D1: 68,
450
+ 0x6D2: 82,
451
+ 0x6D3: 82,
452
+ 0x6D5: 82,
453
+ 0x6D6: 84,
454
+ 0x6D7: 84,
455
+ 0x6D8: 84,
456
+ 0x6D9: 84,
457
+ 0x6DA: 84,
458
+ 0x6DB: 84,
459
+ 0x6DC: 84,
460
+ 0x6DF: 84,
461
+ 0x6E0: 84,
462
+ 0x6E1: 84,
463
+ 0x6E2: 84,
464
+ 0x6E3: 84,
465
+ 0x6E4: 84,
466
+ 0x6E7: 84,
467
+ 0x6E8: 84,
468
+ 0x6EA: 84,
469
+ 0x6EB: 84,
470
+ 0x6EC: 84,
471
+ 0x6ED: 84,
472
+ 0x6EE: 82,
473
+ 0x6EF: 82,
474
+ 0x6FA: 68,
475
+ 0x6FB: 68,
476
+ 0x6FC: 68,
477
+ 0x6FF: 68,
478
+ 0x70F: 84,
479
+ 0x710: 82,
480
+ 0x711: 84,
481
+ 0x712: 68,
482
+ 0x713: 68,
483
+ 0x714: 68,
484
+ 0x715: 82,
485
+ 0x716: 82,
486
+ 0x717: 82,
487
+ 0x718: 82,
488
+ 0x719: 82,
489
+ 0x71A: 68,
490
+ 0x71B: 68,
491
+ 0x71C: 68,
492
+ 0x71D: 68,
493
+ 0x71E: 82,
494
+ 0x71F: 68,
495
+ 0x720: 68,
496
+ 0x721: 68,
497
+ 0x722: 68,
498
+ 0x723: 68,
499
+ 0x724: 68,
500
+ 0x725: 68,
501
+ 0x726: 68,
502
+ 0x727: 68,
503
+ 0x728: 82,
504
+ 0x729: 68,
505
+ 0x72A: 82,
506
+ 0x72B: 68,
507
+ 0x72C: 82,
508
+ 0x72D: 68,
509
+ 0x72E: 68,
510
+ 0x72F: 82,
511
+ 0x730: 84,
512
+ 0x731: 84,
513
+ 0x732: 84,
514
+ 0x733: 84,
515
+ 0x734: 84,
516
+ 0x735: 84,
517
+ 0x736: 84,
518
+ 0x737: 84,
519
+ 0x738: 84,
520
+ 0x739: 84,
521
+ 0x73A: 84,
522
+ 0x73B: 84,
523
+ 0x73C: 84,
524
+ 0x73D: 84,
525
+ 0x73E: 84,
526
+ 0x73F: 84,
527
+ 0x740: 84,
528
+ 0x741: 84,
529
+ 0x742: 84,
530
+ 0x743: 84,
531
+ 0x744: 84,
532
+ 0x745: 84,
533
+ 0x746: 84,
534
+ 0x747: 84,
535
+ 0x748: 84,
536
+ 0x749: 84,
537
+ 0x74A: 84,
538
+ 0x74D: 82,
539
+ 0x74E: 68,
540
+ 0x74F: 68,
541
+ 0x750: 68,
542
+ 0x751: 68,
543
+ 0x752: 68,
544
+ 0x753: 68,
545
+ 0x754: 68,
546
+ 0x755: 68,
547
+ 0x756: 68,
548
+ 0x757: 68,
549
+ 0x758: 68,
550
+ 0x759: 82,
551
+ 0x75A: 82,
552
+ 0x75B: 82,
553
+ 0x75C: 68,
554
+ 0x75D: 68,
555
+ 0x75E: 68,
556
+ 0x75F: 68,
557
+ 0x760: 68,
558
+ 0x761: 68,
559
+ 0x762: 68,
560
+ 0x763: 68,
561
+ 0x764: 68,
562
+ 0x765: 68,
563
+ 0x766: 68,
564
+ 0x767: 68,
565
+ 0x768: 68,
566
+ 0x769: 68,
567
+ 0x76A: 68,
568
+ 0x76B: 82,
569
+ 0x76C: 82,
570
+ 0x76D: 68,
571
+ 0x76E: 68,
572
+ 0x76F: 68,
573
+ 0x770: 68,
574
+ 0x771: 82,
575
+ 0x772: 68,
576
+ 0x773: 82,
577
+ 0x774: 82,
578
+ 0x775: 68,
579
+ 0x776: 68,
580
+ 0x777: 68,
581
+ 0x778: 82,
582
+ 0x779: 82,
583
+ 0x77A: 68,
584
+ 0x77B: 68,
585
+ 0x77C: 68,
586
+ 0x77D: 68,
587
+ 0x77E: 68,
588
+ 0x77F: 68,
589
+ 0x7A6: 84,
590
+ 0x7A7: 84,
591
+ 0x7A8: 84,
592
+ 0x7A9: 84,
593
+ 0x7AA: 84,
594
+ 0x7AB: 84,
595
+ 0x7AC: 84,
596
+ 0x7AD: 84,
597
+ 0x7AE: 84,
598
+ 0x7AF: 84,
599
+ 0x7B0: 84,
600
+ 0x7CA: 68,
601
+ 0x7CB: 68,
602
+ 0x7CC: 68,
603
+ 0x7CD: 68,
604
+ 0x7CE: 68,
605
+ 0x7CF: 68,
606
+ 0x7D0: 68,
607
+ 0x7D1: 68,
608
+ 0x7D2: 68,
609
+ 0x7D3: 68,
610
+ 0x7D4: 68,
611
+ 0x7D5: 68,
612
+ 0x7D6: 68,
613
+ 0x7D7: 68,
614
+ 0x7D8: 68,
615
+ 0x7D9: 68,
616
+ 0x7DA: 68,
617
+ 0x7DB: 68,
618
+ 0x7DC: 68,
619
+ 0x7DD: 68,
620
+ 0x7DE: 68,
621
+ 0x7DF: 68,
622
+ 0x7E0: 68,
623
+ 0x7E1: 68,
624
+ 0x7E2: 68,
625
+ 0x7E3: 68,
626
+ 0x7E4: 68,
627
+ 0x7E5: 68,
628
+ 0x7E6: 68,
629
+ 0x7E7: 68,
630
+ 0x7E8: 68,
631
+ 0x7E9: 68,
632
+ 0x7EA: 68,
633
+ 0x7EB: 84,
634
+ 0x7EC: 84,
635
+ 0x7ED: 84,
636
+ 0x7EE: 84,
637
+ 0x7EF: 84,
638
+ 0x7F0: 84,
639
+ 0x7F1: 84,
640
+ 0x7F2: 84,
641
+ 0x7F3: 84,
642
+ 0x7FA: 67,
643
+ 0x7FD: 84,
644
+ 0x816: 84,
645
+ 0x817: 84,
646
+ 0x818: 84,
647
+ 0x819: 84,
648
+ 0x81B: 84,
649
+ 0x81C: 84,
650
+ 0x81D: 84,
651
+ 0x81E: 84,
652
+ 0x81F: 84,
653
+ 0x820: 84,
654
+ 0x821: 84,
655
+ 0x822: 84,
656
+ 0x823: 84,
657
+ 0x825: 84,
658
+ 0x826: 84,
659
+ 0x827: 84,
660
+ 0x829: 84,
661
+ 0x82A: 84,
662
+ 0x82B: 84,
663
+ 0x82C: 84,
664
+ 0x82D: 84,
665
+ 0x840: 82,
666
+ 0x841: 68,
667
+ 0x842: 68,
668
+ 0x843: 68,
669
+ 0x844: 68,
670
+ 0x845: 68,
671
+ 0x846: 82,
672
+ 0x847: 82,
673
+ 0x848: 68,
674
+ 0x849: 82,
675
+ 0x84A: 68,
676
+ 0x84B: 68,
677
+ 0x84C: 68,
678
+ 0x84D: 68,
679
+ 0x84E: 68,
680
+ 0x84F: 68,
681
+ 0x850: 68,
682
+ 0x851: 68,
683
+ 0x852: 68,
684
+ 0x853: 68,
685
+ 0x854: 82,
686
+ 0x855: 68,
687
+ 0x856: 82,
688
+ 0x857: 82,
689
+ 0x858: 82,
690
+ 0x859: 84,
691
+ 0x85A: 84,
692
+ 0x85B: 84,
693
+ 0x860: 68,
694
+ 0x862: 68,
695
+ 0x863: 68,
696
+ 0x864: 68,
697
+ 0x865: 68,
698
+ 0x867: 82,
699
+ 0x868: 68,
700
+ 0x869: 82,
701
+ 0x86A: 82,
702
+ 0x870: 82,
703
+ 0x871: 82,
704
+ 0x872: 82,
705
+ 0x873: 82,
706
+ 0x874: 82,
707
+ 0x875: 82,
708
+ 0x876: 82,
709
+ 0x877: 82,
710
+ 0x878: 82,
711
+ 0x879: 82,
712
+ 0x87A: 82,
713
+ 0x87B: 82,
714
+ 0x87C: 82,
715
+ 0x87D: 82,
716
+ 0x87E: 82,
717
+ 0x87F: 82,
718
+ 0x880: 82,
719
+ 0x881: 82,
720
+ 0x882: 82,
721
+ 0x883: 67,
722
+ 0x884: 67,
723
+ 0x885: 67,
724
+ 0x886: 68,
725
+ 0x889: 68,
726
+ 0x88A: 68,
727
+ 0x88B: 68,
728
+ 0x88C: 68,
729
+ 0x88D: 68,
730
+ 0x88E: 82,
731
+ 0x897: 84,
732
+ 0x898: 84,
733
+ 0x899: 84,
734
+ 0x89A: 84,
735
+ 0x89B: 84,
736
+ 0x89C: 84,
737
+ 0x89D: 84,
738
+ 0x89E: 84,
739
+ 0x89F: 84,
740
+ 0x8A0: 68,
741
+ 0x8A1: 68,
742
+ 0x8A2: 68,
743
+ 0x8A3: 68,
744
+ 0x8A4: 68,
745
+ 0x8A5: 68,
746
+ 0x8A6: 68,
747
+ 0x8A7: 68,
748
+ 0x8A8: 68,
749
+ 0x8A9: 68,
750
+ 0x8AA: 82,
751
+ 0x8AB: 82,
752
+ 0x8AC: 82,
753
+ 0x8AE: 82,
754
+ 0x8AF: 68,
755
+ 0x8B0: 68,
756
+ 0x8B1: 82,
757
+ 0x8B2: 82,
758
+ 0x8B3: 68,
759
+ 0x8B4: 68,
760
+ 0x8B5: 68,
761
+ 0x8B6: 68,
762
+ 0x8B7: 68,
763
+ 0x8B8: 68,
764
+ 0x8B9: 82,
765
+ 0x8BA: 68,
766
+ 0x8BB: 68,
767
+ 0x8BC: 68,
768
+ 0x8BD: 68,
769
+ 0x8BE: 68,
770
+ 0x8BF: 68,
771
+ 0x8C0: 68,
772
+ 0x8C1: 68,
773
+ 0x8C2: 68,
774
+ 0x8C3: 68,
775
+ 0x8C4: 68,
776
+ 0x8C5: 68,
777
+ 0x8C6: 68,
778
+ 0x8C7: 68,
779
+ 0x8C8: 68,
780
+ 0x8CA: 84,
781
+ 0x8CB: 84,
782
+ 0x8CC: 84,
783
+ 0x8CD: 84,
784
+ 0x8CE: 84,
785
+ 0x8CF: 84,
786
+ 0x8D0: 84,
787
+ 0x8D1: 84,
788
+ 0x8D2: 84,
789
+ 0x8D3: 84,
790
+ 0x8D4: 84,
791
+ 0x8D5: 84,
792
+ 0x8D6: 84,
793
+ 0x8D7: 84,
794
+ 0x8D8: 84,
795
+ 0x8D9: 84,
796
+ 0x8DA: 84,
797
+ 0x8DB: 84,
798
+ 0x8DC: 84,
799
+ 0x8DD: 84,
800
+ 0x8DE: 84,
801
+ 0x8DF: 84,
802
+ 0x8E0: 84,
803
+ 0x8E1: 84,
804
+ 0x8E3: 84,
805
+ 0x8E4: 84,
806
+ 0x8E5: 84,
807
+ 0x8E6: 84,
808
+ 0x8E7: 84,
809
+ 0x8E8: 84,
810
+ 0x8E9: 84,
811
+ 0x8EA: 84,
812
+ 0x8EB: 84,
813
+ 0x8EC: 84,
814
+ 0x8ED: 84,
815
+ 0x8EE: 84,
816
+ 0x8EF: 84,
817
+ 0x8F0: 84,
818
+ 0x8F1: 84,
819
+ 0x8F2: 84,
820
+ 0x8F3: 84,
821
+ 0x8F4: 84,
822
+ 0x8F5: 84,
823
+ 0x8F6: 84,
824
+ 0x8F7: 84,
825
+ 0x8F8: 84,
826
+ 0x8F9: 84,
827
+ 0x8FA: 84,
828
+ 0x8FB: 84,
829
+ 0x8FC: 84,
830
+ 0x8FD: 84,
831
+ 0x8FE: 84,
832
+ 0x8FF: 84,
833
+ 0x900: 84,
834
+ 0x901: 84,
835
+ 0x902: 84,
836
+ 0x93A: 84,
837
+ 0x93C: 84,
838
+ 0x941: 84,
839
+ 0x942: 84,
840
+ 0x943: 84,
841
+ 0x944: 84,
842
+ 0x945: 84,
843
+ 0x946: 84,
844
+ 0x947: 84,
845
+ 0x948: 84,
846
+ 0x94D: 84,
847
+ 0x951: 84,
848
+ 0x952: 84,
849
+ 0x953: 84,
850
+ 0x954: 84,
851
+ 0x955: 84,
852
+ 0x956: 84,
853
+ 0x957: 84,
854
+ 0x962: 84,
855
+ 0x963: 84,
856
+ 0x981: 84,
857
+ 0x9BC: 84,
858
+ 0x9C1: 84,
859
+ 0x9C2: 84,
860
+ 0x9C3: 84,
861
+ 0x9C4: 84,
862
+ 0x9CD: 84,
863
+ 0x9E2: 84,
864
+ 0x9E3: 84,
865
+ 0x9FE: 84,
866
+ 0xA01: 84,
867
+ 0xA02: 84,
868
+ 0xA3C: 84,
869
+ 0xA41: 84,
870
+ 0xA42: 84,
871
+ 0xA47: 84,
872
+ 0xA48: 84,
873
+ 0xA4B: 84,
874
+ 0xA4C: 84,
875
+ 0xA4D: 84,
876
+ 0xA51: 84,
877
+ 0xA70: 84,
878
+ 0xA71: 84,
879
+ 0xA75: 84,
880
+ 0xA81: 84,
881
+ 0xA82: 84,
882
+ 0xABC: 84,
883
+ 0xAC1: 84,
884
+ 0xAC2: 84,
885
+ 0xAC3: 84,
886
+ 0xAC4: 84,
887
+ 0xAC5: 84,
888
+ 0xAC7: 84,
889
+ 0xAC8: 84,
890
+ 0xACD: 84,
891
+ 0xAE2: 84,
892
+ 0xAE3: 84,
893
+ 0xAFA: 84,
894
+ 0xAFB: 84,
895
+ 0xAFC: 84,
896
+ 0xAFD: 84,
897
+ 0xAFE: 84,
898
+ 0xAFF: 84,
899
+ 0xB01: 84,
900
+ 0xB3C: 84,
901
+ 0xB3F: 84,
902
+ 0xB41: 84,
903
+ 0xB42: 84,
904
+ 0xB43: 84,
905
+ 0xB44: 84,
906
+ 0xB4D: 84,
907
+ 0xB55: 84,
908
+ 0xB56: 84,
909
+ 0xB62: 84,
910
+ 0xB63: 84,
911
+ 0xB82: 84,
912
+ 0xBC0: 84,
913
+ 0xBCD: 84,
914
+ 0xC00: 84,
915
+ 0xC04: 84,
916
+ 0xC3C: 84,
917
+ 0xC3E: 84,
918
+ 0xC3F: 84,
919
+ 0xC40: 84,
920
+ 0xC46: 84,
921
+ 0xC47: 84,
922
+ 0xC48: 84,
923
+ 0xC4A: 84,
924
+ 0xC4B: 84,
925
+ 0xC4C: 84,
926
+ 0xC4D: 84,
927
+ 0xC55: 84,
928
+ 0xC56: 84,
929
+ 0xC62: 84,
930
+ 0xC63: 84,
931
+ 0xC81: 84,
932
+ 0xCBC: 84,
933
+ 0xCBF: 84,
934
+ 0xCC6: 84,
935
+ 0xCCC: 84,
936
+ 0xCCD: 84,
937
+ 0xCE2: 84,
938
+ 0xCE3: 84,
939
+ 0xD00: 84,
940
+ 0xD01: 84,
941
+ 0xD3B: 84,
942
+ 0xD3C: 84,
943
+ 0xD41: 84,
944
+ 0xD42: 84,
945
+ 0xD43: 84,
946
+ 0xD44: 84,
947
+ 0xD4D: 84,
948
+ 0xD62: 84,
949
+ 0xD63: 84,
950
+ 0xD81: 84,
951
+ 0xDCA: 84,
952
+ 0xDD2: 84,
953
+ 0xDD3: 84,
954
+ 0xDD4: 84,
955
+ 0xDD6: 84,
956
+ 0xE31: 84,
957
+ 0xE34: 84,
958
+ 0xE35: 84,
959
+ 0xE36: 84,
960
+ 0xE37: 84,
961
+ 0xE38: 84,
962
+ 0xE39: 84,
963
+ 0xE3A: 84,
964
+ 0xE47: 84,
965
+ 0xE48: 84,
966
+ 0xE49: 84,
967
+ 0xE4A: 84,
968
+ 0xE4B: 84,
969
+ 0xE4C: 84,
970
+ 0xE4D: 84,
971
+ 0xE4E: 84,
972
+ 0xEB1: 84,
973
+ 0xEB4: 84,
974
+ 0xEB5: 84,
975
+ 0xEB6: 84,
976
+ 0xEB7: 84,
977
+ 0xEB8: 84,
978
+ 0xEB9: 84,
979
+ 0xEBA: 84,
980
+ 0xEBB: 84,
981
+ 0xEBC: 84,
982
+ 0xEC8: 84,
983
+ 0xEC9: 84,
984
+ 0xECA: 84,
985
+ 0xECB: 84,
986
+ 0xECC: 84,
987
+ 0xECD: 84,
988
+ 0xECE: 84,
989
+ 0xF18: 84,
990
+ 0xF19: 84,
991
+ 0xF35: 84,
992
+ 0xF37: 84,
993
+ 0xF39: 84,
994
+ 0xF71: 84,
995
+ 0xF72: 84,
996
+ 0xF73: 84,
997
+ 0xF74: 84,
998
+ 0xF75: 84,
999
+ 0xF76: 84,
1000
+ 0xF77: 84,
1001
+ 0xF78: 84,
1002
+ 0xF79: 84,
1003
+ 0xF7A: 84,
1004
+ 0xF7B: 84,
1005
+ 0xF7C: 84,
1006
+ 0xF7D: 84,
1007
+ 0xF7E: 84,
1008
+ 0xF80: 84,
1009
+ 0xF81: 84,
1010
+ 0xF82: 84,
1011
+ 0xF83: 84,
1012
+ 0xF84: 84,
1013
+ 0xF86: 84,
1014
+ 0xF87: 84,
1015
+ 0xF8D: 84,
1016
+ 0xF8E: 84,
1017
+ 0xF8F: 84,
1018
+ 0xF90: 84,
1019
+ 0xF91: 84,
1020
+ 0xF92: 84,
1021
+ 0xF93: 84,
1022
+ 0xF94: 84,
1023
+ 0xF95: 84,
1024
+ 0xF96: 84,
1025
+ 0xF97: 84,
1026
+ 0xF99: 84,
1027
+ 0xF9A: 84,
1028
+ 0xF9B: 84,
1029
+ 0xF9C: 84,
1030
+ 0xF9D: 84,
1031
+ 0xF9E: 84,
1032
+ 0xF9F: 84,
1033
+ 0xFA0: 84,
1034
+ 0xFA1: 84,
1035
+ 0xFA2: 84,
1036
+ 0xFA3: 84,
1037
+ 0xFA4: 84,
1038
+ 0xFA5: 84,
1039
+ 0xFA6: 84,
1040
+ 0xFA7: 84,
1041
+ 0xFA8: 84,
1042
+ 0xFA9: 84,
1043
+ 0xFAA: 84,
1044
+ 0xFAB: 84,
1045
+ 0xFAC: 84,
1046
+ 0xFAD: 84,
1047
+ 0xFAE: 84,
1048
+ 0xFAF: 84,
1049
+ 0xFB0: 84,
1050
+ 0xFB1: 84,
1051
+ 0xFB2: 84,
1052
+ 0xFB3: 84,
1053
+ 0xFB4: 84,
1054
+ 0xFB5: 84,
1055
+ 0xFB6: 84,
1056
+ 0xFB7: 84,
1057
+ 0xFB8: 84,
1058
+ 0xFB9: 84,
1059
+ 0xFBA: 84,
1060
+ 0xFBB: 84,
1061
+ 0xFBC: 84,
1062
+ 0xFC6: 84,
1063
+ 0x102D: 84,
1064
+ 0x102E: 84,
1065
+ 0x102F: 84,
1066
+ 0x1030: 84,
1067
+ 0x1032: 84,
1068
+ 0x1033: 84,
1069
+ 0x1034: 84,
1070
+ 0x1035: 84,
1071
+ 0x1036: 84,
1072
+ 0x1037: 84,
1073
+ 0x1039: 84,
1074
+ 0x103A: 84,
1075
+ 0x103D: 84,
1076
+ 0x103E: 84,
1077
+ 0x1058: 84,
1078
+ 0x1059: 84,
1079
+ 0x105E: 84,
1080
+ 0x105F: 84,
1081
+ 0x1060: 84,
1082
+ 0x1071: 84,
1083
+ 0x1072: 84,
1084
+ 0x1073: 84,
1085
+ 0x1074: 84,
1086
+ 0x1082: 84,
1087
+ 0x1085: 84,
1088
+ 0x1086: 84,
1089
+ 0x108D: 84,
1090
+ 0x109D: 84,
1091
+ 0x135D: 84,
1092
+ 0x135E: 84,
1093
+ 0x135F: 84,
1094
+ 0x1712: 84,
1095
+ 0x1713: 84,
1096
+ 0x1714: 84,
1097
+ 0x1732: 84,
1098
+ 0x1733: 84,
1099
+ 0x1752: 84,
1100
+ 0x1753: 84,
1101
+ 0x1772: 84,
1102
+ 0x1773: 84,
1103
+ 0x17B4: 84,
1104
+ 0x17B5: 84,
1105
+ 0x17B7: 84,
1106
+ 0x17B8: 84,
1107
+ 0x17B9: 84,
1108
+ 0x17BA: 84,
1109
+ 0x17BB: 84,
1110
+ 0x17BC: 84,
1111
+ 0x17BD: 84,
1112
+ 0x17C6: 84,
1113
+ 0x17C9: 84,
1114
+ 0x17CA: 84,
1115
+ 0x17CB: 84,
1116
+ 0x17CC: 84,
1117
+ 0x17CD: 84,
1118
+ 0x17CE: 84,
1119
+ 0x17CF: 84,
1120
+ 0x17D0: 84,
1121
+ 0x17D1: 84,
1122
+ 0x17D2: 84,
1123
+ 0x17D3: 84,
1124
+ 0x17DD: 84,
1125
+ 0x1807: 68,
1126
+ 0x180A: 67,
1127
+ 0x180B: 84,
1128
+ 0x180C: 84,
1129
+ 0x180D: 84,
1130
+ 0x180F: 84,
1131
+ 0x1820: 68,
1132
+ 0x1821: 68,
1133
+ 0x1822: 68,
1134
+ 0x1823: 68,
1135
+ 0x1824: 68,
1136
+ 0x1825: 68,
1137
+ 0x1826: 68,
1138
+ 0x1827: 68,
1139
+ 0x1828: 68,
1140
+ 0x1829: 68,
1141
+ 0x182A: 68,
1142
+ 0x182B: 68,
1143
+ 0x182C: 68,
1144
+ 0x182D: 68,
1145
+ 0x182E: 68,
1146
+ 0x182F: 68,
1147
+ 0x1830: 68,
1148
+ 0x1831: 68,
1149
+ 0x1832: 68,
1150
+ 0x1833: 68,
1151
+ 0x1834: 68,
1152
+ 0x1835: 68,
1153
+ 0x1836: 68,
1154
+ 0x1837: 68,
1155
+ 0x1838: 68,
1156
+ 0x1839: 68,
1157
+ 0x183A: 68,
1158
+ 0x183B: 68,
1159
+ 0x183C: 68,
1160
+ 0x183D: 68,
1161
+ 0x183E: 68,
1162
+ 0x183F: 68,
1163
+ 0x1840: 68,
1164
+ 0x1841: 68,
1165
+ 0x1842: 68,
1166
+ 0x1843: 68,
1167
+ 0x1844: 68,
1168
+ 0x1845: 68,
1169
+ 0x1846: 68,
1170
+ 0x1847: 68,
1171
+ 0x1848: 68,
1172
+ 0x1849: 68,
1173
+ 0x184A: 68,
1174
+ 0x184B: 68,
1175
+ 0x184C: 68,
1176
+ 0x184D: 68,
1177
+ 0x184E: 68,
1178
+ 0x184F: 68,
1179
+ 0x1850: 68,
1180
+ 0x1851: 68,
1181
+ 0x1852: 68,
1182
+ 0x1853: 68,
1183
+ 0x1854: 68,
1184
+ 0x1855: 68,
1185
+ 0x1856: 68,
1186
+ 0x1857: 68,
1187
+ 0x1858: 68,
1188
+ 0x1859: 68,
1189
+ 0x185A: 68,
1190
+ 0x185B: 68,
1191
+ 0x185C: 68,
1192
+ 0x185D: 68,
1193
+ 0x185E: 68,
1194
+ 0x185F: 68,
1195
+ 0x1860: 68,
1196
+ 0x1861: 68,
1197
+ 0x1862: 68,
1198
+ 0x1863: 68,
1199
+ 0x1864: 68,
1200
+ 0x1865: 68,
1201
+ 0x1866: 68,
1202
+ 0x1867: 68,
1203
+ 0x1868: 68,
1204
+ 0x1869: 68,
1205
+ 0x186A: 68,
1206
+ 0x186B: 68,
1207
+ 0x186C: 68,
1208
+ 0x186D: 68,
1209
+ 0x186E: 68,
1210
+ 0x186F: 68,
1211
+ 0x1870: 68,
1212
+ 0x1871: 68,
1213
+ 0x1872: 68,
1214
+ 0x1873: 68,
1215
+ 0x1874: 68,
1216
+ 0x1875: 68,
1217
+ 0x1876: 68,
1218
+ 0x1877: 68,
1219
+ 0x1878: 68,
1220
+ 0x1885: 84,
1221
+ 0x1886: 84,
1222
+ 0x1887: 68,
1223
+ 0x1888: 68,
1224
+ 0x1889: 68,
1225
+ 0x188A: 68,
1226
+ 0x188B: 68,
1227
+ 0x188C: 68,
1228
+ 0x188D: 68,
1229
+ 0x188E: 68,
1230
+ 0x188F: 68,
1231
+ 0x1890: 68,
1232
+ 0x1891: 68,
1233
+ 0x1892: 68,
1234
+ 0x1893: 68,
1235
+ 0x1894: 68,
1236
+ 0x1895: 68,
1237
+ 0x1896: 68,
1238
+ 0x1897: 68,
1239
+ 0x1898: 68,
1240
+ 0x1899: 68,
1241
+ 0x189A: 68,
1242
+ 0x189B: 68,
1243
+ 0x189C: 68,
1244
+ 0x189D: 68,
1245
+ 0x189E: 68,
1246
+ 0x189F: 68,
1247
+ 0x18A0: 68,
1248
+ 0x18A1: 68,
1249
+ 0x18A2: 68,
1250
+ 0x18A3: 68,
1251
+ 0x18A4: 68,
1252
+ 0x18A5: 68,
1253
+ 0x18A6: 68,
1254
+ 0x18A7: 68,
1255
+ 0x18A8: 68,
1256
+ 0x18A9: 84,
1257
+ 0x18AA: 68,
1258
+ 0x1920: 84,
1259
+ 0x1921: 84,
1260
+ 0x1922: 84,
1261
+ 0x1927: 84,
1262
+ 0x1928: 84,
1263
+ 0x1932: 84,
1264
+ 0x1939: 84,
1265
+ 0x193A: 84,
1266
+ 0x193B: 84,
1267
+ 0x1A17: 84,
1268
+ 0x1A18: 84,
1269
+ 0x1A1B: 84,
1270
+ 0x1A56: 84,
1271
+ 0x1A58: 84,
1272
+ 0x1A59: 84,
1273
+ 0x1A5A: 84,
1274
+ 0x1A5B: 84,
1275
+ 0x1A5C: 84,
1276
+ 0x1A5D: 84,
1277
+ 0x1A5E: 84,
1278
+ 0x1A60: 84,
1279
+ 0x1A62: 84,
1280
+ 0x1A65: 84,
1281
+ 0x1A66: 84,
1282
+ 0x1A67: 84,
1283
+ 0x1A68: 84,
1284
+ 0x1A69: 84,
1285
+ 0x1A6A: 84,
1286
+ 0x1A6B: 84,
1287
+ 0x1A6C: 84,
1288
+ 0x1A73: 84,
1289
+ 0x1A74: 84,
1290
+ 0x1A75: 84,
1291
+ 0x1A76: 84,
1292
+ 0x1A77: 84,
1293
+ 0x1A78: 84,
1294
+ 0x1A79: 84,
1295
+ 0x1A7A: 84,
1296
+ 0x1A7B: 84,
1297
+ 0x1A7C: 84,
1298
+ 0x1A7F: 84,
1299
+ 0x1AB0: 84,
1300
+ 0x1AB1: 84,
1301
+ 0x1AB2: 84,
1302
+ 0x1AB3: 84,
1303
+ 0x1AB4: 84,
1304
+ 0x1AB5: 84,
1305
+ 0x1AB6: 84,
1306
+ 0x1AB7: 84,
1307
+ 0x1AB8: 84,
1308
+ 0x1AB9: 84,
1309
+ 0x1ABA: 84,
1310
+ 0x1ABB: 84,
1311
+ 0x1ABC: 84,
1312
+ 0x1ABD: 84,
1313
+ 0x1ABE: 84,
1314
+ 0x1ABF: 84,
1315
+ 0x1AC0: 84,
1316
+ 0x1AC1: 84,
1317
+ 0x1AC2: 84,
1318
+ 0x1AC3: 84,
1319
+ 0x1AC4: 84,
1320
+ 0x1AC5: 84,
1321
+ 0x1AC6: 84,
1322
+ 0x1AC7: 84,
1323
+ 0x1AC8: 84,
1324
+ 0x1AC9: 84,
1325
+ 0x1ACA: 84,
1326
+ 0x1ACB: 84,
1327
+ 0x1ACC: 84,
1328
+ 0x1ACD: 84,
1329
+ 0x1ACE: 84,
1330
+ 0x1B00: 84,
1331
+ 0x1B01: 84,
1332
+ 0x1B02: 84,
1333
+ 0x1B03: 84,
1334
+ 0x1B34: 84,
1335
+ 0x1B36: 84,
1336
+ 0x1B37: 84,
1337
+ 0x1B38: 84,
1338
+ 0x1B39: 84,
1339
+ 0x1B3A: 84,
1340
+ 0x1B3C: 84,
1341
+ 0x1B42: 84,
1342
+ 0x1B6B: 84,
1343
+ 0x1B6C: 84,
1344
+ 0x1B6D: 84,
1345
+ 0x1B6E: 84,
1346
+ 0x1B6F: 84,
1347
+ 0x1B70: 84,
1348
+ 0x1B71: 84,
1349
+ 0x1B72: 84,
1350
+ 0x1B73: 84,
1351
+ 0x1B80: 84,
1352
+ 0x1B81: 84,
1353
+ 0x1BA2: 84,
1354
+ 0x1BA3: 84,
1355
+ 0x1BA4: 84,
1356
+ 0x1BA5: 84,
1357
+ 0x1BA8: 84,
1358
+ 0x1BA9: 84,
1359
+ 0x1BAB: 84,
1360
+ 0x1BAC: 84,
1361
+ 0x1BAD: 84,
1362
+ 0x1BE6: 84,
1363
+ 0x1BE8: 84,
1364
+ 0x1BE9: 84,
1365
+ 0x1BED: 84,
1366
+ 0x1BEF: 84,
1367
+ 0x1BF0: 84,
1368
+ 0x1BF1: 84,
1369
+ 0x1C2C: 84,
1370
+ 0x1C2D: 84,
1371
+ 0x1C2E: 84,
1372
+ 0x1C2F: 84,
1373
+ 0x1C30: 84,
1374
+ 0x1C31: 84,
1375
+ 0x1C32: 84,
1376
+ 0x1C33: 84,
1377
+ 0x1C36: 84,
1378
+ 0x1C37: 84,
1379
+ 0x1CD0: 84,
1380
+ 0x1CD1: 84,
1381
+ 0x1CD2: 84,
1382
+ 0x1CD4: 84,
1383
+ 0x1CD5: 84,
1384
+ 0x1CD6: 84,
1385
+ 0x1CD7: 84,
1386
+ 0x1CD8: 84,
1387
+ 0x1CD9: 84,
1388
+ 0x1CDA: 84,
1389
+ 0x1CDB: 84,
1390
+ 0x1CDC: 84,
1391
+ 0x1CDD: 84,
1392
+ 0x1CDE: 84,
1393
+ 0x1CDF: 84,
1394
+ 0x1CE0: 84,
1395
+ 0x1CE2: 84,
1396
+ 0x1CE3: 84,
1397
+ 0x1CE4: 84,
1398
+ 0x1CE5: 84,
1399
+ 0x1CE6: 84,
1400
+ 0x1CE7: 84,
1401
+ 0x1CE8: 84,
1402
+ 0x1CED: 84,
1403
+ 0x1CF4: 84,
1404
+ 0x1CF8: 84,
1405
+ 0x1CF9: 84,
1406
+ 0x1DC0: 84,
1407
+ 0x1DC1: 84,
1408
+ 0x1DC2: 84,
1409
+ 0x1DC3: 84,
1410
+ 0x1DC4: 84,
1411
+ 0x1DC5: 84,
1412
+ 0x1DC6: 84,
1413
+ 0x1DC7: 84,
1414
+ 0x1DC8: 84,
1415
+ 0x1DC9: 84,
1416
+ 0x1DCA: 84,
1417
+ 0x1DCB: 84,
1418
+ 0x1DCC: 84,
1419
+ 0x1DCD: 84,
1420
+ 0x1DCE: 84,
1421
+ 0x1DCF: 84,
1422
+ 0x1DD0: 84,
1423
+ 0x1DD1: 84,
1424
+ 0x1DD2: 84,
1425
+ 0x1DD3: 84,
1426
+ 0x1DD4: 84,
1427
+ 0x1DD5: 84,
1428
+ 0x1DD6: 84,
1429
+ 0x1DD7: 84,
1430
+ 0x1DD8: 84,
1431
+ 0x1DD9: 84,
1432
+ 0x1DDA: 84,
1433
+ 0x1DDB: 84,
1434
+ 0x1DDC: 84,
1435
+ 0x1DDD: 84,
1436
+ 0x1DDE: 84,
1437
+ 0x1DDF: 84,
1438
+ 0x1DE0: 84,
1439
+ 0x1DE1: 84,
1440
+ 0x1DE2: 84,
1441
+ 0x1DE3: 84,
1442
+ 0x1DE4: 84,
1443
+ 0x1DE5: 84,
1444
+ 0x1DE6: 84,
1445
+ 0x1DE7: 84,
1446
+ 0x1DE8: 84,
1447
+ 0x1DE9: 84,
1448
+ 0x1DEA: 84,
1449
+ 0x1DEB: 84,
1450
+ 0x1DEC: 84,
1451
+ 0x1DED: 84,
1452
+ 0x1DEE: 84,
1453
+ 0x1DEF: 84,
1454
+ 0x1DF0: 84,
1455
+ 0x1DF1: 84,
1456
+ 0x1DF2: 84,
1457
+ 0x1DF3: 84,
1458
+ 0x1DF4: 84,
1459
+ 0x1DF5: 84,
1460
+ 0x1DF6: 84,
1461
+ 0x1DF7: 84,
1462
+ 0x1DF8: 84,
1463
+ 0x1DF9: 84,
1464
+ 0x1DFA: 84,
1465
+ 0x1DFB: 84,
1466
+ 0x1DFC: 84,
1467
+ 0x1DFD: 84,
1468
+ 0x1DFE: 84,
1469
+ 0x1DFF: 84,
1470
+ 0x200B: 84,
1471
+ 0x200D: 67,
1472
+ 0x200E: 84,
1473
+ 0x200F: 84,
1474
+ 0x202A: 84,
1475
+ 0x202B: 84,
1476
+ 0x202C: 84,
1477
+ 0x202D: 84,
1478
+ 0x202E: 84,
1479
+ 0x2060: 84,
1480
+ 0x2061: 84,
1481
+ 0x2062: 84,
1482
+ 0x2063: 84,
1483
+ 0x2064: 84,
1484
+ 0x206A: 84,
1485
+ 0x206B: 84,
1486
+ 0x206C: 84,
1487
+ 0x206D: 84,
1488
+ 0x206E: 84,
1489
+ 0x206F: 84,
1490
+ 0x20D0: 84,
1491
+ 0x20D1: 84,
1492
+ 0x20D2: 84,
1493
+ 0x20D3: 84,
1494
+ 0x20D4: 84,
1495
+ 0x20D5: 84,
1496
+ 0x20D6: 84,
1497
+ 0x20D7: 84,
1498
+ 0x20D8: 84,
1499
+ 0x20D9: 84,
1500
+ 0x20DA: 84,
1501
+ 0x20DB: 84,
1502
+ 0x20DC: 84,
1503
+ 0x20DD: 84,
1504
+ 0x20DE: 84,
1505
+ 0x20DF: 84,
1506
+ 0x20E0: 84,
1507
+ 0x20E1: 84,
1508
+ 0x20E2: 84,
1509
+ 0x20E3: 84,
1510
+ 0x20E4: 84,
1511
+ 0x20E5: 84,
1512
+ 0x20E6: 84,
1513
+ 0x20E7: 84,
1514
+ 0x20E8: 84,
1515
+ 0x20E9: 84,
1516
+ 0x20EA: 84,
1517
+ 0x20EB: 84,
1518
+ 0x20EC: 84,
1519
+ 0x20ED: 84,
1520
+ 0x20EE: 84,
1521
+ 0x20EF: 84,
1522
+ 0x20F0: 84,
1523
+ 0x2CEF: 84,
1524
+ 0x2CF0: 84,
1525
+ 0x2CF1: 84,
1526
+ 0x2D7F: 84,
1527
+ 0x2DE0: 84,
1528
+ 0x2DE1: 84,
1529
+ 0x2DE2: 84,
1530
+ 0x2DE3: 84,
1531
+ 0x2DE4: 84,
1532
+ 0x2DE5: 84,
1533
+ 0x2DE6: 84,
1534
+ 0x2DE7: 84,
1535
+ 0x2DE8: 84,
1536
+ 0x2DE9: 84,
1537
+ 0x2DEA: 84,
1538
+ 0x2DEB: 84,
1539
+ 0x2DEC: 84,
1540
+ 0x2DED: 84,
1541
+ 0x2DEE: 84,
1542
+ 0x2DEF: 84,
1543
+ 0x2DF0: 84,
1544
+ 0x2DF1: 84,
1545
+ 0x2DF2: 84,
1546
+ 0x2DF3: 84,
1547
+ 0x2DF4: 84,
1548
+ 0x2DF5: 84,
1549
+ 0x2DF6: 84,
1550
+ 0x2DF7: 84,
1551
+ 0x2DF8: 84,
1552
+ 0x2DF9: 84,
1553
+ 0x2DFA: 84,
1554
+ 0x2DFB: 84,
1555
+ 0x2DFC: 84,
1556
+ 0x2DFD: 84,
1557
+ 0x2DFE: 84,
1558
+ 0x2DFF: 84,
1559
+ 0x302A: 84,
1560
+ 0x302B: 84,
1561
+ 0x302C: 84,
1562
+ 0x302D: 84,
1563
+ 0x3099: 84,
1564
+ 0x309A: 84,
1565
+ 0xA66F: 84,
1566
+ 0xA670: 84,
1567
+ 0xA671: 84,
1568
+ 0xA672: 84,
1569
+ 0xA674: 84,
1570
+ 0xA675: 84,
1571
+ 0xA676: 84,
1572
+ 0xA677: 84,
1573
+ 0xA678: 84,
1574
+ 0xA679: 84,
1575
+ 0xA67A: 84,
1576
+ 0xA67B: 84,
1577
+ 0xA67C: 84,
1578
+ 0xA67D: 84,
1579
+ 0xA69E: 84,
1580
+ 0xA69F: 84,
1581
+ 0xA6F0: 84,
1582
+ 0xA6F1: 84,
1583
+ 0xA802: 84,
1584
+ 0xA806: 84,
1585
+ 0xA80B: 84,
1586
+ 0xA825: 84,
1587
+ 0xA826: 84,
1588
+ 0xA82C: 84,
1589
+ 0xA840: 68,
1590
+ 0xA841: 68,
1591
+ 0xA842: 68,
1592
+ 0xA843: 68,
1593
+ 0xA844: 68,
1594
+ 0xA845: 68,
1595
+ 0xA846: 68,
1596
+ 0xA847: 68,
1597
+ 0xA848: 68,
1598
+ 0xA849: 68,
1599
+ 0xA84A: 68,
1600
+ 0xA84B: 68,
1601
+ 0xA84C: 68,
1602
+ 0xA84D: 68,
1603
+ 0xA84E: 68,
1604
+ 0xA84F: 68,
1605
+ 0xA850: 68,
1606
+ 0xA851: 68,
1607
+ 0xA852: 68,
1608
+ 0xA853: 68,
1609
+ 0xA854: 68,
1610
+ 0xA855: 68,
1611
+ 0xA856: 68,
1612
+ 0xA857: 68,
1613
+ 0xA858: 68,
1614
+ 0xA859: 68,
1615
+ 0xA85A: 68,
1616
+ 0xA85B: 68,
1617
+ 0xA85C: 68,
1618
+ 0xA85D: 68,
1619
+ 0xA85E: 68,
1620
+ 0xA85F: 68,
1621
+ 0xA860: 68,
1622
+ 0xA861: 68,
1623
+ 0xA862: 68,
1624
+ 0xA863: 68,
1625
+ 0xA864: 68,
1626
+ 0xA865: 68,
1627
+ 0xA866: 68,
1628
+ 0xA867: 68,
1629
+ 0xA868: 68,
1630
+ 0xA869: 68,
1631
+ 0xA86A: 68,
1632
+ 0xA86B: 68,
1633
+ 0xA86C: 68,
1634
+ 0xA86D: 68,
1635
+ 0xA86E: 68,
1636
+ 0xA86F: 68,
1637
+ 0xA870: 68,
1638
+ 0xA871: 68,
1639
+ 0xA872: 76,
1640
+ 0xA8C4: 84,
1641
+ 0xA8C5: 84,
1642
+ 0xA8E0: 84,
1643
+ 0xA8E1: 84,
1644
+ 0xA8E2: 84,
1645
+ 0xA8E3: 84,
1646
+ 0xA8E4: 84,
1647
+ 0xA8E5: 84,
1648
+ 0xA8E6: 84,
1649
+ 0xA8E7: 84,
1650
+ 0xA8E8: 84,
1651
+ 0xA8E9: 84,
1652
+ 0xA8EA: 84,
1653
+ 0xA8EB: 84,
1654
+ 0xA8EC: 84,
1655
+ 0xA8ED: 84,
1656
+ 0xA8EE: 84,
1657
+ 0xA8EF: 84,
1658
+ 0xA8F0: 84,
1659
+ 0xA8F1: 84,
1660
+ 0xA8FF: 84,
1661
+ 0xA926: 84,
1662
+ 0xA927: 84,
1663
+ 0xA928: 84,
1664
+ 0xA929: 84,
1665
+ 0xA92A: 84,
1666
+ 0xA92B: 84,
1667
+ 0xA92C: 84,
1668
+ 0xA92D: 84,
1669
+ 0xA947: 84,
1670
+ 0xA948: 84,
1671
+ 0xA949: 84,
1672
+ 0xA94A: 84,
1673
+ 0xA94B: 84,
1674
+ 0xA94C: 84,
1675
+ 0xA94D: 84,
1676
+ 0xA94E: 84,
1677
+ 0xA94F: 84,
1678
+ 0xA950: 84,
1679
+ 0xA951: 84,
1680
+ 0xA980: 84,
1681
+ 0xA981: 84,
1682
+ 0xA982: 84,
1683
+ 0xA9B3: 84,
1684
+ 0xA9B6: 84,
1685
+ 0xA9B7: 84,
1686
+ 0xA9B8: 84,
1687
+ 0xA9B9: 84,
1688
+ 0xA9BC: 84,
1689
+ 0xA9BD: 84,
1690
+ 0xA9E5: 84,
1691
+ 0xAA29: 84,
1692
+ 0xAA2A: 84,
1693
+ 0xAA2B: 84,
1694
+ 0xAA2C: 84,
1695
+ 0xAA2D: 84,
1696
+ 0xAA2E: 84,
1697
+ 0xAA31: 84,
1698
+ 0xAA32: 84,
1699
+ 0xAA35: 84,
1700
+ 0xAA36: 84,
1701
+ 0xAA43: 84,
1702
+ 0xAA4C: 84,
1703
+ 0xAA7C: 84,
1704
+ 0xAAB0: 84,
1705
+ 0xAAB2: 84,
1706
+ 0xAAB3: 84,
1707
+ 0xAAB4: 84,
1708
+ 0xAAB7: 84,
1709
+ 0xAAB8: 84,
1710
+ 0xAABE: 84,
1711
+ 0xAABF: 84,
1712
+ 0xAAC1: 84,
1713
+ 0xAAEC: 84,
1714
+ 0xAAED: 84,
1715
+ 0xAAF6: 84,
1716
+ 0xABE5: 84,
1717
+ 0xABE8: 84,
1718
+ 0xABED: 84,
1719
+ 0xFB1E: 84,
1720
+ 0xFE00: 84,
1721
+ 0xFE01: 84,
1722
+ 0xFE02: 84,
1723
+ 0xFE03: 84,
1724
+ 0xFE04: 84,
1725
+ 0xFE05: 84,
1726
+ 0xFE06: 84,
1727
+ 0xFE07: 84,
1728
+ 0xFE08: 84,
1729
+ 0xFE09: 84,
1730
+ 0xFE0A: 84,
1731
+ 0xFE0B: 84,
1732
+ 0xFE0C: 84,
1733
+ 0xFE0D: 84,
1734
+ 0xFE0E: 84,
1735
+ 0xFE0F: 84,
1736
+ 0xFE20: 84,
1737
+ 0xFE21: 84,
1738
+ 0xFE22: 84,
1739
+ 0xFE23: 84,
1740
+ 0xFE24: 84,
1741
+ 0xFE25: 84,
1742
+ 0xFE26: 84,
1743
+ 0xFE27: 84,
1744
+ 0xFE28: 84,
1745
+ 0xFE29: 84,
1746
+ 0xFE2A: 84,
1747
+ 0xFE2B: 84,
1748
+ 0xFE2C: 84,
1749
+ 0xFE2D: 84,
1750
+ 0xFE2E: 84,
1751
+ 0xFE2F: 84,
1752
+ 0xFEFF: 84,
1753
+ 0xFFF9: 84,
1754
+ 0xFFFA: 84,
1755
+ 0xFFFB: 84,
1756
+ 0x101FD: 84,
1757
+ 0x102E0: 84,
1758
+ 0x10376: 84,
1759
+ 0x10377: 84,
1760
+ 0x10378: 84,
1761
+ 0x10379: 84,
1762
+ 0x1037A: 84,
1763
+ 0x10A01: 84,
1764
+ 0x10A02: 84,
1765
+ 0x10A03: 84,
1766
+ 0x10A05: 84,
1767
+ 0x10A06: 84,
1768
+ 0x10A0C: 84,
1769
+ 0x10A0D: 84,
1770
+ 0x10A0E: 84,
1771
+ 0x10A0F: 84,
1772
+ 0x10A38: 84,
1773
+ 0x10A39: 84,
1774
+ 0x10A3A: 84,
1775
+ 0x10A3F: 84,
1776
+ 0x10AC0: 68,
1777
+ 0x10AC1: 68,
1778
+ 0x10AC2: 68,
1779
+ 0x10AC3: 68,
1780
+ 0x10AC4: 68,
1781
+ 0x10AC5: 82,
1782
+ 0x10AC7: 82,
1783
+ 0x10AC9: 82,
1784
+ 0x10ACA: 82,
1785
+ 0x10ACD: 76,
1786
+ 0x10ACE: 82,
1787
+ 0x10ACF: 82,
1788
+ 0x10AD0: 82,
1789
+ 0x10AD1: 82,
1790
+ 0x10AD2: 82,
1791
+ 0x10AD3: 68,
1792
+ 0x10AD4: 68,
1793
+ 0x10AD5: 68,
1794
+ 0x10AD6: 68,
1795
+ 0x10AD7: 76,
1796
+ 0x10AD8: 68,
1797
+ 0x10AD9: 68,
1798
+ 0x10ADA: 68,
1799
+ 0x10ADB: 68,
1800
+ 0x10ADC: 68,
1801
+ 0x10ADD: 82,
1802
+ 0x10ADE: 68,
1803
+ 0x10ADF: 68,
1804
+ 0x10AE0: 68,
1805
+ 0x10AE1: 82,
1806
+ 0x10AE4: 82,
1807
+ 0x10AE5: 84,
1808
+ 0x10AE6: 84,
1809
+ 0x10AEB: 68,
1810
+ 0x10AEC: 68,
1811
+ 0x10AED: 68,
1812
+ 0x10AEE: 68,
1813
+ 0x10AEF: 82,
1814
+ 0x10B80: 68,
1815
+ 0x10B81: 82,
1816
+ 0x10B82: 68,
1817
+ 0x10B83: 82,
1818
+ 0x10B84: 82,
1819
+ 0x10B85: 82,
1820
+ 0x10B86: 68,
1821
+ 0x10B87: 68,
1822
+ 0x10B88: 68,
1823
+ 0x10B89: 82,
1824
+ 0x10B8A: 68,
1825
+ 0x10B8B: 68,
1826
+ 0x10B8C: 82,
1827
+ 0x10B8D: 68,
1828
+ 0x10B8E: 82,
1829
+ 0x10B8F: 82,
1830
+ 0x10B90: 68,
1831
+ 0x10B91: 82,
1832
+ 0x10BA9: 82,
1833
+ 0x10BAA: 82,
1834
+ 0x10BAB: 82,
1835
+ 0x10BAC: 82,
1836
+ 0x10BAD: 68,
1837
+ 0x10BAE: 68,
1838
+ 0x10D00: 76,
1839
+ 0x10D01: 68,
1840
+ 0x10D02: 68,
1841
+ 0x10D03: 68,
1842
+ 0x10D04: 68,
1843
+ 0x10D05: 68,
1844
+ 0x10D06: 68,
1845
+ 0x10D07: 68,
1846
+ 0x10D08: 68,
1847
+ 0x10D09: 68,
1848
+ 0x10D0A: 68,
1849
+ 0x10D0B: 68,
1850
+ 0x10D0C: 68,
1851
+ 0x10D0D: 68,
1852
+ 0x10D0E: 68,
1853
+ 0x10D0F: 68,
1854
+ 0x10D10: 68,
1855
+ 0x10D11: 68,
1856
+ 0x10D12: 68,
1857
+ 0x10D13: 68,
1858
+ 0x10D14: 68,
1859
+ 0x10D15: 68,
1860
+ 0x10D16: 68,
1861
+ 0x10D17: 68,
1862
+ 0x10D18: 68,
1863
+ 0x10D19: 68,
1864
+ 0x10D1A: 68,
1865
+ 0x10D1B: 68,
1866
+ 0x10D1C: 68,
1867
+ 0x10D1D: 68,
1868
+ 0x10D1E: 68,
1869
+ 0x10D1F: 68,
1870
+ 0x10D20: 68,
1871
+ 0x10D21: 68,
1872
+ 0x10D22: 82,
1873
+ 0x10D23: 68,
1874
+ 0x10D24: 84,
1875
+ 0x10D25: 84,
1876
+ 0x10D26: 84,
1877
+ 0x10D27: 84,
1878
+ 0x10D69: 84,
1879
+ 0x10D6A: 84,
1880
+ 0x10D6B: 84,
1881
+ 0x10D6C: 84,
1882
+ 0x10D6D: 84,
1883
+ 0x10EAB: 84,
1884
+ 0x10EAC: 84,
1885
+ 0x10EC2: 82,
1886
+ 0x10EC3: 68,
1887
+ 0x10EC4: 68,
1888
+ 0x10EFC: 84,
1889
+ 0x10EFD: 84,
1890
+ 0x10EFE: 84,
1891
+ 0x10EFF: 84,
1892
+ 0x10F30: 68,
1893
+ 0x10F31: 68,
1894
+ 0x10F32: 68,
1895
+ 0x10F33: 82,
1896
+ 0x10F34: 68,
1897
+ 0x10F35: 68,
1898
+ 0x10F36: 68,
1899
+ 0x10F37: 68,
1900
+ 0x10F38: 68,
1901
+ 0x10F39: 68,
1902
+ 0x10F3A: 68,
1903
+ 0x10F3B: 68,
1904
+ 0x10F3C: 68,
1905
+ 0x10F3D: 68,
1906
+ 0x10F3E: 68,
1907
+ 0x10F3F: 68,
1908
+ 0x10F40: 68,
1909
+ 0x10F41: 68,
1910
+ 0x10F42: 68,
1911
+ 0x10F43: 68,
1912
+ 0x10F44: 68,
1913
+ 0x10F46: 84,
1914
+ 0x10F47: 84,
1915
+ 0x10F48: 84,
1916
+ 0x10F49: 84,
1917
+ 0x10F4A: 84,
1918
+ 0x10F4B: 84,
1919
+ 0x10F4C: 84,
1920
+ 0x10F4D: 84,
1921
+ 0x10F4E: 84,
1922
+ 0x10F4F: 84,
1923
+ 0x10F50: 84,
1924
+ 0x10F51: 68,
1925
+ 0x10F52: 68,
1926
+ 0x10F53: 68,
1927
+ 0x10F54: 82,
1928
+ 0x10F70: 68,
1929
+ 0x10F71: 68,
1930
+ 0x10F72: 68,
1931
+ 0x10F73: 68,
1932
+ 0x10F74: 82,
1933
+ 0x10F75: 82,
1934
+ 0x10F76: 68,
1935
+ 0x10F77: 68,
1936
+ 0x10F78: 68,
1937
+ 0x10F79: 68,
1938
+ 0x10F7A: 68,
1939
+ 0x10F7B: 68,
1940
+ 0x10F7C: 68,
1941
+ 0x10F7D: 68,
1942
+ 0x10F7E: 68,
1943
+ 0x10F7F: 68,
1944
+ 0x10F80: 68,
1945
+ 0x10F81: 68,
1946
+ 0x10F82: 84,
1947
+ 0x10F83: 84,
1948
+ 0x10F84: 84,
1949
+ 0x10F85: 84,
1950
+ 0x10FB0: 68,
1951
+ 0x10FB2: 68,
1952
+ 0x10FB3: 68,
1953
+ 0x10FB4: 82,
1954
+ 0x10FB5: 82,
1955
+ 0x10FB6: 82,
1956
+ 0x10FB8: 68,
1957
+ 0x10FB9: 82,
1958
+ 0x10FBA: 82,
1959
+ 0x10FBB: 68,
1960
+ 0x10FBC: 68,
1961
+ 0x10FBD: 82,
1962
+ 0x10FBE: 68,
1963
+ 0x10FBF: 68,
1964
+ 0x10FC1: 68,
1965
+ 0x10FC2: 82,
1966
+ 0x10FC3: 82,
1967
+ 0x10FC4: 68,
1968
+ 0x10FC9: 82,
1969
+ 0x10FCA: 68,
1970
+ 0x10FCB: 76,
1971
+ 0x11001: 84,
1972
+ 0x11038: 84,
1973
+ 0x11039: 84,
1974
+ 0x1103A: 84,
1975
+ 0x1103B: 84,
1976
+ 0x1103C: 84,
1977
+ 0x1103D: 84,
1978
+ 0x1103E: 84,
1979
+ 0x1103F: 84,
1980
+ 0x11040: 84,
1981
+ 0x11041: 84,
1982
+ 0x11042: 84,
1983
+ 0x11043: 84,
1984
+ 0x11044: 84,
1985
+ 0x11045: 84,
1986
+ 0x11046: 84,
1987
+ 0x11070: 84,
1988
+ 0x11073: 84,
1989
+ 0x11074: 84,
1990
+ 0x1107F: 84,
1991
+ 0x11080: 84,
1992
+ 0x11081: 84,
1993
+ 0x110B3: 84,
1994
+ 0x110B4: 84,
1995
+ 0x110B5: 84,
1996
+ 0x110B6: 84,
1997
+ 0x110B9: 84,
1998
+ 0x110BA: 84,
1999
+ 0x110C2: 84,
2000
+ 0x11100: 84,
2001
+ 0x11101: 84,
2002
+ 0x11102: 84,
2003
+ 0x11127: 84,
2004
+ 0x11128: 84,
2005
+ 0x11129: 84,
2006
+ 0x1112A: 84,
2007
+ 0x1112B: 84,
2008
+ 0x1112D: 84,
2009
+ 0x1112E: 84,
2010
+ 0x1112F: 84,
2011
+ 0x11130: 84,
2012
+ 0x11131: 84,
2013
+ 0x11132: 84,
2014
+ 0x11133: 84,
2015
+ 0x11134: 84,
2016
+ 0x11173: 84,
2017
+ 0x11180: 84,
2018
+ 0x11181: 84,
2019
+ 0x111B6: 84,
2020
+ 0x111B7: 84,
2021
+ 0x111B8: 84,
2022
+ 0x111B9: 84,
2023
+ 0x111BA: 84,
2024
+ 0x111BB: 84,
2025
+ 0x111BC: 84,
2026
+ 0x111BD: 84,
2027
+ 0x111BE: 84,
2028
+ 0x111C9: 84,
2029
+ 0x111CA: 84,
2030
+ 0x111CB: 84,
2031
+ 0x111CC: 84,
2032
+ 0x111CF: 84,
2033
+ 0x1122F: 84,
2034
+ 0x11230: 84,
2035
+ 0x11231: 84,
2036
+ 0x11234: 84,
2037
+ 0x11236: 84,
2038
+ 0x11237: 84,
2039
+ 0x1123E: 84,
2040
+ 0x11241: 84,
2041
+ 0x112DF: 84,
2042
+ 0x112E3: 84,
2043
+ 0x112E4: 84,
2044
+ 0x112E5: 84,
2045
+ 0x112E6: 84,
2046
+ 0x112E7: 84,
2047
+ 0x112E8: 84,
2048
+ 0x112E9: 84,
2049
+ 0x112EA: 84,
2050
+ 0x11300: 84,
2051
+ 0x11301: 84,
2052
+ 0x1133B: 84,
2053
+ 0x1133C: 84,
2054
+ 0x11340: 84,
2055
+ 0x11366: 84,
2056
+ 0x11367: 84,
2057
+ 0x11368: 84,
2058
+ 0x11369: 84,
2059
+ 0x1136A: 84,
2060
+ 0x1136B: 84,
2061
+ 0x1136C: 84,
2062
+ 0x11370: 84,
2063
+ 0x11371: 84,
2064
+ 0x11372: 84,
2065
+ 0x11373: 84,
2066
+ 0x11374: 84,
2067
+ 0x113BB: 84,
2068
+ 0x113BC: 84,
2069
+ 0x113BD: 84,
2070
+ 0x113BE: 84,
2071
+ 0x113BF: 84,
2072
+ 0x113C0: 84,
2073
+ 0x113CE: 84,
2074
+ 0x113D0: 84,
2075
+ 0x113D2: 84,
2076
+ 0x113E1: 84,
2077
+ 0x113E2: 84,
2078
+ 0x11438: 84,
2079
+ 0x11439: 84,
2080
+ 0x1143A: 84,
2081
+ 0x1143B: 84,
2082
+ 0x1143C: 84,
2083
+ 0x1143D: 84,
2084
+ 0x1143E: 84,
2085
+ 0x1143F: 84,
2086
+ 0x11442: 84,
2087
+ 0x11443: 84,
2088
+ 0x11444: 84,
2089
+ 0x11446: 84,
2090
+ 0x1145E: 84,
2091
+ 0x114B3: 84,
2092
+ 0x114B4: 84,
2093
+ 0x114B5: 84,
2094
+ 0x114B6: 84,
2095
+ 0x114B7: 84,
2096
+ 0x114B8: 84,
2097
+ 0x114BA: 84,
2098
+ 0x114BF: 84,
2099
+ 0x114C0: 84,
2100
+ 0x114C2: 84,
2101
+ 0x114C3: 84,
2102
+ 0x115B2: 84,
2103
+ 0x115B3: 84,
2104
+ 0x115B4: 84,
2105
+ 0x115B5: 84,
2106
+ 0x115BC: 84,
2107
+ 0x115BD: 84,
2108
+ 0x115BF: 84,
2109
+ 0x115C0: 84,
2110
+ 0x115DC: 84,
2111
+ 0x115DD: 84,
2112
+ 0x11633: 84,
2113
+ 0x11634: 84,
2114
+ 0x11635: 84,
2115
+ 0x11636: 84,
2116
+ 0x11637: 84,
2117
+ 0x11638: 84,
2118
+ 0x11639: 84,
2119
+ 0x1163A: 84,
2120
+ 0x1163D: 84,
2121
+ 0x1163F: 84,
2122
+ 0x11640: 84,
2123
+ 0x116AB: 84,
2124
+ 0x116AD: 84,
2125
+ 0x116B0: 84,
2126
+ 0x116B1: 84,
2127
+ 0x116B2: 84,
2128
+ 0x116B3: 84,
2129
+ 0x116B4: 84,
2130
+ 0x116B5: 84,
2131
+ 0x116B7: 84,
2132
+ 0x1171D: 84,
2133
+ 0x1171F: 84,
2134
+ 0x11722: 84,
2135
+ 0x11723: 84,
2136
+ 0x11724: 84,
2137
+ 0x11725: 84,
2138
+ 0x11727: 84,
2139
+ 0x11728: 84,
2140
+ 0x11729: 84,
2141
+ 0x1172A: 84,
2142
+ 0x1172B: 84,
2143
+ 0x1182F: 84,
2144
+ 0x11830: 84,
2145
+ 0x11831: 84,
2146
+ 0x11832: 84,
2147
+ 0x11833: 84,
2148
+ 0x11834: 84,
2149
+ 0x11835: 84,
2150
+ 0x11836: 84,
2151
+ 0x11837: 84,
2152
+ 0x11839: 84,
2153
+ 0x1183A: 84,
2154
+ 0x1193B: 84,
2155
+ 0x1193C: 84,
2156
+ 0x1193E: 84,
2157
+ 0x11943: 84,
2158
+ 0x119D4: 84,
2159
+ 0x119D5: 84,
2160
+ 0x119D6: 84,
2161
+ 0x119D7: 84,
2162
+ 0x119DA: 84,
2163
+ 0x119DB: 84,
2164
+ 0x119E0: 84,
2165
+ 0x11A01: 84,
2166
+ 0x11A02: 84,
2167
+ 0x11A03: 84,
2168
+ 0x11A04: 84,
2169
+ 0x11A05: 84,
2170
+ 0x11A06: 84,
2171
+ 0x11A07: 84,
2172
+ 0x11A08: 84,
2173
+ 0x11A09: 84,
2174
+ 0x11A0A: 84,
2175
+ 0x11A33: 84,
2176
+ 0x11A34: 84,
2177
+ 0x11A35: 84,
2178
+ 0x11A36: 84,
2179
+ 0x11A37: 84,
2180
+ 0x11A38: 84,
2181
+ 0x11A3B: 84,
2182
+ 0x11A3C: 84,
2183
+ 0x11A3D: 84,
2184
+ 0x11A3E: 84,
2185
+ 0x11A47: 84,
2186
+ 0x11A51: 84,
2187
+ 0x11A52: 84,
2188
+ 0x11A53: 84,
2189
+ 0x11A54: 84,
2190
+ 0x11A55: 84,
2191
+ 0x11A56: 84,
2192
+ 0x11A59: 84,
2193
+ 0x11A5A: 84,
2194
+ 0x11A5B: 84,
2195
+ 0x11A8A: 84,
2196
+ 0x11A8B: 84,
2197
+ 0x11A8C: 84,
2198
+ 0x11A8D: 84,
2199
+ 0x11A8E: 84,
2200
+ 0x11A8F: 84,
2201
+ 0x11A90: 84,
2202
+ 0x11A91: 84,
2203
+ 0x11A92: 84,
2204
+ 0x11A93: 84,
2205
+ 0x11A94: 84,
2206
+ 0x11A95: 84,
2207
+ 0x11A96: 84,
2208
+ 0x11A98: 84,
2209
+ 0x11A99: 84,
2210
+ 0x11C30: 84,
2211
+ 0x11C31: 84,
2212
+ 0x11C32: 84,
2213
+ 0x11C33: 84,
2214
+ 0x11C34: 84,
2215
+ 0x11C35: 84,
2216
+ 0x11C36: 84,
2217
+ 0x11C38: 84,
2218
+ 0x11C39: 84,
2219
+ 0x11C3A: 84,
2220
+ 0x11C3B: 84,
2221
+ 0x11C3C: 84,
2222
+ 0x11C3D: 84,
2223
+ 0x11C3F: 84,
2224
+ 0x11C92: 84,
2225
+ 0x11C93: 84,
2226
+ 0x11C94: 84,
2227
+ 0x11C95: 84,
2228
+ 0x11C96: 84,
2229
+ 0x11C97: 84,
2230
+ 0x11C98: 84,
2231
+ 0x11C99: 84,
2232
+ 0x11C9A: 84,
2233
+ 0x11C9B: 84,
2234
+ 0x11C9C: 84,
2235
+ 0x11C9D: 84,
2236
+ 0x11C9E: 84,
2237
+ 0x11C9F: 84,
2238
+ 0x11CA0: 84,
2239
+ 0x11CA1: 84,
2240
+ 0x11CA2: 84,
2241
+ 0x11CA3: 84,
2242
+ 0x11CA4: 84,
2243
+ 0x11CA5: 84,
2244
+ 0x11CA6: 84,
2245
+ 0x11CA7: 84,
2246
+ 0x11CAA: 84,
2247
+ 0x11CAB: 84,
2248
+ 0x11CAC: 84,
2249
+ 0x11CAD: 84,
2250
+ 0x11CAE: 84,
2251
+ 0x11CAF: 84,
2252
+ 0x11CB0: 84,
2253
+ 0x11CB2: 84,
2254
+ 0x11CB3: 84,
2255
+ 0x11CB5: 84,
2256
+ 0x11CB6: 84,
2257
+ 0x11D31: 84,
2258
+ 0x11D32: 84,
2259
+ 0x11D33: 84,
2260
+ 0x11D34: 84,
2261
+ 0x11D35: 84,
2262
+ 0x11D36: 84,
2263
+ 0x11D3A: 84,
2264
+ 0x11D3C: 84,
2265
+ 0x11D3D: 84,
2266
+ 0x11D3F: 84,
2267
+ 0x11D40: 84,
2268
+ 0x11D41: 84,
2269
+ 0x11D42: 84,
2270
+ 0x11D43: 84,
2271
+ 0x11D44: 84,
2272
+ 0x11D45: 84,
2273
+ 0x11D47: 84,
2274
+ 0x11D90: 84,
2275
+ 0x11D91: 84,
2276
+ 0x11D95: 84,
2277
+ 0x11D97: 84,
2278
+ 0x11EF3: 84,
2279
+ 0x11EF4: 84,
2280
+ 0x11F00: 84,
2281
+ 0x11F01: 84,
2282
+ 0x11F36: 84,
2283
+ 0x11F37: 84,
2284
+ 0x11F38: 84,
2285
+ 0x11F39: 84,
2286
+ 0x11F3A: 84,
2287
+ 0x11F40: 84,
2288
+ 0x11F42: 84,
2289
+ 0x11F5A: 84,
2290
+ 0x13430: 84,
2291
+ 0x13431: 84,
2292
+ 0x13432: 84,
2293
+ 0x13433: 84,
2294
+ 0x13434: 84,
2295
+ 0x13435: 84,
2296
+ 0x13436: 84,
2297
+ 0x13437: 84,
2298
+ 0x13438: 84,
2299
+ 0x13439: 84,
2300
+ 0x1343A: 84,
2301
+ 0x1343B: 84,
2302
+ 0x1343C: 84,
2303
+ 0x1343D: 84,
2304
+ 0x1343E: 84,
2305
+ 0x1343F: 84,
2306
+ 0x13440: 84,
2307
+ 0x13447: 84,
2308
+ 0x13448: 84,
2309
+ 0x13449: 84,
2310
+ 0x1344A: 84,
2311
+ 0x1344B: 84,
2312
+ 0x1344C: 84,
2313
+ 0x1344D: 84,
2314
+ 0x1344E: 84,
2315
+ 0x1344F: 84,
2316
+ 0x13450: 84,
2317
+ 0x13451: 84,
2318
+ 0x13452: 84,
2319
+ 0x13453: 84,
2320
+ 0x13454: 84,
2321
+ 0x13455: 84,
2322
+ 0x1611E: 84,
2323
+ 0x1611F: 84,
2324
+ 0x16120: 84,
2325
+ 0x16121: 84,
2326
+ 0x16122: 84,
2327
+ 0x16123: 84,
2328
+ 0x16124: 84,
2329
+ 0x16125: 84,
2330
+ 0x16126: 84,
2331
+ 0x16127: 84,
2332
+ 0x16128: 84,
2333
+ 0x16129: 84,
2334
+ 0x1612D: 84,
2335
+ 0x1612E: 84,
2336
+ 0x1612F: 84,
2337
+ 0x16AF0: 84,
2338
+ 0x16AF1: 84,
2339
+ 0x16AF2: 84,
2340
+ 0x16AF3: 84,
2341
+ 0x16AF4: 84,
2342
+ 0x16B30: 84,
2343
+ 0x16B31: 84,
2344
+ 0x16B32: 84,
2345
+ 0x16B33: 84,
2346
+ 0x16B34: 84,
2347
+ 0x16B35: 84,
2348
+ 0x16B36: 84,
2349
+ 0x16F4F: 84,
2350
+ 0x16F8F: 84,
2351
+ 0x16F90: 84,
2352
+ 0x16F91: 84,
2353
+ 0x16F92: 84,
2354
+ 0x16FE4: 84,
2355
+ 0x1BC9D: 84,
2356
+ 0x1BC9E: 84,
2357
+ 0x1BCA0: 84,
2358
+ 0x1BCA1: 84,
2359
+ 0x1BCA2: 84,
2360
+ 0x1BCA3: 84,
2361
+ 0x1CF00: 84,
2362
+ 0x1CF01: 84,
2363
+ 0x1CF02: 84,
2364
+ 0x1CF03: 84,
2365
+ 0x1CF04: 84,
2366
+ 0x1CF05: 84,
2367
+ 0x1CF06: 84,
2368
+ 0x1CF07: 84,
2369
+ 0x1CF08: 84,
2370
+ 0x1CF09: 84,
2371
+ 0x1CF0A: 84,
2372
+ 0x1CF0B: 84,
2373
+ 0x1CF0C: 84,
2374
+ 0x1CF0D: 84,
2375
+ 0x1CF0E: 84,
2376
+ 0x1CF0F: 84,
2377
+ 0x1CF10: 84,
2378
+ 0x1CF11: 84,
2379
+ 0x1CF12: 84,
2380
+ 0x1CF13: 84,
2381
+ 0x1CF14: 84,
2382
+ 0x1CF15: 84,
2383
+ 0x1CF16: 84,
2384
+ 0x1CF17: 84,
2385
+ 0x1CF18: 84,
2386
+ 0x1CF19: 84,
2387
+ 0x1CF1A: 84,
2388
+ 0x1CF1B: 84,
2389
+ 0x1CF1C: 84,
2390
+ 0x1CF1D: 84,
2391
+ 0x1CF1E: 84,
2392
+ 0x1CF1F: 84,
2393
+ 0x1CF20: 84,
2394
+ 0x1CF21: 84,
2395
+ 0x1CF22: 84,
2396
+ 0x1CF23: 84,
2397
+ 0x1CF24: 84,
2398
+ 0x1CF25: 84,
2399
+ 0x1CF26: 84,
2400
+ 0x1CF27: 84,
2401
+ 0x1CF28: 84,
2402
+ 0x1CF29: 84,
2403
+ 0x1CF2A: 84,
2404
+ 0x1CF2B: 84,
2405
+ 0x1CF2C: 84,
2406
+ 0x1CF2D: 84,
2407
+ 0x1CF30: 84,
2408
+ 0x1CF31: 84,
2409
+ 0x1CF32: 84,
2410
+ 0x1CF33: 84,
2411
+ 0x1CF34: 84,
2412
+ 0x1CF35: 84,
2413
+ 0x1CF36: 84,
2414
+ 0x1CF37: 84,
2415
+ 0x1CF38: 84,
2416
+ 0x1CF39: 84,
2417
+ 0x1CF3A: 84,
2418
+ 0x1CF3B: 84,
2419
+ 0x1CF3C: 84,
2420
+ 0x1CF3D: 84,
2421
+ 0x1CF3E: 84,
2422
+ 0x1CF3F: 84,
2423
+ 0x1CF40: 84,
2424
+ 0x1CF41: 84,
2425
+ 0x1CF42: 84,
2426
+ 0x1CF43: 84,
2427
+ 0x1CF44: 84,
2428
+ 0x1CF45: 84,
2429
+ 0x1CF46: 84,
2430
+ 0x1D167: 84,
2431
+ 0x1D168: 84,
2432
+ 0x1D169: 84,
2433
+ 0x1D173: 84,
2434
+ 0x1D174: 84,
2435
+ 0x1D175: 84,
2436
+ 0x1D176: 84,
2437
+ 0x1D177: 84,
2438
+ 0x1D178: 84,
2439
+ 0x1D179: 84,
2440
+ 0x1D17A: 84,
2441
+ 0x1D17B: 84,
2442
+ 0x1D17C: 84,
2443
+ 0x1D17D: 84,
2444
+ 0x1D17E: 84,
2445
+ 0x1D17F: 84,
2446
+ 0x1D180: 84,
2447
+ 0x1D181: 84,
2448
+ 0x1D182: 84,
2449
+ 0x1D185: 84,
2450
+ 0x1D186: 84,
2451
+ 0x1D187: 84,
2452
+ 0x1D188: 84,
2453
+ 0x1D189: 84,
2454
+ 0x1D18A: 84,
2455
+ 0x1D18B: 84,
2456
+ 0x1D1AA: 84,
2457
+ 0x1D1AB: 84,
2458
+ 0x1D1AC: 84,
2459
+ 0x1D1AD: 84,
2460
+ 0x1D242: 84,
2461
+ 0x1D243: 84,
2462
+ 0x1D244: 84,
2463
+ 0x1DA00: 84,
2464
+ 0x1DA01: 84,
2465
+ 0x1DA02: 84,
2466
+ 0x1DA03: 84,
2467
+ 0x1DA04: 84,
2468
+ 0x1DA05: 84,
2469
+ 0x1DA06: 84,
2470
+ 0x1DA07: 84,
2471
+ 0x1DA08: 84,
2472
+ 0x1DA09: 84,
2473
+ 0x1DA0A: 84,
2474
+ 0x1DA0B: 84,
2475
+ 0x1DA0C: 84,
2476
+ 0x1DA0D: 84,
2477
+ 0x1DA0E: 84,
2478
+ 0x1DA0F: 84,
2479
+ 0x1DA10: 84,
2480
+ 0x1DA11: 84,
2481
+ 0x1DA12: 84,
2482
+ 0x1DA13: 84,
2483
+ 0x1DA14: 84,
2484
+ 0x1DA15: 84,
2485
+ 0x1DA16: 84,
2486
+ 0x1DA17: 84,
2487
+ 0x1DA18: 84,
2488
+ 0x1DA19: 84,
2489
+ 0x1DA1A: 84,
2490
+ 0x1DA1B: 84,
2491
+ 0x1DA1C: 84,
2492
+ 0x1DA1D: 84,
2493
+ 0x1DA1E: 84,
2494
+ 0x1DA1F: 84,
2495
+ 0x1DA20: 84,
2496
+ 0x1DA21: 84,
2497
+ 0x1DA22: 84,
2498
+ 0x1DA23: 84,
2499
+ 0x1DA24: 84,
2500
+ 0x1DA25: 84,
2501
+ 0x1DA26: 84,
2502
+ 0x1DA27: 84,
2503
+ 0x1DA28: 84,
2504
+ 0x1DA29: 84,
2505
+ 0x1DA2A: 84,
2506
+ 0x1DA2B: 84,
2507
+ 0x1DA2C: 84,
2508
+ 0x1DA2D: 84,
2509
+ 0x1DA2E: 84,
2510
+ 0x1DA2F: 84,
2511
+ 0x1DA30: 84,
2512
+ 0x1DA31: 84,
2513
+ 0x1DA32: 84,
2514
+ 0x1DA33: 84,
2515
+ 0x1DA34: 84,
2516
+ 0x1DA35: 84,
2517
+ 0x1DA36: 84,
2518
+ 0x1DA3B: 84,
2519
+ 0x1DA3C: 84,
2520
+ 0x1DA3D: 84,
2521
+ 0x1DA3E: 84,
2522
+ 0x1DA3F: 84,
2523
+ 0x1DA40: 84,
2524
+ 0x1DA41: 84,
2525
+ 0x1DA42: 84,
2526
+ 0x1DA43: 84,
2527
+ 0x1DA44: 84,
2528
+ 0x1DA45: 84,
2529
+ 0x1DA46: 84,
2530
+ 0x1DA47: 84,
2531
+ 0x1DA48: 84,
2532
+ 0x1DA49: 84,
2533
+ 0x1DA4A: 84,
2534
+ 0x1DA4B: 84,
2535
+ 0x1DA4C: 84,
2536
+ 0x1DA4D: 84,
2537
+ 0x1DA4E: 84,
2538
+ 0x1DA4F: 84,
2539
+ 0x1DA50: 84,
2540
+ 0x1DA51: 84,
2541
+ 0x1DA52: 84,
2542
+ 0x1DA53: 84,
2543
+ 0x1DA54: 84,
2544
+ 0x1DA55: 84,
2545
+ 0x1DA56: 84,
2546
+ 0x1DA57: 84,
2547
+ 0x1DA58: 84,
2548
+ 0x1DA59: 84,
2549
+ 0x1DA5A: 84,
2550
+ 0x1DA5B: 84,
2551
+ 0x1DA5C: 84,
2552
+ 0x1DA5D: 84,
2553
+ 0x1DA5E: 84,
2554
+ 0x1DA5F: 84,
2555
+ 0x1DA60: 84,
2556
+ 0x1DA61: 84,
2557
+ 0x1DA62: 84,
2558
+ 0x1DA63: 84,
2559
+ 0x1DA64: 84,
2560
+ 0x1DA65: 84,
2561
+ 0x1DA66: 84,
2562
+ 0x1DA67: 84,
2563
+ 0x1DA68: 84,
2564
+ 0x1DA69: 84,
2565
+ 0x1DA6A: 84,
2566
+ 0x1DA6B: 84,
2567
+ 0x1DA6C: 84,
2568
+ 0x1DA75: 84,
2569
+ 0x1DA84: 84,
2570
+ 0x1DA9B: 84,
2571
+ 0x1DA9C: 84,
2572
+ 0x1DA9D: 84,
2573
+ 0x1DA9E: 84,
2574
+ 0x1DA9F: 84,
2575
+ 0x1DAA1: 84,
2576
+ 0x1DAA2: 84,
2577
+ 0x1DAA3: 84,
2578
+ 0x1DAA4: 84,
2579
+ 0x1DAA5: 84,
2580
+ 0x1DAA6: 84,
2581
+ 0x1DAA7: 84,
2582
+ 0x1DAA8: 84,
2583
+ 0x1DAA9: 84,
2584
+ 0x1DAAA: 84,
2585
+ 0x1DAAB: 84,
2586
+ 0x1DAAC: 84,
2587
+ 0x1DAAD: 84,
2588
+ 0x1DAAE: 84,
2589
+ 0x1DAAF: 84,
2590
+ 0x1E000: 84,
2591
+ 0x1E001: 84,
2592
+ 0x1E002: 84,
2593
+ 0x1E003: 84,
2594
+ 0x1E004: 84,
2595
+ 0x1E005: 84,
2596
+ 0x1E006: 84,
2597
+ 0x1E008: 84,
2598
+ 0x1E009: 84,
2599
+ 0x1E00A: 84,
2600
+ 0x1E00B: 84,
2601
+ 0x1E00C: 84,
2602
+ 0x1E00D: 84,
2603
+ 0x1E00E: 84,
2604
+ 0x1E00F: 84,
2605
+ 0x1E010: 84,
2606
+ 0x1E011: 84,
2607
+ 0x1E012: 84,
2608
+ 0x1E013: 84,
2609
+ 0x1E014: 84,
2610
+ 0x1E015: 84,
2611
+ 0x1E016: 84,
2612
+ 0x1E017: 84,
2613
+ 0x1E018: 84,
2614
+ 0x1E01B: 84,
2615
+ 0x1E01C: 84,
2616
+ 0x1E01D: 84,
2617
+ 0x1E01E: 84,
2618
+ 0x1E01F: 84,
2619
+ 0x1E020: 84,
2620
+ 0x1E021: 84,
2621
+ 0x1E023: 84,
2622
+ 0x1E024: 84,
2623
+ 0x1E026: 84,
2624
+ 0x1E027: 84,
2625
+ 0x1E028: 84,
2626
+ 0x1E029: 84,
2627
+ 0x1E02A: 84,
2628
+ 0x1E08F: 84,
2629
+ 0x1E130: 84,
2630
+ 0x1E131: 84,
2631
+ 0x1E132: 84,
2632
+ 0x1E133: 84,
2633
+ 0x1E134: 84,
2634
+ 0x1E135: 84,
2635
+ 0x1E136: 84,
2636
+ 0x1E2AE: 84,
2637
+ 0x1E2EC: 84,
2638
+ 0x1E2ED: 84,
2639
+ 0x1E2EE: 84,
2640
+ 0x1E2EF: 84,
2641
+ 0x1E4EC: 84,
2642
+ 0x1E4ED: 84,
2643
+ 0x1E4EE: 84,
2644
+ 0x1E4EF: 84,
2645
+ 0x1E5EE: 84,
2646
+ 0x1E5EF: 84,
2647
+ 0x1E8D0: 84,
2648
+ 0x1E8D1: 84,
2649
+ 0x1E8D2: 84,
2650
+ 0x1E8D3: 84,
2651
+ 0x1E8D4: 84,
2652
+ 0x1E8D5: 84,
2653
+ 0x1E8D6: 84,
2654
+ 0x1E900: 68,
2655
+ 0x1E901: 68,
2656
+ 0x1E902: 68,
2657
+ 0x1E903: 68,
2658
+ 0x1E904: 68,
2659
+ 0x1E905: 68,
2660
+ 0x1E906: 68,
2661
+ 0x1E907: 68,
2662
+ 0x1E908: 68,
2663
+ 0x1E909: 68,
2664
+ 0x1E90A: 68,
2665
+ 0x1E90B: 68,
2666
+ 0x1E90C: 68,
2667
+ 0x1E90D: 68,
2668
+ 0x1E90E: 68,
2669
+ 0x1E90F: 68,
2670
+ 0x1E910: 68,
2671
+ 0x1E911: 68,
2672
+ 0x1E912: 68,
2673
+ 0x1E913: 68,
2674
+ 0x1E914: 68,
2675
+ 0x1E915: 68,
2676
+ 0x1E916: 68,
2677
+ 0x1E917: 68,
2678
+ 0x1E918: 68,
2679
+ 0x1E919: 68,
2680
+ 0x1E91A: 68,
2681
+ 0x1E91B: 68,
2682
+ 0x1E91C: 68,
2683
+ 0x1E91D: 68,
2684
+ 0x1E91E: 68,
2685
+ 0x1E91F: 68,
2686
+ 0x1E920: 68,
2687
+ 0x1E921: 68,
2688
+ 0x1E922: 68,
2689
+ 0x1E923: 68,
2690
+ 0x1E924: 68,
2691
+ 0x1E925: 68,
2692
+ 0x1E926: 68,
2693
+ 0x1E927: 68,
2694
+ 0x1E928: 68,
2695
+ 0x1E929: 68,
2696
+ 0x1E92A: 68,
2697
+ 0x1E92B: 68,
2698
+ 0x1E92C: 68,
2699
+ 0x1E92D: 68,
2700
+ 0x1E92E: 68,
2701
+ 0x1E92F: 68,
2702
+ 0x1E930: 68,
2703
+ 0x1E931: 68,
2704
+ 0x1E932: 68,
2705
+ 0x1E933: 68,
2706
+ 0x1E934: 68,
2707
+ 0x1E935: 68,
2708
+ 0x1E936: 68,
2709
+ 0x1E937: 68,
2710
+ 0x1E938: 68,
2711
+ 0x1E939: 68,
2712
+ 0x1E93A: 68,
2713
+ 0x1E93B: 68,
2714
+ 0x1E93C: 68,
2715
+ 0x1E93D: 68,
2716
+ 0x1E93E: 68,
2717
+ 0x1E93F: 68,
2718
+ 0x1E940: 68,
2719
+ 0x1E941: 68,
2720
+ 0x1E942: 68,
2721
+ 0x1E943: 68,
2722
+ 0x1E944: 84,
2723
+ 0x1E945: 84,
2724
+ 0x1E946: 84,
2725
+ 0x1E947: 84,
2726
+ 0x1E948: 84,
2727
+ 0x1E949: 84,
2728
+ 0x1E94A: 84,
2729
+ 0x1E94B: 84,
2730
+ 0xE0001: 84,
2731
+ 0xE0020: 84,
2732
+ 0xE0021: 84,
2733
+ 0xE0022: 84,
2734
+ 0xE0023: 84,
2735
+ 0xE0024: 84,
2736
+ 0xE0025: 84,
2737
+ 0xE0026: 84,
2738
+ 0xE0027: 84,
2739
+ 0xE0028: 84,
2740
+ 0xE0029: 84,
2741
+ 0xE002A: 84,
2742
+ 0xE002B: 84,
2743
+ 0xE002C: 84,
2744
+ 0xE002D: 84,
2745
+ 0xE002E: 84,
2746
+ 0xE002F: 84,
2747
+ 0xE0030: 84,
2748
+ 0xE0031: 84,
2749
+ 0xE0032: 84,
2750
+ 0xE0033: 84,
2751
+ 0xE0034: 84,
2752
+ 0xE0035: 84,
2753
+ 0xE0036: 84,
2754
+ 0xE0037: 84,
2755
+ 0xE0038: 84,
2756
+ 0xE0039: 84,
2757
+ 0xE003A: 84,
2758
+ 0xE003B: 84,
2759
+ 0xE003C: 84,
2760
+ 0xE003D: 84,
2761
+ 0xE003E: 84,
2762
+ 0xE003F: 84,
2763
+ 0xE0040: 84,
2764
+ 0xE0041: 84,
2765
+ 0xE0042: 84,
2766
+ 0xE0043: 84,
2767
+ 0xE0044: 84,
2768
+ 0xE0045: 84,
2769
+ 0xE0046: 84,
2770
+ 0xE0047: 84,
2771
+ 0xE0048: 84,
2772
+ 0xE0049: 84,
2773
+ 0xE004A: 84,
2774
+ 0xE004B: 84,
2775
+ 0xE004C: 84,
2776
+ 0xE004D: 84,
2777
+ 0xE004E: 84,
2778
+ 0xE004F: 84,
2779
+ 0xE0050: 84,
2780
+ 0xE0051: 84,
2781
+ 0xE0052: 84,
2782
+ 0xE0053: 84,
2783
+ 0xE0054: 84,
2784
+ 0xE0055: 84,
2785
+ 0xE0056: 84,
2786
+ 0xE0057: 84,
2787
+ 0xE0058: 84,
2788
+ 0xE0059: 84,
2789
+ 0xE005A: 84,
2790
+ 0xE005B: 84,
2791
+ 0xE005C: 84,
2792
+ 0xE005D: 84,
2793
+ 0xE005E: 84,
2794
+ 0xE005F: 84,
2795
+ 0xE0060: 84,
2796
+ 0xE0061: 84,
2797
+ 0xE0062: 84,
2798
+ 0xE0063: 84,
2799
+ 0xE0064: 84,
2800
+ 0xE0065: 84,
2801
+ 0xE0066: 84,
2802
+ 0xE0067: 84,
2803
+ 0xE0068: 84,
2804
+ 0xE0069: 84,
2805
+ 0xE006A: 84,
2806
+ 0xE006B: 84,
2807
+ 0xE006C: 84,
2808
+ 0xE006D: 84,
2809
+ 0xE006E: 84,
2810
+ 0xE006F: 84,
2811
+ 0xE0070: 84,
2812
+ 0xE0071: 84,
2813
+ 0xE0072: 84,
2814
+ 0xE0073: 84,
2815
+ 0xE0074: 84,
2816
+ 0xE0075: 84,
2817
+ 0xE0076: 84,
2818
+ 0xE0077: 84,
2819
+ 0xE0078: 84,
2820
+ 0xE0079: 84,
2821
+ 0xE007A: 84,
2822
+ 0xE007B: 84,
2823
+ 0xE007C: 84,
2824
+ 0xE007D: 84,
2825
+ 0xE007E: 84,
2826
+ 0xE007F: 84,
2827
+ 0xE0100: 84,
2828
+ 0xE0101: 84,
2829
+ 0xE0102: 84,
2830
+ 0xE0103: 84,
2831
+ 0xE0104: 84,
2832
+ 0xE0105: 84,
2833
+ 0xE0106: 84,
2834
+ 0xE0107: 84,
2835
+ 0xE0108: 84,
2836
+ 0xE0109: 84,
2837
+ 0xE010A: 84,
2838
+ 0xE010B: 84,
2839
+ 0xE010C: 84,
2840
+ 0xE010D: 84,
2841
+ 0xE010E: 84,
2842
+ 0xE010F: 84,
2843
+ 0xE0110: 84,
2844
+ 0xE0111: 84,
2845
+ 0xE0112: 84,
2846
+ 0xE0113: 84,
2847
+ 0xE0114: 84,
2848
+ 0xE0115: 84,
2849
+ 0xE0116: 84,
2850
+ 0xE0117: 84,
2851
+ 0xE0118: 84,
2852
+ 0xE0119: 84,
2853
+ 0xE011A: 84,
2854
+ 0xE011B: 84,
2855
+ 0xE011C: 84,
2856
+ 0xE011D: 84,
2857
+ 0xE011E: 84,
2858
+ 0xE011F: 84,
2859
+ 0xE0120: 84,
2860
+ 0xE0121: 84,
2861
+ 0xE0122: 84,
2862
+ 0xE0123: 84,
2863
+ 0xE0124: 84,
2864
+ 0xE0125: 84,
2865
+ 0xE0126: 84,
2866
+ 0xE0127: 84,
2867
+ 0xE0128: 84,
2868
+ 0xE0129: 84,
2869
+ 0xE012A: 84,
2870
+ 0xE012B: 84,
2871
+ 0xE012C: 84,
2872
+ 0xE012D: 84,
2873
+ 0xE012E: 84,
2874
+ 0xE012F: 84,
2875
+ 0xE0130: 84,
2876
+ 0xE0131: 84,
2877
+ 0xE0132: 84,
2878
+ 0xE0133: 84,
2879
+ 0xE0134: 84,
2880
+ 0xE0135: 84,
2881
+ 0xE0136: 84,
2882
+ 0xE0137: 84,
2883
+ 0xE0138: 84,
2884
+ 0xE0139: 84,
2885
+ 0xE013A: 84,
2886
+ 0xE013B: 84,
2887
+ 0xE013C: 84,
2888
+ 0xE013D: 84,
2889
+ 0xE013E: 84,
2890
+ 0xE013F: 84,
2891
+ 0xE0140: 84,
2892
+ 0xE0141: 84,
2893
+ 0xE0142: 84,
2894
+ 0xE0143: 84,
2895
+ 0xE0144: 84,
2896
+ 0xE0145: 84,
2897
+ 0xE0146: 84,
2898
+ 0xE0147: 84,
2899
+ 0xE0148: 84,
2900
+ 0xE0149: 84,
2901
+ 0xE014A: 84,
2902
+ 0xE014B: 84,
2903
+ 0xE014C: 84,
2904
+ 0xE014D: 84,
2905
+ 0xE014E: 84,
2906
+ 0xE014F: 84,
2907
+ 0xE0150: 84,
2908
+ 0xE0151: 84,
2909
+ 0xE0152: 84,
2910
+ 0xE0153: 84,
2911
+ 0xE0154: 84,
2912
+ 0xE0155: 84,
2913
+ 0xE0156: 84,
2914
+ 0xE0157: 84,
2915
+ 0xE0158: 84,
2916
+ 0xE0159: 84,
2917
+ 0xE015A: 84,
2918
+ 0xE015B: 84,
2919
+ 0xE015C: 84,
2920
+ 0xE015D: 84,
2921
+ 0xE015E: 84,
2922
+ 0xE015F: 84,
2923
+ 0xE0160: 84,
2924
+ 0xE0161: 84,
2925
+ 0xE0162: 84,
2926
+ 0xE0163: 84,
2927
+ 0xE0164: 84,
2928
+ 0xE0165: 84,
2929
+ 0xE0166: 84,
2930
+ 0xE0167: 84,
2931
+ 0xE0168: 84,
2932
+ 0xE0169: 84,
2933
+ 0xE016A: 84,
2934
+ 0xE016B: 84,
2935
+ 0xE016C: 84,
2936
+ 0xE016D: 84,
2937
+ 0xE016E: 84,
2938
+ 0xE016F: 84,
2939
+ 0xE0170: 84,
2940
+ 0xE0171: 84,
2941
+ 0xE0172: 84,
2942
+ 0xE0173: 84,
2943
+ 0xE0174: 84,
2944
+ 0xE0175: 84,
2945
+ 0xE0176: 84,
2946
+ 0xE0177: 84,
2947
+ 0xE0178: 84,
2948
+ 0xE0179: 84,
2949
+ 0xE017A: 84,
2950
+ 0xE017B: 84,
2951
+ 0xE017C: 84,
2952
+ 0xE017D: 84,
2953
+ 0xE017E: 84,
2954
+ 0xE017F: 84,
2955
+ 0xE0180: 84,
2956
+ 0xE0181: 84,
2957
+ 0xE0182: 84,
2958
+ 0xE0183: 84,
2959
+ 0xE0184: 84,
2960
+ 0xE0185: 84,
2961
+ 0xE0186: 84,
2962
+ 0xE0187: 84,
2963
+ 0xE0188: 84,
2964
+ 0xE0189: 84,
2965
+ 0xE018A: 84,
2966
+ 0xE018B: 84,
2967
+ 0xE018C: 84,
2968
+ 0xE018D: 84,
2969
+ 0xE018E: 84,
2970
+ 0xE018F: 84,
2971
+ 0xE0190: 84,
2972
+ 0xE0191: 84,
2973
+ 0xE0192: 84,
2974
+ 0xE0193: 84,
2975
+ 0xE0194: 84,
2976
+ 0xE0195: 84,
2977
+ 0xE0196: 84,
2978
+ 0xE0197: 84,
2979
+ 0xE0198: 84,
2980
+ 0xE0199: 84,
2981
+ 0xE019A: 84,
2982
+ 0xE019B: 84,
2983
+ 0xE019C: 84,
2984
+ 0xE019D: 84,
2985
+ 0xE019E: 84,
2986
+ 0xE019F: 84,
2987
+ 0xE01A0: 84,
2988
+ 0xE01A1: 84,
2989
+ 0xE01A2: 84,
2990
+ 0xE01A3: 84,
2991
+ 0xE01A4: 84,
2992
+ 0xE01A5: 84,
2993
+ 0xE01A6: 84,
2994
+ 0xE01A7: 84,
2995
+ 0xE01A8: 84,
2996
+ 0xE01A9: 84,
2997
+ 0xE01AA: 84,
2998
+ 0xE01AB: 84,
2999
+ 0xE01AC: 84,
3000
+ 0xE01AD: 84,
3001
+ 0xE01AE: 84,
3002
+ 0xE01AF: 84,
3003
+ 0xE01B0: 84,
3004
+ 0xE01B1: 84,
3005
+ 0xE01B2: 84,
3006
+ 0xE01B3: 84,
3007
+ 0xE01B4: 84,
3008
+ 0xE01B5: 84,
3009
+ 0xE01B6: 84,
3010
+ 0xE01B7: 84,
3011
+ 0xE01B8: 84,
3012
+ 0xE01B9: 84,
3013
+ 0xE01BA: 84,
3014
+ 0xE01BB: 84,
3015
+ 0xE01BC: 84,
3016
+ 0xE01BD: 84,
3017
+ 0xE01BE: 84,
3018
+ 0xE01BF: 84,
3019
+ 0xE01C0: 84,
3020
+ 0xE01C1: 84,
3021
+ 0xE01C2: 84,
3022
+ 0xE01C3: 84,
3023
+ 0xE01C4: 84,
3024
+ 0xE01C5: 84,
3025
+ 0xE01C6: 84,
3026
+ 0xE01C7: 84,
3027
+ 0xE01C8: 84,
3028
+ 0xE01C9: 84,
3029
+ 0xE01CA: 84,
3030
+ 0xE01CB: 84,
3031
+ 0xE01CC: 84,
3032
+ 0xE01CD: 84,
3033
+ 0xE01CE: 84,
3034
+ 0xE01CF: 84,
3035
+ 0xE01D0: 84,
3036
+ 0xE01D1: 84,
3037
+ 0xE01D2: 84,
3038
+ 0xE01D3: 84,
3039
+ 0xE01D4: 84,
3040
+ 0xE01D5: 84,
3041
+ 0xE01D6: 84,
3042
+ 0xE01D7: 84,
3043
+ 0xE01D8: 84,
3044
+ 0xE01D9: 84,
3045
+ 0xE01DA: 84,
3046
+ 0xE01DB: 84,
3047
+ 0xE01DC: 84,
3048
+ 0xE01DD: 84,
3049
+ 0xE01DE: 84,
3050
+ 0xE01DF: 84,
3051
+ 0xE01E0: 84,
3052
+ 0xE01E1: 84,
3053
+ 0xE01E2: 84,
3054
+ 0xE01E3: 84,
3055
+ 0xE01E4: 84,
3056
+ 0xE01E5: 84,
3057
+ 0xE01E6: 84,
3058
+ 0xE01E7: 84,
3059
+ 0xE01E8: 84,
3060
+ 0xE01E9: 84,
3061
+ 0xE01EA: 84,
3062
+ 0xE01EB: 84,
3063
+ 0xE01EC: 84,
3064
+ 0xE01ED: 84,
3065
+ 0xE01EE: 84,
3066
+ 0xE01EF: 84,
3067
+ }
3068
+ codepoint_classes = {
3069
+ "PVALID": (
3070
+ 0x2D0000002E,
3071
+ 0x300000003A,
3072
+ 0x610000007B,
3073
+ 0xDF000000F7,
3074
+ 0xF800000100,
3075
+ 0x10100000102,
3076
+ 0x10300000104,
3077
+ 0x10500000106,
3078
+ 0x10700000108,
3079
+ 0x1090000010A,
3080
+ 0x10B0000010C,
3081
+ 0x10D0000010E,
3082
+ 0x10F00000110,
3083
+ 0x11100000112,
3084
+ 0x11300000114,
3085
+ 0x11500000116,
3086
+ 0x11700000118,
3087
+ 0x1190000011A,
3088
+ 0x11B0000011C,
3089
+ 0x11D0000011E,
3090
+ 0x11F00000120,
3091
+ 0x12100000122,
3092
+ 0x12300000124,
3093
+ 0x12500000126,
3094
+ 0x12700000128,
3095
+ 0x1290000012A,
3096
+ 0x12B0000012C,
3097
+ 0x12D0000012E,
3098
+ 0x12F00000130,
3099
+ 0x13100000132,
3100
+ 0x13500000136,
3101
+ 0x13700000139,
3102
+ 0x13A0000013B,
3103
+ 0x13C0000013D,
3104
+ 0x13E0000013F,
3105
+ 0x14200000143,
3106
+ 0x14400000145,
3107
+ 0x14600000147,
3108
+ 0x14800000149,
3109
+ 0x14B0000014C,
3110
+ 0x14D0000014E,
3111
+ 0x14F00000150,
3112
+ 0x15100000152,
3113
+ 0x15300000154,
3114
+ 0x15500000156,
3115
+ 0x15700000158,
3116
+ 0x1590000015A,
3117
+ 0x15B0000015C,
3118
+ 0x15D0000015E,
3119
+ 0x15F00000160,
3120
+ 0x16100000162,
3121
+ 0x16300000164,
3122
+ 0x16500000166,
3123
+ 0x16700000168,
3124
+ 0x1690000016A,
3125
+ 0x16B0000016C,
3126
+ 0x16D0000016E,
3127
+ 0x16F00000170,
3128
+ 0x17100000172,
3129
+ 0x17300000174,
3130
+ 0x17500000176,
3131
+ 0x17700000178,
3132
+ 0x17A0000017B,
3133
+ 0x17C0000017D,
3134
+ 0x17E0000017F,
3135
+ 0x18000000181,
3136
+ 0x18300000184,
3137
+ 0x18500000186,
3138
+ 0x18800000189,
3139
+ 0x18C0000018E,
3140
+ 0x19200000193,
3141
+ 0x19500000196,
3142
+ 0x1990000019C,
3143
+ 0x19E0000019F,
3144
+ 0x1A1000001A2,
3145
+ 0x1A3000001A4,
3146
+ 0x1A5000001A6,
3147
+ 0x1A8000001A9,
3148
+ 0x1AA000001AC,
3149
+ 0x1AD000001AE,
3150
+ 0x1B0000001B1,
3151
+ 0x1B4000001B5,
3152
+ 0x1B6000001B7,
3153
+ 0x1B9000001BC,
3154
+ 0x1BD000001C4,
3155
+ 0x1CE000001CF,
3156
+ 0x1D0000001D1,
3157
+ 0x1D2000001D3,
3158
+ 0x1D4000001D5,
3159
+ 0x1D6000001D7,
3160
+ 0x1D8000001D9,
3161
+ 0x1DA000001DB,
3162
+ 0x1DC000001DE,
3163
+ 0x1DF000001E0,
3164
+ 0x1E1000001E2,
3165
+ 0x1E3000001E4,
3166
+ 0x1E5000001E6,
3167
+ 0x1E7000001E8,
3168
+ 0x1E9000001EA,
3169
+ 0x1EB000001EC,
3170
+ 0x1ED000001EE,
3171
+ 0x1EF000001F1,
3172
+ 0x1F5000001F6,
3173
+ 0x1F9000001FA,
3174
+ 0x1FB000001FC,
3175
+ 0x1FD000001FE,
3176
+ 0x1FF00000200,
3177
+ 0x20100000202,
3178
+ 0x20300000204,
3179
+ 0x20500000206,
3180
+ 0x20700000208,
3181
+ 0x2090000020A,
3182
+ 0x20B0000020C,
3183
+ 0x20D0000020E,
3184
+ 0x20F00000210,
3185
+ 0x21100000212,
3186
+ 0x21300000214,
3187
+ 0x21500000216,
3188
+ 0x21700000218,
3189
+ 0x2190000021A,
3190
+ 0x21B0000021C,
3191
+ 0x21D0000021E,
3192
+ 0x21F00000220,
3193
+ 0x22100000222,
3194
+ 0x22300000224,
3195
+ 0x22500000226,
3196
+ 0x22700000228,
3197
+ 0x2290000022A,
3198
+ 0x22B0000022C,
3199
+ 0x22D0000022E,
3200
+ 0x22F00000230,
3201
+ 0x23100000232,
3202
+ 0x2330000023A,
3203
+ 0x23C0000023D,
3204
+ 0x23F00000241,
3205
+ 0x24200000243,
3206
+ 0x24700000248,
3207
+ 0x2490000024A,
3208
+ 0x24B0000024C,
3209
+ 0x24D0000024E,
3210
+ 0x24F000002B0,
3211
+ 0x2B9000002C2,
3212
+ 0x2C6000002D2,
3213
+ 0x2EC000002ED,
3214
+ 0x2EE000002EF,
3215
+ 0x30000000340,
3216
+ 0x34200000343,
3217
+ 0x3460000034F,
3218
+ 0x35000000370,
3219
+ 0x37100000372,
3220
+ 0x37300000374,
3221
+ 0x37700000378,
3222
+ 0x37B0000037E,
3223
+ 0x39000000391,
3224
+ 0x3AC000003CF,
3225
+ 0x3D7000003D8,
3226
+ 0x3D9000003DA,
3227
+ 0x3DB000003DC,
3228
+ 0x3DD000003DE,
3229
+ 0x3DF000003E0,
3230
+ 0x3E1000003E2,
3231
+ 0x3E3000003E4,
3232
+ 0x3E5000003E6,
3233
+ 0x3E7000003E8,
3234
+ 0x3E9000003EA,
3235
+ 0x3EB000003EC,
3236
+ 0x3ED000003EE,
3237
+ 0x3EF000003F0,
3238
+ 0x3F3000003F4,
3239
+ 0x3F8000003F9,
3240
+ 0x3FB000003FD,
3241
+ 0x43000000460,
3242
+ 0x46100000462,
3243
+ 0x46300000464,
3244
+ 0x46500000466,
3245
+ 0x46700000468,
3246
+ 0x4690000046A,
3247
+ 0x46B0000046C,
3248
+ 0x46D0000046E,
3249
+ 0x46F00000470,
3250
+ 0x47100000472,
3251
+ 0x47300000474,
3252
+ 0x47500000476,
3253
+ 0x47700000478,
3254
+ 0x4790000047A,
3255
+ 0x47B0000047C,
3256
+ 0x47D0000047E,
3257
+ 0x47F00000480,
3258
+ 0x48100000482,
3259
+ 0x48300000488,
3260
+ 0x48B0000048C,
3261
+ 0x48D0000048E,
3262
+ 0x48F00000490,
3263
+ 0x49100000492,
3264
+ 0x49300000494,
3265
+ 0x49500000496,
3266
+ 0x49700000498,
3267
+ 0x4990000049A,
3268
+ 0x49B0000049C,
3269
+ 0x49D0000049E,
3270
+ 0x49F000004A0,
3271
+ 0x4A1000004A2,
3272
+ 0x4A3000004A4,
3273
+ 0x4A5000004A6,
3274
+ 0x4A7000004A8,
3275
+ 0x4A9000004AA,
3276
+ 0x4AB000004AC,
3277
+ 0x4AD000004AE,
3278
+ 0x4AF000004B0,
3279
+ 0x4B1000004B2,
3280
+ 0x4B3000004B4,
3281
+ 0x4B5000004B6,
3282
+ 0x4B7000004B8,
3283
+ 0x4B9000004BA,
3284
+ 0x4BB000004BC,
3285
+ 0x4BD000004BE,
3286
+ 0x4BF000004C0,
3287
+ 0x4C2000004C3,
3288
+ 0x4C4000004C5,
3289
+ 0x4C6000004C7,
3290
+ 0x4C8000004C9,
3291
+ 0x4CA000004CB,
3292
+ 0x4CC000004CD,
3293
+ 0x4CE000004D0,
3294
+ 0x4D1000004D2,
3295
+ 0x4D3000004D4,
3296
+ 0x4D5000004D6,
3297
+ 0x4D7000004D8,
3298
+ 0x4D9000004DA,
3299
+ 0x4DB000004DC,
3300
+ 0x4DD000004DE,
3301
+ 0x4DF000004E0,
3302
+ 0x4E1000004E2,
3303
+ 0x4E3000004E4,
3304
+ 0x4E5000004E6,
3305
+ 0x4E7000004E8,
3306
+ 0x4E9000004EA,
3307
+ 0x4EB000004EC,
3308
+ 0x4ED000004EE,
3309
+ 0x4EF000004F0,
3310
+ 0x4F1000004F2,
3311
+ 0x4F3000004F4,
3312
+ 0x4F5000004F6,
3313
+ 0x4F7000004F8,
3314
+ 0x4F9000004FA,
3315
+ 0x4FB000004FC,
3316
+ 0x4FD000004FE,
3317
+ 0x4FF00000500,
3318
+ 0x50100000502,
3319
+ 0x50300000504,
3320
+ 0x50500000506,
3321
+ 0x50700000508,
3322
+ 0x5090000050A,
3323
+ 0x50B0000050C,
3324
+ 0x50D0000050E,
3325
+ 0x50F00000510,
3326
+ 0x51100000512,
3327
+ 0x51300000514,
3328
+ 0x51500000516,
3329
+ 0x51700000518,
3330
+ 0x5190000051A,
3331
+ 0x51B0000051C,
3332
+ 0x51D0000051E,
3333
+ 0x51F00000520,
3334
+ 0x52100000522,
3335
+ 0x52300000524,
3336
+ 0x52500000526,
3337
+ 0x52700000528,
3338
+ 0x5290000052A,
3339
+ 0x52B0000052C,
3340
+ 0x52D0000052E,
3341
+ 0x52F00000530,
3342
+ 0x5590000055A,
3343
+ 0x56000000587,
3344
+ 0x58800000589,
3345
+ 0x591000005BE,
3346
+ 0x5BF000005C0,
3347
+ 0x5C1000005C3,
3348
+ 0x5C4000005C6,
3349
+ 0x5C7000005C8,
3350
+ 0x5D0000005EB,
3351
+ 0x5EF000005F3,
3352
+ 0x6100000061B,
3353
+ 0x62000000640,
3354
+ 0x64100000660,
3355
+ 0x66E00000675,
3356
+ 0x679000006D4,
3357
+ 0x6D5000006DD,
3358
+ 0x6DF000006E9,
3359
+ 0x6EA000006F0,
3360
+ 0x6FA00000700,
3361
+ 0x7100000074B,
3362
+ 0x74D000007B2,
3363
+ 0x7C0000007F6,
3364
+ 0x7FD000007FE,
3365
+ 0x8000000082E,
3366
+ 0x8400000085C,
3367
+ 0x8600000086B,
3368
+ 0x87000000888,
3369
+ 0x8890000088F,
3370
+ 0x897000008E2,
3371
+ 0x8E300000958,
3372
+ 0x96000000964,
3373
+ 0x96600000970,
3374
+ 0x97100000984,
3375
+ 0x9850000098D,
3376
+ 0x98F00000991,
3377
+ 0x993000009A9,
3378
+ 0x9AA000009B1,
3379
+ 0x9B2000009B3,
3380
+ 0x9B6000009BA,
3381
+ 0x9BC000009C5,
3382
+ 0x9C7000009C9,
3383
+ 0x9CB000009CF,
3384
+ 0x9D7000009D8,
3385
+ 0x9E0000009E4,
3386
+ 0x9E6000009F2,
3387
+ 0x9FC000009FD,
3388
+ 0x9FE000009FF,
3389
+ 0xA0100000A04,
3390
+ 0xA0500000A0B,
3391
+ 0xA0F00000A11,
3392
+ 0xA1300000A29,
3393
+ 0xA2A00000A31,
3394
+ 0xA3200000A33,
3395
+ 0xA3500000A36,
3396
+ 0xA3800000A3A,
3397
+ 0xA3C00000A3D,
3398
+ 0xA3E00000A43,
3399
+ 0xA4700000A49,
3400
+ 0xA4B00000A4E,
3401
+ 0xA5100000A52,
3402
+ 0xA5C00000A5D,
3403
+ 0xA6600000A76,
3404
+ 0xA8100000A84,
3405
+ 0xA8500000A8E,
3406
+ 0xA8F00000A92,
3407
+ 0xA9300000AA9,
3408
+ 0xAAA00000AB1,
3409
+ 0xAB200000AB4,
3410
+ 0xAB500000ABA,
3411
+ 0xABC00000AC6,
3412
+ 0xAC700000ACA,
3413
+ 0xACB00000ACE,
3414
+ 0xAD000000AD1,
3415
+ 0xAE000000AE4,
3416
+ 0xAE600000AF0,
3417
+ 0xAF900000B00,
3418
+ 0xB0100000B04,
3419
+ 0xB0500000B0D,
3420
+ 0xB0F00000B11,
3421
+ 0xB1300000B29,
3422
+ 0xB2A00000B31,
3423
+ 0xB3200000B34,
3424
+ 0xB3500000B3A,
3425
+ 0xB3C00000B45,
3426
+ 0xB4700000B49,
3427
+ 0xB4B00000B4E,
3428
+ 0xB5500000B58,
3429
+ 0xB5F00000B64,
3430
+ 0xB6600000B70,
3431
+ 0xB7100000B72,
3432
+ 0xB8200000B84,
3433
+ 0xB8500000B8B,
3434
+ 0xB8E00000B91,
3435
+ 0xB9200000B96,
3436
+ 0xB9900000B9B,
3437
+ 0xB9C00000B9D,
3438
+ 0xB9E00000BA0,
3439
+ 0xBA300000BA5,
3440
+ 0xBA800000BAB,
3441
+ 0xBAE00000BBA,
3442
+ 0xBBE00000BC3,
3443
+ 0xBC600000BC9,
3444
+ 0xBCA00000BCE,
3445
+ 0xBD000000BD1,
3446
+ 0xBD700000BD8,
3447
+ 0xBE600000BF0,
3448
+ 0xC0000000C0D,
3449
+ 0xC0E00000C11,
3450
+ 0xC1200000C29,
3451
+ 0xC2A00000C3A,
3452
+ 0xC3C00000C45,
3453
+ 0xC4600000C49,
3454
+ 0xC4A00000C4E,
3455
+ 0xC5500000C57,
3456
+ 0xC5800000C5B,
3457
+ 0xC5D00000C5E,
3458
+ 0xC6000000C64,
3459
+ 0xC6600000C70,
3460
+ 0xC8000000C84,
3461
+ 0xC8500000C8D,
3462
+ 0xC8E00000C91,
3463
+ 0xC9200000CA9,
3464
+ 0xCAA00000CB4,
3465
+ 0xCB500000CBA,
3466
+ 0xCBC00000CC5,
3467
+ 0xCC600000CC9,
3468
+ 0xCCA00000CCE,
3469
+ 0xCD500000CD7,
3470
+ 0xCDD00000CDF,
3471
+ 0xCE000000CE4,
3472
+ 0xCE600000CF0,
3473
+ 0xCF100000CF4,
3474
+ 0xD0000000D0D,
3475
+ 0xD0E00000D11,
3476
+ 0xD1200000D45,
3477
+ 0xD4600000D49,
3478
+ 0xD4A00000D4F,
3479
+ 0xD5400000D58,
3480
+ 0xD5F00000D64,
3481
+ 0xD6600000D70,
3482
+ 0xD7A00000D80,
3483
+ 0xD8100000D84,
3484
+ 0xD8500000D97,
3485
+ 0xD9A00000DB2,
3486
+ 0xDB300000DBC,
3487
+ 0xDBD00000DBE,
3488
+ 0xDC000000DC7,
3489
+ 0xDCA00000DCB,
3490
+ 0xDCF00000DD5,
3491
+ 0xDD600000DD7,
3492
+ 0xDD800000DE0,
3493
+ 0xDE600000DF0,
3494
+ 0xDF200000DF4,
3495
+ 0xE0100000E33,
3496
+ 0xE3400000E3B,
3497
+ 0xE4000000E4F,
3498
+ 0xE5000000E5A,
3499
+ 0xE8100000E83,
3500
+ 0xE8400000E85,
3501
+ 0xE8600000E8B,
3502
+ 0xE8C00000EA4,
3503
+ 0xEA500000EA6,
3504
+ 0xEA700000EB3,
3505
+ 0xEB400000EBE,
3506
+ 0xEC000000EC5,
3507
+ 0xEC600000EC7,
3508
+ 0xEC800000ECF,
3509
+ 0xED000000EDA,
3510
+ 0xEDE00000EE0,
3511
+ 0xF0000000F01,
3512
+ 0xF0B00000F0C,
3513
+ 0xF1800000F1A,
3514
+ 0xF2000000F2A,
3515
+ 0xF3500000F36,
3516
+ 0xF3700000F38,
3517
+ 0xF3900000F3A,
3518
+ 0xF3E00000F43,
3519
+ 0xF4400000F48,
3520
+ 0xF4900000F4D,
3521
+ 0xF4E00000F52,
3522
+ 0xF5300000F57,
3523
+ 0xF5800000F5C,
3524
+ 0xF5D00000F69,
3525
+ 0xF6A00000F6D,
3526
+ 0xF7100000F73,
3527
+ 0xF7400000F75,
3528
+ 0xF7A00000F81,
3529
+ 0xF8200000F85,
3530
+ 0xF8600000F93,
3531
+ 0xF9400000F98,
3532
+ 0xF9900000F9D,
3533
+ 0xF9E00000FA2,
3534
+ 0xFA300000FA7,
3535
+ 0xFA800000FAC,
3536
+ 0xFAD00000FB9,
3537
+ 0xFBA00000FBD,
3538
+ 0xFC600000FC7,
3539
+ 0x10000000104A,
3540
+ 0x10500000109E,
3541
+ 0x10D0000010FB,
3542
+ 0x10FD00001100,
3543
+ 0x120000001249,
3544
+ 0x124A0000124E,
3545
+ 0x125000001257,
3546
+ 0x125800001259,
3547
+ 0x125A0000125E,
3548
+ 0x126000001289,
3549
+ 0x128A0000128E,
3550
+ 0x1290000012B1,
3551
+ 0x12B2000012B6,
3552
+ 0x12B8000012BF,
3553
+ 0x12C0000012C1,
3554
+ 0x12C2000012C6,
3555
+ 0x12C8000012D7,
3556
+ 0x12D800001311,
3557
+ 0x131200001316,
3558
+ 0x13180000135B,
3559
+ 0x135D00001360,
3560
+ 0x138000001390,
3561
+ 0x13A0000013F6,
3562
+ 0x14010000166D,
3563
+ 0x166F00001680,
3564
+ 0x16810000169B,
3565
+ 0x16A0000016EB,
3566
+ 0x16F1000016F9,
3567
+ 0x170000001716,
3568
+ 0x171F00001735,
3569
+ 0x174000001754,
3570
+ 0x17600000176D,
3571
+ 0x176E00001771,
3572
+ 0x177200001774,
3573
+ 0x1780000017B4,
3574
+ 0x17B6000017D4,
3575
+ 0x17D7000017D8,
3576
+ 0x17DC000017DE,
3577
+ 0x17E0000017EA,
3578
+ 0x18100000181A,
3579
+ 0x182000001879,
3580
+ 0x1880000018AB,
3581
+ 0x18B0000018F6,
3582
+ 0x19000000191F,
3583
+ 0x19200000192C,
3584
+ 0x19300000193C,
3585
+ 0x19460000196E,
3586
+ 0x197000001975,
3587
+ 0x1980000019AC,
3588
+ 0x19B0000019CA,
3589
+ 0x19D0000019DA,
3590
+ 0x1A0000001A1C,
3591
+ 0x1A2000001A5F,
3592
+ 0x1A6000001A7D,
3593
+ 0x1A7F00001A8A,
3594
+ 0x1A9000001A9A,
3595
+ 0x1AA700001AA8,
3596
+ 0x1AB000001ABE,
3597
+ 0x1ABF00001ACF,
3598
+ 0x1B0000001B4D,
3599
+ 0x1B5000001B5A,
3600
+ 0x1B6B00001B74,
3601
+ 0x1B8000001BF4,
3602
+ 0x1C0000001C38,
3603
+ 0x1C4000001C4A,
3604
+ 0x1C4D00001C7E,
3605
+ 0x1C8A00001C8B,
3606
+ 0x1CD000001CD3,
3607
+ 0x1CD400001CFB,
3608
+ 0x1D0000001D2C,
3609
+ 0x1D2F00001D30,
3610
+ 0x1D3B00001D3C,
3611
+ 0x1D4E00001D4F,
3612
+ 0x1D6B00001D78,
3613
+ 0x1D7900001D9B,
3614
+ 0x1DC000001E00,
3615
+ 0x1E0100001E02,
3616
+ 0x1E0300001E04,
3617
+ 0x1E0500001E06,
3618
+ 0x1E0700001E08,
3619
+ 0x1E0900001E0A,
3620
+ 0x1E0B00001E0C,
3621
+ 0x1E0D00001E0E,
3622
+ 0x1E0F00001E10,
3623
+ 0x1E1100001E12,
3624
+ 0x1E1300001E14,
3625
+ 0x1E1500001E16,
3626
+ 0x1E1700001E18,
3627
+ 0x1E1900001E1A,
3628
+ 0x1E1B00001E1C,
3629
+ 0x1E1D00001E1E,
3630
+ 0x1E1F00001E20,
3631
+ 0x1E2100001E22,
3632
+ 0x1E2300001E24,
3633
+ 0x1E2500001E26,
3634
+ 0x1E2700001E28,
3635
+ 0x1E2900001E2A,
3636
+ 0x1E2B00001E2C,
3637
+ 0x1E2D00001E2E,
3638
+ 0x1E2F00001E30,
3639
+ 0x1E3100001E32,
3640
+ 0x1E3300001E34,
3641
+ 0x1E3500001E36,
3642
+ 0x1E3700001E38,
3643
+ 0x1E3900001E3A,
3644
+ 0x1E3B00001E3C,
3645
+ 0x1E3D00001E3E,
3646
+ 0x1E3F00001E40,
3647
+ 0x1E4100001E42,
3648
+ 0x1E4300001E44,
3649
+ 0x1E4500001E46,
3650
+ 0x1E4700001E48,
3651
+ 0x1E4900001E4A,
3652
+ 0x1E4B00001E4C,
3653
+ 0x1E4D00001E4E,
3654
+ 0x1E4F00001E50,
3655
+ 0x1E5100001E52,
3656
+ 0x1E5300001E54,
3657
+ 0x1E5500001E56,
3658
+ 0x1E5700001E58,
3659
+ 0x1E5900001E5A,
3660
+ 0x1E5B00001E5C,
3661
+ 0x1E5D00001E5E,
3662
+ 0x1E5F00001E60,
3663
+ 0x1E6100001E62,
3664
+ 0x1E6300001E64,
3665
+ 0x1E6500001E66,
3666
+ 0x1E6700001E68,
3667
+ 0x1E6900001E6A,
3668
+ 0x1E6B00001E6C,
3669
+ 0x1E6D00001E6E,
3670
+ 0x1E6F00001E70,
3671
+ 0x1E7100001E72,
3672
+ 0x1E7300001E74,
3673
+ 0x1E7500001E76,
3674
+ 0x1E7700001E78,
3675
+ 0x1E7900001E7A,
3676
+ 0x1E7B00001E7C,
3677
+ 0x1E7D00001E7E,
3678
+ 0x1E7F00001E80,
3679
+ 0x1E8100001E82,
3680
+ 0x1E8300001E84,
3681
+ 0x1E8500001E86,
3682
+ 0x1E8700001E88,
3683
+ 0x1E8900001E8A,
3684
+ 0x1E8B00001E8C,
3685
+ 0x1E8D00001E8E,
3686
+ 0x1E8F00001E90,
3687
+ 0x1E9100001E92,
3688
+ 0x1E9300001E94,
3689
+ 0x1E9500001E9A,
3690
+ 0x1E9C00001E9E,
3691
+ 0x1E9F00001EA0,
3692
+ 0x1EA100001EA2,
3693
+ 0x1EA300001EA4,
3694
+ 0x1EA500001EA6,
3695
+ 0x1EA700001EA8,
3696
+ 0x1EA900001EAA,
3697
+ 0x1EAB00001EAC,
3698
+ 0x1EAD00001EAE,
3699
+ 0x1EAF00001EB0,
3700
+ 0x1EB100001EB2,
3701
+ 0x1EB300001EB4,
3702
+ 0x1EB500001EB6,
3703
+ 0x1EB700001EB8,
3704
+ 0x1EB900001EBA,
3705
+ 0x1EBB00001EBC,
3706
+ 0x1EBD00001EBE,
3707
+ 0x1EBF00001EC0,
3708
+ 0x1EC100001EC2,
3709
+ 0x1EC300001EC4,
3710
+ 0x1EC500001EC6,
3711
+ 0x1EC700001EC8,
3712
+ 0x1EC900001ECA,
3713
+ 0x1ECB00001ECC,
3714
+ 0x1ECD00001ECE,
3715
+ 0x1ECF00001ED0,
3716
+ 0x1ED100001ED2,
3717
+ 0x1ED300001ED4,
3718
+ 0x1ED500001ED6,
3719
+ 0x1ED700001ED8,
3720
+ 0x1ED900001EDA,
3721
+ 0x1EDB00001EDC,
3722
+ 0x1EDD00001EDE,
3723
+ 0x1EDF00001EE0,
3724
+ 0x1EE100001EE2,
3725
+ 0x1EE300001EE4,
3726
+ 0x1EE500001EE6,
3727
+ 0x1EE700001EE8,
3728
+ 0x1EE900001EEA,
3729
+ 0x1EEB00001EEC,
3730
+ 0x1EED00001EEE,
3731
+ 0x1EEF00001EF0,
3732
+ 0x1EF100001EF2,
3733
+ 0x1EF300001EF4,
3734
+ 0x1EF500001EF6,
3735
+ 0x1EF700001EF8,
3736
+ 0x1EF900001EFA,
3737
+ 0x1EFB00001EFC,
3738
+ 0x1EFD00001EFE,
3739
+ 0x1EFF00001F08,
3740
+ 0x1F1000001F16,
3741
+ 0x1F2000001F28,
3742
+ 0x1F3000001F38,
3743
+ 0x1F4000001F46,
3744
+ 0x1F5000001F58,
3745
+ 0x1F6000001F68,
3746
+ 0x1F7000001F71,
3747
+ 0x1F7200001F73,
3748
+ 0x1F7400001F75,
3749
+ 0x1F7600001F77,
3750
+ 0x1F7800001F79,
3751
+ 0x1F7A00001F7B,
3752
+ 0x1F7C00001F7D,
3753
+ 0x1FB000001FB2,
3754
+ 0x1FB600001FB7,
3755
+ 0x1FC600001FC7,
3756
+ 0x1FD000001FD3,
3757
+ 0x1FD600001FD8,
3758
+ 0x1FE000001FE3,
3759
+ 0x1FE400001FE8,
3760
+ 0x1FF600001FF7,
3761
+ 0x214E0000214F,
3762
+ 0x218400002185,
3763
+ 0x2C3000002C60,
3764
+ 0x2C6100002C62,
3765
+ 0x2C6500002C67,
3766
+ 0x2C6800002C69,
3767
+ 0x2C6A00002C6B,
3768
+ 0x2C6C00002C6D,
3769
+ 0x2C7100002C72,
3770
+ 0x2C7300002C75,
3771
+ 0x2C7600002C7C,
3772
+ 0x2C8100002C82,
3773
+ 0x2C8300002C84,
3774
+ 0x2C8500002C86,
3775
+ 0x2C8700002C88,
3776
+ 0x2C8900002C8A,
3777
+ 0x2C8B00002C8C,
3778
+ 0x2C8D00002C8E,
3779
+ 0x2C8F00002C90,
3780
+ 0x2C9100002C92,
3781
+ 0x2C9300002C94,
3782
+ 0x2C9500002C96,
3783
+ 0x2C9700002C98,
3784
+ 0x2C9900002C9A,
3785
+ 0x2C9B00002C9C,
3786
+ 0x2C9D00002C9E,
3787
+ 0x2C9F00002CA0,
3788
+ 0x2CA100002CA2,
3789
+ 0x2CA300002CA4,
3790
+ 0x2CA500002CA6,
3791
+ 0x2CA700002CA8,
3792
+ 0x2CA900002CAA,
3793
+ 0x2CAB00002CAC,
3794
+ 0x2CAD00002CAE,
3795
+ 0x2CAF00002CB0,
3796
+ 0x2CB100002CB2,
3797
+ 0x2CB300002CB4,
3798
+ 0x2CB500002CB6,
3799
+ 0x2CB700002CB8,
3800
+ 0x2CB900002CBA,
3801
+ 0x2CBB00002CBC,
3802
+ 0x2CBD00002CBE,
3803
+ 0x2CBF00002CC0,
3804
+ 0x2CC100002CC2,
3805
+ 0x2CC300002CC4,
3806
+ 0x2CC500002CC6,
3807
+ 0x2CC700002CC8,
3808
+ 0x2CC900002CCA,
3809
+ 0x2CCB00002CCC,
3810
+ 0x2CCD00002CCE,
3811
+ 0x2CCF00002CD0,
3812
+ 0x2CD100002CD2,
3813
+ 0x2CD300002CD4,
3814
+ 0x2CD500002CD6,
3815
+ 0x2CD700002CD8,
3816
+ 0x2CD900002CDA,
3817
+ 0x2CDB00002CDC,
3818
+ 0x2CDD00002CDE,
3819
+ 0x2CDF00002CE0,
3820
+ 0x2CE100002CE2,
3821
+ 0x2CE300002CE5,
3822
+ 0x2CEC00002CED,
3823
+ 0x2CEE00002CF2,
3824
+ 0x2CF300002CF4,
3825
+ 0x2D0000002D26,
3826
+ 0x2D2700002D28,
3827
+ 0x2D2D00002D2E,
3828
+ 0x2D3000002D68,
3829
+ 0x2D7F00002D97,
3830
+ 0x2DA000002DA7,
3831
+ 0x2DA800002DAF,
3832
+ 0x2DB000002DB7,
3833
+ 0x2DB800002DBF,
3834
+ 0x2DC000002DC7,
3835
+ 0x2DC800002DCF,
3836
+ 0x2DD000002DD7,
3837
+ 0x2DD800002DDF,
3838
+ 0x2DE000002E00,
3839
+ 0x2E2F00002E30,
3840
+ 0x300500003008,
3841
+ 0x302A0000302E,
3842
+ 0x303C0000303D,
3843
+ 0x304100003097,
3844
+ 0x30990000309B,
3845
+ 0x309D0000309F,
3846
+ 0x30A1000030FB,
3847
+ 0x30FC000030FF,
3848
+ 0x310500003130,
3849
+ 0x31A0000031C0,
3850
+ 0x31F000003200,
3851
+ 0x340000004DC0,
3852
+ 0x4E000000A48D,
3853
+ 0xA4D00000A4FE,
3854
+ 0xA5000000A60D,
3855
+ 0xA6100000A62C,
3856
+ 0xA6410000A642,
3857
+ 0xA6430000A644,
3858
+ 0xA6450000A646,
3859
+ 0xA6470000A648,
3860
+ 0xA6490000A64A,
3861
+ 0xA64B0000A64C,
3862
+ 0xA64D0000A64E,
3863
+ 0xA64F0000A650,
3864
+ 0xA6510000A652,
3865
+ 0xA6530000A654,
3866
+ 0xA6550000A656,
3867
+ 0xA6570000A658,
3868
+ 0xA6590000A65A,
3869
+ 0xA65B0000A65C,
3870
+ 0xA65D0000A65E,
3871
+ 0xA65F0000A660,
3872
+ 0xA6610000A662,
3873
+ 0xA6630000A664,
3874
+ 0xA6650000A666,
3875
+ 0xA6670000A668,
3876
+ 0xA6690000A66A,
3877
+ 0xA66B0000A66C,
3878
+ 0xA66D0000A670,
3879
+ 0xA6740000A67E,
3880
+ 0xA67F0000A680,
3881
+ 0xA6810000A682,
3882
+ 0xA6830000A684,
3883
+ 0xA6850000A686,
3884
+ 0xA6870000A688,
3885
+ 0xA6890000A68A,
3886
+ 0xA68B0000A68C,
3887
+ 0xA68D0000A68E,
3888
+ 0xA68F0000A690,
3889
+ 0xA6910000A692,
3890
+ 0xA6930000A694,
3891
+ 0xA6950000A696,
3892
+ 0xA6970000A698,
3893
+ 0xA6990000A69A,
3894
+ 0xA69B0000A69C,
3895
+ 0xA69E0000A6E6,
3896
+ 0xA6F00000A6F2,
3897
+ 0xA7170000A720,
3898
+ 0xA7230000A724,
3899
+ 0xA7250000A726,
3900
+ 0xA7270000A728,
3901
+ 0xA7290000A72A,
3902
+ 0xA72B0000A72C,
3903
+ 0xA72D0000A72E,
3904
+ 0xA72F0000A732,
3905
+ 0xA7330000A734,
3906
+ 0xA7350000A736,
3907
+ 0xA7370000A738,
3908
+ 0xA7390000A73A,
3909
+ 0xA73B0000A73C,
3910
+ 0xA73D0000A73E,
3911
+ 0xA73F0000A740,
3912
+ 0xA7410000A742,
3913
+ 0xA7430000A744,
3914
+ 0xA7450000A746,
3915
+ 0xA7470000A748,
3916
+ 0xA7490000A74A,
3917
+ 0xA74B0000A74C,
3918
+ 0xA74D0000A74E,
3919
+ 0xA74F0000A750,
3920
+ 0xA7510000A752,
3921
+ 0xA7530000A754,
3922
+ 0xA7550000A756,
3923
+ 0xA7570000A758,
3924
+ 0xA7590000A75A,
3925
+ 0xA75B0000A75C,
3926
+ 0xA75D0000A75E,
3927
+ 0xA75F0000A760,
3928
+ 0xA7610000A762,
3929
+ 0xA7630000A764,
3930
+ 0xA7650000A766,
3931
+ 0xA7670000A768,
3932
+ 0xA7690000A76A,
3933
+ 0xA76B0000A76C,
3934
+ 0xA76D0000A76E,
3935
+ 0xA76F0000A770,
3936
+ 0xA7710000A779,
3937
+ 0xA77A0000A77B,
3938
+ 0xA77C0000A77D,
3939
+ 0xA77F0000A780,
3940
+ 0xA7810000A782,
3941
+ 0xA7830000A784,
3942
+ 0xA7850000A786,
3943
+ 0xA7870000A789,
3944
+ 0xA78C0000A78D,
3945
+ 0xA78E0000A790,
3946
+ 0xA7910000A792,
3947
+ 0xA7930000A796,
3948
+ 0xA7970000A798,
3949
+ 0xA7990000A79A,
3950
+ 0xA79B0000A79C,
3951
+ 0xA79D0000A79E,
3952
+ 0xA79F0000A7A0,
3953
+ 0xA7A10000A7A2,
3954
+ 0xA7A30000A7A4,
3955
+ 0xA7A50000A7A6,
3956
+ 0xA7A70000A7A8,
3957
+ 0xA7A90000A7AA,
3958
+ 0xA7AF0000A7B0,
3959
+ 0xA7B50000A7B6,
3960
+ 0xA7B70000A7B8,
3961
+ 0xA7B90000A7BA,
3962
+ 0xA7BB0000A7BC,
3963
+ 0xA7BD0000A7BE,
3964
+ 0xA7BF0000A7C0,
3965
+ 0xA7C10000A7C2,
3966
+ 0xA7C30000A7C4,
3967
+ 0xA7C80000A7C9,
3968
+ 0xA7CA0000A7CB,
3969
+ 0xA7CD0000A7CE,
3970
+ 0xA7D10000A7D2,
3971
+ 0xA7D30000A7D4,
3972
+ 0xA7D50000A7D6,
3973
+ 0xA7D70000A7D8,
3974
+ 0xA7D90000A7DA,
3975
+ 0xA7DB0000A7DC,
3976
+ 0xA7F60000A7F8,
3977
+ 0xA7FA0000A828,
3978
+ 0xA82C0000A82D,
3979
+ 0xA8400000A874,
3980
+ 0xA8800000A8C6,
3981
+ 0xA8D00000A8DA,
3982
+ 0xA8E00000A8F8,
3983
+ 0xA8FB0000A8FC,
3984
+ 0xA8FD0000A92E,
3985
+ 0xA9300000A954,
3986
+ 0xA9800000A9C1,
3987
+ 0xA9CF0000A9DA,
3988
+ 0xA9E00000A9FF,
3989
+ 0xAA000000AA37,
3990
+ 0xAA400000AA4E,
3991
+ 0xAA500000AA5A,
3992
+ 0xAA600000AA77,
3993
+ 0xAA7A0000AAC3,
3994
+ 0xAADB0000AADE,
3995
+ 0xAAE00000AAF0,
3996
+ 0xAAF20000AAF7,
3997
+ 0xAB010000AB07,
3998
+ 0xAB090000AB0F,
3999
+ 0xAB110000AB17,
4000
+ 0xAB200000AB27,
4001
+ 0xAB280000AB2F,
4002
+ 0xAB300000AB5B,
4003
+ 0xAB600000AB69,
4004
+ 0xABC00000ABEB,
4005
+ 0xABEC0000ABEE,
4006
+ 0xABF00000ABFA,
4007
+ 0xAC000000D7A4,
4008
+ 0xFA0E0000FA10,
4009
+ 0xFA110000FA12,
4010
+ 0xFA130000FA15,
4011
+ 0xFA1F0000FA20,
4012
+ 0xFA210000FA22,
4013
+ 0xFA230000FA25,
4014
+ 0xFA270000FA2A,
4015
+ 0xFB1E0000FB1F,
4016
+ 0xFE200000FE30,
4017
+ 0xFE730000FE74,
4018
+ 0x100000001000C,
4019
+ 0x1000D00010027,
4020
+ 0x100280001003B,
4021
+ 0x1003C0001003E,
4022
+ 0x1003F0001004E,
4023
+ 0x100500001005E,
4024
+ 0x10080000100FB,
4025
+ 0x101FD000101FE,
4026
+ 0x102800001029D,
4027
+ 0x102A0000102D1,
4028
+ 0x102E0000102E1,
4029
+ 0x1030000010320,
4030
+ 0x1032D00010341,
4031
+ 0x103420001034A,
4032
+ 0x103500001037B,
4033
+ 0x103800001039E,
4034
+ 0x103A0000103C4,
4035
+ 0x103C8000103D0,
4036
+ 0x104280001049E,
4037
+ 0x104A0000104AA,
4038
+ 0x104D8000104FC,
4039
+ 0x1050000010528,
4040
+ 0x1053000010564,
4041
+ 0x10597000105A2,
4042
+ 0x105A3000105B2,
4043
+ 0x105B3000105BA,
4044
+ 0x105BB000105BD,
4045
+ 0x105C0000105F4,
4046
+ 0x1060000010737,
4047
+ 0x1074000010756,
4048
+ 0x1076000010768,
4049
+ 0x1078000010781,
4050
+ 0x1080000010806,
4051
+ 0x1080800010809,
4052
+ 0x1080A00010836,
4053
+ 0x1083700010839,
4054
+ 0x1083C0001083D,
4055
+ 0x1083F00010856,
4056
+ 0x1086000010877,
4057
+ 0x108800001089F,
4058
+ 0x108E0000108F3,
4059
+ 0x108F4000108F6,
4060
+ 0x1090000010916,
4061
+ 0x109200001093A,
4062
+ 0x10980000109B8,
4063
+ 0x109BE000109C0,
4064
+ 0x10A0000010A04,
4065
+ 0x10A0500010A07,
4066
+ 0x10A0C00010A14,
4067
+ 0x10A1500010A18,
4068
+ 0x10A1900010A36,
4069
+ 0x10A3800010A3B,
4070
+ 0x10A3F00010A40,
4071
+ 0x10A6000010A7D,
4072
+ 0x10A8000010A9D,
4073
+ 0x10AC000010AC8,
4074
+ 0x10AC900010AE7,
4075
+ 0x10B0000010B36,
4076
+ 0x10B4000010B56,
4077
+ 0x10B6000010B73,
4078
+ 0x10B8000010B92,
4079
+ 0x10C0000010C49,
4080
+ 0x10CC000010CF3,
4081
+ 0x10D0000010D28,
4082
+ 0x10D3000010D3A,
4083
+ 0x10D4000010D50,
4084
+ 0x10D6900010D6E,
4085
+ 0x10D6F00010D86,
4086
+ 0x10E8000010EAA,
4087
+ 0x10EAB00010EAD,
4088
+ 0x10EB000010EB2,
4089
+ 0x10EC200010EC5,
4090
+ 0x10EFC00010F1D,
4091
+ 0x10F2700010F28,
4092
+ 0x10F3000010F51,
4093
+ 0x10F7000010F86,
4094
+ 0x10FB000010FC5,
4095
+ 0x10FE000010FF7,
4096
+ 0x1100000011047,
4097
+ 0x1106600011076,
4098
+ 0x1107F000110BB,
4099
+ 0x110C2000110C3,
4100
+ 0x110D0000110E9,
4101
+ 0x110F0000110FA,
4102
+ 0x1110000011135,
4103
+ 0x1113600011140,
4104
+ 0x1114400011148,
4105
+ 0x1115000011174,
4106
+ 0x1117600011177,
4107
+ 0x11180000111C5,
4108
+ 0x111C9000111CD,
4109
+ 0x111CE000111DB,
4110
+ 0x111DC000111DD,
4111
+ 0x1120000011212,
4112
+ 0x1121300011238,
4113
+ 0x1123E00011242,
4114
+ 0x1128000011287,
4115
+ 0x1128800011289,
4116
+ 0x1128A0001128E,
4117
+ 0x1128F0001129E,
4118
+ 0x1129F000112A9,
4119
+ 0x112B0000112EB,
4120
+ 0x112F0000112FA,
4121
+ 0x1130000011304,
4122
+ 0x113050001130D,
4123
+ 0x1130F00011311,
4124
+ 0x1131300011329,
4125
+ 0x1132A00011331,
4126
+ 0x1133200011334,
4127
+ 0x113350001133A,
4128
+ 0x1133B00011345,
4129
+ 0x1134700011349,
4130
+ 0x1134B0001134E,
4131
+ 0x1135000011351,
4132
+ 0x1135700011358,
4133
+ 0x1135D00011364,
4134
+ 0x113660001136D,
4135
+ 0x1137000011375,
4136
+ 0x113800001138A,
4137
+ 0x1138B0001138C,
4138
+ 0x1138E0001138F,
4139
+ 0x11390000113B6,
4140
+ 0x113B7000113C1,
4141
+ 0x113C2000113C3,
4142
+ 0x113C5000113C6,
4143
+ 0x113C7000113CB,
4144
+ 0x113CC000113D4,
4145
+ 0x113E1000113E3,
4146
+ 0x114000001144B,
4147
+ 0x114500001145A,
4148
+ 0x1145E00011462,
4149
+ 0x11480000114C6,
4150
+ 0x114C7000114C8,
4151
+ 0x114D0000114DA,
4152
+ 0x11580000115B6,
4153
+ 0x115B8000115C1,
4154
+ 0x115D8000115DE,
4155
+ 0x1160000011641,
4156
+ 0x1164400011645,
4157
+ 0x116500001165A,
4158
+ 0x11680000116B9,
4159
+ 0x116C0000116CA,
4160
+ 0x116D0000116E4,
4161
+ 0x117000001171B,
4162
+ 0x1171D0001172C,
4163
+ 0x117300001173A,
4164
+ 0x1174000011747,
4165
+ 0x118000001183B,
4166
+ 0x118C0000118EA,
4167
+ 0x118FF00011907,
4168
+ 0x119090001190A,
4169
+ 0x1190C00011914,
4170
+ 0x1191500011917,
4171
+ 0x1191800011936,
4172
+ 0x1193700011939,
4173
+ 0x1193B00011944,
4174
+ 0x119500001195A,
4175
+ 0x119A0000119A8,
4176
+ 0x119AA000119D8,
4177
+ 0x119DA000119E2,
4178
+ 0x119E3000119E5,
4179
+ 0x11A0000011A3F,
4180
+ 0x11A4700011A48,
4181
+ 0x11A5000011A9A,
4182
+ 0x11A9D00011A9E,
4183
+ 0x11AB000011AF9,
4184
+ 0x11BC000011BE1,
4185
+ 0x11BF000011BFA,
4186
+ 0x11C0000011C09,
4187
+ 0x11C0A00011C37,
4188
+ 0x11C3800011C41,
4189
+ 0x11C5000011C5A,
4190
+ 0x11C7200011C90,
4191
+ 0x11C9200011CA8,
4192
+ 0x11CA900011CB7,
4193
+ 0x11D0000011D07,
4194
+ 0x11D0800011D0A,
4195
+ 0x11D0B00011D37,
4196
+ 0x11D3A00011D3B,
4197
+ 0x11D3C00011D3E,
4198
+ 0x11D3F00011D48,
4199
+ 0x11D5000011D5A,
4200
+ 0x11D6000011D66,
4201
+ 0x11D6700011D69,
4202
+ 0x11D6A00011D8F,
4203
+ 0x11D9000011D92,
4204
+ 0x11D9300011D99,
4205
+ 0x11DA000011DAA,
4206
+ 0x11EE000011EF7,
4207
+ 0x11F0000011F11,
4208
+ 0x11F1200011F3B,
4209
+ 0x11F3E00011F43,
4210
+ 0x11F5000011F5B,
4211
+ 0x11FB000011FB1,
4212
+ 0x120000001239A,
4213
+ 0x1248000012544,
4214
+ 0x12F9000012FF1,
4215
+ 0x1300000013430,
4216
+ 0x1344000013456,
4217
+ 0x13460000143FB,
4218
+ 0x1440000014647,
4219
+ 0x161000001613A,
4220
+ 0x1680000016A39,
4221
+ 0x16A4000016A5F,
4222
+ 0x16A6000016A6A,
4223
+ 0x16A7000016ABF,
4224
+ 0x16AC000016ACA,
4225
+ 0x16AD000016AEE,
4226
+ 0x16AF000016AF5,
4227
+ 0x16B0000016B37,
4228
+ 0x16B4000016B44,
4229
+ 0x16B5000016B5A,
4230
+ 0x16B6300016B78,
4231
+ 0x16B7D00016B90,
4232
+ 0x16D4000016D6D,
4233
+ 0x16D7000016D7A,
4234
+ 0x16E6000016E80,
4235
+ 0x16F0000016F4B,
4236
+ 0x16F4F00016F88,
4237
+ 0x16F8F00016FA0,
4238
+ 0x16FE000016FE2,
4239
+ 0x16FE300016FE5,
4240
+ 0x16FF000016FF2,
4241
+ 0x17000000187F8,
4242
+ 0x1880000018CD6,
4243
+ 0x18CFF00018D09,
4244
+ 0x1AFF00001AFF4,
4245
+ 0x1AFF50001AFFC,
4246
+ 0x1AFFD0001AFFF,
4247
+ 0x1B0000001B123,
4248
+ 0x1B1320001B133,
4249
+ 0x1B1500001B153,
4250
+ 0x1B1550001B156,
4251
+ 0x1B1640001B168,
4252
+ 0x1B1700001B2FC,
4253
+ 0x1BC000001BC6B,
4254
+ 0x1BC700001BC7D,
4255
+ 0x1BC800001BC89,
4256
+ 0x1BC900001BC9A,
4257
+ 0x1BC9D0001BC9F,
4258
+ 0x1CCF00001CCFA,
4259
+ 0x1CF000001CF2E,
4260
+ 0x1CF300001CF47,
4261
+ 0x1DA000001DA37,
4262
+ 0x1DA3B0001DA6D,
4263
+ 0x1DA750001DA76,
4264
+ 0x1DA840001DA85,
4265
+ 0x1DA9B0001DAA0,
4266
+ 0x1DAA10001DAB0,
4267
+ 0x1DF000001DF1F,
4268
+ 0x1DF250001DF2B,
4269
+ 0x1E0000001E007,
4270
+ 0x1E0080001E019,
4271
+ 0x1E01B0001E022,
4272
+ 0x1E0230001E025,
4273
+ 0x1E0260001E02B,
4274
+ 0x1E08F0001E090,
4275
+ 0x1E1000001E12D,
4276
+ 0x1E1300001E13E,
4277
+ 0x1E1400001E14A,
4278
+ 0x1E14E0001E14F,
4279
+ 0x1E2900001E2AF,
4280
+ 0x1E2C00001E2FA,
4281
+ 0x1E4D00001E4FA,
4282
+ 0x1E5D00001E5FB,
4283
+ 0x1E7E00001E7E7,
4284
+ 0x1E7E80001E7EC,
4285
+ 0x1E7ED0001E7EF,
4286
+ 0x1E7F00001E7FF,
4287
+ 0x1E8000001E8C5,
4288
+ 0x1E8D00001E8D7,
4289
+ 0x1E9220001E94C,
4290
+ 0x1E9500001E95A,
4291
+ 0x200000002A6E0,
4292
+ 0x2A7000002B73A,
4293
+ 0x2B7400002B81E,
4294
+ 0x2B8200002CEA2,
4295
+ 0x2CEB00002EBE1,
4296
+ 0x2EBF00002EE5E,
4297
+ 0x300000003134B,
4298
+ 0x31350000323B0,
4299
+ ),
4300
+ "CONTEXTJ": (0x200C0000200E,),
4301
+ "CONTEXTO": (
4302
+ 0xB7000000B8,
4303
+ 0x37500000376,
4304
+ 0x5F3000005F5,
4305
+ 0x6600000066A,
4306
+ 0x6F0000006FA,
4307
+ 0x30FB000030FC,
4308
+ ),
4309
+ }
env/lib/python3.13/site-packages/idna/intranges.py ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Given a list of integers, made up of (hopefully) a small number of long runs
3
+ of consecutive integers, compute a representation of the form
4
+ ((start1, end1), (start2, end2) ...). Then answer the question "was x present
5
+ in the original list?" in time O(log(# runs)).
6
+ """
7
+
8
+ import bisect
9
+ from typing import List, Tuple
10
+
11
+
12
+ def intranges_from_list(list_: List[int]) -> Tuple[int, ...]:
13
+ """Represent a list of integers as a sequence of ranges:
14
+ ((start_0, end_0), (start_1, end_1), ...), such that the original
15
+ integers are exactly those x such that start_i <= x < end_i for some i.
16
+
17
+ Ranges are encoded as single integers (start << 32 | end), not as tuples.
18
+ """
19
+
20
+ sorted_list = sorted(list_)
21
+ ranges = []
22
+ last_write = -1
23
+ for i in range(len(sorted_list)):
24
+ if i + 1 < len(sorted_list):
25
+ if sorted_list[i] == sorted_list[i + 1] - 1:
26
+ continue
27
+ current_range = sorted_list[last_write + 1 : i + 1]
28
+ ranges.append(_encode_range(current_range[0], current_range[-1] + 1))
29
+ last_write = i
30
+
31
+ return tuple(ranges)
32
+
33
+
34
+ def _encode_range(start: int, end: int) -> int:
35
+ return (start << 32) | end
36
+
37
+
38
+ def _decode_range(r: int) -> Tuple[int, int]:
39
+ return (r >> 32), (r & ((1 << 32) - 1))
40
+
41
+
42
+ def intranges_contain(int_: int, ranges: Tuple[int, ...]) -> bool:
43
+ """Determine if `int_` falls into one of the ranges in `ranges`."""
44
+ tuple_ = _encode_range(int_, 0)
45
+ pos = bisect.bisect_left(ranges, tuple_)
46
+ # we could be immediately ahead of a tuple (start, end)
47
+ # with start < int_ <= end
48
+ if pos > 0:
49
+ left, right = _decode_range(ranges[pos - 1])
50
+ if left <= int_ < right:
51
+ return True
52
+ # or we could be immediately behind a tuple (int_, end)
53
+ if pos < len(ranges):
54
+ left, _ = _decode_range(ranges[pos])
55
+ if left == int_:
56
+ return True
57
+ return False
env/lib/python3.13/site-packages/idna/package_data.py ADDED
@@ -0,0 +1 @@
 
 
1
+ __version__ = "3.11"
env/lib/python3.13/site-packages/idna/py.typed ADDED
File without changes
env/lib/python3.13/site-packages/idna/uts46data.py ADDED
The diff for this file is too large to render. See raw diff
 
env/lib/python3.13/site-packages/pip/__init__.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import List, Optional
2
+
3
+ __version__ = "25.1.1"
4
+
5
+
6
+ def main(args: Optional[List[str]] = None) -> int:
7
+ """This is an internal API only meant for use by pip's own console scripts.
8
+
9
+ For additional details, see https://github.com/pypa/pip/issues/7498.
10
+ """
11
+ from pip._internal.utils.entrypoints import _wrapper
12
+
13
+ return _wrapper(args)
env/lib/python3.13/site-packages/pip/__main__.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import sys
3
+
4
+ # Remove '' and current working directory from the first entry
5
+ # of sys.path, if present to avoid using current directory
6
+ # in pip commands check, freeze, install, list and show,
7
+ # when invoked as python -m pip <command>
8
+ if sys.path[0] in ("", os.getcwd()):
9
+ sys.path.pop(0)
10
+
11
+ # If we are running from a wheel, add the wheel to sys.path
12
+ # This allows the usage python pip-*.whl/pip install pip-*.whl
13
+ if __package__ == "":
14
+ # __file__ is pip-*.whl/pip/__main__.py
15
+ # first dirname call strips of '/__main__.py', second strips off '/pip'
16
+ # Resulting path is the name of the wheel itself
17
+ # Add that to sys.path so we can import pip
18
+ path = os.path.dirname(os.path.dirname(__file__))
19
+ sys.path.insert(0, path)
20
+
21
+ if __name__ == "__main__":
22
+ from pip._internal.cli.main import main as _main
23
+
24
+ sys.exit(_main())
env/lib/python3.13/site-packages/pip/__pip-runner__.py ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Execute exactly this copy of pip, within a different environment.
2
+
3
+ This file is named as it is, to ensure that this module can't be imported via
4
+ an import statement.
5
+ """
6
+
7
+ # /!\ This version compatibility check section must be Python 2 compatible. /!\
8
+
9
+ import sys
10
+
11
+ # Copied from pyproject.toml
12
+ PYTHON_REQUIRES = (3, 9)
13
+
14
+
15
+ def version_str(version): # type: ignore
16
+ return ".".join(str(v) for v in version)
17
+
18
+
19
+ if sys.version_info[:2] < PYTHON_REQUIRES:
20
+ raise SystemExit(
21
+ "This version of pip does not support python {} (requires >={}).".format(
22
+ version_str(sys.version_info[:2]), version_str(PYTHON_REQUIRES)
23
+ )
24
+ )
25
+
26
+ # From here on, we can use Python 3 features, but the syntax must remain
27
+ # Python 2 compatible.
28
+
29
+ import runpy # noqa: E402
30
+ from importlib.machinery import PathFinder # noqa: E402
31
+ from os.path import dirname # noqa: E402
32
+
33
+ PIP_SOURCES_ROOT = dirname(dirname(__file__))
34
+
35
+
36
+ class PipImportRedirectingFinder:
37
+ @classmethod
38
+ def find_spec(self, fullname, path=None, target=None): # type: ignore
39
+ if fullname != "pip":
40
+ return None
41
+
42
+ spec = PathFinder.find_spec(fullname, [PIP_SOURCES_ROOT], target)
43
+ assert spec, (PIP_SOURCES_ROOT, fullname)
44
+ return spec
45
+
46
+
47
+ sys.meta_path.insert(0, PipImportRedirectingFinder())
48
+
49
+ assert __name__ == "__main__", "Cannot run __pip-runner__.py as a non-main module"
50
+ runpy.run_module("pip", run_name="__main__", alter_sys=True)
env/lib/python3.13/site-packages/pip/py.typed ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ pip is a command line program. While it is implemented in Python, and so is
2
+ available for import, you must not use pip's internal APIs in this way. Typing
3
+ information is provided as a convenience only and is not a guarantee. Expect
4
+ unannounced changes to the API and types in releases.
env/lib/python3.13/site-packages/pyyaml-6.0.3.dist-info/INSTALLER ADDED
@@ -0,0 +1 @@
 
 
1
+ pip
env/lib/python3.13/site-packages/pyyaml-6.0.3.dist-info/METADATA ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Metadata-Version: 2.4
2
+ Name: PyYAML
3
+ Version: 6.0.3
4
+ Summary: YAML parser and emitter for Python
5
+ Home-page: https://pyyaml.org/
6
+ Download-URL: https://pypi.org/project/PyYAML/
7
+ Author: Kirill Simonov
8
+ Author-email: xi@resolvent.net
9
+ License: MIT
10
+ Project-URL: Bug Tracker, https://github.com/yaml/pyyaml/issues
11
+ Project-URL: CI, https://github.com/yaml/pyyaml/actions
12
+ Project-URL: Documentation, https://pyyaml.org/wiki/PyYAMLDocumentation
13
+ Project-URL: Mailing lists, http://lists.sourceforge.net/lists/listinfo/yaml-core
14
+ Project-URL: Source Code, https://github.com/yaml/pyyaml
15
+ Platform: Any
16
+ Classifier: Development Status :: 5 - Production/Stable
17
+ Classifier: Intended Audience :: Developers
18
+ Classifier: License :: OSI Approved :: MIT License
19
+ Classifier: Operating System :: OS Independent
20
+ Classifier: Programming Language :: Cython
21
+ Classifier: Programming Language :: Python
22
+ Classifier: Programming Language :: Python :: 3
23
+ Classifier: Programming Language :: Python :: 3.8
24
+ Classifier: Programming Language :: Python :: 3.9
25
+ Classifier: Programming Language :: Python :: 3.10
26
+ Classifier: Programming Language :: Python :: 3.11
27
+ Classifier: Programming Language :: Python :: 3.12
28
+ Classifier: Programming Language :: Python :: 3.13
29
+ Classifier: Programming Language :: Python :: 3.14
30
+ Classifier: Programming Language :: Python :: Implementation :: CPython
31
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
32
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
33
+ Classifier: Topic :: Text Processing :: Markup
34
+ Requires-Python: >=3.8
35
+ License-File: LICENSE
36
+ Dynamic: author
37
+ Dynamic: author-email
38
+ Dynamic: classifier
39
+ Dynamic: description
40
+ Dynamic: download-url
41
+ Dynamic: home-page
42
+ Dynamic: license
43
+ Dynamic: license-file
44
+ Dynamic: platform
45
+ Dynamic: project-url
46
+ Dynamic: requires-python
47
+ Dynamic: summary
48
+
49
+ YAML is a data serialization format designed for human readability
50
+ and interaction with scripting languages. PyYAML is a YAML parser
51
+ and emitter for Python.
52
+
53
+ PyYAML features a complete YAML 1.1 parser, Unicode support, pickle
54
+ support, capable extension API, and sensible error messages. PyYAML
55
+ supports standard YAML tags and provides Python-specific tags that
56
+ allow to represent an arbitrary Python object.
57
+
58
+ PyYAML is applicable for a broad range of tasks from complex
59
+ configuration files to object serialization and persistence.
env/lib/python3.13/site-packages/pyyaml-6.0.3.dist-info/RECORD ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ _yaml/__init__.py,sha256=04Ae_5osxahpJHa3XBZUAf4wi6XX32gR8D6X6p64GEA,1402
2
+ _yaml/__pycache__/__init__.cpython-313.pyc,,
3
+ pyyaml-6.0.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
4
+ pyyaml-6.0.3.dist-info/METADATA,sha256=A8O0Fe040J-u3Ek2DpMHabQMWPaFhebeAOLkkWqFjTQ,2351
5
+ pyyaml-6.0.3.dist-info/RECORD,,
6
+ pyyaml-6.0.3.dist-info/WHEEL,sha256=2iHh9e2o6T3nHtu_NVT7Cs7pebIqF94rZK8zrQfgoJI,190
7
+ pyyaml-6.0.3.dist-info/licenses/LICENSE,sha256=jTko-dxEkP1jVwfLiOsmvXZBAqcoKVQwfT5RZ6V36KQ,1101
8
+ pyyaml-6.0.3.dist-info/top_level.txt,sha256=rpj0IVMTisAjh_1vG3Ccf9v5jpCQwAz6cD1IVU5ZdhQ,11
9
+ yaml/__init__.py,sha256=sZ38wzPWp139cwc5ARZFByUvJxtB07X32FUQAzoFR6c,12311
10
+ yaml/__pycache__/__init__.cpython-313.pyc,,
11
+ yaml/__pycache__/composer.cpython-313.pyc,,
12
+ yaml/__pycache__/constructor.cpython-313.pyc,,
13
+ yaml/__pycache__/cyaml.cpython-313.pyc,,
14
+ yaml/__pycache__/dumper.cpython-313.pyc,,
15
+ yaml/__pycache__/emitter.cpython-313.pyc,,
16
+ yaml/__pycache__/error.cpython-313.pyc,,
17
+ yaml/__pycache__/events.cpython-313.pyc,,
18
+ yaml/__pycache__/loader.cpython-313.pyc,,
19
+ yaml/__pycache__/nodes.cpython-313.pyc,,
20
+ yaml/__pycache__/parser.cpython-313.pyc,,
21
+ yaml/__pycache__/reader.cpython-313.pyc,,
22
+ yaml/__pycache__/representer.cpython-313.pyc,,
23
+ yaml/__pycache__/resolver.cpython-313.pyc,,
24
+ yaml/__pycache__/scanner.cpython-313.pyc,,
25
+ yaml/__pycache__/serializer.cpython-313.pyc,,
26
+ yaml/__pycache__/tokens.cpython-313.pyc,,
27
+ yaml/_yaml.cpython-313-x86_64-linux-gnu.so,sha256=P5FgHX2lDz0VIegH8EggvhmMyu3CqJCU1pAxz4ko2K8,2653048
28
+ yaml/composer.py,sha256=_Ko30Wr6eDWUeUpauUGT3Lcg9QPBnOPVlTnIMRGJ9FM,4883
29
+ yaml/constructor.py,sha256=kNgkfaeLUkwQYY_Q6Ff1Tz2XVw_pG1xVE9Ak7z-viLA,28639
30
+ yaml/cyaml.py,sha256=6ZrAG9fAYvdVe2FK_w0hmXoG7ZYsoYUwapG8CiC72H0,3851
31
+ yaml/dumper.py,sha256=PLctZlYwZLp7XmeUdwRuv4nYOZ2UBnDIUy8-lKfLF-o,2837
32
+ yaml/emitter.py,sha256=jghtaU7eFwg31bG0B7RZea_29Adi9CKmXq_QjgQpCkQ,43006
33
+ yaml/error.py,sha256=Ah9z-toHJUbE9j-M8YpxgSRM5CgLCcwVzJgLLRF2Fxo,2533
34
+ yaml/events.py,sha256=50_TksgQiE4up-lKo_V-nBy-tAIxkIPQxY5qDhKCeHw,2445
35
+ yaml/loader.py,sha256=UVa-zIqmkFSCIYq_PgSGm4NSJttHY2Rf_zQ4_b1fHN0,2061
36
+ yaml/nodes.py,sha256=gPKNj8pKCdh2d4gr3gIYINnPOaOxGhJAUiYhGRnPE84,1440
37
+ yaml/parser.py,sha256=ilWp5vvgoHFGzvOZDItFoGjD6D42nhlZrZyjAwa0oJo,25495
38
+ yaml/reader.py,sha256=0dmzirOiDG4Xo41RnuQS7K9rkY3xjHiVasfDMNTqCNw,6794
39
+ yaml/representer.py,sha256=IuWP-cAW9sHKEnS0gCqSa894k1Bg4cgTxaDwIcbRQ-Y,14190
40
+ yaml/resolver.py,sha256=9L-VYfm4mWHxUD1Vg4X7rjDRK_7VZd6b92wzq7Y2IKY,9004
41
+ yaml/scanner.py,sha256=YEM3iLZSaQwXcQRg2l2R4MdT0zGP2F9eHkKGKnHyWQY,51279
42
+ yaml/serializer.py,sha256=ChuFgmhU01hj4xgI8GaKv6vfM2Bujwa9i7d2FAHj7cA,4165
43
+ yaml/tokens.py,sha256=lTQIzSVw8Mg9wv459-TjiOQe6wVziqaRlqX2_89rp54,2573
env/lib/python3.13/site-packages/pyyaml-6.0.3.dist-info/WHEEL ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: false
4
+ Tag: cp313-cp313-manylinux_2_17_x86_64
5
+ Tag: cp313-cp313-manylinux2014_x86_64
6
+ Tag: cp313-cp313-manylinux_2_28_x86_64
7
+