vtlengine 1.0__py3-none-any.whl → 1.0.2__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.

Files changed (56) hide show
  1. vtlengine/API/_InternalApi.py +159 -102
  2. vtlengine/API/__init__.py +110 -68
  3. vtlengine/AST/ASTConstructor.py +188 -98
  4. vtlengine/AST/ASTConstructorModules/Expr.py +402 -205
  5. vtlengine/AST/ASTConstructorModules/ExprComponents.py +248 -104
  6. vtlengine/AST/ASTConstructorModules/Terminals.py +158 -95
  7. vtlengine/AST/ASTEncoders.py +1 -1
  8. vtlengine/AST/ASTTemplate.py +24 -9
  9. vtlengine/AST/ASTVisitor.py +8 -12
  10. vtlengine/AST/DAG/__init__.py +43 -35
  11. vtlengine/AST/DAG/_words.py +4 -4
  12. vtlengine/AST/Grammar/Vtl.g4 +49 -20
  13. vtlengine/AST/Grammar/VtlTokens.g4 +13 -1
  14. vtlengine/AST/Grammar/lexer.py +2012 -1312
  15. vtlengine/AST/Grammar/parser.py +7524 -4343
  16. vtlengine/AST/Grammar/tokens.py +140 -128
  17. vtlengine/AST/VtlVisitor.py +16 -5
  18. vtlengine/AST/__init__.py +41 -11
  19. vtlengine/DataTypes/NumericTypesHandling.py +5 -4
  20. vtlengine/DataTypes/TimeHandling.py +196 -301
  21. vtlengine/DataTypes/__init__.py +304 -218
  22. vtlengine/Exceptions/__init__.py +96 -27
  23. vtlengine/Exceptions/messages.py +149 -69
  24. vtlengine/Interpreter/__init__.py +817 -497
  25. vtlengine/Model/__init__.py +172 -121
  26. vtlengine/Operators/Aggregation.py +156 -95
  27. vtlengine/Operators/Analytic.py +167 -79
  28. vtlengine/Operators/Assignment.py +7 -4
  29. vtlengine/Operators/Boolean.py +27 -32
  30. vtlengine/Operators/CastOperator.py +177 -131
  31. vtlengine/Operators/Clause.py +137 -99
  32. vtlengine/Operators/Comparison.py +148 -117
  33. vtlengine/Operators/Conditional.py +290 -98
  34. vtlengine/Operators/General.py +68 -47
  35. vtlengine/Operators/HROperators.py +91 -72
  36. vtlengine/Operators/Join.py +217 -118
  37. vtlengine/Operators/Numeric.py +129 -46
  38. vtlengine/Operators/RoleSetter.py +16 -15
  39. vtlengine/Operators/Set.py +61 -36
  40. vtlengine/Operators/String.py +213 -139
  41. vtlengine/Operators/Time.py +467 -215
  42. vtlengine/Operators/Validation.py +117 -76
  43. vtlengine/Operators/__init__.py +340 -213
  44. vtlengine/Utils/__init__.py +232 -41
  45. vtlengine/__init__.py +1 -1
  46. vtlengine/files/output/__init__.py +15 -6
  47. vtlengine/files/output/_time_period_representation.py +10 -9
  48. vtlengine/files/parser/__init__.py +79 -52
  49. vtlengine/files/parser/_rfc_dialect.py +6 -5
  50. vtlengine/files/parser/_time_checking.py +48 -37
  51. vtlengine-1.0.2.dist-info/METADATA +245 -0
  52. vtlengine-1.0.2.dist-info/RECORD +58 -0
  53. {vtlengine-1.0.dist-info → vtlengine-1.0.2.dist-info}/WHEEL +1 -1
  54. vtlengine-1.0.dist-info/METADATA +0 -104
  55. vtlengine-1.0.dist-info/RECORD +0 -58
  56. {vtlengine-1.0.dist-info → vtlengine-1.0.2.dist-info}/LICENSE.md +0 -0
@@ -1,21 +1,36 @@
1
- from vtlengine.DataTypes import Boolean, Date, Duration, Integer, Number, String, TimeInterval, \
2
- TimePeriod
1
+ from vtlengine.DataTypes import (
2
+ Boolean,
3
+ Date,
4
+ Duration,
5
+ Integer,
6
+ Number,
7
+ String,
8
+ TimeInterval,
9
+ TimePeriod,
10
+ )
3
11
  from antlr4.tree.Tree import TerminalNodeImpl
