pytrilogy 0.0.3.109__tar.gz → 0.0.3.111__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 (175) hide show
  1. {pytrilogy-0.0.3.109/pytrilogy.egg-info → pytrilogy-0.0.3.111}/PKG-INFO +2 -11
  2. pytrilogy-0.0.3.111/pyproject.toml +49 -0
  3. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111/pytrilogy.egg-info}/PKG-INFO +2 -11
  4. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/pytrilogy.egg-info/SOURCES.txt +1 -1
  5. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/pytrilogy.egg-info/top_level.txt +1 -0
  6. pytrilogy-0.0.3.111/requirements.txt +10 -0
  7. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/__init__.py +1 -1
  8. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/models/execute.py +2 -0
  9. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/processing/node_generators/multiselect_node.py +2 -1
  10. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/processing/nodes/base_node.py +3 -1
  11. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/processing/nodes/merge_node.py +1 -0
  12. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/query_processor.py +1 -0
  13. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/dialect/base.py +11 -0
  14. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/dialect/common.py +4 -9
  15. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/dialect/dataframe.py +3 -0
  16. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/dialect/duckdb.py +13 -1
  17. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/engine.py +6 -0
  18. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/executor.py +24 -3
  19. pytrilogy-0.0.3.109/pyproject.toml +0 -11
  20. pytrilogy-0.0.3.109/setup.py +0 -63
  21. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/LICENSE.md +0 -0
  22. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/README.md +0 -0
  23. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/pytrilogy.egg-info/dependency_links.txt +0 -0
  24. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/pytrilogy.egg-info/entry_points.txt +0 -0
  25. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/pytrilogy.egg-info/requires.txt +0 -0
  26. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/setup.cfg +0 -0
  27. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/tests/test_datatypes.py +0 -0
  28. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/tests/test_declarations.py +0 -0
  29. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/tests/test_derived_concepts.py +0 -0
  30. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/tests/test_discovery_nodes.py +0 -0
  31. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/tests/test_enums.py +0 -0
  32. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/tests/test_environment.py +0 -0
  33. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/tests/test_execute_models.py +0 -0
  34. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/tests/test_executor.py +0 -0
  35. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/tests/test_failure.py +0 -0
  36. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/tests/test_functions.py +0 -0
  37. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/tests/test_imports.py +0 -0
  38. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/tests/test_metadata.py +0 -0
  39. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/tests/test_models.py +0 -0
  40. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/tests/test_multi_join_assignments.py +0 -0
  41. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/tests/test_parse_engine.py +0 -0
  42. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/tests/test_parsing.py +0 -0
  43. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/tests/test_parsing_failures.py +0 -0
  44. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/tests/test_partial_handling.py +0 -0
  45. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/tests/test_query_processing.py +0 -0
  46. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/tests/test_query_render.py +0 -0
  47. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/tests/test_select.py +0 -0
  48. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/tests/test_show.py +0 -0
  49. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/tests/test_statements.py +0 -0
  50. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/tests/test_typing.py +0 -0
  51. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/tests/test_undefined_concept.py +0 -0
  52. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/tests/test_user_functions.py +0 -0
  53. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/tests/test_validators.py +0 -0
  54. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/tests/test_where_clause.py +0 -0
  55. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/ai/__init__.py +0 -0
  56. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/ai/constants.py +0 -0
  57. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/ai/conversation.py +0 -0
  58. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/ai/enums.py +0 -0
  59. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/ai/execute.py +0 -0
  60. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/ai/models.py +0 -0
  61. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/ai/prompts.py +0 -0
  62. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/ai/providers/__init__.py +0 -0
  63. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/ai/providers/anthropic.py +0 -0
  64. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/ai/providers/base.py +0 -0
  65. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/ai/providers/google.py +0 -0
  66. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/ai/providers/openai.py +0 -0
  67. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/ai/providers/utils.py +0 -0
  68. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/authoring/__init__.py +0 -0
  69. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/constants.py +0 -0
  70. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/__init__.py +0 -0
  71. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/constants.py +0 -0
  72. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/enums.py +0 -0
  73. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/env_processor.py +0 -0
  74. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/environment_helpers.py +0 -0
  75. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/ergonomics.py +0 -0
  76. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/exceptions.py +0 -0
  77. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/functions.py +0 -0
  78. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/graph_models.py +0 -0
  79. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/internal.py +0 -0
  80. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/models/__init__.py +0 -0
  81. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/models/author.py +0 -0
  82. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/models/build.py +0 -0
  83. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/models/build_environment.py +0 -0
  84. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/models/core.py +0 -0
  85. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/models/datasource.py +0 -0
  86. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/models/environment.py +0 -0
  87. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/optimization.py +0 -0
  88. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/optimizations/__init__.py +0 -0
  89. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/optimizations/base_optimization.py +0 -0
  90. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/optimizations/hide_unused_concept.py +0 -0
  91. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/optimizations/inline_datasource.py +0 -0
  92. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/optimizations/predicate_pushdown.py +0 -0
  93. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/processing/__init__.py +0 -0
  94. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/processing/concept_strategies_v3.py +0 -0
  95. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/processing/discovery_node_factory.py +0 -0
  96. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/processing/discovery_utility.py +0 -0
  97. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/processing/discovery_validation.py +0 -0
  98. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/processing/graph_utils.py +0 -0
  99. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/processing/node_generators/__init__.py +0 -0
  100. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/processing/node_generators/basic_node.py +0 -0
  101. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/processing/node_generators/common.py +0 -0
  102. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/processing/node_generators/constant_node.py +0 -0
  103. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/processing/node_generators/filter_node.py +0 -0
  104. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/processing/node_generators/group_node.py +0 -0
  105. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/processing/node_generators/group_to_node.py +0 -0
  106. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/processing/node_generators/node_merge_node.py +0 -0
  107. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/processing/node_generators/recursive_node.py +0 -0
  108. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/processing/node_generators/rowset_node.py +0 -0
  109. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/processing/node_generators/select_helpers/__init__.py +0 -0
  110. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/processing/node_generators/select_helpers/datasource_injection.py +0 -0
  111. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/processing/node_generators/select_merge_node.py +0 -0
  112. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/processing/node_generators/select_node.py +0 -0
  113. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/processing/node_generators/synonym_node.py +0 -0
  114. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/processing/node_generators/union_node.py +0 -0
  115. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/processing/node_generators/unnest_node.py +0 -0
  116. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/processing/node_generators/window_node.py +0 -0
  117. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/processing/nodes/__init__.py +0 -0
  118. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/processing/nodes/filter_node.py +0 -0
  119. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/processing/nodes/group_node.py +0 -0
  120. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/processing/nodes/recursive_node.py +0 -0
  121. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/processing/nodes/select_node_v2.py +0 -0
  122. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/processing/nodes/union_node.py +0 -0
  123. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/processing/nodes/unnest_node.py +0 -0
  124. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/processing/nodes/window_node.py +0 -0
  125. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/processing/utility.py +0 -0
  126. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/statements/__init__.py +0 -0
  127. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/statements/author.py +0 -0
  128. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/statements/build.py +0 -0
  129. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/statements/common.py +0 -0
  130. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/statements/execute.py +0 -0
  131. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/utility.py +0 -0
  132. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/validation/__init__.py +0 -0
  133. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/validation/common.py +0 -0
  134. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/validation/concept.py +0 -0
  135. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/validation/datasource.py +0 -0
  136. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/validation/environment.py +0 -0
  137. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/core/validation/fix.py +0 -0
  138. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/dialect/__init__.py +0 -0
  139. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/dialect/bigquery.py +0 -0
  140. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/dialect/config.py +0 -0
  141. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/dialect/enums.py +0 -0
  142. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/dialect/metadata.py +0 -0
  143. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/dialect/postgres.py +0 -0
  144. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/dialect/presto.py +0 -0
  145. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/dialect/snowflake.py +0 -0
  146. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/dialect/sql_server.py +0 -0
  147. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/hooks/__init__.py +0 -0
  148. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/hooks/base_hook.py +0 -0
  149. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/hooks/graph_hook.py +0 -0
  150. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/hooks/query_debugger.py +0 -0
  151. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/metadata/__init__.py +0 -0
  152. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/parser.py +0 -0
  153. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/parsing/__init__.py +0 -0
  154. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/parsing/common.py +0 -0
  155. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/parsing/config.py +0 -0
  156. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/parsing/exceptions.py +0 -0
  157. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/parsing/helpers.py +0 -0
  158. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/parsing/parse_engine.py +0 -0
  159. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/parsing/render.py +0 -0
  160. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/parsing/trilogy.lark +0 -0
  161. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/py.typed +0 -0
  162. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/render.py +0 -0
  163. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/scripts/__init__.py +0 -0
  164. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/scripts/trilogy.py +0 -0
  165. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/std/__init__.py +0 -0
  166. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/std/color.preql +0 -0
  167. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/std/date.preql +0 -0
  168. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/std/display.preql +0 -0
  169. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/std/geography.preql +0 -0
  170. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/std/metric.preql +0 -0
  171. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/std/money.preql +0 -0
  172. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/std/net.preql +0 -0
  173. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/std/ranking.preql +0 -0
  174. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/std/report.preql +0 -0
  175. {pytrilogy-0.0.3.109 → pytrilogy-0.0.3.111}/trilogy/utility.py +0 -0
