pylegend 0.1.0__tar.gz → 0.2.2__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 (116) hide show
  1. {pylegend-0.1.0 → pylegend-0.2.2}/PKG-INFO +10 -4
  2. {pylegend-0.1.0 → pylegend-0.2.2}/README.md +3 -0
  3. pylegend-0.2.2/pylegend/__init__.py +57 -0
  4. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/language/__init__.py +2 -1
  5. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/language/aggregate_specification.py +9 -0
  6. pylegend-0.2.2/pylegend/core/project_cooridnates.py +125 -0
  7. {pylegend-0.1.0/pylegend → pylegend-0.2.2/pylegend/core/request}/__init__.py +8 -6
  8. pylegend-0.2.2/pylegend/core/request/auth.py +61 -0
  9. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/request/legend_client.py +18 -3
  10. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/request/service_client.py +17 -3
  11. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/tds/tds_column.py +1 -1
  12. pylegend-0.2.2/pylegend/extensions/tds/abstract/legend_function_input_frame.py +108 -0
  13. pylegend-0.2.2/pylegend/extensions/tds/abstract/legend_service_input_frame.py +108 -0
  14. pylegend-0.1.0/pylegend/extensions/tds/pandas_api/frames/pandas_api_table_spec_input_frame.py → pylegend-0.2.2/pylegend/extensions/tds/abstract/table_spec_input_frame.py +6 -11
  15. pylegend-0.2.2/pylegend/extensions/tds/legend_api/frames/legend_api_legend_function_input_frame.py +46 -0
  16. pylegend-0.2.2/pylegend/extensions/tds/legend_api/frames/legend_api_legend_service_input_frame.py +46 -0
  17. pylegend-0.2.2/pylegend/extensions/tds/legend_api/frames/legend_api_table_spec_input_frame.py +36 -0
  18. pylegend-0.2.2/pylegend/extensions/tds/pandas_api/frames/pandas_api_legend_function_input_frame.py +46 -0
  19. pylegend-0.2.2/pylegend/extensions/tds/pandas_api/frames/pandas_api_legend_service_input_frame.py +46 -0
  20. pylegend-0.2.2/pylegend/extensions/tds/pandas_api/frames/pandas_api_table_spec_input_frame.py +36 -0
  21. pylegend-0.2.2/pylegend/legend_api_tds_client.py +73 -0
  22. {pylegend-0.1.0 → pylegend-0.2.2}/pyproject.toml +10 -4
  23. pylegend-0.1.0/pylegend/extensions/tds/legend_api/frames/legend_api_table_spec_input_frame.py +0 -75
  24. {pylegend-0.1.0 → pylegend-0.2.2}/LICENSE +0 -0
  25. {pylegend-0.1.0 → pylegend-0.2.2}/LICENSE.spdx +0 -0
  26. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/_typing.py +0 -0
  27. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/__init__.py +0 -0
  28. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/databse/__init__.py +0 -0
  29. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/databse/sql_to_string/__init__.py +0 -0
  30. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/databse/sql_to_string/config.py +0 -0
  31. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/databse/sql_to_string/db_extension.py +0 -0
  32. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/databse/sql_to_string/generator.py +0 -0
  33. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/language/column_expressions.py +0 -0
  34. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/language/expression.py +0 -0
  35. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/language/functions.py +0 -0
  36. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/language/literal_expressions.py +0 -0
  37. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/language/operations/__init__.py +0 -0
  38. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/language/operations/binary_expression.py +0 -0
  39. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/language/operations/boolean_operation_expressions.py +0 -0
  40. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/language/operations/collection_operation_expressions.py +0 -0
  41. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/language/operations/date_operation_expressions.py +0 -0
  42. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/language/operations/float_operation_expressions.py +0 -0
  43. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/language/operations/integer_operation_expressions.py +0 -0
  44. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/language/operations/nullary_expression.py +0 -0
  45. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/language/operations/number_operation_expressions.py +0 -0
  46. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/language/operations/primitive_operation_expressions.py +0 -0
  47. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/language/operations/string_operation_expressions.py +0 -0
  48. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/language/operations/unary_expression.py +0 -0
  49. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/language/primitive_collection.py +0 -0
  50. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/language/primitives/__init__.py +0 -0
  51. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/language/primitives/boolean.py +0 -0
  52. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/language/primitives/date.py +0 -0
  53. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/language/primitives/datetime.py +0 -0
  54. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/language/primitives/float.py +0 -0
  55. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/language/primitives/integer.py +0 -0
  56. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/language/primitives/number.py +0 -0
  57. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/language/primitives/primitive.py +0 -0
  58. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/language/primitives/strictdate.py +0 -0
  59. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/language/primitives/string.py +0 -0
  60. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/language/tds_row.py +0 -0
  61. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/request/response_reader.py +0 -0
  62. {pylegend-0.1.0/pylegend/core/request → pylegend-0.2.2/pylegend/core/sql}/__init__.py +0 -0
  63. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/sql/metamodel.py +0 -0
  64. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/sql/metamodel_extension.py +0 -0
  65. {pylegend-0.1.0/pylegend/core/sql → pylegend-0.2.2/pylegend/core/tds}/__init__.py +0 -0
  66. {pylegend-0.1.0/pylegend/core/tds → pylegend-0.2.2/pylegend/core/tds/legend_api}/__init__.py +0 -0
  67. {pylegend-0.1.0/pylegend/core/tds/legend_api → pylegend-0.2.2/pylegend/core/tds/legend_api/frames}/__init__.py +0 -0
  68. {pylegend-0.1.0/pylegend/core/tds/legend_api/frames → pylegend-0.2.2/pylegend/core/tds/legend_api/frames/functions}/__init__.py +0 -0
  69. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/tds/legend_api/frames/functions/concatenate_function.py +0 -0
  70. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/tds/legend_api/frames/functions/distinct_function.py +0 -0
  71. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/tds/legend_api/frames/functions/drop_function.py +0 -0
  72. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/tds/legend_api/frames/functions/extend_function.py +0 -0
  73. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/tds/legend_api/frames/functions/filter_function.py +0 -0
  74. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/tds/legend_api/frames/functions/function_helpers.py +0 -0
  75. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/tds/legend_api/frames/functions/group_by_function.py +0 -0
  76. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/tds/legend_api/frames/functions/head_function.py +0 -0
  77. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/tds/legend_api/frames/functions/join_by_columns_function.py +0 -0
  78. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/tds/legend_api/frames/functions/join_function.py +0 -0
  79. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/tds/legend_api/frames/functions/rename_columns_function.py +0 -0
  80. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/tds/legend_api/frames/functions/restrict_function.py +0 -0
  81. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/tds/legend_api/frames/functions/slice_function.py +0 -0
  82. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/tds/legend_api/frames/functions/sort_function.py +0 -0
  83. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/tds/legend_api/frames/legend_api_applied_function_tds_frame.py +0 -0
  84. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/tds/legend_api/frames/legend_api_base_tds_frame.py +0 -0
  85. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/tds/legend_api/frames/legend_api_input_tds_frame.py +0 -0
  86. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/tds/legend_api/frames/legend_api_tds_frame.py +0 -0
  87. {pylegend-0.1.0/pylegend/core/tds/legend_api/frames/functions → pylegend-0.2.2/pylegend/core/tds/pandas_api}/__init__.py +0 -0
  88. {pylegend-0.1.0/pylegend/core/tds/pandas_api → pylegend-0.2.2/pylegend/core/tds/pandas_api/frames}/__init__.py +0 -0
  89. {pylegend-0.1.0/pylegend/core/tds/pandas_api/frames → pylegend-0.2.2/pylegend/core/tds/pandas_api/frames/functions}/__init__.py +0 -0
  90. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/tds/pandas_api/frames/functions/assign_function.py +0 -0
  91. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/tds/pandas_api/frames/pandas_api_applied_function_tds_frame.py +0 -0
  92. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/tds/pandas_api/frames/pandas_api_base_tds_frame.py +0 -0
  93. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/tds/pandas_api/frames/pandas_api_input_tds_frame.py +0 -0
  94. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/tds/pandas_api/frames/pandas_api_tds_frame.py +0 -0
  95. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/tds/result_handler/__init__.py +0 -0
  96. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/tds/result_handler/result_handler.py +0 -0
  97. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/tds/result_handler/to_csv_file_result_handler.py +0 -0
  98. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/tds/result_handler/to_json_file_result_handler.py +0 -0
  99. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/tds/result_handler/to_string_result_handler.py +0 -0
  100. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/tds/sql_query_helpers.py +0 -0
  101. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/core/tds/tds_frame.py +0 -0
  102. {pylegend-0.1.0/pylegend/core/tds/pandas_api/frames/functions → pylegend-0.2.2/pylegend/extensions}/__init__.py +0 -0
  103. {pylegend-0.1.0/pylegend/extensions → pylegend-0.2.2/pylegend/extensions/database}/__init__.py +0 -0
  104. {pylegend-0.1.0/pylegend/extensions/database → pylegend-0.2.2/pylegend/extensions/database/vendors}/__init__.py +0 -0
  105. {pylegend-0.1.0/pylegend/extensions/database/vendors → pylegend-0.2.2/pylegend/extensions/database/vendors/postgres}/__init__.py +0 -0
  106. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/extensions/database/vendors/postgres/postgres_sql_to_string.py +0 -0
  107. {pylegend-0.1.0/pylegend/extensions/database/vendors/postgres → pylegend-0.2.2/pylegend/extensions/tds}/__init__.py +0 -0
  108. {pylegend-0.1.0/pylegend/extensions/tds → pylegend-0.2.2/pylegend/extensions/tds/abstract}/__init__.py +0 -0
  109. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/extensions/tds/legend_api/__init__.py +0 -0
  110. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/extensions/tds/legend_api/frames/__init__.py +0 -0
  111. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/extensions/tds/pandas_api/__init__.py +0 -0
  112. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/extensions/tds/pandas_api/frames/__init__.py +0 -0
  113. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/extensions/tds/result_handler/__init__.py +0 -0
  114. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/extensions/tds/result_handler/to_pandas_df_result_handler.py +0 -0
  115. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/utils/__init__.py +0 -0
  116. {pylegend-0.1.0 → pylegend-0.2.2}/pylegend/utils/class_utils.py +0 -0