4
12
 
5
- from vtlengine.AST import BinOp, Collection, Constant, DPRIdentifier, \
6
- Identifier, \
7
- OrderBy, \
8
- ParamConstant, \
9
- ParamOp, VarID, Windowing
13
+ from vtlengine.AST import (
14
+ BinOp,
15
+ Collection,
16
+ Constant,
17
+ DPRIdentifier,
18
+ Identifier,
19
+ OrderBy,
20
+ ParamConstant,
21
+ ParamOp,
22
+ VarID,
23
+ Windowing,
24
+ )
10
25
  from vtlengine.AST.Grammar.parser import Parser
11
26
  from vtlengine.AST.VtlVisitor import VtlVisitor
12
27
  from vtlengine.Model import Component, Dataset, Role, Scalar
13
28
 
14
29
 
15
30
  def _remove_scaped_characters(text):
16
- has_scaped_char = text.find("\'") != -1
31
+ has_scaped_char = text.find("'") != -1
17
32
  if has_scaped_char:
18
- text = str(text.replace("\'", ""))
33
+ text = str(text.replace("'", ""))
19
34
  return text
20
35
 
21
36
 
@@ -24,24 +39,24 @@ class Terminals(VtlVisitor):
24
39
  token = ctx.children[0].getSymbol()
25
40
 
26
41
  if token.type == Parser.INTEGER_CONSTANT:
27
- constant_node = Constant('INTEGER_CONSTANT', int(token.text))
42
+ constant_node = Constant("INTEGER_CONSTANT", int(token.text))
28
43
 
29
44
  elif token.type == Parser.NUMBER_CONSTANT:
30
- constant_node = Constant('FLOAT_CONSTANT', float(token.text))
45
+ constant_node = Constant("FLOAT_CONSTANT", float(token.text))
31
46
 
32
47
  elif token.type == Parser.BOOLEAN_CONSTANT:
33
- if token.text == 'true':
34
- constant_node = Constant('BOOLEAN_CONSTANT', True)
35
- elif token.text == 'false':
36
- constant_node = Constant('BOOLEAN_CONSTANT', False)
48
+ if token.text == "true":
49
+ constant_node = Constant("BOOLEAN_CONSTANT", True)
50
+ elif token.text == "false":
51
+ constant_node = Constant("BOOLEAN_CONSTANT", False)
37
52
  else:
38
53
  raise NotImplementedError
39
54
 
40
55
  elif token.type == Parser.STRING_CONSTANT:
41
- constant_node = Constant('STRING_CONSTANT', token.text[1:-1])
56
+ constant_node = Constant("STRING_CONSTANT", token.text[1:-1])
42
57
 
43
58
  elif token.type == Parser.NULL_CONSTANT:
44
- constant_node = Constant('NULL_CONSTANT', None)
59
+ constant_node = Constant("NULL_CONSTANT", None)
45
60
 
46
61
  else:
47
62
  raise NotImplementedError
@@ -73,26 +88,30 @@ class Terminals(VtlVisitor):
73
88
  # check token text
74
89
  token.text = _remove_scaped_characters(token.text)
75
90
 
76
- return Identifier(token.text, 'ComponentID')
91
+ return Identifier(token.text, "ComponentID")
77
92
 
78
93
  def visitComponentID(self, ctx: Parser.ComponentIDContext):
79
94
  ctx_list = list(ctx.getChildren())
80
95
 
81
96
  if len(ctx_list) == 1:
82
97
  component_name = ctx_list[0].getSymbol().text
83
- if component_name.startswith("\'") and component_name.endswith(
84
- "\'"): # The component could be imbalance, errorcode or errorlevel
98
+ if component_name.startswith("'") and component_name.endswith(
99
+ "'"
100
+ ): # The component could be imbalance, errorcode or errorlevel
85
101
  component_name = component_name[1:-1]
86
- return Identifier(component_name, 'ComponentID')
102
+ return Identifier(component_name, "ComponentID")
87
103
  else:
88
104
  component_name = ctx_list[2].getSymbol().text
