ingestr 0.13.13__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 (139) 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_max/__init__.py +6 -4
  10. ingestr/src/appsflyer/__init__.py +325 -0
  11. ingestr/src/appsflyer/client.py +49 -45
  12. ingestr/src/appstore/__init__.py +1 -0
  13. ingestr/src/arrow/__init__.py +9 -1
  14. ingestr/src/asana_source/__init__.py +1 -1
  15. ingestr/src/attio/__init__.py +102 -0
  16. ingestr/src/attio/helpers.py +65 -0
  17. ingestr/src/blob.py +37 -10
  18. ingestr/src/buildinfo.py +1 -1
  19. ingestr/src/chess/__init__.py +1 -1
  20. ingestr/src/clickup/__init__.py +85 -0
  21. ingestr/src/clickup/helpers.py +47 -0
  22. ingestr/src/collector/spinner.py +43 -0
  23. ingestr/src/couchbase_source/__init__.py +118 -0
  24. ingestr/src/couchbase_source/helpers.py +135 -0
  25. ingestr/src/cursor/__init__.py +83 -0
  26. ingestr/src/cursor/helpers.py +188 -0
  27. ingestr/src/destinations.py +508 -27
  28. ingestr/src/docebo/__init__.py +589 -0
  29. ingestr/src/docebo/client.py +435 -0
  30. ingestr/src/docebo/helpers.py +97 -0
  31. ingestr/src/elasticsearch/__init__.py +80 -0
  32. ingestr/src/elasticsearch/helpers.py +138 -0
  33. ingestr/src/errors.py +8 -0
  34. ingestr/src/facebook_ads/__init__.py +47 -28
  35. ingestr/src/facebook_ads/helpers.py +59 -37
  36. ingestr/src/facebook_ads/settings.py +2 -0
  37. ingestr/src/facebook_ads/utils.py +39 -0
  38. ingestr/src/factory.py +107 -2
  39. ingestr/src/filesystem/__init__.py +8 -3
  40. ingestr/src/filters.py +46 -3
  41. ingestr/src/fluxx/__init__.py +9906 -0
  42. ingestr/src/fluxx/helpers.py +209 -0
  43. ingestr/src/frankfurter/__init__.py +157 -0
  44. ingestr/src/frankfurter/helpers.py +48 -0
  45. ingestr/src/freshdesk/__init__.py +89 -0
  46. ingestr/src/freshdesk/freshdesk_client.py +137 -0
  47. ingestr/src/freshdesk/settings.py +9 -0
  48. ingestr/src/fundraiseup/__init__.py +95 -0
  49. ingestr/src/fundraiseup/client.py +81 -0
  50. ingestr/src/github/__init__.py +41 -6
  51. ingestr/src/github/helpers.py +5 -5
  52. ingestr/src/google_analytics/__init__.py +22 -4
  53. ingestr/src/google_analytics/helpers.py +124 -6
  54. ingestr/src/google_sheets/__init__.py +4 -4
  55. ingestr/src/google_sheets/helpers/data_processing.py +2 -2
  56. ingestr/src/hostaway/__init__.py +302 -0
  57. ingestr/src/hostaway/client.py +288 -0
  58. ingestr/src/http/__init__.py +35 -0
  59. ingestr/src/http/readers.py +114 -0
  60. ingestr/src/http_client.py +24 -0
  61. ingestr/src/hubspot/__init__.py +66 -23
  62. ingestr/src/hubspot/helpers.py +52 -22
  63. ingestr/src/hubspot/settings.py +14 -7
  64. ingestr/src/influxdb/__init__.py +46 -0
  65. ingestr/src/influxdb/client.py +34 -0
  66. ingestr/src/intercom/__init__.py +142 -0
  67. ingestr/src/intercom/helpers.py +674 -0
  68. ingestr/src/intercom/settings.py +279 -0
  69. ingestr/src/isoc_pulse/__init__.py +159 -0
  70. ingestr/src/jira_source/__init__.py +340 -0
  71. ingestr/src/jira_source/helpers.py +439 -0
  72. ingestr/src/jira_source/settings.py +170 -0
  73. ingestr/src/kafka/__init__.py +4 -1
  74. ingestr/src/kinesis/__init__.py +139 -0
  75. ingestr/src/kinesis/helpers.py +82 -0
  76. ingestr/src/klaviyo/{_init_.py → __init__.py} +5 -6
  77. ingestr/src/linear/__init__.py +634 -0
  78. ingestr/src/linear/helpers.py +111 -0
  79. ingestr/src/linkedin_ads/helpers.py +0 -1
  80. ingestr/src/mailchimp/__init__.py +126 -0
  81. ingestr/src/mailchimp/helpers.py +226 -0
  82. ingestr/src/mailchimp/settings.py +164 -0
  83. ingestr/src/masking.py +344 -0
  84. ingestr/src/mixpanel/__init__.py +62 -0
  85. ingestr/src/mixpanel/client.py +99 -0
  86. ingestr/src/monday/__init__.py +246 -0
  87. ingestr/src/monday/helpers.py +392 -0
  88. ingestr/src/monday/settings.py +328 -0
  89. ingestr/src/mongodb/__init__.py +72 -8
  90. ingestr/src/mongodb/helpers.py +915 -38
  91. ingestr/src/partition.py +32 -0
  92. ingestr/src/phantombuster/__init__.py +65 -0
  93. ingestr/src/phantombuster/client.py +87 -0
  94. ingestr/src/pinterest/__init__.py +82 -0
  95. ingestr/src/pipedrive/__init__.py +198 -0
  96. ingestr/src/pipedrive/helpers/__init__.py +23 -0
  97. ingestr/src/pipedrive/helpers/custom_fields_munger.py +102 -0
  98. ingestr/src/pipedrive/helpers/pages.py +115 -0
  99. ingestr/src/pipedrive/settings.py +27 -0
  100. ingestr/src/pipedrive/typing.py +3 -0
  101. ingestr/src/plusvibeai/__init__.py +335 -0
  102. ingestr/src/plusvibeai/helpers.py +544 -0
  103. ingestr/src/plusvibeai/settings.py +252 -0
  104. ingestr/src/quickbooks/__init__.py +117 -0
  105. ingestr/src/resource.py +40 -0
  106. ingestr/src/revenuecat/__init__.py +83 -0
  107. ingestr/src/revenuecat/helpers.py +237 -0
  108. ingestr/src/salesforce/__init__.py +15 -8
  109. ingestr/src/shopify/__init__.py +1 -17
  110. ingestr/src/smartsheets/__init__.py +82 -0
  111. ingestr/src/snapchat_ads/__init__.py +489 -0
  112. ingestr/src/snapchat_ads/client.py +72 -0
  113. ingestr/src/snapchat_ads/helpers.py +535 -0
  114. ingestr/src/socrata_source/__init__.py +83 -0
  115. ingestr/src/socrata_source/helpers.py +85 -0
  116. ingestr/src/socrata_source/settings.py +8 -0
  117. ingestr/src/solidgate/__init__.py +219 -0
  118. ingestr/src/solidgate/helpers.py +154 -0
  119. ingestr/src/sources.py +2933 -245
  120. ingestr/src/stripe_analytics/__init__.py +49 -21
  121. ingestr/src/stripe_analytics/helpers.py +286 -1
  122. ingestr/src/stripe_analytics/settings.py +62 -10
  123. ingestr/src/telemetry/event.py +10 -9
  124. ingestr/src/tiktok_ads/__init__.py +12 -6
  125. ingestr/src/tiktok_ads/tiktok_helpers.py +0 -1
  126. ingestr/src/trustpilot/__init__.py +48 -0
  127. ingestr/src/trustpilot/client.py +48 -0
  128. ingestr/src/wise/__init__.py +68 -0
  129. ingestr/src/wise/client.py +63 -0
  130. ingestr/src/zoom/__init__.py +99 -0
  131. ingestr/src/zoom/helpers.py +102 -0
  132. ingestr/tests/unit/test_smartsheets.py +133 -0
  133. {ingestr-0.13.13.dist-info → ingestr-0.14.104.dist-info}/METADATA +229 -19
  134. ingestr-0.14.104.dist-info/RECORD +203 -0
  135. ingestr/src/appsflyer/_init_.py +0 -24
  136. ingestr-0.13.13.dist-info/RECORD +0 -115
  137. {ingestr-0.13.13.dist-info → ingestr-0.14.104.dist-info}/WHEEL +0 -0
  138. {ingestr-0.13.13.dist-info → ingestr-0.14.104.dist-info}/entry_points.txt +0 -0
  139. {ingestr-0.13.13.dist-info → ingestr-0.14.104.dist-info}/licenses/LICENSE.md +0 -0
