ingestr 0.13.2__py3-none-any.whl → 0.14.104__py3-none-any.whl

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 (146) hide show
  1. ingestr/conftest.py +72 -0
  2. ingestr/main.py +134 -87
  3. ingestr/src/adjust/__init__.py +4 -4
  4. ingestr/src/adjust/adjust_helpers.py +7 -3
  5. ingestr/src/airtable/__init__.py +3 -2
  6. ingestr/src/allium/__init__.py +128 -0
  7. ingestr/src/anthropic/__init__.py +277 -0
  8. ingestr/src/anthropic/helpers.py +525 -0
  9. ingestr/src/applovin/__init__.py +262 -0
  10. ingestr/src/applovin_max/__init__.py +117 -0
  11. ingestr/src/appsflyer/__init__.py +325 -0
  12. ingestr/src/appsflyer/client.py +49 -45
  13. ingestr/src/appstore/__init__.py +1 -0
  14. ingestr/src/arrow/__init__.py +9 -1
  15. ingestr/src/asana_source/__init__.py +1 -1
  16. ingestr/src/attio/__init__.py +102 -0
  17. ingestr/src/attio/helpers.py +65 -0
  18. ingestr/src/blob.py +38 -11
  19. ingestr/src/buildinfo.py +1 -0
  20. ingestr/src/chess/__init__.py +1 -1
  21. ingestr/src/clickup/__init__.py +85 -0
  22. ingestr/src/clickup/helpers.py +47 -0
  23. ingestr/src/collector/spinner.py +43 -0
  24. ingestr/src/couchbase_source/__init__.py +118 -0
  25. ingestr/src/couchbase_source/helpers.py +135 -0
  26. ingestr/src/cursor/__init__.py +83 -0
  27. ingestr/src/cursor/helpers.py +188 -0
  28. ingestr/src/destinations.py +520 -33
  29. ingestr/src/docebo/__init__.py +589 -0
  30. ingestr/src/docebo/client.py +435 -0
  31. ingestr/src/docebo/helpers.py +97 -0
  32. ingestr/src/elasticsearch/__init__.py +80 -0
  33. ingestr/src/elasticsearch/helpers.py +138 -0
  34. ingestr/src/errors.py +8 -0
  35. ingestr/src/facebook_ads/__init__.py +47 -28
  36. ingestr/src/facebook_ads/helpers.py +59 -37
  37. ingestr/src/facebook_ads/settings.py +2 -0
  38. ingestr/src/facebook_ads/utils.py +39 -0
  39. ingestr/src/factory.py +116 -2
  40. ingestr/src/filesystem/__init__.py +8 -3
  41. ingestr/src/filters.py +46 -3
  42. ingestr/src/fluxx/__init__.py +9906 -0
  43. ingestr/src/fluxx/helpers.py +209 -0
  44. ingestr/src/frankfurter/__init__.py +157 -0
  45. ingestr/src/frankfurter/helpers.py +48 -0
  46. ingestr/src/freshdesk/__init__.py +89 -0
  47. ingestr/src/freshdesk/freshdesk_client.py +137 -0
  48. ingestr/src/freshdesk/settings.py +9 -0
  49. ingestr/src/fundraiseup/__init__.py +95 -0
  50. ingestr/src/fundraiseup/client.py +81 -0
  51. ingestr/src/github/__init__.py +41 -6
  52. ingestr/src/github/helpers.py +5 -5
  53. ingestr/src/google_analytics/__init__.py +22 -4
  54. ingestr/src/google_analytics/helpers.py +124 -6
  55. ingestr/src/google_sheets/__init__.py +4 -4
  56. ingestr/src/google_sheets/helpers/data_processing.py +2 -2
  57. ingestr/src/hostaway/__init__.py +302 -0
  58. ingestr/src/hostaway/client.py +288 -0
  59. ingestr/src/http/__init__.py +35 -0
  60. ingestr/src/http/readers.py +114 -0
  61. ingestr/src/http_client.py +24 -0
  62. ingestr/src/hubspot/__init__.py +66 -23
  63. ingestr/src/hubspot/helpers.py +52 -22
  64. ingestr/src/hubspot/settings.py +14 -7
  65. ingestr/src/influxdb/__init__.py +46 -0
  66. ingestr/src/influxdb/client.py +34 -0
  67. ingestr/src/intercom/__init__.py +142 -0
  68. ingestr/src/intercom/helpers.py +674 -0
  69. ingestr/src/intercom/settings.py +279 -0
  70. ingestr/src/isoc_pulse/__init__.py +159 -0
  71. ingestr/src/jira_source/__init__.py +340 -0
  72. ingestr/src/jira_source/helpers.py +439 -0
  73. ingestr/src/jira_source/settings.py +170 -0
  74. ingestr/src/kafka/__init__.py +4 -1
  75. ingestr/src/kinesis/__init__.py +139 -0
  76. ingestr/src/kinesis/helpers.py +82 -0
  77. ingestr/src/klaviyo/{_init_.py → __init__.py} +5 -6
  78. ingestr/src/linear/__init__.py +634 -0
  79. ingestr/src/linear/helpers.py +111 -0
  80. ingestr/src/linkedin_ads/helpers.py +0 -1
  81. ingestr/src/loader.py +69 -0
  82. ingestr/src/mailchimp/__init__.py +126 -0
  83. ingestr/src/mailchimp/helpers.py +226 -0
  84. ingestr/src/mailchimp/settings.py +164 -0
  85. ingestr/src/masking.py +344 -0
  86. ingestr/src/mixpanel/__init__.py +62 -0
  87. ingestr/src/mixpanel/client.py +99 -0
  88. ingestr/src/monday/__init__.py +246 -0
  89. ingestr/src/monday/helpers.py +392 -0
  90. ingestr/src/monday/settings.py +328 -0
  91. ingestr/src/mongodb/__init__.py +72 -8
  92. ingestr/src/mongodb/helpers.py +915 -38
  93. ingestr/src/partition.py +32 -0
  94. ingestr/src/personio/__init__.py +331 -0
  95. ingestr/src/personio/helpers.py +86 -0
  96. ingestr/src/phantombuster/__init__.py +65 -0
  97. ingestr/src/phantombuster/client.py +87 -0
  98. ingestr/src/pinterest/__init__.py +82 -0
  99. ingestr/src/pipedrive/__init__.py +198 -0
  100. ingestr/src/pipedrive/helpers/__init__.py +23 -0
  101. ingestr/src/pipedrive/helpers/custom_fields_munger.py +102 -0
  102. ingestr/src/pipedrive/helpers/pages.py +115 -0
  103. ingestr/src/pipedrive/settings.py +27 -0
  104. ingestr/src/pipedrive/typing.py +3 -0
  105. ingestr/src/plusvibeai/__init__.py +335 -0
  106. ingestr/src/plusvibeai/helpers.py +544 -0
  107. ingestr/src/plusvibeai/settings.py +252 -0
  108. ingestr/src/quickbooks/__init__.py +117 -0
  109. ingestr/src/resource.py +40 -0
  110. ingestr/src/revenuecat/__init__.py +83 -0
  111. ingestr/src/revenuecat/helpers.py +237 -0
  112. ingestr/src/salesforce/__init__.py +156 -0
  113. ingestr/src/salesforce/helpers.py +64 -0
  114. ingestr/src/shopify/__init__.py +1 -17
  115. ingestr/src/smartsheets/__init__.py +82 -0
  116. ingestr/src/snapchat_ads/__init__.py +489 -0
  117. ingestr/src/snapchat_ads/client.py +72 -0
  118. ingestr/src/snapchat_ads/helpers.py +535 -0
  119. ingestr/src/socrata_source/__init__.py +83 -0
  120. ingestr/src/socrata_source/helpers.py +85 -0
  121. ingestr/src/socrata_source/settings.py +8 -0
  122. ingestr/src/solidgate/__init__.py +219 -0
  123. ingestr/src/solidgate/helpers.py +154 -0
  124. ingestr/src/sources.py +3132 -212
  125. ingestr/src/stripe_analytics/__init__.py +49 -21
  126. ingestr/src/stripe_analytics/helpers.py +286 -1
  127. ingestr/src/stripe_analytics/settings.py +62 -10
  128. ingestr/src/telemetry/event.py +10 -9
  129. ingestr/src/tiktok_ads/__init__.py +12 -6
  130. ingestr/src/tiktok_ads/tiktok_helpers.py +0 -1
  131. ingestr/src/trustpilot/__init__.py +48 -0
  132. ingestr/src/trustpilot/client.py +48 -0
  133. ingestr/src/version.py +6 -1
  134. ingestr/src/wise/__init__.py +68 -0
  135. ingestr/src/wise/client.py +63 -0
  136. ingestr/src/zoom/__init__.py +99 -0
  137. ingestr/src/zoom/helpers.py +102 -0
  138. ingestr/tests/unit/test_smartsheets.py +133 -0
  139. ingestr-0.14.104.dist-info/METADATA +563 -0
  140. ingestr-0.14.104.dist-info/RECORD +203 -0
  141. ingestr/src/appsflyer/_init_.py +0 -24
  142. ingestr-0.13.2.dist-info/METADATA +0 -302
  143. ingestr-0.13.2.dist-info/RECORD +0 -107
  144. {ingestr-0.13.2.dist-info → ingestr-0.14.104.dist-info}/WHEEL +0 -0
  145. {ingestr-0.13.2.dist-info → ingestr-0.14.104.dist-info}/entry_points.txt +0 -0
  146. {ingestr-0.13.2.dist-info → ingestr-0.14.104.dist-info}/licenses/LICENSE.md +0 -0
