fugue 0.9.7.dev2__tar.gz → 0.9.9.dev0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/PKG-INFO +17 -13
  2. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/README.md +1 -1
  3. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/dataframe/arrow_dataframe.py +9 -2
  4. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/dataframe/pandas_dataframe.py +12 -1
  5. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/execution/native_execution_engine.py +13 -2
  6. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue.egg-info/PKG-INFO +17 -13
  7. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue.egg-info/requires.txt +24 -8
  8. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_dask/execution_engine.py +2 -2
  9. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_duckdb/dataframe.py +2 -3
  10. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_polars/polars_dataframe.py +3 -9
  11. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_ray/_utils/dataframe.py +3 -2
  12. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_ray/_utils/io.py +37 -29
  13. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_ray/dataframe.py +9 -5
  14. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_spark/_utils/misc.py +8 -10
  15. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_spark/execution_engine.py +11 -4
  16. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/pyproject.toml +27 -14
  17. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/LICENSE +0 -0
  18. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/__init__.py +0 -0
  19. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/_utils/__init__.py +0 -0
  20. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/_utils/display.py +0 -0
  21. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/_utils/exception.py +0 -0
  22. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/_utils/interfaceless.py +0 -0
  23. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/_utils/io.py +0 -0
  24. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/_utils/misc.py +0 -0
  25. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/_utils/registry.py +0 -0
  26. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/api.py +0 -0
  27. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/bag/__init__.py +0 -0
  28. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/bag/array_bag.py +0 -0
  29. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/bag/bag.py +0 -0
  30. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/collections/__init__.py +0 -0
  31. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/collections/partition.py +0 -0
  32. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/collections/sql.py +0 -0
  33. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/collections/yielded.py +0 -0
  34. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/column/__init__.py +0 -0
  35. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/column/expressions.py +0 -0
  36. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/column/functions.py +0 -0
  37. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/column/sql.py +0 -0
  38. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/constants.py +0 -0
  39. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/dataframe/__init__.py +0 -0
  40. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/dataframe/api.py +0 -0
  41. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/dataframe/array_dataframe.py +0 -0
  42. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/dataframe/dataframe.py +0 -0
  43. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/dataframe/dataframe_iterable_dataframe.py +0 -0
  44. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/dataframe/dataframes.py +0 -0
  45. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/dataframe/function_wrapper.py +0 -0
  46. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/dataframe/iterable_dataframe.py +0 -0
  47. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/dataframe/utils.py +0 -0
  48. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/dataset/__init__.py +0 -0
  49. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/dataset/api.py +0 -0
  50. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/dataset/dataset.py +0 -0
  51. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/dev.py +0 -0
  52. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/exceptions.py +0 -0
  53. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/execution/__init__.py +0 -0
  54. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/execution/api.py +0 -0
  55. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/execution/execution_engine.py +0 -0
  56. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/execution/factory.py +0 -0
  57. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/extensions/__init__.py +0 -0
  58. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/extensions/_builtins/__init__.py +0 -0
  59. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/extensions/_builtins/creators.py +0 -0
  60. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/extensions/_builtins/outputters.py +0 -0
  61. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/extensions/_builtins/processors.py +0 -0
  62. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/extensions/_utils.py +0 -0
  63. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/extensions/context.py +0 -0
  64. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/extensions/creator/__init__.py +0 -0
  65. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/extensions/creator/convert.py +0 -0
  66. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/extensions/creator/creator.py +0 -0
  67. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/extensions/outputter/__init__.py +0 -0
  68. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/extensions/outputter/convert.py +0 -0
  69. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/extensions/outputter/outputter.py +0 -0
  70. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/extensions/processor/__init__.py +0 -0
  71. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/extensions/processor/convert.py +0 -0
  72. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/extensions/processor/processor.py +0 -0
  73. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/extensions/transformer/__init__.py +0 -0
  74. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/extensions/transformer/constants.py +0 -0
  75. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/extensions/transformer/convert.py +0 -0
  76. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/extensions/transformer/transformer.py +0 -0
  77. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/plugins.py +0 -0
  78. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/py.typed +0 -0
  79. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/registry.py +0 -0
  80. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/rpc/__init__.py +0 -0
  81. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/rpc/base.py +0 -0
  82. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/rpc/flask.py +0 -0
  83. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/sql/__init__.py +0 -0
  84. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/sql/_utils.py +0 -0
  85. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/sql/_visitors.py +0 -0
  86. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/sql/api.py +0 -0
  87. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/sql/workflow.py +0 -0
  88. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/test/__init__.py +0 -0
  89. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/test/pandas_tester.py +0 -0
  90. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/test/plugins.py +0 -0
  91. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/workflow/__init__.py +0 -0
  92. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/workflow/_checkpoint.py +0 -0
  93. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/workflow/_tasks.py +0 -0
  94. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/workflow/_workflow_context.py +0 -0
  95. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/workflow/api.py +0 -0
  96. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/workflow/input.py +0 -0
  97. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/workflow/module.py +0 -0
  98. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue/workflow/workflow.py +0 -0
  99. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue.egg-info/SOURCES.txt +0 -0
  100. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue.egg-info/dependency_links.txt +0 -0
  101. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue.egg-info/entry_points.txt +0 -0
  102. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue.egg-info/top_level.txt +0 -0
  103. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_contrib/__init__.py +0 -0
  104. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_contrib/contrib.py +0 -0
  105. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_contrib/seaborn/__init__.py +0 -0
  106. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_contrib/viz/__init__.py +0 -0
  107. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_contrib/viz/_ext.py +0 -0
  108. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_dask/__init__.py +0 -0
  109. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_dask/_constants.py +0 -0
  110. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_dask/_dask_sql_wrapper.py +0 -0
  111. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_dask/_io.py +0 -0
  112. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_dask/_utils.py +0 -0
  113. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_dask/dataframe.py +0 -0
  114. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_dask/registry.py +0 -0
  115. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_dask/tester.py +0 -0
  116. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_duckdb/__init__.py +0 -0
  117. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_duckdb/_io.py +0 -0
  118. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_duckdb/_utils.py +0 -0
  119. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_duckdb/dask.py +0 -0
  120. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_duckdb/execution_engine.py +0 -0
  121. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_duckdb/registry.py +0 -0
  122. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_duckdb/tester.py +0 -0
  123. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_ibis/__init__.py +0 -0
  124. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_ibis/_compat.py +0 -0
  125. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_ibis/_utils.py +0 -0
  126. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_ibis/dataframe.py +0 -0
  127. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_ibis/execution_engine.py +0 -0
  128. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_notebook/__init__.py +0 -0
  129. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_notebook/env.py +0 -0
  130. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_notebook/nbextension/README.md +0 -0
  131. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_notebook/nbextension/__init__.py +0 -0
  132. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_notebook/nbextension/description.yaml +0 -0
  133. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_notebook/nbextension/main.js +0 -0
  134. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_polars/__init__.py +0 -0
  135. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_polars/_utils.py +0 -0
  136. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_polars/registry.py +0 -0
  137. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_ray/__init__.py +0 -0
  138. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_ray/_constants.py +0 -0
  139. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_ray/_utils/__init__.py +0 -0
  140. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_ray/_utils/cluster.py +0 -0
  141. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_ray/execution_engine.py +0 -0
  142. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_ray/registry.py +0 -0
  143. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_ray/tester.py +0 -0
  144. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_spark/__init__.py +0 -0
  145. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_spark/_constants.py +0 -0
  146. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_spark/_utils/__init__.py +0 -0
  147. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_spark/_utils/convert.py +0 -0
  148. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_spark/_utils/io.py +0 -0
  149. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_spark/_utils/partition.py +0 -0
  150. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_spark/dataframe.py +0 -0
  151. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_spark/registry.py +0 -0
  152. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_spark/tester.py +0 -0
  153. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_sql/__init__.py +0 -0
  154. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_sql/exceptions.py +0 -0
  155. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_test/__init__.py +0 -0
  156. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_test/bag_suite.py +0 -0
  157. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_test/builtin_suite.py +0 -0
  158. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_test/dataframe_suite.py +0 -0
  159. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_test/execution_suite.py +0 -0
  160. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/fugue_test/fixtures.py +0 -0
  161. {fugue-0.9.7.dev2 → fugue-0.9.9.dev0}/setup.cfg +0 -0