@@ -1,16 +1,14 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pytrilogy
3
- Version: 0.0.3.109
3
+ Version: 0.0.3.111
4
4
  Summary: Declarative, typed query language that compiles to SQL.
5
- Home-page:
6
- Author:
7
- Author-email: preql-community@gmail.com
8
5
  Classifier: Programming Language :: Python
9
6
  Classifier: Programming Language :: Python :: 3
10
7
  Classifier: Programming Language :: Python :: 3.9
11
8
  Classifier: Programming Language :: Python :: 3.10
12
9
  Classifier: Programming Language :: Python :: 3.11
13
10
  Classifier: Programming Language :: Python :: 3.12
11
+ Classifier: Programming Language :: Python :: 3.13
14
12
  Description-Content-Type: text/markdown
15
13
  License-File: LICENSE.md
16
14
  Requires-Dist: lark
@@ -30,14 +28,7 @@ Provides-Extra: snowflake
30
28
  Requires-Dist: snowflake-sqlalchemy; extra == "snowflake"
31
29
  Provides-Extra: ai
32
30
  Requires-Dist: httpx; extra == "ai"
33
- Dynamic: author-email
34
- Dynamic: classifier
35
- Dynamic: description
36
- Dynamic: description-content-type
37
31
  Dynamic: license-file
