pytrilogy 0.0.2.23__py3-none-any.whl → 0.0.2.26__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.
- {pytrilogy-0.0.2.23.dist-info → pytrilogy-0.0.2.26.dist-info}/METADATA +1 -1
- {pytrilogy-0.0.2.23.dist-info → pytrilogy-0.0.2.26.dist-info}/RECORD +25 -25
- trilogy/__init__.py +1 -1
- trilogy/constants.py +1 -1
- trilogy/core/env_processor.py +12 -6
- trilogy/core/environment_helpers.py +0 -1
- trilogy/core/models.py +163 -86
- trilogy/core/processing/concept_strategies_v3.py +23 -4
- trilogy/core/processing/node_generators/common.py +0 -1
- trilogy/core/processing/node_generators/node_merge_node.py +4 -4
- trilogy/core/processing/node_generators/select_merge_node.py +49 -22
- trilogy/core/processing/nodes/merge_node.py +2 -2
- trilogy/core/processing/utility.py +241 -259
- trilogy/core/query_processor.py +47 -39
- trilogy/dialect/base.py +6 -1
- trilogy/dialect/common.py +4 -25
- trilogy/executor.py +12 -3
- trilogy/parsing/common.py +4 -6
- trilogy/parsing/parse_engine.py +3 -2
- trilogy/parsing/render.py +41 -17
- trilogy/parsing/trilogy.lark +2 -2
- {pytrilogy-0.0.2.23.dist-info → pytrilogy-0.0.2.26.dist-info}/LICENSE.md +0 -0
- {pytrilogy-0.0.2.23.dist-info → pytrilogy-0.0.2.26.dist-info}/WHEEL +0 -0
- {pytrilogy-0.0.2.23.dist-info → pytrilogy-0.0.2.26.dist-info}/entry_points.txt +0 -0
- {pytrilogy-0.0.2.23.dist-info → pytrilogy-0.0.2.26.dist-info}/top_level.txt +0 -0
|
@@ -28,14 +28,18 @@ def extract_address(node: str):
|
|
|
28
28
|
return node.split("~")[1].split("@")[0]
|
|
29
29
|
|
|
30
30
|
|
|
31
|
-
def get_graph_partial_nodes(
|
|
31
|
+
def get_graph_partial_nodes(
|
|
32
|
+
g: nx.DiGraph, conditions: WhereClause | None
|
|
33
|
+
) -> dict[str, list[str]]:
|
|
32
34
|
datasources: dict[str, Datasource] = nx.get_node_attributes(g, "datasource")
|
|
33
35
|
partial: dict[str, list[str]] = {}
|
|
34
36
|
for node in g.nodes:
|
|
35
37
|
if node in datasources:
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
ds = datasources[node]
|
|
39
|
+
partial[node] = [concept_to_node(c) for c in ds.partial_concepts]
|
|
40
|
+
if ds.non_partial_for and conditions == ds.non_partial_for:
|
|
41
|
+
partial[node] = []
|
|
42
|
+
|
|
39
43
|
return partial
|
|
40
44
|
|
|
41
45
|
|
|
@@ -49,7 +53,10 @@ def get_graph_grain_length(g: nx.DiGraph) -> dict[str, int]:
|
|
|
49
53
|
|
|
50
54
|
|
|
51
55
|
def create_pruned_concept_graph(
|
|
52
|
-
g: nx.DiGraph,
|
|
56
|
+
g: nx.DiGraph,
|
|
57
|
+
all_concepts: List[Concept],
|
|
58
|
+
accept_partial: bool = False,
|
|
59
|
+
conditions: WhereClause | None = None,
|
|
53
60
|
) -> nx.DiGraph:
|
|
54
61
|
orig_g = g
|
|
55
62
|
g = g.copy()
|
|
@@ -66,11 +73,7 @@ def create_pruned_concept_graph(
|
|
|
66
73
|
relevent_datasets: list[str] = []
|
|
67
74
|
if not accept_partial:
|
|
68
75
|
partial = {}
|
|
69
|
-
|
|
70
|
-
if node in datasources:
|
|
71
|
-
partial[node] = [
|
|
72
|
-
concept_to_node(c) for c in datasources[node].partial_concepts
|
|
73
|
-
]
|
|
76
|
+
partial = get_graph_partial_nodes(g, conditions)
|
|
74
77
|
to_remove = []
|
|
75
78
|
for edge in g.edges:
|
|
76
79
|
if (
|
|
@@ -133,31 +136,53 @@ def create_pruned_concept_graph(
|
|
|
133
136
|
return g
|
|
134
137
|
|
|
135
138
|
|
|
136
|
-
def resolve_subgraphs(
|
|
139
|
+
def resolve_subgraphs(
|
|
140
|
+
g: nx.DiGraph, conditions: WhereClause | None
|
|
141
|
+
) -> dict[str, list[str]]:
|
|
137
142
|
datasources = [n for n in g.nodes if n.startswith("ds~")]
|
|
138
|
-
subgraphs
|
|
139
|
-
|
|
143
|
+
subgraphs: dict[str, list[str]] = {
|
|
144
|
+
ds: list(set(list(nx.all_neighbors(g, ds)))) for ds in datasources
|
|
145
|
+
}
|
|
146
|
+
partial_map = get_graph_partial_nodes(g, conditions)
|
|
140
147
|
grain_length = get_graph_grain_length(g)
|
|
141
|
-
|
|
142
|
-
|
|
148
|
+
concepts: dict[str, Concept] = nx.get_node_attributes(g, "concept")
|
|
149
|
+
non_partial_map = {
|
|
150
|
+
ds: [concepts[c].address for c in subgraphs[ds] if c not in partial_map[ds]]
|
|
151
|
+
for ds in datasources
|
|
152
|
+
}
|
|
153
|
+
concept_map = {
|
|
154
|
+
ds: [concepts[c].address for c in subgraphs[ds]] for ds in datasources
|
|
143
155
|
}
|
|
144
156
|
pruned_subgraphs = {}
|
|
145
|
-
for key,
|
|
157
|
+
for key, nodes in subgraphs.items():
|
|
158
|
+
value = non_partial_map[key]
|
|
159
|
+
all_concepts = concept_map[key]
|
|
146
160
|
is_subset = False
|
|
147
161
|
matches = set()
|
|
148
162
|
# Compare current list with other lists
|
|
149
|
-
for other_key,
|
|
150
|
-
|
|
163
|
+
for other_key, other_all_concepts in concept_map.items():
|
|
164
|
+
other_value = non_partial_map[other_key]
|
|
165
|
+
# needs to be a subset of non partial and a subset of all
|
|
166
|
+
if (
|
|
167
|
+
key != other_key
|
|
168
|
+
and set(value).issubset(set(other_value))
|
|
169
|
+
and set(all_concepts).issubset(set(other_all_concepts))
|
|
170
|
+
):
|
|
151
171
|
if len(value) < len(other_value):
|
|
152
172
|
is_subset = True
|
|
173
|
+
logger.debug(
|
|
174
|
+
f"Dropping subgraph {key} with {value} as it is a subset of {other_key} with {other_value}"
|
|
175
|
+
)
|
|
153
176
|
break
|
|
154
|
-
elif len(value) == len(other_value)
|
|
177
|
+
elif len(value) == len(other_value) and len(all_concepts) == len(
|
|
178
|
+
other_all_concepts
|
|
179
|
+
):
|
|
155
180
|
matches.add(other_key)
|
|
156
181
|
matches.add(key)
|
|
157
182
|
if matches:
|
|
158
183
|
is_subset = key is not min(matches, key=lambda x: (grain_length[x], x))
|
|
159
184
|
if not is_subset:
|
|
160
|
-
pruned_subgraphs[key] =
|
|
185
|
+
pruned_subgraphs[key] = nodes
|
|
161
186
|
return pruned_subgraphs
|
|
162
187
|
|
|
163
188
|
|
|
@@ -261,7 +286,9 @@ def gen_select_merge_node(
|
|
|
261
286
|
force_group=False,
|
|
262
287
|
)
|
|
263
288
|
for attempt in [False, True]:
|
|
264
|
-
pruned_concept_graph = create_pruned_concept_graph(
|
|
289
|
+
pruned_concept_graph = create_pruned_concept_graph(
|
|
290
|
+
g, non_constant, attempt, conditions
|
|
291
|
+
)
|
|
265
292
|
if pruned_concept_graph:
|
|
266
293
|
logger.info(
|
|
267
294
|
f"{padding(depth)}{LOGGER_PREFIX} found covering graph w/ partial flag {attempt}"
|
|
@@ -274,7 +301,7 @@ def gen_select_merge_node(
|
|
|
274
301
|
)
|
|
275
302
|
return None
|
|
276
303
|
|
|
277
|
-
sub_nodes = resolve_subgraphs(pruned_concept_graph)
|
|
304
|
+
sub_nodes = resolve_subgraphs(pruned_concept_graph, conditions)
|
|
278
305
|
|
|
279
306
|
logger.info(f"{padding(depth)}{LOGGER_PREFIX} fetching subgraphs {sub_nodes}")
|
|
280
307
|
parents = [
|
|
@@ -215,7 +215,7 @@ class MergeNode(StrategyNode):
|
|
|
215
215
|
logger.info(
|
|
216
216
|
f"{self.logging_prefix}{LOGGER_PREFIX} inferring node joins to target grain {str(grain)}"
|
|
217
217
|
)
|
|
218
|
-
joins = get_node_joins(dataset_list,
|
|
218
|
+
joins = get_node_joins(dataset_list, environment=environment)
|
|
219
219
|
elif final_joins:
|
|
220
220
|
logger.info(
|
|
221
221
|
f"{self.logging_prefix}{LOGGER_PREFIX} translating provided node joins {len(final_joins)}"
|
|
@@ -314,7 +314,7 @@ class MergeNode(StrategyNode):
|
|
|
314
314
|
full_join_concepts = []
|
|
315
315
|
for join in joins:
|
|
316
316
|
if isinstance(join, BaseJoin) and join.join_type == JoinType.FULL:
|
|
317
|
-
full_join_concepts += join.
|
|
317
|
+
full_join_concepts += join.input_concepts
|
|
318
318
|
if self.whole_grain:
|
|
319
319
|
force_group = False
|
|
320
320
|
elif self.force_group is False:
|