pytrilogy 0.0.3.67__py3-none-any.whl → 0.0.3.68__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pytrilogy
3
- Version: 0.0.3.67
3
+ Version: 0.0.3.68
4
4
  Summary: Declarative, typed query language that compiles to SQL.
5
5
  Home-page:
6
6
  Author:
@@ -1,5 +1,5 @@
1
- pytrilogy-0.0.3.67.dist-info/licenses/LICENSE.md,sha256=5ZRvtTyCCFwz1THxDTjAu3Lidds9WjPvvzgVwPSYNDo,1042
2
- trilogy/__init__.py,sha256=kIt0gE_lZ8Zmqhi-fcE9krdwlETcz0sP0kiCjnsBQog,303
1
+ pytrilogy-0.0.3.68.dist-info/licenses/LICENSE.md,sha256=5ZRvtTyCCFwz1THxDTjAu3Lidds9WjPvvzgVwPSYNDo,1042
2
+ trilogy/__init__.py,sha256=c1CqFUPhjgRs6876P3SAh2D8kHJp6_QydaF_JJeDlJc,303
3
3
  trilogy/compiler.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  trilogy/constants.py,sha256=lv_aJWP6dn6e2aF4BAE72jbnNtceFddfqtiDSsvzno0,1692
5
5
  trilogy/engine.py,sha256=OK2RuqCIUId6yZ5hfF8J1nxGP0AJqHRZiafcowmW0xc,1728
@@ -37,11 +37,11 @@ trilogy/core/optimizations/predicate_pushdown.py,sha256=g4AYE8Aw_iMlAh68TjNXGP75
37
37
  trilogy/core/processing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
38
  trilogy/core/processing/concept_strategies_v3.py,sha256=zy5VZa9LITOws6aIILfv_bSR2-jR1Ndldy-nmwMyQ5w,23144
39
39
  trilogy/core/processing/discovery_loop.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
40
- trilogy/core/processing/discovery_node_factory.py,sha256=73fViHQfKsrFbuk8zfx8YIiaT66pF5AFvw4suV7bXbM,14985
40
+ trilogy/core/processing/discovery_node_factory.py,sha256=Uza_wrB6K965rXbwCuWvBtsDMftq2m0hAav9B5bxQ8k,15049
41
41
  trilogy/core/processing/discovery_utility.py,sha256=3xdd1ypKappSDm0SJs7WtW5YegL80SlYhDQlkNePp4E,4549
42
42
  trilogy/core/processing/discovery_validation.py,sha256=fGWJmKpgEd1f4RkK-fYOBUT1cwsJnahwXFAdRlou7MI,5365
43
43
  trilogy/core/processing/graph_utils.py,sha256=8QUVrkE9j-9C1AyrCb1nQEh8daCe0u1HuXl-Te85lag,1205
44
- trilogy/core/processing/utility.py,sha256=mrfR9pgek-xjxoDQSlvPqOW9dpmREjgzqn4AGoqpGeM,22774
44
+ trilogy/core/processing/utility.py,sha256=b1F3NT7-MP_-U4KmpC52BOAwLu6mybfndeA1iiZwChw,22016
45
45
  trilogy/core/processing/node_generators/__init__.py,sha256=w8TQQgNhyAra6JQHdg1_Ags4BGyxjXYruu6UeC5yOkI,873
46
46
  trilogy/core/processing/node_generators/basic_node.py,sha256=luN8LftafZepoFgDRv4gmvEGFlOI2j0icJ5fz4UT7uo,5165
47
47
  trilogy/core/processing/node_generators/common.py,sha256=PdysdroW9DUADP7f5Wv_GKPUyCTROZV1g3L45fawxi8,9443
@@ -52,9 +52,9 @@ trilogy/core/processing/node_generators/multiselect_node.py,sha256=GWV5yLmKTe1yy
52
52
  trilogy/core/processing/node_generators/node_merge_node.py,sha256=dSqfqWp2SolhDB16nkPaaTXgNQo4QquEufPdf7q0Tb4,17398
53
53
  trilogy/core/processing/node_generators/recursive_node.py,sha256=l5zdh0dURKwmAy8kK4OpMtZfyUEQRk6N-PwSWIyBpSM,2468
54
54
  trilogy/core/processing/node_generators/rowset_node.py,sha256=2BiSsegbRF9csJ_Xl8P_CxIm4dAAb7dF29u6v_Odr-A,6709
55
- trilogy/core/processing/node_generators/select_merge_node.py,sha256=fisCkMyzNDEdDIi9BMuekpIJT5lBF4h0z_pEwR14x9s,21438
55
+ trilogy/core/processing/node_generators/select_merge_node.py,sha256=EmU6QUOEKOOKVJreHxDJZakd2FpD1V1W8ZGOOLLaWdo,21462
56
56
  trilogy/core/processing/node_generators/select_node.py,sha256=Ta1G39V94gjX_AgyZDz9OqnwLz4BjY3D6Drx9YpziMQ,3555