@@ -0,0 +1,188 @@
1
+ """Cursor source helpers"""
2
+
3
+ from typing import Any, Callable, Dict, Iterator, List, Optional
4
+
5
+ import requests
6
+
7
+ REQUEST_TIMEOUT = 30
8
+
9
+
10
+ class CursorClient:
11
+ """Cursor REST API client with API key authentication."""
12
+
13
+ def __init__(
14
+ self,
15
+ api_key: str,
16
+ base_url: str = "https://api.cursor.com",
17
+ timeout: int = REQUEST_TIMEOUT,
18
+ ):
19
+ """
20
+ Initialize Cursor client with API key authentication.
21
+
22
+ Args:
23
+ api_key: API key for authentication
24
+ base_url: Cursor API base URL
25
+ timeout: Request timeout in seconds
26
+ """
27
+ self.base_url = base_url.rstrip("/")
28
+ self.timeout = timeout
29
+ self.api_key = api_key
30
+
31
+ def _make_request(
32
+ self,
33
+ endpoint: str,
34
+ method: str = "POST",
35
+ json_data: Optional[Dict[str, Any]] = None,
36
+ ) -> Dict[str, Any]:
37
+ """
38
+ Make HTTP request to Cursor API.
39
+
40
+ Args:
41
+ endpoint: API endpoint path
42
+ method: HTTP method (default: POST)
43
+ json_data: JSON data for request body
44
+
45
+ Returns:
46
+ JSON response data
47
+ """
48
+ url = f"{self.base_url}/{endpoint.lstrip('/')}"
49
+
50
+ if json_data is not None:
51
+ response = requests.request(
52
+ method=method,
53
+ url=url,
54
+ auth=(self.api_key, ""),
55
+ timeout=self.timeout,
56
+ headers={"Content-Type": "application/json"},
57
+ json=json_data,
58
+ )
59
+ else:
60
+ response = requests.request(
61
+ method=method,
62
+ url=url,
63
+ auth=(self.api_key, ""),
64
+ timeout=self.timeout,
65
+ headers={"Content-Type": "application/json"},
66
+ json={},
67
+ )
68
+
69
+ response.raise_for_status()
70
+ return response.json()
71
+
72
+ def _paginate(
73
+ self,
74
+ endpoint: str,
75
+ data_key: str,
76
+ base_payload: Optional[Dict[str, Any]] = None,
77
+ page_size: Optional[int] = 100,
78
+ has_next_page_check: Optional[Callable[[Dict[str, Any]], bool]] = None,
79
+ ) -> Iterator[Dict[str, Any]]:
80
+ """
81
+ Generic pagination helper for API endpoints.
82
+
83
+ Args:
84
+ endpoint: API endpoint to call
85
+ data_key: Key in response containing the data array
86
+ base_payload: Base payload to include in each request
87
+ page_size: Number of results per page (default: 100)
88
+ has_next_page_check: Optional function to check if there's a next page from response
89
+
90
+ Yields:
91
+ Individual records from the paginated response
92
+ """
93
+ page = 1
94
+ base_payload = base_payload or {}
95
+
96
+ while True:
97
+ payload = base_payload.copy()
98
+
99
+ if page_size:
100
+ payload["pageSize"] = page_size
101
+ payload["page"] = page
102
+
103
+ result = self._make_request(endpoint, json_data=payload)
104
+ data = result.get(data_key, [])
105
+
106
+ if not data:
107
+ break
108
+
109
+ for record in data:
110
+ yield record
111
+
112
+ # If page_size is not set, we get all data in one request
113
+ if not page_size:
114
+ break
115
+
116
+ # Custom check for next page if provided
117
+ if has_next_page_check:
118
+ if not has_next_page_check(result):
119
+ break
120
+ # Default: if we got less data than page_size, we've reached the end
121
+ elif len(data) < page_size:
122
+ break
123
+
124
+ page += 1
125
+
126
+ def get_team_members(self) -> List[Dict[str, Any]]:
127
+ response = self._make_request("teams/members", method="GET")
128
+ return response.get("teamMembers", [])
129
+
130
+ def get_daily_usage_data(
131
+ self,
132
+ start_date: Optional[int] = None,
133
+ end_date: Optional[int] = None,
134
+ page_size: Optional[int] = 100,
135
+ ) -> Iterator[Dict[str, Any]]:
136
+ base_payload = {}
137
+ if start_date is not None:
138
+ base_payload["startDate"] = start_date
139
+ if end_date is not None:
140
+ base_payload["endDate"] = end_date
141
+
142
+ yield from self._paginate(
143
+ endpoint="teams/daily-usage-data",
144
+ data_key="data",
145
+ base_payload=base_payload,
146
+ page_size=page_size,
147
+ )
148
+
149
+ def get_team_spend(
150
+ self,
151
+ page_size: Optional[int] = 100,
152
+ ) -> Iterator[Dict[str, Any]]:
153
+ def check_has_next_page(response: Dict[str, Any]) -> bool:
154
+ current_page = response.get("currentPage", 1)
155
+ total_pages = response.get("totalPages", 1)
156
+ return current_page < total_pages
157
+
158
+ yield from self._paginate(
159
+ endpoint="teams/spend",
160
+ data_key="teamMemberSpend",
161
+ page_size=page_size,
162
+ has_next_page_check=check_has_next_page,
163
+ )
164
+
165
+ def get_filtered_usage_events(
166
+ self,
167
+ start_date: Optional[int] = None,
168
+ end_date: Optional[int] = None,
169
+ page_size: Optional[int] = 100,
170
+ ) -> Iterator[Dict[str, Any]]:
171
+ base_payload = {}
172
+ if start_date is not None:
173
+ base_payload["startDate"] = start_date
174
+ if end_date is not None:
175
+ base_payload["endDate"] = end_date
176
+
177
+ # Custom check for hasNextPage
178
+ def check_has_next_page(response: Dict[str, Any]) -> bool:
179
+ pagination = response.get("pagination", {})
180
+ return pagination.get("hasNextPage", False)
181
+
182
+ yield from self._paginate(
183
+ endpoint="teams/filtered-usage-events",
184
+ data_key="usageEvents",
185
+ base_payload=base_payload,
186
+ page_size=page_size,
187
+ has_next_page_check=check_has_next_page,
188
+ )