89
- if component_name.startswith("\'") and component_name.endswith(
90
- "\'"): # The component could be imbalance, errorcode or errorlevel
105
+ if component_name.startswith("'") and component_name.endswith(
106
+ "'"
107
+ ): # The component could be imbalance, errorcode or errorlevel
91
108
  component_name = component_name[1:-1]
92
109
  op_node = ctx_list[1].getSymbol().text
93
- return BinOp(left=Identifier(ctx_list[0].getSymbol().text, 'DatasetID'),
94
- op=op_node,
95
- right=Identifier(component_name, 'ComponentID'))
110
+ return BinOp(
111
+ left=Identifier(ctx_list[0].getSymbol().text, "DatasetID"),
112
+ op=op_node,
113
+ right=Identifier(component_name, "ComponentID"),
114
+ )
96
115
 
97
116
  def visitOperatorID(self, ctx: Parser.OperatorIDContext):
98
117
  """
@@ -107,8 +126,9 @@ class Terminals(VtlVisitor):
107
126
  """
108
127
  valueDomainID: IDENTIFIER ;
109
128
  """
110
- return Collection(name=ctx.children[0].getSymbol().text, children=[],
111
- kind='ValueDomain', type='')
129
+ return Collection(
130
+ name=ctx.children[0].getSymbol().text, children=[], kind="ValueDomain", type=""
131
+ )
112
132
 
113
133
  def visitRulesetID(self, ctx: Parser.RulesetIDContext):
114
134
  """
@@ -126,8 +146,9 @@ class Terminals(VtlVisitor):
126
146
  ctx_list = list(ctx.getChildren())
127
147
  # AST_ASTCONSTRUCTOR.48
128
148
  raise NotImplementedError(
129
- 'Value Domain \'{}\' not available for cast operator or scalar type representation or rulesets.'.format(
130
- ctx_list[0].getSymbol().text))
149
+ "Value Domain '{}' not available for cast operator or scalar type "
150
+ "representation or rulesets.".format(ctx_list[0].getSymbol().text)
151
+ )
131
152
 
132
153
  def visitValueDomainValue(self, ctx: Parser.ValueDomainValueContext):
133
154
  return _remove_scaped_characters(ctx.children[0].getSymbol().text)
@@ -205,9 +226,9 @@ class Terminals(VtlVisitor):
205
226
  """
206
227
  viralAttribute: VIRAL ATTRIBUTE;
207
228
  """
208
- ctx_list = list(ctx.getChildren())
209
- c = ctx_list[0]
210
- token = c.getSymbol()
229
+ # ctx_list = list(ctx.getChildren())
230
+ # c = ctx_list[0]
231
+ # token = c.getSymbol()
211
232
 
212
233
  raise NotImplementedError
213
234
 
@@ -222,7 +243,8 @@ class Terminals(VtlVisitor):
222
243
  scalars = [scalar for scalar in ctx_list if isinstance(scalar, Parser.SimpleScalarContext)]
223
244
 
224
245
  scalars_with_cast = [
225
- scalar for scalar in ctx_list if isinstance(scalar, Parser.ScalarWithCastContext)]
246
+ scalar for scalar in ctx_list if isinstance(scalar, Parser.ScalarWithCastContext)
247
+ ]
226
248
 
227
249
  for scalar in scalars:
228
250
  scalar_nodes.append(self.visitSimpleScalar(scalar))
@@ -230,7 +252,7 @@ class Terminals(VtlVisitor):
230
252
  for scalar_with_cast in scalars_with_cast:
231
253
  scalar_nodes.append(self.visitScalarWithCast(scalar_with_cast))
232
254
 
233
- return Collection('Set', None, scalar_nodes)
255
+ return Collection("Set", None, scalar_nodes)
234
256
 
235
257
  def visitMultModifier(self, ctx: Parser.MultModifierContext):
236
258
  """
@@ -244,12 +266,21 @@ class Terminals(VtlVisitor):
244
266
  """
245
267
  ctx_list = list(ctx.getChildren())
246
268
 
