pydpm_xl 0.2.4__tar.gz → 0.2.5rc1__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.
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/PKG-INFO +54 -1
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/README.md +53 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/__init__.py +1 -1
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/api/dpm_xl/ast_generator.py +188 -10
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/api/dpm_xl/complete_ast.py +10 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/pydpm_xl.egg-info/PKG-INFO +54 -1
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/pyproject.toml +2 -2
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/LICENSE +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/api/__init__.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/api/dpm/__init__.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/api/dpm/data_dictionary.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/api/dpm/explorer.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/api/dpm/hierarchical_queries.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/api/dpm/instance.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/api/dpm/migration.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/api/dpm_xl/__init__.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/api/dpm_xl/operation_scopes.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/api/dpm_xl/semantic.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/api/dpm_xl/syntax.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/cli/__init__.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/cli/commands/__init__.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/cli/main.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm/__init__.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm/migration.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm/models.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm/queries/base.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm/queries/basic_objects.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm/queries/explorer_queries.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm/queries/filters.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm/queries/glossary.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm/queries/hierarchical_queries.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm/queries/tables.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm/utils.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/__init__.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/ast/__init__.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/ast/constructor.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/ast/ml_generation.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/ast/module_analyzer.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/ast/module_dependencies.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/ast/nodes.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/ast/operands.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/ast/template.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/ast/visitor.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/ast/where_clause.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/grammar/__init__.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/grammar/generated/__init__.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/grammar/generated/dpm_xlLexer.interp +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/grammar/generated/dpm_xlLexer.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/grammar/generated/dpm_xlLexer.tokens +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/grammar/generated/dpm_xlParser.interp +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/grammar/generated/dpm_xlParser.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/grammar/generated/dpm_xlParser.tokens +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/grammar/generated/dpm_xlParserListener.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/grammar/generated/dpm_xlParserVisitor.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/grammar/generated/listeners.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/operators/__init__.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/operators/aggregate.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/operators/arithmetic.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/operators/base.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/operators/boolean.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/operators/clause.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/operators/comparison.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/operators/conditional.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/operators/string.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/operators/time.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/semantic_analyzer.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/symbols.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/types/__init__.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/types/promotion.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/types/scalar.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/types/time.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/utils/__init__.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/utils/data_handlers.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/utils/operands_mapping.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/utils/operator_mapping.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/utils/scopes_calculator.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/utils/serialization.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/utils/tokens.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/exceptions/__init__.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/exceptions/exceptions.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/exceptions/messages.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/instance/__init__.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/instance/instance.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/pydpm_xl.egg-info/SOURCES.txt +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/pydpm_xl.egg-info/dependency_links.txt +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/pydpm_xl.egg-info/entry_points.txt +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/pydpm_xl.egg-info/requires.txt +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/pydpm_xl.egg-info/top_level.txt +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/setup.cfg +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/tests/test_cli_semantic.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/tests/test_data_dictionary_releases.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/tests/test_db_connection_handling.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/tests/test_get_table_details.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/tests/test_get_tables_date_filter.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/tests/test_get_tables_release_code.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/tests/test_hierarchical_query.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/tests/test_query_refactor.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/tests/test_release_filters_semantic.py +0 -0
- {pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/tests/test_semantic_release.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pydpm_xl
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.5rc1
|
|
4
4
|
Summary: Python library for DPM-XL data processing and analysis
|
|
5
5
|
Author-email: "MeaningfulData S.L." <info@meaningfuldata.eu>
|
|
6
6
|
License: GPL-3.0-or-later
|
|
@@ -241,6 +241,59 @@ migration_api.migrate_from_access(
|
|
|
241
241
|
)
|
|
242
242
|
```
|
|
243
243
|
|
|
244
|
+
#### XBRL-CSV Instance Generation
|
|
245
|
+
|
|
246
|
+
```python
|
|
247
|
+
from py_dpm.api import InstanceAPI
|
|
248
|
+
|
|
249
|
+
api = InstanceAPI()
|
|
250
|
+
|
|
251
|
+
# Build package from dictionary
|
|
252
|
+
data = {
|
|
253
|
+
"module_code": "F_01.01",
|
|
254
|
+
"parameters": {"refPeriod": "2024-12-31"},
|
|
255
|
+
"facts": [
|
|
256
|
+
{"table_code": "t001", "row_code": "r010", "column_code": "c010", "value": 1000000}
|
|
257
|
+
]
|
|
258
|
+
}
|
|
259
|
+
output_path = api.build_package_from_dict(data, "/tmp/output")
|
|
260
|
+
|
|
261
|
+
# Build package from JSON file
|
|
262
|
+
output_path = api.build_package_from_json("instance_data.json", "/tmp/output")
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
#### DPM Explorer - Introspection Queries
|
|
266
|
+
|
|
267
|
+
```python
|
|
268
|
+
from py_dpm.api import ExplorerQueryAPI
|
|
269
|
+
|
|
270
|
+
with ExplorerQueryAPI() as api:
|
|
271
|
+
# Find all properties using a specific item
|
|
272
|
+
properties = api.get_properties_using_item("EUR")
|
|
273
|
+
|
|
274
|
+
# Get module URL for documentation
|
|
275
|
+
url = api.get_module_url(module_code="F_01.01")
|
|
276
|
+
|
|
277
|
+
# Explore variable usage
|
|
278
|
+
tables = api.get_tables_using_variable(variable_code="mi123")
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
#### Hierarchical Queries
|
|
282
|
+
|
|
283
|
+
```python
|
|
284
|
+
from py_dpm.api import HierarchicalQueryAPI
|
|
285
|
+
|
|
286
|
+
with HierarchicalQueryAPI() as api:
|
|
287
|
+
# Get hierarchy for a domain
|
|
288
|
+
hierarchy = api.get_hierarchy(domain_code="DOM_001")
|
|
289
|
+
|
|
290
|
+
# Navigate parent-child relationships
|
|
291
|
+
children = api.get_children(item_code="PARENT_001")
|
|
292
|
+
|
|
293
|
+
# Get all ancestors
|
|
294
|
+
ancestors = api.get_ancestors(item_code="LEAF_001")
|
|
295
|
+
```
|
|
296
|
+
|
|
244
297
|
## Development
|
|
245
298
|
|
|
246
299
|
### Running Tests
|
|
@@ -208,6 +208,59 @@ migration_api.migrate_from_access(
|
|
|
208
208
|
)
|
|
209
209
|
```
|
|
210
210
|
|
|
211
|
+
#### XBRL-CSV Instance Generation
|
|
212
|
+
|
|
213
|
+
```python
|
|
214
|
+
from py_dpm.api import InstanceAPI
|
|
215
|
+
|
|
216
|
+
api = InstanceAPI()
|
|
217
|
+
|
|
218
|
+
# Build package from dictionary
|
|
219
|
+
data = {
|
|
220
|
+
"module_code": "F_01.01",
|
|
221
|
+
"parameters": {"refPeriod": "2024-12-31"},
|
|
222
|
+
"facts": [
|
|
223
|
+
{"table_code": "t001", "row_code": "r010", "column_code": "c010", "value": 1000000}
|
|
224
|
+
]
|
|
225
|
+
}
|
|
226
|
+
output_path = api.build_package_from_dict(data, "/tmp/output")
|
|
227
|
+
|
|
228
|
+
# Build package from JSON file
|
|
229
|
+
output_path = api.build_package_from_json("instance_data.json", "/tmp/output")
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
#### DPM Explorer - Introspection Queries
|
|
233
|
+
|
|
234
|
+
```python
|
|
235
|
+
from py_dpm.api import ExplorerQueryAPI
|
|
236
|
+
|
|
237
|
+
with ExplorerQueryAPI() as api:
|
|
238
|
+
# Find all properties using a specific item
|
|
239
|
+
properties = api.get_properties_using_item("EUR")
|
|
240
|
+
|
|
241
|
+
# Get module URL for documentation
|
|
242
|
+
url = api.get_module_url(module_code="F_01.01")
|
|
243
|
+
|
|
244
|
+
# Explore variable usage
|
|
245
|
+
tables = api.get_tables_using_variable(variable_code="mi123")
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
#### Hierarchical Queries
|
|
249
|
+
|
|
250
|
+
```python
|
|
251
|
+
from py_dpm.api import HierarchicalQueryAPI
|
|
252
|
+
|
|
253
|
+
with HierarchicalQueryAPI() as api:
|
|
254
|
+
# Get hierarchy for a domain
|
|
255
|
+
hierarchy = api.get_hierarchy(domain_code="DOM_001")
|
|
256
|
+
|
|
257
|
+
# Navigate parent-child relationships
|
|
258
|
+
children = api.get_children(item_code="PARENT_001")
|
|
259
|
+
|
|
260
|
+
# Get all ancestors
|
|
261
|
+
ancestors = api.get_ancestors(item_code="LEAF_001")
|
|
262
|
+
```
|
|
263
|
+
|
|
211
264
|
## Development
|
|
212
265
|
|
|
213
266
|
### Running Tests
|
|
@@ -41,7 +41,7 @@ Available packages:
|
|
|
41
41
|
- pydpm.api: Main APIs for migration, syntax, and semantic analysis
|
|
42
42
|
"""
|
|
43
43
|
|
|
44
|
-
__version__ = "0.2.
|
|
44
|
+
__version__ = "0.2.5rc1"
|
|
45
45
|
__author__ = "MeaningfulData S.L."
|
|
46
46
|
__email__ = "info@meaningfuldata.eu"
|
|
47
47
|
__license__ = "GPL-3.0-or-later"
|
|
@@ -369,6 +369,7 @@ class ASTGeneratorAPI:
|
|
|
369
369
|
precondition: Optional[str] = None,
|
|
370
370
|
release_id: Optional[int] = None,
|
|
371
371
|
output_path: Optional[Union[str, Path]] = None,
|
|
372
|
+
primary_module_vid: Optional[int] = None,
|
|
372
373
|
) -> Dict[str, Any]:
|
|
373
374
|
"""
|
|
374
375
|
Generate enriched, engine-ready AST with framework structure (Level 3).
|
|
@@ -381,13 +382,14 @@ class ASTGeneratorAPI:
|
|
|
381
382
|
- Everything from generate_complete_ast() PLUS:
|
|
382
383
|
- Framework structure: operations, variables, tables, preconditions
|
|
383
384
|
- Module metadata: version, release info, dates
|
|
384
|
-
- Dependency information
|
|
385
|
+
- Dependency information (including cross-module dependencies)
|
|
385
386
|
- Coordinates (x/y/z) added to data entries
|
|
386
387
|
|
|
387
388
|
**Typical use case:**
|
|
388
389
|
- Feeding AST to business rule execution engines
|
|
389
390
|
- Validation framework integration
|
|
390
391
|
- Production rule processing
|
|
392
|
+
- Module exports with cross-module dependency tracking
|
|
391
393
|
|
|
392
394
|
Args:
|
|
393
395
|
expression: DPM-XL expression string
|
|
@@ -399,6 +401,11 @@ class ASTGeneratorAPI:
|
|
|
399
401
|
If None, uses all available data (release-agnostic).
|
|
400
402
|
output_path: Optional path (string or Path) to save the enriched_ast as JSON file.
|
|
401
403
|
If provided, the enriched_ast will be automatically saved to this location.
|
|
404
|
+
primary_module_vid: Optional module version ID of the module being exported.
|
|
405
|
+
When provided, enables detection of cross-module dependencies - tables from
|
|
406
|
+
other modules will be identified and added to dependency_modules and
|
|
407
|
+
cross_instance_dependencies fields. If None, cross-module detection uses
|
|
408
|
+
the first table's module as the primary module.
|
|
402
409
|
|
|
403
410
|
Returns:
|
|
404
411
|
dict: {
|
|
@@ -416,14 +423,17 @@ class ASTGeneratorAPI:
|
|
|
416
423
|
... )
|
|
417
424
|
>>> # result['enriched_ast'] contains framework structure ready for engines
|
|
418
425
|
>>>
|
|
419
|
-
>>> #
|
|
426
|
+
>>> # For module exports with cross-module dependency tracking:
|
|
420
427
|
>>> result = generator.generate_enriched_ast(
|
|
421
|
-
... "{
|
|
428
|
+
... "{tC_26.00, r030, c010} * {tC_01.00, r0015, c0010}",
|
|
422
429
|
... dpm_version="4.2",
|
|
423
|
-
... operation_code="
|
|
424
|
-
...
|
|
430
|
+
... operation_code="v2814_m",
|
|
431
|
+
... primary_module_vid=123, # Module being exported
|
|
432
|
+
... release_id=42
|
|
425
433
|
... )
|
|
426
|
-
>>> #
|
|
434
|
+
>>> # result['enriched_ast']['dependency_modules'] contains external module info
|
|
435
|
+
>>> # result['enriched_ast']['dependency_information']['cross_instance_dependencies']
|
|
436
|
+
>>> # contains list of external module dependencies
|
|
427
437
|
"""
|
|
428
438
|
try:
|
|
429
439
|
# Generate complete AST first
|
|
@@ -447,6 +457,8 @@ class ASTGeneratorAPI:
|
|
|
447
457
|
dpm_version=dpm_version,
|
|
448
458
|
operation_code=operation_code,
|
|
449
459
|
precondition=precondition,
|
|
460
|
+
release_id=release_id,
|
|
461
|
+
primary_module_vid=primary_module_vid,
|
|
450
462
|
)
|
|
451
463
|
|
|
452
464
|
# Save to file if output_path is provided
|
|
@@ -723,11 +735,23 @@ class ASTGeneratorAPI:
|
|
|
723
735
|
dpm_version: Optional[str] = None,
|
|
724
736
|
operation_code: Optional[str] = None,
|
|
725
737
|
precondition: Optional[str] = None,
|
|
738
|
+
release_id: Optional[int] = None,
|
|
739
|
+
primary_module_vid: Optional[int] = None,
|
|
726
740
|
) -> Dict[str, Any]:
|
|
727
741
|
"""
|
|
728
742
|
Add framework structure (operations, variables, tables, preconditions) to complete AST.
|
|
729
743
|
|
|
730
744
|
This creates the engine-ready format with all metadata sections.
|
|
745
|
+
|
|
746
|
+
Args:
|
|
747
|
+
ast_dict: Complete AST dictionary
|
|
748
|
+
expression: Original DPM-XL expression
|
|
749
|
+
context: Context dict with table, rows, columns, sheets, default, interval
|
|
750
|
+
dpm_version: DPM version code (e.g., "4.2")
|
|
751
|
+
operation_code: Operation code (defaults to "default_code")
|
|
752
|
+
precondition: Precondition variable reference (e.g., {v_F_44_04})
|
|
753
|
+
release_id: Optional release ID to filter database lookups
|
|
754
|
+
primary_module_vid: Module VID being exported (to identify external dependencies)
|
|
731
755
|
"""
|
|
732
756
|
from py_dpm.dpm.utils import get_engine
|
|
733
757
|
import copy
|
|
@@ -795,15 +819,21 @@ class ASTGeneratorAPI:
|
|
|
795
819
|
engine=engine,
|
|
796
820
|
)
|
|
797
821
|
|
|
822
|
+
# Detect cross-module dependencies
|
|
823
|
+
dependency_modules, cross_instance_dependencies = self._detect_cross_module_dependencies(
|
|
824
|
+
expression=expression,
|
|
825
|
+
variables_by_table=variables_by_table,
|
|
826
|
+
primary_module_vid=primary_module_vid,
|
|
827
|
+
operation_code=operation_code,
|
|
828
|
+
release_id=release_id,
|
|
829
|
+
)
|
|
830
|
+
|
|
798
831
|
# Build dependency information
|
|
799
832
|
dependency_info = {
|
|
800
833
|
"intra_instance_validations": [operation_code],
|
|
801
|
-
"cross_instance_dependencies":
|
|
834
|
+
"cross_instance_dependencies": cross_instance_dependencies,
|
|
802
835
|
}
|
|
803
836
|
|
|
804
|
-
# Build dependency modules
|
|
805
|
-
dependency_modules = {}
|
|
806
|
-
|
|
807
837
|
# Build complete structure
|
|
808
838
|
namespace = "default_module"
|
|
809
839
|
|
|
@@ -1009,6 +1039,154 @@ class ASTGeneratorAPI:
|
|
|
1009
1039
|
extract_from_node(ast_dict)
|
|
1010
1040
|
return all_variables, variables_by_table
|
|
1011
1041
|
|
|
1042
|
+
def _detect_cross_module_dependencies(
|
|
1043
|
+
self,
|
|
1044
|
+
expression: str,
|
|
1045
|
+
variables_by_table: Dict[str, Dict[str, str]],
|
|
1046
|
+
primary_module_vid: Optional[int],
|
|
1047
|
+
operation_code: str,
|
|
1048
|
+
release_id: Optional[int] = None,
|
|
1049
|
+
) -> tuple:
|
|
1050
|
+
"""
|
|
1051
|
+
Detect cross-module dependencies for a single expression.
|
|
1052
|
+
|
|
1053
|
+
Uses existing OperationScopesAPI and ExplorerQuery to detect external module
|
|
1054
|
+
references in cross-module expressions.
|
|
1055
|
+
|
|
1056
|
+
Args:
|
|
1057
|
+
expression: DPM-XL expression
|
|
1058
|
+
variables_by_table: Variables by table code (from _extract_variables_from_ast)
|
|
1059
|
+
primary_module_vid: The module being exported (if known)
|
|
1060
|
+
operation_code: Current operation code
|
|
1061
|
+
release_id: Optional release ID for filtering
|
|
1062
|
+
|
|
1063
|
+
Returns:
|
|
1064
|
+
Tuple of (dependency_modules, cross_instance_dependencies)
|
|
1065
|
+
- dependency_modules: {uri: {tables: {...}, variables: {...}}}
|
|
1066
|
+
- cross_instance_dependencies: [{modules: [...], affected_operations: [...], ...}]
|
|
1067
|
+
"""
|
|
1068
|
+
from py_dpm.api.dpm_xl.operation_scopes import OperationScopesAPI
|
|
1069
|
+
from py_dpm.dpm.queries.explorer_queries import ExplorerQuery
|
|
1070
|
+
import logging
|
|
1071
|
+
|
|
1072
|
+
scopes_api = OperationScopesAPI(
|
|
1073
|
+
database_path=self.database_path,
|
|
1074
|
+
connection_url=self.connection_url
|
|
1075
|
+
)
|
|
1076
|
+
|
|
1077
|
+
try:
|
|
1078
|
+
# Get tables with module info
|
|
1079
|
+
tables_with_modules = scopes_api.get_tables_with_metadata_from_expression(
|
|
1080
|
+
expression=expression,
|
|
1081
|
+
release_id=release_id
|
|
1082
|
+
)
|
|
1083
|
+
|
|
1084
|
+
# Check if cross-module
|
|
1085
|
+
scope_result = scopes_api.calculate_scopes_from_expression(
|
|
1086
|
+
expression=expression,
|
|
1087
|
+
release_id=release_id,
|
|
1088
|
+
read_only=True
|
|
1089
|
+
)
|
|
1090
|
+
|
|
1091
|
+
if scope_result.has_error or not scope_result.is_cross_module:
|
|
1092
|
+
return {}, []
|
|
1093
|
+
|
|
1094
|
+
# Determine primary module from first table if not provided
|
|
1095
|
+
if primary_module_vid is None and tables_with_modules:
|
|
1096
|
+
primary_module_vid = tables_with_modules[0].get("module_vid")
|
|
1097
|
+
|
|
1098
|
+
# Group external tables by module
|
|
1099
|
+
external_modules = {}
|
|
1100
|
+
for table_info in tables_with_modules:
|
|
1101
|
+
module_vid = table_info.get("module_vid")
|
|
1102
|
+
if module_vid == primary_module_vid:
|
|
1103
|
+
continue # Skip primary module
|
|
1104
|
+
|
|
1105
|
+
module_code = table_info.get("module_code")
|
|
1106
|
+
if not module_code:
|
|
1107
|
+
continue
|
|
1108
|
+
|
|
1109
|
+
# Get module URI using existing ExplorerQuery
|
|
1110
|
+
try:
|
|
1111
|
+
module_uri = ExplorerQuery.get_module_url(
|
|
1112
|
+
scopes_api.session,
|
|
1113
|
+
module_code=module_code,
|
|
1114
|
+
release_id=release_id,
|
|
1115
|
+
)
|
|
1116
|
+
# Remove .json suffix if present (for consistency with expected format)
|
|
1117
|
+
if module_uri.endswith(".json"):
|
|
1118
|
+
module_uri = module_uri[:-5]
|
|
1119
|
+
except Exception:
|
|
1120
|
+
continue
|
|
1121
|
+
|
|
1122
|
+
if module_uri not in external_modules:
|
|
1123
|
+
external_modules[module_uri] = {
|
|
1124
|
+
"module_vid": module_vid,
|
|
1125
|
+
"tables": {},
|
|
1126
|
+
"variables": {},
|
|
1127
|
+
"from_date": None,
|
|
1128
|
+
"to_date": None
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
# Add table - get variables from variables_by_table
|
|
1132
|
+
table_code = table_info.get("code")
|
|
1133
|
+
if table_code:
|
|
1134
|
+
# Look up variables in variables_by_table (handles t prefix)
|
|
1135
|
+
table_variables = variables_by_table.get(table_code, {})
|
|
1136
|
+
if not table_variables:
|
|
1137
|
+
# Try with t prefix
|
|
1138
|
+
table_variables = variables_by_table.get(f"t{table_code}", {})
|
|
1139
|
+
external_modules[module_uri]["tables"][table_code] = {
|
|
1140
|
+
"variables": table_variables,
|
|
1141
|
+
"open_keys": {}
|
|
1142
|
+
}
|
|
1143
|
+
external_modules[module_uri]["variables"].update(table_variables)
|
|
1144
|
+
|
|
1145
|
+
# Get date info from scopes metadata
|
|
1146
|
+
scopes_metadata = scopes_api.get_scopes_with_metadata_from_expression(
|
|
1147
|
+
expression=expression,
|
|
1148
|
+
release_id=release_id
|
|
1149
|
+
)
|
|
1150
|
+
for scope_info in scopes_metadata:
|
|
1151
|
+
for module in scope_info.module_versions:
|
|
1152
|
+
mvid = module.get("module_vid")
|
|
1153
|
+
for uri, data in external_modules.items():
|
|
1154
|
+
if data["module_vid"] == mvid:
|
|
1155
|
+
data["from_date"] = module.get("from_reference_date")
|
|
1156
|
+
data["to_date"] = module.get("to_reference_date")
|
|
1157
|
+
|
|
1158
|
+
# Build output structures
|
|
1159
|
+
dependency_modules = {}
|
|
1160
|
+
cross_instance_dependencies = []
|
|
1161
|
+
|
|
1162
|
+
for uri, data in external_modules.items():
|
|
1163
|
+
# dependency_modules entry
|
|
1164
|
+
dependency_modules[uri] = {
|
|
1165
|
+
"tables": data["tables"],
|
|
1166
|
+
"variables": data["variables"]
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
# cross_instance_dependencies entry (one per external module)
|
|
1170
|
+
from_date = data["from_date"]
|
|
1171
|
+
to_date = data["to_date"]
|
|
1172
|
+
cross_instance_dependencies.append({
|
|
1173
|
+
"modules": [{
|
|
1174
|
+
"URI": uri,
|
|
1175
|
+
"ref_period": "T"
|
|
1176
|
+
}],
|
|
1177
|
+
"affected_operations": [operation_code],
|
|
1178
|
+
"from_reference_date": str(from_date) if from_date else "",
|
|
1179
|
+
"to_reference_date": str(to_date) if to_date else ""
|
|
1180
|
+
})
|
|
1181
|
+
|
|
1182
|
+
return dependency_modules, cross_instance_dependencies
|
|
1183
|
+
|
|
1184
|
+
except Exception as e:
|
|
1185
|
+
logging.warning(f"Failed to detect cross-module dependencies: {e}")
|
|
1186
|
+
return {}, []
|
|
1187
|
+
finally:
|
|
1188
|
+
scopes_api.close()
|
|
1189
|
+
|
|
1012
1190
|
def _add_coordinates_to_ast(
|
|
1013
1191
|
self, ast_dict: Dict[str, Any], context: Optional[Dict[str, Any]]
|
|
1014
1192
|
) -> Dict[str, Any]:
|
|
@@ -117,6 +117,7 @@ def generate_enriched_ast(
|
|
|
117
117
|
table_context: Optional[Dict[str, Any]] = None,
|
|
118
118
|
precondition: Optional[str] = None,
|
|
119
119
|
release_id: Optional[int] = None,
|
|
120
|
+
primary_module_vid: Optional[int] = None,
|
|
120
121
|
) -> Dict[str, Any]:
|
|
121
122
|
"""
|
|
122
123
|
Generate enriched, engine-ready AST from DPM-XL expression.
|
|
@@ -133,6 +134,8 @@ def generate_enriched_ast(
|
|
|
133
134
|
precondition: Optional precondition variable reference (e.g., {v_F_44_04})
|
|
134
135
|
release_id: Optional release ID to filter database lookups by specific release.
|
|
135
136
|
If None, uses all available data (release-agnostic).
|
|
137
|
+
primary_module_vid: Optional module version ID of the module being exported.
|
|
138
|
+
When provided, enables detection of cross-module dependencies.
|
|
136
139
|
|
|
137
140
|
Returns:
|
|
138
141
|
dict: {
|
|
@@ -153,6 +156,7 @@ def generate_enriched_ast(
|
|
|
153
156
|
table_context=table_context,
|
|
154
157
|
precondition=precondition,
|
|
155
158
|
release_id=release_id,
|
|
159
|
+
primary_module_vid=primary_module_vid,
|
|
156
160
|
)
|
|
157
161
|
|
|
158
162
|
|
|
@@ -165,6 +169,8 @@ def enrich_ast_with_metadata(
|
|
|
165
169
|
dpm_version: Optional[str] = None,
|
|
166
170
|
operation_code: Optional[str] = None,
|
|
167
171
|
precondition: Optional[str] = None,
|
|
172
|
+
release_id: Optional[int] = None,
|
|
173
|
+
primary_module_vid: Optional[int] = None,
|
|
168
174
|
) -> Dict[str, Any]:
|
|
169
175
|
"""
|
|
170
176
|
Add framework structure (operations, variables, tables, preconditions) to complete AST.
|
|
@@ -180,6 +186,8 @@ def enrich_ast_with_metadata(
|
|
|
180
186
|
dpm_version: DPM version code (e.g., "4.2")
|
|
181
187
|
operation_code: Operation code (defaults to "default_code")
|
|
182
188
|
precondition: Precondition variable reference (e.g., {v_F_44_04})
|
|
189
|
+
release_id: Optional release ID to filter database lookups
|
|
190
|
+
primary_module_vid: Optional module VID of the module being exported
|
|
183
191
|
|
|
184
192
|
Returns:
|
|
185
193
|
dict: Engine-ready AST with framework structure
|
|
@@ -196,4 +204,6 @@ def enrich_ast_with_metadata(
|
|
|
196
204
|
dpm_version=dpm_version,
|
|
197
205
|
operation_code=operation_code,
|
|
198
206
|
precondition=precondition,
|
|
207
|
+
release_id=release_id,
|
|
208
|
+
primary_module_vid=primary_module_vid,
|
|
199
209
|
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pydpm_xl
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.5rc1
|
|
4
4
|
Summary: Python library for DPM-XL data processing and analysis
|
|
5
5
|
Author-email: "MeaningfulData S.L." <info@meaningfuldata.eu>
|
|
6
6
|
License: GPL-3.0-or-later
|
|
@@ -241,6 +241,59 @@ migration_api.migrate_from_access(
|
|
|
241
241
|
)
|
|
242
242
|
```
|
|
243
243
|
|
|
244
|
+
#### XBRL-CSV Instance Generation
|
|
245
|
+
|
|
246
|
+
```python
|
|
247
|
+
from py_dpm.api import InstanceAPI
|
|
248
|
+
|
|
249
|
+
api = InstanceAPI()
|
|
250
|
+
|
|
251
|
+
# Build package from dictionary
|
|
252
|
+
data = {
|
|
253
|
+
"module_code": "F_01.01",
|
|
254
|
+
"parameters": {"refPeriod": "2024-12-31"},
|
|
255
|
+
"facts": [
|
|
256
|
+
{"table_code": "t001", "row_code": "r010", "column_code": "c010", "value": 1000000}
|
|
257
|
+
]
|
|
258
|
+
}
|
|
259
|
+
output_path = api.build_package_from_dict(data, "/tmp/output")
|
|
260
|
+
|
|
261
|
+
# Build package from JSON file
|
|
262
|
+
output_path = api.build_package_from_json("instance_data.json", "/tmp/output")
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
#### DPM Explorer - Introspection Queries
|
|
266
|
+
|
|
267
|
+
```python
|
|
268
|
+
from py_dpm.api import ExplorerQueryAPI
|
|
269
|
+
|
|
270
|
+
with ExplorerQueryAPI() as api:
|
|
271
|
+
# Find all properties using a specific item
|
|
272
|
+
properties = api.get_properties_using_item("EUR")
|
|
273
|
+
|
|
274
|
+
# Get module URL for documentation
|
|
275
|
+
url = api.get_module_url(module_code="F_01.01")
|
|
276
|
+
|
|
277
|
+
# Explore variable usage
|
|
278
|
+
tables = api.get_tables_using_variable(variable_code="mi123")
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
#### Hierarchical Queries
|
|
282
|
+
|
|
283
|
+
```python
|
|
284
|
+
from py_dpm.api import HierarchicalQueryAPI
|
|
285
|
+
|
|
286
|
+
with HierarchicalQueryAPI() as api:
|
|
287
|
+
# Get hierarchy for a domain
|
|
288
|
+
hierarchy = api.get_hierarchy(domain_code="DOM_001")
|
|
289
|
+
|
|
290
|
+
# Navigate parent-child relationships
|
|
291
|
+
children = api.get_children(item_code="PARENT_001")
|
|
292
|
+
|
|
293
|
+
# Get all ancestors
|
|
294
|
+
ancestors = api.get_ancestors(item_code="LEAF_001")
|
|
295
|
+
```
|
|
296
|
+
|
|
244
297
|
## Development
|
|
245
298
|
|
|
246
299
|
### Running Tests
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "pydpm_xl"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.5rc1"
|
|
4
4
|
description = "Python library for DPM-XL data processing and analysis"
|
|
5
5
|
authors = [
|
|
6
6
|
{name = "MeaningfulData S.L.", email = "info@meaningfuldata.eu"}
|
|
@@ -52,7 +52,7 @@ exclude = []
|
|
|
52
52
|
|
|
53
53
|
[tool.poetry]
|
|
54
54
|
name = "pydpm_xl"
|
|
55
|
-
version = "0.2.
|
|
55
|
+
version = "0.2.5rc1"
|
|
56
56
|
description = "Python library for DPM-XL data processing and analysis"
|
|
57
57
|
authors = ["MeaningfulData S.L. <info@meaningfuldata.eu>"]
|
|
58
58
|
readme = "README.md"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pydpm_xl-0.2.4 → pydpm_xl-0.2.5rc1}/py_dpm/dpm_xl/grammar/generated/dpm_xlParserListener.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|