findly.unified-reporting-sdk 0.7.14__py3-none-any.whl → 0.7.16__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.
@@ -2,6 +2,7 @@ import re
2
2
  import pandas as pd
3
3
  from datetime import datetime
4
4
  from dateutil.relativedelta import relativedelta
5
+ import sqlglot
5
6
 
6
7
  from typing import List, Optional, Callable, Tuple, Any, TypedDict
7
8
  from findly.unified_reporting_sdk.protos.findly_semantic_layer_pb2 import (
@@ -16,6 +17,60 @@ from findly.unified_reporting_sdk.data_sources.common.date_range_helper import (
16
17
  NONE_VALUE = "none"
17
18
  RESERVED_TOTAL = "RESERVED_TOTAL"
18
19
 
20
+ # Regex pattern for valid SQL identifiers
21
+ _IDENTIFIER_PATTERN = re.compile(r"^[a-zA-Z_][a-zA-Z0-9_]*$")
22
+ # Regex pattern for ORDER BY column (identifier with optional ASC/DESC)
23
+ _ORDER_BY_PATTERN = re.compile(r"^([a-zA-Z_][a-zA-Z0-9_]*)\s*(ASC|DESC)?$", re.IGNORECASE)
24
+ # Regex pattern for YYYY-MM-DD date format
25
+ _DATE_PATTERN = re.compile(r"^\d{4}-\d{2}-\d{2}$")
26
+
27
+
28
+ def _validate_identifier(name: str) -> str:
29
+ """Validate that a string is a safe SQL identifier."""
30
+ if not _IDENTIFIER_PATTERN.match(name):
31
+ raise ValueError(f"Invalid SQL identifier: {name!r}")
32
+ return name
33
+
34
+
35
+ def _validate_order_by_column(col: str) -> str:
36
+ """Validate an ORDER BY column (identifier with optional ASC/DESC)."""
37
+ if not _ORDER_BY_PATTERN.match(col):
38
+ raise ValueError(f"Invalid ORDER BY column: {col!r}")
39
+ return col
40
+
41
+
42
+ def _validate_date(date_str: str) -> str:
43
+ """Validate that a string is a valid YYYY-MM-DD date."""
44
+ if not _DATE_PATTERN.match(date_str):
45
+ raise ValueError(f"Invalid date format (expected YYYY-MM-DD): {date_str!r}")
46
+ return date_str
47
+
48
+
49
+ def _validate_positive_integer(value: Any) -> int:
50
+ """Validate that a value is a positive integer."""
51
+ try:
52
+ int_value = int(value)
53
+ except (TypeError, ValueError) as e:
54
+ raise ValueError(f"Invalid integer value: {value!r}") from e
55
+ if int_value <= 0:
56
+ raise ValueError(f"Value must be positive: {int_value}")
57
+ return int_value
58
+
59
+
60
+ def _validate_sql_clause(clause: str, clause_type: str) -> str:
61
+ """Validate a SQL clause (WHERE/HAVING) using sqlglot parsing."""
62
+ if not clause or not clause.strip():
63
+ raise ValueError(f"Empty {clause_type} clause")
64
+ # Wrap in a minimal SELECT statement to validate the clause
65
+ test_query = f"SELECT 1 FROM t {clause_type} {clause}"
66
+ try:
67
+ parsed = sqlglot.parse(test_query)
68
+ if not parsed or parsed[0] is None:
69
+ raise ValueError(f"Failed to parse {clause_type} clause: {clause!r}")
70
+ except sqlglot.errors.ParseError as e:
71
+ raise ValueError(f"Invalid {clause_type} clause: {clause!r}") from e
72
+ return clause
73
+
19
74
 
20
75
  class DefaultFormattedDateRange(TypedDict):
21
76
  since: str
@@ -102,17 +157,24 @@ class CommonParser:
102
157
 
103
158
  Returns:
104
159
  str: The SQL query generated from the QueryArgs object.
160
+
161
+ Raises:
162
+ ValueError: If any input fails validation.
105
163
  """
106
164
  query_parts = []
107
165
 
108
166
  select_parts = []
109
167
  # Metrics and Metrics Expression
110
168
  if query.metrics:
111
- select_parts.append(", ".join(query.metrics))
169
+ validated_metrics = [_validate_identifier(m) for m in query.metrics]
170
+ select_parts.append(", ".join(validated_metrics))
112
171
  elif query.metrics_expression:
113
172
  select_parts.append(", ".join(query.metrics_expression))
114
173
  if query.group_by_columns:
115
- select_parts.append(", ".join(query.group_by_columns))
174
+ validated_group_cols = [
175
+ _validate_identifier(col) for col in query.group_by_columns
176
+ ]
177
+ select_parts.append(", ".join(validated_group_cols))
116
178
  if len(select_parts) > 0:
117
179
  select_str = "SELECT " + ", ".join(select_parts)
118
180
  query_parts.append(select_str)
@@ -123,13 +185,14 @@ class CommonParser:
123
185
  where_clause_modified = re.sub(
124
186
  r"\bwhere\b", "", query.where_clause, flags=re.IGNORECASE
125
187
  ).strip()
188
+ _validate_sql_clause(where_clause_modified, "WHERE")
126
189
  conditions.append(f"WHERE {where_clause_modified}")
127
190
 
128
191
  # Date Where clause
129
192
  if query.date_ranges:
130
193
  for date_range in list(query.date_ranges):
131
- start_date = date_range.start_date
132
- end_date = date_range.end_date
194
+ start_date = _validate_date(date_range.start_date)
195
+ end_date = _validate_date(date_range.end_date)
133
196
  # Check if start and end dates are the same
134
197
  if start_date == end_date:
135
198
  # Use equality condition when dates are the same
@@ -143,7 +206,10 @@ class CommonParser:
143
206
 
144
207
  # Group By
145
208
  if query.group_by_columns:
146
- group_by_str = ", ".join(query.group_by_columns)
209
+ validated_group_cols = [
210
+ _validate_identifier(col) for col in query.group_by_columns
211
+ ]
212
+ group_by_str = ", ".join(validated_group_cols)
147
213
  query_parts.append(f"GROUP BY {group_by_str}")
148
214
 
149
215
  # Having
@@ -151,16 +217,21 @@ class CommonParser:
151
217
  having_clause_modified = re.sub(
152
218
  r"\bhaving\b", "", query.having_clause, flags=re.IGNORECASE
153
219
  ).strip()
220
+ _validate_sql_clause(having_clause_modified, "HAVING")
154
221
  query_parts.append(f"HAVING {having_clause_modified}")
155
222
 
156
223
  # Order By
157
224
  if query.order_by:
158
- order_by_str = ", ".join(query.order_by)
225
+ validated_order_cols = [
226
+ _validate_order_by_column(col) for col in query.order_by
227
+ ]
228
+ order_by_str = ", ".join(validated_order_cols)
159
229
  query_parts.append(f"ORDER BY {order_by_str}")
160
230
 
161
231
  # Limit
162
232
  if query.limit:
163
- query_parts.append(f"LIMIT {query.limit}")
233
+ validated_limit = _validate_positive_integer(query.limit)
234
+ query_parts.append(f"LIMIT {validated_limit}")
164
235
 
165
236
  return "\n".join(query_parts)
166
237
 
@@ -1,3 +1 @@
1
- *
2
- !.gitignore
3
- !__init__.py
1
+ __pycache__/
@@ -2,10 +2,10 @@
2
2
  # Generated by the protocol buffer compiler. DO NOT EDIT!
3
3
  # source: findly_semantic_layer.proto
4
4
  """Generated protocol buffer code."""
5
+ from google.protobuf.internal import builder as _builder
5
6
  from google.protobuf import descriptor as _descriptor
6
7
  from google.protobuf import descriptor_pool as _descriptor_pool
7
8
  from google.protobuf import symbol_database as _symbol_database
8
- from google.protobuf.internal import builder as _builder
9
9
  # @@protoc_insertion_point(imports)
10
10
 
11
11
  _sym_db = _symbol_database.Default()
@@ -15,37 +15,37 @@ _sym_db = _symbol_database.Default()
15
15
 
16
16
  DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1b\x66indly_semantic_layer.proto\x12\x15\x66indly_semantic_layer\"\xd4\x02\n\tDimension\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x02 \x01(\t\x12\x0c\n\x04\x65xpr\x18\x03 \x01(\t\x12\x32\n\x04type\x18\x04 \x01(\x0e\x32$.findly_semantic_layer.DimensionType\x12?\n\x0btype_params\x18\x05 \x01(\x0b\x32*.findly_semantic_layer.DimensionTypeParams\x12\x14\n\x0ctop_n_values\x18\x06 \x03(\t\x12\x16\n\nvalue_type\x18\x07 \x01(\tB\x02\x18\x01\x12\x19\n\x11\x64\x61ta_source_names\x18\x08 \x03(\t\x12\x14\n\x0c\x64isplay_name\x18\t \x01(\t\x12\x42\n\x0fvalue_type_enum\x18\n \x01(\x0e\x32).findly_semantic_layer.DimensionValueType\"k\n\x13\x44imensionTypeParams\x12@\n\x10time_granularity\x18\x01 \x01(\x0e\x32&.findly_semantic_layer.DateGranularity\x12\x12\n\nis_primary\x18\x02 \x01(\x08\"\x8b\x03\n\x06Metric\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x03 \x01(\t\x12\x12\n\nexpression\x18\x04 \x01(\t\x12\x18\n\x10view_id_of_table\x18\x05 \x01(\t\x12\x12\n\ntable_name\x18\x06 \x01(\t\x12\x10\n\x08measures\x18\x07 \x03(\t\x12\x11\n\tnumerator\x18\x08 \x01(\t\x12\x13\n\x0b\x64\x65nominator\x18\t \x01(\t\x12/\n\x04type\x18\n \x01(\x0e\x32!.findly_semantic_layer.MetricType\x12\x10\n\x06window\x18\x0b \x01(\tH\x00\x12\x17\n\rgrain_to_date\x18\x0c \x01(\tH\x00\x12:\n\nvalue_type\x18\r \x01(\x0e\x32&.findly_semantic_layer.MetricValueType\x12\x14\n\x0c\x64isplay_name\x18\x0e \x01(\t\x12\x12\n\nis_numeric\x18\x0f \x01(\x08\x42\x14\n\x12\x63umulative_process\"4\n\x0c\x44\x61teStrRange\x12\x12\n\nstart_date\x18\x01 \x01(\t\x12\x10\n\x08\x65nd_date\x18\x02 \x01(\t\"\x93\x03\n\tQueryArgs\x12\x14\n\x0cwhere_clause\x18\x01 \x01(\t\x12\x18\n\x10group_by_columns\x18\x02 \x03(\t\x12\x1a\n\x12metrics_expression\x18\x03 \x03(\t\x12\r\n\x05limit\x18\x04 \x01(\t\x12\x10\n\x08order_by\x18\x05 \x03(\t\x12\x19\n\x11\x64\x61te_where_clause\x18\x06 \x01(\t\x12\x0f\n\x07metrics\x18\x07 \x03(\t\x12\x15\n\rhaving_clause\x18\x08 \x01(\t\x12\x1c\n\x14incompatible_metrics\x18\t \x03(\t\x12\x1f\n\x17incompatible_dimensions\x18\n \x03(\t\x12\x38\n\x0b\x64\x61te_ranges\x18\x0b \x03(\x0b\x32#.findly_semantic_layer.DateStrRange\x12\x17\n\x0fsql_explanation\x18\x0c \x01(\t\x12\r\n\x05level\x18\r \x01(\t\x12\x16\n\x0etime_increment\x18\x0e \x01(\t\x12\x1d\n\x15main_data_source_name\x18\x0f \x01(\t\"\x80\x01\n\x12\x44\x61tasourceMetadata\x12>\n\x08location\x18\x01 \x01(\x0e\x32,.findly_semantic_layer.DataSourceIntegration\x12\x13\n\x0bproperty_id\x18\x02 \x01(\t\x12\x15\n\rproperty_name\x18\x03 \x01(\t*b\n\x15\x44\x61taSourceIntegration\x12 \n\x1c\x44\x41TA_SOURCE_LOCATION_UNKNOWN\x10\x00\x12\x12\n\x0eSEMANTIC_LAYER\x10\x01\x12\x07\n\x03GA4\x10\x02\x12\n\n\x06\x46\x42_ADS\x10\x03*S\n\x0f\x44\x61teGranularity\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x07\n\x03\x44\x41Y\x10\x01\x12\x08\n\x04WEEK\x10\x02\x12\t\n\x05MONTH\x10\x03\x12\x0b\n\x07QUARTER\x10\x04\x12\x08\n\x04YEAR\x10\x05*\x7f\n\x0b\x41ggregation\x12\x17\n\x13\x41GGREGATION_UNKNOWN\x10\x00\x12\x07\n\x03SUM\x10\x01\x12\x0f\n\x0bSUM_BOOLEAN\x10\x02\x12\x12\n\x0e\x43OUNT_DISTINCT\x10\x03\x12\x07\n\x03MIN\x10\x04\x12\x07\n\x03MAX\x10\x05\x12\x0b\n\x07\x41VERAGE\x10\x06\x12\n\n\x06MEDIAN\x10\x07*\xab\x01\n\rDimensionType\x12\x15\n\x11\x44IMENSION_UNKNOWN\x10\x00\x12\x0f\n\x0b\x43\x41TEGORICAL\x10\x01\x12\x08\n\x04TIME\x10\x02\x12\x10\n\x0c\x46\x42_ADS_FIELD\x10\x03\x12\x14\n\x10\x46\x42_ADS_BREAKDOWN\x10\x04\x12\x1b\n\x17\x46\x42_ADS_ACTION_BREAKDOWN\x10\x05\x12#\n\x1f\x46\x42_ADS_SUMMARY_ACTION_BREAKDOWN\x10\x06*\x84\x01\n\x12\x44imensionValueType\x12\x16\n\x12VALUE_TYPE_UNKNOWN\x10\x00\x12\n\n\x06STRING\x10\x01\x12\x0b\n\x07INTEGER\x10\x02\x12\t\n\x05\x46LOAT\x10\x03\x12\x0b\n\x07\x42OOLEAN\x10\x04\x12\x08\n\x04\x44\x41TE\x10\x05\x12\x0c\n\x08\x44\x41TETIME\x10\x06\x12\r\n\tTIMESTAMP\x10\x07*o\n\nMetricType\x12\x12\n\x0eMETRIC_UNKNOWN\x10\x00\x12\x11\n\rMEASURE_PROXY\x10\x01\x12\x0e\n\nCUMULATIVE\x10\x02\x12\t\n\x05RATIO\x10\x03\x12\x0b\n\x07\x44\x45RIVED\x10\x04\x12\x12\n\x0eSQL_EXPRESSION\x10\x05*\xf9\x04\n\x0fMetricValueType\x12\x1d\n\x19METRIC_VALUE_TYPE_UNKNOWN\x10\x00\x12\x1d\n\x19METRIC_VALUE_TYPE_INTEGER\x10\x01\x12\x1b\n\x17METRIC_VALUE_TYPE_FLOAT\x10\x02\x12\x1d\n\x19METRIC_VALUE_TYPE_SECONDS\x10\x03\x12\"\n\x1eMETRIC_VALUE_TYPE_MILLISECONDS\x10\x04\x12\x1d\n\x19METRIC_VALUE_TYPE_MINUTES\x10\x05\x12\x1b\n\x17METRIC_VALUE_TYPE_HOURS\x10\x06\x12\x1e\n\x1aMETRIC_VALUE_TYPE_STANDARD\x10\x07\x12\x1e\n\x1aMETRIC_VALUE_TYPE_CURRENCY\x10\x08\x12\x1a\n\x16METRIC_VALUE_TYPE_FEET\x10\t\x12\x1b\n\x17METRIC_VALUE_TYPE_MILES\x10\n\x12\x1c\n\x18METRIC_VALUE_TYPE_METERS\x10\x0b\x12 \n\x1cMETRIC_VALUE_TYPE_KILOMETERS\x10\x0c\x12\x1c\n\x18METRIC_VALUE_TYPE_STRING\x10\r\x12$\n METRIC_VALUE_TYPE_NUMERIC_STRING\x10\x0e\x12+\n\'METRIC_VALUE_TYPE_LIST_ADS_ACTION_STATS\x10\x0f\x12\x32\n.METRIC_VALUE_TYPE_LIST_ADS_INSIGHTS_DDA_RESULT\x10\x10\x12.\n*METRIC_VALUE_TYPE_LIST_ADS_HISTOGRAM_STATS\x10\x11\x62\x06proto3')
17
17
 
18
- _globals = globals()
19
- _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
20
- _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'findly_semantic_layer_pb2', _globals)
18
+ _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
19
+ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'findly_semantic_layer_pb2', globals())
21
20
  if _descriptor._USE_C_DESCRIPTORS == False:
21
+
22
22
  DESCRIPTOR._options = None
23
- _globals['_DIMENSION'].fields_by_name['value_type']._options = None
24
- _globals['_DIMENSION'].fields_by_name['value_type']._serialized_options = b'\030\001'
25
- _globals['_DATASOURCEINTEGRATION']._serialized_start=1495
26
- _globals['_DATASOURCEINTEGRATION']._serialized_end=1593
27
- _globals['_DATEGRANULARITY']._serialized_start=1595
28
- _globals['_DATEGRANULARITY']._serialized_end=1678
29
- _globals['_AGGREGATION']._serialized_start=1680
30
- _globals['_AGGREGATION']._serialized_end=1807
31
- _globals['_DIMENSIONTYPE']._serialized_start=1810
32
- _globals['_DIMENSIONTYPE']._serialized_end=1981
33
- _globals['_DIMENSIONVALUETYPE']._serialized_start=1984
34
- _globals['_DIMENSIONVALUETYPE']._serialized_end=2116
35
- _globals['_METRICTYPE']._serialized_start=2118
36
- _globals['_METRICTYPE']._serialized_end=2229
37
- _globals['_METRICVALUETYPE']._serialized_start=2232
38
- _globals['_METRICVALUETYPE']._serialized_end=2865
39
- _globals['_DIMENSION']._serialized_start=55
40
- _globals['_DIMENSION']._serialized_end=395
41
- _globals['_DIMENSIONTYPEPARAMS']._serialized_start=397
42
- _globals['_DIMENSIONTYPEPARAMS']._serialized_end=504
43
- _globals['_METRIC']._serialized_start=507
44
- _globals['_METRIC']._serialized_end=902
45
- _globals['_DATESTRRANGE']._serialized_start=904
46
- _globals['_DATESTRRANGE']._serialized_end=956
47
- _globals['_QUERYARGS']._serialized_start=959
48
- _globals['_QUERYARGS']._serialized_end=1362
49
- _globals['_DATASOURCEMETADATA']._serialized_start=1365
50
- _globals['_DATASOURCEMETADATA']._serialized_end=1493
23
+ _DIMENSION.fields_by_name['value_type']._options = None
24
+ _DIMENSION.fields_by_name['value_type']._serialized_options = b'\030\001'
25
+ _DATASOURCEINTEGRATION._serialized_start=1495
26
+ _DATASOURCEINTEGRATION._serialized_end=1593
27
+ _DATEGRANULARITY._serialized_start=1595
28
+ _DATEGRANULARITY._serialized_end=1678
29
+ _AGGREGATION._serialized_start=1680
30
+ _AGGREGATION._serialized_end=1807
31
+ _DIMENSIONTYPE._serialized_start=1810
32
+ _DIMENSIONTYPE._serialized_end=1981
33
+ _DIMENSIONVALUETYPE._serialized_start=1984
34
+ _DIMENSIONVALUETYPE._serialized_end=2116
35
+ _METRICTYPE._serialized_start=2118
36
+ _METRICTYPE._serialized_end=2229
37
+ _METRICVALUETYPE._serialized_start=2232
38
+ _METRICVALUETYPE._serialized_end=2865
39
+ _DIMENSION._serialized_start=55
40
+ _DIMENSION._serialized_end=395
41
+ _DIMENSIONTYPEPARAMS._serialized_start=397
42
+ _DIMENSIONTYPEPARAMS._serialized_end=504
43
+ _METRIC._serialized_start=507
44
+ _METRIC._serialized_end=902
45
+ _DATESTRRANGE._serialized_start=904
46
+ _DATESTRRANGE._serialized_end=956
47
+ _QUERYARGS._serialized_start=959
48
+ _QUERYARGS._serialized_end=1362
49
+ _DATASOURCEMETADATA._serialized_start=1365
50
+ _DATASOURCEMETADATA._serialized_end=1493
51
51
  # @@protoc_insertion_point(module_scope)
@@ -36,7 +36,7 @@ DATA_SOURCE_LOCATION_UNKNOWN: DataSourceIntegration.ValueType # 0
36
36
  SEMANTIC_LAYER: DataSourceIntegration.ValueType # 1
37
37
  GA4: DataSourceIntegration.ValueType # 2
38
38
  FB_ADS: DataSourceIntegration.ValueType # 3
39
- global___DataSourceIntegration = DataSourceIntegration
39
+ Global___DataSourceIntegration: typing_extensions.TypeAlias = DataSourceIntegration
40
40
 
41
41
  class _DateGranularity:
42
42
  ValueType = typing.NewType("ValueType", builtins.int)
@@ -59,7 +59,7 @@ WEEK: DateGranularity.ValueType # 2
59
59
  MONTH: DateGranularity.ValueType # 3
60
60
  QUARTER: DateGranularity.ValueType # 4
61
61
  YEAR: DateGranularity.ValueType # 5
62
- global___DateGranularity = DateGranularity
62
+ Global___DateGranularity: typing_extensions.TypeAlias = DateGranularity
63
63
 
64
64
  class _Aggregation:
65
65
  ValueType = typing.NewType("ValueType", builtins.int)
@@ -86,7 +86,7 @@ MIN: Aggregation.ValueType # 4
86
86
  MAX: Aggregation.ValueType # 5
87
87
  AVERAGE: Aggregation.ValueType # 6
88
88
  MEDIAN: Aggregation.ValueType # 7
89
- global___Aggregation = Aggregation
89
+ Global___Aggregation: typing_extensions.TypeAlias = Aggregation
90
90
 
91
91
  class _DimensionType:
92
92
  ValueType = typing.NewType("ValueType", builtins.int)
@@ -125,7 +125,7 @@ FB_ADS_FIELD: DimensionType.ValueType # 3
125
125
  FB_ADS_BREAKDOWN: DimensionType.ValueType # 4
126
126
  FB_ADS_ACTION_BREAKDOWN: DimensionType.ValueType # 5
127
127
  FB_ADS_SUMMARY_ACTION_BREAKDOWN: DimensionType.ValueType # 6
128
- global___DimensionType = DimensionType
128
+ Global___DimensionType: typing_extensions.TypeAlias = DimensionType
129
129
 
130
130
  class _DimensionValueType:
131
131
  ValueType = typing.NewType("ValueType", builtins.int)
@@ -152,7 +152,7 @@ BOOLEAN: DimensionValueType.ValueType # 4
152
152
  DATE: DimensionValueType.ValueType # 5
153
153
  DATETIME: DimensionValueType.ValueType # 6
154
154
  TIMESTAMP: DimensionValueType.ValueType # 7
155
- global___DimensionValueType = DimensionValueType
155
+ Global___DimensionValueType: typing_extensions.TypeAlias = DimensionValueType
156
156
 
157
157
  class _MetricType:
158
158
  ValueType = typing.NewType("ValueType", builtins.int)
@@ -204,7 +204,7 @@ Note that if an optional constraint string is applied, the constraint is applied
204
204
  DERIVED: MetricType.ValueType # 4
205
205
  SQL_EXPRESSION: MetricType.ValueType # 5
206
206
  """When you are building a metric that involves a SQL expression of multiple measures, you can use an expression metric."""
207
- global___MetricType = MetricType
207
+ Global___MetricType: typing_extensions.TypeAlias = MetricType
208
208
 
209
209
  class _MetricValueType:
210
210
  ValueType = typing.NewType("ValueType", builtins.int)
@@ -285,7 +285,7 @@ METRIC_VALUE_TYPE_LIST_ADS_ACTION_STATS: MetricValueType.ValueType # 15
285
285
  """A single action for a Statistics result -> https://github.com/facebook/facebook-python-business-sdk/blob/main/facebook_business/adobjects/adsactionstats.py"""
286
286
  METRIC_VALUE_TYPE_LIST_ADS_INSIGHTS_DDA_RESULT: MetricValueType.ValueType # 16
287
287
  METRIC_VALUE_TYPE_LIST_ADS_HISTOGRAM_STATS: MetricValueType.ValueType # 17
288
- global___MetricValueType = MetricValueType
288
+ Global___MetricValueType: typing_extensions.TypeAlias = MetricValueType
289
289
 
290
290
  @typing.final
291
291
  class Dimension(google.protobuf.message.Message):
@@ -311,7 +311,7 @@ class Dimension(google.protobuf.message.Message):
311
311
  And we want to define a date range of interest for our queries
312
312
  Use DATE_TRUNC(CAST(dimension.name, DATETIME), DateGranularity) to ensure we can use WHERE date range correctly
313
313
  """
314
- type: global___DimensionType.ValueType
314
+ type: Global___DimensionType.ValueType
315
315
  """The type of the dimension, e.g. CATEGORICAL or TIME."""
316
316
  value_type: builtins.str
317
317
  """The type of the values of the dimension, e.g. STRING, INTEGER, FLOAT, etc.
@@ -319,9 +319,9 @@ class Dimension(google.protobuf.message.Message):
319
319
  """
320
320
  display_name: builtins.str
321
321
  """The display name."""
322
- value_type_enum: global___DimensionValueType.ValueType
322
+ value_type_enum: Global___DimensionValueType.ValueType
323
323
  @property
324
- def type_params(self) -> global___DimensionTypeParams:
324
+ def type_params(self) -> Global___DimensionTypeParams:
325
325
  """The parameters of the dimension type."""
326
326
 
327
327
  @property
@@ -338,18 +338,18 @@ class Dimension(google.protobuf.message.Message):
338
338
  name: builtins.str = ...,
339
339
  description: builtins.str = ...,
340
340
  expr: builtins.str = ...,
341
- type: global___DimensionType.ValueType = ...,
342
- type_params: global___DimensionTypeParams | None = ...,
341
+ type: Global___DimensionType.ValueType = ...,
342
+ type_params: Global___DimensionTypeParams | None = ...,
343
343
  top_n_values: collections.abc.Iterable[builtins.str] | None = ...,
344
344
  value_type: builtins.str = ...,
345
345
  data_source_names: collections.abc.Iterable[builtins.str] | None = ...,
346
346
  display_name: builtins.str = ...,
347
- value_type_enum: global___DimensionValueType.ValueType = ...,
347
+ value_type_enum: Global___DimensionValueType.ValueType = ...,
348
348
  ) -> None: ...
349
349
  def HasField(self, field_name: typing.Literal["type_params", b"type_params"]) -> builtins.bool: ...
350
350
  def ClearField(self, field_name: typing.Literal["data_source_names", b"data_source_names", "description", b"description", "display_name", b"display_name", "expr", b"expr", "name", b"name", "top_n_values", b"top_n_values", "type", b"type", "type_params", b"type_params", "value_type", b"value_type", "value_type_enum", b"value_type_enum"]) -> None: ...
351
351
 
352
- global___Dimension = Dimension
352
+ Global___Dimension: typing_extensions.TypeAlias = Dimension
353
353
 
354
354
  @typing.final
355
355
  class DimensionTypeParams(google.protobuf.message.Message):
@@ -357,7 +357,7 @@ class DimensionTypeParams(google.protobuf.message.Message):
357
357
 
358
358
  TIME_GRANULARITY_FIELD_NUMBER: builtins.int
359
359
  IS_PRIMARY_FIELD_NUMBER: builtins.int
360
- time_granularity: global___DateGranularity.ValueType
360
+ time_granularity: Global___DateGranularity.ValueType
361
361
  """The date granularity of the dimension if it is a time dimension."""
362
362
  is_primary: builtins.bool
363
363
  """Note for Time dimensions: For data sources with a measure involved, a primary time dimension is required (notice the is_primary: True parameter).
@@ -366,12 +366,12 @@ class DimensionTypeParams(google.protobuf.message.Message):
366
366
  def __init__(
367
367
  self,
368
368
  *,
369
- time_granularity: global___DateGranularity.ValueType = ...,
369
+ time_granularity: Global___DateGranularity.ValueType = ...,
370
370
  is_primary: builtins.bool = ...,
371
371
  ) -> None: ...
372
372
  def ClearField(self, field_name: typing.Literal["is_primary", b"is_primary", "time_granularity", b"time_granularity"]) -> None: ...
373
373
 
374
- global___DimensionTypeParams = DimensionTypeParams
374
+ Global___DimensionTypeParams: typing_extensions.TypeAlias = DimensionTypeParams
375
375
 
376
376
  @typing.final
377
377
  class Metric(google.protobuf.message.Message):
@@ -428,7 +428,7 @@ class Metric(google.protobuf.message.Message):
428
428
  """
429
429
  denominator: builtins.str
430
430
  """The denominator of the metric if it is a ratio metric. It should be a measure."""
431
- type: global___MetricType.ValueType
431
+ type: Global___MetricType.ValueType
432
432
  """The type of the metric, e.g. MEASURE_PROXY, CUMULATIVE, RATIO, etc.
433
433
  If the type is MEASURE_PROXY, the name of the metric must match the measure name in the expression
434
434
  """
@@ -436,7 +436,7 @@ class Metric(google.protobuf.message.Message):
436
436
  """The window of the metric if it is a cumulative metric."""
437
437
  grain_to_date: builtins.str
438
438
  """The grain of the metric if it is a cumulative metric."""
439
- value_type: global___MetricValueType.ValueType
439
+ value_type: Global___MetricValueType.ValueType
440
440
  """The value type of the metric, e.g. INTEGER, FLOAT, etc.
441
441
  Always set this field to METRIC_VALUE_TYPE_UNKNOWN = 0
442
442
  """
@@ -463,10 +463,10 @@ class Metric(google.protobuf.message.Message):
463
463
  measures: collections.abc.Iterable[builtins.str] | None = ...,
464
464
  numerator: builtins.str = ...,
465
465
  denominator: builtins.str = ...,
466
- type: global___MetricType.ValueType = ...,
466
+ type: Global___MetricType.ValueType = ...,
467
467
  window: builtins.str = ...,
468
468
  grain_to_date: builtins.str = ...,
469
- value_type: global___MetricValueType.ValueType = ...,
469
+ value_type: Global___MetricValueType.ValueType = ...,
470
470
  display_name: builtins.str = ...,
471
471
  is_numeric: builtins.bool = ...,
472
472
  ) -> None: ...
@@ -474,7 +474,7 @@ class Metric(google.protobuf.message.Message):
474
474
  def ClearField(self, field_name: typing.Literal["cumulative_process", b"cumulative_process", "denominator", b"denominator", "description", b"description", "display_name", b"display_name", "expression", b"expression", "grain_to_date", b"grain_to_date", "id", b"id", "is_numeric", b"is_numeric", "measures", b"measures", "name", b"name", "numerator", b"numerator", "table_name", b"table_name", "type", b"type", "value_type", b"value_type", "view_id_of_table", b"view_id_of_table", "window", b"window"]) -> None: ...
475
475
  def WhichOneof(self, oneof_group: typing.Literal["cumulative_process", b"cumulative_process"]) -> typing.Literal["window", "grain_to_date"] | None: ...
476
476
 
477
- global___Metric = Metric
477
+ Global___Metric: typing_extensions.TypeAlias = Metric
478
478
 
479
479
  @typing.final
480
480
  class DateStrRange(google.protobuf.message.Message):
@@ -494,7 +494,7 @@ class DateStrRange(google.protobuf.message.Message):
494
494
  ) -> None: ...
495
495
  def ClearField(self, field_name: typing.Literal["end_date", b"end_date", "start_date", b"start_date"]) -> None: ...
496
496
 
497
- global___DateStrRange = DateStrRange
497
+ Global___DateStrRange: typing_extensions.TypeAlias = DateStrRange
498
498
 
499
499
  @typing.final
500
500
  class QueryArgs(google.protobuf.message.Message):
@@ -554,7 +554,7 @@ class QueryArgs(google.protobuf.message.Message):
554
554
  """The list of dimensions selected by the pipeline, but are incompatible for the request."""
555
555
 
556
556
  @property
557
- def date_ranges(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___DateStrRange]:
557
+ def date_ranges(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[Global___DateStrRange]:
558
558
  """The date ranges to be queried."""
559
559
 
560
560
  def __init__(
@@ -570,7 +570,7 @@ class QueryArgs(google.protobuf.message.Message):
570
570
  having_clause: builtins.str = ...,
571
571
  incompatible_metrics: collections.abc.Iterable[builtins.str] | None = ...,
572
572
  incompatible_dimensions: collections.abc.Iterable[builtins.str] | None = ...,
573
- date_ranges: collections.abc.Iterable[global___DateStrRange] | None = ...,
573
+ date_ranges: collections.abc.Iterable[Global___DateStrRange] | None = ...,
574
574
  sql_explanation: builtins.str = ...,
575
575
  level: builtins.str = ...,
576
576
  time_increment: builtins.str = ...,
@@ -578,7 +578,7 @@ class QueryArgs(google.protobuf.message.Message):
578
578
  ) -> None: ...
579
579
  def ClearField(self, field_name: typing.Literal["date_ranges", b"date_ranges", "date_where_clause", b"date_where_clause", "group_by_columns", b"group_by_columns", "having_clause", b"having_clause", "incompatible_dimensions", b"incompatible_dimensions", "incompatible_metrics", b"incompatible_metrics", "level", b"level", "limit", b"limit", "main_data_source_name", b"main_data_source_name", "metrics", b"metrics", "metrics_expression", b"metrics_expression", "order_by", b"order_by", "sql_explanation", b"sql_explanation", "time_increment", b"time_increment", "where_clause", b"where_clause"]) -> None: ...
580
580
 
581
- global___QueryArgs = QueryArgs
581
+ Global___QueryArgs: typing_extensions.TypeAlias = QueryArgs
582
582
 
583
583
  @typing.final
584
584
  class DatasourceMetadata(google.protobuf.message.Message):
@@ -587,16 +587,16 @@ class DatasourceMetadata(google.protobuf.message.Message):
587
587
  LOCATION_FIELD_NUMBER: builtins.int
588
588
  PROPERTY_ID_FIELD_NUMBER: builtins.int
589
589
  PROPERTY_NAME_FIELD_NUMBER: builtins.int
590
- location: global___DataSourceIntegration.ValueType
590
+ location: Global___DataSourceIntegration.ValueType
591
591
  property_id: builtins.str
592
592
  property_name: builtins.str
593
593
  def __init__(
594
594
  self,
595
595
  *,
596
- location: global___DataSourceIntegration.ValueType = ...,
596
+ location: Global___DataSourceIntegration.ValueType = ...,
597
597
  property_id: builtins.str = ...,
598
598
  property_name: builtins.str = ...,
599
599
  ) -> None: ...
600
600
  def ClearField(self, field_name: typing.Literal["location", b"location", "property_id", b"property_id", "property_name", b"property_name"]) -> None: ...
601
601
 
602
- global___DatasourceMetadata = DatasourceMetadata
602
+ Global___DatasourceMetadata: typing_extensions.TypeAlias = DatasourceMetadata
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.3
2
2
  Name: findly.unified-reporting-sdk
3
- Version: 0.7.14
3
+ Version: 0.7.16
4
4
  Summary:
5
5
  License: GPL-3.0-only
6
6
  Requires-Python: >=3.9,<4.0
@@ -17,9 +17,8 @@ Requires-Dist: facebook-business (>=22.0.5,<23.0.0)
17
17
  Requires-Dist: google-analytics-admin (>=0.24.0,<0.25.0)
18
18
  Requires-Dist: google-analytics-data (>=0.18.18,<0.19.0)
19
19
  Requires-Dist: google-api-python-client (>=2.169.0,<3.0.0)
20
- Requires-Dist: oauth2client (>=4.1.3,<5.0.0)
21
20
  Requires-Dist: pandas (>=2.2.3,<3.0.0)
22
- Requires-Dist: protobuf (>=4.25.3,<5.0.0)
21
+ Requires-Dist: protobuf (>=6.33.5,<7.0.0)
23
22
  Requires-Dist: sqlglot (>=26.17.1,<27.0.0)
24
23
  Description-Content-Type: text/markdown
25
24
 
@@ -2,7 +2,7 @@ findly/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  findly/unified_reporting_sdk/__init__.py,sha256=1GE1LJq5zf-0fuObZtLXJN6RaxkeByKX3-bgEkzpi6I,342
3
3
  findly/unified_reporting_sdk/data_sources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  findly/unified_reporting_sdk/data_sources/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
- findly/unified_reporting_sdk/data_sources/common/common_parser.py,sha256=76yLDRQkSuf0UyxmadPTZ8qvgOnMeSZNvsd4lygnx34,7866
5
+ findly/unified_reporting_sdk/data_sources/common/common_parser.py,sha256=mT5oOTjVMvtKuv7U-Kasp00fNwRqokfQQEKuCSL9r70,10779
6
6
  findly/unified_reporting_sdk/data_sources/common/date_range_helper.py,sha256=z2L1YU1Mzbybkl1wZK_mXL9lKFfG6CEomvlTfADD_80,971
7
7
  findly/unified_reporting_sdk/data_sources/common/entities.py,sha256=vz6V1KaZVqMpLghFOD-KaBGuTikt1rJFzfpkz53gBbU,243
8
8
  findly/unified_reporting_sdk/data_sources/common/reports_client.py,sha256=zvr6itv2MSV_O1zlhlgiHSWZNMyyjs-2OQG59aWMZLg,3628
@@ -22,12 +22,12 @@ findly/unified_reporting_sdk/data_sources/ga4/metadata/dimensions.jsonl,sha256=n
22
22
  findly/unified_reporting_sdk/data_sources/gsc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
23
  findly/unified_reporting_sdk/data_sources/gsc/gsc_client.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
24
  findly/unified_reporting_sdk/data_sources/gsc/gsc_service.py,sha256=C6wm38Hu-UozFll71G3b03e2hgLFiC4I5yjcuo9hB4M,934
25
- findly/unified_reporting_sdk/protos/.gitignore,sha256=jyvVCY11J1OlOGM-nZCWKSR1vfO6fP65lnH65qf5W20,27
25
+ findly/unified_reporting_sdk/protos/.gitignore,sha256=MtrjBS8zHuNNYo71NXCbMBJZpF33x1IsTTXc9Jhz8As,13
26
26
  findly/unified_reporting_sdk/protos/__init__.py,sha256=sfz7Yn3hvQrnhTfoZPGTbo0F1_Fw4X494wPSZojRajA,137
27
- findly/unified_reporting_sdk/protos/findly_semantic_layer_pb2.py,sha256=SaY46pOt8sDiVWrpY_f0uDwfgm_OPcHUkCdetnbPnUw,7279
28
- findly/unified_reporting_sdk/protos/findly_semantic_layer_pb2.pyi,sha256=jjoQm4TljpS8pcF6bqj21ygTQ-ayCzS3ScrRtbd5hPA,31043
27
+ findly/unified_reporting_sdk/protos/findly_semantic_layer_pb2.py,sha256=aVZGPhrYEKN8PExrm8GzAZJI6Yzip8XxfIaDJlh4R88,6925
28
+ findly/unified_reporting_sdk/protos/findly_semantic_layer_pb2.pyi,sha256=_07pudIa9mF-Gpkhnfjxq7s9lhCZxXpfGMPX6xqbfG4,31420
29
29
  findly/unified_reporting_sdk/urs.py,sha256=-vhOFpi-M0uo_tZ_O_hTDDEGO-ATf78nqEf5JhIcaz4,2956
30
- findly_unified_reporting_sdk-0.7.14.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
31
- findly_unified_reporting_sdk-0.7.14.dist-info/METADATA,sha256=0zNhdl6yBerd1pxBEOGD0qA-K67Hni8_yLi63-8brvo,3213
32
- findly_unified_reporting_sdk-0.7.14.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
33
- findly_unified_reporting_sdk-0.7.14.dist-info/RECORD,,
30
+ findly_unified_reporting_sdk-0.7.16.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
31
+ findly_unified_reporting_sdk-0.7.16.dist-info/METADATA,sha256=uQ4KrVzJmt9d3NFWLH9_Vul7rR1bjbpuTEbgRtJMTRc,3168
32
+ findly_unified_reporting_sdk-0.7.16.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
33
+ findly_unified_reporting_sdk-0.7.16.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 1.9.1
2
+ Generator: poetry-core 2.1.3
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any