Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- env/lib/python3.13/site-packages/fsspec-2025.12.0.dist-info/INSTALLER +1 -0
- env/lib/python3.13/site-packages/fsspec-2025.12.0.dist-info/METADATA +256 -0
- env/lib/python3.13/site-packages/fsspec-2025.12.0.dist-info/RECORD +119 -0
- env/lib/python3.13/site-packages/fsspec-2025.12.0.dist-info/WHEEL +4 -0
- env/lib/python3.13/site-packages/hf_xet/__init__.py +5 -0
- env/lib/python3.13/site-packages/huggingface_hub-1.2.1.dist-info/INSTALLER +1 -0
- env/lib/python3.13/site-packages/huggingface_hub-1.2.1.dist-info/METADATA +320 -0
- env/lib/python3.13/site-packages/huggingface_hub-1.2.1.dist-info/RECORD +307 -0
- env/lib/python3.13/site-packages/huggingface_hub-1.2.1.dist-info/REQUESTED +0 -0
- env/lib/python3.13/site-packages/huggingface_hub-1.2.1.dist-info/WHEEL +5 -0
- env/lib/python3.13/site-packages/huggingface_hub-1.2.1.dist-info/entry_points.txt +6 -0
- env/lib/python3.13/site-packages/huggingface_hub-1.2.1.dist-info/top_level.txt +1 -0
- env/lib/python3.13/site-packages/huggingface_hub/__init__.py +1560 -0
- env/lib/python3.13/site-packages/huggingface_hub/_commit_api.py +966 -0
- env/lib/python3.13/site-packages/huggingface_hub/_commit_scheduler.py +353 -0
- env/lib/python3.13/site-packages/huggingface_hub/_inference_endpoints.py +418 -0
- env/lib/python3.13/site-packages/huggingface_hub/_jobs_api.py +301 -0
- env/lib/python3.13/site-packages/huggingface_hub/_local_folder.py +447 -0
- env/lib/python3.13/site-packages/huggingface_hub/_oauth.py +460 -0
- env/lib/python3.13/site-packages/huggingface_hub/_snapshot_download.py +465 -0
- env/lib/python3.13/site-packages/huggingface_hub/_space_api.py +168 -0
- env/lib/python3.13/site-packages/huggingface_hub/_tensorboard_logger.py +190 -0
- env/lib/python3.13/site-packages/huggingface_hub/_webhooks_payload.py +137 -0
- env/lib/python3.13/site-packages/huggingface_hub/community.py +363 -0
- env/lib/python3.13/site-packages/huggingface_hub/constants.py +279 -0
- env/lib/python3.13/site-packages/huggingface_hub/errors.py +404 -0
- env/lib/python3.13/site-packages/huggingface_hub/fastai_utils.py +414 -0
- env/lib/python3.13/site-packages/huggingface_hub/file_download.py +1958 -0
- env/lib/python3.13/site-packages/huggingface_hub/hf_api.py +0 -0
- env/lib/python3.13/site-packages/huggingface_hub/hub_mixin.py +831 -0
- env/lib/python3.13/site-packages/huggingface_hub/lfs.py +393 -0
- env/lib/python3.13/site-packages/huggingface_hub/py.typed +0 -0
- env/lib/python3.13/site-packages/huggingface_hub/repocard_data.py +770 -0
- env/lib/python3.13/site-packages/idna/__init__.py +45 -0
- env/lib/python3.13/site-packages/idna/codec.py +122 -0
- env/lib/python3.13/site-packages/idna/compat.py +15 -0
- env/lib/python3.13/site-packages/idna/core.py +437 -0
- env/lib/python3.13/site-packages/idna/idnadata.py +4309 -0
- env/lib/python3.13/site-packages/idna/intranges.py +57 -0
- env/lib/python3.13/site-packages/idna/package_data.py +1 -0
- env/lib/python3.13/site-packages/idna/py.typed +0 -0
- env/lib/python3.13/site-packages/idna/uts46data.py +0 -0
- env/lib/python3.13/site-packages/pip/__init__.py +13 -0
- env/lib/python3.13/site-packages/pip/__main__.py +24 -0
- env/lib/python3.13/site-packages/pip/__pip-runner__.py +50 -0
- env/lib/python3.13/site-packages/pip/py.typed +4 -0
- env/lib/python3.13/site-packages/pyyaml-6.0.3.dist-info/INSTALLER +1 -0
- env/lib/python3.13/site-packages/pyyaml-6.0.3.dist-info/METADATA +59 -0
- env/lib/python3.13/site-packages/pyyaml-6.0.3.dist-info/RECORD +43 -0
- 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 |
+
[](https://pypi.python.org/pypi/fsspec/)
|
| 154 |
+
[](https://anaconda.org/conda-forge/fsspec)
|
| 155 |
+

|
| 156 |
+
[](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 |
+
|