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,81 @@
1
+ from . import (
2
+ bq_functions,
3
+ free_form_report_GA4,
4
+ funnel_report_GA4,
5
+ ga4_admin_functions,
6
+ ga4_audience,
7
+ gtm_functions,
8
+ utils,
9
+ )
10
+ from .bq_functions import (
11
+ get_from_bigquery,
12
+ get_ga4_data_from_bq,
13
+ list_bq_datasets,
14
+ )
15
+ from .free_form_report_GA4 import dimension_filter_generation, free_form_report_GA4
16
+ from .funnel_report_GA4 import Funnel_Reports
17
+ from .ga4_admin_functions import (
18
+ get_ga4_accounts_list,
19
+ get_ga4_properties_list,
20
+ get_ga4_property_bq_link,
21
+ get_ga4_property_keyEvents,
22
+ )
23
+ from .ga4_audience import (
24
+ GA4AudienceClient,
25
+ GA4AudienceError,
26
+ build_admin_client,
27
+ create_audience,
28
+ )
29
+ from .gtm_functions import (
30
+ get_accounts,
31
+ get_built_in_variables,
32
+ get_containers,
33
+ get_custom_templates,
34
+ get_tags,
35
+ get_triggers,
36
+ get_variables,
37
+ get_workspaces,
38
+ getLatestVersionHeader,
39
+ )
40
+ from .utils import get_dimension_metric
41
+
42
+ __version__ = "0.1.0"
43
+
44
+ __all__ = [
45
+ # Submodules
46
+ "bq_functions",
47
+ "ga4_admin_functions",
48
+ "ga4_audience",
49
+ "gtm_functions",
50
+ "utils",
51
+ # Reporting
52
+ "Funnel_Reports",
53
+ "free_form_report_GA4",
54
+ "dimension_filter_generation",
55
+ # GA4 Admin
56
+ "get_ga4_accounts_list",
57
+ "get_ga4_properties_list",
58
+ "get_ga4_property_keyEvents",
59
+ "get_ga4_property_bq_link",
60
+ # Audiences
61
+ "GA4AudienceClient",
62
+ "create_audience",
63
+ "build_admin_client",
64
+ "GA4AudienceError",
65
+ # GTM
66
+ "get_accounts",
67
+ "get_containers",
68
+ "get_workspaces",
69
+ "getLatestVersionHeader",
70
+ "get_tags",
71
+ "get_variables",
72
+ "get_triggers",
73
+ "get_built_in_variables",
74
+ "get_custom_templates",
75
+ # BigQuery
76
+ "list_bq_datasets",
77
+ "get_from_bigquery",
78
+ "get_ga4_data_from_bq",
79
+ # Utilities
80
+ "get_dimension_metric",
81
+ ]
@@ -0,0 +1,97 @@
1
+ import pandas as pd
2
+ from google.cloud import bigquery
3
+ from typing import Optional
4
+ from google.oauth2 import service_account
5
+
6
+
7
+ def list_bq_datasets(credentials, gcp_project_id):
8
+ """
9
+ List all BigQuery datasets in a given Google Cloud project.
10
+
11
+ Args:
12
+ credentials: Authenticated Google credentials object used to initialize
13
+ the BigQuery client.
14
+ gcp_project_id (str): The Google Cloud project ID.
15
+ """
16
+ client = bigquery.Client(project=gcp_project_id, credentials=credentials)
17
+ dataset_objects = client.list_datasets(project=str(gcp_project_id))
18
+
19
+ # Extract just the string IDs from the objects
20
+ datasets = [dataset.dataset_id for dataset in dataset_objects]
21
+
22
+ return datasets
23
+
24
+
25
+ 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:
26
+ '''
27
+ Args:
28
+ --------
29
+ project_id: str
30
+ Google Cloud Project ID where the BigQuery table is located.
31
+
32
+ dataset_id: str
33
+ BigQuery dataset ID where the table is located.
34
+
35
+ table_id: str
36
+ BigQuery table ID from where the data needs to be extracted.
37
+ service_account_file: str
38
+ API service account JSON key file.
39
+
40
+ --------
41
+ Returns:
42
+ pd.DataFrame
43
+ '''
44
+ if service_account_file != None:
45
+ credentials = service_account.Credentials.from_service_account_file(
46
+ service_account_file,
47
+ scopes=["https://www.googleapis.com/auth/cloud-platform"]
48
+ )
49
+ elif OAuth_creds != None:
50
+ credentials = OAuth_creds
51
+ client = bigquery.Client(credentials=credentials, project=project_id)
52
+ query = f"SELECT * FROM `{project_id}.{dataset_id}.{table_id}`"
53
+ query_job = client.query(query)
54
+ results = query_job.result().to_dataframe()
55
+ return results
56
+
57
+ def get_ga4_data_from_bq(project_id: str,query: str, service_account_file:Optional[str] = None, OAuth_creds:Optional[str] = None) -> pd.DataFrame:
58
+ '''
59
+ Args:
60
+ --------
61
+ project_id: str
62
+ Google Cloud Project ID where the BigQuery table is located.
63
+ query: str
64
+ SQL query to execute.
65
+ service_account: str
66
+ Path to service account json file
67
+ OAuth_creds:
68
+ OAuth creds
69
+ --------
70
+ Returns:
71
+ pd.DataFrame
72
+ '''
73
+ if service_account_file != None:
74
+ credentials = service_account.Credentials.from_service_account_file(
75
+ service_account_file,
76
+ scopes=["https://www.googleapis.com/auth/cloud-platform"]
77
+ )
78
+ elif OAuth_creds != None:
79
+ credentials = OAuth_creds
80
+ client = bigquery.Client(credentials=credentials, project=project_id)
81
+ query_job = client.query(query)
82
+ results = query_job.result().to_dataframe()
83
+ return results
84
+
85
+ # def create_bq_table(project_id:str,dataset_id:str,table_id:str,schema_dict:dict,service_account_file:Optional[str] = None, OAuth_creds:Optional[str] = None) -> pd.DataFrame:
86
+ # table_path = f"{project_id}.{dataset_id}.{table_id}"
87
+ # schema = []
88
+ # for key, value in schema_dict.items():
89
+ # if type(value) == dict:
90
+ # temp_list = []
91
+ # for nested_key, nested_value in value.items():
92
+ # temp_list.append(bigquery.SchemaField(nested_key,nested_value))
93
+ # schema.append(bigquery.SchemaField(key, "RECORD",fields=temp_list))
94
+ # else:
95
+ # schema.append(bigquery.SchemaField(key, value))
96
+ # table = bigquery.Table(table_path, schema=schema)
97
+ # def write_to_bq(project_id:str,dataset_id:str,table_id:str,service_account_file:Optional[str] = None, OAuth_creds:Optional[str] = None) -> pd.DataFrame:
@@ -0,0 +1,155 @@
1
+ from google.oauth2 import service_account
2
+ from google.analytics.data_v1beta import BetaAnalyticsDataClient
3
+ import pandas as pd
4
+ from datetime import datetime
5
+ from typing import Optional, Union
6
+
7
+ class free_form_report_GA4():
8
+ '''
9
+ Generate Free Form GA4 reports.
10
+
11
+ Args:
12
+ service_account_file (str): API service account JSON key file.
13
+ property_id (str): Property ID of the Google Analytics Property from which report needs to be generated.
14
+ '''
15
+ def __init__(self, service_account_file: str, property_id: str):
16
+ self.service_account_file = service_account_file
17
+ self.property_id = property_id
18
+ self.credentials = service_account.Credentials.from_service_account_file(self.service_account_file)
19
+ self.client = BetaAnalyticsDataClient(credentials=self.credentials)
20
+ self.property_id = f'properties/{property_id}'
21
+
22
+ def free_form_report(self, start_date, end_date, metrics: list, dimensions:Optional[list] = None, dimension_filter:Optional[str] = None, metric_filter:Optional[str] = None):
23
+ '''
24
+ Collects date ranges, metrics and dimensions to generate report.
25
+
26
+ Args:
27
+ start_date (str):
28
+ Report date range starting date in "YYYY-MM-DD" format or "YYYY-MM-DD HH:MM:SS" format or GA4 string format like "7daysAgo", "today" etc.
29
+ end_date (str):
30
+ Report date range ending date in "YYYY-MM-DD" format or "YYYY-MM-DD HH:MM:SS" format or GA4 string format like "7daysAgo", "today" etc.
31
+ metrics (list):
32
+ List of metrics required in the report pass only the api names.
33
+ example: ['totalUsers', 'eventCount']
34
+ dimensions (list, Optional):
35
+ List of dimensional breakdown required in the report pass only the api names.
36
+ example: ['browser','sessionDefaultChannelGroup']
37
+ dimension_filter (str, Optional):
38
+ Dimension Filter condition required in the report in JSON format
39
+ metric_filter (str, Optional):
40
+ Metrics Filter condition required in the report in JSON format
41
+
42
+ Returns:
43
+ result_df (DataFrame): Report generated in pandas DataFrame format.
44
+ '''
45
+ self.dimensions = []
46
+ self.metrics = []
47
+ if "-" in str(start_date):
48
+ self.start_date = str(start_date).split(" ")[0]
49
+ else:
50
+ self.start_date = str(start_date)
51
+ if "-" in str(end_date):
52
+ self.end_date = str(end_date).split(" ")[0]
53
+ else:
54
+ self.end_date = str(end_date)
55
+ try:
56
+ for dim in dimensions:
57
+ self.dimensions.append({'name' : dim})
58
+ except TypeError as e:
59
+ print("dimensions received is not in list format")
60
+ try:
61
+ for met in metrics:
62
+ self.metrics.append({'name' : met})
63
+ except TypeError as e:
64
+ print("metrics received is not in list format")
65
+ self.request = {
66
+ "property": self.property_id,
67
+ "date_ranges" : [
68
+ {
69
+ "start_date" : self.start_date,
70
+ "end_date" : self.end_date,
71
+ }
72
+ ],
73
+ "dimensions" : self.dimensions,
74
+ "metrics" : self.metrics,
75
+ "dimension_filter" : dimension_filter,
76
+ "metric_filter" : metric_filter,
77
+ "limit" : "250000"
78
+ }
79
+
80
+ try:
81
+ self.response = self.client.run_report(request=self.request)
82
+ except Exception as e:
83
+ print(e)
84
+ return None
85
+ self.data = []
86
+ for row in self.response.rows:
87
+ dimension_values = [value.value for value in row.dimension_values]
88
+ metric_values = [float(value.value) for value in row.metric_values]
89
+ self.data.append(dimension_values + metric_values)
90
+ self.columns = [dimension.name for dimension in self.response.dimension_headers] + [metric.name for metric in self.response.metric_headers]
91
+ self.result_df = pd.DataFrame(data=self.data, columns=self.columns)
92
+
93
+ return self.result_df
94
+
95
+ def dimension_filter_generation(operator: str, value: Union[str, list], dimension_name: Optional[str] = None):
96
+ '''
97
+ Generates dimension filter in JSON format to be used in report generation.
98
+
99
+ Args:
100
+ operator (str): Operator for the filter condition. available options: "EXACT", "BEGINS_WITH", "ENDS_WITH", "CONTAINS", "FULL_REGEXP", "AND", "OR", "NOT", "IN_LIST".
101
+ value (Union[str, list]): Value for the filter condition. For operators "AND", "OR" and "NOT", pass the value in list format with each condition as a separate item in the list.
102
+ dimension_name (str): Name of the dimension for which filter needs to be generated. Required only when operator is not "AND", "OR" or "NOT".
103
+
104
+ Returns:
105
+ dimension_filter (str): Generated dimension filter in JSON format.
106
+ '''
107
+ secondary_opeartor = {
108
+ "AND" : "and_group",
109
+ "OR" : "or_group",
110
+ "NOT" : "not_expression"
111
+ }
112
+ if operator in ["AND", "OR"]:
113
+ # filter_expression = value.split(",")
114
+ # filter_expression = [item.strip() for item in filter_expression]
115
+ filter_expression = value
116
+ dimension_filter = {
117
+ secondary_opeartor[operator] : {
118
+ "expressions" : filter_expression
119
+ }
120
+ }
121
+ elif operator in ["NOT"]:
122
+ # filter_expression = value.split(",")
123
+ # filter_expression = [item.strip() for item in filter_expression]
124
+ filter_expression = value
125
+ dimension_filter = {
126
+ secondary_opeartor[operator] : filter_expression
127
+ }
128
+ elif operator == "IN_LIST":
129
+ dimension_filter = {
130
+ "filter": {
131
+ "field_name": dimension_name,
132
+ "in_list_filter": {
133
+ "values": value
134
+ }
135
+ }
136
+ }
137
+ else:
138
+ dimension_filter = {
139
+ "filter": {
140
+ "field_name": dimension_name,
141
+ "string_filter": {
142
+ "match_type": operator,
143
+ "value": value
144
+ }
145
+ }
146
+ }
147
+ return dimension_filter
148
+ # def anomaly_detection(self, report, comparison_report, report_date_range, comparison_date_range, dimensions_list):
149
+ # self.data = report
150
+ # self.comp_data = comparison_report
151
+ # self.dimensions_list = dimensions_list
152
+ # self.data_start_date, self.data_end_date = [str(date).split(" ")[0] for date in report_date_range]
153
+ # self.comp_start_date, self.comp_end_date = [str(date).split(" ")[0] for date in comparison_date_range]
154
+
155
+ # merged_df = pd.merge(self.data, self.comp_data, on=self.dimensions_list, how="outer")
@@ -0,0 +1,269 @@
1
+ import gspread
2
+ from google.oauth2 import service_account
3
+ from google.analytics.data_v1alpha import AlphaAnalyticsDataClient
4
+ from datetime import datetime
5
+ from typing import Optional
6
+ from google.analytics.data_v1alpha.types import (
7
+ DateRange,
8
+ Dimension,
9
+ Funnel,
10
+ FunnelBreakdown,
11
+ FunnelEventFilter,
12
+ FunnelFieldFilter,
13
+ FunnelFilterExpression,
14
+ FunnelFilterExpressionList,
15
+ FunnelStep,
16
+ RunFunnelReportRequest,
17
+ StringFilter,
18
+ Filter,
19
+ FilterExpressionList,
20
+ FilterExpression,
21
+ QuotaStatus,
22
+ InListFilter,
23
+ )
24
+ import pandas as pd
25
+
26
+ class Funnel_Reports():
27
+
28
+ '''
29
+
30
+ Initializing object to run funnel reports.
31
+
32
+ Parameters:
33
+ -----------
34
+ reporting_client : str
35
+ Service Account JSON key for Google Analytics Data API
36
+ prop_id : str
37
+ Property ID of the Google Analytics Property from which report needs to be generated.
38
+
39
+ Funnel functions covered:
40
+ -----------
41
+ 1. OR Group
42
+ 2. AND Group
43
+ 3. Contains
44
+ 4. Event Name
45
+ 5. Equals To
46
+ 6. Is One of
47
+ 7. Begins with
48
+ 8. Ends with
49
+ 9. Matched Regex
50
+ 10. Does not in combition with all the other mentioned functions
51
+ '''
52
+
53
+ def __init__(self,reporting_client: str,prop_id: str):
54
+ self.property_id = prop_id
55
+ self.SCOPES = [
56
+ 'https://www.googleapis.com/auth/analytics.readonly',
57
+ 'https://www.googleapis.com/auth/spreadsheets',
58
+ 'https://www.googleapis.com/auth/drive'
59
+ ]
60
+ # self.file_n = file_n
61
+ self.credentials = service_account.Credentials.from_service_account_file(reporting_client, scopes=self.SCOPES)
62
+ self.client = AlphaAnalyticsDataClient(credentials = self.credentials)
63
+
64
+
65
+ def condition_creator(self,condition_string):
66
+ if ' or ' in condition_string.lower():
67
+ conditions_li = condition_string.lower().split(' or ')
68
+ expressions = []
69
+ funnel_filter_expression = FunnelFilterExpression(
70
+ or_group = FunnelFilterExpressionList(
71
+ expressions = [self.condition_creator(condition) for condition in conditions_li]
72
+ )
73
+ )
74
+ elif ' and ' in condition_string.lower():
75
+ conditions_li = condition_string.split(' and ')
76
+ expressions = []
77
+ funnel_filter_expression = FunnelFilterExpression(
78
+ and_group = FunnelFilterExpressionList(
79
+ expressions = [self.condition_creator(condition) for condition in conditions_li]
80
+ )
81
+ )
82
+ elif ' does not ' in condition_string.lower():
83
+ new_condition = condition_string.split(' does not ')[0]+ ' '+condition_string.split(' does not ')[1]
84
+ funnel_filter_expression = FunnelFilterExpression(
85
+ not_expression = FunnelFilterExpression(
86
+ self.condition_creator(new_condition)
87
+ )
88
+ )
89
+ else:
90
+ if '= ' in condition_string and 'eventName' in condition_string:
91
+ event_name = condition_string.split('"')[1]
92
+ funnel_event_filter = FunnelEventFilter(event_name=event_name)
93
+ funnel_filter_expression = FunnelFilterExpression(funnel_event_filter=funnel_event_filter)
94
+ elif 'contains' in condition_string:
95
+ field_name = condition_string.split(' contains ')[0]
96
+ event_name = condition_string.split('"')[1]
97
+ string_filter=StringFilter(match_type=StringFilter.MatchType.CONTAINS,case_sensitive=False,value=event_name)
98
+ funnel_field_filter = FunnelFieldFilter(field_name= field_name, string_filter=string_filter)
99
+ funnel_filter_expression = FunnelFilterExpression(funnel_field_filter=funnel_field_filter)
100
+
101
+ elif 'is one of' in condition_string:
102
+ field_name, event_name = condition_string.split(' is one of ')[0], condition_string.split(' is one of ')[1]
103
+ test_str = event_name.replace('"','').replace('[','').replace(']','').replace('\n','')
104
+ new_list = test_str.split(', ')
105
+ # print(event_name)
106
+ in_list_filter=InListFilter(values=new_list)
107
+
108
+ funnel_field_filter = FunnelFieldFilter(field_name= field_name, in_list_filter=in_list_filter)
109
+ funnel_filter_expression = FunnelFilterExpression(funnel_field_filter=funnel_field_filter)
110
+
111
+ elif '=' in condition_string:
112
+ field_name = condition_string.split(' = ')[0]
113
+ event_name = condition_string.split('"')[1]
114
+ string_filter=StringFilter(match_type=StringFilter.MatchType.EXACT,case_sensitive=False,value=event_name)
115
+ funnel_field_filter = FunnelFieldFilter(field_name= field_name, string_filter=string_filter)
116
+ funnel_filter_expression = FunnelFilterExpression(funnel_field_filter=funnel_field_filter)
117
+ elif 'begins with' in condition_string:
118
+ field_name = condition_string.split(' begins with ')[0]
119
+ event_name = condition_string.split('"')[1]
120
+ string_filter=StringFilter(match_type=StringFilter.MatchType.BEGINS_WITH,case_sensitive=False,value=event_name)
121
+ funnel_field_filter = FunnelFieldFilter(field_name= field_name, string_filter=string_filter)
122
+ funnel_filter_expression = FunnelFilterExpression(funnel_field_filter=funnel_field_filter)
123
+ elif 'ends with' in condition_string:
124
+ field_name = condition_string.split(' ends with ')[0]
125
+ event_name = condition_string.split('"')[1]
126
+ string_filter=StringFilter(match_type=StringFilter.MatchType.ENDS_WITH,case_sensitive=False,value=event_name)
127
+ funnel_field_filter = FunnelFieldFilter(field_name= field_name, string_filter=string_filter)
128
+ funnel_filter_expression = FunnelFilterExpression(funnel_field_filter=funnel_field_filter)
129
+ elif 'matches regex' in condition_string:
130
+ field_name = condition_string.split(' matches regex ')[0]
131
+ field_name = field_name.strip()
132
+ event_name = condition_string.split('"')[1]
133
+ string_filter=StringFilter(match_type=StringFilter.MatchType.FULL_REGEXP,case_sensitive=False,value=event_name)
134
+ funnel_field_filter = FunnelFieldFilter(field_name= field_name, string_filter=string_filter)
135
+ funnel_filter_expression = FunnelFilterExpression(funnel_field_filter=funnel_field_filter)
136
+ return funnel_filter_expression
137
+
138
+ def generate_dimension_filter(self, dim_filter):
139
+ '''
140
+ Pass filter in string format
141
+
142
+ Example:
143
+ ---
144
+ 1. sessionDefaultChannelGroup contains "Organic"
145
+ 2. sessionDefaultChannelGroup = "Direct"
146
+ '''
147
+ if 'contains' in dim_filter:
148
+ filter_field_name = dim_filter.split(' contains ')[0]
149
+ filter_event_name = dim_filter.split('"')[1]
150
+ str_filter = StringFilter(match_type=StringFilter.MatchType.CONTAINS, case_sensitive=False, value=filter_event_name)
151
+ filter_condition = Filter(field_name=filter_field_name, string_filter=str_filter)
152
+ dimension_filter = FilterExpression(filter=filter_condition)
153
+ elif ' = ' in dim_filter:
154
+ filter_field_name = dim_filter.split(' contains ')[0]
155
+ filter_event_name = dim_filter.split('"')[1]
156
+ str_filter = StringFilter(match_type=StringFilter.MatchType.EXACT, value=filter_event_name)
157
+ filter_condition = Filter(field_name=filter_field_name, string_filter=str_filter)
158
+ dimension_filter = FilterExpression(filter=filter_condition)
159
+ return dimension_filter
160
+
161
+
162
+ def get_funnel_steps(self):
163
+ self.steps = len(self.funnel_data.keys())
164
+ funnel_steps = []
165
+ for i in range(1,self.steps):
166
+ if self.funnel_data.iloc[0,i] == 'Single Condition':
167
+ fs = FunnelStep(
168
+ name = self.funnel_data.keys()[i],
169
+ filter_expression = FunnelFilterExpression(self.condition_creator(self.funnel_data.iloc[1,i]))
170
+ )
171
+ funnel_steps.append(fs)
172
+ elif self.funnel_data.iloc[0,i] == 'AND Group':
173
+ fs = FunnelStep(
174
+ name = self.funnel_data.keys()[i],
175
+ filter_expression = FunnelFilterExpression(
176
+ and_group = FunnelFilterExpressionList(
177
+ expressions = [self.condition_creator(self.funnel_data.iloc[j,i]) for j in range(1,len(self.funnel_data))]
178
+ )
179
+ )
180
+ )
181
+ funnel_steps.append(fs)
182
+ elif self.funnel_data.iloc[0,i] == 'OR Group':
183
+ fs = FunnelStep(
184
+ name = self.funnel_data.keys()[i],
185
+ filter_expression = FunnelFilterExpression(
186
+ or_group = FunnelFilterExpressionList(
187
+ expressions = [self.condition_creator(self.funnel_data.iloc[j,i]) for j in range(1,len(self.funnel_data))]
188
+ )
189
+ )
190
+ )
191
+ funnel_steps.append(fs)
192
+ return funnel_steps
193
+
194
+ def funnel_report(self,startDate: datetime,endDate: datetime,file_n: str,dimension_filter:Optional[str] = None, breakdown:Optional[str] = None,breakdown_limit:Optional[str] = None):
195
+ '''
196
+ Generate funnel report between two dates.
197
+
198
+ Parameters
199
+ ----------
200
+ startDate : datetime
201
+ Start date of the report.
202
+ endDate : datetime
203
+ End date of the report.
204
+ file_n : str
205
+ Google Sheets File containing Steps of the funnel.
206
+ dimension_filter : str, optional
207
+ Filter condition for the report (must be a string if provided).
208
+ breakdown : str, optional
209
+ Breakdown dimension to view funnels across dimension.
210
+ breakdown_limit : str, optional
211
+ Available limit 1 - 15.
212
+ Need to specify the number of breakdown rows to be displayed per step.
213
+
214
+ Default limit = 15
215
+ '''
216
+ self.SCOPES = [
217
+ 'https://www.googleapis.com/auth/analytics.readonly',
218
+ 'https://www.googleapis.com/auth/spreadsheets',
219
+ 'https://www.googleapis.com/auth/drive'
220
+ ]
221
+ self.breakdown = breakdown
222
+ if breakdown_limit == None:
223
+ self.breakdown_limit = '15'
224
+ else:
225
+ self.breakdown_limit = breakdown_limit
226
+ self.dimension_filter = dimension_filter
227
+ self.file_n = file_n
228
+ self.gc = gspread.authorize(self.credentials)
229
+ self.worksheet = self.gc.open(f'{self.file_n}').sheet1
230
+ self.rows = self.worksheet.get_all_values()
231
+ self.funnel_data = pd.DataFrame(self.rows[1:], columns=self.rows[0])
232
+ if dimension_filter == None:
233
+ if self.breakdown == None:
234
+ request = RunFunnelReportRequest(
235
+ property=f"properties/{self.property_id}",
236
+ date_ranges=[DateRange(start_date=str(startDate).split(" ")[0], end_date=str(endDate).split(" ")[0])],
237
+ funnel=Funnel(steps = self.get_funnel_steps()),
238
+ )
239
+ else:
240
+ request = RunFunnelReportRequest(
241
+ property=f"properties/{self.property_id}",
242
+ date_ranges=[DateRange(start_date=str(startDate).split(" ")[0], end_date=str(endDate).split(" ")[0])],
243
+ funnel_breakdown = FunnelBreakdown(
244
+ breakdown_dimension = Dimension(name=self.breakdown),
245
+ limit = self.breakdown_limit
246
+ ),
247
+ funnel=Funnel(steps = self.get_funnel_steps()),
248
+ )
249
+ else:
250
+ if self.breakdown == None:
251
+ request = RunFunnelReportRequest(
252
+ property=f"properties/{self.property_id}",
253
+ date_ranges=[DateRange(start_date=str(startDate).split(" ")[0], end_date=str(endDate).split(" ")[0])],
254
+ funnel=Funnel(steps = self.get_funnel_steps()),
255
+ dimension_filter = self.generate_dimension_filter(self.dimension_filter)
256
+ )
257
+ else:
258
+ request = RunFunnelReportRequest(
259
+ property=f"properties/{self.property_id}",
260
+ date_ranges=[DateRange(start_date=str(startDate).split(" ")[0], end_date=str(endDate).split(" ")[0])],
261
+ funnel_breakdown = FunnelBreakdown(
262
+ breakdown_dimension = Dimension(name=self.breakdown),
263
+ limit = self.breakdown_limit
264
+ ),
265
+ funnel=Funnel(steps = self.get_funnel_steps()),
266
+ dimension_filter = self.generate_dimension_filter(self.dimension_filter)
267
+ )
268
+ response = self.client.run_funnel_report(request)
269
+ return response