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