57
- trilogy/core/processing/node_generators/synonym_node.py,sha256=F9DWaKEmJDYnwAmQduTuQP2LCCHqAMDA3oDERRDN2pU,3773
57
+ trilogy/core/processing/node_generators/synonym_node.py,sha256=AnAsa_Wj50NJ_IK0HSgab_7klYmKVrv0WI1uUe-GvEY,3766
58
58
  trilogy/core/processing/node_generators/union_node.py,sha256=VNo6Oey4p8etU9xrOh2oTT2lIOTvY6PULUPRvVa2uxU,2877
59
59
  trilogy/core/processing/node_generators/unnest_node.py,sha256=ueOQtoTf2iJHO09RzWHDFQ5iKZq2fVhGf2KAF2U2kU8,2677
60
60
  trilogy/core/processing/node_generators/window_node.py,sha256=GP3Hvkbb0TDA6ef7W7bmvQEHVH-NRIfBT_0W4fcH3g4,6529
@@ -76,7 +76,7 @@ trilogy/core/statements/build.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hS
76
76
  trilogy/core/statements/common.py,sha256=KxEmz2ySySyZ6CTPzn0fJl5NX2KOk1RPyuUSwWhnK1g,759
77
77
  trilogy/core/statements/execute.py,sha256=rqfuoMuXPcH7L7TmE1dSiZ_K_A1ohB8whVMfGimZBOk,1294
78
78
  trilogy/dialect/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
79
- trilogy/dialect/base.py,sha256=_EkBijBaJGF_d0SBNBCf_mbmDD7N9HrnO2XbRWM8ypg,43629
79
+ trilogy/dialect/base.py,sha256=CMrYlE-oQzdmefmNPBRzT7OA842UV-P1sCqa0JAcP4Q,43741
80
80
  trilogy/dialect/bigquery.py,sha256=6ghCqy-k7UioIJc1EEQ7gRo_PHaO8Vm7yYbiQ-kgpzs,3629
81
81
  trilogy/dialect/common.py,sha256=hhzuMTFW9QQIP7TKLT9BlJy6lw2R03a68jKQ-7t4-2c,6070
82
82
  trilogy/dialect/config.py,sha256=olnyeVU5W5T6b9-dMeNAnvxuPlyc2uefb7FRME094Ec,3834
@@ -110,8 +110,8 @@ trilogy/std/money.preql,sha256=XWwvAV3WxBsHX9zfptoYRnBigcfYwrYtBHXTME0xJuQ,2082
110
110
  trilogy/std/net.preql,sha256=-bMV6dyofskl4Kvows-iQ4JCxjVUwsZOeWCy8JO5Ftw,135
111
111
  trilogy/std/ranking.preql,sha256=LDoZrYyz4g3xsII9XwXfmstZD-_92i1Eox1UqkBIfi8,83
112
112
  trilogy/std/report.preql,sha256=LbV-XlHdfw0jgnQ8pV7acG95xrd1-p65fVpiIc-S7W4,202
113
- pytrilogy-0.0.3.67.dist-info/METADATA,sha256=q69gBB9Ympec6F7E9ASBDjTfuRs06HmUws7QvAxVBeA,9095
114
- pytrilogy-0.0.3.67.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
115
- pytrilogy-0.0.3.67.dist-info/entry_points.txt,sha256=ewBPU2vLnVexZVnB-NrVj-p3E-4vukg83Zk8A55Wp2w,56
116
- pytrilogy-0.0.3.67.dist-info/top_level.txt,sha256=cAy__NW_eMAa_yT9UnUNlZLFfxcg6eimUAZ184cdNiE,8
117
- pytrilogy-0.0.3.67.dist-info/RECORD,,
113
+ pytrilogy-0.0.3.68.dist-info/METADATA,sha256=XA1FhFxajFv-4bT9JSbdv5gH5LvikdjwiJ33kAUdfQI,9095
114
+ pytrilogy-0.0.3.68.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
115
+ pytrilogy-0.0.3.68.dist-info/entry_points.txt,sha256=ewBPU2vLnVexZVnB-NrVj-p3E-4vukg83Zk8A55Wp2w,56
116
+ pytrilogy-0.0.3.68.dist-info/top_level.txt,sha256=cAy__NW_eMAa_yT9UnUNlZLFfxcg6eimUAZ184cdNiE,8
117
+ pytrilogy-0.0.3.68.dist-info/RECORD,,
trilogy/__init__.py CHANGED
@@ -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.67"
7
+ __version__ = "0.0.3.68"
8
8
 
9
9
  __all__ = ["parse", "Executor", "Dialects", "Environment", "CONFIG"]