38
- Dynamic: provides-extra
39
- Dynamic: requires-dist
40
- Dynamic: summary
41
32
 
42
33
  # Trilogy
43
34
  **SQL with superpowers for analytics**
@@ -0,0 +1,49 @@
1
+ [tool.pytest.ini_options]
2
+ markers = [
3
+ "adventureworks",
4
+ "adventureworks_execution",
5
+ ]
6
+ log_cli_level="INFO"
7
+
8
+ [tool.ruff]
9
+ # Allow lines to be as long as 200 characters.
10
+ line-length = 200
11
+ lint.extend-select = ["I"]
12
+
13
+ [project]
14
+ name = "pytrilogy"
15
+ description = "Declarative, typed query language that compiles to SQL."
16
+ dynamic = ["version", "dependencies"]
17
+ readme = {file = "README.md", content-type = "text/markdown"}
18
+ classifiers = [
19
+ "Programming Language :: Python",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.9",
22
+ "Programming Language :: Python :: 3.10",
23
+ "Programming Language :: Python :: 3.11",
24
+ "Programming Language :: Python :: 3.12",
25
+ "Programming Language :: Python :: 3.13",
26
+ ]
27
+
28
+ [project.scripts]
29
+ trilogy = "trilogy.scripts.trilogy:cli"
30
+
31
+ [project.optional-dependencies]
32
+ postgres = ["psycopg2-binary"]
33
+ bigquery = ["sqlalchemy-bigquery"]
34
+ snowflake = ["snowflake-sqlalchemy"]
35
+ ai = ["httpx"]
36
+
37
+ [tool.setuptools.dynamic]
38
+ version = {attr = "trilogy.__version__"}
39
+ dependencies = {file = ["requirements.txt"]}
40
+
41
+ [tool.setuptools]
42
+ packages = {find = {exclude = ["dist", "build", "*.tests", "*.tests.*", "tests.*", "tests", "docs", ".github", "examples"]}}
43
+
44
+ [tool.setuptools.package-data]
45
+ "*" = ["*.tf", "*.jinja", "py.typed", "*.lark", "*.preql"]
46
+
47
+ [build-system]
48
+ requires = ["setuptools>=61.0", "wheel"]
49
+ build-backend = "setuptools.build_meta"
@@ -1,16 +1,14 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pytrilogy
3
- Version: 0.0.3.109
3
+ Version: 0.0.3.111
4
4
  Summary: Declarative, typed query language that compiles to SQL.
