pydpm_xl 0.2.2__py3-none-any.whl → 0.2.3__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.
@@ -1244,7 +1244,7 @@ def calculate_scopes_from_expression(
1244
1244
  OperationScopeResult: Result containing existing and new scopes
1245
1245
 
1246
1246
  Example:
1247
- >>> from py_dpm.api.dpm.operation_scopes import calculate_scopes_from_expression
1247
+ >>> from py_dpm.api.dpm_xl.operation_scopes import calculate_scopes_from_expression
1248
1248
  >>> result = calculate_scopes_from_expression(
1249
1249
  ... "{tC_01.00, r0100, c0010}",
1250
1250
  ... release_id=4,
@@ -1275,7 +1275,7 @@ def get_existing_scopes(
1275
1275
  List[OperationScope]: List of existing scopes
1276
1276
 
1277
1277
  Example:
1278
- >>> from py_dpm.api.dpm.operation_scopes import get_existing_scopes
1278
+ >>> from py_dpm.api.dpm_xl.operation_scopes import get_existing_scopes
1279
1279
  >>> scopes = get_existing_scopes(operation_version_id=1, database_path="./database.db")
1280
1280
  """
1281
1281
  api = OperationScopesAPI(database_path=database_path, connection_url=connection_url)
py_dpm/cli/main.py CHANGED
@@ -8,7 +8,7 @@ import pandas as pd
8
8
 
9
9
  from py_dpm.api import SemanticAPI, SyntaxAPI
10
10
  from py_dpm.api.dpm_xl.semantic import SemanticValidationResult
11
- from py_dpm.api.dpm.operation_scopes import OperationScopesAPI
11
+ from py_dpm.api.dpm_xl.operation_scopes import OperationScopesAPI
12
12
  from py_dpm.dpm.migration import run_migration
13
13
  from py_dpm.dpm_xl.utils.tokens import (
14
14
  CODE,
py_dpm/dpm/models.py CHANGED
@@ -1293,7 +1293,11 @@ class Organisation(Base):
1293
1293
  name = Column("Name", String(200), unique=True)
1294
1294
  acronym = Column("Acronym", String(20))
1295
1295
  idprefix = Column("IDPrefix", Integer, unique=True)
1296
- rowguid = Column("RowGUID", String(36), ForeignKey("Concept.ConceptGUID"))
1296
+ rowguid = Column(
1297
+ "RowGUID",
1298
+ String(36),
1299
+ ForeignKey("Concept.ConceptGUID", use_alter=True, name="fk_org_concept"),
1300
+ )
1297
1301
 
1298
1302
  # Relationships
1299
1303
  concept = relationship("Concept", foreign_keys=[rowguid])
File without changes
@@ -0,0 +1,265 @@
1
+ from pathlib import Path
2
+ import tempfile
3
+ import zipfile
4
+ import json
5
+ from datetime import datetime
6
+
7
+ from py_dpm.api import ExplorerQueryAPI
8
+
9
+
10
+ class Fact:
11
+ def __init__(
12
+ self,
13
+ table_code: str,
14
+ column_code: str = None,
15
+ row_code: str = None,
16
+ sheet_code: str = None,
17
+ open_values: dict = None,
18
+ value: int = None,
19
+ date: str = None,
20
+ ):
21
+ self.table_code = table_code
22
+ self.column_code = column_code
23
+ self.row_code = row_code
24
+ self.sheet_code = sheet_code
25
+ self.open_values = open_values
26
+ self.value = value
27
+ self.variable_id = None
28
+
29
+ self.resolve_datapoint_id(date)
30
+
31
+ def __str__(self):
32
+ return f"Operand(table={self.table_code}, column={self.column_code}, row={self.row_code}, sheet={self.sheet_code}, open_values={self.open_values}, value={self.value})"
33
+
34
+ def resolve_datapoint_id(self, date: str) -> str:
35
+ variables = ExplorerQueryAPI().get_variable_from_cell_address(
36
+ table_code=self.table_code,
37
+ column_code=self.column_code,
38
+ sheet_code=self.sheet_code,
39
+ row_code=self.row_code,
40
+ date=date,
41
+ )
42
+
43
+ if len(variables) == 0:
44
+ raise ValueError(f"No mapping found for {self.operand_code}")
45
+ if len(variables) > 1:
46
+ raise ValueError(f"Multiple mappings found for {self.operand_code}")
47
+
48
+ self.variable_id = variables[0]["variable_id"]
49
+
50
+ @property
51
+ def operand_code(self):
52
+ code = f"{self.table_code}"
53
+
54
+ if self.row_code:
55
+ code += f", r{self.row_code}"
56
+ if self.column_code:
57
+ code += f", c{self.column_code}"
58
+ if self.sheet_code:
59
+ code += f", s{self.sheet_code}"
60
+
61
+ return code
62
+
63
+ @property
64
+ def variable_csv_row(self):
65
+ return f"dp{self.variable_id}"
66
+
67
+ @classmethod
68
+ def from_dict(cls, operand_data: dict):
69
+ operand = cls(
70
+ table_code=operand_data["table_code"],
71
+ column_code=(
72
+ operand_data["column_code"] if "column_code" in operand_data else None
73
+ ),
74
+ row_code=operand_data["row_code"] if "row_code" in operand_data else None,
75
+ sheet_code=(
76
+ operand_data["sheet_code"] if "sheet_code" in operand_data else None
77
+ ),
78
+ open_values=(
79
+ operand_data["open_values"] if "open_values" in operand_data else None
80
+ ),
81
+ value=operand_data["value"] if "value" in operand_data else None,
82
+ date=operand_data["date"] if "date" in operand_data else None,
83
+ )
84
+
85
+ return operand
86
+
87
+
88
+ class Instance:
89
+ PARAMETERS_DEFAULT = {
90
+ "entityID": "rs:DUMMYLEI123456789012.CON",
91
+ "baseCurrency": "iso4217:EUR",
92
+ "decimalsInteger": 0,
93
+ "decimalsMonetary": 2,
94
+ "decimalsPercentage": 8,
95
+ "decimalsDecimal": 2,
96
+ }
97
+
98
+ META_JSON = {
99
+ "documentInfo": {
100
+ "documentType": "http://xbrl.org/PWD/2020-12-09/report-package"
101
+ }
102
+ }
103
+
104
+ REPORTS_JSON = {
105
+ "documentInfo": {
106
+ "documentType": "https://xbrl.org/CR/2021-02-03/xbrl-csv",
107
+ "extends": [],
108
+ }
109
+ }
110
+
111
+ def __init__(self, module_url: str, operands: dict[Fact], parameters: dict = None):
112
+
113
+ self.module_url = module_url
114
+ self.operands = operands
115
+ self.parameters = parameters
116
+
117
+ @staticmethod
118
+ def _validate_dict_structure(instance_json: dict):
119
+ required_keys = {"module_code", "parameters", "operands"}
120
+ if required_keys != set(instance_json.keys()):
121
+ missing = required_keys - set(instance_json.keys())
122
+ raise ValueError(f"Missing required keys: {missing}")
123
+
124
+ if not isinstance(instance_json["module_code"], str):
125
+ raise TypeError("module_code must be a string")
126
+
127
+ if not isinstance(instance_json["parameters"], dict):
128
+ raise TypeError("parameters must be a dictionary")
129
+
130
+ if "refPeriod" not in instance_json["parameters"]:
131
+ raise ValueError("parameters must contain 'refPeriod'")
132
+
133
+ if not isinstance(instance_json["operands"], list):
134
+ raise TypeError("operands must be a list")
135
+
136
+ @classmethod
137
+ def from_json_file(cls, json_file: Path):
138
+ with open(json_file, "r") as f:
139
+ json_data = json.load(f)
140
+ instance = cls.from_dict(json_data)
141
+ return instance
142
+
143
+ @classmethod
144
+ def from_dict(cls, instance_json: dict):
145
+ cls._validate_dict_structure(instance_json)
146
+
147
+ url = ExplorerQueryAPI().get_module_url(
148
+ module_code=instance_json["module_code"],
149
+ date=instance_json["parameters"]["refPeriod"],
150
+ )
151
+
152
+ parameters = cls.PARAMETERS_DEFAULT.copy()
153
+ parameters.update(instance_json["parameters"])
154
+
155
+ operands = {}
156
+ for operand in instance_json["operands"]:
157
+ operand["date"] = parameters["refPeriod"]
158
+ operand = Fact.from_dict(operand)
159
+ if operand.table_code not in operands:
160
+ operands[operand.table_code] = []
161
+ operands[operand.table_code].append(operand)
162
+
163
+ instance = cls(
164
+ module_url=url,
165
+ operands=operands,
166
+ parameters=parameters,
167
+ )
168
+
169
+ return instance
170
+
171
+ @property
172
+ def folder_name(self):
173
+ module_code = self.module_url.split("/")[-1].split(".")[0]
174
+ entity_id = self.parameters["entityID"].split(":")[1]
175
+ ref_period = self.parameters["refPeriod"]
176
+ return f"{entity_id}_{ref_period}_{module_code}"
177
+
178
+ def build_package(self, output_folder: Path | str, file_prefix: str = None):
179
+ """Build the XBRL‑CSV package and write to *output_zip*."""
180
+
181
+ if isinstance(output_folder, str):
182
+ output_folder = Path(output_folder)
183
+
184
+ with tempfile.TemporaryDirectory() as tmpdir:
185
+ if file_prefix:
186
+ file_name_root = f"{file_prefix}_{self.folder_name}-{datetime.now().strftime('%Y%m%d%H%M%S')}"
187
+ else:
188
+ file_name_root = (
189
+ f"{self.folder_name}-{datetime.now().strftime('%Y%m%d%H%M%S')}"
190
+ )
191
+
192
+ tmp = Path(tmpdir)
193
+ root = tmp / file_name_root
194
+ root.mkdir()
195
+
196
+ # META‑INF/reportPackage.json
197
+ meta_dir = root / "META-INF"
198
+ meta_dir.mkdir(parents=True, exist_ok=True)
199
+ (meta_dir / "reportPackage.json").write_text(
200
+ json.dumps(self.META_JSON, indent=2)
201
+ )
202
+
203
+ # reports/
204
+ reports_dir = root / "reports"
205
+ reports_dir.mkdir()
206
+
207
+ # parameters.csv
208
+ param_lines = ["name,value"] + [
209
+ f"{k},{v}" for k, v in self.parameters.items()
210
+ ]
211
+ (reports_dir / "parameters.csv").write_text("\n".join(param_lines))
212
+
213
+ # FilingIndicators.csv
214
+ filing_indicators_lines = ["templateID,reported"]
215
+ for table in self.operands.keys():
216
+ if "." in table:
217
+ table = table.split(".")
218
+ table = table[0] + "." + table[1]
219
+ if f"{table},true" not in filing_indicators_lines:
220
+ filing_indicators_lines.append(f"{table},true")
221
+
222
+ (reports_dir / "FilingIndicators.csv").write_text(
223
+ "\n".join(filing_indicators_lines)
224
+ )
225
+
226
+ # report.json
227
+ reports_json_dict = self.REPORTS_JSON
228
+ reports_json_dict["documentInfo"]["extends"] = [self.module_url]
229
+ (reports_dir / "report.json").write_text(
230
+ json.dumps(reports_json_dict, indent=2)
231
+ )
232
+
233
+ # tables.csv
234
+ for table, operands in self.operands.items():
235
+ header = ["datapoint", "factValue"]
236
+ first_operand = operands[0]
237
+ if first_operand.open_values:
238
+ for key_dimension in first_operand.open_values.keys():
239
+ header.append(key_dimension)
240
+ header = ",".join(header)
241
+ lines = [header]
242
+ for operand in operands:
243
+ line = [operand.variable_csv_row, str(operand.value)]
244
+ if operand.open_values:
245
+ for key_dimension in operand.open_values.keys():
246
+ line.append(str(operand.open_values[key_dimension]))
247
+ line = ",".join(line)
248
+ lines.append(line)
249
+ (reports_dir / f"{table}.csv").write_text("\n".join(lines))
250
+
251
+ # Zip everything
252
+
253
+ with zipfile.ZipFile(
254
+ output_folder / (file_name_root + ".zip"),
255
+ "w",
256
+ compression=zipfile.ZIP_DEFLATED,
257
+ ) as zf:
258
+ for file_path in tmp.rglob("*"):
259
+ zf.write(file_path, file_path.relative_to(tmp))
260
+
261
+ output_path = output_folder / (file_name_root + ".zip")
262
+
263
+ print(f"Instance package written to: {output_path}")
264
+
265
+ return output_path
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pydpm_xl
3
- Version: 0.2.2
3
+ Version: 0.2.3
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
@@ -1,24 +1,23 @@
1
- py_dpm/__init__.py,sha256=f5HSKe3TKudiLPviLZ9Tc47ePZMOG3hNRwQS7-UqbB8,1858
2
- py_dpm/api/__init__.py,sha256=g0w2FOtETU1ZMuhGnbdgBmmTZwmWoBtBEDmkLR1t8sc,1824
3
- py_dpm/api/explorer.py,sha256=1dBc2ZidcAR5DfPEBRiyVk54Xv9u_G9mU66u7PA9Z-E,86
4
- py_dpm/api/semantic.py,sha256=QT0znXXa4ihqk4GmlmJQrdceCRy1o_3J17koW6rT5PE,1304
5
- py_dpm/api/dpm/__init__.py,sha256=FfyTxv29mxIrdw_y7QOdwwf8p4F9YsdiJ_H7HfL2gJo,528
1
+ py_dpm/__init__.py,sha256=AsLh4kv-iu9KOJD1YfgPwAP2PD-WGt2ZHfgNtpU25tw,1858
2
+ py_dpm/api/__init__.py,sha256=n79vAD7qatlYaXaI2N5IAD9m_8Fgb00EOdapVXZYTpI,1081
3
+ py_dpm/api/dpm/__init__.py,sha256=HQflgiRbs1eDi3KTadNhxS1NoaG6PGQDVMvFnuIEfXo,506
6
4
  py_dpm/api/dpm/data_dictionary.py,sha256=g0h6Yfschz7rboYly9LTbP-2SS5UxltU3AXu0v0tqrU,29457
7
5
  py_dpm/api/dpm/explorer.py,sha256=gW2RC59XwGl9YbEA-M4syHAs6MvqPWVw4wR_XdVFJ4Y,7888
8
6
  py_dpm/api/dpm/hierarchical_queries.py,sha256=X4AbpsWy3iItOTVIdVbtaTmRgOHPf0Y64Ig-_377uns,4054
7
+ py_dpm/api/dpm/instance.py,sha256=OSq-sEZ9bn3zNZFQV6vI3Ed0c20s5VzhDwYEhemZ4Dc,3804
9
8
  py_dpm/api/dpm/migration.py,sha256=9FT7zzz4QdUIRR6MD01gMODBtfq9HH_RF4hRgZqMcZc,2404
10
- py_dpm/api/dpm/operation_scopes.py,sha256=Vw9cdPiFM7uCsQyMY1AgT5XhHbxFcVeMwIcIXANuty4,48486
11
- py_dpm/api/dpm_xl/__init__.py,sha256=rjiIf9XDi2IGf0G_LiOWp29e5ANyoREfzl5Z5phJU_8,603
12
- py_dpm/api/dpm_xl/ast_generator.py,sha256=-wOgUEM1DMpyVwflkplLr7BOZFfjaDeXi-R_PLhsAxo,16160
13
- py_dpm/api/dpm_xl/complete_ast.py,sha256=XmXvE1zWLxL732FvyUpK4WffKwZSrw5yrzJI-QGOpFI,24341
9
+ py_dpm/api/dpm_xl/__init__.py,sha256=aRjaMAf_i2a33UAGTg-TF1BfO6miOOrbCydTUqAVvRU,910
10
+ py_dpm/api/dpm_xl/ast_generator.py,sha256=maVFlxBnBBZ6UYgVxbvewPFTbrTUqXfdKpmjB0ue0qc,42979
11
+ py_dpm/api/dpm_xl/complete_ast.py,sha256=sOaN9uSQo-Nns8twElVQHBg7MnaDSo_8EuZPSIqGdU0,7125
12
+ py_dpm/api/dpm_xl/operation_scopes.py,sha256=7AyOFAn9h012JPF9H5EtZ3sPzv6DOxkoinpj5ArzVOc,48492
14
13
  py_dpm/api/dpm_xl/semantic.py,sha256=Buo_t-sEv65r6RmYDy1xkCWGlU2pB2WQsDM-X-FX4cc,13629
15
14
  py_dpm/api/dpm_xl/syntax.py,sha256=Ke_kKd9ModoJ6siL3GPT9j9QClmopryCRcdDAT3M5-E,5954
16
15
  py_dpm/cli/__init__.py,sha256=UrfGHoQ0sZLjWfA0hoOoI4iTrn-bjr2f9Q8wDWd5nMo,133
17
- py_dpm/cli/main.py,sha256=Cu04d3hpv0UdcROdkvpNipNfiAkde59YCbPu0gKKCYA,22444
16
+ py_dpm/cli/main.py,sha256=v8ZgIjg4Zqf6UWNv2bydYlZV6KfDLnPACyqplNIJyNE,22447
18
17
  py_dpm/cli/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
18
  py_dpm/dpm/__init__.py,sha256=moagUo5Gxf24-Tl9FL_3n2wmVoD_oXtpC-YIGktH_rc,212
20
19
  py_dpm/dpm/migration.py,sha256=ivO_ObvKzVomTns6qfo-o5FuciWxkXbMd_gJ4_tu7Xc,14110
21
- py_dpm/dpm/models.py,sha256=mk0zLUpPHZn5DN2iIFsZ4dJUjgT5b4rroD_Q8W-o_ns,124751
20
+ py_dpm/dpm/models.py,sha256=d70oZ_3wXsKBRGM2TJRlsuDrHWSVkzetLAZeMIoImwc,124821
22
21
  py_dpm/dpm/utils.py,sha256=JNdAeOXjzQtye94jLPRHHGUMcvkGtTsjA5HFl92rWig,12783
23
22
  py_dpm/dpm/queries/base.py,sha256=EddMeJMwtp63DyyIFO7_XxGvdlCtJQWWpeOVImlKp4I,3648
24
23
  py_dpm/dpm/queries/basic_objects.py,sha256=JOXC235lMDfVENrFAhZAl7_nqePJ4RrwJhFF0WDyk0M,955
@@ -72,17 +71,14 @@ py_dpm/dpm_xl/utils/operator_mapping.py,sha256=BFgbVbSCSuutFNHJ4gtgm5VuG38pcl8Km
72
71
  py_dpm/dpm_xl/utils/scopes_calculator.py,sha256=nCx2mz_qtw61BESp38ORQYlF2uRT8SyUKawSX9OQljM,17832
73
72
  py_dpm/dpm_xl/utils/serialization.py,sha256=LPcmudFfzHeEjIIr57kr5BvGPZbxshOAAeUYOrLl7XM,32482
74
73
  py_dpm/dpm_xl/utils/tokens.py,sha256=VRIrPDi5ttwgH-on5Qt4-l4ho4bLA755-nfTalponcA,3496
75
- py_dpm/dpm_xl/validation/__init__.py,sha256=pzSTkLzUgK16XsV_maXn__erzs0blDBDRApuRWJwwMs,250
76
- py_dpm/dpm_xl/validation/generation_utils.py,sha256=2UvYorpLor-8PiEUTWFFVr-xEzKjxQzZrLXz3lvedPk,22655
77
- py_dpm/dpm_xl/validation/property_constraints.py,sha256=d95p2LxIGGmtGJBz0X14Z4LsS404fvO61VHeAJkN8V8,8272
78
- py_dpm/dpm_xl/validation/utils.py,sha256=2dV23OJfhDbLYTKkwTUVsXaQeO8zJUs9LbjDXcO5OO4,4196
79
- py_dpm/dpm_xl/validation/variants.py,sha256=LM_2U_sCf8rnlUyt6k4WQwSKj5eTJLt4Ba8q9VVi4kg,13824
80
74
  py_dpm/exceptions/__init__.py,sha256=yDERfUxYW7NUUEiTQChGpuJx6abr7IDe2XUpwVFPtvM,416
81
75
  py_dpm/exceptions/exceptions.py,sha256=6S3p-_i5O1oStvSMixt_JQG0xwTeSfBcdzrwL8yBy6Q,2413
82
76
  py_dpm/exceptions/messages.py,sha256=UwY6QIK8c-POcDCc9HYbZFGArCIYAanUGNh2LNKPx3U,7534
83
- pydpm_xl-0.2.2.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
84
- pydpm_xl-0.2.2.dist-info/METADATA,sha256=AG1po-jCkskQP5DFl49SMCF0y4QJHivL287Y3KLE3T0,7974
85
- pydpm_xl-0.2.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
86
- pydpm_xl-0.2.2.dist-info/entry_points.txt,sha256=6DDmBfw-AjtgvMHgq_I730i_LAAs_7-N3C95HD_bRr4,47
87
- pydpm_xl-0.2.2.dist-info/top_level.txt,sha256=495PvWZRoKl2NvbQU25W7dqWIBHqY-mFMPt83uxPpcM,7
88
- pydpm_xl-0.2.2.dist-info/RECORD,,
77
+ py_dpm/instance/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
78
+ py_dpm/instance/instance.py,sha256=ROUXOcd2lBV5fKdGHBAli6lnmL-YP-n02bUhtwARZhE,9119
79
+ pydpm_xl-0.2.3.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
80
+ pydpm_xl-0.2.3.dist-info/METADATA,sha256=cYguvXm7dSViN9mNqxZf9kKo9vlg-eP2lpctZu6oJDI,7974
81
+ pydpm_xl-0.2.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
82
+ pydpm_xl-0.2.3.dist-info/entry_points.txt,sha256=6DDmBfw-AjtgvMHgq_I730i_LAAs_7-N3C95HD_bRr4,47
83
+ pydpm_xl-0.2.3.dist-info/top_level.txt,sha256=495PvWZRoKl2NvbQU25W7dqWIBHqY-mFMPt83uxPpcM,7
84
+ pydpm_xl-0.2.3.dist-info/RECORD,,
py_dpm/api/explorer.py DELETED
@@ -1,4 +0,0 @@
1
- from py_dpm.api.dpm.explorer import ExplorerQueryAPI
2
-
3
- __all__ = ["ExplorerQueryAPI"]
4
-
py_dpm/api/semantic.py DELETED
@@ -1,56 +0,0 @@
1
- from typing import Optional
2
-
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
- )
9
-
10
-
11
- SemanticAPI = _SemanticAPI
12
-
13
-
14
- def validate_expression(
15
- expression: str,
16
- database_path: Optional[str] = None,
17
- connection_url: Optional[str] = None,
18
- release_id: Optional[int] = None,
19
- ) -> SemanticValidationResult:
20
- """
21
- Backwards-compatible wrapper for semantic validation.
22
-
23
- This delegates to the DPM-XL SemanticAPI implementation.
24
- """
25
- return _validate_expression(
26
- expression,
27
- database_path=database_path,
28
- connection_url=connection_url,
29
- release_id=release_id,
30
- )
31
-
32
-
33
- def is_valid_semantics(
34
- expression: str,
35
- database_path: Optional[str] = None,
36
- connection_url: Optional[str] = None,
37
- release_id: Optional[int] = None,
38
- ) -> bool:
39
- """
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
- )
48
-
49
-
50
- __all__ = [
51
- "SemanticAPI",
52
- "SemanticValidationResult",
53
- "validate_expression",
54
- "is_valid_semantics",
55
- ]
56
-
@@ -1,12 +0,0 @@
1
- """
2
- DPM-XL Validation
3
-
4
- Syntax and semantic validation for DPM-XL expressions.
5
- """
6
-
7
- from py_dpm.dpm_xl.validation.variants import *
8
- from py_dpm.dpm_xl.validation.property_constraints import *
9
-
10
- __all__ = [
11
- # Re-export will be handled by import *
12
- ]