247
- component_node = [self.visitComponentType(component) for component in ctx_list if
248
- isinstance(component, Parser.ComponentTypeContext)]
249
- component_name = [self.visitComponentID(component).value for component in ctx_list if
250
- isinstance(component, Parser.ComponentIDContext)]
251
- component_mult = [self.visitMultModifier(modifier) for modifier in ctx_list if
252
- isinstance(modifier, Parser.MultModifierContext)]
269
+ component_node = [
270
+ self.visitComponentType(component)
271
+ for component in ctx_list
272
+ if isinstance(component, Parser.ComponentTypeContext)
273
+ ]
274
+ component_name = [
275
+ self.visitComponentID(component).value
276
+ for component in ctx_list
277
+ if isinstance(component, Parser.ComponentIDContext)
278
+ ]
279
+ component_mult = [
280
+ self.visitMultModifier(modifier)
281
+ for modifier in ctx_list
282
+ if isinstance(modifier, Parser.MultModifierContext)
283
+ ]
253
284
 
254
285
  if len(component_mult) != 0:
255
286
  # AST_ASTCONSTRUCTOR.51
@@ -272,17 +303,28 @@ class Terminals(VtlVisitor):
272
303
  """
273
304
  ctx_list = list(ctx.getChildren())
274
305
 
275
- types = (Parser.BasicScalarTypeContext, Parser.ValueDomainNameContext,
276
- Parser.ScalarTypeConstraintContext)
306
+ types = (
307
+ Parser.BasicScalarTypeContext,
308
+ Parser.ValueDomainNameContext,
309
+ Parser.ScalarTypeConstraintContext,
310
+ )
277
311
  scalartype = [scalartype for scalartype in ctx_list if isinstance(scalartype, types)][0]
278
312
 
279
- scalartype_constraint = [constraint for constraint in ctx_list if
280
- isinstance(constraint, Parser.ScalarTypeConstraintContext)]
281
- not_ = [not_.getSymbol().text for not_ in ctx_list if
282
- isinstance(not_, TerminalNodeImpl) and not_.getSymbol().type == Parser.NOT]
283
- null_constant = [null.getSymbol().text for null in ctx_list if
284
- isinstance(null,
285
- TerminalNodeImpl) and null.getSymbol().type == Parser.NULL_CONSTANT]
313
+ scalartype_constraint = [
314
+ constraint
315
+ for constraint in ctx_list
316
+ if isinstance(constraint, Parser.ScalarTypeConstraintContext)
317
+ ]
318
+ not_ = [
319
+ not_.getSymbol().text
320
+ for not_ in ctx_list
321
+ if isinstance(not_, TerminalNodeImpl) and not_.getSymbol().type == Parser.NOT
322
+ ]
323
+ null_constant = [
324
+ null.getSymbol().text
325
+ for null in ctx_list
326
+ if isinstance(null, TerminalNodeImpl) and null.getSymbol().type == Parser.NULL_CONSTANT
327
+ ]
286
328
 
287
329
  if isinstance(scalartype, Parser.BasicScalarTypeContext):
288
330
  if scalartype.children[0].getSymbol().type == Parser.SCALAR:
@@ -315,8 +357,11 @@ class Terminals(VtlVisitor):
315
357
  """
316
358
  ctx_list = list(ctx.getChildren())
317
359
 
318
- components = [self.visitCompConstraint(constraint) for constraint in ctx_list if
319
- isinstance(constraint, Parser.CompConstraintContext)]
360
+ components = [
361
+ self.visitCompConstraint(constraint)
362
+ for constraint in ctx_list
363
+ if isinstance(constraint, Parser.CompConstraintContext)
364
+ ]
320
365
  components = {component.name: component for component in components}
321
366
 
322
367
  return Dataset(name="Dataset", components=components, data=None)
@@ -332,9 +377,9 @@ class Terminals(VtlVisitor):
332
377
 
333
378
  def visitDpRuleset(self, ctx: Parser.DpRulesetContext):
334
379
  """
335
- DATAPOINT # dataPoint
336
- | DATAPOINT_ON_VD (GLPAREN valueDomainName (MUL valueDomainName)* GRPAREN )? # dataPointVd
337
- | DATAPOINT_ON_VAR (GLPAREN varID (MUL varID)* GRPAREN )? # dataPointVar
380
+ DATAPOINT # dataPoint # noqa E501
381
+ | DATAPOINT_ON_VD (GLPAREN valueDomainName (MUL valueDomainName)* GRPAREN )? # dataPointVd # noqa E501
382
+ | DATAPOINT_ON_VAR (GLPAREN varID (MUL varID)* GRPAREN )? # dataPointVar # noqa E501
338
383
  ;
339
384
  """
