vtlengine 1.2.1rc1__tar.gz → 1.3.0rc1__tar.gz

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 (66) hide show
  1. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/PKG-INFO +7 -6
  2. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/pyproject.toml +17 -17
  3. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/API/_InternalApi.py +35 -12
  4. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/API/__init__.py +52 -13
  5. vtlengine-1.3.0rc1/src/vtlengine/API/data/schema/external_routines_schema.json +34 -0
  6. vtlengine-1.3.0rc1/src/vtlengine/API/data/schema/value_domain_schema.json +97 -0
  7. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/AST/ASTConstructorModules/Terminals.py +1 -5
  8. vtlengine-1.3.0rc1/src/vtlengine/AST/Grammar/lexer.py +2139 -0
  9. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/AST/Grammar/parser.py +3224 -17981
  10. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/AST/__init__.py +3 -3
  11. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/DataTypes/TimeHandling.py +12 -7
  12. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/DataTypes/__init__.py +92 -0
  13. {vtlengine-1.2.1rc1/src/vtlengine/files/parser → vtlengine-1.3.0rc1/src/vtlengine/DataTypes}/_time_checking.py +8 -3
  14. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/Exceptions/messages.py +13 -0
  15. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/Interpreter/__init__.py +60 -16
  16. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/Model/__init__.py +47 -3
  17. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/Operators/Aggregation.py +10 -2
  18. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/Operators/Conditional.py +52 -34
  19. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/Operators/General.py +1 -1
  20. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/Operators/Validation.py +33 -5
  21. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/Operators/__init__.py +10 -4
  22. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/__init__.py +1 -1
  23. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/files/parser/__init__.py +17 -7
  24. vtlengine-1.2.1rc1/src/vtlengine/AST/Grammar/lexer.py +0 -20785
  25. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/LICENSE.md +0 -0
  26. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/README.md +0 -0
  27. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/API/data/schema/json_schema_2.1.json +0 -0
  28. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/AST/ASTComment.py +0 -0
  29. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/AST/ASTConstructor.py +0 -0
  30. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/AST/ASTConstructorModules/Expr.py +0 -0
  31. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/AST/ASTConstructorModules/ExprComponents.py +0 -0
  32. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/AST/ASTConstructorModules/__init__.py +0 -0
  33. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/AST/ASTDataExchange.py +0 -0
  34. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/AST/ASTEncoders.py +0 -0
  35. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/AST/ASTString.py +0 -0
  36. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/AST/ASTTemplate.py +0 -0
  37. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/AST/ASTVisitor.py +0 -0
  38. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/AST/DAG/__init__.py +0 -0
  39. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/AST/DAG/_words.py +0 -0
  40. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/AST/Grammar/Vtl.g4 +0 -0
  41. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/AST/Grammar/VtlTokens.g4 +0 -0
  42. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/AST/Grammar/__init__.py +0 -0
  43. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/AST/Grammar/tokens.py +0 -0
  44. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/AST/VtlVisitor.py +0 -0
  45. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/Exceptions/__init__.py +0 -0
  46. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/Operators/Analytic.py +0 -0
  47. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/Operators/Assignment.py +0 -0
  48. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/Operators/Boolean.py +0 -0
  49. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/Operators/CastOperator.py +0 -0
  50. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/Operators/Clause.py +0 -0
  51. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/Operators/Comparison.py +0 -0
  52. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/Operators/HROperators.py +0 -0
  53. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/Operators/Join.py +0 -0
  54. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/Operators/Numeric.py +0 -0
  55. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/Operators/RoleSetter.py +0 -0
  56. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/Operators/Set.py +0 -0
  57. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/Operators/String.py +0 -0
  58. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/Operators/Time.py +0 -0
  59. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/Utils/__Virtual_Assets.py +0 -0
  60. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/Utils/__init__.py +0 -0
  61. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/__extras_check.py +0 -0
  62. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/files/__init__.py +0 -0
  63. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/files/output/__init__.py +0 -0
  64. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/files/output/_time_period_representation.py +0 -0
  65. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/files/parser/_rfc_dialect.py +0 -0
  66. {vtlengine-1.2.1rc1 → vtlengine-1.3.0rc1}/src/vtlengine/py.typed +0 -0
@@ -1,8 +1,9 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: vtlengine
3
- Version: 1.2.1rc1
3
+ Version: 1.3.0rc1
4
4
  Summary: Run and Validate VTL Scripts
5
- License: AGPL-3.0
5
+ License-Expression: AGPL-3.0
6
+ License-File: LICENSE.md
6
7
  Keywords: vtl,sdmx,vtlengine,Validation and Transformation Language
7
8
  Author: MeaningfulData
8
9
  Author-email: info@meaningfuldata.eu
@@ -16,8 +17,8 @@ Classifier: Intended Audience :: Science/Research
16
17
  Classifier: Typing :: Typed
17
18
  Provides-Extra: all
18
19
  Provides-Extra: s3
19
- Requires-Dist: antlr4-python3-runtime (>=4.13.2,<4.14)
20
- Requires-Dist: duckdb (>=1.1,<1.2)
20
+ Requires-Dist: antlr4-python3-runtime (>=4.9,<4.10)
21
+ Requires-Dist: duckdb (>=1.4,<1.5)
21
22
  Requires-Dist: fsspec (>=2022.11.0,<2023.0) ; extra == "all"
22
23
  Requires-Dist: fsspec (>=2022.11.0,<2023.0) ; extra == "s3"
23
24
  Requires-Dist: jsonschema (>=3.2.0,<5.0)
@@ -25,7 +26,7 @@ Requires-Dist: networkx (>=2.8,<3.0)
25
26
  Requires-Dist: numpy (>=1.23.2,<2) ; python_version < "3.13"
26
27
  Requires-Dist: numpy (>=2.1.0) ; python_version >= "3.13"
27
28
  Requires-Dist: pandas (>=2.1.4,<3.0)
28
- Requires-Dist: pysdmx[xml] (>=1.4.0rc1,<2.0)
29
+ Requires-Dist: pysdmx[xml] (>=1.5.2,<2.0)
29
30
  Requires-Dist: s3fs (>=2022.11.0,<2023.0) ; extra == "all"
30
31
  Requires-Dist: s3fs (>=2022.11.0,<2023.0) ; extra == "s3"
31
32
  Requires-Dist: sqlglot (>=22.2.0,<23.0)
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "vtlengine"
3
- version = "1.2.1rc1"
3
+ version = "1.3.0rc1"
4
4
  description = "Run and Validate VTL Scripts"
5
5
  license = "AGPL-3.0"
6
6
  readme = "README.md"
