pylegend 0.8.0__py3-none-any.whl → 0.10.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.
Files changed (36) hide show
  1. pylegend/_typing.py +6 -0
  2. pylegend/core/database/sql_to_string/db_extension.py +35 -6
  3. pylegend/core/language/pandas_api/__init__.py +13 -0
  4. pylegend/core/language/pandas_api/pandas_api_aggregate_specification.py +54 -0
  5. pylegend/core/language/pandas_api/pandas_api_custom_expressions.py +85 -0
  6. pylegend/core/language/pandas_api/pandas_api_series.py +174 -0
  7. pylegend/core/language/pandas_api/pandas_api_tds_row.py +74 -0
  8. pylegend/core/language/shared/functions.py +7 -0
  9. pylegend/core/language/shared/operations/integer_operation_expressions.py +42 -1
  10. pylegend/core/language/shared/operations/nary_expression.py +104 -0
  11. pylegend/core/language/shared/operations/number_operation_expressions.py +264 -0
  12. pylegend/core/language/shared/operations/primitive_operation_expressions.py +30 -0
  13. pylegend/core/language/shared/operations/string_operation_expressions.py +624 -1
  14. pylegend/core/language/shared/primitives/integer.py +6 -0
  15. pylegend/core/language/shared/primitives/number.py +28 -0
  16. pylegend/core/language/shared/primitives/primitive.py +6 -0
  17. pylegend/core/language/shared/primitives/string.py +129 -1
  18. pylegend/core/sql/metamodel.py +3 -1
  19. pylegend/core/sql/metamodel_extension.py +18 -0
  20. pylegend/core/tds/pandas_api/frames/functions/aggregate_function.py +316 -0
  21. pylegend/core/tds/pandas_api/frames/functions/assign_function.py +20 -15
  22. pylegend/core/tds/pandas_api/frames/functions/drop.py +171 -0
  23. pylegend/core/tds/pandas_api/frames/functions/filter.py +193 -0
  24. pylegend/core/tds/pandas_api/frames/functions/filtering.py +85 -0
  25. pylegend/core/tds/pandas_api/frames/functions/sort_values_function.py +189 -0
  26. pylegend/core/tds/pandas_api/frames/functions/truncate_function.py +120 -0
  27. pylegend/core/tds/pandas_api/frames/pandas_api_applied_function_tds_frame.py +5 -1
  28. pylegend/core/tds/pandas_api/frames/pandas_api_base_tds_frame.py +204 -7
  29. pylegend/core/tds/pandas_api/frames/pandas_api_input_tds_frame.py +5 -3
  30. pylegend/core/tds/pandas_api/frames/pandas_api_tds_frame.py +90 -3
  31. {pylegend-0.8.0.dist-info → pylegend-0.10.0.dist-info}/METADATA +1 -1
  32. {pylegend-0.8.0.dist-info → pylegend-0.10.0.dist-info}/RECORD +36 -24
  33. {pylegend-0.8.0.dist-info → pylegend-0.10.0.dist-info}/WHEEL +0 -0
  34. {pylegend-0.8.0.dist-info → pylegend-0.10.0.dist-info}/licenses/LICENSE +0 -0
  35. {pylegend-0.8.0.dist-info → pylegend-0.10.0.dist-info}/licenses/LICENSE.spdx +0 -0
  36. {pylegend-0.8.0.dist-info → pylegend-0.10.0.dist-info}/licenses/NOTICE +0 -0