340
385
  # AST_ASTCONSTRUCTOR.54
@@ -342,9 +387,9 @@ class Terminals(VtlVisitor):
342
387
 
343
388
  def visitHrRuleset(self, ctx: Parser.HrRulesetContext):
344
389
  """
345
- hrRuleset: HIERARCHICAL # hrRulesetType
346
- | HIERARCHICAL_ON_VD ( GLPAREN vdName=IDENTIFIER (LPAREN valueDomainName (MUL valueDomainName)* RPAREN)? GRPAREN )? # hrRulesetVdType
347
- | HIERARCHICAL_ON_VAR ( GLPAREN varName=varID (LPAREN varID (MUL varID)* RPAREN)? GRPAREN )? # hrRulesetVarType
390
+ hrRuleset: HIERARCHICAL # hrRulesetType # noqa E501
391
+ | HIERARCHICAL_ON_VD ( GLPAREN vdName=IDENTIFIER (LPAREN valueDomainName (MUL valueDomainName)* RPAREN)? GRPAREN )? # hrRulesetVdType # noqa E501
392
+ | HIERARCHICAL_ON_VAR ( GLPAREN varName=varID (LPAREN varID (MUL varID)* RPAREN)? GRPAREN )? # hrRulesetVarType # noqa E501
348
393
  ;
349
394
  """
350
395
  # AST_ASTCONSTRUCTOR.55
@@ -357,8 +402,11 @@ class Terminals(VtlVisitor):
357
402
  ctx_list = list(ctx.getChildren())
358
403
 
359
404
  role_node = self.visitComponentRole(ctx_list[0])
360
- data_type = [self.visitScalarType(constraint) for constraint in ctx_list if
361
- isinstance(constraint, Parser.ScalarTypeContext)]
405
+ data_type = [
406
+ self.visitScalarType(constraint)
407
+ for constraint in ctx_list
408
+ if isinstance(constraint, Parser.ScalarTypeContext)
409
+ ]
362
410
  if len(data_type) > 0:
363
411
  data_type = data_type[0]
364
412
  else:
@@ -454,7 +502,7 @@ class Terminals(VtlVisitor):
454
502
 
455
503
  def visitScalarWithCast(self, ctx: Parser.ScalarWithCastContext):
456
504
  """
457
- | CAST LPAREN constant COMMA (basicScalarType) (COMMA STRING_CONSTANT)? RPAREN #scalarWithCast
505
+ | CAST LPAREN constant COMMA (basicScalarType) (COMMA STRING_CONSTANT)? RPAREN #scalarWithCast # noqa E501
458
506
  """
459
507
  ctx_list = list(ctx.getChildren())
460
508
  c = ctx_list[0]
@@ -466,7 +514,7 @@ class Terminals(VtlVisitor):
466
514
  basic_scalar_type = [self.visitBasicScalarType(ctx_list[4])]
467
515
 
468
516
  if len(ctx_list) > 6:
469
- param_node = [ParamConstant('PARAM_CAST', ctx_list[6])]
517
+ param_node = [ParamConstant("PARAM_CAST", ctx_list[6])]
470
518
  else:
471
519
  param_node = []
472
520
 
@@ -495,15 +543,15 @@ class Terminals(VtlVisitor):
495
543
  token = ctx.children[0].getSymbol()
496
544
 
497
545
  if token.type == Parser.BOOLEAN_CONSTANT:
498
- if token.text == 'true':
499
- param_constant_node = Constant('BOOLEAN_CONSTANT', True)
500
- elif token.text == 'false':
501
- param_constant_node = Constant('BOOLEAN_CONSTANT', False)
546
+ if token.text == "true":
547
+ param_constant_node = Constant("BOOLEAN_CONSTANT", True)
548
+ elif token.text == "false":
549
+ param_constant_node = Constant("BOOLEAN_CONSTANT", False)
502
550
  else:
503
551
  raise NotImplementedError
504
552
 
505
553
  elif token.type == Parser.ALL:
506
- param_constant_node = ParamConstant('PARAM_CONSTANT', token.text)
554
+ param_constant_node = ParamConstant("PARAM_CONSTANT", token.text)
507
555
 
508
556
  else:
509
557
  raise NotImplementedError
