pydpm_xl 0.1.39rc32__py3-none-any.whl → 0.2.1__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.
- py_dpm/__init__.py +1 -1
- py_dpm/api/__init__.py +58 -189
- py_dpm/api/dpm/__init__.py +20 -0
- py_dpm/api/{data_dictionary.py → dpm/data_dictionary.py} +903 -984
- py_dpm/api/dpm/explorer.py +236 -0
- py_dpm/api/dpm/hierarchical_queries.py +142 -0
- py_dpm/api/{migration.py → dpm/migration.py} +16 -19
- py_dpm/api/{operation_scopes.py → dpm/operation_scopes.py} +319 -267
- py_dpm/api/dpm_xl/__init__.py +25 -0
- py_dpm/api/{ast_generator.py → dpm_xl/ast_generator.py} +3 -3
- py_dpm/api/{complete_ast.py → dpm_xl/complete_ast.py} +186 -284
- py_dpm/api/dpm_xl/semantic.py +358 -0
- py_dpm/api/{syntax.py → dpm_xl/syntax.py} +6 -5
- py_dpm/api/explorer.py +4 -0
- py_dpm/api/semantic.py +30 -306
- py_dpm/cli/__init__.py +9 -0
- py_dpm/{client.py → cli/main.py} +12 -10
- py_dpm/dpm/__init__.py +11 -0
- py_dpm/{models.py → dpm/models.py} +112 -88
- py_dpm/dpm/queries/base.py +100 -0
- py_dpm/dpm/queries/basic_objects.py +33 -0
- py_dpm/dpm/queries/explorer_queries.py +352 -0
- py_dpm/dpm/queries/filters.py +139 -0
- py_dpm/dpm/queries/glossary.py +45 -0
- py_dpm/dpm/queries/hierarchical_queries.py +838 -0
- py_dpm/dpm/queries/tables.py +133 -0
- py_dpm/dpm/utils.py +356 -0
- py_dpm/dpm_xl/__init__.py +8 -0
- py_dpm/dpm_xl/ast/__init__.py +14 -0
- py_dpm/{AST/ASTConstructor.py → dpm_xl/ast/constructor.py} +6 -6
- py_dpm/{AST/MLGeneration.py → dpm_xl/ast/ml_generation.py} +137 -87
- py_dpm/{AST/ModuleAnalyzer.py → dpm_xl/ast/module_analyzer.py} +7 -7
- py_dpm/{AST/ModuleDependencies.py → dpm_xl/ast/module_dependencies.py} +56 -41
- py_dpm/{AST/ASTObjects.py → dpm_xl/ast/nodes.py} +1 -1
- py_dpm/{AST/check_operands.py → dpm_xl/ast/operands.py} +16 -13
- py_dpm/{AST/ASTTemplate.py → dpm_xl/ast/template.py} +2 -2
- py_dpm/{AST/WhereClauseChecker.py → dpm_xl/ast/where_clause.py} +2 -2
- py_dpm/dpm_xl/grammar/__init__.py +18 -0
- py_dpm/dpm_xl/operators/__init__.py +19 -0
- py_dpm/{Operators/AggregateOperators.py → dpm_xl/operators/aggregate.py} +7 -7
- py_dpm/{Operators/NumericOperators.py → dpm_xl/operators/arithmetic.py} +6 -6
- py_dpm/{Operators/Operator.py → dpm_xl/operators/base.py} +5 -5
- py_dpm/{Operators/BooleanOperators.py → dpm_xl/operators/boolean.py} +5 -5
- py_dpm/{Operators/ClauseOperators.py → dpm_xl/operators/clause.py} +8 -8
- py_dpm/{Operators/ComparisonOperators.py → dpm_xl/operators/comparison.py} +5 -5
- py_dpm/{Operators/ConditionalOperators.py → dpm_xl/operators/conditional.py} +7 -7
- py_dpm/{Operators/StringOperators.py → dpm_xl/operators/string.py} +5 -5
- py_dpm/{Operators/TimeOperators.py → dpm_xl/operators/time.py} +6 -6
- py_dpm/{semantics/SemanticAnalyzer.py → dpm_xl/semantic_analyzer.py} +168 -68
- py_dpm/{semantics/Symbols.py → dpm_xl/symbols.py} +3 -3
- py_dpm/dpm_xl/types/__init__.py +13 -0
- py_dpm/{DataTypes/TypePromotion.py → dpm_xl/types/promotion.py} +2 -2
- py_dpm/{DataTypes/ScalarTypes.py → dpm_xl/types/scalar.py} +2 -2
- py_dpm/dpm_xl/utils/__init__.py +14 -0
- py_dpm/{data_handlers.py → dpm_xl/utils/data_handlers.py} +2 -2
- py_dpm/{Utils → dpm_xl/utils}/operands_mapping.py +1 -1
- py_dpm/{Utils → dpm_xl/utils}/operator_mapping.py +8 -8
- py_dpm/{OperationScopes/OperationScopeService.py → dpm_xl/utils/scopes_calculator.py} +148 -58
- py_dpm/{Utils/ast_serialization.py → dpm_xl/utils/serialization.py} +3 -4
- py_dpm/dpm_xl/validation/__init__.py +12 -0
- py_dpm/{Utils/ValidationsGenerationUtils.py → dpm_xl/validation/generation_utils.py} +2 -3
- py_dpm/{ValidationsGeneration/PropertiesConstraintsProcessor.py → dpm_xl/validation/property_constraints.py} +56 -21
- py_dpm/{ValidationsGeneration/auxiliary_functions.py → dpm_xl/validation/utils.py} +2 -2
- py_dpm/{ValidationsGeneration/VariantsProcessor.py → dpm_xl/validation/variants.py} +149 -55
- py_dpm/exceptions/__init__.py +23 -0
- py_dpm/{Exceptions → exceptions}/exceptions.py +7 -2
- pydpm_xl-0.2.1.dist-info/METADATA +278 -0
- pydpm_xl-0.2.1.dist-info/RECORD +88 -0
- pydpm_xl-0.2.1.dist-info/entry_points.txt +2 -0
- py_dpm/Exceptions/__init__.py +0 -0
- py_dpm/OperationScopes/__init__.py +0 -0
- py_dpm/Operators/__init__.py +0 -0
- py_dpm/Utils/__init__.py +0 -0
- py_dpm/Utils/utils.py +0 -2
- py_dpm/ValidationsGeneration/Utils.py +0 -364
- py_dpm/ValidationsGeneration/__init__.py +0 -0
- py_dpm/api/data_dictionary_validation.py +0 -614
- py_dpm/db_utils.py +0 -221
- py_dpm/grammar/__init__.py +0 -0
- py_dpm/grammar/dist/__init__.py +0 -0
- py_dpm/grammar/dpm_xlLexer.g4 +0 -437
- py_dpm/grammar/dpm_xlParser.g4 +0 -263
- py_dpm/semantics/DAG/DAGAnalyzer.py +0 -158
- py_dpm/semantics/DAG/__init__.py +0 -0
- py_dpm/semantics/__init__.py +0 -0
- py_dpm/views/data_types.sql +0 -12
- py_dpm/views/datapoints.sql +0 -65
- py_dpm/views/hierarchy_operand_reference.sql +0 -11
- py_dpm/views/hierarchy_preconditions.sql +0 -13
- py_dpm/views/hierarchy_variables.sql +0 -26
- py_dpm/views/hierarchy_variables_context.sql +0 -14
- py_dpm/views/key_components.sql +0 -18
- py_dpm/views/module_from_table.sql +0 -11
- py_dpm/views/open_keys.sql +0 -13
- py_dpm/views/operation_info.sql +0 -27
- py_dpm/views/operation_list.sql +0 -18
- py_dpm/views/operations_versions_from_module_version.sql +0 -30
- py_dpm/views/precondition_info.sql +0 -17
- py_dpm/views/report_type_operand_reference_info.sql +0 -18
- py_dpm/views/subcategory_info.sql +0 -17
- py_dpm/views/table_info.sql +0 -19
- pydpm_xl-0.1.39rc32.dist-info/METADATA +0 -53
- pydpm_xl-0.1.39rc32.dist-info/RECORD +0 -96
- pydpm_xl-0.1.39rc32.dist-info/entry_points.txt +0 -2
- /py_dpm/{AST → cli/commands}/__init__.py +0 -0
- /py_dpm/{migration.py → dpm/migration.py} +0 -0
- /py_dpm/{AST/ASTVisitor.py → dpm_xl/ast/visitor.py} +0 -0
- /py_dpm/{DataTypes → dpm_xl/grammar/generated}/__init__.py +0 -0
- /py_dpm/{grammar/dist → dpm_xl/grammar/generated}/dpm_xlLexer.interp +0 -0
- /py_dpm/{grammar/dist → dpm_xl/grammar/generated}/dpm_xlLexer.py +0 -0
- /py_dpm/{grammar/dist → dpm_xl/grammar/generated}/dpm_xlLexer.tokens +0 -0
- /py_dpm/{grammar/dist → dpm_xl/grammar/generated}/dpm_xlParser.interp +0 -0
- /py_dpm/{grammar/dist → dpm_xl/grammar/generated}/dpm_xlParser.py +0 -0
- /py_dpm/{grammar/dist → dpm_xl/grammar/generated}/dpm_xlParser.tokens +0 -0
- /py_dpm/{grammar/dist → dpm_xl/grammar/generated}/dpm_xlParserListener.py +0 -0
- /py_dpm/{grammar/dist → dpm_xl/grammar/generated}/dpm_xlParserVisitor.py +0 -0
- /py_dpm/{grammar/dist → dpm_xl/grammar/generated}/listeners.py +0 -0
- /py_dpm/{DataTypes/TimeClasses.py → dpm_xl/types/time.py} +0 -0
- /py_dpm/{Utils → dpm_xl/utils}/tokens.py +0 -0
- /py_dpm/{Exceptions → exceptions}/messages.py +0 -0
- {pydpm_xl-0.1.39rc32.dist-info → pydpm_xl-0.2.1.dist-info}/WHEEL +0 -0
- {pydpm_xl-0.1.39rc32.dist-info → pydpm_xl-0.2.1.dist-info}/licenses/LICENSE +0 -0
- {pydpm_xl-0.1.39rc32.dist-info → pydpm_xl-0.2.1.dist-info}/top_level.txt +0 -0
py_dpm/api/semantic.py
CHANGED
|
@@ -1,273 +1,16 @@
|
|
|
1
|
-
from typing import
|
|
2
|
-
from dataclasses import dataclass
|
|
1
|
+
from typing import Optional
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
from py_dpm.AST.check_operands import OperandsChecking
|
|
11
|
-
from py_dpm.semantics import SemanticAnalyzer
|
|
12
|
-
from py_dpm.db_utils import get_session, get_engine
|
|
13
|
-
from py_dpm.Exceptions.exceptions import SemanticError
|
|
3
|
+
from py_dpm.api.dpm_xl.semantic import (
|
|
4
|
+
SemanticAPI as _SemanticAPI,
|
|
5
|
+
SemanticValidationResult,
|
|
6
|
+
validate_expression as _validate_expression,
|
|
7
|
+
is_valid_semantics as _is_valid_semantics,
|
|
8
|
+
)
|
|
14
9
|
|
|
15
10
|
|
|
16
|
-
|
|
17
|
-
class SemanticValidationResult:
|
|
18
|
-
"""
|
|
19
|
-
Result of semantic validation.
|
|
20
|
-
|
|
21
|
-
Attributes:
|
|
22
|
-
is_valid (bool): Whether the semantic validation passed
|
|
23
|
-
error_message (Optional[str]): Error message if validation failed
|
|
24
|
-
error_code (Optional[str]): Error code if validation failed
|
|
25
|
-
expression (str): The original expression that was validated
|
|
26
|
-
validation_type (str): Type of validation performed
|
|
27
|
-
results (Optional[Any]): Additional results from semantic analysis
|
|
28
|
-
"""
|
|
29
|
-
|
|
30
|
-
is_valid: bool
|
|
31
|
-
error_message: Optional[str]
|
|
32
|
-
error_code: Optional[str]
|
|
33
|
-
expression: str
|
|
34
|
-
validation_type: str
|
|
35
|
-
results: Optional[Any] = None
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
class SemanticAPI:
|
|
39
|
-
"""
|
|
40
|
-
API for DPM-XL semantic validation and analysis.
|
|
41
|
-
|
|
42
|
-
This class provides methods to perform semantic analysis on DPM-XL expressions,
|
|
43
|
-
including operand checking, data type validation, and structure validation.
|
|
44
|
-
"""
|
|
45
|
-
|
|
46
|
-
def __init__(
|
|
47
|
-
self, database_path: Optional[str] = None, connection_url: Optional[str] = None
|
|
48
|
-
):
|
|
49
|
-
"""
|
|
50
|
-
Initialize the Semantic API.
|
|
51
|
-
|
|
52
|
-
Args:
|
|
53
|
-
database_path (Optional[str]): Path to SQLite database. If None, uses default from environment.
|
|
54
|
-
connection_url (Optional[str]): Full SQLAlchemy connection URL (e.g., postgresql://user:pass@host:port/db).
|
|
55
|
-
Takes precedence over database_path.
|
|
56
|
-
"""
|
|
57
|
-
self.database_path = database_path
|
|
58
|
-
self.connection_url = connection_url
|
|
59
|
-
|
|
60
|
-
if connection_url:
|
|
61
|
-
# Create isolated engine and session for the provided connection URL
|
|
62
|
-
from sqlalchemy.orm import sessionmaker
|
|
63
|
-
from py_dpm.db_utils import create_engine_from_url
|
|
64
|
-
|
|
65
|
-
# Create engine for the connection URL (supports SQLite, PostgreSQL, MySQL, etc.)
|
|
66
|
-
self.engine = create_engine_from_url(connection_url)
|
|
67
|
-
session_maker = sessionmaker(bind=self.engine)
|
|
68
|
-
self.session = session_maker()
|
|
69
|
-
|
|
70
|
-
elif database_path:
|
|
71
|
-
# Create isolated engine and session for this specific database
|
|
72
|
-
from sqlalchemy import create_engine
|
|
73
|
-
from sqlalchemy.orm import sessionmaker
|
|
74
|
-
import os
|
|
75
|
-
|
|
76
|
-
# Create the database directory if it doesn't exist
|
|
77
|
-
db_dir = os.path.dirname(database_path)
|
|
78
|
-
if db_dir and not os.path.exists(db_dir):
|
|
79
|
-
os.makedirs(db_dir)
|
|
80
|
-
|
|
81
|
-
# Create engine for specific database path
|
|
82
|
-
db_connection_url = f"sqlite:///{database_path}"
|
|
83
|
-
self.engine = create_engine(db_connection_url, pool_pre_ping=True)
|
|
84
|
-
session_maker = sessionmaker(bind=self.engine)
|
|
85
|
-
self.session = session_maker()
|
|
86
|
-
else:
|
|
87
|
-
# Use default global connection
|
|
88
|
-
get_engine()
|
|
89
|
-
self.session = get_session()
|
|
90
|
-
self.engine = None
|
|
91
|
-
|
|
92
|
-
self.error_listener = DPMErrorListener()
|
|
93
|
-
self.visitor = ASTVisitor()
|
|
94
|
-
|
|
95
|
-
def validate_expression(
|
|
96
|
-
self, expression: str, release_id: Optional[int] = None
|
|
97
|
-
) -> SemanticValidationResult:
|
|
98
|
-
"""
|
|
99
|
-
Perform semantic validation on a DPM-XL expression.
|
|
100
|
-
|
|
101
|
-
This includes syntax validation, operands checking, data type validation,
|
|
102
|
-
and structure validation.
|
|
103
|
-
|
|
104
|
-
Args:
|
|
105
|
-
expression (str): The DPM-XL expression to validate
|
|
106
|
-
release_id (Optional[int]): Specific release ID for component filtering.
|
|
107
|
-
If None, uses live/latest release (EndReleaseID IS NULL).
|
|
108
|
-
|
|
109
|
-
Returns:
|
|
110
|
-
SemanticValidationResult: Result containing validation status and details
|
|
111
|
-
|
|
112
|
-
Example:
|
|
113
|
-
>>> from pydpm.api import SemanticAPI
|
|
114
|
-
>>> semantic = SemanticAPI()
|
|
115
|
-
>>> result = semantic.validate_expression("{tC_01.00, r0100, c0010} + {tC_01.00, r0200, c0010}")
|
|
116
|
-
>>> print(result.is_valid)
|
|
117
|
-
True
|
|
118
|
-
|
|
119
|
-
>>> # Validate for specific release
|
|
120
|
-
>>> result = semantic.validate_expression("{tC_01.00, r0100, c0010}", release_id=5)
|
|
121
|
-
"""
|
|
122
|
-
try:
|
|
123
|
-
# Parse expression to AST
|
|
124
|
-
input_stream = InputStream(expression)
|
|
125
|
-
lexer = dpm_xlLexer(input_stream)
|
|
126
|
-
lexer._listeners = [self.error_listener]
|
|
127
|
-
token_stream = CommonTokenStream(lexer)
|
|
128
|
-
|
|
129
|
-
parser = dpm_xlParser(token_stream)
|
|
130
|
-
parser._listeners = [self.error_listener]
|
|
131
|
-
parse_tree = parser.start()
|
|
132
|
-
|
|
133
|
-
if parser._syntaxErrors > 0:
|
|
134
|
-
return SemanticValidationResult(
|
|
135
|
-
is_valid=False,
|
|
136
|
-
error_message="Syntax errors detected",
|
|
137
|
-
error_code="SYNTAX_ERROR",
|
|
138
|
-
expression=expression,
|
|
139
|
-
validation_type="SEMANTIC",
|
|
140
|
-
)
|
|
11
|
+
SemanticAPI = _SemanticAPI
|
|
141
12
|
|
|
142
|
-
# Generate AST
|
|
143
|
-
ast = self.visitor.visit(parse_tree)
|
|
144
13
|
|
|
145
|
-
# Perform semantic analysis
|
|
146
|
-
oc = OperandsChecking(
|
|
147
|
-
session=self.session,
|
|
148
|
-
expression=expression,
|
|
149
|
-
ast=ast,
|
|
150
|
-
release_id=release_id,
|
|
151
|
-
)
|
|
152
|
-
semanticAnalysis = SemanticAnalyzer.InputAnalyzer(expression)
|
|
153
|
-
|
|
154
|
-
semanticAnalysis.data = oc.data
|
|
155
|
-
semanticAnalysis.key_components = oc.key_components
|
|
156
|
-
semanticAnalysis.open_keys = oc.open_keys
|
|
157
|
-
semanticAnalysis.preconditions = oc.preconditions
|
|
158
|
-
|
|
159
|
-
results = semanticAnalysis.visit(ast)
|
|
160
|
-
|
|
161
|
-
return SemanticValidationResult(
|
|
162
|
-
is_valid=True,
|
|
163
|
-
error_message=None,
|
|
164
|
-
error_code=None,
|
|
165
|
-
expression=expression,
|
|
166
|
-
validation_type="SEMANTIC",
|
|
167
|
-
results=results,
|
|
168
|
-
)
|
|
169
|
-
|
|
170
|
-
except SemanticError as e:
|
|
171
|
-
return SemanticValidationResult(
|
|
172
|
-
is_valid=False,
|
|
173
|
-
error_message=str(e),
|
|
174
|
-
error_code=getattr(e, "code", None),
|
|
175
|
-
expression=expression,
|
|
176
|
-
validation_type="SEMANTIC",
|
|
177
|
-
)
|
|
178
|
-
except Exception as e:
|
|
179
|
-
return SemanticValidationResult(
|
|
180
|
-
is_valid=False,
|
|
181
|
-
error_message=str(e),
|
|
182
|
-
error_code="UNKNOWN",
|
|
183
|
-
expression=expression,
|
|
184
|
-
validation_type="SEMANTIC",
|
|
185
|
-
)
|
|
186
|
-
|
|
187
|
-
def analyze_expression(
|
|
188
|
-
self, expression: str, release_id: Optional[int] = None
|
|
189
|
-
) -> Dict[str, Any]:
|
|
190
|
-
"""
|
|
191
|
-
Perform detailed semantic analysis on a DPM-XL expression.
|
|
192
|
-
|
|
193
|
-
Args:
|
|
194
|
-
expression (str): The DPM-XL expression to analyze
|
|
195
|
-
release_id (Optional[int]): Specific release ID for component filtering.
|
|
196
|
-
If None, uses live/latest release.
|
|
197
|
-
|
|
198
|
-
Returns:
|
|
199
|
-
Dict[str, Any]: Detailed analysis results
|
|
200
|
-
|
|
201
|
-
Raises:
|
|
202
|
-
Exception: If analysis fails
|
|
203
|
-
|
|
204
|
-
Example:
|
|
205
|
-
>>> from pydpm.api import SemanticAPI
|
|
206
|
-
>>> semantic = SemanticAPI()
|
|
207
|
-
>>> analysis = semantic.analyze_expression("{tC_01.00, r0100, c0010}")
|
|
208
|
-
>>> # Analyze for specific release
|
|
209
|
-
>>> analysis = semantic.analyze_expression("{tC_01.00, r0100, c0010}", release_id=5)
|
|
210
|
-
"""
|
|
211
|
-
result = self.validate_expression(expression, release_id=release_id)
|
|
212
|
-
|
|
213
|
-
if not result.is_valid:
|
|
214
|
-
raise Exception(f"Semantic analysis failed: {result.error_message}")
|
|
215
|
-
|
|
216
|
-
# Extract additional analysis information
|
|
217
|
-
analysis = {
|
|
218
|
-
"expression": expression,
|
|
219
|
-
"is_valid": True,
|
|
220
|
-
"results": result.results,
|
|
221
|
-
"data_types": (
|
|
222
|
-
getattr(result.results, "type", None) if result.results else None
|
|
223
|
-
),
|
|
224
|
-
"components": (
|
|
225
|
-
getattr(result.results, "components", None) if result.results else None
|
|
226
|
-
),
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
return analysis
|
|
230
|
-
|
|
231
|
-
def is_valid_semantics(
|
|
232
|
-
self, expression: str, release_id: Optional[int] = None
|
|
233
|
-
) -> bool:
|
|
234
|
-
"""
|
|
235
|
-
Quick check if expression has valid semantics.
|
|
236
|
-
|
|
237
|
-
Args:
|
|
238
|
-
expression (str): The DPM-XL expression to check
|
|
239
|
-
release_id (Optional[int]): Specific release ID for component filtering.
|
|
240
|
-
If None, uses live/latest release.
|
|
241
|
-
|
|
242
|
-
Returns:
|
|
243
|
-
bool: True if semantics are valid, False otherwise
|
|
244
|
-
|
|
245
|
-
Example:
|
|
246
|
-
>>> from pydpm.api import SemanticAPI
|
|
247
|
-
>>> semantic = SemanticAPI()
|
|
248
|
-
>>> is_valid = semantic.is_valid_semantics("{tC_01.00, r0100, c0010}")
|
|
249
|
-
>>> # Check for specific release
|
|
250
|
-
>>> is_valid = semantic.is_valid_semantics("{tC_01.00, r0100, c0010}", release_id=5)
|
|
251
|
-
"""
|
|
252
|
-
result = self.validate_expression(expression, release_id=release_id)
|
|
253
|
-
return result.is_valid
|
|
254
|
-
|
|
255
|
-
def __del__(self):
|
|
256
|
-
"""Clean up resources."""
|
|
257
|
-
try:
|
|
258
|
-
if hasattr(self, "session") and self.session:
|
|
259
|
-
self.session.close()
|
|
260
|
-
except Exception:
|
|
261
|
-
pass
|
|
262
|
-
|
|
263
|
-
try:
|
|
264
|
-
if hasattr(self, "engine") and self.engine is not None:
|
|
265
|
-
self.engine.dispose()
|
|
266
|
-
except Exception:
|
|
267
|
-
pass
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
# Convenience functions for direct usage
|
|
271
14
|
def validate_expression(
|
|
272
15
|
expression: str,
|
|
273
16
|
database_path: Optional[str] = None,
|
|
@@ -275,29 +18,16 @@ def validate_expression(
|
|
|
275
18
|
release_id: Optional[int] = None,
|
|
276
19
|
) -> SemanticValidationResult:
|
|
277
20
|
"""
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
Args:
|
|
281
|
-
expression (str): The DPM-XL expression to validate
|
|
282
|
-
database_path (Optional[str]): Path to SQLite database. If None, uses default from environment.
|
|
283
|
-
connection_url (Optional[str]): Full SQLAlchemy connection URL (e.g., postgresql://user:pass@host:port/db).
|
|
284
|
-
release_id (Optional[int]): Specific release ID for component filtering.
|
|
285
|
-
If None, uses live/latest release.
|
|
21
|
+
Backwards-compatible wrapper for semantic validation.
|
|
286
22
|
|
|
287
|
-
|
|
288
|
-
SemanticValidationResult: Result containing validation status and details
|
|
289
|
-
|
|
290
|
-
Example:
|
|
291
|
-
>>> from pydpm.api.semantic import validate_expression
|
|
292
|
-
>>> result = validate_expression("{tC_01.00, r0100, c0010}", database_path="./database.db")
|
|
293
|
-
>>> # Using PostgreSQL
|
|
294
|
-
>>> result = validate_expression("{tC_01.00, r0100, c0010}",
|
|
295
|
-
... connection_url="postgresql://user:pass@host:5432/db")
|
|
296
|
-
>>> # Validate for specific release
|
|
297
|
-
>>> result = validate_expression("{tC_01.00, r0100, c0010}", database_path="./database.db", release_id=5)
|
|
23
|
+
This delegates to the DPM-XL SemanticAPI implementation.
|
|
298
24
|
"""
|
|
299
|
-
|
|
300
|
-
|
|
25
|
+
return _validate_expression(
|
|
26
|
+
expression,
|
|
27
|
+
database_path=database_path,
|
|
28
|
+
connection_url=connection_url,
|
|
29
|
+
release_id=release_id,
|
|
30
|
+
)
|
|
301
31
|
|
|
302
32
|
|
|
303
33
|
def is_valid_semantics(
|
|
@@ -307,26 +37,20 @@ def is_valid_semantics(
|
|
|
307
37
|
release_id: Optional[int] = None,
|
|
308
38
|
) -> bool:
|
|
309
39
|
"""
|
|
310
|
-
|
|
40
|
+
Backwards-compatible wrapper to check semantic validity.
|
|
41
|
+
"""
|
|
42
|
+
return _is_valid_semantics(
|
|
43
|
+
expression,
|
|
44
|
+
database_path=database_path,
|
|
45
|
+
connection_url=connection_url,
|
|
46
|
+
release_id=release_id,
|
|
47
|
+
)
|
|
311
48
|
|
|
312
|
-
Args:
|
|
313
|
-
expression (str): The DPM-XL expression to check
|
|
314
|
-
database_path (Optional[str]): Path to SQLite database. If None, uses default from environment.
|
|
315
|
-
connection_url (Optional[str]): Full SQLAlchemy connection URL (e.g., postgresql://user:pass@host:port/db).
|
|
316
|
-
release_id (Optional[int]): Specific release ID for component filtering.
|
|
317
|
-
If None, uses live/latest release.
|
|
318
49
|
|
|
319
|
-
|
|
320
|
-
|
|
50
|
+
__all__ = [
|
|
51
|
+
"SemanticAPI",
|
|
52
|
+
"SemanticValidationResult",
|
|
53
|
+
"validate_expression",
|
|
54
|
+
"is_valid_semantics",
|
|
55
|
+
]
|
|
321
56
|
|
|
322
|
-
Example:
|
|
323
|
-
>>> from pydpm.api.semantic import is_valid_semantics
|
|
324
|
-
>>> is_valid = is_valid_semantics("{tC_01.00, r0100, c0010}", database_path="./database.db")
|
|
325
|
-
>>> # Using PostgreSQL
|
|
326
|
-
>>> is_valid = is_valid_semantics("{tC_01.00, r0100, c0010}",
|
|
327
|
-
... connection_url="postgresql://user:pass@host:5432/db")
|
|
328
|
-
>>> # Check for specific release
|
|
329
|
-
>>> is_valid = is_valid_semantics("{tC_01.00, r0100, c0010}", database_path="./database.db", release_id=5)
|
|
330
|
-
"""
|
|
331
|
-
api = SemanticAPI(database_path=database_path, connection_url=connection_url)
|
|
332
|
-
return api.is_valid_semantics(expression, release_id=release_id)
|
py_dpm/cli/__init__.py
ADDED
py_dpm/{client.py → cli/main.py}
RENAMED
|
@@ -6,11 +6,11 @@ import os
|
|
|
6
6
|
import sys
|
|
7
7
|
import pandas as pd
|
|
8
8
|
|
|
9
|
-
from py_dpm.api import
|
|
10
|
-
from py_dpm.api.semantic import SemanticValidationResult
|
|
11
|
-
from py_dpm.api.operation_scopes import OperationScopesAPI
|
|
12
|
-
from py_dpm.migration import run_migration
|
|
13
|
-
from py_dpm.
|
|
9
|
+
from py_dpm.api import SemanticAPI, SyntaxAPI
|
|
10
|
+
from py_dpm.api.dpm_xl.semantic import SemanticValidationResult
|
|
11
|
+
from py_dpm.api.dpm.operation_scopes import OperationScopesAPI
|
|
12
|
+
from py_dpm.dpm.migration import run_migration
|
|
13
|
+
from py_dpm.dpm_xl.utils.tokens import (
|
|
14
14
|
CODE,
|
|
15
15
|
ERROR,
|
|
16
16
|
ERROR_CODE,
|
|
@@ -23,7 +23,7 @@ from py_dpm.Utils.tokens import (
|
|
|
23
23
|
VALIDATION_TYPE,
|
|
24
24
|
VARIABLES,
|
|
25
25
|
)
|
|
26
|
-
from py_dpm.
|
|
26
|
+
from py_dpm.exceptions.exceptions import SemanticError
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
console = Console()
|
|
@@ -86,7 +86,7 @@ def semantic(expression: str, release_id: int, dpm_version: str):
|
|
|
86
86
|
semantic_api = SemanticAPI()
|
|
87
87
|
|
|
88
88
|
if dpm_version:
|
|
89
|
-
from py_dpm.models import Release
|
|
89
|
+
from py_dpm.dpm.models import Release
|
|
90
90
|
|
|
91
91
|
release_id = (
|
|
92
92
|
semantic_api.session.query(Release.releaseid)
|
|
@@ -147,9 +147,11 @@ def syntax(expression: str):
|
|
|
147
147
|
"""Perform syntactic analysis on a DPM expression."""
|
|
148
148
|
|
|
149
149
|
status = 0
|
|
150
|
-
api =
|
|
150
|
+
api = SyntaxAPI()
|
|
151
151
|
try:
|
|
152
|
-
api.
|
|
152
|
+
result = api.validate_expression(expression)
|
|
153
|
+
if not result.is_valid:
|
|
154
|
+
raise SyntaxError(result.error_message or "Syntax errors detected")
|
|
153
155
|
message_formatted = Text("Syntax OK", style="bold green")
|
|
154
156
|
except SyntaxError as e:
|
|
155
157
|
message = str(e)
|
|
@@ -319,7 +321,7 @@ def calculate_scopes(expression, operation_vid, tables, preconditions, release_i
|
|
|
319
321
|
modules_table.add_column("From Date", justify="center")
|
|
320
322
|
modules_table.add_column("To Date", justify="center")
|
|
321
323
|
|
|
322
|
-
from py_dpm.models import ModuleVersion
|
|
324
|
+
from py_dpm.dpm.models import ModuleVersion
|
|
323
325
|
|
|
324
326
|
for module_vid in result.module_versions:
|
|
325
327
|
module_df = ModuleVersion.get_module_version_by_vid(
|
py_dpm/dpm/__init__.py
ADDED