@@ -0,0 +1,104 @@
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.
14
+
15
+ from abc import ABCMeta
16
+ from pylegend._typing import (
17
+ PyLegendSequence,
18
+ PyLegendDict,
19
+ PyLegendCallable,
20
+ PyLegendList,
21
+ PyLegendOptional
22
+ )
23
+ from pylegend.core.language.shared.expression import (
24
+ PyLegendExpression,
25
+ )
26
+ from pylegend.core.language.shared.helpers import expr_has_matching_start_and_end_parentheses
27
+ from pylegend.core.sql.metamodel import (
28
+ Expression,
29
+ QuerySpecification,
30
+ )
31
+ from pylegend.core.tds.tds_frame import FrameToSqlConfig
32
+ from pylegend.core.tds.tds_frame import FrameToPureConfig
33
+
34
+ __all__: PyLegendSequence[str] = [
35
+ "PyLegendNaryExpression"
36
+ ]
37
+
38
+
39
+ class PyLegendNaryExpression(PyLegendExpression, metaclass=ABCMeta):
40
+ __operands: PyLegendList[PyLegendExpression]
41
+ __to_sql_func: PyLegendCallable[
42
+ [PyLegendList[Expression], PyLegendDict[str, QuerySpecification], FrameToSqlConfig],
43
+ Expression
44
+ ]
45
+ __to_pure_func: PyLegendCallable[
46
+ [PyLegendList[str], FrameToPureConfig],
47
+ str
48
+ ]
49
+ __non_nullable: bool
50
+ __operands_non_nullable_flags: PyLegendList[bool]
51
+
52
+ def __init__(
53
+ self,
54
+ operands: PyLegendList[PyLegendExpression],
55
+ to_sql_func: PyLegendCallable[
56
+ [PyLegendList[Expression], PyLegendDict[str, QuerySpecification], FrameToSqlConfig],
57
+ Expression
58
+ ],
59
+ to_pure_func: PyLegendCallable[
60
+ [PyLegendList[str], FrameToPureConfig],
61
+ str
62
+ ],
63
+ non_nullable: bool = False,
64
+ operands_non_nullable_flags: PyLegendOptional[PyLegendList[bool]] = None
65
+ ) -> None:
66
+ self.__operands = operands
67
+ self.__to_sql_func = to_sql_func
68
+ self.__to_pure_func = to_pure_func
69
+ self.__non_nullable = non_nullable
70
+ self.__operands_non_nullable_flags = (
71
+ operands_non_nullable_flags
72
+ if operands_non_nullable_flags is not None
73
+ else [False] * len(operands)
74
+ )
75
+
76
+ def to_sql_expression(
77
+ self,
78
+ frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
79
+ config: FrameToSqlConfig
80
+ ) -> Expression:
81
+ sql_operands = [
82
+ operand.to_sql_expression(frame_name_to_base_query_map, config)
83
+ for operand in self.__operands
84
+ ]
85
+ return self.__to_sql_func(sql_operands, frame_name_to_base_query_map, config)
86
+
87
+ def to_pure_expression(self, config: FrameToPureConfig) -> str:
88
+ pure_operands: PyLegendList[str] = []
89
+
90
+ for operand, must_be_non_nullable in zip(self.__operands, self.__operands_non_nullable_flags):
91
+ expr = operand.to_pure_expression(config)
92
+
93
+ if must_be_non_nullable:
94
+ expr = (
95
+ expr if operand.is_non_nullable() else
96
+ f"toOne({expr[1:-1] if expr_has_matching_start_and_end_parentheses(expr) else expr})"
97
+ )
98
+
99
+ pure_operands.append(expr)
100
+
101
+ return self.__to_pure_func(pure_operands, config)
102
+
103
+ def is_non_nullable(self) -> bool:
104
+ return self.__non_nullable
@@ -22,6 +22,7 @@ from pylegend.core.language.shared.expression import (
22
22
  PyLegendExpressionBooleanReturn,
23
23
  )
24
24
  from pylegend.core.language.shared.operations.binary_expression import PyLegendBinaryExpression
25
+ from pylegend.core.language.shared.operations.nullary_expression import PyLegendNullaryExpression
25
26
  from pylegend.core.language.shared.operations.unary_expression import PyLegendUnaryExpression
26
27
  from pylegend.core.language.shared.helpers import generate_pure_functional_call
27
28
  from pylegend.core.tds.tds_frame import FrameToSqlConfig
@@ -34,6 +35,8 @@ from pylegend.core.sql.metamodel import (
34
35
  ComparisonOperator,
35
36
  ComparisonExpression,
36
37
  NegativeExpression,
38
+ FunctionCall,
39
+ QualifiedName
37
40
  )
