ingestr 0.13.5__tar.gz → 0.13.7__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.

Files changed (223) hide show
  1. {ingestr-0.13.5 → ingestr-0.13.7}/.github/workflows/release.yml +2 -0
  2. {ingestr-0.13.5 → ingestr-0.13.7}/PKG-INFO +1 -1
  3. {ingestr-0.13.5 → ingestr-0.13.7}/docs/.vitepress/config.mjs +1 -0
  4. ingestr-0.13.7/docs/media/applovin_max.png +0 -0
  5. ingestr-0.13.7/docs/supported-sources/applovin_max.md +36 -0
  6. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/applovin/__init__.py +22 -43
  7. ingestr-0.13.7/ingestr/src/applovin_max/__init__.py +99 -0
  8. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/blob.py +1 -1
  9. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/factory.py +2 -0
  10. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/sources.py +46 -0
  11. {ingestr-0.13.5 → ingestr-0.13.7}/.dockerignore +0 -0
  12. {ingestr-0.13.5 → ingestr-0.13.7}/.githooks/pre-commit-hook.sh +0 -0
  13. {ingestr-0.13.5 → ingestr-0.13.7}/.github/workflows/deploy-docs.yml +0 -0
  14. {ingestr-0.13.5 → ingestr-0.13.7}/.github/workflows/secrets-scan.yml +0 -0
  15. {ingestr-0.13.5 → ingestr-0.13.7}/.github/workflows/tests.yml +0 -0
  16. {ingestr-0.13.5 → ingestr-0.13.7}/.gitignore +0 -0
  17. {ingestr-0.13.5 → ingestr-0.13.7}/.gitleaksignore +0 -0
  18. {ingestr-0.13.5 → ingestr-0.13.7}/.python-version +0 -0
  19. {ingestr-0.13.5 → ingestr-0.13.7}/.vale.ini +0 -0
  20. {ingestr-0.13.5 → ingestr-0.13.7}/Dockerfile +0 -0
  21. {ingestr-0.13.5 → ingestr-0.13.7}/LICENSE.md +0 -0
  22. {ingestr-0.13.5 → ingestr-0.13.7}/Makefile +0 -0
  23. {ingestr-0.13.5 → ingestr-0.13.7}/README.md +0 -0
  24. {ingestr-0.13.5 → ingestr-0.13.7}/docs/.vitepress/theme/custom.css +0 -0
  25. {ingestr-0.13.5 → ingestr-0.13.7}/docs/.vitepress/theme/index.js +0 -0
  26. {ingestr-0.13.5 → ingestr-0.13.7}/docs/commands/example-uris.md +0 -0
  27. {ingestr-0.13.5 → ingestr-0.13.7}/docs/commands/ingest.md +0 -0
  28. {ingestr-0.13.5 → ingestr-0.13.7}/docs/getting-started/core-concepts.md +0 -0
  29. {ingestr-0.13.5 → ingestr-0.13.7}/docs/getting-started/incremental-loading.md +0 -0
  30. {ingestr-0.13.5 → ingestr-0.13.7}/docs/getting-started/quickstart.md +0 -0
  31. {ingestr-0.13.5 → ingestr-0.13.7}/docs/getting-started/telemetry.md +0 -0
  32. {ingestr-0.13.5 → ingestr-0.13.7}/docs/index.md +0 -0
  33. {ingestr-0.13.5 → ingestr-0.13.7}/docs/media/athena.png +0 -0
  34. {ingestr-0.13.5 → ingestr-0.13.7}/docs/media/clickhouse_img.png +0 -0
  35. {ingestr-0.13.5 → ingestr-0.13.7}/docs/media/github.png +0 -0
  36. {ingestr-0.13.5 → ingestr-0.13.7}/docs/media/googleanalytics.png +0 -0
  37. {ingestr-0.13.5 → ingestr-0.13.7}/docs/media/linkedin_ads.png +0 -0
  38. {ingestr-0.13.5 → ingestr-0.13.7}/docs/media/tiktok.png +0 -0
  39. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/adjust.md +0 -0
  40. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/airtable.md +0 -0
  41. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/applovin.md +0 -0
  42. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/appsflyer.md +0 -0
  43. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/appstore.md +0 -0
  44. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/asana.md +0 -0
  45. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/athena.md +0 -0
  46. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/bigquery.md +0 -0
  47. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/chess.md +0 -0
  48. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/clickhouse.md +0 -0
  49. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/csv.md +0 -0
  50. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/custom_queries.md +0 -0
  51. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/databricks.md +0 -0
  52. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/duckdb.md +0 -0
  53. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/dynamodb.md +0 -0
  54. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/facebook-ads.md +0 -0
  55. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/gcs.md +0 -0
  56. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/github.md +0 -0
  57. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/google-ads.md +0 -0
  58. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/google_analytics.md +0 -0
  59. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/gorgias.md +0 -0
  60. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/gsheets.md +0 -0
  61. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/hubspot.md +0 -0
  62. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/kafka.md +0 -0
  63. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/klaviyo.md +0 -0
  64. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/linkedin_ads.md +0 -0
  65. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/mongodb.md +0 -0
  66. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/mssql.md +0 -0
  67. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/mysql.md +0 -0
  68. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/notion.md +0 -0
  69. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/oracle.md +0 -0
  70. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/postgres.md +0 -0
  71. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/redshift.md +0 -0
  72. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/s3.md +0 -0
  73. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/sap-hana.md +0 -0
  74. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/shopify.md +0 -0
  75. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/slack.md +0 -0
  76. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/snowflake.md +0 -0
  77. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/sqlite.md +0 -0
  78. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/stripe.md +0 -0
  79. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/tiktok-ads.md +0 -0
  80. {ingestr-0.13.5 → ingestr-0.13.7}/docs/supported-sources/zendesk.md +0 -0
  81. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/main.py +0 -0
  82. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/.gitignore +0 -0
  83. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/adjust/__init__.py +0 -0
  84. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/adjust/adjust_helpers.py +0 -0
  85. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/airtable/__init__.py +0 -0
  86. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/appsflyer/_init_.py +0 -0
  87. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/appsflyer/client.py +0 -0
  88. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/appstore/__init__.py +0 -0
  89. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/appstore/client.py +0 -0
  90. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/appstore/errors.py +0 -0
  91. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/appstore/models.py +0 -0
  92. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/appstore/resources.py +0 -0
  93. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/arrow/__init__.py +0 -0
  94. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/asana_source/__init__.py +0 -0
  95. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/asana_source/helpers.py +0 -0
  96. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/asana_source/settings.py +0 -0
  97. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/chess/__init__.py +0 -0
  98. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/chess/helpers.py +0 -0
  99. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/chess/settings.py +0 -0
  100. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/destinations.py +0 -0
  101. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/dynamodb/__init__.py +0 -0
  102. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/errors.py +0 -0
  103. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/facebook_ads/__init__.py +0 -0
  104. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/facebook_ads/exceptions.py +0 -0
  105. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/facebook_ads/helpers.py +0 -0
  106. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/facebook_ads/settings.py +0 -0
  107. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/filesystem/__init__.py +0 -0
  108. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/filesystem/helpers.py +0 -0
  109. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/filesystem/readers.py +0 -0
  110. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/filters.py +0 -0
  111. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/github/__init__.py +0 -0
  112. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/github/helpers.py +0 -0
  113. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/github/queries.py +0 -0
  114. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/github/settings.py +0 -0
  115. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/google_ads/__init__.py +0 -0
  116. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/google_ads/field.py +0 -0
  117. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/google_ads/metrics.py +0 -0
  118. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/google_ads/predicates.py +0 -0
  119. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/google_ads/reports.py +0 -0
  120. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/google_analytics/__init__.py +0 -0
  121. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/google_analytics/helpers.py +0 -0
  122. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/google_sheets/README.md +0 -0
  123. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/google_sheets/__init__.py +0 -0
  124. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/google_sheets/helpers/__init__.py +0 -0
  125. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/google_sheets/helpers/api_calls.py +0 -0
  126. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/google_sheets/helpers/data_processing.py +0 -0
  127. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/gorgias/__init__.py +0 -0
  128. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/gorgias/helpers.py +0 -0
  129. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/hubspot/__init__.py +0 -0
  130. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/hubspot/helpers.py +0 -0
  131. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/hubspot/settings.py +0 -0
  132. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/kafka/__init__.py +0 -0
  133. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/kafka/helpers.py +0 -0
  134. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/klaviyo/_init_.py +0 -0
  135. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/klaviyo/client.py +0 -0
  136. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/klaviyo/helpers.py +0 -0
  137. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/linkedin_ads/__init__.py +0 -0
  138. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/linkedin_ads/dimension_time_enum.py +0 -0
  139. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/linkedin_ads/helpers.py +0 -0
  140. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/loader.py +0 -0
  141. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/mongodb/__init__.py +0 -0
  142. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/mongodb/helpers.py +0 -0
  143. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/notion/__init__.py +0 -0
  144. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/notion/helpers/__init__.py +0 -0
  145. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/notion/helpers/client.py +0 -0
  146. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/notion/helpers/database.py +0 -0
  147. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/notion/settings.py +0 -0
  148. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/shopify/__init__.py +0 -0
  149. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/shopify/exceptions.py +0 -0
  150. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/shopify/helpers.py +0 -0
  151. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/shopify/settings.py +0 -0
  152. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/slack/__init__.py +0 -0
  153. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/slack/helpers.py +0 -0
  154. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/slack/settings.py +0 -0
  155. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/sql_database/__init__.py +0 -0
  156. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/sql_database/callbacks.py +0 -0
  157. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/stripe_analytics/__init__.py +0 -0
  158. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/stripe_analytics/helpers.py +0 -0
  159. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/stripe_analytics/settings.py +0 -0
  160. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/table_definition.py +0 -0
  161. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/telemetry/event.py +0 -0
  162. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/testdata/fakebqcredentials.json +0 -0
  163. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/tiktok_ads/__init__.py +0 -0
  164. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/tiktok_ads/tiktok_helpers.py +0 -0
  165. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/time.py +0 -0
  166. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/version.py +0 -0
  167. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/zendesk/__init__.py +0 -0
  168. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/zendesk/helpers/__init__.py +0 -0
  169. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/zendesk/helpers/api_helpers.py +0 -0
  170. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/zendesk/helpers/credentials.py +0 -0
  171. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/zendesk/helpers/talk_api.py +0 -0
  172. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/src/zendesk/settings.py +0 -0
  173. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/testdata/.gitignore +0 -0
  174. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/testdata/create_replace.csv +0 -0
  175. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/testdata/delete_insert_expected.csv +0 -0
  176. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/testdata/delete_insert_part1.csv +0 -0
  177. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/testdata/delete_insert_part2.csv +0 -0
  178. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/testdata/merge_expected.csv +0 -0
  179. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/testdata/merge_part1.csv +0 -0
  180. {ingestr-0.13.5 → ingestr-0.13.7}/ingestr/testdata/merge_part2.csv +0 -0
  181. {ingestr-0.13.5 → ingestr-0.13.7}/package-lock.json +0 -0
  182. {ingestr-0.13.5 → ingestr-0.13.7}/package.json +0 -0
  183. {ingestr-0.13.5 → ingestr-0.13.7}/pyproject.toml +0 -0
  184. {ingestr-0.13.5 → ingestr-0.13.7}/requirements-dev.txt +0 -0
  185. {ingestr-0.13.5 → ingestr-0.13.7}/requirements.txt +0 -0
  186. {ingestr-0.13.5 → ingestr-0.13.7}/resources/demo.gif +0 -0
  187. {ingestr-0.13.5 → ingestr-0.13.7}/resources/demo.tape +0 -0
  188. {ingestr-0.13.5 → ingestr-0.13.7}/resources/ingestr.svg +0 -0
  189. {ingestr-0.13.5 → ingestr-0.13.7}/styles/Google/AMPM.yml +0 -0
  190. {ingestr-0.13.5 → ingestr-0.13.7}/styles/Google/Acronyms.yml +0 -0
  191. {ingestr-0.13.5 → ingestr-0.13.7}/styles/Google/Colons.yml +0 -0
  192. {ingestr-0.13.5 → ingestr-0.13.7}/styles/Google/Contractions.yml +0 -0
  193. {ingestr-0.13.5 → ingestr-0.13.7}/styles/Google/DateFormat.yml +0 -0
  194. {ingestr-0.13.5 → ingestr-0.13.7}/styles/Google/Ellipses.yml +0 -0
  195. {ingestr-0.13.5 → ingestr-0.13.7}/styles/Google/EmDash.yml +0 -0
  196. {ingestr-0.13.5 → ingestr-0.13.7}/styles/Google/Exclamation.yml +0 -0
  197. {ingestr-0.13.5 → ingestr-0.13.7}/styles/Google/FirstPerson.yml +0 -0
  198. {ingestr-0.13.5 → ingestr-0.13.7}/styles/Google/Gender.yml +0 -0
  199. {ingestr-0.13.5 → ingestr-0.13.7}/styles/Google/GenderBias.yml +0 -0
  200. {ingestr-0.13.5 → ingestr-0.13.7}/styles/Google/HeadingPunctuation.yml +0 -0
  201. {ingestr-0.13.5 → ingestr-0.13.7}/styles/Google/Headings.yml +0 -0
  202. {ingestr-0.13.5 → ingestr-0.13.7}/styles/Google/Latin.yml +0 -0
  203. {ingestr-0.13.5 → ingestr-0.13.7}/styles/Google/LyHyphens.yml +0 -0
  204. {ingestr-0.13.5 → ingestr-0.13.7}/styles/Google/OptionalPlurals.yml +0 -0
  205. {ingestr-0.13.5 → ingestr-0.13.7}/styles/Google/Ordinal.yml +0 -0
  206. {ingestr-0.13.5 → ingestr-0.13.7}/styles/Google/OxfordComma.yml +0 -0
  207. {ingestr-0.13.5 → ingestr-0.13.7}/styles/Google/Parens.yml +0 -0
  208. {ingestr-0.13.5 → ingestr-0.13.7}/styles/Google/Passive.yml +0 -0
  209. {ingestr-0.13.5 → ingestr-0.13.7}/styles/Google/Periods.yml +0 -0
  210. {ingestr-0.13.5 → ingestr-0.13.7}/styles/Google/Quotes.yml +0 -0
  211. {ingestr-0.13.5 → ingestr-0.13.7}/styles/Google/Ranges.yml +0 -0
  212. {ingestr-0.13.5 → ingestr-0.13.7}/styles/Google/Semicolons.yml +0 -0
  213. {ingestr-0.13.5 → ingestr-0.13.7}/styles/Google/Slang.yml +0 -0
  214. {ingestr-0.13.5 → ingestr-0.13.7}/styles/Google/Spacing.yml +0 -0
  215. {ingestr-0.13.5 → ingestr-0.13.7}/styles/Google/Spelling.yml +0 -0
  216. {ingestr-0.13.5 → ingestr-0.13.7}/styles/Google/Units.yml +0 -0
  217. {ingestr-0.13.5 → ingestr-0.13.7}/styles/Google/We.yml +0 -0
  218. {ingestr-0.13.5 → ingestr-0.13.7}/styles/Google/Will.yml +0 -0
  219. {ingestr-0.13.5 → ingestr-0.13.7}/styles/Google/WordList.yml +0 -0
  220. {ingestr-0.13.5 → ingestr-0.13.7}/styles/Google/meta.json +0 -0
  221. {ingestr-0.13.5 → ingestr-0.13.7}/styles/Google/vocab.txt +0 -0
  222. {ingestr-0.13.5 → ingestr-0.13.7}/styles/bruin/Ingestr.yml +0 -0
  223. {ingestr-0.13.5 → ingestr-0.13.7}/styles/config/vocabularies/bruin/accept.txt +0 -0
