pytrilogy 0.0.2.33__py3-none-any.whl → 0.0.2.35__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.33.dist-info → pytrilogy-0.0.2.35.dist-info}/METADATA +2 -1
- {pytrilogy-0.0.2.33.dist-info → pytrilogy-0.0.2.35.dist-info}/RECORD +10 -10
- {pytrilogy-0.0.2.33.dist-info → pytrilogy-0.0.2.35.dist-info}/WHEEL +1 -1
- trilogy/__init__.py +1 -1
- trilogy/core/enums.py +17 -0
- trilogy/core/models.py +47 -4
- trilogy/parsing/parse_engine.py +18 -69
- {pytrilogy-0.0.2.33.dist-info → pytrilogy-0.0.2.35.dist-info}/LICENSE.md +0 -0
- {pytrilogy-0.0.2.33.dist-info → pytrilogy-0.0.2.35.dist-info}/entry_points.txt +0 -0
- {pytrilogy-0.0.2.33.dist-info → pytrilogy-0.0.2.35.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pytrilogy
|
|
3
|
-
Version: 0.0.2.
|
|
3
|
+
Version: 0.0.2.35
|
|
4
4
|
Summary: Declarative, typed query language that compiles to SQL.
|
|
5
5
|
Home-page:
|
|
6
6
|
Author:
|
|
@@ -20,6 +20,7 @@ Requires-Dist: networkx
|
|
|
20
20
|
Requires-Dist: pyodbc
|
|
21
21
|
Requires-Dist: pydantic
|
|
22
22
|
Requires-Dist: duckdb-engine
|
|
23
|
+
Requires-Dist: click
|
|
23
24
|
Provides-Extra: bigquery
|
|
24
25
|
Requires-Dist: sqlalchemy-bigquery; extra == "bigquery"
|
|
25
26
|
Provides-Extra: postgres
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
trilogy/__init__.py,sha256=
|
|
1
|
+
trilogy/__init__.py,sha256=U5WUYHe0fhxaKEzGbop_KX-WSQsCDldtJFhRs5Ojqys,291
|
|
2
2
|
trilogy/compiler.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
3
|
trilogy/constants.py,sha256=HQAnGUqJ5uMri7TWtqXHhz8iVWBzi2LCfRG8vKnBIB8,1269
|
|
4
4
|
trilogy/engine.py,sha256=R5ubIxYyrxRExz07aZCUfrTsoXCHQ8DKFTDsobXdWdA,1102
|
|
@@ -8,7 +8,7 @@ trilogy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
8
8
|
trilogy/utility.py,sha256=zM__8r29EsyDW7K9VOHz8yvZC2bXFzh7xKy3cL7GKsk,707
|
|
9
9
|
trilogy/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
10
|
trilogy/core/constants.py,sha256=7XaCpZn5mQmjTobbeBn56SzPWq9eMNDfzfsRU-fP0VE,171
|
|
11
|
-
trilogy/core/enums.py,sha256=
|
|
11
|
+
trilogy/core/enums.py,sha256=z-qBLh0YW52tkRtp6VLn6afxLfgI45r7_QfDtGH9CSw,6858
|
|
12
12
|
trilogy/core/env_processor.py,sha256=SHVB3nkidIlFc5dz-sofRMKXx66stpLQNuVdQSjC-So,2586
|
|
13
13
|
trilogy/core/environment_helpers.py,sha256=DIsoo-GcXmXVPB1JbNh8Oku25Nyef9mexPIdy2ur_sk,7159
|
|
14
14
|
trilogy/core/ergonomics.py,sha256=ASLDd0RqKWrZiG3XcKHo8nyTjaB_8xfE9t4NZ1UvGpc,1639
|
|
@@ -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=9jSrHBh8aE2BD4aoETm_QhRN3KI1mI009xKHTp8fLWE,162668
|
|
20
20
|
trilogy/core/optimization.py,sha256=VFSvJLNoCCOraip-PZUKeE4qrlxtXARjQUzJZiW-yRk,7325
|
|
21
21
|
trilogy/core/query_processor.py,sha256=mbcZlgjChrRjDHkdmMbKe-T70UpbBkJhS09MyU5a6UY,17785
|
|
22
22
|
trilogy/core/optimizations/__init__.py,sha256=bWQecbeiwiDx9LJnLsa7dkWxdbl2wcnkcTN69JyP8iI,356
|
|
@@ -70,14 +70,14 @@ trilogy/parsing/common.py,sha256=_GW9LU6_4RuUgcdcr8EE1ybCRd-7cz3idZtjHZ66pYA,101
|
|
|
70
70
|
trilogy/parsing/config.py,sha256=Z-DaefdKhPDmSXLgg5V4pebhSB0h590vI0_VtHnlukI,111
|
|
71
71
|
trilogy/parsing/exceptions.py,sha256=92E5i2frv5hj9wxObJZsZqj5T6bglvPzvdvco_vW1Zk,38
|
|
72
72
|
trilogy/parsing/helpers.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
73
|
-
trilogy/parsing/parse_engine.py,sha256=
|
|
73
|
+
trilogy/parsing/parse_engine.py,sha256=ukdJ5QlWcWGkvb7kd3PnnOXEVpURHm0rap8QCvvjALg,63811
|
|
74
74
|
trilogy/parsing/render.py,sha256=VKyo8wEOuiOzUtJ6w9EoGGmkhlqDQyy8wFj_Q_h6EfE,15263
|
|
75
75
|
trilogy/parsing/trilogy.lark,sha256=Tuqw5oGMwOYt3TYOEx_hZqGpsAp-PiAKiMW8S3EFRcg,12236
|
|
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.35.dist-info/LICENSE.md,sha256=5ZRvtTyCCFwz1THxDTjAu3Lidds9WjPvvzgVwPSYNDo,1042
|
|
79
|
+
pytrilogy-0.0.2.35.dist-info/METADATA,sha256=X18LM4yuJMZ4kh9Q6BUOWlxvEZgmRXMBCp9F3GNmQuA,8424
|
|
80
|
+
pytrilogy-0.0.2.35.dist-info/WHEEL,sha256=a7TGlA-5DaHMRrarXjVbQagU3Man_dCnGIWMJr5kRWo,91
|
|
81
|
+
pytrilogy-0.0.2.35.dist-info/entry_points.txt,sha256=0petKryjvvtEfTlbZC1AuMFumH_WQ9v8A19LvoS6G6c,54
|
|
82
|
+
pytrilogy-0.0.2.35.dist-info/top_level.txt,sha256=cAy__NW_eMAa_yT9UnUNlZLFfxcg6eimUAZ184cdNiE,8
|
|
83
|
+
pytrilogy-0.0.2.35.dist-info/RECORD,,
|
trilogy/__init__.py
CHANGED
trilogy/core/enums.py
CHANGED
|
@@ -215,11 +215,28 @@ class Boolean(Enum):
|
|
|
215
215
|
TRUE = "true"
|
|
216
216
|
FALSE = "false"
|
|
217
217
|
|
|
218
|
+
@classmethod
|
|
219
|
+
def _missing_(cls, value):
|
|
220
|
+
if value is True:
|
|
221
|
+
return Boolean.TRUE
|
|
222
|
+
elif value is False:
|
|
223
|
+
return Boolean.FALSE
|
|
224
|
+
strval = str(value)
|
|
225
|
+
if strval.lower() != strval:
|
|
226
|
+
return Boolean(strval.lower())
|
|
227
|
+
|
|
218
228
|
|
|
219
229
|
class BooleanOperator(Enum):
|
|
220
230
|
AND = "and"
|
|
221
231
|
OR = "or"
|
|
222
232
|
|
|
233
|
+
@classmethod
|
|
234
|
+
def _missing_(cls, value):
|
|
235
|
+
strval = str(value)
|
|
236
|
+
if strval.lower() != strval:
|
|
237
|
+
return BooleanOperator(strval.lower())
|
|
238
|
+
return None
|
|
239
|
+
|
|
223
240
|
|
|
224
241
|
class ComparisonOperator(Enum):
|
|
225
242
|
LT = "<"
|
trilogy/core/models.py
CHANGED
|
@@ -1629,6 +1629,45 @@ class SelectStatement(HasUUID, Mergeable, Namespaced, SelectTypeMixin, BaseModel
|
|
|
1629
1629
|
self.grain
|
|
1630
1630
|
)
|
|
1631
1631
|
|
|
1632
|
+
def validate_syntax(self):
|
|
1633
|
+
all_in_output = [x.address for x in self.output_components]
|
|
1634
|
+
if self.where_clause:
|
|
1635
|
+
for concept in self.where_clause.concept_arguments:
|
|
1636
|
+
|
|
1637
|
+
if (
|
|
1638
|
+
concept.lineage
|
|
1639
|
+
and isinstance(concept.lineage, Function)
|
|
1640
|
+
and concept.lineage.operator
|
|
1641
|
+
in FunctionClass.AGGREGATE_FUNCTIONS.value
|
|
1642
|
+
):
|
|
1643
|
+
if concept.address in self.locally_derived:
|
|
1644
|
+
raise SyntaxError(
|
|
1645
|
+
f"Cannot reference an aggregate derived in the select ({concept.address}) in the same statement where clause; move to the HAVING clause instead; Line: {self.meta.line_number}"
|
|
1646
|
+
)
|
|
1647
|
+
|
|
1648
|
+
if (
|
|
1649
|
+
concept.lineage
|
|
1650
|
+
and isinstance(concept.lineage, AggregateWrapper)
|
|
1651
|
+
and concept.lineage.function.operator
|
|
1652
|
+
in FunctionClass.AGGREGATE_FUNCTIONS.value
|
|
1653
|
+
):
|
|
1654
|
+
if concept.address in self.locally_derived:
|
|
1655
|
+
raise SyntaxError(
|
|
1656
|
+
f"Cannot reference an aggregate derived in the select ({concept.address}) in the same statement where clause; move to the HAVING clause instead; Line: {self.meta.line_number}"
|
|
1657
|
+
)
|
|
1658
|
+
if self.having_clause:
|
|
1659
|
+
for concept in self.having_clause.concept_arguments:
|
|
1660
|
+
if concept.address not in [x.address for x in self.output_components]:
|
|
1661
|
+
raise SyntaxError(
|
|
1662
|
+
f"Cannot reference a column ({concept.address}) that is not in the select projection in the HAVING clause, move to WHERE; Line: {self.meta.line_number}"
|
|
1663
|
+
)
|
|
1664
|
+
if self.order_by:
|
|
1665
|
+
for concept in self.order_by.concept_arguments:
|
|
1666
|
+
if concept.address not in all_in_output:
|
|
1667
|
+
raise SyntaxError(
|
|
1668
|
+
f"Cannot order by a column that is not in the output projection; {self.meta.line_number}"
|
|
1669
|
+
)
|
|
1670
|
+
|
|
1632
1671
|
def __str__(self):
|
|
1633
1672
|
from trilogy.parsing.render import render_query
|
|
1634
1673
|
|
|
@@ -3218,7 +3257,7 @@ class EnvironmentConceptDict(dict):
|
|
|
3218
3257
|
def __init__(self, *args, **kwargs) -> None:
|
|
3219
3258
|
super().__init__(self, *args, **kwargs)
|
|
3220
3259
|
self.undefined: dict[str, UndefinedConcept] = {}
|
|
3221
|
-
self.fail_on_missing: bool =
|
|
3260
|
+
self.fail_on_missing: bool = True
|
|
3222
3261
|
self.populate_default_concepts()
|
|
3223
3262
|
|
|
3224
3263
|
def populate_default_concepts(self):
|
|
@@ -3460,8 +3499,8 @@ class Environment(BaseModel):
|
|
|
3460
3499
|
|
|
3461
3500
|
if not exists:
|
|
3462
3501
|
self.imports[alias].append(imp_stm)
|
|
3463
|
-
|
|
3464
|
-
|
|
3502
|
+
# we can't exit early
|
|
3503
|
+
# as there may be new concepts
|
|
3465
3504
|
for k, concept in source.concepts.items():
|
|
3466
3505
|
if same_namespace:
|
|
3467
3506
|
new = self.add_concept(concept, _ignore_cache=True)
|
|
@@ -3525,8 +3564,11 @@ class Environment(BaseModel):
|
|
|
3525
3564
|
try:
|
|
3526
3565
|
with open(target, "r", encoding="utf-8") as f:
|
|
3527
3566
|
text = f.read()
|
|
3567
|
+
nenv = Environment(
|
|
3568
|
+
working_path=target.parent,
|
|
3569
|
+
)
|
|
3570
|
+
nenv.concepts.fail_on_missing = False
|
|
3528
3571
|
nparser = ParseToObjects(
|
|
3529
|
-
visit_tokens=True,
|
|
3530
3572
|
environment=Environment(
|
|
3531
3573
|
working_path=target.parent,
|
|
3532
3574
|
),
|
|
@@ -3535,6 +3577,7 @@ class Environment(BaseModel):
|
|
|
3535
3577
|
)
|
|
3536
3578
|
nparser.set_text(text)
|
|
3537
3579
|
nparser.transform(PARSER.parse(text))
|
|
3580
|
+
|
|
3538
3581
|
except Exception as e:
|
|
3539
3582
|
raise ImportError(
|
|
3540
3583
|
f"Unable to import file {target.parent}, parsing error: {e}"
|
trilogy/parsing/parse_engine.py
CHANGED
|
@@ -30,7 +30,6 @@ from trilogy.core.enums import (
|
|
|
30
30
|
WindowType,
|
|
31
31
|
DatePart,
|
|
32
32
|
ShowCategory,
|
|
33
|
-
FunctionClass,
|
|
34
33
|
IOType,
|
|
35
34
|
ConceptSource,
|
|
36
35
|
)
|
|
@@ -227,7 +226,6 @@ def unwrap_transformation(
|
|
|
227
226
|
class ParseToObjects(Transformer):
|
|
228
227
|
def __init__(
|
|
229
228
|
self,
|
|
230
|
-
visit_tokens,
|
|
231
229
|
environment: Environment,
|
|
232
230
|
parse_address: str | None = None,
|
|
233
231
|
token_address: Path | None = None,
|
|
@@ -235,7 +233,7 @@ class ParseToObjects(Transformer):
|
|
|
235
233
|
tokens: dict[Path | str, ParseTree] | None = None,
|
|
236
234
|
text_lookup: dict[Path | str, str] | None = None,
|
|
237
235
|
):
|
|
238
|
-
Transformer.__init__(self,
|
|
236
|
+
Transformer.__init__(self, True)
|
|
239
237
|
self.environment: Environment = environment
|
|
240
238
|
self.parse_address: str = parse_address or SELF_LABEL
|
|
241
239
|
self.token_address: Path | str = token_address or SELF_LABEL
|
|
@@ -254,16 +252,19 @@ class ParseToObjects(Transformer):
|
|
|
254
252
|
self.tokens[self.token_address] = tree
|
|
255
253
|
return results
|
|
256
254
|
|
|
255
|
+
def prepare_parse(self):
|
|
256
|
+
self.pass_count = 1
|
|
257
|
+
self.environment.concepts.fail_on_missing = False
|
|
258
|
+
for _, v in self.parsed.items():
|
|
259
|
+
v.prepare_parse()
|
|
260
|
+
|
|
257
261
|
def hydrate_missing(self):
|
|
258
262
|
self.pass_count = 2
|
|
259
263
|
for k, v in self.parsed.items():
|
|
260
|
-
|
|
261
264
|
if v.pass_count == 2:
|
|
262
265
|
continue
|
|
263
266
|
v.hydrate_missing()
|
|
264
|
-
|
|
265
|
-
# if not self.environment.concepts.undefined:
|
|
266
|
-
# return self._results_stash
|
|
267
|
+
self.environment.concepts.fail_on_missing = True
|
|
267
268
|
reparsed = self.transform(self.tokens[self.token_address])
|
|
268
269
|
self.environment.concepts.undefined = {}
|
|
269
270
|
return reparsed
|
|
@@ -850,12 +851,12 @@ class ParseToObjects(Transformer):
|
|
|
850
851
|
nparser = self.parsed[cache_lookup]
|
|
851
852
|
else:
|
|
852
853
|
try:
|
|
854
|
+
new_env = Environment(
|
|
855
|
+
working_path=dirname(target),
|
|
856
|
+
)
|
|
857
|
+
new_env.concepts.fail_on_missing = False
|
|
853
858
|
nparser = ParseToObjects(
|
|
854
|
-
|
|
855
|
-
environment=Environment(
|
|
856
|
-
working_path=dirname(target),
|
|
857
|
-
# namespace=alias,
|
|
858
|
-
),
|
|
859
|
+
environment=new_env,
|
|
859
860
|
parse_address=cache_lookup,
|
|
860
861
|
token_address=token_lookup,
|
|
861
862
|
parsed={**self.parsed, **{self.parse_address: self}},
|
|
@@ -985,8 +986,6 @@ class ParseToObjects(Transformer):
|
|
|
985
986
|
order_by=order_by,
|
|
986
987
|
meta=Metadata(line_number=meta.line),
|
|
987
988
|
)
|
|
988
|
-
locally_derived: set[str] = set()
|
|
989
|
-
all_in_output: set[str] = set()
|
|
990
989
|
for item in select_items:
|
|
991
990
|
# we don't know the grain of an aggregate at assignment time
|
|
992
991
|
# so rebuild at this point in the tree
|
|
@@ -995,25 +994,16 @@ class ParseToObjects(Transformer):
|
|
|
995
994
|
new_concept = item.content.output.with_select_context(
|
|
996
995
|
output.grain,
|
|
997
996
|
conditional=None,
|
|
998
|
-
# conditional=(
|
|
999
|
-
# output.where_clause.conditional
|
|
1000
|
-
# if output.where_clause
|
|
1001
|
-
# and output.where_clause_category == SelectFiltering.IMPLICIT
|
|
1002
|
-
# else None
|
|
1003
|
-
# ),
|
|
1004
997
|
environment=self.environment,
|
|
1005
998
|
)
|
|
1006
999
|
self.environment.add_concept(new_concept, meta=meta)
|
|
1007
1000
|
item.content.output = new_concept
|
|
1008
|
-
locally_derived.add(new_concept.address)
|
|
1009
|
-
all_in_output.add(new_concept.address)
|
|
1010
1001
|
elif isinstance(item.content, Concept):
|
|
1011
1002
|
# Sometimes cached values here don't have the latest info
|
|
1012
1003
|
# but we can't just use environment, as it might not have the right grain.
|
|
1013
1004
|
item.content = self.environment.concepts[
|
|
1014
1005
|
item.content.address
|
|
1015
1006
|
].with_grain(item.content.grain)
|
|
1016
|
-
all_in_output.add(item.content.address)
|
|
1017
1007
|
if order_by:
|
|
1018
1008
|
for orderitem in order_by.items:
|
|
1019
1009
|
if isinstance(orderitem.expr, Concept):
|
|
@@ -1021,52 +1011,9 @@ class ParseToObjects(Transformer):
|
|
|
1021
1011
|
orderitem.expr = orderitem.expr.with_select_context(
|
|
1022
1012
|
output.grain,
|
|
1023
1013
|
conditional=None,
|
|
1024
|
-
# conditional=(
|
|
1025
|
-
# output.where_clause.conditional
|
|
1026
|
-
# if output.where_clause
|
|
1027
|
-
# and output.where_clause_category
|
|
1028
|
-
# == SelectFiltering.IMPLICIT
|
|
1029
|
-
# else None
|
|
1030
|
-
# ),
|
|
1031
1014
|
environment=self.environment,
|
|
1032
1015
|
)
|
|
1033
|
-
|
|
1034
|
-
for concept in output.where_clause.concept_arguments:
|
|
1035
|
-
|
|
1036
|
-
if (
|
|
1037
|
-
concept.lineage
|
|
1038
|
-
and isinstance(concept.lineage, Function)
|
|
1039
|
-
and concept.lineage.operator
|
|
1040
|
-
in FunctionClass.AGGREGATE_FUNCTIONS.value
|
|
1041
|
-
):
|
|
1042
|
-
if concept.address in locally_derived:
|
|
1043
|
-
raise SyntaxError(
|
|
1044
|
-
f"Cannot reference an aggregate derived in the select ({concept.address}) in the same statement where clause; move to the HAVING clause instead; Line: {meta.line}"
|
|
1045
|
-
)
|
|
1046
|
-
|
|
1047
|
-
if (
|
|
1048
|
-
concept.lineage
|
|
1049
|
-
and isinstance(concept.lineage, AggregateWrapper)
|
|
1050
|
-
and concept.lineage.function.operator
|
|
1051
|
-
in FunctionClass.AGGREGATE_FUNCTIONS.value
|
|
1052
|
-
):
|
|
1053
|
-
if concept.address in locally_derived:
|
|
1054
|
-
raise SyntaxError(
|
|
1055
|
-
f"Cannot reference an aggregate derived in the select ({concept.address}) in the same statement where clause; move to the HAVING clause instead; Line: {meta.line}"
|
|
1056
|
-
)
|
|
1057
|
-
if output.having_clause:
|
|
1058
|
-
for concept in output.having_clause.concept_arguments:
|
|
1059
|
-
if concept.address not in all_in_output:
|
|
1060
|
-
raise SyntaxError(
|
|
1061
|
-
f"Cannot reference a column ({concept.address}) that is not in the select projection in the HAVING clause, move to WHERE; Line: {meta.line}"
|
|
1062
|
-
)
|
|
1063
|
-
if output.order_by:
|
|
1064
|
-
for concept in output.order_by.concept_arguments:
|
|
1065
|
-
if concept.address not in all_in_output:
|
|
1066
|
-
raise SyntaxError(
|
|
1067
|
-
f"Cannot order by a column that is not in the output projection; {meta.line}"
|
|
1068
|
-
)
|
|
1069
|
-
|
|
1016
|
+
output.validate_syntax()
|
|
1070
1017
|
return output
|
|
1071
1018
|
|
|
1072
1019
|
@v_args(meta=True)
|
|
@@ -1954,12 +1901,14 @@ def parse_text(text: str, environment: Optional[Environment] = None) -> Tuple[
|
|
|
1954
1901
|
],
|
|
1955
1902
|
]:
|
|
1956
1903
|
environment = environment or Environment()
|
|
1957
|
-
parser = ParseToObjects(
|
|
1904
|
+
parser = ParseToObjects(environment=environment)
|
|
1958
1905
|
|
|
1959
1906
|
try:
|
|
1960
1907
|
parser.set_text(text)
|
|
1908
|
+
# disable fail on missing to allow for circular dependencies
|
|
1909
|
+
parser.prepare_parse()
|
|
1961
1910
|
parser.transform(PARSER.parse(text))
|
|
1962
|
-
#
|
|
1911
|
+
# this will reset fail on missing
|
|
1963
1912
|
pass_two = parser.hydrate_missing()
|
|
1964
1913
|
output = [v for v in pass_two if v]
|
|
1965
1914
|
except VisitError as e:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|