@@ -1,26 +1,32 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pylegend
3
- Version: 0.1.0
3
+ Version: 0.2.2
4
4
  Summary: Python language binding for Legend data management platform
5
5
  Home-page: https://github.com/finos/pylegend
6
6
  License: Apache-2.0
7
7
  Author: PyLegend Maintainers
8
8
  Author-email: legend@finos.org
9
- Requires-Python: >=3.8
9
+ Requires-Python: >=3.8,<3.13
10
10
  Classifier: License :: OSI Approved :: Apache Software License
11
11
  Classifier: Programming Language :: Python :: 3
12
12
  Classifier: Programming Language :: Python :: 3.8
13
13
  Classifier: Programming Language :: Python :: 3.9
14
14
  Classifier: Programming Language :: Python :: 3.10
15
15
  Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
16
17
  Requires-Dist: ijson (>=3.1.4)
17
- Requires-Dist: numpy (>=1.20.0)
18
- Requires-Dist: pandas (>=1.0.0)
18
+ Requires-Dist: numpy (>=1.20.0) ; python_version < "3.12"
19
+ Requires-Dist: numpy (>=1.26.0) ; python_version >= "3.12"
20
+ Requires-Dist: pandas (>=1.0.0) ; python_version < "3.12"
21
+ Requires-Dist: pandas (>=2.1.1) ; python_version >= "3.12"
19
22
  Requires-Dist: requests (>=2.27.1)