@@ -0,0 +1,340 @@
1
+ """
2
+ This source provides data extraction from Jira Cloud via the REST API v3.
3
+
4
+ It defines several functions to fetch data from different parts of Jira including
5
+ projects, issues, users, boards, sprints, and various configuration objects like
6
+ issue types, statuses, and priorities.
7
+ """
8
+
9
+ from typing import Any, Iterable, Optional
10
+
11
+ import dlt
12
+ from dlt.common.typing import TDataItem
13
+
14
+ from .helpers import get_client
15
+ from .settings import (
16
+ DEFAULT_PAGE_SIZE,
17
+ DEFAULT_START_DATE,
18
+ ISSUE_FIELDS,
19
+ )
20
+
21
+
22
+ @dlt.source
23
+ def jira_source() -> Any:
24
+ """
25
+ The main function that runs all the other functions to fetch data from Jira.
26
+
27
+ Returns:
28
+ Sequence[DltResource]: A sequence of DltResource objects containing the fetched data.
29
+ """
30
+ return [
31
+ projects,
32
+ issues,
33
+ users,
34
+ issue_types,
35
+ statuses,
36
+ priorities,
37
+ resolutions,
38
+ project_versions,
39
+ project_components,
40
+ events,
41
+ ]
42
+
43
+
44
+ @dlt.resource(write_disposition="replace")
45
+ def projects(
46
+ base_url: str = dlt.secrets.value,
47
+ email: str = dlt.secrets.value,
48
+ api_token: str = dlt.secrets.value,
49
+ expand: Optional[str] = None,
50
+ recent: Optional[int] = None,
51
+ ) -> Iterable[TDataItem]:
52
+ """
53
+ Fetches and returns a list of projects from Jira.
54
+
55
+ Args:
56
+ base_url (str): Jira instance URL (e.g., https://your-domain.atlassian.net)
57
+ email (str): User email for authentication
58
+ api_token (str): API token for authentication
59
+ expand (str): Comma-separated list of fields to expand
60
+ recent (int): Number of recent projects to return
61
+
62
+ Yields:
63
+ dict: The project data.
64
+ """
65
+ client = get_client(base_url, email, api_token)
66
+ yield from client.get_projects(expand=expand, recent=recent)
67
+
68
+
69
+ @dlt.resource(
70
+ write_disposition="merge",
71
+ primary_key="id",
72
+ max_table_nesting=2,
73
+ )
74
+ def issues(
75
+ base_url: str = dlt.secrets.value,
76
+ email: str = dlt.secrets.value,
77
+ api_token: str = dlt.secrets.value,
78
+ jql: str = "order by updated DESC",
79
+ fields: Optional[str] = None,
80
+ expand: Optional[str] = None,
81
+ max_results: Optional[int] = None,
82
+ updated: dlt.sources.incremental[str] = dlt.sources.incremental(
83
+ "fields.updated",
84
+ initial_value=DEFAULT_START_DATE,
85
+ range_end="closed",
86
+ range_start="closed",
87
+ ),
88
+ ) -> Iterable[TDataItem]:
89
+ """
90
+ Fetches issues from Jira using JQL search.
91
+
92
+ Args:
93
+ base_url (str): Jira instance URL
94
+ email (str): User email for authentication
95
+ api_token (str): API token for authentication
96
+ jql (str): JQL query string
97
+ fields (str): Comma-separated list of fields to return
98
+ expand (str): Comma-separated list of fields to expand
99
+ max_results (int): Maximum number of results to return
100
+ updated (str): The date from which to fetch updated issues
101
+
102
+ Yields:
103
+ dict: The issue data.
104
+ """
105
+ client = get_client(base_url, email, api_token)
106
+
107
+ # Build JQL with incremental filter
108
+ incremental_jql = jql
109
+ if updated.start_value:
110
+ date_filter = f"updated >= '{updated.start_value}'"
111
+
112
+ # Check if JQL has ORDER BY clause and handle it properly
113
+ jql_upper = jql.upper()
114
+ if "ORDER BY" in jql_upper:
115
+ # Split at ORDER BY and add filter before it
116
+ order_by_index = jql_upper.find("ORDER BY")
117
+ main_query = jql[:order_by_index].strip()
118
+ order_clause = jql[order_by_index:].strip()
119
+
120
+ if main_query and (
121
+ "WHERE" in main_query.upper()
122
+ or "AND" in main_query.upper()
123
+ or "OR" in main_query.upper()
124
+ ):
125
+ incremental_jql = f"({main_query}) AND {date_filter} {order_clause}"
126
+ else:
127
+ if main_query:
128
+ incremental_jql = f"{main_query} AND {date_filter} {order_clause}"
129
+ else:
130
+ incremental_jql = f"{date_filter} {order_clause}"
131
+ else:
132
+ # No ORDER BY clause, use original logic
133
+ if "WHERE" in jql_upper or "AND" in jql_upper or "OR" in jql_upper:
134
+ incremental_jql = f"({jql}) AND {date_filter}"
135
+ else:
136
+ incremental_jql = f"{jql} AND {date_filter}"
137
+
138
+ # Use default fields if not specified
139
+ if fields is None:
140
+ fields = ",".join(ISSUE_FIELDS)
141
+
142
+ yield from client.search_issues(
143
+ jql=incremental_jql, fields=fields, expand=expand, max_results=max_results
144
+ )
145
+
146
+
147
+ @dlt.resource(write_disposition="replace")
148
+ def users(
149
+ base_url: str = dlt.secrets.value,
150
+ email: str = dlt.secrets.value,
151
+ api_token: str = dlt.secrets.value,
152
+ username: Optional[str] = None,
153
+ account_id: Optional[str] = None,
154
+ max_results: int = DEFAULT_PAGE_SIZE,
155
+ ) -> Iterable[TDataItem]:
156
+ """
157
+ Fetches users from Jira.
158
+
159
+ Args:
160
+ base_url (str): Jira instance URL
161
+ email (str): User email for authentication
162
+ api_token (str): API token for authentication
163
+ username (str): Username to search for
164
+ account_id (str): Account ID to search for
165
+ max_results (int): Maximum results per page
166
+
167
+ Yields:
168
+ dict: The user data.
169
+ """
170
+ client = get_client(base_url, email, api_token)
171
+ yield from client.get_users(
172
+ username=username, account_id=account_id, max_results=max_results
173
+ )
174
+
175
+
176
+ @dlt.resource(write_disposition="replace")
177
+ def issue_types(
178
+ base_url: str = dlt.secrets.value,
179
+ email: str = dlt.secrets.value,
180
+ api_token: str = dlt.secrets.value,
181
+ ) -> Iterable[TDataItem]:
182
+ """
183
+ Fetches all issue types from Jira.
184
+
185
+ Args:
186
+ base_url (str): Jira instance URL
187
+ email (str): User email for authentication
188
+ api_token (str): API token for authentication
189
+
190
+ Yields:
191
+ dict: The issue type data.
192
+ """
193
+ client = get_client(base_url, email, api_token)
194
+ yield from client.get_issue_types()
195
+
196
+
197
+ @dlt.resource(write_disposition="replace")
198
+ def statuses(
199
+ base_url: str = dlt.secrets.value,
200
+ email: str = dlt.secrets.value,
201
+ api_token: str = dlt.secrets.value,
202
+ ) -> Iterable[TDataItem]:
203
+ """
204
+ Fetches all statuses from Jira.
205
+
206
+ Args:
207
+ base_url (str): Jira instance URL
208
+ email (str): User email for authentication
209
+ api_token (str): API token for authentication
210
+
211
+ Yields:
212
+ dict: The status data.
213
+ """
214
+ client = get_client(base_url, email, api_token)
215
+ yield from client.get_statuses()
216
+
217
+
218
+ @dlt.resource(write_disposition="replace")
219
+ def priorities(
220
+ base_url: str = dlt.secrets.value,
221
+ email: str = dlt.secrets.value,
222
+ api_token: str = dlt.secrets.value,
223
+ ) -> Iterable[TDataItem]:
224
+ """
225
+ Fetches all priorities from Jira.
226
+
227
+ Args:
228
+ base_url (str): Jira instance URL
229
+ email (str): User email for authentication
230
+ api_token (str): API token for authentication
231
+
232
+ Yields:
233
+ dict: The priority data.
234
+ """
235
+ client = get_client(base_url, email, api_token)
236
+ yield from client.get_priorities()
237
+
238
+
239
+ @dlt.resource(write_disposition="replace")
240
+ def resolutions(
241
+ base_url: str = dlt.secrets.value,
242
+ email: str = dlt.secrets.value,
243
+ api_token: str = dlt.secrets.value,
244
+ ) -> Iterable[TDataItem]:
245
+ """
246
+ Fetches all resolutions from Jira.
247
+
248
+ Args:
249
+ base_url (str): Jira instance URL
250
+ email (str): User email for authentication
251
+ api_token (str): API token for authentication
252
+
253
+ Yields:
254
+ dict: The resolution data.
255
+ """
256
+ client = get_client(base_url, email, api_token)
257
+ yield from client.get_resolutions()
258
+
259
+
260
+ @dlt.transformer(
261
+ data_from=projects,
262
+ write_disposition="replace",
263
+ )
264
+ @dlt.defer
265
+ def project_versions(
266
+ project: TDataItem,
267
+ base_url: str = dlt.secrets.value,
268
+ email: str = dlt.secrets.value,
269
+ api_token: str = dlt.secrets.value,
270
+ ) -> Iterable[TDataItem]:
271
+ """
272
+ Fetches versions for each project from Jira.
273
+
274
+ Args:
275
+ project (dict): The project data.
276
+ base_url (str): Jira instance URL
277
+ email (str): User email for authentication
278
+ api_token (str): API token for authentication
279
+
280
+ Returns:
281
+ list[dict]: The version data for the given project.
282
+ """
283
+ client = get_client(base_url, email, api_token)
284
+ project_key = project.get("key")
285
+ if not project_key:
286
+ return []
287
+
288
+ return list(client.get_project_versions(project_key))
289
+
290
+
291
+ @dlt.transformer(
292
+ data_from=projects,
293
+ write_disposition="replace",
294
+ )
295
+ @dlt.defer
296
+ def project_components(
297
+ project: TDataItem,
298
+ base_url: str = dlt.secrets.value,
299
+ email: str = dlt.secrets.value,
300
+ api_token: str = dlt.secrets.value,
301
+ ) -> Iterable[TDataItem]:
302
+ """
303
+ Fetches components for each project from Jira.
304
+
305
+ Args:
306
+ project (dict): The project data.
307
+ base_url (str): Jira instance URL
308
+ email (str): User email for authentication
309
+ api_token (str): API token for authentication
310
+
311
+ Returns:
312
+ list[dict]: The component data for the given project.
313
+ """
314
+ client = get_client(base_url, email, api_token)
315
+ project_key = project.get("key")
316
+ if not project_key:
317
+ return []
318
+
319
+ return list(client.get_project_components(project_key))
320
+
321
+
322
+ @dlt.resource(write_disposition="replace")
323
+ def events(
324
+ base_url: str = dlt.secrets.value,
325
+ email: str = dlt.secrets.value,
326
+ api_token: str = dlt.secrets.value,
327
+ ) -> Iterable[TDataItem]:
328
+ """
329
+ Fetches all event types from Jira (e.g., Issue Created, Issue Updated, etc.).
330
+
331
+ Args:
332
+ base_url (str): Jira instance URL
333
+ email (str): User email for authentication
334
+ api_token (str): API token for authentication
335
+
336
+ Yields:
337
+ dict: The event data.
338
+ """
339
+ client = get_client(base_url, email, api_token)
340
+ yield from client.get_events()