ingestr 0.13.50__tar.gz → 0.13.52__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.50 → ingestr-0.13.52}/PKG-INFO +1 -1
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/solidgate.md +3 -2
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/sqlite.md +1 -1
- ingestr-0.13.52/docs/supported-sources/stripe.md +91 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/main.py +19 -2
- ingestr-0.13.52/ingestr/src/buildinfo.py +1 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/destinations.py +12 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/factory.py +4 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/filters.py +14 -0
- ingestr-0.13.52/ingestr/src/http_client.py +24 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/solidgate/__init__.py +33 -3
- ingestr-0.13.52/ingestr/src/solidgate/helpers.py +139 -0
- ingestr-0.13.52/ingestr/src/stripe_analytics/settings.py +73 -0
- ingestr-0.13.50/docs/supported-sources/stripe.md +0 -51
- ingestr-0.13.50/ingestr/src/buildinfo.py +0 -1
- ingestr-0.13.50/ingestr/src/http_client.py +0 -18
- ingestr-0.13.50/ingestr/src/solidgate/helpers.py +0 -74
- ingestr-0.13.50/ingestr/src/stripe_analytics/settings.py +0 -26
- {ingestr-0.13.50 → ingestr-0.13.52}/.dockerignore +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/.githooks/pre-commit-hook.sh +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/.github/workflows/deploy-docs.yml +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/.github/workflows/release.yml +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/.github/workflows/secrets-scan.yml +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/.github/workflows/tests.yml +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/.gitignore +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/.gitleaksignore +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/.python-version +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/.vale.ini +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/Dockerfile +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/LICENSE.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/Makefile +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/README.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/.vitepress/config.mjs +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/.vitepress/theme/custom.css +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/.vitepress/theme/index.js +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/commands/example-uris.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/commands/ingest.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/getting-started/core-concepts.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/getting-started/incremental-loading.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/getting-started/quickstart.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/getting-started/telemetry.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/index.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/media/applovin_max.png +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/media/athena.png +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/media/clickhouse_img.png +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/media/freshdesk_ingestion.png +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/media/gcp_spanner_ingestion.png +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/media/github.png +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/media/google_analytics_realtime_report.png +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/media/googleanalytics.png +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/media/ingestion_elasticsearch_img.png +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/media/kinesis.bigquery.png +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/media/linkedin_ads.png +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/media/personio.png +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/media/personio_duckdb.png +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/media/phantombuster.png +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/media/pipedrive.png +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/media/stripe_postgres.png +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/media/tiktok.png +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/adjust.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/airtable.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/applovin.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/applovin_max.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/appsflyer.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/appstore.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/asana.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/athena.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/attio.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/bigquery.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/chess.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/clickhouse.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/csv.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/custom_queries.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/databricks.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/db2.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/duckdb.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/dynamodb.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/elasticsearch.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/facebook-ads.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/frankfurter.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/freshdesk.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/gcs.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/github.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/google-ads.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/google_analytics.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/gorgias.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/gsheets.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/hubspot.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/kafka.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/kinesis.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/klaviyo.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/linkedin_ads.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/mongodb.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/mssql.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/mysql.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/notion.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/oracle.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/personio.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/phantombuster.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/pipedrive.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/postgres.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/redshift.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/s3.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/salesforce.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/sap-hana.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/shopify.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/slack.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/smartsheets.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/snowflake.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/spanner.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/tiktok-ads.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/supported-sources/zendesk.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/tutorials/load-kinesis-bigquery.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/tutorials/load-personio-duckdb.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/docs/tutorials/load-stripe-postgres.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/conftest.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/.gitignore +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/adjust/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/adjust/adjust_helpers.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/airtable/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/applovin/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/applovin_max/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/appsflyer/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/appsflyer/client.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/appstore/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/appstore/client.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/appstore/errors.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/appstore/models.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/appstore/resources.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/arrow/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/asana_source/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/asana_source/helpers.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/asana_source/settings.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/attio/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/attio/helpers.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/blob.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/chess/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/chess/helpers.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/chess/settings.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/collector/spinner.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/dynamodb/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/elasticsearch/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/errors.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/facebook_ads/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/facebook_ads/exceptions.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/facebook_ads/helpers.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/facebook_ads/settings.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/filesystem/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/filesystem/helpers.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/filesystem/readers.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/frankfurter/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/frankfurter/helpers.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/freshdesk/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/freshdesk/freshdesk_client.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/freshdesk/settings.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/github/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/github/helpers.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/github/queries.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/github/settings.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/google_ads/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/google_ads/field.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/google_ads/metrics.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/google_ads/predicates.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/google_ads/reports.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/google_analytics/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/google_analytics/helpers.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/google_sheets/README.md +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/google_sheets/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/google_sheets/helpers/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/google_sheets/helpers/api_calls.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/google_sheets/helpers/data_processing.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/gorgias/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/gorgias/helpers.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/hubspot/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/hubspot/helpers.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/hubspot/settings.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/kafka/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/kafka/helpers.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/kinesis/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/kinesis/helpers.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/klaviyo/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/klaviyo/client.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/klaviyo/helpers.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/linkedin_ads/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/linkedin_ads/dimension_time_enum.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/linkedin_ads/helpers.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/loader.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/mongodb/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/mongodb/helpers.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/notion/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/notion/helpers/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/notion/helpers/client.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/notion/helpers/database.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/notion/settings.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/partition.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/personio/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/personio/helpers.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/phantombuster/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/phantombuster/client.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/pipedrive/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/pipedrive/helpers/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/pipedrive/helpers/custom_fields_munger.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/pipedrive/helpers/pages.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/pipedrive/settings.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/pipedrive/typing.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/resource.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/salesforce/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/salesforce/helpers.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/shopify/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/shopify/exceptions.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/shopify/helpers.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/shopify/settings.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/slack/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/slack/helpers.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/slack/settings.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/smartsheets/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/sources.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/sql_database/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/sql_database/callbacks.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/stripe_analytics/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/stripe_analytics/helpers.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/table_definition.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/telemetry/event.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/testdata/fakebqcredentials.json +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/tiktok_ads/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/tiktok_ads/tiktok_helpers.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/time.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/version.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/zendesk/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/zendesk/helpers/__init__.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/zendesk/helpers/api_helpers.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/zendesk/helpers/credentials.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/zendesk/helpers/talk_api.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/src/zendesk/settings.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/testdata/.gitignore +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/testdata/create_replace.csv +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/testdata/delete_insert_expected.csv +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/testdata/delete_insert_part1.csv +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/testdata/delete_insert_part2.csv +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/testdata/merge_expected.csv +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/testdata/merge_part1.csv +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/testdata/merge_part2.csv +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/ingestr/tests/unit/test_smartsheets.py +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/package-lock.json +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/package.json +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/pyproject.toml +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/requirements-dev.txt +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/requirements.in +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/requirements.txt +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/requirements_arm64.txt +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/resources/demo.gif +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/resources/demo.tape +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/resources/ingestr.svg +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/styles/Google/AMPM.yml +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/styles/Google/Acronyms.yml +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/styles/Google/Colons.yml +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/styles/Google/Contractions.yml +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/styles/Google/DateFormat.yml +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/styles/Google/Ellipses.yml +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/styles/Google/EmDash.yml +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/styles/Google/Exclamation.yml +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/styles/Google/FirstPerson.yml +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/styles/Google/Gender.yml +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/styles/Google/GenderBias.yml +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/styles/Google/HeadingPunctuation.yml +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/styles/Google/Headings.yml +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/styles/Google/Latin.yml +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/styles/Google/LyHyphens.yml +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/styles/Google/OptionalPlurals.yml +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/styles/Google/Ordinal.yml +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/styles/Google/OxfordComma.yml +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/styles/Google/Parens.yml +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/styles/Google/Passive.yml +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/styles/Google/Periods.yml +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/styles/Google/Quotes.yml +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/styles/Google/Ranges.yml +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/styles/Google/Semicolons.yml +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/styles/Google/Slang.yml +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/styles/Google/Spacing.yml +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/styles/Google/Spelling.yml +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/styles/Google/Units.yml +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/styles/Google/We.yml +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/styles/Google/Will.yml +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/styles/Google/WordList.yml +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/styles/Google/meta.json +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/styles/Google/vocab.txt +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/styles/bruin/Ingestr.yml +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/styles/config/vocabularies/bruin/accept.txt +0 -0
- {ingestr-0.13.50 → ingestr-0.13.52}/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.52
|
|
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
|
|
@@ -39,8 +39,9 @@ The result of this command will be a table in the `Solidgate.duckdb` database wi
|
|
|
39
39
|
|
|
40
40
|
Solidgate source allows ingesting the following sources into separate tables:
|
|
41
41
|
- `subscriptions`: Provides a comprehensive view of customer subscriptions, including subscription IDs, statuses, and key timestamps such as creation, update, and expiration dates.
|
|
42
|
-
- `
|
|
43
|
-
- `
|
|
42
|
+
- `apm_orders`: Provides essential information for anti-fraud purposes, including order IDs, transaction statuses, amounts, currencies, and payment methods, along with crucial customer details such as email addresses.
|
|
43
|
+
- `card_orders`: Provides detailed information on orders processed via card payments, including transaction data, payment status, and customer details.
|
|
44
|
+
- `financial_entries`: Provides a detailed transaction-level breakdown of financial records.
|
|
44
45
|
|
|
45
46
|
Use these as `--source-table` parameter in the `ingestr ingest` command.
|
|
46
47
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# SQLite
|
|
2
2
|
SQLite is a C-language library that implements a small, fast, self-contained, high-reliability, full-featured, SQL database engine.
|
|
3
3
|
|
|
4
|
-
ingestr supports SQLite as a source.
|
|
4
|
+
ingestr supports SQLite as a source and a destination.
|
|
5
5
|
|
|
6
6
|
## URI format
|
|
7
7
|
The URI format for SQLite is as follows:
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Stripe
|
|
2
|
+
|
|
3
|
+
[Stripe](https://www.stripe.com/) is a technology company that builds economic infrastructure for the internet, providing payment processing software and APIs for e-commerce websites and mobile applications.
|
|
4
|
+
|
|
5
|
+
ingestr supports Stripe as a source.
|
|
6
|
+
|
|
7
|
+
## URI format
|
|
8
|
+
|
|
9
|
+
The URI format for Stripe is as follows:
|
|
10
|
+
|
|
11
|
+
```plaintext
|
|
12
|
+
stripe://?api_key=<api-key-here>
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
URI parameters:
|
|
16
|
+
|
|
17
|
+
- `api_key`: the API key used for authentication with the Stripe API
|
|
18
|
+
|
|
19
|
+
The URI is used to connect to the Stripe API for extracting data. More details on setting up Stripe integrations can be found [here](https://stripe.com/docs/api).
|
|
20
|
+
|
|
21
|
+
## Setting up a Stripe Integration
|
|
22
|
+
|
|
23
|
+
Stripe requires a few steps to set up an integration, please follow the guide dltHub [has built here](https://dlthub.com/docs/dlt-ecosystem/verified-sources/stripe#setup-guide).
|
|
24
|
+
|
|
25
|
+
Once you complete the guide, you should have an API key. Let's say your API key is `sk_test_12345`, here's a sample command that will copy the data from Stripe into a DuckDB database:
|
|
26
|
+
|
|
27
|
+
```sh
|
|
28
|
+
ingestr ingest --source-uri 'stripe://?api_key=sk_test_12345' --source-table 'charges' --dest-uri duckdb:///stripe.duckdb --dest-table 'dest.charges'
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The result of this command will be a table in the `stripe.duckdb` database with JSON columns.
|
|
32
|
+
|
|
33
|
+
## Tables
|
|
34
|
+
|
|
35
|
+
Stripe source allows ingesting the following sources into separate tables:
|
|
36
|
+
|
|
37
|
+
### Regular Endpoints
|
|
38
|
+
|
|
39
|
+
- `account`: Contains information about a Stripe account, including balances, payouts, and account settings.
|
|
40
|
+
- `apple_pay_domain`: Represents Apple Pay domains registered with Stripe for processing Apple Pay payments.
|
|
41
|
+
- `application_fee`: Records fees collected by platforms on payments processed through connected accounts.
|
|
42
|
+
- `checkout_session`: Contains data about Checkout sessions created for payment processing workflows.
|
|
43
|
+
- `coupon`: Stores data about discount codes or coupons that can be applied to invoices, subscriptions, or other charges.
|
|
44
|
+
- `customer`: Holds information about customers, such as billing details, payment methods, and associated transactions.
|
|
45
|
+
- `dispute`: Records payment disputes and chargebacks filed by customers or banks.
|
|
46
|
+
- `payment_intent`: Represents payment intents tracking the lifecycle of payments from creation to completion.
|
|
47
|
+
- `payment_link`: Contains information about payment links created for collecting payments.
|
|
48
|
+
- `payment_method`: Stores payment method information such as cards, bank accounts, and other payment instruments.
|
|
49
|
+
- `payment_method_domain`: Represents domains verified for payment method collection.
|
|
50
|
+
- `payout`: Records payouts made from Stripe accounts to bank accounts or debit cards.
|
|
51
|
+
- `plan`: Contains subscription plan information including pricing and billing intervals.
|
|
52
|
+
- `price`: Contains pricing information for products, including currency, amount, and billing intervals.
|
|
53
|
+
- `product`: Represents products that can be sold or subscribed to, including metadata and pricing information.
|
|
54
|
+
- `promotion_code`: Stores data about promotion codes that customers can use to apply coupons.
|
|
55
|
+
- `quote`: Contains quote information for customers, including line items and pricing.
|
|
56
|
+
- `refund`: Records refunds issued for charges, including partial and full refunds.
|
|
57
|
+
- `review`: Contains payment review information for payments flagged by Stripe Radar.
|
|
58
|
+
- `setup_attempt`: Records attempts to set up payment methods for future payments.
|
|
59
|
+
- `setup_intent`: Represents setup intents for collecting payment method information.
|
|
60
|
+
- `shipping_rate`: Contains shipping rate information for orders and invoices.
|
|
61
|
+
- `subscription`: Represents a customer's subscription to a recurring service, detailing billing cycles, plans, and status.
|
|
62
|
+
- `subscription_item`: Contains individual items within a subscription, including quantities and pricing.
|
|
63
|
+
- `subscription_schedule`: Represents scheduled changes to subscriptions over time.
|
|
64
|
+
- `tax_code`: Contains tax code information for products and services.
|
|
65
|
+
- `tax_id`: Stores tax ID information for customers and accounts.
|
|
66
|
+
- `tax_rate`: Contains tax rate information applied to invoices and subscriptions.
|
|
67
|
+
- `top_up`: Records top-ups made to Stripe accounts.
|
|
68
|
+
- `transfer`: Records transfers between Stripe accounts.
|
|
69
|
+
- `webhook_endpoint`: Contains webhook endpoint configurations for receiving event notifications.
|
|
70
|
+
|
|
71
|
+
### Incremental Endpoints
|
|
72
|
+
|
|
73
|
+
The following endpoints support incremental loading, meaning only new or updated records will be fetched:
|
|
74
|
+
|
|
75
|
+
- `application_fee`: Records fees collected by platforms (incremental).
|
|
76
|
+
- `balance_transaction`: Records transactions that affect the Stripe account balance, such as charges, refunds, and payouts.
|
|
77
|
+
- `charge`: Returns a list of charges.
|
|
78
|
+
- `credit_note`: Contains credit note information for refunds and adjustments.
|
|
79
|
+
- `event`: Logs all events in the Stripe account, including customer actions, account updates, and system-generated events.
|
|
80
|
+
- `invoice`: Represents invoices sent to customers, detailing line items, amounts, and payment status.
|
|
81
|
+
- `invoice_item`: Contains individual line items that can be added to invoices.
|
|
82
|
+
- `invoice_line_item`: Represents line items within invoices.
|
|
83
|
+
- `setup_attempt`: Records attempts to set up payment methods (also available as incremental).
|
|
84
|
+
|
|
85
|
+
Use these as `--source-table` parameter in the `ingestr ingest` command.
|
|
86
|
+
|
|
87
|
+
> [!WARNING]
|
|
88
|
+
> Stripe does not support incremental loading for many endpoints in its APIs, which means ingestr will load endpoints incrementally if they support it, and do a full-refresh if not.
|
|
89
|
+
|
|
90
|
+
> [!NOTE]
|
|
91
|
+
> For backward compatibility, non-underscored versions of table names (e.g., `checkoutsession`, `paymentintent`, `subscriptionitem`) are still supported but will be deprecated in future versions. Please use the underscored versions (e.g., `checkout_session`, `payment_intent`, `subscription_item`) for new integrations.
|
|
@@ -58,6 +58,7 @@ class LoaderFileFormat(str, Enum):
|
|
|
58
58
|
|
|
59
59
|
|
|
60
60
|
class SqlBackend(str, Enum):
|
|
61
|
+
default = "default"
|
|
61
62
|
sqlalchemy = "sqlalchemy"
|
|
62
63
|
pyarrow = "pyarrow"
|
|
63
64
|
connectorx = "connectorx"
|
|
@@ -187,7 +188,7 @@ def ingest(
|
|
|
187
188
|
help="The SQL backend to use",
|
|
188
189
|
envvar=["SQL_BACKEND", "INGESTR_SQL_BACKEND"],
|
|
189
190
|
),
|
|
190
|
-
] = SqlBackend.
|
|
191
|
+
] = SqlBackend.default, # type: ignore
|
|
191
192
|
loader_file_format: Annotated[
|
|
192
193
|
Optional[LoaderFileFormat],
|
|
193
194
|
typer.Option(
|
|
@@ -289,7 +290,11 @@ def ingest(
|
|
|
289
290
|
from ingestr.src.collector.spinner import SpinnerCollector
|
|
290
291
|
from ingestr.src.destinations import AthenaDestination
|
|
291
292
|
from ingestr.src.factory import SourceDestinationFactory
|
|
292
|
-
from ingestr.src.filters import
|
|
293
|
+
from ingestr.src.filters import (
|
|
294
|
+
cast_set_to_list,
|
|
295
|
+
cast_spanner_types,
|
|
296
|
+
handle_mysql_empty_dates,
|
|
297
|
+
)
|
|
293
298
|
from ingestr.src.sources import MongoDbSource
|
|
294
299
|
|
|
295
300
|
def report_errors(run_info: LoadInfo):
|
|
@@ -517,6 +522,15 @@ def ingest(
|
|
|
517
522
|
if interval_end:
|
|
518
523
|
interval_end = interval_end.date() # type: ignore
|
|
519
524
|
|
|
525
|
+
if factory.source_scheme.startswith("spanner"):
|
|
526
|
+
# we tend to use the 'pyarrow' backend in general, however, it has issues with JSON objects, so we override it to 'sqlalchemy' for Spanner.
|
|
527
|
+
if sql_backend.value == SqlBackend.default:
|
|
528
|
+
sql_backend = SqlBackend.sqlalchemy
|
|
529
|
+
|
|
530
|
+
# this allows us to identify the cases where the user does not have a preference, so that for some sources we can override it.
|
|
531
|
+
if sql_backend == SqlBackend.default:
|
|
532
|
+
sql_backend = SqlBackend.pyarrow
|
|
533
|
+
|
|
520
534
|
dlt_source = source.dlt_source(
|
|
521
535
|
uri=source_uri,
|
|
522
536
|
table=source_table,
|
|
@@ -535,6 +549,9 @@ def ingest(
|
|
|
535
549
|
if factory.source_scheme.startswith("mysql"):
|
|
536
550
|
resource.for_each(dlt_source, lambda x: x.add_map(handle_mysql_empty_dates))
|
|
537
551
|
|
|
552
|
+
if factory.source_scheme.startswith("spanner"):
|
|
553
|
+
resource.for_each(dlt_source, lambda x: x.add_map(cast_spanner_types))
|
|
554
|
+
|
|
538
555
|
if yield_limit:
|
|
539
556
|
resource.for_each(dlt_source, lambda x: x.add_limit(yield_limit))
|
|
540
557
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
version = "v0.13.52"
|
|
@@ -468,3 +468,15 @@ class S3Destination:
|
|
|
468
468
|
|
|
469
469
|
def post_load(self) -> None:
|
|
470
470
|
pass
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
class SqliteDestination(GenericSqlDestination):
|
|
474
|
+
def dlt_dest(self, uri: str, **kwargs):
|
|
475
|
+
return dlt.destinations.sqlalchemy(credentials=uri)
|
|
476
|
+
|
|
477
|
+
def dlt_run_params(self, uri: str, table: str, **kwargs):
|
|
478
|
+
return {
|
|
479
|
+
#https://dlthub.com/docs/dlt-ecosystem/destinations/sqlalchemy#dataset-files
|
|
480
|
+
"dataset_name": "main",
|
|
481
|
+
"table_name": table,
|
|
482
|
+
}
|
|
@@ -15,6 +15,7 @@ from ingestr.src.destinations import (
|
|
|
15
15
|
RedshiftDestination,
|
|
16
16
|
S3Destination,
|
|
17
17
|
SnowflakeDestination,
|
|
18
|
+
SqliteDestination,
|
|
18
19
|
SynapseDestination,
|
|
19
20
|
)
|
|
20
21
|
from ingestr.src.sources import (
|
|
@@ -54,6 +55,7 @@ from ingestr.src.sources import (
|
|
|
54
55
|
SalesforceSource,
|
|
55
56
|
ShopifySource,
|
|
56
57
|
SlackSource,
|
|
58
|
+
SmartsheetSource,
|
|
57
59
|
SolidgateSource,
|
|
58
60
|
SqlSource,
|
|
59
61
|
StripeAnalyticsSource,
|
|
@@ -161,6 +163,7 @@ class SourceDestinationFactory:
|
|
|
161
163
|
"elasticsearch": ElasticsearchSource,
|
|
162
164
|
"attio": AttioSource,
|
|
163
165
|
"solidgate": SolidgateSource,
|
|
166
|
+
"smartsheet": SmartsheetSource,
|
|
164
167
|
}
|
|
165
168
|
destinations: Dict[str, Type[DestinationProtocol]] = {
|
|
166
169
|
"bigquery": BigQueryDestination,
|
|
@@ -180,6 +183,7 @@ class SourceDestinationFactory:
|
|
|
180
183
|
"clickhouse+native": ClickhouseDestination,
|
|
181
184
|
"clickhouse": ClickhouseDestination,
|
|
182
185
|
"s3": S3Destination,
|
|
186
|
+
"sqlite": SqliteDestination,
|
|
183
187
|
}
|
|
184
188
|
|
|
185
189
|
def __init__(self, source_uri: str, destination_uri: str):
|
|
@@ -7,6 +7,20 @@ def cast_set_to_list(row):
|
|
|
7
7
|
return row
|
|
8
8
|
|
|
9
9
|
|
|
10
|
+
def cast_spanner_types(row):
|
|
11
|
+
if not isinstance(row, dict):
|
|
12
|
+
return row
|
|
13
|
+
|
|
14
|
+
from google.cloud.spanner_v1.data_types import JsonObject
|
|
15
|
+
|
|
16
|
+
for key in row.keys():
|
|
17
|
+
if isinstance(row[key], JsonObject):
|
|
18
|
+
import json
|
|
19
|
+
|
|
20
|
+
row[key] = json.loads(row[key].serialize())
|
|
21
|
+
return row
|
|
22
|
+
|
|
23
|
+
|
|
10
24
|
def handle_mysql_empty_dates(row):
|
|
11
25
|
# MySQL returns empty dates as 0000-00-00, which is not a valid date, we handle them here.
|
|
12
26
|
if not isinstance(row, dict):
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
from dlt.sources.helpers.requests import Client
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def create_client(retry_status_codes: list[int] | None = None) -> requests.Session:
|
|
6
|
+
if retry_status_codes is None:
|
|
7
|
+
retry_status_codes = [502]
|
|
8
|
+
return Client(
|
|
9
|
+
raise_for_status=False,
|
|
10
|
+
retry_condition=retry_on_status_code(retry_status_codes),
|
|
11
|
+
request_max_attempts=12,
|
|
12
|
+
request_backoff_factor=10,
|
|
13
|
+
).session
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def retry_on_status_code(retry_status_codes: list[int]):
|
|
17
|
+
def retry_on_limit(
|
|
18
|
+
response: requests.Response | None, exception: BaseException | None
|
|
19
|
+
) -> bool:
|
|
20
|
+
if response is None:
|
|
21
|
+
return False
|
|
22
|
+
return response.status_code in retry_status_codes
|
|
23
|
+
|
|
24
|
+
return retry_on_limit
|
|
@@ -43,7 +43,7 @@ def solidgate_source(
|
|
|
43
43
|
yield solidgate_client.fetch_data(path, date_from=start_dt, date_to=end_dt)
|
|
44
44
|
|
|
45
45
|
@dlt.resource(
|
|
46
|
-
name="
|
|
46
|
+
name="apm_orders",
|
|
47
47
|
write_disposition="merge",
|
|
48
48
|
primary_key="order_id",
|
|
49
49
|
columns={
|
|
@@ -69,7 +69,7 @@ def solidgate_source(
|
|
|
69
69
|
yield solidgate_client.fetch_data(path, date_from=start_dt, date_to=end_dt)
|
|
70
70
|
|
|
71
71
|
@dlt.resource(
|
|
72
|
-
name="
|
|
72
|
+
name="card_orders",
|
|
73
73
|
write_disposition="merge",
|
|
74
74
|
primary_key="order_id",
|
|
75
75
|
columns={
|
|
@@ -94,4 +94,34 @@ def solidgate_source(
|
|
|
94
94
|
start_dt = dateTime.last_value
|
|
95
95
|
yield solidgate_client.fetch_data(path, date_from=start_dt, date_to=end_dt)
|
|
96
96
|
|
|
97
|
-
|
|
97
|
+
@dlt.resource(
|
|
98
|
+
name="financial_entries",
|
|
99
|
+
write_disposition="merge",
|
|
100
|
+
primary_key="id",
|
|
101
|
+
columns={
|
|
102
|
+
"created_at": {"data_type": "timestamp", "partition": True},
|
|
103
|
+
},
|
|
104
|
+
)
|
|
105
|
+
def fetch_financial_entries(
|
|
106
|
+
dateTime=dlt.sources.incremental(
|
|
107
|
+
"created_at",
|
|
108
|
+
initial_value=start_date,
|
|
109
|
+
end_value=end_date,
|
|
110
|
+
range_start="closed",
|
|
111
|
+
range_end="closed",
|
|
112
|
+
),
|
|
113
|
+
):
|
|
114
|
+
if dateTime.end_value is None:
|
|
115
|
+
end_date = pendulum.now(tz="UTC")
|
|
116
|
+
else:
|
|
117
|
+
end_date = dateTime.end_value
|
|
118
|
+
|
|
119
|
+
start_date = dateTime.last_value
|
|
120
|
+
yield solidgate_client.fetch_financial_entry_data(start_date, end_date)
|
|
121
|
+
|
|
122
|
+
return (
|
|
123
|
+
fetch_all_subscriptions,
|
|
124
|
+
fetch_apm_orders,
|
|
125
|
+
fetch_card_orders,
|
|
126
|
+
fetch_financial_entries,
|
|
127
|
+
)
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
import hashlib
|
|
3
|
+
import hmac
|
|
4
|
+
import json
|
|
5
|
+
import time
|
|
6
|
+
from io import StringIO
|
|
7
|
+
|
|
8
|
+
import pandas as pd # type: ignore
|
|
9
|
+
import pendulum
|
|
10
|
+
|
|
11
|
+
from ingestr.src.http_client import create_client
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class SolidgateClient:
|
|
15
|
+
def __init__(self, public_key, secret_key):
|
|
16
|
+
self.base_url = "https://reports.solidgate.com/api/v1"
|
|
17
|
+
self.public_key = public_key
|
|
18
|
+
self.secret_key = secret_key
|
|
19
|
+
self.client = create_client(retry_status_codes=[204])
|
|
20
|
+
|
|
21
|
+
def fetch_data(
|
|
22
|
+
self,
|
|
23
|
+
path: str,
|
|
24
|
+
date_from: pendulum.DateTime,
|
|
25
|
+
date_to: pendulum.DateTime,
|
|
26
|
+
):
|
|
27
|
+
request_payload = {
|
|
28
|
+
"date_from": date_from.format("YYYY-MM-DD HH:mm:ss"),
|
|
29
|
+
"date_to": date_to.format("YYYY-MM-DD HH:mm:ss"),
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
json_string = json.dumps(request_payload)
|
|
33
|
+
signature = self.generateSignature(json_string)
|
|
34
|
+
headers = {
|
|
35
|
+
"merchant": self.public_key,
|
|
36
|
+
"Signature": signature,
|
|
37
|
+
"Content-Type": "application/json",
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
next_page_iterator = None
|
|
41
|
+
url = f"{self.base_url}/{path}"
|
|
42
|
+
|
|
43
|
+
while True:
|
|
44
|
+
payload = request_payload.copy()
|
|
45
|
+
if next_page_iterator:
|
|
46
|
+
payload["page_iterator"] = next_page_iterator
|
|
47
|
+
|
|
48
|
+
response = self.client.post(url, headers=headers, json=payload)
|
|
49
|
+
response.raise_for_status()
|
|
50
|
+
response_json = response.json()
|
|
51
|
+
|
|
52
|
+
if path == "subscriptions":
|
|
53
|
+
data = response_json["subscriptions"]
|
|
54
|
+
for _, value in data.items():
|
|
55
|
+
if "updated_at" in value:
|
|
56
|
+
value["updated_at"] = pendulum.parse(value["updated_at"])
|
|
57
|
+
yield value
|
|
58
|
+
|
|
59
|
+
else:
|
|
60
|
+
data = response_json["orders"]
|
|
61
|
+
for value in data:
|
|
62
|
+
if "updated_at" in value:
|
|
63
|
+
value["updated_at"] = pendulum.parse(value["updated_at"])
|
|
64
|
+
yield value
|
|
65
|
+
|
|
66
|
+
next_page_iterator = response_json.get("metadata", {}).get(
|
|
67
|
+
"next_page_iterator"
|
|
68
|
+
)
|
|
69
|
+
if not next_page_iterator or next_page_iterator == "None":
|
|
70
|
+
break
|
|
71
|
+
|
|
72
|
+
def fetch_financial_entry_data(
|
|
73
|
+
self, date_from: pendulum.DateTime, date_to: pendulum.DateTime
|
|
74
|
+
):
|
|
75
|
+
request_payload = {
|
|
76
|
+
"date_from": date_from.format("YYYY-MM-DD HH:mm:ss"),
|
|
77
|
+
"date_to": date_to.format("YYYY-MM-DD HH:mm:ss"),
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
json_string = json.dumps(request_payload)
|
|
81
|
+
signature = self.generateSignature(json_string)
|
|
82
|
+
headers = {
|
|
83
|
+
"merchant": self.public_key,
|
|
84
|
+
"Signature": signature,
|
|
85
|
+
"Content-Type": "application/json",
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
url = f"{self.base_url}/finance/financial_entries"
|
|
89
|
+
post_response = self.client.post(url, headers=headers, json=request_payload)
|
|
90
|
+
post_response.raise_for_status()
|
|
91
|
+
report_url = post_response.json().get("report_url")
|
|
92
|
+
if not report_url:
|
|
93
|
+
return f"Report URL not found in the response: {post_response.json()}", 400
|
|
94
|
+
|
|
95
|
+
# Wait for 5 seconds before attempting to download the report as report may not be immediately available
|
|
96
|
+
time.sleep(5)
|
|
97
|
+
|
|
98
|
+
data = self.public_key + self.public_key
|
|
99
|
+
hmac_hash = hmac.new(
|
|
100
|
+
self.secret_key.encode("utf-8"), data.encode("utf-8"), hashlib.sha512
|
|
101
|
+
).digest()
|
|
102
|
+
signature_get = base64.b64encode(hmac_hash.hex().encode("utf-8")).decode(
|
|
103
|
+
"utf-8"
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
headers_get = {
|
|
107
|
+
"merchant": self.public_key,
|
|
108
|
+
"Signature": signature_get,
|
|
109
|
+
"Content-Type": "application/json",
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
get_response = self.client.get(report_url, headers=headers_get)
|
|
113
|
+
|
|
114
|
+
if get_response.status_code == 200:
|
|
115
|
+
try:
|
|
116
|
+
response_json = json.loads(get_response.content)
|
|
117
|
+
if "error" in response_json:
|
|
118
|
+
raise Exception(f"API Error: {response_json['error']['messages']}")
|
|
119
|
+
except json.JSONDecodeError:
|
|
120
|
+
try:
|
|
121
|
+
csv_data = get_response.content.decode("utf-8")
|
|
122
|
+
df = pd.read_csv(StringIO(csv_data))
|
|
123
|
+
df["created_at"] = df["created_at"].apply(
|
|
124
|
+
lambda x: pendulum.parse(x)
|
|
125
|
+
)
|
|
126
|
+
return df
|
|
127
|
+
except Exception as e:
|
|
128
|
+
raise Exception(f"Error reading CSV: {e}")
|
|
129
|
+
else:
|
|
130
|
+
raise Exception(
|
|
131
|
+
f"Failed to get report. Status code: {get_response.status_code}"
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
def generateSignature(self, json_string):
|
|
135
|
+
data = self.public_key + json_string + self.public_key
|
|
136
|
+
hmac_hash = hmac.new(
|
|
137
|
+
self.secret_key.encode("utf-8"), data.encode("utf-8"), hashlib.sha512
|
|
138
|
+
).digest()
|
|
139
|
+
return base64.b64encode(hmac_hash.hex().encode("utf-8")).decode("utf-8")
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""Stripe analytics source settings and constants"""
|
|
2
|
+
|
|
3
|
+
# the most popular endpoints
|
|
4
|
+
# Full list of the Stripe API endpoints you can find here: https://stripe.com/docs/api.
|
|
5
|
+
ENDPOINTS = {
|
|
6
|
+
"account": "Account",
|
|
7
|
+
"applepaydomain": "ApplePayDomain",
|
|
8
|
+
"apple_pay_domain": "ApplePayDomain",
|
|
9
|
+
"applicationfee": "ApplicationFee",
|
|
10
|
+
"application_fee": "ApplicationFee",
|
|
11
|
+
"checkoutsession": "CheckoutSession",
|
|
12
|
+
"checkout_session": "CheckoutSession",
|
|
13
|
+
"coupon": "Coupon",
|
|
14
|
+
"customer": "Customer",
|
|
15
|
+
"dispute": "Dispute",
|
|
16
|
+
"paymentintent": "PaymentIntent",
|
|
17
|
+
"payment_intent": "PaymentIntent",
|
|
18
|
+
"paymentlink": "PaymentLink",
|
|
19
|
+
"payment_link": "PaymentLink",
|
|
20
|
+
"paymentmethod": "PaymentMethod",
|
|
21
|
+
"payment_method": "PaymentMethod",
|
|
22
|
+
"paymentmethoddomain": "PaymentMethodDomain",
|
|
23
|
+
"payment_method_domain": "PaymentMethodDomain",
|
|
24
|
+
"payout": "Payout",
|
|
25
|
+
"plan": "Plan",
|
|
26
|
+
"price": "Price",
|
|
27
|
+
"product": "Product",
|
|
28
|
+
"promotioncode": "PromotionCode",
|
|
29
|
+
"promotion_code": "PromotionCode",
|
|
30
|
+
"quote": "Quote",
|
|
31
|
+
"refund": "Refund",
|
|
32
|
+
"review": "Review",
|
|
33
|
+
"setupattempt": "SetupAttempt",
|
|
34
|
+
"setup_attempt": "SetupAttempt",
|
|
35
|
+
"setupintent": "SetupIntent",
|
|
36
|
+
"setup_intent": "SetupIntent",
|
|
37
|
+
"shippingrate": "ShippingRate",
|
|
38
|
+
"shipping_rate": "ShippingRate",
|
|
39
|
+
"subscription": "Subscription",
|
|
40
|
+
"subscriptionitem": "SubscriptionItem",
|
|
41
|
+
"subscription_item": "SubscriptionItem",
|
|
42
|
+
"subscriptionschedule": "SubscriptionSchedule",
|
|
43
|
+
"subscription_schedule": "SubscriptionSchedule",
|
|
44
|
+
"transfer": "Transfer",
|
|
45
|
+
"taxcode": "TaxCode",
|
|
46
|
+
"tax_code": "TaxCode",
|
|
47
|
+
"taxid": "TaxId",
|
|
48
|
+
"tax_id": "TaxId",
|
|
49
|
+
"taxrate": "TaxRate",
|
|
50
|
+
"tax_rate": "TaxRate",
|
|
51
|
+
"topup": "Topup",
|
|
52
|
+
"top_up": "Topup",
|
|
53
|
+
"webhookendpoint": "WebhookEndpoint",
|
|
54
|
+
"webhook_endpoint": "WebhookEndpoint",
|
|
55
|
+
}
|
|
56
|
+
# possible incremental endpoints
|
|
57
|
+
INCREMENTAL_ENDPOINTS = {
|
|
58
|
+
"applicationfee": "ApplicationFee",
|
|
59
|
+
"application_fee": "ApplicationFee",
|
|
60
|
+
"balancetransaction": "BalanceTransaction",
|
|
61
|
+
"balance_transaction": "BalanceTransaction",
|
|
62
|
+
"charge": "Charge",
|
|
63
|
+
"creditnote": "CreditNote",
|
|
64
|
+
"credit_note": "CreditNote",
|
|
65
|
+
"event": "Event",
|
|
66
|
+
"invoice": "Invoice",
|
|
67
|
+
"invoiceitem": "InvoiceItem",
|
|
68
|
+
"invoice_item": "InvoiceItem",
|
|
69
|
+
"invoicelineitem": "InvoiceLineItem",
|
|
70
|
+
"invoice_line_item": "InvoiceLineItem",
|
|
71
|
+
"setupattempt": "SetupAttempt",
|
|
72
|
+
"setup_attempt": "SetupAttempt",
|
|
73
|
+
}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
# Stripe
|
|
2
|
-
|
|
3
|
-
[Stripe](https://www.stripe.com/) is a technology company that builds economic infrastructure for the internet, providing payment processing software and APIs for e-commerce websites and mobile applications.
|
|
4
|
-
|
|
5
|
-
ingestr supports Stripe as a source.
|
|
6
|
-
|
|
7
|
-
## URI format
|
|
8
|
-
|
|
9
|
-
The URI format for Stripe is as follows:
|
|
10
|
-
|
|
11
|
-
```plaintext
|
|
12
|
-
stripe://?api_key=<api-key-here>
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
URI parameters:
|
|
16
|
-
|
|
17
|
-
- `api_key`: the API key used for authentication with the Stripe API
|
|
18
|
-
|
|
19
|
-
The URI is used to connect to the Stripe API for extracting data. More details on setting up Stripe integrations can be found [here](https://stripe.com/docs/api).
|
|
20
|
-
|
|
21
|
-
## Setting up a Stripe Integration
|
|
22
|
-
|
|
23
|
-
Stripe requires a few steps to set up an integration, please follow the guide dltHub [has built here](https://dlthub.com/docs/dlt-ecosystem/verified-sources/stripe#setup-guide).
|
|
24
|
-
|
|
25
|
-
Once you complete the guide, you should have an API key. Let's say your API key is `sk_test_12345`, here's a sample command that will copy the data from Stripe into a DuckDB database:
|
|
26
|
-
|
|
27
|
-
```sh
|
|
28
|
-
ingestr ingest --source-uri 'stripe://?api_key=sk_test_12345' --source-table 'charges' --dest-uri duckdb:///stripe.duckdb --dest-table 'dest.charges'
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
The result of this command will be a table in the `stripe.duckdb` database with JSON columns.
|
|
32
|
-
|
|
33
|
-
## Tables
|
|
34
|
-
|
|
35
|
-
Stripe source allows ingesting the following sources into separate tables:
|
|
36
|
-
|
|
37
|
-
- `subscription`: Represents a customer's subscription to a recurring service, detailing billing cycles, plans, and status.
|
|
38
|
-
- `account`: Contains information about a Stripe account, including balances, payouts, and account settings.
|
|
39
|
-
- `coupon`: Stores data about discount codes or coupons that can be applied to invoices, subscriptions, or other charges.
|
|
40
|
-
- `customer`: Holds information about customers, such as billing details, payment methods, and associated transactions.
|
|
41
|
-
- `product`: Represents products that can be sold or subscribed to, including metadata and pricing information.
|
|
42
|
-
- `price`: Contains pricing information for products, including currency, amount, and billing intervals.
|
|
43
|
-
- `balancetransaction`: Records transactions that affect the Stripe account balance, such as charges, refunds, and payouts.
|
|
44
|
-
- `invoice`: Represents invoices sent to customers, detailing line items, amounts, and payment status.
|
|
45
|
-
- `event`: Logs all events in the Stripe account, including customer actions, account updates, and system-generated events.
|
|
46
|
-
- `charge`: Returns a list of charges.
|
|
47
|
-
|
|
48
|
-
Use these as `--source-table` parameter in the `ingestr ingest` command.
|
|
49
|
-
|
|
50
|
-
> [!WARNING]
|
|
51
|
-
> Stripe does not support incremental loading for many endpoints in its APIs, which means ingestr will load endpoints incrementally if they support it, and do a full-refresh if not.
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
version = "v0.13.50"
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import requests
|
|
2
|
-
from dlt.sources.helpers.requests import Client
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
def create_client() -> requests.Session:
|
|
6
|
-
return Client(
|
|
7
|
-
raise_for_status=False,
|
|
8
|
-
retry_condition=retry_on_limit,
|
|
9
|
-
request_max_attempts=12,
|
|
10
|
-
).session
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
def retry_on_limit(
|
|
14
|
-
response: requests.Response | None, exception: BaseException | None
|
|
15
|
-
) -> bool:
|
|
16
|
-
if response is None:
|
|
17
|
-
return False
|
|
18
|
-
return response.status_code == 502
|