pydpm_xl 0.1.10__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/AST/ASTConstructor.py +503 -0
- py_dpm/AST/ASTObjects.py +827 -0
- py_dpm/AST/ASTTemplate.py +101 -0
- py_dpm/AST/ASTVisitor.py +13 -0
- py_dpm/AST/MLGeneration.py +588 -0
- py_dpm/AST/ModuleAnalyzer.py +79 -0
- py_dpm/AST/ModuleDependencies.py +203 -0
- py_dpm/AST/WhereClauseChecker.py +12 -0
- py_dpm/AST/__init__.py +0 -0
- py_dpm/AST/check_operands.py +302 -0
- py_dpm/DataTypes/ScalarTypes.py +324 -0
- py_dpm/DataTypes/TimeClasses.py +370 -0
- py_dpm/DataTypes/TypePromotion.py +195 -0
- py_dpm/DataTypes/__init__.py +0 -0
- py_dpm/Exceptions/__init__.py +0 -0
- py_dpm/Exceptions/exceptions.py +84 -0
- py_dpm/Exceptions/messages.py +114 -0
- py_dpm/OperationScopes/OperationScopeService.py +247 -0
- py_dpm/OperationScopes/__init__.py +0 -0
- py_dpm/Operators/AggregateOperators.py +138 -0
- py_dpm/Operators/BooleanOperators.py +30 -0
- py_dpm/Operators/ClauseOperators.py +159 -0
- py_dpm/Operators/ComparisonOperators.py +69 -0
- py_dpm/Operators/ConditionalOperators.py +362 -0
- py_dpm/Operators/NumericOperators.py +101 -0
- py_dpm/Operators/Operator.py +388 -0
- py_dpm/Operators/StringOperators.py +27 -0
- py_dpm/Operators/TimeOperators.py +53 -0
- py_dpm/Operators/__init__.py +0 -0
- py_dpm/Utils/ValidationsGenerationUtils.py +429 -0
- py_dpm/Utils/__init__.py +0 -0
- py_dpm/Utils/operands_mapping.py +73 -0
- py_dpm/Utils/operator_mapping.py +89 -0
- py_dpm/Utils/tokens.py +172 -0
- py_dpm/Utils/utils.py +2 -0
- py_dpm/ValidationsGeneration/PropertiesConstraintsProcessor.py +190 -0
- py_dpm/ValidationsGeneration/Utils.py +364 -0
- py_dpm/ValidationsGeneration/VariantsProcessor.py +265 -0
- py_dpm/ValidationsGeneration/__init__.py +0 -0
- py_dpm/ValidationsGeneration/auxiliary_functions.py +98 -0
- py_dpm/__init__.py +61 -0
- py_dpm/api/__init__.py +140 -0
- py_dpm/api/ast_generator.py +438 -0
- py_dpm/api/complete_ast.py +241 -0
- py_dpm/api/data_dictionary_validation.py +577 -0
- py_dpm/api/migration.py +77 -0
- py_dpm/api/semantic.py +224 -0
- py_dpm/api/syntax.py +182 -0
- py_dpm/client.py +106 -0
- py_dpm/data_handlers.py +99 -0
- py_dpm/db_utils.py +117 -0
- py_dpm/grammar/__init__.py +0 -0
- py_dpm/grammar/dist/__init__.py +0 -0
- py_dpm/grammar/dist/dpm_xlLexer.interp +428 -0
- py_dpm/grammar/dist/dpm_xlLexer.py +804 -0
- py_dpm/grammar/dist/dpm_xlLexer.tokens +106 -0
- py_dpm/grammar/dist/dpm_xlParser.interp +249 -0
- py_dpm/grammar/dist/dpm_xlParser.py +5224 -0
- py_dpm/grammar/dist/dpm_xlParser.tokens +106 -0
- py_dpm/grammar/dist/dpm_xlParserListener.py +742 -0
- py_dpm/grammar/dist/dpm_xlParserVisitor.py +419 -0
- py_dpm/grammar/dist/listeners.py +10 -0
- py_dpm/grammar/dpm_xlLexer.g4 +435 -0
- py_dpm/grammar/dpm_xlParser.g4 +260 -0
- py_dpm/migration.py +282 -0
- py_dpm/models.py +2139 -0
- py_dpm/semantics/DAG/DAGAnalyzer.py +158 -0
- py_dpm/semantics/DAG/__init__.py +0 -0
- py_dpm/semantics/SemanticAnalyzer.py +320 -0
- py_dpm/semantics/Symbols.py +223 -0
- py_dpm/semantics/__init__.py +0 -0
- py_dpm/utils/__init__.py +0 -0
- py_dpm/utils/ast_serialization.py +481 -0
- py_dpm/views/data_types.sql +12 -0
- py_dpm/views/datapoints.sql +65 -0
- py_dpm/views/hierarchy_operand_reference.sql +11 -0
- py_dpm/views/hierarchy_preconditions.sql +13 -0
- py_dpm/views/hierarchy_variables.sql +26 -0
- py_dpm/views/hierarchy_variables_context.sql +14 -0
- py_dpm/views/key_components.sql +18 -0
- py_dpm/views/module_from_table.sql +11 -0
- py_dpm/views/open_keys.sql +13 -0
- py_dpm/views/operation_info.sql +27 -0
- py_dpm/views/operation_list.sql +18 -0
- py_dpm/views/operations_versions_from_module_version.sql +30 -0
- py_dpm/views/precondition_info.sql +17 -0
- py_dpm/views/report_type_operand_reference_info.sql +18 -0
- py_dpm/views/subcategory_info.sql +17 -0
- py_dpm/views/table_info.sql +19 -0
- pydpm_xl-0.1.10.dist-info/LICENSE +674 -0
- pydpm_xl-0.1.10.dist-info/METADATA +50 -0
- pydpm_xl-0.1.10.dist-info/RECORD +94 -0
- pydpm_xl-0.1.10.dist-info/WHEEL +4 -0
- pydpm_xl-0.1.10.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import pandas as pd
|
|
3
|
+
|
|
4
|
+
from py_dpm.Utils.ValidationsGenerationUtils import ValidationsGenerationUtils
|
|
5
|
+
from py_dpm.Utils.tokens import *
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def generate_context_structure(lst: list, group_df: pd.DataFrame):
|
|
9
|
+
"""
|
|
10
|
+
Method to generate the structure of the contexts of variables in order to generate the hierarchy validations
|
|
11
|
+
:param lst: list to store the structure of contexts
|
|
12
|
+
:param group_df: Dataframe with information about properties and items of variables
|
|
13
|
+
"""
|
|
14
|
+
group_df.set_index(CONTEXT_PROPERTY, inplace=True)
|
|
15
|
+
result = group_df.to_dict()[CONTEXT_ITEM]
|
|
16
|
+
result[VARIABLE_VID] = group_df[VARIABLE_VID].tolist()[0]
|
|
17
|
+
result[VARIABLE_PROPERTY_ID] = group_df[VARIABLE_PROPERTY_ID].tolist()[0]
|
|
18
|
+
|
|
19
|
+
lst.append(result)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def generate_subexpression(common_values, data, table, operator:str=None):
|
|
23
|
+
"""
|
|
24
|
+
Method to generate the subexpression of a hierarchy expression
|
|
25
|
+
:param common_values: dictionary with information about the common components and their values
|
|
26
|
+
:param data: variable datapoints
|
|
27
|
+
:param table: table code
|
|
28
|
+
"""
|
|
29
|
+
abs_value = True if operator and operator != '=' else False
|
|
30
|
+
if ROW_CODE in common_values:
|
|
31
|
+
rows = None
|
|
32
|
+
else:
|
|
33
|
+
rows = ROW + data[ROW_CODE].iloc[0] if data[ROW_CODE].iloc[0] else None
|
|
34
|
+
|
|
35
|
+
if COLUMN_CODE in common_values:
|
|
36
|
+
cols = None
|
|
37
|
+
else:
|
|
38
|
+
cols = COLUMN + data[COLUMN_CODE].iloc[0] if data[COLUMN_CODE].iloc[0] else None
|
|
39
|
+
|
|
40
|
+
if SHEET_CODE in common_values:
|
|
41
|
+
sheets = None
|
|
42
|
+
else:
|
|
43
|
+
sheets = SHEET + data[SHEET_CODE].iloc[0] if data[SHEET_CODE].iloc[0] else None
|
|
44
|
+
|
|
45
|
+
if abs_value:
|
|
46
|
+
expr = ValidationsGenerationUtils.write_cell(table, rows, cols, sheets)
|
|
47
|
+
return 'abs(' + expr + ')'
|
|
48
|
+
|
|
49
|
+
return ValidationsGenerationUtils.write_cell(table, rows, cols, sheets)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def get_common_components(left_data: pd.DataFrame, right_data: pd.DataFrame):
|
|
53
|
+
"""
|
|
54
|
+
Method to get the common components of expression operands
|
|
55
|
+
:param left_data: Dataframe corresponding to the data of the left operand
|
|
56
|
+
:param right_data: Dataframe corresponding to the data of the right side operands
|
|
57
|
+
"""
|
|
58
|
+
common_components = {}
|
|
59
|
+
for component in CELL_COMPONENTS:
|
|
60
|
+
left = left_data[component].dropna().tolist()
|
|
61
|
+
right = right_data[component].isnull().values.any()
|
|
62
|
+
if left and not right:
|
|
63
|
+
intersection_component = np.intersect1d(left_data[component], right_data[component])
|
|
64
|
+
if len(intersection_component):
|
|
65
|
+
if all(right_data[component].isin(intersection_component)):
|
|
66
|
+
common_components[component] = intersection_component
|
|
67
|
+
return common_components
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def group_hierarchy_right_data(right_data: pd.DataFrame, left_table: str, common_components: list, comparisson_operator:str=None):
|
|
71
|
+
"""
|
|
72
|
+
Method to group right side operands
|
|
73
|
+
:param right_data: Dataframe with the datapoints of the right side of expression
|
|
74
|
+
:param left_table: Table code of left operand
|
|
75
|
+
:param common_components: List with the common components of right and left operands
|
|
76
|
+
"""
|
|
77
|
+
right_table = right_data[TABLE_CODE].tolist()[0]
|
|
78
|
+
is_table_unique = left_table == right_table
|
|
79
|
+
right_operands_lst = []
|
|
80
|
+
right_table_cell = right_table if not is_table_unique else None
|
|
81
|
+
# Here we have to add the order of the items in the expression
|
|
82
|
+
order_dict = {}
|
|
83
|
+
for keys, group in right_data.groupby([ARITHMETIC_OPERATOR_SYMBOL, ITEM_ID]):
|
|
84
|
+
operand = generate_subexpression(common_components, group, right_table_cell,comparisson_operator)
|
|
85
|
+
operand = keys[0] + operand
|
|
86
|
+
if ORDER in group:
|
|
87
|
+
order_dict[group[ORDER].tolist()[0]] = operand
|
|
88
|
+
else:
|
|
89
|
+
order_dict[group[ORDER + '_x'].tolist()[0]] = operand
|
|
90
|
+
|
|
91
|
+
right_operands_lst = [order_dict[order] for order in sorted(order_dict)]
|
|
92
|
+
|
|
93
|
+
right_expression = ' '.join(right_operands_lst)
|
|
94
|
+
if DUPLICATE_VARIABLES not in right_data:
|
|
95
|
+
right_data[DUPLICATE_VARIABLES] = False
|
|
96
|
+
duplicate_variables = right_data[DUPLICATE_VARIABLES].any()
|
|
97
|
+
right_items = right_data[ITEM_ID].unique().tolist()
|
|
98
|
+
return [right_expression, right_table, duplicate_variables,right_items]
|
py_dpm/__init__.py
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""
|
|
2
|
+
PyDPM - Python Data Processing and Migration
|
|
3
|
+
============================================
|
|
4
|
+
|
|
5
|
+
A Python library for DPM-XL data processing, migration, and analysis.
|
|
6
|
+
|
|
7
|
+
This program is free software: you can redistribute it and/or modify
|
|
8
|
+
it under the terms of the GNU General Public License as published by
|
|
9
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
10
|
+
(at your option) any later version.
|
|
11
|
+
|
|
12
|
+
This program is distributed in the hope that it will be useful,
|
|
13
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
15
|
+
GNU General Public License for more details.
|
|
16
|
+
|
|
17
|
+
You should have received a copy of the GNU General Public License
|
|
18
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
19
|
+
|
|
20
|
+
Main Features:
|
|
21
|
+
- Database migration from Access to SQLite
|
|
22
|
+
- DPM-XL syntax validation and parsing
|
|
23
|
+
- DPM-XL semantic analysis
|
|
24
|
+
|
|
25
|
+
Quick Start:
|
|
26
|
+
>>> import pydpm
|
|
27
|
+
>>>
|
|
28
|
+
>>> # Migration
|
|
29
|
+
>>> migration = pydpm.api.MigrationAPI()
|
|
30
|
+
>>> engine = migration.migrate_access_to_sqlite("data.mdb", "output.db")
|
|
31
|
+
>>>
|
|
32
|
+
>>> # Syntax validation
|
|
33
|
+
>>> syntax = pydpm.api.SyntaxAPI()
|
|
34
|
+
>>> result = syntax.validate_expression("{tC_01.00, r0100, c0010}")
|
|
35
|
+
>>>
|
|
36
|
+
>>> # Semantic analysis
|
|
37
|
+
>>> semantic = pydpm.api.SemanticAPI()
|
|
38
|
+
>>> result = semantic.validate_expression("{tC_01.00, r0100, c0010}")
|
|
39
|
+
|
|
40
|
+
Available packages:
|
|
41
|
+
- pydpm.api: Main APIs for migration, syntax, and semantic analysis
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
__version__ = "0.1.10"
|
|
45
|
+
__author__ = "MeaningfulData S.L."
|
|
46
|
+
__email__ = "info@meaningfuldata.eu"
|
|
47
|
+
__license__ = "GPL-3.0-or-later"
|
|
48
|
+
|
|
49
|
+
# Import main API modules for convenient access
|
|
50
|
+
from py_dpm import api
|
|
51
|
+
|
|
52
|
+
# Import main classes for direct usage
|
|
53
|
+
from py_dpm.api import MigrationAPI, SyntaxAPI, SemanticAPI
|
|
54
|
+
|
|
55
|
+
__all__ = [
|
|
56
|
+
'api',
|
|
57
|
+
'MigrationAPI',
|
|
58
|
+
'SyntaxAPI',
|
|
59
|
+
'SemanticAPI',
|
|
60
|
+
'__version__'
|
|
61
|
+
]
|
py_dpm/api/__init__.py
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
from py_dpm.api.migration import MigrationAPI
|
|
2
|
+
from py_dpm.api.syntax import SyntaxAPI
|
|
3
|
+
from py_dpm.api.semantic import SemanticAPI
|
|
4
|
+
from py_dpm.api.ast_generator import ASTGenerator, parse_expression, validate_expression, parse_batch
|
|
5
|
+
from py_dpm.api.complete_ast import generate_complete_ast, generate_complete_batch
|
|
6
|
+
|
|
7
|
+
from antlr4 import CommonTokenStream, InputStream
|
|
8
|
+
|
|
9
|
+
from py_dpm.grammar.dist.dpm_xlLexer import dpm_xlLexer
|
|
10
|
+
from py_dpm.grammar.dist.dpm_xlParser import dpm_xlParser
|
|
11
|
+
from py_dpm.grammar.dist.listeners import DPMErrorListener
|
|
12
|
+
from py_dpm.AST.ASTConstructor import ASTVisitor
|
|
13
|
+
from py_dpm.AST.ASTObjects import TemporaryAssignment
|
|
14
|
+
from py_dpm.AST.MLGeneration import MLGeneration
|
|
15
|
+
from py_dpm.AST.ModuleAnalyzer import ModuleAnalyzer
|
|
16
|
+
from py_dpm.AST.ModuleDependencies import ModuleDependencies
|
|
17
|
+
from py_dpm.AST.check_operands import OperandsChecking
|
|
18
|
+
from py_dpm.semantics import SemanticAnalyzer
|
|
19
|
+
|
|
20
|
+
from py_dpm.ValidationsGeneration.VariantsProcessor import (
|
|
21
|
+
VariantsProcessor,
|
|
22
|
+
VariantsProcessorChecker,
|
|
23
|
+
)
|
|
24
|
+
from py_dpm.ValidationsGeneration.PropertiesConstraintsProcessor import (
|
|
25
|
+
PropertiesConstraintsChecker,
|
|
26
|
+
PropertiesConstraintsProcessor,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
from py_dpm.db_utils import get_session, get_engine
|
|
30
|
+
|
|
31
|
+
# Export the main API classes
|
|
32
|
+
__all__ = [
|
|
33
|
+
# Complete AST API (recommended - includes data fields)
|
|
34
|
+
'generate_complete_ast',
|
|
35
|
+
'generate_complete_batch',
|
|
36
|
+
|
|
37
|
+
# Simple AST API
|
|
38
|
+
'ASTGenerator',
|
|
39
|
+
'parse_expression',
|
|
40
|
+
'validate_expression',
|
|
41
|
+
'parse_batch',
|
|
42
|
+
|
|
43
|
+
# Advanced APIs
|
|
44
|
+
'MigrationAPI',
|
|
45
|
+
'SyntaxAPI',
|
|
46
|
+
'SemanticAPI',
|
|
47
|
+
'API' # Keep for backward compatibility
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class API:
|
|
52
|
+
error_listener = DPMErrorListener()
|
|
53
|
+
visitor = ASTVisitor()
|
|
54
|
+
|
|
55
|
+
def __init__(self):
|
|
56
|
+
get_engine()
|
|
57
|
+
self.session = get_session()
|
|
58
|
+
|
|
59
|
+
@classmethod
|
|
60
|
+
def lexer(cls, text: str):
|
|
61
|
+
"""
|
|
62
|
+
Extracts the tokens from the input expression
|
|
63
|
+
:param text: Expression to be analyzed
|
|
64
|
+
"""
|
|
65
|
+
lexer = dpm_xlLexer(InputStream(text))
|
|
66
|
+
lexer._listeners = [cls.error_listener]
|
|
67
|
+
cls.stream = CommonTokenStream(lexer)
|
|
68
|
+
|
|
69
|
+
@classmethod
|
|
70
|
+
def parser(cls):
|
|
71
|
+
"""
|
|
72
|
+
Parses the token from the lexer stream
|
|
73
|
+
"""
|
|
74
|
+
parser = dpm_xlParser(cls.stream)
|
|
75
|
+
parser._listeners = [cls.error_listener]
|
|
76
|
+
cls.CST = parser.start()
|
|
77
|
+
|
|
78
|
+
if parser._syntaxErrors == 0:
|
|
79
|
+
return True
|
|
80
|
+
|
|
81
|
+
@classmethod
|
|
82
|
+
def syntax_validation(cls, expression):
|
|
83
|
+
"""
|
|
84
|
+
Validates that the input expression is syntactically correct by applying the ANTLR lexer and parser
|
|
85
|
+
:param expression: Expression to be analyzed
|
|
86
|
+
"""
|
|
87
|
+
cls.lexer(expression)
|
|
88
|
+
cls.parser()
|
|
89
|
+
|
|
90
|
+
@classmethod
|
|
91
|
+
def create_ast(cls, expression):
|
|
92
|
+
"""
|
|
93
|
+
Generates the AST from the expression
|
|
94
|
+
:param expression: Expression to be analyzed
|
|
95
|
+
"""
|
|
96
|
+
cls.lexer(expression)
|
|
97
|
+
if cls.parser():
|
|
98
|
+
cls.visitor = ASTVisitor()
|
|
99
|
+
cls.AST = cls.visitor.visit(cls.CST)
|
|
100
|
+
|
|
101
|
+
def semantic_validation(self, expression):
|
|
102
|
+
self.create_ast(expression=expression)
|
|
103
|
+
|
|
104
|
+
oc = OperandsChecking(session=self.session, expression=expression, ast=self.AST, release_id=None)
|
|
105
|
+
semanticAnalysis = SemanticAnalyzer.InputAnalyzer(expression)
|
|
106
|
+
|
|
107
|
+
semanticAnalysis.data = oc.data
|
|
108
|
+
semanticAnalysis.key_components = oc.key_components
|
|
109
|
+
semanticAnalysis.open_keys = oc.open_keys
|
|
110
|
+
|
|
111
|
+
semanticAnalysis.preconditions = oc.preconditions
|
|
112
|
+
|
|
113
|
+
results = semanticAnalysis.visit(self.AST)
|
|
114
|
+
return results
|
|
115
|
+
|
|
116
|
+
def _check_property_constraints(self, ast):
|
|
117
|
+
"""
|
|
118
|
+
Method to check property constraints
|
|
119
|
+
:return: Boolean value indicating if the ast has property constraints
|
|
120
|
+
"""
|
|
121
|
+
pcc = PropertiesConstraintsChecker(ast=ast, session=self.session)
|
|
122
|
+
return pcc.is_property_constraint
|
|
123
|
+
|
|
124
|
+
def _check_property_constraints_from_expression(self, expression):
|
|
125
|
+
"""
|
|
126
|
+
Method to check property constraints
|
|
127
|
+
:return: Boolean value indicating if the ast has property constraints
|
|
128
|
+
"""
|
|
129
|
+
self.create_ast(expression=expression)
|
|
130
|
+
pcc = PropertiesConstraintsChecker(ast=self.AST, session=self.session)
|
|
131
|
+
return pcc.is_property_constraint
|
|
132
|
+
|
|
133
|
+
def _check_variants(self, expression):
|
|
134
|
+
"""
|
|
135
|
+
Method to check table groups
|
|
136
|
+
:return: Boolean value indicating if the ast has table groups
|
|
137
|
+
"""
|
|
138
|
+
self.create_ast(expression=expression)
|
|
139
|
+
tgc = VariantsProcessorChecker(ast=self.AST)
|
|
140
|
+
return tgc.is_variant
|