pytrilogy 0.3.485__tar.gz → 0.3.487__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 (450) hide show
  1. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/PKG-INFO +1 -1
  2. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/__init__.py +1 -1
  3. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/optimizations/predicate_pushdown.py +23 -0
  4. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/aggregate_rollup.py +31 -1
  5. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/concept_strategies_v4.py +46 -7
  6. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_helper/group_graph.py +170 -104
  7. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_helper/source_planning.py +4 -15
  8. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/dependency/Cargo.lock +1 -1
  9. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/dependency/Cargo.toml +1 -1
  10. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/.scripts/__init__.py +0 -0
  11. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/.scripts/build_backend.py +0 -0
  12. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/.scripts/sync_version.py +0 -0
  13. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/LICENSE.md +0 -0
  14. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/README.md +0 -0
  15. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/pyproject.toml +0 -0
  16. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/ai/README.md +0 -0
  17. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/ai/__init__.py +0 -0
  18. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/ai/constants.py +0 -0
  19. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/ai/conversation.py +0 -0
  20. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/ai/enums.py +0 -0
  21. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/ai/execute.py +0 -0
  22. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/ai/models.py +0 -0
  23. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/ai/prompts.py +0 -0
  24. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/ai/providers/__init__.py +0 -0
  25. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/ai/providers/anthropic.py +0 -0
  26. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/ai/providers/base.py +0 -0
  27. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/ai/providers/deepseek.py +0 -0
  28. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/ai/providers/google.py +0 -0
  29. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/ai/providers/openai.py +0 -0
  30. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/ai/providers/openrouter.py +0 -0
  31. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/ai/providers/utils.py +0 -0
  32. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/ai/syntax_examples.py +0 -0
  33. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/authoring/README.md +0 -0
  34. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/authoring/__init__.py +0 -0
  35. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/constants.py +0 -0
  36. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/README.md +0 -0
  37. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/__init__.py +0 -0
  38. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/assertions.py +0 -0
  39. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/average_parts.py +0 -0
  40. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/casts.py +0 -0
  41. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/constants.py +0 -0
  42. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/domain_graph.py +0 -0
  43. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/domain_validation.py +0 -0
  44. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/enums.py +0 -0
  45. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/env_processor.py +0 -0
  46. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/environment_helpers.py +0 -0
  47. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/ergonomics.py +0 -0
  48. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/exceptions.py +0 -0
  49. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/fingerprint.py +0 -0
  50. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/functions.py +0 -0
  51. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/grain_pin.py +0 -0
  52. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/graph.py +0 -0
  53. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/graph_models.py +0 -0
  54. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/having_normalization.py +0 -0
  55. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/internal.py +0 -0
  56. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/like_patterns.py +0 -0
  57. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/models/__init__.py +0 -0
  58. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/models/author.py +0 -0
  59. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/models/build.py +0 -0
  60. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/models/build_environment.py +0 -0
  61. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/models/copying.py +0 -0
  62. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/models/core.py +0 -0
  63. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/models/datasource.py +0 -0
  64. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/models/environment.py +0 -0
  65. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/models/execute.py +0 -0
  66. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/models/keyspace.py +0 -0
  67. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/optimization.py +0 -0
  68. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/optimizations/__init__.py +0 -0
  69. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/optimizations/atom_contract.py +0 -0
  70. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/optimizations/base_optimization.py +0 -0
  71. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/optimizations/collapse_single_parent.py +0 -0
  72. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/optimizations/existence_having_fold.py +0 -0
  73. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/optimizations/filtered_aggregate.py +0 -0
  74. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/optimizations/full_join_lowering.py +0 -0
  75. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/optimizations/hide_unused_concept.py +0 -0
  76. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/optimizations/identity_group.py +0 -0
  77. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/optimizations/inline_datasource.py +0 -0
  78. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/optimizations/join_hoist.py +0 -0
  79. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/optimizations/join_upgrade.py +0 -0
  80. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/optimizations/merge_irrelevant_group_by.py +0 -0
  81. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/optimizations/null_safe_join.py +0 -0
  82. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/optimizations/order_inner_joins.py +0 -0
  83. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/optimizations/reuse_parent_lookup.py +0 -0
  84. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/optimizations/semi_join_pushdown.py +0 -0
  85. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/optimizations/strip_redundant_not_null.py +0 -0
  86. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/optimizations/union_dim_pushdown.py +0 -0
  87. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/optimizations/utils.py +0 -0
  88. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/optimizations/value_set_join_upgrade.py +0 -0
  89. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/README.md +0 -0
  90. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/__init__.py +0 -0
  91. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/basic_graph.py +0 -0
  92. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/condition_utility.py +0 -0
  93. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/constants.py +0 -0
  94. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/discovery_utility.py +0 -0
  95. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/discovery_validation.py +0 -0
  96. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/grain_utility.py +0 -0
  97. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/join_key_groups.py +0 -0
  98. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/join_resolution.py +0 -0
  99. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/model_ambiguity.py +0 -0
  100. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/node_generators/__init__.py +0 -0
  101. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/node_generators/common.py +0 -0
  102. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/node_generators/presence_probe.py +0 -0
  103. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/node_generators/select_helpers/__init__.py +0 -0
  104. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/node_generators/select_helpers/condition_routing.py +0 -0
  105. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/node_generators/select_helpers/datasource_injection.py +0 -0
  106. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/node_generators/select_helpers/datasource_nodes.py +0 -0
  107. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/node_generators/select_helpers/source_scoring.py +0 -0
  108. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/node_generators/select_merge_node.py +0 -0
  109. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/node_generators/select_node.py +0 -0
  110. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/nodes/README.md +0 -0
  111. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/nodes/__init__.py +0 -0
  112. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/nodes/base_node.py +0 -0
  113. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/nodes/filter_node.py +0 -0
  114. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/nodes/group_node.py +0 -0
  115. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/nodes/merge_node.py +0 -0
  116. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/nodes/recursive_node.py +0 -0
  117. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/nodes/select_node_v2.py +0 -0
  118. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/nodes/subselect_node.py +0 -0
  119. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/nodes/union_node.py +0 -0
  120. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/nodes/unnest_node.py +0 -0
  121. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/nodes/window_node.py +0 -0
  122. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/null_provenance.py +0 -0
  123. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/partial_bridging.py +0 -0
  124. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/plan_trace.py +0 -0
  125. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/plan_trace_model.py +0 -0
  126. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/relation_rollup.py +0 -0
  127. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/scan_partials.py +0 -0
  128. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/source_dominance.py +0 -0
  129. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/statement_scope.py +0 -0
  130. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/utility.py +0 -0
  131. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_helper/__init__.py +0 -0
  132. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_helper/concept_graph.py +0 -0
  133. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_helper/condition_injection.py +0 -0
  134. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_helper/condition_placement.py +0 -0
  135. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_helper/constants.py +0 -0
  136. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_helper/edges.py +0 -0
  137. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_helper/extent_ownership.py +0 -0
  138. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_helper/final_cover.py +0 -0
  139. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_helper/functional_dependency.py +0 -0
  140. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_helper/group_behaviors.py +0 -0
  141. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_helper/group_rules.py +0 -0
  142. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_helper/history.py +0 -0
  143. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_helper/join_plan.py +0 -0
  144. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_helper/keyspace.py +0 -0
  145. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_helper/models.py +0 -0
  146. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_helper/network_build.py +0 -0
  147. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_helper/network_coalescing.py +0 -0
  148. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_helper/network_model.py +0 -0
  149. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_helper/network_obligations.py +0 -0
  150. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_helper/network_search.py +0 -0
  151. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_helper/network_topology.py +0 -0
  152. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_helper/projection.py +0 -0
  153. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_helper/region_domains.py +0 -0
  154. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_helper/region_reads.py +0 -0
  155. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_helper/renders.py +0 -0
  156. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_helper/root_partition.py +0 -0
  157. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_helper/staged_where.py +0 -0
  158. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_helper/strategy_builder.py +0 -0
  159. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_helper/union_arms.py +0 -0
  160. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_node_generators/__init__.py +0 -0
  161. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_node_generators/aggregate.py +0 -0
  162. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_node_generators/basic.py +0 -0
  163. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_node_generators/common.py +0 -0
  164. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_node_generators/condition_sources.py +0 -0
  165. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_node_generators/constant.py +0 -0
  166. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_node_generators/dispatch.py +0 -0
  167. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_node_generators/filter.py +0 -0
  168. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_node_generators/group_to.py +0 -0
  169. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_node_generators/multiselect.py +0 -0
  170. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_node_generators/nested_select.py +0 -0
  171. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_node_generators/recursive.py +0 -0
  172. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_node_generators/root.py +0 -0
  173. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_node_generators/rowset.py +0 -0
  174. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_node_generators/rowset_witness.py +0 -0
  175. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_node_generators/subselect.py +0 -0
  176. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_node_generators/union.py +0 -0
  177. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_node_generators/union_select.py +0 -0
  178. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_node_generators/unnest.py +0 -0
  179. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/processing/v4_node_generators/window.py +0 -0
  180. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/query_processor.py +0 -0
  181. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/scope_diagnostics.py +0 -0
  182. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/statements/README.md +0 -0
  183. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/statements/__init__.py +0 -0
  184. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/statements/author.py +0 -0
  185. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/statements/build.py +0 -0
  186. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/statements/common.py +0 -0
  187. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/statements/execute.py +0 -0
  188. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/table_processor.py +0 -0
  189. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/union_find.py +0 -0
  190. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/utility.py +0 -0
  191. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/validation/README.md +0 -0
  192. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/validation/__init__.py +0 -0
  193. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/validation/common.py +0 -0
  194. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/validation/concept.py +0 -0
  195. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/validation/datasource.py +0 -0
  196. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/validation/environment.py +0 -0
  197. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/validation/fix.py +0 -0
  198. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/validation/rows.py +0 -0
  199. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/core/where_scope_normalization.py +0 -0
  200. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/dialect/__init__.py +0 -0
  201. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/dialect/base.py +0 -0
  202. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/dialect/bigquery.py +0 -0
  203. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/dialect/bigquery_engine.py +0 -0
  204. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/dialect/bigquery_persist.py +0 -0
  205. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/dialect/bigquery_staging.py +0 -0
  206. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/dialect/cancel.py +0 -0
  207. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/dialect/clickhouse.py +0 -0
  208. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/dialect/clickhouse_chdb.py +0 -0
  209. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/dialect/common.py +0 -0
  210. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/dialect/config.py +0 -0
  211. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/dialect/dataframe.py +0 -0
  212. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/dialect/duckdb.py +0 -0
  213. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/dialect/duckdb_pool.py +0 -0
  214. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/dialect/duckdb_uv.py +0 -0
  215. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/dialect/duckdb_vgi.py +0 -0
  216. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/dialect/enums.py +0 -0
  217. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/dialect/haybarn_engine.py +0 -0
  218. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/dialect/metadata.py +0 -0
  219. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/dialect/mock.py +0 -0
  220. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/dialect/mock_pattern.py +0 -0
  221. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/dialect/mysql.py +0 -0
  222. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/dialect/postgres.py +0 -0
  223. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/dialect/presto.py +0 -0
  224. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/dialect/python_source.py +0 -0
  225. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/dialect/results.py +0 -0
  226. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/dialect/snowflake.py +0 -0
  227. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/dialect/source_pushdown.py +0 -0
  228. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/dialect/sql_server.py +0 -0
  229. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/dialect/sqlite.py +0 -0
  230. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/dialect/table_function.py +0 -0
  231. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/engine.py +0 -0
  232. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/execution/__init__.py +0 -0
  233. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/execution/assertions.py +0 -0
  234. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/execution/client_copy.py +0 -0
  235. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/execution/config.py +0 -0
  236. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/execution/envs.py +0 -0
  237. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/execution/model_fingerprint.py +0 -0
  238. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/execution/outputs.py +0 -0
  239. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/execution/report.py +0 -0
  240. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/execution/staged_write.py +0 -0
  241. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/execution/state/AGENTS.md +0 -0
  242. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/execution/state/CLAUDE.md +0 -0
  243. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/execution/state/__init__.py +0 -0
  244. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/execution/state/cache.py +0 -0
  245. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/execution/state/declaration.py +0 -0
  246. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/execution/state/exceptions.py +0 -0
  247. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/execution/state/isolation.py +0 -0
  248. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/execution/state/partitions.py +0 -0
  249. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/execution/state/persistence.py +0 -0
  250. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/execution/state/phases.py +0 -0
  251. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/execution/state/snapshot.py +0 -0
  252. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/execution/state/state_store.py +0 -0
  253. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/execution/state/watermarks.py +0 -0
  254. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/execution/write_order.py +0 -0
  255. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/executor.py +0 -0
  256. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/hooks/__init__.py +0 -0
  257. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/hooks/base_hook.py +0 -0
  258. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/hooks/graph_hook.py +0 -0
  259. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/hooks/query_debugger.py +0 -0
  260. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/io/__init__.py +0 -0
  261. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/io/adapters.py +0 -0
  262. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/io/arrow.py +0 -0
  263. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/io/click_support.py +0 -0
  264. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/io/contract.py +0 -0
  265. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/io/describe.py +0 -0
  266. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/io/errors.py +0 -0
  267. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/io/runner.py +0 -0
  268. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/io/sinks.py +0 -0
  269. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/io/vgi.py +0 -0
  270. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/metadata/__init__.py +0 -0
  271. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parser.py +0 -0
  272. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/README.md +0 -0
  273. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/__init__.py +0 -0
  274. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/common.py +0 -0
  275. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/exceptions.py +0 -0
  276. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/helpers.py +0 -0
  277. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/parse_engine_v2.py +0 -0
  278. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/pretty.py +0 -0
  279. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/render.py +0 -0
  280. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/trilogy.lark +0 -0
  281. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/README.md +0 -0
  282. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/__init__.py +0 -0
  283. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/concept_syntax.py +0 -0
  284. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/errors.py +0 -0
  285. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/function_syntax.py +0 -0
  286. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/hydration.py +0 -0
  287. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/import_service.py +0 -0
  288. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/lark_backend.py +0 -0
  289. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/model.py +0 -0
  290. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/pest_backend.py +0 -0
  291. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/rowset_semantics.py +0 -0
  292. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/rules/__init__.py +0 -0
  293. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/rules/chart_rules.py +0 -0
  294. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/rules/concept_rules.py +0 -0
  295. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/rules/conditional_rules.py +0 -0
  296. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/rules/datasource_rules.py +0 -0
  297. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/rules/expression_rules.py +0 -0
  298. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/rules/function_definition_rules.py +0 -0
  299. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/rules/function_rules.py +0 -0
  300. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/rules/import_rules.py +0 -0
  301. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/rules/merge_rules.py +0 -0
  302. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/rules/multiselect_rules.py +0 -0
  303. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/rules/operational_rules.py +0 -0
  304. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/rules/order_rules.py +0 -0
  305. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/rules/persist_rules.py +0 -0
  306. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/rules/rawsql_rules.py +0 -0
  307. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/rules/rowset_rules.py +0 -0
  308. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/rules/select_rules.py +0 -0
  309. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/rules/select_statement_rules.py +0 -0
  310. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/rules/statement_rules.py +0 -0
  311. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/rules/subselect_rules.py +0 -0
  312. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/rules/token_rules.py +0 -0
  313. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/rules/tvf_rules.py +0 -0
  314. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/rules/type_rules.py +0 -0
  315. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/rules_context.py +0 -0
  316. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/select_finalize.py +0 -0
  317. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/semantic_scope.py +0 -0
  318. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/semantic_state.py +0 -0
  319. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/statement_planner.py +0 -0
  320. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/statement_plans.py +0 -0
  321. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/symbols.py +0 -0
  322. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/parsing/v2/syntax.py +0 -0
  323. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/py.typed +0 -0
  324. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/render.py +0 -0
  325. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/rendering/__init__.py +0 -0
  326. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/rendering/altair_renderer.py +0 -0
  327. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/rendering/base.py +0 -0
  328. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/rendering/chart_theme.py +0 -0
  329. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/rendering/rich_types.py +0 -0
  330. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/rendering/terminal_renderer.py +0 -0
  331. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/rendering/theme.py +0 -0
  332. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/report/__init__.py +0 -0
  333. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/report/backends/__init__.py +0 -0
  334. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/report/backends/base.py +0 -0
  335. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/report/backends/html.py +0 -0
  336. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/report/backends/png.py +0 -0
  337. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/report/charts.py +0 -0
  338. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/report/document.py +0 -0
  339. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/report/runner.py +0 -0
  340. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/report/tables.py +0 -0
  341. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/AGENTS.md +0 -0
  342. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/CLAUDE.md +0 -0
  343. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/README.md +0 -0
  344. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/__init__.py +0 -0
  345. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/agent.py +0 -0
  346. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/agent_info.py +0 -0
  347. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/agent_info_docs/__init__.py +0 -0
  348. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/agent_info_docs/cli.py +0 -0
  349. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/agent_info_docs/content.py +0 -0
  350. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/agent_info_docs/directory.py +0 -0
  351. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/agent_sessions.py +0 -0
  352. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/agent_sql_tools.py +0 -0
  353. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/agent_tools.py +0 -0
  354. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/click_utils.py +0 -0
  355. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/cloud.py +0 -0
  356. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/cloud_models.py +0 -0
  357. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/common.py +0 -0
  358. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/database.py +0 -0
  359. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/dependency/README.md +0 -0
  360. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/dependency/build.sh +0 -0
  361. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/dependency/examples/basic_usage.rs +0 -0
  362. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/dependency/src/directory_resolver.rs +0 -0
  363. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/dependency/src/graph.rs +0 -0
  364. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/dependency/src/lib.rs +0 -0
  365. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/dependency/src/main.rs +0 -0
  366. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/dependency/src/network_search.rs +0 -0
  367. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/dependency/src/parser.rs +0 -0
  368. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/dependency/src/python_bindings.rs +0 -0
  369. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/dependency/src/resolver.rs +0 -0
  370. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/dependency/src/trilogy.pest +0 -0
  371. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/dependency/src/trilogy_parser.rs +0 -0
  372. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/dependency/tests/base.preql +0 -0
  373. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/dependency/tests/cli_integration.rs +0 -0
  374. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/dependency/tests/customer.preql +0 -0
  375. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/dependency/tests/main.preql +0 -0
  376. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/dependency/tests/orders.preql +0 -0
  377. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/dependency/tests/parse_cost.rs +0 -0
  378. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/dependency/tests/public_api.rs +0 -0
  379. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/dependency/tests/test_data/base.preql +0 -0
  380. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/dependency/tests/test_data/consumer.preql +0 -0
  381. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/dependency.py +0 -0
  382. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/display.py +0 -0
  383. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/display_core.py +0 -0
  384. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/display_execution.py +0 -0
  385. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/display_ingest.py +0 -0
  386. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/display_init.py +0 -0
  387. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/display_models.py +0 -0
  388. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/display_parallel.py +0 -0
  389. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/display_refresh.py +0 -0
  390. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/display_validation.py +0 -0
  391. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/env_commands.py +0 -0
  392. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/environment.py +0 -0
  393. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/explore.py +0 -0
  394. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/explore_seen.py +0 -0
  395. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/file.py +0 -0
  396. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/file_helpers/__init__.py +0 -0
  397. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/file_helpers/backends.py +0 -0
  398. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/file_helpers/preql_description.py +0 -0
  399. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/file_helpers/preql_validation.py +0 -0
  400. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/fmt.py +0 -0
  401. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/ingest.py +0 -0
  402. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/ingest_helpers/__init__.py +0 -0
  403. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/ingest_helpers/fk_inference.py +0 -0
  404. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/ingest_helpers/foreign_keys.py +0 -0
  405. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/ingest_helpers/formatting.py +0 -0
  406. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/ingest_helpers/introspection.py +0 -0
  407. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/ingest_helpers/typing.py +0 -0
  408. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/init.py +0 -0
  409. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/parallel_execution.py +0 -0
  410. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/plan.py +0 -0
  411. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/project_config.py +0 -0
  412. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/public.py +0 -0
  413. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/refresh.py +0 -0
  414. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/render.py +0 -0
  415. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/run.py +0 -0
  416. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/serve.py +0 -0
  417. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/serve_helpers/__init__.py +0 -0
  418. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/serve_helpers/connection_spec.py +0 -0
  419. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/serve_helpers/file_discovery.py +0 -0
  420. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/serve_helpers/index_generation.py +0 -0
  421. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/serve_helpers/jobs.py +0 -0
  422. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/serve_helpers/mcp_server.py +0 -0
  423. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/serve_helpers/models.py +0 -0
  424. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/serve_helpers/state_cache.py +0 -0
  425. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/serve_helpers/state_computation.py +0 -0
  426. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/serve_helpers/studio_bundle.py +0 -0
  427. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/single_execution.py +0 -0
  428. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/source.py +0 -0
  429. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/source_identity.py +0 -0
  430. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/state.py +0 -0
  431. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/testing.py +0 -0
  432. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/trilogy.py +0 -0
  433. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/scripts/validate_agent.py +0 -0
  434. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/staging.py +0 -0
  435. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/std/__init__.py +0 -0
  436. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/std/bytes.preql +0 -0
  437. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/std/chart.preql +0 -0
  438. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/std/collection.preql +0 -0
  439. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/std/color.preql +0 -0
  440. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/std/currency.preql +0 -0
  441. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/std/date.preql +0 -0
  442. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/std/display.preql +0 -0
  443. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/std/geography.preql +0 -0
  444. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/std/metric.preql +0 -0
  445. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/std/money.preql +0 -0
  446. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/std/net.preql +0 -0
  447. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/std/ranking.preql +0 -0
  448. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/std/report.preql +0 -0
  449. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/std/semantic.preql +0 -0
  450. {pytrilogy-0.3.485 → pytrilogy-0.3.487}/trilogy/utility.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pytrilogy
