querysource 4.5.13__tar.gz → 4.5.15__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 (641) hide show
  1. querysource-4.5.15/.parrot/wiki.json +29 -0
  2. querysource-4.5.15/.parrot/wiki.local.json +3 -0
  3. {querysource-4.5.13 → querysource-4.5.15}/CHANGES.rst +32 -0
  4. {querysource-4.5.13 → querysource-4.5.15}/Makefile +12 -2
  5. {querysource-4.5.13 → querysource-4.5.15}/PKG-INFO +1 -2
  6. {querysource-4.5.13 → querysource-4.5.15}/pyproject.toml +0 -1
  7. {querysource-4.5.13 → querysource-4.5.15}/querysource/_version.py +3 -3
  8. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/dt/iter.py +6 -1
  9. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/writers/abstract.py +6 -5
  10. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/writers/csv.py +9 -1
  11. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/writers/tsv.py +9 -1
  12. {querysource-4.5.13 → querysource-4.5.15}/querysource/types/dt/filters.py +11 -6
  13. querysource-4.5.15/querysource/utils/dataframes.py +41 -0
  14. {querysource-4.5.13 → querysource-4.5.15}/querysource/version.py +1 -1
  15. {querysource-4.5.13 → querysource-4.5.15}/querysource.egg-info/PKG-INFO +1 -2
  16. {querysource-4.5.13 → querysource-4.5.15}/querysource.egg-info/SOURCES.txt +7 -0
  17. {querysource-4.5.13 → querysource-4.5.15}/querysource.egg-info/requires.txt +0 -1
  18. {querysource-4.5.13 → querysource-4.5.15}/querysource.egg-info/scm_file_list.json +7 -0
  19. querysource-4.5.15/querysource.egg-info/scm_version.json +8 -0
  20. querysource-4.5.15/tests/integration/test_csv_stream_response.py +36 -0
  21. querysource-4.5.15/tests/test_filters_drop_duplicates.py +55 -0
  22. querysource-4.5.15/tests/unit/test_csv_writer_dataframe.py +82 -0
  23. querysource-4.5.15/tests/unit/test_iter_format_dataframe.py +66 -0
  24. querysource-4.5.13/querysource.egg-info/scm_version.json +0 -8
  25. {querysource-4.5.13 → querysource-4.5.15}/.agent/rules/async-programming-expert.md +0 -0
  26. {querysource-4.5.13 → querysource-4.5.15}/.agent/rules/code-reviewer.md +0 -0
  27. {querysource-4.5.13 → querysource-4.5.15}/.agent/rules/cython-development.md +0 -0
  28. {querysource-4.5.13 → querysource-4.5.15}/.agent/rules/prompt-expert.md +0 -0
  29. {querysource-4.5.13 → querysource-4.5.15}/.agent/rules/python-development.md +0 -0
  30. {querysource-4.5.13 → querysource-4.5.15}/.agent/rules/rust-development.md +0 -0
  31. {querysource-4.5.13 → querysource-4.5.15}/.agent/workflows/create-parrot-tool.md +0 -0
  32. {querysource-4.5.13 → querysource-4.5.15}/.agent/workflows/create-workflow.md +0 -0
  33. {querysource-4.5.13 → querysource-4.5.15}/.agent/workflows/debug-regressions-with-git-bisect-binary-search.md +0 -0
  34. {querysource-4.5.13 → querysource-4.5.15}/.agent/workflows/generate-tests.md +0 -0
  35. {querysource-4.5.13 → querysource-4.5.15}/.agent/workflows/git-new-feature.md +0 -0
  36. {querysource-4.5.13 → querysource-4.5.15}/.agent/workflows/parrot-mcp-server.md +0 -0
  37. {querysource-4.5.13 → querysource-4.5.15}/.agent/workflows/release_package.md +0 -0
  38. {querysource-4.5.13 → querysource-4.5.15}/.agent/workflows/start-flow.md +0 -0
  39. {querysource-4.5.13 → querysource-4.5.15}/.bumpversion.cfg +0 -0
  40. {querysource-4.5.13 → querysource-4.5.15}/.claude/agents/code-reviewer.md +0 -0
  41. {querysource-4.5.13 → querysource-4.5.15}/.claude/agents/sdd-autopilot.md +0 -0
  42. {querysource-4.5.13 → querysource-4.5.15}/.claude/agents/sdd-qa.md +0 -0
  43. {querysource-4.5.13 → querysource-4.5.15}/.claude/agents/sdd-research.md +0 -0
  44. {querysource-4.5.13 → querysource-4.5.15}/.claude/agents/sdd-worker.md +0 -0
  45. {querysource-4.5.13 → querysource-4.5.15}/.claude/commands/pr-review.md +0 -0
  46. {querysource-4.5.13 → querysource-4.5.15}/.claude/commands/sdd-brainstorm.md +0 -0
  47. {querysource-4.5.13 → querysource-4.5.15}/.claude/commands/sdd-codereview.md +0 -0
  48. {querysource-4.5.13 → querysource-4.5.15}/.claude/commands/sdd-done.md +0 -0
  49. {querysource-4.5.13 → querysource-4.5.15}/.claude/commands/sdd-fromjira.md +0 -0
  50. {querysource-4.5.13 → querysource-4.5.15}/.claude/commands/sdd-next.md +0 -0
  51. {querysource-4.5.13 → querysource-4.5.15}/.claude/commands/sdd-proposal.md +0 -0
  52. {querysource-4.5.13 → querysource-4.5.15}/.claude/commands/sdd-spec.md +0 -0
  53. {querysource-4.5.13 → querysource-4.5.15}/.claude/commands/sdd-start.md +0 -0
  54. {querysource-4.5.13 → querysource-4.5.15}/.claude/commands/sdd-status.md +0 -0
  55. {querysource-4.5.13 → querysource-4.5.15}/.claude/commands/sdd-task.md +0 -0
  56. {querysource-4.5.13 → querysource-4.5.15}/.claude/commands/sdd-tojira.md +0 -0
  57. {querysource-4.5.13 → querysource-4.5.15}/.claude/rules/aws-cost-optimization.md +0 -0
  58. {querysource-4.5.13 → querysource-4.5.15}/.claude/rules/code-reviewer.md +0 -0
  59. {querysource-4.5.13 → querysource-4.5.15}/.claude/rules/cython-development.md +0 -0
  60. {querysource-4.5.13 → querysource-4.5.15}/.claude/rules/python-development.md +0 -0
  61. {querysource-4.5.13 → querysource-4.5.15}/.claude/rules/rust-development.md +0 -0
  62. {querysource-4.5.13 → querysource-4.5.15}/.claude/rules/using-git-worktrees.md +0 -0
  63. {querysource-4.5.13 → querysource-4.5.15}/.claude/rules/worktree-pr-and-clean.md +0 -0
  64. {querysource-4.5.13 → querysource-4.5.15}/.claude/rules/worktree-start-feature.md +0 -0
  65. {querysource-4.5.13 → querysource-4.5.15}/.claude/rules/worktree-status.md +0 -0
  66. {querysource-4.5.13 → querysource-4.5.15}/.github/dependabot.yml +0 -0
  67. {querysource-4.5.13 → querysource-4.5.15}/.github/workflows/codeql-analysis.yml +0 -0
  68. {querysource-4.5.13 → querysource-4.5.15}/.github/workflows/release.yml +0 -0
  69. {querysource-4.5.13 → querysource-4.5.15}/.isort.cfg +0 -0
  70. {querysource-4.5.13 → querysource-4.5.15}/.jupyter/jupyter_notebook_config.py +0 -0
  71. {querysource-4.5.13 → querysource-4.5.15}/.pre-commit-config.yaml +0 -0
  72. {querysource-4.5.13 → querysource-4.5.15}/.pylintrc +0 -0
  73. {querysource-4.5.13 → querysource-4.5.15}/CODE_OF_CONDUCT.md +0 -0
  74. {querysource-4.5.13 → querysource-4.5.15}/CONTRIBUTING.md +0 -0
  75. {querysource-4.5.13 → querysource-4.5.15}/INSTALL +0 -0
  76. {querysource-4.5.13 → querysource-4.5.15}/JOIN_CONDITIONS_FEATURE.md +0 -0
  77. {querysource-4.5.13 → querysource-4.5.15}/JOIN_CONDITIONS_SUMMARY.md +0 -0
  78. {querysource-4.5.13 → querysource-4.5.15}/LICENSE +0 -0
  79. {querysource-4.5.13 → querysource-4.5.15}/MANIFEST.in +0 -0
  80. {querysource-4.5.13 → querysource-4.5.15}/README.md +0 -0
  81. {querysource-4.5.13 → querysource-4.5.15}/app.py +0 -0
  82. {querysource-4.5.13 → querysource-4.5.15}/bin/README.md +0 -0
  83. {querysource-4.5.13 → querysource-4.5.15}/conftest.py +0 -0
  84. {querysource-4.5.13 → querysource-4.5.15}/generated/AirtableSource.json +0 -0
  85. {querysource-4.5.13 → querysource-4.5.15}/generated/Concat.json +0 -0
  86. {querysource-4.5.13 → querysource-4.5.15}/generated/DWHDestination.json +0 -0
  87. {querysource-4.5.13 → querysource-4.5.15}/generated/DropCols.json +0 -0
  88. {querysource-4.5.13 → querysource-4.5.15}/generated/FileSource.json +0 -0
  89. {querysource-4.5.13 → querysource-4.5.15}/generated/Filter.json +0 -0
  90. {querysource-4.5.13 → querysource-4.5.15}/generated/FilterCols.json +0 -0
  91. {querysource-4.5.13 → querysource-4.5.15}/generated/Forecast.json +0 -0
  92. {querysource-4.5.13 → querysource-4.5.15}/generated/GoogleMaps.json +0 -0
  93. {querysource-4.5.13 → querysource-4.5.15}/generated/GroupBy.json +0 -0
  94. {querysource-4.5.13 → querysource-4.5.15}/generated/Info.json +0 -0
  95. {querysource-4.5.13 → querysource-4.5.15}/generated/Join.json +0 -0
  96. {querysource-4.5.13 → querysource-4.5.15}/generated/Map.json +0 -0
  97. {querysource-4.5.13 → querysource-4.5.15}/generated/Melt.json +0 -0
  98. {querysource-4.5.13 → querysource-4.5.15}/generated/Merge.json +0 -0
  99. {querysource-4.5.13 → querysource-4.5.15}/generated/NormalizeColumns.json +0 -0
  100. {querysource-4.5.13 → querysource-4.5.15}/generated/PluckCols.json +0 -0
  101. {querysource-4.5.13 → querysource-4.5.15}/generated/Query.json +0 -0
  102. {querysource-4.5.13 → querysource-4.5.15}/generated/S3Source.json +0 -0
  103. {querysource-4.5.13 → querysource-4.5.15}/generated/SharepointSource.json +0 -0
  104. {querysource-4.5.13 → querysource-4.5.15}/generated/SmartSheetSource.json +0 -0
  105. {querysource-4.5.13 → querysource-4.5.15}/generated/Table.json +0 -0
  106. {querysource-4.5.13 → querysource-4.5.15}/generated/TableDestination.json +0 -0
  107. {querysource-4.5.13 → querysource-4.5.15}/generated/TableOutput.json +0 -0
  108. {querysource-4.5.13 → querysource-4.5.15}/generated/TableOutputAdapter.json +0 -0
  109. {querysource-4.5.13 → querysource-4.5.15}/generated/TableSource.json +0 -0
  110. {querysource-4.5.13 → querysource-4.5.15}/generated/ToS3.json +0 -0
  111. {querysource-4.5.13 → querysource-4.5.15}/generated/ToSharepoint.json +0 -0
  112. {querysource-4.5.13 → querysource-4.5.15}/generated/correlation.json +0 -0
  113. {querysource-4.5.13 → querysource-4.5.15}/generated/crosstab.json +0 -0
  114. {querysource-4.5.13 → querysource-4.5.15}/generated/pivot.json +0 -0
  115. {querysource-4.5.13 → querysource-4.5.15}/generated/tExplode.json +0 -0
  116. {querysource-4.5.13 → querysource-4.5.15}/generated/tOrder.json +0 -0
  117. {querysource-4.5.13 → querysource-4.5.15}/generated/tPandas.json +0 -0
  118. {querysource-4.5.13 → querysource-4.5.15}/gunicorn_config.py +0 -0
  119. {querysource-4.5.13 → querysource-4.5.15}/mypy.ini +0 -0
  120. {querysource-4.5.13 → querysource-4.5.15}/nav.py +0 -0
  121. {querysource-4.5.13 → querysource-4.5.15}/policies/HARDENING.md +0 -0
  122. {querysource-4.5.13 → querysource-4.5.15}/policies/authorized.yaml +0 -0
  123. {querysource-4.5.13 → querysource-4.5.15}/policies/baseline.yaml +0 -0
  124. {querysource-4.5.13 → querysource-4.5.15}/policies/datasources.yaml +0 -0
  125. {querysource-4.5.13 → querysource-4.5.15}/policies/defaults.yaml +0 -0
  126. {querysource-4.5.13 → querysource-4.5.15}/policies/drivers.yaml +0 -0
  127. {querysource-4.5.13 → querysource-4.5.15}/policies/raw_queries.yaml +0 -0
  128. {querysource-4.5.13 → querysource-4.5.15}/policies/slugs.yaml +0 -0
  129. {querysource-4.5.13 → querysource-4.5.15}/policies/superusers.yaml +0 -0
  130. {querysource-4.5.13 → querysource-4.5.15}/pytest.ini +0 -0
  131. {querysource-4.5.13 → querysource-4.5.15}/querysource/__cli__.py +0 -0
  132. {querysource-4.5.13 → querysource-4.5.15}/querysource/__init__.py +0 -0
  133. {querysource-4.5.13 → querysource-4.5.15}/querysource/auth/__init__.py +0 -0
  134. {querysource-4.5.13 → querysource-4.5.15}/querysource/auth/_resource_types.py +0 -0
  135. {querysource-4.5.13 → querysource-4.5.15}/querysource/auth/credentials.py +0 -0
  136. {querysource-4.5.13 → querysource-4.5.15}/querysource/auth/pbac.py +0 -0
  137. {querysource-4.5.13 → querysource-4.5.15}/querysource/cache/__init__.py +0 -0
  138. {querysource-4.5.13 → querysource-4.5.15}/querysource/cache/backends/__init__.py +0 -0
  139. {querysource-4.5.13 → querysource-4.5.15}/querysource/cache/backends/abstract.py +0 -0
  140. {querysource-4.5.13 → querysource-4.5.15}/querysource/cache/backends/memcache.py +0 -0
  141. {querysource-4.5.13 → querysource-4.5.15}/querysource/cache/backends/redis.py +0 -0
  142. {querysource-4.5.13 → querysource-4.5.15}/querysource/cache/base.py +0 -0
  143. {querysource-4.5.13 → querysource-4.5.15}/querysource/cli/__init__.py +0 -0
  144. {querysource-4.5.13 → querysource-4.5.15}/querysource/cli/generate_docs.py +0 -0
  145. {querysource-4.5.13 → querysource-4.5.15}/querysource/conf.py +0 -0
  146. {querysource-4.5.13 → querysource-4.5.15}/querysource/connections.py +0 -0
  147. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/__init__.py +0 -0
  148. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/__init__.py +0 -0
  149. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/abstract.py +0 -0
  150. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/arangodb.py +0 -0
  151. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/athena.py +0 -0
  152. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/bigquery.py +0 -0
  153. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/cassandra.py +0 -0
  154. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/clickhouse.py +0 -0
  155. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/cockroachdb.py +0 -0
  156. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/couchbase.py +0 -0
  157. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/couchdb.py +0 -0
  158. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/countries.py +0 -0
  159. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/delta.py +0 -0
  160. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/documentdb.py +0 -0
  161. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/dynamodb.py +0 -0
  162. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/elastic.py +0 -0
  163. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/ga.py +0 -0
  164. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/gcalc.py +0 -0
  165. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/hazel.py +0 -0
  166. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/iceberg.py +0 -0
  167. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/influx.py +0 -0
  168. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/jdbc.py +0 -0
  169. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/jira.py +0 -0
  170. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/mariadb.py +0 -0
  171. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/memcached.py +0 -0
  172. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/mongo.py +0 -0
  173. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/mysql.py +0 -0
  174. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/odbc.py +0 -0
  175. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/openweather.py +0 -0
  176. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/oracle.py +0 -0
  177. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/pg.py +0 -0
  178. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/pg_admin.py +0 -0
  179. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/postgres.py +0 -0
  180. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/py.typed +0 -0
  181. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/qs.py +0 -0
  182. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/redis.py +0 -0
  183. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/rest.py +0 -0
  184. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/rethink.py +0 -0
  185. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/sa.py +0 -0
  186. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/salesforce.py +0 -0
  187. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/scylladb.py +0 -0
  188. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/sqlalchemy.py +0 -0
  189. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/sqlite.py +0 -0
  190. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/sqlserver.py +0 -0
  191. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/upc.py +0 -0
  192. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/zipcodeapi.py +0 -0
  193. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/handlers/__init__.py +0 -0
  194. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/handlers/datasource.py +0 -0
  195. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/handlers/utils.py +0 -0
  196. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/introspection.py +0 -0
  197. {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/models.py +0 -0
  198. {querysource-4.5.13 → querysource-4.5.15}/querysource/events/__init__.py +0 -0
  199. {querysource-4.5.13 → querysource-4.5.15}/querysource/exceptions.py +0 -0
  200. {querysource-4.5.13 → querysource-4.5.15}/querysource/handlers/__init__.py +0 -0
  201. {querysource-4.5.13 → querysource-4.5.15}/querysource/handlers/_pagination.py +0 -0
  202. {querysource-4.5.13 → querysource-4.5.15}/querysource/handlers/abstract.py +0 -0
  203. {querysource-4.5.13 → querysource-4.5.15}/querysource/handlers/components.py +0 -0
  204. {querysource-4.5.13 → querysource-4.5.15}/querysource/handlers/executor.py +0 -0
  205. {querysource-4.5.13 → querysource-4.5.15}/querysource/handlers/integrations/__init__.py +0 -0
  206. {querysource-4.5.13 → querysource-4.5.15}/querysource/handlers/integrations/airtable.py +0 -0
  207. {querysource-4.5.13 → querysource-4.5.15}/querysource/handlers/log.py +0 -0
  208. {querysource-4.5.13 → querysource-4.5.15}/querysource/handlers/manager.py +0 -0
  209. {querysource-4.5.13 → querysource-4.5.15}/querysource/handlers/multi.py +0 -0
  210. {querysource-4.5.13 → querysource-4.5.15}/querysource/handlers/outputs/__init__.py +0 -0
  211. {querysource-4.5.13 → querysource-4.5.15}/querysource/handlers/outputs/tableOutput/__init__.py +0 -0
  212. {querysource-4.5.13 → querysource-4.5.15}/querysource/handlers/outputs/tableOutput/postgres.py +0 -0
  213. {querysource-4.5.13 → querysource-4.5.15}/querysource/handlers/outputs/tableOutput/table.py +0 -0
  214. {querysource-4.5.13 → querysource-4.5.15}/querysource/handlers/scheduler.py +0 -0
  215. {querysource-4.5.13 → querysource-4.5.15}/querysource/handlers/service.py +0 -0
  216. {querysource-4.5.13 → querysource-4.5.15}/querysource/handlers/variables.py +0 -0
  217. {querysource-4.5.13 → querysource-4.5.15}/querysource/interfaces/__init__.py +0 -0
  218. {querysource-4.5.13 → querysource-4.5.15}/querysource/interfaces/airtable.py +0 -0
  219. {querysource-4.5.13 → querysource-4.5.15}/querysource/interfaces/connections.py +0 -0
  220. {querysource-4.5.13 → querysource-4.5.15}/querysource/interfaces/credentials.py +0 -0
  221. {querysource-4.5.13 → querysource-4.5.15}/querysource/interfaces/databases/__init__.py +0 -0
  222. {querysource-4.5.13 → querysource-4.5.15}/querysource/interfaces/databases/abstract.py +0 -0
  223. {querysource-4.5.13 → querysource-4.5.15}/querysource/interfaces/databases/bigquery.py +0 -0
  224. {querysource-4.5.13 → querysource-4.5.15}/querysource/interfaces/databases/db.py +0 -0
  225. {querysource-4.5.13 → querysource-4.5.15}/querysource/interfaces/databases/mongo.py +0 -0
  226. {querysource-4.5.13 → querysource-4.5.15}/querysource/interfaces/databases/rethink.py +0 -0
  227. {querysource-4.5.13 → querysource-4.5.15}/querysource/interfaces/http.py +0 -0
  228. {querysource-4.5.13 → querysource-4.5.15}/querysource/interfaces/playwright_service.py +0 -0
  229. {querysource-4.5.13 → querysource-4.5.15}/querysource/interfaces/queries.py +0 -0
  230. {querysource-4.5.13 → querysource-4.5.15}/querysource/interfaces/selenium_service.py +0 -0
  231. {querysource-4.5.13 → querysource-4.5.15}/querysource/libs/__init__.py +0 -0
  232. {querysource-4.5.13 → querysource-4.5.15}/querysource/libs/encoders.py +0 -0
  233. {querysource-4.5.13 → querysource-4.5.15}/querysource/libs/functions/__init__.py +0 -0
  234. {querysource-4.5.13 → querysource-4.5.15}/querysource/libs/py.typed +0 -0
  235. {querysource-4.5.13 → querysource-4.5.15}/querysource/models.py +0 -0
  236. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/__init__.py +0 -0
  237. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/destinations/__init__.py +0 -0
  238. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/destinations/abstract.py +0 -0
  239. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/destinations/dwh.py +0 -0
  240. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/destinations/s3.py +0 -0
  241. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/destinations/sharepoint.py +0 -0
  242. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/destinations/table.py +0 -0
  243. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/dt/__init__.py +0 -0
  244. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/dt/abstract.py +0 -0
  245. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/dt/arrow.py +0 -0
  246. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/dt/dt.py +0 -0
  247. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/dt/factory.py +0 -0
  248. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/dt/modin.py +0 -0
  249. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/dt/pandas.py +0 -0
  250. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/dt/polars.py +0 -0
  251. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/output.py +0 -0
  252. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/tables/TableOutput/__init__.py +0 -0
  253. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/tables/TableOutput/abstract.py +0 -0
  254. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/tables/TableOutput/bigquery.py +0 -0
  255. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/tables/TableOutput/documentdb.py +0 -0
  256. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/tables/TableOutput/mongodb.py +0 -0
  257. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/tables/TableOutput/mysql.py +0 -0
  258. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/tables/TableOutput/postgres.py +0 -0
  259. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/tables/TableOutput/rethink.py +0 -0
  260. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/tables/TableOutput/sa.py +0 -0
  261. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/tables/TableOutput/table.py +0 -0
  262. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/tables/__init__.py +0 -0
  263. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/writers/__init__.py +0 -0
  264. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/writers/bokeh.py +0 -0
  265. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/writers/clustering.py +0 -0
  266. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/writers/describe.py +0 -0
  267. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/writers/eda.py +0 -0
  268. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/writers/excel.py +0 -0
  269. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/writers/html.py +0 -0
  270. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/writers/json.py +0 -0
  271. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/writers/pdf.py +0 -0
  272. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/writers/pickle.py +0 -0
  273. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/writers/plotly.py +0 -0
  274. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/writers/profiling.py +0 -0
  275. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/writers/report.py +0 -0
  276. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/writers/table.py +0 -0
  277. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/writers/txt.py +0 -0
  278. {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/writers/xml.py +0 -0
  279. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/__init__.py +0 -0
  280. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/abstract.c +0 -0
  281. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/abstract.pxd +0 -0
  282. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/abstract.pyx +0 -0
  283. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/arangodb.c +0 -0
  284. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/arangodb.pxd +0 -0
  285. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/arangodb.pyx +0 -0
  286. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/bigquery.c +0 -0
  287. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/bigquery.pxd +0 -0
  288. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/bigquery.pyx +0 -0
  289. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/cql.c +0 -0
  290. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/cql.pxd +0 -0
  291. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/cql.pyx +0 -0
  292. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/deltatbl.c +0 -0
  293. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/deltatbl.pxd +0 -0
  294. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/deltatbl.pyx +0 -0
  295. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/elastic.cpp +0 -0
  296. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/elastic.pxd +0 -0
  297. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/elastic.pyx +0 -0
  298. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/iceberg.c +0 -0
  299. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/iceberg.pxd +0 -0
  300. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/iceberg.pyx +0 -0
  301. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/influx.c +0 -0
  302. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/influx.pxd +0 -0
  303. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/influx.pyx +0 -0
  304. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/mongo.cpp +0 -0
  305. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/mongo.pxd +0 -0
  306. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/mongo.pyx +0 -0
  307. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/parser.c +0 -0
  308. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/parser.pxd +0 -0
  309. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/parser.pyx +0 -0
  310. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/pgsql.c +0 -0
  311. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/pgsql.pxd +0 -0
  312. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/pgsql.pyx +0 -0
  313. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/rethink.c +0 -0
  314. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/rethink.pxd +0 -0
  315. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/rethink.pyx +0 -0
  316. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/sosql.c +0 -0
  317. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/sosql.pxd +0 -0
  318. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/sosql.pyx +0 -0
  319. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/sql.c +0 -0
  320. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/sql.pxd +0 -0
  321. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/sql.pyx +0 -0
  322. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/sqlserver.c +0 -0
  323. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/sqlserver.pxd +0 -0
  324. {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/sqlserver.pyx +0 -0
  325. {querysource-4.5.13 → querysource-4.5.15}/querysource/plugins/__init__.py +0 -0
  326. {querysource-4.5.13 → querysource-4.5.15}/querysource/plugins/importer.py +0 -0
  327. {querysource-4.5.13 → querysource-4.5.15}/querysource/plugins/sources/__init__.py +0 -0
  328. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/__init__.py +0 -0
  329. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/abstract.py +0 -0
  330. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/arangodb.py +0 -0
  331. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/bigquery.py +0 -0
  332. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/cassandra.py +0 -0
  333. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/db.py +0 -0
  334. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/default.py +0 -0
  335. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/deltatbl.py +0 -0
  336. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/documentdb.py +0 -0
  337. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/dummy.py +0 -0
  338. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/elastic.py +0 -0
  339. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/external.py +0 -0
  340. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/http.py +0 -0
  341. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/iceberg.py +0 -0
  342. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/influx.py +0 -0
  343. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/mysql.py +0 -0
  344. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/pg.py +0 -0
  345. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/py.typed +0 -0
  346. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/rest.py +0 -0
  347. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/rethink.py +0 -0
  348. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/salesforce.py +0 -0
  349. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/scylladb.py +0 -0
  350. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/__init__.py +0 -0
  351. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/abstract.py +0 -0
  352. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/amazon.py +0 -0
  353. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/countries.py +0 -0
  354. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/ga.py +0 -0
  355. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/geofcc.py +0 -0
  356. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/gmaps.py +0 -0
  357. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/graphcountries.py +0 -0
  358. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/graphql.py +0 -0
  359. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/http.py +0 -0
  360. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/hubspot.py +0 -0
  361. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/openweather.py +0 -0
  362. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/parsers/__init__.py +0 -0
  363. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/parsers/amproduct.py +0 -0
  364. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/parsers/xpath.py +0 -0
  365. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/pokemon.py +0 -0
  366. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/populartimes.py +0 -0
  367. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/py.typed +0 -0
  368. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/rest.py +0 -0
  369. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/retailnext.py +0 -0
  370. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/rssapp.py +0 -0
  371. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/salesforce.py +0 -0
  372. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/scrapper.py +0 -0
  373. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/shoppertrack.py +0 -0
  374. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/swop.py +0 -0
  375. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/uap.py +0 -0
  376. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/upc.py +0 -0
  377. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/wm_stores.py +0 -0
  378. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/zammad.py +0 -0
  379. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/zipcodeapi.py +0 -0
  380. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sql.py +0 -0
  381. {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sqlserver.py +0 -0
  382. {querysource-4.5.13 → querysource-4.5.15}/querysource/py.typed +0 -0
  383. {querysource-4.5.13 → querysource-4.5.15}/querysource/qs_parsers/__init__.py +0 -0
  384. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/__init__.py +0 -0
  385. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/base.py +0 -0
  386. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/executor.py +0 -0
  387. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/models.py +0 -0
  388. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/__init__.py +0 -0
  389. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/_introspect.py +0 -0
  390. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/abstract.py +0 -0
  391. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/components/__init__.py +0 -0
  392. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/components/abstract.py +0 -0
  393. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/destinations/__init__.py +0 -0
  394. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/destinations/dwh.py +0 -0
  395. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/destinations/s3.py +0 -0
  396. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/destinations/sharepoint.py +0 -0
  397. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/destinations/table.py +0 -0
  398. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/operators/Concat.py +0 -0
  399. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/operators/GroupBy.catalog.yaml +0 -0
  400. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/operators/GroupBy.py +0 -0
  401. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/operators/Info.py +0 -0
  402. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/operators/Join.catalog.yaml +0 -0
  403. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/operators/Join.py +0 -0
  404. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/operators/Melt.catalog.yaml +0 -0
  405. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/operators/Melt.py +0 -0
  406. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/operators/Merge.catalog.yaml +0 -0
  407. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/operators/Merge.py +0 -0
  408. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/operators/__init__.py +0 -0
  409. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/operators/abstract.py +0 -0
  410. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/operators/filter/Filter.catalog.yaml +0 -0
  411. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/operators/filter/__init__.py +0 -0
  412. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/operators/filter/flt.py +0 -0
  413. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/registry.py +0 -0
  414. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/sources/__init__.py +0 -0
  415. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/sources/airtable.py +0 -0
  416. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/sources/base.py +0 -0
  417. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/sources/executors.py +0 -0
  418. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/sources/file.py +0 -0
  419. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/sources/query.catalog.yaml +0 -0
  420. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/sources/query.py +0 -0
  421. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/sources/s3.py +0 -0
  422. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/sources/sharepoint.py +0 -0
  423. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/sources/smartsheet.py +0 -0
  424. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/sources/table.py +0 -0
  425. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/DropCols.catalog.yaml +0 -0
  426. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/DropCols.py +0 -0
  427. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/FilterCols.catalog.yaml +0 -0
  428. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/FilterCols.py +0 -0
  429. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/Forecast.catalog.yaml +0 -0
  430. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/Forecast.py +0 -0
  431. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/Map.catalog.yaml +0 -0
  432. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/Map.py +0 -0
  433. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/NormalizeColumns.catalog.yaml +0 -0
  434. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/NormalizeColumns.py +0 -0
  435. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/PluckCols.catalog.yaml +0 -0
  436. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/PluckCols.py +0 -0
  437. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/__init__.py +0 -0
  438. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/abstract.py +0 -0
  439. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/correlation.catalog.yaml +0 -0
  440. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/correlation.py +0 -0
  441. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/crosstab.catalog.yaml +0 -0
  442. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/crosstab.py +0 -0
  443. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/google/GoogleMaps.catalog.yaml +0 -0
  444. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/google/__init__.py +0 -0
  445. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/google/maps.py +0 -0
  446. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/pivot.catalog.yaml +0 -0
  447. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/pivot.py +0 -0
  448. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/tExplode.catalog.yaml +0 -0
  449. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/tExplode.py +0 -0
  450. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/tOrder.catalog.yaml +0 -0
  451. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/tOrder.py +0 -0
  452. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/tPandas.py +0 -0
  453. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/obj.py +0 -0
  454. {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/qs.py +0 -0
  455. {querysource-4.5.13 → querysource-4.5.15}/querysource/scheduler/__init__.py +0 -0
  456. {querysource-4.5.13 → querysource-4.5.15}/querysource/scheduler/jobs.py +0 -0
  457. {querysource-4.5.13 → querysource-4.5.15}/querysource/scheduler/notifications.py +0 -0
  458. {querysource-4.5.13 → querysource-4.5.15}/querysource/scheduler/scheduler.py +0 -0
  459. {querysource-4.5.13 → querysource-4.5.15}/querysource/services.py +0 -0
  460. {querysource-4.5.13 → querysource-4.5.15}/querysource/template/__init__.py +0 -0
  461. {querysource-4.5.13 → querysource-4.5.15}/querysource/template/parser.py +0 -0
  462. {querysource-4.5.13 → querysource-4.5.15}/querysource/types/__init__.py +0 -0
  463. {querysource-4.5.13 → querysource-4.5.15}/querysource/types/converters.cpp +0 -0
  464. {querysource-4.5.13 → querysource-4.5.15}/querysource/types/converters.pyx +0 -0
  465. {querysource-4.5.13 → querysource-4.5.15}/querysource/types/dt/__init__.py +0 -0
  466. {querysource-4.5.13 → querysource-4.5.15}/querysource/types/dt/transforms.py +0 -0
  467. {querysource-4.5.13 → querysource-4.5.15}/querysource/types/py.typed +0 -0
  468. {querysource-4.5.13 → querysource-4.5.15}/querysource/types/typedefs.c +0 -0
  469. {querysource-4.5.13 → querysource-4.5.15}/querysource/types/typedefs.pyx +0 -0
  470. {querysource-4.5.13 → querysource-4.5.15}/querysource/types/validators.cpp +0 -0
  471. {querysource-4.5.13 → querysource-4.5.15}/querysource/types/validators.pyx +0 -0
  472. {querysource-4.5.13 → querysource-4.5.15}/querysource/utils/__init__.py +0 -0
  473. {querysource-4.5.13 → querysource-4.5.15}/querysource/utils/cache_serialization.py +0 -0
  474. {querysource-4.5.13 → querysource-4.5.15}/querysource/utils/errors.py +0 -0
  475. {querysource-4.5.13 → querysource-4.5.15}/querysource/utils/events.py +0 -0
  476. {querysource-4.5.13 → querysource-4.5.15}/querysource/utils/fn.py +0 -0
  477. {querysource-4.5.13 → querysource-4.5.15}/querysource/utils/functions.cpp +0 -0
  478. {querysource-4.5.13 → querysource-4.5.15}/querysource/utils/functions.pyx +0 -0
  479. {querysource-4.5.13 → querysource-4.5.15}/querysource/utils/getfunc.py +0 -0
  480. {querysource-4.5.13 → querysource-4.5.15}/querysource/utils/handlers.py +0 -0
  481. {querysource-4.5.13 → querysource-4.5.15}/querysource/utils/parseqs.cpp +0 -0
  482. {querysource-4.5.13 → querysource-4.5.15}/querysource/utils/parseqs.pyx +0 -0
  483. {querysource-4.5.13 → querysource-4.5.15}/querysource/utils/validators.py +0 -0
  484. {querysource-4.5.13 → querysource-4.5.15}/querysource.egg-info/dependency_links.txt +0 -0
  485. {querysource-4.5.13 → querysource-4.5.15}/querysource.egg-info/entry_points.txt +0 -0
  486. {querysource-4.5.13 → querysource-4.5.15}/querysource.egg-info/not-zip-safe +0 -0
  487. {querysource-4.5.13 → querysource-4.5.15}/querysource.egg-info/top_level.txt +0 -0
  488. {querysource-4.5.13 → querysource-4.5.15}/run.py +0 -0
  489. {querysource-4.5.13 → querysource-4.5.15}/rust/Cargo.lock +0 -0
  490. {querysource-4.5.13 → querysource-4.5.15}/rust/Cargo.toml +0 -0
  491. {querysource-4.5.13 → querysource-4.5.15}/rust/pyproject.toml +0 -0
  492. {querysource-4.5.13 → querysource-4.5.15}/rust/src/arangodb_parser.rs +0 -0
  493. {querysource-4.5.13 → querysource-4.5.15}/rust/src/bigquery_parser.rs +0 -0
  494. {querysource-4.5.13 → querysource-4.5.15}/rust/src/cql_parser.rs +0 -0
  495. {querysource-4.5.13 → querysource-4.5.15}/rust/src/elastic_parser.rs +0 -0
  496. {querysource-4.5.13 → querysource-4.5.15}/rust/src/filter_common.rs +0 -0
  497. {querysource-4.5.13 → querysource-4.5.15}/rust/src/flux_parser.rs +0 -0
  498. {querysource-4.5.13 → querysource-4.5.15}/rust/src/lib.rs +0 -0
  499. {querysource-4.5.13 → querysource-4.5.15}/rust/src/mongo_parser.rs +0 -0
  500. {querysource-4.5.13 → querysource-4.5.15}/rust/src/mssql_parser.rs +0 -0
  501. {querysource-4.5.13 → querysource-4.5.15}/rust/src/parseqs.rs +0 -0
  502. {querysource-4.5.13 → querysource-4.5.15}/rust/src/pgsql_parser.rs +0 -0
  503. {querysource-4.5.13 → querysource-4.5.15}/rust/src/rethink_parser.rs +0 -0
  504. {querysource-4.5.13 → querysource-4.5.15}/rust/src/safe_dict.rs +0 -0
  505. {querysource-4.5.13 → querysource-4.5.15}/rust/src/soql_parser.rs +0 -0
  506. {querysource-4.5.13 → querysource-4.5.15}/rust/src/sql_parser.rs +0 -0
  507. {querysource-4.5.13 → querysource-4.5.15}/rust/src/validators.rs +0 -0
  508. {querysource-4.5.13 → querysource-4.5.15}/setup.cfg +0 -0
  509. {querysource-4.5.13 → querysource-4.5.15}/setup.py +0 -0
  510. {querysource-4.5.13 → querysource-4.5.15}/static/notebook/bundle.js +0 -0
  511. {querysource-4.5.13 → querysource-4.5.15}/templates/__init__.py +0 -0
  512. {querysource-4.5.13 → querysource-4.5.15}/templates/base.html +0 -0
  513. {querysource-4.5.13 → querysource-4.5.15}/templates/default.html +0 -0
  514. {querysource-4.5.13 → querysource-4.5.15}/templates/default_table.html +0 -0
  515. {querysource-4.5.13 → querysource-4.5.15}/templates/fontlist-v330.json +0 -0
  516. {querysource-4.5.13 → querysource-4.5.15}/templates/fontlist-v390.json +0 -0
  517. {querysource-4.5.13 → querysource-4.5.15}/templates/table_charts.html +0 -0
  518. {querysource-4.5.13 → querysource-4.5.15}/tests/auth/__init__.py +0 -0
  519. {querysource-4.5.13 → querysource-4.5.15}/tests/auth/test_credentials.py +0 -0
  520. {querysource-4.5.13 → querysource-4.5.15}/tests/auth/test_pbac_bootstrap.py +0 -0
  521. {querysource-4.5.13 → querysource-4.5.15}/tests/check_concurrent_get_slug.py +0 -0
  522. {querysource-4.5.13 → querysource-4.5.15}/tests/conftest.py +0 -0
  523. {querysource-4.5.13 → querysource-4.5.15}/tests/datasources/__init__.py +0 -0
  524. {querysource-4.5.13 → querysource-4.5.15}/tests/datasources/test_datasource_view_pbac.py +0 -0
  525. {querysource-4.5.13 → querysource-4.5.15}/tests/datasources/test_driver_factory_session.py +0 -0
  526. {querysource-4.5.13 → querysource-4.5.15}/tests/datasources/test_pg_admin_registration.py +0 -0
  527. {querysource-4.5.13 → querysource-4.5.15}/tests/datasources/test_pg_params_for.py +0 -0
  528. {querysource-4.5.13 → querysource-4.5.15}/tests/handlers/__init__.py +0 -0
  529. {querysource-4.5.13 → querysource-4.5.15}/tests/handlers/conftest.py +0 -0
  530. {querysource-4.5.13 → querysource-4.5.15}/tests/handlers/test_abstract_pbac_helpers.py +0 -0
  531. {querysource-4.5.13 → querysource-4.5.15}/tests/handlers/test_airtable_oauth.py +0 -0
  532. {querysource-4.5.13 → querysource-4.5.15}/tests/handlers/test_multiquery_pbac_smoke.py +0 -0
  533. {querysource-4.5.13 → querysource-4.5.15}/tests/handlers/test_query_param_exclusion.py +0 -0
  534. {querysource-4.5.13 → querysource-4.5.15}/tests/handlers/test_queryexecutor_pbac_smoke.py +0 -0
  535. {querysource-4.5.13 → querysource-4.5.15}/tests/handlers/test_querymanager_pagination.py +0 -0
  536. {querysource-4.5.13 → querysource-4.5.15}/tests/handlers/test_queryservice_pbac_smoke.py +0 -0
  537. {querysource-4.5.13 → querysource-4.5.15}/tests/integration/__init__.py +0 -0
  538. {querysource-4.5.13 → querysource-4.5.15}/tests/integration/test_datasource_endpoint.py +0 -0
  539. {querysource-4.5.13 → querysource-4.5.15}/tests/integration/test_multiquery_output_errors.py +0 -0
  540. {querysource-4.5.13 → querysource-4.5.15}/tests/integration/test_pbac_credentials.py +0 -0
  541. {querysource-4.5.13 → querysource-4.5.15}/tests/integration/test_pbac_enforcement.py +0 -0
  542. {querysource-4.5.13 → querysource-4.5.15}/tests/integration/test_pbac_listing.py +0 -0
  543. {querysource-4.5.13 → querysource-4.5.15}/tests/integration/test_slug_injection.py +0 -0
  544. {querysource-4.5.13 → querysource-4.5.15}/tests/integration/test_slug_regression.py +0 -0
  545. {querysource-4.5.13 → querysource-4.5.15}/tests/interfaces/__init__.py +0 -0
  546. {querysource-4.5.13 → querysource-4.5.15}/tests/interfaces/test_airtable_interface.py +0 -0
  547. {querysource-4.5.13 → querysource-4.5.15}/tests/multi/__init__.py +0 -0
  548. {querysource-4.5.13 → querysource-4.5.15}/tests/multi/sources/__init__.py +0 -0
  549. {querysource-4.5.13 → querysource-4.5.15}/tests/multi/sources/test_airtable_source.py +0 -0
  550. {querysource-4.5.13 → querysource-4.5.15}/tests/multi/sources/test_registry.py +0 -0
  551. {querysource-4.5.13 → querysource-4.5.15}/tests/perf/__init__.py +0 -0
  552. {querysource-4.5.13 → querysource-4.5.15}/tests/perf/test_pbac_overhead.py +0 -0
  553. {querysource-4.5.13 → querysource-4.5.15}/tests/policies/__init__.py +0 -0
  554. {querysource-4.5.13 → querysource-4.5.15}/tests/policies/test_authorized_policy.py +0 -0
  555. {querysource-4.5.13 → querysource-4.5.15}/tests/policies/test_default_policies_load.py +0 -0
  556. {querysource-4.5.13 → querysource-4.5.15}/tests/scheduler/__init__.py +0 -0
  557. {querysource-4.5.13 → querysource-4.5.15}/tests/scheduler/test_parse_trigger_shorthands.py +0 -0
  558. {querysource-4.5.13 → querysource-4.5.15}/tests/scheduler/test_shorthand_loaders.py +0 -0
  559. {querysource-4.5.13 → querysource-4.5.15}/tests/services/__init__.py +0 -0
  560. {querysource-4.5.13 → querysource-4.5.15}/tests/services/test_querysource_setup_pbac.py +0 -0
  561. {querysource-4.5.13 → querysource-4.5.15}/tests/test_abstract_multi.py +0 -0
  562. {querysource-4.5.13 → querysource-4.5.15}/tests/test_abstract_refactor.py +0 -0
  563. {querysource-4.5.13 → querysource-4.5.15}/tests/test_api.py +0 -0
  564. {querysource-4.5.13 → querysource-4.5.15}/tests/test_arangodb_parser.py +0 -0
  565. {querysource-4.5.13 → querysource-4.5.15}/tests/test_catalog_colcols.py +0 -0
  566. {querysource-4.5.13 → querysource-4.5.15}/tests/test_catalog_correlation.py +0 -0
  567. {querysource-4.5.13 → querysource-4.5.15}/tests/test_catalog_filter.py +0 -0
  568. {querysource-4.5.13 → querysource-4.5.15}/tests/test_catalog_forecast.py +0 -0
  569. {querysource-4.5.13 → querysource-4.5.15}/tests/test_catalog_googlemaps.py +0 -0
  570. {querysource-4.5.13 → querysource-4.5.15}/tests/test_catalog_groupby.py +0 -0
  571. {querysource-4.5.13 → querysource-4.5.15}/tests/test_catalog_map.py +0 -0
  572. {querysource-4.5.13 → querysource-4.5.15}/tests/test_catalog_pivot.py +0 -0
  573. {querysource-4.5.13 → querysource-4.5.15}/tests/test_catalog_remote.py +0 -0
  574. {querysource-4.5.13 → querysource-4.5.15}/tests/test_catalog_texplode.py +0 -0
  575. {querysource-4.5.13 → querysource-4.5.15}/tests/test_catalog_torder.py +0 -0
  576. {querysource-4.5.13 → querysource-4.5.15}/tests/test_cli_generate_docs.py +0 -0
  577. {querysource-4.5.13 → querysource-4.5.15}/tests/test_column_filters.py +0 -0
  578. {querysource-4.5.13 → querysource-4.5.15}/tests/test_component_handler.py +0 -0
  579. {querysource-4.5.13 → querysource-4.5.15}/tests/test_component_registry.py +0 -0
  580. {querysource-4.5.13 → querysource-4.5.15}/tests/test_conf_airtable.py +0 -0
  581. {querysource-4.5.13 → querysource-4.5.15}/tests/test_destination_base.py +0 -0
  582. {querysource-4.5.13 → querysource-4.5.15}/tests/test_destination_dwh.py +0 -0
  583. {querysource-4.5.13 → querysource-4.5.15}/tests/test_destination_integration.py +0 -0
  584. {querysource-4.5.13 → querysource-4.5.15}/tests/test_destination_s3.py +0 -0
  585. {querysource-4.5.13 → querysource-4.5.15}/tests/test_destination_sharepoint.py +0 -0
  586. {querysource-4.5.13 → querysource-4.5.15}/tests/test_destination_table.py +0 -0
  587. {querysource-4.5.13 → querysource-4.5.15}/tests/test_destinations_documentation_endpoint.py +0 -0
  588. {querysource-4.5.13 → querysource-4.5.15}/tests/test_elastic_parser.py +0 -0
  589. {querysource-4.5.13 → querysource-4.5.15}/tests/test_error_formatter.py +0 -0
  590. {querysource-4.5.13 → querysource-4.5.15}/tests/test_eval.py +0 -0
  591. {querysource-4.5.13 → querysource-4.5.15}/tests/test_feat102_error_redaction.py +0 -0
  592. {querysource-4.5.13 → querysource-4.5.15}/tests/test_grouping_sync.py +0 -0
  593. {querysource-4.5.13 → querysource-4.5.15}/tests/test_info_eda.py +0 -0
  594. {querysource-4.5.13 → querysource-4.5.15}/tests/test_info_eda_e2e.py +0 -0
  595. {querysource-4.5.13 → querysource-4.5.15}/tests/test_info_eda_integration.py +0 -0
  596. {querysource-4.5.13 → querysource-4.5.15}/tests/test_join_conditions.py +0 -0
  597. {querysource-4.5.13 → querysource-4.5.15}/tests/test_join_with_column_filter.py +0 -0
  598. {querysource-4.5.13 → querysource-4.5.15}/tests/test_local_executor.py +0 -0
  599. {querysource-4.5.13 → querysource-4.5.15}/tests/test_multi_destinations_subpackage.py +0 -0
  600. {querysource-4.5.13 → querysource-4.5.15}/tests/test_multiqs_column_transforms.py +0 -0
  601. {querysource-4.5.13 → querysource-4.5.15}/tests/test_multiqs_destination_dispatch.py +0 -0
  602. {querysource-4.5.13 → querysource-4.5.15}/tests/test_multiqs_remote_dispatch.py +0 -0
  603. {querysource-4.5.13 → querysource-4.5.15}/tests/test_multiqs_slug_sources_normalize.py +0 -0
  604. {querysource-4.5.13 → querysource-4.5.15}/tests/test_multiqs_sources_integration.py +0 -0
  605. {querysource-4.5.13 → querysource-4.5.15}/tests/test_queryslug_concurrency.py +0 -0
  606. {querysource-4.5.13 → querysource-4.5.15}/tests/test_querysource_setup_airtable.py +0 -0
  607. {querysource-4.5.13 → querysource-4.5.15}/tests/test_qworker_config.py +0 -0
  608. {querysource-4.5.13 → querysource-4.5.15}/tests/test_remote_executor.py +0 -0
  609. {querysource-4.5.13 → querysource-4.5.15}/tests/test_route_registration.py +0 -0
  610. {querysource-4.5.13 → querysource-4.5.15}/tests/test_rss.py +0 -0
  611. {querysource-4.5.13 → querysource-4.5.15}/tests/test_rust_parsers.py +0 -0
  612. {querysource-4.5.13 → querysource-4.5.15}/tests/test_scheduler_core.py +0 -0
  613. {querysource-4.5.13 → querysource-4.5.15}/tests/test_scheduler_handler_integration.py +0 -0
  614. {querysource-4.5.13 → querysource-4.5.15}/tests/test_scheduler_handler_unit.py +0 -0
  615. {querysource-4.5.13 → querysource-4.5.15}/tests/test_scheduler_integration.py +0 -0
  616. {querysource-4.5.13 → querysource-4.5.15}/tests/test_scheduler_jobs.py +0 -0
  617. {querysource-4.5.13 → querysource-4.5.15}/tests/test_scheduler_multi_routing.py +0 -0
  618. {querysource-4.5.13 → querysource-4.5.15}/tests/test_scheduler_notifications.py +0 -0
  619. {querysource-4.5.13 → querysource-4.5.15}/tests/test_schema_introspectable.py +0 -0
  620. {querysource-4.5.13 → querysource-4.5.15}/tests/test_source_registry.py +0 -0
  621. {querysource-4.5.13 → querysource-4.5.15}/tests/test_source_s3.py +0 -0
  622. {querysource-4.5.13 → querysource-4.5.15}/tests/test_source_sharepoint.py +0 -0
  623. {querysource-4.5.13 → querysource-4.5.15}/tests/test_source_smartsheet.py +0 -0
  624. {querysource-4.5.13 → querysource-4.5.15}/tests/test_source_table.py +0 -0
  625. {querysource-4.5.13 → querysource-4.5.15}/tests/test_sql_parser_combinations.py +0 -0
  626. {querysource-4.5.13 → querysource-4.5.15}/tests/test_texplode.py +0 -0
  627. {querysource-4.5.13 → querysource-4.5.15}/tests/test_thread_file_refactor.py +0 -0
  628. {querysource-4.5.13 → querysource-4.5.15}/tests/test_thread_query_refactor.py +0 -0
  629. {querysource-4.5.13 → querysource-4.5.15}/tests/test_thread_source_base.py +0 -0
  630. {querysource-4.5.13 → querysource-4.5.15}/tests/test_threadquery_executor.py +0 -0
  631. {querysource-4.5.13 → querysource-4.5.15}/tests/test_zammad_search.py +0 -0
  632. {querysource-4.5.13 → querysource-4.5.15}/tests/unit/test_cython_filter_fallback.py +0 -0
  633. {querysource-4.5.13 → querysource-4.5.15}/tests/unit/test_datasource_redaction.py +0 -0
  634. {querysource-4.5.13 → querysource-4.5.15}/tests/unit/test_error_payload.py +0 -0
  635. {querysource-4.5.13 → querysource-4.5.15}/tests/unit/test_handler_output_status.py +0 -0
  636. {querysource-4.5.13 → querysource-4.5.15}/tests/unit/test_multiqs_output_raise.py +0 -0
  637. {querysource-4.5.13 → querysource-4.5.15}/tests/unit/test_output_error.py +0 -0
  638. {querysource-4.5.13 → querysource-4.5.15}/tests/unit/test_provider_raw_query_validated.py +0 -0
  639. {querysource-4.5.13 → querysource-4.5.15}/tests/unit/test_qs_parsers_validated.py +0 -0
  640. {querysource-4.5.13 → querysource-4.5.15}/tests/unit/test_raw_query_cond_definition_wiring.py +0 -0
  641. {querysource-4.5.13 → querysource-4.5.15}/tox.ini +0 -0
@@ -0,0 +1,29 @@
1
+ {
2
+ "wiki_name": "querysource",
3
+ "storage_dir": ".parrot/wiki",
4
+ "backend": "sqlite",
5
+ "include_suffixes": [],
6
+ "exclude_dirs": [
7
+ ".parrot/wiki"
8
+ ],
9
+ "body_max_chars": 16000,
10
+ "max_file_kb": 512,
11
+ "claude": {
12
+ "nudge_cooldown_seconds": 60,
13
+ "nudge_tools": [
14
+ "Grep",
15
+ "Glob",
16
+ "Read",
17
+ "Bash"
18
+ ]
19
+ },
20
+ "sync_graph": false,
21
+ "arango_database": null,
22
+ "arango_credentials_env": "ARANGODB",
23
+ "arango_text_analyzer": "text_en",
24
+ "vault_dir": null,
25
+ "namespaces": {},
26
+ "obsidian_sync": null,
27
+ "symbol_depth": 2,
28
+ "structural_backend": true
29
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "backend": "sqlite"
3
+ }
@@ -1,6 +1,38 @@
1
1
  Unreleased
2
2
  ==========
3
3
 
4
+ Row-oriented outputs — DataFrame results and swallowed errors
5
+ -------------------------------------------------------------
6
+
7
+ The ``iter`` output format now honours its contract and returns a list of
8
+ dictionaries for ``pandas.DataFrame`` results (``bigquery``, ``deltatbl``,
9
+ ``iceberg`` providers) instead of passing the frame through. Iterating a
10
+ DataFrame yields column names, not rows, so every writer declaring
11
+ ``output_format = 'iter'`` received garbage: ``aiocsv`` raised
12
+ ``AttributeError`` in ``CSVWriter``/``TSVWriter`` and the writers'
13
+ ``TmpFile.__aexit__`` returned a truthy value, suppressing the exception —
14
+ ``slug:csv`` answered HTTP 200 with only the header line. ``slug:txt`` and the
15
+ report writers (``slug:html``, ``slug:pdf``) were broken by the same cause.
16
+
17
+ - ``iterFormat.serialize`` converts DataFrames to records
18
+ (``NaN``/``NaT``/``NA`` -> ``None``) via the new
19
+ ``querysource.utils.dataframes`` helpers.
20
+ - ``CSVWriter``/``TSVWriter`` apply the same normalisation defensively, for
21
+ callers handing a frame straight to a writer.
22
+ - ``TmpFile.__aexit__`` no longer suppresses exceptions, so writer errors
23
+ surface as HTTP 500 instead of a silent, truncated 200.
24
+ Drop invalid ``Content-Range`` header from streamed responses
25
+ ------------------------------------------------------------
26
+
27
+ ``AbstractWriter.stream_response()`` advertised
28
+ ``Content-Range: bytes 0-16384/<content-length>`` on ``200`` responses that
29
+ carry the **full** body. The header is only defined for ``206``/``416``
30
+ (RFC 9110 s14.4), the range is off by one (inclusive positions, so
31
+ ``0-16384`` spans 16385 bytes) and for any body under 16385 bytes the
32
+ last-byte-pos exceeded the complete length, making the field value invalid.
33
+ QuerySource does not honour request ``Range`` headers at all, so nothing
34
+ relied on it. ``Content-Length`` is unchanged.
35
+
4
36
  FEAT-090 — Query Slug list pagination
5
37
  -------------------------------------
6
38
 
@@ -28,9 +28,14 @@ venv:
28
28
  @echo 'run `source .venv/bin/activate` to start develop with QuerySource.'
29
29
 
30
30
  # Install production dependencies using lock file
31
- install: build-rust
31
+ # NOTE: uv sync must run BEFORE build-rust — build-rust invokes .venv/bin/maturin,
32
+ # which only exists once it has been installed. maturin is a `dev`-only extra
33
+ # (see pyproject.toml), so it is excluded from `--no-dev` and installed explicitly.
34
+ install:
32
35
  uv sync --frozen --no-dev --extra analytics --extra vectors
33
36
  uv pip install navigator-api[uvloop,locale]
37
+ uv pip install "maturin>=1.7,<2.0"
38
+ $(MAKE) build-rust
34
39
  @echo "Production dependencies installed. Use 'make develop' for development setup."
35
40
 
36
41
  # Generate lock files (uv only)
@@ -42,8 +47,13 @@ else
42
47
  endif
43
48
 
44
49
  # Install all dependencies including dev dependencies
45
- develop: build-rust
50
+ # NOTE: uv sync must run BEFORE build-rust — build-rust invokes .venv/bin/maturin,
51
+ # which is installed by the `dev` extra during uv sync. Making build-rust a
52
+ # prerequisite (instead of a recipe step) would run it first and fail on a
53
+ # fresh .venv where maturin isn't installed yet.
54
+ develop:
46
55
  uv sync --frozen --extra analytics --extra dev
56
+ $(MAKE) build-rust
47
57
  $(MAKE) build-inplace
48
58
 
49
59
  # Build the Rust-accelerated parser extension (querysource.qs_parsers._qs_parsers)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: querysource
3
- Version: 4.5.13
3
+ Version: 4.5.15
4
4
  Summary: Aiohttp web service for querying several databases easily
5
5
  Author-email: Jesus Lara <jesuslarag@gmail.com>
6
6
  License: BSD-3-Clause
@@ -37,7 +37,6 @@ Requires-Dist: oauth2client>=4.1.3
37
37
  Requires-Dist: google-analytics-data>=0.18.15
38
38
  Requires-Dist: google-api-python-client>=2.151.0
39
39
  Requires-Dist: google-auth-oauthlib==1.2.1
40
- Requires-Dist: sqloxide==0.1.39
41
40
  Requires-Dist: aiocsv>=1.3.2
42
41
  Requires-Dist: lxml>=5.3.0
43
42
  Requires-Dist: xlsxwriter==3.2.0
@@ -50,7 +50,6 @@ dependencies = [
50
50
  "google-analytics-data>=0.18.15",
51
51
  "google-api-python-client>=2.151.0", # Aligned with flowtask
52
52
  "google-auth-oauthlib==1.2.1",
53
- "sqloxide==0.1.39",
54
53
  "aiocsv>=1.3.2",
55
54
  "lxml>=5.3.0",
56
55
  "xlsxwriter==3.2.0",
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '4.5.13'
22
- __version_tuple__ = version_tuple = (4, 5, 13)
21
+ __version__ = version = '4.5.15'
22
+ __version_tuple__ = version_tuple = (4, 5, 15)
23
23
 
24
- __commit_id__ = commit_id = 'g31553f851'
24
+ __commit_id__ = commit_id = 'g33895edcd'
@@ -8,6 +8,7 @@ try:
8
8
  from google.cloud.bigquery.table import RowIterator
9
9
  except ImportError:
10
10
  RowIterator = None
11
+ from ...utils.dataframes import df_to_records
11
12
  from .abstract import OutputFormat
12
13
 
13
14
 
@@ -17,7 +18,11 @@ class iterFormat(OutputFormat):
17
18
  """
18
19
  async def serialize(self, result, error, *args, **kwargs):
19
20
  if isinstance(result, pandas.DataFrame):
20
- data = result
21
+ # pandas-backed providers (bigquery, deltatbl, iceberg) return a
22
+ # DataFrame. Iterating it yields column names, not rows, so every
23
+ # row-oriented consumer (csv, tsv, txt, report/pdf) has to receive
24
+ # records here — this format's contract is a list of dictionaries.
25
+ data = df_to_records(result)
21
26
  elif isinstance(result, (RowIterator, list)):
22
27
  data = [dict(row) for row in result]
23
28
  else:
@@ -15,6 +15,7 @@ from aiohttp.web_exceptions import (
15
15
  from ...interfaces.queries import AbstractQuery
16
16
  from ...libs.encoders import DefaultEncoder
17
17
  from ...utils.functions import check_empty
18
+ from ...utils.dataframes import df_to_records
18
19
  from ...utils.errors import build_error_payload
19
20
  from ...exceptions import (
20
21
  CacheException,
@@ -157,10 +158,9 @@ class AbstractWriter(ABC):
157
158
  content_length = len(data)
158
159
  response.content_length = content_length
159
160
  if self.response_type == 'stream': # an stream response:
161
+ # NOTE: no Content-Range header here: the full body is sent with a
162
+ # 200 status and range requests are not supported.
160
163
  chunk_size = 16384
161
- response.headers[
162
- "Content-Range"
163
- ] = f"bytes 0-{chunk_size}/{content_length}"
164
164
  try:
165
165
  i = 0
166
166
  await response.prepare(self.request)
@@ -305,8 +305,9 @@ class AbstractWriter(ABC):
305
305
  from pandas import DataFrame
306
306
  if isinstance(self.query, DataFrame):
307
307
  if self.output_format == 'iter':
308
- # convert dataframe into a list of dictionaries:
309
- self.data = self.query.to_dict(orient='records')
308
+ # convert dataframe into a list of dictionaries,
309
+ # same normalisation the 'iter' format applies:
310
+ self.data = df_to_records(self.query)
310
311
  else:
311
312
  self.data = self.query
312
313
  error = None
@@ -6,6 +6,7 @@ from ...conf import (
6
6
  CSV_DEFAULT_DELIMITER,
7
7
  CSV_DEFAULT_QUOTING
8
8
  )
9
+ from ...utils.dataframes import df_to_records, is_dataframe
9
10
  from .abstract import AbstractWriter
10
11
 
11
12
 
@@ -22,7 +23,10 @@ class TmpFile:
22
23
 
23
24
  async def __aexit__(self, exc_type, exc, tb):
24
25
  self.output.seek(0)
25
- return self
26
+ # A truthy return from __aexit__ suppresses the in-flight exception:
27
+ # any error raised while writing rows was silently dropped and the
28
+ # response went out as HTTP 200 with only the header line.
29
+ return False
26
30
 
27
31
  def get(self):
28
32
  return self.output.getvalue()
@@ -36,6 +40,10 @@ class CSVWriter(AbstractWriter):
36
40
  async def get_response(self) -> web.StreamResponse:
37
41
  try:
38
42
  await self.get_buffer()
43
+ if is_dataframe(self.data):
44
+ # Defence in depth: the 'iter' output format already normalises
45
+ # DataFrames, but a writer can also be handed one directly.
46
+ self.data = df_to_records(self.data)
39
47
  if 'delimiter' in self.kwargs:
40
48
  delimiter = self.kwargs['delimiter']
41
49
  else:
@@ -2,6 +2,7 @@ import csv
2
2
  from io import StringIO
3
3
  from aiocsv import AsyncDictWriter
4
4
  from aiohttp import web
5
+ from ...utils.dataframes import df_to_records, is_dataframe
5
6
  from .abstract import AbstractWriter
6
7
 
7
8
 
@@ -18,7 +19,10 @@ class TmpFile:
18
19
 
19
20
  async def __aexit__(self, exc_type, exc, tb):
20
21
  self.output.seek(0)
21
- return self
22
+ # A truthy return from __aexit__ suppresses the in-flight exception:
23
+ # any error raised while writing rows was silently dropped and the
24
+ # response went out as HTTP 200 with only the header line.
25
+ return False
22
26
 
23
27
  def get(self):
24
28
  return self.output.getvalue()
@@ -32,6 +36,10 @@ class TSVWriter(AbstractWriter):
32
36
  async def get_response(self) -> web.StreamResponse:
33
37
  try:
34
38
  await self.get_buffer()
39
+ if is_dataframe(self.data):
40
+ # Defence in depth: the 'iter' output format already normalises
41
+ # DataFrames, but a writer can also be handed one directly.
42
+ self.data = df_to_records(self.data)
35
43
  tmp = TmpFile()
36
44
  async with tmp.open_buffer() as afp:
37
45
  writer = AsyncDictWriter(afp, self.columns, restval="NULL", quoting=csv.QUOTE_NONE, delimiter='\t', skipinitialspace=True)
@@ -299,12 +299,17 @@ def drop_duplicates(df: pd.DataFrame, columns: Optional[list] = None, **kwargs):
299
299
  :return: The DataFrame with duplicates dropped.
300
300
  """
301
301
  if columns and isinstance(columns, list):
302
- # NOTE: do not ``set_index(columns, drop=False)`` here — it leaves the
303
- # same names as both an index level and a column, which makes the
304
- # subsequent ``sort_values(by=columns)`` raise "is both an index level
305
- # and a column label, which is ambiguous". Sorting on the columns
306
- # directly keeps ``keep='first'`` deterministic without that clash.
307
- df = df.sort_values(by=columns).drop_duplicates(subset=columns, **kwargs)
302
+ # NOTE: do NOT sort before dropping. ``sort_values(by=columns)`` is
303
+ # unnecessary for ``keep='first'`` (drop_duplicates already keeps the
304
+ # first occurrence in the DataFrame's existing order) and it is fragile:
305
+ # with a multi-column subset, if any column holds mixed/unorderable
306
+ # values (e.g. an object column mixing str and NaN, or ints and str),
307
+ # ``sort_values`` raises ``TypeError: '<' not supported between
308
+ # instances of ...`` — which the Filter operator swallows, so the rows
309
+ # are never de-duplicated and the downstream upsert then fails with a
310
+ # CardinalityViolation. Dropping directly on the subset is order-stable
311
+ # and type-agnostic.
312
+ df = df.drop_duplicates(subset=columns, **kwargs)
308
313
  return df
309
314
 
310
315
 
@@ -0,0 +1,41 @@
1
+ """
2
+ DataFrame helpers.
3
+
4
+ Shared normalisation used by the ``iter`` output format and by the row-oriented
5
+ writers, so a pandas-backed provider (``bigquery``, ``deltatbl``, ``iceberg``)
6
+ and a plain ``list[dict]`` provider hand the same shape downstream.
7
+ """
8
+ from typing import Any
9
+
10
+
11
+ def is_dataframe(data: Any) -> bool:
12
+ """Duck-typed check for a pandas-like DataFrame.
13
+
14
+ Avoids importing pandas just to test the type, matching the check already
15
+ used by :meth:`querysource.outputs.writers.abstract.AbstractWriter.get_buffer`.
16
+
17
+ Args:
18
+ data: Object to inspect.
19
+
20
+ Returns:
21
+ bool: True when *data* exposes both ``to_dict`` and ``columns``.
22
+ """
23
+ return hasattr(data, 'to_dict') and hasattr(data, 'columns')
24
+
25
+
26
+ def df_to_records(df: Any) -> list[dict]:
27
+ """Convert a DataFrame into a list of row dictionaries.
28
+
29
+ Iterating a DataFrame yields its *column names*, not its rows, so any
30
+ consumer expecting an iterable of mappings (``csv.DictWriter``,
31
+ ``aiocsv.AsyncDictWriter``, Jinja2 report templates) silently receives
32
+ garbage. Missing values (``NaN``/``NaT``/``pandas.NA``) become ``None`` so
33
+ they serialise as empty/null instead of the string ``"nan"``.
34
+
35
+ Args:
36
+ df: A pandas DataFrame (or DataFrame-like object).
37
+
38
+ Returns:
39
+ list[dict]: One dictionary per row, keyed by column name.
40
+ """
41
+ return df.astype(object).where(df.notna(), None).to_dict(orient='records')
@@ -6,7 +6,7 @@ __description__ = (
6
6
  'QuerySource Query parser and generator.'
7
7
  'Supports SQL, NoSQL, MongoDB, Cassandra, Elasticsearch, etc.'
8
8
  )
9
- __version__ = '4.5.13'
9
+ __version__ = '4.5.15'
10
10
  __url__ = 'https://github.com/phenobarbital/querysource'
11
11
  __copyright__ = 'Copyright (c) 2018-2025 Jesus Lara'
12
12
  __author__ = 'Jesus Lara'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: querysource
3
- Version: 4.5.13
3
+ Version: 4.5.15
4
4
  Summary: Aiohttp web service for querying several databases easily
5
5
  Author-email: Jesus Lara <jesuslarag@gmail.com>
6
6
  License: BSD-3-Clause
@@ -37,7 +37,6 @@ Requires-Dist: oauth2client>=4.1.3
37
37
  Requires-Dist: google-analytics-data>=0.18.15
38
38
  Requires-Dist: google-api-python-client>=2.151.0
39
39
  Requires-Dist: google-auth-oauthlib==1.2.1
40
- Requires-Dist: sqloxide==0.1.39
41
40
  Requires-Dist: aiocsv>=1.3.2
42
41
  Requires-Dist: lxml>=5.3.0
43
42
  Requires-Dist: xlsxwriter==3.2.0
@@ -66,6 +66,8 @@ tox.ini
66
66
  .github/workflows/codeql-analysis.yml
67
67
  .github/workflows/release.yml
68
68
  .jupyter/jupyter_notebook_config.py
69
+ .parrot/wiki.json
70
+ .parrot/wiki.local.json
69
71
  bin/README.md
70
72
  generated/AirtableSource.json
71
73
  generated/Concat.json
@@ -469,6 +471,7 @@ querysource/types/dt/filters.py
469
471
  querysource/types/dt/transforms.py
470
472
  querysource/utils/__init__.py
471
473
  querysource/utils/cache_serialization.py
474
+ querysource/utils/dataframes.py
472
475
  querysource/utils/errors.py
473
476
  querysource/utils/events.py
474
477
  querysource/utils/fn.py
@@ -539,6 +542,7 @@ tests/test_elastic_parser.py
539
542
  tests/test_error_formatter.py
540
543
  tests/test_eval.py
541
544
  tests/test_feat102_error_redaction.py
545
+ tests/test_filters_drop_duplicates.py
542
546
  tests/test_grouping_sync.py
543
547
  tests/test_info_eda.py
544
548
  tests/test_info_eda_e2e.py
@@ -597,6 +601,7 @@ tests/handlers/test_queryexecutor_pbac_smoke.py
597
601
  tests/handlers/test_querymanager_pagination.py
598
602
  tests/handlers/test_queryservice_pbac_smoke.py
599
603
  tests/integration/__init__.py
604
+ tests/integration/test_csv_stream_response.py
600
605
  tests/integration/test_datasource_endpoint.py
601
606
  tests/integration/test_multiquery_output_errors.py
602
607
  tests/integration/test_pbac_credentials.py
@@ -620,10 +625,12 @@ tests/scheduler/test_parse_trigger_shorthands.py
620
625
  tests/scheduler/test_shorthand_loaders.py
621
626
  tests/services/__init__.py
622
627
  tests/services/test_querysource_setup_pbac.py
628
+ tests/unit/test_csv_writer_dataframe.py
623
629
  tests/unit/test_cython_filter_fallback.py
624
630
  tests/unit/test_datasource_redaction.py
625
631
  tests/unit/test_error_payload.py
626
632
  tests/unit/test_handler_output_status.py
633
+ tests/unit/test_iter_format_dataframe.py
627
634
  tests/unit/test_multiqs_output_raise.py
628
635
  tests/unit/test_output_error.py
629
636
  tests/unit/test_provider_raw_query_validated.py
@@ -6,7 +6,6 @@ oauth2client>=4.1.3
6
6
  google-analytics-data>=0.18.15
7
7
  google-api-python-client>=2.151.0
8
8
  google-auth-oauthlib==1.2.1
9
- sqloxide==0.1.39
10
9
  aiocsv>=1.3.2
11
10
  lxml>=5.3.0
12
11
  xlsxwriter==3.2.0
@@ -47,6 +47,8 @@
47
47
  ".gitignore",
48
48
  ".isort.cfg",
49
49
  ".jupyter/jupyter_notebook_config.py",
50
+ ".parrot/wiki.json",
51
+ ".parrot/wiki.local.json",
50
52
  ".pre-commit-config.yaml",
51
53
  ".pylintrc",
52
54
  "CHANGES.rst",
@@ -463,6 +465,7 @@
463
465
  "querysource/types/validators.pyx",
464
466
  "querysource/utils/__init__.py",
465
467
  "querysource/utils/cache_serialization.py",
468
+ "querysource/utils/dataframes.py",
466
469
  "querysource/utils/errors.py",
467
470
  "querysource/utils/events.py",
468
471
  "querysource/utils/fn.py",
@@ -853,6 +856,7 @@
853
856
  "tests/handlers/test_querymanager_pagination.py",
854
857
  "tests/handlers/test_queryservice_pbac_smoke.py",
855
858
  "tests/integration/__init__.py",
859
+ "tests/integration/test_csv_stream_response.py",
856
860
  "tests/integration/test_datasource_endpoint.py",
857
861
  "tests/integration/test_multiquery_output_errors.py",
858
862
  "tests/integration/test_pbac_credentials.py",
@@ -907,6 +911,7 @@
907
911
  "tests/test_error_formatter.py",
908
912
  "tests/test_eval.py",
909
913
  "tests/test_feat102_error_redaction.py",
914
+ "tests/test_filters_drop_duplicates.py",
910
915
  "tests/test_grouping_sync.py",
911
916
  "tests/test_info_eda.py",
912
917
  "tests/test_info_eda_e2e.py",
@@ -947,10 +952,12 @@
947
952
  "tests/test_thread_source_base.py",
948
953
  "tests/test_threadquery_executor.py",
949
954
  "tests/test_zammad_search.py",
955
+ "tests/unit/test_csv_writer_dataframe.py",
950
956
  "tests/unit/test_cython_filter_fallback.py",
951
957
  "tests/unit/test_datasource_redaction.py",
952
958
  "tests/unit/test_error_payload.py",
953
959
  "tests/unit/test_handler_output_status.py",
960
+ "tests/unit/test_iter_format_dataframe.py",
954
961
  "tests/unit/test_multiqs_output_raise.py",
955
962
  "tests/unit/test_output_error.py",
956
963
  "tests/unit/test_provider_raw_query_validated.py",
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "4.5.15",
3
+ "distance": 0,
4
+ "node": "g33895edcdbbdcf345220a28cb04c608a24524c37",
5
+ "dirty": false,
6
+ "branch": "HEAD",
7
+ "node_date": "2026-09-14"
8
+ }
@@ -0,0 +1,36 @@
1
+ """Verify full CSV responses do not advertise partial byte ranges."""
2
+
3
+ import pytest
4
+ from aiohttp import web
5
+ from aiohttp.test_utils import TestClient, TestServer
6
+
7
+ from querysource.outputs.output import DataOutput
8
+
9
+
10
+ @pytest.mark.asyncio
11
+ @pytest.mark.parametrize("body_size", [421, 16384, 16385, 32769])
12
+ async def test_full_csv_stream_has_no_content_range(body_size: int) -> None:
13
+ value = "x" * (body_size - len(b"name\r\n\r\n"))
14
+ expected = f"name\r\n{value}\r\n".encode("utf-8")
15
+
16
+ async def handler(request: web.Request) -> web.StreamResponse:
17
+ output = DataOutput(
18
+ request,
19
+ query=[{"name": value}],
20
+ ctype="csv",
21
+ slug="pokemon_warehouse_list_count",
22
+ writer_options={"delimiter": ",", "quoting": "minimal"},
23
+ )
24
+ return await output.response()
25
+
26
+ app = web.Application()
27
+ app.router.add_get("/csv", handler)
28
+ async with TestClient(TestServer(app)) as client:
29
+ async with client.get(
30
+ "/csv", headers={"Accept-Encoding": "gzip, deflate, br"}
31
+ ) as response:
32
+ assert response.status == 200
33
+ assert response.content_type == "text/csv"
34
+ assert response.content_length == body_size
35
+ assert await response.read() == expected
36
+ assert "Content-Range" not in response.headers
@@ -0,0 +1,55 @@
1
+ """Regression tests for filters.drop_duplicates (multi-column, order-stable).
2
+
3
+ Background: drop_duplicates previously did
4
+ ``df.sort_values(by=columns).drop_duplicates(subset=columns, ...)``. The
5
+ ``sort_values`` is unnecessary for ``keep='first'`` (drop_duplicates already
6
+ keeps the first occurrence in the frame's existing order) and is fragile on a
7
+ multi-column subset when a column holds mixed/unorderable values. The Filter
8
+ operator swallows the resulting error, so the rows are never de-duplicated and
9
+ the downstream upsert fails with a CardinalityViolation.
10
+
11
+ These tests pin the intended behaviour: de-duplicate on the *combination* of
12
+ the given columns, keep the first occurrence, and preserve the original order.
13
+ """
14
+ import numpy as np
15
+ import pandas as pd
16
+
17
+ from querysource.types.dt.filters import drop_duplicates
18
+
19
+
20
+ def test_multicolumn_dedups_on_combination():
21
+ df = pd.DataFrame({
22
+ "user": ["u1", "u1", "u2", "u2", "u3"],
23
+ "content_id": [5, 5, 7, 8, 9], # (u1,5) is the only real duplicate
24
+ })
25
+ out = drop_duplicates(df, columns=["user", "content_id"], keep="first")
26
+ # 5 rows, one duplicate pair (u1,5) collapses -> 4 unique combinations
27
+ assert len(out) == 4
28
+ assert out.duplicated(subset=["user", "content_id"]).sum() == 0
29
+
30
+
31
+ def test_keep_first_preserves_original_order():
32
+ df = pd.DataFrame({
33
+ "user": ["b", "a", "b", "a"],
34
+ "content_id": [2, 1, 2, 1], # rows 2 and 3 duplicate rows 0 and 1
35
+ })
36
+ out = drop_duplicates(df, columns=["user", "content_id"], keep="first")
37
+ # first occurrences kept, in their original order (b,2) then (a,1)
38
+ assert list(zip(out["user"], out["content_id"])) == [("b", 2), ("a", 1)]
39
+
40
+
41
+ def test_multicolumn_with_mixed_and_null_values_does_not_raise():
42
+ # An object column mixing ints, strings and NaN must not blow up the dedup.
43
+ df = pd.DataFrame({
44
+ "user": ["u1", "u1", "u2", "u2"],
45
+ "content_id": [10, 10, np.nan, "abc"],
46
+ })
47
+ out = drop_duplicates(df, columns=["user", "content_id"], keep="first")
48
+ # only (u1,10) repeats -> 3 rows remain
49
+ assert len(out) == 3
50
+
51
+
52
+ def test_single_column_still_works():
53
+ df = pd.DataFrame({"user": ["u1", "u1", "u2"], "content_id": [1, 2, 3]})
54
+ out = drop_duplicates(df, columns=["user"], keep="first")
55
+ assert len(out) == 2 # one row per user
@@ -0,0 +1,82 @@
1
+ """CSVWriter / TSVWriter must serialise a pandas DataFrame row by row and must
2
+ not swallow writer exceptions.
3
+
4
+ Regression: slugs served by pandas-backed providers (bigquery, deltatbl,
5
+ iceberg) exported as ``:csv`` returned HTTP 200 with only the header line —
6
+ ``writerows(DataFrame)`` iterated column names, raised ``AttributeError`` and
7
+ ``TmpFile.__aexit__`` (returning ``self``) suppressed it.
8
+ """
9
+ import pandas
10
+ import pytest
11
+
12
+ from querysource.outputs.writers.csv import CSVWriter, TmpFile
13
+ from querysource.outputs.writers.tsv import TSVWriter
14
+
15
+
16
+ class _Req:
17
+ headers = {}
18
+
19
+
20
+ class _Resp:
21
+ def __init__(self):
22
+ self.headers = {}
23
+ self.content_length = None
24
+
25
+
26
+ def _writer(cls, **kwargs):
27
+ writer = cls(
28
+ request=_Req(), resultset=[{"x": 1}], filename="slug",
29
+ response_type="stream", download=False, compression="gzip",
30
+ ctype=cls.ctype, **kwargs,
31
+ )
32
+
33
+ async def fake_response(response_type):
34
+ return _Resp()
35
+
36
+ async def fake_stream(response, data):
37
+ return data
38
+
39
+ writer.response = fake_response
40
+ writer.stream_response = fake_stream
41
+ return writer
42
+
43
+
44
+ DF = pandas.DataFrame([{"a": 1, "b": "x"}, {"a": 2, "b": None}])
45
+
46
+
47
+ async def test_csv_dataframe_writes_every_row():
48
+ writer = _writer(CSVWriter, delimiter=",", quoting="string")
49
+ writer.data = DF
50
+ out = await writer.get_response()
51
+ lines = out.decode().splitlines()
52
+ assert lines == ['"a","b"', '1,"x"', '2,""']
53
+
54
+
55
+ async def test_tsv_dataframe_writes_every_row():
56
+ writer = _writer(TSVWriter)
57
+ writer.data = DF
58
+ out = await writer.get_response()
59
+ lines = out.decode().splitlines()
60
+ assert lines == ["a\tb", "1\tx", "2\t"]
61
+
62
+
63
+ async def test_csv_list_of_dicts_unchanged():
64
+ writer = _writer(CSVWriter, delimiter=",", quoting="string")
65
+ writer.data = DF.to_dict(orient="records")
66
+ out = await writer.get_response()
67
+ assert out.decode().splitlines()[1] == '1,"x"'
68
+
69
+
70
+ async def test_writer_errors_are_not_swallowed():
71
+ writer = _writer(CSVWriter, delimiter=",", quoting="string")
72
+ writer.data = ["not-a-mapping"]
73
+ writer.columns = ["a"]
74
+ with pytest.raises(AttributeError):
75
+ await writer.get_response()
76
+
77
+
78
+ async def test_tmpfile_propagates_exceptions():
79
+ tmp = TmpFile()
80
+ with pytest.raises(RuntimeError):
81
+ async with tmp.open_buffer():
82
+ raise RuntimeError("boom")