@@ -307,16 +307,17 @@ class RootNodeHandler:
307
307
  def _resolve_root_concepts(
308
308
  self, root_targets: List[BuildConcept]
309
309
  ) -> Optional[StrategyNode]:
310
- synonym_node = self._try_synonym_resolution(root_targets)
311
- if synonym_node:
312
- logger.info(
313
- f"{depth_to_prefix(self.ctx.depth)}{LOGGER_PREFIX} "
314
- f"resolved root concepts through synonyms"
315
- )
316
- return synonym_node
317
310
  expanded_node = self._try_merge_expansion(root_targets)
318
311
  if expanded_node:
319
312
  return expanded_node
313
+ if self.ctx.accept_partial:
314
+ synonym_node = self._try_synonym_resolution(root_targets)
315
+ if synonym_node:
316
+ logger.info(
317
+ f"{depth_to_prefix(self.ctx.depth)}{LOGGER_PREFIX} "
318
+ f"resolved root concepts through synonyms"
319
+ )
320
+ return synonym_node
320
321
 
321
322
  return None
322
323
 
@@ -493,7 +493,7 @@ def create_select_node(
493
493
  else:
494
494
 
495
495
  candidate = bcandidate
496
- assert candidate.resolve().output_concepts == all_concepts
496
+
497
497
  return candidate
498
498
 
499
499
 
@@ -536,7 +536,12 @@ def gen_select_merge_node(
536
536
  force_group=False,
537
537
  conditions=conditions.conditional if conditions else None,
538
538
  )
539
- for attempt in [False, True]:
539
+ attempts = [
540
+ False,
541
+ ]
542
+ if accept_partial:
543
+ attempts.append(True)
544
+ for attempt in attempts:
540
545
  pruned_concept_graph = create_pruned_concept_graph(
541
546
  g,
542
547
  non_constant,
@@ -3,8 +3,8 @@ from collections import defaultdict
3
3
  from typing import List
4
4
 
5
5
  from trilogy.constants import logger
6
- from trilogy.core.enums import FunctionType
7
- from trilogy.core.models.build import BuildConcept, BuildFunction, BuildWhereClause
6
+ from trilogy.core.enums import Derivation
7
+ from trilogy.core.models.build import BuildConcept, BuildWhereClause
8
8
  from trilogy.core.models.build_environment import BuildEnvironment
9
9
  from trilogy.core.processing.nodes import History, StrategyNode
10
10
  from trilogy.core.processing.utility import padding
@@ -12,13 +12,6 @@ from trilogy.core.processing.utility import padding
12
12
  LOGGER_PREFIX = "[GEN_SYNONYM_NODE]"
13
13
 
14
14
 
15
- def is_union(c: BuildConcept):
16
- return (
17
- isinstance(c.lineage, BuildFunction)
18
- and c.lineage.operator == FunctionType.UNION
19
- )
20
-
21
-
22
15
  def gen_synonym_node(
23
16
  all_concepts: List[BuildConcept],
24
17
  environment: BuildEnvironment,
@@ -41,7 +34,6 @@ def gen_synonym_node(
41
34
  synonyms[x.address].append(parent)
42
35
  has_synonyms = True
43
36
  for y in x.pseudonyms:
44
-
45
37
  if y in environment.alias_origin_lookup:
46
38
  synonyms[x.address].append(environment.alias_origin_lookup[y])
47
39
  has_synonyms = True
@@ -59,11 +51,14 @@ def gen_synonym_node(
59
51
  itertools.product(*(synonyms[obj] for obj in sorted_keys))
60
52
  )
61
53
 
62
- def similarity_sort_key(combo):
54
+ def similarity_sort_key(combo: tuple[BuildConcept, ...]):
63
55
  addresses = [x.address for x in combo]
64
56
 
65
57
  # Calculate similarity score - count how many pairs share prefixes
66
58
  similarity_score = 0
59
+ roots = sum(
60
+ [1 for x in combo if x.derivation in (Derivation.ROOT, Derivation.CONSTANT)]
61
+ )
67
62
  for i in range(len(addresses)):
68
63
  for j in range(i + 1, len(addresses)):
69
64
  # Find common prefix length
@@ -77,8 +72,8 @@ def gen_synonym_node(
77
72
  break
78
73
  similarity_score += common_prefix_len
79
74
 
80
- # Sort by similarity (descending), then by addresses (ascending) for ties
81
- return (-similarity_score, addresses)
75
+ # Sort by roots, similarity (descending), then by addresses (ascending) for ties
76
+ return (-roots, -similarity_score, addresses)
82
77
 
83
78
  combinations_list.sort(key=similarity_sort_key)
84
79
  for combo in combinations_list:
@@ -322,8 +322,10 @@ def resolve_instantiated_concept(
322
322
  for k in concept.pseudonyms:
323
323
  if k in datasource.output_concepts:
324
324
  return [x for x in datasource.output_concepts if x.address == k].pop()
325
+ if any(k in x.pseudonyms for x in datasource.output_concepts):
326
+ return [x for x in datasource.output_concepts if k in x.pseudonyms].pop()
325
327
  raise SyntaxError(
326
- f"Could not find {concept.address} in {datasource.identifier} output {[c.address for c in datasource.output_concepts]}"
328
+ f"Could not find {concept.address} in {datasource.identifier} output {[c.address for c in datasource.output_concepts]}, acceptable synonyms {concept.pseudonyms}"
327
329
  )
328
330
 
329
331
 
@@ -601,19 +603,28 @@ def find_nullable_concepts(
601
603
 
602
604
 
603
605
  def sort_select_output_processed(
604
- cte: CTE | UnionCTE, query: ProcessedQuery
606
+ cte: CTE | UnionCTE, query: SelectStatement | MultiSelectStatement | ProcessedQuery
605
607
  ) -> CTE | UnionCTE:
606
- output_addresses = [c.address for c in query.output_columns]
608
+ if isinstance(query, ProcessedQuery):
609
+ targets = query.output_columns
610
+ hidden = query.hidden_columns
611
+ else:
612
+ targets = query.output_components
613
+ hidden = query.hidden_components
614
+
615
+ output_addresses = [c.address for c in targets]
607
616
 
608
617
  mapping = {x.address: x for x in cte.output_columns}
609
618
 
610
619
  new_output: list[BuildConcept] = []
611
- for x in query.output_columns:
620
+ for x in targets:
612
621
  if x.address in mapping:
613
622
  new_output.append(mapping[x.address])
614
623
  for oc in cte.output_columns:
615
624
  if x.address in oc.pseudonyms:
616
625
  # create a wrapper BuildConcept to render the pseudonym under the original name
626
+ if any(x.address == y for y in mapping.keys()):
627
+ continue
617
628
  new_output.append(
618
629
  BuildConcept(
619
630
  name=x.name,
@@ -636,10 +647,7 @@ def sort_select_output_processed(
636
647
  [
637
648
  c.address
638
649
  for c in cte.output_columns
639
- if (
640
- c.address not in query.output_columns
641
- or c.address in query.hidden_columns
642
- )
650
+ if (c.address not in targets or c.address in hidden)
643
651
  ]
644
652
  )
645
653
  cte.output_columns = new_output
@@ -650,38 +658,4 @@ def sort_select_output(
650
658
  cte: CTE | UnionCTE, query: SelectStatement | MultiSelectStatement | ProcessedQuery
651
659
  ) -> CTE | UnionCTE:
652
660
 
653
- if isinstance(query, ProcessedQuery):
654
- return sort_select_output_processed(cte, query)
655
-
656
- mapping = {x.address: x for x in cte.output_columns}
657
-
658
- new_output: list[BuildConcept] = []
659
- for x in query.output_components:
660
- if x.address in mapping:
661
- new_output.append(mapping[x.address])
662
- else:
663
- for oc in cte.output_columns:
664
- if x.address in oc.pseudonyms:
665
- # create a wrapper BuildConcept to render the pseudonym under the original name
666
- new_output.append(
667
- BuildConcept(
668
- name=x.name,
669
- namespace=x.namespace,
670
- pseudonyms={oc.address},
671
- datatype=oc.datatype,
672
- purpose=oc.purpose,
673
- grain=oc.grain,
674
- build_is_aggregate=oc.build_is_aggregate,
675
- )
676
- )
677
- break
678
- cte.output_columns = new_output
679
- cte.hidden_concepts = set(
680
- [
681
- c.address
682
- for c in query.output_components
683
- if c.address in query.hidden_components
684
- ]
685
- )
686
-
687
- return cte
661
+ return sort_select_output_processed(cte, query)
trilogy/dialect/base.py CHANGED
@@ -762,6 +762,7 @@ class BaseDialect:
762
762
  ] + [
763
763
  f"{self.QUOTE_CHARACTER}{c.safe_address}{self.QUOTE_CHARACTER}"
764
764
  for c in cte.join_derived_concepts
765
+ if c.address not in cte.hidden_concepts
765
766
  ]
766
767
  elif self.UNNEST_MODE in (UnnestMode.CROSS_JOIN_UNNEST, UnnestMode.PRESTO):
767
768
  select_columns = [
@@ -772,6 +773,7 @@ class BaseDialect:
772
773
  ] + [
773
774
  f"{UNNEST_NAME} as {self.QUOTE_CHARACTER}{c.safe_address}{self.QUOTE_CHARACTER}"
774
775
  for c in cte.join_derived_concepts
776
+ if c.address not in cte.hidden_concepts
775
777
  ]
776
778
  else:
777
779
  # otherwse, assume we are unnesting directly in the select