sqlframe 1.7.0__tar.gz → 1.7.1__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 (208) hide show
  1. {sqlframe-1.7.0 → sqlframe-1.7.1}/PKG-INFO +1 -1
  2. sqlframe-1.7.1/blogs/add_chatgpt_support.md +101 -0
  3. sqlframe-1.7.1/blogs/images/add_chatgpt_support/adding_ai_to_meal.jpeg +0 -0
  4. sqlframe-1.7.1/blogs/images/add_chatgpt_support/hype_train.gif +0 -0
  5. sqlframe-1.7.1/blogs/images/add_chatgpt_support/marvin_paranoid_robot.gif +0 -0
  6. sqlframe-1.7.1/blogs/images/add_chatgpt_support/nonsense_sql.png +0 -0
  7. sqlframe-1.7.1/blogs/images/add_chatgpt_support/openai_full_rewrite.png +0 -0
  8. sqlframe-1.7.1/blogs/images/add_chatgpt_support/openai_replacing_cte_names.png +0 -0
  9. sqlframe-1.7.1/blogs/images/add_chatgpt_support/sqlglot_optimized_code.png +0 -0
  10. sqlframe-1.7.1/blogs/images/add_chatgpt_support/sunny_shake_head_no.gif +0 -0
  11. {sqlframe-1.7.0 → sqlframe-1.7.1}/docs/spark.md +3 -0
  12. {sqlframe-1.7.0 → sqlframe-1.7.1}/setup.py +1 -1
  13. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/_version.py +2 -2
  14. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/base/functions.py +19 -4
  15. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/base/session.py +1 -0
  16. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/spark/functions.py +1 -3
  17. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/spark/functions.pyi +3 -0
  18. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe.egg-info/PKG-INFO +1 -1
  19. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe.egg-info/SOURCES.txt +9 -0
  20. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe.egg-info/requires.txt +1 -1
  21. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/integration/engines/test_int_functions.py +17 -7
  22. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/unit/standalone/test_functions.py +13 -7
  23. {sqlframe-1.7.0 → sqlframe-1.7.1}/.github/CODEOWNERS +0 -0
  24. {sqlframe-1.7.0 → sqlframe-1.7.1}/.github/workflows/main.workflow.yaml +0 -0
  25. {sqlframe-1.7.0 → sqlframe-1.7.1}/.github/workflows/publish.workflow.yaml +0 -0
  26. {sqlframe-1.7.0 → sqlframe-1.7.1}/.gitignore +0 -0
  27. {sqlframe-1.7.0 → sqlframe-1.7.1}/.pre-commit-config.yaml +0 -0
  28. {sqlframe-1.7.0 → sqlframe-1.7.1}/.readthedocs.yaml +0 -0
  29. {sqlframe-1.7.0 → sqlframe-1.7.1}/LICENSE +0 -0
  30. {sqlframe-1.7.0 → sqlframe-1.7.1}/Makefile +0 -0
  31. {sqlframe-1.7.0 → sqlframe-1.7.1}/README.md +0 -0
  32. {sqlframe-1.7.0 → sqlframe-1.7.1}/blogs/images/but_wait_theres_more.gif +0 -0
  33. {sqlframe-1.7.0 → sqlframe-1.7.1}/blogs/images/cake.gif +0 -0
  34. {sqlframe-1.7.0 → sqlframe-1.7.1}/blogs/images/you_get_pyspark_api.gif +0 -0
  35. {sqlframe-1.7.0 → sqlframe-1.7.1}/blogs/sqlframe_universal_dataframe_api.md +0 -0
  36. {sqlframe-1.7.0 → sqlframe-1.7.1}/docs/bigquery.md +0 -0
  37. {sqlframe-1.7.0 → sqlframe-1.7.1}/docs/configuration.md +0 -0
  38. {sqlframe-1.7.0 → sqlframe-1.7.1}/docs/docs/bigquery.md +0 -0
  39. {sqlframe-1.7.0 → sqlframe-1.7.1}/docs/docs/duckdb.md +0 -0
  40. {sqlframe-1.7.0 → sqlframe-1.7.1}/docs/docs/images/SF.png +0 -0
  41. {sqlframe-1.7.0 → sqlframe-1.7.1}/docs/docs/images/favicon.png +0 -0
  42. {sqlframe-1.7.0 → sqlframe-1.7.1}/docs/docs/images/favicon_old.png +0 -0
  43. {sqlframe-1.7.0 → sqlframe-1.7.1}/docs/docs/images/sqlframe_diagram.png +0 -0
  44. {sqlframe-1.7.0 → sqlframe-1.7.1}/docs/docs/images/sqlframe_logo.png +0 -0
  45. {sqlframe-1.7.0 → sqlframe-1.7.1}/docs/docs/postgres.md +0 -0
  46. {sqlframe-1.7.0 → sqlframe-1.7.1}/docs/duckdb.md +0 -0
  47. {sqlframe-1.7.0 → sqlframe-1.7.1}/docs/images/SF.png +0 -0
  48. {sqlframe-1.7.0 → sqlframe-1.7.1}/docs/images/favicon.png +0 -0
  49. {sqlframe-1.7.0 → sqlframe-1.7.1}/docs/images/favicon_old.png +0 -0
  50. {sqlframe-1.7.0 → sqlframe-1.7.1}/docs/images/sqlframe_diagram.png +0 -0
  51. {sqlframe-1.7.0 → sqlframe-1.7.1}/docs/images/sqlframe_logo.png +0 -0
  52. {sqlframe-1.7.0 → sqlframe-1.7.1}/docs/index.md +0 -0
  53. {sqlframe-1.7.0 → sqlframe-1.7.1}/docs/postgres.md +0 -0
  54. {sqlframe-1.7.0 → sqlframe-1.7.1}/docs/requirements.txt +0 -0
  55. {sqlframe-1.7.0 → sqlframe-1.7.1}/docs/snowflake.md +0 -0
  56. {sqlframe-1.7.0 → sqlframe-1.7.1}/docs/standalone.md +0 -0
  57. {sqlframe-1.7.0 → sqlframe-1.7.1}/docs/stylesheets/extra.css +0 -0
  58. {sqlframe-1.7.0 → sqlframe-1.7.1}/mkdocs.yml +0 -0
  59. {sqlframe-1.7.0 → sqlframe-1.7.1}/pytest.ini +0 -0
  60. {sqlframe-1.7.0 → sqlframe-1.7.1}/renovate.json +0 -0
  61. {sqlframe-1.7.0 → sqlframe-1.7.1}/setup.cfg +0 -0
  62. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/LICENSE +0 -0
  63. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/__init__.py +0 -0
  64. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/base/__init__.py +0 -0
  65. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/base/_typing.py +0 -0
  66. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/base/catalog.py +0 -0
  67. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/base/column.py +0 -0
  68. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/base/dataframe.py +0 -0
  69. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/base/decorators.py +0 -0
  70. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/base/exceptions.py +0 -0
  71. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/base/function_alternatives.py +0 -0
  72. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/base/group.py +0 -0
  73. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/base/mixins/__init__.py +0 -0
  74. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/base/mixins/catalog_mixins.py +0 -0
  75. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/base/mixins/dataframe_mixins.py +0 -0
  76. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/base/mixins/readwriter_mixins.py +0 -0
  77. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/base/normalize.py +0 -0
  78. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/base/operations.py +0 -0
  79. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/base/readerwriter.py +0 -0
  80. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/base/transforms.py +0 -0
  81. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/base/types.py +0 -0
  82. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/base/util.py +0 -0
  83. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/base/window.py +0 -0
  84. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/bigquery/__init__.py +0 -0
  85. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/bigquery/catalog.py +0 -0
  86. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/bigquery/column.py +0 -0
  87. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/bigquery/dataframe.py +0 -0
  88. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/bigquery/functions.py +0 -0
  89. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/bigquery/functions.pyi +0 -0
  90. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/bigquery/group.py +0 -0
  91. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/bigquery/readwriter.py +0 -0
  92. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/bigquery/session.py +0 -0
  93. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/bigquery/types.py +0 -0
  94. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/bigquery/window.py +0 -0
  95. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/duckdb/__init__.py +0 -0
  96. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/duckdb/catalog.py +0 -0
  97. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/duckdb/column.py +0 -0
  98. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/duckdb/dataframe.py +0 -0
  99. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/duckdb/functions.py +0 -0
  100. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/duckdb/functions.pyi +0 -0
  101. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/duckdb/group.py +0 -0
  102. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/duckdb/readwriter.py +0 -0
  103. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/duckdb/session.py +0 -0
  104. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/duckdb/types.py +0 -0
  105. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/duckdb/window.py +0 -0
  106. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/postgres/__init__.py +0 -0
  107. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/postgres/catalog.py +0 -0
  108. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/postgres/column.py +0 -0
  109. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/postgres/dataframe.py +0 -0
  110. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/postgres/functions.py +0 -0
  111. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/postgres/functions.pyi +0 -0
  112. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/postgres/group.py +0 -0
  113. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/postgres/readwriter.py +0 -0
  114. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/postgres/session.py +0 -0
  115. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/postgres/types.py +0 -0
  116. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/postgres/window.py +0 -0
  117. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/redshift/__init__.py +0 -0
  118. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/redshift/catalog.py +0 -0
  119. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/redshift/column.py +0 -0
  120. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/redshift/dataframe.py +0 -0
  121. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/redshift/functions.py +0 -0
  122. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/redshift/group.py +0 -0
  123. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/redshift/readwriter.py +0 -0
  124. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/redshift/session.py +0 -0
  125. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/redshift/types.py +0 -0
  126. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/redshift/window.py +0 -0
  127. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/snowflake/__init__.py +0 -0
  128. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/snowflake/catalog.py +0 -0
  129. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/snowflake/column.py +0 -0
  130. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/snowflake/dataframe.py +0 -0
  131. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/snowflake/functions.py +0 -0
  132. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/snowflake/functions.pyi +0 -0
  133. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/snowflake/group.py +0 -0
  134. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/snowflake/readwriter.py +0 -0
  135. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/snowflake/session.py +0 -0
  136. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/snowflake/types.py +0 -0
  137. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/snowflake/window.py +0 -0
  138. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/spark/__init__.py +0 -0
  139. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/spark/catalog.py +0 -0
  140. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/spark/column.py +0 -0
  141. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/spark/dataframe.py +0 -0
  142. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/spark/group.py +0 -0
  143. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/spark/readwriter.py +0 -0
  144. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/spark/session.py +0 -0
  145. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/spark/types.py +0 -0
  146. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/spark/window.py +0 -0
  147. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/standalone/__init__.py +0 -0
  148. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/standalone/catalog.py +0 -0
  149. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/standalone/column.py +0 -0
  150. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/standalone/dataframe.py +0 -0
  151. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/standalone/functions.py +0 -0
  152. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/standalone/group.py +0 -0
  153. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/standalone/readwriter.py +0 -0
  154. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/standalone/session.py +0 -0
  155. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/standalone/types.py +0 -0
  156. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe/standalone/window.py +0 -0
  157. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe.egg-info/dependency_links.txt +0 -0
  158. {sqlframe-1.7.0 → sqlframe-1.7.1}/sqlframe.egg-info/top_level.txt +0 -0
  159. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/__init__.py +0 -0
  160. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/common_fixtures.py +0 -0
  161. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/conftest.py +0 -0
  162. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/fixtures/employee.csv +0 -0
  163. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/fixtures/employee.json +0 -0
  164. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/fixtures/employee.parquet +0 -0
  165. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/fixtures/employee_extra_line.csv +0 -0
  166. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/integration/__init__.py +0 -0
  167. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/integration/engines/__init__.py +0 -0
  168. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/integration/engines/bigquery/__init__.py +0 -0
  169. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/integration/engines/bigquery/test_bigquery_catalog.py +0 -0
  170. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/integration/engines/bigquery/test_bigquery_session.py +0 -0
  171. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/integration/engines/duck/__init__.py +0 -0
  172. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/integration/engines/duck/test_duckdb_catalog.py +0 -0
  173. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/integration/engines/duck/test_duckdb_dataframe.py +0 -0
  174. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/integration/engines/duck/test_duckdb_reader.py +0 -0
  175. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/integration/engines/duck/test_duckdb_session.py +0 -0
  176. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/integration/engines/postgres/__init__.py +0 -0
  177. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/integration/engines/postgres/test_postgres_catalog.py +0 -0
  178. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/integration/engines/postgres/test_postgres_dataframe.py +0 -0
  179. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/integration/engines/postgres/test_postgres_session.py +0 -0
  180. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/integration/engines/redshift/__init__.py +0 -0
  181. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/integration/engines/redshift/test_redshift_catalog.py +0 -0
  182. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/integration/engines/redshift/test_redshift_session.py +0 -0
  183. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/integration/engines/snowflake/__init__.py +0 -0
  184. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/integration/engines/snowflake/test_snowflake_catalog.py +0 -0
  185. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/integration/engines/snowflake/test_snowflake_session.py +0 -0
  186. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/integration/engines/spark/__init__.py +0 -0
  187. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/integration/engines/spark/test_spark_catalog.py +0 -0
  188. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/integration/engines/test_engine_dataframe.py +0 -0
  189. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/integration/engines/test_engine_reader.py +0 -0
  190. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/integration/engines/test_engine_session.py +0 -0
  191. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/integration/engines/test_engine_writer.py +0 -0
  192. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/integration/fixtures.py +0 -0
  193. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/integration/test_int_dataframe.py +0 -0
  194. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/integration/test_int_dataframe_stats.py +0 -0
  195. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/integration/test_int_grouped_data.py +0 -0
  196. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/integration/test_int_session.py +0 -0
  197. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/types.py +0 -0
  198. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/unit/__init__.py +0 -0
  199. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/unit/standalone/__init__.py +0 -0
  200. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/unit/standalone/fixtures.py +0 -0
  201. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/unit/standalone/test_column.py +0 -0
  202. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/unit/standalone/test_dataframe.py +0 -0
  203. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/unit/standalone/test_dataframe_writer.py +0 -0
  204. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/unit/standalone/test_session.py +0 -0
  205. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/unit/standalone/test_session_case_sensitivity.py +0 -0
  206. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/unit/standalone/test_types.py +0 -0
  207. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/unit/standalone/test_window.py +0 -0
  208. {sqlframe-1.7.0 → sqlframe-1.7.1}/tests/unit/test_util.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sqlframe
