ingestr 0.13.57__tar.gz → 0.13.59__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.57 → ingestr-0.13.59}/PKG-INFO +1 -1
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/.vitepress/config.mjs +2 -0
- ingestr-0.13.59/docs/supported-sources/isoc-pulse.md +147 -0
- ingestr-0.13.59/docs/supported-sources/pinterest.md +27 -0
- ingestr-0.13.59/ingestr/src/buildinfo.py +1 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/factory.py +4 -0
- ingestr-0.13.59/ingestr/src/isoc_pulse/__init__.py +159 -0
- ingestr-0.13.59/ingestr/src/pinterest/__init__.py +82 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/sources.py +73 -6
- {ingestr-0.13.57 → ingestr-0.13.59}/requirements_arm64.txt +1 -1
- ingestr-0.13.57/ingestr/src/buildinfo.py +0 -1
- {ingestr-0.13.57 → ingestr-0.13.59}/.dockerignore +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/.githooks/pre-commit-hook.sh +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/.github/workflows/deploy-docs.yml +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/.github/workflows/release.yml +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/.github/workflows/secrets-scan.yml +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/.github/workflows/tests.yml +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/.gitignore +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/.gitleaksignore +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/.python-version +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/.vale.ini +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/Dockerfile +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/LICENSE.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/Makefile +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/README.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/.vitepress/theme/custom.css +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/.vitepress/theme/index.js +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/commands/example-uris.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/commands/ingest.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/getting-started/core-concepts.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/getting-started/incremental-loading.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/getting-started/quickstart.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/getting-started/telemetry.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/index.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/media/applovin_max.png +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/media/athena.png +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/media/clickhouse_img.png +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/media/cratedb-source.png +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/media/freshdesk_ingestion.png +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/media/gcp_spanner_ingestion.png +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/media/github.png +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/media/google_analytics_realtime_report.png +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/media/googleanalytics.png +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/media/ingestion_elasticsearch_img.png +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/media/kinesis.bigquery.png +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/media/linkedin_ads.png +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/media/mixpanel_ingestion.png +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/media/personio.png +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/media/personio_duckdb.png +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/media/phantombuster.png +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/media/pipedrive.png +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/media/quickbook_ingestion.png +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/media/sftp.png +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/media/stripe_postgres.png +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/media/tiktok.png +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/adjust.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/airtable.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/applovin.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/applovin_max.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/appsflyer.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/appstore.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/asana.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/athena.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/attio.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/bigquery.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/chess.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/clickhouse.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/cratedb.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/csv.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/custom_queries.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/databricks.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/db2.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/duckdb.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/dynamodb.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/elasticsearch.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/facebook-ads.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/frankfurter.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/freshdesk.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/gcs.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/github.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/google-ads.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/google_analytics.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/gorgias.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/gsheets.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/hubspot.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/kafka.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/kinesis.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/klaviyo.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/linkedin_ads.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/mixpanel.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/mongodb.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/mssql.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/mysql.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/notion.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/oracle.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/personio.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/phantombuster.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/pipedrive.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/postgres.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/quickbooks.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/redshift.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/s3.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/salesforce.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/sap-hana.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/sftp.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/shopify.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/slack.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/smartsheets.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/snowflake.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/solidgate.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/spanner.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/sqlite.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/stripe.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/tiktok-ads.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/trustpilot.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/supported-sources/zendesk.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/tutorials/load-kinesis-bigquery.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/tutorials/load-personio-duckdb.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/docs/tutorials/load-stripe-postgres.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/conftest.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/main.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/.gitignore +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/adjust/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/adjust/adjust_helpers.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/airtable/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/applovin/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/applovin_max/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/appsflyer/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/appsflyer/client.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/appstore/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/appstore/client.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/appstore/errors.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/appstore/models.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/appstore/resources.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/arrow/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/asana_source/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/asana_source/helpers.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/asana_source/settings.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/attio/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/attio/helpers.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/blob.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/chess/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/chess/helpers.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/chess/settings.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/collector/spinner.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/destinations.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/dynamodb/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/elasticsearch/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/errors.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/facebook_ads/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/facebook_ads/exceptions.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/facebook_ads/helpers.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/facebook_ads/settings.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/facebook_ads/utils.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/filesystem/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/filesystem/helpers.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/filesystem/readers.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/filters.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/frankfurter/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/frankfurter/helpers.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/freshdesk/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/freshdesk/freshdesk_client.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/freshdesk/settings.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/github/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/github/helpers.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/github/queries.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/github/settings.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/google_ads/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/google_ads/field.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/google_ads/metrics.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/google_ads/predicates.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/google_ads/reports.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/google_analytics/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/google_analytics/helpers.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/google_sheets/README.md +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/google_sheets/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/google_sheets/helpers/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/google_sheets/helpers/api_calls.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/google_sheets/helpers/data_processing.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/gorgias/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/gorgias/helpers.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/http_client.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/hubspot/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/hubspot/helpers.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/hubspot/settings.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/kafka/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/kafka/helpers.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/kinesis/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/kinesis/helpers.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/klaviyo/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/klaviyo/client.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/klaviyo/helpers.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/linkedin_ads/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/linkedin_ads/dimension_time_enum.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/linkedin_ads/helpers.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/loader.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/mixpanel/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/mixpanel/client.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/mongodb/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/mongodb/helpers.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/notion/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/notion/helpers/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/notion/helpers/client.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/notion/helpers/database.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/notion/settings.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/partition.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/personio/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/personio/helpers.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/phantombuster/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/phantombuster/client.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/pipedrive/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/pipedrive/helpers/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/pipedrive/helpers/custom_fields_munger.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/pipedrive/helpers/pages.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/pipedrive/settings.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/pipedrive/typing.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/quickbooks/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/resource.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/salesforce/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/salesforce/helpers.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/shopify/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/shopify/exceptions.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/shopify/helpers.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/shopify/settings.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/slack/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/slack/helpers.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/slack/settings.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/smartsheets/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/solidgate/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/solidgate/helpers.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/sql_database/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/sql_database/callbacks.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/stripe_analytics/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/stripe_analytics/helpers.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/stripe_analytics/settings.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/table_definition.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/telemetry/event.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/testdata/fakebqcredentials.json +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/tiktok_ads/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/tiktok_ads/tiktok_helpers.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/time.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/trustpilot/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/trustpilot/client.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/version.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/zendesk/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/zendesk/helpers/__init__.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/zendesk/helpers/api_helpers.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/zendesk/helpers/credentials.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/zendesk/helpers/talk_api.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/src/zendesk/settings.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/testdata/.gitignore +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/testdata/create_replace.csv +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/testdata/delete_insert_expected.csv +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/testdata/delete_insert_part1.csv +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/testdata/delete_insert_part2.csv +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/testdata/merge_expected.csv +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/testdata/merge_part1.csv +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/testdata/merge_part2.csv +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/ingestr/tests/unit/test_smartsheets.py +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/package-lock.json +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/package.json +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/pyproject.toml +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/requirements-dev.txt +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/requirements.in +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/requirements.txt +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/resources/demo.gif +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/resources/demo.tape +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/resources/ingestr.svg +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/styles/Google/AMPM.yml +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/styles/Google/Acronyms.yml +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/styles/Google/Colons.yml +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/styles/Google/Contractions.yml +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/styles/Google/DateFormat.yml +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/styles/Google/Ellipses.yml +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/styles/Google/EmDash.yml +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/styles/Google/Exclamation.yml +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/styles/Google/FirstPerson.yml +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/styles/Google/Gender.yml +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/styles/Google/GenderBias.yml +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/styles/Google/HeadingPunctuation.yml +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/styles/Google/Headings.yml +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/styles/Google/Latin.yml +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/styles/Google/LyHyphens.yml +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/styles/Google/OptionalPlurals.yml +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/styles/Google/Ordinal.yml +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/styles/Google/OxfordComma.yml +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/styles/Google/Parens.yml +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/styles/Google/Passive.yml +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/styles/Google/Periods.yml +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/styles/Google/Quotes.yml +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/styles/Google/Ranges.yml +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/styles/Google/Semicolons.yml +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/styles/Google/Slang.yml +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/styles/Google/Spacing.yml +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/styles/Google/Spelling.yml +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/styles/Google/Units.yml +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/styles/Google/We.yml +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/styles/Google/Will.yml +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/styles/Google/WordList.yml +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/styles/Google/meta.json +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/styles/Google/vocab.txt +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/styles/bruin/Ingestr.yml +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/styles/config/vocabularies/bruin/accept.txt +0 -0
- {ingestr-0.13.57 → ingestr-0.13.59}/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.59
|
|
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
|
|
@@ -131,12 +131,14 @@ export default defineConfig({
|
|
|
131
131
|
{ text: "Google Sheets", link: "/supported-sources/gsheets.md" },
|
|
132
132
|
{ text: "Gorgias", link: "/supported-sources/gorgias.md" },
|
|
133
133
|
{ text: "HubSpot", link: "/supported-sources/hubspot.md" },
|
|
134
|
+
{ text: "Internet Society Pulse", link: "/supported-sources/isoc-pulse.md" },
|
|
134
135
|
{ text: "Klaviyo", link: "/supported-sources/klaviyo.md" },
|
|
135
136
|
{ text: "LinkedIn Ads", link: "/supported-sources/linkedin_ads.md" },
|
|
136
137
|
{ text: "Mixpanel", link: "/supported-sources/mixpanel.md" },
|
|
137
138
|
{ text: "Notion", link: "/supported-sources/notion.md" },
|
|
138
139
|
{ text: "Personio", link: "/supported-sources/personio.md" },
|
|
139
140
|
{ text: "PhantomBuster", link: "/supported-sources/phantombuster.md" },
|
|
141
|
+
{ text: "Pinterest", link: "/supported-sources/pinterest.md" },
|
|
140
142
|
{ text: "Pipedrive", link: "/supported-sources/pipedrive.md" },
|
|
141
143
|
{ text: "QuickBooks", link: "/supported-sources/quickbooks.md" },
|
|
142
144
|
{ text: "S3", link: "/supported-sources/s3.md" },
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# Internet Society Pulse
|
|
2
|
+
|
|
3
|
+
[Internet Society Pulse](https://pulse.internetsociety.org/) is a platform that monitors the health, availability, and evolution of the Internet, providing metrics on key technologies that contribute to its security, resilience, and trustworthiness.
|
|
4
|
+
|
|
5
|
+
ingestr supports Internet Society Pulse as a source.
|
|
6
|
+
|
|
7
|
+
## URI format
|
|
8
|
+
|
|
9
|
+
The URI format for Internet Society Pulse is as follows:
|
|
10
|
+
|
|
11
|
+
```plaintext
|
|
12
|
+
isoc-pulse://?token=<your-token>
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
URI parameters:
|
|
16
|
+
- `token`: The API token used for authentication with the Internet Society Pulse API.
|
|
17
|
+
|
|
18
|
+
## Setting up an Internet Society Pulse Integration
|
|
19
|
+
|
|
20
|
+
To use the Internet Society Pulse source, you need to obtain an API token from the Internet Society.
|
|
21
|
+
|
|
22
|
+
Once you have the token, you can access various metrics from the Pulse platform. Here's a sample command that will copy data from the ISOC Pulse API into a DuckDB database:
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
ingestr ingest \
|
|
26
|
+
--source-uri 'isoc-pulse://?token=your_token_here' \
|
|
27
|
+
--source-table 'https' \
|
|
28
|
+
--dest-uri 'duckdb:///pulse_data.duckdb' \
|
|
29
|
+
--dest-table 'dest.https_adoption' \
|
|
30
|
+
--interval-start '2023-01-01' \
|
|
31
|
+
--interval-end '2023-12-31'
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
This will retrieve HTTPS adoption metrics for the specified date range and store them in your database.
|
|
35
|
+
|
|
36
|
+
## Tables
|
|
37
|
+
|
|
38
|
+
Internet Society Pulse source allows ingesting the following metrics as separate tables:
|
|
39
|
+
|
|
40
|
+
| Metric | Description | Country Support | Additional Options |
|
|
41
|
+
|--------|-------------|----------------|-------------------|
|
|
42
|
+
| `dnssec_adoption` | DNSSEC adoption metrics for specific domains | No | Domain name |
|
|
43
|
+
| `dnssec_tld_adoption` | DNSSEC adoption metrics for top-level domains | Yes | Country code |
|
|
44
|
+
| `dnssec_validation` | DNSSEC validation metrics | Yes | Country code |
|
|
45
|
+
| `http` | HTTP protocol metrics | No | None |
|
|
46
|
+
| `http3` | HTTP/3 protocol metrics | No | None |
|
|
47
|
+
| `https` | HTTPS adoption metrics | Yes | `topsites`, Country code |
|
|
48
|
+
| `ipv6` | IPv6 adoption metrics | Yes | `topsites`, Country code |
|
|
49
|
+
| `net_loss` | Internet disconnection metrics | Yes | Shutdown type, Country code |
|
|
50
|
+
| `resilience` | Internet resilience metrics | Yes | Country code |
|
|
51
|
+
| `roa` | Route Origin Authorization metrics | Yes | IP version (`4`/`6`), Country code |
|
|
52
|
+
| `rov` | Route Origin Validation metrics | No | None |
|
|
53
|
+
| `tls` | TLS protocol metrics | No | None |
|
|
54
|
+
| `tls13` | TLS 1.3 protocol metrics | No | None |
|
|
55
|
+
|
|
56
|
+
## Parameter Syntax
|
|
57
|
+
|
|
58
|
+
Many metrics support additional parameters, including country-specific data. These parameters are specified using colons in the source table name. The general format is:
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
metric[:option][:country]
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Where the options and parameters vary by metric type.
|
|
65
|
+
|
|
66
|
+
### General Parameter Rules
|
|
67
|
+
|
|
68
|
+
1. Country codes should follow the ISO 3166-1 alpha-2 format (e.g., US, GB, DE)
|
|
69
|
+
2. The parameters are position-specific – the order matters
|
|
70
|
+
|
|
71
|
+
## Metric-Specific Parameters
|
|
72
|
+
|
|
73
|
+
### HTTPS Metrics
|
|
74
|
+
|
|
75
|
+
- Global data: `https`
|
|
76
|
+
- Country-specific: `https:US`
|
|
77
|
+
- Top sites data: `https:topsites`
|
|
78
|
+
- Top sites for a specific country: `https:topsites:US`
|
|
79
|
+
|
|
80
|
+
### IPv6 Metrics
|
|
81
|
+
|
|
82
|
+
- Global data: `ipv6`
|
|
83
|
+
- Country-specific: `ipv6:DE`
|
|
84
|
+
- Top sites data: `ipv6:topsites`
|
|
85
|
+
|
|
86
|
+
### DNSSEC Metrics
|
|
87
|
+
|
|
88
|
+
- Global validation: `dnssec_validation`
|
|
89
|
+
- Country-specific validation: `dnssec_validation:SE`
|
|
90
|
+
- Global TLD adoption: `dnssec_tld_adoption`
|
|
91
|
+
- Country-specific TLD adoption: `dnssec_tld_adoption:JP`
|
|
92
|
+
|
|
93
|
+
### ROA Metrics (Route Origin Authorization)
|
|
94
|
+
|
|
95
|
+
- Global for IPv4: `roa:4`
|
|
96
|
+
- Global for IPv6: `roa:6`
|
|
97
|
+
- Country-specific for IPv4: `roa:4:CN`
|
|
98
|
+
- Country-specific for IPv6: `roa:6:BR`
|
|
99
|
+
|
|
100
|
+
### Net Loss Metrics (Internet Disconnections)
|
|
101
|
+
|
|
102
|
+
- Country-specific with shutdown type: `net_loss:shutdown_type:country_code`
|
|
103
|
+
- Example for shutdowns in India: `net_loss:shutdown:IN`
|
|
104
|
+
- Example for internet blocking in Japan: `net_loss:blocking:JP`
|
|
105
|
+
|
|
106
|
+
### Resilience Metrics
|
|
107
|
+
|
|
108
|
+
- Global resilience: `resilience`
|
|
109
|
+
- Country-specific resilience: `resilience::FR`
|
|
110
|
+
|
|
111
|
+
## Examples
|
|
112
|
+
|
|
113
|
+
### Country-specific HTTPS Adoption
|
|
114
|
+
|
|
115
|
+
```sh
|
|
116
|
+
ingestr ingest \
|
|
117
|
+
--source-uri 'isoc-pulse://?token=your_token_here' \
|
|
118
|
+
--source-table 'https::US' \
|
|
119
|
+
--dest-uri 'duckdb:///pulse_data.duckdb' \
|
|
120
|
+
--dest-table 'dest.us_https_adoption' \
|
|
121
|
+
--interval-start '2023-01-01'
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### IPv6 Top Sites Data
|
|
125
|
+
|
|
126
|
+
```sh
|
|
127
|
+
ingestr ingest \
|
|
128
|
+
--source-uri 'isoc-pulse://?token=your_token_here' \
|
|
129
|
+
--source-table 'ipv6:topsites' \
|
|
130
|
+
--dest-uri 'duckdb:///pulse_data.duckdb' \
|
|
131
|
+
--dest-table 'dest.ipv6_topsites' \
|
|
132
|
+
--interval-start '2023-01-01'
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### ROA IPv4 Data by Country
|
|
136
|
+
|
|
137
|
+
```sh
|
|
138
|
+
ingestr ingest \
|
|
139
|
+
--source-uri 'isoc-pulse://?token=your_token_here' \
|
|
140
|
+
--source-table 'roa:4:US' \
|
|
141
|
+
--dest-uri 'duckdb:///pulse_data.duckdb' \
|
|
142
|
+
--dest-table 'dest.us_roa_ipv4' \
|
|
143
|
+
--interval-start '2023-01-01'
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Further Reading:
|
|
147
|
+
* [Pulse Documentation](https://pulse.internetsociety.org/api/docs)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Pinterest
|
|
2
|
+
|
|
3
|
+
[Pinterest](https://www.pinterest.com/) is a social media platform for discovering and sharing ideas using visual bookmarks.
|
|
4
|
+
|
|
5
|
+
ingestr supports Pinterest as a source.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
## URI Format
|
|
9
|
+
|
|
10
|
+
The URI format for Pinterest is as follows:
|
|
11
|
+
|
|
12
|
+
```plaintext
|
|
13
|
+
pinterest://?access_token=<access_token>
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
URI parameters:
|
|
17
|
+
- `access_token`: The token used for authentication with the Pinterest API. You can obtain an access token from the [official Pinterest documentation](https://developers.pinterest.com/docs/getting-started/connect-app/)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
## Tables
|
|
22
|
+
|
|
23
|
+
Pinterest source allows ingesting the following sources into separate tables:
|
|
24
|
+
- `pins`: Retrieves a list of pins.
|
|
25
|
+
- `boards`: Retrieves a list of boards.
|
|
26
|
+
|
|
27
|
+
Use these table names with the `--source-table` parameter in the `ingestr ingest` command.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
version = "v0.13.59"
|
|
@@ -42,6 +42,7 @@ from ingestr.src.sources import (
|
|
|
42
42
|
GoogleSheetsSource,
|
|
43
43
|
GorgiasSource,
|
|
44
44
|
HubspotSource,
|
|
45
|
+
IsocPulseSource,
|
|
45
46
|
KafkaSource,
|
|
46
47
|
KinesisSource,
|
|
47
48
|
KlaviyoSource,
|
|
@@ -52,6 +53,7 @@ from ingestr.src.sources import (
|
|
|
52
53
|
NotionSource,
|
|
53
54
|
PersonioSource,
|
|
54
55
|
PhantombusterSource,
|
|
56
|
+
PinterestSource,
|
|
55
57
|
PipedriveSource,
|
|
56
58
|
QuickBooksSource,
|
|
57
59
|
S3Source,
|
|
@@ -172,8 +174,10 @@ class SourceDestinationFactory:
|
|
|
172
174
|
"attio": AttioSource,
|
|
173
175
|
"solidgate": SolidgateSource,
|
|
174
176
|
"quickbooks": QuickBooksSource,
|
|
177
|
+
"isoc-pulse": IsocPulseSource,
|
|
175
178
|
"smartsheet": SmartsheetSource,
|
|
176
179
|
"sftp": SFTPSource,
|
|
180
|
+
"pinterest": PinterestSource,
|
|
177
181
|
}
|
|
178
182
|
destinations: Dict[str, Type[DestinationProtocol]] = {
|
|
179
183
|
"bigquery": BigQueryDestination,
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import math
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from typing import Any, Dict, Iterable, List, Optional
|
|
5
|
+
|
|
6
|
+
import dlt
|
|
7
|
+
from dlt.sources.rest_api import RESTAPIConfig, rest_api_resources
|
|
8
|
+
|
|
9
|
+
METRICS: Dict[str, str] = {
|
|
10
|
+
"dnssec_adoption": "dnssec/adoption",
|
|
11
|
+
"dnssec_tld_adoption": "dnssec/adoption",
|
|
12
|
+
"dnssec_validation": "dnssec/validation",
|
|
13
|
+
"http": "http",
|
|
14
|
+
"http3": "http3",
|
|
15
|
+
"https": "https",
|
|
16
|
+
"ipv6": "ipv6",
|
|
17
|
+
"net_loss": "net-loss",
|
|
18
|
+
"resilience": "resilience",
|
|
19
|
+
"roa": "roa",
|
|
20
|
+
"rov": "rov",
|
|
21
|
+
"tls": "tls",
|
|
22
|
+
"tls13": "tls13",
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dlt.source
|
|
27
|
+
def pulse_source(
|
|
28
|
+
token: str,
|
|
29
|
+
start_date: str,
|
|
30
|
+
metric: str,
|
|
31
|
+
opts: List[str],
|
|
32
|
+
end_date: Optional[str] = None,
|
|
33
|
+
) -> Iterable[dlt.sources.DltResource]:
|
|
34
|
+
validate(metric, opts)
|
|
35
|
+
cfg = get_metric_cfg(metric, opts, start_date)
|
|
36
|
+
endpoint: Dict[str, Any] = {
|
|
37
|
+
"path": cfg.path,
|
|
38
|
+
"params": {
|
|
39
|
+
"start_date": "{incremental.start_value}",
|
|
40
|
+
**cfg.params,
|
|
41
|
+
},
|
|
42
|
+
"incremental": {
|
|
43
|
+
"cursor_path": "date",
|
|
44
|
+
"start_param": "start_date",
|
|
45
|
+
"end_param": "end_date",
|
|
46
|
+
"initial_value": start_date,
|
|
47
|
+
"end_value": end_date,
|
|
48
|
+
"range_start": "closed",
|
|
49
|
+
"range_end": "closed",
|
|
50
|
+
},
|
|
51
|
+
"paginator": "single_page",
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if end_date is not None:
|
|
55
|
+
endpoint["params"]["end_date"] = end_date
|
|
56
|
+
|
|
57
|
+
resources = [
|
|
58
|
+
{
|
|
59
|
+
"name": metric,
|
|
60
|
+
"write_disposition": "merge",
|
|
61
|
+
"primary_key": "date",
|
|
62
|
+
"columns": {"date": {"data_type": "date"}},
|
|
63
|
+
"endpoint": endpoint,
|
|
64
|
+
}
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
config: RESTAPIConfig = {
|
|
68
|
+
"client": {
|
|
69
|
+
"base_url": "https://pulse.internetsociety.org/api/",
|
|
70
|
+
"headers": {"Authorization": f"Bearer {token}"},
|
|
71
|
+
},
|
|
72
|
+
"resource_defaults": {
|
|
73
|
+
"write_disposition": "merge",
|
|
74
|
+
"primary_key": "date",
|
|
75
|
+
},
|
|
76
|
+
"resources": resources, # type:ignore
|
|
77
|
+
}
|
|
78
|
+
res = rest_api_resources(config)
|
|
79
|
+
if metric == "net_loss":
|
|
80
|
+
res[0].add_map(add_date(start_date))
|
|
81
|
+
yield from res
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
@dataclass
|
|
85
|
+
class MetricCfg:
|
|
86
|
+
path: str
|
|
87
|
+
params: Dict[str, Any]
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def get_metric_cfg(metric: str, opts: List[str], start_date: str) -> MetricCfg:
|
|
91
|
+
path = METRICS.get(metric)
|
|
92
|
+
if path is None:
|
|
93
|
+
raise ValueError(f"Unknown metric '{metric}'.")
|
|
94
|
+
if len(opts) == 0:
|
|
95
|
+
return MetricCfg(path=path, params={})
|
|
96
|
+
|
|
97
|
+
if metric == "https":
|
|
98
|
+
return MetricCfg(
|
|
99
|
+
path=f"{path}/country/{opts[-1]}",
|
|
100
|
+
params={
|
|
101
|
+
"topsites": True if "topsites" in opts else False,
|
|
102
|
+
},
|
|
103
|
+
)
|
|
104
|
+
elif metric in ["dnssec_validation", "dnssec_tld_adoption"]:
|
|
105
|
+
return MetricCfg(path=f"{path}/country/{opts[-1]}", params={})
|
|
106
|
+
elif metric == "dnssec_adoption":
|
|
107
|
+
return MetricCfg(path=f"{path}/domains/{opts[-1]}", params={})
|
|
108
|
+
elif metric == "ipv6":
|
|
109
|
+
if "topsites" in opts:
|
|
110
|
+
return MetricCfg(path=path, params={"topsites": True})
|
|
111
|
+
return MetricCfg(path=f"{path}/country/{opts[-1]}", params={})
|
|
112
|
+
elif metric == "roa":
|
|
113
|
+
if len(opts) > 1:
|
|
114
|
+
return MetricCfg(
|
|
115
|
+
path=f"{path}/country/{opts[-1]}", params={"ip_version": opts[-2]}
|
|
116
|
+
)
|
|
117
|
+
return MetricCfg(path=path, params={"ip_version": opts[-1]})
|
|
118
|
+
elif metric == "net_loss":
|
|
119
|
+
return MetricCfg(
|
|
120
|
+
path=path,
|
|
121
|
+
params={
|
|
122
|
+
"country": opts[-1],
|
|
123
|
+
"shutdown_type": opts[-2],
|
|
124
|
+
},
|
|
125
|
+
)
|
|
126
|
+
elif metric == "resilience":
|
|
127
|
+
date = datetime.strptime(start_date, "%Y-%m-%d")
|
|
128
|
+
return MetricCfg(
|
|
129
|
+
path=path,
|
|
130
|
+
params={
|
|
131
|
+
"country": opts[-1],
|
|
132
|
+
"year": date.year,
|
|
133
|
+
"quarter": math.floor(date.month / 4) + 1,
|
|
134
|
+
},
|
|
135
|
+
)
|
|
136
|
+
else:
|
|
137
|
+
raise ValueError(
|
|
138
|
+
f"Unsupported metric '{metric}' with options {opts}. "
|
|
139
|
+
"Please check the metric and options."
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def add_date(start_date: str):
|
|
144
|
+
def transform(item: dict):
|
|
145
|
+
item["date"] = start_date
|
|
146
|
+
return item
|
|
147
|
+
|
|
148
|
+
return transform
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def validate(metric: str, opts: List[str]) -> None:
|
|
152
|
+
nopts = len(opts)
|
|
153
|
+
if metric == "net_loss" and nopts != 2:
|
|
154
|
+
raise ValueError(
|
|
155
|
+
"For 'net_loss' metric, two options are required: "
|
|
156
|
+
"'shutdown_type' and 'country'."
|
|
157
|
+
)
|
|
158
|
+
if nopts > 0 and metric in ["http", "http3", "tls", "tls13", "rov"]:
|
|
159
|
+
raise ValueError(f"metric '{metric}' does not support options. ")
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
from typing import Iterable
|
|
2
|
+
|
|
3
|
+
import dlt
|
|
4
|
+
import pendulum
|
|
5
|
+
from dlt.common.time import ensure_pendulum_datetime
|
|
6
|
+
from dlt.common.typing import TDataItem
|
|
7
|
+
from dlt.sources import DltResource
|
|
8
|
+
from dlt.sources.helpers import requests
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dlt.source(name="pinterest", max_table_nesting=0)
|
|
12
|
+
def pinterest_source(
|
|
13
|
+
start_date: pendulum.DateTime,
|
|
14
|
+
access_token: str,
|
|
15
|
+
page_size: int = 200,
|
|
16
|
+
end_date: pendulum.DateTime | None = None,
|
|
17
|
+
) -> Iterable[DltResource]:
|
|
18
|
+
session = requests.Session()
|
|
19
|
+
session.headers.update({"Authorization": f"Bearer {access_token}"})
|
|
20
|
+
base_url = "https://api.pinterest.com/v5"
|
|
21
|
+
|
|
22
|
+
def fetch_data(
|
|
23
|
+
endpoint: str,
|
|
24
|
+
start_dt: pendulum.DateTime,
|
|
25
|
+
end_dt: pendulum.DateTime,
|
|
26
|
+
) -> Iterable[TDataItem]:
|
|
27
|
+
url = f"{base_url}/{endpoint}"
|
|
28
|
+
params = {"page_size": page_size}
|
|
29
|
+
bookmark = None
|
|
30
|
+
while True:
|
|
31
|
+
if bookmark:
|
|
32
|
+
params["bookmark"] = bookmark
|
|
33
|
+
|
|
34
|
+
resp = session.get(url, params=params)
|
|
35
|
+
resp.raise_for_status()
|
|
36
|
+
data = resp.json()
|
|
37
|
+
items = data.get("items") or []
|
|
38
|
+
|
|
39
|
+
for item in items:
|
|
40
|
+
item_created = ensure_pendulum_datetime(item["created_at"])
|
|
41
|
+
if item_created <= start_dt:
|
|
42
|
+
continue
|
|
43
|
+
if item_created > end_dt:
|
|
44
|
+
continue
|
|
45
|
+
item["created_at"] = item_created
|
|
46
|
+
yield item
|
|
47
|
+
|
|
48
|
+
bookmark = data.get("bookmark")
|
|
49
|
+
if not bookmark:
|
|
50
|
+
break
|
|
51
|
+
|
|
52
|
+
@dlt.resource(write_disposition="merge", primary_key="id")
|
|
53
|
+
def pins(
|
|
54
|
+
datetime=dlt.sources.incremental(
|
|
55
|
+
"created_at",
|
|
56
|
+
initial_value=start_date,
|
|
57
|
+
end_value=end_date,
|
|
58
|
+
),
|
|
59
|
+
) -> Iterable[TDataItem]:
|
|
60
|
+
_start_date = datetime.last_value or start_date
|
|
61
|
+
if end_date is None:
|
|
62
|
+
_end_date = pendulum.now("UTC")
|
|
63
|
+
else:
|
|
64
|
+
_end_date = datetime.end_value
|
|
65
|
+
yield from fetch_data("pins", _start_date, _end_date)
|
|
66
|
+
|
|
67
|
+
@dlt.resource(write_disposition="merge", primary_key="id")
|
|
68
|
+
def boards(
|
|
69
|
+
datetime=dlt.sources.incremental(
|
|
70
|
+
"created_at",
|
|
71
|
+
initial_value=start_date,
|
|
72
|
+
end_value=end_date,
|
|
73
|
+
),
|
|
74
|
+
) -> Iterable[TDataItem]:
|
|
75
|
+
_start_date = datetime.last_value or start_date
|
|
76
|
+
if end_date is None:
|
|
77
|
+
_end_date = pendulum.now("UTC")
|
|
78
|
+
else:
|
|
79
|
+
_end_date = datetime.end_value
|
|
80
|
+
yield from fetch_data("boards", _start_date, _end_date)
|
|
81
|
+
|
|
82
|
+
return pins, boards
|
|
@@ -16,7 +16,7 @@ from typing import (
|
|
|
16
16
|
TypeAlias,
|
|
17
17
|
Union,
|
|
18
18
|
)
|
|
19
|
-
from urllib.parse import ParseResult, parse_qs,
|
|
19
|
+
from urllib.parse import ParseResult, parse_qs, urlencode, urlparse
|
|
20
20
|
|
|
21
21
|
import fsspec # type: ignore
|
|
22
22
|
import pendulum
|
|
@@ -699,9 +699,7 @@ class StripeAnalyticsSource:
|
|
|
699
699
|
)
|
|
700
700
|
|
|
701
701
|
if incremental and not sync:
|
|
702
|
-
raise ValueError(
|
|
703
|
-
"incremental loads must be used with sync loading"
|
|
704
|
-
)
|
|
702
|
+
raise ValueError("incremental loads must be used with sync loading")
|
|
705
703
|
|
|
706
704
|
if incremental:
|
|
707
705
|
from ingestr.src.stripe_analytics import incremental_stripe_source
|
|
@@ -1370,7 +1368,7 @@ class S3Source:
|
|
|
1370
1368
|
)
|
|
1371
1369
|
|
|
1372
1370
|
parsed_uri = urlparse(uri)
|
|
1373
|
-
source_fields = parse_qs(
|
|
1371
|
+
source_fields = parse_qs(parsed_uri.query)
|
|
1374
1372
|
access_key_id = source_fields.get("access_key_id")
|
|
1375
1373
|
if not access_key_id:
|
|
1376
1374
|
raise ValueError("access_key_id is required to connect to S3")
|
|
@@ -1599,7 +1597,7 @@ class DynamoDBSource:
|
|
|
1599
1597
|
if not region:
|
|
1600
1598
|
raise ValueError("region is required to connect to Dynamodb")
|
|
1601
1599
|
|
|
1602
|
-
qs = parse_qs(
|
|
1600
|
+
qs = parse_qs(parsed_uri.query)
|
|
1603
1601
|
access_key = qs.get("access_key_id")
|
|
1604
1602
|
|
|
1605
1603
|
if not access_key:
|
|
@@ -2783,3 +2781,72 @@ class QuickBooksSource:
|
|
|
2783
2781
|
minor_version=minor_version[0],
|
|
2784
2782
|
object=table_name,
|
|
2785
2783
|
).with_resources(table_name)
|
|
2784
|
+
|
|
2785
|
+
|
|
2786
|
+
class IsocPulseSource:
|
|
2787
|
+
def handles_incrementality(self) -> bool:
|
|
2788
|
+
return True
|
|
2789
|
+
|
|
2790
|
+
def dlt_source(self, uri: str, table: str, **kwargs):
|
|
2791
|
+
parsed_uri = urlparse(uri)
|
|
2792
|
+
params = parse_qs(parsed_uri.query)
|
|
2793
|
+
token = params.get("token")
|
|
2794
|
+
if not token or not token[0].strip():
|
|
2795
|
+
raise MissingValueError("token", "Internet Society Pulse")
|
|
2796
|
+
|
|
2797
|
+
start_date = kwargs.get("interval_start")
|
|
2798
|
+
if start_date is None:
|
|
2799
|
+
start_date = pendulum.now().in_tz("UTC").subtract(days=30)
|
|
2800
|
+
|
|
2801
|
+
end_date = kwargs.get("interval_end")
|
|
2802
|
+
|
|
2803
|
+
metric = table
|
|
2804
|
+
opts = []
|
|
2805
|
+
if ":" in metric:
|
|
2806
|
+
metric, *opts = metric.strip().split(":")
|
|
2807
|
+
opts = [opt.strip() for opt in opts]
|
|
2808
|
+
|
|
2809
|
+
from ingestr.src.isoc_pulse import pulse_source
|
|
2810
|
+
|
|
2811
|
+
src = pulse_source(
|
|
2812
|
+
token=token[0],
|
|
2813
|
+
start_date=start_date.strftime("%Y-%m-%d"),
|
|
2814
|
+
end_date=str(end_date) if end_date else None,
|
|
2815
|
+
metric=metric,
|
|
2816
|
+
opts=opts,
|
|
2817
|
+
)
|
|
2818
|
+
return src.with_resources(metric)
|
|
2819
|
+
|
|
2820
|
+
|
|
2821
|
+
class PinterestSource:
|
|
2822
|
+
def handles_incrementality(self) -> bool:
|
|
2823
|
+
return True
|
|
2824
|
+
|
|
2825
|
+
def dlt_source(self, uri: str, table: str, **kwargs):
|
|
2826
|
+
parsed = urlparse(uri)
|
|
2827
|
+
params = parse_qs(parsed.query)
|
|
2828
|
+
access_token = params.get("access_token")
|
|
2829
|
+
|
|
2830
|
+
if not access_token:
|
|
2831
|
+
raise MissingValueError("access_token", "Pinterest")
|
|
2832
|
+
|
|
2833
|
+
start_date = kwargs.get("interval_start")
|
|
2834
|
+
if start_date is not None:
|
|
2835
|
+
start_date = ensure_pendulum_datetime(start_date)
|
|
2836
|
+
else:
|
|
2837
|
+
start_date = pendulum.datetime(2020, 1, 1).in_tz("UTC")
|
|
2838
|
+
|
|
2839
|
+
end_date = kwargs.get("interval_end")
|
|
2840
|
+
if end_date is not None:
|
|
2841
|
+
end_date = end_date = ensure_pendulum_datetime(end_date).in_tz("UTC")
|
|
2842
|
+
|
|
2843
|
+
from ingestr.src.pinterest import pinterest_source
|
|
2844
|
+
|
|
2845
|
+
if table not in {"pins", "boards"}:
|
|
2846
|
+
raise UnsupportedResourceError(table, "Pinterest")
|
|
2847
|
+
|
|
2848
|
+
return pinterest_source(
|
|
2849
|
+
access_token=access_token[0],
|
|
2850
|
+
start_date=start_date,
|
|
2851
|
+
end_date=end_date,
|
|
2852
|
+
).with_resources(table)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
version = "v0.13.57"
|
|
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
|