pytrilogy 0.3.138__cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.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 (182) hide show
  1. LICENSE.md +19 -0
  2. _preql_import_resolver/__init__.py +5 -0
  3. _preql_import_resolver/_preql_import_resolver.cpython-311-x86_64-linux-gnu.so +0 -0
  4. pytrilogy-0.3.138.dist-info/METADATA +525 -0
  5. pytrilogy-0.3.138.dist-info/RECORD +182 -0
  6. pytrilogy-0.3.138.dist-info/WHEEL +5 -0
  7. pytrilogy-0.3.138.dist-info/entry_points.txt +2 -0
  8. pytrilogy-0.3.138.dist-info/licenses/LICENSE.md +19 -0
  9. trilogy/__init__.py +9 -0
  10. trilogy/ai/README.md +10 -0
  11. trilogy/ai/__init__.py +19 -0
  12. trilogy/ai/constants.py +92 -0
  13. trilogy/ai/conversation.py +107 -0
  14. trilogy/ai/enums.py +7 -0
  15. trilogy/ai/execute.py +50 -0
  16. trilogy/ai/models.py +34 -0
  17. trilogy/ai/prompts.py +87 -0
  18. trilogy/ai/providers/__init__.py +0 -0
  19. trilogy/ai/providers/anthropic.py +106 -0
  20. trilogy/ai/providers/base.py +24 -0
  21. trilogy/ai/providers/google.py +146 -0
  22. trilogy/ai/providers/openai.py +89 -0
  23. trilogy/ai/providers/utils.py +68 -0
  24. trilogy/authoring/README.md +3 -0
  25. trilogy/authoring/__init__.py +143 -0
  26. trilogy/constants.py +113 -0
  27. trilogy/core/README.md +52 -0
  28. trilogy/core/__init__.py +0 -0
  29. trilogy/core/constants.py +6 -0
  30. trilogy/core/enums.py +443 -0
  31. trilogy/core/env_processor.py +120 -0
  32. trilogy/core/environment_helpers.py +320 -0
  33. trilogy/core/ergonomics.py +193 -0
  34. trilogy/core/exceptions.py +123 -0
  35. trilogy/core/functions.py +1227 -0
  36. trilogy/core/graph_models.py +139 -0
  37. trilogy/core/internal.py +85 -0
  38. trilogy/core/models/__init__.py +0 -0
  39. trilogy/core/models/author.py +2672 -0
  40. trilogy/core/models/build.py +2521 -0
  41. trilogy/core/models/build_environment.py +180 -0
  42. trilogy/core/models/core.py +494 -0
  43. trilogy/core/models/datasource.py +322 -0
  44. trilogy/core/models/environment.py +748 -0
  45. trilogy/core/models/execute.py +1177 -0
  46. trilogy/core/optimization.py +251 -0
  47. trilogy/core/optimizations/__init__.py +12 -0
  48. trilogy/core/optimizations/base_optimization.py +17 -0
  49. trilogy/core/optimizations/hide_unused_concept.py +47 -0
  50. trilogy/core/optimizations/inline_datasource.py +102 -0
  51. trilogy/core/optimizations/predicate_pushdown.py +245 -0
  52. trilogy/core/processing/README.md +94 -0
  53. trilogy/core/processing/READMEv2.md +121 -0
  54. trilogy/core/processing/VIRTUAL_UNNEST.md +30 -0
  55. trilogy/core/processing/__init__.py +0 -0
  56. trilogy/core/processing/concept_strategies_v3.py +508 -0
  57. trilogy/core/processing/constants.py +15 -0
  58. trilogy/core/processing/discovery_node_factory.py +451 -0
  59. trilogy/core/processing/discovery_utility.py +517 -0
  60. trilogy/core/processing/discovery_validation.py +167 -0
  61. trilogy/core/processing/graph_utils.py +43 -0
  62. trilogy/core/processing/node_generators/README.md +9 -0
  63. trilogy/core/processing/node_generators/__init__.py +31 -0
  64. trilogy/core/processing/node_generators/basic_node.py +160 -0
  65. trilogy/core/processing/node_generators/common.py +268 -0
  66. trilogy/core/processing/node_generators/constant_node.py +38 -0
  67. trilogy/core/processing/node_generators/filter_node.py +315 -0
  68. trilogy/core/processing/node_generators/group_node.py +213 -0
  69. trilogy/core/processing/node_generators/group_to_node.py +117 -0
  70. trilogy/core/processing/node_generators/multiselect_node.py +205 -0
  71. trilogy/core/processing/node_generators/node_merge_node.py +653 -0
  72. trilogy/core/processing/node_generators/recursive_node.py +88 -0
  73. trilogy/core/processing/node_generators/rowset_node.py +165 -0
  74. trilogy/core/processing/node_generators/select_helpers/__init__.py +0 -0
  75. trilogy/core/processing/node_generators/select_helpers/datasource_injection.py +261 -0
  76. trilogy/core/processing/node_generators/select_merge_node.py +748 -0
  77. trilogy/core/processing/node_generators/select_node.py +95 -0
  78. trilogy/core/processing/node_generators/synonym_node.py +98 -0
  79. trilogy/core/processing/node_generators/union_node.py +91 -0
  80. trilogy/core/processing/node_generators/unnest_node.py +182 -0
  81. trilogy/core/processing/node_generators/window_node.py +201 -0
  82. trilogy/core/processing/nodes/README.md +28 -0
  83. trilogy/core/processing/nodes/__init__.py +179 -0
  84. trilogy/core/processing/nodes/base_node.py +519 -0
  85. trilogy/core/processing/nodes/filter_node.py +75 -0
  86. trilogy/core/processing/nodes/group_node.py +194 -0
  87. trilogy/core/processing/nodes/merge_node.py +420 -0
  88. trilogy/core/processing/nodes/recursive_node.py +46 -0
  89. trilogy/core/processing/nodes/select_node_v2.py +242 -0
  90. trilogy/core/processing/nodes/union_node.py +53 -0
  91. trilogy/core/processing/nodes/unnest_node.py +62 -0
  92. trilogy/core/processing/nodes/window_node.py +56 -0
  93. trilogy/core/processing/utility.py +823 -0
  94. trilogy/core/query_processor.py +596 -0
  95. trilogy/core/statements/README.md +35 -0
  96. trilogy/core/statements/__init__.py +0 -0
  97. trilogy/core/statements/author.py +536 -0
  98. trilogy/core/statements/build.py +0 -0
  99. trilogy/core/statements/common.py +20 -0
  100. trilogy/core/statements/execute.py +155 -0
  101. trilogy/core/table_processor.py +66 -0
  102. trilogy/core/utility.py +8 -0
  103. trilogy/core/validation/README.md +46 -0
  104. trilogy/core/validation/__init__.py +0 -0
  105. trilogy/core/validation/common.py +161 -0
  106. trilogy/core/validation/concept.py +146 -0
  107. trilogy/core/validation/datasource.py +227 -0
  108. trilogy/core/validation/environment.py +73 -0
  109. trilogy/core/validation/fix.py +106 -0
  110. trilogy/dialect/__init__.py +32 -0
  111. trilogy/dialect/base.py +1359 -0
  112. trilogy/dialect/bigquery.py +256 -0
  113. trilogy/dialect/common.py +147 -0
  114. trilogy/dialect/config.py +144 -0
  115. trilogy/dialect/dataframe.py +50 -0
  116. trilogy/dialect/duckdb.py +177 -0
  117. trilogy/dialect/enums.py +147 -0
  118. trilogy/dialect/metadata.py +173 -0
  119. trilogy/dialect/mock.py +190 -0
  120. trilogy/dialect/postgres.py +91 -0
  121. trilogy/dialect/presto.py +104 -0
  122. trilogy/dialect/results.py +89 -0
  123. trilogy/dialect/snowflake.py +90 -0
  124. trilogy/dialect/sql_server.py +92 -0
  125. trilogy/engine.py +48 -0
  126. trilogy/execution/config.py +75 -0
  127. trilogy/executor.py +568 -0
  128. trilogy/hooks/__init__.py +4 -0
  129. trilogy/hooks/base_hook.py +40 -0
  130. trilogy/hooks/graph_hook.py +139 -0
  131. trilogy/hooks/query_debugger.py +166 -0
  132. trilogy/metadata/__init__.py +0 -0
  133. trilogy/parser.py +10 -0
  134. trilogy/parsing/README.md +21 -0
  135. trilogy/parsing/__init__.py +0 -0
  136. trilogy/parsing/common.py +1069 -0
  137. trilogy/parsing/config.py +5 -0
  138. trilogy/parsing/exceptions.py +8 -0
  139. trilogy/parsing/helpers.py +1 -0
  140. trilogy/parsing/parse_engine.py +2813 -0
  141. trilogy/parsing/render.py +750 -0
  142. trilogy/parsing/trilogy.lark +540 -0
  143. trilogy/py.typed +0 -0
  144. trilogy/render.py +42 -0
  145. trilogy/scripts/README.md +7 -0
  146. trilogy/scripts/__init__.py +0 -0
  147. trilogy/scripts/dependency/Cargo.lock +617 -0
  148. trilogy/scripts/dependency/Cargo.toml +39 -0
  149. trilogy/scripts/dependency/README.md +131 -0
  150. trilogy/scripts/dependency/build.sh +25 -0
  151. trilogy/scripts/dependency/src/directory_resolver.rs +162 -0
  152. trilogy/scripts/dependency/src/lib.rs +16 -0
  153. trilogy/scripts/dependency/src/main.rs +770 -0
  154. trilogy/scripts/dependency/src/parser.rs +435 -0
  155. trilogy/scripts/dependency/src/preql.pest +208 -0
  156. trilogy/scripts/dependency/src/python_bindings.rs +289 -0
  157. trilogy/scripts/dependency/src/resolver.rs +716 -0
  158. trilogy/scripts/dependency/tests/base.preql +3 -0
  159. trilogy/scripts/dependency/tests/cli_integration.rs +377 -0
  160. trilogy/scripts/dependency/tests/customer.preql +6 -0
  161. trilogy/scripts/dependency/tests/main.preql +9 -0
  162. trilogy/scripts/dependency/tests/orders.preql +7 -0
  163. trilogy/scripts/dependency/tests/test_data/base.preql +9 -0
  164. trilogy/scripts/dependency/tests/test_data/consumer.preql +1 -0
  165. trilogy/scripts/dependency.py +323 -0
  166. trilogy/scripts/display.py +460 -0
  167. trilogy/scripts/environment.py +46 -0
  168. trilogy/scripts/parallel_execution.py +483 -0
  169. trilogy/scripts/single_execution.py +131 -0
  170. trilogy/scripts/trilogy.py +772 -0
  171. trilogy/std/__init__.py +0 -0
  172. trilogy/std/color.preql +3 -0
  173. trilogy/std/date.preql +13 -0
  174. trilogy/std/display.preql +18 -0
  175. trilogy/std/geography.preql +22 -0
  176. trilogy/std/metric.preql +15 -0
  177. trilogy/std/money.preql +67 -0
  178. trilogy/std/net.preql +14 -0
  179. trilogy/std/ranking.preql +7 -0
  180. trilogy/std/report.preql +5 -0
  181. trilogy/std/semantic.preql +6 -0
  182. trilogy/utility.py +34 -0
