pytrilogy 0.0.3.95__tar.gz → 0.0.3.97__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.

Potentially problematic release.


This version of pytrilogy might be problematic. Click here for more details.

Files changed (159) hide show
  1. {pytrilogy-0.0.3.95/pytrilogy.egg-info → pytrilogy-0.0.3.97}/PKG-INFO +44 -7
  2. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/README.md +43 -6
  3. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97/pytrilogy.egg-info}/PKG-INFO +44 -7
  4. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/pytrilogy.egg-info/SOURCES.txt +2 -1
  5. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/tests/test_executor.py +1 -1
  6. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/tests/test_parsing.py +49 -0
  7. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/__init__.py +1 -1
  8. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/authoring/__init__.py +59 -45
  9. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/constants.py +1 -0
  10. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/enums.py +9 -0
  11. pytrilogy-0.0.3.97/trilogy/core/exceptions.py +105 -0
  12. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/graph_models.py +4 -4
  13. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/statements/execute.py +2 -0
  14. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/validation/common.py +55 -3
  15. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/validation/concept.py +40 -25
  16. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/validation/datasource.py +38 -34
  17. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/validation/environment.py +4 -3
  18. pytrilogy-0.0.3.97/trilogy/core/validation/fix.py +106 -0
  19. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/dialect/base.py +10 -1
  20. pytrilogy-0.0.3.97/trilogy/dialect/metadata.py +233 -0
  21. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/executor.py +33 -163
  22. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/parsing/parse_engine.py +8 -6
  23. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/parsing/render.py +30 -3
  24. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/parsing/trilogy.lark +7 -4
  25. pytrilogy-0.0.3.95/trilogy/compiler.py +0 -0
  26. pytrilogy-0.0.3.95/trilogy/core/exceptions.py +0 -51
  27. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/LICENSE.md +0 -0
  28. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/pyproject.toml +0 -0
  29. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/pytrilogy.egg-info/dependency_links.txt +0 -0
  30. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/pytrilogy.egg-info/entry_points.txt +0 -0
  31. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/pytrilogy.egg-info/requires.txt +0 -0
  32. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/pytrilogy.egg-info/top_level.txt +0 -0
  33. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/setup.cfg +0 -0
  34. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/setup.py +0 -0
  35. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/tests/test_datatypes.py +0 -0
  36. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/tests/test_declarations.py +0 -0
  37. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/tests/test_derived_concepts.py +0 -0
  38. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/tests/test_discovery_nodes.py +0 -0
  39. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/tests/test_enums.py +0 -0
  40. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/tests/test_environment.py +0 -0
  41. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/tests/test_execute_models.py +0 -0
  42. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/tests/test_failure.py +0 -0
  43. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/tests/test_functions.py +0 -0
  44. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/tests/test_imports.py +0 -0
  45. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/tests/test_metadata.py +0 -0
  46. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/tests/test_models.py +0 -0
  47. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/tests/test_multi_join_assignments.py +0 -0
  48. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/tests/test_parse_engine.py +0 -0
  49. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/tests/test_parsing_failures.py +0 -0
  50. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/tests/test_partial_handling.py +0 -0
  51. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/tests/test_query_processing.py +0 -0
  52. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/tests/test_query_render.py +0 -0
  53. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/tests/test_select.py +0 -0
  54. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/tests/test_show.py +0 -0
  55. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/tests/test_statements.py +0 -0
  56. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/tests/test_typing.py +0 -0
  57. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/tests/test_undefined_concept.py +0 -0
  58. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/tests/test_user_functions.py +0 -0
  59. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/tests/test_where_clause.py +0 -0
  60. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/__init__.py +0 -0
  61. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/constants.py +0 -0
  62. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/env_processor.py +0 -0
  63. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/environment_helpers.py +0 -0
  64. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/ergonomics.py +0 -0
  65. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/functions.py +0 -0
  66. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/internal.py +0 -0
  67. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/models/__init__.py +0 -0
  68. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/models/author.py +0 -0
  69. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/models/build.py +0 -0
  70. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/models/build_environment.py +0 -0
  71. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/models/core.py +0 -0
  72. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/models/datasource.py +0 -0
  73. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/models/environment.py +0 -0
  74. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/models/execute.py +0 -0
  75. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/optimization.py +0 -0
  76. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/optimizations/__init__.py +0 -0
  77. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/optimizations/base_optimization.py +0 -0
  78. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/optimizations/inline_datasource.py +0 -0
  79. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/optimizations/predicate_pushdown.py +0 -0
  80. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/processing/__init__.py +0 -0
  81. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/processing/concept_strategies_v3.py +0 -0
  82. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/processing/discovery_loop.py +0 -0
  83. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/processing/discovery_node_factory.py +0 -0
  84. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/processing/discovery_utility.py +0 -0
  85. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/processing/discovery_validation.py +0 -0
  86. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/processing/graph_utils.py +0 -0
  87. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/processing/node_generators/__init__.py +0 -0
  88. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/processing/node_generators/basic_node.py +0 -0
  89. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/processing/node_generators/common.py +0 -0
  90. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/processing/node_generators/constant_node.py +0 -0
  91. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/processing/node_generators/filter_node.py +0 -0
  92. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/processing/node_generators/group_node.py +0 -0
  93. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/processing/node_generators/group_to_node.py +0 -0
  94. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/processing/node_generators/multiselect_node.py +0 -0
  95. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/processing/node_generators/node_merge_node.py +0 -0
  96. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/processing/node_generators/recursive_node.py +0 -0
  97. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/processing/node_generators/rowset_node.py +0 -0
  98. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/processing/node_generators/select_helpers/__init__.py +0 -0
  99. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/processing/node_generators/select_helpers/datasource_injection.py +0 -0
  100. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/processing/node_generators/select_merge_node.py +0 -0
  101. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/processing/node_generators/select_node.py +0 -0
  102. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/processing/node_generators/synonym_node.py +0 -0
  103. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/processing/node_generators/union_node.py +0 -0
  104. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/processing/node_generators/unnest_node.py +0 -0
  105. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/processing/node_generators/window_node.py +0 -0
  106. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/processing/nodes/__init__.py +0 -0
  107. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/processing/nodes/base_node.py +0 -0
  108. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/processing/nodes/filter_node.py +0 -0
  109. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/processing/nodes/group_node.py +0 -0
  110. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/processing/nodes/merge_node.py +0 -0
  111. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/processing/nodes/recursive_node.py +0 -0
  112. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/processing/nodes/select_node_v2.py +0 -0
  113. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/processing/nodes/union_node.py +0 -0
  114. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/processing/nodes/unnest_node.py +0 -0
  115. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/processing/nodes/window_node.py +0 -0
  116. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/processing/utility.py +0 -0
  117. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/query_processor.py +0 -0
  118. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/statements/__init__.py +0 -0
  119. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/statements/author.py +0 -0
  120. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/statements/build.py +0 -0
  121. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/statements/common.py +0 -0
  122. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/utility.py +0 -0
  123. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/core/validation/__init__.py +0 -0
  124. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/dialect/__init__.py +0 -0
  125. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/dialect/bigquery.py +0 -0
  126. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/dialect/common.py +0 -0
  127. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/dialect/config.py +0 -0
  128. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/dialect/dataframe.py +0 -0
  129. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/dialect/duckdb.py +0 -0
  130. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/dialect/enums.py +0 -0
  131. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/dialect/postgres.py +0 -0
  132. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/dialect/presto.py +0 -0
  133. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/dialect/snowflake.py +0 -0
  134. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/dialect/sql_server.py +0 -0
  135. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/engine.py +0 -0
  136. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/hooks/__init__.py +0 -0
  137. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/hooks/base_hook.py +0 -0
  138. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/hooks/graph_hook.py +0 -0
  139. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/hooks/query_debugger.py +0 -0
  140. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/metadata/__init__.py +0 -0
  141. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/parser.py +0 -0
  142. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/parsing/__init__.py +0 -0
  143. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/parsing/common.py +0 -0
  144. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/parsing/config.py +0 -0
  145. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/parsing/exceptions.py +0 -0
  146. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/parsing/helpers.py +0 -0
  147. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/py.typed +0 -0
  148. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/render.py +0 -0
  149. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/scripts/__init__.py +0 -0
  150. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/scripts/trilogy.py +0 -0
  151. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/std/__init__.py +0 -0
  152. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/std/date.preql +0 -0
  153. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/std/display.preql +0 -0
  154. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/std/geography.preql +0 -0
  155. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/std/money.preql +0 -0
  156. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/std/net.preql +0 -0
  157. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/std/ranking.preql +0 -0
  158. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/std/report.preql +0 -0
  159. {pytrilogy-0.0.3.95 → pytrilogy-0.0.3.97}/trilogy/utility.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pytrilogy