@@ -539,7 +587,7 @@ class Terminals(VtlVisitor):
539
587
  try:
540
588
  return str(self.visitConstant(ctx_list[1]).value)
541
589
  except Exception:
542
- raise Exception(f'Error code must be a string, line {ctx_list[1].getSymbol().line}')
590
+ raise Exception(f"Error code must be a string, line {ctx_list[1].getSymbol().line}")
543
591
 
544
592
  def visitErLevel(self, ctx: Parser.ErLevelContext):
545
593
  """
@@ -550,9 +598,9 @@ class Terminals(VtlVisitor):
550
598
  try:
551
599
  return int(self.visitConstant(ctx_list[1]).value)
552
600
  except Exception:
553
- raise Exception(f'Error level must be an integer, line {ctx_list[1].start.line}')
601
+ raise Exception(f"Error level must be an integer, line {ctx_list[1].start.line}")
554
602
 
555
- def visitSignature(self, ctx: Parser.SignatureContext, kind='ComponentID'):
603
+ def visitSignature(self, ctx: Parser.SignatureContext, kind="ComponentID"):
556
604
  """
557
605
  varID (AS alias)?
558
606
  """
@@ -577,8 +625,9 @@ class Terminals(VtlVisitor):
577
625
  def visitConditionClause(self, ctx: Parser.ConditionClauseContext):
578
626
  ctx_list = list(ctx.getChildren())
579
627
 
580
- components = [self.visitComponentID(c) for c in ctx_list
581
- if isinstance(c, Parser.ComponentIDContext)]
628
+ components = [
629
+ self.visitComponentID(c) for c in ctx_list if isinstance(c, Parser.ComponentIDContext)
630
+ ]
582
631
 
583
632
  return components
584
633
 
@@ -604,21 +653,25 @@ class Terminals(VtlVisitor):
604
653
  def visitPartitionByClause(self, ctx: Parser.PartitionByClauseContext):
605
654
  ctx_list = list(ctx.getChildren())
606
655
 
607
- return [self.visitComponentID(compID).value for compID in ctx_list if
608
- isinstance(compID, Parser.ComponentIDContext)]
656
+ return [
657
+ self.visitComponentID(compID).value
658
+ for compID in ctx_list
659
+ if isinstance(compID, Parser.ComponentIDContext)
660
+ ]
609
661
 
610
662
  def visitOrderByClause(self, ctx: Parser.OrderByClauseContext):
611
663
  ctx_list = list(ctx.getChildren())
612
664
 
613
- return [self.visitOrderByItem(c) for c in ctx_list if
614
- isinstance(c, Parser.OrderByItemContext)]
665
+ return [
666
+ self.visitOrderByItem(c) for c in ctx_list if isinstance(c, Parser.OrderByItemContext)
667
+ ]
615
668
 
616
669
  def visitWindowingClause(self, ctx: Parser.WindowingClauseContext):
617
670
  ctx_list = list(ctx.getChildren())
618
671
 
619
672
  win_mode = ctx_list[0].getSymbol().text # Windowing mode (data points | range )
620
673
 
621
- if win_mode == 'data':
674
+ if win_mode == "data":
622
675
  num_rows_1, mode_1 = self.visitLimitClauseItem(ctx_list[3])
623
676
  num_rows_2, mode_2 = self.visitLimitClauseItem(ctx_list[5])
624
677
  else:
@@ -628,23 +681,31 @@ class Terminals(VtlVisitor):
628
681
  first = num_rows_1 # unbounded (default value)
629
682
  second = num_rows_2 # current data point (default value)
630
683
 
631
- if mode_2 == 'preceding':
632
- if mode_1 == 'preceding' and num_rows_1 == -1 and num_rows_2 == -1: # preceding and preceding (error)
684
+ if mode_2 == "preceding":
685
+ if (
686
+ mode_1 == "preceding" and num_rows_1 == -1 and num_rows_2 == -1
687
+ ): # preceding and preceding (error)
633
688
  raise Exception(
634
- f'Cannot have 2 preceding clauses with unbounded in analytic clause, line {ctx_list[3].start.line}')
689
+ f"Cannot have 2 preceding clauses with unbounded in analytic clause, "
690
+ f"line {ctx_list[3].start.line}"
691
+ )
635
692
 
636
- if mode_1 == 'following' and num_rows_1 == -1 and num_rows_2 == -1: # following and following (error)
693
+ if (
694
+ mode_1 == "following" and num_rows_1 == -1 and num_rows_2 == -1
695
+ ): # following and following (error)
637
696
  raise Exception(
638
- f'Cannot have 2 following clauses with unbounded in analytic clause, line {ctx_list[3].start.line}')
697
+ f"Cannot have 2 following clauses with unbounded in analytic clause, "
698
+ f"line {ctx_list[3].start.line}"
699
+ )
639
700
 
640
701
  if mode_1 == mode_2:
641
- if mode_1 == 'preceding' and first != -1 and second > first: # 3 and 1: must be [-3:-1]
702
+ if mode_1 == "preceding" and first != -1 and second > first: # 3 and 1: must be [-3:-1]
642
703
  return create_windowing(win_mode, [second, first], [mode_2, mode_1])
643
- if mode_1 == 'preceding' and second == -1:
704
+ if mode_1 == "preceding" and second == -1:
644
705
  return create_windowing(win_mode, [second, first], [mode_2, mode_1])
645
- if mode_1 == 'following' and second != -1 and second < first: # 3 and 1: must be [1:3]
706
+ if mode_1 == "following" and second != -1 and second < first: # 3 and 1: must be [1:3]
646
707
  return create_windowing(win_mode, [second, first], [mode_2, mode_1])
647
- if mode_1 == 'following' and first == -1:
708
+ if mode_1 == "following" and first == -1:
648
709
  return create_windowing(win_mode, [second, first], [mode_2, mode_1])
649
710
 
650
711
  return create_windowing(win_mode, [first, second], [mode_1, mode_2])
@@ -653,25 +714,26 @@ class Terminals(VtlVisitor):
653
714
  ctx_list = list(ctx.getChildren())
654
715
 
655
716
  if len(ctx_list) == 1:
656
- return OrderBy(component=self.visitComponentID(ctx_list[0]).value,
657
- order='asc')
717
+ return OrderBy(component=self.visitComponentID(ctx_list[0]).value, order="asc")
658
718
 
659
- return OrderBy(component=self.visitComponentID(ctx_list[0]).value,
660
- order=ctx_list[1].getSymbol().text)
719
+ return OrderBy(
720
+ component=self.visitComponentID(ctx_list[0]).value, order=ctx_list[1].getSymbol().text
721
+ )
661
722
 
662
723
  def visitLimitClauseItem(self, ctx: Parser.LimitClauseItemContext):
663
724
  ctx_list = list(ctx.getChildren())
664
725
  c = ctx_list[0]
665
- if c.getSymbol().text == 'unbounded':
726
+ if c.getSymbol().text == "unbounded":
666
727
  result = -1
667
- elif c.getSymbol().text == 'current':
728
+ elif c.getSymbol().text == "current":
668
729
  result = 0
669
730
  return result, ctx_list[0].getSymbol().text
670
731
  else:
671
732
  result = int(c.getSymbol().text)
672
733
  if result < 0:
673
734
  raise Exception(
674
- f'Cannot use negative numbers ({result}) on limitClause, line {c.symbol.line}')
735
+ f"Cannot use negative numbers ({result}) on limitClause, line {c.symbol.line}"
736
+ )
675
737
 
676
738
  return result, ctx_list[1].getSymbol().text
677
739
 
@@ -683,5 +745,6 @@ def create_windowing(win_mode, values, modes):
683
745
  elif values[e] == 0:
684
746
  values[e] = "CURRENT ROW"
685
747
 
686
- return Windowing(type_=win_mode, start=values[0], stop=values[1],
687
- start_mode=modes[0], stop_mode=modes[1])
748
+ return Windowing(
749
+ type_=win_mode, start=values[0], stop=values[1], start_mode=modes[0], stop_mode=modes[1]
750
+ )
@@ -5,7 +5,7 @@ import AST
5
5
 
6
6
  class ComplexEncoder(json.JSONEncoder):
7
7
  def default(self, obj):
8
- if hasattr(obj, 'toJSON'):
8
+ if hasattr(obj, "toJSON"):
9
9
  return obj.toJSON()
10
10
  else:
11
11
  return json.__dict__
@@ -6,6 +6,7 @@ Description
6
6
  -----------
7
7
  Template to start a new visitor for the AST.
8
8
  """