5
- Home-page:
6
- Author:
7
- Author-email: preql-community@gmail.com
8
5
  Classifier: Programming Language :: Python
9
6
  Classifier: Programming Language :: Python :: 3
10
7
  Classifier: Programming Language :: Python :: 3.9
11
8
  Classifier: Programming Language :: Python :: 3.10
12
9
  Classifier: Programming Language :: Python :: 3.11
13
10
  Classifier: Programming Language :: Python :: 3.12
11
+ Classifier: Programming Language :: Python :: 3.13
14
12
  Description-Content-Type: text/markdown
15
13
  License-File: LICENSE.md
16
14
  Requires-Dist: lark
@@ -30,14 +28,7 @@ Provides-Extra: snowflake
30
28
  Requires-Dist: snowflake-sqlalchemy; extra == "snowflake"
31
29
  Provides-Extra: ai
32
30
  Requires-Dist: httpx; extra == "ai"
33
- Dynamic: author-email
34
- Dynamic: classifier
35
- Dynamic: description
36
- Dynamic: description-content-type
37
31
  Dynamic: license-file
38
- Dynamic: provides-extra
39
- Dynamic: requires-dist
40
- Dynamic: summary
41
32
 
42
33
  # Trilogy
43
34
  **SQL with superpowers for analytics**
@@ -1,7 +1,7 @@
1
1
  LICENSE.md
2
2
  README.md
3
3
  pyproject.toml
4
- setup.py
4
+ requirements.txt
5
5
  pytrilogy.egg-info/PKG-INFO
6
6
  pytrilogy.egg-info/SOURCES.txt
7
7
  pytrilogy.egg-info/dependency_links.txt
@@ -0,0 +1,10 @@
1
+ lark
2
+ jinja2
3
+ sqlalchemy<2.0.0
4
+ networkx
5
+ pyodbc
6
+ pydantic
7
+ #https://github.com/Mause/duckdb_engine/issues/1338 - remove as soon as fixed
8
+ duckdb<1.4.0
9
+ duckdb-engine
10
+ click
@@ -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.109"
7
+ __version__ = "0.0.3.111"
8
8
 
9
9
  __all__ = ["parse", "Executor", "Dialects", "Environment", "CONFIG"]
@@ -500,6 +500,7 @@ class BaseJoin(BaseModel):
500
500
  concepts: Optional[List[BuildConcept]] = None
501
501
  left_datasource: Optional[Union[BuildDatasource, "QueryDatasource"]] = None
502
502
  concept_pairs: list[ConceptPair] | None = None
503
+ modifiers: List[Modifier] = Field(default_factory=list)
503
504
 
504
505
  @model_validator(mode="after")
505
506
  def validate_join(self) -> "BaseJoin":
@@ -1103,6 +1104,7 @@ class Join(BaseModel):
1103
1104
  inlined_ctes: set[str] = Field(default_factory=set)
1104
1105
  quote: str | None = None
1105
1106
  condition: BuildConditional | BuildComparison | BuildParenthetical | None = None
1107
+ modifiers: List[Modifier] = Field(default_factory=list)
1106
1108
 
1107
1109
  def inline_cte(self, cte: CTE):
1108
1110
  self.inlined_ctes.add(cte.name)
@@ -3,7 +3,7 @@ from itertools import combinations
3
3
  from typing import List
4
4
 
5
5
  from trilogy.constants import logger
6
- from trilogy.core.enums import JoinType, Purpose
6
+ from trilogy.core.enums import JoinType, Modifier, Purpose
7
7
  from trilogy.core.models.build import (
8
8
  BuildConcept,
9
9
  BuildGrain,
@@ -47,6 +47,7 @@ def extra_align_joins(
47
47
  right_node=right,
48
48
  concepts=matched_concepts,
49
49
  join_type=JoinType.FULL,
50
+ modifiers=[Modifier.NULLABLE],
50
51
  )
51
52
  )