38
41
  from pylegend.core.sql.metamodel_extension import (
39
42
  AbsoluteExpression,
@@ -85,6 +88,14 @@ __all__: PyLegendSequence[str] = [
85
88
  "PyLegendNumberArcTanExpression",
86
89
  "PyLegendNumberArcTan2Expression",
87
90
  "PyLegendNumberCotExpression",
91
+ "PyLegendNumberLog10Expression",
92
+ "PyLegendNumberDegreesExpression",
93
+ "PyLegendNumberRadiansExpression",
94
+ "PyLegendNumberSignExpression",
95
+ "PyLegendNumberHyperbolicSinExpression",
96
+ "PyLegendNumberHyperbolicCosExpression",
97
+ "PyLegendNumberHyperbolicTanExpression",
98
+ "PyLegendNumberPiExpression"
88
99
  ]
89
100
 
90
101
 
@@ -821,3 +832,256 @@ class PyLegendNumberCotExpression(PyLegendUnaryExpression, PyLegendExpressionNum
821
832
  non_nullable=True,
822
833
  operand_needs_to_be_non_nullable=True,
823
834
  )
835
+
836
+
837
+ class PyLegendNumberLog10Expression(PyLegendUnaryExpression, PyLegendExpressionNumberReturn):
838
+
839
+ @staticmethod
840
+ def __to_sql_func(
841
+ expression: Expression,
842
+ frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
843
+ config: FrameToSqlConfig
844
+ ) -> Expression:
845
+ return FunctionCall(
846
+ name=QualifiedName(parts=["LOG10"]),
847
+ distinct=False,
848
+ arguments=[expression],
849
+ filter_=None,
850
+ window=None
851
+ )
852
+
853
+ @staticmethod
854
+ def __to_pure_func(op_expr: str, config: FrameToPureConfig) -> str:
855
+ return generate_pure_functional_call("log10", [op_expr])
856
+
857
+ def __init__(self, operand: PyLegendExpressionNumberReturn) -> None:
858
+ PyLegendExpressionNumberReturn.__init__(self)
859
+ PyLegendUnaryExpression.__init__(
860
+ self,
861
+ operand,
862
+ PyLegendNumberLog10Expression.__to_sql_func,
863
+ PyLegendNumberLog10Expression.__to_pure_func,
864
+ non_nullable=True,
865
+ operand_needs_to_be_non_nullable=True,
866
+ )
867
+
868
+
869
+ class PyLegendNumberDegreesExpression(PyLegendUnaryExpression, PyLegendExpressionNumberReturn):
870
+
871
+ @staticmethod
872
+ def __to_sql_func(
873
+ expression: Expression,
874
+ frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
875
+ config: FrameToSqlConfig
876
+ ) -> Expression:
877
+ return FunctionCall(
878
+ name=QualifiedName(parts=["DEGREES"]),
879
+ distinct=False,
880
+ arguments=[expression],
881
+ filter_=None,
882
+ window=None
883
+ )
884
+
885
+ @staticmethod
886
+ def __to_pure_func(op_expr: str, config: FrameToPureConfig) -> str:
887
+ return generate_pure_functional_call("toDegrees", [op_expr])
888
+
889
+ def __init__(self, operand: PyLegendExpressionNumberReturn) -> None:
890
+ PyLegendExpressionNumberReturn.__init__(self)
891
+ PyLegendUnaryExpression.__init__(
892
+ self,
893
+ operand,
894
+ PyLegendNumberDegreesExpression.__to_sql_func,
895
+ PyLegendNumberDegreesExpression.__to_pure_func,
896
+ non_nullable=True,
897
+ operand_needs_to_be_non_nullable=True,
898
+ )
899
+
900
+
901
+ class PyLegendNumberRadiansExpression(PyLegendUnaryExpression, PyLegendExpressionNumberReturn):
902
+
903
+ @staticmethod
904
+ def __to_sql_func(
905
+ expression: Expression,
906
+ frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
907
+ config: FrameToSqlConfig
908
+ ) -> Expression:
909
+ return FunctionCall(
910
+ name=QualifiedName(parts=["RADIANS"]),
911
+ distinct=False,
912
+ arguments=[expression],
913
+ filter_=None,
914
+ window=None
915
+ )
916
+
917
+ @staticmethod
918
+ def __to_pure_func(op_expr: str, config: FrameToPureConfig) -> str:
919
+ return generate_pure_functional_call("toRadians", [op_expr])
920
+
921
+ def __init__(self, operand: PyLegendExpressionNumberReturn) -> None:
922
+ PyLegendExpressionNumberReturn.__init__(self)
923
+ PyLegendUnaryExpression.__init__(
924
+ self,
925
+ operand,
926
+ PyLegendNumberRadiansExpression.__to_sql_func,
927
+ PyLegendNumberRadiansExpression.__to_pure_func,
928
+ non_nullable=True,
929
+ operand_needs_to_be_non_nullable=True,
930
+ )
931
+
932
+
933
+ class PyLegendNumberSignExpression(PyLegendUnaryExpression, PyLegendExpressionNumberReturn):
934
+
935
+ @staticmethod
936
+ def __to_sql_func(
937
+ expression: Expression,
938
+ frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
939
+ config: FrameToSqlConfig
940
+ ) -> Expression:
941
+ return FunctionCall(
942
+ name=QualifiedName(parts=["SIGN"]),
943
+ distinct=False,
944
+ arguments=[expression],
945
+ filter_=None,
946
+ window=None
947
+ )
948
+
949
+ @staticmethod
950
+ def __to_pure_func(op_expr: str, config: FrameToPureConfig) -> str:
951
+ return generate_pure_functional_call("sign", [op_expr])
952
+
953
+ def __init__(self, operand: PyLegendExpressionNumberReturn) -> None:
954
+ PyLegendExpressionNumberReturn.__init__(self)
955
+ PyLegendUnaryExpression.__init__(
956
+ self,
957
+ operand,
958
+ PyLegendNumberSignExpression.__to_sql_func,
959
+ PyLegendNumberSignExpression.__to_pure_func,
960
+ non_nullable=True,
961
+ operand_needs_to_be_non_nullable=True,
962
+ )
963
+
964
+
965
+ class PyLegendNumberHyperbolicSinExpression(PyLegendUnaryExpression, PyLegendExpressionNumberReturn):
966
+
967
+ @staticmethod
968
+ def __to_sql_func(
969
+ expression: Expression,
970
+ frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
971
+ config: FrameToSqlConfig
972
+ ) -> Expression:
973
+ return FunctionCall(
974
+ name=QualifiedName(parts=["SINH"]),
975
+ distinct=False,
976
+ arguments=[expression],
977
+ filter_=None,
978
+ window=None
979
+ )
980
+
981
+ @staticmethod
982
+ def __to_pure_func(op_expr: str, config: FrameToPureConfig) -> str:
983
+ return generate_pure_functional_call("sinh", [op_expr])
984
+
985
+ def __init__(self, operand: PyLegendExpressionNumberReturn) -> None:
986
+ PyLegendExpressionNumberReturn.__init__(self)
987
+ PyLegendUnaryExpression.__init__(
988
+ self,
989
+ operand,
990
+ PyLegendNumberHyperbolicSinExpression.__to_sql_func,
991
+ PyLegendNumberHyperbolicSinExpression.__to_pure_func,
992
+ non_nullable=True,
993
+ operand_needs_to_be_non_nullable=True,
994
+ )
995
+
996
+
997
+ class PyLegendNumberHyperbolicCosExpression(PyLegendUnaryExpression, PyLegendExpressionNumberReturn):
998
+
999
+ @staticmethod
1000
+ def __to_sql_func(
1001
+ expression: Expression,
1002
+ frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
1003
+ config: FrameToSqlConfig
1004
+ ) -> Expression:
1005
+ return FunctionCall(
1006
+ name=QualifiedName(parts=["COSH"]),
1007
+ distinct=False,
1008
+ arguments=[expression],
1009
+ filter_=None,
1010
+ window=None
1011
+ )
1012
+
1013
+ @staticmethod
1014
+ def __to_pure_func(op_expr: str, config: FrameToPureConfig) -> str:
1015
+ return generate_pure_functional_call("cosh", [op_expr])
1016
+
1017
+ def __init__(self, operand: PyLegendExpressionNumberReturn) -> None:
1018
+ PyLegendExpressionNumberReturn.__init__(self)
1019
+ PyLegendUnaryExpression.__init__(
1020
+ self,
1021
+ operand,
1022
+ PyLegendNumberHyperbolicCosExpression.__to_sql_func,
1023
+ PyLegendNumberHyperbolicCosExpression.__to_pure_func,
1024
+ non_nullable=True,
1025
+ operand_needs_to_be_non_nullable=True,
1026
+ )
1027
+
1028
+
1029
+ class PyLegendNumberHyperbolicTanExpression(PyLegendUnaryExpression, PyLegendExpressionNumberReturn):
1030
+
1031
+ @staticmethod
1032
+ def __to_sql_func(
1033
+ expression: Expression,
1034
+ frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
1035
+ config: FrameToSqlConfig
1036
+ ) -> Expression:
1037
+ return FunctionCall(
1038
+ name=QualifiedName(parts=["TANH"]),
1039
+ distinct=False,
1040
+ arguments=[expression],
1041
+ filter_=None,
1042
+ window=None
1043
+ )
1044
+
1045
+ @staticmethod
1046
+ def __to_pure_func(op_expr: str, config: FrameToPureConfig) -> str:
1047
+ return generate_pure_functional_call("tanh", [op_expr])
1048
+
1049
+ def __init__(self, operand: PyLegendExpressionNumberReturn) -> None:
1050
+ PyLegendExpressionNumberReturn.__init__(self)
1051
+ PyLegendUnaryExpression.__init__(
1052
+ self,
1053
+ operand,
1054
+ PyLegendNumberHyperbolicTanExpression.__to_sql_func,
1055
+ PyLegendNumberHyperbolicTanExpression.__to_pure_func,
1056
+ non_nullable=True,
1057
+ operand_needs_to_be_non_nullable=True,
1058
+ )
1059
+
1060
+
1061
+ class PyLegendNumberPiExpression(PyLegendNullaryExpression, PyLegendExpressionNumberReturn):
1062
+
1063
+ @staticmethod
1064
+ def __to_sql_func(
1065
+ frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
1066
+ config: FrameToSqlConfig
1067
+ ) -> Expression:
1068
+ return FunctionCall(
1069
+ name=QualifiedName(parts=["PI"]),
1070
+ distinct=False,
1071
+ arguments=[],
1072
+ filter_=None,
1073
+ window=None
1074
+ )
1075
+
1076
+ @staticmethod
1077
+ def __to_pure_func(config: FrameToPureConfig) -> str:
1078
+ return "pi()"
1079
+
1080
+ def __init__(self) -> None:
1081
+ PyLegendExpressionNumberReturn.__init__(self)
1082
+ PyLegendNullaryExpression.__init__(
1083
+ self,
1084
+ PyLegendNumberPiExpression.__to_sql_func,
1085
+ PyLegendNumberPiExpression.__to_pure_func,
1086
+ non_nullable=True
1087
+ )
@@ -19,6 +19,7 @@ from pylegend._typing import (
19
19
  from pylegend.core.language.shared.expression import (
20
20
  PyLegendExpression,
21
21
  PyLegendExpressionBooleanReturn,
22
+ PyLegendExpressionStringReturn
22
23
  )
23
24
  from pylegend.core.language.shared.helpers import generate_pure_functional_call
24
25
  from pylegend.core.language.shared.operations.binary_expression import PyLegendBinaryExpression
@@ -30,6 +31,8 @@ from pylegend.core.sql.metamodel import (
30
31
  ComparisonOperator,
31
32
  IsNullPredicate,
32
33
  IsNotNullPredicate,
34
+ Cast,
35
+ ColumnType
33
36
  )
34
37
  from pylegend.core.tds.tds_frame import FrameToSqlConfig
35
38
  from pylegend.core.tds.tds_frame import FrameToPureConfig
@@ -40,6 +43,7 @@ __all__: PyLegendSequence[str] = [
40
43
  "PyLegendPrimitiveNotEqualsExpression",
41
44
  "PyLegendIsEmptyExpression",
42
45
  "PyLegendIsNotEmptyExpression",
46
+ "PyLegendPrimitiveToStringExpression"
43
47
  ]
44
48
 
45
49
 
@@ -145,3 +149,29 @@ class PyLegendIsNotEmptyExpression(PyLegendUnaryExpression, PyLegendExpressionBo
145
149
  PyLegendIsNotEmptyExpression.__to_pure_func,
146
150
  non_nullable=True,
147
151
  )
152
+
153
+
154
+ class PyLegendPrimitiveToStringExpression(PyLegendUnaryExpression, PyLegendExpressionStringReturn):
155
+
156
+ @staticmethod
157
+ def __to_sql_func(
158
+ expression: Expression,
159
+ frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
160
+ config: FrameToSqlConfig
161
+ ) -> Expression:
162
+ return Cast(expression, ColumnType(name="TEXT", parameters=[]))
163
+
164
+ @staticmethod
165
+ def __to_pure_func(op_expr: str, config: FrameToPureConfig) -> str:
166
+ return generate_pure_functional_call("toString", [op_expr])
167
+
168
+ def __init__(self, operand: PyLegendExpression) -> None:
169
+ PyLegendExpressionStringReturn.__init__(self)
170
+ PyLegendUnaryExpression.__init__(
171
+ self,
172
+ operand,
173
+ PyLegendPrimitiveToStringExpression.__to_sql_func,
174
+ PyLegendPrimitiveToStringExpression.__to_pure_func,
175
+ non_nullable=True,
176
+ operand_needs_to_be_non_nullable=True,
177
+ )