pylegend 0.3.0__py3-none-any.whl → 0.4.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.
- pylegend/__init__.py +7 -5
- pylegend/core/{databse → database}/sql_to_string/__init__.py +3 -3
- pylegend/core/{databse → database}/sql_to_string/db_extension.py +11 -5
- pylegend/core/{databse → database}/sql_to_string/generator.py +2 -2
- pylegend/core/language/__init__.py +10 -10
- pylegend/core/language/legacy_api/__init__.py +13 -0
- pylegend/core/language/{aggregate_specification.py → legacy_api/aggregate_specification.py} +10 -10
- pylegend/core/language/legacy_api/legacy_api_tds_row.py +32 -0
- pylegend/core/language/legendql_api/__init__.py +13 -0
- pylegend/core/language/legendql_api/legendql_api_custom_expressions.py +541 -0
- pylegend/core/language/legendql_api/legendql_api_tds_row.py +292 -0
- pylegend/core/language/shared/__init__.py +13 -0
- pylegend/core/language/{column_expressions.py → shared/column_expressions.py} +32 -31
- pylegend/core/language/{expression.py → shared/expression.py} +8 -0
- pylegend/core/language/{functions.py → shared/functions.py} +3 -3
- pylegend/core/language/shared/helpers.py +75 -0
- pylegend/core/language/{literal_expressions.py → shared/literal_expressions.py} +39 -1
- pylegend/core/language/{operations → shared/operations}/binary_expression.py +34 -2
- pylegend/core/language/{operations → shared/operations}/boolean_operation_expressions.py +34 -6
- pylegend/core/language/{operations → shared/operations}/collection_operation_expressions.py +146 -26
- pylegend/core/language/{operations → shared/operations}/date_operation_expressions.py +164 -24
- pylegend/core/language/{operations → shared/operations}/float_operation_expressions.py +53 -8
- pylegend/core/language/{operations → shared/operations}/integer_operation_expressions.py +62 -9
- pylegend/core/language/{operations → shared/operations}/nullary_expression.py +9 -2
- pylegend/core/language/{operations → shared/operations}/number_operation_expressions.py +211 -30
- pylegend/core/language/{operations → shared/operations}/primitive_operation_expressions.py +42 -3
- pylegend/core/language/{operations → shared/operations}/string_operation_expressions.py +169 -21
- pylegend/core/language/{operations → shared/operations}/unary_expression.py +10 -2
- pylegend/core/language/{primitive_collection.py → shared/primitive_collection.py} +2 -2
- pylegend/core/language/{primitives → shared/primitives}/__init__.py +9 -9
- pylegend/core/language/{primitives → shared/primitives}/boolean.py +9 -5
- pylegend/core/language/{primitives → shared/primitives}/date.py +23 -15
- pylegend/core/language/{primitives → shared/primitives}/datetime.py +4 -5
- pylegend/core/language/{primitives → shared/primitives}/float.py +6 -6
- pylegend/core/language/{primitives → shared/primitives}/integer.py +6 -6
- pylegend/core/language/{primitives → shared/primitives}/number.py +16 -13
- pylegend/core/language/{primitives → shared/primitives}/primitive.py +25 -5
- pylegend/core/language/{primitives → shared/primitives}/strictdate.py +4 -5
- pylegend/core/language/{primitives → shared/primitives}/string.py +18 -19
- pylegend/core/language/{tds_row.py → shared/tds_row.py} +46 -16
- pylegend/core/request/__init__.py +7 -1
- pylegend/core/request/auth.py +55 -1
- pylegend/core/request/legend_client.py +32 -0
- pylegend/core/sql/metamodel_extension.py +16 -0
- pylegend/core/tds/abstract/__init__.py +13 -0
- pylegend/core/tds/abstract/frames/__init__.py +13 -0
- pylegend/core/tds/{legend_api/frames/legend_api_applied_function_tds_frame.py → abstract/frames/applied_function_tds_frame.py} +19 -13
- pylegend/core/tds/abstract/frames/base_tds_frame.py +125 -0
- pylegend/core/tds/{legend_api/frames/legend_api_input_tds_frame.py → abstract/frames/input_tds_frame.py} +9 -12
- pylegend/core/tds/{legend_api/frames/functions → abstract}/function_helpers.py +1 -1
- pylegend/core/tds/{legend_api/frames/functions/concatenate_function.py → legacy_api/frames/functions/legacy_api_concatenate_function.py} +25 -13
- pylegend/core/tds/{legend_api/frames/functions/distinct_function.py → legacy_api/frames/functions/legacy_api_distinct_function.py} +13 -8
- pylegend/core/tds/{legend_api/frames/functions/drop_function.py → legacy_api/frames/functions/legacy_api_drop_function.py} +13 -8
- pylegend/core/tds/{legend_api/frames/functions/extend_function.py → legacy_api/frames/functions/legacy_api_extend_function.py} +36 -16
- pylegend/core/tds/{legend_api/frames/functions/filter_function.py → legacy_api/frames/functions/legacy_api_filter_function.py} +25 -13
- pylegend/core/tds/{legend_api/frames/functions/group_by_function.py → legacy_api/frames/functions/legacy_api_group_by_function.py} +44 -17
- pylegend/core/tds/{legend_api/frames/functions/head_function.py → legacy_api/frames/functions/legacy_api_head_function.py} +13 -8
- pylegend/core/tds/{legend_api/frames/functions/join_by_columns_function.py → legacy_api/frames/functions/legacy_api_join_by_columns_function.py} +40 -13
- pylegend/core/tds/{legend_api/frames/functions/join_function.py → legacy_api/frames/functions/legacy_api_join_function.py} +44 -20
- pylegend/core/tds/{legend_api/frames/functions/rename_columns_function.py → legacy_api/frames/functions/legacy_api_rename_columns_function.py} +20 -8
- pylegend/core/tds/{legend_api/frames/functions/restrict_function.py → legacy_api/frames/functions/legacy_api_restrict_function.py} +17 -8
- pylegend/core/tds/{legend_api/frames/functions/slice_function.py → legacy_api/frames/functions/legacy_api_slice_function.py} +13 -8
- pylegend/core/tds/{legend_api/frames/functions/sort_function.py → legacy_api/frames/functions/legacy_api_sort_function.py} +19 -8
- pylegend/core/tds/legacy_api/frames/legacy_api_applied_function_tds_frame.py +37 -0
- pylegend/core/tds/legacy_api/frames/legacy_api_base_tds_frame.py +204 -0
- pylegend/core/tds/legacy_api/frames/legacy_api_input_tds_frame.py +51 -0
- pylegend/core/tds/{legend_api/frames/legend_api_tds_frame.py → legacy_api/frames/legacy_api_tds_frame.py} +28 -28
- pylegend/core/tds/legendql_api/__init__.py +13 -0
- pylegend/core/tds/legendql_api/frames/__init__.py +13 -0
- pylegend/core/tds/legendql_api/frames/functions/__init__.py +13 -0
- pylegend/core/tds/legendql_api/frames/functions/legendql_api_asofjoin_function.py +156 -0
- pylegend/core/tds/legendql_api/frames/functions/legendql_api_concatenate_function.py +139 -0
- pylegend/core/tds/legendql_api/frames/functions/legendql_api_distinct_function.py +69 -0
- pylegend/core/tds/legendql_api/frames/functions/legendql_api_drop_function.py +74 -0
- pylegend/core/tds/legendql_api/frames/functions/legendql_api_extend_function.py +256 -0
- pylegend/core/tds/legendql_api/frames/functions/legendql_api_filter_function.py +121 -0
- pylegend/core/tds/legendql_api/frames/functions/legendql_api_function_helpers.py +137 -0
- pylegend/core/tds/legendql_api/frames/functions/legendql_api_groupby_function.py +256 -0
- pylegend/core/tds/legendql_api/frames/functions/legendql_api_head_function.py +74 -0
- pylegend/core/tds/legendql_api/frames/functions/legendql_api_join_function.py +214 -0
- pylegend/core/tds/legendql_api/frames/functions/legendql_api_project_function.py +169 -0
- pylegend/core/tds/legendql_api/frames/functions/legendql_api_rename_function.py +189 -0
- pylegend/core/tds/legendql_api/frames/functions/legendql_api_select_function.py +131 -0
- pylegend/core/tds/legendql_api/frames/functions/legendql_api_slice_function.py +82 -0
- pylegend/core/tds/legendql_api/frames/functions/legendql_api_sort_function.py +93 -0
- pylegend/core/tds/legendql_api/frames/functions/legendql_api_window_extend_function.py +283 -0
- pylegend/core/tds/legendql_api/frames/legendql_api_applied_function_tds_frame.py +37 -0
- pylegend/core/tds/legendql_api/frames/legendql_api_base_tds_frame.py +419 -0
- pylegend/core/tds/legendql_api/frames/legendql_api_input_tds_frame.py +50 -0
- pylegend/core/tds/legendql_api/frames/legendql_api_tds_frame.py +327 -0
- pylegend/core/tds/pandas_api/frames/functions/assign_function.py +6 -6
- pylegend/core/tds/pandas_api/frames/pandas_api_applied_function_tds_frame.py +4 -0
- pylegend/core/tds/pandas_api/frames/pandas_api_base_tds_frame.py +11 -3
- pylegend/core/tds/pandas_api/frames/pandas_api_tds_frame.py +2 -2
- pylegend/core/tds/tds_frame.py +32 -2
- pylegend/extensions/database/vendors/postgres/postgres_sql_to_string.py +1 -1
- pylegend/extensions/tds/abstract/legend_function_input_frame.py +4 -0
- pylegend/extensions/tds/abstract/legend_service_input_frame.py +4 -0
- pylegend/extensions/tds/abstract/table_spec_input_frame.py +4 -0
- pylegend/extensions/tds/{legend_api/frames/legend_api_legend_function_input_frame.py → legacy_api/frames/legacy_api_legend_function_input_frame.py} +5 -5
- pylegend/extensions/tds/{legend_api/frames/legend_api_legend_service_input_frame.py → legacy_api/frames/legacy_api_legend_service_input_frame.py} +6 -6
- pylegend/extensions/tds/{legend_api/frames/legend_api_table_spec_input_frame.py → legacy_api/frames/legacy_api_table_spec_input_frame.py} +5 -5
- pylegend/extensions/tds/legendql_api/__init__.py +13 -0
- pylegend/extensions/tds/legendql_api/frames/__init__.py +13 -0
- pylegend/extensions/tds/legendql_api/frames/legendql_api_legend_service_input_frame.py +46 -0
- pylegend/extensions/tds/legendql_api/frames/legendql_api_table_spec_input_frame.py +36 -0
- pylegend/{legend_api_tds_client.py → legacy_api_tds_client.py} +15 -15
- {pylegend-0.3.0.dist-info → pylegend-0.4.0.dist-info}/METADATA +7 -8
- pylegend-0.4.0.dist-info/NOTICE +5 -0
- pylegend-0.4.0.dist-info/RECORD +155 -0
- {pylegend-0.3.0.dist-info → pylegend-0.4.0.dist-info}/WHEEL +1 -1
- pylegend/core/tds/legend_api/frames/legend_api_base_tds_frame.py +0 -294
- pylegend-0.3.0.dist-info/RECORD +0 -115
- /pylegend/core/{databse → database}/__init__.py +0 -0
- /pylegend/core/{databse → database}/sql_to_string/config.py +0 -0
- /pylegend/core/language/{operations → shared/operations}/__init__.py +0 -0
- /pylegend/core/tds/{legend_api → legacy_api}/__init__.py +0 -0
- /pylegend/core/tds/{legend_api → legacy_api}/frames/__init__.py +0 -0
- /pylegend/core/tds/{legend_api → legacy_api}/frames/functions/__init__.py +0 -0
- /pylegend/extensions/tds/{legend_api → legacy_api}/__init__.py +0 -0
- /pylegend/extensions/tds/{legend_api → legacy_api}/frames/__init__.py +0 -0
- {pylegend-0.3.0.dist-info → pylegend-0.4.0.dist-info}/LICENSE +0 -0
- {pylegend-0.3.0.dist-info → pylegend-0.4.0.dist-info}/LICENSE.spdx +0 -0
|
@@ -18,15 +18,15 @@ from pylegend._typing import (
|
|
|
18
18
|
PyLegendUnion,
|
|
19
19
|
TYPE_CHECKING,
|
|
20
20
|
)
|
|
21
|
-
from pylegend.core.language.primitives.number import PyLegendNumber
|
|
22
|
-
from pylegend.core.language.expression import PyLegendExpressionFloatReturn
|
|
23
|
-
from pylegend.core.language.literal_expressions import PyLegendFloatLiteralExpression
|
|
21
|
+
from pylegend.core.language.shared.primitives.number import PyLegendNumber
|
|
22
|
+
from pylegend.core.language.shared.expression import PyLegendExpressionFloatReturn
|
|
23
|
+
from pylegend.core.language.shared.literal_expressions import PyLegendFloatLiteralExpression
|
|
24
24
|
from pylegend.core.sql.metamodel import (
|
|
25
25
|
Expression,
|
|
26
26
|
QuerySpecification
|
|
27
27
|
)
|
|
28
28
|
from pylegend.core.tds.tds_frame import FrameToSqlConfig
|
|
29
|
-
from pylegend.core.language.operations.float_operation_expressions import (
|
|
29
|
+
from pylegend.core.language.shared.operations.float_operation_expressions import (
|
|
30
30
|
PyLegendFloatAbsoluteExpression,
|
|
31
31
|
PyLegendFloatAddExpression,
|
|
32
32
|
PyLegendFloatNegativeExpression,
|
|
@@ -34,7 +34,7 @@ from pylegend.core.language.operations.float_operation_expressions import (
|
|
|
34
34
|
PyLegendFloatMultiplyExpression,
|
|
35
35
|
)
|
|
36
36
|
if TYPE_CHECKING:
|
|
37
|
-
from pylegend.core.language.primitives import PyLegendInteger
|
|
37
|
+
from pylegend.core.language.shared.primitives import PyLegendInteger
|
|
38
38
|
|
|
39
39
|
__all__: PyLegendSequence[str] = [
|
|
40
40
|
"PyLegendFloat"
|
|
@@ -141,7 +141,7 @@ class PyLegendFloat(PyLegendNumber):
|
|
|
141
141
|
) -> Expression:
|
|
142
142
|
return super().to_sql_expression(frame_name_to_base_query_map, config)
|
|
143
143
|
|
|
144
|
-
def value(self) ->
|
|
144
|
+
def value(self) -> PyLegendExpressionFloatReturn:
|
|
145
145
|
return self.__value_copy
|
|
146
146
|
|
|
147
147
|
@staticmethod
|
|
@@ -18,15 +18,15 @@ from pylegend._typing import (
|
|
|
18
18
|
PyLegendUnion,
|
|
19
19
|
TYPE_CHECKING,
|
|
20
20
|
)
|
|
21
|
-
from pylegend.core.language.primitives.number import PyLegendNumber
|
|
22
|
-
from pylegend.core.language.expression import PyLegendExpressionIntegerReturn
|
|
23
|
-
from pylegend.core.language.literal_expressions import PyLegendIntegerLiteralExpression
|
|
21
|
+
from pylegend.core.language.shared.primitives.number import PyLegendNumber
|
|
22
|
+
from pylegend.core.language.shared.expression import PyLegendExpressionIntegerReturn
|
|
23
|
+
from pylegend.core.language.shared.literal_expressions import PyLegendIntegerLiteralExpression
|
|
24
24
|
from pylegend.core.sql.metamodel import (
|
|
25
25
|
Expression,
|
|
26
26
|
QuerySpecification
|
|
27
27
|
)
|
|
28
28
|
from pylegend.core.tds.tds_frame import FrameToSqlConfig
|
|
29
|
-
from pylegend.core.language.operations.integer_operation_expressions import (
|
|
29
|
+
from pylegend.core.language.shared.operations.integer_operation_expressions import (
|
|
30
30
|
PyLegendIntegerAddExpression,
|
|
31
31
|
PyLegendIntegerAbsoluteExpression,
|
|
32
32
|
PyLegendIntegerNegativeExpression,
|
|
@@ -35,7 +35,7 @@ from pylegend.core.language.operations.integer_operation_expressions import (
|
|
|
35
35
|
PyLegendIntegerModuloExpression,
|
|
36
36
|
)
|
|
37
37
|
if TYPE_CHECKING:
|
|
38
|
-
from pylegend.core.language.primitives import PyLegendFloat
|
|
38
|
+
from pylegend.core.language.shared.primitives import PyLegendFloat
|
|
39
39
|
|
|
40
40
|
__all__: PyLegendSequence[str] = [
|
|
41
41
|
"PyLegendInteger"
|
|
@@ -59,7 +59,7 @@ class PyLegendInteger(PyLegendNumber):
|
|
|
59
59
|
) -> Expression:
|
|
60
60
|
return super().to_sql_expression(frame_name_to_base_query_map, config)
|
|
61
61
|
|
|
62
|
-
def value(self) ->
|
|
62
|
+
def value(self) -> PyLegendExpressionIntegerReturn:
|
|
63
63
|
return self.__value_copy
|
|
64
64
|
|
|
65
65
|
def __add__(
|
|
@@ -19,17 +19,16 @@ from pylegend._typing import (
|
|
|
19
19
|
PyLegendOptional,
|
|
20
20
|
TYPE_CHECKING,
|
|
21
21
|
)
|
|
22
|
-
from pylegend.core.language.primitives.primitive import PyLegendPrimitive
|
|
23
|
-
from pylegend.core.language.primitives.boolean import PyLegendBoolean
|
|
24
|
-
from pylegend.core.language.expression import (
|
|
25
|
-
PyLegendExpression,
|
|
22
|
+
from pylegend.core.language.shared.primitives.primitive import PyLegendPrimitive
|
|
23
|
+
from pylegend.core.language.shared.primitives.boolean import PyLegendBoolean
|
|
24
|
+
from pylegend.core.language.shared.expression import (
|
|
26
25
|
PyLegendExpressionNumberReturn,
|
|
27
26
|
)
|
|
28
|
-
from pylegend.core.language.literal_expressions import (
|
|
27
|
+
from pylegend.core.language.shared.literal_expressions import (
|
|
29
28
|
PyLegendIntegerLiteralExpression,
|
|
30
29
|
PyLegendFloatLiteralExpression,
|
|
31
30
|
)
|
|
32
|
-
from pylegend.core.language.operations.number_operation_expressions import (
|
|
31
|
+
from pylegend.core.language.shared.operations.number_operation_expressions import (
|
|
33
32
|
PyLegendNumberAddExpression,
|
|
34
33
|
PyLegendNumberMultiplyExpression,
|
|
35
34
|
PyLegendNumberDivideExpression,
|
|
@@ -63,9 +62,10 @@ from pylegend.core.sql.metamodel import (
|
|
|
63
62
|
QuerySpecification
|
|
64
63
|
)
|
|
65
64
|
from pylegend.core.tds.tds_frame import FrameToSqlConfig
|
|
65
|
+
from pylegend.core.tds.tds_frame import FrameToPureConfig
|
|
66
66
|
if TYPE_CHECKING:
|
|
67
|
-
from pylegend.core.language.primitives.integer import PyLegendInteger
|
|
68
|
-
from pylegend.core.language.primitives.float import PyLegendFloat
|
|
67
|
+
from pylegend.core.language.shared.primitives.integer import PyLegendInteger
|
|
68
|
+
from pylegend.core.language.shared.primitives.float import PyLegendFloat
|
|
69
69
|
|
|
70
70
|
|
|
71
71
|
__all__: PyLegendSequence[str] = [
|
|
@@ -89,7 +89,10 @@ class PyLegendNumber(PyLegendPrimitive):
|
|
|
89
89
|
) -> Expression:
|
|
90
90
|
return self.__value.to_sql_expression(frame_name_to_base_query_map, config)
|
|
91
91
|
|
|
92
|
-
def
|
|
92
|
+
def to_pure_expression(self, config: FrameToPureConfig) -> str:
|
|
93
|
+
return self.__value.to_pure_expression(config)
|
|
94
|
+
|
|
95
|
+
def value(self) -> PyLegendExpressionNumberReturn:
|
|
93
96
|
return self.__value
|
|
94
97
|
|
|
95
98
|
def __add__(
|
|
@@ -214,14 +217,14 @@ class PyLegendNumber(PyLegendPrimitive):
|
|
|
214
217
|
return PyLegendNumber(PyLegendNumberPowerExpression(other_op, self.__value))
|
|
215
218
|
|
|
216
219
|
def ceil(self) -> "PyLegendInteger":
|
|
217
|
-
from pylegend.core.language.primitives.integer import PyLegendInteger
|
|
220
|
+
from pylegend.core.language.shared.primitives.integer import PyLegendInteger
|
|
218
221
|
return PyLegendInteger(PyLegendNumberCeilExpression(self.__value))
|
|
219
222
|
|
|
220
223
|
def __ceil__(self) -> "PyLegendInteger":
|
|
221
224
|
return self.ceil()
|
|
222
225
|
|
|
223
226
|
def floor(self) -> "PyLegendInteger":
|
|
224
|
-
from pylegend.core.language.primitives.integer import PyLegendInteger
|
|
227
|
+
from pylegend.core.language.shared.primitives.integer import PyLegendInteger
|
|
225
228
|
return PyLegendInteger(PyLegendNumberFloorExpression(self.__value))
|
|
226
229
|
|
|
227
230
|
def __floor__(self) -> "PyLegendInteger":
|
|
@@ -305,8 +308,8 @@ class PyLegendNumber(PyLegendPrimitive):
|
|
|
305
308
|
param: PyLegendUnion[int, float, "PyLegendInteger", "PyLegendFloat", "PyLegendNumber"],
|
|
306
309
|
desc: str
|
|
307
310
|
) -> None:
|
|
308
|
-
from pylegend.core.language.primitives.integer import PyLegendInteger
|
|
309
|
-
from pylegend.core.language.primitives.float import PyLegendFloat
|
|
311
|
+
from pylegend.core.language.shared.primitives.integer import PyLegendInteger
|
|
312
|
+
from pylegend.core.language.shared.primitives.float import PyLegendFloat
|
|
310
313
|
if not isinstance(param, (int, float, PyLegendInteger, PyLegendFloat, PyLegendNumber)):
|
|
311
314
|
raise TypeError(desc + " should be a int/float or a int/float/number expression"
|
|
312
315
|
" (PyLegendInteger/PyLegendFloat/PyLegendNumber)."
|
|
@@ -25,14 +25,16 @@ from pylegend.core.sql.metamodel import (
|
|
|
25
25
|
Expression,
|
|
26
26
|
QuerySpecification
|
|
27
27
|
)
|
|
28
|
-
from pylegend.core.language.expression import PyLegendExpression
|
|
29
|
-
from pylegend.core.language.literal_expressions import convert_literal_to_literal_expression
|
|
30
|
-
from pylegend.core.language.operations.primitive_operation_expressions import (
|
|
28
|
+
from pylegend.core.language.shared.expression import PyLegendExpression
|
|
29
|
+
from pylegend.core.language.shared.literal_expressions import convert_literal_to_literal_expression
|
|
30
|
+
from pylegend.core.language.shared.operations.primitive_operation_expressions import (
|
|
31
31
|
PyLegendPrimitiveEqualsExpression,
|
|
32
|
+
PyLegendPrimitiveNotEqualsExpression,
|
|
32
33
|
)
|
|
33
34
|
from pylegend.core.tds.tds_frame import FrameToSqlConfig
|
|
35
|
+
from pylegend.core.tds.tds_frame import FrameToPureConfig
|
|
34
36
|
if TYPE_CHECKING:
|
|
35
|
-
from pylegend.core.language.primitives.boolean import PyLegendBoolean
|
|
37
|
+
from pylegend.core.language.shared.primitives.boolean import PyLegendBoolean
|
|
36
38
|
|
|
37
39
|
__all__: PyLegendSequence[str] = [
|
|
38
40
|
"PyLegendPrimitive",
|
|
@@ -50,6 +52,10 @@ class PyLegendPrimitive(metaclass=ABCMeta):
|
|
|
50
52
|
) -> Expression:
|
|
51
53
|
pass
|
|
52
54
|
|
|
55
|
+
@abstractmethod
|
|
56
|
+
def to_pure_expression(self, config: FrameToPureConfig) -> str:
|
|
57
|
+
pass
|
|
58
|
+
|
|
53
59
|
def __eq__( # type: ignore
|
|
54
60
|
self,
|
|
55
61
|
other: "PyLegendUnion[int, float, bool, str, date, datetime, PyLegendPrimitive]"
|
|
@@ -61,9 +67,23 @@ class PyLegendPrimitive(metaclass=ABCMeta):
|
|
|
61
67
|
else:
|
|
62
68
|
other_op = other.value()
|
|
63
69
|
|
|
64
|
-
from pylegend.core.language.primitives.boolean import PyLegendBoolean
|
|
70
|
+
from pylegend.core.language.shared.primitives.boolean import PyLegendBoolean
|
|
65
71
|
return PyLegendBoolean(PyLegendPrimitiveEqualsExpression(self.value(), other_op))
|
|
66
72
|
|
|
73
|
+
def __ne__( # type: ignore
|
|
74
|
+
self,
|
|
75
|
+
other: "PyLegendUnion[int, float, bool, str, date, datetime, PyLegendPrimitive]"
|
|
76
|
+
) -> "PyLegendBoolean":
|
|
77
|
+
PyLegendPrimitive.__validate_param_to_be_primitive(other, "Not Equals (!=) parameter")
|
|
78
|
+
|
|
79
|
+
if isinstance(other, (int, float, bool, str, date, datetime)):
|
|
80
|
+
other_op = convert_literal_to_literal_expression(other)
|
|
81
|
+
else:
|
|
82
|
+
other_op = other.value()
|
|
83
|
+
|
|
84
|
+
from pylegend.core.language.shared.primitives.boolean import PyLegendBoolean
|
|
85
|
+
return PyLegendBoolean(PyLegendPrimitiveNotEqualsExpression(self.value(), other_op))
|
|
86
|
+
|
|
67
87
|
@staticmethod
|
|
68
88
|
def __validate_param_to_be_primitive(
|
|
69
89
|
param: "PyLegendUnion[int, float, bool, str, date, datetime, PyLegendPrimitive]",
|
|
@@ -18,12 +18,11 @@ from pylegend._typing import (
|
|
|
18
18
|
PyLegendDict,
|
|
19
19
|
PyLegendUnion,
|
|
20
20
|
)
|
|
21
|
-
from pylegend.core.language.primitives.date import PyLegendDate
|
|
22
|
-
from pylegend.core.language.expression import (
|
|
23
|
-
PyLegendExpression,
|
|
21
|
+
from pylegend.core.language.shared.primitives.date import PyLegendDate
|
|
22
|
+
from pylegend.core.language.shared.expression import (
|
|
24
23
|
PyLegendExpressionStrictDateReturn,
|
|
25
24
|
)
|
|
26
|
-
from pylegend.core.language.literal_expressions import (
|
|
25
|
+
from pylegend.core.language.shared.literal_expressions import (
|
|
27
26
|
PyLegendStrictDateLiteralExpression,
|
|
28
27
|
)
|
|
29
28
|
from pylegend.core.sql.metamodel import (
|
|
@@ -55,7 +54,7 @@ class PyLegendStrictDate(PyLegendDate):
|
|
|
55
54
|
) -> Expression:
|
|
56
55
|
return self.__value.to_sql_expression(frame_name_to_base_query_map, config)
|
|
57
56
|
|
|
58
|
-
def value(self) ->
|
|
57
|
+
def value(self) -> PyLegendExpressionStrictDateReturn:
|
|
59
58
|
return self.__value
|
|
60
59
|
|
|
61
60
|
@staticmethod
|
|
@@ -17,20 +17,23 @@ from pylegend._typing import (
|
|
|
17
17
|
PyLegendDict,
|
|
18
18
|
PyLegendUnion,
|
|
19
19
|
)
|
|
20
|
-
from pylegend.core.language.primitives.primitive import PyLegendPrimitive
|
|
21
|
-
from pylegend.core.language.primitives.integer import PyLegendInteger
|
|
22
|
-
from pylegend.core.language.primitives.float import PyLegendFloat
|
|
23
|
-
from pylegend.core.language.primitives.boolean import PyLegendBoolean
|
|
24
|
-
from pylegend.core.language.expression import PyLegendExpressionStringReturn
|
|
25
|
-
from pylegend.core.language.literal_expressions import PyLegendStringLiteralExpression
|
|
20
|
+
from pylegend.core.language.shared.primitives.primitive import PyLegendPrimitive
|
|
21
|
+
from pylegend.core.language.shared.primitives.integer import PyLegendInteger
|
|
22
|
+
from pylegend.core.language.shared.primitives.float import PyLegendFloat
|
|
23
|
+
from pylegend.core.language.shared.primitives.boolean import PyLegendBoolean
|
|
24
|
+
from pylegend.core.language.shared.expression import PyLegendExpressionStringReturn
|
|
25
|
+
from pylegend.core.language.shared.literal_expressions import PyLegendStringLiteralExpression
|
|
26
26
|
from pylegend.core.sql.metamodel import (
|
|
27
27
|
Expression,
|
|
28
28
|
QuerySpecification
|
|
29
29
|
)
|
|
30
30
|
from pylegend.core.tds.tds_frame import FrameToSqlConfig
|
|
31
|
-
from pylegend.core.
|
|
31
|
+
from pylegend.core.tds.tds_frame import FrameToPureConfig
|
|
32
|
+
from pylegend.core.language.shared.operations.string_operation_expressions import (
|
|
32
33
|
PyLegendStringLengthExpression,
|
|
33
|
-
|
|
34
|
+
PyLegendStringStartsWithExpression,
|
|
35
|
+
PyLegendStringEndsWithExpression,
|
|
36
|
+
PyLegendStringContainsExpression,
|
|
34
37
|
PyLegendStringUpperExpression,
|
|
35
38
|
PyLegendStringLowerExpression,
|
|
36
39
|
PyLegendStringLTrimExpression,
|
|
@@ -69,23 +72,20 @@ class PyLegendString(PyLegendPrimitive):
|
|
|
69
72
|
|
|
70
73
|
def startswith(self, prefix: str) -> PyLegendBoolean:
|
|
71
74
|
PyLegendString.__validate_param_to_be_str(prefix, "startswith prefix parameter")
|
|
72
|
-
escaped_prefix = PyLegendString.__escape_like_param(prefix)
|
|
73
75
|
return PyLegendBoolean(
|
|
74
|
-
|
|
76
|
+
PyLegendStringStartsWithExpression(self.__value, PyLegendStringLiteralExpression(prefix))
|
|
75
77
|
)
|
|
76
78
|
|
|
77
79
|
def endswith(self, suffix: str) -> PyLegendBoolean:
|
|
78
80
|
PyLegendString.__validate_param_to_be_str(suffix, "endswith suffix parameter")
|
|
79
|
-
escaped_suffix = PyLegendString.__escape_like_param(suffix)
|
|
80
81
|
return PyLegendBoolean(
|
|
81
|
-
|
|
82
|
+
PyLegendStringEndsWithExpression(self.__value, PyLegendStringLiteralExpression(suffix))
|
|
82
83
|
)
|
|
83
84
|
|
|
84
85
|
def contains(self, other: str) -> PyLegendBoolean:
|
|
85
86
|
PyLegendString.__validate_param_to_be_str(other, "contains/in other parameter")
|
|
86
|
-
escaped_other = PyLegendString.__escape_like_param(other)
|
|
87
87
|
return PyLegendBoolean(
|
|
88
|
-
|
|
88
|
+
PyLegendStringContainsExpression(self.__value, PyLegendStringLiteralExpression(other))
|
|
89
89
|
)
|
|
90
90
|
|
|
91
91
|
def upper(self) -> "PyLegendString":
|
|
@@ -157,12 +157,11 @@ class PyLegendString(PyLegendPrimitive):
|
|
|
157
157
|
) -> Expression:
|
|
158
158
|
return self.__value.to_sql_expression(frame_name_to_base_query_map, config)
|
|
159
159
|
|
|
160
|
-
def
|
|
161
|
-
return self.__value
|
|
160
|
+
def to_pure_expression(self, config: FrameToPureConfig) -> str:
|
|
161
|
+
return self.__value.to_pure_expression(config)
|
|
162
162
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
return param.replace("_", "\\_").replace("%", "\\%")
|
|
163
|
+
def value(self) -> PyLegendExpressionStringReturn:
|
|
164
|
+
return self.__value
|
|
166
165
|
|
|
167
166
|
@staticmethod
|
|
168
167
|
def __validate_param_to_be_str_or_str_expr(param: PyLegendUnion[str, "PyLegendString"], desc: str) -> None:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright
|
|
1
|
+
# Copyright 2025 Goldman Sachs
|
|
2
2
|
#
|
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
# you may not use this file except in compliance with the License.
|
|
@@ -12,10 +12,21 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
+
from abc import ABCMeta
|
|
15
16
|
from pylegend._typing import (
|
|
16
17
|
PyLegendSequence,
|
|
18
|
+
PyLegendDict,
|
|
19
|
+
)
|
|
20
|
+
from pylegend.core.sql.metamodel import (
|
|
21
|
+
QuerySpecification,
|
|
22
|
+
Expression,
|
|
23
|
+
SingleColumn,
|
|
24
|
+
)
|
|
25
|
+
from pylegend.core.tds.tds_frame import (
|
|
26
|
+
PyLegendTdsFrame,
|
|
27
|
+
FrameToPureConfig,
|
|
28
|
+
FrameToSqlConfig,
|
|
17
29
|
)
|
|
18
|
-
from pylegend.core.tds.tds_frame import PyLegendTdsFrame
|
|
19
30
|
from pylegend.core.tds.tds_column import TdsColumn, PrimitiveTdsColumn
|
|
20
31
|
from pylegend.core.language import (
|
|
21
32
|
PyLegendColumnExpression,
|
|
@@ -39,11 +50,11 @@ from pylegend.core.language import (
|
|
|
39
50
|
)
|
|
40
51
|
|
|
41
52
|
__all__: PyLegendSequence[str] = [
|
|
42
|
-
"
|
|
53
|
+
"AbstractTdsRow",
|
|
43
54
|
]
|
|
44
55
|
|
|
45
56
|
|
|
46
|
-
class
|
|
57
|
+
class AbstractTdsRow(metaclass=ABCMeta):
|
|
47
58
|
__frame_name: str
|
|
48
59
|
__columns: PyLegendSequence[TdsColumn]
|
|
49
60
|
|
|
@@ -51,10 +62,6 @@ class TdsRow:
|
|
|
51
62
|
self.__frame_name = frame_name
|
|
52
63
|
self.__columns = frame.columns()
|
|
53
64
|
|
|
54
|
-
@staticmethod
|
|
55
|
-
def from_tds_frame(frame_name: str, frame: PyLegendTdsFrame) -> "TdsRow":
|
|
56
|
-
return TdsRow(frame_name=frame_name, frame=frame)
|
|
57
|
-
|
|
58
65
|
def get_boolean(self, column: str) -> PyLegendBoolean:
|
|
59
66
|
col_expr = self.__get_col(column)
|
|
60
67
|
if not isinstance(col_expr, PyLegendBooleanColumnExpression):
|
|
@@ -161,21 +168,21 @@ class TdsRow:
|
|
|
161
168
|
if base_col.get_name() == column:
|
|
162
169
|
if isinstance(base_col, PrimitiveTdsColumn):
|
|
163
170
|
if base_col.get_type() == "Boolean":
|
|
164
|
-
return PyLegendBooleanColumnExpression(self
|
|
171
|
+
return PyLegendBooleanColumnExpression(self, column)
|
|
165
172
|
if base_col.get_type() == "String":
|
|
166
|
-
return PyLegendStringColumnExpression(self
|
|
173
|
+
return PyLegendStringColumnExpression(self, column)
|
|
167
174
|
if base_col.get_type() == "Number":
|
|
168
|
-
return PyLegendNumberColumnExpression(self
|
|
175
|
+
return PyLegendNumberColumnExpression(self, column)
|
|
169
176
|
if base_col.get_type() == "Integer":
|
|
170
|
-
return PyLegendIntegerColumnExpression(self
|
|
177
|
+
return PyLegendIntegerColumnExpression(self, column)
|
|
171
178
|
if base_col.get_type() == "Float":
|
|
172
|
-
return PyLegendFloatColumnExpression(self
|
|
179
|
+
return PyLegendFloatColumnExpression(self, column)
|
|
173
180
|
if base_col.get_type() == "Date":
|
|
174
|
-
return PyLegendDateColumnExpression(self
|
|
181
|
+
return PyLegendDateColumnExpression(self, column)
|
|
175
182
|
if base_col.get_type() == "DateTime":
|
|
176
|
-
return PyLegendDateTimeColumnExpression(self
|
|
183
|
+
return PyLegendDateTimeColumnExpression(self, column)
|
|
177
184
|
if base_col.get_type() == "StrictDate":
|
|
178
|
-
return PyLegendStrictDateColumnExpression(self
|
|
185
|
+
return PyLegendStrictDateColumnExpression(self, column)
|
|
179
186
|
|
|
180
187
|
raise RuntimeError(f"Column '{column}' of type {base_col.get_type()} not supported yet")
|
|
181
188
|
|
|
@@ -183,3 +190,26 @@ class TdsRow:
|
|
|
183
190
|
f"Column - '{column}' doesn't exist in the current frame. "
|
|
184
191
|
f"Current frame columns: {[x.get_name() for x in self.__columns]}"
|
|
185
192
|
)
|
|
193
|
+
|
|
194
|
+
def get_frame_name(self) -> str:
|
|
195
|
+
return self.__frame_name
|
|
196
|
+
|
|
197
|
+
def to_pure_expression(self, config: FrameToPureConfig) -> str:
|
|
198
|
+
return f"${self.__frame_name}"
|
|
199
|
+
|
|
200
|
+
def column_sql_expression(
|
|
201
|
+
self,
|
|
202
|
+
column: str,
|
|
203
|
+
frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
|
|
204
|
+
config: FrameToSqlConfig
|
|
205
|
+
) -> Expression:
|
|
206
|
+
query = frame_name_to_base_query_map[self.__frame_name]
|
|
207
|
+
db_extension = config.sql_to_string_generator().get_db_extension()
|
|
208
|
+
filtered = [
|
|
209
|
+
s for s in query.select.selectItems
|
|
210
|
+
if (isinstance(s, SingleColumn) and
|
|
211
|
+
s.alias == db_extension.quote_identifier(column))
|
|
212
|
+
]
|
|
213
|
+
if len(filtered) == 0:
|
|
214
|
+
raise RuntimeError("Cannot find column: " + column) # pragma: no cover
|
|
215
|
+
return filtered[0].expression
|
|
@@ -16,7 +16,12 @@ from pylegend._typing import (
|
|
|
16
16
|
PyLegendSequence,
|
|
17
17
|
)
|
|
18
18
|
from pylegend.core.request.legend_client import LegendClient
|
|
19
|
-
from pylegend.core.request.auth import
|
|
19
|
+
from pylegend.core.request.auth import (
|
|
20
|
+
AuthScheme,
|
|
21
|
+
LocalhostEmptyAuthScheme,
|
|
22
|
+
HeaderTokenAuthScheme,
|
|
23
|
+
CookieAuthScheme,
|
|
24
|
+
)
|
|
20
25
|
from pylegend.core.request.response_reader import ResponseReader
|
|
21
26
|
|
|
22
27
|
__all__: PyLegendSequence[str] = [
|
|
@@ -25,6 +30,7 @@ __all__: PyLegendSequence[str] = [
|
|
|
25
30
|
"AuthScheme",
|
|
26
31
|
"LocalhostEmptyAuthScheme",
|
|
27
32
|
"HeaderTokenAuthScheme",
|
|
33
|
+
"CookieAuthScheme",
|
|
28
34
|
|
|
29
35
|
"ResponseReader"
|
|
30
36
|
]
|
pylegend/core/request/auth.py
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
from abc import ABCMeta, abstractmethod
|
|
16
16
|
|
|
17
17
|
from requests import PreparedRequest
|
|
18
|
+
from requests.cookies import create_cookie
|
|
18
19
|
|
|
19
20
|
from pylegend._typing import (
|
|
20
21
|
PyLegendSequence,
|
|
@@ -27,7 +28,8 @@ from requests.auth import AuthBase
|
|
|
27
28
|
__all__: PyLegendSequence[str] = [
|
|
28
29
|
"AuthScheme",
|
|
29
30
|
"LocalhostEmptyAuthScheme",
|
|
30
|
-
"HeaderTokenAuthScheme"
|
|
31
|
+
"HeaderTokenAuthScheme",
|
|
32
|
+
"CookieAuthScheme",
|
|
31
33
|
]
|
|
32
34
|
|
|
33
35
|
|
|
@@ -83,3 +85,55 @@ class HeaderTokenAuthScheme(AuthScheme):
|
|
|
83
85
|
|
|
84
86
|
def get_auth_base(self) -> PyLegendOptional[AuthBase]:
|
|
85
87
|
return HeaderTokenAuth(self.__header_name, self.__token_provider, self.__query_params)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class CookieAuth(AuthBase):
|
|
91
|
+
__cookie_name: str
|
|
92
|
+
__cookie_provider: PyLegendCallable[[], str]
|
|
93
|
+
__query_params: PyLegendOptional[PyLegendDict[str, str]]
|
|
94
|
+
|
|
95
|
+
def __init__( # type: ignore
|
|
96
|
+
self,
|
|
97
|
+
cookie_name: str,
|
|
98
|
+
cookie_provider: PyLegendCallable[[], str],
|
|
99
|
+
query_params: PyLegendOptional[PyLegendDict[str, str]] = None,
|
|
100
|
+
**extra_cookie_params
|
|
101
|
+
) -> None:
|
|
102
|
+
self.__cookie_name = cookie_name
|
|
103
|
+
self.__cookie_provider = cookie_provider
|
|
104
|
+
self.__query_params = query_params
|
|
105
|
+
self.__extra_cookie_params = extra_cookie_params
|
|
106
|
+
|
|
107
|
+
def __call__(self, r: PreparedRequest) -> PreparedRequest:
|
|
108
|
+
if self.__query_params:
|
|
109
|
+
r.prepare_url(r.url, self.__query_params)
|
|
110
|
+
r.headers.pop("Cookie", None)
|
|
111
|
+
new_cookie = create_cookie( # type: ignore
|
|
112
|
+
name=self.__cookie_name,
|
|
113
|
+
value=self.__cookie_provider(),
|
|
114
|
+
**self.__extra_cookie_params
|
|
115
|
+
)
|
|
116
|
+
r._cookies.set_cookie(new_cookie) # type: ignore
|
|
117
|
+
r.prepare_cookies(r._cookies) # type: ignore
|
|
118
|
+
return r
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class CookieAuthScheme(AuthScheme):
|
|
122
|
+
__cookie_name: str
|
|
123
|
+
__cookie_provider: PyLegendCallable[[], str]
|
|
124
|
+
__query_params: PyLegendOptional[PyLegendDict[str, str]]
|
|
125
|
+
|
|
126
|
+
def __init__( # type: ignore
|
|
127
|
+
self,
|
|
128
|
+
cookie_name: str,
|
|
129
|
+
cookie_provider: PyLegendCallable[[], str],
|
|
130
|
+
query_params: PyLegendOptional[PyLegendDict[str, str]] = None,
|
|
131
|
+
**extra_cookie_params
|
|
132
|
+
) -> None:
|
|
133
|
+
self.__cookie_name = cookie_name
|
|
134
|
+
self.__cookie_provider = cookie_provider
|
|
135
|
+
self.__query_params = query_params
|
|
136
|
+
self.__extra_cookie_params = extra_cookie_params
|
|
137
|
+
|
|
138
|
+
def get_auth_base(self) -> PyLegendOptional[AuthBase]:
|
|
139
|
+
return CookieAuth(self.__cookie_name, self.__cookie_provider, self.__query_params, **self.__extra_cookie_params)
|
|
@@ -77,6 +77,38 @@ class LegendClient(ServiceClient):
|
|
|
77
77
|
).iter_content(chunk_size=chunk_size)
|
|
78
78
|
return ResponseReader(iter_content)
|
|
79
79
|
|
|
80
|
+
def parse_model(
|
|
81
|
+
self,
|
|
82
|
+
model_code: str,
|
|
83
|
+
return_source_information: bool = False
|
|
84
|
+
) -> str:
|
|
85
|
+
response = super()._execute_service(
|
|
86
|
+
method=RequestMethod.POST,
|
|
87
|
+
path="pure/v1/grammar/grammarToJson/model",
|
|
88
|
+
data=model_code,
|
|
89
|
+
headers={"Content-Type": "text/plain"},
|
|
90
|
+
query_params=[("returnSourceInformation", "true" if return_source_information else "false")]
|
|
91
|
+
)
|
|
92
|
+
return response.text
|
|
93
|
+
|
|
94
|
+
def compile_model(
|
|
95
|
+
self,
|
|
96
|
+
model_json: str
|
|
97
|
+
) -> None:
|
|
98
|
+
super()._execute_service(
|
|
99
|
+
method=RequestMethod.POST,
|
|
100
|
+
path="pure/v1/compilation/compile",
|
|
101
|
+
data=model_json,
|
|
102
|
+
headers={"Content-Type": "application/json"}
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
def parse_and_compile_model(
|
|
106
|
+
self,
|
|
107
|
+
model_code: str
|
|
108
|
+
) -> None:
|
|
109
|
+
parse_response = self.parse_model(model_code)
|
|
110
|
+
self.compile_model(parse_response)
|
|
111
|
+
|
|
80
112
|
def __eq__(self, other: 'object') -> bool:
|
|
81
113
|
if self is other:
|
|
82
114
|
return True
|
|
@@ -19,6 +19,7 @@ from pylegend._typing import (
|
|
|
19
19
|
)
|
|
20
20
|
from pylegend.core.sql.metamodel import (
|
|
21
21
|
Expression,
|
|
22
|
+
Window,
|
|
22
23
|
)
|
|
23
24
|
|
|
24
25
|
__all__: PyLegendSequence[str] = [
|
|
@@ -78,6 +79,7 @@ __all__: PyLegendSequence[str] = [
|
|
|
78
79
|
"MinuteExpression",
|
|
79
80
|
"SecondExpression",
|
|
80
81
|
"EpochExpression",
|
|
82
|
+
"WindowExpression",
|
|
81
83
|
]
|
|
82
84
|
|
|
83
85
|
|
|
@@ -717,3 +719,17 @@ class EpochExpression(Expression):
|
|
|
717
719
|
) -> None:
|
|
718
720
|
super().__init__(_type="epochExpression")
|
|
719
721
|
self.value = value
|
|
722
|
+
|
|
723
|
+
|
|
724
|
+
class WindowExpression(Expression):
|
|
725
|
+
nested: "Expression"
|
|
726
|
+
window: "Window"
|
|
727
|
+
|
|
728
|
+
def __init__(
|
|
729
|
+
self,
|
|
730
|
+
nested: "Expression",
|
|
731
|
+
window: "Window",
|
|
732
|
+
) -> None:
|
|
733
|
+
super().__init__(_type="windowExpression")
|
|
734
|
+
self.nested = nested
|
|
735
|
+
self.window = window
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Copyright 2025 Goldman Sachs
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Copyright 2025 Goldman Sachs
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|