ingestr 0.13.80__py3-none-any.whl → 0.13.81__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.
Potentially problematic release.
This version of ingestr might be problematic. Click here for more details.
- ingestr/src/buildinfo.py +1 -1
- ingestr/src/facebook_ads/__init__.py +9 -15
- ingestr/src/facebook_ads/helpers.py +46 -0
- ingestr/src/linear/__init__.py +4 -2
- ingestr/src/linear/helpers.py +6 -8
- ingestr/src/sources.py +2 -19
- {ingestr-0.13.80.dist-info → ingestr-0.13.81.dist-info}/METADATA +1 -1
- {ingestr-0.13.80.dist-info → ingestr-0.13.81.dist-info}/RECORD +11 -11
- {ingestr-0.13.80.dist-info → ingestr-0.13.81.dist-info}/WHEEL +0 -0
- {ingestr-0.13.80.dist-info → ingestr-0.13.81.dist-info}/entry_points.txt +0 -0
- {ingestr-0.13.80.dist-info → ingestr-0.13.81.dist-info}/licenses/LICENSE.md +0 -0
ingestr/src/buildinfo.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
version = "v0.13.
|
|
1
|
+
version = "v0.13.81"
|
|
@@ -22,12 +22,8 @@ from .settings import (
|
|
|
22
22
|
DEFAULT_ADCREATIVE_FIELDS,
|
|
23
23
|
DEFAULT_ADSET_FIELDS,
|
|
24
24
|
DEFAULT_CAMPAIGN_FIELDS,
|
|
25
|
-
DEFAULT_INSIGHT_FIELDS,
|
|
26
25
|
DEFAULT_LEAD_FIELDS,
|
|
27
26
|
INSIGHT_FIELDS_TYPES,
|
|
28
|
-
INSIGHTS_BREAKDOWNS_OPTIONS,
|
|
29
|
-
INVALID_INSIGHTS_FIELDS,
|
|
30
|
-
TInsightsBreakdownOptions,
|
|
31
27
|
TInsightsLevels,
|
|
32
28
|
)
|
|
33
29
|
|
|
@@ -105,10 +101,9 @@ def facebook_insights_source(
|
|
|
105
101
|
account_id: str = dlt.config.value,
|
|
106
102
|
access_token: str = dlt.secrets.value,
|
|
107
103
|
initial_load_past_days: int = 1,
|
|
108
|
-
|
|
109
|
-
|
|
104
|
+
dimensions: Sequence[str] = None,
|
|
105
|
+
fields: Sequence[str] = None,
|
|
110
106
|
time_increment_days: int = 1,
|
|
111
|
-
breakdowns: TInsightsBreakdownOptions = "ads_insights",
|
|
112
107
|
action_breakdowns: Sequence[str] = ALL_ACTION_BREAKDOWNS,
|
|
113
108
|
level: TInsightsLevels = "ad",
|
|
114
109
|
action_attribution_windows: Sequence[str] = ALL_ACTION_ATTRIBUTION_WINDOWS,
|
|
@@ -155,6 +150,11 @@ def facebook_insights_source(
|
|
|
155
150
|
if start_date is None:
|
|
156
151
|
start_date = pendulum.today().subtract(days=initial_load_past_days)
|
|
157
152
|
|
|
153
|
+
if dimensions is None:
|
|
154
|
+
dimensions = []
|
|
155
|
+
if fields is None:
|
|
156
|
+
fields = []
|
|
157
|
+
|
|
158
158
|
columns = {}
|
|
159
159
|
for field in fields:
|
|
160
160
|
if field in INSIGHT_FIELDS_TYPES:
|
|
@@ -187,15 +187,9 @@ def facebook_insights_source(
|
|
|
187
187
|
query = {
|
|
188
188
|
"level": level,
|
|
189
189
|
"action_breakdowns": list(action_breakdowns),
|
|
190
|
-
"breakdowns":
|
|
191
|
-
INSIGHTS_BREAKDOWNS_OPTIONS[breakdowns]["breakdowns"]
|
|
192
|
-
),
|
|
190
|
+
"breakdowns": dimensions,
|
|
193
191
|
"limit": batch_size,
|
|
194
|
-
"fields":
|
|
195
|
-
set(fields)
|
|
196
|
-
.union(INSIGHTS_BREAKDOWNS_OPTIONS[breakdowns]["fields"])
|
|
197
|
-
.difference(INVALID_INSIGHTS_FIELDS)
|
|
198
|
-
),
|
|
192
|
+
"fields": fields,
|
|
199
193
|
"time_increment": time_increment_days,
|
|
200
194
|
"action_attribution_windows": list(action_attribution_windows),
|
|
201
195
|
"time_ranges": [
|
|
@@ -229,3 +229,49 @@ def notify_on_token_expiration(access_token_expires_at: int = None) -> None:
|
|
|
229
229
|
logger.error(
|
|
230
230
|
f"Access Token expires in {humanize.precisedelta(pendulum.now() - expires_at)}. Replace the token now!"
|
|
231
231
|
)
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def parse_insights_table_to_source_kwargs(table: str) -> DictStrAny:
|
|
235
|
+
import typing
|
|
236
|
+
|
|
237
|
+
from ingestr.src.facebook_ads.settings import (
|
|
238
|
+
INSIGHTS_BREAKDOWNS_OPTIONS,
|
|
239
|
+
TInsightsBreakdownOptions,
|
|
240
|
+
TInsightsLevels,
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
parts = table.split(":")
|
|
244
|
+
|
|
245
|
+
source_kwargs = {}
|
|
246
|
+
|
|
247
|
+
breakdown_type = parts[1]
|
|
248
|
+
|
|
249
|
+
valid_breakdowns = list(typing.get_args(TInsightsBreakdownOptions))
|
|
250
|
+
if breakdown_type in valid_breakdowns:
|
|
251
|
+
dimensions = INSIGHTS_BREAKDOWNS_OPTIONS[breakdown_type]["breakdowns"]
|
|
252
|
+
fields = INSIGHTS_BREAKDOWNS_OPTIONS[breakdown_type]["fields"]
|
|
253
|
+
source_kwargs["dimensions"] = dimensions
|
|
254
|
+
source_kwargs["fields"] = fields
|
|
255
|
+
else:
|
|
256
|
+
dimensions = breakdown_type.split(",")
|
|
257
|
+
valid_levels = list(typing.get_args(TInsightsLevels))
|
|
258
|
+
level = None
|
|
259
|
+
for valid_level in reversed(valid_levels):
|
|
260
|
+
if valid_level in dimensions:
|
|
261
|
+
level = valid_level
|
|
262
|
+
dimensions.remove(valid_level)
|
|
263
|
+
break
|
|
264
|
+
|
|
265
|
+
source_kwargs["level"] = level
|
|
266
|
+
source_kwargs["dimensions"] = dimensions
|
|
267
|
+
|
|
268
|
+
# If custom metrics are provided, parse them
|
|
269
|
+
if len(parts) == 3:
|
|
270
|
+
fields = [f.strip() for f in parts[2].split(",") if f.strip()]
|
|
271
|
+
if not fields:
|
|
272
|
+
raise ValueError(
|
|
273
|
+
"Custom metrics must be provided after the second colon in format: facebook_insights:breakdown_type:metric1,metric2..."
|
|
274
|
+
)
|
|
275
|
+
source_kwargs["fields"] = fields
|
|
276
|
+
|
|
277
|
+
return source_kwargs
|
ingestr/src/linear/__init__.py
CHANGED
|
@@ -17,9 +17,10 @@ def _get_date_range(updated_at, start_date):
|
|
|
17
17
|
current_end_date = pendulum.parse(updated_at.end_value)
|
|
18
18
|
else:
|
|
19
19
|
current_end_date = pendulum.now(tz="UTC")
|
|
20
|
-
|
|
20
|
+
|
|
21
21
|
return current_start_date, current_end_date
|
|
22
22
|
|
|
23
|
+
|
|
23
24
|
ISSUES_QUERY = """
|
|
24
25
|
query Issues($cursor: String) {
|
|
25
26
|
issues(first: 50, after: $cursor) {
|
|
@@ -119,6 +120,7 @@ query WorkflowStates($cursor: String) {
|
|
|
119
120
|
}
|
|
120
121
|
"""
|
|
121
122
|
|
|
123
|
+
|
|
122
124
|
@dlt.source(name="linear", max_table_nesting=0)
|
|
123
125
|
def linear_source(
|
|
124
126
|
api_key: str,
|
|
@@ -211,5 +213,5 @@ def linear_source(
|
|
|
211
213
|
if pendulum.parse(item["updatedAt"]) >= current_start_date:
|
|
212
214
|
if pendulum.parse(item["updatedAt"]) <= current_end_date:
|
|
213
215
|
yield normalize_dictionaries(item)
|
|
214
|
-
return [issues, projects, teams, users, workflow_states]
|
|
215
216
|
|
|
217
|
+
return [issues, projects, teams, users, workflow_states]
|
ingestr/src/linear/helpers.py
CHANGED
|
@@ -32,8 +32,6 @@ def _paginate(api_key: str, query: str, root: str) -> Iterator[Dict[str, Any]]:
|
|
|
32
32
|
cursor = data["pageInfo"]["endCursor"]
|
|
33
33
|
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
35
|
def normalize_dictionaries(item: Dict[str, Any]) -> Dict[str, Any]:
|
|
38
36
|
"""
|
|
39
37
|
Automatically normalize dictionary fields by detecting their structure:
|
|
@@ -41,15 +39,15 @@ def normalize_dictionaries(item: Dict[str, Any]) -> Dict[str, Any]:
|
|
|
41
39
|
- Convert objects with 'nodes' field to arrays
|
|
42
40
|
"""
|
|
43
41
|
normalized_item = item.copy()
|
|
44
|
-
|
|
42
|
+
|
|
45
43
|
for key, value in list(normalized_item.items()):
|
|
46
44
|
if isinstance(value, dict):
|
|
47
45
|
# If the dict has an 'id' field, replace with {key}_id
|
|
48
|
-
if
|
|
49
|
-
normalized_item[f"{key}_id"] = value[
|
|
46
|
+
if "id" in value:
|
|
47
|
+
normalized_item[f"{key}_id"] = value["id"]
|
|
50
48
|
del normalized_item[key]
|
|
51
49
|
# If the dict has 'nodes' field, extract the nodes array
|
|
52
|
-
elif
|
|
53
|
-
normalized_item[key] = value[
|
|
54
|
-
|
|
50
|
+
elif "nodes" in value:
|
|
51
|
+
normalized_item[key] = value["nodes"]
|
|
52
|
+
|
|
55
53
|
return normalized_item
|
ingestr/src/sources.py
CHANGED
|
@@ -1056,33 +1056,16 @@ class FacebookAdsSource:
|
|
|
1056
1056
|
# Validate breakdown type against available options from settings
|
|
1057
1057
|
import typing
|
|
1058
1058
|
|
|
1059
|
-
from ingestr.src.facebook_ads.
|
|
1060
|
-
|
|
1061
|
-
# Get valid breakdown options from the type definition
|
|
1062
|
-
valid_breakdowns = list(typing.get_args(TInsightsBreakdownOptions))
|
|
1063
|
-
|
|
1064
|
-
if breakdown_type not in valid_breakdowns:
|
|
1065
|
-
raise ValueError(
|
|
1066
|
-
f"Invalid breakdown type '{breakdown_type}'. Valid options: {', '.join(valid_breakdowns)}"
|
|
1067
|
-
)
|
|
1059
|
+
from ingestr.src.facebook_ads.helpers import parse_insights_table_to_source_kwargs
|
|
1068
1060
|
|
|
1069
1061
|
source_kwargs = {
|
|
1070
1062
|
"access_token": access_token[0],
|
|
1071
1063
|
"account_id": account_id[0],
|
|
1072
1064
|
"start_date": kwargs.get("interval_start"),
|
|
1073
1065
|
"end_date": kwargs.get("interval_end"),
|
|
1074
|
-
"breakdowns": breakdown_type,
|
|
1075
1066
|
}
|
|
1076
1067
|
|
|
1077
|
-
|
|
1078
|
-
if len(parts) == 3:
|
|
1079
|
-
fields = [f.strip() for f in parts[2].split(",") if f.strip()]
|
|
1080
|
-
if not fields:
|
|
1081
|
-
raise ValueError(
|
|
1082
|
-
"Custom metrics must be provided after the second colon in format: facebook_insights:breakdown_type:metric1,metric2..."
|
|
1083
|
-
)
|
|
1084
|
-
source_kwargs["fields"] = fields
|
|
1085
|
-
|
|
1068
|
+
source_kwargs.update(parse_insights_table_to_source_kwargs(table))
|
|
1086
1069
|
return facebook_insights_source(**source_kwargs).with_resources(
|
|
1087
1070
|
"facebook_insights"
|
|
1088
1071
|
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ingestr
|
|
3
|
-
Version: 0.13.
|
|
3
|
+
Version: 0.13.81
|
|
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
|
|
@@ -2,7 +2,7 @@ ingestr/conftest.py,sha256=OE2yxeTCosS9CUFVuqNypm-2ftYvVBeeq7egm3878cI,1981
|
|
|
2
2
|
ingestr/main.py,sha256=qoWHNcHh0-xVnyQxbQ-SKuTxPb1RNV3ENkCpqO7CLrk,26694
|
|
3
3
|
ingestr/src/.gitignore,sha256=8cX1AZTSI0TcdZFGTmS_oyBjpfCzhOEt0DdAo2dFIY8,203
|
|
4
4
|
ingestr/src/blob.py,sha256=UUWMjHUuoR9xP1XZQ6UANQmnMVyDx3d0X4-2FQC271I,2138
|
|
5
|
-
ingestr/src/buildinfo.py,sha256=
|
|
5
|
+
ingestr/src/buildinfo.py,sha256=H6wsXWMjlzTHcGuLKaXl67mkAFCFJzin5gNxWfo6nMg,21
|
|
6
6
|
ingestr/src/destinations.py,sha256=M2Yni6wiWcrvZ8EPJemidqxN156l0rehgCc7xuil7mo,22840
|
|
7
7
|
ingestr/src/errors.py,sha256=Ufs4_DfE77_E3vnA1fOQdi6cmuLVNm7_SbFLkL1XPGk,686
|
|
8
8
|
ingestr/src/factory.py,sha256=rF5Ry4o4t8KulSPBtrd7ZKCI_0TH1DAetG0zs9H7oik,6792
|
|
@@ -11,7 +11,7 @@ ingestr/src/http_client.py,sha256=bxqsk6nJNXCo-79gW04B53DQO-yr25vaSsqP0AKtjx4,73
|
|
|
11
11
|
ingestr/src/loader.py,sha256=9NaWAyfkXdqAZSS-N72Iwo36Lbx4PyqIfaaH1dNdkFs,1712
|
|
12
12
|
ingestr/src/partition.py,sha256=BrIP6wFJvyR7Nus_3ElnfxknUXeCipK_E_bB8kZowfc,969
|
|
13
13
|
ingestr/src/resource.py,sha256=ZqmZxFQVGlF8rFPhBiUB08HES0yoTj8sZ--jKfaaVps,1164
|
|
14
|
-
ingestr/src/sources.py,sha256=
|
|
14
|
+
ingestr/src/sources.py,sha256=wdNRqVzuR8EK8s8SzL3lZ8UE6UrqLMq-FJGkc23rrpM,119190
|
|
15
15
|
ingestr/src/table_definition.py,sha256=REbAbqdlmUMUuRh8nEQRreWjPVOQ5ZcfqGkScKdCrmk,390
|
|
16
16
|
ingestr/src/time.py,sha256=H_Fk2J4ShXyUM-EMY7MqCLZQhlnZMZvO952bmZPc4yE,254
|
|
17
17
|
ingestr/src/version.py,sha256=J_2xgZ0mKlvuHcjdKCx2nlioneLH0I47JiU_Slr_Nwc,189
|
|
@@ -41,9 +41,9 @@ ingestr/src/clickup/helpers.py,sha256=RzDKMUAHccuDhocIQ2ToBXfCERo8CBJqA3t-IPltBC
|
|
|
41
41
|
ingestr/src/collector/spinner.py,sha256=_ZUqF5MI43hVIULdjF5s5mrAZbhEFXaiWirQmrv3Yk4,1201
|
|
42
42
|
ingestr/src/dynamodb/__init__.py,sha256=swhxkeYBbJ35jn1IghCtvYWT2BM33KynVCh_oR4z28A,2264
|
|
43
43
|
ingestr/src/elasticsearch/__init__.py,sha256=m-q93HgUmTwGDUwHOjHawstWL06TC3WIX3H05szybrY,2556
|
|
44
|
-
ingestr/src/facebook_ads/__init__.py,sha256=
|
|
44
|
+
ingestr/src/facebook_ads/__init__.py,sha256=15GiovITANe0al5MI6WWLdl3LDmdBd1YpkUWBV3g6bk,9715
|
|
45
45
|
ingestr/src/facebook_ads/exceptions.py,sha256=4Nlbc0Mv3i5g-9AoyT-n1PIa8IDi3VCTfEAzholx4Wc,115
|
|
46
|
-
ingestr/src/facebook_ads/helpers.py,sha256=
|
|
46
|
+
ingestr/src/facebook_ads/helpers.py,sha256=c-WG008yU_zIdhFwljtqE2jfjVYuaVoNKldxcnJN3U4,9761
|
|
47
47
|
ingestr/src/facebook_ads/settings.py,sha256=Bsic8RcmH-NfEZ7r_NGospTCmwISK9XaMT5y2NZirtg,4938
|
|
48
48
|
ingestr/src/facebook_ads/utils.py,sha256=ES2ylPoW3j3fjp6OMUgp21n1cG1OktXsmWWMk5vBW_I,1590
|
|
49
49
|
ingestr/src/filesystem/__init__.py,sha256=zkIwbRr0ir0EUdniI25p2zGiVc-7M9EmR351AjNb0eA,4163
|
|
@@ -85,8 +85,8 @@ ingestr/src/kinesis/helpers.py,sha256=SO2cFmWNGcykUYmjHdfxWsOQSkLQXyhFtfWnkcUOM0
|
|
|
85
85
|
ingestr/src/klaviyo/__init__.py,sha256=o_noUgbxLk36s4f9W56_ibPorF0n7kVapPUlV0p-jfA,7875
|
|
86
86
|
ingestr/src/klaviyo/client.py,sha256=tPj79ia7AW0ZOJhzlKNPCliGbdojRNwUFp8HvB2ym5s,7434
|
|
87
87
|
ingestr/src/klaviyo/helpers.py,sha256=_i-SHffhv25feLDcjy6Blj1UxYLISCwVCMgGtrlnYHk,496
|
|
88
|
-
ingestr/src/linear/__init__.py,sha256=
|
|
89
|
-
ingestr/src/linear/helpers.py,sha256=
|
|
88
|
+
ingestr/src/linear/__init__.py,sha256=CZnRQfP44L1fy4ppnukuTr1wWKSNlPpaLFE3Xw5vJr0,6605
|
|
89
|
+
ingestr/src/linear/helpers.py,sha256=jpG9l3JhJVXk2K77iny8BMqkYHGycwS4Kmcdq2Xs7aE,1786
|
|
90
90
|
ingestr/src/linkedin_ads/__init__.py,sha256=CAPWFyV24loziiphbLmODxZUXZJwm4JxlFkr56q0jfo,1855
|
|
91
91
|
ingestr/src/linkedin_ads/dimension_time_enum.py,sha256=EmHRdkFyTAfo4chGjThrwqffWJxmAadZMbpTvf0xkQc,198
|
|
92
92
|
ingestr/src/linkedin_ads/helpers.py,sha256=eUWudRVlXl4kqIhfXQ1eVsUpZwJn7UFqKSpnbLfxzds,4498
|
|
@@ -151,8 +151,8 @@ ingestr/testdata/merge_expected.csv,sha256=DReHqWGnQMsf2PBv_Q2pfjsgvikYFnf1zYcQZ
|
|
|
151
151
|
ingestr/testdata/merge_part1.csv,sha256=Pw8Z9IDKcNU0qQHx1z6BUf4rF_-SxKGFOvymCt4OY9I,185
|
|
152
152
|
ingestr/testdata/merge_part2.csv,sha256=T_GiWxA81SN63_tMOIuemcvboEFeAmbKc7xRXvL9esw,287
|
|
153
153
|
ingestr/tests/unit/test_smartsheets.py,sha256=eiC2CCO4iNJcuN36ONvqmEDryCA1bA1REpayHpu42lk,5058
|
|
154
|
-
ingestr-0.13.
|
|
155
|
-
ingestr-0.13.
|
|
156
|
-
ingestr-0.13.
|
|
157
|
-
ingestr-0.13.
|
|
158
|
-
ingestr-0.13.
|
|
154
|
+
ingestr-0.13.81.dist-info/METADATA,sha256=jjolsfHDoVMclLreJMhKFu6s1_FZ5d_eN2F8CFgEDFA,15182
|
|
155
|
+
ingestr-0.13.81.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
156
|
+
ingestr-0.13.81.dist-info/entry_points.txt,sha256=oPJy0KBnPWYjDtP1k8qwAihcTLHSZokSQvRAw_wtfJM,46
|
|
157
|
+
ingestr-0.13.81.dist-info/licenses/LICENSE.md,sha256=cW8wIhn8HFE-KLStDF9jHQ1O_ARWP3kTpk_-eOccL24,1075
|
|
158
|
+
ingestr-0.13.81.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|