ingestr 0.13.70__tar.gz → 0.13.72__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.
Files changed (318) hide show
  1. {ingestr-0.13.70 → ingestr-0.13.72}/PKG-INFO +2 -2
  2. {ingestr-0.13.70 → ingestr-0.13.72}/docs/.vitepress/config.mjs +1 -0
  3. ingestr-0.13.72/docs/media/clickup_ingestion.png +0 -0
  4. ingestr-0.13.72/docs/supported-sources/clickup.md +45 -0
  5. ingestr-0.13.72/ingestr/src/buildinfo.py +1 -0
  6. ingestr-0.13.72/ingestr/src/clickup/__init__.py +85 -0
  7. ingestr-0.13.72/ingestr/src/clickup/helpers.py +47 -0
  8. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/facebook_ads/__init__.py +9 -8
  9. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/facebook_ads/helpers.py +11 -31
  10. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/factory.py +2 -0
  11. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/shopify/__init__.py +0 -16
  12. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/solidgate/__init__.py +4 -8
  13. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/solidgate/helpers.py +13 -5
  14. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/sources.py +35 -0
  15. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/tiktok_ads/__init__.py +8 -6
  16. {ingestr-0.13.70 → ingestr-0.13.72}/pyproject.toml +2 -0
  17. {ingestr-0.13.70 → ingestr-0.13.72}/requirements.in +1 -1
  18. {ingestr-0.13.70 → ingestr-0.13.72}/requirements.txt +1 -1
  19. {ingestr-0.13.70 → ingestr-0.13.72}/requirements_arm64.txt +1 -1
  20. ingestr-0.13.70/ingestr/src/buildinfo.py +0 -1
  21. {ingestr-0.13.70 → ingestr-0.13.72}/.dlt/config.toml +0 -0
  22. {ingestr-0.13.70 → ingestr-0.13.72}/.dockerignore +0 -0
  23. {ingestr-0.13.70 → ingestr-0.13.72}/.githooks/pre-commit-hook.sh +0 -0
  24. {ingestr-0.13.70 → ingestr-0.13.72}/.github/workflows/deploy-docs.yml +0 -0
  25. {ingestr-0.13.70 → ingestr-0.13.72}/.github/workflows/release.yml +0 -0
  26. {ingestr-0.13.70 → ingestr-0.13.72}/.github/workflows/secrets-scan.yml +0 -0
  27. {ingestr-0.13.70 → ingestr-0.13.72}/.github/workflows/tests.yml +0 -0
  28. {ingestr-0.13.70 → ingestr-0.13.72}/.gitignore +0 -0
  29. {ingestr-0.13.70 → ingestr-0.13.72}/.gitleaksignore +0 -0
  30. {ingestr-0.13.70 → ingestr-0.13.72}/.python-version +0 -0
  31. {ingestr-0.13.70 → ingestr-0.13.72}/.vale.ini +0 -0
  32. {ingestr-0.13.70 → ingestr-0.13.72}/Dockerfile +0 -0
  33. {ingestr-0.13.70 → ingestr-0.13.72}/LICENSE.md +0 -0
  34. {ingestr-0.13.70 → ingestr-0.13.72}/Makefile +0 -0
  35. {ingestr-0.13.70 → ingestr-0.13.72}/README.md +0 -0
  36. {ingestr-0.13.70 → ingestr-0.13.72}/docs/.vitepress/theme/custom.css +0 -0
  37. {ingestr-0.13.70 → ingestr-0.13.72}/docs/.vitepress/theme/index.js +0 -0
  38. {ingestr-0.13.70 → ingestr-0.13.72}/docs/commands/example-uris.md +0 -0
  39. {ingestr-0.13.70 → ingestr-0.13.72}/docs/commands/ingest.md +0 -0
  40. {ingestr-0.13.70 → ingestr-0.13.72}/docs/getting-started/core-concepts.md +0 -0
  41. {ingestr-0.13.70 → ingestr-0.13.72}/docs/getting-started/incremental-loading.md +0 -0
  42. {ingestr-0.13.70 → ingestr-0.13.72}/docs/getting-started/quickstart.md +0 -0
  43. {ingestr-0.13.70 → ingestr-0.13.72}/docs/getting-started/telemetry.md +0 -0
  44. {ingestr-0.13.70 → ingestr-0.13.72}/docs/index.md +0 -0
  45. {ingestr-0.13.70 → ingestr-0.13.72}/docs/media/applovin_max.png +0 -0
  46. {ingestr-0.13.70 → ingestr-0.13.72}/docs/media/athena.png +0 -0
  47. {ingestr-0.13.70 → ingestr-0.13.72}/docs/media/clickhouse_img.png +0 -0
  48. {ingestr-0.13.70 → ingestr-0.13.72}/docs/media/cratedb-destination.png +0 -0
  49. {ingestr-0.13.70 → ingestr-0.13.72}/docs/media/cratedb-source.png +0 -0
  50. {ingestr-0.13.70 → ingestr-0.13.72}/docs/media/freshdesk_ingestion.png +0 -0
  51. {ingestr-0.13.70 → ingestr-0.13.72}/docs/media/gcp_spanner_ingestion.png +0 -0
  52. {ingestr-0.13.70 → ingestr-0.13.72}/docs/media/github.png +0 -0
  53. {ingestr-0.13.70 → ingestr-0.13.72}/docs/media/google_analytics_realtime_report.png +0 -0
  54. {ingestr-0.13.70 → ingestr-0.13.72}/docs/media/googleanalytics.png +0 -0
  55. {ingestr-0.13.70 → ingestr-0.13.72}/docs/media/ingestion_elasticsearch_img.png +0 -0
  56. {ingestr-0.13.70 → ingestr-0.13.72}/docs/media/kinesis.bigquery.png +0 -0
  57. {ingestr-0.13.70 → ingestr-0.13.72}/docs/media/linear.png +0 -0
  58. {ingestr-0.13.70 → ingestr-0.13.72}/docs/media/linkedin_ads.png +0 -0
  59. {ingestr-0.13.70 → ingestr-0.13.72}/docs/media/mixpanel_ingestion.png +0 -0
  60. {ingestr-0.13.70 → ingestr-0.13.72}/docs/media/personio.png +0 -0
  61. {ingestr-0.13.70 → ingestr-0.13.72}/docs/media/personio_duckdb.png +0 -0
  62. {ingestr-0.13.70 → ingestr-0.13.72}/docs/media/phantombuster.png +0 -0
  63. {ingestr-0.13.70 → ingestr-0.13.72}/docs/media/pipedrive.png +0 -0
  64. {ingestr-0.13.70 → ingestr-0.13.72}/docs/media/quickbook_ingestion.png +0 -0
  65. {ingestr-0.13.70 → ingestr-0.13.72}/docs/media/sftp.png +0 -0
  66. {ingestr-0.13.70 → ingestr-0.13.72}/docs/media/stripe_postgres.png +0 -0
  67. {ingestr-0.13.70 → ingestr-0.13.72}/docs/media/tiktok.png +0 -0
  68. {ingestr-0.13.70 → ingestr-0.13.72}/docs/media/zoom_ingestion.png +0 -0
  69. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/adjust.md +0 -0
  70. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/airtable.md +0 -0
  71. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/applovin.md +0 -0
  72. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/applovin_max.md +0 -0
  73. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/appsflyer.md +0 -0
  74. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/appstore.md +0 -0
  75. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/asana.md +0 -0
  76. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/athena.md +0 -0
  77. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/attio.md +0 -0
  78. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/bigquery.md +0 -0
  79. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/chess.md +0 -0
  80. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/clickhouse.md +0 -0
  81. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/cratedb.md +0 -0
  82. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/csv.md +0 -0
  83. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/custom_queries.md +0 -0
  84. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/databricks.md +0 -0
  85. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/db2.md +0 -0
  86. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/duckdb.md +0 -0
  87. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/dynamodb.md +0 -0
  88. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/elasticsearch.md +0 -0
  89. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/facebook-ads.md +0 -0
  90. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/frankfurter.md +0 -0
  91. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/freshdesk.md +0 -0
  92. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/gcs.md +0 -0
  93. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/github.md +0 -0
  94. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/google-ads.md +0 -0
  95. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/google_analytics.md +0 -0
  96. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/gorgias.md +0 -0
  97. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/gsheets.md +0 -0
  98. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/hubspot.md +0 -0
  99. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/isoc-pulse.md +0 -0
  100. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/kafka.md +0 -0
  101. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/kinesis.md +0 -0
  102. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/klaviyo.md +0 -0
  103. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/linear.md +0 -0
  104. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/linkedin_ads.md +0 -0
  105. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/mixpanel.md +0 -0
  106. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/mongodb.md +0 -0
  107. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/mssql.md +0 -0
  108. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/mysql.md +0 -0
  109. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/notion.md +0 -0
  110. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/oracle.md +0 -0
  111. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/personio.md +0 -0
  112. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/phantombuster.md +0 -0
  113. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/pinterest.md +0 -0
  114. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/pipedrive.md +0 -0
  115. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/postgres.md +0 -0
  116. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/quickbooks.md +0 -0
  117. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/redshift.md +0 -0
  118. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/s3.md +0 -0
  119. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/salesforce.md +0 -0
  120. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/sap-hana.md +0 -0
  121. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/sftp.md +0 -0
  122. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/shopify.md +0 -0
  123. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/slack.md +0 -0
  124. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/smartsheets.md +0 -0
  125. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/snowflake.md +0 -0
  126. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/solidgate.md +0 -0
  127. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/spanner.md +0 -0
  128. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/sqlite.md +0 -0
  129. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/stripe.md +0 -0
  130. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/tiktok-ads.md +0 -0
  131. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/trustpilot.md +0 -0
  132. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/zendesk.md +0 -0
  133. {ingestr-0.13.70 → ingestr-0.13.72}/docs/supported-sources/zoom.md +0 -0
  134. {ingestr-0.13.70 → ingestr-0.13.72}/docs/tutorials/load-kinesis-bigquery.md +0 -0
  135. {ingestr-0.13.70 → ingestr-0.13.72}/docs/tutorials/load-personio-duckdb.md +0 -0
  136. {ingestr-0.13.70 → ingestr-0.13.72}/docs/tutorials/load-stripe-postgres.md +0 -0
  137. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/conftest.py +0 -0
  138. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/main.py +0 -0
  139. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/.gitignore +0 -0
  140. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/adjust/__init__.py +0 -0
  141. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/adjust/adjust_helpers.py +0 -0
  142. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/airtable/__init__.py +0 -0
  143. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/applovin/__init__.py +0 -0
  144. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/applovin_max/__init__.py +0 -0
  145. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/appsflyer/__init__.py +0 -0
  146. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/appsflyer/client.py +0 -0
  147. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/appstore/__init__.py +0 -0
  148. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/appstore/client.py +0 -0
  149. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/appstore/errors.py +0 -0
  150. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/appstore/models.py +0 -0
  151. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/appstore/resources.py +0 -0
  152. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/arrow/__init__.py +0 -0
  153. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/asana_source/__init__.py +0 -0
  154. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/asana_source/helpers.py +0 -0
  155. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/asana_source/settings.py +0 -0
  156. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/attio/__init__.py +0 -0
  157. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/attio/helpers.py +0 -0
  158. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/blob.py +0 -0
  159. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/chess/__init__.py +0 -0
  160. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/chess/helpers.py +0 -0
  161. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/chess/settings.py +0 -0
  162. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/collector/spinner.py +0 -0
  163. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/destinations.py +0 -0
  164. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/dynamodb/__init__.py +0 -0
  165. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/elasticsearch/__init__.py +0 -0
  166. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/errors.py +0 -0
  167. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/facebook_ads/exceptions.py +0 -0
  168. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/facebook_ads/settings.py +0 -0
  169. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/facebook_ads/utils.py +0 -0
  170. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/filesystem/__init__.py +0 -0
  171. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/filesystem/helpers.py +0 -0
  172. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/filesystem/readers.py +0 -0
  173. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/filters.py +0 -0
  174. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/frankfurter/__init__.py +0 -0
  175. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/frankfurter/helpers.py +0 -0
  176. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/freshdesk/__init__.py +0 -0
  177. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/freshdesk/freshdesk_client.py +0 -0
  178. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/freshdesk/settings.py +0 -0
  179. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/github/__init__.py +0 -0
  180. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/github/helpers.py +0 -0
  181. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/github/queries.py +0 -0
  182. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/github/settings.py +0 -0
  183. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/google_ads/__init__.py +0 -0
  184. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/google_ads/field.py +0 -0
  185. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/google_ads/metrics.py +0 -0
  186. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/google_ads/predicates.py +0 -0
  187. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/google_ads/reports.py +0 -0
  188. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/google_analytics/__init__.py +0 -0
  189. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/google_analytics/helpers.py +0 -0
  190. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/google_sheets/README.md +0 -0
  191. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/google_sheets/__init__.py +0 -0
  192. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/google_sheets/helpers/__init__.py +0 -0
  193. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/google_sheets/helpers/api_calls.py +0 -0
  194. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/google_sheets/helpers/data_processing.py +0 -0
  195. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/gorgias/__init__.py +0 -0
  196. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/gorgias/helpers.py +0 -0
  197. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/http_client.py +0 -0
  198. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/hubspot/__init__.py +0 -0
  199. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/hubspot/helpers.py +0 -0
  200. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/hubspot/settings.py +0 -0
  201. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/isoc_pulse/__init__.py +0 -0
  202. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/kafka/__init__.py +0 -0
  203. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/kafka/helpers.py +0 -0
  204. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/kinesis/__init__.py +0 -0
  205. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/kinesis/helpers.py +0 -0
  206. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/klaviyo/__init__.py +0 -0
  207. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/klaviyo/client.py +0 -0
  208. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/klaviyo/helpers.py +0 -0
  209. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/linear/__init__.py +0 -0
  210. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/linear/helpers.py +0 -0
  211. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/linkedin_ads/__init__.py +0 -0
  212. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/linkedin_ads/dimension_time_enum.py +0 -0
  213. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/linkedin_ads/helpers.py +0 -0
  214. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/loader.py +0 -0
  215. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/mixpanel/__init__.py +0 -0
  216. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/mixpanel/client.py +0 -0
  217. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/mongodb/__init__.py +0 -0
  218. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/mongodb/helpers.py +0 -0
  219. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/notion/__init__.py +0 -0
  220. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/notion/helpers/__init__.py +0 -0
  221. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/notion/helpers/client.py +0 -0
  222. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/notion/helpers/database.py +0 -0
  223. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/notion/settings.py +0 -0
  224. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/partition.py +0 -0
  225. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/personio/__init__.py +0 -0
  226. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/personio/helpers.py +0 -0
  227. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/phantombuster/__init__.py +0 -0
  228. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/phantombuster/client.py +0 -0
  229. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/pinterest/__init__.py +0 -0
  230. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/pipedrive/__init__.py +0 -0
  231. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/pipedrive/helpers/__init__.py +0 -0
  232. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/pipedrive/helpers/custom_fields_munger.py +0 -0
  233. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/pipedrive/helpers/pages.py +0 -0
  234. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/pipedrive/settings.py +0 -0
  235. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/pipedrive/typing.py +0 -0
  236. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/quickbooks/__init__.py +0 -0
  237. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/resource.py +0 -0
  238. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/salesforce/__init__.py +0 -0
  239. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/salesforce/helpers.py +0 -0
  240. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/shopify/exceptions.py +0 -0
  241. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/shopify/helpers.py +0 -0
  242. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/shopify/settings.py +0 -0
  243. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/slack/__init__.py +0 -0
  244. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/slack/helpers.py +0 -0
  245. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/slack/settings.py +0 -0
  246. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/smartsheets/__init__.py +0 -0
  247. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/sql_database/__init__.py +0 -0
  248. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/sql_database/callbacks.py +0 -0
  249. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/stripe_analytics/__init__.py +0 -0
  250. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/stripe_analytics/helpers.py +0 -0
  251. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/stripe_analytics/settings.py +0 -0
  252. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/table_definition.py +0 -0
  253. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/telemetry/event.py +0 -0
  254. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/testdata/fakebqcredentials.json +0 -0
  255. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/tiktok_ads/tiktok_helpers.py +0 -0
  256. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/time.py +0 -0
  257. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/trustpilot/__init__.py +0 -0
  258. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/trustpilot/client.py +0 -0
  259. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/version.py +0 -0
  260. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/zendesk/__init__.py +0 -0
  261. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/zendesk/helpers/__init__.py +0 -0
  262. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/zendesk/helpers/api_helpers.py +0 -0
  263. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/zendesk/helpers/credentials.py +0 -0
  264. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/zendesk/helpers/talk_api.py +0 -0
  265. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/zendesk/settings.py +0 -0
  266. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/zoom/__init__.py +0 -0
  267. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/src/zoom/helpers.py +0 -0
  268. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/testdata/.gitignore +0 -0
  269. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/testdata/create_replace.csv +0 -0
  270. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/testdata/delete_insert_expected.csv +0 -0
  271. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/testdata/delete_insert_part1.csv +0 -0
  272. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/testdata/delete_insert_part2.csv +0 -0
  273. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/testdata/merge_expected.csv +0 -0
  274. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/testdata/merge_part1.csv +0 -0
  275. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/testdata/merge_part2.csv +0 -0
  276. {ingestr-0.13.70 → ingestr-0.13.72}/ingestr/tests/unit/test_smartsheets.py +0 -0
  277. {ingestr-0.13.70 → ingestr-0.13.72}/package-lock.json +0 -0
  278. {ingestr-0.13.70 → ingestr-0.13.72}/package.json +0 -0
  279. {ingestr-0.13.70 → ingestr-0.13.72}/requirements-dev.txt +0 -0
  280. {ingestr-0.13.70 → ingestr-0.13.72}/resources/demo.gif +0 -0
  281. {ingestr-0.13.70 → ingestr-0.13.72}/resources/demo.tape +0 -0
  282. {ingestr-0.13.70 → ingestr-0.13.72}/resources/ingestr.svg +0 -0
  283. {ingestr-0.13.70 → ingestr-0.13.72}/styles/Google/AMPM.yml +0 -0
  284. {ingestr-0.13.70 → ingestr-0.13.72}/styles/Google/Acronyms.yml +0 -0
  285. {ingestr-0.13.70 → ingestr-0.13.72}/styles/Google/Colons.yml +0 -0
  286. {ingestr-0.13.70 → ingestr-0.13.72}/styles/Google/Contractions.yml +0 -0
  287. {ingestr-0.13.70 → ingestr-0.13.72}/styles/Google/DateFormat.yml +0 -0
  288. {ingestr-0.13.70 → ingestr-0.13.72}/styles/Google/Ellipses.yml +0 -0
  289. {ingestr-0.13.70 → ingestr-0.13.72}/styles/Google/EmDash.yml +0 -0
  290. {ingestr-0.13.70 → ingestr-0.13.72}/styles/Google/Exclamation.yml +0 -0
  291. {ingestr-0.13.70 → ingestr-0.13.72}/styles/Google/FirstPerson.yml +0 -0
  292. {ingestr-0.13.70 → ingestr-0.13.72}/styles/Google/Gender.yml +0 -0
  293. {ingestr-0.13.70 → ingestr-0.13.72}/styles/Google/GenderBias.yml +0 -0
  294. {ingestr-0.13.70 → ingestr-0.13.72}/styles/Google/HeadingPunctuation.yml +0 -0
  295. {ingestr-0.13.70 → ingestr-0.13.72}/styles/Google/Headings.yml +0 -0
  296. {ingestr-0.13.70 → ingestr-0.13.72}/styles/Google/Latin.yml +0 -0
  297. {ingestr-0.13.70 → ingestr-0.13.72}/styles/Google/LyHyphens.yml +0 -0
  298. {ingestr-0.13.70 → ingestr-0.13.72}/styles/Google/OptionalPlurals.yml +0 -0
  299. {ingestr-0.13.70 → ingestr-0.13.72}/styles/Google/Ordinal.yml +0 -0
  300. {ingestr-0.13.70 → ingestr-0.13.72}/styles/Google/OxfordComma.yml +0 -0
  301. {ingestr-0.13.70 → ingestr-0.13.72}/styles/Google/Parens.yml +0 -0
  302. {ingestr-0.13.70 → ingestr-0.13.72}/styles/Google/Passive.yml +0 -0
  303. {ingestr-0.13.70 → ingestr-0.13.72}/styles/Google/Periods.yml +0 -0
  304. {ingestr-0.13.70 → ingestr-0.13.72}/styles/Google/Quotes.yml +0 -0
  305. {ingestr-0.13.70 → ingestr-0.13.72}/styles/Google/Ranges.yml +0 -0
  306. {ingestr-0.13.70 → ingestr-0.13.72}/styles/Google/Semicolons.yml +0 -0
  307. {ingestr-0.13.70 → ingestr-0.13.72}/styles/Google/Slang.yml +0 -0
  308. {ingestr-0.13.70 → ingestr-0.13.72}/styles/Google/Spacing.yml +0 -0
  309. {ingestr-0.13.70 → ingestr-0.13.72}/styles/Google/Spelling.yml +0 -0
  310. {ingestr-0.13.70 → ingestr-0.13.72}/styles/Google/Units.yml +0 -0
  311. {ingestr-0.13.70 → ingestr-0.13.72}/styles/Google/We.yml +0 -0
  312. {ingestr-0.13.70 → ingestr-0.13.72}/styles/Google/Will.yml +0 -0
  313. {ingestr-0.13.70 → ingestr-0.13.72}/styles/Google/WordList.yml +0 -0
  314. {ingestr-0.13.70 → ingestr-0.13.72}/styles/Google/meta.json +0 -0
  315. {ingestr-0.13.70 → ingestr-0.13.72}/styles/Google/vocab.txt +0 -0
  316. {ingestr-0.13.70 → ingestr-0.13.72}/styles/bruin/Ingestr.yml +0 -0
  317. {ingestr-0.13.70 → ingestr-0.13.72}/styles/config/vocabularies/bruin/accept.txt +0 -0
  318. {ingestr-0.13.70 → ingestr-0.13.72}/test.env.template +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ingestr