52
53
  return resolve_join_order(output)
@@ -1,11 +1,12 @@
1
1
  from collections import defaultdict
2
- from dataclasses import dataclass
2
+ from dataclasses import dataclass, field
3
3
  from typing import List, Optional
4
4
 
5
5
  from trilogy.core.enums import (
6
6
  BooleanOperator,
7
7
  Derivation,
8
8
  JoinType,
9
+ Modifier,
9
10
  SourceType,
10
11
  )
11
12
  from trilogy.core.models.build import (
@@ -436,6 +437,7 @@ class NodeJoin:
436
437
  join_type: JoinType
437
438
  filter_to_mutual: bool = False
438
439
  concept_pairs: list[ConceptPair] | None = None
440
+ modifiers: List[Modifier] = field(default_factory=list)
439
441
 
440
442
  def __post_init__(self):
441
443
  if self.left_node == self.right_node:
@@ -169,6 +169,7 @@ class MergeNode(StrategyNode):
169
169
  join_type=join.join_type,
170
170
  concepts=join.concepts,
171
171
  concept_pairs=join.concept_pairs,
172
+ modifiers=join.modifiers,
172
173
  )
173
174
  )
174
175
  return joins
@@ -122,6 +122,7 @@ def base_join_to_join(
122
122
  right_cte=right_cte,
123
123
  jointype=base_join.join_type,
124
124
  joinkey_pairs=final_pairs,
125
+ modifiers=base_join.modifiers,
125
126
  )
126
127
 
127
128
 
@@ -17,6 +17,7 @@ from trilogy.core.enums import (
17
17
  DatePart,
18
18
  FunctionType,
19
19
  GroupMode,
20
+ Modifier,
20
21
  Ordering,
21
22
  ShowCategory,
22
23
  UnnestMode,
@@ -89,6 +90,14 @@ from trilogy.core.utility import safe_quote
89
90
  from trilogy.dialect.common import render_join, render_unnest
90
91
  from trilogy.hooks.base_hook import BaseHook
91
92
 
93
+
94
+ def null_wrapper(lval: str, rval: str, modifiers: list[Modifier]) -> str:
95
+
96
+ if Modifier.NULLABLE in modifiers:
97
+ return f"({lval} = {rval} or ({lval} is null and {rval} is null))"
98
+ return f"{lval} = {rval}"
99
+
100
+
92
101
  LOGGER_PREFIX = "[RENDERING]"
93
102
 
94
103
  WINDOW_ITEMS = (BuildWindowItem,)
@@ -353,6 +362,7 @@ class BaseDialect:
353
362
  UNNEST_MODE = UnnestMode.CROSS_APPLY
354
363
  GROUP_MODE = GroupMode.AUTO
355
364
  EXPLAIN_KEYWORD = "EXPLAIN"
365
+ NULL_WRAPPER = staticmethod(null_wrapper)
356
366
 
357
367
  def __init__(self, rendering: Rendering | None = None):
358
368
  self.rendering = rendering or CONFIG.rendering
@@ -964,6 +974,7 @@ class BaseDialect:
964
974
  cte,
965
975
  use_map=self.used_map,
966
976
  unnest_mode=self.UNNEST_MODE,
977
+ null_wrapper=self.NULL_WRAPPER,
967
978
  )
968
979
  for join in final_joins
969
980
  ]
@@ -18,13 +18,6 @@ from trilogy.core.models.execute import (
18
18
  )
19
19
 
20
20
 
21
- def null_wrapper(lval: str, rval: str, modifiers: list[Modifier]) -> str:
22
-
23
- if Modifier.NULLABLE in modifiers:
24
- return f"({lval} = {rval} or ({lval} is null and {rval} is null))"
25
- return f"{lval} = {rval}"
26
-
27
-
28
21
  def render_unnest(
29
22
  unnest_mode: UnnestMode,
30
23
  quote_character: str,
@@ -88,6 +81,7 @@ def render_join(
88
81
  ],
89
82
  cte: CTE,
90
83
  use_map: dict[str, set[str]],
84
+ null_wrapper: Callable[[str, str, list[Modifier]], str],
91
85
  unnest_mode: UnnestMode = UnnestMode.CROSS_APPLY,
92
86
  ) -> str | None:
93
87
  # {% for key in join.joinkeys %}{{ key.inner }} = {{ key.outer}}{% endfor %}
@@ -135,9 +129,10 @@ def render_join(
135
129
  join.inlined_ctes,
136
130
  use_map=use_map,
137
131
  ),
138
- modifiers=pair.modifiers
132
+ pair.modifiers
139
133
  + (pair.left.modifiers or [])
140
- + (pair.right.modifiers or []),
134
+ + (pair.right.modifiers or [])
135
+ + (join.modifiers or []),
141
136
  )
142
137
  for pair in join.joinkey_pairs
143
138
  ]
@@ -45,3 +45,6 @@ class DataframeConnectionWrapper(ExecutionEngine):
45
45
 
46
46
  def connect(self) -> Any:
47
47
  return self.engine.connect()
48
+
49
+ def dispose(self, close=True):
50
+ return super().dispose(close)
@@ -3,7 +3,7 @@ from typing import Any, Callable, Mapping
3
3
 
4
4
  from jinja2 import Template
5
5
 
6
- from trilogy.core.enums import FunctionType, UnnestMode, WindowType
6
+ from trilogy.core.enums import FunctionType, Modifier, UnnestMode, WindowType
7
7
  from trilogy.core.models.core import DataType
8
8
  from trilogy.dialect.base import BaseDialect
9
9
 
@@ -12,6 +12,17 @@ WINDOW_FUNCTION_MAP: Mapping[WindowType, Callable[[Any, Any, Any], str]] = {}
12
12
  SENTINAL_AUTO_CAPTURE_GROUP_VALUE = "-1"
13
13
 
14
14
 
15
+ def null_wrapper(
16
+ lval: str,
17
+ rval: str,
18
+ modifiers: list[Modifier],
19
+ ) -> str:
20
+
21
+ if Modifier.NULLABLE in modifiers:
22
+ return f"{lval} is not distinct from {rval}"
23
+ return f"{lval} = {rval}"
24
+
25
+
15
26
  def generate_regex_extract(x: list[str]) -> str:
16
27
  if str(x[2]) == SENTINAL_AUTO_CAPTURE_GROUP_VALUE:
17
28
  regex = re.compile(x[1])
@@ -151,3 +162,4 @@ class DuckDBDialect(BaseDialect):
151
162
  QUOTE_CHARACTER = '"'
152
163
  SQL_TEMPLATE = DUCKDB_TEMPLATE
153
164
  UNNEST_MODE = UnnestMode.DIRECT
165
+ NULL_WRAPPER = staticmethod(null_wrapper)
@@ -33,6 +33,9 @@ class EngineConnection(Protocol):
33
33
  def rollback(self):
34
34
  raise NotImplementedError()
35
35
 
36
+ def close(self) -> None:
37
+ return
38
+
36
39
 
37
40
  class ExecutionEngine(Protocol):
38
41
  pass
@@ -43,6 +46,9 @@ class ExecutionEngine(Protocol):
43
46
  def setup(self, env: Environment, connection):
44
47
  pass
45
48
 
49
+ def dispose(self, close: bool = True):
50
+ pass
51
+
46
52
 
47
53
  ### Begin default SQLAlchemy implementation
48
54
  class SqlAlchemyResult:
@@ -47,7 +47,7 @@ from trilogy.dialect.metadata import (
47
47
  handle_processed_validate_statement,
48
48
  handle_show_statement_outputs,
49
49
  )
50
- from trilogy.engine import ExecutionEngine, ResultProtocol
50
+ from trilogy.engine import EngineConnection, ExecutionEngine, ResultProtocol
51
51
  from trilogy.hooks.base_hook import BaseHook
52
52
  from trilogy.parser import parse_text
53
53
  from trilogy.render import get_dialect_generator
@@ -69,11 +69,27 @@ class Executor(object):
69
69
  self.logger = logger
70
70
  self.hooks = hooks
71
71
  self.generator = get_dialect_generator(self.dialect, rendering)
72
- self.connection = self.engine.connect()
72
+ self.connection = self.connect()
73
73
  # TODO: make generic
74
74
  if self.dialect == Dialects.DATAFRAME:
75
75
  self.engine.setup(self.environment, self.connection)
76
76
 
77
+ def connect(self) -> EngineConnection:
78
+ self.connection = self.engine.connect()
79
+ self.connected = True
80
+ return self.connection
81
+
82
+ def close(self):
83
+ self.engine.dispose(close=True)
84
+ if self.dialect == Dialects.DUCK_DB:
85
+ import duckdb
86
+
87
+ duckdb.default_connection().close()
88
+ import gc
89
+
90
+ gc.collect()
91
+ self.connected = False
92
+
77
93
  def execute_statement(
78
94
  self,
79
95
  statement: PROCESSED_STATEMENT_TYPES,
@@ -244,7 +260,9 @@ class Executor(object):
244
260
  """generate SQL for execution"""
245
261
  _, parsed = parse_text(command, self.environment)
246
262
  generatable = [
247
- x for x in parsed if isinstance(x, (SelectStatement, PersistStatement))
263
+ x
264
+ for x in parsed
265
+ if isinstance(x, (SelectStatement, PersistStatement, MultiSelectStatement))
248
266
  ]
249
267
  sql = self.generator.generate_queries(
250
268
  self.environment, generatable, hooks=self.hooks
@@ -419,6 +437,9 @@ class Executor(object):
419
437
  def execute_text(
420
438
  self, command: str, non_interactive: bool = False
421
439
  ) -> List[ResultProtocol]:
440
+ if not self.connected:
441
+ self.connect()
442
+
422
443
  """Run a trilogy query expressed as text."""
423
444
  output: list[ResultProtocol] = []
424
445
  # connection = self.engine.connect()
@@ -1,11 +0,0 @@
1
- [tool.pytest.ini_options]
2
- markers = [
3
- "adventureworks",
4
- "adventureworks_execution",
5
- ]
6
- log_cli_level="INFO"
7
-
8
- [tool.ruff]
9
- # Allow lines to be as long as 200 characters.
10
- line-length = 200
11
- lint.extend-select = ["I"]
@@ -1,63 +0,0 @@
1
- # type: ignore
2
- import ast
3
- import re
4
-
5
- import setuptools
6
-
7
- _version_re = re.compile(r"__version__\s+=\s+(.*)")
8
- with open("trilogy/__init__.py", "rb") as f:
9
- _match = _version_re.search(f.read().decode("utf-8"))
10
- if _match is None:
11
- print("No version found")
12
- raise SystemExit(1)
13
- version = str(ast.literal_eval(_match.group(1)))
14
-
15
-
16
- with open("requirements.txt", "r") as f:
17
- install_requires = [line.strip().replace("==", ">=") for line in f.readlines()]
18
-
19
- setuptools.setup(
20
- name="pytrilogy",
21
- version=version,
22
- url="",
23
- author="",
24
- author_email="preql-community@gmail.com",
25
- description="Declarative, typed query language that compiles to SQL.",
26
- long_description=open("README.md").read(),
27
- long_description_content_type="text/markdown",
28
- packages=setuptools.find_packages(
29
- exclude=[
30
- "dist",
31
- "build",
32
- "*.tests",
33
- "*.tests.*",
34
- "tests.*",
35
- "tests",
36
- "docs",
37
- ".github",
38
- "",
39
- "examples",
40
- ]
41
- ),
42
- package_data={
43
- "": ["*.tf", "*.jinja", "py.typed", "*.lark", "*.preql"],
44
- },
45
- install_requires=install_requires,
46
- extras_require={
47
- "postgres": ["psycopg2-binary"],
48
- "bigquery": ["sqlalchemy-bigquery"],
49
- "snowflake": ["snowflake-sqlalchemy"],
50
- "ai": ["httpx"],
51
- },
52
- entry_points={
53
- "console_scripts": ["trilogy=trilogy.scripts.trilogy:cli"],
54
- },
55
- classifiers=[
56
- "Programming Language :: Python",
57
- "Programming Language :: Python :: 3",
58
- "Programming Language :: Python :: 3.9",
59
- "Programming Language :: Python :: 3.10",
60
- "Programming Language :: Python :: 3.11",
61
- "Programming Language :: Python :: 3.12",
62
- ],
63
- )
File without changes
File without changes
File without changes