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.
- querysource-4.5.15/.parrot/wiki.json +29 -0
- querysource-4.5.15/.parrot/wiki.local.json +3 -0
- {querysource-4.5.13 → querysource-4.5.15}/CHANGES.rst +32 -0
- {querysource-4.5.13 → querysource-4.5.15}/Makefile +12 -2
- {querysource-4.5.13 → querysource-4.5.15}/PKG-INFO +1 -2
- {querysource-4.5.13 → querysource-4.5.15}/pyproject.toml +0 -1
- {querysource-4.5.13 → querysource-4.5.15}/querysource/_version.py +3 -3
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/dt/iter.py +6 -1
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/writers/abstract.py +6 -5
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/writers/csv.py +9 -1
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/writers/tsv.py +9 -1
- {querysource-4.5.13 → querysource-4.5.15}/querysource/types/dt/filters.py +11 -6
- querysource-4.5.15/querysource/utils/dataframes.py +41 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/version.py +1 -1
- {querysource-4.5.13 → querysource-4.5.15}/querysource.egg-info/PKG-INFO +1 -2
- {querysource-4.5.13 → querysource-4.5.15}/querysource.egg-info/SOURCES.txt +7 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource.egg-info/requires.txt +0 -1
- {querysource-4.5.13 → querysource-4.5.15}/querysource.egg-info/scm_file_list.json +7 -0
- querysource-4.5.15/querysource.egg-info/scm_version.json +8 -0
- querysource-4.5.15/tests/integration/test_csv_stream_response.py +36 -0
- querysource-4.5.15/tests/test_filters_drop_duplicates.py +55 -0
- querysource-4.5.15/tests/unit/test_csv_writer_dataframe.py +82 -0
- querysource-4.5.15/tests/unit/test_iter_format_dataframe.py +66 -0
- querysource-4.5.13/querysource.egg-info/scm_version.json +0 -8
- {querysource-4.5.13 → querysource-4.5.15}/.agent/rules/async-programming-expert.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.agent/rules/code-reviewer.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.agent/rules/cython-development.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.agent/rules/prompt-expert.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.agent/rules/python-development.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.agent/rules/rust-development.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.agent/workflows/create-parrot-tool.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.agent/workflows/create-workflow.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.agent/workflows/debug-regressions-with-git-bisect-binary-search.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.agent/workflows/generate-tests.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.agent/workflows/git-new-feature.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.agent/workflows/parrot-mcp-server.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.agent/workflows/release_package.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.agent/workflows/start-flow.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.bumpversion.cfg +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.claude/agents/code-reviewer.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.claude/agents/sdd-autopilot.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.claude/agents/sdd-qa.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.claude/agents/sdd-research.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.claude/agents/sdd-worker.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.claude/commands/pr-review.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.claude/commands/sdd-brainstorm.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.claude/commands/sdd-codereview.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.claude/commands/sdd-done.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.claude/commands/sdd-fromjira.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.claude/commands/sdd-next.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.claude/commands/sdd-proposal.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.claude/commands/sdd-spec.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.claude/commands/sdd-start.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.claude/commands/sdd-status.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.claude/commands/sdd-task.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.claude/commands/sdd-tojira.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.claude/rules/aws-cost-optimization.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.claude/rules/code-reviewer.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.claude/rules/cython-development.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.claude/rules/python-development.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.claude/rules/rust-development.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.claude/rules/using-git-worktrees.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.claude/rules/worktree-pr-and-clean.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.claude/rules/worktree-start-feature.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.claude/rules/worktree-status.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.github/dependabot.yml +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.github/workflows/codeql-analysis.yml +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.github/workflows/release.yml +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.isort.cfg +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.jupyter/jupyter_notebook_config.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.pre-commit-config.yaml +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/.pylintrc +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/CODE_OF_CONDUCT.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/CONTRIBUTING.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/INSTALL +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/JOIN_CONDITIONS_FEATURE.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/JOIN_CONDITIONS_SUMMARY.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/LICENSE +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/MANIFEST.in +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/README.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/app.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/bin/README.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/conftest.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/generated/AirtableSource.json +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/generated/Concat.json +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/generated/DWHDestination.json +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/generated/DropCols.json +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/generated/FileSource.json +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/generated/Filter.json +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/generated/FilterCols.json +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/generated/Forecast.json +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/generated/GoogleMaps.json +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/generated/GroupBy.json +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/generated/Info.json +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/generated/Join.json +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/generated/Map.json +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/generated/Melt.json +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/generated/Merge.json +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/generated/NormalizeColumns.json +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/generated/PluckCols.json +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/generated/Query.json +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/generated/S3Source.json +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/generated/SharepointSource.json +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/generated/SmartSheetSource.json +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/generated/Table.json +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/generated/TableDestination.json +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/generated/TableOutput.json +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/generated/TableOutputAdapter.json +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/generated/TableSource.json +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/generated/ToS3.json +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/generated/ToSharepoint.json +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/generated/correlation.json +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/generated/crosstab.json +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/generated/pivot.json +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/generated/tExplode.json +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/generated/tOrder.json +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/generated/tPandas.json +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/gunicorn_config.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/mypy.ini +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/nav.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/policies/HARDENING.md +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/policies/authorized.yaml +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/policies/baseline.yaml +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/policies/datasources.yaml +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/policies/defaults.yaml +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/policies/drivers.yaml +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/policies/raw_queries.yaml +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/policies/slugs.yaml +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/policies/superusers.yaml +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/pytest.ini +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/__cli__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/auth/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/auth/_resource_types.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/auth/credentials.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/auth/pbac.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/cache/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/cache/backends/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/cache/backends/abstract.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/cache/backends/memcache.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/cache/backends/redis.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/cache/base.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/cli/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/cli/generate_docs.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/conf.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/connections.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/abstract.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/arangodb.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/athena.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/bigquery.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/cassandra.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/clickhouse.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/cockroachdb.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/couchbase.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/couchdb.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/countries.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/delta.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/documentdb.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/dynamodb.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/elastic.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/ga.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/gcalc.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/hazel.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/iceberg.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/influx.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/jdbc.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/jira.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/mariadb.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/memcached.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/mongo.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/mysql.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/odbc.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/openweather.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/oracle.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/pg.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/pg_admin.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/postgres.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/py.typed +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/qs.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/redis.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/rest.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/rethink.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/sa.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/salesforce.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/scylladb.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/sqlalchemy.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/sqlite.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/sqlserver.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/upc.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/drivers/zipcodeapi.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/handlers/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/handlers/datasource.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/handlers/utils.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/introspection.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/datasources/models.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/events/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/exceptions.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/handlers/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/handlers/_pagination.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/handlers/abstract.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/handlers/components.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/handlers/executor.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/handlers/integrations/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/handlers/integrations/airtable.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/handlers/log.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/handlers/manager.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/handlers/multi.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/handlers/outputs/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/handlers/outputs/tableOutput/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/handlers/outputs/tableOutput/postgres.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/handlers/outputs/tableOutput/table.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/handlers/scheduler.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/handlers/service.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/handlers/variables.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/interfaces/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/interfaces/airtable.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/interfaces/connections.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/interfaces/credentials.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/interfaces/databases/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/interfaces/databases/abstract.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/interfaces/databases/bigquery.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/interfaces/databases/db.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/interfaces/databases/mongo.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/interfaces/databases/rethink.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/interfaces/http.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/interfaces/playwright_service.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/interfaces/queries.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/interfaces/selenium_service.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/libs/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/libs/encoders.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/libs/functions/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/libs/py.typed +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/models.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/destinations/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/destinations/abstract.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/destinations/dwh.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/destinations/s3.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/destinations/sharepoint.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/destinations/table.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/dt/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/dt/abstract.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/dt/arrow.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/dt/dt.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/dt/factory.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/dt/modin.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/dt/pandas.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/dt/polars.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/output.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/tables/TableOutput/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/tables/TableOutput/abstract.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/tables/TableOutput/bigquery.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/tables/TableOutput/documentdb.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/tables/TableOutput/mongodb.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/tables/TableOutput/mysql.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/tables/TableOutput/postgres.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/tables/TableOutput/rethink.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/tables/TableOutput/sa.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/tables/TableOutput/table.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/tables/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/writers/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/writers/bokeh.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/writers/clustering.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/writers/describe.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/writers/eda.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/writers/excel.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/writers/html.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/writers/json.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/writers/pdf.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/writers/pickle.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/writers/plotly.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/writers/profiling.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/writers/report.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/writers/table.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/writers/txt.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/outputs/writers/xml.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/abstract.c +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/abstract.pxd +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/abstract.pyx +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/arangodb.c +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/arangodb.pxd +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/arangodb.pyx +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/bigquery.c +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/bigquery.pxd +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/bigquery.pyx +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/cql.c +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/cql.pxd +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/cql.pyx +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/deltatbl.c +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/deltatbl.pxd +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/deltatbl.pyx +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/elastic.cpp +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/elastic.pxd +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/elastic.pyx +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/iceberg.c +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/iceberg.pxd +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/iceberg.pyx +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/influx.c +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/influx.pxd +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/influx.pyx +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/mongo.cpp +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/mongo.pxd +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/mongo.pyx +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/parser.c +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/parser.pxd +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/parser.pyx +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/pgsql.c +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/pgsql.pxd +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/pgsql.pyx +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/rethink.c +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/rethink.pxd +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/rethink.pyx +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/sosql.c +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/sosql.pxd +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/sosql.pyx +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/sql.c +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/sql.pxd +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/sql.pyx +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/sqlserver.c +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/sqlserver.pxd +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/parsers/sqlserver.pyx +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/plugins/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/plugins/importer.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/plugins/sources/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/abstract.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/arangodb.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/bigquery.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/cassandra.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/db.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/default.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/deltatbl.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/documentdb.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/dummy.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/elastic.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/external.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/http.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/iceberg.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/influx.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/mysql.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/pg.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/py.typed +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/rest.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/rethink.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/salesforce.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/scylladb.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/abstract.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/amazon.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/countries.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/ga.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/geofcc.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/gmaps.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/graphcountries.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/graphql.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/http.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/hubspot.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/openweather.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/parsers/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/parsers/amproduct.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/parsers/xpath.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/pokemon.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/populartimes.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/py.typed +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/rest.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/retailnext.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/rssapp.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/salesforce.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/scrapper.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/shoppertrack.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/swop.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/uap.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/upc.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/wm_stores.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/zammad.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sources/zipcodeapi.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sql.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/providers/sqlserver.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/py.typed +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/qs_parsers/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/base.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/executor.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/models.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/_introspect.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/abstract.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/components/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/components/abstract.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/destinations/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/destinations/dwh.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/destinations/s3.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/destinations/sharepoint.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/destinations/table.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/operators/Concat.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/operators/GroupBy.catalog.yaml +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/operators/GroupBy.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/operators/Info.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/operators/Join.catalog.yaml +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/operators/Join.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/operators/Melt.catalog.yaml +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/operators/Melt.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/operators/Merge.catalog.yaml +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/operators/Merge.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/operators/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/operators/abstract.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/operators/filter/Filter.catalog.yaml +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/operators/filter/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/operators/filter/flt.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/registry.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/sources/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/sources/airtable.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/sources/base.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/sources/executors.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/sources/file.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/sources/query.catalog.yaml +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/sources/query.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/sources/s3.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/sources/sharepoint.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/sources/smartsheet.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/sources/table.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/DropCols.catalog.yaml +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/DropCols.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/FilterCols.catalog.yaml +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/FilterCols.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/Forecast.catalog.yaml +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/Forecast.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/Map.catalog.yaml +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/Map.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/NormalizeColumns.catalog.yaml +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/NormalizeColumns.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/PluckCols.catalog.yaml +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/PluckCols.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/abstract.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/correlation.catalog.yaml +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/correlation.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/crosstab.catalog.yaml +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/crosstab.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/google/GoogleMaps.catalog.yaml +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/google/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/google/maps.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/pivot.catalog.yaml +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/pivot.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/tExplode.catalog.yaml +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/tExplode.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/tOrder.catalog.yaml +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/tOrder.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/multi/transformations/tPandas.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/obj.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/queries/qs.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/scheduler/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/scheduler/jobs.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/scheduler/notifications.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/scheduler/scheduler.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/services.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/template/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/template/parser.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/types/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/types/converters.cpp +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/types/converters.pyx +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/types/dt/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/types/dt/transforms.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/types/py.typed +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/types/typedefs.c +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/types/typedefs.pyx +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/types/validators.cpp +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/types/validators.pyx +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/utils/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/utils/cache_serialization.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/utils/errors.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/utils/events.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/utils/fn.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/utils/functions.cpp +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/utils/functions.pyx +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/utils/getfunc.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/utils/handlers.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/utils/parseqs.cpp +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/utils/parseqs.pyx +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource/utils/validators.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource.egg-info/dependency_links.txt +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource.egg-info/entry_points.txt +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource.egg-info/not-zip-safe +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/querysource.egg-info/top_level.txt +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/run.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/rust/Cargo.lock +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/rust/Cargo.toml +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/rust/pyproject.toml +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/rust/src/arangodb_parser.rs +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/rust/src/bigquery_parser.rs +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/rust/src/cql_parser.rs +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/rust/src/elastic_parser.rs +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/rust/src/filter_common.rs +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/rust/src/flux_parser.rs +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/rust/src/lib.rs +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/rust/src/mongo_parser.rs +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/rust/src/mssql_parser.rs +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/rust/src/parseqs.rs +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/rust/src/pgsql_parser.rs +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/rust/src/rethink_parser.rs +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/rust/src/safe_dict.rs +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/rust/src/soql_parser.rs +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/rust/src/sql_parser.rs +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/rust/src/validators.rs +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/setup.cfg +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/setup.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/static/notebook/bundle.js +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/templates/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/templates/base.html +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/templates/default.html +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/templates/default_table.html +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/templates/fontlist-v330.json +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/templates/fontlist-v390.json +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/templates/table_charts.html +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/auth/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/auth/test_credentials.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/auth/test_pbac_bootstrap.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/check_concurrent_get_slug.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/conftest.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/datasources/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/datasources/test_datasource_view_pbac.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/datasources/test_driver_factory_session.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/datasources/test_pg_admin_registration.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/datasources/test_pg_params_for.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/handlers/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/handlers/conftest.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/handlers/test_abstract_pbac_helpers.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/handlers/test_airtable_oauth.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/handlers/test_multiquery_pbac_smoke.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/handlers/test_query_param_exclusion.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/handlers/test_queryexecutor_pbac_smoke.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/handlers/test_querymanager_pagination.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/handlers/test_queryservice_pbac_smoke.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/integration/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/integration/test_datasource_endpoint.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/integration/test_multiquery_output_errors.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/integration/test_pbac_credentials.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/integration/test_pbac_enforcement.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/integration/test_pbac_listing.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/integration/test_slug_injection.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/integration/test_slug_regression.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/interfaces/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/interfaces/test_airtable_interface.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/multi/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/multi/sources/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/multi/sources/test_airtable_source.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/multi/sources/test_registry.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/perf/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/perf/test_pbac_overhead.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/policies/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/policies/test_authorized_policy.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/policies/test_default_policies_load.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/scheduler/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/scheduler/test_parse_trigger_shorthands.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/scheduler/test_shorthand_loaders.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/services/__init__.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/services/test_querysource_setup_pbac.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_abstract_multi.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_abstract_refactor.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_api.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_arangodb_parser.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_catalog_colcols.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_catalog_correlation.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_catalog_filter.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_catalog_forecast.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_catalog_googlemaps.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_catalog_groupby.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_catalog_map.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_catalog_pivot.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_catalog_remote.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_catalog_texplode.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_catalog_torder.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_cli_generate_docs.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_column_filters.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_component_handler.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_component_registry.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_conf_airtable.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_destination_base.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_destination_dwh.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_destination_integration.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_destination_s3.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_destination_sharepoint.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_destination_table.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_destinations_documentation_endpoint.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_elastic_parser.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_error_formatter.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_eval.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_feat102_error_redaction.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_grouping_sync.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_info_eda.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_info_eda_e2e.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_info_eda_integration.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_join_conditions.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_join_with_column_filter.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_local_executor.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_multi_destinations_subpackage.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_multiqs_column_transforms.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_multiqs_destination_dispatch.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_multiqs_remote_dispatch.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_multiqs_slug_sources_normalize.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_multiqs_sources_integration.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_queryslug_concurrency.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_querysource_setup_airtable.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_qworker_config.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_remote_executor.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_route_registration.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_rss.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_rust_parsers.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_scheduler_core.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_scheduler_handler_integration.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_scheduler_handler_unit.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_scheduler_integration.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_scheduler_jobs.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_scheduler_multi_routing.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_scheduler_notifications.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_schema_introspectable.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_source_registry.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_source_s3.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_source_sharepoint.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_source_smartsheet.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_source_table.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_sql_parser_combinations.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_texplode.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_thread_file_refactor.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_thread_query_refactor.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_thread_source_base.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_threadquery_executor.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/test_zammad_search.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/unit/test_cython_filter_fallback.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/unit/test_datasource_redaction.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/unit/test_error_payload.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/unit/test_handler_output_status.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/unit/test_multiqs_output_raise.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/unit/test_output_error.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/unit/test_provider_raw_query_validated.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/unit/test_qs_parsers_validated.py +0 -0
- {querysource-4.5.13 → querysource-4.5.15}/tests/unit/test_raw_query_cond_definition_wiring.py +0 -0
- {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
|
+
}
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
|
@@ -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.
|
|
22
|
-
__version_tuple__ = version_tuple = (4, 5,
|
|
21
|
+
__version__ = version = '4.5.15'
|
|
22
|
+
__version_tuple__ = version_tuple = (4, 5, 15)
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
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
|
-
|
|
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
|
-
|
|
309
|
-
|
|
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
|
|
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
|
|
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
|
|
303
|
-
#
|
|
304
|
-
#
|
|
305
|
-
#
|
|
306
|
-
#
|
|
307
|
-
|
|
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.
|
|
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.
|
|
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
|
|
@@ -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,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")
|