pylegend 0.10.0__tar.gz → 0.11.0__tar.gz

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 (177) hide show
  1. {pylegend-0.10.0 → pylegend-0.11.0}/PKG-INFO +1 -1
  2. pylegend-0.11.0/pylegend/core/tds/pandas_api/frames/functions/aggregate_function.py +441 -0
  3. pylegend-0.11.0/pylegend/core/tds/pandas_api/frames/functions/merge.py +513 -0
  4. pylegend-0.11.0/pylegend/core/tds/pandas_api/frames/functions/rename.py +214 -0
  5. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/pandas_api/frames/pandas_api_base_tds_frame.py +275 -0
  6. pylegend-0.11.0/pylegend/core/tds/pandas_api/frames/pandas_api_groupby_tds_frame.py +325 -0
  7. pylegend-0.11.0/pylegend/core/tds/pandas_api/frames/pandas_api_tds_frame.py +267 -0
  8. pylegend-0.11.0/pylegend/extensions/tds/abstract/csv_tds_frame.py +95 -0
  9. pylegend-0.11.0/pylegend/extensions/tds/legendql_api/frames/legendql_api_csv_input_frame.py +36 -0
  10. {pylegend-0.10.0 → pylegend-0.11.0}/pyproject.toml +1 -1
  11. pylegend-0.10.0/pylegend/core/tds/pandas_api/frames/functions/aggregate_function.py +0 -316
  12. pylegend-0.10.0/pylegend/core/tds/pandas_api/frames/pandas_api_tds_frame.py +0 -130
  13. {pylegend-0.10.0 → pylegend-0.11.0}/LICENSE +0 -0
  14. {pylegend-0.10.0 → pylegend-0.11.0}/LICENSE.spdx +0 -0
  15. {pylegend-0.10.0 → pylegend-0.11.0}/NOTICE +0 -0
  16. {pylegend-0.10.0 → pylegend-0.11.0}/README.md +0 -0
  17. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/__init__.py +0 -0
  18. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/_typing.py +0 -0
  19. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/__init__.py +0 -0
  20. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/database/__init__.py +0 -0
  21. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/database/sql_to_string/__init__.py +0 -0
  22. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/database/sql_to_string/config.py +0 -0
  23. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/database/sql_to_string/db_extension.py +0 -0
  24. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/database/sql_to_string/generator.py +0 -0
  25. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/__init__.py +0 -0
  26. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/legacy_api/__init__.py +0 -0
  27. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/legacy_api/aggregate_specification.py +0 -0
  28. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/legacy_api/legacy_api_tds_row.py +0 -0
  29. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/legendql_api/__init__.py +0 -0
  30. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/legendql_api/legendql_api_custom_expressions.py +0 -0
  31. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/legendql_api/legendql_api_tds_row.py +0 -0
  32. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/pandas_api/__init__.py +0 -0
  33. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/pandas_api/pandas_api_aggregate_specification.py +0 -0
  34. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/pandas_api/pandas_api_custom_expressions.py +0 -0
  35. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/pandas_api/pandas_api_series.py +0 -0
  36. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/pandas_api/pandas_api_tds_row.py +0 -0
  37. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/shared/__init__.py +0 -0
  38. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/shared/column_expressions.py +0 -0
  39. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/shared/expression.py +0 -0
  40. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/shared/functions.py +0 -0
  41. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/shared/helpers.py +0 -0
  42. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/shared/literal_expressions.py +0 -0
  43. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/shared/operations/__init__.py +0 -0
  44. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/shared/operations/binary_expression.py +0 -0
  45. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/shared/operations/boolean_operation_expressions.py +0 -0
  46. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/shared/operations/collection_operation_expressions.py +0 -0
  47. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/shared/operations/date_operation_expressions.py +0 -0
  48. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/shared/operations/float_operation_expressions.py +0 -0
  49. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/shared/operations/integer_operation_expressions.py +0 -0
  50. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/shared/operations/nary_expression.py +0 -0
  51. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/shared/operations/nullary_expression.py +0 -0
  52. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/shared/operations/number_operation_expressions.py +0 -0
  53. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/shared/operations/primitive_operation_expressions.py +0 -0
  54. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/shared/operations/string_operation_expressions.py +0 -0
  55. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/shared/operations/unary_expression.py +0 -0
  56. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/shared/pct_helpers.py +0 -0
  57. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/shared/primitive_collection.py +0 -0
  58. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/shared/primitives/__init__.py +0 -0
  59. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/shared/primitives/boolean.py +0 -0
  60. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/shared/primitives/date.py +0 -0
  61. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/shared/primitives/datetime.py +0 -0
  62. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/shared/primitives/float.py +0 -0
  63. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/shared/primitives/integer.py +0 -0
  64. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/shared/primitives/number.py +0 -0
  65. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/shared/primitives/primitive.py +0 -0
  66. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/shared/primitives/strictdate.py +0 -0
  67. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/shared/primitives/string.py +0 -0
  68. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/language/shared/tds_row.py +0 -0
  69. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/project_cooridnates.py +0 -0
  70. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/request/__init__.py +0 -0
  71. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/request/auth.py +0 -0
  72. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/request/legend_client.py +0 -0
  73. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/request/response_reader.py +0 -0
  74. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/request/service_client.py +0 -0
  75. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/sql/__init__.py +0 -0
  76. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/sql/metamodel.py +0 -0
  77. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/sql/metamodel_extension.py +0 -0
  78. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/__init__.py +0 -0
  79. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/abstract/__init__.py +0 -0
  80. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/abstract/frames/__init__.py +0 -0
  81. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/abstract/frames/applied_function_tds_frame.py +0 -0
  82. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/abstract/frames/base_tds_frame.py +0 -0
  83. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/abstract/frames/input_tds_frame.py +0 -0
  84. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/abstract/function_helpers.py +0 -0
  85. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legacy_api/__init__.py +0 -0
  86. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legacy_api/frames/__init__.py +0 -0
  87. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legacy_api/frames/functions/__init__.py +0 -0
  88. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legacy_api/frames/functions/legacy_api_concatenate_function.py +0 -0
  89. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legacy_api/frames/functions/legacy_api_distinct_function.py +0 -0
  90. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legacy_api/frames/functions/legacy_api_drop_function.py +0 -0
  91. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legacy_api/frames/functions/legacy_api_extend_function.py +0 -0
  92. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legacy_api/frames/functions/legacy_api_filter_function.py +0 -0
  93. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legacy_api/frames/functions/legacy_api_group_by_function.py +0 -0
  94. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legacy_api/frames/functions/legacy_api_head_function.py +0 -0
  95. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legacy_api/frames/functions/legacy_api_join_by_columns_function.py +0 -0
  96. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legacy_api/frames/functions/legacy_api_join_function.py +0 -0
  97. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legacy_api/frames/functions/legacy_api_rename_columns_function.py +0 -0
  98. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legacy_api/frames/functions/legacy_api_restrict_function.py +0 -0
  99. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legacy_api/frames/functions/legacy_api_slice_function.py +0 -0
  100. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legacy_api/frames/functions/legacy_api_sort_function.py +0 -0
  101. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legacy_api/frames/legacy_api_applied_function_tds_frame.py +0 -0
  102. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legacy_api/frames/legacy_api_base_tds_frame.py +0 -0
  103. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legacy_api/frames/legacy_api_input_tds_frame.py +0 -0
  104. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legacy_api/frames/legacy_api_tds_frame.py +0 -0
  105. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legendql_api/__init__.py +0 -0
  106. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legendql_api/frames/__init__.py +0 -0
  107. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legendql_api/frames/functions/__init__.py +0 -0
  108. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legendql_api/frames/functions/legendql_api_asofjoin_function.py +0 -0
  109. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legendql_api/frames/functions/legendql_api_concatenate_function.py +0 -0
  110. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legendql_api/frames/functions/legendql_api_distinct_function.py +0 -0
  111. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legendql_api/frames/functions/legendql_api_drop_function.py +0 -0
  112. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legendql_api/frames/functions/legendql_api_extend_function.py +0 -0
  113. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legendql_api/frames/functions/legendql_api_filter_function.py +0 -0
  114. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legendql_api/frames/functions/legendql_api_function_helpers.py +0 -0
  115. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legendql_api/frames/functions/legendql_api_groupby_function.py +0 -0
  116. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legendql_api/frames/functions/legendql_api_head_function.py +0 -0
  117. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legendql_api/frames/functions/legendql_api_join_function.py +0 -0
  118. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legendql_api/frames/functions/legendql_api_project_function.py +0 -0
  119. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legendql_api/frames/functions/legendql_api_rename_function.py +0 -0
  120. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legendql_api/frames/functions/legendql_api_select_function.py +0 -0
  121. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legendql_api/frames/functions/legendql_api_slice_function.py +0 -0
  122. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legendql_api/frames/functions/legendql_api_sort_function.py +0 -0
  123. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legendql_api/frames/functions/legendql_api_window_extend_function.py +0 -0
  124. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legendql_api/frames/legendql_api_applied_function_tds_frame.py +0 -0
  125. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legendql_api/frames/legendql_api_base_tds_frame.py +0 -0
  126. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legendql_api/frames/legendql_api_input_tds_frame.py +0 -0
  127. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/legendql_api/frames/legendql_api_tds_frame.py +0 -0
  128. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/pandas_api/__init__.py +0 -0
  129. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/pandas_api/frames/__init__.py +0 -0
  130. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/pandas_api/frames/functions/__init__.py +0 -0
  131. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/pandas_api/frames/functions/assign_function.py +0 -0
  132. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/pandas_api/frames/functions/drop.py +0 -0
  133. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/pandas_api/frames/functions/filter.py +0 -0
  134. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/pandas_api/frames/functions/filtering.py +0 -0
  135. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/pandas_api/frames/functions/sort_values_function.py +0 -0
  136. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/pandas_api/frames/functions/truncate_function.py +0 -0
  137. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/pandas_api/frames/pandas_api_applied_function_tds_frame.py +0 -0
  138. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/pandas_api/frames/pandas_api_input_tds_frame.py +0 -0
  139. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/result_handler/__init__.py +0 -0
  140. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/result_handler/result_handler.py +0 -0
  141. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/result_handler/to_csv_file_result_handler.py +0 -0
  142. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/result_handler/to_json_file_result_handler.py +0 -0
  143. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/result_handler/to_string_result_handler.py +0 -0
  144. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/sql_query_helpers.py +0 -0
  145. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/tds_column.py +0 -0
  146. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/core/tds/tds_frame.py +0 -0
  147. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/extensions/__init__.py +0 -0
  148. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/extensions/database/__init__.py +0 -0
  149. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/extensions/database/vendors/__init__.py +0 -0
  150. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/extensions/database/vendors/postgres/__init__.py +0 -0
  151. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/extensions/database/vendors/postgres/postgres_sql_to_string.py +0 -0
  152. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/extensions/tds/__init__.py +0 -0
  153. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/extensions/tds/abstract/__init__.py +0 -0
  154. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/extensions/tds/abstract/legend_function_input_frame.py +0 -0
  155. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/extensions/tds/abstract/legend_service_input_frame.py +0 -0
  156. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/extensions/tds/abstract/table_spec_input_frame.py +0 -0
  157. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/extensions/tds/legacy_api/__init__.py +0 -0
  158. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/extensions/tds/legacy_api/frames/__init__.py +0 -0
  159. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/extensions/tds/legacy_api/frames/legacy_api_legend_function_input_frame.py +0 -0
  160. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/extensions/tds/legacy_api/frames/legacy_api_legend_service_input_frame.py +0 -0
  161. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/extensions/tds/legacy_api/frames/legacy_api_table_spec_input_frame.py +0 -0
  162. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/extensions/tds/legendql_api/__init__.py +0 -0
  163. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/extensions/tds/legendql_api/frames/__init__.py +0 -0
  164. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/extensions/tds/legendql_api/frames/legendql_api_legend_function_input_frame.py +0 -0
  165. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/extensions/tds/legendql_api/frames/legendql_api_legend_service_input_frame.py +0 -0
  166. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/extensions/tds/legendql_api/frames/legendql_api_table_spec_input_frame.py +0 -0
  167. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/extensions/tds/pandas_api/__init__.py +0 -0
  168. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/extensions/tds/pandas_api/frames/__init__.py +0 -0
  169. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/extensions/tds/pandas_api/frames/pandas_api_legend_function_input_frame.py +0 -0
  170. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/extensions/tds/pandas_api/frames/pandas_api_legend_service_input_frame.py +0 -0
  171. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/extensions/tds/pandas_api/frames/pandas_api_table_spec_input_frame.py +0 -0
  172. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/extensions/tds/result_handler/__init__.py +0 -0
  173. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/extensions/tds/result_handler/to_pandas_df_result_handler.py +0 -0
  174. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/legacy_api_tds_client.py +0 -0
  175. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/legendql_api_tds_client.py +0 -0
  176. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/utils/__init__.py +0 -0
  177. {pylegend-0.10.0 → pylegend-0.11.0}/pylegend/utils/class_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pylegend