3
- Version: 0.0.3.95
3
+ Version: 0.0.3.97
4
4
  Summary: Declarative, typed query language that compiles to SQL.
5
5
  Home-page:
6
6
  Author:
@@ -136,11 +136,11 @@ Versus SQL, Trilogy aims to:
136
136
 
137
137
  | Backend | Status | Notes |
138
138
  |---------|--------|-------|
139
- | **BigQuery** | Core | Full support |
140
- | **DuckDB** | Core | Full support |
141
- | **Snowflake** | Core | Full support |
142
- | **SQL Server** | ⚠️ Experimental | Limited testing |
143
- | **Presto** | ⚠️ Experimental | Limited testing |
139
+ | **BigQuery** | Core | Full support |
140
+ | **DuckDB** | Core | Full support |
141
+ | **Snowflake** | Core | Full support |
142
+ | **SQL Server** | Experimental | Limited testing |
143
+ | **Presto** | Experimental | Limited testing |
144
144
 
145
145
  ## Examples
146
146
 
@@ -311,7 +311,44 @@ trilogy fmt <path to trilogy file>
311
311
  - [Public model repository](https://github.com/trilogydata/trilogy-public-models) - Great place for modeling examples
312
312
  - [Full documentation](https://trilogydata.dev/)
313
313
 
314
- ## Syntax Reference
314
+ ## Python API Integration
315
+
316
+ ### Root Imports
317
+
318
+ Are stable and should be sufficient for executing code from Trilogy as text.
319
+
320
+ ```python
321
+ from pytrilogy import Executor, Dialect
322
+ ```
323
+
324
+ ### Authoring Imports
325
+
326
+ Are also stable, and should be used for cases which programatically generate Trilogy statements without a base text format
327
+ or need to process/transform parsed code in more complicated ways.
328
+
329
+ ```python
330
+ from pytrilogy.authoring import Concept, Function, ...
331
+ ```
332
+
333
+ ### Other Imports
334
+
335
+ Are likely to be unstable. Open an issue if you need to take dependencies on other modules outside those two paths.
336
+
337
+ ## MCP/Server
338
+
339
+ Trilogy is straightforward to run as a server/MCP server; the former to generate SQL on demand and integrate into other tools, and MCP
340
+ for full interactive query loops.
341
+
342
+ This makes it easy to integrate Trilogy into existing tools or workflows.
343
+
344
+ You can see examples of both use cases in the trilogy-studio codebase [here](https://github.com/trilogy-data/trilogy-studio-core)
345
+ and install and run an MCP server directly with that codebase.
346
+
347
+ If you're interested in a more fleshed out standalone server or MCP server, please open an issue and we'll prioritize it!
348
+
349
+ ## Trilogy Syntax Reference
350
+
351
+ Not exhaustive - see [documentation](https://trilogydata.dev/) for more details.
315
352
 
316
353
  ### Import
317
354
  ```sql
@@ -98,11 +98,11 @@ Versus SQL, Trilogy aims to:
98
98
 
99
99
  | Backend | Status | Notes |
100
100
  |---------|--------|-------|
101
- | **BigQuery** | Core | Full support |
102
- | **DuckDB** | Core | Full support |
103
- | **Snowflake** | Core | Full support |
104
- | **SQL Server** | ⚠️ Experimental | Limited testing |
105
- | **Presto** | ⚠️ Experimental | Limited testing |
101
+ | **BigQuery** | Core | Full support |
102
+ | **DuckDB** | Core | Full support |
103
+ | **Snowflake** | Core | Full support |
104
+ | **SQL Server** | Experimental | Limited testing |
105
+ | **Presto** | Experimental | Limited testing |
106
106
 
107
107
  ## Examples
108
108
 
@@ -273,7 +273,44 @@ trilogy fmt <path to trilogy file>
273
273
  - [Public model repository](https://github.com/trilogydata/trilogy-public-models) - Great place for modeling examples
274
274
  - [Full documentation](https://trilogydata.dev/)
275
275
 
276
- ## Syntax Reference
276
+ ## Python API Integration
277
+
278
+ ### Root Imports
279
+
280
+ Are stable and should be sufficient for executing code from Trilogy as text.
281
+
282
+ ```python
283
+ from pytrilogy import Executor, Dialect
284
+ ```
285
+
286
+ ### Authoring Imports
287
+
288
+ Are also stable, and should be used for cases which programatically generate Trilogy statements without a base text format
289
+ or need to process/transform parsed code in more complicated ways.
290
+
291
+ ```python
292
+ from pytrilogy.authoring import Concept, Function, ...
293
+ ```
294
+
295
+ ### Other Imports
296
+
297
+ Are likely to be unstable. Open an issue if you need to take dependencies on other modules outside those two paths.
298
+
299
+ ## MCP/Server
300
+
301
+ Trilogy is straightforward to run as a server/MCP server; the former to generate SQL on demand and integrate into other tools, and MCP
302
+ for full interactive query loops.
303
+
304
+ This makes it easy to integrate Trilogy into existing tools or workflows.
305
+
306
+ You can see examples of both use cases in the trilogy-studio codebase [here](https://github.com/trilogy-data/trilogy-studio-core)
307
+ and install and run an MCP server directly with that codebase.
308
+
309
+ If you're interested in a more fleshed out standalone server or MCP server, please open an issue and we'll prioritize it!
310
+
311
+ ## Trilogy Syntax Reference
312
+
313
+ Not exhaustive - see [documentation](https://trilogydata.dev/) for more details.
277
314
 
278
315
  ### Import
279
316
  ```sql
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pytrilogy
3
- Version: 0.0.3.95
3
+ Version: 0.0.3.97
4
4
  Summary: Declarative, typed query language that compiles to SQL.
5
5
  Home-page:
6
6
  Author:
@@ -136,11 +136,11 @@ Versus SQL, Trilogy aims to:
136
136
 
137
137
  | Backend | Status | Notes |
138
138
  |---------|--------|-------|
139
- | **BigQuery** | Core | Full support |
140
- | **DuckDB** | Core | Full support |
141
- | **Snowflake** | Core | Full support |
142
- | **SQL Server** | ⚠️ Experimental | Limited testing |
143
- | **Presto** | ⚠️ Experimental | Limited testing |
139
+ | **BigQuery** | Core | Full support |
140
+ | **DuckDB** | Core | Full support |
141
+ | **Snowflake** | Core | Full support |
142
+ | **SQL Server** | Experimental | Limited testing |
143
+ | **Presto** | Experimental | Limited testing |
144
144
 
145
145
  ## Examples
146
146
 
@@ -311,7 +311,44 @@ trilogy fmt <path to trilogy file>
311
311
  - [Public model repository](https://github.com/trilogydata/trilogy-public-models) - Great place for modeling examples
312
312
  - [Full documentation](https://trilogydata.dev/)
313
313
 
314
- ## Syntax Reference
314
+ ## Python API Integration
315
+
316
+ ### Root Imports
317
+
318
+ Are stable and should be sufficient for executing code from Trilogy as text.
319
+
320
+ ```python
321
+ from pytrilogy import Executor, Dialect
322
+ ```
323
+
324
+ ### Authoring Imports
325
+
326
+ Are also stable, and should be used for cases which programatically generate Trilogy statements without a base text format
327
+ or need to process/transform parsed code in more complicated ways.
328
+
329
+ ```python
330
+ from pytrilogy.authoring import Concept, Function, ...
331
+ ```
332
+
333
+ ### Other Imports
334
+
335
+ Are likely to be unstable. Open an issue if you need to take dependencies on other modules outside those two paths.
336
+
337
+ ## MCP/Server
338
+
339
+ Trilogy is straightforward to run as a server/MCP server; the former to generate SQL on demand and integrate into other tools, and MCP
340
+ for full interactive query loops.
341
+
342
+ This makes it easy to integrate Trilogy into existing tools or workflows.
343
+
344
+ You can see examples of both use cases in the trilogy-studio codebase [here](https://github.com/trilogy-data/trilogy-studio-core)
345
+ and install and run an MCP server directly with that codebase.
346
+
347
+ If you're interested in a more fleshed out standalone server or MCP server, please open an issue and we'll prioritize it!
348
+
349
+ ## Trilogy Syntax Reference
350
+
351
+ Not exhaustive - see [documentation](https://trilogydata.dev/) for more details.
315
352
 
316
353
  ### Import
317
354
  ```sql
@@ -36,7 +36,6 @@ tests/test_undefined_concept.py
36
36
  tests/test_user_functions.py
37
37
  tests/test_where_clause.py
38
38
  trilogy/__init__.py
39
- trilogy/compiler.py
40
39
  trilogy/constants.py
41
40
  trilogy/engine.py
42
41
  trilogy/executor.py
@@ -117,6 +116,7 @@ trilogy/core/validation/common.py
117
116
  trilogy/core/validation/concept.py
118
117
  trilogy/core/validation/datasource.py
119
118
  trilogy/core/validation/environment.py
119
+ trilogy/core/validation/fix.py
120
120
  trilogy/dialect/__init__.py
121
121
  trilogy/dialect/base.py
122
122
  trilogy/dialect/bigquery.py
@@ -125,6 +125,7 @@ trilogy/dialect/config.py
125
125
  trilogy/dialect/dataframe.py
126
126
  trilogy/dialect/duckdb.py
127
127
  trilogy/dialect/enums.py
128
+ trilogy/dialect/metadata.py
128
129
  trilogy/dialect/postgres.py
129
130
  trilogy/dialect/presto.py
130
131
  trilogy/dialect/snowflake.py
@@ -2,7 +2,7 @@ from pathlib import Path
2
2
 
3
3
  from trilogy import Dialects, parse
4
4
  from trilogy.core.models.environment import Environment
5
- from trilogy.executor import MockResult, MockResultRow
5
+ from trilogy.dialect.metadata import MockResult, MockResultRow
6
6
 
7
7
 
8
8
  def test_file_parsing():
@@ -321,6 +321,55 @@ def test_the_comments():
321
321
  assert rendered == "null"
322
322
 
323
323
 
324
+ def test_the_comment_multiline():
325
+ env, parsed = parse_text(
326
+ """const
327
+ # comment here?
328
+ order_id <- 4; # this is the order id
329
+ # order ids are important
330
+
331
+ SELECT
332
+ # TOOD - add in more columns?
333
+ order_id
334
+ WHERE
335
+ # order_id should not be null
336
+ order_id
337
+ # in this comp
338
+ is not
339
+ null; # nulls are the worst
340
+
341
+ """
342
+ )
343
+ parsed[-1]
344
+ assert env.concepts["order_id"].metadata.description is not None
345
+ assert " this is the order id" in env.concepts["order_id"].metadata.description
346
+ assert " order ids are important" in env.concepts["order_id"].metadata.description
347
+
348
+
349
+ def test_the_comment_multiline_enter():
350
+ # we should not associate it as a description if there is a newline
351
+ env, parsed = parse_text(
352
+ """const
353
+ # comment here?
354
+ order_id <- 4;
355
+ # this is the order id
356
+ # order ids are important
357
+
358
+ SELECT
359
+ # TOOD - add in more columns?
360
+ order_id
361
+ WHERE
362
+ # order_id should not be null
363
+ order_id
364
+ # in this comp
365
+ is not
366
+ null; # nulls are the worst
367
+
368
+ """
369
+ )
370
+ assert env.concepts["order_id"].metadata.description is None
371
+
372
+
324
373
  def test_purpose_nesting():
325
374
  env, parsed = parse_text(
326
375
  """key year int;
@@ -4,6 +4,6 @@ from trilogy.dialect.enums import Dialects
4
4
  from trilogy.executor import Executor
5
5
  from trilogy.parser import parse
6
6
 
7
- __version__ = "0.0.3.95"
7
+ __version__ = "0.0.3.97"
8
8
 
9
9
  __all__ = ["parse", "Executor", "Dialects", "Environment", "CONFIG"]
@@ -60,68 +60,82 @@ from trilogy.core.statements.author import (
60
60
  RowsetDerivationStatement,
61
61
  SelectItem,
62
62
  SelectStatement,
63
+ ShowCategory,
64
+ ShowStatement,
65
+ ValidateStatement,
63
66
  )
64
67
  from trilogy.parsing.common import arbitrary_to_concept, arg_to_datatype
65
68
 
66
69
  __all__ = [
67
- "Concept",
68
- "Function",
69
- "WhereClause",
70
- "Comparison",
71
- "FilterItem",
72
- "CaseWhen",
73
- "CaseElse",
74
- "AggregateWrapper",
75
- "WindowItem",
76
- "WindowOrder",
77
- "WindowType",
78
- "WindowItemOrder",
79
- "WindowItemOver",
80
- "DataType",
81
- "StructType",
82
- "ArrayType",
83
- "NumericType",
84
- "Grain",
85
- "RowsetDerivationStatement",
86
- "MapType",
87
- "ListWrapper",
70
+ # trilogy.constants
71
+ "DEFAULT_NAMESPACE",
72
+ # trilogy.core.enums
73
+ "BooleanOperator",
74
+ "ComparisonOperator",
75
+ "FunctionClass",
88
76
  "FunctionType",
77
+ "InfiniteFunctionArgs",
78
+ "Ordering",
79
+ "Purpose",
80
+ # trilogy.core.functions
89
81
  "FunctionFactory",
90
- "ConceptDeclarationStatement",
91
- "ConceptTransform",
92
- "SelectItem",
93
- "SelectStatement",
94
- "Environment",
82
+ # trilogy.core.models.author
83
+ "AggregateWrapper",
84
+ "CaseElse",
85
+ "CaseWhen",
86
+ "Comparison",
87
+ "Concept",
95
88
  "ConceptRef",
89
+ "Conditional",
90
+ "FilterItem",
91
+ "Function",
92
+ "FunctionCallWrapper",
96
93
  "HavingClause",
97
94
  "MagicConstants",
98
95
  "Metadata",
96
+ "MultiSelectLineage",
99
97
  "OrderBy",
100
98
  "OrderItem",
101
99
  "Parenthetical",
100
+ "RowsetItem",
102
101
  "SubselectComparison",
103
- "Conditional",
104
- "BooleanOperator",
105
- "ComparisonOperator",
106
- "FunctionClass",
107
- "FunctionType",
108
- "InfiniteFunctionArgs",
109
- "Ordering",
110
- "Purpose",
111
- "DEFAULT_NAMESPACE",
112
- "arbitrary_to_concept",
113
- "arg_to_datatype",
114
- "MultiSelectStatement",
115
- "PersistStatement",
116
- "RawSQLStatement",
102
+ "WhereClause",
103
+ "WindowItem",
104
+ "WindowItemOrder",
105
+ "WindowItemOver",
106
+ "WindowOrder",
107
+ "WindowType",
108
+ # trilogy.core.models.core
109
+ "ArrayType",
110
+ "DataType",
111
+ "ListWrapper",
112
+ "MapType",
113
+ "NumericType",
114
+ "StructType",
115
+ "TraitDataType",
116
+ # trilogy.core.models.datasource
117
+ "Address",
117
118
  "Datasource",
118
119
  "DatasourceMetadata",
119
- "MultiSelectLineage",
120
- "RowsetItem",
121
- "FunctionCallWrapper",
120
+ # trilogy.core.models.environment
121
+ "Environment",
122
+ # trilogy.core.statements.author
123
+ "ConceptDeclarationStatement",
124
+ "ConceptTransform",
122
125
  "CopyStatement",
126
+ "Grain",
123
127
  "HasUUID",
124
128
  "ImportStatement",
125
- "Address",
126
- "TraitDataType",
129
+ "MultiSelectStatement",
130
+ "PersistStatement",
131
+ "RawSQLStatement",
132
+ "RowsetDerivationStatement",
133
+ "SelectItem",
134
+ "SelectStatement",
135
+ "ShowCategory",
136
+ "ShowStatement",
137
+ "ValidateStatement",
138
+ # trilogy.parsing.common
139
+ "arbitrary_to_concept",
140
+ "arg_to_datatype",
127
141
  ]
@@ -16,6 +16,7 @@ ENV_CACHE_NAME = ".preql_cache.json"
16
16
 
17
17
  class MagicConstants(Enum):
18
18
  NULL = "null"
19
+ LINE_SEPARATOR = "\n"
19
20
 
20
21
 
21
22
  NULL_VALUE = MagicConstants.NULL
@@ -82,6 +82,15 @@ class Modifier(Enum):
82
82
  return Modifier.NULLABLE
83
83
  return super()._missing_(value=strval.capitalize())
84
84
 
85
+ def __lt__(self, other):
86
+ order = [
87
+ Modifier.HIDDEN,
88
+ Modifier.PARTIAL,
89
+ Modifier.NULLABLE,
90
+ Modifier.OPTIONAL,
91
+ ]
92
+ return order.index(self) < order.index(other)
93
+
85
94
 
86
95
  class JoinType(Enum):
87
96
  INNER = "inner"
@@ -0,0 +1,105 @@
1
+ from dataclasses import dataclass
2
+ from typing import Any, List, Sequence
3
+
4
+ from trilogy.core.enums import Modifier
5
+ from trilogy.core.models.core import (
6
+ ArrayType,
7
+ DataType,
8
+ MapType,
9
+ NumericType,
10
+ StructType,
11
+ TraitDataType,
12
+ )
13
+
14
+
15
+ class UndefinedConceptException(Exception):
16
+ def __init__(self, message, suggestions: List[str]):
17
+ super().__init__(self, message)
18
+ self.message = message
19
+ self.suggestions = suggestions
20
+
21
+
22
+ class FrozenEnvironmentException(Exception):
23
+ pass
24
+
25
+
26
+ class InvalidSyntaxException(Exception):
27
+ pass
28
+
29
+
30
+ class UnresolvableQueryException(Exception):
31
+ pass
32
+
33
+
34
+ class NoDatasourceException(UnresolvableQueryException):
35
+ pass
36
+
37
+
38
+ class ModelValidationError(Exception):
39
+ def __init__(
40
+ self,
41
+ message,
42
+ children: Sequence["ModelValidationError"] | None = None,
43
+ **kwargs,
44
+ ):
45
+ super().__init__(self, message, **kwargs)
46
+ self.message = message
47
+ self.children = children
48
+
49
+
50
+ class DatasourceModelValidationError(ModelValidationError):
51
+ pass
52
+
53
+
54
+ class DatasourceGrainValidationError(DatasourceModelValidationError):
55
+ pass
56
+
57
+
58
+ @dataclass
59
+ class DatasourceColumnBindingData:
60
+ address: str
61
+ value: Any
62
+ value_type: (
63
+ DataType | ArrayType | StructType | MapType | NumericType | TraitDataType
64
+ )
65
+ value_modifiers: List[Modifier]
66
+ actual_type: (
67
+ DataType | ArrayType | StructType | MapType | NumericType | TraitDataType
68
+ )
69
+ actual_modifiers: List[Modifier]
70
+
71
+ def format_failure(self):
72
+ return f"Concept {self.address} value '{self.value}' with type {self.value_modifiers} does not conform to expected type {str(self.actual_type)} with modifiers {self.actual_modifiers}"
73
+
74
+ def is_modifier_issue(self) -> bool:
75
+ return len(self.value_modifiers) > 0 and any(
76
+ [x not in self.actual_modifiers for x in self.value_modifiers]
77
+ )
78
+
79
+ def is_type_issue(self) -> bool:
80
+ return self.value_type != self.actual_type
81
+
82
+
83
+ class DatasourceColumnBindingError(DatasourceModelValidationError):
84
+ def __init__(
85
+ self,
86
+ address: str,
87
+ errors: list[DatasourceColumnBindingData],
88
+ message: str | None = None,
89
+ ):
90
+ if not message:
91
+ message = f"Datasource {address} failed validation. Found rows that do not conform to types: {[failure.format_failure() for failure in errors]}"
92
+ super().__init__(message)
93
+ self.errors = errors
94
+ self.dataset_address = address
95
+
96
+
97
+ class ConceptModelValidationError(ModelValidationError):
98
+ pass
99
+
100
+
101
+ class AmbiguousRelationshipResolutionException(UnresolvableQueryException):
102
+ def __init__(self, message, parents: List[set[str]]):
103
+ super().__init__(self, message)
104
+ self.message = message
105
+ self.parents = parents
@@ -64,13 +64,13 @@ def datasource_to_node(input: BuildDatasource) -> str:
64
64
 
65
65
 
66
66
  class ReferenceGraph(nx.DiGraph):
67
- def __init__(self, *args, **kwargs):
67
+ def __init__(self, *args, **kwargs) -> None:
68
68
  super().__init__(*args, **kwargs)
69
69
  self.concepts: dict[str, BuildConcept] = {}
70
70
  self.datasources: dict[str, BuildDatasource] = {}
71
71
  self.pseudonyms: set[tuple[str, str]] = set()
72
72
 
73
- def copy(self):
73
+ def copy(self) -> "ReferenceGraph":
74
74
  g = ReferenceGraph()
75
75
  g.concepts = self.concepts.copy()
76
76
  g.datasources = self.datasources.copy()
@@ -83,7 +83,7 @@ class ReferenceGraph(nx.DiGraph):
83
83
  # g.add_edges_from(self.edges(data=True))
84
84
  return g
85
85
 
86
- def remove_node(self, n):
86
+ def remove_node(self, n) -> None:
87
87
  if n in self.concepts:
88
88
  del self.concepts[n]
89
89
  if n in self.datasources:
@@ -98,7 +98,7 @@ class ReferenceGraph(nx.DiGraph):
98
98
  self.datasources[node_name] = attr["datasource"]
99
99
  super().add_node(node_name, **attr)
100
100
 
101
- def add_datasource_node(self, node_name, datasource):
101
+ def add_datasource_node(self, node_name, datasource) -> None:
102
102
  self.datasources[node_name] = datasource
103
103
  super().add_node(node_name, datasource=datasource)
104
104
 
@@ -88,6 +88,8 @@ class ProcessedShowStatement:
88
88
  BuildConcept,
89
89
  BuildDatasource,
90
90
  ProcessedQuery,
91
+ ProcessedQueryPersist,
92
+ ProcessedCopyStatement,
91
93
  ProcessedValidateStatement,
92
94
  ProcessedStaticValueOutput,
93
95
  ]