pytrilogy 0.0.3.38__py3-none-any.whl → 0.0.3.39__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.3.38.dist-info → pytrilogy-0.0.3.39.dist-info}/METADATA +1 -1
- {pytrilogy-0.0.3.38.dist-info → pytrilogy-0.0.3.39.dist-info}/RECORD +14 -14
- trilogy/__init__.py +1 -1
- trilogy/core/environment_helpers.py +59 -42
- trilogy/core/functions.py +5 -4
- trilogy/core/models/author.py +0 -3
- trilogy/core/models/environment.py +11 -4
- trilogy/parsing/common.py +5 -3
- trilogy/parsing/parse_engine.py +25 -3
- trilogy/parsing/trilogy.lark +33 -15
- {pytrilogy-0.0.3.38.dist-info → pytrilogy-0.0.3.39.dist-info}/WHEEL +0 -0
- {pytrilogy-0.0.3.38.dist-info → pytrilogy-0.0.3.39.dist-info}/entry_points.txt +0 -0
- {pytrilogy-0.0.3.38.dist-info → pytrilogy-0.0.3.39.dist-info}/licenses/LICENSE.md +0 -0
- {pytrilogy-0.0.3.38.dist-info → pytrilogy-0.0.3.39.dist-info}/top_level.txt +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
pytrilogy-0.0.3.
|
|
2
|
-
trilogy/__init__.py,sha256=
|
|
1
|
+
pytrilogy-0.0.3.39.dist-info/licenses/LICENSE.md,sha256=5ZRvtTyCCFwz1THxDTjAu3Lidds9WjPvvzgVwPSYNDo,1042
|
|
2
|
+
trilogy/__init__.py,sha256=sSwrSvubMxHHrZZ2-OXo7jwbQqXFn0_nVeSAW4j8vo4,303
|
|
3
3
|
trilogy/compiler.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
4
|
trilogy/constants.py,sha256=5eQxk1A0pv-TQk3CCvgZCFA9_K-6nxrOm7E5Lxd7KIY,1652
|
|
5
5
|
trilogy/engine.py,sha256=OK2RuqCIUId6yZ5hfF8J1nxGP0AJqHRZiafcowmW0xc,1728
|
|
@@ -13,21 +13,21 @@ trilogy/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
13
13
|
trilogy/core/constants.py,sha256=7XaCpZn5mQmjTobbeBn56SzPWq9eMNDfzfsRU-fP0VE,171
|
|
14
14
|
trilogy/core/enums.py,sha256=JwbWyAHOC2xRTZe2SeEvlIGPvmC1KjcJ4uh1Po5USzQ,7380
|
|
15
15
|
trilogy/core/env_processor.py,sha256=pFsxnluKIusGKx1z7tTnfsd_xZcPy9pZDungkjkyvI0,3170
|
|
16
|
-
trilogy/core/environment_helpers.py,sha256=
|
|
16
|
+
trilogy/core/environment_helpers.py,sha256=drsaJvwmwZ1xvyEf1mAcIekQS2k3B9AKMhMzw_X2Hbs,9741
|
|
17
17
|
trilogy/core/ergonomics.py,sha256=e-7gE29vPLFdg0_A1smQ7eOrUwKl5VYdxRSTddHweRA,1631
|
|
18
18
|
trilogy/core/exceptions.py,sha256=JPYyBcit3T_pRtlHdtKSeVJkIyWUTozW2aaut25A2xI,673
|
|
19
|
-
trilogy/core/functions.py,sha256=
|
|
19
|
+
trilogy/core/functions.py,sha256=4fEOGgXWDvgrJtCg_5m2Y9iWnHfLbvLQ82RkIMl_1K0,27722
|
|
20
20
|
trilogy/core/graph_models.py,sha256=z17EoO8oky2QOuO6E2aMWoVNKEVJFhLdsQZOhC4fNLU,2079
|
|
21
21
|
trilogy/core/internal.py,sha256=iicDBlC6nM8d7e7jqzf_ZOmpUsW8yrr2AA8AqEiLx-s,1577
|
|
22
22
|
trilogy/core/optimization.py,sha256=aihzx4-2-mSjx5td1TDTYGvc7e9Zvy-_xEyhPqLS-Ig,8314
|
|
23
23
|
trilogy/core/query_processor.py,sha256=Vl-u0F0rbqI2liv82yJgiZCB255Kx_KiuzZVHL6aeTM,19459
|
|
24
24
|
trilogy/core/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
25
|
-
trilogy/core/models/author.py,sha256=
|
|
25
|
+
trilogy/core/models/author.py,sha256=hS1caD8y7XWRBlHfwgZOrBcz3TisDPba8joFaiEXxX0,77072
|
|
26
26
|
trilogy/core/models/build.py,sha256=flDLLFCR0XJ0fpUhkGg-bpDOkH915tDdXaKmrAzNIcg,61828
|
|
27
27
|
trilogy/core/models/build_environment.py,sha256=s_C9xAHuD3yZ26T15pWVBvoqvlp2LdZ8yjsv2_HdXLk,5363
|
|
28
28
|
trilogy/core/models/core.py,sha256=wx6hJcFECMG-Ij972ADNkr-3nFXkYESr82ObPiC46_U,10875
|
|
29
29
|
trilogy/core/models/datasource.py,sha256=6RjJUd2u4nYmEwFBpJlM9LbHVYDv8iHJxqiBMZqUrwI,9422
|
|
30
|
-
trilogy/core/models/environment.py,sha256=
|
|
30
|
+
trilogy/core/models/environment.py,sha256=FXQ8hOJuwF4Ul5LxNPFe1r94fN8UtI9Gx3MJwXOCiO0,27222
|
|
31
31
|
trilogy/core/models/execute.py,sha256=mQm5Gydo2Ph0W7w9wm5dQEarS04PC-IKAgNVsdqOZsQ,34524
|
|
32
32
|
trilogy/core/optimizations/__init__.py,sha256=EBanqTXEzf1ZEYjAneIWoIcxtMDite5-n2dQ5xcfUtg,356
|
|
33
33
|
trilogy/core/optimizations/base_optimization.py,sha256=gzDOKImoFn36k7XBD3ysEYDnbnb6vdVIztUfFQZsGnM,513
|
|
@@ -87,13 +87,13 @@ trilogy/hooks/graph_hook.py,sha256=c-vC-IXoJ_jDmKQjxQyIxyXPOuUcLIURB573gCsAfzQ,2
|
|
|
87
87
|
trilogy/hooks/query_debugger.py,sha256=1npRjww94sPV5RRBBlLqMJRaFkH9vhEY6o828MeoEcw,5583
|
|
88
88
|
trilogy/metadata/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
89
89
|
trilogy/parsing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
90
|
-
trilogy/parsing/common.py,sha256=
|
|
90
|
+
trilogy/parsing/common.py,sha256=GXGDnlHKTzcNx8NmcUNnfyUVNOcSgajrlz4YXdOTRSM,25931
|
|
91
91
|
trilogy/parsing/config.py,sha256=Z-DaefdKhPDmSXLgg5V4pebhSB0h590vI0_VtHnlukI,111
|
|
92
92
|
trilogy/parsing/exceptions.py,sha256=92E5i2frv5hj9wxObJZsZqj5T6bglvPzvdvco_vW1Zk,38
|
|
93
93
|
trilogy/parsing/helpers.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
94
|
-
trilogy/parsing/parse_engine.py,sha256=
|
|
94
|
+
trilogy/parsing/parse_engine.py,sha256=Tagt3zPBViM-GZYuqHb1SnbEIwa8fx12kF07JMgmyV4,65312
|
|
95
95
|
trilogy/parsing/render.py,sha256=hI4y-xjXrEXvHslY2l2TQ8ic0zAOpN41ADH37J2_FZY,19047
|
|
96
|
-
trilogy/parsing/trilogy.lark,sha256=
|
|
96
|
+
trilogy/parsing/trilogy.lark,sha256=2Noe58vGYteilKd6w-np3fb4lzWI-G9Gt0AMyOMVw3k,13735
|
|
97
97
|
trilogy/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
98
98
|
trilogy/scripts/trilogy.py,sha256=1L0XrH4mVHRt1C9T1HnaDv2_kYEfbWTb5_-cBBke79w,3774
|
|
99
99
|
trilogy/std/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -102,8 +102,8 @@ trilogy/std/display.preql,sha256=2BbhvqR4rcltyAbOXAUo7SZ_yGFYZgFnurglHMbjW2g,40
|
|
|
102
102
|
trilogy/std/geography.preql,sha256=-fqAGnBL6tR-UtT8DbSek3iMFg66ECR_B_41pODxv-k,504
|
|
103
103
|
trilogy/std/money.preql,sha256=ZHW-csTX-kYbOLmKSO-TcGGgQ-_DMrUXy0BjfuJSFxM,80
|
|
104
104
|
trilogy/std/report.preql,sha256=LbV-XlHdfw0jgnQ8pV7acG95xrd1-p65fVpiIc-S7W4,202
|
|
105
|
-
pytrilogy-0.0.3.
|
|
106
|
-
pytrilogy-0.0.3.
|
|
107
|
-
pytrilogy-0.0.3.
|
|
108
|
-
pytrilogy-0.0.3.
|
|
109
|
-
pytrilogy-0.0.3.
|
|
105
|
+
pytrilogy-0.0.3.39.dist-info/METADATA,sha256=4lI1j2Kk43ajM4gujEmJDlu0vXWN2tMPqQfudt4ZKaQ,9100
|
|
106
|
+
pytrilogy-0.0.3.39.dist-info/WHEEL,sha256=SmOxYU7pzNKBqASvQJ7DjX3XGUF92lrGhMb3R6_iiqI,91
|
|
107
|
+
pytrilogy-0.0.3.39.dist-info/entry_points.txt,sha256=ewBPU2vLnVexZVnB-NrVj-p3E-4vukg83Zk8A55Wp2w,56
|
|
108
|
+
pytrilogy-0.0.3.39.dist-info/top_level.txt,sha256=cAy__NW_eMAa_yT9UnUNlZLFfxcg6eimUAZ184cdNiE,8
|
|
109
|
+
pytrilogy-0.0.3.39.dist-info/RECORD,,
|
trilogy/__init__.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
from trilogy.constants import DEFAULT_NAMESPACE
|
|
2
2
|
from trilogy.core.enums import ConceptSource, DatePart, FunctionType, Purpose
|
|
3
|
-
from trilogy.core.functions import AttrAccess
|
|
4
|
-
from trilogy.core.models.author import Concept, Function, Metadata
|
|
3
|
+
from trilogy.core.functions import AttrAccess
|
|
4
|
+
from trilogy.core.models.author import Concept, Function, Metadata, TraitDataType
|
|
5
5
|
from trilogy.core.models.core import DataType, StructType, arg_to_datatype
|
|
6
6
|
from trilogy.core.models.environment import Environment
|
|
7
|
-
from trilogy.parsing.common import Meta
|
|
7
|
+
from trilogy.parsing.common import Meta
|
|
8
8
|
|
|
9
9
|
FUNCTION_DESCRIPTION_MAPS = {
|
|
10
10
|
FunctionType.DATE: "The date part of a timestamp/date. Integer, 0-31 depending on month.",
|
|
@@ -19,7 +19,6 @@ FUNCTION_DESCRIPTION_MAPS = {
|
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
def generate_date_concepts(concept: Concept, environment: Environment):
|
|
22
|
-
factory = FunctionFactory(environment=environment)
|
|
23
22
|
if concept.metadata and concept.metadata.description:
|
|
24
23
|
base_description = concept.metadata.description
|
|
25
24
|
else:
|
|
@@ -28,24 +27,36 @@ def generate_date_concepts(concept: Concept, environment: Environment):
|
|
|
28
27
|
base_line_number = concept.metadata.line_number
|
|
29
28
|
else:
|
|
30
29
|
base_line_number = None
|
|
31
|
-
|
|
32
|
-
FunctionType.MONTH,
|
|
33
|
-
FunctionType.YEAR,
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
30
|
+
arg_tuples: list[tuple[FunctionType, TraitDataType]] = [
|
|
31
|
+
(FunctionType.MONTH, TraitDataType(type=DataType.INTEGER, traits=["month"])),
|
|
32
|
+
(FunctionType.YEAR, TraitDataType(type=DataType.INTEGER, traits=["year"])),
|
|
33
|
+
(
|
|
34
|
+
FunctionType.QUARTER,
|
|
35
|
+
TraitDataType(type=DataType.INTEGER, traits=["quarter"]),
|
|
36
|
+
),
|
|
37
|
+
(FunctionType.DAY, TraitDataType(type=DataType.INTEGER, traits=["day"])),
|
|
38
|
+
(
|
|
39
|
+
FunctionType.DAY_OF_WEEK,
|
|
40
|
+
TraitDataType(type=DataType.INTEGER, traits=["day_of_week"]),
|
|
41
|
+
),
|
|
42
|
+
]
|
|
43
|
+
for ftype, dtype in arg_tuples:
|
|
38
44
|
fname = ftype.name.lower()
|
|
45
|
+
address = concept.address + f".{fname}"
|
|
46
|
+
if address in environment.concepts:
|
|
47
|
+
continue
|
|
39
48
|
default_type = (
|
|
40
49
|
Purpose.CONSTANT
|
|
41
50
|
if concept.purpose == Purpose.CONSTANT
|
|
42
51
|
else Purpose.PROPERTY
|
|
43
52
|
)
|
|
44
|
-
function =
|
|
53
|
+
function = Function.model_construct(
|
|
45
54
|
operator=ftype,
|
|
46
|
-
|
|
55
|
+
arguments=[concept.reference],
|
|
56
|
+
output_datatype=dtype,
|
|
57
|
+
output_purpose=default_type,
|
|
47
58
|
)
|
|
48
|
-
new_concept = Concept(
|
|
59
|
+
new_concept = Concept.model_construct(
|
|
49
60
|
name=f"{concept.name}.{fname}",
|
|
50
61
|
datatype=function.output_datatype,
|
|
51
62
|
purpose=default_type,
|
|
@@ -61,15 +72,19 @@ def generate_date_concepts(concept: Concept, environment: Environment):
|
|
|
61
72
|
concept_source=ConceptSource.AUTO_DERIVED,
|
|
62
73
|
),
|
|
63
74
|
)
|
|
64
|
-
if new_concept.name in environment.concepts:
|
|
65
|
-
continue
|
|
66
75
|
environment.add_concept(new_concept, add_derived=False)
|
|
67
76
|
for grain in [DatePart.MONTH, DatePart.YEAR]:
|
|
68
|
-
|
|
77
|
+
address = concept.address + f".{grain.value}_start"
|
|
78
|
+
if address in environment.concepts:
|
|
79
|
+
continue
|
|
80
|
+
function = Function.model_construct(
|
|
69
81
|
operator=FunctionType.DATE_TRUNCATE,
|
|
70
|
-
|
|
82
|
+
arguments=[concept.reference, grain],
|
|
83
|
+
output_datatype=DataType.DATE,
|
|
84
|
+
output_purpose=default_type,
|
|
85
|
+
arg_count=2,
|
|
71
86
|
)
|
|
72
|
-
new_concept = Concept(
|
|
87
|
+
new_concept = Concept.model_construct(
|
|
73
88
|
name=f"{concept.name}.{grain.value}_start",
|
|
74
89
|
datatype=DataType.DATE,
|
|
75
90
|
purpose=Purpose.PROPERTY,
|
|
@@ -85,13 +100,11 @@ def generate_date_concepts(concept: Concept, environment: Environment):
|
|
|
85
100
|
concept_source=ConceptSource.AUTO_DERIVED,
|
|
86
101
|
),
|
|
87
102
|
)
|
|
88
|
-
|
|
89
|
-
continue
|
|
103
|
+
|
|
90
104
|
environment.add_concept(new_concept, add_derived=False)
|
|
91
105
|
|
|
92
106
|
|
|
93
107
|
def generate_datetime_concepts(concept: Concept, environment: Environment):
|
|
94
|
-
factory = FunctionFactory(environment=environment)
|
|
95
108
|
if concept.metadata and concept.metadata.description:
|
|
96
109
|
base_description = concept.metadata.description
|
|
97
110
|
else:
|
|
@@ -100,24 +113,29 @@ def generate_datetime_concepts(concept: Concept, environment: Environment):
|
|
|
100
113
|
base_line_number = concept.metadata.line_number
|
|
101
114
|
else:
|
|
102
115
|
base_line_number = None
|
|
103
|
-
|
|
104
|
-
FunctionType.DATE,
|
|
105
|
-
FunctionType.HOUR,
|
|
106
|
-
FunctionType.MINUTE,
|
|
107
|
-
FunctionType.SECOND,
|
|
108
|
-
]
|
|
116
|
+
setup_tuples: list[tuple[FunctionType, DataType | TraitDataType]] = [
|
|
117
|
+
(FunctionType.DATE, DataType.DATE),
|
|
118
|
+
(FunctionType.HOUR, TraitDataType(type=DataType.INTEGER, traits=["hour"])),
|
|
119
|
+
(FunctionType.MINUTE, TraitDataType(type=DataType.INTEGER, traits=["minute"])),
|
|
120
|
+
(FunctionType.SECOND, TraitDataType(type=DataType.INTEGER, traits=["second"])),
|
|
121
|
+
]
|
|
122
|
+
for ftype, datatype in setup_tuples:
|
|
109
123
|
fname = ftype.name.lower()
|
|
124
|
+
address = concept.address + f".{fname}"
|
|
125
|
+
if address in environment.concepts:
|
|
126
|
+
continue
|
|
110
127
|
default_type = (
|
|
111
128
|
Purpose.CONSTANT
|
|
112
129
|
if concept.purpose == Purpose.CONSTANT
|
|
113
130
|
else Purpose.PROPERTY
|
|
114
131
|
)
|
|
115
|
-
|
|
116
|
-
const_function = factory.create_function(
|
|
132
|
+
const_function = Function.model_construct(
|
|
117
133
|
operator=ftype,
|
|
118
|
-
|
|
134
|
+
arguments=[concept.reference],
|
|
135
|
+
output_datatype=datatype,
|
|
136
|
+
output_purpose=default_type,
|
|
119
137
|
)
|
|
120
|
-
new_concept = Concept(
|
|
138
|
+
new_concept = Concept.model_construct(
|
|
121
139
|
name=f"{concept.name}.{fname}",
|
|
122
140
|
datatype=const_function.output_datatype,
|
|
123
141
|
purpose=default_type,
|
|
@@ -148,15 +166,18 @@ def generate_key_concepts(concept: Concept, environment: Environment):
|
|
|
148
166
|
else:
|
|
149
167
|
base_line_number = None
|
|
150
168
|
for ftype in [FunctionType.COUNT]:
|
|
169
|
+
address = concept.address + f".{ftype.name.lower()}"
|
|
170
|
+
if address in environment.concepts:
|
|
171
|
+
continue
|
|
151
172
|
fname = ftype.name.lower()
|
|
152
173
|
default_type = Purpose.METRIC
|
|
153
|
-
const_function: Function = Function(
|
|
174
|
+
const_function: Function = Function.model_construct(
|
|
154
175
|
operator=ftype,
|
|
155
176
|
output_datatype=DataType.INTEGER,
|
|
156
177
|
output_purpose=default_type,
|
|
157
|
-
arguments=[concept],
|
|
178
|
+
arguments=[concept.reference],
|
|
158
179
|
)
|
|
159
|
-
new_concept = Concept(
|
|
180
|
+
new_concept = Concept.model_construct(
|
|
160
181
|
name=f"{concept.name}.{fname}",
|
|
161
182
|
datatype=DataType.INTEGER,
|
|
162
183
|
purpose=default_type,
|
|
@@ -172,8 +193,6 @@ def generate_key_concepts(concept: Concept, environment: Environment):
|
|
|
172
193
|
concept_source=ConceptSource.AUTO_DERIVED,
|
|
173
194
|
),
|
|
174
195
|
)
|
|
175
|
-
if new_concept.name in environment.concepts:
|
|
176
|
-
continue
|
|
177
196
|
environment.add_concept(new_concept, add_derived=False)
|
|
178
197
|
|
|
179
198
|
|
|
@@ -199,10 +218,7 @@ def generate_related_concepts(
|
|
|
199
218
|
|
|
200
219
|
if isinstance(concept.datatype, StructType):
|
|
201
220
|
for key, value in concept.datatype.fields_map.items():
|
|
202
|
-
|
|
203
|
-
[concept, key], meta=meta, environment=environment
|
|
204
|
-
)
|
|
205
|
-
auto = Concept(
|
|
221
|
+
auto = Concept.model_construct(
|
|
206
222
|
name=key,
|
|
207
223
|
datatype=arg_to_datatype(value),
|
|
208
224
|
purpose=Purpose.PROPERTY,
|
|
@@ -212,7 +228,8 @@ def generate_related_concepts(
|
|
|
212
228
|
and environment.namespace != DEFAULT_NAMESPACE
|
|
213
229
|
else concept.name
|
|
214
230
|
),
|
|
215
|
-
lineage=AttrAccess(
|
|
231
|
+
lineage=AttrAccess([concept.reference, key], environment=environment),
|
|
232
|
+
grain=concept.grain,
|
|
216
233
|
)
|
|
217
234
|
environment.add_concept(auto, meta=meta)
|
|
218
235
|
if isinstance(value, Concept):
|
trilogy/core/functions.py
CHANGED
|
@@ -17,6 +17,7 @@ from trilogy.core.exceptions import InvalidSyntaxException
|
|
|
17
17
|
from trilogy.core.models.author import (
|
|
18
18
|
AggregateWrapper,
|
|
19
19
|
Concept,
|
|
20
|
+
ConceptRef,
|
|
20
21
|
Function,
|
|
21
22
|
Parenthetical,
|
|
22
23
|
UndefinedConcept,
|
|
@@ -35,7 +36,7 @@ from trilogy.core.models.core import (
|
|
|
35
36
|
)
|
|
36
37
|
from trilogy.core.models.environment import Environment
|
|
37
38
|
|
|
38
|
-
GENERIC_ARGS = Concept | Function | str | int | float | date | datetime
|
|
39
|
+
GENERIC_ARGS = Concept | ConceptRef | Function | str | int | float | date | datetime
|
|
39
40
|
|
|
40
41
|
|
|
41
42
|
@dataclass
|
|
@@ -773,7 +774,7 @@ class FunctionFactory:
|
|
|
773
774
|
output_purpose = Purpose.PROPERTY
|
|
774
775
|
return Function(
|
|
775
776
|
operator=operator,
|
|
776
|
-
arguments=full_args,
|
|
777
|
+
arguments=full_args, # type: ignore
|
|
777
778
|
output_datatype=final_output_type,
|
|
778
779
|
output_purpose=output_purpose,
|
|
779
780
|
valid_inputs=valid_inputs,
|
|
@@ -804,7 +805,7 @@ def create_function_derived_concept(
|
|
|
804
805
|
purpose=purpose,
|
|
805
806
|
lineage=Function(
|
|
806
807
|
operator=operator,
|
|
807
|
-
arguments=arguments,
|
|
808
|
+
arguments=[x.reference for x in arguments],
|
|
808
809
|
output_datatype=output_type,
|
|
809
810
|
output_purpose=purpose,
|
|
810
811
|
arg_count=len(arguments),
|
|
@@ -896,7 +897,7 @@ def Split(args: list[Concept], environment: Environment) -> Function:
|
|
|
896
897
|
)
|
|
897
898
|
|
|
898
899
|
|
|
899
|
-
def AttrAccess(args: list[
|
|
900
|
+
def AttrAccess(args: list[ConceptRef | str | int], environment: Environment):
|
|
900
901
|
return FunctionFactory(environment).create_function(
|
|
901
902
|
args=args, operator=FunctionType.ATTR_ACCESS
|
|
902
903
|
)
|
trilogy/core/models/author.py
CHANGED
|
@@ -1604,9 +1604,6 @@ class Function(DataTyped, ConceptArgs, Mergeable, Namespaced, BaseModel):
|
|
|
1604
1604
|
] = None
|
|
1605
1605
|
arguments: Sequence[FuncArgs]
|
|
1606
1606
|
|
|
1607
|
-
def __init__(self, **kwargs):
|
|
1608
|
-
super().__init__(**kwargs)
|
|
1609
|
-
|
|
1610
1607
|
def __repr__(self):
|
|
1611
1608
|
return f'{self.operator.value}({",".join([str(a) for a in self.arguments])})'
|
|
1612
1609
|
|
|
@@ -129,6 +129,9 @@ class EnvironmentConceptDict(dict):
|
|
|
129
129
|
def __getitem__(
|
|
130
130
|
self, key: str, line_no: int | None = None, file: Path | None = None
|
|
131
131
|
) -> Concept | UndefinedConceptFull:
|
|
132
|
+
# fast access path
|
|
133
|
+
if key in self.keys():
|
|
134
|
+
return super(EnvironmentConceptDict, self).__getitem__(key)
|
|
132
135
|
if isinstance(key, ConceptRef):
|
|
133
136
|
return self.__getitem__(key.address, line_no=line_no, file=file)
|
|
134
137
|
try:
|
|
@@ -311,11 +314,15 @@ class Environment(BaseModel):
|
|
|
311
314
|
f.write(self.model_dump_json())
|
|
312
315
|
return ppath
|
|
313
316
|
|
|
314
|
-
def validate_concept(
|
|
317
|
+
def validate_concept(
|
|
318
|
+
self, new_concept: Concept, meta: Meta | None = None
|
|
319
|
+
) -> Concept | None:
|
|
315
320
|
lookup = new_concept.address
|
|
321
|
+
if lookup not in self.concepts:
|
|
322
|
+
return None
|
|
316
323
|
existing: Concept = self.concepts.get(lookup) # type: ignore
|
|
317
|
-
if
|
|
318
|
-
return
|
|
324
|
+
if isinstance(existing, UndefinedConcept):
|
|
325
|
+
return None
|
|
319
326
|
|
|
320
327
|
def handle_persist():
|
|
321
328
|
deriv_lookup = (
|
|
@@ -361,7 +368,7 @@ class Environment(BaseModel):
|
|
|
361
368
|
if existing and self.config.allow_duplicate_declaration:
|
|
362
369
|
if existing.metadata.concept_source == ConceptSource.PERSIST_STATEMENT:
|
|
363
370
|
return handle_persist()
|
|
364
|
-
return
|
|
371
|
+
return None
|
|
365
372
|
elif existing.metadata:
|
|
366
373
|
if existing.metadata.concept_source == ConceptSource.PERSIST_STATEMENT:
|
|
367
374
|
return handle_persist()
|
trilogy/parsing/common.py
CHANGED
|
@@ -102,8 +102,10 @@ def process_function_arg(
|
|
|
102
102
|
concept.metadata.line_number = meta.line
|
|
103
103
|
environment.add_concept(concept, meta=meta)
|
|
104
104
|
return concept
|
|
105
|
+
elif isinstance(arg, Concept):
|
|
106
|
+
return arg.reference
|
|
105
107
|
elif isinstance(arg, ConceptRef):
|
|
106
|
-
return environment.concepts[arg.address]
|
|
108
|
+
return environment.concepts[arg.address].reference
|
|
107
109
|
return arg
|
|
108
110
|
|
|
109
111
|
|
|
@@ -111,8 +113,8 @@ def process_function_args(
|
|
|
111
113
|
args,
|
|
112
114
|
meta: Meta | None,
|
|
113
115
|
environment: Environment,
|
|
114
|
-
) -> List[
|
|
115
|
-
final: List[
|
|
116
|
+
) -> List[ConceptRef | Function | str | int | float | date | datetime]:
|
|
117
|
+
final: List[ConceptRef | Function | str | int | float | date | datetime] = []
|
|
116
118
|
for arg in args:
|
|
117
119
|
final.append(process_function_arg(arg, meta, environment))
|
|
118
120
|
return final
|
trilogy/parsing/parse_engine.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from dataclasses import dataclass
|
|
2
2
|
from datetime import date, datetime
|
|
3
3
|
from enum import Enum
|
|
4
|
+
from logging import getLogger
|
|
4
5
|
from os.path import dirname, join
|
|
5
6
|
from pathlib import Path
|
|
6
7
|
from re import IGNORECASE
|
|
@@ -137,6 +138,8 @@ from trilogy.parsing.common import (
|
|
|
137
138
|
)
|
|
138
139
|
from trilogy.parsing.exceptions import ParseError
|
|
139
140
|
|
|
141
|
+
perf_logger = getLogger("trilogy.parse.performance")
|
|
142
|
+
|
|
140
143
|
|
|
141
144
|
class ParsePass(Enum):
|
|
142
145
|
INITIAL = 1
|
|
@@ -407,6 +410,7 @@ class ParseToObjects(Transformer):
|
|
|
407
410
|
mapping = self.environment.concepts[address]
|
|
408
411
|
datatype = mapping.output_datatype
|
|
409
412
|
return ConceptRef(
|
|
413
|
+
# this is load-bearing to handle pseudonyms
|
|
410
414
|
address=mapping.address,
|
|
411
415
|
metadata=Metadata(line_number=meta.line),
|
|
412
416
|
datatype=datatype,
|
|
@@ -1010,6 +1014,7 @@ class ParseToObjects(Transformer):
|
|
|
1010
1014
|
return text
|
|
1011
1015
|
|
|
1012
1016
|
def import_statement(self, args: list[str]) -> ImportStatement:
|
|
1017
|
+
start = datetime.now()
|
|
1013
1018
|
if len(args) == 2:
|
|
1014
1019
|
alias = args[-1]
|
|
1015
1020
|
cache_key = args[-1]
|
|
@@ -1046,9 +1051,11 @@ class ParseToObjects(Transformer):
|
|
|
1046
1051
|
)
|
|
1047
1052
|
|
|
1048
1053
|
if token_lookup in self.tokens:
|
|
1054
|
+
perf_logger.debug(f"\tTokens cached for {token_lookup}")
|
|
1049
1055
|
raw_tokens = self.tokens[token_lookup]
|
|
1050
1056
|
text = self.text_lookup[token_lookup]
|
|
1051
1057
|
else:
|
|
1058
|
+
perf_logger.debug(f"\tTokens not cached for {token_lookup}, resolving")
|
|
1052
1059
|
text = self.resolve_import_address(target, is_stdlib)
|
|
1053
1060
|
self.text_lookup[token_lookup] = text
|
|
1054
1061
|
|
|
@@ -1061,12 +1068,19 @@ class ParseToObjects(Transformer):
|
|
|
1061
1068
|
self.tokens[token_lookup] = raw_tokens
|
|
1062
1069
|
|
|
1063
1070
|
if cache_lookup in self.parsed:
|
|
1071
|
+
perf_logger.debug(f"\tEnvironment cached for {token_lookup}")
|
|
1064
1072
|
nparser = self.parsed[cache_lookup]
|
|
1065
1073
|
new_env = nparser.environment
|
|
1066
1074
|
if nparser.parse_pass != ParsePass.VALIDATION:
|
|
1067
1075
|
# nparser.transform(raw_tokens)
|
|
1076
|
+
second_pass_start = datetime.now()
|
|
1068
1077
|
nparser.run_second_parse_pass()
|
|
1078
|
+
second_pass_end = datetime.now()
|
|
1079
|
+
perf_logger.debug(
|
|
1080
|
+
f"{second_pass_end - second_pass_start} seconds | Import {alias} key ({cache_key}) second pass took {second_pass_end - second_pass_start} to parse, {len(new_env.concepts)} concepts"
|
|
1081
|
+
)
|
|
1069
1082
|
else:
|
|
1083
|
+
perf_logger.debug(f"\tParsing new for {token_lookup}")
|
|
1070
1084
|
try:
|
|
1071
1085
|
new_env = Environment(
|
|
1072
1086
|
working_path=dirname(target),
|
|
@@ -1098,6 +1112,10 @@ class ParseToObjects(Transformer):
|
|
|
1098
1112
|
self.environment.add_import(
|
|
1099
1113
|
alias, new_env, Import(alias=alias, path=parsed_path)
|
|
1100
1114
|
)
|
|
1115
|
+
end = datetime.now()
|
|
1116
|
+
perf_logger.debug(
|
|
1117
|
+
f"{end - start} seconds | Import {alias} key ({cache_key}) took to parse, {len(new_env.concepts)} concepts"
|
|
1118
|
+
)
|
|
1101
1119
|
return imps
|
|
1102
1120
|
|
|
1103
1121
|
@v_args(meta=True)
|
|
@@ -1273,8 +1291,8 @@ class ParseToObjects(Transformer):
|
|
|
1273
1291
|
@v_args(meta=True)
|
|
1274
1292
|
def function_binding_item(self, meta: Meta, args) -> ArgBinding:
|
|
1275
1293
|
if len(args) == 2:
|
|
1276
|
-
return ArgBinding(name=args[0], default=args[1])
|
|
1277
|
-
return ArgBinding(name=args[0], default=None)
|
|
1294
|
+
return ArgBinding.model_construct(name=args[0], default=args[1])
|
|
1295
|
+
return ArgBinding.model_construct(name=args[0], default=None)
|
|
1278
1296
|
|
|
1279
1297
|
@v_args(meta=True)
|
|
1280
1298
|
def raw_function(self, meta: Meta, args) -> FunctionDeclaration:
|
|
@@ -1857,7 +1875,7 @@ def parse_text(
|
|
|
1857
1875
|
parser = ParseToObjects(
|
|
1858
1876
|
environment=environment, import_keys=["root"], parse_config=parse_config
|
|
1859
1877
|
)
|
|
1860
|
-
|
|
1878
|
+
start = datetime.now()
|
|
1861
1879
|
try:
|
|
1862
1880
|
parser.set_text(text)
|
|
1863
1881
|
# disable fail on missing to allow for circular dependencies
|
|
@@ -1867,6 +1885,10 @@ def parse_text(
|
|
|
1867
1885
|
pass_two = parser.run_second_parse_pass()
|
|
1868
1886
|
output = [v for v in pass_two if v]
|
|
1869
1887
|
environment.concepts.fail_on_missing = True
|
|
1888
|
+
end = datetime.now()
|
|
1889
|
+
perf_logger.debug(
|
|
1890
|
+
f"Parse time: {end - start} for {len(text)} characters, {len(output)} objects"
|
|
1891
|
+
)
|
|
1870
1892
|
except VisitError as e:
|
|
1871
1893
|
unpack_visit_error(e)
|
|
1872
1894
|
# this will never be reached
|
trilogy/parsing/trilogy.lark
CHANGED
|
@@ -129,7 +129,7 @@
|
|
|
129
129
|
|
|
130
130
|
limit: "LIMIT"i /[0-9]+/
|
|
131
131
|
|
|
132
|
-
!window_order:
|
|
132
|
+
!window_order: /TOP|BOTTOM/i
|
|
133
133
|
|
|
134
134
|
window: window_order /[0-9]+/
|
|
135
135
|
|
|
@@ -139,19 +139,26 @@
|
|
|
139
139
|
|
|
140
140
|
over_list: concept_lit ("," concept_lit )* ","?
|
|
141
141
|
|
|
142
|
-
!ordering:
|
|
142
|
+
!ordering: /ASC|DESC/i ("NULLS"i /FIRST|LAST|AUTO/i )?
|
|
143
143
|
|
|
144
144
|
order_by: "ORDER"i "BY"i order_list
|
|
145
145
|
|
|
146
146
|
//WHERE STATEMENT
|
|
147
|
+
LOGICAL_OR: "or"i
|
|
148
|
+
LOGICAL_AND: "and"i
|
|
147
149
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
150
|
+
conditional: _or_condition
|
|
151
|
+
|
|
152
|
+
_or_condition: _and_condition
|
|
153
|
+
| (_or_condition LOGICAL_OR _and_condition)
|
|
151
154
|
|
|
152
|
-
|
|
155
|
+
_and_condition: _condition_unit
|
|
156
|
+
| (_and_condition LOGICAL_AND _condition_unit)
|
|
153
157
|
|
|
154
|
-
|
|
158
|
+
condition_parenthetical: "(" conditional ")"
|
|
159
|
+
|
|
160
|
+
_condition_unit: expr
|
|
161
|
+
| condition_parenthetical
|
|
155
162
|
|
|
156
163
|
where: "WHERE"i conditional
|
|
157
164
|
|
|
@@ -159,7 +166,7 @@
|
|
|
159
166
|
|
|
160
167
|
!array_comparison: ( ("NOT"i "IN"i) | "IN"i)
|
|
161
168
|
|
|
162
|
-
COMPARISON_OPERATOR: (
|
|
169
|
+
COMPARISON_OPERATOR: /(is\s+not|is|=|>=|<=|!=|>|<)/i
|
|
163
170
|
|
|
164
171
|
comparison: expr COMPARISON_OPERATOR expr
|
|
165
172
|
|
|
@@ -185,16 +192,28 @@
|
|
|
185
192
|
attr_access: expr "." string_lit
|
|
186
193
|
|
|
187
194
|
|
|
188
|
-
expr:
|
|
189
|
-
|
|
195
|
+
expr: _basic_expr | _functional_expr | _operation_expr | _access_expr
|
|
196
|
+
|
|
197
|
+
# Most common/basic expressions
|
|
198
|
+
_basic_expr: literal | concept_lit | parenthetical | expr_tuple
|
|
199
|
+
|
|
200
|
+
# Operations and comparisons
|
|
201
|
+
_operation_expr: comparison | alt_like | between_comparison | subselect_comparison
|
|
202
|
+
|
|
203
|
+
# Function-like expressions
|
|
204
|
+
_functional_expr: _constant_functions | _static_functions | filter_item | aggregate_functions | window_item | custom_function | fgroup | unnest | union | aggregate_by
|
|
205
|
+
|
|
206
|
+
# Access patterns
|
|
207
|
+
_access_expr: index_access | map_key_access | attr_access
|
|
190
208
|
// functions
|
|
191
209
|
|
|
192
|
-
fadd: (
|
|
210
|
+
fadd: (/add\(/ expr "," expr ")" ) | ( expr "+" expr )
|
|
193
211
|
fsub: ("subtract"i "(" expr "," expr ")" ) | ( expr "-" expr )
|
|
194
212
|
fmul: ("multiply"i "(" expr "," expr ")" ) | ( expr "*" expr )
|
|
195
213
|
fdiv: ( "divide"i "(" expr "," expr ")") | ( expr "/" expr )
|
|
196
214
|
fmod: ( "mod"i "(" expr "," (int_lit | concept_lit ) ")") | ( expr "%" (int_lit | concept_lit ) )
|
|
197
|
-
|
|
215
|
+
_ROUND.1: "round"i "("
|
|
216
|
+
fround: _ROUND expr "," expr ")"
|
|
198
217
|
fabs: "abs"i "(" expr ")"
|
|
199
218
|
_SQRT.1: "sqrt("
|
|
200
219
|
fsqrt: _SQRT expr ")"
|
|
@@ -355,9 +374,9 @@
|
|
|
355
374
|
|
|
356
375
|
literal: null_lit | string_lit | int_lit | float_lit | bool_lit | array_lit | map_lit | struct_lit | tuple_lit
|
|
357
376
|
|
|
358
|
-
MODIFIER:
|
|
377
|
+
MODIFIER: /OPTIONAL|PARTIAL|NULLABLE/i
|
|
359
378
|
|
|
360
|
-
SHORTHAND_MODIFIER:
|
|
379
|
+
SHORTHAND_MODIFIER: /~|\?/
|
|
361
380
|
|
|
362
381
|
struct_type: "struct"i "<" ((data_type | IDENTIFIER) ",")* (data_type | IDENTIFIER) ","? ">"
|
|
363
382
|
|
|
@@ -373,7 +392,6 @@
|
|
|
373
392
|
PROPERTY: "property"i
|
|
374
393
|
CONST: "const"i | "constant"i
|
|
375
394
|
AUTO: "AUTO"i
|
|
376
|
-
|
|
377
395
|
// meta functions
|
|
378
396
|
CONCEPTS: "CONCEPTS"i
|
|
379
397
|
DATASOURCES: "DATASOURCES"i
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|