ingestr 0.13.12__py3-none-any.whl → 0.13.13__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.
- ingestr/src/applovin_max/__init__.py +58 -42
- ingestr/src/buildinfo.py +1 -1
- ingestr/src/sources.py +36 -17
- {ingestr-0.13.12.dist-info → ingestr-0.13.13.dist-info}/METADATA +3 -2
- {ingestr-0.13.12.dist-info → ingestr-0.13.13.dist-info}/RECORD +8 -8
- {ingestr-0.13.12.dist-info → ingestr-0.13.13.dist-info}/WHEEL +0 -0
- {ingestr-0.13.12.dist-info → ingestr-0.13.13.dist-info}/entry_points.txt +0 -0
- {ingestr-0.13.12.dist-info → ingestr-0.13.13.dist-info}/licenses/LICENSE.md +0 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from datetime import timedelta
|
|
1
2
|
from typing import Iterator
|
|
2
3
|
|
|
3
4
|
import dlt
|
|
@@ -11,20 +12,23 @@ from pendulum.date import Date
|
|
|
11
12
|
|
|
12
13
|
@dlt.source(max_table_nesting=0)
|
|
13
14
|
def applovin_max_source(
|
|
14
|
-
start_date:
|
|
15
|
-
|
|
15
|
+
start_date: Date,
|
|
16
|
+
applications: list[str],
|
|
16
17
|
api_key: str,
|
|
17
|
-
end_date:
|
|
18
|
+
end_date: Date | None,
|
|
18
19
|
) -> DltResource:
|
|
19
20
|
@dlt.resource(
|
|
20
|
-
name="
|
|
21
|
+
name="user_ad_revenue",
|
|
21
22
|
write_disposition="merge",
|
|
22
|
-
merge_key="
|
|
23
|
+
merge_key="partition_date",
|
|
24
|
+
columns={
|
|
25
|
+
"partition_date": {"data_type": "date", "partition": True},
|
|
26
|
+
},
|
|
23
27
|
)
|
|
24
28
|
def fetch_ad_revenue_report(
|
|
25
29
|
dateTime=(
|
|
26
30
|
dlt.sources.incremental(
|
|
27
|
-
"
|
|
31
|
+
"partition_date",
|
|
28
32
|
initial_value=start_date,
|
|
29
33
|
end_value=end_date,
|
|
30
34
|
range_start="closed",
|
|
@@ -33,18 +37,31 @@ def applovin_max_source(
|
|
|
33
37
|
),
|
|
34
38
|
) -> Iterator[dict]:
|
|
35
39
|
url = "https://r.applovin.com/max/userAdRevenueReport"
|
|
36
|
-
start_date =
|
|
40
|
+
start_date = dateTime.last_value
|
|
41
|
+
|
|
37
42
|
if dateTime.end_value is None:
|
|
38
43
|
end_date = (pendulum.yesterday("UTC")).date()
|
|
39
44
|
else:
|
|
40
|
-
end_date =
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
end_date = dateTime.end_value
|
|
46
|
+
|
|
47
|
+
client = create_client()
|
|
48
|
+
platforms = ["ios", "android", "fireos"]
|
|
49
|
+
|
|
50
|
+
for app in applications:
|
|
51
|
+
current_date = start_date
|
|
52
|
+
while current_date <= end_date:
|
|
53
|
+
for platform in platforms:
|
|
54
|
+
df = get_data(
|
|
55
|
+
url=url,
|
|
56
|
+
current_date=current_date,
|
|
57
|
+
application=app,
|
|
58
|
+
api_key=api_key,
|
|
59
|
+
client=client,
|
|
60
|
+
platform=platform,
|
|
61
|
+
)
|
|
62
|
+
if df is not None:
|
|
63
|
+
yield df
|
|
64
|
+
current_date = current_date + timedelta(days=1)
|
|
48
65
|
|
|
49
66
|
return fetch_ad_revenue_report
|
|
50
67
|
|
|
@@ -67,33 +84,32 @@ def retry_on_limit(
|
|
|
67
84
|
|
|
68
85
|
|
|
69
86
|
def get_data(
|
|
70
|
-
url: str,
|
|
87
|
+
url: str,
|
|
88
|
+
current_date: Date,
|
|
89
|
+
application: str,
|
|
90
|
+
api_key: str,
|
|
91
|
+
platform: str,
|
|
92
|
+
client: requests.Session,
|
|
71
93
|
):
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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
|
|
94
|
+
params = {
|
|
95
|
+
"api_key": api_key,
|
|
96
|
+
"date": current_date.isoformat(),
|
|
97
|
+
"platform": platform,
|
|
98
|
+
"application": application,
|
|
99
|
+
"aggregated": "false",
|
|
100
|
+
}
|
|
92
101
|
|
|
93
|
-
|
|
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
|
|
102
|
+
response = client.get(url=url, params=params)
|
|
98
103
|
|
|
99
|
-
|
|
104
|
+
if response.status_code != 200:
|
|
105
|
+
if response.status_code == 404:
|
|
106
|
+
if "No Mediation App Id found for platform" in response.text:
|
|
107
|
+
return None
|
|
108
|
+
error_message = f"AppLovin MAX API error (status {response.status_code}): {response.text}"
|
|
109
|
+
raise requests.HTTPError(error_message)
|
|
110
|
+
|
|
111
|
+
response_url = response.json().get("ad_revenue_report_url")
|
|
112
|
+
df = pd.read_csv(response_url)
|
|
113
|
+
df["Date"] = pd.to_datetime(df["Date"])
|
|
114
|
+
df["partition_date"] = df["Date"].dt.date
|
|
115
|
+
return df
|
ingestr/src/buildinfo.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
version = "v0.13.
|
|
1
|
+
version = "v0.13.13"
|
ingestr/src/sources.py
CHANGED
|
@@ -1833,6 +1833,9 @@ class AppLovinSource:
|
|
|
1833
1833
|
|
|
1834
1834
|
|
|
1835
1835
|
class ApplovinMaxSource:
|
|
1836
|
+
#expected uri format: applovinmax://?api_key=<api_key>
|
|
1837
|
+
#expected table format: user_ad_revenue:app_id_1,app_id_2
|
|
1838
|
+
|
|
1836
1839
|
def handles_incrementality(self) -> bool:
|
|
1837
1840
|
return True
|
|
1838
1841
|
|
|
@@ -1843,38 +1846,54 @@ class ApplovinMaxSource:
|
|
|
1843
1846
|
api_key = params.get("api_key")
|
|
1844
1847
|
if api_key is None:
|
|
1845
1848
|
raise ValueError("api_key is required to connect to AppLovin Max API.")
|
|
1849
|
+
|
|
1850
|
+
AVAILABLE_TABLES = ["user_ad_revenue"]
|
|
1846
1851
|
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
raise ValueError("application is required to connect to AppLovin Max API.")
|
|
1852
|
+
table_fields = table.split(":")
|
|
1853
|
+
requested_table = table_fields[0]
|
|
1850
1854
|
|
|
1851
|
-
|
|
1852
|
-
interval_end = kwargs.get("interval_end")
|
|
1853
|
-
|
|
1854
|
-
if "ad_revenue" in table:
|
|
1855
|
-
table = "ad_revenue"
|
|
1856
|
-
else:
|
|
1855
|
+
if len(table_fields) != 2:
|
|
1857
1856
|
raise ValueError(
|
|
1858
|
-
|
|
1857
|
+
"Invalid table format. Expected format is user_ad_revenue:app_id_1,app_id_2"
|
|
1858
|
+
)
|
|
1859
|
+
|
|
1860
|
+
if requested_table not in AVAILABLE_TABLES:
|
|
1861
|
+
raise ValueError(
|
|
1862
|
+
f"Table name '{requested_table}' is not supported for AppLovin Max source yet."
|
|
1863
|
+
f"Only '{AVAILABLE_TABLES}' are currently supported. "
|
|
1864
|
+
"If you need additional tables, please create a GitHub issue at "
|
|
1865
|
+
"https://github.com/bruin-data/ingestr"
|
|
1866
|
+
)
|
|
1867
|
+
|
|
1868
|
+
applications = [i for i in table_fields[1].replace(" ", "").split(",") if i.strip()]
|
|
1869
|
+
if len(applications) == 0:
|
|
1870
|
+
raise ValueError(
|
|
1871
|
+
"At least one application id is required"
|
|
1872
|
+
)
|
|
1873
|
+
|
|
1874
|
+
if len(applications) != len(set(applications)):
|
|
1875
|
+
raise ValueError(
|
|
1876
|
+
"Application ids must be unique."
|
|
1859
1877
|
)
|
|
1860
1878
|
|
|
1879
|
+
interval_start = kwargs.get("interval_start")
|
|
1880
|
+
interval_end = kwargs.get("interval_end")
|
|
1881
|
+
|
|
1861
1882
|
now = pendulum.now("UTC")
|
|
1862
1883
|
default_start = now.subtract(days=30).date()
|
|
1863
1884
|
|
|
1864
1885
|
start_date = (
|
|
1865
|
-
interval_start if interval_start is not None else default_start
|
|
1866
|
-
).strftime("%Y-%m-%d")
|
|
1867
|
-
|
|
1868
|
-
end_date = (
|
|
1869
|
-
interval_end.strftime("%Y-%m-%d") if interval_end is not None else None
|
|
1886
|
+
interval_start.date() if interval_start is not None else default_start
|
|
1870
1887
|
)
|
|
1871
1888
|
|
|
1889
|
+
end_date = interval_end.date() if interval_end is not None else None
|
|
1890
|
+
|
|
1872
1891
|
return applovin_max_source(
|
|
1873
1892
|
start_date=start_date,
|
|
1874
1893
|
end_date=end_date,
|
|
1875
1894
|
api_key=api_key[0],
|
|
1876
|
-
|
|
1877
|
-
).with_resources(
|
|
1895
|
+
applications=applications,
|
|
1896
|
+
).with_resources(requested_table)
|
|
1878
1897
|
|
|
1879
1898
|
|
|
1880
1899
|
class SalesforceSource:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ingestr
|
|
3
|
-
Version: 0.13.
|
|
3
|
+
Version: 0.13.13
|
|
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,6 +57,7 @@ Requires-Dist: stripe==10.7.0
|
|
|
57
57
|
Requires-Dist: tqdm==4.67.1
|
|
58
58
|
Requires-Dist: typer==0.13.1
|
|
59
59
|
Requires-Dist: types-requests==2.32.0.20240907
|
|
60
|
+
Requires-Dist: zstd==1.5.6.1
|
|
60
61
|
Provides-Extra: odbc
|
|
61
62
|
Requires-Dist: pyodbc==5.1.0; extra == 'odbc'
|
|
62
63
|
Provides-Extra: oracle
|
|
@@ -149,7 +150,7 @@ Pull requests are welcome. However, please open an issue first to discuss what y
|
|
|
149
150
|
</tr>
|
|
150
151
|
<tr>
|
|
151
152
|
<td>ClickHouse</td>
|
|
152
|
-
<td
|
|
153
|
+
<td>✅</td>
|
|
153
154
|
<td>✅</td>
|
|
154
155
|
</tr>
|
|
155
156
|
<tr>
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
ingestr/main.py,sha256=ufn8AcM2ID80ChUApJzYDjnQaurMXOkYfTm6GzAggSQ,24746
|
|
2
2
|
ingestr/src/.gitignore,sha256=8cX1AZTSI0TcdZFGTmS_oyBjpfCzhOEt0DdAo2dFIY8,203
|
|
3
3
|
ingestr/src/blob.py,sha256=LtEZWoUhm5i2aKerdgEpLtNCf3fdhGGMM4td-LRZVbY,1407
|
|
4
|
-
ingestr/src/buildinfo.py,sha256=
|
|
4
|
+
ingestr/src/buildinfo.py,sha256=hLtrn_2NNb0KhD_VpjlyF4uvE7jjsD2W10llc0aDpxE,21
|
|
5
5
|
ingestr/src/destinations.py,sha256=vrGij4qMPCdXTMIimROWBJFqzOqCM4DFmgyubgSHejA,11279
|
|
6
6
|
ingestr/src/errors.py,sha256=Ufs4_DfE77_E3vnA1fOQdi6cmuLVNm7_SbFLkL1XPGk,686
|
|
7
7
|
ingestr/src/factory.py,sha256=lvq-RTdzCqok-F0IVCZN0Q9ALVnuhNT06T1ju3lnPn8,5127
|
|
8
8
|
ingestr/src/filters.py,sha256=0JQXeAr2APFMnW2sd-6BlAMWv93bXV17j8b5MM8sHmM,580
|
|
9
9
|
ingestr/src/loader.py,sha256=9NaWAyfkXdqAZSS-N72Iwo36Lbx4PyqIfaaH1dNdkFs,1712
|
|
10
|
-
ingestr/src/sources.py,sha256=
|
|
10
|
+
ingestr/src/sources.py,sha256=vCZ20jVD5jCCNyTxR7VxNXpJFCE218t0ydbaZwls48M,69510
|
|
11
11
|
ingestr/src/table_definition.py,sha256=REbAbqdlmUMUuRh8nEQRreWjPVOQ5ZcfqGkScKdCrmk,390
|
|
12
12
|
ingestr/src/time.py,sha256=H_Fk2J4ShXyUM-EMY7MqCLZQhlnZMZvO952bmZPc4yE,254
|
|
13
13
|
ingestr/src/version.py,sha256=J_2xgZ0mKlvuHcjdKCx2nlioneLH0I47JiU_Slr_Nwc,189
|
|
@@ -15,7 +15,7 @@ ingestr/src/adjust/__init__.py,sha256=ULjtJqrNS6XDvUyGl0tjl12-tLyXlCgeFe2icTbtu3
|
|
|
15
15
|
ingestr/src/adjust/adjust_helpers.py,sha256=av97NPSn-hQtTbAC0vUSCAWYePmOiG5R-DGdMssm7FQ,3646
|
|
16
16
|
ingestr/src/airtable/__init__.py,sha256=GHWYrjI2qhs_JihdNJysB0Ni3bzqT_MLXn_S9_Q5zRA,2775
|
|
17
17
|
ingestr/src/applovin/__init__.py,sha256=X_YCLppPrnL8KXfYWICE_uDfMzHHH3JZ-DBGZ1RlaOI,6984
|
|
18
|
-
ingestr/src/applovin_max/__init__.py,sha256=
|
|
18
|
+
ingestr/src/applovin_max/__init__.py,sha256=o0aL4jBZqwK528MVw9dS1G5EZbF4tx6_Ef0IfqkhAT0,3294
|
|
19
19
|
ingestr/src/appsflyer/_init_.py,sha256=ne2-9FQ654Drtd3GkKQv8Bwb6LEqCnJw49MfO5Jyzgs,739
|
|
20
20
|
ingestr/src/appsflyer/client.py,sha256=TNmwakLzmO6DZW3wcfLfQRl7aNBHgFqSsk4ef-MmJ1w,3084
|
|
21
21
|
ingestr/src/appstore/__init__.py,sha256=3P4VZH2WJF477QjW19jMTwu6L8DXcLkYSdutnvp3AmM,4742
|
|
@@ -108,8 +108,8 @@ ingestr/testdata/delete_insert_part2.csv,sha256=B_KUzpzbNdDY_n7wWop1mT2cz36TmayS
|
|
|
108
108
|
ingestr/testdata/merge_expected.csv,sha256=DReHqWGnQMsf2PBv_Q2pfjsgvikYFnf1zYcQZ7ZqYN0,276
|
|
109
109
|
ingestr/testdata/merge_part1.csv,sha256=Pw8Z9IDKcNU0qQHx1z6BUf4rF_-SxKGFOvymCt4OY9I,185
|
|
110
110
|
ingestr/testdata/merge_part2.csv,sha256=T_GiWxA81SN63_tMOIuemcvboEFeAmbKc7xRXvL9esw,287
|
|
111
|
-
ingestr-0.13.
|
|
112
|
-
ingestr-0.13.
|
|
113
|
-
ingestr-0.13.
|
|
114
|
-
ingestr-0.13.
|
|
115
|
-
ingestr-0.13.
|
|
111
|
+
ingestr-0.13.13.dist-info/METADATA,sha256=D8jPk86Pl8XTtLvx2VFSbjC-wqCz9X0r8K74q29T26o,9200
|
|
112
|
+
ingestr-0.13.13.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
113
|
+
ingestr-0.13.13.dist-info/entry_points.txt,sha256=oPJy0KBnPWYjDtP1k8qwAihcTLHSZokSQvRAw_wtfJM,46
|
|
114
|
+
ingestr-0.13.13.dist-info/licenses/LICENSE.md,sha256=cW8wIhn8HFE-KLStDF9jHQ1O_ARWP3kTpk_-eOccL24,1075
|
|
115
|
+
ingestr-0.13.13.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|