digital-analytics-toolkit 0.1.0__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.
@@ -0,0 +1,468 @@
1
+ from googleapiclient.discovery import build
2
+ import pandas as pd
3
+
4
+ def get_accounts(creds):
5
+ """
6
+ Retrieve all Google Tag Manager (GTM) accounts accessible to the
7
+ authenticated user.
8
+
9
+ Args:
10
+ creds: Google OAuth2 credentials used to authenticate with the
11
+ GTM API.
12
+
13
+ Returns:
14
+ list[dict]: A list of GTM account resources. Returns an empty list
15
+ if no accounts are found.
16
+ """
17
+ service = build("tagmanager", "v2", credentials=creds)
18
+ response = service.accounts().list().execute()
19
+ return response.get("account", [])
20
+
21
+ def get_containers(creds, account_id):
22
+ """
23
+ Retrieve all GTM containers accessible to the authenticated user.
24
+
25
+ Args:
26
+ creds: Google OAuth2 credentials used to authenticate with the
27
+ GTM API.
28
+ account_id (str): The GTM account ID.
29
+
30
+ Returns:
31
+ DataFrame: A DataFrame containing the GTM container resources.
32
+ """
33
+ service = build("tagmanager", "v2", credentials=creds)
34
+ parent = f"accounts/{account_id}"
35
+ response = service.accounts().containers().list(parent=parent).execute()
36
+ containers = pd.DataFrame(response.get("container", []))
37
+ return containers.loc[:, ["path", "accountId", "containerId", "name", "publicId", "usageContext", "fingerprint", "tagManagerUrl"]]
38
+
39
+ def get_container_type(creds, account_id, container_id):
40
+ """
41
+ Retrieve the type of a specific GTM container.
42
+
43
+ Args:
44
+ creds: Google OAuth2 credentials used to authenticate with the
45
+ GTM API.
46
+ account_id (str): The GTM account ID.
47
+ container_id (str): The GTM container ID.
48
+
49
+ Returns:
50
+ str: The type of the container.
51
+ """
52
+ service = build("tagmanager", "v2", credentials=creds)
53
+ parent = f"accounts/{account_id}/containers/{container_id}"
54
+ response = service.accounts().containers().get(path=parent).execute()
55
+ return response.get("usageContext")[0]
56
+
57
+ def get_workspaces(creds, account_id, container_id):
58
+ """
59
+ Retrieve workspace information for a specific GTM container.
60
+
61
+ Args:
62
+ creds: Google OAuth2 credentials used to authenticate with the
63
+ GTM API.
64
+ account_id (str): The GTM account ID.
65
+ container_id (str): The GTM container ID.
66
+
67
+ Returns:
68
+ str | None: The workspace ID of the last workspace returned by the
69
+ API response. Returns ``None`` if no workspaces are found.
70
+
71
+ Note:
72
+ Although the API may return multiple workspaces, this function
73
+ currently returns only the last workspace ID from the response.
74
+
75
+ """
76
+ service = build("tagmanager", "v2", credentials=creds)
77
+ parent = f"accounts/{account_id}/containers/{container_id}"
78
+ response = service.accounts().containers().workspaces().list(
79
+ parent=parent
80
+ ).execute()
81
+
82
+ for w in response.get("workspace", []):
83
+ workspace_id = w.get("workspaceId")
84
+
85
+ # Workspaces are returned under key "workspace"
86
+ return workspace_id
87
+
88
+ def getLatestVersionHeader(creds, account_id, container_id):
89
+ """
90
+ Retrieve the latest GTM container version header.
91
+
92
+ Args:
93
+ creds: Google OAuth2 credentials.
94
+ account_id (str): GTM account ID.
95
+ container_id (str): GTM container ID.
96
+
97
+ Returns:
98
+ dict: Latest container version header.
99
+ """
100
+ service = build("tagmanager", "v2", credentials=creds)
101
+
102
+ parent = f"accounts/{account_id}/containers/{container_id}"
103
+
104
+ response = (
105
+ service.accounts()
106
+ .containers()
107
+ .version_headers()
108
+ .latest(parent=parent)
109
+ .execute()
110
+ )
111
+
112
+ return response
113
+
114
+ def get_tags(creds, account_id, container_id, workspace_id):
115
+ """
116
+ Retrieve all tags from a specific Google Tag Manager (GTM) workspace.
117
+
118
+ Args:
119
+ creds: Google OAuth2 credentials used to authenticate with the GTM API.
120
+ account_id (str): The GTM account ID.
121
+ container_id (str): The GTM container ID.
122
+ workspace_id (str): The GTM workspace ID.
123
+
124
+ Returns:
125
+ list[dict]: A list of GTM tag resources. Returns an empty list
126
+ if no tags are found in the workspace.
127
+ """
128
+ service = build("tagmanager", "v2", credentials=creds)
129
+ parent = f"accounts/{account_id}/containers/{container_id}/workspaces/{workspace_id}"
130
+ response = service.accounts().containers().workspaces().tags().list(
131
+ parent=parent
132
+ ).execute()
133
+
134
+ # Tags are returned under key "tag"
135
+ return response.get("tag", [])
136
+
137
+ def get_variables(creds, account_id, container_id, workspace_id):
138
+ """
139
+ Retrieve all variables from a specific Google Tag Manager (GTM) workspace.
140
+
141
+ Args:
142
+ creds: Google OAuth2 credentials used to authenticate with the
143
+ GTM API.
144
+ account_id (str): The GTM account ID.
145
+ container_id (str): The GTM container ID.
146
+ workspace_id (str): The GTM workspace ID.
147
+
148
+ Returns:
149
+ list[dict]: A list of GTM variable resources. Returns an empty list
150
+ if no variables are found in the workspace.
151
+ """
152
+ service = build("tagmanager", "v2", credentials=creds)
153
+ parent = f"accounts/{account_id}/containers/{container_id}/workspaces/{workspace_id}"
154
+ response = service.accounts().containers().workspaces().variables().list(
155
+ parent=parent
156
+ ).execute()
157
+
158
+ # Variables are returned under key "variable"
159
+ return response.get("variable", [])
160
+
161
+ def get_triggers(creds, account_id, container_id, workspace_id):
162
+ """
163
+ Retrieve all triggers from a specific Google Tag Manager (GTM) workspace.
164
+ Args:
165
+ creds: Google OAuth2 credentials used to authenticate with the
166
+ GTM API.
167
+ account_id (str): The GTM account ID.
168
+ container_id (str): The GTM container ID.
169
+ workspace_id (str): The GTM workspace ID.
170
+ Returns:
171
+ list[dict]: A list of GTM trigger resources. Returns an empty list
172
+ if no triggers are found in the workspace.
173
+ """
174
+ service = build("tagmanager", "v2", credentials=creds)
175
+ parent = f"accounts/{account_id}/containers/{container_id}/workspaces/{workspace_id}"
176
+ response = service.accounts().containers().workspaces().triggers().list(
177
+ parent=parent
178
+ ).execute()
179
+
180
+ # Triggers are returned under key "trigger"
181
+ return response.get("trigger", [])
182
+
183
+
184
+ from googleapiclient.discovery import build
185
+
186
+ def get_built_in_variables(creds, account_id, container_id, workspace_id):
187
+ """
188
+ Retrieve all enabled built-in variables from a specific GTM workspace.
189
+
190
+ Args:
191
+ creds: Google OAuth2 credentials.
192
+ account_id (str): GTM account ID.
193
+ container_id (str): GTM container ID.
194
+ workspace_id (str): GTM workspace ID.
195
+
196
+ Returns:
197
+ list[dict]: A list of built-in variable resources.
198
+ """
199
+ service = build("tagmanager", "v2", credentials=creds)
200
+
201
+ parent = (
202
+ f"accounts/{account_id}"
203
+ f"/containers/{container_id}"
204
+ f"/workspaces/{workspace_id}"
205
+ )
206
+
207
+ response = (
208
+ service.accounts()
209
+ .containers()
210
+ .workspaces()
211
+ .built_in_variables()
212
+ .list(parent=parent)
213
+ .execute()
214
+ )
215
+
216
+ return response.get("builtInVariable", [])
217
+
218
+
219
+ from googleapiclient.discovery import build
220
+
221
+ def get_custom_templates(creds, account_id, container_id, workspace_id):
222
+ """
223
+ Retrieve all custom templates from a specific GTM workspace.
224
+
225
+ Args:
226
+ creds: Google OAuth2 credentials.
227
+ account_id (str): GTM account ID.
228
+ container_id (str): GTM container ID.
229
+ workspace_id (str): GTM workspace ID.
230
+
231
+ Returns:
232
+ list[dict]: A list of custom template resources.
233
+ """
234
+ service = build("tagmanager", "v2", credentials=creds)
235
+
236
+ parent = (
237
+ f"accounts/{account_id}"
238
+ f"/containers/{container_id}"
239
+ f"/workspaces/{workspace_id}"
240
+ )
241
+
242
+ response = (
243
+ service.accounts()
244
+ .containers()
245
+ .workspaces()
246
+ .templates()
247
+ .list(parent=parent)
248
+ .execute()
249
+ )
250
+
251
+ return response.get("template", [])
252
+
253
+ def _as_id_list(ids):
254
+ """
255
+ Normalize a single ID or list of IDs into a list.
256
+ Args:
257
+ ids (str | list[str]): A single resource ID or list of IDs.
258
+ Returns:
259
+ list[str]: A list of resource IDs.
260
+ """
261
+ return [ids] if isinstance(ids, str) else list(ids)
262
+
263
+
264
+ def delete_tags(creds, account_id, container_id, workspace_id, tag_ids):
265
+ """
266
+ Delete one or more tags from a GTM workspace.
267
+ Args:
268
+ creds: Google OAuth2 credentials.
269
+ account_id (str): GTM account ID.
270
+ container_id (str): GTM container ID.
271
+ workspace_id (str): GTM workspace ID.
272
+ tag_ids (str | list[str]): A single tag ID or list of tag IDs to delete.
273
+ Returns:
274
+ dict: {"deleted": [...], "failed": [{"id": ..., "error": ...}, ...]}
275
+ """
276
+ service = build("tagmanager", "v2", credentials=creds)
277
+ parent = (
278
+ f"accounts/{account_id}"
279
+ f"/containers/{container_id}"
280
+ f"/workspaces/{workspace_id}"
281
+ )
282
+
283
+ results = {"deleted": [], "failed": []}
284
+ for tag_id in _as_id_list(tag_ids):
285
+ path = f"{parent}/tags/{tag_id}"
286
+ try:
287
+ service.accounts().containers().workspaces().tags().delete(
288
+ path=path
289
+ ).execute()
290
+ results["deleted"].append(tag_id)
291
+ except Exception as e:
292
+ results["failed"].append({"id": tag_id, "error": str(e)})
293
+
294
+ return results
295
+
296
+
297
+ def delete_triggers(creds, account_id, container_id, workspace_id, trigger_ids):
298
+ """
299
+ Delete one or more triggers from a GTM workspace.
300
+ Args:
301
+ creds: Google OAuth2 credentials.
302
+ account_id (str): GTM account ID.
303
+ container_id (str): GTM container ID.
304
+ workspace_id (str): GTM workspace ID.
305
+ trigger_ids (str | list[str]): A single trigger ID or list of trigger IDs to delete.
306
+ Returns:
307
+ dict: {"deleted": [...], "failed": [{"id": ..., "error": ...}, ...]}
308
+ """
309
+ service = build("tagmanager", "v2", credentials=creds)
310
+ parent = (
311
+ f"accounts/{account_id}"
312
+ f"/containers/{container_id}"
313
+ f"/workspaces/{workspace_id}"
314
+ )
315
+
316
+ results = {"deleted": [], "failed": []}
317
+ for trigger_id in _as_id_list(trigger_ids):
318
+ path = f"{parent}/triggers/{trigger_id}"
319
+ try:
320
+ service.accounts().containers().workspaces().triggers().delete(
321
+ path=path
322
+ ).execute()
323
+ results["deleted"].append(trigger_id)
324
+ except Exception as e:
325
+ results["failed"].append({"id": trigger_id, "error": str(e)})
326
+
327
+ return results
328
+
329
+ def delete_templates(creds, account_id, container_id, workspace_id, template_ids):
330
+ """
331
+ Delete one or more templates from a GTM workspace.
332
+ Args:
333
+ creds: Google OAuth2 credentials.
334
+ account_id (str): GTM account ID.
335
+ container_id (str): GTM container ID.
336
+ workspace_id (str): GTM workspace ID.
337
+ template_ids (str | list[str]): A single template ID or list of template IDs to delete.
338
+ Returns:
339
+ dict: {"deleted": [...], "failed": [{"id": ..., "error": ...}, ...]}
340
+ """
341
+ service = build("tagmanager", "v2", credentials=creds)
342
+ parent = (
343
+ f"accounts/{account_id}"
344
+ f"/containers/{container_id}"
345
+ f"/workspaces/{workspace_id}"
346
+ )
347
+
348
+ results = {"deleted": [], "failed": []}
349
+ for template_id in _as_id_list(template_ids):
350
+ path = f"{parent}/templates/{template_id}"
351
+ try:
352
+ service.accounts().containers().workspaces().templates().delete(
353
+ path=path
354
+ ).execute()
355
+ results["deleted"].append(template_id)
356
+ except Exception as e:
357
+ results["failed"].append({"id": template_id, "error": str(e)})
358
+
359
+ return results
360
+
361
+ def create_version(creds, account_id, container_id, workspace_id, name=None, notes=None):
362
+ """
363
+ Create a container version from a GTM workspace (snapshot of pending changes).
364
+ Args:
365
+ creds: Google OAuth2 credentials.
366
+ account_id (str): GTM account ID.
367
+ container_id (str): GTM container ID.
368
+ workspace_id (str): GTM workspace ID.
369
+ name (str, optional): Name for the new version.
370
+ notes (str, optional): Notes describing the changes in this version.
371
+ Returns:
372
+ dict: The created ContainerVersion resource, e.g.
373
+ {"containerVersion": {...}, "compilerError": bool, "syncStatus": {...}}
374
+ """
375
+ service = build("tagmanager", "v2", credentials=creds)
376
+ path = (
377
+ f"accounts/{account_id}"
378
+ f"/containers/{container_id}"
379
+ f"/workspaces/{workspace_id}"
380
+ )
381
+
382
+ body = {}
383
+ if name:
384
+ body["name"] = name
385
+ if notes:
386
+ body["notes"] = notes
387
+
388
+ response = (
389
+ service.accounts()
390
+ .containers()
391
+ .workspaces()
392
+ .create_version(path=path, body=body)
393
+ .execute()
394
+ )
395
+ return response
396
+
397
+
398
+ def publish_version(creds, account_id, container_id, version_id, fingerprint=None):
399
+ """
400
+ Publish a specific GTM container version, making it live.
401
+ Args:
402
+ creds: Google OAuth2 credentials.
403
+ account_id (str): GTM account ID.
404
+ container_id (str): GTM container ID.
405
+ version_id (str): GTM container version ID to publish.
406
+ fingerprint (str, optional): Version fingerprint for optimistic concurrency
407
+ control (prevents accidental overwrite of a
408
+ version that changed since you fetched it).
409
+ Returns:
410
+ dict: The published ContainerVersion resource.
411
+ """
412
+ service = build("tagmanager", "v2", credentials=creds)
413
+ path = (
414
+ f"accounts/{account_id}"
415
+ f"/containers/{container_id}"
416
+ f"/versions/{version_id}"
417
+ )
418
+
419
+ request = service.accounts().containers().versions().publish(path=path)
420
+ if fingerprint:
421
+ request = service.accounts().containers().versions().publish(
422
+ path=path, fingerprint=fingerprint
423
+ )
424
+
425
+ response = request.execute()
426
+ return response
427
+
428
+
429
+ def publish_workspace(creds, account_id, container_id, workspace_id, name=None, notes=None):
430
+ """
431
+ Create a version from a workspace and immediately publish it — a convenience
432
+ wrapper combining create_version + publish_version.
433
+ Args:
434
+ creds: Google OAuth2 credentials.
435
+ account_id (str): GTM account ID.
436
+ container_id (str): GTM container ID.
437
+ workspace_id (str): GTM workspace ID.
438
+ name (str, optional): Name for the new version.
439
+ notes (str, optional): Notes describing the changes in this version.
440
+ Returns:
441
+ dict: {"version": {...}, "compilerError": bool, "published": {...}}
442
+ Raises:
443
+ RuntimeError: If the created version has a compiler error, publish is
444
+ skipped and the version response is returned for inspection.
445
+ """
446
+ version_response = create_version(
447
+ creds, account_id, container_id, workspace_id, name=name, notes=notes
448
+ )
449
+
450
+ if version_response.get("compilerError"):
451
+ raise RuntimeError(
452
+ "Version created but contains a compiler error — publish aborted. "
453
+ f"Inspect version details: {version_response}"
454
+ )
455
+
456
+ container_version = version_response["containerVersion"]
457
+ version_id = container_version["containerVersionId"]
458
+ fingerprint = container_version.get("fingerprint")
459
+
460
+ published = publish_version(
461
+ creds, account_id, container_id, version_id, fingerprint=fingerprint
462
+ )
463
+
464
+ return {
465
+ "version": container_version,
466
+ "compilerError": False,
467
+ "published": published,
468
+ }
@@ -0,0 +1,94 @@
1
+ # funnelreporting/utils.py
2
+
3
+ # Common functions can be written here and called in other class functions to remove redundancy
4
+
5
+ from google.oauth2 import service_account
6
+ from google.analytics.data_v1beta import BetaAnalyticsDataClient, GetMetadataRequest, MetricType
7
+ import pandas as pd
8
+ from google.cloud import bigquery
9
+ from typing import Optional
10
+
11
+ def get_dimension_metric(service_account_file:str,property_id:str,file_name:str):
12
+ '''
13
+ Args:
14
+ ----------
15
+ service_account_file: str
16
+ API service account JSON key file.
17
+
18
+ property_id: str
19
+ Property ID of the Google Analytics Property from which report needs to be generated.
20
+ '''
21
+ credentials = service_account.Credentials.from_service_account_file(service_account_file)
22
+ client = BetaAnalyticsDataClient(credentials=credentials)
23
+ request = GetMetadataRequest(name=f"properties/{property_id}/metadata")
24
+ response = client.get_metadata(request)
25
+
26
+ output =[]
27
+ for dimension in response.dimensions:
28
+ output.append({"Type": "Dimension", "API_Name": f"{dimension.api_name}", "UI_Name": f"{dimension.ui_name}", "Description": f"{dimension.description}", "Custom_definition": f"{dimension.custom_definition}", "Metric_type": "N/A"})
29
+
30
+ for metric in response.metrics:
31
+ output.append({"Type": "Metric", "API_Name": f"{metric.api_name}", "UI_Name": f"{metric.ui_name}", "Description": f"{metric.description}", "Custom_definition": f"{metric.custom_definition}", "Metric_type": f"{MetricType(metric.type_).name}"})
32
+
33
+ df = pd.DataFrame(output)
34
+ df.to_csv(f"{file_name}.csv",index=False)
35
+
36
+ def get_from_bigquery(project_id:str,dataset_id:str,table_id:str,service_account_file:Optional[str] = None, OAuth_creds:Optional[str] = None) -> pd.DataFrame:
37
+ '''
38
+ Args:
39
+ --------
40
+ project_id: str
41
+ Google Cloud Project ID where the BigQuery table is located.
42
+
43
+ dataset_id: str
44
+ BigQuery dataset ID where the table is located.
45
+
46
+ table_id: str
47
+ BigQuery table ID from where the data needs to be extracted.
48
+ service_account_file: str
49
+ API service account JSON key file.
50
+
51
+ --------
52
+ Returns:
53
+ pd.DataFrame
54
+ '''
55
+ if service_account_file != None:
56
+ credentials = service_account.Credentials.from_service_account_file(
57
+ service_account_file,
58
+ scopes=["https://www.googleapis.com/auth/cloud-platform"]
59
+ )
60
+ elif OAuth_creds != None:
61
+ credentials = OAuth_creds
62
+ client = bigquery.Client(credentials=credentials, project=project_id)
63
+ query = f"SELECT * FROM `{project_id}.{dataset_id}.{table_id}`"
64
+ query_job = client.query(query)
65
+ results = query_job.result().to_dataframe()
66
+ return results
67
+
68
+ def get_ga4_data_from_bq(project_id: str,query: str, service_account_file:Optional[str] = None, OAuth_creds:Optional[str] = None) -> pd.DataFrame:
69
+ '''
70
+ Args:
71
+ --------
72
+ project_id: str
73
+ Google Cloud Project ID where the BigQuery table is located.
74
+ query: str
75
+ SQL query to execute.
76
+ service_account: str
77
+ Path to service account json file
78
+ OAuth_creds:
79
+ OAuth creds
80
+ --------
81
+ Returns:
82
+ pd.DataFrame
83
+ '''
84
+ if service_account_file != None:
85
+ credentials = service_account.Credentials.from_service_account_file(
86
+ service_account_file,
87
+ scopes=["https://www.googleapis.com/auth/cloud-platform"]
88
+ )
89
+ elif OAuth_creds != None:
90
+ credentials = OAuth_creds
91
+ client = bigquery.Client(credentials=credentials, project=project_id)
92
+ query_job = client.query(query)
93
+ results = query_job.result().to_dataframe()
94
+ return results