@@ -24,12 +24,12 @@ keywords = ['vtl', 'sdmx', 'vtlengine', 'Validation and Transformation Language'
24
24
 
25
25
  dependencies = [
26
26
  # PyPi dependencies
27
- "duckdb>=1.1,<1.2",
28
- "pysdmx[xml]>=1.4.0rc1,<2.0",
27
+ "duckdb>=1.4,<1.5",
28
+ "pysdmx[xml]>=1.5.2,<2.0",
29
29
  # APT-supported dependencies
30
30
  "jsonschema>=3.2.0,<5.0",
31
31
  "sqlglot>=22.2.0,<23.0",
32
- "antlr4-python3-runtime>=4.13.2,<4.14",
32
+ "antlr4-python3-runtime>=4.9,<4.10",
33
33
  "pandas>=2.1.4,<3.0",
34
34
  "networkx>=2.8,<3.0",
35
35
  "numpy>=1.23.2,<2 ; python_version < '3.13'",
@@ -51,19 +51,19 @@ Authors = 'https://github.com/Meaningful-Data/vtlengine/graphs/contributors'
51
51
  python = ">=3.9,<4.0"
52
52
 
53
53
  [tool.poetry.group.dev.dependencies]
54
- pytest = "^8.4"
55
- pytest-cov = "^6.2.1"
56
- pytest-xdist = "^3.8.0"
57
- line-profiler-pycharm = "^1.2.0"
58
- mypy = "1.17.1"
59
- pandas-stubs = "2.2.2.240807"
60
- ruff = "^0.12.7"
61
- types-jsonschema = "4.25.0.20250720"
54
+ pytest = ">=8.4,<9.0"
55
+ pytest-cov = ">=7.0.0,<8.0"
56
+ pytest-xdist = ">=3.8.0,<4.0"
57
+ line-profiler-pycharm = ">=1.2.0,<2.0"
58
+ mypy = ">=1.18,<2.0"
59
+ pandas-stubs = ">=2.2.2,<3.0"
60
+ ruff = ">=0.14,<1.0.0"
61
+ types-jsonschema = ">=4.25.1,<5.0"
62
62
 
63
63
  [tool.poetry.group.docs.dependencies]
64
- sphinx = "^7.4.7"
65
- sphinx-rtd-theme = "^3.0.2"
66
- toml = "^0.10.2"
64
+ sphinx = ">=7.4.7,<8.0"
65
+ sphinx-rtd-theme = ">=3.0.2,<4.0"
66
+ toml = ">=0.10.2,<0.11.0"
67
67
 
68
68
 
69
69
 
@@ -77,7 +77,7 @@ lint.select = [
77
77
  lint.ignore = ["B023", "B028", "B904", "C403", "D100", "D101", "D102", "D103", "D104", "D105",
78
78
  "D107", "D200", "D201", "D202", "D203", "D205", "D209", "D212", "D213", "D301",
79
79
  "D400", "D401", "D404", "D411", "D413", "D415", "D419", "E203", "S608"]
80
- lint.exclude = ["*/Grammar/*", "*/main.py"]
80
+ lint.exclude = ["*/Grammar/*", "*/main.py", "*/dev.py"]
81
81
 
82
82
  [tool.ruff.lint.per-file-ignores]
83
83
  "tests/*" = ["S101", "PT006", "PT012", "PT013", "E501", "W605"]
@@ -85,7 +85,7 @@ lint.exclude = ["*/Grammar/*", "*/main.py"]
85
85
 
86
86
  [tool.mypy]
87
87
  files = "src"
88
- exclude = "src/vtlengine/AST/.*"
88
+ exclude = "src/vtlengine/AST/.*|src/dev.py"
89
89
  disallow_untyped_defs = true
90
90
  disallow_untyped_calls = true
91
91
  ignore_errors = false
@@ -46,6 +46,10 @@ schema_path = base_path / "data" / "schema"
46
46
  sdmx_csv_path = base_path / "data" / "sdmx_csv"
47
47
  with open(schema_path / "json_schema_2.1.json", "r") as file:
48
48
  schema = json.load(file)
49
+ with open(schema_path / "value_domain_schema.json", "r") as file:
50
+ vd_schema = json.load(file)
51
+ with open(schema_path / "external_routines_schema.json", "r") as file:
52
+ external_routine_schema = json.load(file)
49
53
 
50
54
 
51
55
  def _load_dataset_from_structure(
@@ -112,6 +116,7 @@ def _load_dataset_from_structure(
112
116
  if "scalars" in structures:
113
117
  for scalar_json in structures["scalars"]:
114
118
  scalar_name = scalar_json["name"]
119
+ check_key("type", SCALAR_TYPES.keys(), scalar_json["type"])
115
120
  scalar = Scalar(
116
121
  name=scalar_name,
117
122
  data_type=SCALAR_TYPES[scalar_json["type"]],
@@ -235,8 +240,16 @@ def _handle_scalars_values(
235
240
  # Handling scalar values with the scalar dict
236
241
  for name, value in scalar_values.items():
237
242
  if name not in scalars:
238
- raise Exception(f"Not found scalar {name} in datastructures")
243
+ raise InputValidationException(code="0-1-2-6", name=name)
239
244
  # Casting value to scalar data type
245
+ if not scalars[name].data_type.check(value):
246
+ raise InputValidationException(
247
+ code="0-1-2-7",
248
+ value=value,
249
+ type_=scalars[name].data_type.__name__,
250
+ op_type=type(scalars[name]).__name__,
251
+ name=name,
252
+ )
240
253
  scalars[name].value = scalars[name].data_type.cast(value)
241
254
 
242
255
 
@@ -321,11 +334,20 @@ def load_vtl(input: Union[str, Path]) -> str:
321
334
  return f.read()
322
335
 
323
336
 
337
+ def _validate_json(data: Dict[str, Any], schema: Dict[str, Any]) -> None:
338
+ try:
339
+ jsonschema.validate(instance=data, schema=schema)
340
+ except jsonschema.ValidationError:
341
+ raise Exception("The given json does not follow the schema.")
342
+
343
+
324
344
  def _load_single_value_domain(input: Path) -> Dict[str, ValueDomain]:
325
345
  if input.suffix != ".json":
326
346
  raise Exception("Invalid Value Domain file. Must have .json extension")
327
347
  with open(input, "r") as f:
328
- vd = ValueDomain.from_dict(json.load(f))
348
+ data = json.load(f)
349
+ _validate_json(data, vd_schema)
350
+ vd = ValueDomain.from_dict(data)
329
351
  return {vd.name: vd}
330
352
 
331
353
 
@@ -344,6 +366,7 @@ def load_value_domains(input: Union[Dict[str, Any], Path]) -> Dict[str, ValueDom
344
366
  or the value domains file does not exist.
345
367
  """
346
368
  if isinstance(input, dict):
369
+ _validate_json(input, vd_schema)
347
370
  vd = ValueDomain.from_dict(input)
348
371
  return {vd.name: vd}
349
372
  if not isinstance(input, Path):
@@ -377,12 +400,12 @@ def load_external_routines(input: Union[Dict[str, Any], Path, str]) -> Any:
377
400
  """
378
401
  external_routines = {}
379
402
  if isinstance(input, dict):
380
- for name, query in input.items():
381
- ext_routine = ExternalRoutine.from_sql_query(name, query)
382
- external_routines[ext_routine.name] = ext_routine
403
+ _validate_json(input, external_routine_schema)
404
+ ext_routine = ExternalRoutine.from_sql_query(input["name"], input["query"])
405
+ external_routines[ext_routine.name] = ext_routine
383
406
  return external_routines
384
407
  if not isinstance(input, Path):
385
- raise Exception("Input invalid. Input must be a sql file.")
408
+ raise Exception("Input invalid. Input must be a json file.")
386
409
  if not input.exists():
387
410
  raise Exception("Input invalid. Input does not exist")
388
411
  if input.is_dir():
@@ -411,17 +434,17 @@ def _return_only_persistent_datasets(
411
434
 
412
435
 
413
436
  def _load_single_external_routine_from_file(input: Path) -> Any:
414
- """
415
- Returns a single external routine.
416
- """
417
437
  if not isinstance(input, Path):
418
438
  raise Exception("Input invalid")
419
439
  if not input.exists():
420
440
  raise Exception("Input does not exist")
421
- if input.suffix != ".sql":
422
- raise Exception("Input must be a sql file")
441
+ if input.suffix != ".json":
442
+ raise Exception("Input must be a json file")
443
+ routine_name = input.stem
423
444
  with open(input, "r") as f:
424
- ext_rout = ExternalRoutine.from_sql_query(input.name.removesuffix(".sql"), f.read())
445
+ data = json.load(f)
446
+ _validate_json(data, external_routine_schema)
447
+ ext_rout = ExternalRoutine.from_sql_query(routine_name, data["query"])
425
448
  return ext_rout
426
449
 
427
450
 
@@ -163,8 +163,17 @@ def semantic_analysis(
163
163
  that holds the vtl script.
164
164
  data_structures: Dict or Path (file or folder), \
165
165
  or List of Dicts or Paths with the data structures JSON files.
166
- value_domains: Dict or Path of the value domains JSON files. (default: None)
167
- external_routines: String or Path of the external routines SQL files. (default: None)
166
+ value_domains: Dict or Path, or List of Dicts or Paths of the \
167
+ value domains JSON files. (default:None) It is passed as an object, that can be read from \
168
+ a Path or from a dictionary. Furthermore, a list of those objects can be passed. \
169
+ Check the following example: \
170
+ :ref:`Example 6 <example_6_run_with_multiple_value_domains_and_external_routines>`.
171
+
172
+ external_routines: String or Path, or List of Strings or Paths of the \
173
+ external routines SQL files. (default: None) It is passed as an object, that can be read \
174
+ from a Path or from a dictionary. Furthermore, a list of those objects can be passed. \
175
+ Check the following example: \
176
+ :ref:`Example 6 <example_6_run_with_multiple_value_domains_and_external_routines>`.
168
177
 
169
178
  Returns:
170
179
  The computed datasets.
@@ -206,8 +215,10 @@ def run(
206
215
  script: Union[str, TransformationScheme, Path],
207
216
  data_structures: Union[Dict[str, Any], Path, List[Dict[str, Any]], List[Path]],
208
217
  datapoints: Union[Dict[str, pd.DataFrame], str, Path, List[Dict[str, Any]], List[Path]],
209
- value_domains: Optional[Union[Dict[str, Any], Path]] = None,
210
- external_routines: Optional[Union[str, Path]] = None,
218
+ value_domains: Optional[Union[Dict[str, Any], Path, List[Union[Dict[str, Any], Path]]]] = None,
219
+ external_routines: Optional[
220
+ Union[Dict[str, Any], Path, List[Union[Dict[str, Any], Path]]]
221
+ ] = None,
211
222
  time_period_output_format: str = "vtl",
212
223
  return_only_persistent: bool = True,
213
224
  output_folder: Optional[Union[str, Path]] = None,
@@ -265,9 +276,17 @@ def run(
265
276
 
266
277
  datapoints: Dict, Path, S3 URI or List of S3 URIs or Paths with data.
267
278
 
268
- value_domains: Dict or Path of the value domains JSON files. (default:None)
279
+ value_domains: Dict or Path, or List of Dicts or Paths of the \
280
+ value domains JSON files. (default:None) It is passed as an object, that can be read from \
281
+ a Path or from a dictionary. Furthermore, a list of those objects can be passed. \
282
+ Check the following example: \
283
+ :ref:`Example 6 <example_6_run_with_multiple_value_domains_and_external_routines>`.
269
284
 
270
- external_routines: String or Path of the external routines SQL files. (default: None)
285
+ external_routines: String or Path, or List of Strings or Paths of the \
286
+ external routines JSON files. (default: None) It is passed as an object, that can be read \
287
+ from a Path or from a dictionary. Furthermore, a list of those objects can be passed. \
288
+ Check the following example: \
289
+ :ref:`Example 6 <example_6_run_with_multiple_value_domains_and_external_routines>`.
271
290
 
272
291
  time_period_output_format: String with the possible values \
273
292
  ("sdmx_gregorian", "sdmx_reporting", "vtl") for the representation of the \
@@ -303,10 +322,20 @@ def run(
303
322
  # Handling of library items
304
323
  vd = None
305
324
  if value_domains is not None:
306
- vd = load_value_domains(value_domains)
325
+ if isinstance(value_domains, list):
326
+ vd = {}
327
+ for item in value_domains:
328
+ vd.update(load_value_domains(item))
329
+ else:
330
+ vd = load_value_domains(value_domains)
307
331
  ext_routines = None
308
332
  if external_routines is not None:
309
- ext_routines = load_external_routines(external_routines)
333
+ if isinstance(external_routines, list):
334
+ ext_routines = {}
335
+ for item in external_routines:
336
+ ext_routines.update(load_external_routines(item))
337
+ else:
338
+ ext_routines = load_external_routines(external_routines)
310
339
 
311
340
  # Checking time period output format value
312
341
  time_period_representation = TimePeriodRepresentation.check_value(time_period_output_format)
@@ -348,8 +377,10 @@ def run_sdmx( # noqa: C901
348
377
  script: Union[str, TransformationScheme, Path],
349
378
  datasets: Sequence[PandasDataset],
350
379
  mappings: Optional[Union[VtlDataflowMapping, Dict[str, str]]] = None,
351
- value_domains: Optional[Union[Dict[str, Any], Path]] = None,
352
- external_routines: Optional[Union[str, Path]] = None,
380
+ value_domains: Optional[Union[Dict[str, Any], Path, List[Union[Dict[str, Any], Path]]]] = None,
381
+ external_routines: Optional[
382
+ Union[Dict[str, Any], Path, List[Union[Dict[str, Any], Path]]]
383
+ ] = None,
353
384
  time_period_output_format: str = "vtl",
354
385
  return_only_persistent: bool = True,
355
386
  output_folder: Optional[Union[str, Path]] = None,
@@ -388,9 +419,17 @@ def run_sdmx( # noqa: C901
388
419
 
389
420
  mappings: A dictionary or VtlDataflowMapping object that maps the dataset names.
390
421
 
391
- value_domains: Dict or Path of the value domains JSON files. (default:None)
392
-
393
- external_routines: String or Path of the external routines SQL files. (default: None)
422
+ value_domains: Dict or Path, or List of Dicts or Paths of the \
423
+ value domains JSON files. (default:None) It is passed as an object, that can be read from \
424
+ a Path or from a dictionary. Furthermore, a list of those objects can be passed. \
425
+ Check the following example: \
426
+ :ref:`Example 6 <example_6_run_with_multiple_value_domains_and_external_routines>`.
427
+
428
+ external_routines: String or Path, or List of Strings or Paths of the \
429
+ external routines JSON files. (default: None) It is passed as an object, that can be read \
430
+ from a Path or from a dictionary. Furthermore, a list of those objects can be passed. \
431
+ Check the following example: \
432
+ :ref:`Example 6 <example_6_run_with_multiple_value_domains_and_external_routines>`.
394
433
 
395
434
  time_period_output_format: String with the possible values \
396
435
  ("sdmx_gregorian", "sdmx_reporting", "vtl") for the representation of the \
@@ -0,0 +1,34 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "definitions": {
4
+ "sqlQuery": {
5
+ "type": "object",
6
+ "properties": {
7
+ "name": {
8
+ "type": "string",
9
+ "minLength": 1,
10
+ "description": "Identifier for the SQL query"
11
+ },
12
+ "query": {
13
+ "type": "string",
14
+ "minLength": 1,
15
+ "description": "SQL query statement"
16
+ }
17
+ },
18
+ "required": ["name", "query"],
19
+ "additionalProperties": false
20
+ }
21
+ },
22
+ "oneOf": [
23
+ {
24
+ "$ref": "#/definitions/sqlQuery"
25
+ },
26
+ {
27
+ "type": "array",
28
+ "items": {
29
+ "$ref": "#/definitions/sqlQuery"
30
+ },
31
+ "minItems": 1
32
+ }
33
+ ]
34
+ }
@@ -0,0 +1,97 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "definitions": {
4
+ "ValueDomain": {
5
+ "type": "object",
6
+ "properties": {
7
+ "name": {
8
+ "type": "string",
9
+ "description": "Name identifier for the Value Domain"
10
+ },
11
+ "setlist": {
12
+ "type": "array",
13
+ "minItems": 1,
14
+ "uniqueItems": true,
15
+ "description": "List of unique values of the Value Domain"
16
+ },
17
+ "type": {
18
+ "type": "string",
19
+ "enum": ["Integer", "Number", "String", "Boolean", "Date", "Time_Period", "Time", "Duration"],
20
+ "description": "Data type of the Value Domain"
21
+ }
22
+ },
23
+ "required": ["name", "setlist", "type"],
24
+ "additionalProperties": false,
25
+ "allOf": [
26
+ {
27
+ "if": {
28
+ "properties": {
29
+ "type": {"const": "Integer"}
30
+ }
31
+ },
32
+ "then": {
33
+ "properties": {
34
+ "setlist": {
35
+ "items": {"type": "integer"}
36
+ }
37
+ }
38
+ }
39
+ },
40
+ {
41
+ "if": {
42
+ "properties": {
43
+ "type": {"const": "Number"}
44
+ }
45
+ },
46
+ "then": {
47
+ "properties": {
48
+ "setlist": {
49
+ "items": {"type": "number"}
50
+ }
51
+ }
52
+ }
53
+ },
54
+ {
55
+ "if": {
56
+ "properties": {
57
+ "type": {"const": "Boolean"}
58
+ }
59
+ },
60
+ "then": {
61
+ "properties": {
62
+ "setlist": {
63
+ "items": {"type": "boolean"}
64
+ }
65
+ }
66
+ }
67
+ },
68
+ {
69
+ "if": {
70
+ "properties": {
71
+ "type": {"enum": ["String", "Date", "Time_Period", "Time", "Duration"]}
72
+ }
73
+ },
74
+ "then": {
75
+ "properties": {
76
+ "setlist": {
77
+ "items": {"type": "string"}
78
+ }
79
+ }
80
+ }
81
+ }
82
+ ]
83
+ }
84
+ },
85
+ "oneOf": [
86
+ {
87
+ "$ref": "#/definitions/ValueDomain"
88
+ },
89
+ {
90
+ "type": "array",
91
+ "items": {
92
+ "$ref": "#/definitions/ValueDomain"
93
+ },
94
+ "minItems": 1
95
+ }
96
+ ]
97
+ }
@@ -622,11 +622,7 @@ class Terminals(VtlVisitor):
622
622
  erLevel: ERRORLEVEL constant;
623
623
  """
624
624
  ctx_list = list(ctx.getChildren())
625
-
626
- try:
627
- return int(self.visitConstant(ctx_list[1]).value)
628
- except Exception:
629
- raise Exception(f"Error level must be an integer, line {ctx_list[1].start.line}")
625
+ return self.visitConstant(ctx_list[1]).value
630
626
 
631
627
  def visitSignature(self, ctx: Parser.SignatureContext, kind="ComponentID"):
632
628
  """