@@ -1,3 +1,5 @@
1
+ # WARN: this is used as a notification filter in our slack.
2
+ # When updating this, make sure to update the workflow subscription as well.
1
3
  name: "Release ingestr on pip and ghcr.io"
2
4
 
3
5
  on:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ingestr
3
- Version: 0.13.5
3
+ Version: 0.13.7
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
@@ -97,6 +97,7 @@ export default defineConfig({
97
97
  { text: "AppsFlyer", link: "/supported-sources/appsflyer.md" },
98
98
  { text: "Apple App Store", link: "/supported-sources/appstore.md"},
99
99
  { text: "Applovin", link: "/supported-sources/applovin.md"},
100
+ { text: "Applovin Max", link: "/supported-sources/applovin_max.md"},
100
101
  { text: "Asana", link: "/supported-sources/asana.md" },
101
102
  { text: "Chess.com", link: "/supported-sources/chess.md" },
102
103
  { text: "DynamoDB", link: "/supported-sources/dynamodb.md" },
@@ -0,0 +1,36 @@
1
+ # Applovin Max
2
+ [AppLovin Max](https://developers.applovin.com/en/max/getting-started/) is a tool from AppLovin that helps app developers optimize ad revenue by selecting the highest-paying ads from various ad networks.
3
+
4
+ `ingestr` allows ingesting data from AppLovin Max reporting API.
5
+
6
+ ## URI Format
7
+ The URI format for Applovin Max is as follows:
8
+ ```
9
+ applovinmax://?api_key=<your_api_key>&application=<application_name>
10
+ ```
11
+
12
+ URI Parameters:
13
+ - `api_key`: It is the `report key` which is used for authenticating the request.
14
+ - `application`: The application package name (for Android and Fire OS) or bundle ID (for iOS).
15
+
16
+ ## Setting up Applovin Integration
17
+
18
+ ### Generate a Report Key
19
+ You can generate a report key from your [AppLovin dashboard](https://developers.applovin.com/en/max/max-dashboard/account/account-info/#keys).
20
+
21
+ ### Example:
22
+ To retrieve `ad revenue` data for an application `com.example.app` with api key `key_123`, and to store it in a DuckDB database, use the following command:
23
+
24
+ ```sh
25
+ ingestr ingest \
26
+ --source-uri "applovinmax://?api_key=key_123&application=com.example.app" \
27
+ --source-table "ad_revenue" \
28
+ --dest-uri "duckdb:///applovin_max.db" \
29
+ --dest-table "dest.ad_revenue"
30
+ ```
31
+ By default, `ingestr` retrieves data for the last 30 days. For a custom date range, use the `--interval-start` and `--interval-end` parameters.
32
+
33
+ <img alt="applovin_max_img" src="../media/applovin_max.png"/>
34
+
35
+ ## Table
36
+ [ad_revenue](https://developers.applovin.com/en/max/reporting-apis/user-level-ad-revenue-api/): Provides daily metrics from the user-level ad revenue API.User-level revenue data is available eight hours after UTC day end. So, for example, data for UTC 2025-01-01 is available on UTC 2025-01-02 after 08:00.
@@ -1,6 +1,7 @@
1
- from datetime import datetime, timezone
1
+ from datetime import datetime, timezone, timedelta
2
2
  from enum import Enum
3
3
  from typing import Dict, List, Optional
4
+ from requests import Response
4
5
 
5
6
  import dlt
6
7
  from dlt.sources.rest_api import EndpointResource, RESTAPIConfig, rest_api_resources
@@ -12,11 +13,8 @@ class InvalidCustomReportError(Exception):
12
13
  "Custom report should be in the format 'custom:{endpoint}:{report_type}:{dimensions}"
13
14
  )
14
15
 
15
-
16
- class InvalidDimensionError(Exception):
17
- def __init__(self, dim: str, report_type: str):
18
- super().__init__(f"Unknown dimension {dim} for report type {report_type}")
19
-
16
+ class ClientError(Exception):
17
+ pass
20
18
 
21
19
  TYPE_HINTS = {
22
20
  "application_is_hidden": {"data_type": "bool"},
@@ -108,32 +106,6 @@ REPORT_SCHEMA: Dict[ReportType, List[str]] = {
108
106
  ],
109
107
  }
110
108
 
111
- # NOTE(turtledev): These values are valid columns,
112
- # but often don't produce a value. Find a way to either add
113
- # a default value, or use an alternative strategy to de-duplicate
114
- # OR make them nullable
115
- SKA_REPORT_EXCLUDE = [
116
- "ad",
117
- "ad_id",
118
- "ad_type",
119
- "average_cpc",
120
- "campaign_ad_type",
121
- "clicks",
122
- "conversions",
123
- "conversion_rate",
124
- "creative_set",
125
- "creative_set_id",
126
- "ctr",
127
- "custom_page_id",
128
- "device_type",
129
- "first_purchase",
130
- "impressions",
131
- "placement_type",
132
- "sales",
133
- "size",
134
- "traffic_source",
135
- ]
136
-
137
109
  PROBABILISTIC_REPORT_EXCLUDE = [
138
110
  "installs",
139
111
  "redownloads",
@@ -147,19 +119,16 @@ def applovin_source(
147
119
  end_date: Optional[str],
148
120
  custom: Optional[str],
149
121
  ):
150
- ska_report_columns = exclude(
151
- REPORT_SCHEMA[ReportType.ADVERTISER],
152
- SKA_REPORT_EXCLUDE,
153
- )
154
122
 
155
- probabilistic_report_columns = exclude(
156
- REPORT_SCHEMA[ReportType.ADVERTISER],
157
- PROBABILISTIC_REPORT_EXCLUDE,
158
- )
159
123
  backfill = False
160
124
  if end_date is None:
161
125
  backfill = True
162
- end_date = datetime.now(timezone.utc).date().strftime("%Y-%m-%d")
126
+
127
+ # use the greatest of yesterday and start_date
128
+ end_date = max(
129
+ datetime.now(timezone.utc) - timedelta(days=1),
130
+ datetime.fromisoformat(start_date).replace(tzinfo=timezone.utc)
131
+ ).strftime("%Y-%m-%d")
163
132
 
164
133
  config: RESTAPIConfig = {
165
134
  "client": {
@@ -186,6 +155,9 @@ def applovin_source(
186
155
  "end": end_date,
187
156
  },
188
157
  "paginator": "single_page",
158
+ "response_actions": [
159
+ http_error_handler,
160
+ ]
189
161
  },
190
162
  },
191
163
  "resources": [
@@ -204,13 +176,16 @@ def applovin_source(
204
176
  resource(
205
177
  "advertiser-probabilistic-report",
206
178
  "probabilisticReport",
207
- probabilistic_report_columns,
179
+ exclude(
180
+ REPORT_SCHEMA[ReportType.ADVERTISER],
181
+ PROBABILISTIC_REPORT_EXCLUDE
182
+ ),
208
183
  ReportType.ADVERTISER,
209
184
  ),
210
185
  resource(
211
186
  "advertiser-ska-report",
212
187
  "skaReport",
213
- ska_report_columns,
188
+ REPORT_SCHEMA[ReportType.ADVERTISER],
214
189
  ReportType.ADVERTISER,
215
190
  ),
216
191
  ],
@@ -280,3 +255,7 @@ def exclude(source: List[str], exclude_list: List[str]) -> List[str]:
280
255
 
281
256
  def build_type_hints(cols: List[str]) -> dict:
282
257
  return {col: TYPE_HINTS[col] for col in cols if col in TYPE_HINTS}
258
+
259
+ def http_error_handler(resp: Response):
260
+ if not resp.ok:
261
+ raise ClientError(f"HTTP Status {resp.status_code}: {resp.text}")
@@ -0,0 +1,99 @@
1
+ from typing import Iterator
2
+
3
+ import dlt
4
+ import pandas as pd # type: ignore[import-untyped]
5
+ import pendulum
6
+ import requests
7
+ from dlt.sources import DltResource
8
+ from dlt.sources.helpers.requests import Client
9
+ from pendulum.date import Date
10
+
11
+
12
+ @dlt.source(max_table_nesting=0)
13
+ def applovin_max_source(
14
+ start_date: str,
15
+ application: str,
16
+ api_key: str,
17
+ end_date: str | None,
18
+ ) -> DltResource:
19
+ @dlt.resource(
20
+ name="ad_revenue",
21
+ write_disposition="merge",
22
+ merge_key="_partition_date",
23
+ )
24
+ def fetch_ad_revenue_report(
25
+ dateTime=(
26
+ dlt.sources.incremental(
27
+ "_partition_date",
28
+ initial_value=start_date,
29
+ end_value=end_date,
30
+ range_start="closed",
31
+ range_end="closed",
32
+ )
33
+ ),
34
+ ) -> Iterator[dict]:
35
+ url = "https://r.applovin.com/max/userAdRevenueReport"
36
+ start_date = pendulum.from_format(dateTime.last_value, "YYYY-MM-DD").date()
37
+ if dateTime.end_value is None:
38
+ end_date = (pendulum.yesterday("UTC")).date()
39
+ else:
40
+ end_date = pendulum.from_format(dateTime.end_value, "YYYY-MM-DD").date()
41
+ yield get_data(
42
+ url=url,
43
+ start_date=start_date,
44
+ end_date=end_date,
45
+ application=application,
46
+ api_key=api_key,
47
+ )
48
+
49
+ return fetch_ad_revenue_report
50
+
51
+
52
+ def create_client() -> requests.Session:
53
+ return Client(
54
+ request_timeout=10.0,
55
+ raise_for_status=False,
56
+ retry_condition=retry_on_limit,
57
+ request_max_attempts=12,
58
+ ).session
59
+
60
+
61
+ def retry_on_limit(
62
+ response: requests.Response | None, exception: BaseException | None
63
+ ) -> bool:
64
+ if response is None:
65
+ return False
66
+ return response.status_code == 429
67
+
68
+
69
+ def get_data(
70
+ url: str, start_date: Date, end_date: Date, application: str, api_key: str
71
+ ):
72
+ client = create_client()
73
+ platforms = ["ios", "android", "fireos"]
74
+ current_date = start_date
75
+ while current_date <= end_date:
76
+ for platform in platforms:
77
+ params = {
78
+ "api_key": api_key,
79
+ "date": current_date.strftime("%Y-%m-%d"),
80
+ "platform": platform,
81
+ "application": application,
82
+ "aggregated": "false",
83
+ }
84
+
85
+ response = client.get(url=url, params=params)
86
+
87
+ if response.status_code == 400:
88
+ raise ValueError(response.text)
89
+
90
+ if response.status_code != 200:
91
+ continue
92
+
93
+ response_url = response.json().get("ad_revenue_report_url")
94
+ df = pd.read_csv(response_url)
95
+ df["Date"] = pd.to_datetime(df["Date"])
96
+ df["_partition_date"] = df["Date"].dt.strftime("%Y-%m-%d")
97
+ yield df
98
+
99
+ current_date = current_date.add(days=1)
@@ -26,7 +26,7 @@ def parse_uri(uri: ParseResult, table: str) -> Tuple[BucketName, FileGlob]:
26
26
  table = table.strip()
27
27
  host = uri.netloc.strip()
28
28
 
29
- if table == "":
29
+ if table == "" or uri.path.strip() != "":
30
30
  warnings.warn(
31
31
  f"Using the form '{uri.scheme}://bucket-name/file-glob' is deprecated and will be removed in future versions.",
32
32
  DeprecationWarning,
@@ -20,6 +20,7 @@ from ingestr.src.sources import (
20
20
  AdjustSource,
21
21
  AirtableSource,
22
22
  AppleAppStoreSource,
23
+ ApplovinMaxSource,
23
24
  AppLovinSource,
24
25
  AppsflyerSource,
25
26
  ArrowMemoryMappedSource,
@@ -134,6 +135,7 @@ class SourceDestinationFactory:
134
135
  "gs": GCSSource,
135
136
  "linkedinads": LinkedInAdsSource,
136
137
  "applovin": AppLovinSource,
138
+ "applovinmax": ApplovinMaxSource,
137
139
  }
138
140
  destinations: Dict[str, Type[DestinationProtocol]] = {
139
141
  "bigquery": BigQueryDestination,
@@ -51,6 +51,7 @@ from ingestr.src.adjust import REQUIRED_CUSTOM_DIMENSIONS, adjust_source
51
51
  from ingestr.src.adjust.adjust_helpers import parse_filters
52
52
  from ingestr.src.airtable import airtable_source
53
53
  from ingestr.src.applovin import applovin_source
54
+ from ingestr.src.applovin_max import applovin_max_source
54
55
  from ingestr.src.appsflyer._init_ import appsflyer_source
55
56
  from ingestr.src.appstore import app_store
56
57
  from ingestr.src.appstore.client import AppStoreConnectClient
@@ -1787,3 +1788,48 @@ class AppLovinSource:
1787
1788
  raise UnsupportedResourceError(table, "AppLovin")
1788
1789
 
1789
1790
  return src.with_resources(table)
1791
+
1792
+
1793
+ class ApplovinMaxSource:
1794
+ def handles_incrementality(self) -> bool:
1795
+ return True
1796
+
1797
+ def dlt_source(self, uri: str, table: str, **kwargs):
1798
+ parsed_uri = urlparse(uri)
1799
+ params = parse_qs(parsed_uri.query)
1800
+
1801
+ api_key = params.get("api_key")
1802
+ if api_key is None:
1803
+ raise ValueError("api_key is required to connect to AppLovin Max API.")
1804
+
1805
+ application = params.get("application")
1806
+ if application is None:
1807
+ raise ValueError("application is required to connect to AppLovin Max API.")
1808
+
1809
+ interval_start = kwargs.get("interval_start")
1810
+ interval_end = kwargs.get("interval_end")
1811
+
1812
+ if "ad_revenue" in table:
1813
+ table = "ad_revenue"
1814
+ else:
1815
+ raise ValueError(
1816
+ f"Table name '{table}' is not supported for AppLovin Max source yet, if you are interested in it please create a GitHub issue at https://github.com/bruin-data/ingestr"
1817
+ )
1818
+
1819
+ now = pendulum.now("UTC")
1820
+ default_start = now.subtract(days=30).date()
1821
+
1822
+ start_date = (
1823
+ interval_start if interval_start is not None else default_start
1824
+ ).strftime("%Y-%m-%d")
1825
+
1826
+ end_date = (
1827
+ interval_end.strftime("%Y-%m-%d") if interval_end is not None else None
1828
+ )
1829
+
1830
+ return applovin_max_source(
1831
+ start_date=start_date,
1832
+ end_date=end_date,
1833
+ api_key=api_key[0],
1834
+ application=application[0],
1835
+ ).with_resources(table)
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