9
+
9
10
  from typing import Any
10
11
 
11
12
  import vtlengine.AST as AST
@@ -168,7 +169,7 @@ class ASTTemplate(NodeVisitor):
168
169
  """
169
170
  return node.value
170
171
 
171
- def visit_ParamConstant(self, node: AST.ParamConstant) -> AST.AST:
172
+ def visit_ParamConstant(self, node: AST.ParamConstant) -> Any:
172
173
  """
173
174
  Constant: (type, value)
174
175
 
@@ -178,7 +179,7 @@ class ASTTemplate(NodeVisitor):
178
179
  """
179
180
  return node.value
180
181
 
181
- def visit_Identifier(self, node: AST.Identifier) -> AST.AST:
182
+ def visit_Identifier(self, node: AST.Identifier) -> Any:
182
183
  """
183
184
  Identifier: (value)
184
185
 
@@ -208,7 +209,7 @@ class ASTTemplate(NodeVisitor):
208
209
 
209
210
  return node.value
210
211
  """
211
- if node.value == '_':
212
+ if node.value == "_":
212
213
  return
213
214
  return node.value
214
215
 
@@ -277,9 +278,7 @@ class ASTTemplate(NodeVisitor):
277
278
  self.visit(group)
278
279
 
279
280
  def visit_Analytic(self, node: AST.Analytic) -> None:
280
- """
281
-
282
- """
281
+ """ """
283
282
  if node.operand is not None:
284
283
  self.visit(node.operand)
285
284
 
@@ -301,7 +300,7 @@ class ASTTemplate(NodeVisitor):
301
300
  if node.operand is not None:
302
301
  self.visit(node.operand)
303
302
 
304
- def visit_If(self, node: AST.If) -> None:
303
+ def visit_If(self, node: AST.If) -> Any:
305
304
  """