@@ -1,28 +1,30 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fugue
3
- Version: 0.9.7.dev2
3
+ Version: 0.9.9.dev0
4
4
  Summary: An abstraction layer for distributed computing
5
5
  Author-email: The Fugue Development Team <hello@fugue.ai>
6
6
  License: Apache-2.0
7
7
  Project-URL: Homepage, http://github.com/fugue-project/fugue
8
8
  Project-URL: Repository, http://github.com/fugue-project/fugue
9
- Keywords: distributed,spark,dask,ray,sql,dsl,domain specific language
9
+ Keywords: distributed,spark,dask,ray,duckdb,sql,dsl,domain specific language
10
10
  Classifier: Development Status :: 5 - Production/Stable
11
11
  Classifier: Intended Audience :: Developers
12
12
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
13
13
  Classifier: Programming Language :: Python :: 3
14
- Classifier: Programming Language :: Python :: 3.10
15
14
  Classifier: Programming Language :: Python :: 3.11
16
15
  Classifier: Programming Language :: Python :: 3.12
17
16
  Classifier: Programming Language :: Python :: 3.13
18
17
  Classifier: Programming Language :: Python :: 3.14
18
+ Classifier: Programming Language :: Python :: 3.15
19
19
  Classifier: Programming Language :: Python :: 3 :: Only
20
- Requires-Python: >=3.10
20
+ Requires-Python: >=3.11
21
21
  Description-Content-Type: text/markdown
22
22
  License-File: LICENSE
23
- Requires-Dist: triad>=1.0.1
23
+ Requires-Dist: triad>=1.0.4
24
24
  Requires-Dist: adagio>=0.2.6
25
- Requires-Dist: pandas<3
25
+ Requires-Dist: pandas; python_version < "3.15"
26
+ Requires-Dist: pandas>=3; python_version >= "3.15"
27
+ Requires-Dist: packaging
26
28
  Provides-Extra: sql
27
29
  Requires-Dist: duckdb>=0.5.0; extra == "sql"
28
30
  Requires-Dist: fugue-sql-antlr>=0.2.4; extra == "sql"
@@ -31,10 +33,11 @@ Requires-Dist: jinja2; extra == "sql"
31
33
  Provides-Extra: cpp-sql-parser
32
34
  Requires-Dist: fugue-sql-antlr[cpp]>=0.2.4; extra == "cpp-sql-parser"
33
35
  Provides-Extra: spark
34
- Requires-Dist: pyspark>=3.1.1; extra == "spark"
36
+ Requires-Dist: pyspark>=3.5; python_version < "3.12" and extra == "spark"
37
+ Requires-Dist: pyspark>=4.0; python_version >= "3.12" and extra == "spark"
35
38
  Requires-Dist: zstandard>=0.25.0; extra == "spark"
36
39
  Provides-Extra: dask
37
- Requires-Dist: dask[dataframe,distributed]>=2024.4.0; extra == "dask"
40
+ Requires-Dist: dask[dataframe,distributed]>=2025.12.0; extra == "dask"
38
41
  Requires-Dist: pyarrow>=7.0.0; extra == "dask"
39
42
  Requires-Dist: pandas>=2.0.2; extra == "dask"
40
43
  Provides-Extra: ray
@@ -54,7 +57,7 @@ Provides-Extra: ibis
54
57
  Requires-Dist: fugue-sql-antlr>=0.2.4; extra == "ibis"