3
- Version: 1.7.0
3
+ Version: 1.7.1
4
4
  Summary: Turning PySpark Into a Universal DataFrame API
5
5
  Home-page: https://github.com/eakmanrq/sqlframe
6
6
  Author: Ryan Eakman
@@ -0,0 +1,101 @@
1
+ # Adding ChatGPT to SQLFrame - What is the Right Amount of AI?
2
+
3
+ <div align="center">
4
+ <img src="images/add_chatgpt_support/adding_ai_to_meal.jpeg" alt="Adding AI to Meal" width="800"/>
5
+ </div>
6
+
7
+ Like many people today, I often grapple with how much AI to integrate into my daily tasks.
8
+ In my experience, AI can be a valuable tool for brainstorming when writing, but over-reliance on it can lead to generic text devoid of personality.
9
+ While I might be overly verbose and fond of metaphors, these quirks add character and make communication more engaging.
10
+ Take "Marvin the Paranoid Robot" from "Hitchhiker's Guide to the Galaxy," for instance.
11
+ His melancholic outlook makes him relatable to the audience, even though his intelligence is 50,000 times greater than ours.
12
+
13
+ <div align="center">
14
+ <img src="images/add_chatgpt_support/marvin_paranoid_robot.gif" alt="Sad Robot" width="800"/>
15
+ </div>
16
+
17
+ When it comes to coding, I strive to eliminate imperfections as much as possible.
18
+ However, AI's tendency to hallucinate makes even a "trust but verify" approach challenging.
19
+ More often than not, especially when working with new libraries or languages, I find myself in a "that just can't be right, so let's move on" mindset.
20
+
21
+ <div align="center">
22
+ <img src="images/add_chatgpt_support/sunny_shake_head_no.gif" alt="Shake Head No" width="800"/>
23
+ </div>
24
+
25
+ When I first considered integrating AI into SQLFrame, it immediately struck me as a bad idea.
26
+ Correctness and consistency are crucial attributes of the product.
27
+ It's one thing to say this, but I've backed it up by writing around 1,800 tests to cover PySpark functionality and ensure reliability.
28
+ Until AI improves significantly in this area, SQLFrame will continue to rely on and enhance its understanding of PySpark, ensuring it's available where people need it most.
29
+
30
+ I've received feedback that the SQL generated by SQLFrame can be hard to read, which is much appreciated feedback.
31
+ I realized that while my primary goal is to produce reliable SQL that runs consistently on my engine, readability is also crucial when sharing code with others.
32
+ Minor imperfections in the SQL are acceptable as long as they don't impede understanding. Large Language Models (LLMs) excel at understanding human communication and have been trained to interpret user intent.
33
+ Could SQLFrame leverage this capability?
34
+ Is it time for SQLFrame to join the AI hype train?
35
+
36
+ <div align="center">
37
+ <img src="images/add_chatgpt_support/hype_train.gif" alt="All aboard the train" width="800"/>
38
+ </div>
39
+
40
+ Starting with [1.4.0](https://github.com/eakmanrq/sqlframe), you can now have SQLFrame enrich generated SQL using OpenAI.
41
+ Provide your API key and include `df.sql(openai_config={})` (to use defaults, [config options here](https://sqlframe.readthedocs.io/en/stable/configuration/#optimized)) when generating SQL to see what it looks like.
42
+ Let's take a look at the example from the README.
43
+
44
+ ```python
45
+ from sqlframe.bigquery import BigQuerySession
46
+ from sqlframe.bigquery import functions as F
47
+ from sqlframe.bigquery import Window
48
+
49
+ session = BigQuerySession()
50
+ table_path = "bigquery-public-data.samples.natality"
51
+ # Top 5 years with the greatest year-over-year % change in new families with single child
52
+ df = (
53
+ session.table(table_path)
54
+ .where(F.col("ever_born") == 1)
55
+ .groupBy("year")
56
+ .agg(F.count("*").alias("num_single_child_families"))
57
+ .withColumn(
58
+ "last_year_num_single_child_families",
59
+ F.lag(F.col("num_single_child_families"), 1).over(Window.orderBy("year"))
60
+ )
61
+ .withColumn(
62
+ "percent_change",
63
+ (F.col("num_single_child_families") - F.col("last_year_num_single_child_families"))
64
+ / F.col("last_year_num_single_child_families")
65
+ )
66
+ .orderBy(F.abs(F.col("percent_change")).desc())
67
+ .select(
68
+ F.col("year").alias("year"),
69
+ F.format_number("num_single_child_families", 0).alias("new families single child"),
70
+ F.format_number(F.col("percent_change") * 100, 2).alias("percent change"),
71
+ )
72
+ .limit(5)
73
+ )
74
+ ```
75
+
76
+ Next we will compare SQLGlot optimized, OpenAI replacing SQLGlot optimized CTE names, and then OpenAI doing a full rewrite.
77
+
78
+ <div align="center">
79
+ <img src="images/add_chatgpt_support/sqlglot_optimized_code.png" alt="SQLGlot optimized code" width="800"/>
80
+ </div>
81
+
82
+ <div align="center">
83
+ <img src="images/add_chatgpt_support/openai_replacing_cte_names.png" alt="OpenAI Replacing CTE Names" width="800"/>
84
+ </div>
85
+
86
+ <div align="center">
87
+ <img src="images/add_chatgpt_support/openai_full_rewrite.png" alt="OpenAI Full Rewrite" width="800"/>
88
+ </div>
89
+
90
+ Overall, the results are promising and make me optimistic that SQLFrame can generate human-like SQL.
91
+ I believe the ideal approach would be to combine tuned SQLGlot optimization rules with OpenAI for tasks such as naming CTEs.
92
+ In the long term, it wouldn't surprise me if models are able to consistently convert accurate SQL into very human-friendly formats without needing any optimization assistance. 💪
93
+ If you are new to SQLFrame, checkout the [repo](https://github.com/eakmanrq/sqlframe) or [announcement blog post](https://towardsdev.com/sqlframe-turning-pyspark-into-a-universal-dataframe-api-e06a1c678f35). 🚀
94
+ If you want to see how I added this integration, checkout [part 1](https://www.loom.com/share/3fab8493818b46f7bff03faf101d2bb6?sid=ffc6a134-f465-478a-a453-7c69b296dc77) or [part 2](https://www.loom.com/share/4055e86dafdd406283d7ba0e0656f0c9?sid=ff0e2af4-1f5a-4760-bf10-9feb89ef9451) where I added this feature ([part 2](https://www.loom.com/share/4055e86dafdd406283d7ba0e0656f0c9?sid=ff0e2af4-1f5a-4760-bf10-9feb89ef9451) is shorter and I think better). 🍿
95
+ Final treat, I overrode the normal prompt with "turn the SQL into complete nonsense". The results:
96
+
97
+ <div align="center">
98
+ <img src="images/add_chatgpt_support/nonsense_sql.png" alt="OpenAI Full Rewrite" width="800"/>
99
+ </div>
100
+
101
+ Nailed it.
@@ -356,6 +356,8 @@ df.show(5)
356
356
  * [row_number](https://spark.apache.org/docs/latest/api/python/reference/pyspark.sql/api/pyspark.sql.functions.row_number.html)
357
357
  * [rpad](https://spark.apache.org/docs/latest/api/python/reference/pyspark.sql/api/pyspark.sql.functions.rpad.html)
358
358
  * [rtrim](https://spark.apache.org/docs/latest/api/python/reference/pyspark.sql/api/pyspark.sql.functions.rtrim.html)
359
+ * [schema_of_csv](https://spark.apache.org/docs/latest/api/python/reference/pyspark.sql/api/pyspark.sql.functions.schema_of_csv.html)
360
+ * [schema_of_json](https://spark.apache.org/docs/latest/api/python/reference/pyspark.sql/api/pyspark.sql.functions.schema_of_json.html)
359
361
  * [sec](https://spark.apache.org/docs/latest/api/python/reference/pyspark.sql/api/pyspark.sql.functions.sec.html)
360
362
  * [second](https://spark.apache.org/docs/latest/api/python/reference/pyspark.sql/api/pyspark.sql.functions.second.html)
361
363
  * [sentences](https://spark.apache.org/docs/latest/api/python/reference/pyspark.sql/api/pyspark.sql.functions.sentences.html)
@@ -375,6 +377,7 @@ df.show(5)
375
377
  * [size](https://spark.apache.org/docs/latest/api/python/reference/pyspark.sql/api/pyspark.sql.functions.size.html)
376
378
  * [skewness](https://spark.apache.org/docs/latest/api/python/reference/pyspark.sql/api/pyspark.sql.functions.skewness.html)
377
379
  * [slice](https://spark.apache.org/docs/latest/api/python/reference/pyspark.sql/api/pyspark.sql.functions.slice.html)
380
+ * [stack](https://spark.apache.org/docs/latest/api/python/reference/pyspark.sql/api/pyspark.sql.functions.stack.html)
378
381
  * [sort_array](https://spark.apache.org/docs/latest/api/python/reference/pyspark.sql/api/pyspark.sql.functions.sort_array.html)
379
382
  * [soundex](https://spark.apache.org/docs/latest/api/python/reference/pyspark.sql/api/pyspark.sql.functions.soundex.html)
380
383
  * [split](https://spark.apache.org/docs/latest/api/python/reference/pyspark.sql/api/pyspark.sql.functions.split.html)
@@ -21,6 +21,7 @@ setup(
21
21
  install_requires=[
22
22
  "prettytable<3.11.0",
23
23
  "sqlglot>=24.0.0,<25.1",
24
+ "typing_extensions>=4.8,<5",
24
25
  ],
25
26
  extras_require={
26
27
  "bigquery": [
@@ -42,7 +43,6 @@ setup(
42
43
  "pre-commit>=3.5;python_version=='3.8'",
43
44
  "pre-commit>=3.7,<3.8;python_version>='3.9'",
44
45
  "ruff>=0.4.4,<0.5",
45
- "typing_extensions>=4.11,<5",
46
46
  "types-psycopg2>=2.9,<3",
47
47
  ],
48
48
  "docs": [
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '1.7.0'
16
- __version_tuple__ = version_tuple = (1, 7, 0)
15
+ __version__ = version = '1.7.1'
16
+ __version_tuple__ = version_tuple = (1, 7, 1)
@@ -151,9 +151,10 @@ def sumDistinct(col: ColumnOrName) -> Column:
151
151
  sum_distinct = sumDistinct
152
152
 
153
153
 
154
- @meta(unsupported_engines="*")
155
- def product(col: ColumnOrName) -> Column:
156
- raise NotImplementedError("Product is not currently implemented")
154
+ # Product does not have a SQL function available
155
+ # @meta(unsupported_engines="*")
156
+ # def product(col: ColumnOrName) -> Column:
157
+ # raise NotImplementedError("Product is not currently implemented")
157
158
 
158
159
 
159
160
  @meta()
@@ -1430,6 +1431,8 @@ def to_json(col: ColumnOrName, options: t.Optional[t.Dict[str, str]] = None) ->
1430
1431
 
1431
1432
  @meta(unsupported_engines="*")
1432
1433
  def schema_of_json(col: ColumnOrName, options: t.Optional[t.Dict[str, str]] = None) -> Column:
1434
+ if isinstance(col, str):
1435
+ col = lit(col)
1433
1436
  if options is not None:
1434
1437
  options_col = create_map([lit(x) for x in _flatten(options.items())])
1435
1438
  return Column.invoke_anonymous_function(col, "SCHEMA_OF_JSON", options_col)
@@ -1438,6 +1441,8 @@ def schema_of_json(col: ColumnOrName, options: t.Optional[t.Dict[str, str]] = No
1438
1441
 
1439
1442
  @meta(unsupported_engines="*")
1440
1443
  def schema_of_csv(col: ColumnOrName, options: t.Optional[t.Dict[str, str]] = None) -> Column:
1444
+ if isinstance(col, str):
1445
+ col = lit(col)
1441
1446
  if options is not None:
1442
1447
  options_col = create_map([lit(x) for x in _flatten(options.items())])
1443
1448
  return Column.invoke_anonymous_function(col, "SCHEMA_OF_CSV", options_col)
@@ -1560,7 +1565,9 @@ def from_csv(
1560
1565
  ) -> Column:
1561
1566
  schema = schema if isinstance(schema, Column) else lit(schema)
1562
1567
  if options is not None:
1563
- option_cols = create_map([lit(x) for x in _flatten(options.items())])
1568
+ option_cols = create_map(
1569
+ [lit(str(x) if isinstance(x, bool) else x) for x in _flatten(options.items())]
1570
+ )
1564
1571
  return Column.invoke_anonymous_function(col, "FROM_CSV", schema, option_cols)
1565
1572
  return Column.invoke_anonymous_function(col, "FROM_CSV", schema)
1566
1573
 
@@ -1667,6 +1674,14 @@ def nullif(col1: ColumnOrName, col2: ColumnOrName) -> Column:
1667
1674
  return Column.invoke_expression_over_column(col1, expression.Nullif, expression=col2)
1668
1675
 
1669
1676
 
1677
+ @meta(unsupported_engines="*")
1678
+ def stack(*cols: ColumnOrName) -> Column:
1679
+ columns = [Column.ensure_col(x) for x in cols]
1680
+ return Column.invoke_anonymous_function(
1681
+ columns[0], "STACK", *columns[1:] if len(columns) > 1 else []
1682
+ )
1683
+
1684
+
1670
1685
  @meta()
1671
1686
  def _lambda_quoted(value: str) -> t.Optional[bool]:
1672
1687
  return False if value == "_" else None
@@ -569,6 +569,7 @@ class _BaseSession(t.Generic[CATALOG, READER, WRITER, DF, CONN]):
569
569
  self,
570
570
  key: t.Optional[str] = None,
571
571
  value: t.Optional[t.Any] = None,
572
+ conf: t.Optional[t.Any] = None,
572
573
  *,
573
574
  map: t.Optional[t.Dict[str, t.Any]] = None,
574
575
  ) -> Self:
@@ -8,9 +8,7 @@ globals().update(
8
8
  {
9
9
  name: func
10
10
  for name, func in inspect.getmembers(module, inspect.isfunction)
11
- if hasattr(func, "unsupported_engines")
12
- and "spark" not in func.unsupported_engines
13
- and "*" not in func.unsupported_engines
11
+ if hasattr(func, "unsupported_engines") and "spark" not in func.unsupported_engines
14
12
  }
15
13
  )
16
14
 
@@ -177,6 +177,8 @@ from sqlframe.base.functions import (
177
177
  row_number as row_number,
178
178
  rpad as rpad,
179
179
  rtrim as rtrim,
180
+ schema_of_csv as schema_of_csv,
181
+ schema_of_json as schema_of_json,
180
182
  sec as sec,
181
183
  second as second,
182
184
  sentences as sentences,
@@ -200,6 +202,7 @@ from sqlframe.base.functions import (
200
202
  soundex as soundex,
201
203
  split as split,
202
204
  sqrt as sqrt,
205
+ stack as stack,
203
206
  stddev as stddev,
204
207
  stddev_pop as stddev_pop,
205
208
  stddev_samp as stddev_samp,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sqlframe
3
- Version: 1.7.0
3
+ Version: 1.7.1
4
4
  Summary: Turning PySpark Into a Universal DataFrame API
5
5
  Home-page: https://github.com/eakmanrq/sqlframe
6
6
  Author: Ryan Eakman
@@ -12,10 +12,19 @@ setup.py
12
12
  .github/CODEOWNERS
13
13
  .github/workflows/main.workflow.yaml
14
14
  .github/workflows/publish.workflow.yaml
15
+ blogs/add_chatgpt_support.md
15
16
  blogs/sqlframe_universal_dataframe_api.md
16
17
  blogs/images/but_wait_theres_more.gif
17
18
  blogs/images/cake.gif
18
19
  blogs/images/you_get_pyspark_api.gif
20
+ blogs/images/add_chatgpt_support/adding_ai_to_meal.jpeg
21
+ blogs/images/add_chatgpt_support/hype_train.gif
22
+ blogs/images/add_chatgpt_support/marvin_paranoid_robot.gif
23
+ blogs/images/add_chatgpt_support/nonsense_sql.png
24
+ blogs/images/add_chatgpt_support/openai_full_rewrite.png
25
+ blogs/images/add_chatgpt_support/openai_replacing_cte_names.png
26
+ blogs/images/add_chatgpt_support/sqlglot_optimized_code.png
27
+ blogs/images/add_chatgpt_support/sunny_shake_head_no.gif
19
28
  docs/bigquery.md
20
29
  docs/configuration.md
21
30
  docs/duckdb.md
@@ -1,5 +1,6 @@
1
1
  prettytable<3.11.0
2
2
  sqlglot<25.1,>=24.0.0
3
+ typing_extensions<5,>=4.8
3
4
 
4
5
  [bigquery]
5
6
  google-cloud-bigquery-storage<3,>=2
@@ -19,7 +20,6 @@ pytest-xdist<3.7,>=3.6
19
20
  pytest<8.3,>=8.2.0
20
21
  ruff<0.5,>=0.4.4
21
22
  types-psycopg2<3,>=2.9
22
- typing_extensions<5,>=4.11
23
23
 
24
24
  [dev:python_version == "3.8"]
25
25
  pre-commit>=3.5
@@ -2428,17 +2428,17 @@ def test_to_json(get_session_and_func, get_types, get_func):
2428
2428
 
2429
2429
 
2430
2430
  def test_schema_of_json(get_session_and_func, get_func):
2431
- session, schema_of_csv = get_session_and_func("schema_of_csv")
2431
+ session, schema_of_json = get_session_and_func("schema_of_json")
2432
2432
  lit = get_func("lit", session)
2433
- col = get_func("col", session)
2434
- df = session.range(1).select(col("id").alias("a"))
2433
+ df = session.range(1)
2435
2434
  assert (
2436
- df.select(schema_of_csv(lit("1|a"), {"sep": "|"}).alias("csv")).first()[0]
2437
- == "STRUCT<_c0: INT, _c1: STRING>"
2435
+ df.select(schema_of_json(lit('{"a": 0}')).alias("json")).first()[0] == "STRUCT<a: BIGINT>"
2438
2436
  )
2439
2437
  assert (
2440
- df.select(schema_of_csv("1|a", {"sep": "|"}).alias("csv")).first()[0]
2441
- == "STRUCT<_c0: INT, _c1: STRING>"
2438
+ df.select(
2439
+ schema_of_json("{a: 1}", {"allowUnquotedFieldNames": "true"}).alias("json")
2440
+ ).first()[0]
2441
+ == "STRUCT<a: BIGINT>"
2442
2442
  )
2443
2443
 
2444
2444
 
@@ -2873,3 +2873,13 @@ def test_nullif(get_session_and_func):
2873
2873
  ["a", "b"],
2874
2874
  )
2875
2875
  assert df.select(nullif(df.a, df.b).alias("r")).collect() == [Row(r=None), Row(r=1)]
2876
+
2877
+
2878
+ def test_stack(get_session_and_func, get_func):
2879
+ session, stack = get_session_and_func("stack")
2880
+ lit = get_func("lit", session)
2881
+ df = session.createDataFrame([(1, 2, 3)], ["a", "b", "c"])
2882
+ assert df.select(stack(lit(2), df.a, df.b, df.c)).collect() == [
2883
+ Row(key=1, value=2),
2884
+ Row(key=3, value=None),
2885
+ ]
@@ -207,13 +207,6 @@ def test_sum_distinct(expression, expected):
207
207
  assert expression.sql() == expected
208
208
 
209
209
 
210
- def test_product():
211
- with pytest.raises(NotImplementedError):
212
- SF.product("cola")
213
- with pytest.raises(NotImplementedError):
214
- SF.product("cola")
215
-
216
-
217
210
  @pytest.mark.parametrize(
218
211
  "expression, expected",
219
212
  [
@@ -2794,3 +2787,16 @@ def test_map_zip_with():
2794
2787
 
2795
2788
  def test_nullif():
2796
2789
  assert SF.nullif("cola", "colb").sql() == "NULLIF(cola, colb)"
2790
+
2791
+
2792
+ @pytest.mark.parametrize(
2793
+ "expression, expected",
2794
+ [
2795
+ (SF.stack("cola", "colb"), "STACK(cola, colb)"),
2796
+ (SF.stack(SF.col("cola"), SF.col("colb")), "STACK(cola, colb)"),
2797
+ (SF.stack("cola"), "STACK(cola)"),
2798
+ (SF.stack("cola", "colb", "colc", "cold"), "STACK(cola, colb, colc, cold)"),
2799
+ ],
2800
+ )
2801
+ def test_stack(expression, expected):
2802
+ assert expression.sql() == expected
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes