Spaces:
Sleeping
Sleeping
Upload folder using huggingface_hub (part 4)
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- .gitattributes +4 -0
- venv/Lib/site-packages/datasets-5.0.0.dist-info/AUTHORS +8 -0
- venv/Lib/site-packages/datasets-5.0.0.dist-info/INSTALLER +1 -0
- venv/Lib/site-packages/datasets-5.0.0.dist-info/LICENSE +202 -0
- venv/Lib/site-packages/datasets-5.0.0.dist-info/METADATA +500 -0
- venv/Lib/site-packages/datasets-5.0.0.dist-info/RECORD +291 -0
- venv/Lib/site-packages/datasets-5.0.0.dist-info/REQUESTED +0 -0
- venv/Lib/site-packages/datasets-5.0.0.dist-info/WHEEL +5 -0
- venv/Lib/site-packages/datasets-5.0.0.dist-info/entry_points.txt +2 -0
- venv/Lib/site-packages/datasets-5.0.0.dist-info/top_level.txt +1 -0
- venv/Lib/site-packages/datasets/__pycache__/fingerprint.cpython-311.pyc +0 -0
- venv/Lib/site-packages/datasets/__pycache__/hub.cpython-311.pyc +0 -0
- venv/Lib/site-packages/datasets/__pycache__/info.cpython-311.pyc +0 -0
- venv/Lib/site-packages/datasets/__pycache__/inspect.cpython-311.pyc +0 -0
- venv/Lib/site-packages/datasets/__pycache__/iterable_dataset.cpython-311.pyc +3 -0
- venv/Lib/site-packages/datasets/__pycache__/load.cpython-311.pyc +0 -0
- venv/Lib/site-packages/datasets/__pycache__/naming.cpython-311.pyc +0 -0
- venv/Lib/site-packages/datasets/__pycache__/search.cpython-311.pyc +0 -0
- venv/Lib/site-packages/datasets/__pycache__/splits.cpython-311.pyc +0 -0
- venv/Lib/site-packages/datasets/__pycache__/streaming.cpython-311.pyc +0 -0
- venv/Lib/site-packages/datasets/__pycache__/table.cpython-311.pyc +3 -0
- venv/Lib/site-packages/datasets/arrow_dataset.py +0 -0
- venv/Lib/site-packages/datasets/arrow_reader.py +620 -0
- venv/Lib/site-packages/datasets/arrow_writer.py +828 -0
- venv/Lib/site-packages/datasets/builder.py +1916 -0
- venv/Lib/site-packages/datasets/combine.py +232 -0
- venv/Lib/site-packages/datasets/commands/__init__.py +13 -0
- venv/Lib/site-packages/datasets/commands/__pycache__/__init__.cpython-311.pyc +0 -0
- venv/Lib/site-packages/datasets/commands/__pycache__/datasets_cli.cpython-311.pyc +0 -0
- venv/Lib/site-packages/datasets/commands/__pycache__/delete_from_hub.cpython-311.pyc +0 -0
- venv/Lib/site-packages/datasets/commands/__pycache__/env.cpython-311.pyc +0 -0
- venv/Lib/site-packages/datasets/commands/__pycache__/test.cpython-311.pyc +0 -0
- venv/Lib/site-packages/datasets/commands/datasets_cli.py +39 -0
- venv/Lib/site-packages/datasets/commands/delete_from_hub.py +42 -0
- venv/Lib/site-packages/datasets/commands/env.py +41 -0
- venv/Lib/site-packages/datasets/commands/test.py +180 -0
- venv/Lib/site-packages/datasets/config.py +277 -0
- venv/Lib/site-packages/datasets/data_files.py +829 -0
- venv/Lib/site-packages/datasets/dataset_dict.py +0 -0
- venv/Lib/site-packages/datasets/distributed.py +43 -0
- venv/Lib/site-packages/datasets/download/__init__.py +10 -0
- venv/Lib/site-packages/datasets/download/__pycache__/__init__.cpython-311.pyc +0 -0
- venv/Lib/site-packages/datasets/download/__pycache__/download_config.cpython-311.pyc +0 -0
- venv/Lib/site-packages/datasets/download/__pycache__/download_manager.cpython-311.pyc +0 -0
- venv/Lib/site-packages/datasets/download/__pycache__/streaming_download_manager.cpython-311.pyc +0 -0
- venv/Lib/site-packages/datasets/download/download_config.py +81 -0
- venv/Lib/site-packages/datasets/download/download_manager.py +340 -0
- venv/Lib/site-packages/datasets/download/streaming_download_manager.py +219 -0
- venv/Lib/site-packages/datasets/exceptions.py +119 -0
- venv/Lib/site-packages/datasets/features/__init__.py +29 -0
.gitattributes
CHANGED
|
@@ -50,3 +50,7 @@ venv/Lib/site-packages/cv2/opencv_videoio_ffmpeg4130_64.dll filter=lfs diff=lfs
|
|
| 50 |
venv/Lib/site-packages/datasets/__pycache__/arrow_dataset.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text
|
| 51 |
venv/Lib/site-packages/datasets/__pycache__/builder.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text
|
| 52 |
venv/Lib/site-packages/datasets/__pycache__/dataset_dict.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
venv/Lib/site-packages/datasets/__pycache__/arrow_dataset.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text
|
| 51 |
venv/Lib/site-packages/datasets/__pycache__/builder.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text
|
| 52 |
venv/Lib/site-packages/datasets/__pycache__/dataset_dict.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text
|
| 53 |
+
venv/Lib/site-packages/datasets/__pycache__/iterable_dataset.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text
|
| 54 |
+
venv/Lib/site-packages/datasets/__pycache__/table.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text
|
| 55 |
+
venv/Lib/site-packages/datasets/features/__pycache__/features.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text
|
| 56 |
+
venv/Lib/site-packages/dill/__pycache__/_dill.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text
|
venv/Lib/site-packages/datasets-5.0.0.dist-info/AUTHORS
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# This is the list of HuggingFace Datasets authors for copyright purposes.
|
| 2 |
+
#
|
| 3 |
+
# This does not necessarily list everyone who has contributed code, since in
|
| 4 |
+
# some cases, their employer may be the copyright holder. To see the full list
|
| 5 |
+
# of contributors, see the revision history in source control.
|
| 6 |
+
|
| 7 |
+
Google Inc.
|
| 8 |
+
HuggingFace Inc.
|
venv/Lib/site-packages/datasets-5.0.0.dist-info/INSTALLER
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
pip
|
venv/Lib/site-packages/datasets-5.0.0.dist-info/LICENSE
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
Apache License
|
| 3 |
+
Version 2.0, January 2004
|
| 4 |
+
http://www.apache.org/licenses/
|
| 5 |
+
|
| 6 |
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
| 7 |
+
|
| 8 |
+
1. Definitions.
|
| 9 |
+
|
| 10 |
+
"License" shall mean the terms and conditions for use, reproduction,
|
| 11 |
+
and distribution as defined by Sections 1 through 9 of this document.
|
| 12 |
+
|
| 13 |
+
"Licensor" shall mean the copyright owner or entity authorized by
|
| 14 |
+
the copyright owner that is granting the License.
|
| 15 |
+
|
| 16 |
+
"Legal Entity" shall mean the union of the acting entity and all
|
| 17 |
+
other entities that control, are controlled by, or are under common
|
| 18 |
+
control with that entity. For the purposes of this definition,
|
| 19 |
+
"control" means (i) the power, direct or indirect, to cause the
|
| 20 |
+
direction or management of such entity, whether by contract or
|
| 21 |
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
| 22 |
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
| 23 |
+
|
| 24 |
+
"You" (or "Your") shall mean an individual or Legal Entity
|
| 25 |
+
exercising permissions granted by this License.
|
| 26 |
+
|
| 27 |
+
"Source" form shall mean the preferred form for making modifications,
|
| 28 |
+
including but not limited to software source code, documentation
|
| 29 |
+
source, and configuration files.
|
| 30 |
+
|
| 31 |
+
"Object" form shall mean any form resulting from mechanical
|
| 32 |
+
transformation or translation of a Source form, including but
|
| 33 |
+
not limited to compiled object code, generated documentation,
|
| 34 |
+
and conversions to other media types.
|
| 35 |
+
|
| 36 |
+
"Work" shall mean the work of authorship, whether in Source or
|
| 37 |
+
Object form, made available under the License, as indicated by a
|
| 38 |
+
copyright notice that is included in or attached to the work
|
| 39 |
+
(an example is provided in the Appendix below).
|
| 40 |
+
|
| 41 |
+
"Derivative Works" shall mean any work, whether in Source or Object
|
| 42 |
+
form, that is based on (or derived from) the Work and for which the
|
| 43 |
+
editorial revisions, annotations, elaborations, or other modifications
|
| 44 |
+
represent, as a whole, an original work of authorship. For the purposes
|
| 45 |
+
of this License, Derivative Works shall not include works that remain
|
| 46 |
+
separable from, or merely link (or bind by name) to the interfaces of,
|
| 47 |
+
the Work and Derivative Works thereof.
|
| 48 |
+
|
| 49 |
+
"Contribution" shall mean any work of authorship, including
|
| 50 |
+
the original version of the Work and any modifications or additions
|
| 51 |
+
to that Work or Derivative Works thereof, that is intentionally
|
| 52 |
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
| 53 |
+
or by an individual or Legal Entity authorized to submit on behalf of
|
| 54 |
+
the copyright owner. For the purposes of this definition, "submitted"
|
| 55 |
+
means any form of electronic, verbal, or written communication sent
|
| 56 |
+
to the Licensor or its representatives, including but not limited to
|
| 57 |
+
communication on electronic mailing lists, source code control systems,
|
| 58 |
+
and issue tracking systems that are managed by, or on behalf of, the
|
| 59 |
+
Licensor for the purpose of discussing and improving the Work, but
|
| 60 |
+
excluding communication that is conspicuously marked or otherwise
|
| 61 |
+
designated in writing by the copyright owner as "Not a Contribution."
|
| 62 |
+
|
| 63 |
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
| 64 |
+
on behalf of whom a Contribution has been received by Licensor and
|
| 65 |
+
subsequently incorporated within the Work.
|
| 66 |
+
|
| 67 |
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
| 68 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 69 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 70 |
+
copyright license to reproduce, prepare Derivative Works of,
|
| 71 |
+
publicly display, publicly perform, sublicense, and distribute the
|
| 72 |
+
Work and such Derivative Works in Source or Object form.
|
| 73 |
+
|
| 74 |
+
3. Grant of Patent License. Subject to the terms and conditions of
|
| 75 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 76 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 77 |
+
(except as stated in this section) patent license to make, have made,
|
| 78 |
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
| 79 |
+
where such license applies only to those patent claims licensable
|
| 80 |
+
by such Contributor that are necessarily infringed by their
|
| 81 |
+
Contribution(s) alone or by combination of their Contribution(s)
|
| 82 |
+
with the Work to which such Contribution(s) was submitted. If You
|
| 83 |
+
institute patent litigation against any entity (including a
|
| 84 |
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
| 85 |
+
or a Contribution incorporated within the Work constitutes direct
|
| 86 |
+
or contributory patent infringement, then any patent licenses
|
| 87 |
+
granted to You under this License for that Work shall terminate
|
| 88 |
+
as of the date such litigation is filed.
|
| 89 |
+
|
| 90 |
+
4. Redistribution. You may reproduce and distribute copies of the
|
| 91 |
+
Work or Derivative Works thereof in any medium, with or without
|
| 92 |
+
modifications, and in Source or Object form, provided that You
|
| 93 |
+
meet the following conditions:
|
| 94 |
+
|
| 95 |
+
(a) You must give any other recipients of the Work or
|
| 96 |
+
Derivative Works a copy of this License; and
|
| 97 |
+
|
| 98 |
+
(b) You must cause any modified files to carry prominent notices
|
| 99 |
+
stating that You changed the files; and
|
| 100 |
+
|
| 101 |
+
(c) You must retain, in the Source form of any Derivative Works
|
| 102 |
+
that You distribute, all copyright, patent, trademark, and
|
| 103 |
+
attribution notices from the Source form of the Work,
|
| 104 |
+
excluding those notices that do not pertain to any part of
|
| 105 |
+
the Derivative Works; and
|
| 106 |
+
|
| 107 |
+
(d) If the Work includes a "NOTICE" text file as part of its
|
| 108 |
+
distribution, then any Derivative Works that You distribute must
|
| 109 |
+
include a readable copy of the attribution notices contained
|
| 110 |
+
within such NOTICE file, excluding those notices that do not
|
| 111 |
+
pertain to any part of the Derivative Works, in at least one
|
| 112 |
+
of the following places: within a NOTICE text file distributed
|
| 113 |
+
as part of the Derivative Works; within the Source form or
|
| 114 |
+
documentation, if provided along with the Derivative Works; or,
|
| 115 |
+
within a display generated by the Derivative Works, if and
|
| 116 |
+
wherever such third-party notices normally appear. The contents
|
| 117 |
+
of the NOTICE file are for informational purposes only and
|
| 118 |
+
do not modify the License. You may add Your own attribution
|
| 119 |
+
notices within Derivative Works that You distribute, alongside
|
| 120 |
+
or as an addendum to the NOTICE text from the Work, provided
|
| 121 |
+
that such additional attribution notices cannot be construed
|
| 122 |
+
as modifying the License.
|
| 123 |
+
|
| 124 |
+
You may add Your own copyright statement to Your modifications and
|
| 125 |
+
may provide additional or different license terms and conditions
|
| 126 |
+
for use, reproduction, or distribution of Your modifications, or
|
| 127 |
+
for any such Derivative Works as a whole, provided Your use,
|
| 128 |
+
reproduction, and distribution of the Work otherwise complies with
|
| 129 |
+
the conditions stated in this License.
|
| 130 |
+
|
| 131 |
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
| 132 |
+
any Contribution intentionally submitted for inclusion in the Work
|
| 133 |
+
by You to the Licensor shall be under the terms and conditions of
|
| 134 |
+
this License, without any additional terms or conditions.
|
| 135 |
+
Notwithstanding the above, nothing herein shall supersede or modify
|
| 136 |
+
the terms of any separate license agreement you may have executed
|
| 137 |
+
with Licensor regarding such Contributions.
|
| 138 |
+
|
| 139 |
+
6. Trademarks. This License does not grant permission to use the trade
|
| 140 |
+
names, trademarks, service marks, or product names of the Licensor,
|
| 141 |
+
except as required for reasonable and customary use in describing the
|
| 142 |
+
origin of the Work and reproducing the content of the NOTICE file.
|
| 143 |
+
|
| 144 |
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
| 145 |
+
agreed to in writing, Licensor provides the Work (and each
|
| 146 |
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
| 147 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
| 148 |
+
implied, including, without limitation, any warranties or conditions
|
| 149 |
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
| 150 |
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
| 151 |
+
appropriateness of using or redistributing the Work and assume any
|
| 152 |
+
risks associated with Your exercise of permissions under this License.
|
| 153 |
+
|
| 154 |
+
8. Limitation of Liability. In no event and under no legal theory,
|
| 155 |
+
whether in tort (including negligence), contract, or otherwise,
|
| 156 |
+
unless required by applicable law (such as deliberate and grossly
|
| 157 |
+
negligent acts) or agreed to in writing, shall any Contributor be
|
| 158 |
+
liable to You for damages, including any direct, indirect, special,
|
| 159 |
+
incidental, or consequential damages of any character arising as a
|
| 160 |
+
result of this License or out of the use or inability to use the
|
| 161 |
+
Work (including but not limited to damages for loss of goodwill,
|
| 162 |
+
work stoppage, computer failure or malfunction, or any and all
|
| 163 |
+
other commercial damages or losses), even if such Contributor
|
| 164 |
+
has been advised of the possibility of such damages.
|
| 165 |
+
|
| 166 |
+
9. Accepting Warranty or Additional Liability. While redistributing
|
| 167 |
+
the Work or Derivative Works thereof, You may choose to offer,
|
| 168 |
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
| 169 |
+
or other liability obligations and/or rights consistent with this
|
| 170 |
+
License. However, in accepting such obligations, You may act only
|
| 171 |
+
on Your own behalf and on Your sole responsibility, not on behalf
|
| 172 |
+
of any other Contributor, and only if You agree to indemnify,
|
| 173 |
+
defend, and hold each Contributor harmless for any liability
|
| 174 |
+
incurred by, or claims asserted against, such Contributor by reason
|
| 175 |
+
of your accepting any such warranty or additional liability.
|
| 176 |
+
|
| 177 |
+
END OF TERMS AND CONDITIONS
|
| 178 |
+
|
| 179 |
+
APPENDIX: How to apply the Apache License to your work.
|
| 180 |
+
|
| 181 |
+
To apply the Apache License to your work, attach the following
|
| 182 |
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
| 183 |
+
replaced with your own identifying information. (Don't include
|
| 184 |
+
the brackets!) The text should be enclosed in the appropriate
|
| 185 |
+
comment syntax for the file format. We also recommend that a
|
| 186 |
+
file or class name and description of purpose be included on the
|
| 187 |
+
same "printed page" as the copyright notice for easier
|
| 188 |
+
identification within third-party archives.
|
| 189 |
+
|
| 190 |
+
Copyright [yyyy] [name of copyright owner]
|
| 191 |
+
|
| 192 |
+
Licensed under the Apache License, Version 2.0 (the "License");
|
| 193 |
+
you may not use this file except in compliance with the License.
|
| 194 |
+
You may obtain a copy of the License at
|
| 195 |
+
|
| 196 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
| 197 |
+
|
| 198 |
+
Unless required by applicable law or agreed to in writing, software
|
| 199 |
+
distributed under the License is distributed on an "AS IS" BASIS,
|
| 200 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 201 |
+
See the License for the specific language governing permissions and
|
| 202 |
+
limitations under the License.
|
venv/Lib/site-packages/datasets-5.0.0.dist-info/METADATA
ADDED
|
@@ -0,0 +1,500 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Metadata-Version: 2.2
|
| 2 |
+
Name: datasets
|
| 3 |
+
Version: 5.0.0
|
| 4 |
+
Summary: HuggingFace community-driven open-source library of datasets
|
| 5 |
+
Home-page: https://github.com/huggingface/datasets
|
| 6 |
+
Download-URL: https://github.com/huggingface/datasets/tags
|
| 7 |
+
Author: HuggingFace Inc.
|
| 8 |
+
Author-email: thomas@huggingface.co
|
| 9 |
+
License: Apache 2.0
|
| 10 |
+
Keywords: datasets machine learning datasets
|
| 11 |
+
Classifier: Development Status :: 5 - Production/Stable
|
| 12 |
+
Classifier: Intended Audience :: Developers
|
| 13 |
+
Classifier: Intended Audience :: Education
|
| 14 |
+
Classifier: Intended Audience :: Science/Research
|
| 15 |
+
Classifier: License :: OSI Approved :: Apache Software License
|
| 16 |
+
Classifier: Operating System :: OS Independent
|
| 17 |
+
Classifier: Programming Language :: Python :: 3
|
| 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.10.0
|
| 25 |
+
Description-Content-Type: text/markdown
|
| 26 |
+
License-File: LICENSE
|
| 27 |
+
License-File: AUTHORS
|
| 28 |
+
Requires-Dist: filelock
|
| 29 |
+
Requires-Dist: numpy>=1.17
|
| 30 |
+
Requires-Dist: pyarrow>=21.0.0
|
| 31 |
+
Requires-Dist: dill<0.4.2,>=0.3.0
|
| 32 |
+
Requires-Dist: pandas
|
| 33 |
+
Requires-Dist: requests>=2.32.2
|
| 34 |
+
Requires-Dist: httpx<1.0.0
|
| 35 |
+
Requires-Dist: tqdm>=4.66.3
|
| 36 |
+
Requires-Dist: xxhash
|
| 37 |
+
Requires-Dist: multiprocess<0.70.20
|
| 38 |
+
Requires-Dist: fsspec[http]<=2026.4.0,>=2023.1.0
|
| 39 |
+
Requires-Dist: huggingface-hub<2.0,>=0.25.0
|
| 40 |
+
Requires-Dist: packaging
|
| 41 |
+
Requires-Dist: pyyaml>=5.1
|
| 42 |
+
Provides-Extra: audio
|
| 43 |
+
Requires-Dist: torchcodec>=0.6.0; extra == "audio"
|
| 44 |
+
Requires-Dist: torch>=2.8.0; extra == "audio"
|
| 45 |
+
Provides-Extra: vision
|
| 46 |
+
Requires-Dist: Pillow>=9.4.0; extra == "vision"
|
| 47 |
+
Provides-Extra: mesh
|
| 48 |
+
Requires-Dist: trimesh>=4.10.0; extra == "mesh"
|
| 49 |
+
Provides-Extra: tensorflow
|
| 50 |
+
Requires-Dist: tensorflow>=2.6.0; extra == "tensorflow"
|
| 51 |
+
Provides-Extra: tensorflow-gpu
|
| 52 |
+
Requires-Dist: tensorflow>=2.6.0; extra == "tensorflow-gpu"
|
| 53 |
+
Provides-Extra: torch
|
| 54 |
+
Requires-Dist: torch; extra == "torch"
|
| 55 |
+
Provides-Extra: jax
|
| 56 |
+
Requires-Dist: jax>=0.3.14; extra == "jax"
|
| 57 |
+
Requires-Dist: jaxlib>=0.3.14; extra == "jax"
|
| 58 |
+
Provides-Extra: streaming
|
| 59 |
+
Provides-Extra: dev
|
| 60 |
+
Requires-Dist: numba>=0.56.4; python_version < "3.14" and extra == "dev"
|
| 61 |
+
Requires-Dist: absl-py; extra == "dev"
|
| 62 |
+
Requires-Dist: decorator; extra == "dev"
|
| 63 |
+
Requires-Dist: joblib<1.3.0; extra == "dev"
|
| 64 |
+
Requires-Dist: joblibspark; python_version < "3.14" and extra == "dev"
|
| 65 |
+
Requires-Dist: pytest; extra == "dev"
|
| 66 |
+
Requires-Dist: pytest-datadir; extra == "dev"
|
| 67 |
+
Requires-Dist: pytest-xdist; extra == "dev"
|
| 68 |
+
Requires-Dist: aiohttp; extra == "dev"
|
| 69 |
+
Requires-Dist: elasticsearch<8.0.0,>=7.17.12; extra == "dev"
|
| 70 |
+
Requires-Dist: faiss-cpu>=1.8.0.post1; extra == "dev"
|
| 71 |
+
Requires-Dist: h5py; extra == "dev"
|
| 72 |
+
Requires-Dist: pylance; extra == "dev"
|
| 73 |
+
Requires-Dist: pyiceberg[pyarrow,sql-sqlite]; extra == "dev"
|
| 74 |
+
Requires-Dist: jax>=0.3.14; sys_platform != "win32" and extra == "dev"
|
| 75 |
+
Requires-Dist: jaxlib>=0.3.14; sys_platform != "win32" and extra == "dev"
|
| 76 |
+
Requires-Dist: lz4; python_version < "3.14" and extra == "dev"
|
| 77 |
+
Requires-Dist: moto[server]; extra == "dev"
|
| 78 |
+
Requires-Dist: pyspark>=3.4; extra == "dev"
|
| 79 |
+
Requires-Dist: py7zr; extra == "dev"
|
| 80 |
+
Requires-Dist: rarfile>=4.0; extra == "dev"
|
| 81 |
+
Requires-Dist: sqlalchemy; extra == "dev"
|
| 82 |
+
Requires-Dist: protobuf<4.0.0; extra == "dev"
|
| 83 |
+
Requires-Dist: tensorflow>=2.6.0; (python_version < "3.10" and sys_platform != "win32") and extra == "dev"
|
| 84 |
+
Requires-Dist: tensorflow>=2.16.0; (python_version >= "3.10" and sys_platform != "win32" and python_version < "3.14") and extra == "dev"
|
| 85 |
+
Requires-Dist: tiktoken; extra == "dev"
|
| 86 |
+
Requires-Dist: torch>=2.8.0; extra == "dev"
|
| 87 |
+
Requires-Dist: torchdata; extra == "dev"
|
| 88 |
+
Requires-Dist: transformers>=4.42.0; extra == "dev"
|
| 89 |
+
Requires-Dist: zstandard; extra == "dev"
|
| 90 |
+
Requires-Dist: polars[timezone]>=0.20.0; extra == "dev"
|
| 91 |
+
Requires-Dist: Pillow>=9.4.0; extra == "dev"
|
| 92 |
+
Requires-Dist: torchcodec>=0.7.0; python_version < "3.14" and extra == "dev"
|
| 93 |
+
Requires-Dist: nibabel>=5.3.1; extra == "dev"
|
| 94 |
+
Requires-Dist: trimesh>=4.10.0; extra == "dev"
|
| 95 |
+
Requires-Dist: teich==0.1.1a76; extra == "dev"
|
| 96 |
+
Requires-Dist: ruff>=0.3.0; extra == "dev"
|
| 97 |
+
Requires-Dist: transformers; extra == "dev"
|
| 98 |
+
Requires-Dist: torch; extra == "dev"
|
| 99 |
+
Requires-Dist: tensorflow>=2.6.0; extra == "dev"
|
| 100 |
+
Provides-Extra: tests
|
| 101 |
+
Requires-Dist: numba>=0.56.4; python_version < "3.14" and extra == "tests"
|
| 102 |
+
Requires-Dist: absl-py; extra == "tests"
|
| 103 |
+
Requires-Dist: decorator; extra == "tests"
|
| 104 |
+
Requires-Dist: joblib<1.3.0; extra == "tests"
|
| 105 |
+
Requires-Dist: joblibspark; python_version < "3.14" and extra == "tests"
|
| 106 |
+
Requires-Dist: pytest; extra == "tests"
|
| 107 |
+
Requires-Dist: pytest-datadir; extra == "tests"
|
| 108 |
+
Requires-Dist: pytest-xdist; extra == "tests"
|
| 109 |
+
Requires-Dist: aiohttp; extra == "tests"
|
| 110 |
+
Requires-Dist: elasticsearch<8.0.0,>=7.17.12; extra == "tests"
|
| 111 |
+
Requires-Dist: faiss-cpu>=1.8.0.post1; extra == "tests"
|
| 112 |
+
Requires-Dist: h5py; extra == "tests"
|
| 113 |
+
Requires-Dist: pylance; extra == "tests"
|
| 114 |
+
Requires-Dist: pyiceberg[pyarrow,sql-sqlite]; extra == "tests"
|
| 115 |
+
Requires-Dist: jax>=0.3.14; sys_platform != "win32" and extra == "tests"
|
| 116 |
+
Requires-Dist: jaxlib>=0.3.14; sys_platform != "win32" and extra == "tests"
|
| 117 |
+
Requires-Dist: lz4; python_version < "3.14" and extra == "tests"
|
| 118 |
+
Requires-Dist: moto[server]; extra == "tests"
|
| 119 |
+
Requires-Dist: pyspark>=3.4; extra == "tests"
|
| 120 |
+
Requires-Dist: py7zr; extra == "tests"
|
| 121 |
+
Requires-Dist: rarfile>=4.0; extra == "tests"
|
| 122 |
+
Requires-Dist: sqlalchemy; extra == "tests"
|
| 123 |
+
Requires-Dist: protobuf<4.0.0; extra == "tests"
|
| 124 |
+
Requires-Dist: tensorflow>=2.6.0; (python_version < "3.10" and sys_platform != "win32") and extra == "tests"
|
| 125 |
+
Requires-Dist: tensorflow>=2.16.0; (python_version >= "3.10" and sys_platform != "win32" and python_version < "3.14") and extra == "tests"
|
| 126 |
+
Requires-Dist: tiktoken; extra == "tests"
|
| 127 |
+
Requires-Dist: torch>=2.8.0; extra == "tests"
|
| 128 |
+
Requires-Dist: torchdata; extra == "tests"
|
| 129 |
+
Requires-Dist: transformers>=4.42.0; extra == "tests"
|
| 130 |
+
Requires-Dist: zstandard; extra == "tests"
|
| 131 |
+
Requires-Dist: polars[timezone]>=0.20.0; extra == "tests"
|
| 132 |
+
Requires-Dist: Pillow>=9.4.0; extra == "tests"
|
| 133 |
+
Requires-Dist: torchcodec>=0.7.0; python_version < "3.14" and extra == "tests"
|
| 134 |
+
Requires-Dist: nibabel>=5.3.1; extra == "tests"
|
| 135 |
+
Requires-Dist: trimesh>=4.10.0; extra == "tests"
|
| 136 |
+
Requires-Dist: teich==0.1.1a76; extra == "tests"
|
| 137 |
+
Provides-Extra: tests-numpy2
|
| 138 |
+
Requires-Dist: numba>=0.56.4; python_version < "3.14" and extra == "tests-numpy2"
|
| 139 |
+
Requires-Dist: absl-py; extra == "tests-numpy2"
|
| 140 |
+
Requires-Dist: decorator; extra == "tests-numpy2"
|
| 141 |
+
Requires-Dist: joblib<1.3.0; extra == "tests-numpy2"
|
| 142 |
+
Requires-Dist: joblibspark; python_version < "3.14" and extra == "tests-numpy2"
|
| 143 |
+
Requires-Dist: pytest; extra == "tests-numpy2"
|
| 144 |
+
Requires-Dist: pytest-datadir; extra == "tests-numpy2"
|
| 145 |
+
Requires-Dist: pytest-xdist; extra == "tests-numpy2"
|
| 146 |
+
Requires-Dist: aiohttp; extra == "tests-numpy2"
|
| 147 |
+
Requires-Dist: elasticsearch<8.0.0,>=7.17.12; extra == "tests-numpy2"
|
| 148 |
+
Requires-Dist: h5py; extra == "tests-numpy2"
|
| 149 |
+
Requires-Dist: pylance; extra == "tests-numpy2"
|
| 150 |
+
Requires-Dist: pyiceberg[pyarrow,sql-sqlite]; extra == "tests-numpy2"
|
| 151 |
+
Requires-Dist: jax>=0.3.14; sys_platform != "win32" and extra == "tests-numpy2"
|
| 152 |
+
Requires-Dist: jaxlib>=0.3.14; sys_platform != "win32" and extra == "tests-numpy2"
|
| 153 |
+
Requires-Dist: lz4; python_version < "3.14" and extra == "tests-numpy2"
|
| 154 |
+
Requires-Dist: moto[server]; extra == "tests-numpy2"
|
| 155 |
+
Requires-Dist: pyspark>=3.4; extra == "tests-numpy2"
|
| 156 |
+
Requires-Dist: py7zr; extra == "tests-numpy2"
|
| 157 |
+
Requires-Dist: rarfile>=4.0; extra == "tests-numpy2"
|
| 158 |
+
Requires-Dist: sqlalchemy; extra == "tests-numpy2"
|
| 159 |
+
Requires-Dist: protobuf<4.0.0; extra == "tests-numpy2"
|
| 160 |
+
Requires-Dist: tiktoken; extra == "tests-numpy2"
|
| 161 |
+
Requires-Dist: torch>=2.8.0; extra == "tests-numpy2"
|
| 162 |
+
Requires-Dist: torchdata; extra == "tests-numpy2"
|
| 163 |
+
Requires-Dist: transformers>=4.42.0; extra == "tests-numpy2"
|
| 164 |
+
Requires-Dist: zstandard; extra == "tests-numpy2"
|
| 165 |
+
Requires-Dist: polars[timezone]>=0.20.0; extra == "tests-numpy2"
|
| 166 |
+
Requires-Dist: Pillow>=9.4.0; extra == "tests-numpy2"
|
| 167 |
+
Requires-Dist: torchcodec>=0.7.0; python_version < "3.14" and extra == "tests-numpy2"
|
| 168 |
+
Requires-Dist: nibabel>=5.3.1; extra == "tests-numpy2"
|
| 169 |
+
Requires-Dist: trimesh>=4.10.0; extra == "tests-numpy2"
|
| 170 |
+
Requires-Dist: teich==0.1.1a76; extra == "tests-numpy2"
|
| 171 |
+
Provides-Extra: quality
|
| 172 |
+
Requires-Dist: ruff>=0.3.0; extra == "quality"
|
| 173 |
+
Provides-Extra: benchmarks
|
| 174 |
+
Requires-Dist: tensorflow==2.12.0; extra == "benchmarks"
|
| 175 |
+
Requires-Dist: torch==2.0.1; extra == "benchmarks"
|
| 176 |
+
Requires-Dist: transformers==4.30.1; extra == "benchmarks"
|
| 177 |
+
Provides-Extra: docs
|
| 178 |
+
Requires-Dist: transformers; extra == "docs"
|
| 179 |
+
Requires-Dist: torch; extra == "docs"
|
| 180 |
+
Requires-Dist: tensorflow>=2.6.0; extra == "docs"
|
| 181 |
+
Provides-Extra: pdfs
|
| 182 |
+
Requires-Dist: pdfplumber>=0.11.4; extra == "pdfs"
|
| 183 |
+
Provides-Extra: nibabel
|
| 184 |
+
Requires-Dist: nibabel>=5.3.2; extra == "nibabel"
|
| 185 |
+
Requires-Dist: ipyniivue==2.4.2; extra == "nibabel"
|
| 186 |
+
Provides-Extra: iceberg
|
| 187 |
+
Requires-Dist: pyiceberg>=0.7.0; extra == "iceberg"
|
| 188 |
+
Dynamic: author
|
| 189 |
+
Dynamic: author-email
|
| 190 |
+
Dynamic: classifier
|
| 191 |
+
Dynamic: description
|
| 192 |
+
Dynamic: description-content-type
|
| 193 |
+
Dynamic: download-url
|
| 194 |
+
Dynamic: home-page
|
| 195 |
+
Dynamic: keywords
|
| 196 |
+
Dynamic: license
|
| 197 |
+
Dynamic: provides-extra
|
| 198 |
+
Dynamic: requires-dist
|
| 199 |
+
Dynamic: requires-python
|
| 200 |
+
Dynamic: summary
|
| 201 |
+
|
| 202 |
+
<p align="center">
|
| 203 |
+
<picture>
|
| 204 |
+
<source media="(prefers-color-scheme: dark)" srcset="https://huggingface.co/datasets/huggingface/documentation-images/raw/main/datasets-logo-dark.svg">
|
| 205 |
+
<source media="(prefers-color-scheme: light)" srcset="https://huggingface.co/datasets/huggingface/documentation-images/raw/main/datasets-logo-light.svg">
|
| 206 |
+
<img alt="Hugging Face Datasets Library" src="https://huggingface.co/datasets/huggingface/documentation-images/raw/main/datasets-logo-light.svg" width="352" height="59" style="max-width: 100%;">
|
| 207 |
+
</picture>
|
| 208 |
+
<br/>
|
| 209 |
+
<br/>
|
| 210 |
+
</p>
|
| 211 |
+
|
| 212 |
+
<p align="center">
|
| 213 |
+
<a href="https://github.com/huggingface/datasets/actions/workflows/ci.yml?query=branch%3Amain"><img alt="Build" src="https://github.com/huggingface/datasets/actions/workflows/ci.yml/badge.svg?branch=main"></a>
|
| 214 |
+
<a href="https://github.com/huggingface/datasets/blob/main/LICENSE"><img alt="GitHub" src="https://img.shields.io/github/license/huggingface/datasets.svg?color=blue"></a>
|
| 215 |
+
<a href="https://huggingface.co/docs/datasets/index.html"><img alt="Documentation" src="https://img.shields.io/website/http/huggingface.co/docs/datasets/index.html.svg?down_color=red&down_message=offline&up_message=online"></a>
|
| 216 |
+
<a href="https://github.com/huggingface/datasets/releases"><img alt="GitHub release" src="https://img.shields.io/github/release/huggingface/datasets.svg"></a>
|
| 217 |
+
<a href="https://huggingface.co/datasets/"><img alt="Number of datasets" src="https://img.shields.io/endpoint?url=https://huggingface.co/api/shields/datasets&color=brightgreen"></a>
|
| 218 |
+
<a href="CODE_OF_CONDUCT.md"><img alt="Contributor Covenant" src="https://img.shields.io/badge/Contributor%20Covenant-2.0-4baaaa.svg"></a>
|
| 219 |
+
<a href="https://zenodo.org/badge/latestdoi/250213286"><img src="https://zenodo.org/badge/250213286.svg" alt="DOI"></a>
|
| 220 |
+
</p>
|
| 221 |
+
|
| 222 |
+
🤗 Datasets is a lightweight library providing **two** main features:
|
| 223 |
+
|
| 224 |
+
- **one-line dataloaders for many public datasets**: one-liners to download and pre-process any of the  major public datasets (image datasets, audio datasets, text datasets in 467 languages and dialects, 3D medical images, video datasets, agent traces, etc.) provided on the [HuggingFace Datasets Hub](https://huggingface.co/datasets). With a simple command like `squad_dataset = load_dataset("rajpurkar/squad")`, get any of these datasets ready to use in a dataloader for training/evaluating a ML model (Numpy/Pandas/PyTorch/TensorFlow/JAX/Polars),
|
| 225 |
+
- **efficient data pre-processing**: simple, fast and reproducible data pre-processing for the public datasets as well as your own local datasets in CSV, JSON, JSONL, Parquet, HDF5, XML, text, PNG, JPEG, WAV, MP3, PDF, NIfTI, and more. With simple commands like `processed_dataset = dataset.map(process_example)`, efficiently prepare the dataset for inspection and ML model evaluation and training.
|
| 226 |
+
|
| 227 |
+
[🎓 **Documentation**](https://huggingface.co/docs/datasets/) [🔎 **Find a dataset in the Hub**](https://huggingface.co/datasets) [🌟 **Share a dataset on the Hub**](https://huggingface.co/docs/datasets/share)
|
| 228 |
+
|
| 229 |
+
<h3 align="center">
|
| 230 |
+
<a href="https://hf.co/course"><img src="https://raw.githubusercontent.com/huggingface/datasets/main/docs/source/imgs/course_banner.png"></a>
|
| 231 |
+
</h3>
|
| 232 |
+
|
| 233 |
+
# 🚀 Key Features
|
| 234 |
+
|
| 235 |
+
🤗 Datasets is designed to let the community easily add and share new datasets, and provides powerful capabilities for data manipulation:
|
| 236 |
+
|
| 237 |
+
| Feature | Description |
|
| 238 |
+
|---------|-------------|
|
| 239 |
+
| 📦 **One-line dataset loading** | Load AI-ready datasets from the [Hugging Face Hub](https://huggingface.co/datasets) or local files with `load_dataset()` |
|
| 240 |
+
| 🔍 **Multiple formats** | Native support for CSV, JSON, JSONL, Parquet, Arrow, XML, Text, Webdataset, and more |
|
| 241 |
+
| 🖼️ **Multi-modal data** | Built-in support for text, audio, image, video, PDF, and NIfTI (3D medical) data |
|
| 242 |
+
| 🚀 **Streaming mode** | Stream datasets without downloading — iterate over data on-the-fly with `streaming=True` (now up to **100x faster** with Xet backend) |
|
| 243 |
+
| 💾 **HF Storage Buckets** | Read and write directly from/to [Hugging Face Storage Buckets](https://huggingface.co/docs/hub/storage-buckets) for mutable, large-scale raw data |
|
| 244 |
+
| 🧠 **AI Agent Traces** | Load and process AI agent traces (prompts, tool calls, responses) from the Hub |
|
| 245 |
+
| ⚡ **Apache Arrow backend** | Zero-copy memory-mapped storage — datasets naturally free you from RAM limitations |
|
| 246 |
+
| 🔄 **Smart caching** | Never wait for your data to process twice — cached results are automatically reused |
|
| 247 |
+
| 📊 **Multi-framework interoperability** | Native conversion to/from NumPy, Pandas, Polars, Arrow, PyTorch, TensorFlow, JAX, and Spark |
|
| 248 |
+
| 🏎️ **Multi-processing** | Fast parallel data processing with `map(num_proc=N)` |
|
| 249 |
+
| 🔎 **Search & index** | Built-in FAISS and Elasticsearch index support for similarity search |
|
| 250 |
+
| 📦 **JSON type** | Flexible JSON/structured data support with `Json()` feature type |
|
| 251 |
+
|
| 252 |
+
# Installation
|
| 253 |
+
|
| 254 |
+
## With pip
|
| 255 |
+
|
| 256 |
+
🤗 Datasets can be installed from PyPi and should be installed in a virtual environment (venv or conda for instance):
|
| 257 |
+
|
| 258 |
+
```bash
|
| 259 |
+
pip install datasets
|
| 260 |
+
```
|
| 261 |
+
|
| 262 |
+
For the latest development version:
|
| 263 |
+
|
| 264 |
+
```bash
|
| 265 |
+
pip install "datasets @ git+https://github.com/huggingface/datasets.git"
|
| 266 |
+
```
|
| 267 |
+
|
| 268 |
+
## With conda
|
| 269 |
+
|
| 270 |
+
```bash
|
| 271 |
+
conda install -c huggingface -c conda-forge datasets
|
| 272 |
+
```
|
| 273 |
+
|
| 274 |
+
## Optional dependencies
|
| 275 |
+
|
| 276 |
+
🤗 Datasets supports various optional features via extras:
|
| 277 |
+
|
| 278 |
+
```bash
|
| 279 |
+
# For audio (torchcodec)
|
| 280 |
+
pip install datasets[audio]
|
| 281 |
+
|
| 282 |
+
# For image/video (Pillow, torchcodec)
|
| 283 |
+
pip install datasets[vision]
|
| 284 |
+
|
| 285 |
+
# For PDFs/NIfTI (pdfplumber, nibabel)
|
| 286 |
+
pip install datasets[pdfs,nibabel]
|
| 287 |
+
|
| 288 |
+
# For PyTorch/TensorFlow/JAX integration
|
| 289 |
+
pip install datasets[torch,tensorflow,jax]
|
| 290 |
+
|
| 291 |
+
```
|
| 292 |
+
|
| 293 |
+
For more details on installation, check the [installation page](https://huggingface.co/docs/datasets/installation).
|
| 294 |
+
|
| 295 |
+
# Quick Start
|
| 296 |
+
|
| 297 |
+
🤗 Datasets is made to be very simple to use — the API is centered around a single function, `datasets.load_dataset(dataset_name, **kwargs)`, that instantiates a dataset.
|
| 298 |
+
|
| 299 |
+
Here is a quick example:
|
| 300 |
+
|
| 301 |
+
```python
|
| 302 |
+
from datasets import load_dataset
|
| 303 |
+
|
| 304 |
+
# Load a dataset and print the first example in the training set
|
| 305 |
+
squad_dataset = load_dataset('rajpurkar/squad')
|
| 306 |
+
print(squad_dataset['train'][0])
|
| 307 |
+
|
| 308 |
+
# Process the dataset - add a column with the length of the context texts
|
| 309 |
+
dataset_with_length = squad_dataset.map(lambda x: {"length": len(x["context"])})
|
| 310 |
+
|
| 311 |
+
# Tokenize the context texts (using a tokenizer from the 🤗 Transformers library)
|
| 312 |
+
from transformers import AutoTokenizer
|
| 313 |
+
tokenizer = AutoTokenizer.from_pretrained('bert-base-cased')
|
| 314 |
+
|
| 315 |
+
tokenized_dataset = squad_dataset.map(lambda x: tokenizer(x['context']), batched=True)
|
| 316 |
+
|
| 317 |
+
# Tokenize chat conversations with a chat template (using a model that supports chat templates)
|
| 318 |
+
# This is useful for fine-tuning instruction/chat models
|
| 319 |
+
|
| 320 |
+
# Load a popular chat dataset (ultrachat_200k contains ~200k AI assistant conversations)
|
| 321 |
+
chat_dataset = load_dataset('HuggingFaceH4/ultrachat_200k', split='train_sft')
|
| 322 |
+
|
| 323 |
+
chat_tokenizer = AutoTokenizer.from_pretrained('Qwen/Qwen2.5-7B-Instruct')
|
| 324 |
+
|
| 325 |
+
def tokenize_chat(examples):
|
| 326 |
+
# Apply the chat template and tokenize in one step
|
| 327 |
+
return chat_tokenizer.apply_chat_template(examples["messages"])
|
| 328 |
+
|
| 329 |
+
tokenized_chat_dataset = chat_dataset.map(tokenize_chat, batched=True)
|
| 330 |
+
```
|
| 331 |
+
|
| 332 |
+
## Streaming mode
|
| 333 |
+
|
| 334 |
+
If your dataset is bigger than your disk or if you don't want to wait to download the data, you can use streaming:
|
| 335 |
+
|
| 336 |
+
```python
|
| 337 |
+
# Stream the dataset without downloading anything
|
| 338 |
+
image_dataset = load_dataset('timm/imagenet-1k-wds', streaming=True)
|
| 339 |
+
for example in image_dataset["train"]:
|
| 340 |
+
print(example["image"])
|
| 341 |
+
break
|
| 342 |
+
```
|
| 343 |
+
|
| 344 |
+
## Multi-modal data
|
| 345 |
+
|
| 346 |
+
🤗 Datasets supports a wide variety of data types out of the box:
|
| 347 |
+
|
| 348 |
+
```python
|
| 349 |
+
# Audio dataset
|
| 350 |
+
dataset = load_dataset("openslr/librispeech_asr", "clean")
|
| 351 |
+
|
| 352 |
+
# Image dataset
|
| 353 |
+
dataset = load_dataset("ILSVRC/imagenet-1k")
|
| 354 |
+
|
| 355 |
+
# Video dataset
|
| 356 |
+
dataset = load_dataset("Shofo/shofo-tiktok-general-small")
|
| 357 |
+
|
| 358 |
+
# PDF documents
|
| 359 |
+
dataset = load_dataset("pixparse/pdfa-eng-wds")
|
| 360 |
+
|
| 361 |
+
# NIfTI (3D medical imaging)
|
| 362 |
+
dataset = load_dataset("dartbrains/localizer", "betas")
|
| 363 |
+
```
|
| 364 |
+
|
| 365 |
+
## From local files
|
| 366 |
+
|
| 367 |
+
```python
|
| 368 |
+
# Load from local CSV
|
| 369 |
+
dataset = load_dataset('csv', data_files='my_data.csv')
|
| 370 |
+
|
| 371 |
+
# Load from local Parquet
|
| 372 |
+
dataset = load_dataset('parquet', data_files='data/*.parquet')
|
| 373 |
+
|
| 374 |
+
# Load from a local directory (auto-detect format)
|
| 375 |
+
dataset = load_dataset('./path/to/data')
|
| 376 |
+
```
|
| 377 |
+
|
| 378 |
+
## From Python objects
|
| 379 |
+
|
| 380 |
+
```python
|
| 381 |
+
from datasets import Dataset
|
| 382 |
+
|
| 383 |
+
# From a dictionary
|
| 384 |
+
dataset = Dataset.from_dict({"text": ["Hello world", "How are you?"]})
|
| 385 |
+
|
| 386 |
+
# From a list
|
| 387 |
+
dataset = Dataset.from_list([{"text": "Hello world"}, {"text": "How are you?"}])
|
| 388 |
+
|
| 389 |
+
# From Pandas
|
| 390 |
+
import pandas as pd
|
| 391 |
+
df = pd.DataFrame({"col1": [1, 2, 3], "col2": ["a", "b", "c"]})
|
| 392 |
+
dataset = Dataset.from_pandas(df)
|
| 393 |
+
|
| 394 |
+
# From a generator
|
| 395 |
+
def gen():
|
| 396 |
+
for i in range(10):
|
| 397 |
+
yield {"value": i}
|
| 398 |
+
dataset = Dataset.from_generator(gen)
|
| 399 |
+
```
|
| 400 |
+
|
| 401 |
+
For more details on using the library, check the [quick start guide](https://huggingface.co/docs/datasets/quickstart) and the specific pages on:
|
| 402 |
+
|
| 403 |
+
- [Loading a dataset](https://huggingface.co/docs/datasets/loading)
|
| 404 |
+
- [What's in a Dataset](https://huggingface.co/docs/datasets/access)
|
| 405 |
+
- [Processing data with 🤗 Datasets](https://huggingface.co/docs/datasets/process)
|
| 406 |
+
- [Processing audio data](https://huggingface.co/docs/datasets/audio_process)
|
| 407 |
+
- [Processing image data](https://huggingface.co/docs/datasets/image_process)
|
| 408 |
+
- [Processing text data](https://huggingface.co/docs/datasets/nlp_process)
|
| 409 |
+
- [Processing PDF data](https://huggingface.co/docs/datasets/pdf_process)
|
| 410 |
+
- [Processing video data](https://huggingface.co/docs/datasets/video_process)
|
| 411 |
+
- [Streaming a dataset](https://huggingface.co/docs/datasets/stream)
|
| 412 |
+
|
| 413 |
+
# Core Classes
|
| 414 |
+
|
| 415 |
+
The library provides two main dataset classes:
|
| 416 |
+
|
| 417 |
+
| Class | Description |
|
| 418 |
+
|-------|-------------|
|
| 419 |
+
| `Dataset` | In-memory / memory-mapped dataset backed by Apache Arrow. Supports indexing, slicing, random access and caching. |
|
| 420 |
+
| `IterableDataset` | Lazy, streamable dataset for large-scale / out-of-core processing. Supports streaming and infinite iteration. |
|
| 421 |
+
|
| 422 |
+
Both are wrapped in `DatasetDict` / `IterableDatasetDict` for multi-split datasets (e.g., train/test/val).
|
| 423 |
+
|
| 424 |
+
# Add a new dataset to the Hub
|
| 425 |
+
|
| 426 |
+
We have a very detailed step-by-step guide to add a new dataset to the  datasets already provided on the [HuggingFace Datasets Hub](https://huggingface.co/datasets).
|
| 427 |
+
|
| 428 |
+
You can find:
|
| 429 |
+
- [how to upload a dataset to the Hub using your web browser or Python](https://huggingface.co/docs/datasets/upload_dataset) and also
|
| 430 |
+
- [how to upload it using Git](https://huggingface.co/docs/datasets/share).
|
| 431 |
+
|
| 432 |
+
# Disclaimers
|
| 433 |
+
|
| 434 |
+
You can use 🤗 Datasets to load datasets based on versioned git repositories maintained by the dataset authors. For reproducibility reasons, we ask users to pin the `revision` of the repositories they use.
|
| 435 |
+
|
| 436 |
+
If you're a dataset owner and wish to update any part of it (description, citation, license, etc.), or do not want your dataset to be included in the Hugging Face Hub, please get in touch by opening a discussion or a pull request in the Community tab of the dataset page. Thanks for your contribution to the ML community!
|
| 437 |
+
|
| 438 |
+
# Contributing
|
| 439 |
+
|
| 440 |
+
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details on:
|
| 441 |
+
|
| 442 |
+
- How to submit issues and pull requests
|
| 443 |
+
- Code style guidelines (we use [Ruff](https://docs.astral.sh/ruff/))
|
| 444 |
+
- Testing requirements
|
| 445 |
+
- Documentation standards
|
| 446 |
+
|
| 447 |
+
# BibTeX
|
| 448 |
+
|
| 449 |
+
If you want to cite our 🤗 Datasets library, you can use our [paper](https://huggingface.co/papers/2109.02846):
|
| 450 |
+
|
| 451 |
+
```bibtex
|
| 452 |
+
@inproceedings{lhoest-etal-2021-datasets,
|
| 453 |
+
title = "Datasets: A Community Library for Natural Language Processing",
|
| 454 |
+
author = "Lhoest, Quentin and
|
| 455 |
+
Villanova del Moral, Albert and
|
| 456 |
+
Jernite, Yacine and
|
| 457 |
+
Thakur, Abhishek and
|
| 458 |
+
von Platen, Patrick and
|
| 459 |
+
Patil, Suraj and
|
| 460 |
+
Chaumond, Julien and
|
| 461 |
+
Drame, Mariama and
|
| 462 |
+
Plu, Julien and
|
| 463 |
+
Tunstall, Lewis and
|
| 464 |
+
Davison, Joe and
|
| 465 |
+
{\v{S}}a{\v{s}}ko, Mario and
|
| 466 |
+
Chhablani, Gunjan and
|
| 467 |
+
Malik, Bhavitvya and
|
| 468 |
+
Brandeis, Simon and
|
| 469 |
+
Le Scao, Teven and
|
| 470 |
+
Sanh, Victor and
|
| 471 |
+
Xu, Canwen and
|
| 472 |
+
Patry, Nicolas and
|
| 473 |
+
McMillan-Major, Angelina and
|
| 474 |
+
Schmid, Philipp and
|
| 475 |
+
Gugger, Sylvain and
|
| 476 |
+
Delangue, Cl{\'e}ment and
|
| 477 |
+
Matussi{\`e}re, Th{\'e}o and
|
| 478 |
+
Debut, Lysandre and
|
| 479 |
+
Bekman, Stas and
|
| 480 |
+
Cistac, Pierric and
|
| 481 |
+
Goehringer, Thibault and
|
| 482 |
+
Mustar, Victor and
|
| 483 |
+
Lagunas, Fran{\c{c}}ois and
|
| 484 |
+
Rush, Alexander and
|
| 485 |
+
Wolf, Thomas",
|
| 486 |
+
booktitle = "Proceedings of the 2021 Conference on Empirical Methods in Natural Language Processing: System Demonstrations",
|
| 487 |
+
month = nov,
|
| 488 |
+
year = "2021",
|
| 489 |
+
address = "Online and Punta Cana, Dominican Republic",
|
| 490 |
+
publisher = "Association for Computational Linguistics",
|
| 491 |
+
url = "https://aclanthology.org/2021.emnlp-demo.21",
|
| 492 |
+
pages = "175--184",
|
| 493 |
+
abstract = "The scale, variety, and quantity of publicly-available NLP datasets has grown rapidly as researchers propose new tasks, larger models, and novel benchmarks. Datasets is a community library for contemporary NLP designed to support this ecosystem. Datasets aims to standardize end-user interfaces, versioning, and documentation, while providing a lightweight front-end that behaves similarly for small datasets as for internet-scale corpora. The design of the library incorporates a distributed, community-driven approach to adding datasets and documenting usage. After a year of development, the library now includes more than 650 unique datasets, has more than 250 contributors, and has helped support a variety of novel cross-dataset research projects and shared tasks. The library is available at https://github.com/huggingface/datasets.",
|
| 494 |
+
eprint={2109.02846},
|
| 495 |
+
archivePrefix={arXiv},
|
| 496 |
+
primaryClass={cs.CL},
|
| 497 |
+
}
|
| 498 |
+
```
|
| 499 |
+
|
| 500 |
+
If you need to cite a specific version of our 🤗 Datasets library for reproducibility, you can use the corresponding version Zenodo DOI from this [list](https://zenodo.org/search?q=conceptrecid:%224817768%22&sort=-version&all_versions=True).
|
venv/Lib/site-packages/datasets-5.0.0.dist-info/RECORD
ADDED
|
@@ -0,0 +1,291 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
../../Scripts/datasets-cli.exe,sha256=KFWQHy0Gnh0J6GqWrpeb1aex4skMTUzWUFLh5L75GF0,108406
|
| 2 |
+
datasets-5.0.0.dist-info/AUTHORS,sha256=L0FBY23tCNHLmvsOKAbumHn8WZZIK98sH53JYxhAchU,327
|
| 3 |
+
datasets-5.0.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
| 4 |
+
datasets-5.0.0.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
|
| 5 |
+
datasets-5.0.0.dist-info/METADATA,sha256=v2izydMJMyuRNfmA48q25NF19E2gJMOgu-cmYJiGx6A,23743
|
| 6 |
+
datasets-5.0.0.dist-info/RECORD,,
|
| 7 |
+
datasets-5.0.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 8 |
+
datasets-5.0.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
| 9 |
+
datasets-5.0.0.dist-info/entry_points.txt,sha256=iM-h4A7OQCrZqr3L2mwiyMtPeFj8w4HAHzmI45y3tg0,69
|
| 10 |
+
datasets-5.0.0.dist-info/top_level.txt,sha256=9A857YvCQm_Dg3UjeKkWPz9sDBos0t3zN2pf5krTemQ,9
|
| 11 |
+
datasets/__init__.py,sha256=sRMzsbglG4fTNrVE32Yh49LJGbp5AMoXcX8lDQXVhXQ,1630
|
| 12 |
+
datasets/__pycache__/__init__.cpython-311.pyc,,
|
| 13 |
+
datasets/__pycache__/arrow_dataset.cpython-311.pyc,,
|
| 14 |
+
datasets/__pycache__/arrow_reader.cpython-311.pyc,,
|
| 15 |
+
datasets/__pycache__/arrow_writer.cpython-311.pyc,,
|
| 16 |
+
datasets/__pycache__/builder.cpython-311.pyc,,
|
| 17 |
+
datasets/__pycache__/combine.cpython-311.pyc,,
|
| 18 |
+
datasets/__pycache__/config.cpython-311.pyc,,
|
| 19 |
+
datasets/__pycache__/data_files.cpython-311.pyc,,
|
| 20 |
+
datasets/__pycache__/dataset_dict.cpython-311.pyc,,
|
| 21 |
+
datasets/__pycache__/distributed.cpython-311.pyc,,
|
| 22 |
+
datasets/__pycache__/exceptions.cpython-311.pyc,,
|
| 23 |
+
datasets/__pycache__/fingerprint.cpython-311.pyc,,
|
| 24 |
+
datasets/__pycache__/hub.cpython-311.pyc,,
|
| 25 |
+
datasets/__pycache__/info.cpython-311.pyc,,
|
| 26 |
+
datasets/__pycache__/inspect.cpython-311.pyc,,
|
| 27 |
+
datasets/__pycache__/iterable_dataset.cpython-311.pyc,,
|
| 28 |
+
datasets/__pycache__/load.cpython-311.pyc,,
|
| 29 |
+
datasets/__pycache__/naming.cpython-311.pyc,,
|
| 30 |
+
datasets/__pycache__/search.cpython-311.pyc,,
|
| 31 |
+
datasets/__pycache__/splits.cpython-311.pyc,,
|
| 32 |
+
datasets/__pycache__/streaming.cpython-311.pyc,,
|
| 33 |
+
datasets/__pycache__/table.cpython-311.pyc,,
|
| 34 |
+
datasets/arrow_dataset.py,sha256=uy20R--VU08YaBmb1kRvFcwmR8nZVm11lOwgc7MhSqo,342300
|
| 35 |
+
datasets/arrow_reader.py,sha256=54yLKdxCtZsuLgcZ3EiUvun_oors0zS3TTtQn7OPNa4,25215
|
| 36 |
+
datasets/arrow_writer.py,sha256=30Ipiwwb-kiQskaYqh3rAUzG4VouzOW77AQ4Zc2Shy0,38706
|
| 37 |
+
datasets/builder.py,sha256=0RdRBcf59t9sHZPyN_mMR_lrInlC6m8tC4Gd2lbeNJY,87946
|
| 38 |
+
datasets/combine.py,sha256=MAqgg95h_DW1bb00gSZdD_a7DNnF9_kis8xwS4WFRKw,11761
|
| 39 |
+
datasets/commands/__init__.py,sha256=rujbQtxJbwHhF9WQqp2DD9tfVTghDMJdl0v6H551Pcs,312
|
| 40 |
+
datasets/commands/__pycache__/__init__.cpython-311.pyc,,
|
| 41 |
+
datasets/commands/__pycache__/datasets_cli.cpython-311.pyc,,
|
| 42 |
+
datasets/commands/__pycache__/delete_from_hub.cpython-311.pyc,,
|
| 43 |
+
datasets/commands/__pycache__/env.cpython-311.pyc,,
|
| 44 |
+
datasets/commands/__pycache__/test.cpython-311.pyc,,
|
| 45 |
+
datasets/commands/datasets_cli.py,sha256=CRy2H60h2sxJDpfa4LZ4dxipdGIZlTL47pEXLV6tfwQ,1175
|
| 46 |
+
datasets/commands/delete_from_hub.py,sha256=o0wdolb1r1Jnl6F0KdqKn3u0l8VR2od6KzbRoqrSNPM,1396
|
| 47 |
+
datasets/commands/env.py,sha256=8qg-hpXSXXsHvtYFvJkn5rn9IncqPsjjx3nR8no4a2I,1239
|
| 48 |
+
datasets/commands/test.py,sha256=ybafVFdQED7hc4JyY_U8BG9_CkkhL0Gp5dOOAuzaHUw,7824
|
| 49 |
+
datasets/config.py,sha256=47pEpIB7t9D4JwicJ6uN3nhOS5n6X8_Ka1kgktisHZg,10590
|
| 50 |
+
datasets/data_files.py,sha256=lsI_vKh_1BWJABYE5wRF3YUOlJQ4Fv77oDiYbyyvcuE,32812
|
| 51 |
+
datasets/dataset_dict.py,sha256=3pbv445B79RP-_HiAPEDtZZTpdP8tbJHI1jKQotgJBw,128230
|
| 52 |
+
datasets/distributed.py,sha256=YUEhqqx7uxCAQac9dZOHfJIMAVLPW5vDQkTqFZUbXRs,1815
|
| 53 |
+
datasets/download/__init__.py,sha256=lbFOtITDaR7PHrhzJ8VfRnpaOT6NYozSxUcLv_GVfTg,281
|
| 54 |
+
datasets/download/__pycache__/__init__.cpython-311.pyc,,
|
| 55 |
+
datasets/download/__pycache__/download_config.cpython-311.pyc,,
|
| 56 |
+
datasets/download/__pycache__/download_manager.cpython-311.pyc,,
|
| 57 |
+
datasets/download/__pycache__/streaming_download_manager.cpython-311.pyc,,
|
| 58 |
+
datasets/download/download_config.py,sha256=ODHFej2H-JIqFllklUFkiF4ILJ62l8clAGk13b8Ru3U,3796
|
| 59 |
+
datasets/download/download_manager.py,sha256=Jq0BfYhQ7k5sT2tjbTh-zsj-b3MGS_IIP_bcjRUPfeo,12780
|
| 60 |
+
datasets/download/streaming_download_manager.py,sha256=-eRyxNnKj-dH-3bzdKu-rFzHjhh57XKNwJc-087BNw0,7553
|
| 61 |
+
datasets/exceptions.py,sha256=B93GwElhEvlhHPU9GBSY8if27jhRwu875-gL6B2CL6c,4185
|
| 62 |
+
datasets/features/__init__.py,sha256=sfMwgbwdxKKrQTrM5SYQo20MirhHgSNaSb2ZAStmfQU,638
|
| 63 |
+
datasets/features/__pycache__/__init__.cpython-311.pyc,,
|
| 64 |
+
datasets/features/__pycache__/_torchcodec.cpython-311.pyc,,
|
| 65 |
+
datasets/features/__pycache__/audio.cpython-311.pyc,,
|
| 66 |
+
datasets/features/__pycache__/features.cpython-311.pyc,,
|
| 67 |
+
datasets/features/__pycache__/image.cpython-311.pyc,,
|
| 68 |
+
datasets/features/__pycache__/mesh.cpython-311.pyc,,
|
| 69 |
+
datasets/features/__pycache__/nifti.cpython-311.pyc,,
|
| 70 |
+
datasets/features/__pycache__/pdf.cpython-311.pyc,,
|
| 71 |
+
datasets/features/__pycache__/translation.cpython-311.pyc,,
|
| 72 |
+
datasets/features/__pycache__/video.cpython-311.pyc,,
|
| 73 |
+
datasets/features/_torchcodec.py,sha256=Ws7JMYlUlPa7NHh1ZgxWQNrJV0c14kfYYCdrLjCkmjA,627
|
| 74 |
+
datasets/features/audio.py,sha256=eQM6i6kO1057pe1Sob-0tY0GMF9Y8wULAXqsChABOzc,16110
|
| 75 |
+
datasets/features/features.py,sha256=BMeibho5YIcW8WwIYyxqlYl21FciAVmQNRSOoBt9Fnw,98418
|
| 76 |
+
datasets/features/image.py,sha256=0FMvaNyZjdGWCYf2QtY_kYUNqMEk8bTZMrhXcqmhLOc,18403
|
| 77 |
+
datasets/features/mesh.py,sha256=nP6-yBamloz-S5pVPhq4sRSy-_8gwDQLKZ9xV6E7Xx8,12838
|
| 78 |
+
datasets/features/nifti.py,sha256=Zu1fGqZPUK1qj-s5yG19cl0YwXM5QZQ_NDvHy61cFDA,14313
|
| 79 |
+
datasets/features/pdf.py,sha256=Bjex_wBN3SWVSIf5E0ry2mHQL2yeLz5RyOrT_Ro0gVA,12207
|
| 80 |
+
datasets/features/translation.py,sha256=aIJfNMXTTQLamEk4L8mfTDDdyzscZUnhSPAor8RjE_8,4490
|
| 81 |
+
datasets/features/video.py,sha256=KWa61swxqNNtKLq9EC_KSP2VcMpGqCqMJjJHHHgWEYw,17261
|
| 82 |
+
datasets/filesystems/__init__.py,sha256=jBDUQosQqEFIXUDLZwRWaTgNomwL6Fq2qiYPvvxuae0,1523
|
| 83 |
+
datasets/filesystems/__pycache__/__init__.cpython-311.pyc,,
|
| 84 |
+
datasets/filesystems/__pycache__/compression.cpython-311.pyc,,
|
| 85 |
+
datasets/filesystems/compression.py,sha256=J16G_P0F9SxVfsLy9XLesyQJgvp4kpaO9MAihokEUvY,4528
|
| 86 |
+
datasets/fingerprint.py,sha256=hnzIVs-jCCKJYqi6LvE8UWNmLNOJ97bvWz6uA1EAKiI,21922
|
| 87 |
+
datasets/formatting/__init__.py,sha256=-pM10fSzw4MVj_L3NFWEv2sUyBh4mbnvCkfXgfS6WII,5412
|
| 88 |
+
datasets/formatting/__pycache__/__init__.cpython-311.pyc,,
|
| 89 |
+
datasets/formatting/__pycache__/formatting.cpython-311.pyc,,
|
| 90 |
+
datasets/formatting/__pycache__/jax_formatter.cpython-311.pyc,,
|
| 91 |
+
datasets/formatting/__pycache__/np_formatter.cpython-311.pyc,,
|
| 92 |
+
datasets/formatting/__pycache__/polars_formatter.cpython-311.pyc,,
|
| 93 |
+
datasets/formatting/__pycache__/tf_formatter.cpython-311.pyc,,
|
| 94 |
+
datasets/formatting/__pycache__/torch_formatter.cpython-311.pyc,,
|
| 95 |
+
datasets/formatting/formatting.py,sha256=8zMv7dfTyyEDvzNjKDzT7Eb2_fn2n6OknfGmYK_0-MM,26626
|
| 96 |
+
datasets/formatting/jax_formatter.py,sha256=Hd2Lgl94bkka4LNz9_Q45VIKSV2KWkSLp3DRXy9laiY,7494
|
| 97 |
+
datasets/formatting/np_formatter.py,sha256=TlXk6IlA_sxzeESg9jUUlhPX_npO6ImVj56A4Hp58Ms,5184
|
| 98 |
+
datasets/formatting/polars_formatter.py,sha256=oTm4l30SgGha-Oku42C0dA91Y8f2oifF9aWvi3QITDk,4744
|
| 99 |
+
datasets/formatting/tf_formatter.py,sha256=KRtG0yMzbVQ5TzA2WYa3WlZKblLojkqHzbNMKXY5geo,5318
|
| 100 |
+
datasets/formatting/torch_formatter.py,sha256=N-10rmMTD8XVUaS6-LQ9xqVxfyAMVeSJEKS6cojy74k,5393
|
| 101 |
+
datasets/hub.py,sha256=BuD2Jr4zMH8hpfbITMClQ3fq2TBteQQAvhcYiHHDwRg,5041
|
| 102 |
+
datasets/info.py,sha256=R4AV3Of94kWMmFfZ7H66fusd7v2PWnRsCXpJaGRQFa4,19984
|
| 103 |
+
datasets/inspect.py,sha256=dryCltaOJpfKyDxV2i-PWNE2P_VR_NPDBFRbLmeeQDQ,15498
|
| 104 |
+
datasets/io/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 105 |
+
datasets/io/__pycache__/__init__.cpython-311.pyc,,
|
| 106 |
+
datasets/io/__pycache__/abc.cpython-311.pyc,,
|
| 107 |
+
datasets/io/__pycache__/csv.cpython-311.pyc,,
|
| 108 |
+
datasets/io/__pycache__/generator.cpython-311.pyc,,
|
| 109 |
+
datasets/io/__pycache__/json.cpython-311.pyc,,
|
| 110 |
+
datasets/io/__pycache__/parquet.cpython-311.pyc,,
|
| 111 |
+
datasets/io/__pycache__/spark.cpython-311.pyc,,
|
| 112 |
+
datasets/io/__pycache__/sql.cpython-311.pyc,,
|
| 113 |
+
datasets/io/__pycache__/text.cpython-311.pyc,,
|
| 114 |
+
datasets/io/abc.py,sha256=LwDMXYs6YkhZuz1JiMK4PDIqgNjv7I8xH3UMUELW2ys,1672
|
| 115 |
+
datasets/io/csv.py,sha256=aNVSwbZVPyVvi3a5ZsJr11FMEOMKcXKZvoB1OcV0a2U,5198
|
| 116 |
+
datasets/io/generator.py,sha256=WtUWhml4llyZd_6gPuOPcC_YiKc5xkTXAjTN-z4ivsY,2098
|
| 117 |
+
datasets/io/json.py,sha256=pAKp3fhtGYOs2-6fqlTyqdKH_ehZztVnfvvdv1G_IaM,7010
|
| 118 |
+
datasets/io/parquet.py,sha256=QzEK2oKCMopP3talCc5gCvP0xb2e34XTsDD9kF39s9c,5868
|
| 119 |
+
datasets/io/spark.py,sha256=VUIODLHgIbiK0CI0UvthQ_gUO0MQDtHUozvw7Dfs8FI,1797
|
| 120 |
+
datasets/io/sql.py,sha256=KZhCE2-al9QYz-e8rPctYvWQ07uRk11oS08OI1AtA-M,4175
|
| 121 |
+
datasets/io/text.py,sha256=9BdYqlv-XXERc_WJwlD9GugwlAOv53iMVdrBoxKL2UI,1908
|
| 122 |
+
datasets/iterable_dataset.py,sha256=8mkL1g_puZByq4pFp-FtQV6y0qBELP5wjAodXhZuzEE,237188
|
| 123 |
+
datasets/load.py,sha256=LJcBF5_n1aNWg1EchitbtT627m4wTeM8zAmLx9QDuDA,79710
|
| 124 |
+
datasets/naming.py,sha256=WzNdyHVGeAk_YPx3ZF09F-0g0WHVWil6UOQiKZFEFa0,3028
|
| 125 |
+
datasets/packaged_modules/__init__.py,sha256=75vaQxbm5dRpUWRwOvXR2Iu2YXBcR5v1qb2K1tmf15A,7695
|
| 126 |
+
datasets/packaged_modules/__pycache__/__init__.cpython-311.pyc,,
|
| 127 |
+
datasets/packaged_modules/arrow/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 128 |
+
datasets/packaged_modules/arrow/__pycache__/__init__.cpython-311.pyc,,
|
| 129 |
+
datasets/packaged_modules/arrow/__pycache__/arrow.cpython-311.pyc,,
|
| 130 |
+
datasets/packaged_modules/arrow/arrow.py,sha256=L2v-iUt583lAGJ9c_bzPm3gVqX0fV_LtoqSS73sRXUQ,3213
|
| 131 |
+
datasets/packaged_modules/audiofolder/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 132 |
+
datasets/packaged_modules/audiofolder/__pycache__/__init__.cpython-311.pyc,,
|
| 133 |
+
datasets/packaged_modules/audiofolder/__pycache__/audiofolder.cpython-311.pyc,,
|
| 134 |
+
datasets/packaged_modules/audiofolder/audiofolder.py,sha256=N4mOZypp8oTI-9FBSeEFE-oQ23U6ZmqPlFcqbUkviA8,1744
|
| 135 |
+
datasets/packaged_modules/cache/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 136 |
+
datasets/packaged_modules/cache/__pycache__/__init__.cpython-311.pyc,,
|
| 137 |
+
datasets/packaged_modules/cache/__pycache__/cache.cpython-311.pyc,,
|
| 138 |
+
datasets/packaged_modules/cache/cache.py,sha256=qfhDDDuLNTl870-uRFwc6VTxJf9Icg5hYzpsIVrOf_M,8293
|
| 139 |
+
datasets/packaged_modules/conll/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 140 |
+
datasets/packaged_modules/conll/__pycache__/__init__.cpython-311.pyc,,
|
| 141 |
+
datasets/packaged_modules/conll/__pycache__/conll.cpython-311.pyc,,
|
| 142 |
+
datasets/packaged_modules/conll/conll.py,sha256=wmajGnrB63PU_WosBgedZe7-nvfPraqqdj_VdFCm3P0,6846
|
| 143 |
+
datasets/packaged_modules/csv/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 144 |
+
datasets/packaged_modules/csv/__pycache__/__init__.cpython-311.pyc,,
|
| 145 |
+
datasets/packaged_modules/csv/__pycache__/csv.cpython-311.pyc,,
|
| 146 |
+
datasets/packaged_modules/csv/csv.py,sha256=IY7nnFlOZIBmpcbdJ6wPPUVlhjd4K8rbw17h5YJU3Yw,8977
|
| 147 |
+
datasets/packaged_modules/eval/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 148 |
+
datasets/packaged_modules/eval/__pycache__/__init__.cpython-311.pyc,,
|
| 149 |
+
datasets/packaged_modules/eval/__pycache__/eval.cpython-311.pyc,,
|
| 150 |
+
datasets/packaged_modules/eval/eval.py,sha256=GRFbIzWPzDCmWxWBefQ-kN-jjvxM0-2TdEZgVw-Qo0c,3226
|
| 151 |
+
datasets/packaged_modules/folder_based_builder/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 152 |
+
datasets/packaged_modules/folder_based_builder/__pycache__/__init__.cpython-311.pyc,,
|
| 153 |
+
datasets/packaged_modules/folder_based_builder/__pycache__/folder_based_builder.cpython-311.pyc,,
|
| 154 |
+
datasets/packaged_modules/folder_based_builder/folder_based_builder.py,sha256=YaQaj9fCEutUfrZINhuit0j6Szqaj6fOoUm6G9Wio9I,22939
|
| 155 |
+
datasets/packaged_modules/generator/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 156 |
+
datasets/packaged_modules/generator/__pycache__/__init__.cpython-311.pyc,,
|
| 157 |
+
datasets/packaged_modules/generator/__pycache__/generator.cpython-311.pyc,,
|
| 158 |
+
datasets/packaged_modules/generator/generator.py,sha256=HTpaY75-NypiL5g0mCgDcnvTaWvzdTPLIKnsFlLlpuI,1380
|
| 159 |
+
datasets/packaged_modules/hdf5/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 160 |
+
datasets/packaged_modules/hdf5/__pycache__/__init__.cpython-311.pyc,,
|
| 161 |
+
datasets/packaged_modules/hdf5/__pycache__/hdf5.cpython-311.pyc,,
|
| 162 |
+
datasets/packaged_modules/hdf5/hdf5.py,sha256=CchNe8i3boLosSTddnmkn_AxATEEv-sbkDqhS1qwYaw,12592
|
| 163 |
+
datasets/packaged_modules/iceberg/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 164 |
+
datasets/packaged_modules/iceberg/__pycache__/__init__.cpython-311.pyc,,
|
| 165 |
+
datasets/packaged_modules/iceberg/__pycache__/iceberg.cpython-311.pyc,,
|
| 166 |
+
datasets/packaged_modules/iceberg/iceberg.py,sha256=NeOVI_UWwJLQbOuznmvjlB3AnQN3gZ2eTFEOq5KlVz4,7148
|
| 167 |
+
datasets/packaged_modules/imagefolder/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 168 |
+
datasets/packaged_modules/imagefolder/__pycache__/__init__.cpython-311.pyc,,
|
| 169 |
+
datasets/packaged_modules/imagefolder/__pycache__/imagefolder.cpython-311.pyc,,
|
| 170 |
+
datasets/packaged_modules/imagefolder/imagefolder.py,sha256=UpMVe8TUyayzHsVSfKN5wiXcc94QdamMvxauI4oFdw4,1956
|
| 171 |
+
datasets/packaged_modules/json/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 172 |
+
datasets/packaged_modules/json/__pycache__/__init__.cpython-311.pyc,,
|
| 173 |
+
datasets/packaged_modules/json/__pycache__/json.cpython-311.pyc,,
|
| 174 |
+
datasets/packaged_modules/json/json.py,sha256=l5R7OSnd2-1zyI0tRGOY3kLs_x02yA_fWwp4i8tdtgU,23343
|
| 175 |
+
datasets/packaged_modules/lance/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 176 |
+
datasets/packaged_modules/lance/__pycache__/__init__.cpython-311.pyc,,
|
| 177 |
+
datasets/packaged_modules/lance/__pycache__/lance.cpython-311.pyc,,
|
| 178 |
+
datasets/packaged_modules/lance/lance.py,sha256=TQGbGU3_JPrV2C-fUglzLS2oqPe5Dyp7ALKniRISKjw,9880
|
| 179 |
+
datasets/packaged_modules/meshfolder/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 180 |
+
datasets/packaged_modules/meshfolder/__pycache__/__init__.cpython-311.pyc,,
|
| 181 |
+
datasets/packaged_modules/meshfolder/__pycache__/meshfolder.cpython-311.pyc,,
|
| 182 |
+
datasets/packaged_modules/meshfolder/meshfolder.py,sha256=J5Bha52ZP5NAGeWvkQmsNZnZVbxCbWqt3UEVNPDkrww,700
|
| 183 |
+
datasets/packaged_modules/niftifolder/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 184 |
+
datasets/packaged_modules/niftifolder/__pycache__/__init__.cpython-311.pyc,,
|
| 185 |
+
datasets/packaged_modules/niftifolder/__pycache__/niftifolder.cpython-311.pyc,,
|
| 186 |
+
datasets/packaged_modules/niftifolder/niftifolder.py,sha256=VPmkFLF590iCsG6b4vS3cONleyYM26cwUSi7kzj1ebg,575
|
| 187 |
+
datasets/packaged_modules/pandas/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 188 |
+
datasets/packaged_modules/pandas/__pycache__/__init__.cpython-311.pyc,,
|
| 189 |
+
datasets/packaged_modules/pandas/__pycache__/pandas.cpython-311.pyc,,
|
| 190 |
+
datasets/packaged_modules/pandas/pandas.py,sha256=qLtTReWnf2am9BZUa76sJwKags3Zg3qQsLoszZZq81E,1954
|
| 191 |
+
datasets/packaged_modules/parquet/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 192 |
+
datasets/packaged_modules/parquet/__pycache__/__init__.cpython-311.pyc,,
|
| 193 |
+
datasets/packaged_modules/parquet/__pycache__/parquet.cpython-311.pyc,,
|
| 194 |
+
datasets/packaged_modules/parquet/parquet.py,sha256=o90ueHItfJvlXJFBgwcaN_TCYwIZuayfD-FaFcxYzx4,11178
|
| 195 |
+
datasets/packaged_modules/pdffolder/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 196 |
+
datasets/packaged_modules/pdffolder/__pycache__/__init__.cpython-311.pyc,,
|
| 197 |
+
datasets/packaged_modules/pdffolder/__pycache__/pdffolder.cpython-311.pyc,,
|
| 198 |
+
datasets/packaged_modules/pdffolder/pdffolder.py,sha256=bPYBh9-XOr2C-gg_Fl8h-UKhsVQ7VXjBL2FfW8abiGU,565
|
| 199 |
+
datasets/packaged_modules/spark/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 200 |
+
datasets/packaged_modules/spark/__pycache__/__init__.cpython-311.pyc,,
|
| 201 |
+
datasets/packaged_modules/spark/__pycache__/spark.cpython-311.pyc,,
|
| 202 |
+
datasets/packaged_modules/spark/spark.py,sha256=T9LDFok-hAWDgcjyW0SIMfId5BXF3CAbvl9zFx8Ut6w,14685
|
| 203 |
+
datasets/packaged_modules/sql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 204 |
+
datasets/packaged_modules/sql/__pycache__/__init__.cpython-311.pyc,,
|
| 205 |
+
datasets/packaged_modules/sql/__pycache__/sql.cpython-311.pyc,,
|
| 206 |
+
datasets/packaged_modules/sql/sql.py,sha256=DFGr-BdMyO6xE0MS2CCp-TtRZ-PUNKivUXSwF5R4K4g,4536
|
| 207 |
+
datasets/packaged_modules/text/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 208 |
+
datasets/packaged_modules/text/__pycache__/__init__.cpython-311.pyc,,
|
| 209 |
+
datasets/packaged_modules/text/__pycache__/text.cpython-311.pyc,,
|
| 210 |
+
datasets/packaged_modules/text/text.py,sha256=TwrXqmv9-CsceZncffycwKi2BrdvzfLb4MKRQtFTuUM,6862
|
| 211 |
+
datasets/packaged_modules/tsfile/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 212 |
+
datasets/packaged_modules/tsfile/__pycache__/__init__.cpython-311.pyc,,
|
| 213 |
+
datasets/packaged_modules/tsfile/__pycache__/tsfile.cpython-311.pyc,,
|
| 214 |
+
datasets/packaged_modules/tsfile/tsfile.py,sha256=AIfpPfmh0woeNh3IaoiImGPjekIHEFLHH_-YfuDF_wY,34665
|
| 215 |
+
datasets/packaged_modules/videofolder/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 216 |
+
datasets/packaged_modules/videofolder/__pycache__/__init__.cpython-311.pyc,,
|
| 217 |
+
datasets/packaged_modules/videofolder/__pycache__/videofolder.cpython-311.pyc,,
|
| 218 |
+
datasets/packaged_modules/videofolder/videofolder.py,sha256=HLTMldDZ3WfK8OAbI2wssBuNCP6ucRBpNLpCoJVDL10,807
|
| 219 |
+
datasets/packaged_modules/webdataset/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 220 |
+
datasets/packaged_modules/webdataset/__pycache__/__init__.cpython-311.pyc,,
|
| 221 |
+
datasets/packaged_modules/webdataset/__pycache__/_tenbin.cpython-311.pyc,,
|
| 222 |
+
datasets/packaged_modules/webdataset/__pycache__/webdataset.cpython-311.pyc,,
|
| 223 |
+
datasets/packaged_modules/webdataset/_tenbin.py,sha256=oovYsgR2R3eXSn1xSCLG3oTly1szKDP4UOiRp4ORdIk,8533
|
| 224 |
+
datasets/packaged_modules/webdataset/webdataset.py,sha256=Bxd7J0DkxoMjZNWCU9l_X1qz5BDeNde_1Xl6o3rl38w,11166
|
| 225 |
+
datasets/packaged_modules/xml/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 226 |
+
datasets/packaged_modules/xml/__pycache__/__init__.cpython-311.pyc,,
|
| 227 |
+
datasets/packaged_modules/xml/__pycache__/xml.cpython-311.pyc,,
|
| 228 |
+
datasets/packaged_modules/xml/xml.py,sha256=eMbwRIB1N7QSsvlIt1mPwseE_HYVuiXhyabxy-LILQk,2844
|
| 229 |
+
datasets/parallel/__init__.py,sha256=wiRFK4x67ez2vvmjwM2Sb9R1yFdf38laSarU9y0Bido,76
|
| 230 |
+
datasets/parallel/__pycache__/__init__.cpython-311.pyc,,
|
| 231 |
+
datasets/parallel/__pycache__/parallel.cpython-311.pyc,,
|
| 232 |
+
datasets/parallel/parallel.py,sha256=E-oOQ6zwKrkLFPwZ-3EOcr_aANJDhE-d6QTq7Mp7WvA,4738
|
| 233 |
+
datasets/search.py,sha256=PxveDc1hy2Yux7Gtvat1_Qe_0D6aIKQBWI5KbV0gS6I,35592
|
| 234 |
+
datasets/splits.py,sha256=10xtCAtS3XFHawm4AqZrfpXecfNcAcUnOJ9eVtwTkgY,23810
|
| 235 |
+
datasets/streaming.py,sha256=7MIamZ2NmReUmJ_2pxgdSopIf7Oh5nFFAbb7WHLuW7E,5772
|
| 236 |
+
datasets/table.py,sha256=p5nR05j8yRJkUM44RU5240xv1_2NHaSGVRz_m23LI3w,97900
|
| 237 |
+
datasets/utils/__init__.py,sha256=PuZtB9YTbRyvdwubnsx-JGdHuMA7p0I0Rmh0E_uxYF0,999
|
| 238 |
+
datasets/utils/__pycache__/__init__.cpython-311.pyc,,
|
| 239 |
+
datasets/utils/__pycache__/_dataset_viewer.cpython-311.pyc,,
|
| 240 |
+
datasets/utils/__pycache__/_dill.cpython-311.pyc,,
|
| 241 |
+
datasets/utils/__pycache__/_filelock.cpython-311.pyc,,
|
| 242 |
+
datasets/utils/__pycache__/deprecation_utils.cpython-311.pyc,,
|
| 243 |
+
datasets/utils/__pycache__/doc_utils.cpython-311.pyc,,
|
| 244 |
+
datasets/utils/__pycache__/experimental.cpython-311.pyc,,
|
| 245 |
+
datasets/utils/__pycache__/extract.cpython-311.pyc,,
|
| 246 |
+
datasets/utils/__pycache__/file_utils.cpython-311.pyc,,
|
| 247 |
+
datasets/utils/__pycache__/filelock.cpython-311.pyc,,
|
| 248 |
+
datasets/utils/__pycache__/hub.cpython-311.pyc,,
|
| 249 |
+
datasets/utils/__pycache__/info_utils.cpython-311.pyc,,
|
| 250 |
+
datasets/utils/__pycache__/json.cpython-311.pyc,,
|
| 251 |
+
datasets/utils/__pycache__/logging.cpython-311.pyc,,
|
| 252 |
+
datasets/utils/__pycache__/metadata.cpython-311.pyc,,
|
| 253 |
+
datasets/utils/__pycache__/patching.cpython-311.pyc,,
|
| 254 |
+
datasets/utils/__pycache__/py_utils.cpython-311.pyc,,
|
| 255 |
+
datasets/utils/__pycache__/sharding.cpython-311.pyc,,
|
| 256 |
+
datasets/utils/__pycache__/stratify.cpython-311.pyc,,
|
| 257 |
+
datasets/utils/__pycache__/tf_utils.cpython-311.pyc,,
|
| 258 |
+
datasets/utils/__pycache__/tqdm.cpython-311.pyc,,
|
| 259 |
+
datasets/utils/__pycache__/track.cpython-311.pyc,,
|
| 260 |
+
datasets/utils/__pycache__/typing.cpython-311.pyc,,
|
| 261 |
+
datasets/utils/__pycache__/version.cpython-311.pyc,,
|
| 262 |
+
datasets/utils/_dataset_viewer.py,sha256=SrE1N18S5yCoCx0rAhwaHNDVS9uhxjspA84iNT4TFRw,4397
|
| 263 |
+
datasets/utils/_dill.py,sha256=RTXoz1e5nS-eHOsPvPhuKjIweEAl0cP8rFaKZkgmMQY,19409
|
| 264 |
+
datasets/utils/_filelock.py,sha256=iXW3bxsIr5JWNemhKtF_-q_0ysajkUTItzMm8LY9LBY,2355
|
| 265 |
+
datasets/utils/deprecation_utils.py,sha256=hTHwlzRs92NfNVudH71LMpW70sjbsP5amebrIgi3A-U,3452
|
| 266 |
+
datasets/utils/doc_utils.py,sha256=HoSm0TFaQaCYGfDgNhpBJ4Xc2WQZuOD6dTxLd9D87fs,407
|
| 267 |
+
datasets/utils/experimental.py,sha256=JgOjaEY3RWZ--3u0-ry82gLCDUpudfBfl-hWZ46SyS4,1097
|
| 268 |
+
datasets/utils/extract.py,sha256=7rEeGuKxVrLlRwEkAeVFk-zMxq29XrIRyOvQihuEeHs,18318
|
| 269 |
+
datasets/utils/file_utils.py,sha256=FpZJVIHXCXqJfiXXx9qYtxLMHajV3YgglhMUyi2F1I8,55868
|
| 270 |
+
datasets/utils/filelock.py,sha256=H6C5dQGFCzVKyeDRRY8fZ4YGTEvvNd-MTjpL_sWYb5k,352
|
| 271 |
+
datasets/utils/hub.py,sha256=V2JGolL5VjFT0YiEhI0sxJED_9tGdvma7lH22d64S9I,130
|
| 272 |
+
datasets/utils/info_utils.py,sha256=SN9r8OSFSyGCNtpcpmCzbvSNU-_7LqTJsaRv07DeSYI,4217
|
| 273 |
+
datasets/utils/json.py,sha256=Zy-XhSh8Tzz2XFUAfS6VwSdvi0e5C-T7jOjcd120H-0,5439
|
| 274 |
+
datasets/utils/logging.py,sha256=c2g1gl3IV4C7A2-ky0yfrHZuYi4P41HRTdS3XCmdMew,5381
|
| 275 |
+
datasets/utils/metadata.py,sha256=Hrmn8xUoEzwpJKG3Y6tfJt5t7nW1OCxNjfLTlEaxsrI,9367
|
| 276 |
+
datasets/utils/patching.py,sha256=yrDATN-xaGgoM747brbx4ZDMnvp-teahfOaW53RNVyk,4967
|
| 277 |
+
datasets/utils/py_utils.py,sha256=KGsYmXmOXD3QHRMd3aFRYXpj47biTSRwtzUU-d0lm8U,23246
|
| 278 |
+
datasets/utils/resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 279 |
+
datasets/utils/resources/__pycache__/__init__.cpython-311.pyc,,
|
| 280 |
+
datasets/utils/resources/creators.json,sha256=XtIpMZefgBOdTevRrQTkFiufbgCbp_iyxseyphYQkn0,257
|
| 281 |
+
datasets/utils/resources/languages.json,sha256=Z0rQNPsfje8zMi8KdvvwxF4APwwqcskJFUvhNiLAgPM,199138
|
| 282 |
+
datasets/utils/resources/multilingualities.json,sha256=02Uc8RtRzfl13l98Y_alZm5HuMYwPzL78B0S5a1X-8c,205
|
| 283 |
+
datasets/utils/resources/readme_structure.yaml,sha256=hNf9msoBZw5jfakQrDb0Af8T325TXdcaHsAO2MUcZvY,3877
|
| 284 |
+
datasets/utils/resources/size_categories.json,sha256=_5nAP7z8R6t7_GfER81QudFO6Y1tqYu4AWrr4Aot8S8,171
|
| 285 |
+
datasets/utils/sharding.py,sha256=VBQ4bRJQijMNDQTgFb1_ddlQ28wAcA0aQp4e-1jFIAk,4215
|
| 286 |
+
datasets/utils/stratify.py,sha256=-MVaLmijYhGyKDpnZS9A8SiHekaIyVm84HVyIIQOmfg,4085
|
| 287 |
+
datasets/utils/tf_utils.py,sha256=T3OysLGbkO7y-J-o9OVGyn9l-l-A3ruj-24JM_UULm8,24448
|
| 288 |
+
datasets/utils/tqdm.py,sha256=IKCB-lz6BZwRokw1QHaQsWFGWL4ztWtRd5kCGzwp_Oc,4520
|
| 289 |
+
datasets/utils/track.py,sha256=M81CGLn3MyJzHm98CQkbF3_1DG7evQsw-V52_Bp2paI,1838
|
| 290 |
+
datasets/utils/typing.py,sha256=G11ytWmwjqVia2IdziRDIWvQ4mLJee-sKzgJfHqU16E,205
|
| 291 |
+
datasets/utils/version.py,sha256=Z82cHpjTbQVJyWgnwSU8DsW2G0y-sSbSoOVeQrAds9k,3281
|
venv/Lib/site-packages/datasets-5.0.0.dist-info/REQUESTED
ADDED
|
File without changes
|
venv/Lib/site-packages/datasets-5.0.0.dist-info/WHEEL
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Wheel-Version: 1.0
|
| 2 |
+
Generator: setuptools (75.8.0)
|
| 3 |
+
Root-Is-Purelib: true
|
| 4 |
+
Tag: py3-none-any
|
| 5 |
+
|
venv/Lib/site-packages/datasets-5.0.0.dist-info/entry_points.txt
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[console_scripts]
|
| 2 |
+
datasets-cli = datasets.commands.datasets_cli:main
|
venv/Lib/site-packages/datasets-5.0.0.dist-info/top_level.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
datasets
|
venv/Lib/site-packages/datasets/__pycache__/fingerprint.cpython-311.pyc
ADDED
|
Binary file (25.9 kB). View file
|
|
|
venv/Lib/site-packages/datasets/__pycache__/hub.cpython-311.pyc
ADDED
|
Binary file (6.06 kB). View file
|
|
|
venv/Lib/site-packages/datasets/__pycache__/info.cpython-311.pyc
ADDED
|
Binary file (30 kB). View file
|
|
|
venv/Lib/site-packages/datasets/__pycache__/inspect.cpython-311.pyc
ADDED
|
Binary file (16.7 kB). View file
|
|
|
venv/Lib/site-packages/datasets/__pycache__/iterable_dataset.cpython-311.pyc
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:8f1069d468cb4557bca9e7fd248bf22f7bd9f9fd154bf8cb1d16b9387a338ab0
|
| 3 |
+
size 294705
|
venv/Lib/site-packages/datasets/__pycache__/load.cpython-311.pyc
ADDED
|
Binary file (89.7 kB). View file
|
|
|
venv/Lib/site-packages/datasets/__pycache__/naming.cpython-311.pyc
ADDED
|
Binary file (4.83 kB). View file
|
|
|
venv/Lib/site-packages/datasets/__pycache__/search.cpython-311.pyc
ADDED
|
Binary file (46.9 kB). View file
|
|
|
venv/Lib/site-packages/datasets/__pycache__/splits.cpython-311.pyc
ADDED
|
Binary file (33.8 kB). View file
|
|
|
venv/Lib/site-packages/datasets/__pycache__/streaming.cpython-311.pyc
ADDED
|
Binary file (8.47 kB). View file
|
|
|
venv/Lib/site-packages/datasets/__pycache__/table.cpython-311.pyc
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:cd4777d458c7f0ec20c6059316202985d53515db31c4e22beb61c28f8e9c2f7b
|
| 3 |
+
size 126990
|
venv/Lib/site-packages/datasets/arrow_dataset.py
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
venv/Lib/site-packages/datasets/arrow_reader.py
ADDED
|
@@ -0,0 +1,620 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2020 The HuggingFace Datasets Authors and the TensorFlow Datasets Authors.
|
| 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 |
+
# Lint as: python3
|
| 16 |
+
"""Arrow ArrowReader."""
|
| 17 |
+
|
| 18 |
+
import copy
|
| 19 |
+
import math
|
| 20 |
+
import os
|
| 21 |
+
import re
|
| 22 |
+
from dataclasses import dataclass
|
| 23 |
+
from functools import partial
|
| 24 |
+
from typing import TYPE_CHECKING, Optional, Union
|
| 25 |
+
|
| 26 |
+
import pyarrow as pa
|
| 27 |
+
import pyarrow.parquet as pq
|
| 28 |
+
from tqdm.contrib.concurrent import thread_map
|
| 29 |
+
|
| 30 |
+
from .download.download_config import DownloadConfig # noqa: F401
|
| 31 |
+
from .naming import _split_re, filenames_for_dataset_split
|
| 32 |
+
from .table import InMemoryTable, MemoryMappedTable, Table, concat_tables
|
| 33 |
+
from .utils import logging
|
| 34 |
+
from .utils import tqdm as hf_tqdm
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
if TYPE_CHECKING:
|
| 38 |
+
from .info import DatasetInfo # noqa: F401
|
| 39 |
+
from .splits import Split, SplitInfo # noqa: F401
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
logger = logging.get_logger(__name__)
|
| 43 |
+
|
| 44 |
+
HF_GCP_BASE_URL = "https://storage.googleapis.com/huggingface-nlp/cache/datasets"
|
| 45 |
+
|
| 46 |
+
_SUB_SPEC_RE = re.compile(
|
| 47 |
+
rf"""
|
| 48 |
+
^
|
| 49 |
+
(?P<split>{_split_re[1:-1]})
|
| 50 |
+
(\[
|
| 51 |
+
((?P<from>-?[\d_]+)
|
| 52 |
+
(?P<from_pct>%)?)?
|
| 53 |
+
:
|
| 54 |
+
((?P<to>-?[\d_]+)
|
| 55 |
+
(?P<to_pct>%)?)?
|
| 56 |
+
\])?(\((?P<rounding>[^\)]*)\))?
|
| 57 |
+
$
|
| 58 |
+
""", # remove ^ and $
|
| 59 |
+
re.X,
|
| 60 |
+
)
|
| 61 |
+
|
| 62 |
+
_ADDITION_SEP_RE = re.compile(r"\s*\+\s*")
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
class DatasetNotOnHfGcsError(ConnectionError):
|
| 66 |
+
"""When you can't get the dataset from the Hf google cloud storage"""
|
| 67 |
+
|
| 68 |
+
pass
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
class MissingFilesOnHfGcsError(ConnectionError):
|
| 72 |
+
"""When some files are missing on the Hf oogle cloud storage"""
|
| 73 |
+
|
| 74 |
+
pass
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
@dataclass(frozen=True)
|
| 78 |
+
class FileInstructions:
|
| 79 |
+
"""The file instructions associated with a split ReadInstruction.
|
| 80 |
+
|
| 81 |
+
Attributes:
|
| 82 |
+
num_examples: `int`, The total number of examples
|
| 83 |
+
file_instructions: List[dict(filename, skip, take)], the files information.
|
| 84 |
+
The filenames contains the relative path, not absolute.
|
| 85 |
+
skip/take indicates which example read in the file: `ds.slice(skip, take)`
|
| 86 |
+
"""
|
| 87 |
+
|
| 88 |
+
num_examples: int
|
| 89 |
+
file_instructions: list[dict]
|
| 90 |
+
|
| 91 |
+
|
| 92 |
+
def make_file_instructions(
|
| 93 |
+
name: str,
|
| 94 |
+
split_infos: list["SplitInfo"],
|
| 95 |
+
instruction: Union[str, "ReadInstruction"],
|
| 96 |
+
filetype_suffix: Optional[str] = None,
|
| 97 |
+
prefix_path: Optional[str] = None,
|
| 98 |
+
) -> FileInstructions:
|
| 99 |
+
"""Returns instructions of the split dict.
|
| 100 |
+
|
| 101 |
+
Args:
|
| 102 |
+
name (`str`): Name of the dataset.
|
| 103 |
+
split_infos (`list` of `[SplitInfo]`): Dataset splits information.
|
| 104 |
+
instruction ([`ReadInstruction`] or `str`): Reading instruction for a dataset.
|
| 105 |
+
filetype_suffix (`str`, *optional*): Suffix of dataset files, e.g. 'arrow' or 'parquet'.
|
| 106 |
+
prefix_path (`str`, *optional*): Prefix of dataset files, e.g. directory name.
|
| 107 |
+
|
| 108 |
+
Returns:
|
| 109 |
+
[`FileInstructions`]
|
| 110 |
+
"""
|
| 111 |
+
if not isinstance(name, str):
|
| 112 |
+
raise TypeError(f"Expected str 'name', but got: {type(name).__name__}")
|
| 113 |
+
elif not name:
|
| 114 |
+
raise ValueError("Expected non-empty str 'name'")
|
| 115 |
+
name2len = {info.name: info.num_examples for info in split_infos}
|
| 116 |
+
name2shard_lengths = {info.name: info.shard_lengths for info in split_infos}
|
| 117 |
+
name2filenames = {
|
| 118 |
+
info.name: filenames_for_dataset_split(
|
| 119 |
+
path=prefix_path,
|
| 120 |
+
dataset_name=name,
|
| 121 |
+
split=info.name,
|
| 122 |
+
filetype_suffix=filetype_suffix,
|
| 123 |
+
shard_lengths=name2shard_lengths[info.name],
|
| 124 |
+
)
|
| 125 |
+
for info in split_infos
|
| 126 |
+
}
|
| 127 |
+
if not isinstance(instruction, ReadInstruction):
|
| 128 |
+
instruction = ReadInstruction.from_spec(instruction)
|
| 129 |
+
# Create the absolute instruction (per split)
|
| 130 |
+
absolute_instructions = instruction.to_absolute(name2len)
|
| 131 |
+
|
| 132 |
+
# For each split, return the files instruction (skip/take)
|
| 133 |
+
file_instructions = []
|
| 134 |
+
num_examples = 0
|
| 135 |
+
for abs_instr in absolute_instructions:
|
| 136 |
+
split_length = name2len[abs_instr.splitname]
|
| 137 |
+
filenames = name2filenames[abs_instr.splitname]
|
| 138 |
+
shard_lengths = name2shard_lengths[abs_instr.splitname]
|
| 139 |
+
from_ = 0 if abs_instr.from_ is None else abs_instr.from_
|
| 140 |
+
to = split_length if abs_instr.to is None else abs_instr.to
|
| 141 |
+
if shard_lengths is None: # not sharded
|
| 142 |
+
for filename in filenames:
|
| 143 |
+
take = to - from_
|
| 144 |
+
if take == 0:
|
| 145 |
+
continue
|
| 146 |
+
num_examples += take
|
| 147 |
+
file_instructions.append({"filename": filename, "skip": from_, "take": take})
|
| 148 |
+
else: # sharded
|
| 149 |
+
index_start = 0 # Beginning (included) of moving window.
|
| 150 |
+
index_end = 0 # End (excluded) of moving window.
|
| 151 |
+
for filename, shard_length in zip(filenames, shard_lengths):
|
| 152 |
+
index_end += shard_length
|
| 153 |
+
if from_ < index_end and to > index_start: # There is something to take.
|
| 154 |
+
skip = from_ - index_start if from_ > index_start else 0
|
| 155 |
+
take = to - index_start - skip if to < index_end else -1
|
| 156 |
+
if take == 0:
|
| 157 |
+
continue
|
| 158 |
+
file_instructions.append({"filename": filename, "skip": skip, "take": take})
|
| 159 |
+
num_examples += shard_length - skip if take == -1 else take
|
| 160 |
+
index_start += shard_length
|
| 161 |
+
return FileInstructions(
|
| 162 |
+
num_examples=num_examples,
|
| 163 |
+
file_instructions=file_instructions,
|
| 164 |
+
)
|
| 165 |
+
|
| 166 |
+
|
| 167 |
+
class BaseReader:
|
| 168 |
+
"""
|
| 169 |
+
Build a Dataset object out of Instruction instance(s).
|
| 170 |
+
"""
|
| 171 |
+
|
| 172 |
+
def __init__(self, path: str, info: Optional["DatasetInfo"]):
|
| 173 |
+
"""Initializes ArrowReader.
|
| 174 |
+
|
| 175 |
+
Args:
|
| 176 |
+
path (str): path where tfrecords are stored.
|
| 177 |
+
info (DatasetInfo): info about the dataset.
|
| 178 |
+
"""
|
| 179 |
+
self._path: str = path
|
| 180 |
+
self._info: Optional["DatasetInfo"] = info
|
| 181 |
+
self._filetype_suffix: Optional[str] = None
|
| 182 |
+
|
| 183 |
+
def _get_table_from_filename(self, filename_skip_take, in_memory=False) -> Table:
|
| 184 |
+
"""Returns a Dataset instance from given (filename, skip, take)."""
|
| 185 |
+
raise NotImplementedError
|
| 186 |
+
|
| 187 |
+
def _read_files(self, files, in_memory=False) -> Table:
|
| 188 |
+
"""Returns Dataset for given file instructions.
|
| 189 |
+
|
| 190 |
+
Args:
|
| 191 |
+
files: List[dict(filename, skip, take)], the files information.
|
| 192 |
+
The filenames contain the absolute path, not relative.
|
| 193 |
+
skip/take indicates which example read in the file: `ds.slice(skip, take)`
|
| 194 |
+
in_memory (bool, default False): Whether to copy the data in-memory.
|
| 195 |
+
"""
|
| 196 |
+
if len(files) == 0 or not all(isinstance(f, dict) for f in files):
|
| 197 |
+
raise ValueError("please provide valid file informations")
|
| 198 |
+
files = copy.deepcopy(files)
|
| 199 |
+
for f in files:
|
| 200 |
+
f["filename"] = os.path.join(self._path, f["filename"])
|
| 201 |
+
|
| 202 |
+
pa_tables = thread_map(
|
| 203 |
+
partial(self._get_table_from_filename, in_memory=in_memory),
|
| 204 |
+
files,
|
| 205 |
+
tqdm_class=hf_tqdm,
|
| 206 |
+
desc="Loading dataset shards",
|
| 207 |
+
# set `disable=None` rather than `disable=False` by default to disable progress bar when no TTY attached
|
| 208 |
+
disable=len(files) <= 16 or None,
|
| 209 |
+
)
|
| 210 |
+
pa_tables = [t for t in pa_tables if len(t) > 0]
|
| 211 |
+
if not pa_tables and (self._info is None or self._info.features is None):
|
| 212 |
+
raise ValueError(
|
| 213 |
+
"Tried to read an empty table. Please specify at least info.features to create an empty table with the right type."
|
| 214 |
+
)
|
| 215 |
+
pa_tables = pa_tables or [InMemoryTable.from_batches([], schema=pa.schema(self._info.features.type))]
|
| 216 |
+
pa_table = concat_tables(pa_tables) if len(pa_tables) != 1 else pa_tables[0]
|
| 217 |
+
return pa_table
|
| 218 |
+
|
| 219 |
+
def get_file_instructions(self, name, instruction, split_infos):
|
| 220 |
+
"""Return list of dict {'filename': str, 'skip': int, 'take': int}"""
|
| 221 |
+
file_instructions = make_file_instructions(
|
| 222 |
+
name, split_infos, instruction, filetype_suffix=self._filetype_suffix, prefix_path=self._path
|
| 223 |
+
)
|
| 224 |
+
files = file_instructions.file_instructions
|
| 225 |
+
return files
|
| 226 |
+
|
| 227 |
+
def read(
|
| 228 |
+
self,
|
| 229 |
+
name,
|
| 230 |
+
instructions,
|
| 231 |
+
split_infos,
|
| 232 |
+
in_memory=False,
|
| 233 |
+
):
|
| 234 |
+
"""Returns Dataset instance(s).
|
| 235 |
+
|
| 236 |
+
Args:
|
| 237 |
+
name (str): name of the dataset.
|
| 238 |
+
instructions (ReadInstruction): instructions to read.
|
| 239 |
+
Instruction can be string and will then be passed to the Instruction
|
| 240 |
+
constructor as it.
|
| 241 |
+
split_infos (list of SplitInfo proto): the available splits for dataset.
|
| 242 |
+
in_memory (bool, default False): Whether to copy the data in-memory.
|
| 243 |
+
|
| 244 |
+
Returns:
|
| 245 |
+
kwargs to build a single Dataset instance.
|
| 246 |
+
"""
|
| 247 |
+
|
| 248 |
+
files = self.get_file_instructions(name, instructions, split_infos)
|
| 249 |
+
if not files:
|
| 250 |
+
msg = f'Instruction "{instructions}" corresponds to no data!'
|
| 251 |
+
raise ValueError(msg)
|
| 252 |
+
return self.read_files(files=files, original_instructions=instructions, in_memory=in_memory)
|
| 253 |
+
|
| 254 |
+
def read_files(
|
| 255 |
+
self,
|
| 256 |
+
files: list[dict],
|
| 257 |
+
original_instructions: Union[None, "ReadInstruction", "Split"] = None,
|
| 258 |
+
in_memory=False,
|
| 259 |
+
):
|
| 260 |
+
"""Returns single Dataset instance for the set of file instructions.
|
| 261 |
+
|
| 262 |
+
Args:
|
| 263 |
+
files: List[dict(filename, skip, take)], the files information.
|
| 264 |
+
The filenames contains the relative path, not absolute.
|
| 265 |
+
skip/take indicates which example read in the file: `ds.skip().take()`
|
| 266 |
+
original_instructions: store the original instructions used to build the dataset split in the dataset.
|
| 267 |
+
in_memory (bool, default False): Whether to copy the data in-memory.
|
| 268 |
+
|
| 269 |
+
Returns:
|
| 270 |
+
kwargs to build a Dataset instance.
|
| 271 |
+
"""
|
| 272 |
+
# Prepend path to filename
|
| 273 |
+
pa_table = self._read_files(files, in_memory=in_memory)
|
| 274 |
+
# If original_instructions is not None, convert it to a human-readable NamedSplit
|
| 275 |
+
if original_instructions is not None:
|
| 276 |
+
from .splits import Split # noqa
|
| 277 |
+
|
| 278 |
+
split = Split(str(original_instructions))
|
| 279 |
+
else:
|
| 280 |
+
split = None
|
| 281 |
+
dataset_kwargs = {"arrow_table": pa_table, "info": self._info, "split": split}
|
| 282 |
+
return dataset_kwargs
|
| 283 |
+
|
| 284 |
+
|
| 285 |
+
class ArrowReader(BaseReader):
|
| 286 |
+
"""
|
| 287 |
+
Build a Dataset object out of Instruction instance(s).
|
| 288 |
+
This Reader uses either memory mapping or file descriptors (in-memory) on arrow files.
|
| 289 |
+
"""
|
| 290 |
+
|
| 291 |
+
def __init__(self, path: str, info: Optional["DatasetInfo"]):
|
| 292 |
+
"""Initializes ArrowReader.
|
| 293 |
+
|
| 294 |
+
Args:
|
| 295 |
+
path (str): path where Arrow files are stored.
|
| 296 |
+
info (DatasetInfo): info about the dataset.
|
| 297 |
+
"""
|
| 298 |
+
super().__init__(path, info)
|
| 299 |
+
self._filetype_suffix = "arrow"
|
| 300 |
+
|
| 301 |
+
def _get_table_from_filename(self, filename_skip_take, in_memory=False) -> Table:
|
| 302 |
+
"""Returns a Dataset instance from given (filename, skip, take)."""
|
| 303 |
+
filename, skip, take = (
|
| 304 |
+
filename_skip_take["filename"],
|
| 305 |
+
filename_skip_take["skip"] if "skip" in filename_skip_take else None,
|
| 306 |
+
filename_skip_take["take"] if "take" in filename_skip_take else None,
|
| 307 |
+
)
|
| 308 |
+
table = ArrowReader.read_table(filename, in_memory=in_memory)
|
| 309 |
+
if take == -1:
|
| 310 |
+
take = len(table) - skip
|
| 311 |
+
# here we don't want to slice an empty table, or it may segfault
|
| 312 |
+
if skip is not None and take is not None and not (skip == 0 and take == len(table)):
|
| 313 |
+
table = table.slice(skip, take)
|
| 314 |
+
return table
|
| 315 |
+
|
| 316 |
+
@staticmethod
|
| 317 |
+
def read_table(filename, in_memory=False) -> Table:
|
| 318 |
+
"""
|
| 319 |
+
Read table from file.
|
| 320 |
+
|
| 321 |
+
Args:
|
| 322 |
+
filename (str): File name of the table.
|
| 323 |
+
in_memory (bool, default=False): Whether to copy the data in-memory.
|
| 324 |
+
|
| 325 |
+
Returns:
|
| 326 |
+
pyarrow.Table
|
| 327 |
+
"""
|
| 328 |
+
table_cls = InMemoryTable if in_memory else MemoryMappedTable
|
| 329 |
+
return table_cls.from_file(filename)
|
| 330 |
+
|
| 331 |
+
|
| 332 |
+
class ParquetReader(BaseReader):
|
| 333 |
+
"""
|
| 334 |
+
Build a Dataset object out of Instruction instance(s).
|
| 335 |
+
This Reader uses memory mapping on parquet files.
|
| 336 |
+
"""
|
| 337 |
+
|
| 338 |
+
def __init__(self, path: str, info: Optional["DatasetInfo"]):
|
| 339 |
+
"""Initializes ParquetReader.
|
| 340 |
+
|
| 341 |
+
Args:
|
| 342 |
+
path (str): path where tfrecords are stored.
|
| 343 |
+
info (DatasetInfo): info about the dataset.
|
| 344 |
+
"""
|
| 345 |
+
super().__init__(path, info)
|
| 346 |
+
self._filetype_suffix = "parquet"
|
| 347 |
+
|
| 348 |
+
def _get_table_from_filename(self, filename_skip_take, **kwargs):
|
| 349 |
+
"""Returns a Dataset instance from given (filename, skip, take)."""
|
| 350 |
+
filename, skip, take = (
|
| 351 |
+
filename_skip_take["filename"],
|
| 352 |
+
filename_skip_take["skip"] if "skip" in filename_skip_take else None,
|
| 353 |
+
filename_skip_take["take"] if "take" in filename_skip_take else None,
|
| 354 |
+
)
|
| 355 |
+
# Parquet read_table always loads data in memory, independently of memory_map
|
| 356 |
+
pa_table = pq.read_table(filename, memory_map=True)
|
| 357 |
+
# here we don't want to slice an empty table, or it may segfault
|
| 358 |
+
if skip is not None and take is not None and not (skip == 0 and take == len(pa_table)):
|
| 359 |
+
pa_table = pa_table.slice(skip, take)
|
| 360 |
+
return pa_table
|
| 361 |
+
|
| 362 |
+
|
| 363 |
+
@dataclass(frozen=True)
|
| 364 |
+
class _AbsoluteInstruction:
|
| 365 |
+
"""A machine friendly slice: defined absolute positive boundaries."""
|
| 366 |
+
|
| 367 |
+
splitname: str
|
| 368 |
+
from_: int # uint (starting index).
|
| 369 |
+
to: int # uint (ending index).
|
| 370 |
+
|
| 371 |
+
|
| 372 |
+
@dataclass(frozen=True)
|
| 373 |
+
class _RelativeInstruction:
|
| 374 |
+
"""Represents a single parsed slicing instruction, can use % and negatives."""
|
| 375 |
+
|
| 376 |
+
splitname: str
|
| 377 |
+
from_: Optional[int] = None # int (starting index) or None if no lower boundary.
|
| 378 |
+
to: Optional[int] = None # int (ending index) or None if no upper boundary.
|
| 379 |
+
unit: Optional[str] = None
|
| 380 |
+
rounding: Optional[str] = None
|
| 381 |
+
|
| 382 |
+
def __post_init__(self):
|
| 383 |
+
if self.unit is not None and self.unit not in ["%", "abs"]:
|
| 384 |
+
raise ValueError("unit must be either % or abs")
|
| 385 |
+
if self.rounding is not None and self.rounding not in ["closest", "pct1_dropremainder"]:
|
| 386 |
+
raise ValueError("rounding must be either closest or pct1_dropremainder")
|
| 387 |
+
if self.unit != "%" and self.rounding is not None:
|
| 388 |
+
raise ValueError("It is forbidden to specify rounding if not using percent slicing.")
|
| 389 |
+
if self.unit == "%" and self.from_ is not None and abs(self.from_) > 100:
|
| 390 |
+
raise ValueError("Percent slice boundaries must be > -100 and < 100.")
|
| 391 |
+
if self.unit == "%" and self.to is not None and abs(self.to) > 100:
|
| 392 |
+
raise ValueError("Percent slice boundaries must be > -100 and < 100.")
|
| 393 |
+
# Update via __dict__ due to instance being "frozen"
|
| 394 |
+
self.__dict__["rounding"] = "closest" if self.rounding is None and self.unit == "%" else self.rounding
|
| 395 |
+
|
| 396 |
+
|
| 397 |
+
def _str_to_read_instruction(spec):
|
| 398 |
+
"""Returns ReadInstruction for given string."""
|
| 399 |
+
res = _SUB_SPEC_RE.match(spec)
|
| 400 |
+
if not res:
|
| 401 |
+
raise ValueError(f"Unrecognized instruction format: {spec}")
|
| 402 |
+
unit = "%" if res.group("from_pct") or res.group("to_pct") else "abs"
|
| 403 |
+
return ReadInstruction(
|
| 404 |
+
split_name=res.group("split"),
|
| 405 |
+
rounding=res.group("rounding"),
|
| 406 |
+
from_=int(res.group("from")) if res.group("from") else None,
|
| 407 |
+
to=int(res.group("to")) if res.group("to") else None,
|
| 408 |
+
unit=unit,
|
| 409 |
+
)
|
| 410 |
+
|
| 411 |
+
|
| 412 |
+
def _pct_to_abs_pct1(boundary, num_examples):
|
| 413 |
+
# Using math.trunc here, since -99.5% should give -99%, not -100%.
|
| 414 |
+
if num_examples < 100:
|
| 415 |
+
msg = (
|
| 416 |
+
'Using "pct1_dropremainder" rounding on a split with less than 100 '
|
| 417 |
+
"elements is forbidden: it always results in an empty dataset."
|
| 418 |
+
)
|
| 419 |
+
raise ValueError(msg)
|
| 420 |
+
return boundary * math.trunc(num_examples / 100.0)
|
| 421 |
+
|
| 422 |
+
|
| 423 |
+
def _pct_to_abs_closest(boundary, num_examples):
|
| 424 |
+
return int(round(boundary * num_examples / 100.0))
|
| 425 |
+
|
| 426 |
+
|
| 427 |
+
def _rel_to_abs_instr(rel_instr, name2len):
|
| 428 |
+
"""Returns _AbsoluteInstruction instance for given RelativeInstruction.
|
| 429 |
+
|
| 430 |
+
Args:
|
| 431 |
+
rel_instr: RelativeInstruction instance.
|
| 432 |
+
name2len: dict {split_name: num_examples}.
|
| 433 |
+
"""
|
| 434 |
+
pct_to_abs = _pct_to_abs_closest if rel_instr.rounding == "closest" else _pct_to_abs_pct1
|
| 435 |
+
split = rel_instr.splitname
|
| 436 |
+
if split not in name2len:
|
| 437 |
+
raise ValueError(f'Unknown split "{split}". Should be one of {list(name2len)}.')
|
| 438 |
+
num_examples = name2len[split]
|
| 439 |
+
from_ = rel_instr.from_
|
| 440 |
+
to = rel_instr.to
|
| 441 |
+
if rel_instr.unit == "%":
|
| 442 |
+
from_ = 0 if from_ is None else pct_to_abs(from_, num_examples)
|
| 443 |
+
to = num_examples if to is None else pct_to_abs(to, num_examples)
|
| 444 |
+
else:
|
| 445 |
+
from_ = 0 if from_ is None else from_
|
| 446 |
+
to = num_examples if to is None else to
|
| 447 |
+
if from_ < 0:
|
| 448 |
+
from_ = max(num_examples + from_, 0)
|
| 449 |
+
if to < 0:
|
| 450 |
+
to = max(num_examples + to, 0)
|
| 451 |
+
from_ = min(from_, num_examples)
|
| 452 |
+
to = min(to, num_examples)
|
| 453 |
+
return _AbsoluteInstruction(split, from_, to)
|
| 454 |
+
|
| 455 |
+
|
| 456 |
+
class ReadInstruction:
|
| 457 |
+
"""Reading instruction for a dataset.
|
| 458 |
+
|
| 459 |
+
Examples::
|
| 460 |
+
|
| 461 |
+
# The following lines are equivalent:
|
| 462 |
+
ds = datasets.load_dataset('ylecun/mnist', split='test[:33%]')
|
| 463 |
+
ds = datasets.load_dataset('ylecun/mnist', split=datasets.ReadInstruction.from_spec('test[:33%]'))
|
| 464 |
+
ds = datasets.load_dataset('ylecun/mnist', split=datasets.ReadInstruction('test', to=33, unit='%'))
|
| 465 |
+
ds = datasets.load_dataset('ylecun/mnist', split=datasets.ReadInstruction(
|
| 466 |
+
'test', from_=0, to=33, unit='%'))
|
| 467 |
+
|
| 468 |
+
# The following lines are equivalent:
|
| 469 |
+
ds = datasets.load_dataset('ylecun/mnist', split='test[:33%]+train[1:-1]')
|
| 470 |
+
ds = datasets.load_dataset('ylecun/mnist', split=datasets.ReadInstruction.from_spec(
|
| 471 |
+
'test[:33%]+train[1:-1]'))
|
| 472 |
+
ds = datasets.load_dataset('ylecun/mnist', split=(
|
| 473 |
+
datasets.ReadInstruction('test', to=33, unit='%') +
|
| 474 |
+
datasets.ReadInstruction('train', from_=1, to=-1, unit='abs')))
|
| 475 |
+
|
| 476 |
+
# The following lines are equivalent:
|
| 477 |
+
ds = datasets.load_dataset('ylecun/mnist', split='test[:33%](pct1_dropremainder)')
|
| 478 |
+
ds = datasets.load_dataset('ylecun/mnist', split=datasets.ReadInstruction.from_spec(
|
| 479 |
+
'test[:33%](pct1_dropremainder)'))
|
| 480 |
+
ds = datasets.load_dataset('ylecun/mnist', split=datasets.ReadInstruction(
|
| 481 |
+
'test', from_=0, to=33, unit='%', rounding="pct1_dropremainder"))
|
| 482 |
+
|
| 483 |
+
# 10-fold validation:
|
| 484 |
+
tests = datasets.load_dataset(
|
| 485 |
+
'ylecun/mnist',
|
| 486 |
+
[datasets.ReadInstruction('train', from_=k, to=k+10, unit='%')
|
| 487 |
+
for k in range(0, 100, 10)])
|
| 488 |
+
trains = datasets.load_dataset(
|
| 489 |
+
'ylecun/mnist',
|
| 490 |
+
[datasets.ReadInstruction('train', to=k, unit='%') + datasets.ReadInstruction('train', from_=k+10, unit='%')
|
| 491 |
+
for k in range(0, 100, 10)])
|
| 492 |
+
|
| 493 |
+
"""
|
| 494 |
+
|
| 495 |
+
def _init(self, relative_instructions):
|
| 496 |
+
# Private initializer.
|
| 497 |
+
self._relative_instructions = relative_instructions
|
| 498 |
+
|
| 499 |
+
@classmethod
|
| 500 |
+
def _read_instruction_from_relative_instructions(cls, relative_instructions):
|
| 501 |
+
"""Returns ReadInstruction obj initialized with relative_instructions."""
|
| 502 |
+
# Use __new__ to bypass __init__ used by public API and not conveniant here.
|
| 503 |
+
result = cls.__new__(cls)
|
| 504 |
+
result._init(relative_instructions) # pylint: disable=protected-access
|
| 505 |
+
return result
|
| 506 |
+
|
| 507 |
+
def __init__(self, split_name, rounding=None, from_=None, to=None, unit=None):
|
| 508 |
+
"""Initialize ReadInstruction.
|
| 509 |
+
|
| 510 |
+
Args:
|
| 511 |
+
split_name (str): name of the split to read. Eg: 'train'.
|
| 512 |
+
rounding (str, optional): The rounding behaviour to use when percent slicing is
|
| 513 |
+
used. Ignored when slicing with absolute indices.
|
| 514 |
+
Possible values:
|
| 515 |
+
- 'closest' (default): The specified percentages are rounded to the
|
| 516 |
+
closest value. Use this if you want specified percents to be as
|
| 517 |
+
much exact as possible.
|
| 518 |
+
- 'pct1_dropremainder': the specified percentages are treated as
|
| 519 |
+
multiple of 1%. Use this option if you want consistency. Eg:
|
| 520 |
+
len(5%) == 5 * len(1%).
|
| 521 |
+
Using this option, one might not be able to use the full set of
|
| 522 |
+
examples, if the number of those is not a multiple of 100.
|
| 523 |
+
from_ (int):
|
| 524 |
+
to (int): alternative way of specifying slicing boundaries. If any of
|
| 525 |
+
{from_, to, unit} argument is used, slicing cannot be specified as
|
| 526 |
+
string.
|
| 527 |
+
unit (str): optional, one of:
|
| 528 |
+
'%': to set the slicing unit as percents of the split size.
|
| 529 |
+
'abs': to set the slicing unit as absolute numbers.
|
| 530 |
+
"""
|
| 531 |
+
# This constructor is not always called. See factory method
|
| 532 |
+
# `_read_instruction_from_relative_instructions`. Common init instructions
|
| 533 |
+
# MUST be placed in the _init method.
|
| 534 |
+
self._init([_RelativeInstruction(split_name, from_, to, unit, rounding)])
|
| 535 |
+
|
| 536 |
+
@classmethod
|
| 537 |
+
def from_spec(cls, spec):
|
| 538 |
+
"""Creates a `ReadInstruction` instance out of a string spec.
|
| 539 |
+
|
| 540 |
+
Args:
|
| 541 |
+
spec (`str`):
|
| 542 |
+
Split(s) + optional slice(s) to read + optional rounding
|
| 543 |
+
if percents are used as the slicing unit. A slice can be specified,
|
| 544 |
+
using absolute numbers (`int`) or percentages (`int`).
|
| 545 |
+
|
| 546 |
+
Examples:
|
| 547 |
+
|
| 548 |
+
```
|
| 549 |
+
test: test split.
|
| 550 |
+
test + validation: test split + validation split.
|
| 551 |
+
test[10:]: test split, minus its first 10 records.
|
| 552 |
+
test[:10%]: first 10% records of test split.
|
| 553 |
+
test[:20%](pct1_dropremainder): first 10% records, rounded with the pct1_dropremainder rounding.
|
| 554 |
+
test[:-5%]+train[40%:60%]: first 95% of test + middle 20% of train.
|
| 555 |
+
```
|
| 556 |
+
|
| 557 |
+
Returns:
|
| 558 |
+
ReadInstruction instance.
|
| 559 |
+
"""
|
| 560 |
+
spec = str(spec) # Need to convert to str in case of NamedSplit instance.
|
| 561 |
+
subs = _ADDITION_SEP_RE.split(spec)
|
| 562 |
+
if not subs:
|
| 563 |
+
raise ValueError(f"No instructions could be built out of {spec}")
|
| 564 |
+
instruction = _str_to_read_instruction(subs[0])
|
| 565 |
+
return sum((_str_to_read_instruction(sub) for sub in subs[1:]), instruction)
|
| 566 |
+
|
| 567 |
+
def to_spec(self):
|
| 568 |
+
rel_instr_specs = []
|
| 569 |
+
for rel_instr in self._relative_instructions:
|
| 570 |
+
rel_instr_spec = rel_instr.splitname
|
| 571 |
+
if rel_instr.from_ is not None or rel_instr.to is not None:
|
| 572 |
+
from_ = rel_instr.from_
|
| 573 |
+
to = rel_instr.to
|
| 574 |
+
unit = rel_instr.unit
|
| 575 |
+
rounding = rel_instr.rounding
|
| 576 |
+
unit = unit if unit == "%" else ""
|
| 577 |
+
from_ = str(from_) + unit if from_ is not None else ""
|
| 578 |
+
to = str(to) + unit if to is not None else ""
|
| 579 |
+
slice_str = f"[{from_}:{to}]"
|
| 580 |
+
rounding_str = (
|
| 581 |
+
f"({rounding})" if unit == "%" and rounding is not None and rounding != "closest" else ""
|
| 582 |
+
)
|
| 583 |
+
rel_instr_spec += slice_str + rounding_str
|
| 584 |
+
rel_instr_specs.append(rel_instr_spec)
|
| 585 |
+
return "+".join(rel_instr_specs)
|
| 586 |
+
|
| 587 |
+
def __add__(self, other):
|
| 588 |
+
"""Returns a new ReadInstruction obj, result of appending other to self."""
|
| 589 |
+
if not isinstance(other, ReadInstruction):
|
| 590 |
+
msg = "ReadInstruction can only be added to another ReadInstruction obj."
|
| 591 |
+
raise TypeError(msg)
|
| 592 |
+
self_ris = self._relative_instructions
|
| 593 |
+
other_ris = other._relative_instructions # pylint: disable=protected-access
|
| 594 |
+
if (
|
| 595 |
+
self_ris[0].unit != "abs"
|
| 596 |
+
and other_ris[0].unit != "abs"
|
| 597 |
+
and self._relative_instructions[0].rounding != other_ris[0].rounding
|
| 598 |
+
):
|
| 599 |
+
raise ValueError("It is forbidden to sum ReadInstruction instances with different rounding values.")
|
| 600 |
+
return self._read_instruction_from_relative_instructions(self_ris + other_ris)
|
| 601 |
+
|
| 602 |
+
def __str__(self):
|
| 603 |
+
return self.to_spec()
|
| 604 |
+
|
| 605 |
+
def __repr__(self):
|
| 606 |
+
return f"ReadInstruction({self._relative_instructions})"
|
| 607 |
+
|
| 608 |
+
def to_absolute(self, name2len):
|
| 609 |
+
"""Translate instruction into a list of absolute instructions.
|
| 610 |
+
|
| 611 |
+
Those absolute instructions are then to be added together.
|
| 612 |
+
|
| 613 |
+
Args:
|
| 614 |
+
name2len (`dict`):
|
| 615 |
+
Associating split names to number of examples.
|
| 616 |
+
|
| 617 |
+
Returns:
|
| 618 |
+
list of _AbsoluteInstruction instances (corresponds to the + in spec).
|
| 619 |
+
"""
|
| 620 |
+
return [_rel_to_abs_instr(rel_instr, name2len) for rel_instr in self._relative_instructions]
|
venv/Lib/site-packages/datasets/arrow_writer.py
ADDED
|
@@ -0,0 +1,828 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2020 The HuggingFace Datasets Authors and the TensorFlow Datasets Authors.
|
| 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 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 8 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 9 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 10 |
+
# See the License for the specific language governing permissions and
|
| 11 |
+
# limitations under the License.
|
| 12 |
+
|
| 13 |
+
# Lint as: python3
|
| 14 |
+
"""To write records into Parquet files."""
|
| 15 |
+
|
| 16 |
+
import io
|
| 17 |
+
import json
|
| 18 |
+
import sys
|
| 19 |
+
from collections.abc import Iterable
|
| 20 |
+
from typing import Any, Literal, Optional
|
| 21 |
+
|
| 22 |
+
import fsspec
|
| 23 |
+
import numpy as np
|
| 24 |
+
import pyarrow as pa
|
| 25 |
+
import pyarrow.json as paj
|
| 26 |
+
import pyarrow.parquet as pq
|
| 27 |
+
from fsspec.core import url_to_fs
|
| 28 |
+
|
| 29 |
+
from . import config
|
| 30 |
+
from .features import Audio, Features, Image, Pdf, Value, Video
|
| 31 |
+
from .features.features import (
|
| 32 |
+
FeatureType,
|
| 33 |
+
List,
|
| 34 |
+
_ArrayXDExtensionType,
|
| 35 |
+
_visit,
|
| 36 |
+
cast_to_python_objects,
|
| 37 |
+
generate_from_arrow_type,
|
| 38 |
+
get_nested_type,
|
| 39 |
+
list_of_np_array_to_pyarrow_listarray,
|
| 40 |
+
numpy_to_pyarrow_listarray,
|
| 41 |
+
require_storage_embed,
|
| 42 |
+
to_pyarrow_listarray,
|
| 43 |
+
)
|
| 44 |
+
from .filesystems import is_remote_filesystem
|
| 45 |
+
from .info import DatasetInfo
|
| 46 |
+
from .table import array_cast, cast_array_to_feature, embed_table_storage, table_cast
|
| 47 |
+
from .utils import logging
|
| 48 |
+
from .utils.json import (
|
| 49 |
+
find_mixed_struct_types_field_paths,
|
| 50 |
+
get_json_field_path_from_pyarrow_json_error,
|
| 51 |
+
get_json_field_paths_from_feature,
|
| 52 |
+
insert_json_field_path,
|
| 53 |
+
json_encode_field,
|
| 54 |
+
json_encode_fields_in_json_lines,
|
| 55 |
+
set_json_types_in_feature,
|
| 56 |
+
ujson_dumps,
|
| 57 |
+
)
|
| 58 |
+
from .utils.py_utils import asdict, convert_file_size_to_int, first_non_null_non_empty_value
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
logger = logging.get_logger(__name__)
|
| 62 |
+
|
| 63 |
+
type_ = type # keep python's type function
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
def get_arrow_writer_batch_size_from_features(features: Optional[Features]) -> Optional[int]:
|
| 67 |
+
"""
|
| 68 |
+
Get the writer_batch_size that defines the maximum record batch size in the arrow files based on configuration values.
|
| 69 |
+
The default value is 100 for image/audio datasets and 10 for videos.
|
| 70 |
+
This allows to avoid overflows in arrow buffers.
|
| 71 |
+
|
| 72 |
+
Args:
|
| 73 |
+
features (`datasets.Features` or `None`):
|
| 74 |
+
Dataset Features from `datasets`.
|
| 75 |
+
Returns:
|
| 76 |
+
writer_batch_size (`Optional[int]`):
|
| 77 |
+
Writer batch size to pass to a dataset builder.
|
| 78 |
+
If `None`, then it will use the `datasets` default, i.e. `datasets.config.DEFAULT_MAX_BATCH_SIZE`.
|
| 79 |
+
"""
|
| 80 |
+
if not features:
|
| 81 |
+
return None
|
| 82 |
+
|
| 83 |
+
batch_size = np.inf
|
| 84 |
+
|
| 85 |
+
def set_batch_size(feature: FeatureType) -> None:
|
| 86 |
+
nonlocal batch_size
|
| 87 |
+
if isinstance(feature, Image) and config.ARROW_RECORD_BATCH_SIZE_FOR_IMAGE_DATASETS is not None:
|
| 88 |
+
batch_size = min(batch_size, config.ARROW_RECORD_BATCH_SIZE_FOR_IMAGE_DATASETS)
|
| 89 |
+
elif isinstance(feature, Audio) and config.ARROW_RECORD_BATCH_SIZE_FOR_AUDIO_DATASETS is not None:
|
| 90 |
+
batch_size = min(batch_size, config.ARROW_RECORD_BATCH_SIZE_FOR_AUDIO_DATASETS)
|
| 91 |
+
elif isinstance(feature, Video) and config.ARROW_RECORD_BATCH_SIZE_FOR_VIDEO_DATASETS is not None:
|
| 92 |
+
batch_size = min(batch_size, config.ARROW_RECORD_BATCH_SIZE_FOR_VIDEO_DATASETS)
|
| 93 |
+
elif (
|
| 94 |
+
isinstance(feature, Value)
|
| 95 |
+
and feature.dtype == "binary"
|
| 96 |
+
and config.ARROW_RECORD_BATCH_SIZE_FOR_BINARY_DATASETS is not None
|
| 97 |
+
):
|
| 98 |
+
batch_size = min(batch_size, config.ARROW_RECORD_BATCH_SIZE_FOR_BINARY_DATASETS)
|
| 99 |
+
|
| 100 |
+
_visit(features, set_batch_size)
|
| 101 |
+
|
| 102 |
+
return None if batch_size is np.inf else batch_size
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
def get_writer_batch_size_from_features(features: Optional[Features]) -> Optional[int]:
|
| 106 |
+
"""
|
| 107 |
+
Get the writer_batch_size that defines the maximum row group size in the parquet files based on configuration values.
|
| 108 |
+
By default these are not set, but it can be helpful to hard set those values in some cases.
|
| 109 |
+
This allows to optimize random access to parquet file, since accessing 1 row requires
|
| 110 |
+
to read its entire row group.
|
| 111 |
+
|
| 112 |
+
Args:
|
| 113 |
+
features (`datasets.Features` or `None`):
|
| 114 |
+
Dataset Features from `datasets`.
|
| 115 |
+
Returns:
|
| 116 |
+
writer_batch_size (`Optional[int]`):
|
| 117 |
+
Writer batch size to pass to a parquet writer.
|
| 118 |
+
If `None`, then it will use the `datasets` default, i.e. aiming for row groups of 100MB.
|
| 119 |
+
"""
|
| 120 |
+
if not features:
|
| 121 |
+
return None
|
| 122 |
+
|
| 123 |
+
batch_size = np.inf
|
| 124 |
+
|
| 125 |
+
def set_batch_size(feature: FeatureType) -> None:
|
| 126 |
+
nonlocal batch_size
|
| 127 |
+
if isinstance(feature, Image) and config.PARQUET_ROW_GROUP_SIZE_FOR_IMAGE_DATASETS is not None:
|
| 128 |
+
batch_size = min(batch_size, config.PARQUET_ROW_GROUP_SIZE_FOR_IMAGE_DATASETS)
|
| 129 |
+
elif isinstance(feature, Audio) and config.PARQUET_ROW_GROUP_SIZE_FOR_AUDIO_DATASETS is not None:
|
| 130 |
+
batch_size = min(batch_size, config.PARQUET_ROW_GROUP_SIZE_FOR_AUDIO_DATASETS)
|
| 131 |
+
elif isinstance(feature, Video) and config.PARQUET_ROW_GROUP_SIZE_FOR_VIDEO_DATASETS is not None:
|
| 132 |
+
batch_size = min(batch_size, config.PARQUET_ROW_GROUP_SIZE_FOR_VIDEO_DATASETS)
|
| 133 |
+
elif (
|
| 134 |
+
isinstance(feature, Value)
|
| 135 |
+
and feature.dtype == "binary"
|
| 136 |
+
and config.PARQUET_ROW_GROUP_SIZE_FOR_BINARY_DATASETS is not None
|
| 137 |
+
):
|
| 138 |
+
batch_size = min(batch_size, config.PARQUET_ROW_GROUP_SIZE_FOR_BINARY_DATASETS)
|
| 139 |
+
|
| 140 |
+
_visit(features, set_batch_size)
|
| 141 |
+
|
| 142 |
+
return None if batch_size is np.inf else batch_size
|
| 143 |
+
|
| 144 |
+
|
| 145 |
+
def get_writer_batch_size_from_data_size(num_rows: int, num_bytes: int) -> int:
|
| 146 |
+
"""
|
| 147 |
+
Get the writer_batch_size that defines the maximum row group size in the parquet files.
|
| 148 |
+
The default in `datasets` is aiming for row groups of maximum 100MB uncompressed.
|
| 149 |
+
This allows to optimize random access to parquet file, since accessing 1 row requires
|
| 150 |
+
to read its entire row group.
|
| 151 |
+
|
| 152 |
+
This can be improved to get optimized size for querying/iterating
|
| 153 |
+
but at least it matches the dataset viewer expectations on HF.
|
| 154 |
+
|
| 155 |
+
Args:
|
| 156 |
+
num_rows (`int`):
|
| 157 |
+
Number of rows in the dataset.
|
| 158 |
+
num_bytes (`int`):
|
| 159 |
+
Number of bytes in the dataset.
|
| 160 |
+
For dataset with external files to embed (image, audio, videos), this can also be an
|
| 161 |
+
estimate from `dataset._estimate_nbytes()`.
|
| 162 |
+
Returns:
|
| 163 |
+
writer_batch_size (`Optional[int]`):
|
| 164 |
+
Writer batch size to pass to a parquet writer.
|
| 165 |
+
"""
|
| 166 |
+
return max(1, num_rows * convert_file_size_to_int(config.MAX_ROW_GROUP_SIZE) // num_bytes) if num_bytes > 0 else 1
|
| 167 |
+
|
| 168 |
+
|
| 169 |
+
class SchemaInferenceError(ValueError):
|
| 170 |
+
pass
|
| 171 |
+
|
| 172 |
+
|
| 173 |
+
class TypedSequence:
|
| 174 |
+
"""
|
| 175 |
+
This data container generalizes the typing when instantiating pyarrow arrays, tables or batches.
|
| 176 |
+
|
| 177 |
+
More specifically it adds several features:
|
| 178 |
+
- Support extension types like ``datasets.features.Array2DExtensionType``:
|
| 179 |
+
By default pyarrow arrays don't return extension arrays. One has to call
|
| 180 |
+
``pa.ExtensionArray.from_storage(type, pa.array(data, type.storage_type))``
|
| 181 |
+
in order to get an extension array.
|
| 182 |
+
- Support for ``try_type`` parameter that can be used instead of ``type``:
|
| 183 |
+
When an array is transformed, we like to keep the same type as before if possible.
|
| 184 |
+
For example when calling :func:`datasets.Dataset.map`, we don't want to change the type
|
| 185 |
+
of each column by default.
|
| 186 |
+
- Better error message when a pyarrow array overflows.
|
| 187 |
+
|
| 188 |
+
Example::
|
| 189 |
+
|
| 190 |
+
from datasets.features import Array2D, Array2DExtensionType, Value
|
| 191 |
+
from datasets.arrow_writer import TypedSequence
|
| 192 |
+
import pyarrow as pa
|
| 193 |
+
|
| 194 |
+
arr = pa.array(TypedSequence([1, 2, 3], type=Value("int32")))
|
| 195 |
+
assert arr.type == pa.int32()
|
| 196 |
+
|
| 197 |
+
arr = pa.array(TypedSequence([1, 2, 3], try_type=Value("int32")))
|
| 198 |
+
assert arr.type == pa.int32()
|
| 199 |
+
|
| 200 |
+
arr = pa.array(TypedSequence(["foo", "bar"], try_type=Value("int32")))
|
| 201 |
+
assert arr.type == pa.string()
|
| 202 |
+
|
| 203 |
+
arr = pa.array(TypedSequence([[[1, 2, 3]]], type=Array2D((1, 3), "int64")))
|
| 204 |
+
assert arr.type == Array2DExtensionType((1, 3), "int64")
|
| 205 |
+
|
| 206 |
+
table = pa.Table.from_pydict({
|
| 207 |
+
"image": TypedSequence([[[1, 2, 3]]], type=Array2D((1, 3), "int64"))
|
| 208 |
+
})
|
| 209 |
+
assert table["image"].type == Array2DExtensionType((1, 3), "int64")
|
| 210 |
+
|
| 211 |
+
"""
|
| 212 |
+
|
| 213 |
+
def __init__(
|
| 214 |
+
self,
|
| 215 |
+
data: Iterable,
|
| 216 |
+
type: Optional[FeatureType] = None,
|
| 217 |
+
try_type: Optional[FeatureType] = None,
|
| 218 |
+
optimized_int_type: Optional[FeatureType] = None,
|
| 219 |
+
on_mixed_types: Optional[Literal["use_json"]] = None,
|
| 220 |
+
):
|
| 221 |
+
# assert type is None or try_type is None,
|
| 222 |
+
if type is not None and try_type is not None:
|
| 223 |
+
raise ValueError("You cannot specify both type and try_type")
|
| 224 |
+
# set attributes
|
| 225 |
+
self.data = data
|
| 226 |
+
self.type = type
|
| 227 |
+
self.try_type = try_type # is ignored if it doesn't match the data
|
| 228 |
+
self.optimized_int_type = optimized_int_type
|
| 229 |
+
self.on_mixed_types = on_mixed_types
|
| 230 |
+
# when trying a type (is ignored if data is not compatible)
|
| 231 |
+
self.trying_type = self.try_type is not None
|
| 232 |
+
self.trying_int_optimization = optimized_int_type is not None and type is None and try_type is None
|
| 233 |
+
# used to get back the inferred type after __arrow_array__() is called once
|
| 234 |
+
self._inferred_type = None
|
| 235 |
+
|
| 236 |
+
def get_inferred_type(self) -> FeatureType:
|
| 237 |
+
"""Return the inferred feature type.
|
| 238 |
+
This is done by converting the sequence to an Arrow array, and getting the corresponding
|
| 239 |
+
feature type.
|
| 240 |
+
|
| 241 |
+
Since building the Arrow array can be expensive, the value of the inferred type is cached
|
| 242 |
+
as soon as pa.array is called on the typed sequence.
|
| 243 |
+
|
| 244 |
+
Returns:
|
| 245 |
+
FeatureType: inferred feature type of the sequence.
|
| 246 |
+
"""
|
| 247 |
+
if self._inferred_type is None:
|
| 248 |
+
pa.array(self)
|
| 249 |
+
return self._inferred_type
|
| 250 |
+
|
| 251 |
+
@staticmethod
|
| 252 |
+
def _infer_custom_type_and_encode(data: Iterable) -> tuple[Iterable, Optional[FeatureType]]:
|
| 253 |
+
"""Implement type inference for custom objects like PIL.Image.Image -> Image type.
|
| 254 |
+
|
| 255 |
+
This function is only used for custom python objects that can't be directly passed to build
|
| 256 |
+
an Arrow array. In such cases is infers the feature type to use, and it encodes the data so
|
| 257 |
+
that they can be passed to an Arrow array.
|
| 258 |
+
|
| 259 |
+
Args:
|
| 260 |
+
data (Iterable): array of data to infer the type, e.g. a list of PIL images.
|
| 261 |
+
|
| 262 |
+
Returns:
|
| 263 |
+
Tuple[Iterable, Optional[FeatureType]]: a tuple with:
|
| 264 |
+
- the (possibly encoded) array, if the inferred feature type requires encoding
|
| 265 |
+
- the inferred feature type if the array is made of supported custom objects like
|
| 266 |
+
PIL images, else None.
|
| 267 |
+
"""
|
| 268 |
+
if config.PIL_AVAILABLE and "PIL" in sys.modules:
|
| 269 |
+
import PIL.Image
|
| 270 |
+
|
| 271 |
+
non_null_idx, non_null_value = first_non_null_non_empty_value(data)
|
| 272 |
+
if isinstance(non_null_value, PIL.Image.Image):
|
| 273 |
+
return [Image().encode_example(value) if value is not None else None for value in data], Image()
|
| 274 |
+
if isinstance(non_null_value, list) and isinstance(non_null_value[0], PIL.Image.Image):
|
| 275 |
+
return [
|
| 276 |
+
[Image().encode_example(x) for x in value] if value is not None else None for value in data
|
| 277 |
+
], List(Image())
|
| 278 |
+
if config.PDFPLUMBER_AVAILABLE and "pdfplumber" in sys.modules:
|
| 279 |
+
import pdfplumber
|
| 280 |
+
|
| 281 |
+
non_null_idx, non_null_value = first_non_null_non_empty_value(data)
|
| 282 |
+
if isinstance(non_null_value, pdfplumber.pdf.PDF):
|
| 283 |
+
return [Pdf().encode_example(value) if value is not None else None for value in data], Pdf()
|
| 284 |
+
if isinstance(non_null_value, list) and isinstance(non_null_value[0], pdfplumber.pdf.PDF):
|
| 285 |
+
return [
|
| 286 |
+
[Pdf().encode_example(x) for x in value] if value is not None else None for value in data
|
| 287 |
+
], List(Pdf())
|
| 288 |
+
return data, None
|
| 289 |
+
|
| 290 |
+
def __arrow_array__(self, type: Optional[pa.DataType] = None):
|
| 291 |
+
out = self._arrow_array(type=type)
|
| 292 |
+
if self._inferred_type is None:
|
| 293 |
+
self._inferred_type = generate_from_arrow_type(out.type)
|
| 294 |
+
return out
|
| 295 |
+
|
| 296 |
+
def _arrow_array(self, type: Optional[pa.DataType] = None):
|
| 297 |
+
"""This function is called when calling pa.array(typed_sequence)"""
|
| 298 |
+
|
| 299 |
+
if type is not None:
|
| 300 |
+
raise ValueError("TypedSequence is supposed to be used with pa.array(typed_sequence, type=None)")
|
| 301 |
+
del type # make sure we don't use it
|
| 302 |
+
data = self.data
|
| 303 |
+
# automatic type inference for custom objects
|
| 304 |
+
if self.type is None and self.try_type is None:
|
| 305 |
+
data, self._inferred_type = self._infer_custom_type_and_encode(data)
|
| 306 |
+
if self._inferred_type is None:
|
| 307 |
+
type = self.try_type if self.trying_type else self.type
|
| 308 |
+
else:
|
| 309 |
+
type = self._inferred_type
|
| 310 |
+
pa_type = get_nested_type(type) if type is not None else None
|
| 311 |
+
optimized_int_pa_type = (
|
| 312 |
+
get_nested_type(self.optimized_int_type) if self.optimized_int_type is not None else None
|
| 313 |
+
)
|
| 314 |
+
trying_cast_to_python_objects = False
|
| 315 |
+
json_field_paths = []
|
| 316 |
+
try:
|
| 317 |
+
# custom pyarrow types
|
| 318 |
+
if isinstance(pa_type, _ArrayXDExtensionType):
|
| 319 |
+
storage = to_pyarrow_listarray(data, pa_type)
|
| 320 |
+
return pa.ExtensionArray.from_storage(pa_type, storage)
|
| 321 |
+
|
| 322 |
+
# efficient np array to pyarrow array
|
| 323 |
+
if isinstance(data, np.ndarray):
|
| 324 |
+
out = numpy_to_pyarrow_listarray(data)
|
| 325 |
+
elif isinstance(data, list) and data and isinstance(first_non_null_non_empty_value(data)[1], np.ndarray):
|
| 326 |
+
out = list_of_np_array_to_pyarrow_listarray(data)
|
| 327 |
+
else:
|
| 328 |
+
trying_cast_to_python_objects = True
|
| 329 |
+
examples = data
|
| 330 |
+
# find fields to json-encode
|
| 331 |
+
if self.on_mixed_types == "use_json" and type is None:
|
| 332 |
+
json_field_paths = find_mixed_struct_types_field_paths(examples, allow_root=True)
|
| 333 |
+
elif type is not None:
|
| 334 |
+
json_field_paths = get_json_field_paths_from_feature(type)
|
| 335 |
+
# json encode if needed
|
| 336 |
+
if json_field_paths:
|
| 337 |
+
for json_field_path in json_field_paths:
|
| 338 |
+
examples = [json_encode_field(examples, json_field_path) for examples in examples]
|
| 339 |
+
# to arrow array
|
| 340 |
+
out = pa.array(cast_to_python_objects(examples, only_1d_for_numpy=True))
|
| 341 |
+
# cast to json type if needed
|
| 342 |
+
if json_field_paths:
|
| 343 |
+
pa_table = pa.Table.from_arrays([out], names=["obj"])
|
| 344 |
+
features = Features.from_arrow_schema(pa_table.schema)
|
| 345 |
+
feature = set_json_types_in_feature(features["obj"], json_field_paths)
|
| 346 |
+
pa_table = table_cast(pa_table, Features({"obj": feature}).arrow_schema)
|
| 347 |
+
out = pa_table[0] # get the "obj" column
|
| 348 |
+
# use smaller integer precisions if possible
|
| 349 |
+
if self.trying_int_optimization:
|
| 350 |
+
if pa.types.is_int64(out.type):
|
| 351 |
+
out = out.cast(optimized_int_pa_type)
|
| 352 |
+
elif pa.types.is_list(out.type):
|
| 353 |
+
if pa.types.is_int64(out.type.value_type):
|
| 354 |
+
out = array_cast(out, pa.list_(optimized_int_pa_type))
|
| 355 |
+
elif pa.types.is_list(out.type.value_type) and pa.types.is_int64(out.type.value_type.value_type):
|
| 356 |
+
out = array_cast(out, pa.list_(pa.list_(optimized_int_pa_type)))
|
| 357 |
+
# otherwise we can finally use the user's type
|
| 358 |
+
elif type is not None:
|
| 359 |
+
# We use cast_array_to_feature to support casting to custom types like Audio and Image
|
| 360 |
+
# Also, when trying type "string", we don't want to convert integers or floats to "string".
|
| 361 |
+
# We only do it if trying_type is False - since this is what the user asks for.
|
| 362 |
+
out = cast_array_to_feature(
|
| 363 |
+
out, type, allow_primitive_to_str=not self.trying_type, allow_decimal_to_str=not self.trying_type
|
| 364 |
+
)
|
| 365 |
+
return out
|
| 366 |
+
except (
|
| 367 |
+
TypeError,
|
| 368 |
+
pa.lib.ArrowTypeError,
|
| 369 |
+
pa.lib.ArrowInvalid,
|
| 370 |
+
pa.lib.ArrowNotImplementedError,
|
| 371 |
+
) as e: # handle type errors and overflows
|
| 372 |
+
# Ignore ArrowNotImplementedError caused by trying type, otherwise re-raise
|
| 373 |
+
if not self.trying_type and isinstance(e, pa.lib.ArrowNotImplementedError):
|
| 374 |
+
raise
|
| 375 |
+
|
| 376 |
+
if self.trying_type:
|
| 377 |
+
try: # second chance
|
| 378 |
+
if isinstance(data, np.ndarray):
|
| 379 |
+
return numpy_to_pyarrow_listarray(data)
|
| 380 |
+
elif isinstance(data, list) and data and any(isinstance(value, np.ndarray) for value in data):
|
| 381 |
+
return list_of_np_array_to_pyarrow_listarray(data)
|
| 382 |
+
else:
|
| 383 |
+
trying_cast_to_python_objects = True
|
| 384 |
+
return pa.array(cast_to_python_objects(data, only_1d_for_numpy=True))
|
| 385 |
+
except pa.lib.ArrowInvalid as e:
|
| 386 |
+
if "overflow" in str(e):
|
| 387 |
+
raise OverflowError(
|
| 388 |
+
f"There was an overflow with type {type_(data)}. Try to reduce writer_batch_size to have batches smaller than 2GB.\n({e})"
|
| 389 |
+
) from None
|
| 390 |
+
elif self.trying_int_optimization and "not in range" in str(e):
|
| 391 |
+
optimized_int_pa_type_str = np.dtype(optimized_int_pa_type.to_pandas_dtype()).name
|
| 392 |
+
logger.info(
|
| 393 |
+
f"Failed to cast a sequence to {optimized_int_pa_type_str}. Falling back to int64."
|
| 394 |
+
)
|
| 395 |
+
return out
|
| 396 |
+
elif trying_cast_to_python_objects and "Could not convert" in str(e):
|
| 397 |
+
out = pa.array(
|
| 398 |
+
cast_to_python_objects(data, only_1d_for_numpy=True, optimize_list_casting=False)
|
| 399 |
+
)
|
| 400 |
+
if type is not None:
|
| 401 |
+
out = cast_array_to_feature(
|
| 402 |
+
out, type, allow_primitive_to_str=True, allow_decimal_to_str=True
|
| 403 |
+
)
|
| 404 |
+
return out
|
| 405 |
+
else:
|
| 406 |
+
raise
|
| 407 |
+
elif "overflow" in str(e):
|
| 408 |
+
raise OverflowError(
|
| 409 |
+
f"There was an overflow with type {type_(data)}. Try to reduce writer_batch_size to have batches smaller than 2GB.\n({e})"
|
| 410 |
+
) from None
|
| 411 |
+
elif self.trying_int_optimization and "not in range" in str(e):
|
| 412 |
+
optimized_int_pa_type_str = np.dtype(optimized_int_pa_type.to_pandas_dtype()).name
|
| 413 |
+
logger.info(f"Failed to cast a sequence to {optimized_int_pa_type_str}. Falling back to int64.")
|
| 414 |
+
return out
|
| 415 |
+
elif trying_cast_to_python_objects and (
|
| 416 |
+
"Could not convert" in str(e) or "cannot mix struct and non-struct" in str(e) or "Expected " in str(e)
|
| 417 |
+
):
|
| 418 |
+
try: # third chance
|
| 419 |
+
out = pa.array(cast_to_python_objects(data, only_1d_for_numpy=True, optimize_list_casting=False))
|
| 420 |
+
except (pa.ArrowInvalid, pa.ArrowTypeError) as ee:
|
| 421 |
+
# in case of mixed types, we use the JSON Lines reader in pyarrow to locate them and set them to json fields
|
| 422 |
+
if self.on_mixed_types == "use_json" and (
|
| 423 |
+
"Could not convert " in str(ee)
|
| 424 |
+
or "cannot mix struct and non-struct" in str(ee)
|
| 425 |
+
or "Expected " in str(ee)
|
| 426 |
+
):
|
| 427 |
+
# we use "obj" to have valid JSON Lines since data may contain lists
|
| 428 |
+
original_batch = "\n".join([ujson_dumps({"obj": example}) for example in data]).encode()
|
| 429 |
+
json_field_paths = [["obj"] + json_field_path for json_field_path in json_field_paths]
|
| 430 |
+
batch = json_encode_fields_in_json_lines(original_batch, json_field_paths)
|
| 431 |
+
pa_table = None
|
| 432 |
+
while True:
|
| 433 |
+
try: # fourth chance
|
| 434 |
+
pa_table = paj.read_json(
|
| 435 |
+
io.BytesIO(batch), read_options=paj.ReadOptions(use_threads=False)
|
| 436 |
+
)
|
| 437 |
+
break
|
| 438 |
+
except pa.ArrowInvalid as eee:
|
| 439 |
+
if "JSON parse error: Column(" in str(eee) and ") changed from" in str(eee):
|
| 440 |
+
json_field_path = get_json_field_path_from_pyarrow_json_error(str(eee))
|
| 441 |
+
insert_json_field_path(json_field_paths, json_field_path)
|
| 442 |
+
batch = json_encode_fields_in_json_lines(original_batch, json_field_paths)
|
| 443 |
+
else:
|
| 444 |
+
break
|
| 445 |
+
if pa_table is not None:
|
| 446 |
+
features = Features.from_arrow_schema(pa_table.schema)
|
| 447 |
+
features = set_json_types_in_feature(features, json_field_paths)
|
| 448 |
+
pa_table = table_cast(pa_table, features.arrow_schema)
|
| 449 |
+
out = pa_table[0] # get the "obj" column
|
| 450 |
+
return out
|
| 451 |
+
else:
|
| 452 |
+
raise
|
| 453 |
+
else:
|
| 454 |
+
raise
|
| 455 |
+
if type is not None:
|
| 456 |
+
out = cast_array_to_feature(out, type, allow_primitive_to_str=True, allow_decimal_to_str=True)
|
| 457 |
+
return out
|
| 458 |
+
else:
|
| 459 |
+
raise
|
| 460 |
+
|
| 461 |
+
|
| 462 |
+
class OptimizedTypedSequence(TypedSequence):
|
| 463 |
+
def __init__(
|
| 464 |
+
self,
|
| 465 |
+
data,
|
| 466 |
+
type: Optional[FeatureType] = None,
|
| 467 |
+
try_type: Optional[FeatureType] = None,
|
| 468 |
+
col: Optional[str] = None,
|
| 469 |
+
optimized_int_type: Optional[FeatureType] = None,
|
| 470 |
+
on_mixed_types: Optional[Literal["use_json"]] = None,
|
| 471 |
+
):
|
| 472 |
+
optimized_int_type_by_col = {
|
| 473 |
+
"attention_mask": Value("int8"), # binary tensor
|
| 474 |
+
"special_tokens_mask": Value("int8"),
|
| 475 |
+
"input_ids": Value("int32"), # typical vocab size: 0-50k (max ~500k, never > 1M)
|
| 476 |
+
"token_type_ids": Value(
|
| 477 |
+
"int8"
|
| 478 |
+
), # binary mask; some (XLNetModel) use an additional token represented by a 2
|
| 479 |
+
}
|
| 480 |
+
if type is None and try_type is None:
|
| 481 |
+
optimized_int_type = optimized_int_type_by_col.get(col, None)
|
| 482 |
+
super().__init__(
|
| 483 |
+
data, type=type, try_type=try_type, optimized_int_type=optimized_int_type, on_mixed_types=on_mixed_types
|
| 484 |
+
)
|
| 485 |
+
|
| 486 |
+
|
| 487 |
+
class ArrowWriter:
|
| 488 |
+
"""Shuffles and writes Examples to Arrow files."""
|
| 489 |
+
|
| 490 |
+
def __init__(
|
| 491 |
+
self,
|
| 492 |
+
schema: Optional[pa.Schema] = None,
|
| 493 |
+
features: Optional[Features] = None,
|
| 494 |
+
path: Optional[str] = None,
|
| 495 |
+
stream: Optional[pa.NativeFile] = None,
|
| 496 |
+
fingerprint: Optional[str] = None,
|
| 497 |
+
writer_batch_size: Optional[int] = None,
|
| 498 |
+
disable_nullable: bool = False,
|
| 499 |
+
update_features: bool = False,
|
| 500 |
+
on_mixed_types: Optional[Literal["use_json"]] = "use_json",
|
| 501 |
+
with_metadata: bool = True,
|
| 502 |
+
unit: str = "examples",
|
| 503 |
+
embed_local_files: bool = False,
|
| 504 |
+
storage_options: Optional[dict] = None,
|
| 505 |
+
):
|
| 506 |
+
if path is None and stream is None:
|
| 507 |
+
raise ValueError("At least one of path and stream must be provided.")
|
| 508 |
+
if features is not None:
|
| 509 |
+
self._features = features
|
| 510 |
+
self._schema = None
|
| 511 |
+
elif schema is not None:
|
| 512 |
+
self._schema: pa.Schema = schema
|
| 513 |
+
self._features = Features.from_arrow_schema(self._schema)
|
| 514 |
+
else:
|
| 515 |
+
self._features = None
|
| 516 |
+
self._schema = None
|
| 517 |
+
|
| 518 |
+
self._disable_nullable = disable_nullable
|
| 519 |
+
|
| 520 |
+
if stream is None:
|
| 521 |
+
fs, path = url_to_fs(path, **(storage_options or {}))
|
| 522 |
+
self._fs: fsspec.AbstractFileSystem = fs
|
| 523 |
+
self._path = path if not is_remote_filesystem(self._fs) else self._fs.unstrip_protocol(path)
|
| 524 |
+
self.stream = self._fs.open(path, "wb")
|
| 525 |
+
self._closable_stream = True
|
| 526 |
+
else:
|
| 527 |
+
self._fs = None
|
| 528 |
+
self._path = None
|
| 529 |
+
self.stream = stream
|
| 530 |
+
self._closable_stream = False
|
| 531 |
+
|
| 532 |
+
self.fingerprint = fingerprint
|
| 533 |
+
self.disable_nullable = disable_nullable
|
| 534 |
+
self.writer_batch_size = (
|
| 535 |
+
writer_batch_size
|
| 536 |
+
or get_arrow_writer_batch_size_from_features(self._features)
|
| 537 |
+
or config.DEFAULT_MAX_BATCH_SIZE
|
| 538 |
+
)
|
| 539 |
+
self.update_features = update_features
|
| 540 |
+
self.on_mixed_types = on_mixed_types
|
| 541 |
+
self.with_metadata = with_metadata
|
| 542 |
+
self.unit = unit
|
| 543 |
+
self.embed_local_files = embed_local_files
|
| 544 |
+
|
| 545 |
+
self._num_examples = 0
|
| 546 |
+
self._num_bytes = 0
|
| 547 |
+
self.current_examples: list[tuple[dict[str, Any], str]] = []
|
| 548 |
+
self.current_rows: list[pa.Table] = []
|
| 549 |
+
self.pa_writer: Optional[pa.RecordBatchStreamWriter] = None
|
| 550 |
+
self.hkey_record = []
|
| 551 |
+
|
| 552 |
+
def __len__(self):
|
| 553 |
+
"""Return the number of writed and staged examples"""
|
| 554 |
+
return self._num_examples + len(self.current_examples) + len(self.current_rows)
|
| 555 |
+
|
| 556 |
+
def __enter__(self):
|
| 557 |
+
return self
|
| 558 |
+
|
| 559 |
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
| 560 |
+
self.close()
|
| 561 |
+
|
| 562 |
+
def close(self):
|
| 563 |
+
# Try closing if opened; if closed: pyarrow.lib.ArrowInvalid: Invalid operation on closed file
|
| 564 |
+
if self.pa_writer: # it might be None
|
| 565 |
+
try:
|
| 566 |
+
self.pa_writer.close()
|
| 567 |
+
except Exception: # pyarrow.lib.ArrowInvalid, OSError
|
| 568 |
+
pass
|
| 569 |
+
if self._closable_stream and not self.stream.closed:
|
| 570 |
+
self.stream.close() # This also closes self.pa_writer if it is opened
|
| 571 |
+
|
| 572 |
+
def _build_schema(self, inferred_schema: pa.Schema):
|
| 573 |
+
schema = self.schema
|
| 574 |
+
features = self._features
|
| 575 |
+
inferred_features = Features.from_arrow_schema(inferred_schema)
|
| 576 |
+
if self._features is not None:
|
| 577 |
+
if self.update_features: # keep original features it they match, or update them
|
| 578 |
+
fields = {field.name: field for field in self._features.type}
|
| 579 |
+
for inferred_field in inferred_features.type:
|
| 580 |
+
name = inferred_field.name
|
| 581 |
+
if name in fields:
|
| 582 |
+
if inferred_field == fields[name]:
|
| 583 |
+
inferred_features[name] = self._features[name]
|
| 584 |
+
features = inferred_features
|
| 585 |
+
schema: pa.Schema = inferred_schema
|
| 586 |
+
else:
|
| 587 |
+
features = inferred_features
|
| 588 |
+
schema: pa.Schema = inferred_features.arrow_schema
|
| 589 |
+
|
| 590 |
+
if self.disable_nullable:
|
| 591 |
+
schema = pa.schema(pa.field(field.name, field.type, nullable=False) for field in schema)
|
| 592 |
+
if self.with_metadata:
|
| 593 |
+
schema = schema.with_metadata(self._build_metadata(DatasetInfo(features=features), self.fingerprint))
|
| 594 |
+
else:
|
| 595 |
+
schema = schema.with_metadata({})
|
| 596 |
+
|
| 597 |
+
return schema, features
|
| 598 |
+
|
| 599 |
+
def _build_writer(self, inferred_schema: pa.Schema):
|
| 600 |
+
self._schema, self._features = self._build_schema(inferred_schema)
|
| 601 |
+
self.pa_writer = pa.RecordBatchStreamWriter(self.stream, self._schema)
|
| 602 |
+
|
| 603 |
+
@property
|
| 604 |
+
def schema(self):
|
| 605 |
+
_schema = (
|
| 606 |
+
self._schema
|
| 607 |
+
if self._schema is not None
|
| 608 |
+
else (pa.schema(self._features.type) if self._features is not None else None)
|
| 609 |
+
)
|
| 610 |
+
if self._disable_nullable and _schema is not None:
|
| 611 |
+
_schema = pa.schema(pa.field(field.name, field.type, nullable=False) for field in _schema)
|
| 612 |
+
return _schema if _schema is not None else []
|
| 613 |
+
|
| 614 |
+
@staticmethod
|
| 615 |
+
def _build_metadata(info: DatasetInfo, fingerprint: Optional[str] = None) -> dict[str, str]:
|
| 616 |
+
info_keys = ["features"] # we can add support for more DatasetInfo keys in the future
|
| 617 |
+
info_as_dict = asdict(info)
|
| 618 |
+
metadata = {}
|
| 619 |
+
metadata["info"] = {key: info_as_dict[key] for key in info_keys}
|
| 620 |
+
if fingerprint is not None:
|
| 621 |
+
metadata["fingerprint"] = fingerprint
|
| 622 |
+
return {"huggingface": json.dumps(metadata)}
|
| 623 |
+
|
| 624 |
+
def write_examples_on_file(self):
|
| 625 |
+
"""Write stored examples from the write-pool of examples. It makes a table out of the examples and write it."""
|
| 626 |
+
if not self.current_examples:
|
| 627 |
+
return
|
| 628 |
+
# preserve the order the columns
|
| 629 |
+
if self.schema:
|
| 630 |
+
schema_cols = set(self.schema.names)
|
| 631 |
+
examples_cols = self.current_examples[0][0].keys() # .keys() preserves the order (unlike set)
|
| 632 |
+
common_cols = [col for col in self.schema.names if col in examples_cols]
|
| 633 |
+
extra_cols = [col for col in examples_cols if col not in schema_cols]
|
| 634 |
+
cols = common_cols + extra_cols
|
| 635 |
+
else:
|
| 636 |
+
cols = list(self.current_examples[0][0])
|
| 637 |
+
batch_examples = {}
|
| 638 |
+
for col in cols:
|
| 639 |
+
# We use row[0][col] since current_examples contains (example, key) tuples.
|
| 640 |
+
# Moreover, examples could be Arrow arrays of 1 element.
|
| 641 |
+
# This can happen in `.map()` when we want to re-write the same Arrow data
|
| 642 |
+
if all(isinstance(row[0][col], (pa.Array, pa.ChunkedArray)) for row in self.current_examples):
|
| 643 |
+
arrays = [row[0][col] for row in self.current_examples]
|
| 644 |
+
arrays = [
|
| 645 |
+
chunk
|
| 646 |
+
for array in arrays
|
| 647 |
+
for chunk in (array.chunks if isinstance(array, pa.ChunkedArray) else [array])
|
| 648 |
+
]
|
| 649 |
+
batch_examples[col] = pa.concat_arrays(arrays)
|
| 650 |
+
else:
|
| 651 |
+
batch_examples[col] = [
|
| 652 |
+
row[0][col].to_pylist()[0] if isinstance(row[0][col], (pa.Array, pa.ChunkedArray)) else row[0][col]
|
| 653 |
+
for row in self.current_examples
|
| 654 |
+
]
|
| 655 |
+
self._write_batch(batch_examples=batch_examples)
|
| 656 |
+
self.current_examples = []
|
| 657 |
+
|
| 658 |
+
def write_rows_on_file(self):
|
| 659 |
+
"""Write stored rows from the write-pool of rows. It concatenates the single-row tables and it writes the resulting table."""
|
| 660 |
+
if not self.current_rows:
|
| 661 |
+
return
|
| 662 |
+
table = pa.concat_tables(self.current_rows)
|
| 663 |
+
self._write_table(table)
|
| 664 |
+
self.current_rows = []
|
| 665 |
+
|
| 666 |
+
def write(
|
| 667 |
+
self,
|
| 668 |
+
example: dict[str, Any],
|
| 669 |
+
writer_batch_size: Optional[int] = None,
|
| 670 |
+
):
|
| 671 |
+
"""Add a given (Example,Key) pair to the write-pool of examples which is written to file.
|
| 672 |
+
|
| 673 |
+
Args:
|
| 674 |
+
example: the Example to add.
|
| 675 |
+
"""
|
| 676 |
+
# Store example as a tuple so as to keep the structure of `self.current_examples` uniform
|
| 677 |
+
self.current_examples.append((example, ""))
|
| 678 |
+
|
| 679 |
+
if writer_batch_size is None:
|
| 680 |
+
writer_batch_size = self.writer_batch_size
|
| 681 |
+
if writer_batch_size is not None and len(self.current_examples) >= writer_batch_size:
|
| 682 |
+
self.write_examples_on_file()
|
| 683 |
+
|
| 684 |
+
def write_row(self, row: pa.Table, writer_batch_size: Optional[int] = None):
|
| 685 |
+
"""Add a given single-row Table to the write-pool of rows which is written to file.
|
| 686 |
+
|
| 687 |
+
Args:
|
| 688 |
+
row: the row to add.
|
| 689 |
+
"""
|
| 690 |
+
if len(row) != 1:
|
| 691 |
+
raise ValueError(f"Only single-row pyarrow tables are allowed but got table with {len(row)} rows.")
|
| 692 |
+
self.current_rows.append(row)
|
| 693 |
+
if writer_batch_size is None:
|
| 694 |
+
writer_batch_size = self.writer_batch_size
|
| 695 |
+
if writer_batch_size is not None and len(self.current_rows) >= writer_batch_size:
|
| 696 |
+
self.write_rows_on_file()
|
| 697 |
+
|
| 698 |
+
def write_batch(
|
| 699 |
+
self,
|
| 700 |
+
batch_examples: dict[str, list],
|
| 701 |
+
writer_batch_size: Optional[int] = None,
|
| 702 |
+
try_original_type: Optional[bool] = True,
|
| 703 |
+
):
|
| 704 |
+
"""Write a batch of Example to file.
|
| 705 |
+
Ignores the batch if it appears to be empty,
|
| 706 |
+
preventing a potential schema update of unknown types.
|
| 707 |
+
|
| 708 |
+
Args:
|
| 709 |
+
batch_examples: the batch of examples to add.
|
| 710 |
+
try_original_type: use `try_type` when instantiating OptimizedTypedSequence if `True`, otherwise `try_type = None`.
|
| 711 |
+
"""
|
| 712 |
+
self.write_examples_on_file() # in case there are buffered examples to write first
|
| 713 |
+
self._write_batch(batch_examples, writer_batch_size=writer_batch_size, try_original_type=try_original_type)
|
| 714 |
+
|
| 715 |
+
def _write_batch(
|
| 716 |
+
self,
|
| 717 |
+
batch_examples: dict[str, list],
|
| 718 |
+
writer_batch_size: Optional[int] = None,
|
| 719 |
+
try_original_type: Optional[bool] = True,
|
| 720 |
+
):
|
| 721 |
+
if batch_examples and len(next(iter(batch_examples.values()))) == 0:
|
| 722 |
+
return
|
| 723 |
+
features = None if self.pa_writer is None and self.update_features else self._features
|
| 724 |
+
try_features = self._features if self.pa_writer is None and self.update_features else None
|
| 725 |
+
arrays = []
|
| 726 |
+
inferred_features = Features()
|
| 727 |
+
# preserve the order the columns
|
| 728 |
+
if self.schema:
|
| 729 |
+
schema_cols = set(self.schema.names)
|
| 730 |
+
batch_cols = batch_examples.keys() # .keys() preserves the order (unlike set)
|
| 731 |
+
common_cols = [col for col in self.schema.names if col in batch_cols]
|
| 732 |
+
extra_cols = [col for col in batch_cols if col not in schema_cols]
|
| 733 |
+
cols = common_cols + extra_cols
|
| 734 |
+
else:
|
| 735 |
+
cols = list(batch_examples)
|
| 736 |
+
for col in cols:
|
| 737 |
+
col_values = batch_examples[col]
|
| 738 |
+
col_type = features[col] if features else None
|
| 739 |
+
if isinstance(col_values, (pa.Array, pa.ChunkedArray)):
|
| 740 |
+
array = cast_array_to_feature(col_values, col_type) if col_type is not None else col_values
|
| 741 |
+
arrays.append(array)
|
| 742 |
+
inferred_features[col] = generate_from_arrow_type(col_values.type)
|
| 743 |
+
else:
|
| 744 |
+
col_try_type = (
|
| 745 |
+
try_features[col]
|
| 746 |
+
if try_features is not None and col in try_features and try_original_type
|
| 747 |
+
else None
|
| 748 |
+
)
|
| 749 |
+
typed_sequence = OptimizedTypedSequence(
|
| 750 |
+
col_values, type=col_type, try_type=col_try_type, col=col, on_mixed_types=self.on_mixed_types
|
| 751 |
+
)
|
| 752 |
+
arrays.append(pa.array(typed_sequence))
|
| 753 |
+
inferred_features[col] = typed_sequence.get_inferred_type()
|
| 754 |
+
schema = inferred_features.arrow_schema if self.pa_writer is None else self.schema
|
| 755 |
+
pa_table = pa.Table.from_arrays(arrays, schema=schema)
|
| 756 |
+
self.write_table(pa_table, writer_batch_size)
|
| 757 |
+
|
| 758 |
+
def write_table(self, pa_table: pa.Table, writer_batch_size: Optional[int] = None):
|
| 759 |
+
"""Write a Table to file.
|
| 760 |
+
|
| 761 |
+
Args:
|
| 762 |
+
example: the Table to add.
|
| 763 |
+
"""
|
| 764 |
+
self.write_rows_on_file() # in case there are buffered rows to write first
|
| 765 |
+
self._write_table(pa_table, writer_batch_size=writer_batch_size)
|
| 766 |
+
|
| 767 |
+
def _write_table(self, pa_table: pa.Table, writer_batch_size: Optional[int] = None):
|
| 768 |
+
if writer_batch_size is None:
|
| 769 |
+
writer_batch_size = self.writer_batch_size
|
| 770 |
+
if self.pa_writer is None:
|
| 771 |
+
self._build_writer(inferred_schema=pa_table.schema)
|
| 772 |
+
pa_table = pa_table.combine_chunks()
|
| 773 |
+
pa_table = table_cast(pa_table, self._schema)
|
| 774 |
+
if self.embed_local_files:
|
| 775 |
+
pa_table = embed_table_storage(pa_table, local_files=True, remote_files=False)
|
| 776 |
+
self._num_bytes += pa_table.nbytes
|
| 777 |
+
self._num_examples += pa_table.num_rows
|
| 778 |
+
self.pa_writer.write_table(pa_table, writer_batch_size)
|
| 779 |
+
|
| 780 |
+
def finalize(self, close_stream=True):
|
| 781 |
+
self.write_rows_on_file()
|
| 782 |
+
# In case current_examples < writer_batch_size, but user uses finalize()
|
| 783 |
+
self.write_examples_on_file()
|
| 784 |
+
# If schema is known, infer features even if no examples were written
|
| 785 |
+
if self.pa_writer is None and self.schema:
|
| 786 |
+
self._build_writer(self.schema)
|
| 787 |
+
if self.pa_writer is not None:
|
| 788 |
+
self.pa_writer.close()
|
| 789 |
+
self.pa_writer = None
|
| 790 |
+
if close_stream:
|
| 791 |
+
self.stream.close()
|
| 792 |
+
else:
|
| 793 |
+
if close_stream:
|
| 794 |
+
self.stream.close()
|
| 795 |
+
raise SchemaInferenceError("Please pass `features` or at least one example when writing data")
|
| 796 |
+
logger.debug(
|
| 797 |
+
f"Done writing {self._num_examples} {self.unit} in {self._num_bytes} bytes {self._path if self._path else ''}."
|
| 798 |
+
)
|
| 799 |
+
return self._num_examples, self._num_bytes
|
| 800 |
+
|
| 801 |
+
|
| 802 |
+
class ParquetWriter(ArrowWriter):
|
| 803 |
+
def __init__(self, *args, use_content_defined_chunking=True, write_page_index=True, **kwargs):
|
| 804 |
+
super().__init__(*args, **kwargs)
|
| 805 |
+
if use_content_defined_chunking is True:
|
| 806 |
+
use_content_defined_chunking = config.DEFAULT_CDC_OPTIONS
|
| 807 |
+
self.use_content_defined_chunking = use_content_defined_chunking
|
| 808 |
+
self.write_page_index = write_page_index
|
| 809 |
+
|
| 810 |
+
def _build_writer(self, inferred_schema: pa.Schema):
|
| 811 |
+
self._schema, self._features = self._build_schema(inferred_schema)
|
| 812 |
+
self.pa_writer = pq.ParquetWriter(
|
| 813 |
+
self.stream,
|
| 814 |
+
self._schema,
|
| 815 |
+
use_content_defined_chunking=self.use_content_defined_chunking,
|
| 816 |
+
write_page_index=self.write_page_index,
|
| 817 |
+
compression={
|
| 818 |
+
col: "none" if require_storage_embed(feature) else "snappy" for col, feature in self._features.items()
|
| 819 |
+
},
|
| 820 |
+
use_dictionary=[col for col, feature in self._features.items() if not require_storage_embed(feature)],
|
| 821 |
+
column_encoding={
|
| 822 |
+
col: "PLAIN" for col, feature in self._features.items() if require_storage_embed(feature)
|
| 823 |
+
},
|
| 824 |
+
)
|
| 825 |
+
if self.use_content_defined_chunking is not False:
|
| 826 |
+
self.pa_writer.add_key_value_metadata(
|
| 827 |
+
{"content_defined_chunking": json.dumps(self.use_content_defined_chunking)}
|
| 828 |
+
)
|
venv/Lib/site-packages/datasets/builder.py
ADDED
|
@@ -0,0 +1,1916 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2020 The HuggingFace Datasets Authors and the TensorFlow Datasets Authors.
|
| 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 |
+
# Lint as: python3
|
| 16 |
+
"""DatasetBuilder base class."""
|
| 17 |
+
|
| 18 |
+
import abc
|
| 19 |
+
import contextlib
|
| 20 |
+
import copy
|
| 21 |
+
import inspect
|
| 22 |
+
import os
|
| 23 |
+
import posixpath
|
| 24 |
+
import shutil
|
| 25 |
+
import time
|
| 26 |
+
import urllib
|
| 27 |
+
from collections.abc import Iterator
|
| 28 |
+
from dataclasses import dataclass
|
| 29 |
+
from functools import partial
|
| 30 |
+
from pathlib import Path
|
| 31 |
+
from typing import TYPE_CHECKING, Any, Optional, Union
|
| 32 |
+
from unittest.mock import patch
|
| 33 |
+
|
| 34 |
+
import fsspec
|
| 35 |
+
import pyarrow as pa
|
| 36 |
+
from fsspec.core import url_to_fs
|
| 37 |
+
from multiprocess import Pool
|
| 38 |
+
from tqdm.contrib.concurrent import thread_map
|
| 39 |
+
|
| 40 |
+
from . import config, utils
|
| 41 |
+
from .arrow_dataset import Dataset
|
| 42 |
+
from .arrow_reader import (
|
| 43 |
+
ArrowReader,
|
| 44 |
+
ReadInstruction,
|
| 45 |
+
)
|
| 46 |
+
from .arrow_writer import ArrowWriter, ParquetWriter, SchemaInferenceError
|
| 47 |
+
from .data_files import DataFilesDict, DataFilesPatternsDict, sanitize_patterns
|
| 48 |
+
from .dataset_dict import DatasetDict, IterableDatasetDict
|
| 49 |
+
from .download.download_config import DownloadConfig
|
| 50 |
+
from .download.download_manager import DownloadManager, DownloadMode
|
| 51 |
+
from .download.streaming_download_manager import StreamingDownloadManager, xjoin
|
| 52 |
+
from .exceptions import DatasetGenerationCastError, DatasetGenerationError, FileFormatError
|
| 53 |
+
from .features import Features
|
| 54 |
+
from .filesystems import (
|
| 55 |
+
is_remote_filesystem,
|
| 56 |
+
rename,
|
| 57 |
+
)
|
| 58 |
+
from .fingerprint import Hasher
|
| 59 |
+
from .info import DatasetInfo
|
| 60 |
+
from .iterable_dataset import (
|
| 61 |
+
ArrowExamplesIterable,
|
| 62 |
+
ExamplesIterable,
|
| 63 |
+
IterableDataset,
|
| 64 |
+
_concatenate_iterable_datasets,
|
| 65 |
+
)
|
| 66 |
+
from .naming import INVALID_WINDOWS_CHARACTERS_IN_PATH, camelcase_to_snakecase
|
| 67 |
+
from .splits import Split, SplitDict, SplitGenerator, SplitInfo
|
| 68 |
+
from .streaming import extend_dataset_builder_for_streaming
|
| 69 |
+
from .table import CastError
|
| 70 |
+
from .utils import logging
|
| 71 |
+
from .utils import tqdm as hf_tqdm
|
| 72 |
+
from .utils._filelock import FileLock
|
| 73 |
+
from .utils.file_utils import is_remote_url
|
| 74 |
+
from .utils.info_utils import VerificationMode, verify_checksums, verify_splits
|
| 75 |
+
from .utils.py_utils import (
|
| 76 |
+
classproperty,
|
| 77 |
+
convert_file_size_to_int,
|
| 78 |
+
has_sufficient_disk_space,
|
| 79 |
+
iflatmap_unordered,
|
| 80 |
+
map_nested,
|
| 81 |
+
memoize,
|
| 82 |
+
size_str,
|
| 83 |
+
temporary_assignment,
|
| 84 |
+
)
|
| 85 |
+
from .utils.sharding import _number_of_shards_in_gen_kwargs, _split_gen_kwargs
|
| 86 |
+
from .utils.track import tracked_list
|
| 87 |
+
|
| 88 |
+
|
| 89 |
+
if TYPE_CHECKING:
|
| 90 |
+
from .load import DatasetModule
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
logger = logging.get_logger(__name__)
|
| 94 |
+
|
| 95 |
+
|
| 96 |
+
class InvalidConfigName(ValueError):
|
| 97 |
+
pass
|
| 98 |
+
|
| 99 |
+
|
| 100 |
+
@dataclass
|
| 101 |
+
class BuilderConfig:
|
| 102 |
+
"""Base class for `DatasetBuilder` data configuration.
|
| 103 |
+
|
| 104 |
+
`DatasetBuilder` subclasses with data configuration options should subclass
|
| 105 |
+
`BuilderConfig` and add their own properties.
|
| 106 |
+
|
| 107 |
+
Attributes:
|
| 108 |
+
name (`str`, defaults to `default`):
|
| 109 |
+
The name of the configuration.
|
| 110 |
+
version (`Version` or `str`, defaults to `0.0.0`):
|
| 111 |
+
The version of the configuration.
|
| 112 |
+
data_dir (`str`, *optional*):
|
| 113 |
+
Path to the directory containing the source data.
|
| 114 |
+
data_files (`str` or `Sequence` or `Mapping`, *optional*):
|
| 115 |
+
Path(s) to source data file(s).
|
| 116 |
+
description (`str`, *optional*):
|
| 117 |
+
A human description of the configuration.
|
| 118 |
+
"""
|
| 119 |
+
|
| 120 |
+
name: str = "default"
|
| 121 |
+
version: Optional[Union[utils.Version, str]] = utils.Version("0.0.0")
|
| 122 |
+
data_dir: Optional[str] = None
|
| 123 |
+
data_files: Optional[Union[DataFilesDict, DataFilesPatternsDict]] = None
|
| 124 |
+
description: Optional[str] = None
|
| 125 |
+
|
| 126 |
+
def __post_init__(self):
|
| 127 |
+
# The config name is used to name the cache directory.
|
| 128 |
+
for invalid_char in INVALID_WINDOWS_CHARACTERS_IN_PATH:
|
| 129 |
+
if invalid_char in self.name:
|
| 130 |
+
raise InvalidConfigName(
|
| 131 |
+
f"Bad characters from black list '{INVALID_WINDOWS_CHARACTERS_IN_PATH}' found in '{self.name}'. "
|
| 132 |
+
f"They could create issues when creating a directory for this config on Windows filesystem."
|
| 133 |
+
)
|
| 134 |
+
if self.data_files is not None and not isinstance(self.data_files, (DataFilesDict, DataFilesPatternsDict)):
|
| 135 |
+
raise ValueError(f"Expected a DataFilesDict in data_files but got {self.data_files}")
|
| 136 |
+
|
| 137 |
+
def __eq__(self, o):
|
| 138 |
+
# we need to override the default dataclass __eq__ since it doesn't check for
|
| 139 |
+
# other attributes that the ones of the signature.
|
| 140 |
+
if set(self.__dict__.keys()) != set(o.__dict__.keys()):
|
| 141 |
+
return False
|
| 142 |
+
return all((k, getattr(self, k)) == (k, getattr(o, k)) for k in self.__dict__.keys())
|
| 143 |
+
|
| 144 |
+
def create_config_id(
|
| 145 |
+
self,
|
| 146 |
+
config_kwargs: dict,
|
| 147 |
+
custom_features: Optional[Features] = None,
|
| 148 |
+
) -> str:
|
| 149 |
+
"""
|
| 150 |
+
The config id is used to build the cache directory.
|
| 151 |
+
By default it is equal to the config name.
|
| 152 |
+
However the name of a config is not sufficient to have a unique identifier for the dataset being generated
|
| 153 |
+
since it doesn't take into account:
|
| 154 |
+
- the config kwargs that can be used to overwrite attributes
|
| 155 |
+
- the custom features used to write the dataset
|
| 156 |
+
- the data_files for json/text/csv/pandas datasets
|
| 157 |
+
|
| 158 |
+
Therefore the config id is just the config name with an optional suffix based on these.
|
| 159 |
+
"""
|
| 160 |
+
# Possibly add a suffix to the name to handle custom features/data_files/config_kwargs
|
| 161 |
+
suffix: Optional[str] = None
|
| 162 |
+
config_kwargs_to_add_to_suffix = config_kwargs.copy()
|
| 163 |
+
# name and version are already used to build the cache directory
|
| 164 |
+
config_kwargs_to_add_to_suffix.pop("name", None)
|
| 165 |
+
config_kwargs_to_add_to_suffix.pop("version", None)
|
| 166 |
+
# data dir handling (when specified it points to the manually downloaded data):
|
| 167 |
+
# it was previously ignored before the introduction of config id because we didn't want
|
| 168 |
+
# to change the config name. Now it's fine to take it into account for the config id.
|
| 169 |
+
# config_kwargs_to_add_to_suffix.pop("data_dir", None)
|
| 170 |
+
if "data_dir" in config_kwargs_to_add_to_suffix:
|
| 171 |
+
if config_kwargs_to_add_to_suffix["data_dir"] is None:
|
| 172 |
+
config_kwargs_to_add_to_suffix.pop("data_dir", None)
|
| 173 |
+
else:
|
| 174 |
+
# canonicalize the data dir to avoid two paths to the same location having different
|
| 175 |
+
# hashes
|
| 176 |
+
data_dir = config_kwargs_to_add_to_suffix["data_dir"]
|
| 177 |
+
data_dir = os.path.normpath(data_dir)
|
| 178 |
+
config_kwargs_to_add_to_suffix["data_dir"] = data_dir
|
| 179 |
+
if config_kwargs_to_add_to_suffix:
|
| 180 |
+
# we don't care about the order of the kwargs
|
| 181 |
+
config_kwargs_to_add_to_suffix = {
|
| 182 |
+
k: config_kwargs_to_add_to_suffix[k] for k in sorted(config_kwargs_to_add_to_suffix)
|
| 183 |
+
}
|
| 184 |
+
if all(isinstance(v, (str, bool, int, float)) for v in config_kwargs_to_add_to_suffix.values()):
|
| 185 |
+
suffix = ",".join(
|
| 186 |
+
str(k) + "=" + urllib.parse.quote_plus(str(v)) for k, v in config_kwargs_to_add_to_suffix.items()
|
| 187 |
+
)
|
| 188 |
+
if len(suffix) > 32: # hash if too long
|
| 189 |
+
suffix = Hasher.hash(config_kwargs_to_add_to_suffix)
|
| 190 |
+
else:
|
| 191 |
+
suffix = Hasher.hash(config_kwargs_to_add_to_suffix)
|
| 192 |
+
|
| 193 |
+
if custom_features is not None:
|
| 194 |
+
m = Hasher()
|
| 195 |
+
if suffix:
|
| 196 |
+
m.update(suffix)
|
| 197 |
+
m.update(custom_features)
|
| 198 |
+
suffix = m.hexdigest()
|
| 199 |
+
|
| 200 |
+
if suffix:
|
| 201 |
+
config_id = self.name + "-" + suffix
|
| 202 |
+
if len(config_id) > config.MAX_DATASET_CONFIG_ID_READABLE_LENGTH:
|
| 203 |
+
config_id = self.name + "-" + Hasher.hash(suffix)
|
| 204 |
+
return config_id
|
| 205 |
+
else:
|
| 206 |
+
return self.name
|
| 207 |
+
|
| 208 |
+
def _resolve_data_files(self, base_path: str, download_config: DownloadConfig) -> None:
|
| 209 |
+
if isinstance(self.data_files, DataFilesPatternsDict):
|
| 210 |
+
base_path = xjoin(base_path, self.data_dir) if self.data_dir else base_path
|
| 211 |
+
self.data_files = self.data_files.resolve(base_path, download_config)
|
| 212 |
+
|
| 213 |
+
|
| 214 |
+
class DatasetBuilder:
|
| 215 |
+
"""Abstract base class for all datasets.
|
| 216 |
+
|
| 217 |
+
`DatasetBuilder` has 3 key methods:
|
| 218 |
+
|
| 219 |
+
- [`DatasetBuilder.info`]: Documents the dataset, including feature
|
| 220 |
+
names, types, shapes, version, splits, citation, etc.
|
| 221 |
+
- [`DatasetBuilder.download_and_prepare`]: Downloads the source data
|
| 222 |
+
and writes it to disk.
|
| 223 |
+
- [`DatasetBuilder.as_dataset`]: Generates a [`Dataset`].
|
| 224 |
+
|
| 225 |
+
Some `DatasetBuilder`s expose multiple variants of the
|
| 226 |
+
dataset by defining a [`BuilderConfig`] subclass and accepting a
|
| 227 |
+
config object (or name) on construction. Configurable datasets expose a
|
| 228 |
+
pre-defined set of configurations in [`DatasetBuilder.builder_configs`].
|
| 229 |
+
|
| 230 |
+
Args:
|
| 231 |
+
cache_dir (`str`, *optional*):
|
| 232 |
+
Directory to cache data. Defaults to `"~/.cache/huggingface/datasets"`.
|
| 233 |
+
dataset_name (`str`, *optional*):
|
| 234 |
+
Name of the dataset, if different from the builder name. Useful for packaged builders
|
| 235 |
+
like csv, imagefolder, audiofolder, etc. to reflect the difference between datasets
|
| 236 |
+
that use the same packaged builder.
|
| 237 |
+
config_name (`str`, *optional*):
|
| 238 |
+
Name of the dataset configuration.
|
| 239 |
+
It affects the data generated on disk. Different configurations will have their own subdirectories and
|
| 240 |
+
versions.
|
| 241 |
+
If not provided, the default configuration is used (if it exists).
|
| 242 |
+
|
| 243 |
+
<Added version="2.3.0">
|
| 244 |
+
|
| 245 |
+
Parameter `name` was renamed to `config_name`.
|
| 246 |
+
|
| 247 |
+
</Added>
|
| 248 |
+
hash (`str`, *optional*):
|
| 249 |
+
Hash specific to the dataset builder code. Used to update the caching directory when the
|
| 250 |
+
dataset builder code is updated (to avoid reusing old data).
|
| 251 |
+
The typical caching directory (defined in `self._relative_data_dir`) is `name/version/hash/`.
|
| 252 |
+
base_path (`str`, *optional*):
|
| 253 |
+
Base path for relative paths that are used to download files.
|
| 254 |
+
This can be a remote URL.
|
| 255 |
+
features ([`Features`], *optional*):
|
| 256 |
+
Features types to use with this dataset.
|
| 257 |
+
It can be used to change the [`Features`] types of a dataset, for example.
|
| 258 |
+
token (`str` or `bool`, *optional*):
|
| 259 |
+
String or boolean to use as Bearer token for remote files on the
|
| 260 |
+
Datasets Hub. If `True`, will get token from `"~/.huggingface"`.
|
| 261 |
+
repo_id (`str`, *optional*):
|
| 262 |
+
ID of the dataset repository.
|
| 263 |
+
Used to distinguish builders with the same name but not coming from the same namespace, for example "rajpurkar/squad"
|
| 264 |
+
and "lhoestq/squad" repo IDs. In the latter, the builder name would be "lhoestq___squad".
|
| 265 |
+
data_files (`str` or `Sequence` or `Mapping`, *optional*):
|
| 266 |
+
Path(s) to source data file(s).
|
| 267 |
+
For builders like "csv" or "json" that need the user to specify data files. They can be either
|
| 268 |
+
local or remote files. For convenience, you can use a `DataFilesDict`.
|
| 269 |
+
data_dir (`str`, *optional*):
|
| 270 |
+
Path to directory containing source data file(s).
|
| 271 |
+
Use only if `data_files` is not passed, in which case it is equivalent to passing
|
| 272 |
+
`os.path.join(data_dir, "**")` as `data_files`.
|
| 273 |
+
For builders that require manual download, it must be the path to the local directory containing the
|
| 274 |
+
manually downloaded data.
|
| 275 |
+
storage_options (`dict`, *optional*):
|
| 276 |
+
Key/value pairs to be passed on to the dataset file-system backend, if any.
|
| 277 |
+
writer_batch_size (`int`, *optional*):
|
| 278 |
+
Batch size used by the ArrowWriter.
|
| 279 |
+
It defines the number of samples that are kept in memory before writing them
|
| 280 |
+
and also the length of the arrow chunks.
|
| 281 |
+
None means that the ArrowWriter will use its default value.
|
| 282 |
+
**config_kwargs (additional keyword arguments): Keyword arguments to be passed to the corresponding builder
|
| 283 |
+
configuration class, set on the class attribute [`DatasetBuilder.BUILDER_CONFIG_CLASS`]. The builder
|
| 284 |
+
configuration class is [`BuilderConfig`] or a subclass of it.
|
| 285 |
+
"""
|
| 286 |
+
|
| 287 |
+
# Default version
|
| 288 |
+
VERSION = None # Default version set in BuilderConfig
|
| 289 |
+
|
| 290 |
+
# Class for the builder config.
|
| 291 |
+
BUILDER_CONFIG_CLASS = BuilderConfig
|
| 292 |
+
|
| 293 |
+
# Named configurations that modify the data generated by download_and_prepare.
|
| 294 |
+
BUILDER_CONFIGS = []
|
| 295 |
+
|
| 296 |
+
# Optional default config name to be used when name is None
|
| 297 |
+
DEFAULT_CONFIG_NAME = None
|
| 298 |
+
|
| 299 |
+
# Default batch size used by the ArrowWriter
|
| 300 |
+
# It defines the number of samples that are kept in memory before writing them
|
| 301 |
+
# and also the length of the arrow chunks
|
| 302 |
+
# None means that the ArrowWriter will use its default value
|
| 303 |
+
DEFAULT_WRITER_BATCH_SIZE = None
|
| 304 |
+
|
| 305 |
+
# Useful to make sure PyArrow threads in c++ have time to shut down before gargabe collection
|
| 306 |
+
SLEEP_ON_THREADS_SHUTDOWNS = False
|
| 307 |
+
|
| 308 |
+
def __init__(
|
| 309 |
+
self,
|
| 310 |
+
cache_dir: Optional[str] = None,
|
| 311 |
+
dataset_name: Optional[str] = None,
|
| 312 |
+
config_name: Optional[str] = None,
|
| 313 |
+
hash: Optional[str] = None,
|
| 314 |
+
base_path: Optional[str] = None,
|
| 315 |
+
info: Optional[DatasetInfo] = None,
|
| 316 |
+
features: Optional[Features] = None,
|
| 317 |
+
token: Optional[Union[bool, str]] = None,
|
| 318 |
+
repo_id: Optional[str] = None,
|
| 319 |
+
data_files: Optional[Union[str, list, dict, DataFilesDict]] = None,
|
| 320 |
+
data_dir: Optional[str] = None,
|
| 321 |
+
storage_options: Optional[dict] = None,
|
| 322 |
+
writer_batch_size: Optional[int] = None,
|
| 323 |
+
config_id: Optional[str] = None,
|
| 324 |
+
**config_kwargs,
|
| 325 |
+
):
|
| 326 |
+
# DatasetBuilder name
|
| 327 |
+
self.name: str = camelcase_to_snakecase(self.__module__.split(".")[-1])
|
| 328 |
+
self.hash: Optional[str] = hash
|
| 329 |
+
self.base_path = base_path
|
| 330 |
+
self.token = token
|
| 331 |
+
self.repo_id = repo_id
|
| 332 |
+
self.storage_options = storage_options or {}
|
| 333 |
+
self.dataset_name = camelcase_to_snakecase(dataset_name) if dataset_name else self.name
|
| 334 |
+
self._writer_batch_size = writer_batch_size or self.DEFAULT_WRITER_BATCH_SIZE
|
| 335 |
+
|
| 336 |
+
if data_files is not None and not isinstance(data_files, DataFilesDict):
|
| 337 |
+
data_files = DataFilesDict.from_patterns(
|
| 338 |
+
sanitize_patterns(data_files),
|
| 339 |
+
base_path=base_path,
|
| 340 |
+
download_config=DownloadConfig(token=token, storage_options=self.storage_options),
|
| 341 |
+
)
|
| 342 |
+
|
| 343 |
+
# Prepare config: DatasetConfig contains name, version and description but can be extended by each dataset
|
| 344 |
+
if "features" in inspect.signature(self.BUILDER_CONFIG_CLASS.__init__).parameters and features is not None:
|
| 345 |
+
config_kwargs["features"] = features
|
| 346 |
+
if data_files is not None:
|
| 347 |
+
config_kwargs["data_files"] = data_files
|
| 348 |
+
if data_dir is not None:
|
| 349 |
+
config_kwargs["data_dir"] = data_dir
|
| 350 |
+
self.config_kwargs = config_kwargs
|
| 351 |
+
self.config, self.config_id = self._create_builder_config(
|
| 352 |
+
config_name=config_name,
|
| 353 |
+
custom_features=features,
|
| 354 |
+
config_id=config_id,
|
| 355 |
+
**config_kwargs,
|
| 356 |
+
)
|
| 357 |
+
|
| 358 |
+
# prepare info: DatasetInfo are a standardized dataclass across all datasets
|
| 359 |
+
# Prefill datasetinfo
|
| 360 |
+
if info is None:
|
| 361 |
+
info = self._info()
|
| 362 |
+
info.builder_name = self.name
|
| 363 |
+
info.dataset_name = self.dataset_name
|
| 364 |
+
info.config_name = self.config.name
|
| 365 |
+
info.version = self.config.version
|
| 366 |
+
self.info = info
|
| 367 |
+
# update info with user specified infos
|
| 368 |
+
if features is not None:
|
| 369 |
+
self.info.features = features
|
| 370 |
+
|
| 371 |
+
# Prepare data dirs:
|
| 372 |
+
# cache_dir can be a remote bucket on GCS or S3
|
| 373 |
+
self._cache_dir_root = str(cache_dir or config.HF_DATASETS_CACHE)
|
| 374 |
+
self._cache_dir_root = (
|
| 375 |
+
self._cache_dir_root if is_remote_url(self._cache_dir_root) else os.path.expanduser(self._cache_dir_root)
|
| 376 |
+
)
|
| 377 |
+
self._cache_downloaded_dir = (
|
| 378 |
+
posixpath.join(self._cache_dir_root, config.DOWNLOADED_DATASETS_DIR)
|
| 379 |
+
if cache_dir
|
| 380 |
+
else str(config.DOWNLOADED_DATASETS_PATH)
|
| 381 |
+
)
|
| 382 |
+
self._cache_downloaded_dir = (
|
| 383 |
+
self._cache_downloaded_dir
|
| 384 |
+
if is_remote_url(self._cache_downloaded_dir)
|
| 385 |
+
else os.path.expanduser(self._cache_downloaded_dir)
|
| 386 |
+
)
|
| 387 |
+
|
| 388 |
+
# In case there exists a legacy cache directory
|
| 389 |
+
self._legacy_relative_data_dir = None
|
| 390 |
+
|
| 391 |
+
self._cache_dir = self._build_cache_dir()
|
| 392 |
+
if not is_remote_url(self._cache_dir_root):
|
| 393 |
+
os.makedirs(self._cache_dir_root, exist_ok=True)
|
| 394 |
+
lock_path = os.path.join(
|
| 395 |
+
self._cache_dir_root, Path(self._cache_dir).as_posix().replace("/", "_") + ".lock"
|
| 396 |
+
)
|
| 397 |
+
with FileLock(lock_path):
|
| 398 |
+
if os.path.exists(self._cache_dir): # check if data exist
|
| 399 |
+
if len(os.listdir(self._cache_dir)) > 0:
|
| 400 |
+
if os.path.exists(os.path.join(self._cache_dir, config.DATASET_INFO_FILENAME)):
|
| 401 |
+
logger.debug("Overwrite dataset info from restored data version if exists.")
|
| 402 |
+
self.info = DatasetInfo.from_directory(self._cache_dir)
|
| 403 |
+
else: # dir exists but no data, remove the empty dir as data aren't available anymore
|
| 404 |
+
logger.warning(
|
| 405 |
+
f"Old caching folder {self._cache_dir} for dataset {self.dataset_name} exists but no data were found. Removing it. "
|
| 406 |
+
)
|
| 407 |
+
os.rmdir(self._cache_dir)
|
| 408 |
+
|
| 409 |
+
# Store in the cache by default unless the user specifies a custom output_dir to download_and_prepare
|
| 410 |
+
self._output_dir = self._cache_dir
|
| 411 |
+
self._fs: fsspec.AbstractFileSystem = fsspec.filesystem("file")
|
| 412 |
+
|
| 413 |
+
# Set download manager
|
| 414 |
+
self.dl_manager = None
|
| 415 |
+
|
| 416 |
+
# Set to True by "datasets-cli test" to generate file checksums for (deprecated) dataset_infos.json independently of verification_mode value.
|
| 417 |
+
self._record_checksums = False
|
| 418 |
+
|
| 419 |
+
# Set in `.download_and_prepare` once the format of the generated dataset is known
|
| 420 |
+
self._file_format = None
|
| 421 |
+
|
| 422 |
+
# Enable streaming (e.g. it patches "open" to work with remote files)
|
| 423 |
+
extend_dataset_builder_for_streaming(self)
|
| 424 |
+
|
| 425 |
+
def __getstate__(self):
|
| 426 |
+
return self.__dict__
|
| 427 |
+
|
| 428 |
+
def __setstate__(self, d):
|
| 429 |
+
self.__dict__ = d
|
| 430 |
+
# Re-enable streaming, since patched functions are not kept when pickling
|
| 431 |
+
extend_dataset_builder_for_streaming(self)
|
| 432 |
+
|
| 433 |
+
def _check_legacy_cache(self) -> Optional[str]:
|
| 434 |
+
"""Check for the old cache directory template {cache_dir}/{namespace}___{builder_name} from 2.13"""
|
| 435 |
+
if (
|
| 436 |
+
self.__module__.startswith("datasets.")
|
| 437 |
+
and not is_remote_url(self._cache_dir_root)
|
| 438 |
+
and self.config.name == "default"
|
| 439 |
+
):
|
| 440 |
+
from .packaged_modules import _PACKAGED_DATASETS_MODULES
|
| 441 |
+
|
| 442 |
+
namespace = self.repo_id.split("/")[0] if self.repo_id and self.repo_id.count("/") > 0 else None
|
| 443 |
+
config_name = self.repo_id.replace("/", "--") if self.repo_id is not None else self.dataset_name
|
| 444 |
+
config_id = config_name + self.config_id[len(self.config.name) :]
|
| 445 |
+
hash = _PACKAGED_DATASETS_MODULES.get(self.name, "missing")[1]
|
| 446 |
+
legacy_relative_data_dir = posixpath.join(
|
| 447 |
+
self.dataset_name if namespace is None else f"{namespace}___{self.dataset_name}",
|
| 448 |
+
config_id,
|
| 449 |
+
"0.0.0",
|
| 450 |
+
hash,
|
| 451 |
+
)
|
| 452 |
+
legacy_cache_dir = posixpath.join(self._cache_dir_root, legacy_relative_data_dir)
|
| 453 |
+
if os.path.isdir(legacy_cache_dir):
|
| 454 |
+
return legacy_relative_data_dir
|
| 455 |
+
|
| 456 |
+
def _check_legacy_cache2(self, dataset_module: "DatasetModule") -> Optional[str]:
|
| 457 |
+
"""Check for the old cache directory template {cache_dir}/{namespace}___{dataset_name}/{config_name}-xxx from 2.14 and 2.15"""
|
| 458 |
+
if (
|
| 459 |
+
self.__module__.startswith("datasets.")
|
| 460 |
+
and not is_remote_url(self._cache_dir_root)
|
| 461 |
+
and not (set(self.config_kwargs) - {"data_files", "data_dir"})
|
| 462 |
+
):
|
| 463 |
+
from .packaged_modules import _PACKAGED_DATASETS_MODULES_2_15_HASHES
|
| 464 |
+
from .utils._dill import Pickler
|
| 465 |
+
|
| 466 |
+
def update_hash_with_config_parameters(hash: str, config_parameters: dict) -> str:
|
| 467 |
+
"""
|
| 468 |
+
Used to update hash of packaged modules which is used for creating unique cache directories to reflect
|
| 469 |
+
different config parameters which are passed in metadata from readme.
|
| 470 |
+
"""
|
| 471 |
+
params_to_exclude = {"config_name", "version", "description"}
|
| 472 |
+
params_to_add_to_hash = {
|
| 473 |
+
param: value
|
| 474 |
+
for param, value in sorted(config_parameters.items())
|
| 475 |
+
if param not in params_to_exclude
|
| 476 |
+
}
|
| 477 |
+
m = Hasher()
|
| 478 |
+
m.update(hash)
|
| 479 |
+
m.update(params_to_add_to_hash)
|
| 480 |
+
return m.hexdigest()
|
| 481 |
+
|
| 482 |
+
namespace = self.repo_id.split("/")[0] if self.repo_id and self.repo_id.count("/") > 0 else None
|
| 483 |
+
with patch.object(Pickler, "_legacy_no_dict_keys_sorting", True):
|
| 484 |
+
config_id = self.config.name + "-" + Hasher.hash({"data_files": self.config.data_files})
|
| 485 |
+
hash = _PACKAGED_DATASETS_MODULES_2_15_HASHES.get(self.name, "missing")
|
| 486 |
+
if (
|
| 487 |
+
dataset_module.builder_configs_parameters.metadata_configs
|
| 488 |
+
and self.config.name in dataset_module.builder_configs_parameters.metadata_configs
|
| 489 |
+
):
|
| 490 |
+
hash = update_hash_with_config_parameters(
|
| 491 |
+
hash, dataset_module.builder_configs_parameters.metadata_configs[self.config.name]
|
| 492 |
+
)
|
| 493 |
+
legacy_relative_data_dir = posixpath.join(
|
| 494 |
+
self.dataset_name if namespace is None else f"{namespace}___{self.dataset_name}",
|
| 495 |
+
config_id,
|
| 496 |
+
"0.0.0",
|
| 497 |
+
hash,
|
| 498 |
+
)
|
| 499 |
+
legacy_cache_dir = posixpath.join(self._cache_dir_root, legacy_relative_data_dir)
|
| 500 |
+
if os.path.isdir(legacy_cache_dir):
|
| 501 |
+
return legacy_relative_data_dir
|
| 502 |
+
|
| 503 |
+
def _create_builder_config(
|
| 504 |
+
self, config_name=None, custom_features=None, config_id=None, **config_kwargs
|
| 505 |
+
) -> tuple[BuilderConfig, str]:
|
| 506 |
+
"""Create and validate BuilderConfig object as well as a unique config id for this config.
|
| 507 |
+
Raises ValueError if there are multiple builder configs and config_name and DEFAULT_CONFIG_NAME are None.
|
| 508 |
+
config_kwargs override the defaults kwargs in config
|
| 509 |
+
"""
|
| 510 |
+
builder_config = None
|
| 511 |
+
|
| 512 |
+
# try default config
|
| 513 |
+
if config_name is None and self.BUILDER_CONFIGS:
|
| 514 |
+
if self.DEFAULT_CONFIG_NAME is not None:
|
| 515 |
+
builder_config = self.builder_configs.get(self.DEFAULT_CONFIG_NAME)
|
| 516 |
+
logger.info(f"No config specified, defaulting to: {self.dataset_name}/{builder_config.name}")
|
| 517 |
+
else:
|
| 518 |
+
if len(self.BUILDER_CONFIGS) > 1:
|
| 519 |
+
if not config_kwargs:
|
| 520 |
+
example_of_usage = (
|
| 521 |
+
f"load_dataset('{self.repo_id or self.dataset_name}', '{self.BUILDER_CONFIGS[0].name}')"
|
| 522 |
+
)
|
| 523 |
+
raise ValueError(
|
| 524 |
+
"Config name is missing."
|
| 525 |
+
f"\nPlease pick one among the available configs: {list(self.builder_configs.keys())}"
|
| 526 |
+
+ f"\nExample of usage:\n\t`{example_of_usage}`"
|
| 527 |
+
)
|
| 528 |
+
else:
|
| 529 |
+
builder_config = self.BUILDER_CONFIGS[0]
|
| 530 |
+
logger.info(
|
| 531 |
+
f"No config specified, defaulting to the single config: {self.dataset_name}/{builder_config.name}"
|
| 532 |
+
)
|
| 533 |
+
|
| 534 |
+
# try to get config by name
|
| 535 |
+
if isinstance(config_name, str):
|
| 536 |
+
builder_config = self.builder_configs.get(config_name)
|
| 537 |
+
if builder_config is None and self.BUILDER_CONFIGS:
|
| 538 |
+
raise ValueError(
|
| 539 |
+
f"BuilderConfig '{config_name}' not found. Available: {list(self.builder_configs.keys())}"
|
| 540 |
+
)
|
| 541 |
+
|
| 542 |
+
# if not using an existing config, then create a new config on the fly
|
| 543 |
+
if not builder_config:
|
| 544 |
+
if config_name is not None:
|
| 545 |
+
config_kwargs["name"] = config_name
|
| 546 |
+
elif self.DEFAULT_CONFIG_NAME and not config_kwargs:
|
| 547 |
+
# Use DEFAULT_CONFIG_NAME only if no config_kwargs are passed
|
| 548 |
+
config_kwargs["name"] = self.DEFAULT_CONFIG_NAME
|
| 549 |
+
if "version" not in config_kwargs and hasattr(self, "VERSION") and self.VERSION:
|
| 550 |
+
config_kwargs["version"] = self.VERSION
|
| 551 |
+
builder_config = self.BUILDER_CONFIG_CLASS(**config_kwargs)
|
| 552 |
+
|
| 553 |
+
# otherwise use the config_kwargs to overwrite the attributes
|
| 554 |
+
else:
|
| 555 |
+
builder_config = copy.deepcopy(builder_config) if config_kwargs else builder_config
|
| 556 |
+
for key, value in config_kwargs.items():
|
| 557 |
+
if value is not None:
|
| 558 |
+
if not hasattr(builder_config, key):
|
| 559 |
+
raise ValueError(f"BuilderConfig {builder_config} doesn't have a '{key}' key.")
|
| 560 |
+
setattr(builder_config, key, value)
|
| 561 |
+
|
| 562 |
+
if not builder_config.name:
|
| 563 |
+
raise ValueError(f"BuilderConfig must have a name, got {builder_config.name}")
|
| 564 |
+
|
| 565 |
+
# resolve data files if needed
|
| 566 |
+
builder_config._resolve_data_files(
|
| 567 |
+
base_path=self.base_path,
|
| 568 |
+
download_config=DownloadConfig(token=self.token, storage_options=self.storage_options),
|
| 569 |
+
)
|
| 570 |
+
|
| 571 |
+
# compute the config id that is going to be used for caching
|
| 572 |
+
if config_id is None:
|
| 573 |
+
config_id = builder_config.create_config_id(
|
| 574 |
+
config_kwargs,
|
| 575 |
+
custom_features=custom_features,
|
| 576 |
+
)
|
| 577 |
+
is_custom = (config_id not in self.builder_configs) and config_id != "default"
|
| 578 |
+
if is_custom:
|
| 579 |
+
logger.info(f"Using custom data configuration {config_id}")
|
| 580 |
+
else:
|
| 581 |
+
if (
|
| 582 |
+
builder_config.name in self.builder_configs
|
| 583 |
+
and builder_config != self.builder_configs[builder_config.name]
|
| 584 |
+
):
|
| 585 |
+
raise ValueError(
|
| 586 |
+
"Cannot name a custom BuilderConfig the same as an available "
|
| 587 |
+
f"BuilderConfig. Change the name. Available BuilderConfigs: {list(self.builder_configs.keys())}"
|
| 588 |
+
)
|
| 589 |
+
if not builder_config.version:
|
| 590 |
+
raise ValueError(f"BuilderConfig {builder_config.name} must have a version")
|
| 591 |
+
|
| 592 |
+
return builder_config, config_id
|
| 593 |
+
|
| 594 |
+
@classproperty
|
| 595 |
+
@classmethod
|
| 596 |
+
@memoize()
|
| 597 |
+
def builder_configs(cls) -> dict[str, BuilderConfig]:
|
| 598 |
+
"""Dictionary of pre-defined configurations for this builder class."""
|
| 599 |
+
configs = {config.name: config for config in cls.BUILDER_CONFIGS}
|
| 600 |
+
if len(configs) != len(cls.BUILDER_CONFIGS):
|
| 601 |
+
names = [config.name for config in cls.BUILDER_CONFIGS]
|
| 602 |
+
raise ValueError(f"Names in BUILDER_CONFIGS must not be duplicated. Got {names}")
|
| 603 |
+
return configs
|
| 604 |
+
|
| 605 |
+
@property
|
| 606 |
+
def cache_dir(self):
|
| 607 |
+
return self._cache_dir
|
| 608 |
+
|
| 609 |
+
def _use_legacy_cache_dir_if_possible(self, dataset_module: "DatasetModule"):
|
| 610 |
+
# Check for the legacy cache directory template (datasets<3.0.0)
|
| 611 |
+
self._legacy_relative_data_dir = (
|
| 612 |
+
self._check_legacy_cache2(dataset_module) or self._check_legacy_cache() or None
|
| 613 |
+
)
|
| 614 |
+
self._cache_dir = self._build_cache_dir()
|
| 615 |
+
self._output_dir = self._cache_dir
|
| 616 |
+
|
| 617 |
+
def _relative_data_dir(self, with_version=True, with_hash=True) -> str:
|
| 618 |
+
"""Relative path of this dataset in cache_dir:
|
| 619 |
+
Will be:
|
| 620 |
+
self.dataset_name/self.config.version/self.hash/
|
| 621 |
+
or if a repo_id with a namespace has been specified:
|
| 622 |
+
self.namespace___self.dataset_name/self.config.version/self.hash/
|
| 623 |
+
If any of these element is missing or if ``with_version=False`` the corresponding subfolders are dropped.
|
| 624 |
+
"""
|
| 625 |
+
if self._legacy_relative_data_dir is not None and with_version and with_hash:
|
| 626 |
+
return self._legacy_relative_data_dir
|
| 627 |
+
|
| 628 |
+
namespace = self.repo_id.split("/")[0] if self.repo_id and self.repo_id.count("/") > 0 else None
|
| 629 |
+
builder_data_dir = self.dataset_name if namespace is None else f"{namespace}___{self.dataset_name}"
|
| 630 |
+
builder_data_dir = posixpath.join(builder_data_dir, self.config_id)
|
| 631 |
+
if with_version:
|
| 632 |
+
builder_data_dir = posixpath.join(builder_data_dir, str(self.config.version))
|
| 633 |
+
if with_hash and self.hash and isinstance(self.hash, str):
|
| 634 |
+
builder_data_dir = posixpath.join(builder_data_dir, self.hash)
|
| 635 |
+
return builder_data_dir
|
| 636 |
+
|
| 637 |
+
def _build_cache_dir(self):
|
| 638 |
+
"""Return the data directory for the current version."""
|
| 639 |
+
builder_data_dir = posixpath.join(self._cache_dir_root, self._relative_data_dir(with_version=False))
|
| 640 |
+
version_data_dir = posixpath.join(self._cache_dir_root, self._relative_data_dir(with_version=True))
|
| 641 |
+
|
| 642 |
+
def _other_versions_on_disk():
|
| 643 |
+
"""Returns previous versions on disk."""
|
| 644 |
+
if not os.path.exists(builder_data_dir):
|
| 645 |
+
return []
|
| 646 |
+
|
| 647 |
+
version_dirnames = []
|
| 648 |
+
for dir_name in os.listdir(builder_data_dir):
|
| 649 |
+
try:
|
| 650 |
+
version_dirnames.append((utils.Version(dir_name), dir_name))
|
| 651 |
+
except ValueError: # Invalid version (ex: incomplete data dir)
|
| 652 |
+
pass
|
| 653 |
+
version_dirnames.sort(reverse=True)
|
| 654 |
+
return version_dirnames
|
| 655 |
+
|
| 656 |
+
# Check and warn if other versions exist
|
| 657 |
+
if not is_remote_url(builder_data_dir):
|
| 658 |
+
version_dirs = _other_versions_on_disk()
|
| 659 |
+
if version_dirs:
|
| 660 |
+
other_version = version_dirs[0][0]
|
| 661 |
+
if other_version != self.config.version:
|
| 662 |
+
warn_msg = (
|
| 663 |
+
f"Found a different version {str(other_version)} of dataset {self.dataset_name} in "
|
| 664 |
+
f"cache_dir {self._cache_dir_root}. Using currently defined version "
|
| 665 |
+
f"{str(self.config.version)}."
|
| 666 |
+
)
|
| 667 |
+
logger.warning(warn_msg)
|
| 668 |
+
|
| 669 |
+
return version_data_dir
|
| 670 |
+
|
| 671 |
+
@abc.abstractmethod
|
| 672 |
+
def _info(self) -> DatasetInfo:
|
| 673 |
+
"""Construct the DatasetInfo object. See `DatasetInfo` for details.
|
| 674 |
+
|
| 675 |
+
Warning: This function is only called once and the result is cached for all
|
| 676 |
+
following .info() calls.
|
| 677 |
+
|
| 678 |
+
Returns:
|
| 679 |
+
info: (DatasetInfo) The dataset information
|
| 680 |
+
"""
|
| 681 |
+
raise NotImplementedError
|
| 682 |
+
|
| 683 |
+
@classmethod
|
| 684 |
+
def get_imported_module_dir(cls):
|
| 685 |
+
"""Return the path of the module of this class or subclass."""
|
| 686 |
+
return os.path.dirname(inspect.getfile(inspect.getmodule(cls)))
|
| 687 |
+
|
| 688 |
+
def _rename(self, src: str, dst: str):
|
| 689 |
+
rename(self._fs, src, dst)
|
| 690 |
+
|
| 691 |
+
def download_and_prepare(
|
| 692 |
+
self,
|
| 693 |
+
output_dir: Optional[str] = None,
|
| 694 |
+
download_config: Optional[DownloadConfig] = None,
|
| 695 |
+
download_mode: Optional[Union[DownloadMode, str]] = None,
|
| 696 |
+
verification_mode: Optional[Union[VerificationMode, str]] = None,
|
| 697 |
+
dl_manager: Optional[DownloadManager] = None,
|
| 698 |
+
base_path: Optional[str] = None,
|
| 699 |
+
file_format: str = "arrow",
|
| 700 |
+
max_shard_size: Optional[Union[int, str]] = None,
|
| 701 |
+
num_proc: Optional[int] = None,
|
| 702 |
+
storage_options: Optional[dict] = None,
|
| 703 |
+
**download_and_prepare_kwargs,
|
| 704 |
+
):
|
| 705 |
+
"""Downloads and prepares dataset for reading.
|
| 706 |
+
|
| 707 |
+
Args:
|
| 708 |
+
output_dir (`str`, *optional*):
|
| 709 |
+
Output directory for the dataset.
|
| 710 |
+
Default to this builder's `cache_dir`, which is inside `~/.cache/huggingface/datasets` by default.
|
| 711 |
+
|
| 712 |
+
<Added version="2.5.0"/>
|
| 713 |
+
download_config (`DownloadConfig`, *optional*):
|
| 714 |
+
Specific download configuration parameters.
|
| 715 |
+
download_mode ([`DownloadMode`] or `str`, *optional*):
|
| 716 |
+
Select the download/generate mode, default to `REUSE_DATASET_IF_EXISTS`.
|
| 717 |
+
verification_mode ([`VerificationMode`] or `str`, defaults to `BASIC_CHECKS`):
|
| 718 |
+
Verification mode determining the checks to run on the downloaded/processed dataset information (checksums/size/splits/...).
|
| 719 |
+
|
| 720 |
+
<Added version="2.9.1"/>
|
| 721 |
+
dl_manager (`DownloadManager`, *optional*):
|
| 722 |
+
Specific `DownloadManger` to use.
|
| 723 |
+
base_path (`str`, *optional*):
|
| 724 |
+
Base path for relative paths that are used to download files. This can be a remote url.
|
| 725 |
+
If not specified, the value of the `base_path` attribute (`self.base_path`) will be used instead.
|
| 726 |
+
file_format (`str`, *optional*):
|
| 727 |
+
Format of the data files in which the dataset will be written.
|
| 728 |
+
Supported formats: "arrow", "parquet". Default to "arrow" format.
|
| 729 |
+
If the format is "parquet", then image and audio data are embedded into the Parquet files instead of pointing to local files.
|
| 730 |
+
|
| 731 |
+
<Added version="2.5.0"/>
|
| 732 |
+
max_shard_size (`Union[str, int]`, *optional*):
|
| 733 |
+
Maximum number of bytes written per shard, default is "500MB".
|
| 734 |
+
The size is based on uncompressed data size, so in practice your shard files may be smaller than
|
| 735 |
+
`max_shard_size` thanks to Parquet compression for example.
|
| 736 |
+
|
| 737 |
+
<Added version="2.5.0"/>
|
| 738 |
+
num_proc (`int`, *optional*, defaults to `None`):
|
| 739 |
+
Number of processes when downloading and generating the dataset locally.
|
| 740 |
+
Multiprocessing is disabled by default.
|
| 741 |
+
|
| 742 |
+
<Added version="2.7.0"/>
|
| 743 |
+
storage_options (`dict`, *optional*):
|
| 744 |
+
Key/value pairs to be passed on to the caching file-system backend, if any.
|
| 745 |
+
|
| 746 |
+
<Added version="2.5.0"/>
|
| 747 |
+
**download_and_prepare_kwargs (additional keyword arguments): Keyword arguments.
|
| 748 |
+
|
| 749 |
+
Example:
|
| 750 |
+
|
| 751 |
+
Download and prepare the dataset as Arrow files that can be loaded as a Dataset using `builder.as_dataset()`:
|
| 752 |
+
|
| 753 |
+
```py
|
| 754 |
+
>>> from datasets import load_dataset_builder
|
| 755 |
+
>>> builder = load_dataset_builder("cornell-movie-review-data/rotten_tomatoes")
|
| 756 |
+
>>> builder.download_and_prepare()
|
| 757 |
+
```
|
| 758 |
+
|
| 759 |
+
Download and prepare the dataset as sharded Parquet files locally:
|
| 760 |
+
|
| 761 |
+
```py
|
| 762 |
+
>>> from datasets import load_dataset_builder
|
| 763 |
+
>>> builder = load_dataset_builder("cornell-movie-review-data/rotten_tomatoes")
|
| 764 |
+
>>> builder.download_and_prepare("./output_dir", file_format="parquet")
|
| 765 |
+
```
|
| 766 |
+
|
| 767 |
+
Download and prepare the dataset as sharded Parquet files in a cloud storage:
|
| 768 |
+
|
| 769 |
+
```py
|
| 770 |
+
>>> from datasets import load_dataset_builder
|
| 771 |
+
>>> storage_options = {"key": aws_access_key_id, "secret": aws_secret_access_key}
|
| 772 |
+
>>> builder = load_dataset_builder("cornell-movie-review-data/rotten_tomatoes")
|
| 773 |
+
>>> builder.download_and_prepare("s3://my-bucket/my_rotten_tomatoes", storage_options=storage_options, file_format="parquet")
|
| 774 |
+
```
|
| 775 |
+
"""
|
| 776 |
+
output_dir = output_dir if output_dir is not None else self._cache_dir
|
| 777 |
+
# output_dir can be a remote bucket on GCS or S3
|
| 778 |
+
fs, output_dir = url_to_fs(output_dir, **(storage_options or {}))
|
| 779 |
+
self._fs = fs
|
| 780 |
+
self._output_dir = output_dir if not is_remote_filesystem(self._fs) else self._fs.unstrip_protocol(output_dir)
|
| 781 |
+
|
| 782 |
+
download_mode = DownloadMode(download_mode or DownloadMode.REUSE_DATASET_IF_EXISTS)
|
| 783 |
+
verification_mode = VerificationMode(verification_mode or VerificationMode.BASIC_CHECKS)
|
| 784 |
+
base_path = base_path if base_path is not None else self.base_path
|
| 785 |
+
|
| 786 |
+
if file_format is not None and file_format not in ["arrow", "parquet"]:
|
| 787 |
+
raise ValueError(f"Unsupported file_format: {file_format}. Expected 'arrow' or 'parquet'")
|
| 788 |
+
self._file_format = file_format
|
| 789 |
+
|
| 790 |
+
if self._fs._strip_protocol(self._output_dir) == "":
|
| 791 |
+
# We don't support the root directory, because it has no dirname,
|
| 792 |
+
# and we need a dirname to use a <dirname>.incomplete directory
|
| 793 |
+
# when the dataset is being written
|
| 794 |
+
raise RuntimeError(
|
| 795 |
+
f"Unable to download and prepare the dataset at the root {self._output_dir}. "
|
| 796 |
+
f"Please specify a subdirectory, e.g. '{self._output_dir + self.dataset_name}'"
|
| 797 |
+
)
|
| 798 |
+
|
| 799 |
+
if dl_manager is None:
|
| 800 |
+
if download_config is None:
|
| 801 |
+
download_config = DownloadConfig(
|
| 802 |
+
cache_dir=self._cache_downloaded_dir,
|
| 803 |
+
force_download=download_mode == DownloadMode.FORCE_REDOWNLOAD,
|
| 804 |
+
force_extract=download_mode == DownloadMode.FORCE_REDOWNLOAD,
|
| 805 |
+
use_etag=False,
|
| 806 |
+
num_proc=num_proc,
|
| 807 |
+
token=self.token,
|
| 808 |
+
storage_options=self.storage_options,
|
| 809 |
+
) # We don't use etag for data files to speed up the process
|
| 810 |
+
|
| 811 |
+
dl_manager = DownloadManager(
|
| 812 |
+
dataset_name=self.dataset_name,
|
| 813 |
+
download_config=download_config,
|
| 814 |
+
data_dir=self.config.data_dir,
|
| 815 |
+
base_path=base_path,
|
| 816 |
+
record_checksums=self._record_checksums,
|
| 817 |
+
)
|
| 818 |
+
|
| 819 |
+
is_local = not is_remote_filesystem(self._fs)
|
| 820 |
+
self.dl_manager = dl_manager
|
| 821 |
+
|
| 822 |
+
# Prevent parallel local disk operations
|
| 823 |
+
if is_local:
|
| 824 |
+
# Create parent directory of the output_dir to put the lock file in there
|
| 825 |
+
Path(self._output_dir).parent.mkdir(parents=True, exist_ok=True)
|
| 826 |
+
lock_path = self._output_dir + "_builder.lock"
|
| 827 |
+
|
| 828 |
+
# File locking only with local paths; no file locking on GCS or S3
|
| 829 |
+
with FileLock(lock_path) if is_local else contextlib.nullcontext():
|
| 830 |
+
# Check if the data already exists
|
| 831 |
+
data_exists = self._fs.exists(posixpath.join(self._output_dir, config.DATASET_INFO_FILENAME))
|
| 832 |
+
if data_exists and download_mode == DownloadMode.REUSE_DATASET_IF_EXISTS:
|
| 833 |
+
logger.info(f"Found cached dataset {self.dataset_name} ({self._output_dir})")
|
| 834 |
+
# We need to update the info in case some splits were added in the meantime
|
| 835 |
+
# for example when calling load_dataset from multiple workers.
|
| 836 |
+
self.info = self._load_info()
|
| 837 |
+
return
|
| 838 |
+
|
| 839 |
+
logger.info(f"Generating dataset {self.dataset_name} ({self._output_dir})")
|
| 840 |
+
if is_local: # if cache dir is local, check for available space
|
| 841 |
+
if not has_sufficient_disk_space(
|
| 842 |
+
self.info.size_in_bytes or 0, directory=Path(self._output_dir).parent
|
| 843 |
+
):
|
| 844 |
+
raise OSError(
|
| 845 |
+
f"Not enough disk space. Needed: {size_str(self.info.size_in_bytes or 0)} (download: {size_str(self.info.download_size or 0)}, generated: {size_str(self.info.dataset_size or 0)}"
|
| 846 |
+
)
|
| 847 |
+
|
| 848 |
+
@contextlib.contextmanager
|
| 849 |
+
def incomplete_dir(dirname):
|
| 850 |
+
"""Create temporary dir for dirname and rename on exit."""
|
| 851 |
+
if not is_local:
|
| 852 |
+
self._fs.makedirs(dirname, exist_ok=True)
|
| 853 |
+
yield dirname
|
| 854 |
+
else:
|
| 855 |
+
tmp_dir = dirname + ".incomplete"
|
| 856 |
+
os.makedirs(tmp_dir, exist_ok=True)
|
| 857 |
+
try:
|
| 858 |
+
yield tmp_dir
|
| 859 |
+
if os.path.isdir(dirname):
|
| 860 |
+
shutil.rmtree(dirname)
|
| 861 |
+
# LocalFileSystem.mv does copy + rm, it is more efficient to simply rename a local directory
|
| 862 |
+
shutil.move(tmp_dir, dirname)
|
| 863 |
+
finally:
|
| 864 |
+
if os.path.exists(tmp_dir):
|
| 865 |
+
shutil.rmtree(tmp_dir)
|
| 866 |
+
|
| 867 |
+
# Print is intentional: we want this to always go to stdout so user has
|
| 868 |
+
# information needed to cancel download/preparation if needed.
|
| 869 |
+
# This comes right before the progress bar.
|
| 870 |
+
if self.info.size_in_bytes:
|
| 871 |
+
logger.info(
|
| 872 |
+
f"Downloading and preparing dataset {self.dataset_name}/{self.config.name} "
|
| 873 |
+
f"(download: {size_str(self.info.download_size)}, generated: {size_str(self.info.dataset_size)}, "
|
| 874 |
+
f"total: {size_str(self.info.size_in_bytes)}) to {self._output_dir}..."
|
| 875 |
+
)
|
| 876 |
+
else:
|
| 877 |
+
_dest = self._fs._strip_protocol(self._output_dir) if is_local else self._output_dir
|
| 878 |
+
logger.info(f"Downloading and preparing dataset {self.dataset_name}/{self.config.name} to {_dest}...")
|
| 879 |
+
|
| 880 |
+
# Create a tmp dir and rename to self._output_dir on successful exit.
|
| 881 |
+
with incomplete_dir(self._output_dir) as tmp_output_dir:
|
| 882 |
+
# Temporarily assign _output_dir to tmp_data_dir to avoid having to forward
|
| 883 |
+
# it to every sub function.
|
| 884 |
+
with temporary_assignment(self, "_output_dir", tmp_output_dir):
|
| 885 |
+
prepare_split_kwargs = {"file_format": file_format}
|
| 886 |
+
if max_shard_size is not None:
|
| 887 |
+
prepare_split_kwargs["max_shard_size"] = max_shard_size
|
| 888 |
+
if num_proc is not None:
|
| 889 |
+
prepare_split_kwargs["num_proc"] = num_proc
|
| 890 |
+
self._download_and_prepare(
|
| 891 |
+
dl_manager=dl_manager,
|
| 892 |
+
verification_mode=verification_mode,
|
| 893 |
+
**prepare_split_kwargs,
|
| 894 |
+
**download_and_prepare_kwargs,
|
| 895 |
+
)
|
| 896 |
+
# Sync info
|
| 897 |
+
self.info.dataset_size = sum(split.num_bytes for split in self.info.splits.values())
|
| 898 |
+
if dl_manager.record_checksums:
|
| 899 |
+
self.info.download_checksums = dl_manager.get_recorded_sizes_checksums()
|
| 900 |
+
if self.info.download_size is not None:
|
| 901 |
+
self.info.size_in_bytes = self.info.dataset_size + self.info.download_size
|
| 902 |
+
# Save info
|
| 903 |
+
self._save_info()
|
| 904 |
+
|
| 905 |
+
logger.info(
|
| 906 |
+
f"Dataset {self.dataset_name} downloaded and prepared to {self._output_dir}. "
|
| 907 |
+
f"Subsequent calls will reuse this data."
|
| 908 |
+
)
|
| 909 |
+
|
| 910 |
+
def _download_and_prepare(self, dl_manager, verification_mode, **prepare_split_kwargs):
|
| 911 |
+
"""Downloads and prepares dataset for reading.
|
| 912 |
+
|
| 913 |
+
This is the internal implementation to overwrite called when user calls
|
| 914 |
+
`download_and_prepare`. It should download all required data and generate
|
| 915 |
+
the pre-processed datasets files.
|
| 916 |
+
|
| 917 |
+
Args:
|
| 918 |
+
dl_manager ([`DownloadManager`]):
|
| 919 |
+
`DownloadManager` used to download and cache data.
|
| 920 |
+
verification_mode ([`VerificationMode`]):
|
| 921 |
+
if `ALL_CHECKS`, perform all the verifications including checksums.
|
| 922 |
+
if `BASIC_CHECKS`, do not perform checksums, only perform split tests.
|
| 923 |
+
if `NO_CHECKS`, do not perform any verification.
|
| 924 |
+
prepare_split_kwargs: Additional options, such as `file_format`, `max_shard_size`
|
| 925 |
+
"""
|
| 926 |
+
# Generating data for all splits
|
| 927 |
+
split_dict = SplitDict(dataset_name=self.dataset_name)
|
| 928 |
+
split_generators_kwargs = self._make_split_generators_kwargs(prepare_split_kwargs)
|
| 929 |
+
split_generators: list[SplitGenerator] = self._split_generators(dl_manager, **split_generators_kwargs)
|
| 930 |
+
|
| 931 |
+
# Checksums verification
|
| 932 |
+
if verification_mode == VerificationMode.ALL_CHECKS and dl_manager.record_checksums:
|
| 933 |
+
verify_checksums(
|
| 934 |
+
self.info.download_checksums, dl_manager.get_recorded_sizes_checksums(), "dataset source files"
|
| 935 |
+
)
|
| 936 |
+
|
| 937 |
+
# Build splits
|
| 938 |
+
for split_generator in split_generators:
|
| 939 |
+
if str(split_generator.split_info.name).lower() == "all":
|
| 940 |
+
raise ValueError(
|
| 941 |
+
"`all` is a special split keyword corresponding to the "
|
| 942 |
+
"union of all splits, so cannot be used as key in "
|
| 943 |
+
"._split_generator()."
|
| 944 |
+
)
|
| 945 |
+
|
| 946 |
+
logger.info(f"Generating {split_generator.split_info.name} split")
|
| 947 |
+
split_dict.add(split_generator.split_info)
|
| 948 |
+
|
| 949 |
+
try:
|
| 950 |
+
# Prepare split will record examples associated to the split
|
| 951 |
+
self._prepare_split(split_generator, **prepare_split_kwargs)
|
| 952 |
+
except OSError as e:
|
| 953 |
+
raise OSError("Cannot find data file. " + "\nOriginal error:\n" + str(e)) from None
|
| 954 |
+
dl_manager.manage_extracted_files()
|
| 955 |
+
|
| 956 |
+
if verification_mode == VerificationMode.BASIC_CHECKS or verification_mode == VerificationMode.ALL_CHECKS:
|
| 957 |
+
verify_splits(self.info.splits, split_dict)
|
| 958 |
+
|
| 959 |
+
# Update the info object with the splits.
|
| 960 |
+
self.info.splits = split_dict
|
| 961 |
+
self.info.download_size = dl_manager.downloaded_size
|
| 962 |
+
|
| 963 |
+
def _load_info(self) -> DatasetInfo:
|
| 964 |
+
return DatasetInfo.from_directory(self._output_dir, storage_options=self._fs.storage_options)
|
| 965 |
+
|
| 966 |
+
def _save_info(self):
|
| 967 |
+
file_lock = (
|
| 968 |
+
FileLock(self._output_dir + "_info.lock")
|
| 969 |
+
if not is_remote_filesystem(self._fs)
|
| 970 |
+
else contextlib.nullcontext()
|
| 971 |
+
)
|
| 972 |
+
with file_lock:
|
| 973 |
+
self.info.write_to_directory(self._output_dir, storage_options=self._fs.storage_options)
|
| 974 |
+
|
| 975 |
+
def _make_split_generators_kwargs(self, prepare_split_kwargs):
|
| 976 |
+
"""Get kwargs for `self._split_generators()` from `prepare_split_kwargs`."""
|
| 977 |
+
del prepare_split_kwargs
|
| 978 |
+
return {}
|
| 979 |
+
|
| 980 |
+
def as_dataset(
|
| 981 |
+
self,
|
| 982 |
+
split: Optional[Union[str, Split, list[str], list[Split]]] = None,
|
| 983 |
+
in_memory=False,
|
| 984 |
+
) -> Union[Dataset, DatasetDict]:
|
| 985 |
+
"""Return a Dataset for the specified split.
|
| 986 |
+
|
| 987 |
+
Args:
|
| 988 |
+
split (`datasets.Split`):
|
| 989 |
+
Which subset of the data to return.
|
| 990 |
+
verification_mode ([`VerificationMode`] or `str`, defaults to `BASIC_CHECKS`):
|
| 991 |
+
Verification mode determining the checks to run on the
|
| 992 |
+
downloaded/processed dataset information (checksums/size/splits/...).
|
| 993 |
+
|
| 994 |
+
<Added version="2.9.1"/>
|
| 995 |
+
in_memory (`bool`, defaults to `False`):
|
| 996 |
+
Whether to copy the data in-memory.
|
| 997 |
+
|
| 998 |
+
Returns:
|
| 999 |
+
datasets.Dataset
|
| 1000 |
+
|
| 1001 |
+
Example:
|
| 1002 |
+
|
| 1003 |
+
```py
|
| 1004 |
+
>>> from datasets import load_dataset_builder
|
| 1005 |
+
>>> builder = load_dataset_builder('cornell-movie-review-data/rotten_tomatoes')
|
| 1006 |
+
>>> builder.download_and_prepare()
|
| 1007 |
+
>>> ds = builder.as_dataset(split='train')
|
| 1008 |
+
>>> ds
|
| 1009 |
+
Dataset({
|
| 1010 |
+
features: ['text', 'label'],
|
| 1011 |
+
num_rows: 8530
|
| 1012 |
+
})
|
| 1013 |
+
```
|
| 1014 |
+
"""
|
| 1015 |
+
if self._file_format is not None and self._file_format != "arrow":
|
| 1016 |
+
raise FileFormatError('Loading a dataset not written in the "arrow" format is not supported.')
|
| 1017 |
+
if is_remote_filesystem(self._fs):
|
| 1018 |
+
raise NotImplementedError(f"Loading a dataset cached in a {type(self._fs).__name__} is not supported.")
|
| 1019 |
+
if not os.path.exists(self._output_dir):
|
| 1020 |
+
raise FileNotFoundError(
|
| 1021 |
+
f"Dataset {self.dataset_name}: could not find data in {self._output_dir}. Please make sure to call "
|
| 1022 |
+
"builder.download_and_prepare(), or use "
|
| 1023 |
+
"datasets.load_dataset() before trying to access the Dataset object."
|
| 1024 |
+
)
|
| 1025 |
+
|
| 1026 |
+
logger.debug(f"Constructing Dataset for split {split or ', '.join(self.info.splits)}, from {self._output_dir}")
|
| 1027 |
+
|
| 1028 |
+
# By default, return all splits
|
| 1029 |
+
if split is None:
|
| 1030 |
+
split = {s: s for s in self.info.splits}
|
| 1031 |
+
|
| 1032 |
+
# Create a dataset for each of the given splits
|
| 1033 |
+
datasets = map_nested(
|
| 1034 |
+
partial(
|
| 1035 |
+
self._build_single_dataset,
|
| 1036 |
+
in_memory=in_memory,
|
| 1037 |
+
),
|
| 1038 |
+
split,
|
| 1039 |
+
map_tuple=True,
|
| 1040 |
+
disable_tqdm=True,
|
| 1041 |
+
)
|
| 1042 |
+
if isinstance(datasets, dict):
|
| 1043 |
+
datasets = DatasetDict(datasets)
|
| 1044 |
+
return datasets
|
| 1045 |
+
|
| 1046 |
+
def _build_single_dataset(
|
| 1047 |
+
self,
|
| 1048 |
+
split: Union[str, ReadInstruction, Split],
|
| 1049 |
+
in_memory: bool = False,
|
| 1050 |
+
):
|
| 1051 |
+
"""as_dataset for a single split."""
|
| 1052 |
+
if not isinstance(split, ReadInstruction):
|
| 1053 |
+
split = str(split)
|
| 1054 |
+
if split == "all":
|
| 1055 |
+
split = "+".join(self.info.splits.keys())
|
| 1056 |
+
split = Split(split)
|
| 1057 |
+
|
| 1058 |
+
# Build base dataset
|
| 1059 |
+
ds = self._as_dataset(
|
| 1060 |
+
split=split,
|
| 1061 |
+
in_memory=in_memory,
|
| 1062 |
+
)
|
| 1063 |
+
return ds
|
| 1064 |
+
|
| 1065 |
+
def _as_dataset(self, split: Union[ReadInstruction, Split] = Split.TRAIN, in_memory: bool = False) -> Dataset:
|
| 1066 |
+
"""Constructs a `Dataset`.
|
| 1067 |
+
|
| 1068 |
+
This is the internal implementation to overwrite called when user calls
|
| 1069 |
+
`as_dataset`. It should read the pre-processed datasets files and generate
|
| 1070 |
+
the `Dataset` object.
|
| 1071 |
+
|
| 1072 |
+
Args:
|
| 1073 |
+
split (`datasets.Split`):
|
| 1074 |
+
which subset of the data to read.
|
| 1075 |
+
in_memory (`bool`, defaults to `False`):
|
| 1076 |
+
Whether to copy the data in-memory.
|
| 1077 |
+
|
| 1078 |
+
Returns:
|
| 1079 |
+
`Dataset`
|
| 1080 |
+
"""
|
| 1081 |
+
cache_dir = self._fs._strip_protocol(self._output_dir)
|
| 1082 |
+
dataset_name = self.dataset_name
|
| 1083 |
+
if self._check_legacy_cache():
|
| 1084 |
+
dataset_name = self.name
|
| 1085 |
+
dataset_kwargs = ArrowReader(cache_dir, self.info).read(
|
| 1086 |
+
name=dataset_name,
|
| 1087 |
+
instructions=split,
|
| 1088 |
+
split_infos=self.info.splits.values(),
|
| 1089 |
+
in_memory=in_memory,
|
| 1090 |
+
)
|
| 1091 |
+
fingerprint = self._get_dataset_fingerprint(split)
|
| 1092 |
+
return Dataset(fingerprint=fingerprint, **dataset_kwargs)
|
| 1093 |
+
|
| 1094 |
+
def _get_dataset_fingerprint(self, split: Union[ReadInstruction, Split]) -> str:
|
| 1095 |
+
"""The dataset fingerprint is the hash of the relative directory dataset_name/config_name/version/hash, as well as the split specs."""
|
| 1096 |
+
hasher = Hasher()
|
| 1097 |
+
hasher.update(Path(self._relative_data_dir()).as_posix())
|
| 1098 |
+
hasher.update(str(split)) # for example: train, train+test, train[:10%], test[:33%](pct1_dropremainder)
|
| 1099 |
+
fingerprint = hasher.hexdigest()
|
| 1100 |
+
return fingerprint
|
| 1101 |
+
|
| 1102 |
+
def as_streaming_dataset(
|
| 1103 |
+
self,
|
| 1104 |
+
split: Optional[str] = None,
|
| 1105 |
+
base_path: Optional[str] = None,
|
| 1106 |
+
) -> Union[dict[str, IterableDataset], IterableDataset]:
|
| 1107 |
+
if is_remote_filesystem(self._fs):
|
| 1108 |
+
raise NotImplementedError(
|
| 1109 |
+
f"Loading a streaming dataset cached in a {type(self._fs).__name__} is not supported yet."
|
| 1110 |
+
)
|
| 1111 |
+
|
| 1112 |
+
dl_manager = StreamingDownloadManager(
|
| 1113 |
+
base_path=base_path or self.base_path,
|
| 1114 |
+
download_config=DownloadConfig(token=self.token, storage_options=self.storage_options),
|
| 1115 |
+
dataset_name=self.dataset_name,
|
| 1116 |
+
data_dir=self.config.data_dir,
|
| 1117 |
+
)
|
| 1118 |
+
splits_generators = {sg.name: sg for sg in self._split_generators(dl_manager)}
|
| 1119 |
+
# By default, return all splits
|
| 1120 |
+
if split is None:
|
| 1121 |
+
splits_generator = splits_generators
|
| 1122 |
+
elif str(split) in splits_generators:
|
| 1123 |
+
splits_generator = splits_generators[str(split)]
|
| 1124 |
+
elif hasattr(split, "get_read_instruction"):
|
| 1125 |
+
split_dict = SplitDict({name: sg.split_info for name, sg in splits_generators.items()})
|
| 1126 |
+
split_instruction = split.get_read_instruction(split_dict)
|
| 1127 |
+
split_infos = split_instruction.get_list_sliced_split_info()
|
| 1128 |
+
if any(split_info.slice_value is not None for split_info in split_infos):
|
| 1129 |
+
raise ValueError(f"Bad split: {split}. Available splits: {list(splits_generators)}")
|
| 1130 |
+
return _concatenate_iterable_datasets(
|
| 1131 |
+
[
|
| 1132 |
+
self._as_streaming_dataset_single(splits_generators[split_info.split_info.name])
|
| 1133 |
+
for split_info in split_infos
|
| 1134 |
+
],
|
| 1135 |
+
info=self.info,
|
| 1136 |
+
split=split,
|
| 1137 |
+
)
|
| 1138 |
+
elif str(split) == str(Split.ALL):
|
| 1139 |
+
return _concatenate_iterable_datasets(
|
| 1140 |
+
[self._as_streaming_dataset_single(sg) for sg in splits_generators.values()],
|
| 1141 |
+
info=self.info,
|
| 1142 |
+
split=split,
|
| 1143 |
+
)
|
| 1144 |
+
elif "+" in str(split) and "[" not in str(split) and "]" not in str(split):
|
| 1145 |
+
split_names = [split_name.strip() for split_name in str(split).split("+")]
|
| 1146 |
+
if not all(split_name in splits_generators for split_name in split_names):
|
| 1147 |
+
raise ValueError(f"Bad split: {split}. Available splits: {list(splits_generators)}")
|
| 1148 |
+
return _concatenate_iterable_datasets(
|
| 1149 |
+
[self._as_streaming_dataset_single(splits_generators[split_name]) for split_name in split_names],
|
| 1150 |
+
info=self.info,
|
| 1151 |
+
split=split,
|
| 1152 |
+
)
|
| 1153 |
+
else:
|
| 1154 |
+
raise ValueError(f"Bad split: {split}. Available splits: {list(splits_generators)}")
|
| 1155 |
+
|
| 1156 |
+
# Create a dataset for each of the given splits
|
| 1157 |
+
datasets = map_nested(
|
| 1158 |
+
self._as_streaming_dataset_single,
|
| 1159 |
+
splits_generator,
|
| 1160 |
+
map_tuple=True,
|
| 1161 |
+
)
|
| 1162 |
+
if isinstance(datasets, dict):
|
| 1163 |
+
datasets = IterableDatasetDict(datasets)
|
| 1164 |
+
return datasets
|
| 1165 |
+
|
| 1166 |
+
def _as_streaming_dataset_single(
|
| 1167 |
+
self,
|
| 1168 |
+
splits_generator,
|
| 1169 |
+
) -> IterableDataset:
|
| 1170 |
+
ex_iterable = self._get_examples_iterable_for_split(splits_generator)
|
| 1171 |
+
# add auth to be able to access and decode audio/image files from private repositories.
|
| 1172 |
+
token_per_repo_id = {self.repo_id: self.token} if self.repo_id else {}
|
| 1173 |
+
return IterableDataset(
|
| 1174 |
+
ex_iterable, info=self.info, split=splits_generator.name, token_per_repo_id=token_per_repo_id
|
| 1175 |
+
)
|
| 1176 |
+
|
| 1177 |
+
@abc.abstractmethod
|
| 1178 |
+
def _split_generators(self, dl_manager: Union[DownloadManager, StreamingDownloadManager]):
|
| 1179 |
+
"""Specify feature dictionary generators and dataset splits.
|
| 1180 |
+
|
| 1181 |
+
This function returns a list of `SplitGenerator`s defining how to generate
|
| 1182 |
+
data and what splits to use.
|
| 1183 |
+
|
| 1184 |
+
Example:
|
| 1185 |
+
|
| 1186 |
+
return [
|
| 1187 |
+
datasets.SplitGenerator(
|
| 1188 |
+
name=datasets.Split.TRAIN,
|
| 1189 |
+
gen_kwargs={'file': 'train_data.zip'},
|
| 1190 |
+
),
|
| 1191 |
+
datasets.SplitGenerator(
|
| 1192 |
+
name=datasets.Split.TEST,
|
| 1193 |
+
gen_kwargs={'file': 'test_data.zip'},
|
| 1194 |
+
),
|
| 1195 |
+
]
|
| 1196 |
+
|
| 1197 |
+
The above code will first call `_generate_examples(file='train_data.zip')`
|
| 1198 |
+
to write the train data, then `_generate_examples(file='test_data.zip')` to
|
| 1199 |
+
write the test data.
|
| 1200 |
+
|
| 1201 |
+
Datasets are typically split into different subsets to be used at various
|
| 1202 |
+
stages of training and evaluation.
|
| 1203 |
+
|
| 1204 |
+
Note that for datasets without a `VALIDATION` split, you can use a
|
| 1205 |
+
fraction of the `TRAIN` data for evaluation as you iterate on your model
|
| 1206 |
+
so as not to overfit to the `TEST` data.
|
| 1207 |
+
|
| 1208 |
+
For downloads and extractions, use the given `download_manager`.
|
| 1209 |
+
Note that the `DownloadManager` caches downloads, so it is fine to have each
|
| 1210 |
+
generator attempt to download the source data.
|
| 1211 |
+
|
| 1212 |
+
A good practice is to download all data in this function, and then
|
| 1213 |
+
distribute the relevant parts to each split with the `gen_kwargs` argument
|
| 1214 |
+
|
| 1215 |
+
Args:
|
| 1216 |
+
dl_manager (`Union[DownloadManager, StreamingDownloadManager]`):
|
| 1217 |
+
Download manager to download the data
|
| 1218 |
+
|
| 1219 |
+
Returns:
|
| 1220 |
+
`list<SplitGenerator>`.
|
| 1221 |
+
"""
|
| 1222 |
+
raise NotImplementedError()
|
| 1223 |
+
|
| 1224 |
+
@abc.abstractmethod
|
| 1225 |
+
def _prepare_split(
|
| 1226 |
+
self,
|
| 1227 |
+
split_generator: SplitGenerator,
|
| 1228 |
+
file_format: str = "arrow",
|
| 1229 |
+
max_shard_size: Optional[Union[str, int]] = None,
|
| 1230 |
+
num_proc: Optional[int] = None,
|
| 1231 |
+
**kwargs,
|
| 1232 |
+
):
|
| 1233 |
+
"""Generate the examples and record them on disk.
|
| 1234 |
+
|
| 1235 |
+
Args:
|
| 1236 |
+
split_generator (`SplitGenerator`):
|
| 1237 |
+
Split generator to process
|
| 1238 |
+
file_format (`str`, *optional*):
|
| 1239 |
+
format of the data files in which the dataset will be written.
|
| 1240 |
+
Supported formats: "arrow", "parquet". Default to "arrow" format.
|
| 1241 |
+
max_shard_size (`Union[str, int]`, *optional*):
|
| 1242 |
+
Maximum number of bytes written per shard, default is "500MB".
|
| 1243 |
+
The size is based on uncompressed data size, so in practice your shard files may be smaller than
|
| 1244 |
+
`max_shard_size` thanks to Parquet compression for example.
|
| 1245 |
+
num_proc (`int`, *optional*, defaults to `None`):
|
| 1246 |
+
Number of processes when downloading and generating the dataset locally.
|
| 1247 |
+
Multiprocessing is disabled by default.
|
| 1248 |
+
|
| 1249 |
+
<Added version="2.7.0"/>
|
| 1250 |
+
**kwargs: Additional kwargs forwarded from _download_and_prepare
|
| 1251 |
+
"""
|
| 1252 |
+
raise NotImplementedError()
|
| 1253 |
+
|
| 1254 |
+
def _get_examples_iterable_for_split(self, split_generator: SplitGenerator) -> ExamplesIterable:
|
| 1255 |
+
"""Generate the examples on the fly.
|
| 1256 |
+
|
| 1257 |
+
Args:
|
| 1258 |
+
split_generator (`SplitGenerator`):
|
| 1259 |
+
Split generator to process
|
| 1260 |
+
"""
|
| 1261 |
+
raise NotImplementedError()
|
| 1262 |
+
|
| 1263 |
+
|
| 1264 |
+
@dataclass
|
| 1265 |
+
class Key:
|
| 1266 |
+
original_shard_id: int
|
| 1267 |
+
item_or_batch_id: int
|
| 1268 |
+
|
| 1269 |
+
def __str__(self):
|
| 1270 |
+
return str((self.original_shard_id, self.item_or_batch_id))
|
| 1271 |
+
|
| 1272 |
+
|
| 1273 |
+
class GeneratorBasedBuilder(DatasetBuilder):
|
| 1274 |
+
"""Base class for datasets with data generation based on dict generators.
|
| 1275 |
+
|
| 1276 |
+
`GeneratorBasedBuilder` is a convenience class that abstracts away much
|
| 1277 |
+
of the data writing and reading of `DatasetBuilder`. It expects subclasses to
|
| 1278 |
+
implement generators of feature dictionaries across the dataset splits
|
| 1279 |
+
(`_split_generators`). See the method docstrings for details.
|
| 1280 |
+
"""
|
| 1281 |
+
|
| 1282 |
+
def _generate_shards(self, **kwargs) -> Iterator[Union[str, dict[str, Any]]]:
|
| 1283 |
+
"""Default function generating shards paths for each `SplitGenerator`.
|
| 1284 |
+
|
| 1285 |
+
This function is useful to list the original shards from where the data
|
| 1286 |
+
comes from and is either converted to Arrow or streamed to an IterableDataset.
|
| 1287 |
+
|
| 1288 |
+
This is optional and only used for certain utilities, but not in Dataset
|
| 1289 |
+
nor IterableDataset. E.g. it's used to map original shard files to Parquet
|
| 1290 |
+
files in the Dataset Viewer after conversion.
|
| 1291 |
+
|
| 1292 |
+
Args:
|
| 1293 |
+
**kwargs (additional keyword arguments):
|
| 1294 |
+
Arguments forwarded from the SplitGenerator.gen_kwargs
|
| 1295 |
+
|
| 1296 |
+
Yields:
|
| 1297 |
+
shard: generally a string representing the shard path, or a dict
|
| 1298 |
+
representing the shard in case of shards spanning intra or inter-files.
|
| 1299 |
+
"""
|
| 1300 |
+
raise NotImplementedError()
|
| 1301 |
+
|
| 1302 |
+
@abc.abstractmethod
|
| 1303 |
+
def _generate_examples(self, **kwargs) -> Iterator[tuple[Key, dict[str, Any]]]:
|
| 1304 |
+
"""Default function generating examples for each `SplitGenerator`.
|
| 1305 |
+
|
| 1306 |
+
This function preprocess the examples from the raw data to the preprocessed
|
| 1307 |
+
dataset files.
|
| 1308 |
+
This function is called once for each `SplitGenerator` defined in
|
| 1309 |
+
`_split_generators`. The examples yielded here will be written on
|
| 1310 |
+
disk.
|
| 1311 |
+
|
| 1312 |
+
Args:
|
| 1313 |
+
**kwargs (additional keyword arguments):
|
| 1314 |
+
Arguments forwarded from the SplitGenerator.gen_kwargs
|
| 1315 |
+
|
| 1316 |
+
Yields:
|
| 1317 |
+
key: `str` or `int`, a unique deterministic example identification key.
|
| 1318 |
+
* Unique: An error will be raised if two examples are yield with the
|
| 1319 |
+
same key.
|
| 1320 |
+
* Deterministic: When generating the dataset twice, the same example
|
| 1321 |
+
should have the same key.
|
| 1322 |
+
Good keys can be the image id, or line number if examples are extracted
|
| 1323 |
+
from a text file.
|
| 1324 |
+
The key will be hashed and sorted to shuffle examples deterministically,
|
| 1325 |
+
such as generating the dataset multiple times keep examples in the
|
| 1326 |
+
same order.
|
| 1327 |
+
example: `dict<str feature_name, feature_value>`, a feature dictionary
|
| 1328 |
+
ready to be encoded and written to disk. The example will be
|
| 1329 |
+
encoded with `self.info.features.encode_example({...})`.
|
| 1330 |
+
"""
|
| 1331 |
+
raise NotImplementedError()
|
| 1332 |
+
|
| 1333 |
+
def _prepare_split(
|
| 1334 |
+
self,
|
| 1335 |
+
split_generator: SplitGenerator,
|
| 1336 |
+
file_format="arrow",
|
| 1337 |
+
num_proc: Optional[int] = None,
|
| 1338 |
+
max_shard_size: Optional[Union[int, str]] = None,
|
| 1339 |
+
):
|
| 1340 |
+
max_shard_size = convert_file_size_to_int(max_shard_size or config.MAX_SHARD_SIZE)
|
| 1341 |
+
|
| 1342 |
+
if self.info.splits is not None:
|
| 1343 |
+
split_info = self.info.splits[split_generator.name]
|
| 1344 |
+
else:
|
| 1345 |
+
split_info = split_generator.split_info
|
| 1346 |
+
|
| 1347 |
+
SUFFIX = "-JJJJJ-SSSSS-of-NNNNN"
|
| 1348 |
+
fname = f"{self.dataset_name}-{split_generator.name}{SUFFIX}.{file_format}"
|
| 1349 |
+
fpath = posixpath.join(self._output_dir, fname)
|
| 1350 |
+
|
| 1351 |
+
if num_proc and num_proc > 1:
|
| 1352 |
+
num_original_shards = _number_of_shards_in_gen_kwargs(split_generator.gen_kwargs)
|
| 1353 |
+
if num_original_shards <= 1:
|
| 1354 |
+
logger.warning(
|
| 1355 |
+
f"Setting num_proc from {num_proc} back to 1 for the {split_info.name} split to disable multiprocessing as it only contains one shard."
|
| 1356 |
+
)
|
| 1357 |
+
num_proc = 1
|
| 1358 |
+
elif num_original_shards < num_proc:
|
| 1359 |
+
logger.warning(
|
| 1360 |
+
f"Setting num_proc from {num_proc} to {num_original_shards} for the {split_info.name} split as it only contains {num_original_shards} shards."
|
| 1361 |
+
)
|
| 1362 |
+
num_proc = num_original_shards
|
| 1363 |
+
|
| 1364 |
+
pbar = hf_tqdm(
|
| 1365 |
+
unit=" examples",
|
| 1366 |
+
total=split_info.num_examples,
|
| 1367 |
+
desc=f"Generating {split_info.name} split",
|
| 1368 |
+
)
|
| 1369 |
+
|
| 1370 |
+
_prepare_split_args = {
|
| 1371 |
+
"fpath": fpath,
|
| 1372 |
+
"file_format": file_format,
|
| 1373 |
+
"max_shard_size": max_shard_size,
|
| 1374 |
+
"split_info": split_info,
|
| 1375 |
+
}
|
| 1376 |
+
|
| 1377 |
+
if num_proc is None or num_proc == 1:
|
| 1378 |
+
result = None
|
| 1379 |
+
gen_kwargs = split_generator.gen_kwargs
|
| 1380 |
+
job_id = 0
|
| 1381 |
+
with pbar:
|
| 1382 |
+
for job_id, done, content in self._prepare_split_single(
|
| 1383 |
+
gen_kwargs=gen_kwargs, job_id=job_id, **_prepare_split_args
|
| 1384 |
+
):
|
| 1385 |
+
if done:
|
| 1386 |
+
result = content
|
| 1387 |
+
else:
|
| 1388 |
+
pbar.update(content)
|
| 1389 |
+
# wrapping everything into lists for consistency with the multiprocessed code path
|
| 1390 |
+
assert result is not None, "Failed to retrieve results from prepare_split"
|
| 1391 |
+
(
|
| 1392 |
+
examples_per_job,
|
| 1393 |
+
bytes_per_job,
|
| 1394 |
+
features_per_job,
|
| 1395 |
+
shards_per_job,
|
| 1396 |
+
shard_lengths_per_job,
|
| 1397 |
+
original_shards_per_job,
|
| 1398 |
+
original_shard_lengths_per_job,
|
| 1399 |
+
) = ([item] for item in result)
|
| 1400 |
+
else:
|
| 1401 |
+
kwargs_per_job = [
|
| 1402 |
+
{"gen_kwargs": gen_kwargs, "job_id": job_id, **_prepare_split_args}
|
| 1403 |
+
for job_id, gen_kwargs in enumerate(
|
| 1404 |
+
_split_gen_kwargs(split_generator.gen_kwargs, max_num_jobs=num_proc)
|
| 1405 |
+
)
|
| 1406 |
+
]
|
| 1407 |
+
num_jobs = len(kwargs_per_job)
|
| 1408 |
+
|
| 1409 |
+
examples_per_job = [None] * num_jobs
|
| 1410 |
+
bytes_per_job = [None] * num_jobs
|
| 1411 |
+
features_per_job = [None] * num_jobs
|
| 1412 |
+
shards_per_job = [None] * num_jobs
|
| 1413 |
+
shard_lengths_per_job = [None] * num_jobs
|
| 1414 |
+
original_shards_per_job = [None] * num_jobs
|
| 1415 |
+
original_shard_lengths_per_job = [None] * num_jobs
|
| 1416 |
+
|
| 1417 |
+
with Pool(num_proc) as pool:
|
| 1418 |
+
with pbar:
|
| 1419 |
+
for job_id, done, content in iflatmap_unordered(
|
| 1420 |
+
pool, self._prepare_split_single, kwargs_iterable=kwargs_per_job
|
| 1421 |
+
):
|
| 1422 |
+
if done:
|
| 1423 |
+
# the content is the result of the job
|
| 1424 |
+
(
|
| 1425 |
+
examples_per_job[job_id],
|
| 1426 |
+
bytes_per_job[job_id],
|
| 1427 |
+
features_per_job[job_id],
|
| 1428 |
+
shards_per_job[job_id],
|
| 1429 |
+
shard_lengths_per_job[job_id],
|
| 1430 |
+
original_shards_per_job[job_id],
|
| 1431 |
+
original_shard_lengths_per_job[job_id],
|
| 1432 |
+
) = content
|
| 1433 |
+
else:
|
| 1434 |
+
# the content is the number of examples progress update
|
| 1435 |
+
pbar.update(content)
|
| 1436 |
+
|
| 1437 |
+
assert None not in examples_per_job, (
|
| 1438 |
+
f"Failed to retrieve results from prepare_split: result list {examples_per_job} still contains None - at least one worker failed to return its results"
|
| 1439 |
+
)
|
| 1440 |
+
|
| 1441 |
+
total_shards = sum(shards_per_job)
|
| 1442 |
+
total_original_shards = sum(original_shards_per_job)
|
| 1443 |
+
total_num_examples = sum(examples_per_job)
|
| 1444 |
+
total_num_bytes = sum(bytes_per_job)
|
| 1445 |
+
features = features_per_job[0]
|
| 1446 |
+
|
| 1447 |
+
split_generator.split_info.num_examples = total_num_examples
|
| 1448 |
+
split_generator.split_info.num_bytes = total_num_bytes
|
| 1449 |
+
|
| 1450 |
+
# should rename everything at the end
|
| 1451 |
+
logger.debug(f"Renaming {total_shards} shards.")
|
| 1452 |
+
if total_shards > 1:
|
| 1453 |
+
# use the -SSSSS-of-NNNNN pattern
|
| 1454 |
+
|
| 1455 |
+
def _rename_shard(shard_and_job: tuple[int]):
|
| 1456 |
+
shard_id, job_id = shard_and_job
|
| 1457 |
+
global_shard_id = sum(shards_per_job[:job_id]) + shard_id
|
| 1458 |
+
self._rename(
|
| 1459 |
+
fpath.replace("SSSSS", f"{shard_id:05d}").replace("JJJJJ", f"{job_id:05d}"),
|
| 1460 |
+
fpath.replace("JJJJJ-SSSSS", f"{global_shard_id:05d}").replace("NNNNN", f"{total_shards:05d}"),
|
| 1461 |
+
)
|
| 1462 |
+
|
| 1463 |
+
shards_and_jobs = [
|
| 1464 |
+
(shard_id, job_id)
|
| 1465 |
+
for job_id, num_shards in enumerate(shards_per_job)
|
| 1466 |
+
for shard_id in range(num_shards)
|
| 1467 |
+
]
|
| 1468 |
+
thread_map(_rename_shard, shards_and_jobs, disable=True, max_workers=64)
|
| 1469 |
+
|
| 1470 |
+
split_generator.split_info.shard_lengths = [
|
| 1471 |
+
shard_length for shard_lengths in shard_lengths_per_job for shard_length in shard_lengths
|
| 1472 |
+
]
|
| 1473 |
+
else:
|
| 1474 |
+
# don't use any pattern
|
| 1475 |
+
shard_id, job_id = 0, 0
|
| 1476 |
+
self._rename(
|
| 1477 |
+
fpath.replace("SSSSS", f"{shard_id:05d}").replace("JJJJJ", f"{job_id:05d}"),
|
| 1478 |
+
fpath.replace(SUFFIX, ""),
|
| 1479 |
+
)
|
| 1480 |
+
|
| 1481 |
+
if total_original_shards > 1 and config.SAVE_ORIGINAL_SHARD_LENGTHS:
|
| 1482 |
+
split_generator.split_info.original_shard_lengths = [
|
| 1483 |
+
original_shard_length
|
| 1484 |
+
for original_shard_lengths in original_shard_lengths_per_job
|
| 1485 |
+
for original_shard_length in original_shard_lengths
|
| 1486 |
+
]
|
| 1487 |
+
|
| 1488 |
+
if self.info.features is None:
|
| 1489 |
+
self.info.features = features
|
| 1490 |
+
|
| 1491 |
+
def _prepare_split_single(
|
| 1492 |
+
self,
|
| 1493 |
+
gen_kwargs: dict,
|
| 1494 |
+
fpath: str,
|
| 1495 |
+
file_format: str,
|
| 1496 |
+
max_shard_size: int,
|
| 1497 |
+
split_info: SplitInfo,
|
| 1498 |
+
job_id: int,
|
| 1499 |
+
) -> Iterator[tuple[int, bool, tuple[int, int, Features, int, int, int]]]:
|
| 1500 |
+
generator = self._generate_examples(**gen_kwargs)
|
| 1501 |
+
writer_class = ParquetWriter if file_format == "parquet" else ArrowWriter
|
| 1502 |
+
embed_local_files = file_format == "parquet"
|
| 1503 |
+
shard_lengths = []
|
| 1504 |
+
original_shard_lengths = []
|
| 1505 |
+
total_num_examples, total_num_bytes = 0, 0
|
| 1506 |
+
|
| 1507 |
+
shard_id = 0
|
| 1508 |
+
original_shard_id = 0
|
| 1509 |
+
num_examples_progress_update = 0
|
| 1510 |
+
try:
|
| 1511 |
+
writer = writer_class(
|
| 1512 |
+
features=self.info.features,
|
| 1513 |
+
path=fpath.replace("SSSSS", f"{shard_id:05d}").replace("JJJJJ", f"{job_id:05d}"),
|
| 1514 |
+
writer_batch_size=self._writer_batch_size,
|
| 1515 |
+
storage_options=self._fs.storage_options,
|
| 1516 |
+
embed_local_files=embed_local_files,
|
| 1517 |
+
)
|
| 1518 |
+
try:
|
| 1519 |
+
_time = time.time()
|
| 1520 |
+
for key, record in generator:
|
| 1521 |
+
if isinstance(key, Key): # old custom builders may not use Key
|
| 1522 |
+
original_shard_id = key.original_shard_id
|
| 1523 |
+
if max_shard_size is not None and writer._num_bytes > max_shard_size:
|
| 1524 |
+
num_examples, num_bytes = writer.finalize()
|
| 1525 |
+
writer.close()
|
| 1526 |
+
shard_lengths.append(num_examples)
|
| 1527 |
+
total_num_examples += num_examples
|
| 1528 |
+
total_num_bytes += num_bytes
|
| 1529 |
+
shard_id += 1
|
| 1530 |
+
writer = writer_class(
|
| 1531 |
+
features=writer._features,
|
| 1532 |
+
path=fpath.replace("SSSSS", f"{shard_id:05d}").replace("JJJJJ", f"{job_id:05d}"),
|
| 1533 |
+
writer_batch_size=self._writer_batch_size,
|
| 1534 |
+
storage_options=self._fs.storage_options,
|
| 1535 |
+
embed_local_files=embed_local_files,
|
| 1536 |
+
)
|
| 1537 |
+
example = self.info.features.encode_example(record) if self.info.features is not None else record
|
| 1538 |
+
writer.write(example)
|
| 1539 |
+
if len(original_shard_lengths) <= original_shard_id:
|
| 1540 |
+
original_shard_lengths.extend([0] * (1 + original_shard_id - len(original_shard_lengths)))
|
| 1541 |
+
original_shard_lengths[original_shard_id] += 1
|
| 1542 |
+
num_examples_progress_update += 1
|
| 1543 |
+
if time.time() > _time + config.PBAR_REFRESH_TIME_INTERVAL:
|
| 1544 |
+
_time = time.time()
|
| 1545 |
+
yield job_id, False, num_examples_progress_update
|
| 1546 |
+
num_examples_progress_update = 0
|
| 1547 |
+
finally:
|
| 1548 |
+
yield job_id, False, num_examples_progress_update
|
| 1549 |
+
num_shards = shard_id + 1
|
| 1550 |
+
num_original_shards = original_shard_id + 1
|
| 1551 |
+
num_examples, num_bytes = writer.finalize()
|
| 1552 |
+
writer.close()
|
| 1553 |
+
shard_lengths.append(num_examples)
|
| 1554 |
+
total_num_examples += num_examples
|
| 1555 |
+
total_num_bytes += num_bytes
|
| 1556 |
+
except Exception as e:
|
| 1557 |
+
# Ignore the writer's error for no examples written to the file if this error was caused by the error in _generate_examples before the first example was yielded
|
| 1558 |
+
if isinstance(e, SchemaInferenceError) and e.__context__ is not None:
|
| 1559 |
+
e = e.__context__
|
| 1560 |
+
raise DatasetGenerationError("An error occurred while generating the dataset") from e
|
| 1561 |
+
|
| 1562 |
+
yield (
|
| 1563 |
+
job_id,
|
| 1564 |
+
True,
|
| 1565 |
+
(
|
| 1566 |
+
total_num_examples,
|
| 1567 |
+
total_num_bytes,
|
| 1568 |
+
writer._features,
|
| 1569 |
+
num_shards,
|
| 1570 |
+
shard_lengths,
|
| 1571 |
+
num_original_shards,
|
| 1572 |
+
original_shard_lengths,
|
| 1573 |
+
),
|
| 1574 |
+
)
|
| 1575 |
+
|
| 1576 |
+
def _download_and_prepare(self, dl_manager, verification_mode, **prepare_splits_kwargs):
|
| 1577 |
+
super()._download_and_prepare(
|
| 1578 |
+
dl_manager,
|
| 1579 |
+
verification_mode,
|
| 1580 |
+
**prepare_splits_kwargs,
|
| 1581 |
+
)
|
| 1582 |
+
|
| 1583 |
+
def _get_examples_iterable_for_split(self, split_generator: SplitGenerator) -> ExamplesIterable:
|
| 1584 |
+
return ExamplesIterable(
|
| 1585 |
+
self._generate_examples,
|
| 1586 |
+
split_generator.gen_kwargs,
|
| 1587 |
+
generate_more_kwargs_fn=getattr(self, "_generate_more_gen_kwargs", None),
|
| 1588 |
+
)
|
| 1589 |
+
|
| 1590 |
+
|
| 1591 |
+
class ArrowBasedBuilder(DatasetBuilder):
|
| 1592 |
+
"""Base class for datasets with data generation based on Arrow loading functions (CSV/JSON/Parquet)."""
|
| 1593 |
+
|
| 1594 |
+
def _generate_shards(self, **kwargs) -> Iterator[Union[str, dict[str, Any]]]:
|
| 1595 |
+
"""Default function generating shards paths for each `SplitGenerator`.
|
| 1596 |
+
|
| 1597 |
+
This function is useful to list the original shards from where the data
|
| 1598 |
+
comes from and is either converted to Arrow or streamed to an IterableDataset.
|
| 1599 |
+
|
| 1600 |
+
This is optional and only used for certain utilities, but not in Dataset
|
| 1601 |
+
nor IterableDataset. E.g. it's used to map original shard files to Parquet
|
| 1602 |
+
files in the Dataset Viewer after conversion.
|
| 1603 |
+
|
| 1604 |
+
Args:
|
| 1605 |
+
**kwargs (additional keyword arguments):
|
| 1606 |
+
Arguments forwarded from the SplitGenerator.gen_kwargs
|
| 1607 |
+
|
| 1608 |
+
Yields:
|
| 1609 |
+
shard: generally a string representing the shard path, or a dict
|
| 1610 |
+
representing the shard in case of shards spanning intra or inter-files.
|
| 1611 |
+
"""
|
| 1612 |
+
raise NotImplementedError()
|
| 1613 |
+
|
| 1614 |
+
@abc.abstractmethod
|
| 1615 |
+
def _generate_tables(self, **kwargs) -> Iterator[tuple[Key, pa.Table]]:
|
| 1616 |
+
"""Default function generating examples for each `SplitGenerator`.
|
| 1617 |
+
|
| 1618 |
+
This function preprocess the examples from the raw data to the preprocessed
|
| 1619 |
+
dataset files.
|
| 1620 |
+
This function is called once for each `SplitGenerator` defined in
|
| 1621 |
+
`_split_generators`. The examples yielded here will be written on
|
| 1622 |
+
disk.
|
| 1623 |
+
|
| 1624 |
+
Args:
|
| 1625 |
+
**kwargs (additional keyword arguments):
|
| 1626 |
+
Arguments forwarded from the SplitGenerator.gen_kwargs
|
| 1627 |
+
|
| 1628 |
+
Yields:
|
| 1629 |
+
key: tuple[int, int] original_shard_id and table_idx within that shard
|
| 1630 |
+
example: `pyarrow.Table`, a feature table
|
| 1631 |
+
ready to be encoded and written to disk.
|
| 1632 |
+
"""
|
| 1633 |
+
raise NotImplementedError()
|
| 1634 |
+
|
| 1635 |
+
def _prepare_split(
|
| 1636 |
+
self,
|
| 1637 |
+
split_generator: SplitGenerator,
|
| 1638 |
+
file_format: str = "arrow",
|
| 1639 |
+
num_proc: Optional[int] = None,
|
| 1640 |
+
max_shard_size: Optional[Union[str, int]] = None,
|
| 1641 |
+
):
|
| 1642 |
+
max_shard_size = convert_file_size_to_int(max_shard_size or config.MAX_SHARD_SIZE)
|
| 1643 |
+
|
| 1644 |
+
try:
|
| 1645 |
+
split_info = self.info.splits[split_generator.name]
|
| 1646 |
+
except Exception:
|
| 1647 |
+
split_info = split_generator.split_info
|
| 1648 |
+
|
| 1649 |
+
SUFFIX = "-JJJJJ-SSSSS-of-NNNNN"
|
| 1650 |
+
fname = f"{self.dataset_name}-{split_generator.name}{SUFFIX}.{file_format}"
|
| 1651 |
+
fpath = posixpath.join(self._output_dir, fname)
|
| 1652 |
+
|
| 1653 |
+
if num_proc and num_proc > 1:
|
| 1654 |
+
num_original_shards = _number_of_shards_in_gen_kwargs(split_generator.gen_kwargs)
|
| 1655 |
+
if num_original_shards <= 1:
|
| 1656 |
+
logger.warning(
|
| 1657 |
+
f"Setting num_proc from {num_proc} back to 1 for the {split_info.name} split to disable multiprocessing as it only contains one shard."
|
| 1658 |
+
)
|
| 1659 |
+
num_proc = 1
|
| 1660 |
+
elif num_original_shards < num_proc:
|
| 1661 |
+
logger.warning(
|
| 1662 |
+
f"Setting num_proc from {num_proc} to {num_original_shards} for the {split_info.name} split as it only contains {num_original_shards} shards."
|
| 1663 |
+
)
|
| 1664 |
+
num_proc = num_original_shards
|
| 1665 |
+
|
| 1666 |
+
pbar = hf_tqdm(
|
| 1667 |
+
unit=" examples",
|
| 1668 |
+
total=split_info.num_examples,
|
| 1669 |
+
desc=f"Generating {split_info.name} split",
|
| 1670 |
+
)
|
| 1671 |
+
|
| 1672 |
+
_prepare_split_args = {
|
| 1673 |
+
"fpath": fpath,
|
| 1674 |
+
"file_format": file_format,
|
| 1675 |
+
"max_shard_size": max_shard_size,
|
| 1676 |
+
}
|
| 1677 |
+
|
| 1678 |
+
if num_proc is None or num_proc == 1:
|
| 1679 |
+
result = None
|
| 1680 |
+
gen_kwargs = split_generator.gen_kwargs
|
| 1681 |
+
job_id = 0
|
| 1682 |
+
with pbar:
|
| 1683 |
+
for job_id, done, content in self._prepare_split_single(
|
| 1684 |
+
gen_kwargs=gen_kwargs, job_id=job_id, **_prepare_split_args
|
| 1685 |
+
):
|
| 1686 |
+
if done:
|
| 1687 |
+
result = content
|
| 1688 |
+
else:
|
| 1689 |
+
pbar.update(content)
|
| 1690 |
+
# wrapping everything into lists for consistency with the multiprocessed code path
|
| 1691 |
+
assert result is not None, "Failed to retrieve results from prepare_split"
|
| 1692 |
+
(
|
| 1693 |
+
examples_per_job,
|
| 1694 |
+
bytes_per_job,
|
| 1695 |
+
features_per_job,
|
| 1696 |
+
shards_per_job,
|
| 1697 |
+
shard_lengths_per_job,
|
| 1698 |
+
original_shards_per_job,
|
| 1699 |
+
original_shard_lengths_per_job,
|
| 1700 |
+
) = ([item] for item in result)
|
| 1701 |
+
else:
|
| 1702 |
+
kwargs_per_job = [
|
| 1703 |
+
{"gen_kwargs": gen_kwargs, "job_id": job_id, **_prepare_split_args}
|
| 1704 |
+
for job_id, gen_kwargs in enumerate(
|
| 1705 |
+
_split_gen_kwargs(split_generator.gen_kwargs, max_num_jobs=num_proc)
|
| 1706 |
+
)
|
| 1707 |
+
]
|
| 1708 |
+
num_jobs = len(kwargs_per_job)
|
| 1709 |
+
|
| 1710 |
+
examples_per_job = [None] * num_jobs
|
| 1711 |
+
bytes_per_job = [None] * num_jobs
|
| 1712 |
+
features_per_job = [None] * num_jobs
|
| 1713 |
+
shards_per_job = [None] * num_jobs
|
| 1714 |
+
shard_lengths_per_job = [None] * num_jobs
|
| 1715 |
+
original_shards_per_job = [None] * num_jobs
|
| 1716 |
+
original_shard_lengths_per_job = [None] * num_jobs
|
| 1717 |
+
|
| 1718 |
+
with Pool(num_proc) as pool:
|
| 1719 |
+
with pbar:
|
| 1720 |
+
for job_id, done, content in iflatmap_unordered(
|
| 1721 |
+
pool, self._prepare_split_single, kwargs_iterable=kwargs_per_job
|
| 1722 |
+
):
|
| 1723 |
+
if done:
|
| 1724 |
+
# the content is the result of the job
|
| 1725 |
+
(
|
| 1726 |
+
examples_per_job[job_id],
|
| 1727 |
+
bytes_per_job[job_id],
|
| 1728 |
+
features_per_job[job_id],
|
| 1729 |
+
shards_per_job[job_id],
|
| 1730 |
+
shard_lengths_per_job[job_id],
|
| 1731 |
+
original_shards_per_job[job_id],
|
| 1732 |
+
original_shard_lengths_per_job[job_id],
|
| 1733 |
+
) = content
|
| 1734 |
+
else:
|
| 1735 |
+
# the content is the number of examples progress update
|
| 1736 |
+
pbar.update(content)
|
| 1737 |
+
|
| 1738 |
+
assert None not in examples_per_job, (
|
| 1739 |
+
f"Failed to retrieve results from prepare_split: result list {examples_per_job} still contains None - at least one worker failed to return its results"
|
| 1740 |
+
)
|
| 1741 |
+
|
| 1742 |
+
total_shards = sum(shards_per_job)
|
| 1743 |
+
total_original_shards = sum(original_shards_per_job)
|
| 1744 |
+
total_num_examples = sum(examples_per_job)
|
| 1745 |
+
total_num_bytes = sum(bytes_per_job)
|
| 1746 |
+
features = features_per_job[0]
|
| 1747 |
+
|
| 1748 |
+
split_generator.split_info.num_examples = total_num_examples
|
| 1749 |
+
split_generator.split_info.num_bytes = total_num_bytes
|
| 1750 |
+
|
| 1751 |
+
# should rename everything at the end
|
| 1752 |
+
logger.debug(f"Renaming {total_shards} shards.")
|
| 1753 |
+
if total_shards > 1:
|
| 1754 |
+
# use the -SSSSS-of-NNNNN pattern
|
| 1755 |
+
|
| 1756 |
+
def _rename_shard(shard_id_and_job: tuple[int]):
|
| 1757 |
+
shard_id, job_id = shard_id_and_job
|
| 1758 |
+
global_shard_id = sum(shards_per_job[:job_id]) + shard_id
|
| 1759 |
+
self._rename(
|
| 1760 |
+
fpath.replace("SSSSS", f"{shard_id:05d}").replace("JJJJJ", f"{job_id:05d}"),
|
| 1761 |
+
fpath.replace("JJJJJ-SSSSS", f"{global_shard_id:05d}").replace("NNNNN", f"{total_shards:05d}"),
|
| 1762 |
+
)
|
| 1763 |
+
|
| 1764 |
+
shard_ids_and_jobs = [
|
| 1765 |
+
(shard_id, job_id)
|
| 1766 |
+
for job_id, num_shards in enumerate(shards_per_job)
|
| 1767 |
+
for shard_id in range(num_shards)
|
| 1768 |
+
]
|
| 1769 |
+
thread_map(_rename_shard, shard_ids_and_jobs, disable=True, max_workers=64)
|
| 1770 |
+
|
| 1771 |
+
split_generator.split_info.shard_lengths = [
|
| 1772 |
+
shard_length for shard_lengths in shard_lengths_per_job for shard_length in shard_lengths
|
| 1773 |
+
]
|
| 1774 |
+
else:
|
| 1775 |
+
# don't use any pattern
|
| 1776 |
+
shard_id, job_id = 0, 0
|
| 1777 |
+
self._rename(
|
| 1778 |
+
fpath.replace("SSSSS", f"{shard_id:05d}").replace("JJJJJ", f"{job_id:05d}"),
|
| 1779 |
+
fpath.replace(SUFFIX, ""),
|
| 1780 |
+
)
|
| 1781 |
+
|
| 1782 |
+
if total_original_shards > 1 and config.SAVE_ORIGINAL_SHARD_LENGTHS:
|
| 1783 |
+
split_generator.split_info.original_shard_lengths = [
|
| 1784 |
+
original_shard_length
|
| 1785 |
+
for original_shard_lengths in original_shard_lengths_per_job
|
| 1786 |
+
for original_shard_length in original_shard_lengths
|
| 1787 |
+
]
|
| 1788 |
+
|
| 1789 |
+
if self.info.features is None:
|
| 1790 |
+
self.info.features = features
|
| 1791 |
+
|
| 1792 |
+
def _prepare_split_single(
|
| 1793 |
+
self, gen_kwargs: dict, fpath: str, file_format: str, max_shard_size: int, job_id: int
|
| 1794 |
+
) -> Iterator[tuple[int, bool, tuple[int, int, Features, int, int, int]]]:
|
| 1795 |
+
gen_kwargs = {k: tracked_list(v) if isinstance(v, list) else v for k, v in gen_kwargs.items()}
|
| 1796 |
+
generator = self._generate_tables(**gen_kwargs)
|
| 1797 |
+
writer_class = ParquetWriter if file_format == "parquet" else ArrowWriter
|
| 1798 |
+
embed_local_files = file_format == "parquet"
|
| 1799 |
+
shard_lengths = []
|
| 1800 |
+
original_shard_lengths = []
|
| 1801 |
+
total_num_examples, total_num_bytes = 0, 0
|
| 1802 |
+
|
| 1803 |
+
shard_id = 0
|
| 1804 |
+
original_shard_id = 0
|
| 1805 |
+
num_examples_progress_update = 0
|
| 1806 |
+
try:
|
| 1807 |
+
writer = writer_class(
|
| 1808 |
+
features=self.info.features,
|
| 1809 |
+
path=fpath.replace("SSSSS", f"{shard_id:05d}").replace("JJJJJ", f"{job_id:05d}"),
|
| 1810 |
+
writer_batch_size=self._writer_batch_size,
|
| 1811 |
+
storage_options=self._fs.storage_options,
|
| 1812 |
+
embed_local_files=embed_local_files,
|
| 1813 |
+
)
|
| 1814 |
+
try:
|
| 1815 |
+
_time = time.time()
|
| 1816 |
+
for key, table in generator:
|
| 1817 |
+
if isinstance(key, Key): # old custom builders may not use Key
|
| 1818 |
+
original_shard_id = key.original_shard_id
|
| 1819 |
+
if max_shard_size is not None and writer._num_bytes > max_shard_size:
|
| 1820 |
+
num_examples, num_bytes = writer.finalize()
|
| 1821 |
+
writer.close()
|
| 1822 |
+
shard_lengths.append(num_examples)
|
| 1823 |
+
total_num_examples += num_examples
|
| 1824 |
+
total_num_bytes += num_bytes
|
| 1825 |
+
shard_id += 1
|
| 1826 |
+
writer = writer_class(
|
| 1827 |
+
features=writer._features,
|
| 1828 |
+
path=fpath.replace("SSSSS", f"{shard_id:05d}").replace("JJJJJ", f"{job_id:05d}"),
|
| 1829 |
+
writer_batch_size=self._writer_batch_size,
|
| 1830 |
+
storage_options=self._fs.storage_options,
|
| 1831 |
+
embed_local_files=embed_local_files,
|
| 1832 |
+
)
|
| 1833 |
+
try:
|
| 1834 |
+
if len(table) == 1:
|
| 1835 |
+
writer.write_row(table)
|
| 1836 |
+
else:
|
| 1837 |
+
writer.write_table(table)
|
| 1838 |
+
except CastError as cast_error:
|
| 1839 |
+
raise DatasetGenerationCastError.from_cast_error(
|
| 1840 |
+
cast_error=cast_error,
|
| 1841 |
+
builder_name=self.info.builder_name,
|
| 1842 |
+
gen_kwargs=gen_kwargs,
|
| 1843 |
+
token=self.token,
|
| 1844 |
+
)
|
| 1845 |
+
if len(original_shard_lengths) == original_shard_id:
|
| 1846 |
+
original_shard_lengths.append(len(table))
|
| 1847 |
+
else:
|
| 1848 |
+
original_shard_lengths[original_shard_id] += len(table)
|
| 1849 |
+
num_examples_progress_update += len(table)
|
| 1850 |
+
if time.time() > _time + config.PBAR_REFRESH_TIME_INTERVAL:
|
| 1851 |
+
_time = time.time()
|
| 1852 |
+
yield job_id, False, num_examples_progress_update
|
| 1853 |
+
num_examples_progress_update = 0
|
| 1854 |
+
finally:
|
| 1855 |
+
yield job_id, False, num_examples_progress_update
|
| 1856 |
+
num_shards = shard_id + 1
|
| 1857 |
+
num_original_shards = original_shard_id + 1
|
| 1858 |
+
num_examples, num_bytes = writer.finalize()
|
| 1859 |
+
writer.close()
|
| 1860 |
+
shard_lengths.append(num_examples)
|
| 1861 |
+
total_num_examples += num_examples
|
| 1862 |
+
total_num_bytes += num_bytes
|
| 1863 |
+
except Exception as e:
|
| 1864 |
+
# Ignore the writer's error for no examples written to the file if this error was caused by the error in _generate_examples before the first example was yielded
|
| 1865 |
+
if isinstance(e, SchemaInferenceError) and e.__context__ is not None:
|
| 1866 |
+
e = e.__context__
|
| 1867 |
+
if isinstance(e, DatasetGenerationError):
|
| 1868 |
+
raise
|
| 1869 |
+
raise DatasetGenerationError("An error occurred while generating the dataset") from e
|
| 1870 |
+
|
| 1871 |
+
yield (
|
| 1872 |
+
job_id,
|
| 1873 |
+
True,
|
| 1874 |
+
(
|
| 1875 |
+
total_num_examples,
|
| 1876 |
+
total_num_bytes,
|
| 1877 |
+
writer._features,
|
| 1878 |
+
num_shards,
|
| 1879 |
+
shard_lengths,
|
| 1880 |
+
num_original_shards,
|
| 1881 |
+
original_shard_lengths,
|
| 1882 |
+
),
|
| 1883 |
+
)
|
| 1884 |
+
|
| 1885 |
+
def _get_examples_iterable_for_split(self, split_generator: SplitGenerator) -> ExamplesIterable:
|
| 1886 |
+
return ArrowExamplesIterable(
|
| 1887 |
+
self._generate_tables,
|
| 1888 |
+
kwargs=split_generator.gen_kwargs,
|
| 1889 |
+
generate_more_kwargs_fn=getattr(self, "_generate_more_gen_kwargs", None),
|
| 1890 |
+
sleep_on_threads_shutdown=self.SLEEP_ON_THREADS_SHUTDOWNS,
|
| 1891 |
+
)
|
| 1892 |
+
|
| 1893 |
+
|
| 1894 |
+
class _CountableBuilderMixin(DatasetBuilder):
|
| 1895 |
+
@abc.abstractmethod
|
| 1896 |
+
def _generate_num_examples(self, **kwargs) -> Iterator[int]:
|
| 1897 |
+
raise NotImplementedError()
|
| 1898 |
+
|
| 1899 |
+
def count_examples(self, dl_manager: DownloadManager) -> dict[str, int]:
|
| 1900 |
+
split_generators_kwargs = self._make_split_generators_kwargs({})
|
| 1901 |
+
split_generators: list[SplitGenerator] = self._split_generators(dl_manager, **split_generators_kwargs)
|
| 1902 |
+
return {split_generator.name: self._count_examples(split_generator) for split_generator in split_generators}
|
| 1903 |
+
|
| 1904 |
+
def _count_examples(self, split_generator: SplitGenerator) -> int:
|
| 1905 |
+
max_workers = min(32, os.cpu_count() + 4)
|
| 1906 |
+
return sum(
|
| 1907 |
+
thread_map(
|
| 1908 |
+
self._count_examples_single,
|
| 1909 |
+
_split_gen_kwargs(split_generator.gen_kwargs, max_workers),
|
| 1910 |
+
delay=5,
|
| 1911 |
+
desc=f"Counting rows for split={split_generator.name}",
|
| 1912 |
+
)
|
| 1913 |
+
)
|
| 1914 |
+
|
| 1915 |
+
def _count_examples_single(self, gen_kwargs: dict[str, Any]) -> int:
|
| 1916 |
+
return sum(self._generate_num_examples(**gen_kwargs))
|
venv/Lib/site-packages/datasets/combine.py
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import Optional, TypeVar
|
| 2 |
+
|
| 3 |
+
from .arrow_dataset import Dataset, _concatenate_map_style_datasets, _interleave_map_style_datasets
|
| 4 |
+
from .dataset_dict import DatasetDict, IterableDatasetDict
|
| 5 |
+
from .info import DatasetInfo
|
| 6 |
+
from .iterable_dataset import IterableDataset, _concatenate_iterable_datasets, _interleave_iterable_datasets
|
| 7 |
+
from .splits import NamedSplit
|
| 8 |
+
from .utils import logging
|
| 9 |
+
from .utils.py_utils import Literal
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
logger = logging.get_logger(__name__)
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
DatasetType = TypeVar("DatasetType", Dataset, IterableDataset)
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def interleave_datasets(
|
| 19 |
+
datasets: list[DatasetType],
|
| 20 |
+
probabilities: Optional[list[float]] = None,
|
| 21 |
+
seed: Optional[int] = None,
|
| 22 |
+
info: Optional[DatasetInfo] = None,
|
| 23 |
+
split: Optional[NamedSplit] = None,
|
| 24 |
+
stopping_strategy: Literal[
|
| 25 |
+
"first_exhausted", "all_exhausted", "all_exhausted_without_replacement"
|
| 26 |
+
] = "first_exhausted",
|
| 27 |
+
) -> DatasetType:
|
| 28 |
+
"""
|
| 29 |
+
Interleave several datasets (sources) into a single dataset.
|
| 30 |
+
The new dataset is constructed by alternating between the sources to get the examples.
|
| 31 |
+
|
| 32 |
+
You can use this function on a list of [`Dataset`] objects, or on a list of [`IterableDataset`] objects.
|
| 33 |
+
|
| 34 |
+
- If `probabilities` is `None` (default) the new dataset is constructed by cycling between each source to get the examples.
|
| 35 |
+
- If `probabilities` is not `None`, the new dataset is constructed by getting examples from a random source at a time according to the provided probabilities.
|
| 36 |
+
|
| 37 |
+
The resulting dataset ends when one of the source datasets runs out of examples except when `oversampling` is `True`,
|
| 38 |
+
in which case, the resulting dataset ends when all datasets have ran out of examples at least one time.
|
| 39 |
+
|
| 40 |
+
Note for iterable datasets:
|
| 41 |
+
|
| 42 |
+
* The resulting dataset's `num_shards` is the minimum of each dataset's `num_shards` to ensure good parallelism.
|
| 43 |
+
If some of your datasets have a very low number of shards, you may use [`IterableDataset.reshard`].
|
| 44 |
+
* In a distributed setup or in PyTorch DataLoader workers, the stopping strategy is applied per process.
|
| 45 |
+
Therefore the "first_exhausted" strategy on an sharded iterable dataset can generate less samples in total (up to 1 missing sample per subdataset per worker).
|
| 46 |
+
|
| 47 |
+
Args:
|
| 48 |
+
datasets (`List[Dataset]` or `List[IterableDataset]`):
|
| 49 |
+
List of datasets to interleave.
|
| 50 |
+
probabilities (`List[float]`, *optional*, defaults to `None`):
|
| 51 |
+
If specified, the new dataset is constructed by sampling
|
| 52 |
+
examples from one source at a time according to these probabilities.
|
| 53 |
+
seed (`int`, *optional*, defaults to `None`):
|
| 54 |
+
The random seed used to choose a source for each example.
|
| 55 |
+
info ([`DatasetInfo`], *optional*):
|
| 56 |
+
Dataset information, like description, citation, etc.
|
| 57 |
+
<Added version="2.4.0"/>
|
| 58 |
+
split ([`NamedSplit`], *optional*):
|
| 59 |
+
Name of the dataset split.
|
| 60 |
+
<Added version="2.4.0"/>
|
| 61 |
+
stopping_strategy (`str`, defaults to `first_exhausted`):
|
| 62 |
+
Three strategies are proposed right now, `first_exhausted`, `all_exhausted` and `all_exhausted_without_replacement`.
|
| 63 |
+
By default, `first_exhausted` is an undersampling strategy, i.e the dataset construction is stopped as soon as one dataset has ran out of samples.
|
| 64 |
+
If the strategy is `all_exhausted`, we use an oversampling strategy, i.e the dataset construction is stopped as soon as every samples of every dataset has been added at least once.
|
| 65 |
+
When strategy is `all_exhausted_without_replacement` we make sure that each sample in each dataset is sampled only once.
|
| 66 |
+
Note that if the strategy is `all_exhausted`, the interleaved dataset size can get enormous:
|
| 67 |
+
- with no probabilities, the resulting dataset will have `max_length_datasets*nb_dataset` samples.
|
| 68 |
+
- with given probabilities, the resulting dataset will have more samples if some datasets have really low probability of visiting.
|
| 69 |
+
Returns:
|
| 70 |
+
[`Dataset`] or [`IterableDataset`]: Return type depends on the input `datasets`
|
| 71 |
+
parameter. `Dataset` if the input is a list of `Dataset`, `IterableDataset` if the input is a list of
|
| 72 |
+
`IterableDataset`.
|
| 73 |
+
|
| 74 |
+
Example:
|
| 75 |
+
|
| 76 |
+
For regular datasets (map-style):
|
| 77 |
+
|
| 78 |
+
```python
|
| 79 |
+
>>> from datasets import Dataset, interleave_datasets
|
| 80 |
+
>>> d1 = Dataset.from_dict({"a": [0, 1, 2]})
|
| 81 |
+
>>> d2 = Dataset.from_dict({"a": [10, 11, 12]})
|
| 82 |
+
>>> d3 = Dataset.from_dict({"a": [20, 21, 22]})
|
| 83 |
+
>>> dataset = interleave_datasets([d1, d2, d3], probabilities=[0.7, 0.2, 0.1], seed=42, stopping_strategy="all_exhausted")
|
| 84 |
+
>>> dataset["a"]
|
| 85 |
+
[10, 0, 11, 1, 2, 20, 12, 10, 0, 1, 2, 21, 0, 11, 1, 2, 0, 1, 12, 2, 10, 0, 22]
|
| 86 |
+
>>> dataset = interleave_datasets([d1, d2, d3], probabilities=[0.7, 0.2, 0.1], seed=42)
|
| 87 |
+
>>> dataset["a"]
|
| 88 |
+
[10, 0, 11, 1, 2]
|
| 89 |
+
>>> dataset = interleave_datasets([d1, d2, d3])
|
| 90 |
+
>>> dataset["a"]
|
| 91 |
+
[0, 10, 20, 1, 11, 21, 2, 12, 22]
|
| 92 |
+
>>> dataset = interleave_datasets([d1, d2, d3], stopping_strategy="all_exhausted")
|
| 93 |
+
>>> dataset["a"]
|
| 94 |
+
[0, 10, 20, 1, 11, 21, 2, 12, 22]
|
| 95 |
+
>>> d1 = Dataset.from_dict({"a": [0, 1, 2]})
|
| 96 |
+
>>> d2 = Dataset.from_dict({"a": [10, 11, 12, 13]})
|
| 97 |
+
>>> d3 = Dataset.from_dict({"a": [20, 21, 22, 23, 24]})
|
| 98 |
+
>>> dataset = interleave_datasets([d1, d2, d3])
|
| 99 |
+
>>> dataset["a"]
|
| 100 |
+
[0, 10, 20, 1, 11, 21, 2, 12, 22]
|
| 101 |
+
>>> dataset = interleave_datasets([d1, d2, d3], stopping_strategy="all_exhausted")
|
| 102 |
+
>>> dataset["a"]
|
| 103 |
+
[0, 10, 20, 1, 11, 21, 2, 12, 22, 0, 13, 23, 1, 10, 24]
|
| 104 |
+
>>> dataset = interleave_datasets([d1, d2, d3], probabilities=[0.7, 0.2, 0.1], seed=42)
|
| 105 |
+
>>> dataset["a"]
|
| 106 |
+
[10, 0, 11, 1, 2]
|
| 107 |
+
>>> dataset = interleave_datasets([d1, d2, d3], probabilities=[0.7, 0.2, 0.1], seed=42, stopping_strategy="all_exhausted")
|
| 108 |
+
>>> dataset["a"]
|
| 109 |
+
[10, 0, 11, 1, 2, 20, 12, 13, ..., 0, 1, 2, 0, 24]
|
| 110 |
+
For datasets in streaming mode (iterable):
|
| 111 |
+
|
| 112 |
+
>>> from datasets import interleave_datasets
|
| 113 |
+
>>> d1 = load_dataset('allenai/c4', 'es', split='train', streaming=True)
|
| 114 |
+
>>> d2 = load_dataset('allenai/c4', 'fr', split='train', streaming=True)
|
| 115 |
+
>>> dataset = interleave_datasets([d1, d2])
|
| 116 |
+
>>> iterator = iter(dataset)
|
| 117 |
+
>>> next(iterator)
|
| 118 |
+
{'text': 'Comprar Zapatillas para niña en chancla con goma por...'}
|
| 119 |
+
>>> next(iterator)
|
| 120 |
+
{'text': 'Le sacre de philippe ier, 23 mai 1059 - Compte Rendu...'
|
| 121 |
+
```
|
| 122 |
+
"""
|
| 123 |
+
from .arrow_dataset import Dataset
|
| 124 |
+
from .iterable_dataset import IterableDataset
|
| 125 |
+
|
| 126 |
+
if not datasets:
|
| 127 |
+
raise ValueError("Unable to interleave an empty list of datasets.")
|
| 128 |
+
for i, dataset in enumerate(datasets):
|
| 129 |
+
if not isinstance(dataset, (Dataset, IterableDataset)):
|
| 130 |
+
if isinstance(dataset, (DatasetDict, IterableDatasetDict)):
|
| 131 |
+
if not dataset:
|
| 132 |
+
raise ValueError(
|
| 133 |
+
f"Expected a list of Dataset objects or a list of IterableDataset objects, but element at position {i} "
|
| 134 |
+
"is an empty dataset dictionary."
|
| 135 |
+
)
|
| 136 |
+
raise ValueError(
|
| 137 |
+
f"Dataset at position {i} has at least one split: {list(dataset)}\n"
|
| 138 |
+
f"Please pick one to interleave with the other datasets, for example: dataset['{next(iter(dataset))}']"
|
| 139 |
+
)
|
| 140 |
+
raise ValueError(
|
| 141 |
+
f"Expected a list of Dataset objects or a list of IterableDataset objects, but element at position {i} is a {type(dataset).__name__}."
|
| 142 |
+
)
|
| 143 |
+
if i == 0:
|
| 144 |
+
dataset_type, other_type = (
|
| 145 |
+
(Dataset, IterableDataset) if isinstance(dataset, Dataset) else (IterableDataset, Dataset)
|
| 146 |
+
)
|
| 147 |
+
elif not isinstance(dataset, dataset_type):
|
| 148 |
+
raise ValueError(
|
| 149 |
+
f"Unable to interleave a {dataset_type.__name__} (at position 0) with a {other_type.__name__} (at position {i}). Expected a list of Dataset objects or a list of IterableDataset objects."
|
| 150 |
+
)
|
| 151 |
+
if stopping_strategy not in ["first_exhausted", "all_exhausted", "all_exhausted_without_replacement"]:
|
| 152 |
+
raise ValueError(f"{stopping_strategy} is not supported. Please enter a valid stopping_strategy.")
|
| 153 |
+
if dataset_type is Dataset:
|
| 154 |
+
return _interleave_map_style_datasets(
|
| 155 |
+
datasets, probabilities, seed, info=info, split=split, stopping_strategy=stopping_strategy
|
| 156 |
+
)
|
| 157 |
+
else:
|
| 158 |
+
return _interleave_iterable_datasets(
|
| 159 |
+
datasets,
|
| 160 |
+
probabilities,
|
| 161 |
+
seed,
|
| 162 |
+
info=info,
|
| 163 |
+
split=split,
|
| 164 |
+
stopping_strategy=stopping_strategy,
|
| 165 |
+
)
|
| 166 |
+
|
| 167 |
+
|
| 168 |
+
def concatenate_datasets(
|
| 169 |
+
dsets: list[DatasetType],
|
| 170 |
+
info: Optional[DatasetInfo] = None,
|
| 171 |
+
split: Optional[NamedSplit] = None,
|
| 172 |
+
axis: int = 0,
|
| 173 |
+
) -> DatasetType:
|
| 174 |
+
"""
|
| 175 |
+
Concatenate several datasets (sources) into a single dataset.
|
| 176 |
+
|
| 177 |
+
Use axis=0 to concatenate vertically (default), or axis=1 to concatenate horizontally.
|
| 178 |
+
|
| 179 |
+
Note for iterable datasets:
|
| 180 |
+
|
| 181 |
+
* if axis=0, the resulting dataset's `num_shards` is the sum of each dataset's `num_shards`.
|
| 182 |
+
* if axis=1, the resulting dataset has one (1) shard to not misalign data.
|
| 183 |
+
|
| 184 |
+
Args:
|
| 185 |
+
dsets (`List[datasets.Dataset]` or `List[datasets.IterableDataset]`):
|
| 186 |
+
List of Datasets to concatenate.
|
| 187 |
+
info (`DatasetInfo`, *optional*):
|
| 188 |
+
Dataset information, like description, citation, etc.
|
| 189 |
+
split (`NamedSplit`, *optional*):
|
| 190 |
+
Name of the dataset split.
|
| 191 |
+
axis (`{0, 1}`, defaults to `0`):
|
| 192 |
+
Axis to concatenate over, where `0` means over rows (vertically) and `1` means over columns
|
| 193 |
+
(horizontally).
|
| 194 |
+
|
| 195 |
+
<Added version="1.6.0"/>
|
| 196 |
+
|
| 197 |
+
Example:
|
| 198 |
+
|
| 199 |
+
```py
|
| 200 |
+
>>> ds3 = concatenate_datasets([ds1, ds2])
|
| 201 |
+
```
|
| 202 |
+
"""
|
| 203 |
+
|
| 204 |
+
if not dsets:
|
| 205 |
+
raise ValueError("Unable to concatenate an empty list of datasets.")
|
| 206 |
+
for i, dataset in enumerate(dsets):
|
| 207 |
+
if not isinstance(dataset, (Dataset, IterableDataset)):
|
| 208 |
+
if isinstance(dataset, (DatasetDict, IterableDatasetDict)):
|
| 209 |
+
if not dataset:
|
| 210 |
+
raise ValueError(
|
| 211 |
+
f"Expected a list of Dataset objects or a list of IterableDataset objects, but element at position {i} "
|
| 212 |
+
"is an empty dataset dictionary."
|
| 213 |
+
)
|
| 214 |
+
raise ValueError(
|
| 215 |
+
f"Dataset at position {i} has at least one split: {list(dataset)}\n"
|
| 216 |
+
f"Please pick one to interleave with the other datasets, for example: dataset['{next(iter(dataset))}']"
|
| 217 |
+
)
|
| 218 |
+
raise ValueError(
|
| 219 |
+
f"Expected a list of Dataset objects or a list of IterableDataset objects, but element at position {i} is a {type(dataset).__name__}."
|
| 220 |
+
)
|
| 221 |
+
if i == 0:
|
| 222 |
+
dataset_type, other_type = (
|
| 223 |
+
(Dataset, IterableDataset) if isinstance(dataset, Dataset) else (IterableDataset, Dataset)
|
| 224 |
+
)
|
| 225 |
+
elif not isinstance(dataset, dataset_type):
|
| 226 |
+
raise ValueError(
|
| 227 |
+
f"Unable to interleave a {dataset_type.__name__} (at position 0) with a {other_type.__name__} (at position {i}). Expected a list of Dataset objects or a list of IterableDataset objects."
|
| 228 |
+
)
|
| 229 |
+
if dataset_type is Dataset:
|
| 230 |
+
return _concatenate_map_style_datasets(dsets, info=info, split=split, axis=axis)
|
| 231 |
+
else:
|
| 232 |
+
return _concatenate_iterable_datasets(dsets, info=info, split=split, axis=axis)
|
venv/Lib/site-packages/datasets/commands/__init__.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from abc import ABC, abstractmethod
|
| 2 |
+
from argparse import ArgumentParser
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
class BaseDatasetsCLICommand(ABC):
|
| 6 |
+
@staticmethod
|
| 7 |
+
@abstractmethod
|
| 8 |
+
def register_subcommand(parser: ArgumentParser):
|
| 9 |
+
raise NotImplementedError()
|
| 10 |
+
|
| 11 |
+
@abstractmethod
|
| 12 |
+
def run(self):
|
| 13 |
+
raise NotImplementedError()
|
venv/Lib/site-packages/datasets/commands/__pycache__/__init__.cpython-311.pyc
ADDED
|
Binary file (1.11 kB). View file
|
|
|
venv/Lib/site-packages/datasets/commands/__pycache__/datasets_cli.cpython-311.pyc
ADDED
|
Binary file (2.36 kB). View file
|
|
|
venv/Lib/site-packages/datasets/commands/__pycache__/delete_from_hub.cpython-311.pyc
ADDED
|
Binary file (2.7 kB). View file
|
|
|
venv/Lib/site-packages/datasets/commands/__pycache__/env.cpython-311.pyc
ADDED
|
Binary file (2.8 kB). View file
|
|
|
venv/Lib/site-packages/datasets/commands/__pycache__/test.cpython-311.pyc
ADDED
|
Binary file (9.84 kB). View file
|
|
|
venv/Lib/site-packages/datasets/commands/datasets_cli.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python
|
| 2 |
+
from argparse import ArgumentParser
|
| 3 |
+
|
| 4 |
+
from datasets.commands.delete_from_hub import DeleteFromHubCommand
|
| 5 |
+
from datasets.commands.env import EnvironmentCommand
|
| 6 |
+
from datasets.commands.test import TestCommand
|
| 7 |
+
from datasets.utils.logging import set_verbosity_info
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
def parse_unknown_args(unknown_args):
|
| 11 |
+
return {key.lstrip("-"): value for key, value in zip(unknown_args[::2], unknown_args[1::2])}
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
def main():
|
| 15 |
+
parser = ArgumentParser(
|
| 16 |
+
"HuggingFace Datasets CLI tool", usage="datasets-cli <command> [<args>]", allow_abbrev=False
|
| 17 |
+
)
|
| 18 |
+
commands_parser = parser.add_subparsers(help="datasets-cli command helpers")
|
| 19 |
+
set_verbosity_info()
|
| 20 |
+
|
| 21 |
+
# Register commands
|
| 22 |
+
EnvironmentCommand.register_subcommand(commands_parser)
|
| 23 |
+
TestCommand.register_subcommand(commands_parser)
|
| 24 |
+
DeleteFromHubCommand.register_subcommand(commands_parser)
|
| 25 |
+
|
| 26 |
+
# Parse args
|
| 27 |
+
args, unknown_args = parser.parse_known_args()
|
| 28 |
+
if not hasattr(args, "func"):
|
| 29 |
+
parser.print_help()
|
| 30 |
+
exit(1)
|
| 31 |
+
kwargs = parse_unknown_args(unknown_args)
|
| 32 |
+
|
| 33 |
+
# Run
|
| 34 |
+
service = args.func(args, **kwargs)
|
| 35 |
+
service.run()
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
if __name__ == "__main__":
|
| 39 |
+
main()
|
venv/Lib/site-packages/datasets/commands/delete_from_hub.py
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from argparse import ArgumentParser
|
| 2 |
+
from typing import Optional
|
| 3 |
+
|
| 4 |
+
from datasets.commands import BaseDatasetsCLICommand
|
| 5 |
+
from datasets.hub import delete_from_hub
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
def _command_factory(args):
|
| 9 |
+
return DeleteFromHubCommand(
|
| 10 |
+
args.dataset_id,
|
| 11 |
+
args.config_name,
|
| 12 |
+
args.token,
|
| 13 |
+
args.revision,
|
| 14 |
+
)
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
class DeleteFromHubCommand(BaseDatasetsCLICommand):
|
| 18 |
+
@staticmethod
|
| 19 |
+
def register_subcommand(parser):
|
| 20 |
+
parser: ArgumentParser = parser.add_parser("delete_from_hub", help="Delete dataset config from the Hub")
|
| 21 |
+
parser.add_argument(
|
| 22 |
+
"dataset_id", help="source dataset ID, e.g. USERNAME/DATASET_NAME or ORGANIZATION/DATASET_NAME"
|
| 23 |
+
)
|
| 24 |
+
parser.add_argument("config_name", help="config name to delete")
|
| 25 |
+
parser.add_argument("--token", help="access token to the Hugging Face Hub")
|
| 26 |
+
parser.add_argument("--revision", help="source revision")
|
| 27 |
+
parser.set_defaults(func=_command_factory)
|
| 28 |
+
|
| 29 |
+
def __init__(
|
| 30 |
+
self,
|
| 31 |
+
dataset_id: str,
|
| 32 |
+
config_name: str,
|
| 33 |
+
token: Optional[str],
|
| 34 |
+
revision: Optional[str],
|
| 35 |
+
):
|
| 36 |
+
self._dataset_id = dataset_id
|
| 37 |
+
self._config_name = config_name
|
| 38 |
+
self._token = token
|
| 39 |
+
self._revision = revision
|
| 40 |
+
|
| 41 |
+
def run(self) -> None:
|
| 42 |
+
_ = delete_from_hub(self._dataset_id, self._config_name, revision=self._revision, token=self._token)
|
venv/Lib/site-packages/datasets/commands/env.py
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import platform
|
| 2 |
+
from argparse import ArgumentParser
|
| 3 |
+
|
| 4 |
+
import fsspec
|
| 5 |
+
import huggingface_hub
|
| 6 |
+
import pandas
|
| 7 |
+
import pyarrow
|
| 8 |
+
|
| 9 |
+
from datasets import __version__ as version
|
| 10 |
+
from datasets.commands import BaseDatasetsCLICommand
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
def info_command_factory(_):
|
| 14 |
+
return EnvironmentCommand()
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
class EnvironmentCommand(BaseDatasetsCLICommand):
|
| 18 |
+
@staticmethod
|
| 19 |
+
def register_subcommand(parser: ArgumentParser):
|
| 20 |
+
download_parser = parser.add_parser("env", help="Print relevant system environment info.")
|
| 21 |
+
download_parser.set_defaults(func=info_command_factory)
|
| 22 |
+
|
| 23 |
+
def run(self):
|
| 24 |
+
info = {
|
| 25 |
+
"`datasets` version": version,
|
| 26 |
+
"Platform": platform.platform(),
|
| 27 |
+
"Python version": platform.python_version(),
|
| 28 |
+
"`huggingface_hub` version": huggingface_hub.__version__,
|
| 29 |
+
"PyArrow version": pyarrow.__version__,
|
| 30 |
+
"Pandas version": pandas.__version__,
|
| 31 |
+
"`fsspec` version": fsspec.__version__,
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
print("\nCopy-and-paste the text below in your GitHub issue.\n")
|
| 35 |
+
print(self.format_dict(info))
|
| 36 |
+
|
| 37 |
+
return info
|
| 38 |
+
|
| 39 |
+
@staticmethod
|
| 40 |
+
def format_dict(d):
|
| 41 |
+
return "\n".join([f"- {prop}: {val}" for prop, val in d.items()]) + "\n"
|
venv/Lib/site-packages/datasets/commands/test.py
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import logging
|
| 2 |
+
import os
|
| 3 |
+
from argparse import ArgumentParser
|
| 4 |
+
from collections.abc import Generator
|
| 5 |
+
from shutil import rmtree
|
| 6 |
+
|
| 7 |
+
import datasets.config
|
| 8 |
+
from datasets.builder import DatasetBuilder
|
| 9 |
+
from datasets.commands import BaseDatasetsCLICommand
|
| 10 |
+
from datasets.download.download_manager import DownloadMode
|
| 11 |
+
from datasets.info import DatasetInfosDict
|
| 12 |
+
from datasets.load import dataset_module_factory, get_dataset_builder_class
|
| 13 |
+
from datasets.utils.info_utils import VerificationMode
|
| 14 |
+
from datasets.utils.logging import ERROR, get_logger
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
logger = get_logger(__name__)
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
def _test_command_factory(args):
|
| 21 |
+
return TestCommand(
|
| 22 |
+
args.dataset,
|
| 23 |
+
args.name,
|
| 24 |
+
args.cache_dir,
|
| 25 |
+
args.data_dir,
|
| 26 |
+
args.all_configs,
|
| 27 |
+
args.save_info or args.save_infos,
|
| 28 |
+
args.ignore_verifications,
|
| 29 |
+
args.force_redownload,
|
| 30 |
+
args.clear_cache,
|
| 31 |
+
args.num_proc,
|
| 32 |
+
)
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
class TestCommand(BaseDatasetsCLICommand):
|
| 36 |
+
__test__ = False # to tell pytest it's not a test class
|
| 37 |
+
|
| 38 |
+
@staticmethod
|
| 39 |
+
def register_subcommand(parser: ArgumentParser):
|
| 40 |
+
test_parser = parser.add_parser("test", help="Test dataset loading.")
|
| 41 |
+
test_parser.add_argument("--name", type=str, default=None, help="Dataset processing name")
|
| 42 |
+
test_parser.add_argument(
|
| 43 |
+
"--cache_dir",
|
| 44 |
+
type=str,
|
| 45 |
+
default=None,
|
| 46 |
+
help="Cache directory where the datasets are stored.",
|
| 47 |
+
)
|
| 48 |
+
test_parser.add_argument(
|
| 49 |
+
"--data_dir",
|
| 50 |
+
type=str,
|
| 51 |
+
default=None,
|
| 52 |
+
help="Can be used to specify a manual directory to get the files from.",
|
| 53 |
+
)
|
| 54 |
+
test_parser.add_argument("--all_configs", action="store_true", help="Test all dataset configurations")
|
| 55 |
+
test_parser.add_argument(
|
| 56 |
+
"--save_info", action="store_true", help="Save the dataset infos in the dataset card (README.md)"
|
| 57 |
+
)
|
| 58 |
+
test_parser.add_argument(
|
| 59 |
+
"--ignore_verifications",
|
| 60 |
+
action="store_true",
|
| 61 |
+
help="Run the test without checksums and splits checks.",
|
| 62 |
+
)
|
| 63 |
+
test_parser.add_argument("--force_redownload", action="store_true", help="Force dataset redownload")
|
| 64 |
+
test_parser.add_argument(
|
| 65 |
+
"--clear_cache",
|
| 66 |
+
action="store_true",
|
| 67 |
+
help="Remove downloaded files and cached datasets after each config test",
|
| 68 |
+
)
|
| 69 |
+
test_parser.add_argument("--num_proc", type=int, default=None, help="Number of processes")
|
| 70 |
+
# aliases
|
| 71 |
+
test_parser.add_argument("--save_infos", action="store_true", help="alias to save_info")
|
| 72 |
+
test_parser.add_argument("dataset", type=str, help="Name of the dataset to download")
|
| 73 |
+
test_parser.set_defaults(func=_test_command_factory)
|
| 74 |
+
|
| 75 |
+
def __init__(
|
| 76 |
+
self,
|
| 77 |
+
dataset: str,
|
| 78 |
+
name: str,
|
| 79 |
+
cache_dir: str,
|
| 80 |
+
data_dir: str,
|
| 81 |
+
all_configs: bool,
|
| 82 |
+
save_infos: bool,
|
| 83 |
+
ignore_verifications: bool,
|
| 84 |
+
force_redownload: bool,
|
| 85 |
+
clear_cache: bool,
|
| 86 |
+
num_proc: int,
|
| 87 |
+
):
|
| 88 |
+
self._dataset = dataset
|
| 89 |
+
self._name = name
|
| 90 |
+
self._cache_dir = cache_dir
|
| 91 |
+
self._data_dir = data_dir
|
| 92 |
+
self._all_configs = all_configs
|
| 93 |
+
self._save_infos = save_infos
|
| 94 |
+
self._ignore_verifications = ignore_verifications
|
| 95 |
+
self._force_redownload = force_redownload
|
| 96 |
+
self._clear_cache = clear_cache
|
| 97 |
+
self._num_proc = num_proc
|
| 98 |
+
if clear_cache and not cache_dir:
|
| 99 |
+
print(
|
| 100 |
+
"When --clear_cache is used, specifying a cache directory is mandatory.\n"
|
| 101 |
+
"The 'download' folder of the cache directory and the dataset builder cache will be deleted after each configuration test.\n"
|
| 102 |
+
"Please provide a --cache_dir that will be used to test the dataset."
|
| 103 |
+
)
|
| 104 |
+
exit(1)
|
| 105 |
+
if save_infos:
|
| 106 |
+
self._ignore_verifications = True
|
| 107 |
+
|
| 108 |
+
def run(self):
|
| 109 |
+
logging.getLogger("filelock").setLevel(ERROR)
|
| 110 |
+
if self._name is not None and self._all_configs:
|
| 111 |
+
print("Both parameters `config` and `all_configs` can't be used at once.")
|
| 112 |
+
exit(1)
|
| 113 |
+
path, config_name = self._dataset, self._name
|
| 114 |
+
module = dataset_module_factory(path)
|
| 115 |
+
builder_cls = get_dataset_builder_class(module)
|
| 116 |
+
n_builders = len(builder_cls.BUILDER_CONFIGS) if self._all_configs and builder_cls.BUILDER_CONFIGS else 1
|
| 117 |
+
|
| 118 |
+
def get_builders() -> Generator[DatasetBuilder, None, None]:
|
| 119 |
+
if self._all_configs and builder_cls.BUILDER_CONFIGS:
|
| 120 |
+
for i, config in enumerate(builder_cls.BUILDER_CONFIGS):
|
| 121 |
+
if "config_name" in module.builder_kwargs:
|
| 122 |
+
yield builder_cls(
|
| 123 |
+
cache_dir=self._cache_dir,
|
| 124 |
+
data_dir=self._data_dir,
|
| 125 |
+
**module.builder_kwargs,
|
| 126 |
+
)
|
| 127 |
+
else:
|
| 128 |
+
yield builder_cls(
|
| 129 |
+
config_name=config.name,
|
| 130 |
+
cache_dir=self._cache_dir,
|
| 131 |
+
data_dir=self._data_dir,
|
| 132 |
+
**module.builder_kwargs,
|
| 133 |
+
)
|
| 134 |
+
else:
|
| 135 |
+
if "config_name" in module.builder_kwargs:
|
| 136 |
+
yield builder_cls(cache_dir=self._cache_dir, data_dir=self._data_dir, **module.builder_kwargs)
|
| 137 |
+
else:
|
| 138 |
+
yield builder_cls(
|
| 139 |
+
config_name=config_name,
|
| 140 |
+
cache_dir=self._cache_dir,
|
| 141 |
+
data_dir=self._data_dir,
|
| 142 |
+
**module.builder_kwargs,
|
| 143 |
+
)
|
| 144 |
+
|
| 145 |
+
for j, builder in enumerate(get_builders()):
|
| 146 |
+
print(f"Testing builder '{builder.config.name}' ({j + 1}/{n_builders})")
|
| 147 |
+
builder._record_checksums = os.path.exists(
|
| 148 |
+
os.path.join(builder.get_imported_module_dir(), datasets.config.DATASETDICT_INFOS_FILENAME)
|
| 149 |
+
) # record checksums only if we need to update a (deprecated) dataset_infos.json
|
| 150 |
+
builder.download_and_prepare(
|
| 151 |
+
download_mode=DownloadMode.REUSE_CACHE_IF_EXISTS
|
| 152 |
+
if not self._force_redownload
|
| 153 |
+
else DownloadMode.FORCE_REDOWNLOAD,
|
| 154 |
+
verification_mode=VerificationMode.NO_CHECKS
|
| 155 |
+
if self._ignore_verifications
|
| 156 |
+
else VerificationMode.ALL_CHECKS,
|
| 157 |
+
num_proc=self._num_proc,
|
| 158 |
+
)
|
| 159 |
+
builder.as_dataset()
|
| 160 |
+
|
| 161 |
+
# If save_infos=True, we create the dataset card (README.md)
|
| 162 |
+
# The dataset_infos are saved in the YAML part of the README.md
|
| 163 |
+
# This is to allow the user to upload them on HF afterwards.
|
| 164 |
+
if self._save_infos:
|
| 165 |
+
save_infos_dir = os.path.basename(path) if not os.path.isdir(path) else path
|
| 166 |
+
os.makedirs(save_infos_dir, exist_ok=True)
|
| 167 |
+
DatasetInfosDict(**{builder.config.name: builder.info}).write_to_directory(save_infos_dir)
|
| 168 |
+
print(f"Dataset card saved at {os.path.join(save_infos_dir, datasets.config.REPOCARD_FILENAME)}")
|
| 169 |
+
|
| 170 |
+
# If clear_cache=True, the download folder and the dataset builder cache directory are deleted
|
| 171 |
+
if self._clear_cache:
|
| 172 |
+
if os.path.isdir(builder._cache_dir):
|
| 173 |
+
logger.warning(f"Clearing cache at {builder._cache_dir}")
|
| 174 |
+
rmtree(builder._cache_dir)
|
| 175 |
+
download_dir = os.path.join(self._cache_dir, datasets.config.DOWNLOADED_DATASETS_DIR)
|
| 176 |
+
if os.path.isdir(download_dir):
|
| 177 |
+
logger.warning(f"Clearing cache at {download_dir}")
|
| 178 |
+
rmtree(download_dir)
|
| 179 |
+
|
| 180 |
+
print("Test successful.")
|
venv/Lib/site-packages/datasets/config.py
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import importlib
|
| 2 |
+
import importlib.metadata
|
| 3 |
+
import logging
|
| 4 |
+
import os
|
| 5 |
+
import platform
|
| 6 |
+
from pathlib import Path
|
| 7 |
+
from typing import Optional
|
| 8 |
+
|
| 9 |
+
from huggingface_hub import constants
|
| 10 |
+
from packaging import version
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
logger = logging.getLogger(__name__.split(".", 1)[0]) # to avoid circular import from .utils.logging
|
| 14 |
+
|
| 15 |
+
# Datasets
|
| 16 |
+
S3_DATASETS_BUCKET_PREFIX = "https://s3.amazonaws.com/datasets.huggingface.co/datasets/datasets"
|
| 17 |
+
CLOUDFRONT_DATASETS_DISTRIB_PREFIX = "https://cdn-datasets.huggingface.co/datasets/datasets"
|
| 18 |
+
REPO_DATASETS_URL = "https://raw.githubusercontent.com/huggingface/datasets/{revision}/datasets/{path}/{name}"
|
| 19 |
+
|
| 20 |
+
# Hub
|
| 21 |
+
HF_ENDPOINT = os.environ.get("HF_ENDPOINT", "https://huggingface.co")
|
| 22 |
+
HUB_DATASETS_URL = HF_ENDPOINT + "/datasets/{repo_id}/resolve/{revision}/{path}"
|
| 23 |
+
HUB_DATASETS_HFFS_URL = "hf://datasets/{repo_id}@{revision}/{path}"
|
| 24 |
+
HUB_DEFAULT_VERSION = "main"
|
| 25 |
+
|
| 26 |
+
PY_VERSION = version.parse(platform.python_version())
|
| 27 |
+
|
| 28 |
+
# General environment variables accepted values for booleans
|
| 29 |
+
ENV_VARS_TRUE_VALUES = {"1", "ON", "YES", "TRUE"}
|
| 30 |
+
ENV_VARS_FALSE_VALUES = {"0", "OFF", "NO", "FALSE"}
|
| 31 |
+
ENV_VARS_TRUE_AND_AUTO_VALUES = ENV_VARS_TRUE_VALUES.union({"AUTO"})
|
| 32 |
+
ENV_VARS_FALSE_AND_AUTO_VALUES = ENV_VARS_FALSE_VALUES.union({"AUTO"})
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
# Imports
|
| 36 |
+
DILL_VERSION = version.parse(importlib.metadata.version("dill"))
|
| 37 |
+
FSSPEC_VERSION = version.parse(importlib.metadata.version("fsspec"))
|
| 38 |
+
PANDAS_VERSION = version.parse(importlib.metadata.version("pandas"))
|
| 39 |
+
PYARROW_VERSION = version.parse(importlib.metadata.version("pyarrow"))
|
| 40 |
+
HF_HUB_VERSION = version.parse(importlib.metadata.version("huggingface_hub"))
|
| 41 |
+
|
| 42 |
+
USE_TF = os.environ.get("USE_TF", "AUTO").upper()
|
| 43 |
+
USE_TORCH = os.environ.get("USE_TORCH", "AUTO").upper()
|
| 44 |
+
USE_JAX = os.environ.get("USE_JAX", "AUTO").upper()
|
| 45 |
+
|
| 46 |
+
TORCH_VERSION = "N/A"
|
| 47 |
+
TORCH_AVAILABLE = False
|
| 48 |
+
|
| 49 |
+
if USE_TORCH in ENV_VARS_TRUE_AND_AUTO_VALUES and USE_TF not in ENV_VARS_TRUE_VALUES:
|
| 50 |
+
TORCH_AVAILABLE = importlib.util.find_spec("torch") is not None
|
| 51 |
+
if TORCH_AVAILABLE:
|
| 52 |
+
try:
|
| 53 |
+
TORCH_VERSION = version.parse(importlib.metadata.version("torch"))
|
| 54 |
+
logger.debug(f"PyTorch version {TORCH_VERSION} available.")
|
| 55 |
+
except importlib.metadata.PackageNotFoundError:
|
| 56 |
+
pass
|
| 57 |
+
else:
|
| 58 |
+
logger.info("Disabling PyTorch because USE_TF is set")
|
| 59 |
+
|
| 60 |
+
POLARS_VERSION = "N/A"
|
| 61 |
+
POLARS_AVAILABLE = importlib.util.find_spec("polars") is not None
|
| 62 |
+
|
| 63 |
+
if POLARS_AVAILABLE:
|
| 64 |
+
try:
|
| 65 |
+
POLARS_VERSION = version.parse(importlib.metadata.version("polars"))
|
| 66 |
+
logger.debug(f"Polars version {POLARS_VERSION} available.")
|
| 67 |
+
except importlib.metadata.PackageNotFoundError:
|
| 68 |
+
pass
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
DUCKDB_VERSION = "N/A"
|
| 72 |
+
DUCKDB_AVAILABLE = importlib.util.find_spec("duckdb") is not None
|
| 73 |
+
|
| 74 |
+
if DUCKDB_AVAILABLE:
|
| 75 |
+
try:
|
| 76 |
+
DUCKDB_VERSION = version.parse(importlib.metadata.version("duckdb"))
|
| 77 |
+
logger.debug(f"Duckdb version {DUCKDB_VERSION} available.")
|
| 78 |
+
except importlib.metadata.PackageNotFoundError:
|
| 79 |
+
pass
|
| 80 |
+
|
| 81 |
+
TF_VERSION = "N/A"
|
| 82 |
+
TF_AVAILABLE = False
|
| 83 |
+
|
| 84 |
+
if USE_TF in ENV_VARS_TRUE_AND_AUTO_VALUES and USE_TORCH not in ENV_VARS_TRUE_VALUES:
|
| 85 |
+
TF_AVAILABLE = importlib.util.find_spec("tensorflow") is not None
|
| 86 |
+
if TF_AVAILABLE:
|
| 87 |
+
# For the metadata, we have to look for both tensorflow and tensorflow-cpu
|
| 88 |
+
for package in [
|
| 89 |
+
"tensorflow",
|
| 90 |
+
"tensorflow-cpu",
|
| 91 |
+
"tensorflow-gpu",
|
| 92 |
+
"tf-nightly",
|
| 93 |
+
"tf-nightly-cpu",
|
| 94 |
+
"tf-nightly-gpu",
|
| 95 |
+
"intel-tensorflow",
|
| 96 |
+
"tensorflow-rocm",
|
| 97 |
+
"tensorflow-macos",
|
| 98 |
+
]:
|
| 99 |
+
try:
|
| 100 |
+
TF_VERSION = version.parse(importlib.metadata.version(package))
|
| 101 |
+
except importlib.metadata.PackageNotFoundError:
|
| 102 |
+
continue
|
| 103 |
+
else:
|
| 104 |
+
break
|
| 105 |
+
else:
|
| 106 |
+
TF_AVAILABLE = False
|
| 107 |
+
if TF_AVAILABLE:
|
| 108 |
+
if TF_VERSION.major < 2:
|
| 109 |
+
logger.info(f"TensorFlow found but with version {TF_VERSION}. `datasets` requires version 2 minimum.")
|
| 110 |
+
TF_AVAILABLE = False
|
| 111 |
+
else:
|
| 112 |
+
logger.info(f"TensorFlow version {TF_VERSION} available.")
|
| 113 |
+
else:
|
| 114 |
+
logger.info("Disabling Tensorflow because USE_TORCH is set")
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
JAX_VERSION = "N/A"
|
| 118 |
+
JAX_AVAILABLE = False
|
| 119 |
+
|
| 120 |
+
if USE_JAX in ENV_VARS_TRUE_AND_AUTO_VALUES:
|
| 121 |
+
JAX_AVAILABLE = importlib.util.find_spec("jax") is not None and importlib.util.find_spec("jaxlib") is not None
|
| 122 |
+
if JAX_AVAILABLE:
|
| 123 |
+
try:
|
| 124 |
+
JAX_VERSION = version.parse(importlib.metadata.version("jax"))
|
| 125 |
+
logger.info(f"JAX version {JAX_VERSION} available.")
|
| 126 |
+
except importlib.metadata.PackageNotFoundError:
|
| 127 |
+
pass
|
| 128 |
+
else:
|
| 129 |
+
logger.info("Disabling JAX because USE_JAX is set to False")
|
| 130 |
+
|
| 131 |
+
|
| 132 |
+
# Optional tools for data loading
|
| 133 |
+
SQLALCHEMY_AVAILABLE = importlib.util.find_spec("sqlalchemy") is not None
|
| 134 |
+
|
| 135 |
+
# Optional tools for file parsing and feature decoding
|
| 136 |
+
PIL_AVAILABLE = importlib.util.find_spec("PIL") is not None
|
| 137 |
+
IS_OPUS_SUPPORTED = True
|
| 138 |
+
IS_MP3_SUPPORTED = True
|
| 139 |
+
TORCHCODEC_AVAILABLE = importlib.util.find_spec("torchcodec") is not None
|
| 140 |
+
TORCHVISION_AVAILABLE = importlib.util.find_spec("torchvision") is not None
|
| 141 |
+
PDFPLUMBER_AVAILABLE = importlib.util.find_spec("pdfplumber") is not None
|
| 142 |
+
NIBABEL_AVAILABLE = importlib.util.find_spec("nibabel") is not None
|
| 143 |
+
TRIMESH_AVAILABLE = importlib.util.find_spec("trimesh") is not None
|
| 144 |
+
TEICH_AVAILABLE = importlib.util.find_spec("teich") is not None
|
| 145 |
+
|
| 146 |
+
# Optional compression tools
|
| 147 |
+
RARFILE_AVAILABLE = importlib.util.find_spec("rarfile") is not None
|
| 148 |
+
ZSTANDARD_AVAILABLE = importlib.util.find_spec("zstandard") is not None
|
| 149 |
+
LZ4_AVAILABLE = importlib.util.find_spec("lz4") is not None
|
| 150 |
+
PY7ZR_AVAILABLE = importlib.util.find_spec("py7zr") is not None
|
| 151 |
+
|
| 152 |
+
# Cache location
|
| 153 |
+
DEFAULT_XDG_CACHE_HOME = "~/.cache"
|
| 154 |
+
XDG_CACHE_HOME = os.getenv("XDG_CACHE_HOME", DEFAULT_XDG_CACHE_HOME)
|
| 155 |
+
DEFAULT_HF_CACHE_HOME = os.path.join(XDG_CACHE_HOME, "huggingface")
|
| 156 |
+
HF_CACHE_HOME = os.path.expanduser(os.getenv("HF_HOME", DEFAULT_HF_CACHE_HOME))
|
| 157 |
+
|
| 158 |
+
DEFAULT_HF_DATASETS_CACHE = os.path.join(HF_CACHE_HOME, "datasets")
|
| 159 |
+
HF_DATASETS_CACHE = Path(os.getenv("HF_DATASETS_CACHE", DEFAULT_HF_DATASETS_CACHE))
|
| 160 |
+
|
| 161 |
+
DEFAULT_HF_MODULES_CACHE = os.path.join(HF_CACHE_HOME, "modules")
|
| 162 |
+
HF_MODULES_CACHE = Path(os.getenv("HF_MODULES_CACHE", DEFAULT_HF_MODULES_CACHE))
|
| 163 |
+
|
| 164 |
+
DOWNLOADED_DATASETS_DIR = "downloads"
|
| 165 |
+
DEFAULT_DOWNLOADED_DATASETS_PATH = os.path.join(HF_DATASETS_CACHE, DOWNLOADED_DATASETS_DIR)
|
| 166 |
+
DOWNLOADED_DATASETS_PATH = Path(os.getenv("HF_DATASETS_DOWNLOADED_DATASETS_PATH", DEFAULT_DOWNLOADED_DATASETS_PATH))
|
| 167 |
+
|
| 168 |
+
EXTRACTED_DATASETS_DIR = "extracted"
|
| 169 |
+
DEFAULT_EXTRACTED_DATASETS_PATH = os.path.join(DEFAULT_DOWNLOADED_DATASETS_PATH, EXTRACTED_DATASETS_DIR)
|
| 170 |
+
EXTRACTED_DATASETS_PATH = Path(os.getenv("HF_DATASETS_EXTRACTED_DATASETS_PATH", DEFAULT_EXTRACTED_DATASETS_PATH))
|
| 171 |
+
|
| 172 |
+
# Cached dataset info options
|
| 173 |
+
SAVE_ORIGINAL_SHARD_LENGTHS = False
|
| 174 |
+
|
| 175 |
+
# Download count for the website
|
| 176 |
+
HF_UPDATE_DOWNLOAD_COUNTS = (
|
| 177 |
+
os.environ.get("HF_UPDATE_DOWNLOAD_COUNTS", "AUTO").upper() in ENV_VARS_TRUE_AND_AUTO_VALUES
|
| 178 |
+
)
|
| 179 |
+
|
| 180 |
+
# For downloads and to check remote files metadata
|
| 181 |
+
HF_DATASETS_MULTITHREADING_MAX_WORKERS = 16
|
| 182 |
+
|
| 183 |
+
# Dataset viewer API
|
| 184 |
+
USE_PARQUET_EXPORT = True
|
| 185 |
+
|
| 186 |
+
# Batch size constants. For more info, see:
|
| 187 |
+
# https://github.com/apache/arrow/blob/master/docs/source/cpp/arrays.rst#size-limitations-and-recommendations)
|
| 188 |
+
DEFAULT_MAX_BATCH_SIZE = 1000
|
| 189 |
+
|
| 190 |
+
DEFAULT_CDC_OPTIONS = {"min_chunk_size": 256 * 1024, "max_chunk_size": 1024 * 1024, "norm_level": 0}
|
| 191 |
+
|
| 192 |
+
# Size of the preloaded record batch in `Dataset.__iter__`
|
| 193 |
+
ARROW_READER_BATCH_SIZE_IN_DATASET_ITER = 10
|
| 194 |
+
|
| 195 |
+
# Max uncompressed shard size in bytes (e.g. to shard parquet datasets in push_to_hub or download_and_prepare)
|
| 196 |
+
MAX_SHARD_SIZE = "500MB"
|
| 197 |
+
|
| 198 |
+
# Max uncompressed row group size in bytes (e.g. for parquet files in push_to_hub or download_and_prepare)
|
| 199 |
+
MAX_ROW_GROUP_SIZE = "100MB"
|
| 200 |
+
|
| 201 |
+
# Parquet configuration
|
| 202 |
+
PARQUET_ROW_GROUP_SIZE_FOR_AUDIO_DATASETS = None
|
| 203 |
+
PARQUET_ROW_GROUP_SIZE_FOR_IMAGE_DATASETS = None
|
| 204 |
+
PARQUET_ROW_GROUP_SIZE_FOR_BINARY_DATASETS = None
|
| 205 |
+
PARQUET_ROW_GROUP_SIZE_FOR_VIDEO_DATASETS = None
|
| 206 |
+
|
| 207 |
+
# Arrow configuration
|
| 208 |
+
ARROW_RECORD_BATCH_SIZE_FOR_AUDIO_DATASETS = 100
|
| 209 |
+
ARROW_RECORD_BATCH_SIZE_FOR_IMAGE_DATASETS = 100
|
| 210 |
+
ARROW_RECORD_BATCH_SIZE_FOR_BINARY_DATASETS = 100
|
| 211 |
+
ARROW_RECORD_BATCH_SIZE_FOR_VIDEO_DATASETS = 10
|
| 212 |
+
|
| 213 |
+
# Offline mode
|
| 214 |
+
_offline = os.environ.get("HF_DATASETS_OFFLINE")
|
| 215 |
+
HF_HUB_OFFLINE = constants.HF_HUB_OFFLINE if _offline is None else _offline.upper() in ENV_VARS_TRUE_VALUES
|
| 216 |
+
HF_DATASETS_OFFLINE = HF_HUB_OFFLINE # kept for backward-compatibility
|
| 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_DATASETS_DISABLE_PROGRESS_BARS = os.environ.get("HF_DATASETS_DISABLE_PROGRESS_BARS")
|
| 224 |
+
HF_DATASETS_DISABLE_PROGRESS_BARS: Optional[bool] = (
|
| 225 |
+
__HF_DATASETS_DISABLE_PROGRESS_BARS.upper() in ENV_VARS_TRUE_VALUES
|
| 226 |
+
if __HF_DATASETS_DISABLE_PROGRESS_BARS is not None
|
| 227 |
+
else None
|
| 228 |
+
)
|
| 229 |
+
|
| 230 |
+
# In-memory
|
| 231 |
+
DEFAULT_IN_MEMORY_MAX_SIZE = 0 # Disabled
|
| 232 |
+
IN_MEMORY_MAX_SIZE = float(os.environ.get("HF_DATASETS_IN_MEMORY_MAX_SIZE", DEFAULT_IN_MEMORY_MAX_SIZE))
|
| 233 |
+
|
| 234 |
+
# File names
|
| 235 |
+
DATASET_ARROW_FILENAME = "dataset.arrow"
|
| 236 |
+
DATASET_INDICES_FILENAME = "indices.arrow"
|
| 237 |
+
DATASET_STATE_JSON_FILENAME = "state.json"
|
| 238 |
+
DATASET_INFO_FILENAME = "dataset_info.json"
|
| 239 |
+
DATASETDICT_INFOS_FILENAME = "dataset_infos.json"
|
| 240 |
+
LICENSE_FILENAME = "LICENSE"
|
| 241 |
+
DATASETDICT_JSON_FILENAME = "dataset_dict.json"
|
| 242 |
+
METADATA_CONFIGS_FIELD = "configs"
|
| 243 |
+
REPOCARD_FILENAME = "README.md"
|
| 244 |
+
REPOYAML_FILENAME = ".huggingface.yaml"
|
| 245 |
+
|
| 246 |
+
MODULE_NAME_FOR_DYNAMIC_MODULES = "datasets_modules"
|
| 247 |
+
|
| 248 |
+
MAX_DATASET_CONFIG_ID_READABLE_LENGTH = 255
|
| 249 |
+
|
| 250 |
+
# Temporary cache directory prefix
|
| 251 |
+
TEMP_CACHE_DIR_PREFIX = "hf_datasets-"
|
| 252 |
+
|
| 253 |
+
# Streaming
|
| 254 |
+
STREAMING_READ_MAX_RETRIES = 20
|
| 255 |
+
STREAMING_READ_RETRY_INTERVAL = 5
|
| 256 |
+
STREAMING_READ_SERVER_UNAVAILABLE_RETRY_INTERVAL = 20
|
| 257 |
+
STREAMING_READ_RATE_LIMIT_RETRY_INTERVAL = 60
|
| 258 |
+
STREAMING_OPEN_MAX_RETRIES = 20
|
| 259 |
+
STREAMING_OPEN_RETRY_INTERVAL = 5
|
| 260 |
+
|
| 261 |
+
# Datasets repositories exploration
|
| 262 |
+
ARCHIVES_MAX_NUMBER_FOR_MODULE_INFERENCE = 10
|
| 263 |
+
|
| 264 |
+
# Async map functions
|
| 265 |
+
MAX_NUM_RUNNING_ASYNC_MAP_FUNCTIONS_IN_PARALLEL = 1000
|
| 266 |
+
|
| 267 |
+
# Progress bars
|
| 268 |
+
PBAR_REFRESH_TIME_INTERVAL = 0.05 # 20 progress updates per sec
|
| 269 |
+
|
| 270 |
+
# Maximum number of uploaded files per commit
|
| 271 |
+
UPLOADS_MAX_NUMBER_PER_COMMIT = 50
|
| 272 |
+
|
| 273 |
+
# Backward compatibility
|
| 274 |
+
MAX_TABLE_NBYTES_FOR_PICKLING = 4 << 30
|
| 275 |
+
|
| 276 |
+
# Time to let PyArrow close threads gracefully
|
| 277 |
+
SLEEP_TIME_ON_THREADS_SHUTDOWN = 5
|
venv/Lib/site-packages/datasets/data_files.py
ADDED
|
@@ -0,0 +1,829 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import re
|
| 3 |
+
from functools import partial
|
| 4 |
+
from glob import has_magic
|
| 5 |
+
from pathlib import Path, PurePath
|
| 6 |
+
from typing import Callable, Optional, Union
|
| 7 |
+
|
| 8 |
+
import huggingface_hub
|
| 9 |
+
from fsspec.core import url_to_fs
|
| 10 |
+
from huggingface_hub import HfFileSystem
|
| 11 |
+
from packaging import version
|
| 12 |
+
from tqdm.contrib.concurrent import thread_map
|
| 13 |
+
|
| 14 |
+
from . import config
|
| 15 |
+
from .download import DownloadConfig
|
| 16 |
+
from .naming import _split_re
|
| 17 |
+
from .splits import Split
|
| 18 |
+
from .utils import logging
|
| 19 |
+
from .utils import tqdm as hf_tqdm
|
| 20 |
+
from .utils.file_utils import _prepare_path_and_storage_options, is_local_path, is_relative_path, xbasename, xjoin
|
| 21 |
+
from .utils.py_utils import string_to_dict
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
SingleOriginMetadata = Union[tuple[str, str], tuple[str], tuple[()]]
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
SANITIZED_DEFAULT_SPLIT = str(Split.TRAIN)
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
logger = logging.get_logger(__name__)
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
class Url(str):
|
| 34 |
+
pass
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
class EmptyDatasetError(FileNotFoundError):
|
| 38 |
+
pass
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
SPLIT_PATTERN_SHARDED = "data/{split}-[0-9][0-9][0-9][0-9][0-9]-of-[0-9][0-9][0-9][0-9][0-9]*.*"
|
| 42 |
+
|
| 43 |
+
SPLIT_KEYWORDS = {
|
| 44 |
+
Split.TRAIN: ["train", "training"],
|
| 45 |
+
Split.VALIDATION: ["validation", "valid", "dev", "val"],
|
| 46 |
+
Split.TEST: ["test", "testing", "eval", "evaluation"],
|
| 47 |
+
}
|
| 48 |
+
NON_WORDS_CHARS = "-._ 0-9"
|
| 49 |
+
if config.FSSPEC_VERSION < version.parse("2023.9.0"):
|
| 50 |
+
KEYWORDS_IN_FILENAME_BASE_PATTERNS = ["**[{sep}/]{keyword}[{sep}]*", "{keyword}[{sep}]*"]
|
| 51 |
+
KEYWORDS_IN_DIR_NAME_BASE_PATTERNS = [
|
| 52 |
+
"{keyword}/**",
|
| 53 |
+
"{keyword}[{sep}]*/**",
|
| 54 |
+
"**[{sep}/]{keyword}/**",
|
| 55 |
+
"**[{sep}/]{keyword}[{sep}]*/**",
|
| 56 |
+
]
|
| 57 |
+
elif config.FSSPEC_VERSION < version.parse("2023.12.0"):
|
| 58 |
+
KEYWORDS_IN_FILENAME_BASE_PATTERNS = ["**/*[{sep}/]{keyword}[{sep}]*", "{keyword}[{sep}]*"]
|
| 59 |
+
KEYWORDS_IN_DIR_NAME_BASE_PATTERNS = [
|
| 60 |
+
"{keyword}/**/*",
|
| 61 |
+
"{keyword}[{sep}]*/**/*",
|
| 62 |
+
"**/*[{sep}/]{keyword}/**/*",
|
| 63 |
+
"**/*[{sep}/]{keyword}[{sep}]*/**/*",
|
| 64 |
+
]
|
| 65 |
+
else:
|
| 66 |
+
KEYWORDS_IN_FILENAME_BASE_PATTERNS = ["**/{keyword}[{sep}]*", "**/*[{sep}]{keyword}[{sep}]*"]
|
| 67 |
+
KEYWORDS_IN_DIR_NAME_BASE_PATTERNS = [
|
| 68 |
+
"**/{keyword}/**",
|
| 69 |
+
"**/{keyword}[{sep}]*/**",
|
| 70 |
+
"**/*[{sep}]{keyword}/**",
|
| 71 |
+
"**/*[{sep}]{keyword}[{sep}]*/**",
|
| 72 |
+
]
|
| 73 |
+
|
| 74 |
+
DEFAULT_SPLITS = [Split.TRAIN, Split.VALIDATION, Split.TEST]
|
| 75 |
+
DEFAULT_PATTERNS_SPLIT_IN_FILENAME = {
|
| 76 |
+
split: [
|
| 77 |
+
pattern.format(keyword=keyword, sep=NON_WORDS_CHARS)
|
| 78 |
+
for keyword in SPLIT_KEYWORDS[split]
|
| 79 |
+
for pattern in KEYWORDS_IN_FILENAME_BASE_PATTERNS
|
| 80 |
+
]
|
| 81 |
+
for split in DEFAULT_SPLITS
|
| 82 |
+
}
|
| 83 |
+
DEFAULT_PATTERNS_SPLIT_IN_DIR_NAME = {
|
| 84 |
+
split: [
|
| 85 |
+
pattern.format(keyword=keyword, sep=NON_WORDS_CHARS)
|
| 86 |
+
for keyword in SPLIT_KEYWORDS[split]
|
| 87 |
+
for pattern in KEYWORDS_IN_DIR_NAME_BASE_PATTERNS
|
| 88 |
+
]
|
| 89 |
+
for split in DEFAULT_SPLITS
|
| 90 |
+
}
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
DEFAULT_PATTERNS_ALL = {
|
| 94 |
+
Split.TRAIN: ["**"],
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
DEFAULT_PATTERNS_LOGS = {"logs": ["**/*.eval"]}
|
| 98 |
+
|
| 99 |
+
ALL_SPLIT_PATTERNS = [SPLIT_PATTERN_SHARDED]
|
| 100 |
+
ALL_DEFAULT_PATTERNS = [
|
| 101 |
+
DEFAULT_PATTERNS_LOGS,
|
| 102 |
+
DEFAULT_PATTERNS_SPLIT_IN_DIR_NAME,
|
| 103 |
+
DEFAULT_PATTERNS_SPLIT_IN_FILENAME,
|
| 104 |
+
DEFAULT_PATTERNS_ALL,
|
| 105 |
+
]
|
| 106 |
+
WILDCARD_CHARACTERS = "*[]"
|
| 107 |
+
FILES_TO_IGNORE = [
|
| 108 |
+
"README.md",
|
| 109 |
+
"config.json",
|
| 110 |
+
"dataset_info.json",
|
| 111 |
+
"dataset_infos.json",
|
| 112 |
+
"dummy_data.zip",
|
| 113 |
+
"dataset_dict.json",
|
| 114 |
+
]
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
def contains_wildcards(pattern: str) -> bool:
|
| 118 |
+
return any(wildcard_character in pattern for wildcard_character in WILDCARD_CHARACTERS)
|
| 119 |
+
|
| 120 |
+
|
| 121 |
+
def sanitize_patterns(patterns: Union[dict, list, str]) -> dict[str, Union[list[str], "DataFilesList"]]:
|
| 122 |
+
"""
|
| 123 |
+
Take the data_files patterns from the user, and format them into a dictionary.
|
| 124 |
+
Each key is the name of the split, and each value is a list of data files patterns (paths or urls).
|
| 125 |
+
The default split is "train".
|
| 126 |
+
|
| 127 |
+
Returns:
|
| 128 |
+
patterns: dictionary of split_name -> list of patterns
|
| 129 |
+
"""
|
| 130 |
+
if isinstance(patterns, dict):
|
| 131 |
+
return {str(key): value if isinstance(value, list) else [value] for key, value in patterns.items()}
|
| 132 |
+
elif isinstance(patterns, str):
|
| 133 |
+
return {SANITIZED_DEFAULT_SPLIT: [patterns]}
|
| 134 |
+
elif isinstance(patterns, list):
|
| 135 |
+
if any(isinstance(pattern, dict) for pattern in patterns):
|
| 136 |
+
for pattern in patterns:
|
| 137 |
+
if not (
|
| 138 |
+
isinstance(pattern, dict)
|
| 139 |
+
and len(pattern) == 2
|
| 140 |
+
and "split" in pattern
|
| 141 |
+
and isinstance(pattern.get("path"), (str, list))
|
| 142 |
+
):
|
| 143 |
+
raise ValueError(
|
| 144 |
+
"Invalid format for data_files entry. "
|
| 145 |
+
"Each item must be a dictionary with the structure "
|
| 146 |
+
"{'split': <split_name>, 'path': <path_or_list_of_paths>}.\n"
|
| 147 |
+
f"Received: {pattern}"
|
| 148 |
+
)
|
| 149 |
+
splits = [pattern["split"] for pattern in patterns]
|
| 150 |
+
if len(set(splits)) != len(splits):
|
| 151 |
+
raise ValueError(f"Some splits are duplicated in data_files: {splits}")
|
| 152 |
+
return {
|
| 153 |
+
str(pattern["split"]): pattern["path"] if isinstance(pattern["path"], list) else [pattern["path"]]
|
| 154 |
+
for pattern in patterns
|
| 155 |
+
}
|
| 156 |
+
else:
|
| 157 |
+
return {SANITIZED_DEFAULT_SPLIT: patterns}
|
| 158 |
+
else:
|
| 159 |
+
return sanitize_patterns(list(patterns))
|
| 160 |
+
|
| 161 |
+
|
| 162 |
+
def _is_inside_unrequested_special_dir(matched_rel_path: str, pattern: str) -> bool:
|
| 163 |
+
"""
|
| 164 |
+
When a path matches a pattern, we additionally check if it's inside a special directory
|
| 165 |
+
we ignore by default (if it starts with a double underscore).
|
| 166 |
+
|
| 167 |
+
Users can still explicitly request a filepath inside such a directory if "__pycache__" is
|
| 168 |
+
mentioned explicitly in the requested pattern.
|
| 169 |
+
|
| 170 |
+
Some examples:
|
| 171 |
+
|
| 172 |
+
base directory:
|
| 173 |
+
|
| 174 |
+
./
|
| 175 |
+
└── __pycache__
|
| 176 |
+
└── b.txt
|
| 177 |
+
|
| 178 |
+
>>> _is_inside_unrequested_special_dir("__pycache__/b.txt", "**")
|
| 179 |
+
True
|
| 180 |
+
>>> _is_inside_unrequested_special_dir("__pycache__/b.txt", "*/b.txt")
|
| 181 |
+
True
|
| 182 |
+
>>> _is_inside_unrequested_special_dir("__pycache__/b.txt", "__pycache__/*")
|
| 183 |
+
False
|
| 184 |
+
>>> _is_inside_unrequested_special_dir("__pycache__/b.txt", "__*/*")
|
| 185 |
+
False
|
| 186 |
+
"""
|
| 187 |
+
# We just need to check if every special directories from the path is present explicitly in the pattern.
|
| 188 |
+
# Since we assume that the path matches the pattern, it's equivalent to counting that both
|
| 189 |
+
# the parent path and the parent pattern have the same number of special directories.
|
| 190 |
+
data_dirs_to_ignore_in_path = [part for part in PurePath(matched_rel_path).parent.parts if part.startswith("__")]
|
| 191 |
+
data_dirs_to_ignore_in_pattern = [part for part in PurePath(pattern).parent.parts if part.startswith("__")]
|
| 192 |
+
return len(data_dirs_to_ignore_in_path) != len(data_dirs_to_ignore_in_pattern)
|
| 193 |
+
|
| 194 |
+
|
| 195 |
+
def _is_unrequested_hidden_file_or_is_inside_unrequested_hidden_dir(matched_rel_path: str, pattern: str) -> bool:
|
| 196 |
+
"""
|
| 197 |
+
When a path matches a pattern, we additionally check if it's a hidden file or if it's inside
|
| 198 |
+
a hidden directory we ignore by default, i.e. if the file name or a parent directory name starts with a dot.
|
| 199 |
+
|
| 200 |
+
Users can still explicitly request a filepath that is hidden or is inside a hidden directory
|
| 201 |
+
if the hidden part is mentioned explicitly in the requested pattern.
|
| 202 |
+
|
| 203 |
+
Some examples:
|
| 204 |
+
|
| 205 |
+
base directory:
|
| 206 |
+
|
| 207 |
+
./
|
| 208 |
+
└── .hidden_file.txt
|
| 209 |
+
|
| 210 |
+
>>> _is_unrequested_hidden_file_or_is_inside_unrequested_hidden_dir(".hidden_file.txt", "**")
|
| 211 |
+
True
|
| 212 |
+
>>> _is_unrequested_hidden_file_or_is_inside_unrequested_hidden_dir(".hidden_file.txt", ".*")
|
| 213 |
+
False
|
| 214 |
+
|
| 215 |
+
base directory:
|
| 216 |
+
|
| 217 |
+
./
|
| 218 |
+
└── .hidden_dir
|
| 219 |
+
└── a.txt
|
| 220 |
+
|
| 221 |
+
>>> _is_unrequested_hidden_file_or_is_inside_unrequested_hidden_dir(".hidden_dir/a.txt", "**")
|
| 222 |
+
True
|
| 223 |
+
>>> _is_unrequested_hidden_file_or_is_inside_unrequested_hidden_dir(".hidden_dir/a.txt", ".*/*")
|
| 224 |
+
False
|
| 225 |
+
>>> _is_unrequested_hidden_file_or_is_inside_unrequested_hidden_dir(".hidden_dir/a.txt", ".hidden_dir/*")
|
| 226 |
+
False
|
| 227 |
+
|
| 228 |
+
base directory:
|
| 229 |
+
|
| 230 |
+
./
|
| 231 |
+
└── .hidden_dir
|
| 232 |
+
└── .hidden_file.txt
|
| 233 |
+
|
| 234 |
+
>>> _is_unrequested_hidden_file_or_is_inside_unrequested_hidden_dir(".hidden_dir/.hidden_file.txt", "**")
|
| 235 |
+
True
|
| 236 |
+
>>> _is_unrequested_hidden_file_or_is_inside_unrequested_hidden_dir(".hidden_dir/.hidden_file.txt", ".*/*")
|
| 237 |
+
True
|
| 238 |
+
>>> _is_unrequested_hidden_file_or_is_inside_unrequested_hidden_dir(".hidden_dir/.hidden_file.txt", ".*/.*")
|
| 239 |
+
False
|
| 240 |
+
>>> _is_unrequested_hidden_file_or_is_inside_unrequested_hidden_dir(".hidden_dir/.hidden_file.txt", ".hidden_dir/*")
|
| 241 |
+
True
|
| 242 |
+
>>> _is_unrequested_hidden_file_or_is_inside_unrequested_hidden_dir(".hidden_dir/.hidden_file.txt", ".hidden_dir/.*")
|
| 243 |
+
False
|
| 244 |
+
"""
|
| 245 |
+
# We just need to check if every hidden part from the path is present explicitly in the pattern.
|
| 246 |
+
# Since we assume that the path matches the pattern, it's equivalent to counting that both
|
| 247 |
+
# the path and the pattern have the same number of hidden parts.
|
| 248 |
+
hidden_directories_in_path = [
|
| 249 |
+
part for part in PurePath(matched_rel_path).parts if part.startswith(".") and not set(part) == {"."}
|
| 250 |
+
]
|
| 251 |
+
hidden_directories_in_pattern = [
|
| 252 |
+
part for part in PurePath(pattern).parts if part.startswith(".") and not set(part) == {"."}
|
| 253 |
+
]
|
| 254 |
+
return len(hidden_directories_in_path) != len(hidden_directories_in_pattern)
|
| 255 |
+
|
| 256 |
+
|
| 257 |
+
def _get_data_files_patterns(pattern_resolver: Callable[[str], list[str]]) -> dict[str, list[str]]:
|
| 258 |
+
"""
|
| 259 |
+
Get the default pattern from a directory or repository by testing all the supported patterns.
|
| 260 |
+
The first patterns to return a non-empty list of data files is returned.
|
| 261 |
+
|
| 262 |
+
In order, it first tests if SPLIT_PATTERN_SHARDED works, otherwise it tests the patterns in ALL_DEFAULT_PATTERNS.
|
| 263 |
+
"""
|
| 264 |
+
# first check the split patterns like data/{split}-00000-of-00001.parquet
|
| 265 |
+
for split_pattern in ALL_SPLIT_PATTERNS:
|
| 266 |
+
pattern = split_pattern.replace("{split}", "*")
|
| 267 |
+
try:
|
| 268 |
+
data_files = pattern_resolver(pattern)
|
| 269 |
+
except FileNotFoundError:
|
| 270 |
+
continue
|
| 271 |
+
if len(data_files) > 0:
|
| 272 |
+
splits: set[str] = set()
|
| 273 |
+
for p in data_files:
|
| 274 |
+
p_parts = string_to_dict(xbasename(p), xbasename(split_pattern))
|
| 275 |
+
assert p_parts is not None
|
| 276 |
+
splits.add(p_parts["split"])
|
| 277 |
+
|
| 278 |
+
if any(not re.match(_split_re, split) for split in splits):
|
| 279 |
+
raise ValueError(f"Split name should match '{_split_re}'' but got '{splits}'.")
|
| 280 |
+
sorted_splits = [str(split) for split in DEFAULT_SPLITS if split in splits] + sorted(
|
| 281 |
+
splits - {str(split) for split in DEFAULT_SPLITS}
|
| 282 |
+
)
|
| 283 |
+
return {split: [split_pattern.format(split=split)] for split in sorted_splits}
|
| 284 |
+
# then check the default patterns based on train/valid/test splits
|
| 285 |
+
for patterns_dict in ALL_DEFAULT_PATTERNS:
|
| 286 |
+
non_empty_splits = []
|
| 287 |
+
for split, patterns in patterns_dict.items():
|
| 288 |
+
for pattern in patterns:
|
| 289 |
+
try:
|
| 290 |
+
data_files = pattern_resolver(pattern)
|
| 291 |
+
except FileNotFoundError:
|
| 292 |
+
continue
|
| 293 |
+
if len(data_files) > 0:
|
| 294 |
+
non_empty_splits.append(split)
|
| 295 |
+
break
|
| 296 |
+
if non_empty_splits:
|
| 297 |
+
return {split: patterns_dict[split] for split in non_empty_splits}
|
| 298 |
+
raise FileNotFoundError(f"Couldn't resolve pattern {pattern} with resolver {pattern_resolver}")
|
| 299 |
+
|
| 300 |
+
|
| 301 |
+
def resolve_pattern(
|
| 302 |
+
pattern: str,
|
| 303 |
+
base_path: str,
|
| 304 |
+
allowed_extensions: Optional[list[str]] = None,
|
| 305 |
+
download_config: Optional[DownloadConfig] = None,
|
| 306 |
+
) -> list[str]:
|
| 307 |
+
"""
|
| 308 |
+
Resolve the paths and URLs of the data files from the pattern passed by the user.
|
| 309 |
+
|
| 310 |
+
You can use patterns to resolve multiple local files. Here are a few examples:
|
| 311 |
+
- *.csv to match all the CSV files at the first level
|
| 312 |
+
- **.csv to match all the CSV files at any level
|
| 313 |
+
- data/* to match all the files inside "data"
|
| 314 |
+
- data/** to match all the files inside "data" and its subdirectories
|
| 315 |
+
|
| 316 |
+
The patterns are resolved using the fsspec glob. In fsspec>=2023.12.0 this is equivalent to
|
| 317 |
+
Python's glob.glob, Path.glob, Path.match and fnmatch where ** is unsupported with a prefix/suffix
|
| 318 |
+
other than a forward slash /.
|
| 319 |
+
|
| 320 |
+
More generally:
|
| 321 |
+
- '*' matches any character except a forward-slash (to match just the file or directory name)
|
| 322 |
+
- '**' matches any character including a forward-slash /
|
| 323 |
+
|
| 324 |
+
Hidden files and directories (i.e. whose names start with a dot) are ignored, unless they are explicitly requested.
|
| 325 |
+
The same applies to special directories that start with a double underscore like "__pycache__".
|
| 326 |
+
You can still include one if the pattern explicitly mentions it:
|
| 327 |
+
- to include a hidden file: "*/.hidden.txt" or "*/.*"
|
| 328 |
+
- to include a hidden directory: ".hidden/*" or ".*/*"
|
| 329 |
+
- to include a special directory: "__special__/*" or "__*/*"
|
| 330 |
+
|
| 331 |
+
Example::
|
| 332 |
+
|
| 333 |
+
>>> from datasets.data_files import resolve_pattern
|
| 334 |
+
>>> base_path = "."
|
| 335 |
+
>>> resolve_pattern("docs/**/*.py", base_path)
|
| 336 |
+
[/Users/mariosasko/Desktop/projects/datasets/docs/source/_config.py']
|
| 337 |
+
|
| 338 |
+
Args:
|
| 339 |
+
pattern (str): Unix pattern or paths or URLs of the data files to resolve.
|
| 340 |
+
The paths can be absolute or relative to base_path.
|
| 341 |
+
Remote filesystems using fsspec are supported, e.g. with the hf:// protocol.
|
| 342 |
+
base_path (str): Base path to use when resolving relative paths.
|
| 343 |
+
allowed_extensions (Optional[list], optional): White-list of file extensions to use. Defaults to None (all extensions).
|
| 344 |
+
For example: allowed_extensions=[".csv", ".json", ".txt", ".parquet"]
|
| 345 |
+
download_config ([`DownloadConfig`], *optional*): Specific download configuration parameters.
|
| 346 |
+
Returns:
|
| 347 |
+
List[str]: List of paths or URLs to the local or remote files that match the patterns.
|
| 348 |
+
"""
|
| 349 |
+
if is_relative_path(pattern):
|
| 350 |
+
pattern = xjoin(base_path, pattern)
|
| 351 |
+
elif is_local_path(pattern):
|
| 352 |
+
base_path = os.path.splitdrive(pattern)[0] + os.sep
|
| 353 |
+
else:
|
| 354 |
+
base_path = ""
|
| 355 |
+
pattern, storage_options = _prepare_path_and_storage_options(pattern, download_config=download_config)
|
| 356 |
+
fs, fs_pattern = url_to_fs(pattern, **storage_options)
|
| 357 |
+
files_to_ignore = set(FILES_TO_IGNORE) - {xbasename(pattern)}
|
| 358 |
+
protocol = (
|
| 359 |
+
pattern.split("://")[0]
|
| 360 |
+
if "://" in pattern
|
| 361 |
+
else (fs.protocol if isinstance(fs.protocol, str) else fs.protocol[0])
|
| 362 |
+
)
|
| 363 |
+
protocol_prefix = protocol + "://" if protocol != "file" else ""
|
| 364 |
+
glob_kwargs = {}
|
| 365 |
+
if protocol == "hf":
|
| 366 |
+
# 10 times faster glob with detail=True (ignores costly info like lastCommit)
|
| 367 |
+
glob_kwargs["expand_info"] = False
|
| 368 |
+
|
| 369 |
+
# if the pattern contains hops like "zip://csv/*.csv::data.zip", we need to keep them after globbing
|
| 370 |
+
_, *rest_hops = pattern.split("::")
|
| 371 |
+
matched_paths = []
|
| 372 |
+
for filepath, info in fs.glob(fs_pattern, detail=True, **glob_kwargs).items():
|
| 373 |
+
if not (info["type"] == "file" or (info.get("islink") and os.path.isfile(os.path.realpath(filepath)))) or (
|
| 374 |
+
xbasename(filepath) in files_to_ignore
|
| 375 |
+
):
|
| 376 |
+
continue
|
| 377 |
+
if _is_inside_unrequested_special_dir(filepath, fs_pattern):
|
| 378 |
+
continue
|
| 379 |
+
if _is_unrequested_hidden_file_or_is_inside_unrequested_hidden_dir(filepath, fs_pattern):
|
| 380 |
+
continue
|
| 381 |
+
filepath = filepath if "://" in filepath else protocol_prefix + filepath
|
| 382 |
+
if rest_hops:
|
| 383 |
+
filepath = "::".join([filepath] + rest_hops)
|
| 384 |
+
matched_paths.append(filepath)
|
| 385 |
+
# ignore .ipynb and __pycache__, but keep /../
|
| 386 |
+
if allowed_extensions is not None:
|
| 387 |
+
out = [
|
| 388 |
+
filepath
|
| 389 |
+
for filepath in matched_paths
|
| 390 |
+
if any("." + suffix in allowed_extensions for suffix in xbasename(filepath).split(".")[1:])
|
| 391 |
+
]
|
| 392 |
+
if len(out) < len(matched_paths):
|
| 393 |
+
invalid_matched_files = list(set(matched_paths) - set(out))
|
| 394 |
+
logger.info(
|
| 395 |
+
f"Some files matched the pattern '{pattern}' but don't have valid data file extensions: {invalid_matched_files}"
|
| 396 |
+
)
|
| 397 |
+
else:
|
| 398 |
+
out = matched_paths
|
| 399 |
+
if not out:
|
| 400 |
+
error_msg = f"Unable to find '{pattern}'"
|
| 401 |
+
if allowed_extensions is not None:
|
| 402 |
+
error_msg += f" with any supported extension {list(allowed_extensions)}"
|
| 403 |
+
raise FileNotFoundError(error_msg)
|
| 404 |
+
return out
|
| 405 |
+
|
| 406 |
+
|
| 407 |
+
def get_data_patterns(base_path: str, download_config: Optional[DownloadConfig] = None) -> dict[str, list[str]]:
|
| 408 |
+
"""
|
| 409 |
+
Get the default pattern from a directory testing all the supported patterns.
|
| 410 |
+
The first patterns to return a non-empty list of data files is returned.
|
| 411 |
+
|
| 412 |
+
Some examples of supported patterns:
|
| 413 |
+
|
| 414 |
+
Input:
|
| 415 |
+
|
| 416 |
+
my_dataset_repository/
|
| 417 |
+
├── README.md
|
| 418 |
+
└── dataset.csv
|
| 419 |
+
|
| 420 |
+
Output:
|
| 421 |
+
|
| 422 |
+
{'train': ['**']}
|
| 423 |
+
|
| 424 |
+
Input:
|
| 425 |
+
|
| 426 |
+
my_dataset_repository/
|
| 427 |
+
├── README.md
|
| 428 |
+
├── train.csv
|
| 429 |
+
└── test.csv
|
| 430 |
+
|
| 431 |
+
my_dataset_repository/
|
| 432 |
+
├── README.md
|
| 433 |
+
└── data/
|
| 434 |
+
├── train.csv
|
| 435 |
+
└── test.csv
|
| 436 |
+
|
| 437 |
+
my_dataset_repository/
|
| 438 |
+
├── README.md
|
| 439 |
+
├── train_0.csv
|
| 440 |
+
├── train_1.csv
|
| 441 |
+
├── train_2.csv
|
| 442 |
+
├── train_3.csv
|
| 443 |
+
├── test_0.csv
|
| 444 |
+
└── test_1.csv
|
| 445 |
+
|
| 446 |
+
Output:
|
| 447 |
+
|
| 448 |
+
{'train': ['**/train[-._ 0-9]*', '**/*[-._ 0-9]train[-._ 0-9]*', '**/training[-._ 0-9]*', '**/*[-._ 0-9]training[-._ 0-9]*'],
|
| 449 |
+
'test': ['**/test[-._ 0-9]*', '**/*[-._ 0-9]test[-._ 0-9]*', '**/testing[-._ 0-9]*', '**/*[-._ 0-9]testing[-._ 0-9]*', ...]}
|
| 450 |
+
|
| 451 |
+
Input:
|
| 452 |
+
|
| 453 |
+
my_dataset_repository/
|
| 454 |
+
├── README.md
|
| 455 |
+
└── data/
|
| 456 |
+
├── train/
|
| 457 |
+
│ ├── shard_0.csv
|
| 458 |
+
│ ├── shard_1.csv
|
| 459 |
+
│ ├── shard_2.csv
|
| 460 |
+
│ └── shard_3.csv
|
| 461 |
+
└── test/
|
| 462 |
+
├── shard_0.csv
|
| 463 |
+
└── shard_1.csv
|
| 464 |
+
|
| 465 |
+
Output:
|
| 466 |
+
|
| 467 |
+
{'train': ['**/train/**', '**/train[-._ 0-9]*/**', '**/*[-._ 0-9]train/**', '**/*[-._ 0-9]train[-._ 0-9]*/**', ...],
|
| 468 |
+
'test': ['**/test/**', '**/test[-._ 0-9]*/**', '**/*[-._ 0-9]test/**', '**/*[-._ 0-9]test[-._ 0-9]*/**', ...]}
|
| 469 |
+
|
| 470 |
+
Input:
|
| 471 |
+
|
| 472 |
+
my_dataset_repository/
|
| 473 |
+
├── README.md
|
| 474 |
+
└── data/
|
| 475 |
+
├── train-00000-of-00003.csv
|
| 476 |
+
├── train-00001-of-00003.csv
|
| 477 |
+
├── train-00002-of-00003.csv
|
| 478 |
+
├── test-00000-of-00001.csv
|
| 479 |
+
├── random-00000-of-00003.csv
|
| 480 |
+
├── random-00001-of-00003.csv
|
| 481 |
+
└── random-00002-of-00003.csv
|
| 482 |
+
|
| 483 |
+
Output:
|
| 484 |
+
|
| 485 |
+
{'train': ['data/train-[0-9][0-9][0-9][0-9][0-9]-of-[0-9][0-9][0-9][0-9][0-9]*.*'],
|
| 486 |
+
'test': ['data/test-[0-9][0-9][0-9][0-9][0-9]-of-[0-9][0-9][0-9][0-9][0-9]*.*'],
|
| 487 |
+
'random': ['data/random-[0-9][0-9][0-9][0-9][0-9]-of-[0-9][0-9][0-9][0-9][0-9]*.*']}
|
| 488 |
+
|
| 489 |
+
In order, it first tests if SPLIT_PATTERN_SHARDED works, otherwise it tests the patterns in ALL_DEFAULT_PATTERNS.
|
| 490 |
+
"""
|
| 491 |
+
resolver = partial(resolve_pattern, base_path=base_path, download_config=download_config)
|
| 492 |
+
try:
|
| 493 |
+
return _get_data_files_patterns(resolver)
|
| 494 |
+
except FileNotFoundError:
|
| 495 |
+
raise EmptyDatasetError(f"The directory at {base_path} doesn't contain any data files") from None
|
| 496 |
+
|
| 497 |
+
|
| 498 |
+
def _get_single_origin_metadata(
|
| 499 |
+
data_file: str,
|
| 500 |
+
download_config: Optional[DownloadConfig] = None,
|
| 501 |
+
) -> SingleOriginMetadata:
|
| 502 |
+
if data_file.startswith(config.HF_ENDPOINT):
|
| 503 |
+
fs = HfFileSystem(endpoint=config.HF_ENDPOINT, token=download_config.token)
|
| 504 |
+
data_file = "hf://" + data_file[len(config.HF_ENDPOINT) + 1 :]
|
| 505 |
+
data_file = data_file.replace("/resolve/", "/" if data_file.startswith("hf://buckets/") else "@", 1)
|
| 506 |
+
fs_path = data_file
|
| 507 |
+
else:
|
| 508 |
+
data_file, storage_options = _prepare_path_and_storage_options(data_file, download_config=download_config)
|
| 509 |
+
fs, fs_path = url_to_fs(data_file, **storage_options)
|
| 510 |
+
if isinstance(fs, HfFileSystem):
|
| 511 |
+
resolved_path = fs.resolve_path(fs_path)
|
| 512 |
+
if hasattr(resolved_path, "revision"): # no revision for buckets
|
| 513 |
+
return resolved_path.repo_id, resolved_path.revision
|
| 514 |
+
info = fs.info(fs_path)
|
| 515 |
+
# s3fs uses "ETag", gcsfs uses "etag", and for local we simply check mtime
|
| 516 |
+
for key in ["ETag", "etag", "mtime"]:
|
| 517 |
+
if key in info:
|
| 518 |
+
return (str(info[key]),)
|
| 519 |
+
return ()
|
| 520 |
+
|
| 521 |
+
|
| 522 |
+
def _get_origin_metadata(
|
| 523 |
+
data_files: list[str],
|
| 524 |
+
download_config: Optional[DownloadConfig] = None,
|
| 525 |
+
max_workers: Optional[int] = None,
|
| 526 |
+
) -> list[SingleOriginMetadata]:
|
| 527 |
+
max_workers = max_workers if max_workers is not None else config.HF_DATASETS_MULTITHREADING_MAX_WORKERS
|
| 528 |
+
if all("hf://" in data_file for data_file in data_files):
|
| 529 |
+
# No need for multithreading here since the origin metadata of HF files
|
| 530 |
+
# is (repo_id, revision) and is cached after first .info() call.
|
| 531 |
+
return [
|
| 532 |
+
_get_single_origin_metadata(data_file, download_config=download_config)
|
| 533 |
+
for data_file in hf_tqdm(
|
| 534 |
+
data_files,
|
| 535 |
+
desc="Resolving data files",
|
| 536 |
+
# set `disable=None` rather than `disable=False` by default to disable progress bar when no TTY attached
|
| 537 |
+
disable=len(data_files) <= 16 or None,
|
| 538 |
+
)
|
| 539 |
+
]
|
| 540 |
+
return thread_map(
|
| 541 |
+
partial(_get_single_origin_metadata, download_config=download_config),
|
| 542 |
+
data_files,
|
| 543 |
+
max_workers=max_workers,
|
| 544 |
+
tqdm_class=hf_tqdm,
|
| 545 |
+
desc="Resolving data files",
|
| 546 |
+
# set `disable=None` rather than `disable=False` by default to disable progress bar when no TTY attached
|
| 547 |
+
disable=len(data_files) <= 16 or None,
|
| 548 |
+
)
|
| 549 |
+
|
| 550 |
+
|
| 551 |
+
class DataFilesList(list[str]):
|
| 552 |
+
"""
|
| 553 |
+
List of data files (absolute local paths or URLs).
|
| 554 |
+
It has two construction methods given the user's data files patterns:
|
| 555 |
+
- ``from_hf_repo``: resolve patterns inside a dataset repository
|
| 556 |
+
- ``from_local_or_remote``: resolve patterns from a local path
|
| 557 |
+
|
| 558 |
+
Moreover, DataFilesList has an additional attribute ``origin_metadata``.
|
| 559 |
+
It can store:
|
| 560 |
+
- the last modified time of local files
|
| 561 |
+
- ETag of remote files
|
| 562 |
+
- commit sha of a dataset repository
|
| 563 |
+
|
| 564 |
+
Thanks to this additional attribute, it is possible to hash the list
|
| 565 |
+
and get a different hash if and only if at least one file changed.
|
| 566 |
+
This is useful for caching Dataset objects that are obtained from a list of data files.
|
| 567 |
+
"""
|
| 568 |
+
|
| 569 |
+
def __init__(self, data_files: list[str], origin_metadata: list[SingleOriginMetadata]) -> None:
|
| 570 |
+
super().__init__(data_files)
|
| 571 |
+
self.origin_metadata = origin_metadata
|
| 572 |
+
|
| 573 |
+
def __add__(self, other: "DataFilesList") -> "DataFilesList":
|
| 574 |
+
return DataFilesList([*self, *other], self.origin_metadata + other.origin_metadata)
|
| 575 |
+
|
| 576 |
+
@classmethod
|
| 577 |
+
def from_hf_repo(
|
| 578 |
+
cls,
|
| 579 |
+
patterns: list[str],
|
| 580 |
+
dataset_info: huggingface_hub.hf_api.DatasetInfo,
|
| 581 |
+
base_path: Optional[str] = None,
|
| 582 |
+
allowed_extensions: Optional[list[str]] = None,
|
| 583 |
+
download_config: Optional[DownloadConfig] = None,
|
| 584 |
+
) -> "DataFilesList":
|
| 585 |
+
base_path = f"hf://datasets/{dataset_info.id}@{dataset_info.sha}/{base_path or ''}".rstrip("/")
|
| 586 |
+
return cls.from_patterns(
|
| 587 |
+
patterns, base_path=base_path, allowed_extensions=allowed_extensions, download_config=download_config
|
| 588 |
+
)
|
| 589 |
+
|
| 590 |
+
@classmethod
|
| 591 |
+
def from_local_or_remote(
|
| 592 |
+
cls,
|
| 593 |
+
patterns: list[str],
|
| 594 |
+
base_path: Optional[str] = None,
|
| 595 |
+
allowed_extensions: Optional[list[str]] = None,
|
| 596 |
+
download_config: Optional[DownloadConfig] = None,
|
| 597 |
+
) -> "DataFilesList":
|
| 598 |
+
base_path = base_path if base_path is not None else Path().resolve().as_posix()
|
| 599 |
+
return cls.from_patterns(
|
| 600 |
+
patterns, base_path=base_path, allowed_extensions=allowed_extensions, download_config=download_config
|
| 601 |
+
)
|
| 602 |
+
|
| 603 |
+
@classmethod
|
| 604 |
+
def from_patterns(
|
| 605 |
+
cls,
|
| 606 |
+
patterns: list[str],
|
| 607 |
+
base_path: Optional[str] = None,
|
| 608 |
+
allowed_extensions: Optional[list[str]] = None,
|
| 609 |
+
download_config: Optional[DownloadConfig] = None,
|
| 610 |
+
) -> "DataFilesList":
|
| 611 |
+
base_path = base_path if base_path is not None else Path().resolve().as_posix()
|
| 612 |
+
data_files = []
|
| 613 |
+
for pattern in patterns:
|
| 614 |
+
try:
|
| 615 |
+
data_files.extend(
|
| 616 |
+
resolve_pattern(
|
| 617 |
+
pattern,
|
| 618 |
+
base_path=base_path,
|
| 619 |
+
allowed_extensions=allowed_extensions,
|
| 620 |
+
download_config=download_config,
|
| 621 |
+
)
|
| 622 |
+
)
|
| 623 |
+
except FileNotFoundError:
|
| 624 |
+
if not has_magic(pattern):
|
| 625 |
+
raise
|
| 626 |
+
origin_metadata = _get_origin_metadata(data_files, download_config=download_config)
|
| 627 |
+
return cls(data_files, origin_metadata)
|
| 628 |
+
|
| 629 |
+
def filter(
|
| 630 |
+
self, *, extensions: Optional[list[str]] = None, file_names: Optional[list[str]] = None
|
| 631 |
+
) -> "DataFilesList":
|
| 632 |
+
patterns = []
|
| 633 |
+
if extensions:
|
| 634 |
+
ext_pattern = "|".join(re.escape(ext) for ext in extensions)
|
| 635 |
+
patterns.append(re.compile(f".*({ext_pattern})(\\..+)?$"))
|
| 636 |
+
if file_names:
|
| 637 |
+
fn_pattern = "|".join(re.escape(fn) for fn in file_names)
|
| 638 |
+
patterns.append(re.compile(rf".*[\/]?({fn_pattern})$"))
|
| 639 |
+
if patterns:
|
| 640 |
+
return DataFilesList(
|
| 641 |
+
[data_file for data_file in self if any(pattern.match(data_file) for pattern in patterns)],
|
| 642 |
+
origin_metadata=self.origin_metadata,
|
| 643 |
+
)
|
| 644 |
+
else:
|
| 645 |
+
return DataFilesList(list(self), origin_metadata=self.origin_metadata)
|
| 646 |
+
|
| 647 |
+
|
| 648 |
+
class DataFilesDict(dict[str, DataFilesList]):
|
| 649 |
+
"""
|
| 650 |
+
Dict of split_name -> list of data files (absolute local paths or URLs).
|
| 651 |
+
It has two construction methods given the user's data files patterns :
|
| 652 |
+
- ``from_hf_repo``: resolve patterns inside a dataset repository
|
| 653 |
+
- ``from_local_or_remote``: resolve patterns from a local path
|
| 654 |
+
|
| 655 |
+
Moreover, each list is a DataFilesList. It is possible to hash the dictionary
|
| 656 |
+
and get a different hash if and only if at least one file changed.
|
| 657 |
+
For more info, see [`DataFilesList`].
|
| 658 |
+
|
| 659 |
+
This is useful for caching Dataset objects that are obtained from a list of data files.
|
| 660 |
+
|
| 661 |
+
Changing the order of the keys of this dictionary also doesn't change its hash.
|
| 662 |
+
"""
|
| 663 |
+
|
| 664 |
+
@classmethod
|
| 665 |
+
def from_local_or_remote(
|
| 666 |
+
cls,
|
| 667 |
+
patterns: dict[str, Union[list[str], DataFilesList]],
|
| 668 |
+
base_path: Optional[str] = None,
|
| 669 |
+
allowed_extensions: Optional[list[str]] = None,
|
| 670 |
+
download_config: Optional[DownloadConfig] = None,
|
| 671 |
+
) -> "DataFilesDict":
|
| 672 |
+
out = cls()
|
| 673 |
+
for key, patterns_for_key in patterns.items():
|
| 674 |
+
out[key] = (
|
| 675 |
+
patterns_for_key
|
| 676 |
+
if isinstance(patterns_for_key, DataFilesList)
|
| 677 |
+
else DataFilesList.from_local_or_remote(
|
| 678 |
+
patterns_for_key,
|
| 679 |
+
base_path=base_path,
|
| 680 |
+
allowed_extensions=allowed_extensions,
|
| 681 |
+
download_config=download_config,
|
| 682 |
+
)
|
| 683 |
+
)
|
| 684 |
+
return out
|
| 685 |
+
|
| 686 |
+
@classmethod
|
| 687 |
+
def from_hf_repo(
|
| 688 |
+
cls,
|
| 689 |
+
patterns: dict[str, Union[list[str], DataFilesList]],
|
| 690 |
+
dataset_info: huggingface_hub.hf_api.DatasetInfo,
|
| 691 |
+
base_path: Optional[str] = None,
|
| 692 |
+
allowed_extensions: Optional[list[str]] = None,
|
| 693 |
+
download_config: Optional[DownloadConfig] = None,
|
| 694 |
+
) -> "DataFilesDict":
|
| 695 |
+
out = cls()
|
| 696 |
+
for key, patterns_for_key in patterns.items():
|
| 697 |
+
out[key] = (
|
| 698 |
+
patterns_for_key
|
| 699 |
+
if isinstance(patterns_for_key, DataFilesList)
|
| 700 |
+
else DataFilesList.from_hf_repo(
|
| 701 |
+
patterns_for_key,
|
| 702 |
+
dataset_info=dataset_info,
|
| 703 |
+
base_path=base_path,
|
| 704 |
+
allowed_extensions=allowed_extensions,
|
| 705 |
+
download_config=download_config,
|
| 706 |
+
)
|
| 707 |
+
)
|
| 708 |
+
return out
|
| 709 |
+
|
| 710 |
+
@classmethod
|
| 711 |
+
def from_patterns(
|
| 712 |
+
cls,
|
| 713 |
+
patterns: dict[str, Union[list[str], DataFilesList]],
|
| 714 |
+
base_path: Optional[str] = None,
|
| 715 |
+
allowed_extensions: Optional[list[str]] = None,
|
| 716 |
+
download_config: Optional[DownloadConfig] = None,
|
| 717 |
+
) -> "DataFilesDict":
|
| 718 |
+
out = cls()
|
| 719 |
+
for key, patterns_for_key in patterns.items():
|
| 720 |
+
out[key] = (
|
| 721 |
+
patterns_for_key
|
| 722 |
+
if isinstance(patterns_for_key, DataFilesList)
|
| 723 |
+
else DataFilesList.from_patterns(
|
| 724 |
+
patterns_for_key,
|
| 725 |
+
base_path=base_path,
|
| 726 |
+
allowed_extensions=allowed_extensions,
|
| 727 |
+
download_config=download_config,
|
| 728 |
+
)
|
| 729 |
+
)
|
| 730 |
+
return out
|
| 731 |
+
|
| 732 |
+
def filter(
|
| 733 |
+
self, *, extensions: Optional[list[str]] = None, file_names: Optional[list[str]] = None
|
| 734 |
+
) -> "DataFilesDict":
|
| 735 |
+
out = type(self)()
|
| 736 |
+
for key, data_files_list in self.items():
|
| 737 |
+
out[key] = data_files_list.filter(extensions=extensions, file_names=file_names)
|
| 738 |
+
return out
|
| 739 |
+
|
| 740 |
+
|
| 741 |
+
class DataFilesPatternsList(list[str]):
|
| 742 |
+
"""
|
| 743 |
+
List of data files patterns (absolute local paths or URLs).
|
| 744 |
+
For each pattern there should also be a list of allowed extensions
|
| 745 |
+
to keep, or a None ot keep all the files for the pattern.
|
| 746 |
+
"""
|
| 747 |
+
|
| 748 |
+
def __init__(
|
| 749 |
+
self,
|
| 750 |
+
patterns: list[str],
|
| 751 |
+
allowed_extensions: list[Optional[list[str]]],
|
| 752 |
+
):
|
| 753 |
+
super().__init__(patterns)
|
| 754 |
+
self.allowed_extensions = allowed_extensions
|
| 755 |
+
|
| 756 |
+
def __add__(self, other):
|
| 757 |
+
return DataFilesList([*self, *other], self.allowed_extensions + other.allowed_extensions)
|
| 758 |
+
|
| 759 |
+
@classmethod
|
| 760 |
+
def from_patterns(
|
| 761 |
+
cls, patterns: list[str], allowed_extensions: Optional[list[str]] = None
|
| 762 |
+
) -> "DataFilesPatternsList":
|
| 763 |
+
return cls(patterns, [allowed_extensions] * len(patterns))
|
| 764 |
+
|
| 765 |
+
def resolve(
|
| 766 |
+
self,
|
| 767 |
+
base_path: str,
|
| 768 |
+
download_config: Optional[DownloadConfig] = None,
|
| 769 |
+
) -> "DataFilesList":
|
| 770 |
+
base_path = base_path if base_path is not None else Path().resolve().as_posix()
|
| 771 |
+
data_files = []
|
| 772 |
+
for pattern, allowed_extensions in zip(self, self.allowed_extensions):
|
| 773 |
+
try:
|
| 774 |
+
data_files.extend(
|
| 775 |
+
resolve_pattern(
|
| 776 |
+
pattern,
|
| 777 |
+
base_path=base_path,
|
| 778 |
+
allowed_extensions=allowed_extensions,
|
| 779 |
+
download_config=download_config,
|
| 780 |
+
)
|
| 781 |
+
)
|
| 782 |
+
except FileNotFoundError:
|
| 783 |
+
if not has_magic(pattern):
|
| 784 |
+
raise
|
| 785 |
+
origin_metadata = _get_origin_metadata(data_files, download_config=download_config)
|
| 786 |
+
return DataFilesList(data_files, origin_metadata)
|
| 787 |
+
|
| 788 |
+
def filter_extensions(self, extensions: list[str]) -> "DataFilesPatternsList":
|
| 789 |
+
return DataFilesPatternsList(
|
| 790 |
+
self, [allowed_extensions + extensions for allowed_extensions in self.allowed_extensions]
|
| 791 |
+
)
|
| 792 |
+
|
| 793 |
+
|
| 794 |
+
class DataFilesPatternsDict(dict[str, DataFilesPatternsList]):
|
| 795 |
+
"""
|
| 796 |
+
Dict of split_name -> list of data files patterns (absolute local paths or URLs).
|
| 797 |
+
"""
|
| 798 |
+
|
| 799 |
+
@classmethod
|
| 800 |
+
def from_patterns(
|
| 801 |
+
cls, patterns: dict[str, list[str]], allowed_extensions: Optional[list[str]] = None
|
| 802 |
+
) -> "DataFilesPatternsDict":
|
| 803 |
+
out = cls()
|
| 804 |
+
for key, patterns_for_key in patterns.items():
|
| 805 |
+
out[key] = (
|
| 806 |
+
patterns_for_key
|
| 807 |
+
if isinstance(patterns_for_key, DataFilesPatternsList)
|
| 808 |
+
else DataFilesPatternsList.from_patterns(
|
| 809 |
+
patterns_for_key,
|
| 810 |
+
allowed_extensions=allowed_extensions,
|
| 811 |
+
)
|
| 812 |
+
)
|
| 813 |
+
return out
|
| 814 |
+
|
| 815 |
+
def resolve(
|
| 816 |
+
self,
|
| 817 |
+
base_path: str,
|
| 818 |
+
download_config: Optional[DownloadConfig] = None,
|
| 819 |
+
) -> "DataFilesDict":
|
| 820 |
+
out = DataFilesDict()
|
| 821 |
+
for key, data_files_patterns_list in self.items():
|
| 822 |
+
out[key] = data_files_patterns_list.resolve(base_path, download_config)
|
| 823 |
+
return out
|
| 824 |
+
|
| 825 |
+
def filter_extensions(self, extensions: list[str]) -> "DataFilesPatternsDict":
|
| 826 |
+
out = type(self)()
|
| 827 |
+
for key, data_files_patterns_list in self.items():
|
| 828 |
+
out[key] = data_files_patterns_list.filter_extensions(extensions)
|
| 829 |
+
return out
|
venv/Lib/site-packages/datasets/dataset_dict.py
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
venv/Lib/site-packages/datasets/distributed.py
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import TypeVar
|
| 2 |
+
|
| 3 |
+
from .arrow_dataset import Dataset, _split_by_node_map_style_dataset
|
| 4 |
+
from .iterable_dataset import IterableDataset, _split_by_node_iterable_dataset
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
DatasetType = TypeVar("DatasetType", Dataset, IterableDataset)
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
def split_dataset_by_node(dataset: DatasetType, rank: int, world_size: int) -> DatasetType:
|
| 11 |
+
"""
|
| 12 |
+
Split a dataset for the node at rank `rank` in a pool of nodes of size `world_size`.
|
| 13 |
+
|
| 14 |
+
For map-style datasets:
|
| 15 |
+
|
| 16 |
+
Each node is assigned a chunk of data, e.g. rank 0 is given the first chunk of the dataset.
|
| 17 |
+
To maximize data loading throughput, chunks are made of contiguous data on disk if possible.
|
| 18 |
+
|
| 19 |
+
For iterable datasets:
|
| 20 |
+
|
| 21 |
+
If the dataset has a number of shards that is a factor of `world_size` (i.e. if `dataset.num_shards % world_size == 0`),
|
| 22 |
+
then the shards are evenly assigned across the nodes, which is the most optimized.
|
| 23 |
+
Otherwise, each node keeps 1 example out of `world_size`, skipping the other examples.
|
| 24 |
+
|
| 25 |
+
> [!WARNING]
|
| 26 |
+
> If you shuffle your iterable dataset in a distributed setup, make sure to set a fixed `seed` in [`IterableDataset.shuffle`]
|
| 27 |
+
so the same shuffled list of shards is used on every node to know which shards the node should skip.
|
| 28 |
+
|
| 29 |
+
Args:
|
| 30 |
+
dataset ([`Dataset`] or [`IterableDataset`]):
|
| 31 |
+
The dataset to split by node.
|
| 32 |
+
rank (`int`):
|
| 33 |
+
Rank of the current node.
|
| 34 |
+
world_size (`int`):
|
| 35 |
+
Total number of nodes.
|
| 36 |
+
|
| 37 |
+
Returns:
|
| 38 |
+
[`Dataset`] or [`IterableDataset`]: The dataset to be used on the node at rank `rank`.
|
| 39 |
+
"""
|
| 40 |
+
if isinstance(dataset, Dataset):
|
| 41 |
+
return _split_by_node_map_style_dataset(dataset, rank=rank, world_size=world_size)
|
| 42 |
+
else:
|
| 43 |
+
return _split_by_node_iterable_dataset(dataset, rank=rank, world_size=world_size)
|
venv/Lib/site-packages/datasets/download/__init__.py
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
__all__ = [
|
| 2 |
+
"DownloadConfig",
|
| 3 |
+
"DownloadManager",
|
| 4 |
+
"DownloadMode",
|
| 5 |
+
"StreamingDownloadManager",
|
| 6 |
+
]
|
| 7 |
+
|
| 8 |
+
from .download_config import DownloadConfig
|
| 9 |
+
from .download_manager import DownloadManager, DownloadMode
|
| 10 |
+
from .streaming_download_manager import StreamingDownloadManager
|
venv/Lib/site-packages/datasets/download/__pycache__/__init__.cpython-311.pyc
ADDED
|
Binary file (522 Bytes). View file
|
|
|
venv/Lib/site-packages/datasets/download/__pycache__/download_config.cpython-311.pyc
ADDED
|
Binary file (5.63 kB). View file
|
|
|
venv/Lib/site-packages/datasets/download/__pycache__/download_manager.cpython-311.pyc
ADDED
|
Binary file (16.6 kB). View file
|
|
|
venv/Lib/site-packages/datasets/download/__pycache__/streaming_download_manager.cpython-311.pyc
ADDED
|
Binary file (10.2 kB). View file
|
|
|
venv/Lib/site-packages/datasets/download/download_config.py
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import copy
|
| 2 |
+
from dataclasses import dataclass, field
|
| 3 |
+
from pathlib import Path
|
| 4 |
+
from typing import Any, Optional, Union
|
| 5 |
+
|
| 6 |
+
from .. import config
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
@dataclass
|
| 10 |
+
class DownloadConfig:
|
| 11 |
+
"""Configuration for our cached path manager.
|
| 12 |
+
|
| 13 |
+
Attributes:
|
| 14 |
+
cache_dir (`str` or `Path`, *optional*):
|
| 15 |
+
Specify a cache directory to save the file to (overwrite the
|
| 16 |
+
default cache dir).
|
| 17 |
+
force_download (`bool`, defaults to `False`):
|
| 18 |
+
If `True`, re-download the file even if it's already cached in
|
| 19 |
+
the cache dir.
|
| 20 |
+
resume_download (`bool`, defaults to `False`):
|
| 21 |
+
If `True`, resume the download if an incompletely received file is
|
| 22 |
+
found.
|
| 23 |
+
proxies (`dict`, *optional*):
|
| 24 |
+
user_agent (`str`, *optional*):
|
| 25 |
+
Optional string or dict that will be appended to the user-agent on remote
|
| 26 |
+
requests.
|
| 27 |
+
extract_compressed_file (`bool`, defaults to `False`):
|
| 28 |
+
If `True` and the path point to a zip or tar file,
|
| 29 |
+
extract the compressed file in a folder along the archive.
|
| 30 |
+
force_extract (`bool`, defaults to `False`):
|
| 31 |
+
If `True` when `extract_compressed_file` is `True` and the archive
|
| 32 |
+
was already extracted, re-extract the archive and override the folder where it was extracted.
|
| 33 |
+
delete_extracted (`bool`, defaults to `False`):
|
| 34 |
+
Whether to delete (or keep) the extracted files.
|
| 35 |
+
extract_on_the_fly (`bool`, defaults to `False`):
|
| 36 |
+
If `True`, extract compressed files while they are being read.
|
| 37 |
+
use_etag (`bool`, defaults to `True`):
|
| 38 |
+
Whether to use the ETag HTTP response header to validate the cached files.
|
| 39 |
+
num_proc (`int`, *optional*):
|
| 40 |
+
The number of processes to launch to download the files in parallel.
|
| 41 |
+
max_retries (`int`, default to `1`):
|
| 42 |
+
The number of times to retry an HTTP request if it fails.
|
| 43 |
+
token (`str` or `bool`, *optional*):
|
| 44 |
+
Optional string or boolean to use as Bearer token
|
| 45 |
+
for remote files on the Datasets Hub. If `True`, or not specified, will get token from `~/.huggingface`.
|
| 46 |
+
storage_options (`dict`, *optional*):
|
| 47 |
+
Key/value pairs to be passed on to the dataset file-system backend, if any.
|
| 48 |
+
download_desc (`str`, *optional*):
|
| 49 |
+
A description to be displayed alongside with the progress bar while downloading the files.
|
| 50 |
+
disable_tqdm (`bool`, defaults to `False`):
|
| 51 |
+
Whether to disable the individual files download progress bar
|
| 52 |
+
"""
|
| 53 |
+
|
| 54 |
+
cache_dir: Optional[Union[str, Path]] = None
|
| 55 |
+
force_download: bool = False
|
| 56 |
+
resume_download: bool = False
|
| 57 |
+
local_files_only: bool = False
|
| 58 |
+
proxies: Optional[dict] = None
|
| 59 |
+
user_agent: Optional[str] = None
|
| 60 |
+
extract_compressed_file: bool = False
|
| 61 |
+
force_extract: bool = False
|
| 62 |
+
delete_extracted: bool = False
|
| 63 |
+
extract_on_the_fly: bool = False
|
| 64 |
+
use_etag: bool = True
|
| 65 |
+
num_proc: Optional[int] = None
|
| 66 |
+
max_retries: int = 1
|
| 67 |
+
token: Optional[Union[str, bool]] = None
|
| 68 |
+
storage_options: dict[str, Any] = field(default_factory=dict)
|
| 69 |
+
download_desc: Optional[str] = None
|
| 70 |
+
disable_tqdm: bool = False
|
| 71 |
+
|
| 72 |
+
def copy(self) -> "DownloadConfig":
|
| 73 |
+
return self.__class__(**{k: copy.deepcopy(v) for k, v in self.__dict__.items()})
|
| 74 |
+
|
| 75 |
+
def __setattr__(self, name, value):
|
| 76 |
+
if name == "token" and getattr(self, "storage_options", None) is not None:
|
| 77 |
+
if "hf" not in self.storage_options:
|
| 78 |
+
self.storage_options["hf"] = {"endpoint": config.HF_ENDPOINT, "token": value}
|
| 79 |
+
elif getattr(self.storage_options["hf"], "token", None) is None:
|
| 80 |
+
self.storage_options["hf"]["token"] = value
|
| 81 |
+
super().__setattr__(name, value)
|
venv/Lib/site-packages/datasets/download/download_manager.py
ADDED
|
@@ -0,0 +1,340 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2020 The TensorFlow Datasets Authors.
|
| 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 |
+
# Lint as: python3
|
| 16 |
+
"""Download manager interface."""
|
| 17 |
+
|
| 18 |
+
import enum
|
| 19 |
+
import io
|
| 20 |
+
import multiprocessing
|
| 21 |
+
import os
|
| 22 |
+
from datetime import datetime
|
| 23 |
+
from functools import partial
|
| 24 |
+
from typing import Optional, Union
|
| 25 |
+
|
| 26 |
+
import fsspec
|
| 27 |
+
from fsspec.core import url_to_fs
|
| 28 |
+
from tqdm.contrib.concurrent import thread_map
|
| 29 |
+
|
| 30 |
+
from .. import config
|
| 31 |
+
from ..utils import tqdm as hf_tqdm
|
| 32 |
+
from ..utils.file_utils import (
|
| 33 |
+
ArchiveIterable,
|
| 34 |
+
FilesIterable,
|
| 35 |
+
cached_path,
|
| 36 |
+
is_relative_path,
|
| 37 |
+
stack_multiprocessing_download_progress_bars,
|
| 38 |
+
url_or_path_join,
|
| 39 |
+
)
|
| 40 |
+
from ..utils.info_utils import get_size_checksum_dict
|
| 41 |
+
from ..utils.logging import get_logger, tqdm
|
| 42 |
+
from ..utils.py_utils import NestedDataStructure, map_nested
|
| 43 |
+
from ..utils.track import tracked_str
|
| 44 |
+
from .download_config import DownloadConfig
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
logger = get_logger(__name__)
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
class DownloadMode(enum.Enum):
|
| 51 |
+
"""`Enum` for how to treat pre-existing downloads and data.
|
| 52 |
+
|
| 53 |
+
The default mode is `REUSE_DATASET_IF_EXISTS`, which will reuse both
|
| 54 |
+
raw downloads and the prepared dataset if they exist.
|
| 55 |
+
|
| 56 |
+
The generations modes:
|
| 57 |
+
|
| 58 |
+
| | Downloads | Dataset |
|
| 59 |
+
|-------------------------------------|-----------|---------|
|
| 60 |
+
| `REUSE_DATASET_IF_EXISTS` (default) | Reuse | Reuse |
|
| 61 |
+
| `REUSE_CACHE_IF_EXISTS` | Reuse | Fresh |
|
| 62 |
+
| `FORCE_REDOWNLOAD` | Fresh | Fresh |
|
| 63 |
+
|
| 64 |
+
"""
|
| 65 |
+
|
| 66 |
+
REUSE_DATASET_IF_EXISTS = "reuse_dataset_if_exists"
|
| 67 |
+
REUSE_CACHE_IF_EXISTS = "reuse_cache_if_exists"
|
| 68 |
+
FORCE_REDOWNLOAD = "force_redownload"
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
class DownloadManager:
|
| 72 |
+
is_streaming = False
|
| 73 |
+
|
| 74 |
+
def __init__(
|
| 75 |
+
self,
|
| 76 |
+
dataset_name: Optional[str] = None,
|
| 77 |
+
data_dir: Optional[str] = None,
|
| 78 |
+
download_config: Optional[DownloadConfig] = None,
|
| 79 |
+
base_path: Optional[str] = None,
|
| 80 |
+
record_checksums=False,
|
| 81 |
+
):
|
| 82 |
+
"""Download manager constructor.
|
| 83 |
+
|
| 84 |
+
Args:
|
| 85 |
+
data_dir:
|
| 86 |
+
can be used to specify a manual directory to get the files from.
|
| 87 |
+
dataset_name (`str`):
|
| 88 |
+
name of dataset this instance will be used for. If
|
| 89 |
+
provided, downloads will contain which datasets they were used for.
|
| 90 |
+
download_config (`DownloadConfig`):
|
| 91 |
+
to specify the cache directory and other
|
| 92 |
+
download options
|
| 93 |
+
base_path (`str`):
|
| 94 |
+
base path that is used when relative paths are used to
|
| 95 |
+
download files. This can be a remote url.
|
| 96 |
+
record_checksums (`bool`, defaults to `False`):
|
| 97 |
+
Whether to record the checksums of the downloaded files. If None, the value is inferred from the builder.
|
| 98 |
+
"""
|
| 99 |
+
self._dataset_name = dataset_name
|
| 100 |
+
self._data_dir = data_dir
|
| 101 |
+
self._base_path = base_path or os.path.abspath(".")
|
| 102 |
+
# To record what is being used: {url: {num_bytes: int, checksum: str}}
|
| 103 |
+
self._recorded_sizes_checksums: dict[str, dict[str, Optional[Union[int, str]]]] = {}
|
| 104 |
+
self.record_checksums = record_checksums
|
| 105 |
+
self.download_config = download_config or DownloadConfig()
|
| 106 |
+
self.downloaded_paths = {}
|
| 107 |
+
self.extracted_paths = {}
|
| 108 |
+
|
| 109 |
+
@property
|
| 110 |
+
def manual_dir(self):
|
| 111 |
+
return self._data_dir
|
| 112 |
+
|
| 113 |
+
@property
|
| 114 |
+
def downloaded_size(self):
|
| 115 |
+
"""Returns the total size of downloaded files."""
|
| 116 |
+
return sum(checksums_dict["num_bytes"] for checksums_dict in self._recorded_sizes_checksums.values())
|
| 117 |
+
|
| 118 |
+
def _record_sizes_checksums(self, url_or_urls: NestedDataStructure, downloaded_path_or_paths: NestedDataStructure):
|
| 119 |
+
"""Record size/checksum of downloaded files."""
|
| 120 |
+
delay = 5
|
| 121 |
+
for url, path in hf_tqdm(
|
| 122 |
+
list(zip(url_or_urls.flatten(), downloaded_path_or_paths.flatten())),
|
| 123 |
+
delay=delay,
|
| 124 |
+
desc="Computing checksums",
|
| 125 |
+
):
|
| 126 |
+
# call str to support PathLike objects
|
| 127 |
+
self._recorded_sizes_checksums[str(url)] = get_size_checksum_dict(
|
| 128 |
+
path, record_checksum=self.record_checksums
|
| 129 |
+
)
|
| 130 |
+
|
| 131 |
+
def download(self, url_or_urls):
|
| 132 |
+
"""Download given URL(s).
|
| 133 |
+
|
| 134 |
+
By default, only one process is used for download. Pass customized `download_config.num_proc` to change this behavior.
|
| 135 |
+
|
| 136 |
+
Args:
|
| 137 |
+
url_or_urls (`str` or `list` or `dict`):
|
| 138 |
+
URL or `list` or `dict` of URLs to download. Each URL is a `str`.
|
| 139 |
+
|
| 140 |
+
Returns:
|
| 141 |
+
`str` or `list` or `dict`:
|
| 142 |
+
The downloaded paths matching the given input `url_or_urls`.
|
| 143 |
+
|
| 144 |
+
Example:
|
| 145 |
+
|
| 146 |
+
```py
|
| 147 |
+
>>> downloaded_files = dl_manager.download('https://storage.googleapis.com/seldon-datasets/sentence_polarity_v1/rt-polaritydata.tar.gz')
|
| 148 |
+
```
|
| 149 |
+
"""
|
| 150 |
+
download_config = self.download_config.copy()
|
| 151 |
+
download_config.extract_compressed_file = False
|
| 152 |
+
if download_config.download_desc is None:
|
| 153 |
+
download_config.download_desc = "Downloading data"
|
| 154 |
+
|
| 155 |
+
download_func = partial(self._download_batched, download_config=download_config)
|
| 156 |
+
|
| 157 |
+
start_time = datetime.now()
|
| 158 |
+
with stack_multiprocessing_download_progress_bars():
|
| 159 |
+
downloaded_path_or_paths = map_nested(
|
| 160 |
+
download_func,
|
| 161 |
+
url_or_urls,
|
| 162 |
+
map_tuple=True,
|
| 163 |
+
num_proc=download_config.num_proc,
|
| 164 |
+
desc="Downloading data files",
|
| 165 |
+
batched=True,
|
| 166 |
+
batch_size=-1,
|
| 167 |
+
)
|
| 168 |
+
duration = datetime.now() - start_time
|
| 169 |
+
logger.info(f"Downloading took {duration.total_seconds() // 60} min")
|
| 170 |
+
url_or_urls = NestedDataStructure(url_or_urls)
|
| 171 |
+
downloaded_path_or_paths = NestedDataStructure(downloaded_path_or_paths)
|
| 172 |
+
self.downloaded_paths.update(dict(zip(url_or_urls.flatten(), downloaded_path_or_paths.flatten())))
|
| 173 |
+
|
| 174 |
+
start_time = datetime.now()
|
| 175 |
+
self._record_sizes_checksums(url_or_urls, downloaded_path_or_paths)
|
| 176 |
+
duration = datetime.now() - start_time
|
| 177 |
+
logger.info(f"Checksum Computation took {duration.total_seconds() // 60} min")
|
| 178 |
+
|
| 179 |
+
return downloaded_path_or_paths.data
|
| 180 |
+
|
| 181 |
+
def _download_batched(
|
| 182 |
+
self,
|
| 183 |
+
url_or_filenames: list[str],
|
| 184 |
+
download_config: DownloadConfig,
|
| 185 |
+
) -> list[str]:
|
| 186 |
+
if len(url_or_filenames) >= 16:
|
| 187 |
+
download_config = download_config.copy()
|
| 188 |
+
download_config.disable_tqdm = True
|
| 189 |
+
download_func = partial(self._download_single, download_config=download_config)
|
| 190 |
+
|
| 191 |
+
fs: fsspec.AbstractFileSystem
|
| 192 |
+
path = str(url_or_filenames[0])
|
| 193 |
+
if is_relative_path(path):
|
| 194 |
+
# append the relative path to the base_path
|
| 195 |
+
path = url_or_path_join(self._base_path, path)
|
| 196 |
+
fs, path = url_to_fs(path, **download_config.storage_options)
|
| 197 |
+
size = 0
|
| 198 |
+
try:
|
| 199 |
+
size = fs.info(path).get("size", 0)
|
| 200 |
+
except Exception:
|
| 201 |
+
pass
|
| 202 |
+
max_workers = (
|
| 203 |
+
config.HF_DATASETS_MULTITHREADING_MAX_WORKERS if size < (20 << 20) else 1
|
| 204 |
+
) # enable multithreading if files are small
|
| 205 |
+
|
| 206 |
+
return thread_map(
|
| 207 |
+
download_func,
|
| 208 |
+
url_or_filenames,
|
| 209 |
+
desc=download_config.download_desc or "Downloading",
|
| 210 |
+
unit="files",
|
| 211 |
+
position=multiprocessing.current_process()._identity[-1] # contains the ranks of subprocesses
|
| 212 |
+
if os.environ.get("HF_DATASETS_STACK_MULTIPROCESSING_DOWNLOAD_PROGRESS_BARS") == "1"
|
| 213 |
+
and multiprocessing.current_process()._identity
|
| 214 |
+
else None,
|
| 215 |
+
max_workers=max_workers,
|
| 216 |
+
tqdm_class=tqdm,
|
| 217 |
+
)
|
| 218 |
+
else:
|
| 219 |
+
return [
|
| 220 |
+
self._download_single(url_or_filename, download_config=download_config)
|
| 221 |
+
for url_or_filename in url_or_filenames
|
| 222 |
+
]
|
| 223 |
+
|
| 224 |
+
def _download_single(self, url_or_filename: str, download_config: DownloadConfig) -> str:
|
| 225 |
+
url_or_filename = str(url_or_filename)
|
| 226 |
+
if is_relative_path(url_or_filename):
|
| 227 |
+
# append the relative path to the base_path
|
| 228 |
+
url_or_filename = url_or_path_join(self._base_path, url_or_filename)
|
| 229 |
+
out = cached_path(url_or_filename, download_config=download_config)
|
| 230 |
+
out = tracked_str(out)
|
| 231 |
+
out.set_origin(url_or_filename)
|
| 232 |
+
return out
|
| 233 |
+
|
| 234 |
+
def iter_archive(self, path_or_buf: Union[str, io.BufferedReader]):
|
| 235 |
+
"""Iterate over files within an archive.
|
| 236 |
+
|
| 237 |
+
Args:
|
| 238 |
+
path_or_buf (`str` or `io.BufferedReader`):
|
| 239 |
+
Archive path or archive binary file object.
|
| 240 |
+
|
| 241 |
+
Yields:
|
| 242 |
+
`tuple[str, io.BufferedReader]`:
|
| 243 |
+
2-tuple (path_within_archive, file_object).
|
| 244 |
+
File object is opened in binary mode.
|
| 245 |
+
|
| 246 |
+
Example:
|
| 247 |
+
|
| 248 |
+
```py
|
| 249 |
+
>>> archive = dl_manager.download('https://storage.googleapis.com/seldon-datasets/sentence_polarity_v1/rt-polaritydata.tar.gz')
|
| 250 |
+
>>> files = dl_manager.iter_archive(archive)
|
| 251 |
+
```
|
| 252 |
+
"""
|
| 253 |
+
|
| 254 |
+
if hasattr(path_or_buf, "read"):
|
| 255 |
+
return ArchiveIterable.from_buf(path_or_buf)
|
| 256 |
+
else:
|
| 257 |
+
return ArchiveIterable.from_urlpath(path_or_buf)
|
| 258 |
+
|
| 259 |
+
def iter_files(self, paths: Union[str, list[str]]):
|
| 260 |
+
"""Iterate over file paths.
|
| 261 |
+
|
| 262 |
+
Args:
|
| 263 |
+
paths (`str` or `list` of `str`):
|
| 264 |
+
Root paths.
|
| 265 |
+
|
| 266 |
+
Yields:
|
| 267 |
+
`str`: File path.
|
| 268 |
+
|
| 269 |
+
Example:
|
| 270 |
+
|
| 271 |
+
```py
|
| 272 |
+
>>> files = dl_manager.download_and_extract('https://huggingface.co/datasets/AI-Lab-Makerere/beans/resolve/main/data/train.zip')
|
| 273 |
+
>>> files = dl_manager.iter_files(files)
|
| 274 |
+
```
|
| 275 |
+
"""
|
| 276 |
+
return FilesIterable.from_urlpaths(paths)
|
| 277 |
+
|
| 278 |
+
def extract(self, path_or_paths):
|
| 279 |
+
"""Extract given path(s).
|
| 280 |
+
|
| 281 |
+
Args:
|
| 282 |
+
path_or_paths (path or `list` or `dict`):
|
| 283 |
+
Path of file to extract. Each path is a `str`.
|
| 284 |
+
|
| 285 |
+
Returns:
|
| 286 |
+
extracted_path(s): `str`, The extracted paths matching the given input
|
| 287 |
+
path_or_paths.
|
| 288 |
+
|
| 289 |
+
Example:
|
| 290 |
+
|
| 291 |
+
```py
|
| 292 |
+
>>> downloaded_files = dl_manager.download('https://storage.googleapis.com/seldon-datasets/sentence_polarity_v1/rt-polaritydata.tar.gz')
|
| 293 |
+
>>> extracted_files = dl_manager.extract(downloaded_files)
|
| 294 |
+
```
|
| 295 |
+
"""
|
| 296 |
+
download_config = self.download_config.copy()
|
| 297 |
+
download_config.extract_compressed_file = True
|
| 298 |
+
extract_func = partial(self._download_single, download_config=download_config)
|
| 299 |
+
extracted_paths = map_nested(
|
| 300 |
+
extract_func,
|
| 301 |
+
path_or_paths,
|
| 302 |
+
num_proc=download_config.num_proc,
|
| 303 |
+
desc="Extracting data files",
|
| 304 |
+
)
|
| 305 |
+
path_or_paths = NestedDataStructure(path_or_paths)
|
| 306 |
+
extracted_paths = NestedDataStructure(extracted_paths)
|
| 307 |
+
self.extracted_paths.update(dict(zip(path_or_paths.flatten(), extracted_paths.flatten())))
|
| 308 |
+
return extracted_paths.data
|
| 309 |
+
|
| 310 |
+
def download_and_extract(self, url_or_urls):
|
| 311 |
+
"""Download and extract given `url_or_urls`.
|
| 312 |
+
|
| 313 |
+
Is roughly equivalent to:
|
| 314 |
+
|
| 315 |
+
```
|
| 316 |
+
extracted_paths = dl_manager.extract(dl_manager.download(url_or_urls))
|
| 317 |
+
```
|
| 318 |
+
|
| 319 |
+
Args:
|
| 320 |
+
url_or_urls (`str` or `list` or `dict`):
|
| 321 |
+
URL or `list` or `dict` of URLs to download and extract. Each URL is a `str`.
|
| 322 |
+
|
| 323 |
+
Returns:
|
| 324 |
+
extracted_path(s): `str`, extracted paths of given URL(s).
|
| 325 |
+
"""
|
| 326 |
+
return self.extract(self.download(url_or_urls))
|
| 327 |
+
|
| 328 |
+
def get_recorded_sizes_checksums(self):
|
| 329 |
+
return self._recorded_sizes_checksums.copy()
|
| 330 |
+
|
| 331 |
+
def delete_extracted_files(self):
|
| 332 |
+
paths_to_delete = set(self.extracted_paths.values()) - set(self.downloaded_paths.values())
|
| 333 |
+
for key, path in list(self.extracted_paths.items()):
|
| 334 |
+
if path in paths_to_delete and os.path.isfile(path):
|
| 335 |
+
os.remove(path)
|
| 336 |
+
del self.extracted_paths[key]
|
| 337 |
+
|
| 338 |
+
def manage_extracted_files(self):
|
| 339 |
+
if self.download_config.delete_extracted:
|
| 340 |
+
self.delete_extracted_files()
|
venv/Lib/site-packages/datasets/download/streaming_download_manager.py
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import io
|
| 2 |
+
import os
|
| 3 |
+
from collections.abc import Iterable
|
| 4 |
+
from typing import Optional, Union
|
| 5 |
+
|
| 6 |
+
from ..utils.file_utils import ( # noqa: F401 # backward compatibility
|
| 7 |
+
SINGLE_FILE_COMPRESSION_PROTOCOLS,
|
| 8 |
+
ArchiveIterable,
|
| 9 |
+
FilesIterable,
|
| 10 |
+
_get_extraction_protocol,
|
| 11 |
+
_get_path_extension,
|
| 12 |
+
_prepare_path_and_storage_options,
|
| 13 |
+
is_relative_path,
|
| 14 |
+
url_or_path_join,
|
| 15 |
+
xbasename,
|
| 16 |
+
xdirname,
|
| 17 |
+
xet_parse,
|
| 18 |
+
xexists,
|
| 19 |
+
xgetsize,
|
| 20 |
+
xglob,
|
| 21 |
+
xgzip_open,
|
| 22 |
+
xisdir,
|
| 23 |
+
xisfile,
|
| 24 |
+
xjoin,
|
| 25 |
+
xlistdir,
|
| 26 |
+
xnumpy_load,
|
| 27 |
+
xopen,
|
| 28 |
+
xpandas_read_csv,
|
| 29 |
+
xpandas_read_excel,
|
| 30 |
+
xPath,
|
| 31 |
+
xpyarrow_parquet_read_table,
|
| 32 |
+
xrelpath,
|
| 33 |
+
xsio_loadmat,
|
| 34 |
+
xsplit,
|
| 35 |
+
xsplitext,
|
| 36 |
+
xwalk,
|
| 37 |
+
xxml_dom_minidom_parse,
|
| 38 |
+
)
|
| 39 |
+
from ..utils.logging import get_logger
|
| 40 |
+
from ..utils.py_utils import map_nested
|
| 41 |
+
from .download_config import DownloadConfig
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
logger = get_logger(__name__)
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
class StreamingDownloadManager:
|
| 48 |
+
"""
|
| 49 |
+
Download manager that uses the "::" separator to navigate through (possibly remote) compressed archives.
|
| 50 |
+
Contrary to the regular `DownloadManager`, the `download` and `extract` methods don't actually download nor extract
|
| 51 |
+
data, but they rather return the path or url that could be opened using the `xopen` function which extends the
|
| 52 |
+
built-in `open` function to stream data from remote files.
|
| 53 |
+
"""
|
| 54 |
+
|
| 55 |
+
is_streaming = True
|
| 56 |
+
|
| 57 |
+
def __init__(
|
| 58 |
+
self,
|
| 59 |
+
dataset_name: Optional[str] = None,
|
| 60 |
+
data_dir: Optional[str] = None,
|
| 61 |
+
download_config: Optional[DownloadConfig] = None,
|
| 62 |
+
base_path: Optional[str] = None,
|
| 63 |
+
):
|
| 64 |
+
self._dataset_name = dataset_name
|
| 65 |
+
self._data_dir = data_dir
|
| 66 |
+
self._base_path = base_path or os.path.abspath(".")
|
| 67 |
+
self.download_config = download_config or DownloadConfig()
|
| 68 |
+
self.downloaded_size = None
|
| 69 |
+
self.record_checksums = False
|
| 70 |
+
|
| 71 |
+
@property
|
| 72 |
+
def manual_dir(self):
|
| 73 |
+
return self._data_dir
|
| 74 |
+
|
| 75 |
+
def download(self, url_or_urls):
|
| 76 |
+
"""Normalize URL(s) of files to stream data from.
|
| 77 |
+
This is the lazy version of `DownloadManager.download` for streaming.
|
| 78 |
+
|
| 79 |
+
Args:
|
| 80 |
+
url_or_urls (`str` or `list` or `dict`):
|
| 81 |
+
URL(s) of files to stream data from. Each url is a `str`.
|
| 82 |
+
|
| 83 |
+
Returns:
|
| 84 |
+
url(s): (`str` or `list` or `dict`), URL(s) to stream data from matching the given input url_or_urls.
|
| 85 |
+
|
| 86 |
+
Example:
|
| 87 |
+
|
| 88 |
+
```py
|
| 89 |
+
>>> downloaded_files = dl_manager.download('https://storage.googleapis.com/seldon-datasets/sentence_polarity_v1/rt-polaritydata.tar.gz')
|
| 90 |
+
```
|
| 91 |
+
"""
|
| 92 |
+
url_or_urls = map_nested(self._download_single, url_or_urls, map_tuple=True)
|
| 93 |
+
return url_or_urls
|
| 94 |
+
|
| 95 |
+
def _download_single(self, urlpath: str) -> str:
|
| 96 |
+
urlpath = str(urlpath)
|
| 97 |
+
if is_relative_path(urlpath):
|
| 98 |
+
# append the relative path to the base_path
|
| 99 |
+
urlpath = url_or_path_join(self._base_path, urlpath)
|
| 100 |
+
return urlpath
|
| 101 |
+
|
| 102 |
+
def extract(self, url_or_urls):
|
| 103 |
+
"""Add extraction protocol for given url(s) for streaming.
|
| 104 |
+
|
| 105 |
+
This is the lazy version of `DownloadManager.extract` for streaming.
|
| 106 |
+
|
| 107 |
+
Args:
|
| 108 |
+
url_or_urls (`str` or `list` or `dict`):
|
| 109 |
+
URL(s) of files to stream data from. Each url is a `str`.
|
| 110 |
+
|
| 111 |
+
Returns:
|
| 112 |
+
url(s): (`str` or `list` or `dict`), URL(s) to stream data from matching the given input `url_or_urls`.
|
| 113 |
+
|
| 114 |
+
Example:
|
| 115 |
+
|
| 116 |
+
```py
|
| 117 |
+
>>> downloaded_files = dl_manager.download('https://storage.googleapis.com/seldon-datasets/sentence_polarity_v1/rt-polaritydata.tar.gz')
|
| 118 |
+
>>> extracted_files = dl_manager.extract(downloaded_files)
|
| 119 |
+
```
|
| 120 |
+
"""
|
| 121 |
+
urlpaths = map_nested(self._extract, url_or_urls, map_tuple=True)
|
| 122 |
+
return urlpaths
|
| 123 |
+
|
| 124 |
+
def _extract(self, urlpath: str) -> str:
|
| 125 |
+
urlpath = str(urlpath)
|
| 126 |
+
# get inner file: zip://train-00000.json.gz::https://foo.bar/data.zip -> zip://train-00000.json.gz
|
| 127 |
+
protocol = _get_extraction_protocol(urlpath, download_config=self.download_config)
|
| 128 |
+
path = urlpath.split("::")[0]
|
| 129 |
+
extension = _get_path_extension(path)
|
| 130 |
+
if extension in ["tgz", "tar"] or path.endswith((".tar.gz", ".tar.bz2", ".tar.xz")):
|
| 131 |
+
raise NotImplementedError(
|
| 132 |
+
f"Extraction protocol for TAR archives like '{urlpath}' is not implemented in streaming mode. "
|
| 133 |
+
f"Please use `dl_manager.iter_archive` instead.\n\n"
|
| 134 |
+
f"Example usage:\n\n"
|
| 135 |
+
f"\turl = dl_manager.download(url)\n"
|
| 136 |
+
f"\ttar_archive_iterator = dl_manager.iter_archive(url)\n\n"
|
| 137 |
+
f"\tfor filename, file in tar_archive_iterator:\n"
|
| 138 |
+
f"\t\t..."
|
| 139 |
+
)
|
| 140 |
+
if protocol is None:
|
| 141 |
+
# no extraction
|
| 142 |
+
return urlpath
|
| 143 |
+
elif protocol in SINGLE_FILE_COMPRESSION_PROTOCOLS:
|
| 144 |
+
# there is one single file which is the uncompressed file
|
| 145 |
+
inner_file = os.path.basename(urlpath.split("::")[0])
|
| 146 |
+
inner_file = inner_file[: inner_file.rindex(".")] if "." in inner_file else inner_file
|
| 147 |
+
return f"{protocol}://{inner_file}::{urlpath}"
|
| 148 |
+
else:
|
| 149 |
+
return f"{protocol}://::{urlpath}"
|
| 150 |
+
|
| 151 |
+
def download_and_extract(self, url_or_urls):
|
| 152 |
+
"""Prepare given `url_or_urls` for streaming (add extraction protocol).
|
| 153 |
+
|
| 154 |
+
This is the lazy version of `DownloadManager.download_and_extract` for streaming.
|
| 155 |
+
|
| 156 |
+
Is equivalent to:
|
| 157 |
+
|
| 158 |
+
```
|
| 159 |
+
urls = dl_manager.extract(dl_manager.download(url_or_urls))
|
| 160 |
+
```
|
| 161 |
+
|
| 162 |
+
Args:
|
| 163 |
+
url_or_urls (`str` or `list` or `dict`):
|
| 164 |
+
URL(s) to stream from data from. Each url is a `str`.
|
| 165 |
+
|
| 166 |
+
Returns:
|
| 167 |
+
url(s): (`str` or `list` or `dict`), URL(s) to stream data from matching the given input `url_or_urls`.
|
| 168 |
+
"""
|
| 169 |
+
return self.extract(self.download(url_or_urls))
|
| 170 |
+
|
| 171 |
+
def iter_archive(self, urlpath_or_buf: Union[str, io.BufferedReader]) -> Iterable[tuple]:
|
| 172 |
+
"""Iterate over files within an archive.
|
| 173 |
+
|
| 174 |
+
Args:
|
| 175 |
+
urlpath_or_buf (`str` or `io.BufferedReader`):
|
| 176 |
+
Archive path or archive binary file object.
|
| 177 |
+
|
| 178 |
+
Yields:
|
| 179 |
+
`tuple[str, io.BufferedReader]`:
|
| 180 |
+
2-tuple (path_within_archive, file_object).
|
| 181 |
+
File object is opened in binary mode.
|
| 182 |
+
|
| 183 |
+
Example:
|
| 184 |
+
|
| 185 |
+
```py
|
| 186 |
+
>>> archive = dl_manager.download('https://storage.googleapis.com/seldon-datasets/sentence_polarity_v1/rt-polaritydata.tar.gz')
|
| 187 |
+
>>> files = dl_manager.iter_archive(archive)
|
| 188 |
+
```
|
| 189 |
+
"""
|
| 190 |
+
|
| 191 |
+
if hasattr(urlpath_or_buf, "read"):
|
| 192 |
+
return ArchiveIterable.from_buf(urlpath_or_buf)
|
| 193 |
+
else:
|
| 194 |
+
return ArchiveIterable.from_urlpath(urlpath_or_buf, download_config=self.download_config)
|
| 195 |
+
|
| 196 |
+
def iter_files(self, urlpaths: Union[str, list[str]]) -> Iterable[str]:
|
| 197 |
+
"""Iterate over files.
|
| 198 |
+
|
| 199 |
+
Args:
|
| 200 |
+
urlpaths (`str` or `list` of `str`):
|
| 201 |
+
Root paths.
|
| 202 |
+
|
| 203 |
+
Yields:
|
| 204 |
+
str: File URL path.
|
| 205 |
+
|
| 206 |
+
Example:
|
| 207 |
+
|
| 208 |
+
```py
|
| 209 |
+
>>> files = dl_manager.download_and_extract('https://huggingface.co/datasets/AI-Lab-Makerere/beans/resolve/main/data/train.zip')
|
| 210 |
+
>>> files = dl_manager.iter_files(files)
|
| 211 |
+
```
|
| 212 |
+
"""
|
| 213 |
+
return FilesIterable.from_urlpaths(urlpaths, download_config=self.download_config)
|
| 214 |
+
|
| 215 |
+
def manage_extracted_files(self):
|
| 216 |
+
pass
|
| 217 |
+
|
| 218 |
+
def get_recorded_sizes_checksums(self):
|
| 219 |
+
pass
|
venv/Lib/site-packages/datasets/exceptions.py
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# SPDX-License-Identifier: Apache-2.0
|
| 2 |
+
# Copyright 2023 The HuggingFace Authors.
|
| 3 |
+
from typing import Any, Optional, Union
|
| 4 |
+
|
| 5 |
+
from huggingface_hub import HfFileSystem
|
| 6 |
+
|
| 7 |
+
from . import config
|
| 8 |
+
from .table import CastError
|
| 9 |
+
from .utils.track import TrackedIterableFromGenerator, tracked_list, tracked_str
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
class DatasetsError(Exception):
|
| 13 |
+
"""Base class for exceptions in this library."""
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
class DefunctDatasetError(DatasetsError):
|
| 17 |
+
"""The dataset has been defunct."""
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
class FileNotFoundDatasetsError(DatasetsError, FileNotFoundError):
|
| 21 |
+
"""FileNotFoundError raised by this library."""
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
class DataFilesNotFoundError(FileNotFoundDatasetsError):
|
| 25 |
+
"""No (supported) data files found."""
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
class DatasetNotFoundError(FileNotFoundDatasetsError):
|
| 29 |
+
"""Dataset not found.
|
| 30 |
+
|
| 31 |
+
Raised when trying to access:
|
| 32 |
+
- a missing dataset, or
|
| 33 |
+
- a private/gated dataset and the user is not authenticated.
|
| 34 |
+
"""
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
class DatasetBuildError(DatasetsError):
|
| 38 |
+
pass
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
class ManualDownloadError(DatasetBuildError):
|
| 42 |
+
pass
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
class FileFormatError(DatasetBuildError):
|
| 46 |
+
pass
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
class DatasetGenerationError(DatasetBuildError):
|
| 50 |
+
pass
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
class DatasetGenerationCastError(DatasetGenerationError):
|
| 54 |
+
@classmethod
|
| 55 |
+
def from_cast_error(
|
| 56 |
+
cls,
|
| 57 |
+
cast_error: CastError,
|
| 58 |
+
builder_name: str,
|
| 59 |
+
gen_kwargs: dict[str, Any],
|
| 60 |
+
token: Optional[Union[bool, str]],
|
| 61 |
+
) -> "DatasetGenerationCastError":
|
| 62 |
+
explanation_message = (
|
| 63 |
+
f"\n\nAll the data files must have the same columns, but at some point {cast_error.details()}"
|
| 64 |
+
)
|
| 65 |
+
formatted_tracked_gen_kwargs: list[str] = []
|
| 66 |
+
for gen_kwarg in gen_kwargs.values():
|
| 67 |
+
if not isinstance(gen_kwarg, (tracked_str, tracked_list, TrackedIterableFromGenerator)):
|
| 68 |
+
continue
|
| 69 |
+
while (
|
| 70 |
+
isinstance(gen_kwarg, (tracked_list, TrackedIterableFromGenerator)) and gen_kwarg.last_item is not None
|
| 71 |
+
):
|
| 72 |
+
gen_kwarg = gen_kwarg.last_item
|
| 73 |
+
if isinstance(gen_kwarg, tracked_str):
|
| 74 |
+
gen_kwarg = gen_kwarg.get_origin()
|
| 75 |
+
if isinstance(gen_kwarg, str) and gen_kwarg.startswith("hf://"):
|
| 76 |
+
resolved_path = HfFileSystem(endpoint=config.HF_ENDPOINT, token=token).resolve_path(gen_kwarg)
|
| 77 |
+
gen_kwarg = "hf://" + resolved_path.unresolve()
|
| 78 |
+
if "@" + resolved_path.revision in gen_kwarg:
|
| 79 |
+
gen_kwarg = (
|
| 80 |
+
gen_kwarg.replace("@" + resolved_path.revision, "", 1)
|
| 81 |
+
+ f" (at revision {resolved_path.revision})"
|
| 82 |
+
)
|
| 83 |
+
formatted_tracked_gen_kwargs.append(str(gen_kwarg))
|
| 84 |
+
if formatted_tracked_gen_kwargs:
|
| 85 |
+
explanation_message += f"\n\nThis happened while the {builder_name} dataset builder was generating data using\n\n{', '.join(formatted_tracked_gen_kwargs)}"
|
| 86 |
+
help_message = "\n\nPlease either edit the data files to have matching columns, or separate them into different configurations (see docs at https://hf.co/docs/hub/datasets-manual-configuration#multiple-configurations)"
|
| 87 |
+
return cls("An error occurred while generating the dataset" + explanation_message + help_message)
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
class ChecksumVerificationError(DatasetsError):
|
| 91 |
+
"""Error raised during checksums verifications of downloaded files."""
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
class UnexpectedDownloadedFileError(ChecksumVerificationError):
|
| 95 |
+
"""Some downloaded files were not expected."""
|
| 96 |
+
|
| 97 |
+
|
| 98 |
+
class ExpectedMoreDownloadedFilesError(ChecksumVerificationError):
|
| 99 |
+
"""Some files were supposed to be downloaded but were not."""
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
class NonMatchingChecksumError(ChecksumVerificationError):
|
| 103 |
+
"""The downloaded file checksum don't match the expected checksum."""
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
class SplitsVerificationError(DatasetsError):
|
| 107 |
+
"""Error raised during splits verifications."""
|
| 108 |
+
|
| 109 |
+
|
| 110 |
+
class UnexpectedSplitsError(SplitsVerificationError):
|
| 111 |
+
"""The expected splits of the downloaded file is missing."""
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
class ExpectedMoreSplitsError(SplitsVerificationError):
|
| 115 |
+
"""Some recorded splits are missing."""
|
| 116 |
+
|
| 117 |
+
|
| 118 |
+
class NonMatchingSplitsSizesError(SplitsVerificationError):
|
| 119 |
+
"""The splits sizes don't match the expected splits sizes."""
|
venv/Lib/site-packages/datasets/features/__init__.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
__all__ = [
|
| 2 |
+
"Audio",
|
| 3 |
+
"Array2D",
|
| 4 |
+
"Array3D",
|
| 5 |
+
"Array4D",
|
| 6 |
+
"Array5D",
|
| 7 |
+
"ClassLabel",
|
| 8 |
+
"Features",
|
| 9 |
+
"Json",
|
| 10 |
+
"LargeList",
|
| 11 |
+
"List",
|
| 12 |
+
"Sequence",
|
| 13 |
+
"Value",
|
| 14 |
+
"Image",
|
| 15 |
+
"Mesh",
|
| 16 |
+
"Translation",
|
| 17 |
+
"TranslationVariableLanguages",
|
| 18 |
+
"Video",
|
| 19 |
+
"Pdf",
|
| 20 |
+
"Nifti",
|
| 21 |
+
]
|
| 22 |
+
from .audio import Audio
|
| 23 |
+
from .features import Array2D, Array3D, Array4D, Array5D, ClassLabel, Features, Json, LargeList, List, Sequence, Value
|
| 24 |
+
from .image import Image
|
| 25 |
+
from .mesh import Mesh
|
| 26 |
+
from .nifti import Nifti
|
| 27 |
+
from .pdf import Pdf
|
| 28 |
+
from .translation import Translation, TranslationVariableLanguages
|
| 29 |
+
from .video import Video
|