pytrilogy 0.0.2.27__py3-none-any.whl → 0.0.2.28__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.27.dist-info → pytrilogy-0.0.2.28.dist-info}/METADATA +1 -1
- {pytrilogy-0.0.2.27.dist-info → pytrilogy-0.0.2.28.dist-info}/RECORD +10 -10
- trilogy/__init__.py +1 -1
- trilogy/core/models.py +38 -10
- trilogy/core/processing/utility.py +3 -6
- trilogy/executor.py +17 -1
- {pytrilogy-0.0.2.27.dist-info → pytrilogy-0.0.2.28.dist-info}/LICENSE.md +0 -0
- {pytrilogy-0.0.2.27.dist-info → pytrilogy-0.0.2.28.dist-info}/WHEEL +0 -0
- {pytrilogy-0.0.2.27.dist-info → pytrilogy-0.0.2.28.dist-info}/entry_points.txt +0 -0
- {pytrilogy-0.0.2.27.dist-info → pytrilogy-0.0.2.28.dist-info}/top_level.txt +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
trilogy/__init__.py,sha256=
|
|
1
|
+
trilogy/__init__.py,sha256=Oj4rApJpgEd7VNBVDA5Sy1tHnI0ISyXQcfpiH-fv6UY,291
|
|
2
2
|
trilogy/compiler.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
3
|
trilogy/constants.py,sha256=KiyYnctoZen4Hzv8WG2jeN-IE-dfQbWHdVCUeTZYjBg,1270
|
|
4
4
|
trilogy/engine.py,sha256=R5ubIxYyrxRExz07aZCUfrTsoXCHQ8DKFTDsobXdWdA,1102
|
|
5
|
-
trilogy/executor.py,sha256=
|
|
5
|
+
trilogy/executor.py,sha256=VcZ2U3RUU2al_VJ75AKVwmCJQLltYouxlgTjq4oxPB0,12577
|
|
6
6
|
trilogy/parser.py,sha256=UtuqSiGiCjpMAYgo1bvNq-b7NSzCA5hzbUW31RXaMII,281
|
|
7
7
|
trilogy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
8
|
trilogy/utility.py,sha256=zM__8r29EsyDW7K9VOHz8yvZC2bXFzh7xKy3cL7GKsk,707
|
|
@@ -16,7 +16,7 @@ trilogy/core/exceptions.py,sha256=NvV_4qLOgKXbpotgRf7c8BANDEvHxlqRPaA53IThQ2o,56
|
|
|
16
16
|
trilogy/core/functions.py,sha256=IhVpt3n6wEanKHnGu3oA2w6-hKIlxWpEyz7fHN66mpo,10720
|
|
17
17
|
trilogy/core/graph_models.py,sha256=mameUTiuCajtihDw_2-W218xyJlvTusOWrEKP1yAWgk,2003
|
|
18
18
|
trilogy/core/internal.py,sha256=jNGFHKENnbMiMCtAgsnLZYVSENDK4b5ALecXFZpTDzQ,1075
|
|
19
|
-
trilogy/core/models.py,sha256=
|
|
19
|
+
trilogy/core/models.py,sha256=W_0ZfIIEuyHfYsSXGMJOJPNJf7vSljSrRm42nLyiL8w,159702
|
|
20
20
|
trilogy/core/optimization.py,sha256=od_60A9F8J8Nj24MHgrxl4vwRwmBFH13TMdoMQvgVKs,7717
|
|
21
21
|
trilogy/core/query_processor.py,sha256=mbcZlgjChrRjDHkdmMbKe-T70UpbBkJhS09MyU5a6UY,17785
|
|
22
22
|
trilogy/core/optimizations/__init__.py,sha256=bWQecbeiwiDx9LJnLsa7dkWxdbl2wcnkcTN69JyP8iI,356
|
|
@@ -27,7 +27,7 @@ trilogy/core/optimizations/predicate_pushdown.py,sha256=1l9WnFOSv79e341typG3tTdk
|
|
|
27
27
|
trilogy/core/processing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
28
28
|
trilogy/core/processing/concept_strategies_v3.py,sha256=7MT_x6QFHrbSDmjz21pYdQB5ux419ES4QS-8lO16eyw,36091
|
|
29
29
|
trilogy/core/processing/graph_utils.py,sha256=aq-kqk4Iado2HywDxWEejWc-7PGO6Oa-ZQLAM6XWPHw,1199
|
|
30
|
-
trilogy/core/processing/utility.py,sha256=
|
|
30
|
+
trilogy/core/processing/utility.py,sha256=xlaKqnoWg-mEwTF-erBF9QXnXZtESrTuYrK2RQb7Wi4,17411
|
|
31
31
|
trilogy/core/processing/node_generators/__init__.py,sha256=-mzYkRsaRNa_dfTckYkKVFSR8h8a3ihEiPJDU_tAmDo,672
|
|
32
32
|
trilogy/core/processing/node_generators/basic_node.py,sha256=WQNgJ1MwrMS_BQ-b3XwGGB6eToDykelAVj_fesJuqe0,2069
|
|
33
33
|
trilogy/core/processing/node_generators/common.py,sha256=eslHTTPFTkmwHwKIuUsbFn54jxj-Avtt-QScqtNwzdg,8945
|
|
@@ -75,9 +75,9 @@ trilogy/parsing/render.py,sha256=B9J2GrYQcE76kddMQSeAmvAPX-9pv39mpeSHZ10SNj8,146
|
|
|
75
75
|
trilogy/parsing/trilogy.lark,sha256=_z5px2N-e8oLUf7SpPMXXNqbAykDkZOvP4_lPgf5-Uk,12245
|
|
76
76
|
trilogy/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
77
77
|
trilogy/scripts/trilogy.py,sha256=PHxvv6f2ODv0esyyhWxlARgra8dVhqQhYl0lTrSyVNo,3729
|
|
78
|
-
pytrilogy-0.0.2.
|
|
79
|
-
pytrilogy-0.0.2.
|
|
80
|
-
pytrilogy-0.0.2.
|
|
81
|
-
pytrilogy-0.0.2.
|
|
82
|
-
pytrilogy-0.0.2.
|
|
83
|
-
pytrilogy-0.0.2.
|
|
78
|
+
pytrilogy-0.0.2.28.dist-info/LICENSE.md,sha256=5ZRvtTyCCFwz1THxDTjAu3Lidds9WjPvvzgVwPSYNDo,1042
|
|
79
|
+
pytrilogy-0.0.2.28.dist-info/METADATA,sha256=Ftsu-RyQ2c7b05KV4JZm7J9f1DEMup2xjMfLUA-PfWQ,8403
|
|
80
|
+
pytrilogy-0.0.2.28.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
|
|
81
|
+
pytrilogy-0.0.2.28.dist-info/entry_points.txt,sha256=0petKryjvvtEfTlbZC1AuMFumH_WQ9v8A19LvoS6G6c,54
|
|
82
|
+
pytrilogy-0.0.2.28.dist-info/top_level.txt,sha256=cAy__NW_eMAa_yT9UnUNlZLFfxcg6eimUAZ184cdNiE,8
|
|
83
|
+
pytrilogy-0.0.2.28.dist-info/RECORD,,
|
trilogy/__init__.py
CHANGED
trilogy/core/models.py
CHANGED
|
@@ -606,6 +606,8 @@ class Concept(Mergeable, Namespaced, SelectContext, BaseModel):
|
|
|
606
606
|
return self.grain.components_copy if self.grain else []
|
|
607
607
|
|
|
608
608
|
def with_namespace(self, namespace: str) -> "Concept":
|
|
609
|
+
if namespace == self.namespace:
|
|
610
|
+
return self
|
|
609
611
|
return self.__class__(
|
|
610
612
|
name=self.name,
|
|
611
613
|
datatype=self.datatype,
|
|
@@ -3253,7 +3255,6 @@ class EnvironmentConceptDict(dict):
|
|
|
3253
3255
|
)
|
|
3254
3256
|
self.undefined[key] = undefined
|
|
3255
3257
|
return undefined
|
|
3256
|
-
|
|
3257
3258
|
matches = self._find_similar_concepts(key)
|
|
3258
3259
|
message = f"Undefined concept: {key}."
|
|
3259
3260
|
if matches:
|
|
@@ -3263,8 +3264,15 @@ class EnvironmentConceptDict(dict):
|
|
|
3263
3264
|
raise UndefinedConceptException(f"line: {line_no}: " + message, matches)
|
|
3264
3265
|
raise UndefinedConceptException(message, matches)
|
|
3265
3266
|
|
|
3266
|
-
def _find_similar_concepts(self, concept_name):
|
|
3267
|
-
|
|
3267
|
+
def _find_similar_concepts(self, concept_name: str):
|
|
3268
|
+
def strip_local(input: str):
|
|
3269
|
+
if input.startswith(f"{DEFAULT_NAMESPACE}."):
|
|
3270
|
+
return input[len(DEFAULT_NAMESPACE) + 1 :]
|
|
3271
|
+
return input
|
|
3272
|
+
|
|
3273
|
+
matches = difflib.get_close_matches(
|
|
3274
|
+
strip_local(concept_name), [strip_local(x) for x in self.keys()]
|
|
3275
|
+
)
|
|
3268
3276
|
return matches
|
|
3269
3277
|
|
|
3270
3278
|
def items(self) -> ItemsView[str, Concept]: # type: ignore
|
|
@@ -3325,7 +3333,6 @@ class Environment(BaseModel):
|
|
|
3325
3333
|
|
|
3326
3334
|
materialized_concepts: List[Concept] = Field(default_factory=list)
|
|
3327
3335
|
alias_origin_lookup: Dict[str, Concept] = Field(default_factory=dict)
|
|
3328
|
-
canonical_map: Dict[str, str] = Field(default_factory=dict)
|
|
3329
3336
|
_parse_count: int = 0
|
|
3330
3337
|
|
|
3331
3338
|
@classmethod
|
|
@@ -3444,14 +3451,38 @@ class Environment(BaseModel):
|
|
|
3444
3451
|
exists = True
|
|
3445
3452
|
imp_stm = ImportStatement(alias=alias, path=Path(source.working_path))
|
|
3446
3453
|
|
|
3454
|
+
same_namespace = alias == self.namespace
|
|
3455
|
+
|
|
3447
3456
|
if not exists:
|
|
3448
3457
|
self.imports[alias].append(imp_stm)
|
|
3449
3458
|
|
|
3450
|
-
for
|
|
3451
|
-
|
|
3459
|
+
for k, concept in source.concepts.items():
|
|
3460
|
+
if same_namespace:
|
|
3461
|
+
new = self.add_concept(concept, _ignore_cache=True)
|
|
3462
|
+
else:
|
|
3463
|
+
new = self.add_concept(
|
|
3464
|
+
concept.with_namespace(alias), _ignore_cache=True
|
|
3465
|
+
)
|
|
3466
|
+
|
|
3467
|
+
k = address_with_namespace(k, alias)
|
|
3468
|
+
# set this explicitly, to handle aliasing
|
|
3469
|
+
self.concepts[k] = new
|
|
3452
3470
|
|
|
3453
3471
|
for _, datasource in source.datasources.items():
|
|
3454
|
-
|
|
3472
|
+
if same_namespace:
|
|
3473
|
+
self.add_datasource(datasource, _ignore_cache=True)
|
|
3474
|
+
else:
|
|
3475
|
+
self.add_datasource(
|
|
3476
|
+
datasource.with_namespace(alias), _ignore_cache=True
|
|
3477
|
+
)
|
|
3478
|
+
for key, val in source.alias_origin_lookup.items():
|
|
3479
|
+
if same_namespace:
|
|
3480
|
+
self.alias_origin_lookup[key] = val
|
|
3481
|
+
else:
|
|
3482
|
+
self.alias_origin_lookup[address_with_namespace(key, alias)] = (
|
|
3483
|
+
val.with_namespace(alias)
|
|
3484
|
+
)
|
|
3485
|
+
|
|
3455
3486
|
self.gen_concept_list_caches()
|
|
3456
3487
|
return self
|
|
3457
3488
|
|
|
@@ -3542,8 +3573,6 @@ class Environment(BaseModel):
|
|
|
3542
3573
|
existing = self.validate_concept(concept, meta=meta)
|
|
3543
3574
|
if existing:
|
|
3544
3575
|
concept = existing
|
|
3545
|
-
if concept.namespace == DEFAULT_NAMESPACE:
|
|
3546
|
-
self.concepts[concept.name] = concept
|
|
3547
3576
|
self.concepts[concept.address] = concept
|
|
3548
3577
|
from trilogy.core.environment_helpers import generate_related_concepts
|
|
3549
3578
|
|
|
@@ -3631,7 +3660,6 @@ class Environment(BaseModel):
|
|
|
3631
3660
|
v.pseudonyms.add(source.address)
|
|
3632
3661
|
if v.address == source.address:
|
|
3633
3662
|
replacements[k] = target
|
|
3634
|
-
self.canonical_map[k] = target.address
|
|
3635
3663
|
v.pseudonyms.add(target.address)
|
|
3636
3664
|
# we need to update keys and grains of all concepts
|
|
3637
3665
|
else:
|
|
@@ -66,9 +66,6 @@ def resolve_join_order_v2(
|
|
|
66
66
|
) -> list[JoinOrderOutput]:
|
|
67
67
|
datasources = [x for x in g.nodes if x.startswith("ds~")]
|
|
68
68
|
concepts = [x for x in g.nodes if x.startswith("c~")]
|
|
69
|
-
# from trilogy.hooks.graph_hook import GraphHook
|
|
70
|
-
|
|
71
|
-
# GraphHook().query_graph_built(g)
|
|
72
69
|
|
|
73
70
|
output: list[JoinOrderOutput] = []
|
|
74
71
|
pivot_map = {
|
|
@@ -78,7 +75,7 @@ def resolve_join_order_v2(
|
|
|
78
75
|
pivots = list(
|
|
79
76
|
sorted(
|
|
80
77
|
[x for x in pivot_map if len(pivot_map[x]) > 1],
|
|
81
|
-
key=lambda x: len(pivot_map[x]),
|
|
78
|
+
key=lambda x: (len(pivot_map[x]), len(x), x),
|
|
82
79
|
)
|
|
83
80
|
)
|
|
84
81
|
solo = [x for x in pivot_map if len(pivot_map[x]) == 1]
|
|
@@ -95,7 +92,7 @@ def resolve_join_order_v2(
|
|
|
95
92
|
root = pivots.pop()
|
|
96
93
|
|
|
97
94
|
# sort so less partials is last and eligible lefts are
|
|
98
|
-
def score_key(x: str) -> int:
|
|
95
|
+
def score_key(x: str) -> tuple[int, int, str]:
|
|
99
96
|
base = 1
|
|
100
97
|
# if it's left, higher weight
|
|
101
98
|
if x in eligible_left:
|
|
@@ -103,7 +100,7 @@ def resolve_join_order_v2(
|
|
|
103
100
|
# if it has the concept as a partial, lower weight
|
|
104
101
|
if root in partials.get(x, []):
|
|
105
102
|
base -= 1
|
|
106
|
-
return base
|
|
103
|
+
return (base, len(x), x)
|
|
107
104
|
|
|
108
105
|
# get remainig un-joined datasets
|
|
109
106
|
to_join = sorted(
|
trilogy/executor.py
CHANGED
|
@@ -276,6 +276,20 @@ class Executor(object):
|
|
|
276
276
|
output.append(compiled_sql)
|
|
277
277
|
return output
|
|
278
278
|
|
|
279
|
+
def parse_file(self, file: str | Path, persist: bool = False) -> Generator[
|
|
280
|
+
ProcessedQuery
|
|
281
|
+
| ProcessedQueryPersist
|
|
282
|
+
| ProcessedShowStatement
|
|
283
|
+
| ProcessedRawSQLStatement
|
|
284
|
+
| ProcessedCopyStatement,
|
|
285
|
+
None,
|
|
286
|
+
None,
|
|
287
|
+
]:
|
|
288
|
+
file = Path(file)
|
|
289
|
+
with open(file, "r") as f:
|
|
290
|
+
command = f.read()
|
|
291
|
+
return self.parse_text_generator(command, persist=persist)
|
|
292
|
+
|
|
279
293
|
def parse_text(
|
|
280
294
|
self, command: str, persist: bool = False
|
|
281
295
|
) -> List[
|
|
@@ -319,9 +333,11 @@ class Executor(object):
|
|
|
319
333
|
x = self.generator.generate_queries(
|
|
320
334
|
self.environment, [t], hooks=self.hooks
|
|
321
335
|
)[0]
|
|
336
|
+
|
|
337
|
+
yield x
|
|
338
|
+
|
|
322
339
|
if persist and isinstance(x, ProcessedQueryPersist):
|
|
323
340
|
self.environment.add_datasource(x.datasource)
|
|
324
|
-
yield x
|
|
325
341
|
|
|
326
342
|
def execute_raw_sql(
|
|
327
343
|
self, command: str, variables: dict | None = None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|