@@ -0,0 +1,73 @@
1
+ from trilogy import Environment, Executor
2
+ from trilogy.authoring import DataType, Function
3
+ from trilogy.core.enums import FunctionType, Purpose, ValidationScope
4
+ from trilogy.core.exceptions import (
5
+ ModelValidationError,
6
+ )
7
+ from trilogy.core.validation.common import ValidationTest
8
+ from trilogy.core.validation.concept import validate_concept
9
+ from trilogy.core.validation.datasource import validate_datasource
10
+ from trilogy.parsing.common import function_to_concept
11
+
12
+
13
+ def validate_environment(
14
+ env: Environment,
15
+ scope: ValidationScope = ValidationScope.ALL,
16
+ targets: list[str] | None = None,
17
+ exec: Executor | None = None,
18
+ generate_only: bool = False,
19
+ ) -> list[ValidationTest]:
20
+ # avoid mutating the environment for validation
21
+ generate_only = exec is None or generate_only
22
+ env = env.duplicate()
23
+ grain_check = function_to_concept(
24
+ parent=Function(
25
+ operator=FunctionType.SUM,
26
+ arguments=[1],
27
+ output_datatype=DataType.INTEGER,
28
+ output_purpose=Purpose.METRIC,
29
+ ),
30
+ name="grain_check",
31
+ environment=env,
32
+ )
33
+ env.add_concept(grain_check)
34
+ new_concepts = []
35
+ for concept in env.concepts.values():
36
+ concept_grain_check = function_to_concept(
37
+ parent=Function(
38
+ operator=FunctionType.COUNT_DISTINCT,
39
+ arguments=[concept.reference],
40
+ output_datatype=DataType.INTEGER,
41
+ output_purpose=Purpose.METRIC,
42
+ ),
43
+ name=f"grain_check_{concept.safe_address}",
44
+ environment=env,
45
+ )
46
+ new_concepts.append(concept_grain_check)
47
+ for concept in new_concepts:
48
+ env.add_concept(concept)
49
+ build_env = env.materialize_for_select()
50
+ results: list[ValidationTest] = []
51
+ if scope == ValidationScope.ALL or scope == ValidationScope.DATASOURCES:
52
+ for datasource in build_env.datasources.values():
53
+ if targets and datasource.name not in targets:
54
+ continue
55
+ results += validate_datasource(datasource, env, build_env, exec)
56
+ if scope == ValidationScope.ALL or scope == ValidationScope.CONCEPTS:
57
+
58
+ for bconcept in build_env.concepts.values():
59
+ if targets and bconcept.address not in targets:
60
+ continue
61
+ results += validate_concept(bconcept, env, build_env, exec)
62
+
63
+ # raise a nicely formatted union of all exceptions
64
+ exceptions: list[ModelValidationError] = [e.result for e in results if e.result]
65
+ if exceptions:
66
+ if not generate_only:
67
+ messages = "\n".join([str(e) for e in exceptions])
68
+ raise ModelValidationError(
69
+ f"Environment validation failed with the following errors:\n{messages}",
70
+ children=exceptions,
71
+ )
72
+
73
+ return results
@@ -0,0 +1,106 @@
1
+ from collections import defaultdict
2
+ from pathlib import Path
3
+ from typing import Any
4
+
5
+ from trilogy import Environment, Executor
6
+ from trilogy.authoring import ConceptDeclarationStatement, Datasource
7
+ from trilogy.core.exceptions import (
8
+ DatasourceColumnBindingData,
9
+ DatasourceColumnBindingError,
10
+ )
11
+ from trilogy.core.validation.environment import validate_environment
12
+ from trilogy.parsing.render import Renderer
13
+
14
+
15
+ def rewrite_file_with_errors(
16
+ statements: list[Any], errors: list[DatasourceColumnBindingError]
17
+ ):
18
+ renderer = Renderer()
19
+ output = []
20
+ ds_error_map: dict[str, list[DatasourceColumnBindingData]] = defaultdict(list)
21
+ concept_error_map: dict[str, list[DatasourceColumnBindingData]] = defaultdict(list)
22
+ for error in errors:
23
+ if isinstance(error, DatasourceColumnBindingError):
24
+ for x in error.errors:
25
+ if error.dataset_address not in ds_error_map:
26
+ ds_error_map[error.dataset_address] = []
27
+ # this is by dataset address
28
+ if x.is_modifier_issue():
29
+ ds_error_map[error.dataset_address].append(x)
30
+ # this is by column
31
+ if x.is_type_issue():
32
+ concept_error_map[x.address].append(x)
33
+ for statement in statements:
34
+ if isinstance(statement, Datasource):
35
+ if statement.identifier in ds_error_map:
36
+ error_cols = ds_error_map[statement.identifier]
37
+ for col in statement.columns:
38
+ if col.concept.address in [x.address for x in error_cols]:
39
+ error_col = [
40
+ x for x in error_cols if x.address == col.concept.address
41
+ ][0]
42
+ col.modifiers = list(
43
+ set(col.modifiers + error_col.value_modifiers)
44
+ )
45
+ elif isinstance(statement, ConceptDeclarationStatement):
46
+ if statement.concept.address in concept_error_map:
47
+ error_cols = concept_error_map[statement.concept.address]
48
+ statement.concept.datatype = error_cols[0].value_type
49
+ output.append(statement)
50
+
51
+ return renderer.render_statement_string(output)
52
+
53
+
54
+ DEPTH_CUTOFF = 3
55
+
56
+
57
+ def validate_and_rewrite(
58
+ input: Path | str, exec: Executor | None = None, depth: int = 0
59
+ ) -> str | None:
60
+ if depth > DEPTH_CUTOFF:
61
+ print(f"Reached depth cutoff of {DEPTH_CUTOFF}, stopping.")
62
+ return None
63
+ if isinstance(input, str):
64
+ raw = input
65
+ env = Environment()
66
+ else:
67
+ with open(input, "r") as f:
68
+ raw = f.read()
69
+ env = Environment(working_path=input.parent)
70
+ if exec:
71
+ env = exec.environment
72
+ env, statements = env.parse(raw)
73
+
74
+ validation_results = validate_environment(env, exec=exec, generate_only=True)
75
+
76
+ errors = [
77
+ x.result
78
+ for x in validation_results
79
+ if isinstance(x.result, DatasourceColumnBindingError)
80
+ ]
81
+
82
+ if not errors:
83
+ print("No validation errors found")
84
+ return None
85
+ print(
86
+ f"Found {len(errors)} validation errors, attempting to fix, current depth: {depth}..."
87
+ )
88
+ for error in errors:
89
+ for item in error.errors:
90
+ print(f"- {item.format_failure()}")
91
+
92
+ new_text = rewrite_file_with_errors(statements, errors)
93
+
94
+ while iteration := validate_and_rewrite(new_text, exec=exec, depth=depth + 1):
95
+ depth = depth + 1
96
+ if depth >= DEPTH_CUTOFF:
97
+ break
98
+ if iteration:
99
+ new_text = iteration
100
+ depth += 1
101
+ if isinstance(input, Path):
102
+ with open(input, "w") as f:
103
+ f.write(new_text)
104
+ return None
105
+ else:
106
+ return new_text
@@ -0,0 +1,32 @@
1
+ from .bigquery import BigqueryDialect
2
+ from .config import (
3
+ BigQueryConfig,
4
+ DialectConfig,
5
+ DuckDBConfig,
6
+ PostgresConfig,
7
+ PrestoConfig,
8
+ SnowflakeConfig,
9
+ SQLServerConfig,
10
+ )
11
+ from .duckdb import DuckDBDialect
12
+ from .postgres import PostgresDialect
13
+ from .presto import PrestoDialect
14
+ from .snowflake import SnowflakeDialect
15
+ from .sql_server import SqlServerDialect
16
+
17
+ __all__ = [
18
+ "BigqueryDialect",
19
+ "PrestoDialect",
20
+ "DuckDBDialect",
21
+ "SnowflakeDialect",
22
+ "PostgresDialect",
23
+ "SqlServerDialect",
24
+ "SQLServerConfig",
25
+ "DialectConfig",
26
+ "DuckDBConfig",
27
+ "BigQueryConfig",
28
+ "SnowflakeConfig",
29
+ "PrestoConfig",
30
+ "PostgresConfig",
31
+ "DialectConfig",
32
+ ]