55
58
  Requires-Dist: sqlglot<28; extra == "ibis"
56
59
  Requires-Dist: jinja2; extra == "ibis"
57
- Requires-Dist: ibis-framework[pandas]; extra == "ibis"
60
+ Requires-Dist: ibis-framework; extra == "ibis"
58
61
  Provides-Extra: notebook
59
62
  Requires-Dist: notebook; extra == "notebook"
60
63
  Requires-Dist: jupyterlab; extra == "notebook"
@@ -63,8 +66,9 @@ Provides-Extra: all
63
66
  Requires-Dist: fugue-sql-antlr>=0.2.4; extra == "all"
64
67
  Requires-Dist: sqlglot<28; extra == "all"
65
68
  Requires-Dist: jinja2; extra == "all"
66
- Requires-Dist: pyspark>=3.1.1; extra == "all"
67
- Requires-Dist: dask[dataframe,distributed]>=2024.4.0; extra == "all"
69
+ Requires-Dist: pyspark>=3.5; python_version < "3.12" and extra == "all"
70
+ Requires-Dist: pyspark>=4.0; python_version >= "3.12" and extra == "all"
71
+ Requires-Dist: dask[dataframe,distributed]>=2025.12.0; extra == "all"
68
72
  Requires-Dist: dask-sql; extra == "all"
69
73
  Requires-Dist: ray[data]>=2.30.0; python_version < "3.14" and extra == "all"
70
74
  Requires-Dist: notebook; extra == "all"
@@ -73,7 +77,7 @@ Requires-Dist: ipython>=7.10.0; extra == "all"
73
77
  Requires-Dist: duckdb>=0.5.0; extra == "all"
74
78
  Requires-Dist: pyarrow>=6.0.1; extra == "all"
75
79
  Requires-Dist: pandas>=2.0.2; extra == "all"
76
- Requires-Dist: ibis-framework[duckdb,pandas]; extra == "all"
80
+ Requires-Dist: ibis-framework[duckdb]; extra == "all"
77
81
  Requires-Dist: polars; extra == "all"
78
82
  Dynamic: license-file
79
83
 
