vtlengine 1.0.2__py3-none-any.whl → 1.0.3__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 vtlengine might be problematic. Click here for more details.
- vtlengine/API/_InternalApi.py +12 -5
- vtlengine/API/__init__.py +8 -8
- vtlengine/AST/ASTConstructor.py +23 -43
- vtlengine/AST/ASTConstructorModules/Expr.py +69 -84
- vtlengine/AST/ASTConstructorModules/ExprComponents.py +47 -57
- vtlengine/AST/ASTConstructorModules/Terminals.py +28 -39
- vtlengine/AST/ASTTemplate.py +0 -1
- vtlengine/AST/DAG/__init__.py +12 -15
- vtlengine/AST/Grammar/tokens.py +2 -2
- vtlengine/AST/VtlVisitor.py +0 -1
- vtlengine/AST/__init__.py +2 -3
- vtlengine/DataTypes/TimeHandling.py +10 -7
- vtlengine/DataTypes/__init__.py +17 -24
- vtlengine/Exceptions/__init__.py +3 -5
- vtlengine/Exceptions/messages.py +68 -56
- vtlengine/Interpreter/__init__.py +82 -103
- vtlengine/Model/__init__.py +10 -12
- vtlengine/Operators/Aggregation.py +14 -14
- vtlengine/Operators/Analytic.py +3 -10
- vtlengine/Operators/Assignment.py +2 -3
- vtlengine/Operators/Boolean.py +5 -7
- vtlengine/Operators/CastOperator.py +12 -13
- vtlengine/Operators/Clause.py +11 -13
- vtlengine/Operators/Comparison.py +31 -17
- vtlengine/Operators/Conditional.py +48 -49
- vtlengine/Operators/General.py +4 -4
- vtlengine/Operators/HROperators.py +41 -34
- vtlengine/Operators/Join.py +18 -22
- vtlengine/Operators/Numeric.py +44 -45
- vtlengine/Operators/RoleSetter.py +6 -8
- vtlengine/Operators/Set.py +7 -12
- vtlengine/Operators/String.py +19 -27
- vtlengine/Operators/Time.py +298 -109
- vtlengine/Operators/Validation.py +4 -7
- vtlengine/Operators/__init__.py +38 -41
- vtlengine/Utils/__init__.py +133 -114
- vtlengine/__init__.py +1 -1
- vtlengine/files/output/__init__.py +2 -2
- vtlengine/files/output/_time_period_representation.py +0 -1
- vtlengine/files/parser/__init__.py +16 -18
- vtlengine/files/parser/_time_checking.py +1 -2
- {vtlengine-1.0.2.dist-info → vtlengine-1.0.3.dist-info}/METADATA +5 -2
- vtlengine-1.0.3.dist-info/RECORD +58 -0
- vtlengine-1.0.2.dist-info/RECORD +0 -58
- {vtlengine-1.0.2.dist-info → vtlengine-1.0.3.dist-info}/LICENSE.md +0 -0
- {vtlengine-1.0.2.dist-info → vtlengine-1.0.3.dist-info}/WHEEL +0 -0
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
from antlr4.tree.Tree import TerminalNodeImpl
|
|
2
2
|
|
|
3
3
|
from vtlengine.AST import (
|
|
4
|
+
ID,
|
|
4
5
|
Aggregation,
|
|
5
|
-
|
|
6
|
+
Analytic,
|
|
6
7
|
BinOp,
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
ParamOp,
|
|
10
|
-
MulOp,
|
|
8
|
+
Case,
|
|
9
|
+
CaseObj,
|
|
11
10
|
Constant,
|
|
11
|
+
EvalOp,
|
|
12
|
+
Identifier,
|
|
13
|
+
If,
|
|
14
|
+
MulOp,
|
|
12
15
|
ParamConstant,
|
|
16
|
+
ParamOp,
|
|
13
17
|
TimeAggregation,
|
|
14
|
-
Identifier,
|
|
15
|
-
EvalOp,
|
|
16
|
-
VarID,
|
|
17
|
-
Analytic,
|
|
18
18
|
UDOCall,
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
UnaryOp,
|
|
20
|
+
VarID,
|
|
21
21
|
)
|
|
22
22
|
from vtlengine.AST.ASTConstructorModules.Terminals import Terminals
|
|
23
23
|
from vtlengine.AST.Grammar.parser import Parser
|
|
@@ -36,20 +36,20 @@ class ExprComp(VtlVisitor):
|
|
|
36
36
|
def visitExprComponent(self, ctx: Parser.ExprComponentContext):
|
|
37
37
|
"""
|
|
38
38
|
exprComponent:
|
|
39
|
-
LPAREN exprComponent RPAREN # parenthesisExprComp
|
|
40
|
-
| functionsComponents # functionsExpressionComp
|
|
41
|
-
| op=(PLUS|MINUS|NOT) right=exprComponent # unaryExprComp
|
|
42
|
-
| left=exprComponent op=(MUL|DIV) right=exprComponent # arithmeticExprComp
|
|
43
|
-
| left=exprComponent op=(PLUS|MINUS|CONCAT) right=exprComponent # arithmeticExprOrConcatComp
|
|
44
|
-
| left=exprComponent comparisonOperand right=exprComponent # comparisonExprComp
|
|
45
|
-
| left=exprComponent op=(IN|NOT_IN)(lists|valueDomainID) # inNotInExprComp
|
|
46
|
-
| left=exprComponent op=AND right=exprComponent # booleanExprComp
|
|
47
|
-
| left=exprComponent op=(OR|XOR) right=exprComponent # booleanExprComp
|
|
48
|
-
| IF conditionalExpr=exprComponent THEN thenExpr=exprComponent ELSE elseExpr=exprComponent # ifExprComp
|
|
49
|
-
| constant # constantExprComp
|
|
50
|
-
| componentID # compId
|
|
39
|
+
LPAREN exprComponent RPAREN # parenthesisExprComp
|
|
40
|
+
| functionsComponents # functionsExpressionComp
|
|
41
|
+
| op=(PLUS|MINUS|NOT) right=exprComponent # unaryExprComp
|
|
42
|
+
| left=exprComponent op=(MUL|DIV) right=exprComponent # arithmeticExprComp
|
|
43
|
+
| left=exprComponent op=(PLUS|MINUS|CONCAT) right=exprComponent # arithmeticExprOrConcatComp
|
|
44
|
+
| left=exprComponent comparisonOperand right=exprComponent # comparisonExprComp
|
|
45
|
+
| left=exprComponent op=(IN|NOT_IN)(lists|valueDomainID) # inNotInExprComp
|
|
46
|
+
| left=exprComponent op=AND right=exprComponent # booleanExprComp
|
|
47
|
+
| left=exprComponent op=(OR|XOR) right=exprComponent # booleanExprComp
|
|
48
|
+
| IF conditionalExpr=exprComponent THEN thenExpr=exprComponent ELSE elseExpr=exprComponent # ifExprComp
|
|
49
|
+
| constant # constantExprComp
|
|
50
|
+
| componentID # compId
|
|
51
51
|
;
|
|
52
|
-
"""
|
|
52
|
+
""" # noqa E501
|
|
53
53
|
ctx_list = list(ctx.getChildren())
|
|
54
54
|
c = ctx_list[0]
|
|
55
55
|
|
|
@@ -279,8 +279,8 @@ class ExprComp(VtlVisitor):
|
|
|
279
279
|
|
|
280
280
|
def visitCallComponent(self, ctx: Parser.CallComponentContext):
|
|
281
281
|
"""
|
|
282
|
-
callFunction: operatorID LPAREN (parameterComponent (COMMA parameterComponent)*)? RPAREN # callComponent
|
|
283
|
-
"""
|
|
282
|
+
callFunction: operatorID LPAREN (parameterComponent (COMMA parameterComponent)*)? RPAREN # callComponent
|
|
283
|
+
""" # noqa E501
|
|
284
284
|
ctx_list = list(ctx.getChildren())
|
|
285
285
|
c = ctx_list[0]
|
|
286
286
|
|
|
@@ -295,8 +295,8 @@ class ExprComp(VtlVisitor):
|
|
|
295
295
|
|
|
296
296
|
def visitEvalAtomComponent(self, ctx: Parser.EvalAtomComponentContext):
|
|
297
297
|
"""
|
|
298
|
-
| EVAL LPAREN routineName LPAREN (componentID|scalarItem)? (COMMA (componentID|scalarItem))* RPAREN (LANGUAGE STRING_CONSTANT)? (RETURNS outputParameterTypeComponent)? RPAREN # evalAtomComponent
|
|
299
|
-
"""
|
|
298
|
+
| EVAL LPAREN routineName LPAREN (componentID|scalarItem)? (COMMA (componentID|scalarItem))* RPAREN (LANGUAGE STRING_CONSTANT)? (RETURNS outputParameterTypeComponent)? RPAREN # evalAtomComponent
|
|
299
|
+
""" # noqa E501
|
|
300
300
|
ctx_list = list(ctx.getChildren())
|
|
301
301
|
|
|
302
302
|
routine_name = Terminals().visitRoutineName(ctx_list[2])
|
|
@@ -346,8 +346,8 @@ class ExprComp(VtlVisitor):
|
|
|
346
346
|
|
|
347
347
|
def visitCastExprComponent(self, ctx: Parser.CastExprComponentContext):
|
|
348
348
|
"""
|
|
349
|
-
| CAST LPAREN exprComponent COMMA (basicScalarType|valueDomainName) (COMMA STRING_CONSTANT)? RPAREN # castExprComponent
|
|
350
|
-
"""
|
|
349
|
+
| CAST LPAREN exprComponent COMMA (basicScalarType|valueDomainName) (COMMA STRING_CONSTANT)? RPAREN # castExprComponent
|
|
350
|
+
""" # noqa E501
|
|
351
351
|
ctx_list = list(ctx.getChildren())
|
|
352
352
|
c = ctx_list[0]
|
|
353
353
|
|
|
@@ -579,24 +579,19 @@ class ExprComp(VtlVisitor):
|
|
|
579
579
|
elif isinstance(ctx, Parser.CurrentDateAtomComponentContext):
|
|
580
580
|
return self.visitCurrentDateAtomComponent(ctx)
|
|
581
581
|
elif isinstance(ctx, Parser.DateDiffAtomComponentContext):
|
|
582
|
-
return self.
|
|
582
|
+
return self.visitDateDiffAtomComponent(ctx)
|
|
583
583
|
elif isinstance(ctx, Parser.DateAddAtomComponentContext):
|
|
584
584
|
return self.visitDateAddAtomComponentContext(ctx)
|
|
585
|
-
elif isinstance(ctx,
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
elif isinstance(ctx, Parser.DayToMonthAtomComponentContext):
|
|
596
|
-
return self.visitTimeUnaryAtomComponent(ctx)
|
|
597
|
-
elif isinstance(ctx, Parser.YearToDayAtomComponentContext):
|
|
598
|
-
return self.visitTimeUnaryAtomComponent(ctx)
|
|
599
|
-
elif isinstance(ctx, Parser.MonthToDayAtomComponentContext):
|
|
585
|
+
elif (isinstance(ctx, (
|
|
586
|
+
Parser.YearAtomComponentContext,
|
|
587
|
+
Parser.MonthAtomComponentContext,
|
|
588
|
+
Parser.DayOfMonthAtomComponentContext,
|
|
589
|
+
Parser.DayOfYearAtomComponentContext,
|
|
590
|
+
Parser.DayToYearAtomComponentContext,
|
|
591
|
+
Parser.DayToMonthAtomComponentContext,
|
|
592
|
+
Parser.YearToDayAtomComponentContext,
|
|
593
|
+
Parser.MonthToDayAtomComponentContext
|
|
594
|
+
))):
|
|
600
595
|
return self.visitTimeUnaryAtomComponent(ctx)
|
|
601
596
|
else:
|
|
602
597
|
raise NotImplementedError
|
|
@@ -653,9 +648,9 @@ class ExprComp(VtlVisitor):
|
|
|
653
648
|
|
|
654
649
|
def visitTimeAggAtomComponent(self, ctx: Parser.TimeAggAtomComponentContext):
|
|
655
650
|
"""
|
|
656
|
-
TIME_AGG LPAREN periodIndTo=STRING_CONSTANT (COMMA periodIndFrom=(STRING_CONSTANT| OPTIONAL ))?
|
|
657
|
-
(COMMA op=optionalExprComponent)? (COMMA (FIRST|LAST))? RPAREN # timeAggAtomComponent;
|
|
658
|
-
"""
|
|
651
|
+
TIME_AGG LPAREN periodIndTo=STRING_CONSTANT (COMMA periodIndFrom=(STRING_CONSTANT| OPTIONAL ))?
|
|
652
|
+
(COMMA op=optionalExprComponent)? (COMMA (FIRST|LAST))? RPAREN # timeAggAtomComponent;
|
|
653
|
+
""" # noqa E501
|
|
659
654
|
ctx_list = list(ctx.getChildren())
|
|
660
655
|
c = ctx_list[0]
|
|
661
656
|
|
|
@@ -674,10 +669,7 @@ class ExprComp(VtlVisitor):
|
|
|
674
669
|
and str_.getSymbol().type in [Parser.FIRST, Parser.LAST]
|
|
675
670
|
]
|
|
676
671
|
|
|
677
|
-
if len(conf) == 0
|
|
678
|
-
conf = None
|
|
679
|
-
else:
|
|
680
|
-
conf = conf[0]
|
|
672
|
+
conf = None if len(conf) == 0 else conf[0]
|
|
681
673
|
|
|
682
674
|
if ctx.op is not None:
|
|
683
675
|
operand_node = self.visitOptionalExprComponent(ctx.op)
|
|
@@ -706,7 +698,7 @@ class ExprComp(VtlVisitor):
|
|
|
706
698
|
|
|
707
699
|
op = c.getSymbol().text
|
|
708
700
|
left_node = self.visitExprComponent(ctx_list[2])
|
|
709
|
-
right_node =
|
|
701
|
+
right_node = self.visitExprComponent(ctx_list[4])
|
|
710
702
|
|
|
711
703
|
return BinOp(left=left_node, op=op, right=right_node)
|
|
712
704
|
|
|
@@ -889,9 +881,7 @@ class ExprComp(VtlVisitor):
|
|
|
889
881
|
elif isinstance(c, Parser.OrderByClauseContext):
|
|
890
882
|
order_by = Terminals().visitOrderByClause(c)
|
|
891
883
|
continue
|
|
892
|
-
elif isinstance(c, Parser.SignedIntegerContext)
|
|
893
|
-
c, Parser.ScalarItemContext
|
|
894
|
-
):
|
|
884
|
+
elif isinstance(c, (Parser.SignedIntegerContext, Parser.ScalarItemContext)):
|
|
895
885
|
if params is None:
|
|
896
886
|
params = []
|
|
897
887
|
if isinstance(c, Parser.SignedIntegerContext):
|
|
@@ -1,13 +1,3 @@
|
|
|
1
|
-
from vtlengine.DataTypes import (
|
|
2
|
-
Boolean,
|
|
3
|
-
Date,
|
|
4
|
-
Duration,
|
|
5
|
-
Integer,
|
|
6
|
-
Number,
|
|
7
|
-
String,
|
|
8
|
-
TimeInterval,
|
|
9
|
-
TimePeriod,
|
|
10
|
-
)
|
|
11
1
|
from antlr4.tree.Tree import TerminalNodeImpl
|
|
12
2
|
|
|
13
3
|
from vtlengine.AST import (
|
|
@@ -24,6 +14,16 @@ from vtlengine.AST import (
|
|
|
24
14
|
)
|
|
25
15
|
from vtlengine.AST.Grammar.parser import Parser
|
|
26
16
|
from vtlengine.AST.VtlVisitor import VtlVisitor
|
|
17
|
+
from vtlengine.DataTypes import (
|
|
18
|
+
Boolean,
|
|
19
|
+
Date,
|
|
20
|
+
Duration,
|
|
21
|
+
Integer,
|
|
22
|
+
Number,
|
|
23
|
+
String,
|
|
24
|
+
TimeInterval,
|
|
25
|
+
TimePeriod,
|
|
26
|
+
)
|
|
27
27
|
from vtlengine.Model import Component, Dataset, Role, Scalar
|
|
28
28
|
|
|
29
29
|
|
|
@@ -377,21 +377,21 @@ class Terminals(VtlVisitor):
|
|
|
377
377
|
|
|
378
378
|
def visitDpRuleset(self, ctx: Parser.DpRulesetContext):
|
|
379
379
|
"""
|
|
380
|
-
DATAPOINT # dataPoint
|
|
381
|
-
| DATAPOINT_ON_VD (GLPAREN valueDomainName (MUL valueDomainName)* GRPAREN )? # dataPointVd
|
|
382
|
-
| DATAPOINT_ON_VAR (GLPAREN varID (MUL varID)* GRPAREN )? # dataPointVar
|
|
380
|
+
DATAPOINT # dataPoint
|
|
381
|
+
| DATAPOINT_ON_VD (GLPAREN valueDomainName (MUL valueDomainName)* GRPAREN )? # dataPointVd
|
|
382
|
+
| DATAPOINT_ON_VAR (GLPAREN varID (MUL varID)* GRPAREN )? # dataPointVar
|
|
383
383
|
;
|
|
384
|
-
"""
|
|
384
|
+
""" # noqa E501
|
|
385
385
|
# AST_ASTCONSTRUCTOR.54
|
|
386
386
|
raise NotImplementedError
|
|
387
387
|
|
|
388
388
|
def visitHrRuleset(self, ctx: Parser.HrRulesetContext):
|
|
389
389
|
"""
|
|
390
|
-
hrRuleset: HIERARCHICAL # hrRulesetType
|
|
391
|
-
| HIERARCHICAL_ON_VD ( GLPAREN vdName=IDENTIFIER (LPAREN valueDomainName (MUL valueDomainName)* RPAREN)? GRPAREN )? # hrRulesetVdType
|
|
392
|
-
| HIERARCHICAL_ON_VAR ( GLPAREN varName=varID (LPAREN varID (MUL varID)* RPAREN)? GRPAREN )? # hrRulesetVarType
|
|
390
|
+
hrRuleset: HIERARCHICAL # hrRulesetType
|
|
391
|
+
| HIERARCHICAL_ON_VD ( GLPAREN vdName=IDENTIFIER (LPAREN valueDomainName (MUL valueDomainName)* RPAREN)? GRPAREN )? # hrRulesetVdType
|
|
392
|
+
| HIERARCHICAL_ON_VAR ( GLPAREN varName=varID (LPAREN varID (MUL varID)* RPAREN)? GRPAREN )? # hrRulesetVarType
|
|
393
393
|
;
|
|
394
|
-
"""
|
|
394
|
+
""" # noqa E501
|
|
395
395
|
# AST_ASTCONSTRUCTOR.55
|
|
396
396
|
raise NotImplementedError
|
|
397
397
|
|
|
@@ -407,15 +407,9 @@ class Terminals(VtlVisitor):
|
|
|
407
407
|
for constraint in ctx_list
|
|
408
408
|
if isinstance(constraint, Parser.ScalarTypeContext)
|
|
409
409
|
]
|
|
410
|
-
if len(data_type) > 0
|
|
411
|
-
data_type = data_type[0]
|
|
412
|
-
else:
|
|
413
|
-
data_type = String()
|
|
410
|
+
data_type = data_type[0] if len(data_type) > 0 else String()
|
|
414
411
|
|
|
415
|
-
|
|
416
|
-
nullable = False
|
|
417
|
-
else:
|
|
418
|
-
nullable = True
|
|
412
|
+
nullable = role_node != Role.IDENTIFIER
|
|
419
413
|
|
|
420
414
|
return Component(name="Component", data_type=data_type, role=role_node, nullable=nullable)
|
|
421
415
|
|
|
@@ -503,7 +497,7 @@ class Terminals(VtlVisitor):
|
|
|
503
497
|
def visitScalarWithCast(self, ctx: Parser.ScalarWithCastContext):
|
|
504
498
|
"""
|
|
505
499
|
| CAST LPAREN constant COMMA (basicScalarType) (COMMA STRING_CONSTANT)? RPAREN #scalarWithCast # noqa E501
|
|
506
|
-
"""
|
|
500
|
+
""" # noqa E501
|
|
507
501
|
ctx_list = list(ctx.getChildren())
|
|
508
502
|
c = ctx_list[0]
|
|
509
503
|
|
|
@@ -513,10 +507,7 @@ class Terminals(VtlVisitor):
|
|
|
513
507
|
const_node = self.visitConstant(ctx_list[2])
|
|
514
508
|
basic_scalar_type = [self.visitBasicScalarType(ctx_list[4])]
|
|
515
509
|
|
|
516
|
-
if len(ctx_list) > 6
|
|
517
|
-
param_node = [ParamConstant("PARAM_CAST", ctx_list[6])]
|
|
518
|
-
else:
|
|
519
|
-
param_node = []
|
|
510
|
+
param_node = [ParamConstant("PARAM_CAST", ctx_list[6])] if len(ctx_list) > 6 else []
|
|
520
511
|
|
|
521
512
|
if len(basic_scalar_type) == 1:
|
|
522
513
|
children_nodes = [const_node, basic_scalar_type[0]]
|
|
@@ -681,14 +672,12 @@ class Terminals(VtlVisitor):
|
|
|
681
672
|
first = num_rows_1 # unbounded (default value)
|
|
682
673
|
second = num_rows_2 # current data point (default value)
|
|
683
674
|
|
|
684
|
-
if mode_2 == "preceding"
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
f"line {ctx_list[3].start.line}"
|
|
691
|
-
)
|
|
675
|
+
if (mode_2 == "preceding" and mode_1 == "preceding" and num_rows_1 == -1
|
|
676
|
+
and num_rows_2 == -1): # preceding and preceding (error)
|
|
677
|
+
raise Exception(
|
|
678
|
+
f"Cannot have 2 preceding clauses with unbounded in analytic clause, "
|
|
679
|
+
f"line {ctx_list[3].start.line}"
|
|
680
|
+
)
|
|
692
681
|
|
|
693
682
|
if (
|
|
694
683
|
mode_1 == "following" and num_rows_1 == -1 and num_rows_2 == -1
|
vtlengine/AST/ASTTemplate.py
CHANGED
vtlengine/AST/DAG/__init__.py
CHANGED
|
@@ -15,24 +15,24 @@ import networkx as nx
|
|
|
15
15
|
|
|
16
16
|
from vtlengine.AST import (
|
|
17
17
|
AST,
|
|
18
|
-
BinOp,
|
|
19
|
-
VarID,
|
|
20
18
|
Aggregation,
|
|
21
19
|
Analytic,
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
Operator,
|
|
25
|
-
Identifier,
|
|
20
|
+
Assignment,
|
|
21
|
+
BinOp,
|
|
26
22
|
DefIdentifier,
|
|
27
|
-
|
|
23
|
+
DPRuleset,
|
|
28
24
|
HRuleset,
|
|
29
|
-
|
|
25
|
+
Identifier,
|
|
26
|
+
JoinOp,
|
|
27
|
+
Operator,
|
|
28
|
+
ParamOp,
|
|
30
29
|
PersistentAssignment,
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
RegularAggregation,
|
|
31
|
+
Start,
|
|
32
|
+
VarID,
|
|
33
33
|
)
|
|
34
34
|
from vtlengine.AST.ASTTemplate import ASTTemplate
|
|
35
|
-
from vtlengine.AST.DAG._words import
|
|
35
|
+
from vtlengine.AST.DAG._words import DELETE, GLOBAL, INPUTS, INSERT, OUTPUTS, PERSISTENT
|
|
36
36
|
from vtlengine.AST.Grammar.tokens import AS, MEMBERSHIP, TO
|
|
37
37
|
from vtlengine.Exceptions import SemanticError
|
|
38
38
|
|
|
@@ -313,10 +313,7 @@ class DAGAnalyzer(ASTTemplate):
|
|
|
313
313
|
self.visit(node.left)
|
|
314
314
|
self.isDataset = False
|
|
315
315
|
self.visit(node.right)
|
|
316
|
-
elif node.op == AS:
|
|
317
|
-
self.visit(node.left)
|
|
318
|
-
self.alias.append(node.right.value)
|
|
319
|
-
elif node.op == TO:
|
|
316
|
+
elif node.op == AS or node.op == TO:
|
|
320
317
|
self.visit(node.left)
|
|
321
318
|
self.alias.append(node.right.value)
|
|
322
319
|
else:
|
vtlengine/AST/Grammar/tokens.py
CHANGED
|
@@ -91,8 +91,8 @@ STOCK_TO_FLOW = "stock_to_flow"
|
|
|
91
91
|
TIMESHIFT = "timeshift"
|
|
92
92
|
TIME_AGG = "time_agg"
|
|
93
93
|
CURRENT_DATE = "current_date"
|
|
94
|
-
|
|
95
|
-
DATE_ADD = "
|
|
94
|
+
DATEDIFF = "datediff"
|
|
95
|
+
DATE_ADD = "dateadd"
|
|
96
96
|
YEAR = "year"
|
|
97
97
|
MONTH = "month"
|
|
98
98
|
DAYOFMONTH = "dayofmonth"
|
vtlengine/AST/VtlVisitor.py
CHANGED
vtlengine/AST/__init__.py
CHANGED
|
@@ -11,7 +11,6 @@ from dataclasses import dataclass
|
|
|
11
11
|
from typing import Any, Dict, List, Optional, Type, Union
|
|
12
12
|
|
|
13
13
|
from vtlengine.DataTypes import ScalarType
|
|
14
|
-
|
|
15
14
|
from vtlengine.Model import Role
|
|
16
15
|
|
|
17
16
|
|
|
@@ -33,7 +32,7 @@ class AST:
|
|
|
33
32
|
"""Returns a human-friendly description."""
|
|
34
33
|
out = []
|
|
35
34
|
name = self.__class__.__name__
|
|
36
|
-
for k in self.__all_annotations()
|
|
35
|
+
for k in self.__all_annotations():
|
|
37
36
|
v = self.__getattribute__(k)
|
|
38
37
|
if v:
|
|
39
38
|
out.append(f"{k}={str(v)}")
|
|
@@ -41,7 +40,7 @@ class AST:
|
|
|
41
40
|
|
|
42
41
|
def toJSON(self):
|
|
43
42
|
base = {"class_name": self.__class__.__name__}
|
|
44
|
-
for k in self.__all_annotations()
|
|
43
|
+
for k in self.__all_annotations():
|
|
45
44
|
v = self.__getattribute__(k)
|
|
46
45
|
base[k] = v
|
|
47
46
|
return base
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import calendar
|
|
2
2
|
import copy
|
|
3
3
|
import operator
|
|
4
|
-
from datetime import date
|
|
5
|
-
from
|
|
4
|
+
from datetime import date
|
|
5
|
+
from datetime import datetime as dt
|
|
6
|
+
from typing import Any, Dict, Optional, Union
|
|
6
7
|
|
|
7
8
|
import pandas as pd
|
|
8
9
|
|
|
@@ -31,9 +32,11 @@ def date_to_period(date_value: date, period_indicator: str) -> Any:
|
|
|
31
32
|
return TimePeriodHandler(f"{date_value.year}D{date_value.timetuple().tm_yday}")
|
|
32
33
|
|
|
33
34
|
|
|
34
|
-
def period_to_date(
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
def period_to_date(year: int,
|
|
36
|
+
period_indicator: str,
|
|
37
|
+
period_number: int,
|
|
38
|
+
start: bool = False
|
|
39
|
+
) -> date:
|
|
37
40
|
if period_indicator == "A":
|
|
38
41
|
return date(year, 1, 1) if start else date(year, 12, 31)
|
|
39
42
|
periods = {
|
|
@@ -209,7 +212,7 @@ class TimePeriodHandler:
|
|
|
209
212
|
raise SemanticError(
|
|
210
213
|
"2-1-19-7",
|
|
211
214
|
periods=PeriodDuration.periods[self.period_indicator],
|
|
212
|
-
|
|
215
|
+
period_indicator=self.period_indicator,
|
|
213
216
|
)
|
|
214
217
|
# raise ValueError(f'Period Number must be between 1 and '
|
|
215
218
|
# f'{PeriodDuration.periods[self.period_indicator]} '
|
|
@@ -483,7 +486,7 @@ def check_max_date(str_: Optional[str]) -> Optional[str]:
|
|
|
483
486
|
|
|
484
487
|
# Format 2010-01-01. Prevent passthrough of other ISO 8601 formats.
|
|
485
488
|
if len(str_) != 10 or str_[7] != "-":
|
|
486
|
-
raise SemanticError("2-1-19-8", date=
|
|
489
|
+
raise SemanticError("2-1-19-8", date=str_)
|
|
487
490
|
# raise ValueError(f"Invalid date format, must be YYYY-MM-DD: {str_}")
|
|
488
491
|
|
|
489
492
|
result = date.fromisoformat(str_)
|
vtlengine/DataTypes/__init__.py
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
from typing import Any,
|
|
1
|
+
from typing import Any, Dict, Optional, Set, Type, Union
|
|
2
|
+
|
|
2
3
|
import pandas as pd
|
|
3
4
|
|
|
4
|
-
from vtlengine.DataTypes.TimeHandling import
|
|
5
|
+
from vtlengine.DataTypes.TimeHandling import check_max_date, date_to_period_str, str_period_to_date
|
|
5
6
|
from vtlengine.Exceptions import SemanticError
|
|
6
7
|
|
|
7
8
|
DTYPE_MAPPING: Dict[str, str] = {
|
|
@@ -310,7 +311,8 @@ class TimeInterval(ScalarType):
|
|
|
310
311
|
|
|
311
312
|
@classmethod
|
|
312
313
|
def explicit_cast(cls, value: Any, from_type: Any) -> Any:
|
|
313
|
-
|
|
314
|
+
if from_type == String:
|
|
315
|
+
return value # check_time(value). TODO: resolve this to avoid a circular import.
|
|
314
316
|
raise SemanticError(
|
|
315
317
|
"2-1-5-1",
|
|
316
318
|
value=value,
|
|
@@ -328,7 +330,7 @@ class Date(TimeInterval):
|
|
|
328
330
|
def implicit_cast(cls, value: Any, from_type: Any) -> Any:
|
|
329
331
|
# TODO: Remove String, only for compatibility with previous engine
|
|
330
332
|
if from_type in {Date, String}:
|
|
331
|
-
return value
|
|
333
|
+
return check_max_date(value)
|
|
332
334
|
|
|
333
335
|
raise SemanticError(
|
|
334
336
|
"2-1-5-1",
|
|
@@ -341,7 +343,7 @@ class Date(TimeInterval):
|
|
|
341
343
|
def explicit_cast(cls, value: Any, from_type: Any) -> Any:
|
|
342
344
|
# TODO: Remove String, only for compatibility with previous engine
|
|
343
345
|
if from_type == String:
|
|
344
|
-
return value
|
|
346
|
+
return check_max_date(value)
|
|
345
347
|
|
|
346
348
|
raise SemanticError(
|
|
347
349
|
"2-1-5-1",
|
|
@@ -384,7 +386,7 @@ class TimePeriod(TimeInterval):
|
|
|
384
386
|
return period_str
|
|
385
387
|
# TODO: Remove String, only for compatibility with previous engine
|
|
386
388
|
elif from_type == String:
|
|
387
|
-
return value
|
|
389
|
+
return value # check_time_period(value) TODO: resolve this to avoid a circular import.
|
|
388
390
|
|
|
389
391
|
raise SemanticError(
|
|
390
392
|
"2-1-5-1",
|
|
@@ -442,15 +444,9 @@ class Boolean(ScalarType):
|
|
|
442
444
|
else:
|
|
443
445
|
return None
|
|
444
446
|
if isinstance(value, int):
|
|
445
|
-
|
|
446
|
-
return True
|
|
447
|
-
else:
|
|
448
|
-
return False
|
|
447
|
+
return value != 0
|
|
449
448
|
if isinstance(value, float):
|
|
450
|
-
|
|
451
|
-
return True
|
|
452
|
-
else:
|
|
453
|
-
return False
|
|
449
|
+
return value != 0.0
|
|
454
450
|
if isinstance(value, bool):
|
|
455
451
|
return value
|
|
456
452
|
return value
|
|
@@ -470,9 +466,7 @@ class Boolean(ScalarType):
|
|
|
470
466
|
@classmethod
|
|
471
467
|
def explicit_cast(cls, value: Any, from_type: Any) -> bool:
|
|
472
468
|
if from_type in {Number, Integer}:
|
|
473
|
-
|
|
474
|
-
return False
|
|
475
|
-
return True
|
|
469
|
+
return value not in {0}
|
|
476
470
|
|
|
477
471
|
raise SemanticError(
|
|
478
472
|
"2-1-5-1",
|
|
@@ -672,13 +666,12 @@ def unary_implicit_promotion(
|
|
|
672
666
|
return: The resulting type of the operation, after the implicit type promotion
|
|
673
667
|
"""
|
|
674
668
|
operand_implicities = IMPLICIT_TYPE_PROMOTION_MAPPING[operand_type]
|
|
675
|
-
if type_to_check:
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
)
|
|
669
|
+
if type_to_check and not type_to_check.is_included(operand_implicities):
|
|
670
|
+
raise SemanticError(
|
|
671
|
+
code="1-1-1-1",
|
|
672
|
+
type_1=SCALAR_TYPES_CLASS_REVERSE[operand_type],
|
|
673
|
+
type_2=SCALAR_TYPES_CLASS_REVERSE[type_to_check],
|
|
674
|
+
)
|
|
682
675
|
if return_type:
|
|
683
676
|
return return_type
|
|
684
677
|
if (
|
vtlengine/Exceptions/__init__.py
CHANGED
|
@@ -7,7 +7,8 @@ Description
|
|
|
7
7
|
All exceptions exposed by the Vtl engine.
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
|
-
from typing import
|
|
10
|
+
from typing import Any, List, Optional
|
|
11
|
+
|
|
11
12
|
from vtlengine.Exceptions.messages import centralised_messages
|
|
12
13
|
|
|
13
14
|
dataset_output = None
|
|
@@ -165,10 +166,7 @@ def key_distance(key: str, objetive: str) -> int:
|
|
|
165
166
|
|
|
166
167
|
for i in range(1, len(key) + 1):
|
|
167
168
|
for j in range(1, len(objetive) + 1):
|
|
168
|
-
if key[i - 1] == objetive[j - 1]
|
|
169
|
-
cost = 0
|
|
170
|
-
else:
|
|
171
|
-
cost = 1
|
|
169
|
+
cost = 0 if key[i - 1] == objetive[j - 1] else 1
|
|
172
170
|
dp[i][j] = min(dp[i - 1][j] + 1,
|
|
173
171
|
dp[i][j - 1] + 1,
|
|
174
172
|
dp[i - 1][j - 1] + cost)
|