3
- Version: 0.13.70
3
+ Version: 0.13.72
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
@@ -57,7 +57,7 @@ Requires-Dist: elastic-transport==8.17.1
57
57
  Requires-Dist: elasticsearch==8.10.1
58
58
  Requires-Dist: enum-compat==0.0.3
59
59
  Requires-Dist: et-xmlfile==2.0.0
60
- Requires-Dist: facebook-business==20.0.0
60
+ Requires-Dist: facebook-business==23.0.0
61
61
  Requires-Dist: filelock==3.17.0
62
62
  Requires-Dist: flatten-json==0.1.14
63
63
  Requires-Dist: frozenlist==1.5.0
@@ -118,6 +118,7 @@ export default defineConfig({
118
118
  { text: "Asana", link: "/supported-sources/asana.md" },
119
119
  { text: "Attio", link: "/supported-sources/attio.md" },
120
120
  { text: "Chess.com", link: "/supported-sources/chess.md" },
121
+ { text: "ClickUp", link: "/supported-sources/clickup.md" },
121
122
  {
122
123
  text: "Facebook Ads",
123
124
  link: "/supported-sources/facebook-ads.md",
@@ -0,0 +1,45 @@
1
+ # ClickUp
2
+ [ClickUp](https://clickup.com/) is a cloud-based productivity platform designed to help teams and individuals manage tasks, projects, and workflows in one place.
3
+
4
+ ingestr supports ClickUp as a source.
5
+
6
+ ## URI format
7
+
8
+ ```
9
+ clickup://?api_token=<token>
10
+ ```
11
+
12
+ URI parameters:
13
+ - `api_token` is a personal token used to authenticate with the ClickUp API.
14
+
15
+ ClickUp requires a `api_token` to connect to the ClickUP API. For more information, read [here](https://developer.clickup.com/docs/authentication#generate-your-personal-api-token) to get credentail.
16
+
17
+ Once you've completed the guide, you should have `api_token`. Let's say your API Token is `token_123`, here's a sample command that will copy the data from Clickup into a DuckDB database:
18
+
19
+ To ingest tasks from ClickUp into a DuckDB database:
20
+
21
+ ```sh
22
+ ingestr ingest \
23
+ --source-uri "clickup://?api_token=token_123" \
24
+ --source-table "tasks" \
25
+ --dest-uri duckdb:///clickup.duckdb \
26
+ --dest-table "public.tasks"
27
+ ```
28
+ <img alt="clickup_img" src="../media/clickup_ingestion.png"/>
29
+
30
+ ## Tables
31
+
32
+ ClickUp source allows ingesting the following resources into separate tables:
33
+
34
+ | **Table** | **Description** |
35
+ |-----------|-----------------|
36
+ | `user` | The authorised user profile. |
37
+ | `teams` | Workspaces available to the authenticated user. In ClickUp, a "team" in the API is equivalent to a workspace, which is the highest-level container for all spaces, folders, lists, and tasks.
38
+ | `spaces` | Spaces available within a workspace. Spaces are major sections used to organize work, such as departments, projects, or business units. Each space can contain folders, lists, and tasks |
39
+ | `lists` | Lists contained in each space. Lists are collections of tasks, often representing projects, sprints, or workflow stages.|
40
+ | `tasks` | Tasks belonging to each list. |
41
+
42
+ Use these as `--source-table` parameter in the `ingestr ingest` command.
43
+
44
+ > [!WARNING]
45
+ > ClickUp does not support incremental loading for many endpoints, which means ingestr will load endpoints incrementally if they support it, and do a full-refresh if not.
@@ -0,0 +1 @@
1
+ version = "v0.13.72"
@@ -0,0 +1,85 @@
1
+ """Simple ClickUp source."""
2
+
3
+ from datetime import datetime
4
+ from typing import Iterable
5
+
6
+ import dlt
7
+ import pendulum
8
+ from dlt.common.time import ensure_pendulum_datetime
9
+ from dlt.sources import DltResource
10
+
11
+ from .helpers import ClickupClient
12
+
13
+
14
+ @dlt.source(max_table_nesting=0)
15
+ def clickup_source(
16
+ api_token: str = dlt.secrets.value,
17
+ start_date: datetime = None,
18
+ end_date: datetime = None,
19
+ ) -> Iterable[DltResource]:
20
+ client = ClickupClient(api_token)
21
+
22
+ @dlt.resource(
23
+ name="user",
24
+ primary_key="id",
25
+ write_disposition="merge",
26
+ )
27
+ def user() -> Iterable[dict]:
28
+ data = client.get("/user")
29
+ yield data["user"]
30
+
31
+ @dlt.resource(name="teams", primary_key="id", write_disposition="merge")
32
+ def teams() -> Iterable[dict]:
33
+ for team in client.get_teams():
34
+ yield team
35
+
36
+ @dlt.resource(name="spaces", primary_key="id", write_disposition="merge")
37
+ def spaces() -> Iterable[dict]:
38
+ for space in client.get_spaces():
39
+ yield space
40
+
41
+ @dlt.resource(name="lists", write_disposition="merge", primary_key="id")
42
+ def lists() -> Iterable[dict]:
43
+ for list in client.get_lists():
44
+ yield list
45
+
46
+ @dlt.resource(
47
+ name="tasks",
48
+ write_disposition="merge",
49
+ primary_key="id",
50
+ columns={"date_updated": {"data_type": "timestamp"}},
51
+ )
52
+ def tasks(
53
+ date_updated: dlt.sources.incremental[str] = dlt.sources.incremental(
54
+ "date_updated",
55
+ initial_value=ensure_pendulum_datetime(start_date).in_timezone("UTC"),
56
+ range_end="closed",
57
+ range_start="closed",
58
+ ),
59
+ ) -> Iterable[dict]:
60
+ if date_updated.last_value:
61
+ start = ensure_pendulum_datetime(date_updated.last_value).in_timezone("UTC")
62
+ else:
63
+ start = ensure_pendulum_datetime(start_date).in_timezone("UTC")
64
+
65
+ if date_updated.end_value is None:
66
+ end = pendulum.now("UTC")
67
+ else:
68
+ end = date_updated.end_value.in_timezone("UTC")
69
+
70
+ for list_obj in client.get_lists():
71
+ for task in client.paginated(
72
+ f"/list/{list_obj['id']}/task", "tasks", {"page_size": 100}
73
+ ):
74
+ task_dt = ensure_pendulum_datetime(int(task["date_updated"]) / 1000)
75
+ if task_dt >= start and task_dt <= end:
76
+ task["date_updated"] = task_dt
77
+ yield task
78
+
79
+ return (
80
+ user,
81
+ teams,
82
+ spaces,
83
+ lists,
84
+ tasks,
85
+ )
@@ -0,0 +1,47 @@
1
+ from typing import Iterable, Optional
2
+
3
+ from ..http_client import create_client
4
+
5
+
6
+ class ClickupClient:
7
+ def __init__(self, api_token: str):
8
+ self.session = create_client()
9
+ self.base_url = "https://api.clickup.com/api/v2"
10
+ self.headers = {"Authorization": api_token}
11
+
12
+ def get(self, endpoint: str, params: Optional[dict] = None) -> dict:
13
+ url = f"{self.base_url}{endpoint}"
14
+ resp = self.session.get(url, headers=self.headers, params=params or {})
15
+ resp.raise_for_status()
16
+ return resp.json()
17
+
18
+ def paginated(
19
+ self, endpoint: str, key: str, params: Optional[dict] = None
20
+ ) -> Iterable[dict]:
21
+ page = 0
22
+ params = params or {}
23
+ while True:
24
+ params["page"] = page
25
+ data = self.get(endpoint, params)
26
+ items = data.get(key, data)
27
+ if not items:
28
+ break
29
+ for item in items:
30
+ yield item
31
+ if data.get("last_page") or len(items) < params.get("page_size", 100):
32
+ break
33
+ page += 1
34
+
35
+ def get_teams(self):
36
+ data = self.get("/team")
37
+ return data.get("teams", [])
38
+
39
+ def get_spaces(self):
40
+ for team in self.get_teams():
41
+ for space in self.paginated(f"/team/{team['id']}/space", "spaces"):
42
+ yield space
43
+
44
+ def get_lists(self):
45
+ for space in self.get_spaces():
46
+ for lst in self.paginated(f"/space/{space['id']}/list", "lists"):
47
+ yield lst
@@ -1,5 +1,6 @@
1
1
  """Loads campaigns, ads sets, ads, leads and insight data from Facebook Marketing API"""
2
2
 
3
+ from datetime import datetime
3
4
  from typing import Iterator, Sequence
4
5
 
5
6
  import dlt
@@ -7,12 +8,12 @@ from dlt.common import pendulum
7
8
  from dlt.common.typing import TDataItems
8
9
  from dlt.sources import DltResource
9
10
  from facebook_business.adobjects.ad import Ad
11
+ from dlt.common.time import ensure_pendulum_datetime
10
12
 
11
13
  from .helpers import (
12
14
  execute_job,
13
15
  get_ads_account,
14
16
  get_data_chunked,
15
- get_start_date,
16
17
  process_report_item,
17
18
  )
18
19
  from .settings import (
@@ -166,15 +167,14 @@ def facebook_insights_source(
166
167
  def facebook_insights(
167
168
  date_start: dlt.sources.incremental[str] = dlt.sources.incremental(
168
169
  "date_start",
169
- initial_value=start_date.isoformat(),
170
- end_value=end_date.isoformat() if end_date else None,
170
+ initial_value=ensure_pendulum_datetime(start_date).start_of('day').date(),
171
+ end_value=ensure_pendulum_datetime(end_date).end_of('day').date() if end_date else None,
171
172
  range_end="closed",
172
173
  range_start="closed",
173
- lag=attribution_window_days_lag * 24 * 60 * 60, # Convert days to seconds
174
174
  ),
175
175
  ) -> Iterator[TDataItems]:
176
- start_date = get_start_date(date_start)
177
- end_date = pendulum.now()
176
+ start_date = date_start.last_value
177
+ end_date = pendulum.instance(date_start.end_value) if date_start.end_value else pendulum.now()
178
178
 
179
179
  while start_date <= end_date:
180
180
  query = {
@@ -202,9 +202,10 @@ def facebook_insights_source(
202
202
  }
203
203
  job = execute_job(
204
204
  account.get_insights(params=query, is_async=True),
205
- insights_max_async_sleep_seconds=10,
205
+ insights_max_async_sleep_seconds=20,
206
206
  )
207
- yield list(map(process_report_item, job.get_result()))
207
+ output = list(map(process_report_item, job.get_result()))
208
+ yield output
208
209
  start_date = start_date.add(days=time_increment_days)
209
210
 
210
211
  return facebook_insights
@@ -3,6 +3,7 @@
3
3
  import functools
4
4
  import itertools
5
5
  import time
6
+ from datetime import datetime
6
7
  from typing import Any, Iterator, Sequence
7
8
 
8
9
  import dlt
@@ -23,43 +24,17 @@ from facebook_business.api import FacebookResponse
23
24
 
24
25
  from .exceptions import InsightsJobTimeout
25
26
  from .settings import (
26
- FACEBOOK_INSIGHTS_RETENTION_PERIOD,
27
27
  INSIGHTS_PRIMARY_KEY,
28
28
  TFbMethod,
29
29
  )
30
30
 
31
31
 
32
- def get_start_date(
33
- incremental_start_date: dlt.sources.incremental[str],
34
- ) -> pendulum.DateTime:
35
- """
36
- Get the start date for incremental loading of Facebook Insights data.
37
- """
38
- start_date: pendulum.DateTime = ensure_pendulum_datetime(
39
- incremental_start_date.start_value
40
- )
41
-
42
- # facebook forgets insights so trim the lag and warn
43
- min_start_date = pendulum.today().subtract(
44
- months=FACEBOOK_INSIGHTS_RETENTION_PERIOD
45
- )
46
- if start_date < min_start_date:
47
- logger.warning(
48
- "%s: Start date is earlier than %s months ago, using %s instead. "
49
- "For more information, see https://www.facebook.com/business/help/1695754927158071?id=354406972049255",
50
- "facebook_insights",
51
- FACEBOOK_INSIGHTS_RETENTION_PERIOD,
52
- min_start_date,
53
- )
54
- start_date = min_start_date
55
- incremental_start_date.start_value = min_start_date
56
-
57
- # lag the incremental start date by attribution window lag
58
- incremental_start_date.start_value = start_date.isoformat()
59
- return start_date
60
-
61
-
62
32
  def process_report_item(item: AbstractObject) -> DictStrAny:
33
+ if "date_start" in item:
34
+ item["date_start"] = datetime.strptime(item["date_start"], "%Y-%m-%d").date()
35
+ if "date_stop" in item:
36
+ item["date_stop"] = datetime.strptime(item["date_stop"], "%Y-%m-%d").date()
37
+
63
38
  d: DictStrAny = item.export_all_data()
64
39
  for pki in INSIGHTS_PRIMARY_KEY:
65
40
  if pki not in d:
@@ -138,15 +113,20 @@ def execute_job(
138
113
  time_start = time.time()
139
114
  sleep_time = 3
140
115
  while status != "Job Completed":
116
+ print("-----")
117
+ print("waiting for job to finish")
141
118
  duration = time.time() - time_start
142
119
  job = job.api_get()
143
120
  status = job["async_status"]
144
121
  percent_complete = job["async_percent_completion"]
122
+ print("async_status", status)
123
+ print("percent_complete", percent_complete)
145
124
 
146
125
  job_id = job["id"]
147
126
  logger.info("%s, %d%% done", status, percent_complete)
148
127
 
149
128
  if status == "Job Completed":
129
+ print("job completed")
150
130
  return job
151
131
 
152
132
  if duration > insights_max_wait_to_start_seconds and percent_complete == 0:
@@ -32,6 +32,7 @@ from ingestr.src.sources import (
32
32
  AsanaSource,
33
33
  AttioSource,
34
34
  ChessSource,
35
+ ClickupSource,
35
36
  DynamoDBSource,
36
37
  ElasticsearchSource,
37
38
  FacebookAdsSource,
@@ -185,6 +186,7 @@ class SourceDestinationFactory:
185
186
  "sftp": SFTPSource,
186
187
  "pinterest": PinterestSource,
187
188
  "zoom": ZoomSource,
189
+ "clickup": ClickupSource,
188
190
  }
189
191
  destinations: Dict[str, Type[DestinationProtocol]] = {
190
192
  "bigquery": BigQueryDestination,
@@ -1690,16 +1690,6 @@ query discountNodes($after: String, $query: String, $first: Int) {
1690
1690
  "nullable": True,
1691
1691
  "description": "The category of the product from Shopify's Standard Product Taxonomy.",
1692
1692
  },
1693
- "combinedListing": {
1694
- "data_type": "json",
1695
- "nullable": True,
1696
- "description": "A special product type that combines separate products into a single product listing.",
1697
- },
1698
- "combinedListingRole": {
1699
- "data_type": "json",
1700
- "nullable": True,
1701
- "description": "The role of the product in a combined listing.",
1702
- },
1703
1693
  "compareAtPriceRange": {
1704
1694
  "data_type": "json",
1705
1695
  "nullable": True,
@@ -1841,12 +1831,6 @@ query products($after: String, $query: String, $first: Int) {
1841
1831
  category {
1842
1832
  id
1843
1833
  }
1844
- combinedListing {
1845
- parentProduct {
1846
- id
1847
- }
1848
- }
1849
- combinedListingRole
1850
1834
  compareAtPriceRange {
1851
1835
  maxVariantCompareAtPrice {
1852
1836
  amount
@@ -86,16 +86,12 @@ COLUMN_HINTS = {
86
86
  "transaction_datetime_provider": {"data_type": "timestamp"},
87
87
  "transaction_datetime_utc": {"data_type": "timestamp"},
88
88
  "accounting_date": {"data_type": "date"},
89
- "amount": {"data_type": "decimal", "precision": 18, "scale": 4},
90
- "amount_in_major_units": {"data_type": "decimal", "precision": 18, "scale": 4},
89
+ "amount": {"data_type": "double"},
90
+ "amount_in_major_units": {"data_type": "double"},
91
91
  "currency": {"data_type": "text"},
92
92
  "currency_minor_units": {"data_type": "bigint"},
93
- "payout_amount": {"data_type": "decimal", "precision": 18, "scale": 4},
94
- "payout_amount_in_major_units": {
95
- "data_type": "decimal",
96
- "precision": 18,
97
- "scale": 4,
98
- },
93
+ "payout_amount": {"data_type": "double"},
94
+ "payout_amount_in_major_units": {"data_type": "double"},
99
95
  "payout_currency": {"data_type": "text"},
100
96
  "payout_currency_minor_units": {"data_type": "bigint"},
101
97
  "record_type_key": {"data_type": "text"},
@@ -1,4 +1,5 @@
1
1
  import base64
2
+ import csv
2
3
  import hashlib
3
4
  import hmac
4
5
  import json
@@ -123,11 +124,18 @@ class SolidgateClient:
123
124
  except json.JSONDecodeError:
124
125
  try:
125
126
  csv_data = get_response.content.decode("utf-8")
126
- df = pd.read_csv(StringIO(csv_data))
127
- df["created_at"] = df["created_at"].apply(
128
- lambda x: pendulum.parse(x)
129
- )
130
- return df
127
+ reader = csv.DictReader(StringIO(csv_data))
128
+ rows = []
129
+ for row in reader:
130
+ if row["created_at"]:
131
+ row["created_at"] = pendulum.parse(row["created_at"])
132
+ else:
133
+ row["created_at"] = None
134
+
135
+ row2 = {k: v for k, v in row.items() if v != ''}
136
+ rows.append(row2)
137
+
138
+ return rows
131
139
  except Exception as e:
132
140
  raise Exception(f"Error reading CSV: {e}")
133
141
  else:
@@ -2144,6 +2144,41 @@ class LinkedInAdsSource:
2144
2144
  ).with_resources("custom_reports")
2145
2145
 
2146
2146
 
2147
+ class ClickupSource:
2148
+ def handles_incrementality(self) -> bool:
2149
+ return True
2150
+
2151
+ def dlt_source(self, uri: str, table: str, **kwargs):
2152
+ parsed_uri = urlparse(uri)
2153
+ params = parse_qs(parsed_uri.query)
2154
+ api_token = params.get("api_token")
2155
+
2156
+ if api_token is None:
2157
+ raise MissingValueError("api_token", "ClickUp")
2158
+
2159
+ interval_start = kwargs.get("interval_start")
2160
+ interval_end = kwargs.get("interval_end")
2161
+ start_date = (
2162
+ ensure_pendulum_datetime(interval_start).in_timezone("UTC")
2163
+ if interval_start
2164
+ else pendulum.datetime(2020, 1, 1, tz="UTC")
2165
+ )
2166
+ end_date = (
2167
+ ensure_pendulum_datetime(interval_end).in_timezone("UTC")
2168
+ if interval_end
2169
+ else None
2170
+ )
2171
+
2172
+ from ingestr.src.clickup import clickup_source
2173
+
2174
+ if table not in {"user", "teams", "lists", "tasks", "spaces"}:
2175
+ raise UnsupportedResourceError(table, "ClickUp")
2176
+
2177
+ return clickup_source(
2178
+ api_token=api_token[0], start_date=start_date, end_date=end_date
2179
+ ).with_resources(table)
2180
+
2181
+
2147
2182
  class AppLovinSource:
2148
2183
  def handles_incrementality(self) -> bool:
2149
2184
  return True
@@ -112,7 +112,8 @@ def tiktok_source(
112
112
  datetime=(
113
113
  dlt.sources.incremental(
114
114
  incremental_loading_param,
115
- start_date,
115
+ initial_value=start_date,
116
+ end_value=end_date,
116
117
  range_end="closed",
117
118
  range_start="closed",
118
119
  )
@@ -120,15 +121,16 @@ def tiktok_source(
120
121
  else None
121
122
  ),
122
123
  ) -> Iterable[TDataItem]:
123
- current_date = start_date.in_tz(timezone)
124
+ start_date_tz_adjusted = start_date.in_tz(timezone)
125
+ end_date_tz_adjusted = end_date.in_tz(timezone)
124
126
 
125
127
  if datetime is not None:
126
- datetime_str = datetime.last_value
127
- current_date = ensure_pendulum_datetime(datetime_str).in_tz(timezone)
128
+ start_date_tz_adjusted = ensure_pendulum_datetime(datetime.last_value).in_tz(timezone)
129
+ end_date_tz_adjusted = ensure_pendulum_datetime(datetime.end_value).in_tz(timezone)
128
130
 
129
131
  list_of_interval = find_intervals(
130
- current_date=current_date,
131
- end_date=end_date,
132
+ current_date=start_date_tz_adjusted,
133
+ end_date=end_date_tz_adjusted,
132
134
  interval_days=interval_days,
133
135
  )
134
136
 
@@ -91,6 +91,7 @@ exclude = [
91
91
  'src/pipedrive/.*',
92
92
  'src/linear/.*',
93
93
  'src/zoom/.*',
94
+ 'src/clickup/.*',
94
95
  ]
95
96
 
96
97
  [[tool.mypy.overrides]]
@@ -120,6 +121,7 @@ module = [
120
121
  "ingestr.src.pipedrive.*",
121
122
  "ingestr.src.linear.*",
122
123
  "ingestr.src.zoom.*",
124
+ "ingestr.src.clickup.*",
123
125
  ]
124
126
  follow_imports = "skip"
125
127
 
@@ -7,7 +7,7 @@ dlt-cratedb>=0.0.1
7
7
  duckdb_engine==0.17.0
8
8
  duckdb==1.2.1
9
9
  google-ads==25.1.0
10
- facebook-business==20.0.0
10
+ facebook-business==23.0.0
11
11
  google-api-python-client==2.130.0
12
12
  google-cloud-bigquery-storage==2.24.0
13
13
  mysql-connector-python==9.2.0
@@ -121,7 +121,7 @@ enum-compat==0.0.3
121
121
  # via intuit-oauth
122
122
  et-xmlfile==2.0.0
123
123
  # via openpyxl
124
- facebook-business==20.0.0
124
+ facebook-business==23.0.0
125
125
  # via -r requirements.in
126
126
  filelock==3.17.0
127
127
  # via snowflake-connector-python
@@ -121,7 +121,7 @@ enum-compat==0.0.3
121
121
  # via intuit-oauth
122
122
  et-xmlfile==2.0.0
123
123
  # via openpyxl
124
- facebook-business==20.0.0
124
+ facebook-business==23.0.0
125
125
  # via -r requirements.in
126
126
  filelock==3.18.0
127
127
  # via snowflake-connector-python
@@ -1 +0,0 @@
1
- version = "v0.13.70"
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