20
23
  Project-URL: Repository, https://github.com/finos/pylegend
21
24
  Description-Content-Type: text/markdown
22
25
 
23
26
  [![FINOS - Incubating](https://cdn.jsdelivr.net/gh/finos/contrib-toolbox@master/images/badge-incubating.svg)](https://community.finos.org/docs/governance/Software-Projects/stages/incubating)
27
+ [![pypi](https://img.shields.io/pypi/v/pylegend.svg)](https://pypi.org/project/pylegend/)
28
+ [![python](https://img.shields.io/badge/python-3.8%20%7C%203.9%20%7C%203.10%20%7C%203.11%20%7C%203.12-blue)](https://www.python.org/downloads)
29
+ ![CI Testing](https://img.shields.io/badge/CI%20Testing-Linux%20%7C%20%20macOS%20%7C%20Windows%20-orange)
24
30
  [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
25
31
  ![Build](https://github.com/finos/pylegend/workflows/Build%20CI/badge.svg)
26
32
  ![CVE Scan](https://github.com/finos/pylegend/workflows/CVE%20Scan/badge.svg)
@@ -1,4 +1,7 @@
1
1
  [![FINOS - Incubating](https://cdn.jsdelivr.net/gh/finos/contrib-toolbox@master/images/badge-incubating.svg)](https://community.finos.org/docs/governance/Software-Projects/stages/incubating)
2
+ [![pypi](https://img.shields.io/pypi/v/pylegend.svg)](https://pypi.org/project/pylegend/)
3
+ [![python](https://img.shields.io/badge/python-3.8%20%7C%203.9%20%7C%203.10%20%7C%203.11%20%7C%203.12-blue)](https://www.python.org/downloads)
4
+ ![CI Testing](https://img.shields.io/badge/CI%20Testing-Linux%20%7C%20%20macOS%20%7C%20Windows%20-orange)
2
5
  [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
3
6
  ![Build](https://github.com/finos/pylegend/workflows/Build%20CI/badge.svg)
4
7
  ![CVE Scan](https://github.com/finos/pylegend/workflows/CVE%20Scan/badge.svg)
@@ -0,0 +1,57 @@
1
+ # Copyright 2023 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 pylegend._typing import (
16
+ PyLegendSequence,
17
+ )
18
+ from pylegend.legend_api_tds_client import (
19
+ LegendApiTdsClient,
20
+ legend_api_tds_client,
21
+ )
22
+ from pylegend.core.request import (
23
+ LegendClient,
24
+ AuthScheme,
25
+ LocalhostEmptyAuthScheme,
26
+ ResponseReader,
27
+ )
28
+ from pylegend.core.project_cooridnates import (
29
+ VersionedProjectCoordinates,
30
+ PersonalWorkspaceProjectCoordinates,
31
+ GroupWorkspaceProjectCoordinates,
32
+ )
33
+ from pylegend.core.language import agg
34
+
35
+
36
+ __all__: PyLegendSequence[str] = [
37
+ "__version__",
38
+
39
+ "LegendApiTdsClient",
40
+ "legend_api_tds_client",
41
+
42
+ "LegendClient",
43
+ "AuthScheme",
44
+ "LocalhostEmptyAuthScheme",
45
+ "ResponseReader",
46
+
47
+ "VersionedProjectCoordinates",
48
+ "PersonalWorkspaceProjectCoordinates",
49
+ "GroupWorkspaceProjectCoordinates",
50
+
51
+ "agg",
52
+ ]
53
+
54
+
55
+ import importlib.metadata
56
+
57
+ __version__ = importlib.metadata.version("pylegend")
@@ -58,7 +58,7 @@ from pylegend.core.language.column_expressions import (
58
58
  PyLegendStrictDateColumnExpression,
59
59
  )
60
60
  from pylegend.core.language.tds_row import TdsRow
61
- from pylegend.core.language.aggregate_specification import AggregateSpecification
61
+ from pylegend.core.language.aggregate_specification import AggregateSpecification, agg
62
62
  from pylegend.core.language.primitive_collection import (
63
63
  PyLegendPrimitiveCollection,
64
64
  PyLegendIntegerCollection,
@@ -117,6 +117,7 @@ __all__: PyLegendSequence[str] = [
117
117
 
118
118
  "TdsRow",
119
119
  "AggregateSpecification",
120
+ "agg",
120
121
 
121
122
  "PyLegendPrimitiveCollection",
122
123
  "PyLegendIntegerCollection",
@@ -25,6 +25,7 @@ from pylegend.core.language import (
25
25
 
26
26
  __all__: PyLegendSequence[str] = [
27
27
  "AggregateSpecification",
28
+ "agg",
28
29
  ]
29
30
 
30
31
 
@@ -51,3 +52,11 @@ class AggregateSpecification:
51
52
 
52
53
  def get_aggregate_fn(self) -> PyLegendCallable[[PyLegendPrimitiveCollection], PyLegendPrimitive]:
53
54
  return self.__aggregate_fn
55
+
56
+
57
+ def agg(
58
+ map_fn: PyLegendCallable[[TdsRow], PyLegendPrimitiveOrPythonPrimitive],
59
+ aggregate_fn: PyLegendCallable[[PyLegendPrimitiveCollection], PyLegendPrimitive],
60
+ name: str
61
+ ) -> AggregateSpecification:
62
+ return AggregateSpecification(map_fn=map_fn, aggregate_fn=aggregate_fn, name=name)
@@ -0,0 +1,125 @@
1
+ # Copyright 2023 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 abc
16
+ from abc import ABCMeta
17
+ from pylegend._typing import (
18
+ PyLegendSequence,
19
+ PyLegendList,
20
+ )
21
+ from pylegend.core.sql.metamodel import (
22
+ NamedArgumentExpression,
23
+ StringLiteral,
24
+ )
25
+
26
+ __all__: PyLegendSequence[str] = [
27
+ "ProjectCoordinates",
28
+ "VersionedProjectCoordinates",
29
+ "PersonalWorkspaceProjectCoordinates",
30
+ "GroupWorkspaceProjectCoordinates",
31
+ ]
32
+
33
+
34
+ class ProjectCoordinates(metaclass=ABCMeta):
35
+
36
+ @abc.abstractmethod
37
+ def sql_params(self) -> PyLegendList[NamedArgumentExpression]:
38
+ pass
39
+
40
+
41
+ class VersionedProjectCoordinates(ProjectCoordinates):
42
+ __group_id: str
43
+ __artifact_id: str
44
+ __version: str
45
+
46
+ def __init__(self, group_id: str, artifact_id: str, version: str) -> None:
47
+ self.__group_id = group_id
48
+ self.__artifact_id = artifact_id
49
+ self.__version = version
50
+
51
+ def get_group_id(self) -> str:
52
+ return self.__group_id
53
+
54
+ def get_artifact_id(self) -> str:
55
+ return self.__artifact_id
56
+
57
+ def get_version(self) -> str:
58
+ return self.__version
59
+
60
+ def sql_params(self) -> PyLegendList[NamedArgumentExpression]:
61
+ return [
62
+ NamedArgumentExpression(
63
+ name="coordinates",
64
+ expression=StringLiteral(
65
+ value=f"{self.__group_id}:{self.__artifact_id}:{self.__version}",
66
+ quoted=False
67
+ )
68
+ )
69
+ ]
70
+
71
+
72
+ class WorkspaceProjectCoordinates(ProjectCoordinates, metaclass=ABCMeta):
73
+ __project_id: str
74
+
75
+ def __init__(self, project_id: str) -> None:
76
+ self.__project_id = project_id
77
+
78
+ def get_project_id(self) -> str:
79
+ return self.__project_id
80
+
81
+
82
+ class PersonalWorkspaceProjectCoordinates(WorkspaceProjectCoordinates):
83
+ __workspace: str
84
+
85
+ def __init__(self, project_id: str, workspace: str) -> None:
86
+ super().__init__(project_id)
87
+ self.__workspace = workspace
88
+
89
+ def get_workspace(self) -> str:
90
+ return self.__workspace
91
+
92
+ def sql_params(self) -> PyLegendList[NamedArgumentExpression]:
93
+ return [
94
+ NamedArgumentExpression(
95
+ name="project",
96
+ expression=StringLiteral(value=self.get_project_id(), quoted=False)
97
+ ),
98
+ NamedArgumentExpression(
99
+ name="workspace",
100
+ expression=StringLiteral(value=self.__workspace, quoted=False)
101
+ )
102
+ ]
103
+
104
+
105
+ class GroupWorkspaceProjectCoordinates(WorkspaceProjectCoordinates):
106
+ __group_workspace: str
107
+
108
+ def __init__(self, project_id: str, group_workspace: str) -> None:
109
+ super().__init__(project_id)
110
+ self.__group_workspace = group_workspace
111
+
112
+ def get_group_workspace(self) -> str:
113
+ return self.__group_workspace
114
+
115
+ def sql_params(self) -> PyLegendList[NamedArgumentExpression]:
116
+ return [
117
+ NamedArgumentExpression(
118
+ name="project",
119
+ expression=StringLiteral(value=self.get_project_id(), quoted=False)
120
+ ),
121
+ NamedArgumentExpression(
122
+ name="groupWorkspace",
123
+ expression=StringLiteral(value=self.__group_workspace, quoted=False)
124
+ )
125
+ ]
@@ -15,13 +15,15 @@
15
15
  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 AuthScheme, LocalhostEmptyAuthScheme
20
+ from pylegend.core.request.response_reader import ResponseReader
19
21
 
20
22
  __all__: PyLegendSequence[str] = [
21
- "__version__"
22
- ]
23
+ "LegendClient",
23
24
 
25
+ "AuthScheme",
26
+ "LocalhostEmptyAuthScheme",
24
27
 
25
- import importlib.metadata
26
-
27
- __version__ = importlib.metadata.version("pylegend")
28
+ "ResponseReader"
29
+ ]
@@ -0,0 +1,61 @@
1
+ # Copyright 2023 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, abstractmethod
16
+
17
+ from requests import PreparedRequest
18
+
19
+ from pylegend._typing import (
20
+ PyLegendSequence,
21
+ PyLegendOptional,
22
+ )
23
+ from requests.auth import AuthBase
24
+
25
+ __all__: PyLegendSequence[str] = [
26
+ "AuthScheme",
27
+ "LocalhostEmptyAuthScheme",
28
+ "BearerAuthScheme"
29
+ ]
30
+
31
+
32
+ class AuthScheme(metaclass=ABCMeta):
33
+
34
+ @abstractmethod
35
+ def get_auth_base(self) -> PyLegendOptional[AuthBase]:
36
+ pass
37
+
38
+
39
+ class LocalhostEmptyAuthScheme(AuthScheme):
40
+
41
+ def get_auth_base(self) -> PyLegendOptional[AuthBase]:
42
+ return None
43
+
44
+
45
+ class BearerAuth(AuthBase):
46
+ def __init__(self, headerName: str, token: str) -> None:
47
+ self.headerName = headerName
48
+ self.token = token
49
+
50
+ def __call__(self, r: PreparedRequest) -> PreparedRequest:
51
+ r.headers[self.headerName] = self.token
52
+ return r
53
+
54
+
55
+ class BearerAuthScheme(AuthScheme):
56
+ def __init__(self, headerName: str, token: str) -> None:
57
+ self.headerName = headerName
58
+ self.token = token
59
+
60
+ def get_auth_base(self) -> PyLegendOptional[AuthBase]:
61
+ return BearerAuth(self.headerName, self.token)
@@ -17,6 +17,7 @@ from pylegend.core.request.service_client import (
17
17
  RequestMethod
18
18
  )
19
19
  from pylegend.core.request.response_reader import ResponseReader
20
+ from pylegend.core.request.auth import AuthScheme, LocalhostEmptyAuthScheme
20
21
  from pylegend._typing import (
21
22
  PyLegendSequence,
22
23
  PyLegendOptional,
@@ -24,15 +25,29 @@ from pylegend._typing import (
24
25
  from pylegend.core.tds.tds_column import TdsColumn, tds_columns_from_json
25
26
 
26
27
 
28
+ __all__: PyLegendSequence[str] = [
29
+ "LegendClient",
30
+ ]
31
+
32
+
27
33
  class LegendClient(ServiceClient):
28
34
  def __init__(
29
35
  self,
30
36
  host: str,
31
37
  port: int,
32
38
  secure_http: bool = True,
39
+ path_prefix: PyLegendOptional[str] = "/api",
40
+ auth_scheme: AuthScheme = LocalhostEmptyAuthScheme(),
33
41
  retry_count: int = 2
34
42
  ) -> None:
35
- super().__init__(host=host, port=port, secure_http=secure_http, retry_count=retry_count)
43
+ super().__init__(
44
+ host=host,
45
+ port=port,
46
+ secure_http=secure_http,
47
+ path_prefix=path_prefix,
48
+ auth_scheme=auth_scheme,
49
+ retry_count=retry_count
50
+ )
36
51
 
37
52
  def get_sql_string_schema(
38
53
  self,
@@ -40,7 +55,7 @@ class LegendClient(ServiceClient):
40
55
  ) -> PyLegendSequence[TdsColumn]:
41
56
  response = super()._execute_service(
42
57
  method=RequestMethod.POST,
43
- path="api/sql/v1/execution/getSchemaFromQueryString",
58
+ path="sql/v1/execution/getSchemaFromQueryString",
44
59
  data=sql,
45
60
  headers={"Content-Type": "text/plain"},
46
61
  stream=False
@@ -55,7 +70,7 @@ class LegendClient(ServiceClient):
55
70
  ) -> ResponseReader:
56
71
  iter_content = super()._execute_service(
57
72
  method=RequestMethod.POST,
58
- path="api/sql/v1/execution/executeQueryString",
73
+ path="sql/v1/execution/executeQueryString",
59
74
  data=sql,
60
75
  headers={"Content-Type": "text/plain"},
61
76
  stream=True
@@ -17,6 +17,7 @@ from enum import Enum
17
17
 
18
18
  import requests
19
19
  from requests.adapters import HTTPAdapter, Retry
20
+ from pylegend.core.request.auth import AuthScheme
20
21
  from pylegend._typing import (
21
22
  PyLegendSequence,
22
23
  PyLegendOptional,
@@ -39,9 +40,19 @@ class RequestMethod(Enum):
39
40
 
40
41
  class ServiceClient(metaclass=ABCMeta):
41
42
 
42
- def __init__(self, host: str, port: int, secure_http: bool, retry_count: int) -> None:
43
+ def __init__(
44
+ self,
45
+ host: str,
46
+ port: int,
47
+ secure_http: bool,
48
+ path_prefix: PyLegendOptional[str],
49
+ auth_scheme: AuthScheme,
50
+ retry_count: int
51
+ ) -> None:
43
52
  self.__host = host
44
53
  self.__port = port
54
+ self.__auth_scheme = auth_scheme
55
+ self.__path_prefix = path_prefix
45
56
  self.__secure_http = secure_http
46
57
  if retry_count < 1:
47
58
  raise ValueError("Retry count should be a number greater than 1. Got " + str(retry_count))
@@ -64,14 +75,17 @@ class ServiceClient(metaclass=ABCMeta):
64
75
  ) -> requests.Response:
65
76
 
66
77
  scheme = "https" if self.__secure_http else "http"
67
- url = f"{scheme}://{self.__host}:{self.__port}/{path}"
78
+ prefix = (self.__path_prefix if self.__path_prefix.startswith("/") else f"/{self.__path_prefix}") \
79
+ if self.__path_prefix is not None else ""
80
+ url = f"{scheme}://{self.__host}:{self.__port}{prefix}/{path}"
68
81
 
69
82
  request = requests.Request(
70
83
  method=method.name,
71
84
  url=url,
72
85
  headers=headers,
73
86
  data=data,
74
- params=query_params
87
+ params=query_params,
88
+ auth=self.__auth_scheme.get_auth_base(),
75
89
  )
76
90
 
77
91
  session = requests.Session()
@@ -150,7 +150,7 @@ def tds_columns_from_json(s: str) -> PyLegendSequence[TdsColumn]:
150
150
 
151
151
  result_columns: PyLegendList[TdsColumn] = []
152
152
  for col in columns:
153
- if col["__TYPE"] == "meta::external::query::sql::PrimitiveValueSchemaColumn":
153
+ if col["_type"] == "primitiveSchemaColumn":
154
154
  result_columns.append(PrimitiveTdsColumn(col["name"], PrimitiveType[col["type"]]))
155
155
  else:
156
156
  result_columns.append(
@@ -0,0 +1,108 @@
1
+ # Copyright 2023 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
+ PyLegendList,
18
+ PyLegendSequence,
19
+ )
20
+ from pylegend.core.tds.tds_frame import (
21
+ PyLegendTdsFrame,
22
+ FrameToSqlConfig,
23
+ )
24
+ from pylegend.core.project_cooridnates import ProjectCoordinates
25
+ from pylegend.core.sql.metamodel import (
26
+ QuerySpecification,
27
+ TableFunction,
28
+ Select,
29
+ AllColumns,
30
+ FunctionCall,
31
+ QualifiedName,
32
+ NamedArgumentExpression,
33
+ StringLiteral,
34
+ AliasedRelation,
35
+ SingleColumn,
36
+ QualifiedNameReference,
37
+ Expression,
38
+ )
39
+
40
+ __all__: PyLegendSequence[str] = [
41
+ "LegendFunctionInputFrameAbstract",
42
+ ]
43
+
44
+
45
+ class LegendFunctionInputFrameAbstract(PyLegendTdsFrame, metaclass=ABCMeta):
46
+ __path: str
47
+ __project_coordinates: ProjectCoordinates
48
+ __initialized: bool = False
49
+
50
+ def __init__(
51
+ self,
52
+ path: str,
53
+ project_coordinates: ProjectCoordinates,
54
+ ) -> None:
55
+ self.__path = path
56
+ self.__project_coordinates = project_coordinates
57
+
58
+ def to_sql_query_object(self, config: FrameToSqlConfig) -> QuerySpecification:
59
+ db_extension = config.sql_to_string_generator().get_db_extension()
60
+ root_alias = db_extension.quote_identifier("root")
61
+ args: PyLegendList[Expression] = [
62
+ NamedArgumentExpression(
63
+ name="path",
64
+ expression=StringLiteral(value=self.__path, quoted=False)
65
+ )
66
+ ]
67
+ args += self.__project_coordinates.sql_params()
68
+ func_call = FunctionCall(
69
+ name=QualifiedName(["func"]),
70
+ distinct=False,
71
+ filter_=None,
72
+ window=None,
73
+ arguments=args
74
+ )
75
+
76
+ return QuerySpecification(
77
+ select=Select(
78
+ selectItems=[
79
+ SingleColumn(
80
+ alias=db_extension.quote_identifier(x.get_name()),
81
+ expression=QualifiedNameReference(
82
+ name=QualifiedName(parts=[root_alias, db_extension.quote_identifier(x.get_name())])
83
+ )
84
+ )
85
+ for x in self.columns()
86
+ ] if self.__initialized else [AllColumns(prefix=root_alias)],
87
+ distinct=False
88
+ ),
89
+ from_=[
90
+ AliasedRelation(
91
+ relation=TableFunction(functionCall=func_call),
92
+ alias=root_alias,
93
+ columnNames=[x.get_name() for x in self.columns()] if self.__initialized else []
94
+ )
95
+ ],
96
+ where=None,
97
+ groupBy=[],
98
+ having=None,
99
+ orderBy=[],
100
+ limit=None,
101
+ offset=None
102
+ )
103
+
104
+ def get_path(self) -> str:
105
+ return self.__path
106
+
107
+ def set_initialized(self, val: bool) -> None:
108
+ self.__initialized = val
@@ -0,0 +1,108 @@
1
+ # Copyright 2023 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
+ PyLegendList,
18
+ PyLegendSequence,
19
+ )
20
+ from pylegend.core.tds.tds_frame import (
21
+ PyLegendTdsFrame,
22
+ FrameToSqlConfig,
23
+ )
24
+ from pylegend.core.project_cooridnates import ProjectCoordinates
25
+ from pylegend.core.sql.metamodel import (
26
+ QuerySpecification,
27
+ TableFunction,
28
+ Select,
29
+ AllColumns,
30
+ FunctionCall,
31
+ QualifiedName,
32
+ NamedArgumentExpression,
33
+ StringLiteral,
34
+ AliasedRelation,
35
+ SingleColumn,
36
+ QualifiedNameReference,
37
+ Expression,
38
+ )
39
+
40
+ __all__: PyLegendSequence[str] = [
41
+ "LegendServiceInputFrameAbstract",
42
+ ]
43
+
44
+
45
+ class LegendServiceInputFrameAbstract(PyLegendTdsFrame, metaclass=ABCMeta):
46
+ __pattern: str
47
+ __project_coordinates: ProjectCoordinates
48
+ __initialized: bool = False
49
+
50
+ def __init__(
51
+ self,
52
+ pattern: str,
53
+ project_coordinates: ProjectCoordinates,
54
+ ) -> None:
55
+ self.__pattern = pattern
56
+ self.__project_coordinates = project_coordinates
57
+
58
+ def to_sql_query_object(self, config: FrameToSqlConfig) -> QuerySpecification:
59
+ db_extension = config.sql_to_string_generator().get_db_extension()
60
+ root_alias = db_extension.quote_identifier("root")
61
+ args: PyLegendList[Expression] = [
62
+ NamedArgumentExpression(
63
+ name="pattern",
64
+ expression=StringLiteral(value=self.__pattern, quoted=False)
65
+ )
66
+ ]
67
+ args += self.__project_coordinates.sql_params()
68
+ func_call = FunctionCall(
69
+ name=QualifiedName(["service"]),
70
+ distinct=False,
71
+ filter_=None,
72
+ window=None,
73
+ arguments=args
74
+ )
75
+
76
+ return QuerySpecification(
77
+ select=Select(
78
+ selectItems=[
79
+ SingleColumn(
80
+ alias=db_extension.quote_identifier(x.get_name()),
81
+ expression=QualifiedNameReference(
82
+ name=QualifiedName(parts=[root_alias, db_extension.quote_identifier(x.get_name())])
83
+ )
84
+ )
85
+ for x in self.columns()
86
+ ] if self.__initialized else [AllColumns(prefix=root_alias)],
87
+ distinct=False
88
+ ),
89
+ from_=[
90
+ AliasedRelation(
91
+ relation=TableFunction(functionCall=func_call),
92
+ alias=root_alias,
93
+ columnNames=[x.get_name() for x in self.columns()] if self.__initialized else []
94
+ )
95
+ ],
96
+ where=None,
97
+ groupBy=[],
98
+ having=None,
99
+ orderBy=[],
100
+ limit=None,
101
+ offset=None
102
+ )
103
+
104
+ def get_pattern(self) -> str:
105
+ return self.__pattern
106
+
107
+ def set_initialized(self, val: bool) -> None:
108
+ self.__initialized = val