vtlengine 1.4.0rc2__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.
- vtlengine/API/_InternalApi.py +791 -0
- vtlengine/API/__init__.py +612 -0
- vtlengine/API/data/schema/external_routines_schema.json +34 -0
- vtlengine/API/data/schema/json_schema_2.1.json +116 -0
- vtlengine/API/data/schema/value_domain_schema.json +97 -0
- vtlengine/AST/ASTComment.py +57 -0
- vtlengine/AST/ASTConstructor.py +598 -0
- vtlengine/AST/ASTConstructorModules/Expr.py +1928 -0
- vtlengine/AST/ASTConstructorModules/ExprComponents.py +995 -0
- vtlengine/AST/ASTConstructorModules/Terminals.py +790 -0
- vtlengine/AST/ASTConstructorModules/__init__.py +50 -0
- vtlengine/AST/ASTDataExchange.py +10 -0
- vtlengine/AST/ASTEncoders.py +32 -0
- vtlengine/AST/ASTString.py +675 -0
- vtlengine/AST/ASTTemplate.py +558 -0
- vtlengine/AST/ASTVisitor.py +25 -0
- vtlengine/AST/DAG/__init__.py +479 -0
- vtlengine/AST/DAG/_words.py +10 -0
- vtlengine/AST/Grammar/Vtl.g4 +705 -0
- vtlengine/AST/Grammar/VtlTokens.g4 +409 -0
- vtlengine/AST/Grammar/__init__.py +0 -0
- vtlengine/AST/Grammar/lexer.py +2139 -0
- vtlengine/AST/Grammar/parser.py +16597 -0
- vtlengine/AST/Grammar/tokens.py +169 -0
- vtlengine/AST/VtlVisitor.py +824 -0
- vtlengine/AST/__init__.py +674 -0
- vtlengine/DataTypes/TimeHandling.py +562 -0
- vtlengine/DataTypes/__init__.py +863 -0
- vtlengine/DataTypes/_time_checking.py +135 -0
- vtlengine/Exceptions/__exception_file_generator.py +96 -0
- vtlengine/Exceptions/__init__.py +159 -0
- vtlengine/Exceptions/messages.py +1004 -0
- vtlengine/Interpreter/__init__.py +2048 -0
- vtlengine/Model/__init__.py +501 -0
- vtlengine/Operators/Aggregation.py +357 -0
- vtlengine/Operators/Analytic.py +455 -0
- vtlengine/Operators/Assignment.py +23 -0
- vtlengine/Operators/Boolean.py +106 -0
- vtlengine/Operators/CastOperator.py +451 -0
- vtlengine/Operators/Clause.py +366 -0
- vtlengine/Operators/Comparison.py +488 -0
- vtlengine/Operators/Conditional.py +495 -0
- vtlengine/Operators/General.py +191 -0
- vtlengine/Operators/HROperators.py +254 -0
- vtlengine/Operators/Join.py +447 -0
- vtlengine/Operators/Numeric.py +422 -0
- vtlengine/Operators/RoleSetter.py +77 -0
- vtlengine/Operators/Set.py +176 -0
- vtlengine/Operators/String.py +578 -0
- vtlengine/Operators/Time.py +1144 -0
- vtlengine/Operators/Validation.py +275 -0
- vtlengine/Operators/__init__.py +900 -0
- vtlengine/Utils/__Virtual_Assets.py +34 -0
- vtlengine/Utils/__init__.py +479 -0
- vtlengine/__extras_check.py +17 -0
- vtlengine/__init__.py +27 -0
- vtlengine/files/__init__.py +0 -0
- vtlengine/files/output/__init__.py +35 -0
- vtlengine/files/output/_time_period_representation.py +55 -0
- vtlengine/files/parser/__init__.py +240 -0
- vtlengine/files/parser/_rfc_dialect.py +22 -0
- vtlengine/py.typed +0 -0
- vtlengine-1.4.0rc2.dist-info/METADATA +89 -0
- vtlengine-1.4.0rc2.dist-info/RECORD +66 -0
- vtlengine-1.4.0rc2.dist-info/WHEEL +4 -0
- vtlengine-1.4.0rc2.dist-info/licenses/LICENSE.md +661 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import calendar
|
|
2
|
+
import re
|
|
3
|
+
from datetime import date, datetime
|
|
4
|
+
|
|
5
|
+
from vtlengine.DataTypes.TimeHandling import TimePeriodHandler
|
|
6
|
+
from vtlengine.Exceptions import InputValidationException
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def check_date(value: str) -> str:
|
|
10
|
+
"""
|
|
11
|
+
Check if the date is in the correct format.
|
|
12
|
+
"""
|
|
13
|
+
# Remove all whitespaces
|
|
14
|
+
value = value.strip()
|
|
15
|
+
try:
|
|
16
|
+
if len(value) == 9 and value[7] == "-":
|
|
17
|
+
value = value[:-1] + "0" + value[-1]
|
|
18
|
+
date_value = date.fromisoformat(value)
|
|
19
|
+
except ValueError as e:
|
|
20
|
+
if "is out of range" in str(e):
|
|
21
|
+
raise InputValidationException(f"Date {value} is out of range for the month.")
|
|
22
|
+
if "month must be in 1..12" in str(e):
|
|
23
|
+
raise InputValidationException(
|
|
24
|
+
f"Date {value} is invalid. Month must be between 1 and 12."
|
|
25
|
+
)
|
|
26
|
+
raise InputValidationException(
|
|
27
|
+
f"Date {value} is not in the correct format. Use YYYY-MM-DD."
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
# Check date is between 1900 and 9999
|
|
31
|
+
if not 1800 <= date_value.year <= 9999:
|
|
32
|
+
raise InputValidationException(
|
|
33
|
+
f"Date {value} is invalid. Year must be between 1900 and 9999."
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
return date_value.isoformat()
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def dates_to_string(date1: date, date2: date) -> str:
|
|
40
|
+
date1_str = date1.strftime("%Y-%m-%d")
|
|
41
|
+
date2_str = date2.strftime("%Y-%m-%d")
|
|
42
|
+
return f"{date1_str}/{date2_str}"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
date_pattern = r"\d{4}[-][0-1]?\d[-][0-3]?\d"
|
|
46
|
+
year_pattern = r"\d{4}"
|
|
47
|
+
month_pattern = r"\d{4}[-][0-1]?\d"
|
|
48
|
+
time_pattern = r"^" + date_pattern + r"/" + date_pattern + r"$"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def check_time(value: str) -> str:
|
|
52
|
+
value = value.strip()
|
|
53
|
+
year_result = re.fullmatch(year_pattern, value)
|
|
54
|
+
if year_result is not None:
|
|
55
|
+
date1_time = datetime.strptime(value, "%Y")
|
|
56
|
+
date2_time = date1_time.replace(day=31, month=12)
|
|
57
|
+
return dates_to_string(date1_time, date2_time)
|
|
58
|
+
month_result = re.fullmatch(month_pattern, value)
|
|
59
|
+
if month_result is not None:
|
|
60
|
+
date1_time = datetime.strptime(value, "%Y-%m")
|
|
61
|
+
last_month_day = calendar.monthrange(date1_time.year, date1_time.month)[1]
|
|
62
|
+
date2_time = date1_time.replace(day=last_month_day)
|
|
63
|
+
return dates_to_string(date1_time, date2_time)
|
|
64
|
+
time_result = re.fullmatch(time_pattern, value)
|
|
65
|
+
if time_result is not None:
|
|
66
|
+
time_list = value.split("/")
|
|
67
|
+
if time_list[0] > time_list[1]:
|
|
68
|
+
raise ValueError("Start date is greater than end date.")
|
|
69
|
+
return value
|
|
70
|
+
raise ValueError(
|
|
71
|
+
"Time is not in the correct format. Use YYYY-MM-DD/YYYY-MM-DD or YYYY or YYYY-MM."
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
day_period_pattern = r"^\d{4}[-][0-1]?\d[-][0-3]?\d$"
|
|
76
|
+
month_period_pattern = r"^\d{4}[-][0-1]?\d$"
|
|
77
|
+
year_period_pattern = r"^\d{4}$"
|
|
78
|
+
period_pattern = (
|
|
79
|
+
r"^\d{4}[A]$|^\d{4}[S][1-2]$|^\d{4}[Q][1-4]$|^\d{4}[M]"
|
|
80
|
+
r"[0-1]?\d$|^\d{4}[W][0-5]?\d$|^\d{4}[D][0-3]?[0-9]?\d$"
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
# Related with gitlab issue #440, we can say that period pattern
|
|
84
|
+
# matches with our internal representation (or vtl user manual)
|
|
85
|
+
# and further_options_period_pattern matches
|
|
86
|
+
# with other kinds of inputs that we have to accept for the period.
|
|
87
|
+
further_options_period_pattern = (
|
|
88
|
+
r"\d{4}-\d{2}-\d{2}|^\d{4}-D[0-3]\d\d$|^\d{4}-W([0-4]"
|
|
89
|
+
r"\d|5[0-3])|^\d{4}-(0[1-9]|1[0-2]|M(0[1-9]|1[0-2]|[1-9]))$|^"
|
|
90
|
+
r"\d{4}-Q[1-4]$|^\d{4}-S[1-2]$|^\d{4}-A1$"
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def check_time_period(value: str) -> str:
|
|
95
|
+
if isinstance(value, int):
|
|
96
|
+
value = str(value)
|
|
97
|
+
value = value.strip()
|
|
98
|
+
|
|
99
|
+
match = re.fullmatch(r"^(\d{4})-(\d{2})$", value)
|
|
100
|
+
if match:
|
|
101
|
+
value = f"{match.group(1)}-M{match.group(2)}"
|
|
102
|
+
|
|
103
|
+
period_result = re.fullmatch(period_pattern, value)
|
|
104
|
+
if period_result is not None:
|
|
105
|
+
result = TimePeriodHandler(value)
|
|
106
|
+
return str(result)
|
|
107
|
+
|
|
108
|
+
# We allow the user to input the time period in different formats.
|
|
109
|
+
# See gl-440 or documentation in time period tests.
|
|
110
|
+
further_options_period_result = re.fullmatch(further_options_period_pattern, value)
|
|
111
|
+
if further_options_period_result is not None:
|
|
112
|
+
result = TimePeriodHandler(value)
|
|
113
|
+
return str(result)
|
|
114
|
+
|
|
115
|
+
year_result = re.fullmatch(year_period_pattern, value)
|
|
116
|
+
if year_result is not None:
|
|
117
|
+
year = datetime.strptime(value, "%Y")
|
|
118
|
+
year_period_wo_A = str(year.year)
|
|
119
|
+
return year_period_wo_A
|
|
120
|
+
# return year_period
|
|
121
|
+
|
|
122
|
+
month_result = re.fullmatch(month_period_pattern, value)
|
|
123
|
+
if month_result is not None:
|
|
124
|
+
month = datetime.strptime(value, "%Y-%m")
|
|
125
|
+
month_period = month.strftime("%YM%m")
|
|
126
|
+
result = TimePeriodHandler(month_period)
|
|
127
|
+
return str(result)
|
|
128
|
+
|
|
129
|
+
# TODO: Do we use this?
|
|
130
|
+
day_result = re.fullmatch(day_period_pattern, value)
|
|
131
|
+
if day_result is not None:
|
|
132
|
+
day = datetime.strptime(value, "%Y-%m-%d")
|
|
133
|
+
day_period = day.strftime("%YD%-j")
|
|
134
|
+
return day_period
|
|
135
|
+
raise ValueError
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from typing import Any, Dict
|
|
3
|
+
|
|
4
|
+
output_filepath = Path(__file__).parent.parent.parent.parent / "Docs" / "error_messages.rst"
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def generate_errors_rst(file_path: Path, messages: Dict[str, Any]) -> None:
|
|
8
|
+
"""
|
|
9
|
+
Generates an RST file with a grid of error codes, messages, and descriptions.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
def sort_key(code: str) -> Any:
|
|
13
|
+
return tuple(int(part) for part in code.split("-"))
|
|
14
|
+
|
|
15
|
+
def escape_for_sphinx(text: str) -> str:
|
|
16
|
+
"""
|
|
17
|
+
Scapes placeholders for Sphinx formatting.
|
|
18
|
+
"""
|
|
19
|
+
placeholders = ["{type}", "{type_}", "{format}", "{format_}", "{param}", "{op}", "{value}"]
|
|
20
|
+
for ph in placeholders:
|
|
21
|
+
text = text.replace(ph, f"``{ph}``")
|
|
22
|
+
return text
|
|
23
|
+
|
|
24
|
+
path = Path(file_path)
|
|
25
|
+
lines = []
|
|
26
|
+
lines.append("Error Messages")
|
|
27
|
+
lines.append("################")
|
|
28
|
+
lines.append("")
|
|
29
|
+
lines.append(
|
|
30
|
+
"This document provides a complete list of all error messages generated by the VTL engine. "
|
|
31
|
+
"Each entry includes the error code, the corresponding message, and a brief description "
|
|
32
|
+
"to help users to understand the cause of the issue."
|
|
33
|
+
)
|
|
34
|
+
lines.append("")
|
|
35
|
+
lines.append("The following legend explains the error code patterns used in the VTL engine:")
|
|
36
|
+
lines.append("")
|
|
37
|
+
category_header = "Category"
|
|
38
|
+
pattern_header = "Pattern"
|
|
39
|
+
legend_rows = [
|
|
40
|
+
("INPUT ERRORS", "0-1-X-X = Input Validation Errors\n"),
|
|
41
|
+
("", "0-2-X-X = JSON Schema Errors\n"),
|
|
42
|
+
("", "0-3-X-X = DataLoad Errors"),
|
|
43
|
+
("SEMANTIC ERRORS", "1-1-X-X = Operators Semantic Errors\n"),
|
|
44
|
+
("", "1-2-X-X = Semantic Analyzer Errors\n"),
|
|
45
|
+
("", "1-3-X-X = AST Errors"),
|
|
46
|
+
("RUNTIME ERRORS", "2-X-X-X = RunTime Operator Errors"),
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
max_cat = max(len(category_header), max(len(row[0]) for row in legend_rows))
|
|
50
|
+
max_pat = max(len(pattern_header), max(len(row[1]) for row in legend_rows))
|
|
51
|
+
sep_legend = f"{'=' * max_cat} {'=' * max_pat}"
|
|
52
|
+
|
|
53
|
+
lines.append(sep_legend)
|
|
54
|
+
lines.append(f"{category_header.ljust(max_cat)} {pattern_header.ljust(max_pat)}")
|
|
55
|
+
lines.append(sep_legend)
|
|
56
|
+
for cat, pat in legend_rows:
|
|
57
|
+
lines.append(f"{cat.ljust(max_cat)} {pat.ljust(max_pat)}")
|
|
58
|
+
lines.append(sep_legend)
|
|
59
|
+
lines.append("")
|
|
60
|
+
lines.append("The following table contains all available error codes:")
|
|
61
|
+
lines.append("")
|
|
62
|
+
headers = ["Code", "Message", "Description"]
|
|
63
|
+
max_lengths = [len(h) for h in headers]
|
|
64
|
+
|
|
65
|
+
for code, info in messages.items():
|
|
66
|
+
if isinstance(info, dict):
|
|
67
|
+
message = escape_for_sphinx(info.get("message", ""))
|
|
68
|
+
description = escape_for_sphinx(info.get("description", ""))
|
|
69
|
+
else:
|
|
70
|
+
message = escape_for_sphinx(str(info))
|
|
71
|
+
description = ""
|
|
72
|
+
max_lengths[0] = max(max_lengths[0], len(code))
|
|
73
|
+
max_lengths[1] = max(max_lengths[1], len(message))
|
|
74
|
+
max_lengths[2] = max(max_lengths[2], len(description))
|
|
75
|
+
|
|
76
|
+
sep = " ".join("=" * length for length in max_lengths)
|
|
77
|
+
lines.append(sep)
|
|
78
|
+
header_line = " ".join(h.ljust(max_lengths[i]) for i, h in enumerate(headers))
|
|
79
|
+
lines.append(header_line)
|
|
80
|
+
lines.append(sep)
|
|
81
|
+
|
|
82
|
+
for code in sorted(messages.keys(), key=sort_key):
|
|
83
|
+
info = messages[code]
|
|
84
|
+
if isinstance(info, dict):
|
|
85
|
+
message = escape_for_sphinx(info.get("message", ""))
|
|
86
|
+
description = escape_for_sphinx(info.get("description", ""))
|
|
87
|
+
else:
|
|
88
|
+
message = escape_for_sphinx(str(info))
|
|
89
|
+
description = ""
|
|
90
|
+
row = " ".join(s.ljust(max_lengths[i]) for i, s in enumerate([code, message, description]))
|
|
91
|
+
lines.append(row)
|
|
92
|
+
|
|
93
|
+
lines.append(sep)
|
|
94
|
+
|
|
95
|
+
path.write_text("\n".join(lines), encoding="utf-8")
|
|
96
|
+
print(f"RST generated in {path}")
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Exceptions.exceptions.py
|
|
3
|
+
========================
|
|
4
|
+
|
|
5
|
+
Description
|
|
6
|
+
-----------
|
|
7
|
+
All exceptions exposed by the Vtl engine.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from typing import Any, List, Optional
|
|
11
|
+
|
|
12
|
+
from vtlengine.Exceptions.messages import centralised_messages
|
|
13
|
+
|
|
14
|
+
dataset_output = None
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class VTLEngineException(Exception):
|
|
18
|
+
"""Base class for exceptions in this module."""
|
|
19
|
+
|
|
20
|
+
def __init__(
|
|
21
|
+
self,
|
|
22
|
+
message: str,
|
|
23
|
+
lino: Optional[str] = None,
|
|
24
|
+
colno: Optional[str] = None,
|
|
25
|
+
code: Optional[str] = None,
|
|
26
|
+
) -> None:
|
|
27
|
+
if code is not None:
|
|
28
|
+
super().__init__(message, code)
|
|
29
|
+
else:
|
|
30
|
+
super().__init__(message)
|
|
31
|
+
self.lino = lino
|
|
32
|
+
self.colno = colno
|
|
33
|
+
|
|
34
|
+
@property
|
|
35
|
+
def pos(self) -> List[Optional[str]]:
|
|
36
|
+
""" """
|
|
37
|
+
|
|
38
|
+
return [self.lino, self.colno]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class SemanticError(VTLEngineException):
|
|
42
|
+
""" """
|
|
43
|
+
|
|
44
|
+
output_message = " Please check transformation with output Dataset "
|
|
45
|
+
comp_code = None
|
|
46
|
+
|
|
47
|
+
def __init__(self, code: str, comp_code: Optional[str] = None, **kwargs: Any) -> None:
|
|
48
|
+
if dataset_output:
|
|
49
|
+
message = (
|
|
50
|
+
centralised_messages[code]["message"].format(**kwargs)
|
|
51
|
+
+ self.output_message
|
|
52
|
+
+ str(dataset_output)
|
|
53
|
+
)
|
|
54
|
+
else:
|
|
55
|
+
message = centralised_messages[code]["message"].format(**kwargs) # type: ignore[index]
|
|
56
|
+
|
|
57
|
+
super().__init__(message, None, None, code)
|
|
58
|
+
|
|
59
|
+
if comp_code:
|
|
60
|
+
self.comp_code = comp_code
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class RunTimeError(VTLEngineException):
|
|
64
|
+
output_message = " Please check transformation with output Dataset "
|
|
65
|
+
comp_code = None
|
|
66
|
+
|
|
67
|
+
def __init__(
|
|
68
|
+
self,
|
|
69
|
+
code: str,
|
|
70
|
+
comp_code: Optional[str] = None,
|
|
71
|
+
**kwargs: Any,
|
|
72
|
+
) -> None:
|
|
73
|
+
message = centralised_messages[code]["message"].format(**kwargs) # type: ignore[index]
|
|
74
|
+
if dataset_output:
|
|
75
|
+
message += self.output_message + str(dataset_output)
|
|
76
|
+
|
|
77
|
+
super().__init__(message, None, None, code)
|
|
78
|
+
|
|
79
|
+
if comp_code:
|
|
80
|
+
self.comp_code = comp_code
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class InputValidationException(VTLEngineException):
|
|
84
|
+
""" """
|
|
85
|
+
|
|
86
|
+
def __init__(
|
|
87
|
+
self,
|
|
88
|
+
message: str = "default_value",
|
|
89
|
+
lino: Optional[str] = None,
|
|
90
|
+
colno: Optional[str] = None,
|
|
91
|
+
code: Optional[str] = None,
|
|
92
|
+
**kwargs: Any,
|
|
93
|
+
) -> None:
|
|
94
|
+
if code is not None:
|
|
95
|
+
message = centralised_messages[code]["message"].format(**kwargs) # type: ignore[index]
|
|
96
|
+
super().__init__(message, lino, colno, code)
|
|
97
|
+
else:
|
|
98
|
+
super().__init__(message, lino, colno)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def check_key(field: str, dict_keys: Any, key: str) -> None:
|
|
102
|
+
if key not in dict_keys:
|
|
103
|
+
closest_key = find_closest_key(dict_keys, key)
|
|
104
|
+
message_append = f". Did you mean {closest_key}?" if closest_key else ""
|
|
105
|
+
raise SemanticError("0-1-1-13", field=field, key=key, closest_key=message_append)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def find_closest_key(dict_keys: Any, key: str) -> Optional[str]:
|
|
109
|
+
closest_key = None
|
|
110
|
+
max_distance = 3
|
|
111
|
+
min_distance = float("inf")
|
|
112
|
+
|
|
113
|
+
for dict_key in dict_keys:
|
|
114
|
+
distance = key_distance(key, dict_key)
|
|
115
|
+
if distance < min_distance:
|
|
116
|
+
min_distance = distance
|
|
117
|
+
closest_key = dict_key
|
|
118
|
+
|
|
119
|
+
if min_distance <= max_distance:
|
|
120
|
+
return closest_key
|
|
121
|
+
return None
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def key_distance(key: str, objetive: str) -> int:
|
|
125
|
+
dp = [[0] * (len(objetive) + 1) for _ in range(len(key) + 1)]
|
|
126
|
+
|
|
127
|
+
for i in range(len(key) + 1):
|
|
128
|
+
dp[i][0] = i
|
|
129
|
+
for j in range(len(objetive) + 1):
|
|
130
|
+
dp[0][j] = j
|
|
131
|
+
|
|
132
|
+
for i in range(1, len(key) + 1):
|
|
133
|
+
for j in range(1, len(objetive) + 1):
|
|
134
|
+
cost = 0 if key[i - 1] == objetive[j - 1] else 1
|
|
135
|
+
dp[i][j] = min(dp[i - 1][j] + 1, dp[i][j - 1] + 1, dp[i - 1][j - 1] + cost)
|
|
136
|
+
|
|
137
|
+
return dp[-1][-1]
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class DataLoadError(VTLEngineException):
|
|
141
|
+
output_message = " Please check loaded file"
|
|
142
|
+
comp_code: Optional[str] = None
|
|
143
|
+
|
|
144
|
+
def __init__(
|
|
145
|
+
self,
|
|
146
|
+
code: str,
|
|
147
|
+
comp_code: Optional[str] = None,
|
|
148
|
+
**kwargs: Any,
|
|
149
|
+
) -> None:
|
|
150
|
+
message = centralised_messages[code]["message"].format(**kwargs) # type: ignore[index]
|
|
151
|
+
if dataset_output:
|
|
152
|
+
message += self.output_message + " " + str(dataset_output)
|
|
153
|
+
else:
|
|
154
|
+
message += self.output_message
|
|
155
|
+
|
|
156
|
+
super().__init__(message, None, None, code)
|
|
157
|
+
|
|
158
|
+
if comp_code:
|
|
159
|
+
self.comp_code = comp_code
|