@@ -82,7 +86,7 @@ Dynamic: license-file
82
86
  [![PyPI version](https://badge.fury.io/py/fugue.svg)](https://pypi.python.org/pypi/fugue/)
83
87
  [![PyPI pyversions](https://img.shields.io/pypi/pyversions/fugue.svg)](https://pypi.python.org/pypi/fugue/)
84
88
  [![PyPI license](https://img.shields.io/pypi/l/fugue.svg)](https://pypi.python.org/pypi/fugue/)
85
- [![codecov](https://codecov.io/gh/fugue-project/fugue/branch/main/graph/badge.svg?token=ZO9YD5N3IA)](https://codecov.io/gh/fugue-project/fugue)
89
+ [![codecov](https://codecov.io/gh/fugue-project/fugue/graph/badge.svg?token=ZO9YD5N3IA)](https://codecov.io/gh/fugue-project/fugue)
86
90
  [![Codacy Badge](https://app.codacy.com/project/badge/Grade/4fa5f2f53e6f48aaa1218a89f4808b91)](https://www.codacy.com/gh/fugue-project/fugue/dashboard?utm_source=github.com&utm_medium=referral&utm_content=fugue-project/fugue&utm_campaign=Badge_Grade)
87
91
  [![Downloads](https://static.pepy.tech/badge/fugue)](https://pepy.tech/project/fugue)
88
92
 
@@ -3,7 +3,7 @@
3
3
  [![PyPI version](https://badge.fury.io/py/fugue.svg)](https://pypi.python.org/pypi/fugue/)
4
4
  [![PyPI pyversions](https://img.shields.io/pypi/pyversions/fugue.svg)](https://pypi.python.org/pypi/fugue/)
5
5
  [![PyPI license](https://img.shields.io/pypi/l/fugue.svg)](https://pypi.python.org/pypi/fugue/)
6
- [![codecov](https://codecov.io/gh/fugue-project/fugue/branch/main/graph/badge.svg?token=ZO9YD5N3IA)](https://codecov.io/gh/fugue-project/fugue)
6
+ [![codecov](https://codecov.io/gh/fugue-project/fugue/graph/badge.svg?token=ZO9YD5N3IA)](https://codecov.io/gh/fugue-project/fugue)
7
7
  [![Codacy Badge](https://app.codacy.com/project/badge/Grade/4fa5f2f53e6f48aaa1218a89f4808b91)](https://www.codacy.com/gh/fugue-project/fugue/dashboard?utm_source=github.com&utm_medium=referral&utm_content=fugue-project/fugue&utm_campaign=Badge_Grade)
8
8
  [![Downloads](https://static.pepy.tech/badge/fugue)](https://pepy.tech/project/fugue)
9
9
 
@@ -5,7 +5,12 @@ import pyarrow as pa
5
5
  from triad.collections.schema import Schema
6
6
  from triad.exceptions import InvalidOperationError
7
7
  from triad.utils.assertion import assert_or_throw
8
- from triad.utils.pyarrow import cast_pa_table, pa_table_to_pandas
8
+ from triad.utils.pyarrow import (
9
+ cast_pa_table,
10
+ normalize_large_types,
11
+ normalize_large_types_in_table,
12
+ pa_table_to_pandas,
13
+ )
9
14
 
10
15
  from fugue.dataset.api import (
11
16
  as_fugue_dataset,
@@ -73,6 +78,7 @@ class ArrowDataFrame(LocalBoundedDataFrame):
73
78
  schema is None,
74
79
  InvalidOperationError("can't reset schema for pa.Table"),
75
80
  )
81
+ df = normalize_large_types_in_table(df)
76
82
  self._native = df
77
83
  super().__init__(Schema(df.schema))
78
84
  return
@@ -253,6 +259,7 @@ def _pa_table_as_dict_iterable(
253
259
  def _pa_table_alter_columns(
254
260
  df: pa.Table, columns: Any, as_fugue: bool = False
255
261
  ) -> pa.Table:
262
+ df = normalize_large_types_in_table(df)
256
263
  schema = Schema(df.schema)
257
264
  new_schema = schema.alter(columns)
258
265
  if schema != new_schema:
@@ -302,7 +309,7 @@ def _get_pyarrow_table_columns(df: pa.Table) -> List[Any]:
302
309
 
303
310
  @get_schema.candidate(lambda df: isinstance(df, pa.Table))
304
311
  def _get_pyarrow_table_schema(df: pa.Table) -> Schema:
305
- return Schema(df.schema)
312
+ return Schema(normalize_large_types(df.schema))
306
313
 
307
314
 
308
315
  @rename.candidate(lambda df, *args, **kwargs: isinstance(df, pa.Table))
@@ -1,3 +1,4 @@
1
+ import math
1
2
  from typing import Any, Dict, Iterable, List, Optional, Tuple
2
3
 
3
4
  import pandas as pd
@@ -109,7 +110,17 @@ class PandasDataFrame(LocalBoundedDataFrame):
109
110
 
110
111
  def peek_array(self) -> List[Any]:
111
112
  self.assert_not_empty()
112
- return self.native.iloc[0].values.tolist()
113
+ arr = self.native.iloc[0].values.tolist()
114
+ # missing non-float values may come back as nan / pd.NA
115
+ return [
116
+ (
117
+ None
118
+ if (v is pd.NA or (isinstance(v, float) and math.isnan(v)))
119
+ and not pa.types.is_floating(t)
120
+ else v
121
+ )
122
+ for v, t in zip(arr, self.schema.types)
123
+ ]
113
124
 
114
125
  def count(self) -> int:
115
126
  return self.native.shape[0]
@@ -2,7 +2,6 @@ import logging
2
2
  import os
3
3
  from typing import Any, Callable, Dict, List, Optional, Type, Union
4
4
 
5
- import numpy as np
6
5
  import pandas as pd
7
6
  from triad import Schema
8
7
  from triad.collections.dict import IndexedOrderedDict
@@ -149,7 +148,7 @@ class PandasMapEngine(MapEngine):
149
148
  )
150
149
  dfs: List[DataFrame] = []
151
150
  for p, subdf in enumerate(
152
- np.array_split(input_df.as_pandas(), partitions)
151
+ _split_pandas(input_df.as_pandas(), partitions)
153
152
  ):
154
153
  if len(subdf) > 0:
155
154
  tdf = PandasDataFrame(subdf, df.schema, pandas_df_wrapper=True)
@@ -443,3 +442,15 @@ class _NativeExecutionEngineParam(ExecutionEngineParam):
443
442
  def _to_native_execution_engine_df(df: AnyDataFrame, schema: Any = None) -> DataFrame:
444
443
  fdf = as_fugue_df(df) if schema is None else as_fugue_df(df, schema=schema)
445
444
  return fdf.as_local_bounded()
445
+
446
+
447
+ def _split_pandas(df: pd.DataFrame, n: int) -> List[pd.DataFrame]:
448
+ # same chunk sizes as np.array_split, which returns ndarrays on pandas 3
449
+ size, extra = divmod(len(df), n)
450
+ res: List[pd.DataFrame] = []
451
+ start = 0
452
+ for i in range(n):
453
+ end = start + size + (1 if i < extra else 0)
454
+ res.append(df.iloc[start:end].reset_index(drop=True))
455
+ start = end
456
+ return res
@@ -1,28 +1,30 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fugue
3
- Version: 0.9.7.dev2
3
+ Version: 0.9.9.dev0
4
4
  Summary: An abstraction layer for distributed computing
5
5
  Author-email: The Fugue Development Team <hello@fugue.ai>
6
6
  License: Apache-2.0
7
7
  Project-URL: Homepage, http://github.com/fugue-project/fugue
8
8
  Project-URL: Repository, http://github.com/fugue-project/fugue
9
- Keywords: distributed,spark,dask,ray,sql,dsl,domain specific language
9
+ Keywords: distributed,spark,dask,ray,duckdb,sql,dsl,domain specific language
10
10
  Classifier: Development Status :: 5 - Production/Stable
11
11
  Classifier: Intended Audience :: Developers
12
12
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
13
13
  Classifier: Programming Language :: Python :: 3
14
- Classifier: Programming Language :: Python :: 3.10
15
14
  Classifier: Programming Language :: Python :: 3.11
16
15
  Classifier: Programming Language :: Python :: 3.12
17
16
  Classifier: Programming Language :: Python :: 3.13
18
17
  Classifier: Programming Language :: Python :: 3.14
18
+ Classifier: Programming Language :: Python :: 3.15
19
19
  Classifier: Programming Language :: Python :: 3 :: Only
20
- Requires-Python: >=3.10
20
+ Requires-Python: >=3.11
21
21
  Description-Content-Type: text/markdown
22
22
  License-File: LICENSE
23
- Requires-Dist: triad>=1.0.1
23
+ Requires-Dist: triad>=1.0.4
24
24
  Requires-Dist: adagio>=0.2.6
25
- Requires-Dist: pandas<3
25
+ Requires-Dist: pandas; python_version < "3.15"
26
+ Requires-Dist: pandas>=3; python_version >= "3.15"
27
+ Requires-Dist: packaging
26
28
  Provides-Extra: sql
27
29
  Requires-Dist: duckdb>=0.5.0; extra == "sql"
28
30
  Requires-Dist: fugue-sql-antlr>=0.2.4; extra == "sql"
@@ -31,10 +33,11 @@ Requires-Dist: jinja2; extra == "sql"
31
33
  Provides-Extra: cpp-sql-parser
32
34
  Requires-Dist: fugue-sql-antlr[cpp]>=0.2.4; extra == "cpp-sql-parser"
33
35
  Provides-Extra: spark
34
- Requires-Dist: pyspark>=3.1.1; extra == "spark"
36
+ Requires-Dist: pyspark>=3.5; python_version < "3.12" and extra == "spark"
37
+ Requires-Dist: pyspark>=4.0; python_version >= "3.12" and extra == "spark"
35
38
  Requires-Dist: zstandard>=0.25.0; extra == "spark"
36
39
  Provides-Extra: dask
37
- Requires-Dist: dask[dataframe,distributed]>=2024.4.0; extra == "dask"
40
+ Requires-Dist: dask[dataframe,distributed]>=2025.12.0; extra == "dask"
38
41
  Requires-Dist: pyarrow>=7.0.0; extra == "dask"
39
42
  Requires-Dist: pandas>=2.0.2; extra == "dask"
40
43
  Provides-Extra: ray
@@ -54,7 +57,7 @@ Provides-Extra: ibis
54
57
  Requires-Dist: fugue-sql-antlr>=0.2.4; extra == "ibis"
55
58
  Requires-Dist: sqlglot<28; extra == "ibis"
56
59
  Requires-Dist: jinja2; extra == "ibis"
57
- Requires-Dist: ibis-framework[pandas]; extra == "ibis"
60
+ Requires-Dist: ibis-framework; extra == "ibis"
58
61
  Provides-Extra: notebook
59
62
  Requires-Dist: notebook; extra == "notebook"
60
63
  Requires-Dist: jupyterlab; extra == "notebook"
@@ -63,8 +66,9 @@ Provides-Extra: all
63
66
  Requires-Dist: fugue-sql-antlr>=0.2.4; extra == "all"
64
67
  Requires-Dist: sqlglot<28; extra == "all"
65
68
  Requires-Dist: jinja2; extra == "all"
66
- Requires-Dist: pyspark>=3.1.1; extra == "all"
67
- Requires-Dist: dask[dataframe,distributed]>=2024.4.0; extra == "all"
69
+ Requires-Dist: pyspark>=3.5; python_version < "3.12" and extra == "all"
70
+ Requires-Dist: pyspark>=4.0; python_version >= "3.12" and extra == "all"
71
+ Requires-Dist: dask[dataframe,distributed]>=2025.12.0; extra == "all"
68
72
  Requires-Dist: dask-sql; extra == "all"
69
73
  Requires-Dist: ray[data]>=2.30.0; python_version < "3.14" and extra == "all"
70
74
  Requires-Dist: notebook; extra == "all"
@@ -73,7 +77,7 @@ Requires-Dist: ipython>=7.10.0; extra == "all"
73
77
  Requires-Dist: duckdb>=0.5.0; extra == "all"
74
78
  Requires-Dist: pyarrow>=6.0.1; extra == "all"
75
79
  Requires-Dist: pandas>=2.0.2; extra == "all"
76
- Requires-Dist: ibis-framework[duckdb,pandas]; extra == "all"
80
+ Requires-Dist: ibis-framework[duckdb]; extra == "all"
77
81
  Requires-Dist: polars; extra == "all"
78
82
  Dynamic: license-file
79
83
 
@@ -82,7 +86,7 @@ Dynamic: license-file
82
86
  [![PyPI version](https://badge.fury.io/py/fugue.svg)](https://pypi.python.org/pypi/fugue/)
83
87
  [![PyPI pyversions](https://img.shields.io/pypi/pyversions/fugue.svg)](https://pypi.python.org/pypi/fugue/)
84
88
  [![PyPI license](https://img.shields.io/pypi/l/fugue.svg)](https://pypi.python.org/pypi/fugue/)
85
- [![codecov](https://codecov.io/gh/fugue-project/fugue/branch/main/graph/badge.svg?token=ZO9YD5N3IA)](https://codecov.io/gh/fugue-project/fugue)
89
+ [![codecov](https://codecov.io/gh/fugue-project/fugue/graph/badge.svg?token=ZO9YD5N3IA)](https://codecov.io/gh/fugue-project/fugue)
86
90
  [![Codacy Badge](https://app.codacy.com/project/badge/Grade/4fa5f2f53e6f48aaa1218a89f4808b91)](https://www.codacy.com/gh/fugue-project/fugue/dashboard?utm_source=github.com&utm_medium=referral&utm_content=fugue-project/fugue&utm_campaign=Badge_Grade)
87
91
  [![Downloads](https://static.pepy.tech/badge/fugue)](https://pepy.tech/project/fugue)
88
92
 
@@ -1,13 +1,18 @@
1
- triad>=1.0.1
1
+ triad>=1.0.4
2
2
  adagio>=0.2.6
3
- pandas<3
3
+ packaging
4
+
5
+ [:python_version < "3.15"]
6
+ pandas
7
+
8
+ [:python_version >= "3.15"]
9
+ pandas>=3
4
10
 
5
11
  [all]
6
12
  fugue-sql-antlr>=0.2.4
7
13
  sqlglot<28
8
14
  jinja2
9
- pyspark>=3.1.1
10
- dask[dataframe,distributed]>=2024.4.0
15
+ dask[dataframe,distributed]>=2025.12.0
11
16
  dask-sql
12
17
  notebook
13
18
  jupyterlab
@@ -15,17 +20,23 @@ ipython>=7.10.0
15
20
  duckdb>=0.5.0
16
21
  pyarrow>=6.0.1
17
22
  pandas>=2.0.2
18
- ibis-framework[duckdb,pandas]
23
+ ibis-framework[duckdb]
19
24
  polars
20
25
 
26
+ [all:python_version < "3.12"]
27
+ pyspark>=3.5
28
+
21
29
  [all:python_version < "3.14"]
22
30
  ray[data]>=2.30.0
23
31
 
32
+ [all:python_version >= "3.12"]
33
+ pyspark>=4.0
34
+
24
35
  [cpp_sql_parser]
25
36
  fugue-sql-antlr[cpp]>=0.2.4
26
37
 
27
38
  [dask]
28
- dask[dataframe,distributed]>=2024.4.0
39
+ dask[dataframe,distributed]>=2025.12.0
29
40
  pyarrow>=7.0.0
30
41
  pandas>=2.0.2
31
42
 
@@ -40,7 +51,7 @@ numpy
40
51
  fugue-sql-antlr>=0.2.4
41
52
  sqlglot<28
42
53
  jinja2
43
- ibis-framework[pandas]
54
+ ibis-framework
44
55
 
45
56
  [notebook]
46
57
  notebook
@@ -59,9 +70,14 @@ pandas
59
70
  ray[data]>=2.30.0
60
71
 
61
72
  [spark]
62
- pyspark>=3.1.1
63
73
  zstandard>=0.25.0
64
74
 
75
+ [spark:python_version < "3.12"]
76
+ pyspark>=3.5
77
+
78
+ [spark:python_version >= "3.12"]
79
+ pyspark>=4.0
80
+
65
81
  [sql]
66
82
  duckdb>=0.5.0
67
83
  fugue-sql-antlr>=0.2.4
@@ -169,7 +169,7 @@ class DaskMapEngine(MapEngine):
169
169
  sort=False,
170
170
  group_keys=False,
171
171
  dropna=False,
172
- ).apply(_map, meta=output_dtypes)
172
+ )[list(df.native.columns)].apply(_map, meta=output_dtypes)
173
173
  elif partition_spec.algo == "coarse":
174
174
  result = pdf.native.map_partitions( # type: ignore
175
175
  _map, meta=output_dtypes
@@ -515,7 +515,7 @@ class DaskExecutionEngine(ExecutionEngine):
515
515
  )
516
516
 
517
517
  d = (
518
- d.groupby(partition_spec.partition_by, dropna=False)
518
+ d.groupby(partition_spec.partition_by, dropna=False)[list(d.columns)]
519
519
  .apply(_partition_take, n=n, presort=_presort, meta=meta)
520
520
  .reset_index(drop=True)
521
521
  )
@@ -4,7 +4,7 @@ import pandas as pd
4
4
  import pyarrow as pa
5
5
  from duckdb import DuckDBPyRelation
6
6
  from triad import Schema, assert_or_throw
7
- from triad.utils.pyarrow import LARGE_TYPES_REPLACEMENT, replace_types_in_table
7
+ from triad.utils.pyarrow import normalize_large_types_in_table
8
8
 
9
9
  from fugue import ArrowDataFrame, DataFrame, LocalBoundedDataFrame
10
10
  from fugue.dataframe.arrow_dataframe import _pa_table_as_pandas
@@ -166,8 +166,7 @@ def _duck_as_local(df: DuckDBPyRelation) -> DuckDBPyRelation:
166
166
  @as_arrow.candidate(lambda df: isinstance(df, DuckDBPyRelation))
167
167
  def _duck_as_arrow(df: DuckDBPyRelation) -> pa.Table:
168
168
  _df = df.fetch_arrow_table()
169
- _df = replace_types_in_table(_df, LARGE_TYPES_REPLACEMENT, recursive=True)
170
- return _df
169
+ return normalize_large_types_in_table(_df)
171
170
 
172
171
 
173
172
  @as_pandas.candidate(lambda df: isinstance(df, DuckDBPyRelation))
@@ -6,11 +6,7 @@ import pyarrow as pa
6
6
  from triad.collections.schema import Schema
7
7
  from triad.exceptions import InvalidOperationError
8
8
  from triad.utils.assertion import assert_or_throw
9
- from triad.utils.pyarrow import (
10
- LARGE_TYPES_REPLACEMENT,
11
- replace_types_in_schema,
12
- replace_types_in_table,
13
- )
9
+ from triad.utils.pyarrow import normalize_large_types, normalize_large_types_in_table
14
10
 
15
11
  from fugue import ArrowDataFrame
16
12
  from fugue.api import (
@@ -157,8 +153,7 @@ def _pl_as_local_bounded(df: pl.DataFrame) -> pl.DataFrame:
157
153
  @as_arrow.candidate(lambda df: isinstance(df, pl.DataFrame))
158
154
  def _pl_as_arrow(df: pl.DataFrame) -> pa.Table:
159
155
  adf = df.to_arrow()
160
- adf = replace_types_in_table(adf, LARGE_TYPES_REPLACEMENT)
161
- return adf
156
+ return normalize_large_types_in_table(adf)
162
157
 
163
158
 
164
159
  @is_df.candidate(lambda df: isinstance(df, pl.DataFrame))
@@ -199,8 +194,7 @@ def _get_pl_columns(df: pl.DataFrame) -> List[Any]:
199
194
  @get_schema.candidate(lambda df: isinstance(df, pl.DataFrame))
200
195
  def _get_pl_schema(df: pl.DataFrame) -> Schema:
201
196
  adf = df.to_arrow()
202
- schema = replace_types_in_schema(adf.schema, LARGE_TYPES_REPLACEMENT)
203
- return Schema(schema)
197
+ return Schema(normalize_large_types(adf.schema))
204
198
 
205
199
 
206
200
  @rename.candidate(lambda df, *args, **kwargs: isinstance(df, pl.DataFrame))
@@ -5,6 +5,7 @@ import pandas as pd
5
5
  import pyarrow as pa
6
6
  import ray.data as rd
7
7
  from triad import Schema
8
+ from triad.utils.pyarrow import normalize_large_types
8
9
 
9
10
  from .._constants import _ZERO_COPY
10
11
 
@@ -40,10 +41,10 @@ def get_dataset_format(df: rd.Dataset) -> Tuple[Optional[str], rd.Dataset]:
40
41
 
41
42
  def to_schema(schema: Any) -> Schema: # pragma: no cover
42
43
  if isinstance(schema, pa.Schema):
43
- return Schema(schema)
44
+ return Schema(normalize_large_types(schema))
44
45
  if isinstance(schema, rd.Schema):
45
46
  if hasattr(schema, "base_schema") and isinstance(schema.base_schema, pa.Schema):
46
- return Schema(schema.base_schema)
47
+ return Schema(normalize_large_types(schema.base_schema))
47
48
  return Schema(list(zip(schema.names, schema.types)))
48
49
  raise ValueError(f"{schema} is not supported")
49
50
 
@@ -1,17 +1,17 @@
1
1
  import os
2
2
  import pathlib
3
- from typing import Any, Callable, Dict, Iterable, List, Optional, Union
3
+ from collections.abc import Callable, Iterable
4
+ from typing import Any
4
5
 
5
6
  import pyarrow as pa
6
7
  import ray.data as rd
7
8
  from packaging import version
8
9
  from pyarrow import csv as pacsv
9
10
  from pyarrow import json as pajson
10
-
11
11
  from triad.collections import Schema
12
12
  from triad.collections.dict import ParamDict
13
13
  from triad.utils.assertion import assert_or_throw
14
- from triad.utils.io import exists, makedirs, rm, isfile
14
+ from triad.utils.io import exists, isfile, makedirs, rm
15
15
 
16
16
  from fugue import ExecutionEngine
17
17
  from fugue._utils.io import FileParser, save_df
@@ -25,9 +25,7 @@ try:
25
25
  from ray.data.datasource import FileExtensionFilter
26
26
 
27
27
  class _FileFiler(FileExtensionFilter): # pragma: no cover
28
- def __init__(
29
- self, file_extensions: Union[str, List[str]], exclude: Iterable[str]
30
- ):
28
+ def __init__(self, file_extensions: str | list[str], exclude: Iterable[str]):
31
29
  super().__init__(file_extensions, allow_if_no_extension=True)
32
30
  self._exclude = set(exclude)
33
31
 
@@ -36,23 +34,23 @@ try:
36
34
  path
37
35
  ).name not in self._exclude and self._file_has_extension(path)
38
36
 
39
- def __call__(self, paths: List[str]) -> List[str]:
37
+ def __call__(self, paths: list[str]) -> list[str]:
40
38
  return [path for path in paths if self._is_valid(path)]
41
39
 
42
40
  except ImportError: # pragma: no cover
43
41
  pass # ray >=2.10
44
42
 
45
43
 
46
- class RayIO(object):
44
+ class RayIO:
47
45
  def __init__(self, engine: ExecutionEngine):
48
46
  self._engine = engine
49
47
  self._logger = engine.log
50
- self._loads: Dict[str, Callable[..., DataFrame]] = {
48
+ self._loads: dict[str, Callable[..., DataFrame]] = {
51
49
  "csv": self._load_csv,
52
50
  "parquet": self._load_parquet,
53
51
  "json": self._load_json,
54
52
  }
55
- self._saves: Dict[str, Callable[..., None]] = {
53
+ self._saves: dict[str, Callable[..., None]] = {
56
54
  "csv": self._save_csv,
57
55
  "parquet": self._save_parquet,
58
56
  "json": self._save_json,
@@ -60,8 +58,8 @@ class RayIO(object):
60
58
 
61
59
  def load_df(
62
60
  self,
63
- uri: Union[str, List[str]],
64
- format_hint: Optional[str] = None,
61
+ uri: str | list[str],
62
+ format_hint: str | None = None,
65
63
  columns: Any = None,
66
64
  **kwargs: Any,
67
65
  ) -> DataFrame:
@@ -81,8 +79,8 @@ class RayIO(object):
81
79
  self,
82
80
  df: RayDataFrame,
83
81
  uri: str,
84
- format_hint: Optional[str] = None,
85
- partition_spec: Optional[PartitionSpec] = None,
82
+ format_hint: str | None = None,
83
+ partition_spec: PartitionSpec | None = None,
86
84
  mode: str = "overwrite",
87
85
  force_single: bool = False,
88
86
  **kwargs: Any,
@@ -122,7 +120,7 @@ class RayIO(object):
122
120
  if "header" in kw:
123
121
  kw["include_header"] = kw.pop("header")
124
122
 
125
- def _fn() -> Dict[str, Any]: # pragma: no cover
123
+ def _fn() -> dict[str, Any]: # pragma: no cover
126
124
  return dict(write_options=pacsv.WriteOptions(**kw))
127
125
 
128
126
  df.native.write_csv(
@@ -152,13 +150,25 @@ class RayIO(object):
152
150
  )
153
151
 
154
152
  def _load_parquet(
155
- self, p: List[str], columns: Any = None, **kwargs: Any
153
+ self, p: list[str], columns: Any = None, **kwargs: Any
156
154
  ) -> DataFrame:
157
155
  # in 2.52.0 the default changes to ["parquet"]
158
156
  if "file_extensions" not in kwargs:
159
157
  kwargs = kwargs.copy()
160
158
  kwargs["file_extensions"] = None
161
- sdf = rd.read_parquet(p, ray_remote_args=self._remote_args(), **kwargs)
159
+ # ray>=2.60 routes read_parquet to the V2 datasource by default, which
160
+ # (1) forces file_extensions=None to ["parquet"], so single files without
161
+ # extension can't be read, and (2) may raise ImportError from a threaded
162
+ # fsspec HTTPFileSystem import when listing multiple paths. Use V1.
163
+ ctx = rd.DataContext.get_current()
164
+ use_v2 = getattr(ctx, "use_datasource_v2", None)
165
+ if use_v2: # pragma: no cover
166
+ ctx.use_datasource_v2 = False
167
+ try:
168
+ sdf = rd.read_parquet(p, ray_remote_args=self._remote_args(), **kwargs)
169
+ finally:
170
+ if use_v2: # pragma: no cover
171
+ ctx.use_datasource_v2 = use_v2
162
172
  if columns is None:
163
173
  return RayDataFrame(sdf)
164
174
  if isinstance(columns, list): # column names
@@ -166,20 +176,18 @@ class RayIO(object):
166
176
  schema = Schema(columns)
167
177
  return RayDataFrame(sdf)[schema.names].alter_columns(schema)
168
178
 
169
- def _load_csv( # noqa: C901
170
- self, p: List[str], columns: Any = None, **kwargs: Any
171
- ) -> DataFrame:
179
+ def _load_csv(self, p: list[str], columns: Any = None, **kwargs: Any) -> DataFrame:
172
180
  kw = ParamDict(kwargs)
173
181
  infer_schema = kw.get("infer_schema", False)
174
- read_options: Dict[str, Any] = {"use_threads": False}
175
- parse_options: Dict[str, Any] = {}
176
- convert_options: Dict[str, Any] = {}
182
+ read_options: dict[str, Any] = {"use_threads": False}
183
+ parse_options: dict[str, Any] = {}
184
+ convert_options: dict[str, Any] = {}
177
185
  if infer_schema and columns is not None and not isinstance(columns, list):
178
186
  raise ValueError("can't set columns as a schema when infer schema is true")
179
187
 
180
188
  if RAY_VERSION >= version.parse("2.10"):
181
189
  if len(p) == 1 and isfile(p[0]): # TODO: very hacky
182
- params: Dict[str, Any] = {}
190
+ params: dict[str, Any] = {}
183
191
  else:
184
192
  params = {"file_extensions": ["csv"]}
185
193
  else: # pragma: no cover
@@ -230,14 +238,14 @@ class RayIO(object):
230
238
  else: # pragma: no cover
231
239
  raise NotImplementedError(f"{header} is not supported")
232
240
 
233
- def _load_json(self, p: List[str], columns: Any = None, **kwargs: Any) -> DataFrame:
234
- read_options: Dict[str, Any] = {"use_threads": False}
235
- parse_options: Dict[str, Any] = {}
241
+ def _load_json(self, p: list[str], columns: Any = None, **kwargs: Any) -> DataFrame:
242
+ read_options: dict[str, Any] = {"use_threads": False}
243
+ parse_options: dict[str, Any] = {}
236
244
 
237
245
  def _read_json() -> RayDataFrame: # pragma: no cover
238
246
  if RAY_VERSION >= version.parse("2.10"):
239
247
  if len(p) == 1 and isfile(p[0]): # TODO: very hacky
240
- params: Dict[str, Any] = {"file_extensions": None}
248
+ params: dict[str, Any] = {"file_extensions": None}
241
249
  else:
242
250
  params = {"file_extensions": ["json"]}
243
251
  elif RAY_VERSION >= version.parse("2.9"): # pragma: no cover
@@ -272,5 +280,5 @@ class RayIO(object):
272
280
  schema = Schema(columns)
273
281
  return _read_json()[schema.names].alter_columns(schema)
274
282
 
275
- def _remote_args(self) -> Dict[str, Any]:
283
+ def _remote_args(self) -> dict[str, Any]:
276
284
  return {"num_cpus": 1}
@@ -6,11 +6,14 @@ import ray
6
6
  import ray.data as rd
7
7
  from triad import assert_or_throw
8
8
  from triad.collections.schema import Schema
9
- from triad.utils.pyarrow import cast_pa_table
9
+ from triad.utils.pyarrow import cast_pa_table, normalize_large_types_in_table
10
10
 
11
11
  from fugue.dataframe import ArrowDataFrame, DataFrame, LocalBoundedDataFrame
12
12
  from fugue.dataframe.dataframe import _input_schema
13
- from fugue.dataframe.utils import pa_table_as_array, pa_table_as_dicts
13
+ from fugue.dataframe.utils import (
14
+ pa_table_as_array,
15
+ pa_table_as_dicts,
16
+ )
14
17
  from fugue.exceptions import FugueDataFrameOperationError, FugueDatasetEmptyError
15
18
  from fugue.plugins import (
16
19
  as_array,
@@ -140,7 +143,8 @@ class RayDataFrame(DataFrame):
140
143
 
141
144
  @property
142
145
  def num_partitions(self) -> int:
143
- return _rd_num_partitions(self.native)
146
+ self._native = materialize(self._native)
147
+ return self._native.num_blocks()
144
148
 
145
149
  def _drop_cols(self, cols: List[str]) -> DataFrame:
146
150
  cols = (self.schema - cols).names
@@ -263,7 +267,7 @@ def _rd_is_df(df: rd.Dataset) -> bool:
263
267
 
264
268
  @get_num_partitions.candidate(lambda df: isinstance(df, rd.Dataset))
265
269
  def _rd_num_partitions(df: rd.Dataset) -> int:
266
- return df.num_blocks()
270
+ return materialize(df).num_blocks()
267
271
 
268
272
 
269
273
  @as_local_bounded.candidate(lambda df: isinstance(df, rd.Dataset))
@@ -305,7 +309,7 @@ def _rd_as_pandas(df: rd.Dataset) -> pd.DataFrame:
305
309
 
306
310
  @as_arrow.candidate(lambda df: isinstance(df, rd.Dataset))
307
311
  def _rd_as_arrow(df: rd.Dataset) -> pa.Table:
308
- return pa.concat_tables(_get_arrow_tables(df))
312
+ return normalize_large_types_in_table(pa.concat_tables(_get_arrow_tables(df)))
309
313
 
310
314
 
311
315
  @as_array.candidate(lambda df, *args, **kwargs: isinstance(df, rd.Dataset))