Kurtgitgit commited on
Commit
45f89e1
·
verified ·
1 Parent(s): ff1fc5f

Upload folder using huggingface_hub (part 4)

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +4 -0
  2. venv/Lib/site-packages/datasets-5.0.0.dist-info/AUTHORS +8 -0
  3. venv/Lib/site-packages/datasets-5.0.0.dist-info/INSTALLER +1 -0
  4. venv/Lib/site-packages/datasets-5.0.0.dist-info/LICENSE +202 -0
  5. venv/Lib/site-packages/datasets-5.0.0.dist-info/METADATA +500 -0
  6. venv/Lib/site-packages/datasets-5.0.0.dist-info/RECORD +291 -0
  7. venv/Lib/site-packages/datasets-5.0.0.dist-info/REQUESTED +0 -0
  8. venv/Lib/site-packages/datasets-5.0.0.dist-info/WHEEL +5 -0
  9. venv/Lib/site-packages/datasets-5.0.0.dist-info/entry_points.txt +2 -0
  10. venv/Lib/site-packages/datasets-5.0.0.dist-info/top_level.txt +1 -0
  11. venv/Lib/site-packages/datasets/__pycache__/fingerprint.cpython-311.pyc +0 -0
  12. venv/Lib/site-packages/datasets/__pycache__/hub.cpython-311.pyc +0 -0
  13. venv/Lib/site-packages/datasets/__pycache__/info.cpython-311.pyc +0 -0
  14. venv/Lib/site-packages/datasets/__pycache__/inspect.cpython-311.pyc +0 -0
  15. venv/Lib/site-packages/datasets/__pycache__/iterable_dataset.cpython-311.pyc +3 -0
  16. venv/Lib/site-packages/datasets/__pycache__/load.cpython-311.pyc +0 -0
  17. venv/Lib/site-packages/datasets/__pycache__/naming.cpython-311.pyc +0 -0
  18. venv/Lib/site-packages/datasets/__pycache__/search.cpython-311.pyc +0 -0
  19. venv/Lib/site-packages/datasets/__pycache__/splits.cpython-311.pyc +0 -0
  20. venv/Lib/site-packages/datasets/__pycache__/streaming.cpython-311.pyc +0 -0
  21. venv/Lib/site-packages/datasets/__pycache__/table.cpython-311.pyc +3 -0
  22. venv/Lib/site-packages/datasets/arrow_dataset.py +0 -0
  23. venv/Lib/site-packages/datasets/arrow_reader.py +620 -0
  24. venv/Lib/site-packages/datasets/arrow_writer.py +828 -0
  25. venv/Lib/site-packages/datasets/builder.py +1916 -0
  26. venv/Lib/site-packages/datasets/combine.py +232 -0
  27. venv/Lib/site-packages/datasets/commands/__init__.py +13 -0
  28. venv/Lib/site-packages/datasets/commands/__pycache__/__init__.cpython-311.pyc +0 -0
  29. venv/Lib/site-packages/datasets/commands/__pycache__/datasets_cli.cpython-311.pyc +0 -0
  30. venv/Lib/site-packages/datasets/commands/__pycache__/delete_from_hub.cpython-311.pyc +0 -0
  31. venv/Lib/site-packages/datasets/commands/__pycache__/env.cpython-311.pyc +0 -0
  32. venv/Lib/site-packages/datasets/commands/__pycache__/test.cpython-311.pyc +0 -0
  33. venv/Lib/site-packages/datasets/commands/datasets_cli.py +39 -0
  34. venv/Lib/site-packages/datasets/commands/delete_from_hub.py +42 -0
  35. venv/Lib/site-packages/datasets/commands/env.py +41 -0
  36. venv/Lib/site-packages/datasets/commands/test.py +180 -0
  37. venv/Lib/site-packages/datasets/config.py +277 -0
  38. venv/Lib/site-packages/datasets/data_files.py +829 -0
  39. venv/Lib/site-packages/datasets/dataset_dict.py +0 -0
  40. venv/Lib/site-packages/datasets/distributed.py +43 -0
  41. venv/Lib/site-packages/datasets/download/__init__.py +10 -0
  42. venv/Lib/site-packages/datasets/download/__pycache__/__init__.cpython-311.pyc +0 -0
  43. venv/Lib/site-packages/datasets/download/__pycache__/download_config.cpython-311.pyc +0 -0
  44. venv/Lib/site-packages/datasets/download/__pycache__/download_manager.cpython-311.pyc +0 -0
  45. venv/Lib/site-packages/datasets/download/__pycache__/streaming_download_manager.cpython-311.pyc +0 -0
  46. venv/Lib/site-packages/datasets/download/download_config.py +81 -0
  47. venv/Lib/site-packages/datasets/download/download_manager.py +340 -0
  48. venv/Lib/site-packages/datasets/download/streaming_download_manager.py +219 -0
  49. venv/Lib/site-packages/datasets/exceptions.py +119 -0
  50. 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 ![number of datasets](https://img.shields.io/endpoint?url=https://huggingface.co/api/shields/datasets&color=brightgreen) 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 ![number of datasets](https://img.shields.io/endpoint?url=https://huggingface.co/api/shields/datasets&color=brightgreen) 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