3
- Version: 0.3.485
3
+ Version: 0.3.487
4
4
  Classifier: Programming Language :: Python
5
5
  Classifier: Programming Language :: Python :: 3
6
6
  Classifier: Programming Language :: Python :: 3.11
@@ -7,7 +7,7 @@ if TYPE_CHECKING:
7
7
  from trilogy.executor import Executor
8
8
  from trilogy.parser import parse
9
9
 
10
- __version__ = "0.3.485"
10
+ __version__ = "0.3.487"
11
11
 
12
12
  __all__ = [
13
13
  "CONFIG",
@@ -169,6 +169,23 @@ def _parent_holds_the_same_concepts(candidate: BuildConceptArgs, parent: CTE) ->
169
169
  )
170
170
 
171
171
 
172
+ def _parent_holds_partial(
173
+ candidate: BuildConceptArgs,
174
+ parent: CTE,
175
+ inverse_map: dict[str, list[CTE | UnionCTE]],
176
+ ) -> bool:
177
+ """A child of `parent` re-aggregates a column the predicate reads under
178
+ the same address, so `parent` holds one partial per finer group, not the
179
+ value the predicate tests (`Rollup.coarse_gate_on_partial_misfilters`)."""
180
+ rolled = {
181
+ c.address
182
+ for child in inverse_map.get(parent.name, [])
183
+ if isinstance(child, CTE) and child.group_to_grain
184
+ for c in child.rollup_concepts
185
+ }
186
+ return any(arg.address in rolled for arg in candidate.row_arguments)
187
+
188
+
172
189
  def _parent_materialized_addrs(parent: CTE | UnionCTE) -> set[str]:
173
190
  """Addresses a parent CTE exposes as plain output columns: a non-empty
174
191
  ``source_map`` entry means the concept is pulled from upstream rather than
@@ -569,6 +586,12 @@ class PredicatePushdown(OptimizationRule):
569
586
  return False
570
587
  if not _parent_holds_the_same_concepts(candidate, parent_cte):
571
588
  return False
589
+ if _parent_holds_partial(candidate, parent_cte, inverse_map):
590
+ self.debug(
591
+ f"{parent_cte.name} holds a partial of {candidate}'s value that a "
592
+ "child re-aggregates under the same address; not pushing"
593
+ )
594
+ return False
572
595
  materialized = _rendered_source_columns(parent_cte)
573
596
 
574
597
  if not row_conditions or not materialized:
@@ -212,20 +212,36 @@ def _conditions_supported(
212
212
  datasource: BuildDatasource,
213
213
  conditions: BuildWhereClause | None,
214
214
  concepts_by_address: Mapping[str, BuildConcept] | None = None,
215
+ joined: bool = False,
215
216
  ) -> bool:
217
+ """With `joined`, an aggregate at a grain inside the summary's
218
+ (`sum(x) by city` beside `(city, species)`) is a function of its key, which
219
+ the joined plan computes in its own group and joins back
220
+ (`Rollup.coarse_group_value_filter_exact`). A scan of the summary alone
221
+ would read the stored partial as that value."""
216
222
  if not conditions:
217
223
  return True
224
+ grain = set(datasource.grain.components)
218
225
  return _concepts_reachable(
219
226
  datasource,
220
227
  [
221
228
  c
222
229
  for c in conditions.row_arguments
223
230
  if c.granularity != Granularity.SINGLE_ROW
231
+ and not (joined and _keyed_aggregate(c, grain))
224
232
  ],
225
233
  concepts_by_address,
226
234
  )
227
235
 
228
236
 
237
+ def _keyed_aggregate(concept: BuildConcept, grain: set[str]) -> bool:
238
+ return (
239
+ concept.derivation == Derivation.AGGREGATE
240
+ and bool(concept.grain.components)
241
+ and concept.grain.components <= grain
242
+ )
243
+
244
+
229
245
  def filter_finer_row_args(
230
246
  conditions: BuildWhereClause | None,
231
247
  target_grain: BuildGrain,
@@ -244,6 +260,20 @@ def filter_finer_row_args(
244
260
  ]
245
261
 
246
262
 
263
+ def joinable_property(
264
+ concept: BuildConcept | None, datasource: BuildDatasource
265
+ ) -> bool:
266
+ """A dimension's column keyed on `datasource`'s grain: a join onto its rows
267
+ supplies it at that grain."""
268
+ return (
269
+ concept is not None
270
+ and concept.lineage is None
271
+ and concept.purpose == Purpose.PROPERTY
272
+ and bool(concept.keys)
273
+ and set(concept.keys or ()) <= set(datasource.grain.components)
274
+ )
275
+
276
+
247
277
  def finer_than_grain(
248
278
  concept: BuildConcept,
249
279
  grain: BuildGrain,
@@ -351,7 +381,7 @@ def get_rollup_concepts(
351
381
  """The requested aggregates `datasource` rolls up to `target_grain`. With
