generator.views.growth_accounting_view
Class to describe a Growth Accounting View.
1"""Class to describe a Growth Accounting View.""" 2 3from __future__ import annotations 4 5from copy import deepcopy 6from itertools import filterfalse 7from typing import Any, Dict, Iterator, List, Optional, Union 8 9from . import lookml_utils 10from .view import View, ViewDict 11 12 13class GrowthAccountingView(View): 14 """A view for growth accounting measures.""" 15 16 type: str = "growth_accounting_view" 17 DEFAULT_IDENTIFIER_FIELD: str = "client_id" 18 19 other_dimensions: List[Dict[str, str]] = [ 20 { 21 "name": "first", 22 "sql": "{TABLE}.first", 23 "type": "yesno", 24 "hidden": "yes", 25 } 26 ] 27 28 default_measures: List[Dict[str, Union[str, List[Dict[str, str]]]]] = [ 29 { 30 "name": "overall_active_previous", 31 "type": "count", 32 "filters": [{"active_last_week": "yes"}], 33 }, 34 { 35 "name": "overall_active_current", 36 "type": "count", 37 "filters": [{"active_this_week": "yes"}], 38 }, 39 { 40 "name": "overall_resurrected", 41 "type": "count", 42 "filters": [ 43 {"new_last_week": "no"}, 44 {"new_this_week": "no"}, 45 {"active_last_week": "no"}, 46 {"active_this_week": "yes"}, 47 ], 48 }, 49 { 50 "name": "new_users", 51 "type": "count", 52 "filters": [{"new_this_week": "yes"}, {"active_this_week": "yes"}], 53 }, 54 { 55 "name": "established_users_returning", 56 "type": "count", 57 "filters": [ 58 {"new_last_week": "no"}, 59 {"new_this_week": "no"}, 60 {"active_last_week": "yes"}, 61 {"active_this_week": "yes"}, 62 ], 63 }, 64 { 65 "name": "new_users_returning", 66 "type": "count", 67 "filters": [ 68 {"new_last_week": "yes"}, 69 {"active_last_week": "yes"}, 70 {"active_this_week": "yes"}, 71 ], 72 }, 73 { 74 "name": "new_users_churned_count", 75 "type": "count", 76 "filters": [ 77 {"new_last_week": "yes"}, 78 {"active_last_week": "yes"}, 79 {"active_this_week": "no"}, 80 ], 81 }, 82 { 83 "name": "established_users_churned_count", 84 "type": "count", 85 "filters": [ 86 {"new_last_week": "no"}, 87 {"new_this_week": "no"}, 88 {"active_last_week": "yes"}, 89 {"active_this_week": "no"}, 90 ], 91 }, 92 { 93 "name": "new_users_churned", 94 "type": "number", 95 "sql": "-1 * ${new_users_churned_count}", 96 }, 97 { 98 "name": "established_users_churned", 99 "type": "number", 100 "sql": "-1 * ${established_users_churned_count}", 101 }, 102 { 103 "name": "overall_churned", 104 "type": "number", 105 "sql": "${new_users_churned} + ${established_users_churned}", 106 }, 107 { 108 "name": "overall_retention_rate", 109 "type": "number", 110 "sql": ( 111 "SAFE_DIVIDE(" 112 "(${established_users_returning} + ${new_users_returning})," 113 "${overall_active_previous}" 114 ")" 115 ), 116 }, 117 { 118 "name": "established_user_retention_rate", 119 "type": "number", 120 "sql": ( 121 "SAFE_DIVIDE(" 122 "${established_users_returning}," 123 "(${established_users_returning} + ${established_users_churned_count})" 124 ")" 125 ), 126 }, 127 { 128 "name": "new_user_retention_rate", 129 "type": "number", 130 "sql": ( 131 "SAFE_DIVIDE(" 132 "${new_users_returning}," 133 "(${new_users_returning} + ${new_users_churned_count})" 134 ")" 135 ), 136 }, 137 { 138 "name": "overall_churn_rate", 139 "type": "number", 140 "sql": ( 141 "SAFE_DIVIDE(" 142 "(${established_users_churned_count} + ${new_users_churned_count})," 143 "${overall_active_previous}" 144 ")" 145 ), 146 }, 147 { 148 "name": "fraction_of_active_resurrected", 149 "type": "number", 150 "sql": "SAFE_DIVIDE(${overall_resurrected}, ${overall_active_current})", 151 }, 152 { 153 "name": "fraction_of_active_new", 154 "type": "number", 155 "sql": "SAFE_DIVIDE(${new_users}, ${overall_active_current})", 156 }, 157 { 158 "name": "fraction_of_active_established_returning", 159 "type": "number", 160 "sql": ( 161 "SAFE_DIVIDE(" 162 "${established_users_returning}," 163 "${overall_active_current}" 164 ")" 165 ), 166 }, 167 { 168 "name": "fraction_of_active_new_returning", 169 "type": "number", 170 "sql": "SAFE_DIVIDE(${new_users_returning}, ${overall_active_current})", 171 }, 172 { 173 "name": "quick_ratio", 174 "type": "number", 175 "sql": ( 176 "SAFE_DIVIDE(" 177 "${new_users} + ${overall_resurrected}," 178 "${established_users_churned_count} + ${new_users_churned_count}" 179 ")" 180 ), 181 }, 182 ] 183 184 def __init__( 185 self, 186 namespace: str, 187 tables: List[Dict[str, str]], 188 identifier_field: str = DEFAULT_IDENTIFIER_FIELD, 189 ): 190 """Get an instance of a GrowthAccountingView.""" 191 self.identifier_field = identifier_field 192 193 super().__init__( 194 namespace, "growth_accounting", GrowthAccountingView.type, tables 195 ) 196 197 @classmethod 198 def get_default_dimensions( 199 klass, identifier_field: str = DEFAULT_IDENTIFIER_FIELD 200 ) -> List[Dict[str, str]]: 201 """Get dimensions to be added to GrowthAccountingView by default.""" 202 return [ 203 { 204 "name": "active_this_week", 205 "sql": "mozfun.bits28.active_in_range(days_seen_bits, -6, 7)", 206 "type": "yesno", 207 "hidden": "yes", 208 }, 209 { 210 "name": "active_last_week", 211 "sql": "mozfun.bits28.active_in_range(days_seen_bits, -13, 7)", 212 "type": "yesno", 213 "hidden": "yes", 214 }, 215 { 216 "name": "new_this_week", 217 "sql": "DATE_DIFF(${submission_date}, first_run_date, DAY) BETWEEN 0 AND 6", 218 "type": "yesno", 219 "hidden": "yes", 220 }, 221 { 222 "name": "new_last_week", 223 "sql": "DATE_DIFF(${submission_date}, first_run_date, DAY) BETWEEN 7 AND 13", 224 "type": "yesno", 225 "hidden": "yes", 226 }, 227 { 228 "name": f"{identifier_field}_day", 229 "sql": f"CONCAT(CAST(${{TABLE}}.submission_date AS STRING), ${{{identifier_field}}})", 230 "type": "string", 231 "hidden": "yes", 232 "primary_key": "yes", 233 }, 234 ] 235 236 @classmethod 237 def from_db_views( 238 klass, 239 namespace: str, 240 is_glean: bool, 241 channels: List[Dict[str, str]], 242 db_views: dict, 243 identifier_field: str = DEFAULT_IDENTIFIER_FIELD, 244 ) -> Iterator[GrowthAccountingView]: 245 """Get Growth Accounting Views from db views and app variants.""" 246 dataset = next( 247 (channel for channel in channels if channel.get("channel") == "release"), 248 channels[0], 249 )["dataset"] 250 251 for view_id, references in db_views[dataset].items(): 252 if view_id == "baseline_clients_last_seen": 253 yield GrowthAccountingView( 254 namespace, 255 [{"table": f"mozdata.{dataset}.{view_id}"}], 256 identifier_field=identifier_field, 257 ) 258 259 @classmethod 260 def from_dict( 261 klass, namespace: str, name: str, _dict: ViewDict 262 ) -> GrowthAccountingView: 263 """Get a view from a name and dict definition.""" 264 return GrowthAccountingView( 265 namespace, 266 _dict["tables"], 267 identifier_field=str( 268 _dict.get( 269 "identifier_field", GrowthAccountingView.DEFAULT_IDENTIFIER_FIELD 270 ) 271 ), 272 ) 273 274 def to_lookml(self, v1_name: Optional[str], dryrun) -> Dict[str, Any]: 275 """Generate LookML for this view.""" 276 view_defn: Dict[str, Any] = {"name": self.name} 277 table = self.tables[0]["table"] 278 279 # add dimensions and dimension groups 280 dimensions = lookml_utils._generate_dimensions(table, dryrun=dryrun) + deepcopy( 281 GrowthAccountingView.get_default_dimensions( 282 identifier_field=self.identifier_field 283 ) 284 ) 285 286 view_defn["dimensions"] = list( 287 filterfalse(lookml_utils._is_dimension_group, dimensions) 288 ) 289 view_defn["dimension_groups"] = list( 290 filter(lookml_utils._is_dimension_group, dimensions) 291 ) 292 293 # add measures 294 view_defn["measures"] = self.get_measures() 295 296 # SQL Table Name 297 view_defn["sql_table_name"] = f"`{table}`" 298 299 return {"views": [view_defn]} 300 301 def get_measures(self) -> List[Dict[str, Union[str, List[Dict[str, str]]]]]: 302 """Generate measures for the Growth Accounting Framework.""" 303 return deepcopy(GrowthAccountingView.default_measures)
14class GrowthAccountingView(View): 15 """A view for growth accounting measures.""" 16 17 type: str = "growth_accounting_view" 18 DEFAULT_IDENTIFIER_FIELD: str = "client_id" 19 20 other_dimensions: List[Dict[str, str]] = [ 21 { 22 "name": "first", 23 "sql": "{TABLE}.first", 24 "type": "yesno", 25 "hidden": "yes", 26 } 27 ] 28 29 default_measures: List[Dict[str, Union[str, List[Dict[str, str]]]]] = [ 30 { 31 "name": "overall_active_previous", 32 "type": "count", 33 "filters": [{"active_last_week": "yes"}], 34 }, 35 { 36 "name": "overall_active_current", 37 "type": "count", 38 "filters": [{"active_this_week": "yes"}], 39 }, 40 { 41 "name": "overall_resurrected", 42 "type": "count", 43 "filters": [ 44 {"new_last_week": "no"}, 45 {"new_this_week": "no"}, 46 {"active_last_week": "no"}, 47 {"active_this_week": "yes"}, 48 ], 49 }, 50 { 51 "name": "new_users", 52 "type": "count", 53 "filters": [{"new_this_week": "yes"}, {"active_this_week": "yes"}], 54 }, 55 { 56 "name": "established_users_returning", 57 "type": "count", 58 "filters": [ 59 {"new_last_week": "no"}, 60 {"new_this_week": "no"}, 61 {"active_last_week": "yes"}, 62 {"active_this_week": "yes"}, 63 ], 64 }, 65 { 66 "name": "new_users_returning", 67 "type": "count", 68 "filters": [ 69 {"new_last_week": "yes"}, 70 {"active_last_week": "yes"}, 71 {"active_this_week": "yes"}, 72 ], 73 }, 74 { 75 "name": "new_users_churned_count", 76 "type": "count", 77 "filters": [ 78 {"new_last_week": "yes"}, 79 {"active_last_week": "yes"}, 80 {"active_this_week": "no"}, 81 ], 82 }, 83 { 84 "name": "established_users_churned_count", 85 "type": "count", 86 "filters": [ 87 {"new_last_week": "no"}, 88 {"new_this_week": "no"}, 89 {"active_last_week": "yes"}, 90 {"active_this_week": "no"}, 91 ], 92 }, 93 { 94 "name": "new_users_churned", 95 "type": "number", 96 "sql": "-1 * ${new_users_churned_count}", 97 }, 98 { 99 "name": "established_users_churned", 100 "type": "number", 101 "sql": "-1 * ${established_users_churned_count}", 102 }, 103 { 104 "name": "overall_churned", 105 "type": "number", 106 "sql": "${new_users_churned} + ${established_users_churned}", 107 }, 108 { 109 "name": "overall_retention_rate", 110 "type": "number", 111 "sql": ( 112 "SAFE_DIVIDE(" 113 "(${established_users_returning} + ${new_users_returning})," 114 "${overall_active_previous}" 115 ")" 116 ), 117 }, 118 { 119 "name": "established_user_retention_rate", 120 "type": "number", 121 "sql": ( 122 "SAFE_DIVIDE(" 123 "${established_users_returning}," 124 "(${established_users_returning} + ${established_users_churned_count})" 125 ")" 126 ), 127 }, 128 { 129 "name": "new_user_retention_rate", 130 "type": "number", 131 "sql": ( 132 "SAFE_DIVIDE(" 133 "${new_users_returning}," 134 "(${new_users_returning} + ${new_users_churned_count})" 135 ")" 136 ), 137 }, 138 { 139 "name": "overall_churn_rate", 140 "type": "number", 141 "sql": ( 142 "SAFE_DIVIDE(" 143 "(${established_users_churned_count} + ${new_users_churned_count})," 144 "${overall_active_previous}" 145 ")" 146 ), 147 }, 148 { 149 "name": "fraction_of_active_resurrected", 150 "type": "number", 151 "sql": "SAFE_DIVIDE(${overall_resurrected}, ${overall_active_current})", 152 }, 153 { 154 "name": "fraction_of_active_new", 155 "type": "number", 156 "sql": "SAFE_DIVIDE(${new_users}, ${overall_active_current})", 157 }, 158 { 159 "name": "fraction_of_active_established_returning", 160 "type": "number", 161 "sql": ( 162 "SAFE_DIVIDE(" 163 "${established_users_returning}," 164 "${overall_active_current}" 165 ")" 166 ), 167 }, 168 { 169 "name": "fraction_of_active_new_returning", 170 "type": "number", 171 "sql": "SAFE_DIVIDE(${new_users_returning}, ${overall_active_current})", 172 }, 173 { 174 "name": "quick_ratio", 175 "type": "number", 176 "sql": ( 177 "SAFE_DIVIDE(" 178 "${new_users} + ${overall_resurrected}," 179 "${established_users_churned_count} + ${new_users_churned_count}" 180 ")" 181 ), 182 }, 183 ] 184 185 def __init__( 186 self, 187 namespace: str, 188 tables: List[Dict[str, str]], 189 identifier_field: str = DEFAULT_IDENTIFIER_FIELD, 190 ): 191 """Get an instance of a GrowthAccountingView.""" 192 self.identifier_field = identifier_field 193 194 super().__init__( 195 namespace, "growth_accounting", GrowthAccountingView.type, tables 196 ) 197 198 @classmethod 199 def get_default_dimensions( 200 klass, identifier_field: str = DEFAULT_IDENTIFIER_FIELD 201 ) -> List[Dict[str, str]]: 202 """Get dimensions to be added to GrowthAccountingView by default.""" 203 return [ 204 { 205 "name": "active_this_week", 206 "sql": "mozfun.bits28.active_in_range(days_seen_bits, -6, 7)", 207 "type": "yesno", 208 "hidden": "yes", 209 }, 210 { 211 "name": "active_last_week", 212 "sql": "mozfun.bits28.active_in_range(days_seen_bits, -13, 7)", 213 "type": "yesno", 214 "hidden": "yes", 215 }, 216 { 217 "name": "new_this_week", 218 "sql": "DATE_DIFF(${submission_date}, first_run_date, DAY) BETWEEN 0 AND 6", 219 "type": "yesno", 220 "hidden": "yes", 221 }, 222 { 223 "name": "new_last_week", 224 "sql": "DATE_DIFF(${submission_date}, first_run_date, DAY) BETWEEN 7 AND 13", 225 "type": "yesno", 226 "hidden": "yes", 227 }, 228 { 229 "name": f"{identifier_field}_day", 230 "sql": f"CONCAT(CAST(${{TABLE}}.submission_date AS STRING), ${{{identifier_field}}})", 231 "type": "string", 232 "hidden": "yes", 233 "primary_key": "yes", 234 }, 235 ] 236 237 @classmethod 238 def from_db_views( 239 klass, 240 namespace: str, 241 is_glean: bool, 242 channels: List[Dict[str, str]], 243 db_views: dict, 244 identifier_field: str = DEFAULT_IDENTIFIER_FIELD, 245 ) -> Iterator[GrowthAccountingView]: 246 """Get Growth Accounting Views from db views and app variants.""" 247 dataset = next( 248 (channel for channel in channels if channel.get("channel") == "release"), 249 channels[0], 250 )["dataset"] 251 252 for view_id, references in db_views[dataset].items(): 253 if view_id == "baseline_clients_last_seen": 254 yield GrowthAccountingView( 255 namespace, 256 [{"table": f"mozdata.{dataset}.{view_id}"}], 257 identifier_field=identifier_field, 258 ) 259 260 @classmethod 261 def from_dict( 262 klass, namespace: str, name: str, _dict: ViewDict 263 ) -> GrowthAccountingView: 264 """Get a view from a name and dict definition.""" 265 return GrowthAccountingView( 266 namespace, 267 _dict["tables"], 268 identifier_field=str( 269 _dict.get( 270 "identifier_field", GrowthAccountingView.DEFAULT_IDENTIFIER_FIELD 271 ) 272 ), 273 ) 274 275 def to_lookml(self, v1_name: Optional[str], dryrun) -> Dict[str, Any]: 276 """Generate LookML for this view.""" 277 view_defn: Dict[str, Any] = {"name": self.name} 278 table = self.tables[0]["table"] 279 280 # add dimensions and dimension groups 281 dimensions = lookml_utils._generate_dimensions(table, dryrun=dryrun) + deepcopy( 282 GrowthAccountingView.get_default_dimensions( 283 identifier_field=self.identifier_field 284 ) 285 ) 286 287 view_defn["dimensions"] = list( 288 filterfalse(lookml_utils._is_dimension_group, dimensions) 289 ) 290 view_defn["dimension_groups"] = list( 291 filter(lookml_utils._is_dimension_group, dimensions) 292 ) 293 294 # add measures 295 view_defn["measures"] = self.get_measures() 296 297 # SQL Table Name 298 view_defn["sql_table_name"] = f"`{table}`" 299 300 return {"views": [view_defn]} 301 302 def get_measures(self) -> List[Dict[str, Union[str, List[Dict[str, str]]]]]: 303 """Generate measures for the Growth Accounting Framework.""" 304 return deepcopy(GrowthAccountingView.default_measures)
A view for growth accounting measures.
GrowthAccountingView( namespace: str, tables: List[Dict[str, str]], identifier_field: str = 'client_id')
185 def __init__( 186 self, 187 namespace: str, 188 tables: List[Dict[str, str]], 189 identifier_field: str = DEFAULT_IDENTIFIER_FIELD, 190 ): 191 """Get an instance of a GrowthAccountingView.""" 192 self.identifier_field = identifier_field 193 194 super().__init__( 195 namespace, "growth_accounting", GrowthAccountingView.type, tables 196 )
Get an instance of a GrowthAccountingView.
other_dimensions: List[Dict[str, str]] =
[{'name': 'first', 'sql': '{TABLE}.first', 'type': 'yesno', 'hidden': 'yes'}]
default_measures: List[Dict[str, Union[str, List[Dict[str, str]]]]] =
[{'name': 'overall_active_previous', 'type': 'count', 'filters': [{'active_last_week': 'yes'}]}, {'name': 'overall_active_current', 'type': 'count', 'filters': [{'active_this_week': 'yes'}]}, {'name': 'overall_resurrected', 'type': 'count', 'filters': [{'new_last_week': 'no'}, {'new_this_week': 'no'}, {'active_last_week': 'no'}, {'active_this_week': 'yes'}]}, {'name': 'new_users', 'type': 'count', 'filters': [{'new_this_week': 'yes'}, {'active_this_week': 'yes'}]}, {'name': 'established_users_returning', 'type': 'count', 'filters': [{'new_last_week': 'no'}, {'new_this_week': 'no'}, {'active_last_week': 'yes'}, {'active_this_week': 'yes'}]}, {'name': 'new_users_returning', 'type': 'count', 'filters': [{'new_last_week': 'yes'}, {'active_last_week': 'yes'}, {'active_this_week': 'yes'}]}, {'name': 'new_users_churned_count', 'type': 'count', 'filters': [{'new_last_week': 'yes'}, {'active_last_week': 'yes'}, {'active_this_week': 'no'}]}, {'name': 'established_users_churned_count', 'type': 'count', 'filters': [{'new_last_week': 'no'}, {'new_this_week': 'no'}, {'active_last_week': 'yes'}, {'active_this_week': 'no'}]}, {'name': 'new_users_churned', 'type': 'number', 'sql': '-1 * ${new_users_churned_count}'}, {'name': 'established_users_churned', 'type': 'number', 'sql': '-1 * ${established_users_churned_count}'}, {'name': 'overall_churned', 'type': 'number', 'sql': '${new_users_churned} + ${established_users_churned}'}, {'name': 'overall_retention_rate', 'type': 'number', 'sql': 'SAFE_DIVIDE((${established_users_returning} + ${new_users_returning}),${overall_active_previous})'}, {'name': 'established_user_retention_rate', 'type': 'number', 'sql': 'SAFE_DIVIDE(${established_users_returning},(${established_users_returning} + ${established_users_churned_count}))'}, {'name': 'new_user_retention_rate', 'type': 'number', 'sql': 'SAFE_DIVIDE(${new_users_returning},(${new_users_returning} + ${new_users_churned_count}))'}, {'name': 'overall_churn_rate', 'type': 'number', 'sql': 'SAFE_DIVIDE((${established_users_churned_count} + ${new_users_churned_count}),${overall_active_previous})'}, {'name': 'fraction_of_active_resurrected', 'type': 'number', 'sql': 'SAFE_DIVIDE(${overall_resurrected}, ${overall_active_current})'}, {'name': 'fraction_of_active_new', 'type': 'number', 'sql': 'SAFE_DIVIDE(${new_users}, ${overall_active_current})'}, {'name': 'fraction_of_active_established_returning', 'type': 'number', 'sql': 'SAFE_DIVIDE(${established_users_returning},${overall_active_current})'}, {'name': 'fraction_of_active_new_returning', 'type': 'number', 'sql': 'SAFE_DIVIDE(${new_users_returning}, ${overall_active_current})'}, {'name': 'quick_ratio', 'type': 'number', 'sql': 'SAFE_DIVIDE(${new_users} + ${overall_resurrected},${established_users_churned_count} + ${new_users_churned_count})'}]
@classmethod
def
get_default_dimensions(klass, identifier_field: str = 'client_id') -> List[Dict[str, str]]:
198 @classmethod 199 def get_default_dimensions( 200 klass, identifier_field: str = DEFAULT_IDENTIFIER_FIELD 201 ) -> List[Dict[str, str]]: 202 """Get dimensions to be added to GrowthAccountingView by default.""" 203 return [ 204 { 205 "name": "active_this_week", 206 "sql": "mozfun.bits28.active_in_range(days_seen_bits, -6, 7)", 207 "type": "yesno", 208 "hidden": "yes", 209 }, 210 { 211 "name": "active_last_week", 212 "sql": "mozfun.bits28.active_in_range(days_seen_bits, -13, 7)", 213 "type": "yesno", 214 "hidden": "yes", 215 }, 216 { 217 "name": "new_this_week", 218 "sql": "DATE_DIFF(${submission_date}, first_run_date, DAY) BETWEEN 0 AND 6", 219 "type": "yesno", 220 "hidden": "yes", 221 }, 222 { 223 "name": "new_last_week", 224 "sql": "DATE_DIFF(${submission_date}, first_run_date, DAY) BETWEEN 7 AND 13", 225 "type": "yesno", 226 "hidden": "yes", 227 }, 228 { 229 "name": f"{identifier_field}_day", 230 "sql": f"CONCAT(CAST(${{TABLE}}.submission_date AS STRING), ${{{identifier_field}}})", 231 "type": "string", 232 "hidden": "yes", 233 "primary_key": "yes", 234 }, 235 ]
Get dimensions to be added to GrowthAccountingView by default.
@classmethod
def
from_db_views( klass, namespace: str, is_glean: bool, channels: List[Dict[str, str]], db_views: dict, identifier_field: str = 'client_id') -> Iterator[GrowthAccountingView]:
237 @classmethod 238 def from_db_views( 239 klass, 240 namespace: str, 241 is_glean: bool, 242 channels: List[Dict[str, str]], 243 db_views: dict, 244 identifier_field: str = DEFAULT_IDENTIFIER_FIELD, 245 ) -> Iterator[GrowthAccountingView]: 246 """Get Growth Accounting Views from db views and app variants.""" 247 dataset = next( 248 (channel for channel in channels if channel.get("channel") == "release"), 249 channels[0], 250 )["dataset"] 251 252 for view_id, references in db_views[dataset].items(): 253 if view_id == "baseline_clients_last_seen": 254 yield GrowthAccountingView( 255 namespace, 256 [{"table": f"mozdata.{dataset}.{view_id}"}], 257 identifier_field=identifier_field, 258 )
Get Growth Accounting Views from db views and app variants.
@classmethod
def
from_dict( klass, namespace: str, name: str, _dict: generator.views.view.ViewDict) -> GrowthAccountingView:
260 @classmethod 261 def from_dict( 262 klass, namespace: str, name: str, _dict: ViewDict 263 ) -> GrowthAccountingView: 264 """Get a view from a name and dict definition.""" 265 return GrowthAccountingView( 266 namespace, 267 _dict["tables"], 268 identifier_field=str( 269 _dict.get( 270 "identifier_field", GrowthAccountingView.DEFAULT_IDENTIFIER_FIELD 271 ) 272 ), 273 )
Get a view from a name and dict definition.
def
to_lookml(self, v1_name: Optional[str], dryrun) -> Dict[str, Any]:
275 def to_lookml(self, v1_name: Optional[str], dryrun) -> Dict[str, Any]: 276 """Generate LookML for this view.""" 277 view_defn: Dict[str, Any] = {"name": self.name} 278 table = self.tables[0]["table"] 279 280 # add dimensions and dimension groups 281 dimensions = lookml_utils._generate_dimensions(table, dryrun=dryrun) + deepcopy( 282 GrowthAccountingView.get_default_dimensions( 283 identifier_field=self.identifier_field 284 ) 285 ) 286 287 view_defn["dimensions"] = list( 288 filterfalse(lookml_utils._is_dimension_group, dimensions) 289 ) 290 view_defn["dimension_groups"] = list( 291 filter(lookml_utils._is_dimension_group, dimensions) 292 ) 293 294 # add measures 295 view_defn["measures"] = self.get_measures() 296 297 # SQL Table Name 298 view_defn["sql_table_name"] = f"`{table}`" 299 300 return {"views": [view_defn]}
Generate LookML for this view.
def
get_measures(self) -> List[Dict[str, Union[str, List[Dict[str, str]]]]]:
302 def get_measures(self) -> List[Dict[str, Union[str, List[Dict[str, str]]]]]: 303 """Generate measures for the Growth Accounting Framework.""" 304 return deepcopy(GrowthAccountingView.default_measures)
Generate measures for the Growth Accounting Framework.