pydpm_xl 0.2.0__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/dpm_xl/complete_ast.py +67 -189
- py_dpm/api/dpm_xl/semantic.py +4 -0
- py_dpm/cli/main.py +5 -3
- py_dpm/dpm_xl/utils/serialization.py +2 -3
- {pydpm_xl-0.2.0.dist-info → pydpm_xl-0.2.1.dist-info}/METADATA +1 -1
- {pydpm_xl-0.2.0.dist-info → pydpm_xl-0.2.1.dist-info}/RECORD +11 -11
- {pydpm_xl-0.2.0.dist-info → pydpm_xl-0.2.1.dist-info}/WHEEL +0 -0
- {pydpm_xl-0.2.0.dist-info → pydpm_xl-0.2.1.dist-info}/entry_points.txt +0 -0
- {pydpm_xl-0.2.0.dist-info → pydpm_xl-0.2.1.dist-info}/licenses/LICENSE +0 -0
- {pydpm_xl-0.2.0.dist-info → pydpm_xl-0.2.1.dist-info}/top_level.txt +0 -0
py_dpm/__init__.py
CHANGED
|
@@ -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.1"
|
|
45
45
|
__author__ = "MeaningfulData S.L."
|
|
46
46
|
__email__ = "info@meaningfuldata.eu"
|
|
47
47
|
__license__ = "GPL-3.0-or-later"
|
|
@@ -10,7 +10,7 @@ Also provides enrichment functionality to create engine-ready ASTs with framewor
|
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
12
|
from datetime import datetime
|
|
13
|
-
from typing import Dict, Any, Optional
|
|
13
|
+
from typing import Dict, Any, Any, Optional
|
|
14
14
|
from py_dpm.dpm_xl.utils.serialization import ASTToJSONVisitor
|
|
15
15
|
|
|
16
16
|
|
|
@@ -23,8 +23,8 @@ def generate_complete_ast(
|
|
|
23
23
|
"""
|
|
24
24
|
Generate complete AST with all data fields, exactly like json_scripts examples.
|
|
25
25
|
|
|
26
|
-
This function replicates the
|
|
27
|
-
|
|
26
|
+
This function replicates the process used to generate the reference JSON files,
|
|
27
|
+
using the new SemanticAPI to perform full semantic validation and operand checking.
|
|
28
28
|
|
|
29
29
|
Args:
|
|
30
30
|
expression: DPM-XL expression string
|
|
@@ -34,25 +34,18 @@ def generate_complete_ast(
|
|
|
34
34
|
If None, uses all available data (release-agnostic).
|
|
35
35
|
|
|
36
36
|
Returns:
|
|
37
|
-
dict:
|
|
38
|
-
|
|
39
|
-
'ast': dict, # Complete AST with data fields
|
|
40
|
-
'context': dict, # Context from WITH clause
|
|
41
|
-
'error': str, # Error if failed
|
|
42
|
-
'data_populated': bool # Whether data fields were populated
|
|
43
|
-
}
|
|
37
|
+
dict with keys:
|
|
38
|
+
success, ast, context, error, data_populated, semantic_result
|
|
44
39
|
"""
|
|
45
40
|
try:
|
|
46
41
|
# Import here to avoid circular imports
|
|
47
|
-
from py_dpm.api import
|
|
42
|
+
from py_dpm.api.dpm_xl.semantic import SemanticAPI
|
|
48
43
|
from py_dpm.dpm.utils import get_engine
|
|
49
44
|
|
|
50
|
-
# Initialize database connection if provided
|
|
45
|
+
# Initialize database connection if explicitly provided, to surface connection errors early
|
|
51
46
|
if connection_url or database_path:
|
|
52
47
|
try:
|
|
53
|
-
|
|
54
|
-
database_path=database_path, connection_url=connection_url
|
|
55
|
-
)
|
|
48
|
+
get_engine(database_path=database_path, connection_url=connection_url)
|
|
56
49
|
except Exception as e:
|
|
57
50
|
return {
|
|
58
51
|
"success": False,
|
|
@@ -62,194 +55,79 @@ def generate_complete_ast(
|
|
|
62
55
|
"data_populated": False,
|
|
63
56
|
}
|
|
64
57
|
|
|
65
|
-
# Use the
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
# Perform complete semantic validation with operand checking
|
|
70
|
-
# This should populate all data fields on VarID nodes
|
|
71
|
-
semantic_result = api.semantic_validation(expression, release_id=release_id)
|
|
72
|
-
|
|
73
|
-
# Force data population if semantic validation completed successfully
|
|
74
|
-
if hasattr(api, "AST") and api.AST and semantic_result:
|
|
75
|
-
try:
|
|
76
|
-
from py_dpm.dpm_xl.ast.operands import OperandsChecking
|
|
77
|
-
from py_dpm.dpm.utils import get_session
|
|
78
|
-
|
|
79
|
-
session = get_session()
|
|
80
|
-
|
|
81
|
-
# Extract the expression AST
|
|
82
|
-
def get_inner_ast(ast_obj):
|
|
83
|
-
if hasattr(ast_obj, "children") and len(ast_obj.children) > 0:
|
|
84
|
-
child = ast_obj.children[0]
|
|
85
|
-
if hasattr(child, "expression"):
|
|
86
|
-
return child.expression
|
|
87
|
-
else:
|
|
88
|
-
return child
|
|
89
|
-
return ast_obj
|
|
90
|
-
|
|
91
|
-
inner_ast = get_inner_ast(api.AST)
|
|
92
|
-
|
|
93
|
-
# Run operand checking to populate data fields
|
|
94
|
-
oc = OperandsChecking(
|
|
95
|
-
session=session,
|
|
96
|
-
expression=expression,
|
|
97
|
-
ast=inner_ast,
|
|
98
|
-
release_id=release_id,
|
|
99
|
-
)
|
|
100
|
-
|
|
101
|
-
# Apply the data from operand checker to VarID nodes
|
|
102
|
-
if hasattr(oc, "data") and oc.data is not None:
|
|
103
|
-
|
|
104
|
-
# Apply data to VarID nodes in the AST
|
|
105
|
-
def apply_data_to_varids(node):
|
|
106
|
-
if (
|
|
107
|
-
hasattr(node, "__class__")
|
|
108
|
-
and node.__class__.__name__ == "VarID"
|
|
109
|
-
):
|
|
110
|
-
table = getattr(node, "table", None)
|
|
111
|
-
rows = getattr(node, "rows", None)
|
|
112
|
-
cols = getattr(node, "cols", None)
|
|
113
|
-
|
|
114
|
-
if table and table in oc.operands:
|
|
115
|
-
# Filter data for this specific VarID
|
|
116
|
-
# Start with table filter
|
|
117
|
-
filter_mask = oc.data["table_code"] == table
|
|
118
|
-
|
|
119
|
-
# Add row filter only if rows is not None and doesn't contain wildcards
|
|
120
|
-
# IMPORTANT: If rows contains '*', include all rows (don't filter)
|
|
121
|
-
if rows is not None and "*" not in rows:
|
|
122
|
-
filter_mask = filter_mask & (
|
|
123
|
-
oc.data["row_code"].isin(rows)
|
|
124
|
-
)
|
|
125
|
-
|
|
126
|
-
# Add column filter only if cols is not None and doesn't contain wildcards
|
|
127
|
-
# IMPORTANT: If cols contains '*', include all columns (don't filter)
|
|
128
|
-
if cols is not None and "*" not in cols:
|
|
129
|
-
filter_mask = filter_mask & (
|
|
130
|
-
oc.data["column_code"].isin(cols)
|
|
131
|
-
)
|
|
132
|
-
|
|
133
|
-
filtered_data = oc.data[filter_mask]
|
|
134
|
-
|
|
135
|
-
if not filtered_data.empty:
|
|
136
|
-
# IMPORTANT: Remove wildcard entries (NULL column/row/sheet codes)
|
|
137
|
-
# when specific entries exist for the same dimension
|
|
138
|
-
# The database contains both wildcard entries (column_code=NULL for c*)
|
|
139
|
-
# and specific entries (column_code='0010'). When we query with wildcards,
|
|
140
|
-
# we want only the specific entries.
|
|
141
|
-
|
|
142
|
-
# Remove rows where column_code is NULL if there are non-NULL column_code entries
|
|
143
|
-
if filtered_data["column_code"].notna().any():
|
|
144
|
-
filtered_data = filtered_data[
|
|
145
|
-
filtered_data["column_code"].notna()
|
|
146
|
-
]
|
|
147
|
-
|
|
148
|
-
# Remove rows where row_code is NULL if there are non-NULL row_code entries
|
|
149
|
-
if filtered_data["row_code"].notna().any():
|
|
150
|
-
filtered_data = filtered_data[
|
|
151
|
-
filtered_data["row_code"].notna()
|
|
152
|
-
]
|
|
153
|
-
|
|
154
|
-
# Remove rows where sheet_code is NULL if there are non-NULL sheet_code entries
|
|
155
|
-
if filtered_data["sheet_code"].notna().any():
|
|
156
|
-
filtered_data = filtered_data[
|
|
157
|
-
filtered_data["sheet_code"].notna()
|
|
158
|
-
]
|
|
159
|
-
|
|
160
|
-
# IMPORTANT: After filtering, remove any remaining duplicates
|
|
161
|
-
# based on (row_code, column_code, sheet_code) combination
|
|
162
|
-
filtered_data = filtered_data.drop_duplicates(
|
|
163
|
-
subset=[
|
|
164
|
-
"row_code",
|
|
165
|
-
"column_code",
|
|
166
|
-
"sheet_code",
|
|
167
|
-
],
|
|
168
|
-
keep="first",
|
|
169
|
-
)
|
|
170
|
-
|
|
171
|
-
# Set the data attribute on the VarID node
|
|
172
|
-
if not filtered_data.empty:
|
|
173
|
-
node.data = filtered_data
|
|
174
|
-
|
|
175
|
-
# Recursively apply to child nodes
|
|
176
|
-
for attr_name in [
|
|
177
|
-
"children",
|
|
178
|
-
"left",
|
|
179
|
-
"right",
|
|
180
|
-
"operand",
|
|
181
|
-
"operands",
|
|
182
|
-
"expression",
|
|
183
|
-
"condition",
|
|
184
|
-
"then_expr",
|
|
185
|
-
"else_expr",
|
|
186
|
-
]:
|
|
187
|
-
if hasattr(node, attr_name):
|
|
188
|
-
attr_value = getattr(node, attr_name)
|
|
189
|
-
if isinstance(attr_value, list):
|
|
190
|
-
for item in attr_value:
|
|
191
|
-
if hasattr(item, "__class__"):
|
|
192
|
-
apply_data_to_varids(item)
|
|
193
|
-
elif attr_value and hasattr(attr_value, "__class__"):
|
|
194
|
-
apply_data_to_varids(attr_value)
|
|
195
|
-
|
|
196
|
-
# Apply data to all VarID nodes in the AST
|
|
197
|
-
apply_data_to_varids(inner_ast)
|
|
58
|
+
# Use the modern SemanticAPI which performs full semantic validation and operand checking
|
|
59
|
+
semantic_api = SemanticAPI(
|
|
60
|
+
database_path=database_path, connection_url=connection_url
|
|
61
|
+
)
|
|
198
62
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
if hasattr(api, "AST") and api.AST is not None:
|
|
204
|
-
# Extract components exactly like batch_validator does
|
|
205
|
-
def extract_components(ast_obj):
|
|
206
|
-
if hasattr(ast_obj, "children") and len(ast_obj.children) > 0:
|
|
207
|
-
child = ast_obj.children[0]
|
|
208
|
-
if hasattr(child, "expression"):
|
|
209
|
-
return child.expression, child.partial_selection
|
|
210
|
-
else:
|
|
211
|
-
return child, None
|
|
212
|
-
return ast_obj, None
|
|
213
|
-
|
|
214
|
-
actual_ast, context = extract_components(api.AST)
|
|
215
|
-
|
|
216
|
-
# Convert to JSON exactly like batch_validator does
|
|
217
|
-
visitor = ASTToJSONVisitor(context)
|
|
218
|
-
ast_dict = visitor.visit(actual_ast)
|
|
219
|
-
|
|
220
|
-
# Check if data fields were populated
|
|
221
|
-
data_populated = _check_data_fields_populated(ast_dict)
|
|
222
|
-
|
|
223
|
-
# Serialize context
|
|
224
|
-
context_dict = None
|
|
225
|
-
if context:
|
|
226
|
-
context_dict = {
|
|
227
|
-
"table": getattr(context, "table", None),
|
|
228
|
-
"rows": getattr(context, "rows", None),
|
|
229
|
-
"columns": getattr(context, "cols", None),
|
|
230
|
-
"sheets": getattr(context, "sheets", None),
|
|
231
|
-
"default": getattr(context, "default", None),
|
|
232
|
-
"interval": getattr(context, "interval", None),
|
|
233
|
-
}
|
|
63
|
+
semantic_result = semantic_api.validate_expression(
|
|
64
|
+
expression, release_id=release_id
|
|
65
|
+
)
|
|
234
66
|
|
|
67
|
+
# If semantic validation failed, return structured error
|
|
68
|
+
if not semantic_result.is_valid:
|
|
235
69
|
return {
|
|
236
|
-
"success":
|
|
237
|
-
"ast":
|
|
238
|
-
"context":
|
|
239
|
-
"error":
|
|
240
|
-
"data_populated":
|
|
70
|
+
"success": False,
|
|
71
|
+
"ast": None,
|
|
72
|
+
"context": None,
|
|
73
|
+
"error": semantic_result.error_message,
|
|
74
|
+
"data_populated": False,
|
|
241
75
|
"semantic_result": semantic_result,
|
|
242
76
|
}
|
|
243
77
|
|
|
244
|
-
|
|
78
|
+
ast_root = getattr(semantic_api, "ast", None)
|
|
79
|
+
|
|
80
|
+
if ast_root is None:
|
|
245
81
|
return {
|
|
246
82
|
"success": False,
|
|
247
83
|
"ast": None,
|
|
248
84
|
"context": None,
|
|
249
85
|
"error": "Semantic validation did not generate AST",
|
|
250
86
|
"data_populated": False,
|
|
87
|
+
"semantic_result": semantic_result,
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
# Extract components exactly like batch_validator does
|
|
91
|
+
def extract_components(ast_obj):
|
|
92
|
+
if hasattr(ast_obj, "children") and len(ast_obj.children) > 0:
|
|
93
|
+
child = ast_obj.children[0]
|
|
94
|
+
if hasattr(child, "expression"):
|
|
95
|
+
return child.expression, child.partial_selection
|
|
96
|
+
else:
|
|
97
|
+
return child, None
|
|
98
|
+
return ast_obj, None
|
|
99
|
+
|
|
100
|
+
actual_ast, context = extract_components(ast_root)
|
|
101
|
+
|
|
102
|
+
# Convert to JSON using the ASTToJSONVisitor, which uses VarID.data populated
|
|
103
|
+
# during semantic validation / operand checking.
|
|
104
|
+
visitor = ASTToJSONVisitor(context)
|
|
105
|
+
ast_dict = visitor.visit(actual_ast)
|
|
106
|
+
|
|
107
|
+
# Check if data fields were populated
|
|
108
|
+
data_populated = _check_data_fields_populated(ast_dict)
|
|
109
|
+
|
|
110
|
+
# Serialize context
|
|
111
|
+
context_dict = None
|
|
112
|
+
if context:
|
|
113
|
+
context_dict = {
|
|
114
|
+
"table": getattr(context, "table", None),
|
|
115
|
+
"rows": getattr(context, "rows", None),
|
|
116
|
+
"columns": getattr(context, "cols", None),
|
|
117
|
+
"sheets": getattr(context, "sheets", None),
|
|
118
|
+
"default": getattr(context, "default", None),
|
|
119
|
+
"interval": getattr(context, "interval", None),
|
|
251
120
|
}
|
|
252
121
|
|
|
122
|
+
return {
|
|
123
|
+
"success": True,
|
|
124
|
+
"ast": ast_dict,
|
|
125
|
+
"context": context_dict,
|
|
126
|
+
"error": None,
|
|
127
|
+
"data_populated": data_populated,
|
|
128
|
+
"semantic_result": semantic_result,
|
|
129
|
+
}
|
|
130
|
+
|
|
253
131
|
except Exception as e:
|
|
254
132
|
return {
|
|
255
133
|
"success": False,
|
py_dpm/api/dpm_xl/semantic.py
CHANGED
|
@@ -56,6 +56,8 @@ class SemanticAPI:
|
|
|
56
56
|
"""
|
|
57
57
|
self.database_path = database_path
|
|
58
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
|
|
59
61
|
|
|
60
62
|
if connection_url:
|
|
61
63
|
# Create isolated engine and session for the provided connection URL
|
|
@@ -141,6 +143,8 @@ class SemanticAPI:
|
|
|
141
143
|
|
|
142
144
|
# Generate AST
|
|
143
145
|
ast = self.visitor.visit(parse_tree)
|
|
146
|
+
# Expose AST on the instance for downstream consumers
|
|
147
|
+
self.ast = ast
|
|
144
148
|
|
|
145
149
|
# Perform semantic analysis
|
|
146
150
|
oc = OperandsChecking(
|
py_dpm/cli/main.py
CHANGED
|
@@ -6,7 +6,7 @@ import os
|
|
|
6
6
|
import sys
|
|
7
7
|
import pandas as pd
|
|
8
8
|
|
|
9
|
-
from py_dpm.api import SemanticAPI
|
|
9
|
+
from py_dpm.api import SemanticAPI, SyntaxAPI
|
|
10
10
|
from py_dpm.api.dpm_xl.semantic import SemanticValidationResult
|
|
11
11
|
from py_dpm.api.dpm.operation_scopes import OperationScopesAPI
|
|
12
12
|
from py_dpm.dpm.migration import run_migration
|
|
@@ -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)
|
|
@@ -542,10 +542,9 @@ class ASTToJSONVisitor(NodeVisitor):
|
|
|
542
542
|
|
|
543
543
|
return result
|
|
544
544
|
|
|
545
|
-
|
|
546
545
|
# Original serialization functions (kept for backward compatibility)
|
|
547
546
|
import json
|
|
548
|
-
from py_dpm.dpm_xl.ast import nodes
|
|
547
|
+
from py_dpm.dpm_xl.ast import nodes as ASTObjects
|
|
549
548
|
|
|
550
549
|
|
|
551
550
|
def expand_with_expression(node):
|
|
@@ -759,4 +758,4 @@ def ast_from_json_string(json_str):
|
|
|
759
758
|
AST object instance
|
|
760
759
|
"""
|
|
761
760
|
data = json.loads(json_str)
|
|
762
|
-
return deserialize_ast(data)
|
|
761
|
+
return deserialize_ast(data)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
py_dpm/__init__.py,sha256=
|
|
1
|
+
py_dpm/__init__.py,sha256=SfCnl2zNEvxu7CWIE2i9T-IlPrYBwynS4qSBFRloO2E,1858
|
|
2
2
|
py_dpm/api/__init__.py,sha256=g0w2FOtETU1ZMuhGnbdgBmmTZwmWoBtBEDmkLR1t8sc,1824
|
|
3
3
|
py_dpm/api/explorer.py,sha256=1dBc2ZidcAR5DfPEBRiyVk54Xv9u_G9mU66u7PA9Z-E,86
|
|
4
4
|
py_dpm/api/semantic.py,sha256=QT0znXXa4ihqk4GmlmJQrdceCRy1o_3J17koW6rT5PE,1304
|
|
@@ -10,11 +10,11 @@ py_dpm/api/dpm/migration.py,sha256=9FT7zzz4QdUIRR6MD01gMODBtfq9HH_RF4hRgZqMcZc,2
|
|
|
10
10
|
py_dpm/api/dpm/operation_scopes.py,sha256=Vw9cdPiFM7uCsQyMY1AgT5XhHbxFcVeMwIcIXANuty4,48486
|
|
11
11
|
py_dpm/api/dpm_xl/__init__.py,sha256=rjiIf9XDi2IGf0G_LiOWp29e5ANyoREfzl5Z5phJU_8,603
|
|
12
12
|
py_dpm/api/dpm_xl/ast_generator.py,sha256=-wOgUEM1DMpyVwflkplLr7BOZFfjaDeXi-R_PLhsAxo,16160
|
|
13
|
-
py_dpm/api/dpm_xl/complete_ast.py,sha256=
|
|
14
|
-
py_dpm/api/dpm_xl/semantic.py,sha256=
|
|
13
|
+
py_dpm/api/dpm_xl/complete_ast.py,sha256=XmXvE1zWLxL732FvyUpK4WffKwZSrw5yrzJI-QGOpFI,24341
|
|
14
|
+
py_dpm/api/dpm_xl/semantic.py,sha256=Buo_t-sEv65r6RmYDy1xkCWGlU2pB2WQsDM-X-FX4cc,13629
|
|
15
15
|
py_dpm/api/dpm_xl/syntax.py,sha256=Ke_kKd9ModoJ6siL3GPT9j9QClmopryCRcdDAT3M5-E,5954
|
|
16
16
|
py_dpm/cli/__init__.py,sha256=UrfGHoQ0sZLjWfA0hoOoI4iTrn-bjr2f9Q8wDWd5nMo,133
|
|
17
|
-
py_dpm/cli/main.py,sha256=
|
|
17
|
+
py_dpm/cli/main.py,sha256=Cu04d3hpv0UdcROdkvpNipNfiAkde59YCbPu0gKKCYA,22444
|
|
18
18
|
py_dpm/cli/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
19
|
py_dpm/dpm/__init__.py,sha256=moagUo5Gxf24-Tl9FL_3n2wmVoD_oXtpC-YIGktH_rc,212
|
|
20
20
|
py_dpm/dpm/migration.py,sha256=ivO_ObvKzVomTns6qfo-o5FuciWxkXbMd_gJ4_tu7Xc,14110
|
|
@@ -70,7 +70,7 @@ py_dpm/dpm_xl/utils/data_handlers.py,sha256=a0E-IaP_-CDKLcj-Gt2ggAziKIOUiwnT2D9I
|
|
|
70
70
|
py_dpm/dpm_xl/utils/operands_mapping.py,sha256=LG0hPlUuTM2X2uWOtiD6HkmNeDEJkWJ8gV-Fxej_8QM,2241
|
|
71
71
|
py_dpm/dpm_xl/utils/operator_mapping.py,sha256=BFgbVbSCSuutFNHJ4gtgm5VuG38pcl8Kmfi-sefg6JU,1913
|
|
72
72
|
py_dpm/dpm_xl/utils/scopes_calculator.py,sha256=nCx2mz_qtw61BESp38ORQYlF2uRT8SyUKawSX9OQljM,17832
|
|
73
|
-
py_dpm/dpm_xl/utils/serialization.py,sha256=
|
|
73
|
+
py_dpm/dpm_xl/utils/serialization.py,sha256=LPcmudFfzHeEjIIr57kr5BvGPZbxshOAAeUYOrLl7XM,32482
|
|
74
74
|
py_dpm/dpm_xl/utils/tokens.py,sha256=VRIrPDi5ttwgH-on5Qt4-l4ho4bLA755-nfTalponcA,3496
|
|
75
75
|
py_dpm/dpm_xl/validation/__init__.py,sha256=pzSTkLzUgK16XsV_maXn__erzs0blDBDRApuRWJwwMs,250
|
|
76
76
|
py_dpm/dpm_xl/validation/generation_utils.py,sha256=2UvYorpLor-8PiEUTWFFVr-xEzKjxQzZrLXz3lvedPk,22655
|
|
@@ -80,9 +80,9 @@ py_dpm/dpm_xl/validation/variants.py,sha256=LM_2U_sCf8rnlUyt6k4WQwSKj5eTJLt4Ba8q
|
|
|
80
80
|
py_dpm/exceptions/__init__.py,sha256=yDERfUxYW7NUUEiTQChGpuJx6abr7IDe2XUpwVFPtvM,416
|
|
81
81
|
py_dpm/exceptions/exceptions.py,sha256=6S3p-_i5O1oStvSMixt_JQG0xwTeSfBcdzrwL8yBy6Q,2413
|
|
82
82
|
py_dpm/exceptions/messages.py,sha256=UwY6QIK8c-POcDCc9HYbZFGArCIYAanUGNh2LNKPx3U,7534
|
|
83
|
-
pydpm_xl-0.2.
|
|
84
|
-
pydpm_xl-0.2.
|
|
85
|
-
pydpm_xl-0.2.
|
|
86
|
-
pydpm_xl-0.2.
|
|
87
|
-
pydpm_xl-0.2.
|
|
88
|
-
pydpm_xl-0.2.
|
|
83
|
+
pydpm_xl-0.2.1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
84
|
+
pydpm_xl-0.2.1.dist-info/METADATA,sha256=rUtdLeAJq0dbweFf9b5YXGC2wTPSU73pGuCgUyaek4Y,7974
|
|
85
|
+
pydpm_xl-0.2.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
86
|
+
pydpm_xl-0.2.1.dist-info/entry_points.txt,sha256=6DDmBfw-AjtgvMHgq_I730i_LAAs_7-N3C95HD_bRr4,47
|
|
87
|
+
pydpm_xl-0.2.1.dist-info/top_level.txt,sha256=495PvWZRoKl2NvbQU25W7dqWIBHqY-mFMPt83uxPpcM,7
|
|
88
|
+
pydpm_xl-0.2.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|