352
382
  `joined`, `agg(x ? c)` may read `c` from a join onto the summary's rows
353
383
  (`_datasource_has_matching_rollup_aggregate`)."""
354
- if not _conditions_supported(datasource, conditions, concepts_by_address):
384
+ if not _conditions_supported(datasource, conditions, concepts_by_address, joined):
355
385
  return []
356
386
  reach = concepts_by_address if joined else None
357
387
 
@@ -28,7 +28,7 @@ from contextlib import nullcontext
28
28
 
29
29
  from trilogy.constants import logger
30
30
  from trilogy.core import graph as nx
31
- from trilogy.core.enums import Derivation
31
+ from trilogy.core.enums import Derivation, Granularity
32
32
  from trilogy.core.exceptions import UnbuiltGroupException
33
33
  from trilogy.core.graph_models import ReferenceGraph
34
34
  from trilogy.core.models.build import (
@@ -52,6 +52,7 @@ from trilogy.core.processing.aggregate_rollup import (
52
52
  at_own_grain,
53
53
  filter_finer_row_args,
54
54
  holds_every_kept_row,
55
+ joinable_property,
55
56
  source_rollup_concepts,
56
57
  sourced_arguments,
57
58
  )
@@ -849,7 +850,14 @@ def _rollup_sources(
849
850
  summaries read."""