306
305
  If: (condition, thenOp, elseOp)
307
306
 
@@ -315,7 +314,23 @@ class ASTTemplate(NodeVisitor):
315
314
  self.visit(node.thenOp)
316
315
  self.visit(node.elseOp)
317
316
 
318
- def visit_Validation(self, node: AST.Validation) -> None:
317
+ def visit_Case(self, node: AST.Case) -> Any:
318
+ """
319
+ Case: (conditions, thenOp, elseOp)
320
+
321
+ Basic usage:
322
+
323
+ for condition in node.conditions:
324
+ self.visit(condition)
325
+ self.visit(node.thenOp)
326
+ self.visit(node.elseOp)
327
+ """
328
+ for case in node.cases:
329
+ self.visit(case.condition)
330
+ self.visit(case.thenOp)
331
+ self.visit(node.elseOp)
332
+
333
+ def visit_Validation(self, node: AST.Validation) -> Any:
319
334
  """
320
335
  Validation: (op, validation, params, inbalance, invalid)
321
336
 
@@ -476,7 +491,7 @@ class ASTTemplate(NodeVisitor):
476
491
  """
477
492
  return node.value
478
493
 
479
- def visit_EvalOp(self, node: AST.EvalOp) -> None:
494
+ def visit_EvalOp(self, node: AST.EvalOp) -> Any:
480
495
  """
481
496
  EvalOp: (name, children, output, language)
482
497
 
@@ -7,23 +7,19 @@ Description
7
7
  Node Dispatcher.
8
8
  """
9
9
 
10
+ from typing import Any
10
11
 
11
- class NodeVisitor(object):
12
- """
13
-
14
- """
15
12
 
16
- def visit(self, node):
17
- """
13
+ class NodeVisitor(object):
14
+ """ """
18
15
 
19
- """
20
- method_name = 'visit_' + type(node).__name__
16
+ def visit(self, node: Any):
17
+ """ """
18
+ method_name = "visit_" + type(node).__name__
21
19
  visitor = getattr(self, method_name, self.generic_visit)
22
20
  return visitor(node)
23
21
 
24
22
  def generic_visit(self, node):
25
- """
26
-
27
- """
23
+ """ """
28
24
  # AST_ASTVISITOR.1
29
- raise Exception('No visit_{} method'.format(type(node).__name__))
25
+ raise Exception("No visit_{} method".format(type(node).__name__))