ingestr 0.13.79__tar.gz → 0.13.80__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.
Potentially problematic release.
This version of ingestr might be problematic. Click here for more details.
- {ingestr-0.13.79 → ingestr-0.13.80}/PKG-INFO +1 -1
- ingestr-0.13.80/ingestr/src/buildinfo.py +1 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/facebook_ads/__init__.py +6 -1
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/facebook_ads/helpers.py +1 -1
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/linear/__init__.py +61 -43
- ingestr-0.13.80/ingestr/src/linear/helpers.py +55 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/sources.py +108 -1
- ingestr-0.13.79/ingestr/src/buildinfo.py +0 -1
- ingestr-0.13.79/ingestr/src/linear/helpers.py +0 -72
- {ingestr-0.13.79 → ingestr-0.13.80}/.dlt/config.toml +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/.dockerignore +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/.githooks/pre-commit-hook.sh +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/.github/workflows/deploy-docs.yml +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/.github/workflows/release.yml +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/.github/workflows/secrets-scan.yml +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/.github/workflows/tests.yml +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/.gitignore +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/.gitleaksignore +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/.python-version +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/.vale.ini +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/Dockerfile +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/LICENSE.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/Makefile +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/README.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/.vitepress/config.mjs +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/.vitepress/theme/custom.css +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/.vitepress/theme/index.js +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/commands/example-uris.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/commands/ingest.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/getting-started/core-concepts.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/getting-started/incremental-loading.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/getting-started/quickstart.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/getting-started/telemetry.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/index.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/media/applovin_max.png +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/media/athena.png +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/media/clickhouse_img.png +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/media/clickup_ingestion.png +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/media/cratedb-destination.png +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/media/cratedb-source.png +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/media/freshdesk_ingestion.png +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/media/gcp_spanner_ingestion.png +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/media/github.png +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/media/google_analytics_realtime_report.png +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/media/googleanalytics.png +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/media/ingestion_elasticsearch_img.png +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/media/kinesis.bigquery.png +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/media/linear.png +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/media/linkedin_ads.png +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/media/mixpanel_ingestion.png +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/media/personio.png +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/media/personio_duckdb.png +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/media/phantombuster.png +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/media/pipedrive.png +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/media/quickbook_ingestion.png +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/media/sftp.png +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/media/stripe_postgres.png +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/media/tiktok.png +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/media/zoom_ingestion.png +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/adjust.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/airtable.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/applovin.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/applovin_max.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/appsflyer.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/appstore.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/asana.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/athena.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/attio.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/bigquery.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/chess.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/clickhouse.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/clickup.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/cratedb.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/csv.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/custom_queries.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/databricks.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/db2.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/duckdb.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/dynamodb.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/elasticsearch.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/facebook-ads.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/frankfurter.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/freshdesk.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/gcs.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/github.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/google-ads.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/google_analytics.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/gorgias.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/gsheets.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/hubspot.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/influxdb.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/isoc-pulse.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/kafka.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/kinesis.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/klaviyo.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/linear.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/linkedin_ads.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/mixpanel.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/mongodb.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/motherduck.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/mssql.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/mysql.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/notion.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/oracle.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/personio.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/phantombuster.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/pinterest.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/pipedrive.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/postgres.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/quickbooks.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/redshift.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/s3.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/salesforce.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/sap-hana.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/sftp.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/shopify.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/slack.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/smartsheets.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/snowflake.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/solidgate.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/spanner.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/sqlite.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/stripe.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/tiktok-ads.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/trustpilot.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/zendesk.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/supported-sources/zoom.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/tutorials/load-kinesis-bigquery.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/tutorials/load-personio-duckdb.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/docs/tutorials/load-stripe-postgres.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/conftest.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/main.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/.gitignore +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/adjust/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/adjust/adjust_helpers.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/airtable/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/applovin/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/applovin_max/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/appsflyer/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/appsflyer/client.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/appstore/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/appstore/client.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/appstore/errors.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/appstore/models.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/appstore/resources.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/arrow/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/asana_source/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/asana_source/helpers.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/asana_source/settings.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/attio/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/attio/helpers.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/blob.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/chess/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/chess/helpers.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/chess/settings.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/clickup/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/clickup/helpers.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/collector/spinner.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/destinations.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/dynamodb/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/elasticsearch/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/errors.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/facebook_ads/exceptions.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/facebook_ads/settings.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/facebook_ads/utils.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/factory.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/filesystem/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/filesystem/helpers.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/filesystem/readers.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/filters.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/frankfurter/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/frankfurter/helpers.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/freshdesk/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/freshdesk/freshdesk_client.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/freshdesk/settings.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/github/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/github/helpers.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/github/queries.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/github/settings.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/google_ads/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/google_ads/field.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/google_ads/metrics.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/google_ads/predicates.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/google_ads/reports.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/google_analytics/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/google_analytics/helpers.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/google_sheets/README.md +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/google_sheets/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/google_sheets/helpers/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/google_sheets/helpers/api_calls.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/google_sheets/helpers/data_processing.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/gorgias/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/gorgias/helpers.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/http_client.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/hubspot/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/hubspot/helpers.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/hubspot/settings.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/influxdb/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/influxdb/client.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/isoc_pulse/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/kafka/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/kafka/helpers.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/kinesis/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/kinesis/helpers.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/klaviyo/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/klaviyo/client.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/klaviyo/helpers.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/linkedin_ads/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/linkedin_ads/dimension_time_enum.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/linkedin_ads/helpers.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/loader.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/mixpanel/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/mixpanel/client.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/mongodb/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/mongodb/helpers.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/notion/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/notion/helpers/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/notion/helpers/client.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/notion/helpers/database.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/notion/settings.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/partition.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/personio/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/personio/helpers.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/phantombuster/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/phantombuster/client.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/pinterest/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/pipedrive/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/pipedrive/helpers/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/pipedrive/helpers/custom_fields_munger.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/pipedrive/helpers/pages.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/pipedrive/settings.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/pipedrive/typing.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/quickbooks/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/resource.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/salesforce/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/salesforce/helpers.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/shopify/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/shopify/exceptions.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/shopify/helpers.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/shopify/settings.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/slack/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/slack/helpers.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/slack/settings.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/smartsheets/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/solidgate/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/solidgate/helpers.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/sql_database/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/sql_database/callbacks.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/stripe_analytics/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/stripe_analytics/helpers.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/stripe_analytics/settings.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/table_definition.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/telemetry/event.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/testdata/fakebqcredentials.json +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/tiktok_ads/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/tiktok_ads/tiktok_helpers.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/time.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/trustpilot/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/trustpilot/client.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/version.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/zendesk/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/zendesk/helpers/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/zendesk/helpers/api_helpers.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/zendesk/helpers/credentials.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/zendesk/helpers/talk_api.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/zendesk/settings.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/zoom/__init__.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/src/zoom/helpers.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/testdata/.gitignore +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/testdata/create_replace.csv +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/testdata/delete_insert_expected.csv +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/testdata/delete_insert_part1.csv +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/testdata/delete_insert_part2.csv +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/testdata/merge_expected.csv +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/testdata/merge_part1.csv +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/testdata/merge_part2.csv +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/ingestr/tests/unit/test_smartsheets.py +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/package-lock.json +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/package.json +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/pyproject.toml +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/requirements-dev.txt +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/requirements.in +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/requirements.txt +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/requirements_arm64.txt +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/resources/demo.gif +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/resources/demo.tape +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/resources/ingestr.svg +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/styles/Google/AMPM.yml +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/styles/Google/Acronyms.yml +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/styles/Google/Colons.yml +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/styles/Google/Contractions.yml +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/styles/Google/DateFormat.yml +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/styles/Google/Ellipses.yml +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/styles/Google/EmDash.yml +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/styles/Google/Exclamation.yml +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/styles/Google/FirstPerson.yml +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/styles/Google/Gender.yml +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/styles/Google/GenderBias.yml +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/styles/Google/HeadingPunctuation.yml +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/styles/Google/Headings.yml +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/styles/Google/Latin.yml +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/styles/Google/LyHyphens.yml +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/styles/Google/OptionalPlurals.yml +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/styles/Google/Ordinal.yml +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/styles/Google/OxfordComma.yml +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/styles/Google/Parens.yml +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/styles/Google/Passive.yml +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/styles/Google/Periods.yml +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/styles/Google/Quotes.yml +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/styles/Google/Ranges.yml +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/styles/Google/Semicolons.yml +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/styles/Google/Slang.yml +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/styles/Google/Spacing.yml +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/styles/Google/Spelling.yml +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/styles/Google/Units.yml +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/styles/Google/We.yml +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/styles/Google/Will.yml +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/styles/Google/WordList.yml +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/styles/Google/meta.json +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/styles/Google/vocab.txt +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/styles/bruin/Ingestr.yml +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/styles/config/vocabularies/bruin/accept.txt +0 -0
- {ingestr-0.13.79 → ingestr-0.13.80}/test.env.template +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ingestr
|
|
3
|
-
Version: 0.13.
|
|
3
|
+
Version: 0.13.80
|
|
4
4
|
Summary: ingestr is a command-line application that ingests data from various sources and stores them in any database.
|
|
5
5
|
Project-URL: Homepage, https://github.com/bruin-data/ingestr
|
|
6
6
|
Project-URL: Issues, https://github.com/bruin-data/ingestr/issues
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
version = "v0.13.80"
|
|
@@ -117,6 +117,9 @@ def facebook_insights_source(
|
|
|
117
117
|
app_api_version: str = None,
|
|
118
118
|
start_date: pendulum.DateTime | None = None,
|
|
119
119
|
end_date: pendulum.DateTime | None = None,
|
|
120
|
+
insights_max_wait_to_finish_seconds: int = 60 * 60 * 4,
|
|
121
|
+
insights_max_wait_to_start_seconds: int = 60 * 30,
|
|
122
|
+
insights_max_async_sleep_seconds: int = 20,
|
|
120
123
|
) -> DltResource:
|
|
121
124
|
"""Incrementally loads insight reports with defined granularity level, fields, breakdowns etc.
|
|
122
125
|
|
|
@@ -206,7 +209,9 @@ def facebook_insights_source(
|
|
|
206
209
|
}
|
|
207
210
|
job = execute_job(
|
|
208
211
|
account.get_insights(params=query, is_async=True),
|
|
209
|
-
insights_max_async_sleep_seconds=
|
|
212
|
+
insights_max_async_sleep_seconds=insights_max_async_sleep_seconds,
|
|
213
|
+
insights_max_wait_to_finish_seconds=insights_max_wait_to_finish_seconds,
|
|
214
|
+
insights_max_wait_to_start_seconds=insights_max_wait_to_start_seconds,
|
|
210
215
|
)
|
|
211
216
|
output = list(map(process_report_item, job.get_result()))
|
|
212
217
|
yield output
|
|
@@ -3,7 +3,22 @@ from typing import Any, Dict, Iterable, Iterator
|
|
|
3
3
|
import dlt
|
|
4
4
|
import pendulum
|
|
5
5
|
|
|
6
|
-
from .helpers import
|
|
6
|
+
from .helpers import _paginate, normalize_dictionaries
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def _get_date_range(updated_at, start_date):
|
|
10
|
+
"""Extract current start and end dates from incremental state."""
|
|
11
|
+
if updated_at.last_value:
|
|
12
|
+
current_start_date = pendulum.parse(updated_at.last_value)
|
|
13
|
+
else:
|
|
14
|
+
current_start_date = pendulum.parse(start_date)
|
|
15
|
+
|
|
16
|
+
if updated_at.end_value:
|
|
17
|
+
current_end_date = pendulum.parse(updated_at.end_value)
|
|
18
|
+
else:
|
|
19
|
+
current_end_date = pendulum.now(tz="UTC")
|
|
20
|
+
|
|
21
|
+
return current_start_date, current_end_date
|
|
7
22
|
|
|
8
23
|
ISSUES_QUERY = """
|
|
9
24
|
query Issues($cursor: String) {
|
|
@@ -84,7 +99,25 @@ query Users($cursor: String) {
|
|
|
84
99
|
}
|
|
85
100
|
}
|
|
86
101
|
"""
|
|
87
|
-
|
|
102
|
+
WORKFLOW_STATES_QUERY = """
|
|
103
|
+
query WorkflowStates($cursor: String) {
|
|
104
|
+
workflowStates(first: 50, after: $cursor) {
|
|
105
|
+
nodes {
|
|
106
|
+
archivedAt
|
|
107
|
+
color
|
|
108
|
+
createdAt
|
|
109
|
+
id
|
|
110
|
+
inheritedFrom { id }
|
|
111
|
+
name
|
|
112
|
+
position
|
|
113
|
+
team { id }
|
|
114
|
+
type
|
|
115
|
+
updatedAt
|
|
116
|
+
}
|
|
117
|
+
pageInfo { hasNextPage endCursor }
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
"""
|
|
88
121
|
|
|
89
122
|
@dlt.source(name="linear", max_table_nesting=0)
|
|
90
123
|
def linear_source(
|
|
@@ -102,20 +135,12 @@ def linear_source(
|
|
|
102
135
|
range_end="closed",
|
|
103
136
|
),
|
|
104
137
|
) -> Iterator[Dict[str, Any]]:
|
|
105
|
-
|
|
106
|
-
current_start_date = pendulum.parse(updated_at.last_value)
|
|
107
|
-
else:
|
|
108
|
-
current_start_date = pendulum.parse(start_date)
|
|
109
|
-
|
|
110
|
-
if updated_at.end_value:
|
|
111
|
-
current_end_date = pendulum.parse(updated_at.end_value)
|
|
112
|
-
else:
|
|
113
|
-
current_end_date = pendulum.now(tz="UTC")
|
|
138
|
+
current_start_date, current_end_date = _get_date_range(updated_at, start_date)
|
|
114
139
|
|
|
115
140
|
for item in _paginate(api_key, ISSUES_QUERY, "issues"):
|
|
116
141
|
if pendulum.parse(item["updatedAt"]) >= current_start_date:
|
|
117
142
|
if pendulum.parse(item["updatedAt"]) <= current_end_date:
|
|
118
|
-
yield
|
|
143
|
+
yield normalize_dictionaries(item)
|
|
119
144
|
|
|
120
145
|
@dlt.resource(name="projects", primary_key="id", write_disposition="merge")
|
|
121
146
|
def projects(
|
|
@@ -127,20 +152,12 @@ def linear_source(
|
|
|
127
152
|
range_end="closed",
|
|
128
153
|
),
|
|
129
154
|
) -> Iterator[Dict[str, Any]]:
|
|
130
|
-
|
|
131
|
-
current_start_date = pendulum.parse(updated_at.last_value)
|
|
132
|
-
else:
|
|
133
|
-
current_start_date = pendulum.parse(start_date)
|
|
134
|
-
|
|
135
|
-
if updated_at.end_value:
|
|
136
|
-
current_end_date = pendulum.parse(updated_at.end_value)
|
|
137
|
-
else:
|
|
138
|
-
current_end_date = pendulum.now(tz="UTC")
|
|
155
|
+
current_start_date, current_end_date = _get_date_range(updated_at, start_date)
|
|
139
156
|
|
|
140
157
|
for item in _paginate(api_key, PROJECTS_QUERY, "projects"):
|
|
141
158
|
if pendulum.parse(item["updatedAt"]) >= current_start_date:
|
|
142
159
|
if pendulum.parse(item["updatedAt"]) <= current_end_date:
|
|
143
|
-
yield item
|
|
160
|
+
yield normalize_dictionaries(item)
|
|
144
161
|
|
|
145
162
|
@dlt.resource(name="teams", primary_key="id", write_disposition="merge")
|
|
146
163
|
def teams(
|
|
@@ -153,21 +170,13 @@ def linear_source(
|
|
|
153
170
|
),
|
|
154
171
|
) -> Iterator[Dict[str, Any]]:
|
|
155
172
|
print(start_date)
|
|
156
|
-
|
|
157
|
-
current_start_date = pendulum.parse(updated_at.last_value)
|
|
158
|
-
else:
|
|
159
|
-
current_start_date = pendulum.parse(start_date)
|
|
173
|
+
current_start_date, current_end_date = _get_date_range(updated_at, start_date)
|
|
160
174
|
print(current_start_date)
|
|
161
175
|
|
|
162
|
-
if updated_at.end_value:
|
|
163
|
-
current_end_date = pendulum.parse(updated_at.end_value)
|
|
164
|
-
else:
|
|
165
|
-
current_end_date = pendulum.now(tz="UTC")
|
|
166
|
-
|
|
167
176
|
for item in _paginate(api_key, TEAMS_QUERY, "teams"):
|
|
168
177
|
if pendulum.parse(item["updatedAt"]) >= current_start_date:
|
|
169
178
|
if pendulum.parse(item["updatedAt"]) <= current_end_date:
|
|
170
|
-
yield
|
|
179
|
+
yield normalize_dictionaries(item)
|
|
171
180
|
|
|
172
181
|
@dlt.resource(name="users", primary_key="id", write_disposition="merge")
|
|
173
182
|
def users(
|
|
@@ -179,19 +188,28 @@ def linear_source(
|
|
|
179
188
|
range_end="closed",
|
|
180
189
|
),
|
|
181
190
|
) -> Iterator[Dict[str, Any]]:
|
|
182
|
-
|
|
183
|
-
current_start_date = pendulum.parse(updated_at.last_value)
|
|
184
|
-
else:
|
|
185
|
-
current_start_date = pendulum.parse(start_date)
|
|
186
|
-
|
|
187
|
-
if updated_at.end_value:
|
|
188
|
-
current_end_date = pendulum.parse(updated_at.end_value)
|
|
189
|
-
else:
|
|
190
|
-
current_end_date = pendulum.now(tz="UTC")
|
|
191
|
+
current_start_date, current_end_date = _get_date_range(updated_at, start_date)
|
|
191
192
|
|
|
192
193
|
for item in _paginate(api_key, USERS_QUERY, "users"):
|
|
193
194
|
if pendulum.parse(item["updatedAt"]) >= current_start_date:
|
|
194
195
|
if pendulum.parse(item["updatedAt"]) <= current_end_date:
|
|
195
|
-
yield item
|
|
196
|
+
yield normalize_dictionaries(item)
|
|
197
|
+
|
|
198
|
+
@dlt.resource(name="workflow_states", primary_key="id", write_disposition="merge")
|
|
199
|
+
def workflow_states(
|
|
200
|
+
updated_at: dlt.sources.incremental[str] = dlt.sources.incremental(
|
|
201
|
+
"updatedAt",
|
|
202
|
+
initial_value=start_date.isoformat(),
|
|
203
|
+
end_value=end_date.isoformat() if end_date else None,
|
|
204
|
+
range_start="closed",
|
|
205
|
+
range_end="closed",
|
|
206
|
+
),
|
|
207
|
+
) -> Iterator[Dict[str, Any]]:
|
|
208
|
+
current_start_date, current_end_date = _get_date_range(updated_at, start_date)
|
|
209
|
+
|
|
210
|
+
for item in _paginate(api_key, WORKFLOW_STATES_QUERY, "workflowStates"):
|
|
211
|
+
if pendulum.parse(item["updatedAt"]) >= current_start_date:
|
|
212
|
+
if pendulum.parse(item["updatedAt"]) <= current_end_date:
|
|
213
|
+
yield normalize_dictionaries(item)
|
|
214
|
+
return [issues, projects, teams, users, workflow_states]
|
|
196
215
|
|
|
197
|
-
return issues, projects, teams, users
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
from typing import Any, Dict, Iterator, Optional
|
|
2
|
+
|
|
3
|
+
import requests
|
|
4
|
+
|
|
5
|
+
LINEAR_GRAPHQL_ENDPOINT = "https://api.linear.app/graphql"
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def _graphql(
|
|
9
|
+
api_key: str, query: str, variables: Optional[Dict[str, Any]] = None
|
|
10
|
+
) -> Dict[str, Any]:
|
|
11
|
+
headers = {"Authorization": api_key, "Content-Type": "application/json"}
|
|
12
|
+
response = requests.post(
|
|
13
|
+
LINEAR_GRAPHQL_ENDPOINT,
|
|
14
|
+
json={"query": query, "variables": variables or {}},
|
|
15
|
+
headers=headers,
|
|
16
|
+
)
|
|
17
|
+
response.raise_for_status()
|
|
18
|
+
payload = response.json()
|
|
19
|
+
if "errors" in payload:
|
|
20
|
+
raise ValueError(str(payload["errors"]))
|
|
21
|
+
return payload["data"]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _paginate(api_key: str, query: str, root: str) -> Iterator[Dict[str, Any]]:
|
|
25
|
+
cursor: Optional[str] = None
|
|
26
|
+
while True:
|
|
27
|
+
data = _graphql(api_key, query, {"cursor": cursor})[root]
|
|
28
|
+
for item in data["nodes"]:
|
|
29
|
+
yield item
|
|
30
|
+
if not data["pageInfo"]["hasNextPage"]:
|
|
31
|
+
break
|
|
32
|
+
cursor = data["pageInfo"]["endCursor"]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def normalize_dictionaries(item: Dict[str, Any]) -> Dict[str, Any]:
|
|
38
|
+
"""
|
|
39
|
+
Automatically normalize dictionary fields by detecting their structure:
|
|
40
|
+
- Convert nested objects with 'id' field to {field_name}_id
|
|
41
|
+
- Convert objects with 'nodes' field to arrays
|
|
42
|
+
"""
|
|
43
|
+
normalized_item = item.copy()
|
|
44
|
+
|
|
45
|
+
for key, value in list(normalized_item.items()):
|
|
46
|
+
if isinstance(value, dict):
|
|
47
|
+
# If the dict has an 'id' field, replace with {key}_id
|
|
48
|
+
if 'id' in value:
|
|
49
|
+
normalized_item[f"{key}_id"] = value['id']
|
|
50
|
+
del normalized_item[key]
|
|
51
|
+
# If the dict has 'nodes' field, extract the nodes array
|
|
52
|
+
elif 'nodes' in value:
|
|
53
|
+
normalized_item[key] = value['nodes']
|
|
54
|
+
|
|
55
|
+
return normalized_item
|
|
@@ -702,6 +702,11 @@ class ShopifySource:
|
|
|
702
702
|
return True
|
|
703
703
|
|
|
704
704
|
def dlt_source(self, uri: str, table: str, **kwargs):
|
|
705
|
+
if kwargs.get("incremental_key"):
|
|
706
|
+
raise ValueError(
|
|
707
|
+
"Shopify takes care of incrementality on its own, you should not provide incremental_key"
|
|
708
|
+
)
|
|
709
|
+
|
|
705
710
|
source_fields = urlparse(uri)
|
|
706
711
|
source_params = parse_qs(source_fields.query)
|
|
707
712
|
api_key = source_params.get("api_key")
|
|
@@ -1003,6 +1008,16 @@ class FacebookAdsSource:
|
|
|
1003
1008
|
facebook_insights_source,
|
|
1004
1009
|
)
|
|
1005
1010
|
|
|
1011
|
+
insights_max_wait_to_finish_seconds = source_params.get(
|
|
1012
|
+
"insights_max_wait_to_finish_seconds", [60 * 60 * 4]
|
|
1013
|
+
)
|
|
1014
|
+
insights_max_wait_to_start_seconds = source_params.get(
|
|
1015
|
+
"insights_max_wait_to_start_seconds", [60 * 30]
|
|
1016
|
+
)
|
|
1017
|
+
insights_max_async_sleep_seconds = source_params.get(
|
|
1018
|
+
"insights_max_async_sleep_seconds", [20]
|
|
1019
|
+
)
|
|
1020
|
+
|
|
1006
1021
|
endpoint = None
|
|
1007
1022
|
if table in ["campaigns", "ad_sets", "ad_creatives", "ads", "leads"]:
|
|
1008
1023
|
endpoint = table
|
|
@@ -1012,6 +1027,13 @@ class FacebookAdsSource:
|
|
|
1012
1027
|
account_id=account_id[0],
|
|
1013
1028
|
start_date=kwargs.get("interval_start"),
|
|
1014
1029
|
end_date=kwargs.get("interval_end"),
|
|
1030
|
+
insights_max_wait_to_finish_seconds=insights_max_wait_to_finish_seconds[
|
|
1031
|
+
0
|
|
1032
|
+
],
|
|
1033
|
+
insights_max_wait_to_start_seconds=insights_max_wait_to_start_seconds[
|
|
1034
|
+
0
|
|
1035
|
+
],
|
|
1036
|
+
insights_max_async_sleep_seconds=insights_max_async_sleep_seconds[0],
|
|
1015
1037
|
).with_resources("facebook_insights")
|
|
1016
1038
|
elif table.startswith("facebook_insights:"):
|
|
1017
1039
|
# Parse custom breakdowns and metrics from table name
|
|
@@ -1652,6 +1674,11 @@ class TikTokSource:
|
|
|
1652
1674
|
return True
|
|
1653
1675
|
|
|
1654
1676
|
def dlt_source(self, uri: str, table: str, **kwargs):
|
|
1677
|
+
if kwargs.get("incremental_key"):
|
|
1678
|
+
raise ValueError(
|
|
1679
|
+
"TikTok takes care of incrementality on its own, you should not provide incremental_key"
|
|
1680
|
+
)
|
|
1681
|
+
|
|
1655
1682
|
endpoint = "custom_reports"
|
|
1656
1683
|
|
|
1657
1684
|
parsed_uri = urlparse(uri)
|
|
@@ -1874,6 +1901,11 @@ class GoogleAnalyticsSource:
|
|
|
1874
1901
|
def dlt_source(self, uri: str, table: str, **kwargs):
|
|
1875
1902
|
import ingestr.src.google_analytics.helpers as helpers
|
|
1876
1903
|
|
|
1904
|
+
if kwargs.get("incremental_key"):
|
|
1905
|
+
raise ValueError(
|
|
1906
|
+
"Google Analytics takes care of incrementality on its own, you should not provide incremental_key"
|
|
1907
|
+
)
|
|
1908
|
+
|
|
1877
1909
|
result = helpers.parse_google_analytics_uri(uri)
|
|
1878
1910
|
credentials = result["credentials"]
|
|
1879
1911
|
property_id = result["property_id"]
|
|
@@ -2246,6 +2278,11 @@ class LinkedInAdsSource:
|
|
|
2246
2278
|
return True
|
|
2247
2279
|
|
|
2248
2280
|
def dlt_source(self, uri: str, table: str, **kwargs):
|
|
2281
|
+
if kwargs.get("incremental_key"):
|
|
2282
|
+
raise ValueError(
|
|
2283
|
+
"LinkedIn Ads takes care of incrementality on its own, you should not provide incremental_key"
|
|
2284
|
+
)
|
|
2285
|
+
|
|
2249
2286
|
parsed_uri = urlparse(uri)
|
|
2250
2287
|
source_fields = parse_qs(parsed_uri.query)
|
|
2251
2288
|
|
|
@@ -2329,6 +2366,11 @@ class ClickupSource:
|
|
|
2329
2366
|
return True
|
|
2330
2367
|
|
|
2331
2368
|
def dlt_source(self, uri: str, table: str, **kwargs):
|
|
2369
|
+
if kwargs.get("incremental_key"):
|
|
2370
|
+
raise ValueError(
|
|
2371
|
+
"ClickUp takes care of incrementality on its own, you should not provide incremental_key"
|
|
2372
|
+
)
|
|
2373
|
+
|
|
2332
2374
|
parsed_uri = urlparse(uri)
|
|
2333
2375
|
params = parse_qs(parsed_uri.query)
|
|
2334
2376
|
api_token = params.get("api_token")
|
|
@@ -2413,6 +2455,11 @@ class ApplovinMaxSource:
|
|
|
2413
2455
|
return True
|
|
2414
2456
|
|
|
2415
2457
|
def dlt_source(self, uri: str, table: str, **kwargs):
|
|
2458
|
+
if kwargs.get("incremental_key"):
|
|
2459
|
+
raise ValueError(
|
|
2460
|
+
"AppLovin Max takes care of incrementality on its own, you should not provide incremental_key"
|
|
2461
|
+
)
|
|
2462
|
+
|
|
2416
2463
|
parsed_uri = urlparse(uri)
|
|
2417
2464
|
params = parse_qs(parsed_uri.query)
|
|
2418
2465
|
|
|
@@ -2505,6 +2552,11 @@ class PersonioSource:
|
|
|
2505
2552
|
|
|
2506
2553
|
# applovin://?client_id=123&client_secret=123
|
|
2507
2554
|
def dlt_source(self, uri: str, table: str, **kwargs):
|
|
2555
|
+
if kwargs.get("incremental_key"):
|
|
2556
|
+
raise ValueError(
|
|
2557
|
+
"Personio takes care of incrementality on its own, you should not provide incremental_key"
|
|
2558
|
+
)
|
|
2559
|
+
|
|
2508
2560
|
parsed_uri = urlparse(uri)
|
|
2509
2561
|
params = parse_qs(parsed_uri.query)
|
|
2510
2562
|
|
|
@@ -2595,6 +2647,11 @@ class PipedriveSource:
|
|
|
2595
2647
|
return True
|
|
2596
2648
|
|
|
2597
2649
|
def dlt_source(self, uri: str, table: str, **kwargs):
|
|
2650
|
+
if kwargs.get("incremental_key"):
|
|
2651
|
+
raise ValueError(
|
|
2652
|
+
"Pipedrive takes care of incrementality on its own, you should not provide incremental_key"
|
|
2653
|
+
)
|
|
2654
|
+
|
|
2598
2655
|
parsed_uri = urlparse(uri)
|
|
2599
2656
|
params = parse_qs(parsed_uri.query)
|
|
2600
2657
|
api_key = params.get("api_token")
|
|
@@ -2677,6 +2734,11 @@ class FreshdeskSource:
|
|
|
2677
2734
|
return True
|
|
2678
2735
|
|
|
2679
2736
|
def dlt_source(self, uri: str, table: str, **kwargs):
|
|
2737
|
+
if kwargs.get("incremental_key"):
|
|
2738
|
+
raise ValueError(
|
|
2739
|
+
"Freshdesk takes care of incrementality on its own, you should not provide incremental_key"
|
|
2740
|
+
)
|
|
2741
|
+
|
|
2680
2742
|
parsed_uri = urlparse(uri)
|
|
2681
2743
|
domain = parsed_uri.netloc
|
|
2682
2744
|
query = parsed_uri.query
|
|
@@ -2730,6 +2792,11 @@ class TrustpilotSource:
|
|
|
2730
2792
|
return True
|
|
2731
2793
|
|
|
2732
2794
|
def dlt_source(self, uri: str, table: str, **kwargs):
|
|
2795
|
+
if kwargs.get("incremental_key"):
|
|
2796
|
+
raise ValueError(
|
|
2797
|
+
"Trustpilot takes care of incrementality on its own, you should not provide incremental_key"
|
|
2798
|
+
)
|
|
2799
|
+
|
|
2733
2800
|
parsed_uri = urlparse(uri)
|
|
2734
2801
|
business_unit_id = parsed_uri.netloc
|
|
2735
2802
|
params = parse_qs(parsed_uri.query)
|
|
@@ -2770,6 +2837,11 @@ class PhantombusterSource:
|
|
|
2770
2837
|
return True
|
|
2771
2838
|
|
|
2772
2839
|
def dlt_source(self, uri: str, table: str, **kwargs):
|
|
2840
|
+
if kwargs.get("incremental_key"):
|
|
2841
|
+
raise ValueError(
|
|
2842
|
+
"Phantombuster takes care of incrementality on its own, you should not provide incremental_key"
|
|
2843
|
+
)
|
|
2844
|
+
|
|
2773
2845
|
# phantombuster://?api_key=<api_key>
|
|
2774
2846
|
# source table = phantom_results:agent_id
|
|
2775
2847
|
parsed_uri = urlparse(uri)
|
|
@@ -2923,6 +2995,11 @@ class SolidgateSource:
|
|
|
2923
2995
|
return True
|
|
2924
2996
|
|
|
2925
2997
|
def dlt_source(self, uri: str, table: str, **kwargs):
|
|
2998
|
+
if kwargs.get("incremental_key"):
|
|
2999
|
+
raise ValueError(
|
|
3000
|
+
"Solidgate takes care of incrementality on its own, you should not provide incremental_key"
|
|
3001
|
+
)
|
|
3002
|
+
|
|
2926
3003
|
parsed_uri = urlparse(uri)
|
|
2927
3004
|
query_params = parse_qs(parsed_uri.query)
|
|
2928
3005
|
public_key = query_params.get("public_key")
|
|
@@ -3016,6 +3093,11 @@ class QuickBooksSource:
|
|
|
3016
3093
|
|
|
3017
3094
|
# quickbooks://?company_id=<company_id>&client_id=<client_id>&client_secret=<client_secret>&refresh_token=<refresh>&access_token=<access_token>&environment=<env>&minor_version=<version>
|
|
3018
3095
|
def dlt_source(self, uri: str, table: str, **kwargs):
|
|
3096
|
+
if kwargs.get("incremental_key"):
|
|
3097
|
+
raise ValueError(
|
|
3098
|
+
"QuickBooks takes care of incrementality on its own, you should not provide incremental_key"
|
|
3099
|
+
)
|
|
3100
|
+
|
|
3019
3101
|
parsed_uri = urlparse(uri)
|
|
3020
3102
|
|
|
3021
3103
|
params = parse_qs(parsed_uri.query)
|
|
@@ -3085,6 +3167,11 @@ class IsocPulseSource:
|
|
|
3085
3167
|
return True
|
|
3086
3168
|
|
|
3087
3169
|
def dlt_source(self, uri: str, table: str, **kwargs):
|
|
3170
|
+
if kwargs.get("incremental_key"):
|
|
3171
|
+
raise ValueError(
|
|
3172
|
+
"Internet Society Pulse takes care of incrementality on its own, you should not provide incremental_key"
|
|
3173
|
+
)
|
|
3174
|
+
|
|
3088
3175
|
parsed_uri = urlparse(uri)
|
|
3089
3176
|
params = parse_qs(parsed_uri.query)
|
|
3090
3177
|
token = params.get("token")
|
|
@@ -3120,6 +3207,11 @@ class PinterestSource:
|
|
|
3120
3207
|
return True
|
|
3121
3208
|
|
|
3122
3209
|
def dlt_source(self, uri: str, table: str, **kwargs):
|
|
3210
|
+
if kwargs.get("incremental_key"):
|
|
3211
|
+
raise ValueError(
|
|
3212
|
+
"Pinterest takes care of incrementality on its own, you should not provide incremental_key"
|
|
3213
|
+
)
|
|
3214
|
+
|
|
3123
3215
|
parsed = urlparse(uri)
|
|
3124
3216
|
params = parse_qs(parsed.query)
|
|
3125
3217
|
access_token = params.get("access_token")
|
|
@@ -3154,13 +3246,18 @@ class LinearSource:
|
|
|
3154
3246
|
return True
|
|
3155
3247
|
|
|
3156
3248
|
def dlt_source(self, uri: str, table: str, **kwargs):
|
|
3249
|
+
if kwargs.get("incremental_key"):
|
|
3250
|
+
raise ValueError(
|
|
3251
|
+
"Linear takes care of incrementality on its own, you should not provide incremental_key"
|
|
3252
|
+
)
|
|
3253
|
+
|
|
3157
3254
|
parsed_uri = urlparse(uri)
|
|
3158
3255
|
params = parse_qs(parsed_uri.query)
|
|
3159
3256
|
api_key = params.get("api_key")
|
|
3160
3257
|
if api_key is None:
|
|
3161
3258
|
raise MissingValueError("api_key", "Linear")
|
|
3162
3259
|
|
|
3163
|
-
if table not in ["issues", "projects", "teams", "users"]:
|
|
3260
|
+
if table not in ["issues", "projects", "teams", "users", "workflow_states"]:
|
|
3164
3261
|
raise UnsupportedResourceError(table, "Linear")
|
|
3165
3262
|
|
|
3166
3263
|
start_date = kwargs.get("interval_start")
|
|
@@ -3187,6 +3284,11 @@ class ZoomSource:
|
|
|
3187
3284
|
return True
|
|
3188
3285
|
|
|
3189
3286
|
def dlt_source(self, uri: str, table: str, **kwargs):
|
|
3287
|
+
if kwargs.get("incremental_key"):
|
|
3288
|
+
raise ValueError(
|
|
3289
|
+
"Zoom takes care of incrementality on its own, you should not provide incremental_key"
|
|
3290
|
+
)
|
|
3291
|
+
|
|
3190
3292
|
parsed = urlparse(uri)
|
|
3191
3293
|
params = parse_qs(parsed.query)
|
|
3192
3294
|
client_id = params.get("client_id")
|
|
@@ -3228,6 +3330,11 @@ class InfluxDBSource:
|
|
|
3228
3330
|
return True
|
|
3229
3331
|
|
|
3230
3332
|
def dlt_source(self, uri: str, table: str, **kwargs):
|
|
3333
|
+
if kwargs.get("incremental_key"):
|
|
3334
|
+
raise ValueError(
|
|
3335
|
+
"InfluxDB takes care of incrementality on its own, you should not provide incremental_key"
|
|
3336
|
+
)
|
|
3337
|
+
|
|
3231
3338
|
parsed_uri = urlparse(uri)
|
|
3232
3339
|
params = parse_qs(parsed_uri.query)
|
|
3233
3340
|
host = parsed_uri.hostname
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
version = "v0.13.79"
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
from typing import Any, Dict, Iterator, Optional
|
|
2
|
-
|
|
3
|
-
import requests
|
|
4
|
-
|
|
5
|
-
LINEAR_GRAPHQL_ENDPOINT = "https://api.linear.app/graphql"
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def _graphql(
|
|
9
|
-
api_key: str, query: str, variables: Optional[Dict[str, Any]] = None
|
|
10
|
-
) -> Dict[str, Any]:
|
|
11
|
-
headers = {"Authorization": api_key, "Content-Type": "application/json"}
|
|
12
|
-
response = requests.post(
|
|
13
|
-
LINEAR_GRAPHQL_ENDPOINT,
|
|
14
|
-
json={"query": query, "variables": variables or {}},
|
|
15
|
-
headers=headers,
|
|
16
|
-
)
|
|
17
|
-
response.raise_for_status()
|
|
18
|
-
payload = response.json()
|
|
19
|
-
if "errors" in payload:
|
|
20
|
-
raise ValueError(str(payload["errors"]))
|
|
21
|
-
return payload["data"]
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def _paginate(api_key: str, query: str, root: str) -> Iterator[Dict[str, Any]]:
|
|
25
|
-
cursor: Optional[str] = None
|
|
26
|
-
while True:
|
|
27
|
-
data = _graphql(api_key, query, {"cursor": cursor})[root]
|
|
28
|
-
for item in data["nodes"]:
|
|
29
|
-
yield item
|
|
30
|
-
if not data["pageInfo"]["hasNextPage"]:
|
|
31
|
-
break
|
|
32
|
-
cursor = data["pageInfo"]["endCursor"]
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
def _normalize_issue(item: Dict[str, Any]) -> Dict[str, Any]:
|
|
36
|
-
field_mapping = {
|
|
37
|
-
"assignee": "assignee_id",
|
|
38
|
-
"creator": "creator_id",
|
|
39
|
-
"state": "state_id",
|
|
40
|
-
"cycle": "cycle_id",
|
|
41
|
-
"project": "project_id",
|
|
42
|
-
}
|
|
43
|
-
for key, value in field_mapping.items():
|
|
44
|
-
if item.get(key):
|
|
45
|
-
item[value] = item[key]["id"]
|
|
46
|
-
del item[key]
|
|
47
|
-
else:
|
|
48
|
-
item[value] = None
|
|
49
|
-
del item[key]
|
|
50
|
-
json_fields = [
|
|
51
|
-
"comments",
|
|
52
|
-
"subscribers",
|
|
53
|
-
"attachments",
|
|
54
|
-
"labels",
|
|
55
|
-
"subtasks",
|
|
56
|
-
"projects",
|
|
57
|
-
"memberships",
|
|
58
|
-
"members",
|
|
59
|
-
]
|
|
60
|
-
for field in json_fields:
|
|
61
|
-
if item.get(field):
|
|
62
|
-
item[f"{field}"] = item[field].get("nodes", [])
|
|
63
|
-
|
|
64
|
-
return item
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
def _normalize_team(item: Dict[str, Any]) -> Dict[str, Any]:
|
|
68
|
-
json_fields = ["memberships", "members", "projects"]
|
|
69
|
-
for field in json_fields:
|
|
70
|
-
if item.get(field):
|
|
71
|
-
item[f"{field}"] = item[field].get("nodes", [])
|
|
72
|
-
return item
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|