850
851
  out: list[BuildDatasource] = []
851
852
  sources: list[BuildDatasource | BuildUnionDatasource] = [*datasources, *unions]
853
+ gated = _coarse_gate_beside_row_columns(where, target_grain)
852
854
  for source in sources:
855
+ if (
856
+ gated
857
+ and isinstance(source, BuildDatasource)
858
+ and _coarse_gate(where, source)
859
+ ):
860
+ continue
853
861
  if not holds_every_kept_row(source, where):
854
862
  continue
855
863
  if isinstance(source, BuildDatasource) and not (
@@ -882,6 +890,33 @@ def _rollup_sources(
882
890
  return out
883
891
 
884
892
 
893
+ def _coarse_gate(where: BuildWhereClause | None, source: BuildDatasource) -> bool:
894
+ """The WHERE reads an aggregate at a grain inside `source`'s but not at
895
+ it (`sum(x) by city` beside `(city, species)`): its value is a re-sum the
896
+ joined plan computes in its own group."""
897
+ grain = set(source.grain.components)
898
+ return where is not None and any(
899
+ c.derivation == Derivation.AGGREGATE
900
+ and c.granularity != Granularity.SINGLE_ROW
901
+ and set(c.grain.components) < grain
902
+ for c in where.row_arguments
903
+ )
904
+
905
+
906
+ def _coarse_gate_beside_row_columns(
907
+ where: BuildWhereClause | None, target_grain: BuildGrain
908
+ ) -> bool:
909
+ """A row column beside the gate that the target does not group by
910
+ (`species != 'Tilia'` at `tree_form`) widens the pinned request past the
911
+ target, and the search that takes over re-aggregates the gate at it."""
912
+ return where is not None and any(
913
+ not c.is_aggregate
914
+ and c.granularity != Granularity.SINGLE_ROW
915
+ and c.address not in target_grain.components
916
+ for c in where.row_arguments
917
+ )
918
+
919
+
885
920
  def _nested_rollup_roots(
886
921
  mandatory_list: list[BuildConcept],
887
922
  roots: set[str],
@@ -988,13 +1023,10 @@ def _finer_filter_reaches_rollup(
988
1023
  demands = [c for c in mandatory_list if c.address not in rolled_roots]
989
1024
  assert where is not None
990
1025
  # an atom over a stored aggregate filters only the pinned scan's own rows,
991
- # so every other demand must be a column of that scan
1026
+ # so every other demand must be a column of that scan, or a dimension's
1027
+ # column keyed on its grain (`_plan_joined_filter_rollup` joins it on)
992
1028
  if not is_scalar_condition(where.conditional):
993
- return any(
994
- {c.canonical_address for c in demands}
995
- <= {c.canonical_address for c in ds.output_concepts}
996
- for ds in rollup_sources
997
- )
1029
+ return any(_rides_summary_scan(demands, ds) for ds in rollup_sources)
998
1030
  reached = walk_lineage(
999
1031
  [c for c in mandatory_list if c.address not in rolled_roots],
1000
1032
  descend=lambda c: c.address not in rolled_roots,
@@ -1024,6 +1056,13 @@ def _finer_filter_reaches_rollup(
1024
1056
  )
1025
1057
 
1026
1058
 
1059
+ def _rides_summary_scan(demands: list[BuildConcept], ds: BuildDatasource) -> bool:
1060
+ bound = {c.canonical_address for c in ds.output_concepts}
1061
+ return all(
1062
+ c.canonical_address in bound or joinable_property(c, ds) for c in demands
1063
+ )
1064
+
1065
+
1027
1066
  def _aggregates_rolled_groups(
1028
1067
  concept: BuildConcept,
1029
1068
  rolled_roots: set[str],
@@ -17,7 +17,7 @@ single bucket). No derivation is privileged in the orchestrator.
17
17
 
18
18
  from collections import defaultdict
19
19
  from collections.abc import Sequence
20
- from dataclasses import dataclass, field, replace
20
+ from dataclasses import dataclass, field
21
21
 
22
22
  from trilogy.constants import logger
23
23
  from trilogy.core import graph as nx
@@ -2344,13 +2344,14 @@ def build_group_graph(
2344
2344
  environment,
2345
2345
  rollup_padded,
2346
2346
  )
2347
- grouping = _elect_grouping_providers(
2348
- group_graph, group_edges, attrs, concept_attrs, environment
2349
- )
2350
- _state_projection_grains(attrs, buckets, grouping)
2351
- _rehome_groups(
2352
- group_graph, group_edges, attrs, buckets, concept_attrs, environment, grouping
2347
+ folds = _elect_folds(group_graph, group_edges, attrs, concept_attrs)
2348
+ grouping = _elect_grouping_providers(group_graph, attrs, environment, folds)
2349
+ placed = _place_projections(group_graph, group_edges, attrs, buckets, grouping)
2350
+ _fold_groups(group_graph, group_edges, attrs, buckets, folds)
2351
+ read = _read_dimensions(
2352
+ group_graph, group_edges, attrs, buckets, concept_attrs, placed
2353
2353
  )
2354
+ _rehome_groups(group_graph, group_edges, attrs, buckets, environment, placed | read)
2354
2355
  trace_group_graph(
2355
2356
  "FINAL added, concept sets computed, sources regrafted",
2356
2357
  group_graph,
@@ -2457,17 +2458,15 @@ def trace_group_graph(
2457
2458
 
2458
2459
  @dataclass(frozen=True)
2459
2460
  class RowProvider:
2460
- """The row source a regraftable group is re-homed onto: the parent it
2461
- reads, the lineage parents that parent replaces, the dimension ROOT minted
2462
- for it, and whether the parent renders the group inline. Once elected
2463
- (`_as_rewrite`) it holds only what the graph lacks: `parent` is None when
2464
- already a parent."""
2461
+ """The row source a group is re-homed onto: the parent it reads, the
2462
+ lineage parents that parent replaces, and the dimension ROOT minted for
2463
+ it. A placement drops; a dimension read drops and mints; a row provider
2464
+ elected in the rehome (`_as_rewrite`) holds only the edge the graph
2465
+ lacks."""
2465
2466
 
2466
2467
  parent: str | None
2467
2468
  drop: frozenset[str] = frozenset()
2468
2469
  minted: GroupBucket | None = None
2469
- # the parent renders the group in its own SELECT: the group folds into it
2470
- inline: bool = False
2471
2470
 
2472
2471
 
2473
2472
  def _regraft_candidate(
@@ -2865,28 +2864,54 @@ def _inline_window(
2865
2864
  return parent
2866
2865
 
2867
2866
 
2868
- def _elect_grouping_providers(
2867
+ def _elect_folds(
2869
2868
  group_graph: nx.DiGraph,
2870
2869
  group_edges: EdgeMap,
2871
2870
  attrs: dict[str, GroupAttrs],
2872
2871
  concept_attrs: dict[str, ConceptAttrs],
2872
+ ) -> dict[str, str]:
2873
+ """Each scalar BASIC a WINDOW renders inline, to that WINDOW, elected over
2874
+ the graph stage 2 built. A fold target is a WINDOW, so no fold removes
2875
+ another's."""
2876
+ folds: dict[str, str] = {}
2877
+ for gid in group_graph.nodes:
2878
+ if gid == FINAL_NODE_ID:
2879
+ continue
2880
+ window = _inline_window(group_graph, group_edges, attrs, concept_attrs, gid)
2881
+ if window is not None:
2882
+ folds[gid] = window
2883
+ return folds
2884
+
2885
+
2886
+ def _fold_groups(
2887
+ group_graph: nx.DiGraph,
2888
+ group_edges: EdgeMap,
2889
+ attrs: dict[str, GroupAttrs],
2890
+ buckets: dict[str, GroupBucket],
2891
+ folds: dict[str, str],
2892
+ ) -> None:
2893
+ for gid, window in folds.items():
2894
+ _absorb_group(gid, window, group_graph, group_edges, attrs, buckets)
2895
+
2896
+
2897
+ def _elect_grouping_providers(
2898
+ group_graph: nx.DiGraph,
2899
+ attrs: dict[str, GroupAttrs],
2873
2900
  environment: BuildEnvironment,
2901
+ folds: dict[str, str],
2874
2902
  ) -> dict[str, str]:
2875
2903
  """Each terminal scalar projection's grouping provider, elected over the
2876
- graph stage 2 built. A WINDOW that renders the projection inline outranks
2877
- it: that projection folds and keeps its grain."""
2904
+ graph stage 2 built. A fold outranks it: that projection keeps its grain
2905
+ and renders in its WINDOW."""
2878
2906
  providers: dict[str, str] = {}
2879
2907
  for gid in group_graph.nodes:
2880
- if gid == FINAL_NODE_ID:
2908
+ if gid == FINAL_NODE_ID or gid in folds:
2881
2909
  continue
2882
2910
  provider = _terminal_basic_grouping_provider(
2883
2911
  group_graph, attrs, gid, environment
2884
2912
  )
2885
- if provider is None or _inline_window(
2886
- group_graph, group_edges, attrs, concept_attrs, gid
2887
- ):
2888
- continue
2889
- providers[gid] = provider
2913
+ if provider is not None:
2914
+ providers[gid] = provider
2890
2915
  return providers
2891
2916
 
2892
2917
 
@@ -2904,50 +2929,67 @@ def _state_projection_grains(
2904
2929
  buckets[gid].grain_components = grain
2905
2930
 
2906
2931
 
2907
- def _elect_row_provider(
2932
+ def _projection_placements(
2908
2933
  group_graph: nx.DiGraph,
2909
2934
  group_edges: EdgeMap,
2910
2935
  attrs: dict[str, GroupAttrs],
2911
- buckets: dict[str, GroupBucket],
2912
- concept_attrs: dict[str, ConceptAttrs],
2913
- environment: BuildEnvironment,
2914
2936
  grouping: dict[str, str],
2915
- gid: str,
2916
- ) -> RowProvider | None:
2917
- """Pick `gid`'s row source over the graph; mutates nothing. The choices,
2918
- in order: a WINDOW that renders it inline, its grouping provider (whose
2919
- grain it already stands at), a full-coverage sibling, a dimension ROOT, a
2920
- partial spine."""
2921
- grouping_provider = grouping.get(gid)
2922
- if grouping_provider is None:
2923
- window = _inline_window(group_graph, group_edges, attrs, concept_attrs, gid)
2924
- if window is not None:
2925
- return RowProvider(window, inline=True)
2926
- elif not _grain_needed_by_independent_sibling(
2927
- group_graph, attrs, gid, grouping_provider, grouping
2928
- ):
2937
+ ) -> dict[str, RowProvider]:
2938
+ """Each stated projection's edge onto its grouping provider and the
2939
+ lineage parents it replaces, read over the graph stage 2 built. A
2940
+ projection whose provider's grain an independent sibling co-grains on is
2941
+ not placed: it keeps its parents and takes a row provider."""
2942
+ placements: dict[str, RowProvider] = {}
2943
+ for gid, provider in grouping.items():
2944
+ if _grain_needed_by_independent_sibling(
2945
+ group_graph, attrs, gid, provider, grouping
2946
+ ):
2947
+ continue
2929
2948
  # Placed at the provider's grain, the projection has no use for a
2930
2949
  # finer relation the provider was built from. Joined back, it pairs
2931
2950
  # the provider's groups on a non-key (a region domain on a nullable
2932
2951
  # description) and drops or multiplies them.
2933
- provider_ancestors = nx.ancestors(group_graph, grouping_provider)
2952
+ provider_ancestors = nx.ancestors(group_graph, provider)
2934
2953
  drop = frozenset(
2935
2954
  pred
2936
2955
  for pred in lineage_predecessors(group_graph, group_edges, gid)
2937
2956
  if pred in provider_ancestors
2938
2957
  )
2939
- return RowProvider(grouping_provider, drop)
2958
+ placements[gid] = RowProvider(provider, drop)
2959
+ return placements
2960
+
2961
+
2962
+ def _place_projections(
2963
+ group_graph: nx.DiGraph,
2964
+ group_edges: EdgeMap,
2965
+ attrs: dict[str, GroupAttrs],
2966
+ buckets: dict[str, GroupBucket],
2967
+ grouping: dict[str, str],
2968
+ ) -> frozenset[str]:
2969
+ """State each terminal projection's grain and, where no independent
2970
+ sibling needs that grain, its lineage: an edge from its grouping provider
2971
+ in place of the parents the provider was built from. Every projection
2972
+ feeds only FINAL, so no placement moves another group's ancestors.
2973
+ Returns the projections placed."""
2974
+ _state_projection_grains(attrs, buckets, grouping)
2975
+ placements = _projection_placements(group_graph, group_edges, attrs, grouping)
2976
+ for gid, placement in placements.items():
2977
+ _apply_row_provider(group_graph, group_edges, attrs, buckets, gid, placement)
2978
+ return frozenset(placements)
2979
+
2980
+
2981
+ def _elect_row_provider(
2982
+ group_graph: nx.DiGraph,
2983
+ group_edges: EdgeMap,
2984
+ attrs: dict[str, GroupAttrs],
2985
+ environment: BuildEnvironment,
2986
+ gid: str,
2987
+ ) -> RowProvider | None:
2988
+ """Pick `gid`'s row source over the graph; mutates nothing. The choices,
2989
+ in order: a full-coverage sibling, a partial spine."""
2940
2990
  parent_gid = _regraft_candidate(
2941
2991
  group_graph, group_edges, attrs, gid, allow_partial=False
2942
- )
2943
- if parent_gid is not None:
2944
- return RowProvider(parent_gid)
2945
- dimension = _synthetic_dimension_regraft_parent(
2946
- group_graph, group_edges, attrs, buckets, concept_attrs, gid
2947
- )
2948
- if dimension is not None:
2949
- return dimension
2950
- parent_gid = _regraft_candidate(
2992
+ ) or _regraft_candidate(
2951
2993
  group_graph,
2952
2994
  group_edges,
2953
2995
  attrs,
@@ -2958,6 +3000,63 @@ def _elect_row_provider(
2958
3000
  return None if parent_gid is None else RowProvider(parent_gid)
2959
3001
 
2960
3002
 
3003
+ def _rehomeable(
3004
+ attrs: dict[str, GroupAttrs], gid: str, settled: frozenset[str]
3005
+ ) -> bool:
3006
+ return (
3007
+ gid != FINAL_NODE_ID
3008
+ and gid not in settled
3009
+ and attrs[gid].derivation in _REGRAFTABLE_DERIVATIONS
3010
+ )
3011
+
3012
+
3013
+ def _elect_dimension_reads(
3014
+ group_graph: nx.DiGraph,
3015
+ group_edges: EdgeMap,
3016
+ attrs: dict[str, GroupAttrs],
3017
+ buckets: dict[str, GroupBucket],
3018
+ concept_attrs: dict[str, ConceptAttrs],
3019
+ placed: frozenset[str],
3020
+ ) -> dict[str, RowProvider]:
3021
+ """Each unplaced BASIC with no full-coverage sibling that reads its inputs
3022
+ off a dimension ROOT, elected over the folded graph. A sibling outranks
3023
+ a dimension, so a group with one is left to the rehome."""
3024
+ reads: dict[str, RowProvider] = {}
3025
+ for gid in group_graph.nodes:
3026
+ if not _rehomeable(attrs, gid, placed):
3027
+ continue
3028
+ if _regraft_candidate(
3029
+ group_graph, group_edges, attrs, gid, allow_partial=False
3030
+ ):
3031
+ continue
3032
+ read = _synthetic_dimension_regraft_parent(
3033
+ group_graph, group_edges, attrs, buckets, concept_attrs, gid
3034
+ )
3035
+ if read is not None:
3036
+ reads[gid] = read
3037
+ return reads
3038
+
3039
+
3040
+ def _read_dimensions(
3041
+ group_graph: nx.DiGraph,
3042
+ group_edges: EdgeMap,
3043
+ attrs: dict[str, GroupAttrs],
3044
+ buckets: dict[str, GroupBucket],
3045
+ concept_attrs: dict[str, ConceptAttrs],
3046
+ placed: frozenset[str],
3047
+ ) -> frozenset[str]:
3048
+ """Re-home each dimension read onto its ROOT, minting it when none covers
3049
+ its inputs, in place of the ROOT parents it replaces. Every read is
3050
+ elected before any is applied. Returns the groups read, a pick that
3051
+ changes nothing included: the rehome elects none of them."""
3052
+ reads = _elect_dimension_reads(
3053
+ group_graph, group_edges, attrs, buckets, concept_attrs, placed
3054
+ )
3055
+ for gid, read in reads.items():
3056
+ _apply_row_provider(group_graph, group_edges, attrs, buckets, gid, read)
3057
+ return frozenset(reads)
3058
+
3059
+
2961
3060
  def _apply_row_provider(
2962
3061
  group_graph: nx.DiGraph,
2963
3062
  group_edges: EdgeMap,
@@ -2983,11 +3082,8 @@ def _apply_row_provider(
2983
3082
  def _as_rewrite(
2984
3083
  group_graph: nx.DiGraph, gid: str, provider: RowProvider
2985
3084
  ) -> RowProvider | None:
2986
- """`provider` less what the graph stage 2 built already holds, or None
2987
- when it changes nothing: its parent is already a parent, and it drops and
2988
- mints nothing."""
2989
- if provider.inline:
2990
- return provider
3085
+ """`provider` less what the graph already holds, or None when it changes
3086
+ nothing: its parent is already a parent, and it drops and mints nothing."""
2991
3087
  drop = frozenset(p for p in provider.drop if group_graph.has_edge(p, gid))
2992
3088
  minted = provider.minted
2993
3089
  if minted is not None and minted.group_id in group_graph:
@@ -3004,54 +3100,30 @@ def _elect_row_providers(
3004
3100
  group_graph: nx.DiGraph,
3005
3101
  group_edges: EdgeMap,
3006
3102
  attrs: dict[str, GroupAttrs],
3007
- buckets: dict[str, GroupBucket],
3008
- concept_attrs: dict[str, ConceptAttrs],
3009
3103
  environment: BuildEnvironment,
3010
- grouping: dict[str, str],
3104
+ settled: frozenset[str],
3011
3105
  ) -> dict[str, RowProvider]:
3012
- """Each regraftable group whose best row source is already built, elected
3013
- over the graph as stage 2 built it, as the rewrite it makes of that graph.
3014
-
3015
- No provider is a BASIC, so no fold removes one; a parent a provider drops
3016
- that folds is dropped as the WINDOW its edge moves to. Concrete datasource
3017
- selection remains in `source_planning` and StrategyNode construction in
3018
- `strategy_builder`.
3106
+ """Each regraftable group not placed at its grouping provider nor read
3107
+ off a dimension whose best row source is already built, elected over one
3108
+ graph (stage 2's, with the projections placed, the folds made and the
3109
+ dimensions read), as the rewrite it makes of that graph. A provider only
3110
+ adds a lineage edge.
3111
+
3112
+ Concrete datasource selection remains in `source_planning` and
3113
+ StrategyNode construction in `strategy_builder`.
3019
3114
  """
3020
3115
  providers: dict[str, RowProvider] = {}
3021
3116
  for gid in list(group_graph.nodes):
3022
- if (
3023
- gid == FINAL_NODE_ID
3024
- or attrs[gid].derivation not in _REGRAFTABLE_DERIVATIONS
3025
- ):
3117
+ if not _rehomeable(attrs, gid, settled):
3026
3118
  continue
3027
3119
  provider = _elect_row_provider(
3028
- group_graph,
3029
- group_edges,
3030
- attrs,
3031
- buckets,
3032
- concept_attrs,
3033
- environment,
3034
- grouping,
3035
- gid,
3120
+ group_graph, group_edges, attrs, environment, gid
3036
3121
  )
3037
3122
  if provider is not None:
3038
3123
  provider = _as_rewrite(group_graph, gid, provider)
3039
3124
  if provider is not None:
3040
3125
  providers[gid] = provider
3041
- folded = _folds(providers)
3042
- return {
3043
- gid: replace(p, drop=frozenset(folded.get(pred, pred) for pred in p.drop))
3044
- for gid, p in providers.items()
3045
- }
3046
-
3047
-
3048
- def _folds(providers: dict[str, RowProvider]) -> dict[str, str]:
3049
- """Each group its provider renders inline, to that provider."""
3050
- return {
3051
- gid: p.parent
3052
- for gid, p in providers.items()
3053
- if p.inline and p.parent is not None
3054
- }
3126
+ return providers
3055
3127
 
3056
3128
 
3057
3129
  def _rehome_groups(
@@ -3059,19 +3131,13 @@ def _rehome_groups(
3059
3131
  group_edges: EdgeMap,
3060
3132
  attrs: dict[str, GroupAttrs],
3061
3133
  buckets: dict[str, GroupBucket],
3062
- concept_attrs: dict[str, ConceptAttrs],
3063
3134
  environment: BuildEnvironment,
3064
- grouping: dict[str, str],
3135
+ settled: frozenset[str],
3065
3136
  ) -> None:
3066
- """Elect every group's row provider over the graph as stage 2 built it,
3067
- each projection already at its grouping provider's grain, then fold each
3068
- group its provider renders inline and apply the rest: no election reads
3069
- another's fold or edges."""
3137
+ """Elect every unsettled group's row provider over one graph, then apply
3138
+ them all: no election reads another's edges."""
3070
3139
  providers = _elect_row_providers(
3071
- group_graph, group_edges, attrs, buckets, concept_attrs, environment, grouping
3140
+ group_graph, group_edges, attrs, environment, settled
3072
3141
  )
3073
- for gid, parent in _folds(providers).items():
3074
- _absorb_group(gid, parent, group_graph, group_edges, attrs, buckets)
3075
3142
  for gid, provider in providers.items():
3076
- if not provider.inline:
3077
- _apply_row_provider(group_graph, group_edges, attrs, buckets, gid, provider)
3143
+ _apply_row_provider(group_graph, group_edges, attrs, buckets, gid, provider)
@@ -16,7 +16,7 @@ from typing import cast
16
16
 
17
17
  from trilogy.constants import logger
18
18
  from trilogy.core.constants import parent_axis_keys
19
- from trilogy.core.enums import Derivation, Granularity, JoinType, Purpose
19
+ from trilogy.core.enums import Derivation, Granularity, JoinType
20
20
  from trilogy.core.graph_models import ReferenceGraph, concept_to_node
21
21
  from trilogy.core.models.build import (
22
22
  BuildConcept,
@@ -33,6 +33,7 @@ from trilogy.core.processing.aggregate_rollup import (
33
33
  at_own_grain,
34
34
  filter_finer_row_args,
35
35
  holds_every_kept_row,
36
+ joinable_property,
36
37
  joined_condition_columns,
37
38
  merge_rollup_concepts,
38
39
  source_rollup_concepts,
@@ -1705,7 +1706,8 @@ def _finer_filter_rollup_source(
1705
1706
  if not all(
1706
1707
  c in canonicals
1707
1708
  or (
1708
- _joinable_property(environment.concepts.get(c), arms)
1709
+ len(arms) == 1
1710
+ and joinable_property(environment.concepts.get(c), arms[0])
1709
1711
  and all(
1710
1712
  at_own_grain(a, target_grain, environment.concepts)
1711
1713
  for a in aggregates
@@ -1744,19 +1746,6 @@ def _finer_filter_rollup_source(
1744
1746
  return matches[0]
1745
1747
 
1746
1748
 
1747
- def _joinable_property(
1748
- concept: BuildConcept | None, arms: list[BuildDatasource]
1749
- ) -> bool:
1750
- return (
1751
- concept is not None
1752
- and concept.lineage is None
1753
- and concept.purpose == Purpose.PROPERTY
1754
- and bool(concept.keys)
1755
- and len(arms) == 1
1756
- and set(concept.keys or ()) <= set(arms[0].grain.components)
1757
- )
1758
-
1759
-
1760
1749
  def _rolls_every_aggregate(
1761
1750
  datasource: BuildDatasource | BuildUnionDatasource,
1762
1751
  request: SourceRequest,
@@ -546,7 +546,7 @@ dependencies = [
546
546
 
547
547
  [[package]]
548
548
  name = "trilogy-parser"
549
- version = "0.3.485"
549
+ version = "0.3.487"
550
550
  dependencies = [
551
551
  "clap",
552
552
  "pathdiff",
@@ -4,7 +4,7 @@ name = "trilogy-parser"
4
4
  # crates.io releases ride the same stream (see pythonpublish.yml), so a
5
5
  # published crate version always corresponds to the pytrilogy release
6
6
  # whose grammar it carries.
7
- version = "0.3.485"
7
+ version = "0.3.487"
8
8
  edition = "2021"
9
9
  description = "Parser and import/datasource dependency resolver for the Trilogy language"
10
10
  license = "MIT"