3
- Version: 0.10.0
3
+ Version: 0.11.0
4
4
  Summary: Python language binding for Legend data management platform
5
5
  License: Apache-2.0
6
6
  License-File: LICENSE
@@ -0,0 +1,441 @@
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
+ import numpy as np
16
+ import collections.abc
17
+ from pylegend._typing import (
18
+ PyLegendCallable,
19
+ PyLegendSequence,
20
+ PyLegendTuple,
21
+ PyLegendUnion,
22
+ PyLegendList,
23
+ PyLegendMapping,
24
+ )
25
+ from pylegend.core.language.pandas_api.pandas_api_aggregate_specification import (
26
+ PyLegendAggFunc,
27
+ PyLegendAggInput,
28
+ PyLegendAggList,
29
+ )
30
+ from pylegend.core.language.pandas_api.pandas_api_tds_row import PandasApiTdsRow
31
+ from pylegend.core.language.shared.helpers import escape_column_name, generate_pure_lambda
32
+ from pylegend.core.language.shared.literal_expressions import convert_literal_to_literal_expression
33
+ from pylegend.core.language.shared.primitive_collection import PyLegendPrimitiveCollection, create_primitive_collection
34
+ from pylegend.core.language.shared.primitives.boolean import PyLegendBoolean
35
+ from pylegend.core.language.shared.primitives.date import PyLegendDate
36
+ from pylegend.core.language.shared.primitives.datetime import PyLegendDateTime
37
+ from pylegend.core.language.shared.primitives.float import PyLegendFloat
38
+ from pylegend.core.language.shared.primitives.integer import PyLegendInteger
39
+ from pylegend.core.language.shared.primitives.number import PyLegendNumber
40
+ from pylegend.core.language.shared.primitives.primitive import PyLegendPrimitive, PyLegendPrimitiveOrPythonPrimitive
41
+ from pylegend.core.language.shared.primitives.strictdate import PyLegendStrictDate
42
+ from pylegend.core.language.shared.primitives.string import PyLegendString
43
+ from pylegend.core.sql.metamodel import (
44
+ QuerySpecification,
45
+ SelectItem,
46
+ SingleColumn,
47
+ )
48
+ from pylegend.core.tds.pandas_api.frames.pandas_api_applied_function_tds_frame import PandasApiAppliedFunction
49
+ from pylegend.core.tds.pandas_api.frames.pandas_api_base_tds_frame import PandasApiBaseTdsFrame
50
+ from pylegend.core.tds.pandas_api.frames.pandas_api_groupby_tds_frame import PandasApiGroupbyTdsFrame
51
+ from pylegend.core.tds.sql_query_helpers import copy_query, create_sub_query
52
+ from pylegend.core.tds.tds_column import PrimitiveTdsColumn, TdsColumn
53
+ from pylegend.core.tds.tds_frame import FrameToPureConfig, FrameToSqlConfig
54
+
55
+
56
+ class AggregateFunction(PandasApiAppliedFunction):
57
+ __base_frame: PyLegendUnion[PandasApiBaseTdsFrame, PandasApiGroupbyTdsFrame]
58
+ __func: PyLegendAggInput
59
+ __axis: PyLegendUnion[int, str]
60
+ __args: PyLegendSequence[PyLegendPrimitiveOrPythonPrimitive]
61
+ __kwargs: PyLegendMapping[str, PyLegendPrimitiveOrPythonPrimitive]
62
+
63
+ @classmethod
64
+ def name(cls) -> str:
65
+ return "aggregate" # pragma: no cover
66
+
67
+ def __init__(
68
+ self,
69
+ base_frame: PyLegendUnion[PandasApiBaseTdsFrame, PandasApiGroupbyTdsFrame],
70
+ func: PyLegendAggInput,
71
+ axis: PyLegendUnion[int, str],
72
+ *args: PyLegendPrimitiveOrPythonPrimitive,
73
+ **kwargs: PyLegendPrimitiveOrPythonPrimitive,
74
+ ) -> None:
75
+ self.__base_frame = base_frame
76
+ self.__func = func
77
+ self.__axis = axis
78
+ self.__args = args
79
+ self.__kwargs = kwargs
80
+
81
+ def to_sql(self, config: FrameToSqlConfig) -> QuerySpecification:
82
+ db_extension = config.sql_to_string_generator().get_db_extension()
83
+
84
+ base_query: QuerySpecification = self.base_frame().to_sql_query_object(config)
85
+
86
+ should_create_sub_query = (
87
+ len(base_query.groupBy) > 0
88
+ or base_query.select.distinct
89
+ or base_query.offset is not None
90
+ or base_query.limit is not None
91
+ )
92
+
93
+ new_query: QuerySpecification
94
+ if should_create_sub_query:
95
+ new_query = create_sub_query(base_query, config, "root")
96
+ else:
97
+ new_query = copy_query(base_query)
98
+
99
+ new_select_items: PyLegendList[SelectItem] = []
100
+
101
+ if isinstance(self.__base_frame, PandasApiGroupbyTdsFrame):
102
+ columns_to_retain: PyLegendList[str] = [
103
+ db_extension.quote_identifier(x) for x in self.__base_frame.grouping_column_name_list()
104
+ ]
105
+ new_cols_with_index: PyLegendList[PyLegendTuple[int, "SelectItem"]] = []
106
+ for col in new_query.select.selectItems:
107
+ if not isinstance(col, SingleColumn):
108
+ raise ValueError(
109
+ "Group By operation not supported for queries " "with columns other than SingleColumn"
110
+ ) # pragma: no cover
111
+ if col.alias is None:
112
+ raise ValueError(
113
+ "Group By operation not supported for queries " "with SingleColumns with missing alias"
114
+ ) # pragma: no cover
115
+ if col.alias in columns_to_retain:
116
+ new_cols_with_index.append((columns_to_retain.index(col.alias), col))
117
+
118
+ new_select_items = [y[1] for y in sorted(new_cols_with_index, key=lambda x: x[0])]
119
+
120
+ for agg in self.__aggregates_list:
121
+ agg_sql_expr = agg[2].to_sql_expression({"r": new_query}, config)
122
+
123
+ new_select_items.append(SingleColumn(alias=db_extension.quote_identifier(agg[0]), expression=agg_sql_expr))
124
+
125
+ new_query.select.selectItems = new_select_items
126
+
127
+ if isinstance(self.__base_frame, PandasApiGroupbyTdsFrame):
128
+ tds_row = PandasApiTdsRow.from_tds_frame("r", self.base_frame())
129
+ new_query.groupBy = [
130
+ (lambda x: x[c])(tds_row).to_sql_expression({"r": new_query}, config)
131
+ for c in self.__base_frame.grouping_column_name_list()
132
+ ]
133
+
134
+ return new_query
135
+
136
+ def to_pure(self, config: FrameToPureConfig) -> str:
137
+ agg_strings = []
138
+ for agg in self.__aggregates_list:
139
+ map_expr_string = (
140
+ agg[1].to_pure_expression(config)
141
+ if isinstance(agg[1], PyLegendPrimitive)
142
+ else convert_literal_to_literal_expression(agg[1]).to_pure_expression(config)
143
+ )
144
+ agg_expr_string = agg[2].to_pure_expression(config).replace(map_expr_string, "$c")
145
+ agg_strings.append(
146
+ f"{escape_column_name(agg[0])}:{generate_pure_lambda('r', map_expr_string)}:"
147
+ f"{generate_pure_lambda('c', agg_expr_string)}"
148
+ )
149
+
150
+ if isinstance(self.__base_frame, PandasApiGroupbyTdsFrame):
151
+ group_strings = []
152
+ for col_name in self.__base_frame.grouping_column_name_list():
153
+ group_strings.append(escape_column_name(col_name))
154
+
155
+ pure_expression = (
156
+ f"{self.base_frame().to_pure(config)}{config.separator(1)}" + f"->groupBy({config.separator(2)}"
157
+ f"~[{', '.join(group_strings)}],{config.separator(2, True)}"
158
+ f"~[{', '.join(agg_strings)}]{config.separator(1)}"
159
+ f")"
160
+ )
161
+
162
+ return pure_expression
163
+ else:
164
+ return (
165
+ f"{self.__base_frame.to_pure(config)}{config.separator(1)}"
166
+ f"->aggregate({config.separator(2)}"
167
+ f"~[{', '.join(agg_strings)}]{config.separator(1)}"
168
+ f")"
169
+ )
170
+
171
+ def base_frame(self) -> PandasApiBaseTdsFrame:
172
+ if isinstance(self.__base_frame, PandasApiGroupbyTdsFrame):
173
+ return self.__base_frame.base_frame()
174
+ else:
175
+ return self.__base_frame
176
+
177
+ def tds_frame_parameters(self) -> PyLegendList["PandasApiBaseTdsFrame"]:
178
+ return []
179
+
180
+ def calculate_columns(self) -> PyLegendSequence["TdsColumn"]:
181
+ new_columns = []
182
+
183
+ if isinstance(self.__base_frame, PandasApiGroupbyTdsFrame):
184
+ base_cols_map = {c.get_name(): c for c in self.base_frame().columns()}
185
+ for group_col_name in self.__base_frame.grouping_column_name_list():
186
+ if group_col_name in base_cols_map:
187
+ new_columns.append(base_cols_map[group_col_name].copy())
188
+
189
+ for alias, _, agg_expr in self.__aggregates_list:
190
+ new_columns.append(self.__infer_column_from_expression(alias, agg_expr))
191
+
192
+ return new_columns
193
+
194
+ def __infer_column_from_expression(self, name: str, expr: PyLegendPrimitive) -> TdsColumn:
195
+ if isinstance(expr, PyLegendInteger):
196
+ return PrimitiveTdsColumn.integer_column(name)
197
+ elif isinstance(expr, PyLegendFloat):
198
+ return PrimitiveTdsColumn.float_column(name)
199
+ elif isinstance(expr, PyLegendNumber):
200
+ return PrimitiveTdsColumn.number_column(name)
201
+ elif isinstance(expr, PyLegendString):
202
+ return PrimitiveTdsColumn.string_column(name)
203
+ elif isinstance(expr, PyLegendBoolean):
204
+ return PrimitiveTdsColumn.boolean_column(name) # pragma: no cover
205
+ elif isinstance(expr, PyLegendDate):
206
+ return PrimitiveTdsColumn.date_column(name)
207
+ elif isinstance(expr, PyLegendDateTime):
208
+ return PrimitiveTdsColumn.datetime_column(name)
209
+ elif isinstance(expr, PyLegendStrictDate):
210
+ return PrimitiveTdsColumn.strictdate_column(name)
211
+ else:
212
+ raise TypeError(f"Could not infer TdsColumn type for aggregation result type: {type(expr)}") # pragma: no cover
213
+
214
+ def validate(self) -> bool:
215
+ if self.__axis not in [0, "index"]:
216
+ raise NotImplementedError(
217
+ f"The 'axis' parameter of the aggregate function must be 0 or 'index', but got: {self.__axis}"
218
+ )
219
+
220
+ if len(self.__args) > 0 or len(self.__kwargs) > 0:
221
+ raise NotImplementedError(
222
+ "AggregateFunction currently does not support additional positional "
223
+ "or keyword arguments. Please remove extra *args/**kwargs."
224
+ )
225
+
226
+ self.__aggregates_list: PyLegendList[PyLegendTuple[str, PyLegendPrimitiveOrPythonPrimitive, PyLegendPrimitive]] = []
227
+
228
+ normalized_func: dict[str, PyLegendUnion[PyLegendAggFunc, PyLegendAggList]] = (
229
+ self.__normalize_input_func_to_standard_dict(self.__func)
230
+ )
231
+
232
+ tds_row = PandasApiTdsRow.from_tds_frame("r", self.base_frame())
233
+
234
+ for column_name, agg_input in normalized_func.items():
235
+ mapper_function: PyLegendCallable[[PandasApiTdsRow], PyLegendPrimitiveOrPythonPrimitive] = eval(
236
+ f'lambda r: r["{column_name}"]'
237
+ )
238
+ map_result: PyLegendPrimitiveOrPythonPrimitive = mapper_function(tds_row)
239
+ collection: PyLegendPrimitiveCollection = create_primitive_collection(map_result)
240
+
241
+ if isinstance(agg_input, list):
242
+ lambda_counter = 0
243
+ for func in agg_input:
244
+ is_anonymous_lambda = False
245
+ if not isinstance(func, str):
246
+ if getattr(func, "__name__", "<lambda>") == "<lambda>":
247
+ is_anonymous_lambda = True
248
+
249
+ if is_anonymous_lambda:
250
+ lambda_counter += 1
251
+
252
+ normalized_agg_func = self.__normalize_agg_func_to_lambda_function(func)
253
+ agg_result = normalized_agg_func(collection)
254
+
255
+ alias = self._generate_column_alias(column_name, func, lambda_counter)
256
+ self.__aggregates_list.append((alias, map_result, agg_result))
257
+
258
+ else:
259
+ normalized_agg_func = self.__normalize_agg_func_to_lambda_function(agg_input)
260
+ agg_result = normalized_agg_func(collection)
261
+
262
+ self.__aggregates_list.append((column_name, map_result, agg_result))
263
+
264
+ return True
265
+
266
+ def __normalize_input_func_to_standard_dict(
267
+ self, func_input: PyLegendAggInput
268
+ ) -> dict[str, PyLegendUnion[PyLegendAggFunc, PyLegendAggList]]:
269
+
270
+ validation_columns: PyLegendList[str]
271
+ default_broadcast_columns: PyLegendList[str]
272
+ group_cols: set[str] = set()
273
+
274
+ all_cols = [col.get_name() for col in self.base_frame().columns()]
275
+
276
+ if isinstance(self.__base_frame, PandasApiGroupbyTdsFrame):
277
+ group_cols = set(self.__base_frame.grouping_column_name_list())
278
+
279
+ selected_cols = self.__base_frame.selected_columns()
280
+
281
+ if selected_cols is not None:
282
+ validation_columns = selected_cols
283
+ default_broadcast_columns = selected_cols
284
+ else:
285
+ validation_columns = all_cols
286
+ default_broadcast_columns = [c for c in all_cols if c not in group_cols]
287
+ else:
288
+ validation_columns = all_cols
289
+ default_broadcast_columns = all_cols
290
+
291
+ if isinstance(func_input, collections.abc.Mapping):
292
+ normalized: dict[str, PyLegendUnion[PyLegendAggFunc, PyLegendAggList]] = {}
293
+
294
+ for key, value in func_input.items():
295
+ if not isinstance(key, str):
296
+ raise TypeError(
297
+ f"Invalid `func` argument for the aggregate function.\n"
298
+ f"When a dictionary is provided, all keys must be strings.\n"
299
+ f"But got key: {key!r} (type: {type(key).__name__})\n"
300
+ )
301
+
302
+ if key not in validation_columns:
303
+ raise ValueError(
304
+ f"Invalid `func` argument for the aggregate function.\n"
305
+ f"When a dictionary is provided, all keys must be column names.\n"
306
+ f"Available columns are: {sorted(validation_columns)}\n"
307
+ f"But got key: {key!r} (type: {type(key).__name__})\n"
308
+ )
309
+
310
+ if isinstance(value, collections.abc.Sequence) and not isinstance(value, str):
311
+ for i, f in enumerate(value):
312
+ if not (callable(f) or isinstance(f, str) or isinstance(f, np.ufunc)):
313
+ raise TypeError(
314
+ f"Invalid `func` argument for the aggregate function.\n"
315
+ f"When a list is provided for a column, all elements must be callable, str, or np.ufunc.\n"
316
+ f"But got element at index {i}: {f!r} (type: {type(f).__name__})\n"
317
+ )
318
+ normalized[key] = value
319
+
320
+ else:
321
+ if not (callable(value) or isinstance(value, str) or isinstance(value, np.ufunc)):
322
+ raise TypeError(
323
+ f"Invalid `func` argument for the aggregate function.\n"
324
+ f"When a dictionary is provided, the value must be a callable, str, or np.ufunc "
325
+ f"(or a list containing these).\n"
326
+ f"But got value for key '{key}': {value} (type: {type(value).__name__})\n"
327
+ )
328
+
329
+ if key in group_cols:
330
+ normalized[key] = [value]
331
+ else:
332
+ normalized[key] = value
333
+
334
+ return normalized
335
+
336
+ elif isinstance(func_input, collections.abc.Sequence) and not isinstance(func_input, str):
337
+ for i, f in enumerate(func_input):
338
+ if not (callable(f) or isinstance(f, str) or isinstance(f, np.ufunc)):
339
+ raise TypeError(
340
+ f"Invalid `func` argument for the aggregate function.\n"
341
+ f"When a list is provided as the main argument, all elements must be callable, str, or np.ufunc.\n"
342
+ f"But got element at index {i}: {f!r} (type: {type(f).__name__})\n"
343
+ )
344
+
345
+ return {col: func_input for col in default_broadcast_columns}
346
+
347
+ elif callable(func_input) or isinstance(func_input, str) or isinstance(func_input, np.ufunc):
348
+ return {col: func_input for col in default_broadcast_columns}
349
+
350
+ else:
351
+ raise TypeError(
352
+ "Invalid `func` argument for aggregate function. "
353
+ "Expected a callable, str, np.ufunc, a list containing exactly one of these, "
354
+ "or a mapping[str -> callable/str/ufunc/a list containing exactly one of these]. "
355
+ f"But got: {func_input!r} (type: {type(func_input).__name__})"
356
+ )
357
+
358
+ def __normalize_agg_func_to_lambda_function(
359
+ self, func: PyLegendAggFunc
360
+ ) -> PyLegendCallable[[PyLegendPrimitiveCollection], PyLegendPrimitive]:
361
+
362
+ PYTHON_FUNCTION_TO_LEGEND_FUNCTION_MAPPING: PyLegendMapping[str, PyLegendList[str]] = {
363
+ "average": ["mean", "average", "nanmean"],
364
+ "sum": ["sum", "nansum"],
365
+ "min": ["min", "amin", "minimum", "nanmin"],
366
+ "max": ["max", "amax", "maximum", "nanmax"],
367
+ "std_dev_sample": ["std", "std_dev", "nanstd"],
368
+ "variance_sample": ["var", "variance", "nanvar"],
369
+ "count": ["count", "size", "len", "length"],
370
+ }
371
+
372
+ FLATTENED_FUNCTION_MAPPING: dict[str, str] = {}
373
+ for target_method, source_list in PYTHON_FUNCTION_TO_LEGEND_FUNCTION_MAPPING.items():
374
+ for alias in source_list:
375
+ FLATTENED_FUNCTION_MAPPING[alias] = target_method
376
+
377
+ lambda_source: str
378
+ final_lambda: PyLegendCallable[[PyLegendPrimitiveCollection], PyLegendPrimitive]
379
+
380
+ if isinstance(func, str):
381
+ func_lower = func.lower()
382
+ if func_lower in FLATTENED_FUNCTION_MAPPING:
383
+ internal_method_name = FLATTENED_FUNCTION_MAPPING[func_lower]
384
+ else:
385
+ raise NotImplementedError(
386
+ f"Invalid `func` argument for the aggregate function.\n"
387
+ f"The string {func!r} does not correspond to any supported aggregation.\n"
388
+ f"Available string functions are: {sorted(FLATTENED_FUNCTION_MAPPING.keys())}"
389
+ ) # pragma: no cover
390
+ lambda_source = self._generate_lambda_source(internal_method_name)
391
+ final_lambda = eval(lambda_source)
392
+ return final_lambda
393
+
394
+ elif isinstance(func, np.ufunc):
395
+ func_name = func.__name__
396
+ if func_name in FLATTENED_FUNCTION_MAPPING:
397
+ internal_method_name = FLATTENED_FUNCTION_MAPPING[func_name]
398
+ else:
399
+ raise NotImplementedError(
400
+ f"Invalid `func` argument for the aggregate function.\n"
401
+ f"The NumPy function {func_name!r} is not supported.\n"
402
+ f"Supported aggregate functions are: {sorted(FLATTENED_FUNCTION_MAPPING.keys())}"
403
+ ) # pragma: no cover
404
+ lambda_source = self._generate_lambda_source(internal_method_name)
405
+ final_lambda = eval(lambda_source)
406
+ return final_lambda
407
+
408
+ else:
409
+ func_name = getattr(func, "__name__", "").lower()
410
+ if func_name in FLATTENED_FUNCTION_MAPPING and func_name != "<lambda>":
411
+ internal_method_name = FLATTENED_FUNCTION_MAPPING[func_name]
412
+ lambda_source = self._generate_lambda_source(internal_method_name)
413
+ final_lambda = eval(lambda_source)
414
+ return final_lambda
415
+ else:
416
+
417
+ def validation_wrapper(x: PyLegendPrimitiveCollection) -> PyLegendPrimitive:
418
+ result = func(x)
419
+ if not isinstance(result, PyLegendPrimitive):
420
+ raise TypeError(
421
+ f"Custom aggregation function must return a PyLegendPrimitive (Expression).\n"
422
+ f"But got type: {type(result).__name__}\n"
423
+ f"Value: {result!r}"
424
+ ) # pragma: no cover
425
+ return result
426
+
427
+ return validation_wrapper
428
+
429
+ def _generate_lambda_source(self, internal_method_name: str) -> str:
430
+ return f"lambda x: x.{internal_method_name}()"
431
+
432
+ def _generate_column_alias(self, col_name: str, func: PyLegendAggFunc, lambda_counter: int) -> str:
433
+ if isinstance(func, str):
434
+ return f"{func}({col_name})"
435
+
436
+ func_name = getattr(func, "__name__", "<lambda>")
437
+
438
+ if func_name != "<lambda>":
439
+ return f"{func_name}({col_name})"
440
+ else:
441
+ return f"lambda_{lambda_counter}({col_name})"