pydpm_xl 0.2.5rc3__py3-none-any.whl → 0.2.6__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.
@@ -239,6 +239,7 @@ class ExplorerQuery:
239
239
  row_code: Optional[str] = None,
240
240
  column_code: Optional[str] = None,
241
241
  sheet_code: Optional[str] = None,
242
+ module_code: Optional[str] = None,
242
243
  release_id: Optional[int] = None,
243
244
  release_code: Optional[str] = None,
244
245
  date: Optional[str] = None,
@@ -326,6 +327,8 @@ class ExplorerQuery:
326
327
  q = q.filter(hv_col.code == column_code)
327
328
  if sheet_code is not None:
328
329
  q = q.filter(hv_sheet.code == sheet_code)
330
+ if module_code is not None:
331
+ q = q.filter(ModuleVersion.code == module_code)
329
332
 
330
333
  # Apply standard release/date filtering on ModuleVersion.
331
334
  # For this method, if no release argument is provided, we default
@@ -350,3 +353,119 @@ class ExplorerQuery:
350
353
 
351
354
  results = q.all()
352
355
  return [dict(row._mapping) for row in results]
356
+
357
+ @staticmethod
358
+ def get_variable_by_code(
359
+ session: Session,
360
+ variable_code: str,
361
+ release_id: Optional[int] = None,
362
+ release_code: Optional[str] = None,
363
+ ) -> Optional[Dict[str, Any]]:
364
+ """
365
+ Get variable_id and variable_vid for a given variable code.
366
+
367
+ This is useful for resolving precondition variable references like {v_C_01.00}
368
+ where the variable code is the table code (e.g., "C_01.00").
369
+
370
+ Args:
371
+ session: SQLAlchemy session
372
+ variable_code: The variable code to look up (e.g., "C_01.00")
373
+ release_id: Optional release ID to filter by
374
+ release_code: Optional release code to filter by
375
+
376
+ Returns:
377
+ Dict with variable_id and variable_vid if found, None otherwise.
378
+ If multiple versions exist, returns the one matching the release filter
379
+ or the latest active version if no filter is provided.
380
+ """
381
+ if release_id is not None and release_code is not None:
382
+ raise ValueError(
383
+ "Specify a maximum of one of release_id or release_code."
384
+ )
385
+
386
+ q = (
387
+ session.query(
388
+ VariableVersion.variableid.label("variable_id"),
389
+ VariableVersion.variablevid.label("variable_vid"),
390
+ VariableVersion.code.label("variable_code"),
391
+ VariableVersion.name.label("variable_name"),
392
+ )
393
+ .select_from(VariableVersion)
394
+ .filter(VariableVersion.code == variable_code)
395
+ )
396
+
397
+ # Apply release filtering
398
+ if release_id or release_code:
399
+ q = filter_by_release(
400
+ q,
401
+ start_col=VariableVersion.startreleaseid,
402
+ end_col=VariableVersion.endreleaseid,
403
+ release_id=release_id,
404
+ release_code=release_code,
405
+ )
406
+ else:
407
+ # Default to active-only (endreleaseid is NULL)
408
+ q = filter_active_only(q, end_col=VariableVersion.endreleaseid)
409
+
410
+ result = q.first()
411
+ if result:
412
+ return dict(result._mapping)
413
+ return None
414
+
415
+ @staticmethod
416
+ def get_variables_by_codes(
417
+ session: Session,
418
+ variable_codes: List[str],
419
+ release_id: Optional[int] = None,
420
+ release_code: Optional[str] = None,
421
+ ) -> Dict[str, Dict[str, Any]]:
422
+ """
423
+ Batch lookup of variable_id and variable_vid for multiple variable codes.
424
+
425
+ This is more efficient than calling get_variable_by_code multiple times
426
+ when resolving multiple precondition variables.
427
+
428
+ Args:
429
+ session: SQLAlchemy session
430
+ variable_codes: List of variable codes to look up
431
+ release_id: Optional release ID to filter by
432
+ release_code: Optional release code to filter by
433
+
434
+ Returns:
435
+ Dict mapping variable_code to {variable_id, variable_vid, ...}
436
+ Only includes codes that were found in the database.
437
+ """
438
+ if release_id is not None and release_code is not None:
439
+ raise ValueError(
440
+ "Specify a maximum of one of release_id or release_code."
441
+ )
442
+
443
+ if not variable_codes:
444
+ return {}
445
+
446
+ q = (
447
+ session.query(
448
+ VariableVersion.variableid.label("variable_id"),
449
+ VariableVersion.variablevid.label("variable_vid"),
450
+ VariableVersion.code.label("variable_code"),
451
+ VariableVersion.name.label("variable_name"),
452
+ )
453
+ .select_from(VariableVersion)
454
+ .filter(VariableVersion.code.in_(variable_codes))
455
+ )
456
+
457
+ # Apply release filtering
458
+ if release_id or release_code:
459
+ q = filter_by_release(
460
+ q,
461
+ start_col=VariableVersion.startreleaseid,
462
+ end_col=VariableVersion.endreleaseid,
463
+ release_id=release_id,
464
+ release_code=release_code,
465
+ )
466
+ else:
467
+ # Default to active-only (endreleaseid is NULL)
468
+ q = filter_active_only(q, end_col=VariableVersion.endreleaseid)
469
+
470
+ results = q.all()
471
+ return {row.variable_code: dict(row._mapping) for row in results}
@@ -71,9 +71,19 @@ class OperationScopeService:
71
71
  if len(modules_info_dataframe) == 1:
72
72
  module_vid = modules_vids[0]
73
73
  from_date = modules_info_dataframe["FromReferenceDate"].values[0]
74
+ to_date = modules_info_dataframe["ToReferenceDate"].values[0]
75
+ module_code = modules_info_dataframe["ModuleCode"].values[0]
76
+ version_number = modules_info_dataframe["VersionNumber"].values[0]
74
77
  operation_scope = self.create_operation_scope(from_date)
75
78
  self.create_operation_scope_composition(
76
- operation_scope=operation_scope, module_vid=module_vid
79
+ operation_scope=operation_scope,
80
+ module_vid=module_vid,
81
+ module_info={
82
+ "code": module_code,
83
+ "version_number": version_number,
84
+ "from_reference_date": from_date,
85
+ "to_reference_date": to_date,
86
+ },
77
87
  )
78
88
  else:
79
89
  intra_modules = []
@@ -83,11 +93,10 @@ class OperationScopeService:
83
93
  if table_codes:
84
94
  unique_operands_number = len(table_codes) + len(precondition_items)
85
95
 
86
- # Categorize modules by lifecycle: starting vs ending in this release
87
- starting_modules = (
88
- {}
89
- ) # Modules that START in this release (replacements)
90
- ending_modules = {} # Modules that END in this release (being replaced)
96
+ # First pass: categorize modules by table code and lifecycle
97
+ # We track lifecycle to handle version transitions within the SAME module
98
+ starting_by_code = {} # table_code -> [module_vids that START in this release]
99
+ ending_by_code = {} # table_code -> [module_vids that END or are active]
91
100
 
92
101
  for module_vid, group_df in modules_info_dataframe.groupby(MODULE_VID):
93
102
  table_codes_in_module = (
@@ -105,31 +114,55 @@ class OperationScopeService:
105
114
  end_release = group_df["EndReleaseID"].values[0]
106
115
 
107
116
  # Determine if this is a "new" module starting in this release
108
- # or an "old" module ending in this release
109
117
  is_starting = start_release == release_id
110
- is_ending = end_release == release_id or end_release == float(
111
- release_id
112
- )
113
118
 
114
119
  if len(table_codes_in_module) == unique_operands_number:
115
120
  # Intra-module: include ALL modules active in the release
116
- # (don't filter by lifecycle - that's only for cross-module)
117
121
  intra_modules.append(module_vid)
118
122
  else:
119
- # For cross-module, group by table code AND lifecycle stage
120
- target_dict = (
121
- starting_modules if is_starting else ending_modules
122
- )
123
+ # Track modules by table code and lifecycle
123
124
  for table_code in table_codes_in_module:
124
- if table_code not in target_dict:
125
- target_dict[table_code] = []
126
- target_dict[table_code].append(module_vid)
127
-
128
- # Process cross-module scopes separately for each generation
129
- if starting_modules:
130
- cross_modules["_starting"] = starting_modules
131
- if ending_modules:
132
- cross_modules["_ending"] = ending_modules
125
+ if is_starting:
126
+ if table_code not in starting_by_code:
127
+ starting_by_code[table_code] = []
128
+ starting_by_code[table_code].append(module_vid)
129
+ else:
130
+ if table_code not in ending_by_code:
131
+ ending_by_code[table_code] = []
132
+ ending_by_code[table_code].append(module_vid)
133
+
134
+ # Second pass: determine if lifecycle separation is needed
135
+ # Only separate if a table code has modules in BOTH starting and ending
136
+ # (indicating a version transition for that table)
137
+ needs_lifecycle_separation = any(
138
+ code in starting_by_code and code in ending_by_code
139
+ for code in set(starting_by_code.keys()) | set(ending_by_code.keys())
140
+ )
141
+
142
+ if needs_lifecycle_separation:
143
+ # Separate into starting and ending scopes
144
+ starting_modules = {}
145
+ ending_modules = {}
146
+ for code, vids in starting_by_code.items():
147
+ starting_modules[code] = vids
148
+ for code, vids in ending_by_code.items():
149
+ ending_modules[code] = vids
150
+ if starting_modules:
151
+ cross_modules["_starting"] = starting_modules
152
+ if ending_modules:
153
+ cross_modules["_ending"] = ending_modules
154
+ else:
155
+ # No version transitions - combine all modules by table code
156
+ all_by_code = {}
157
+ for code, vids in starting_by_code.items():
158
+ if code not in all_by_code:
159
+ all_by_code[code] = []
160
+ all_by_code[code].extend(vids)
161
+ for code, vids in ending_by_code.items():
162
+ if code not in all_by_code:
163
+ all_by_code[code] = []
164
+ all_by_code[code].extend(vids)
165
+ cross_modules = all_by_code
133
166
  else:
134
167
  # Original logic for table VIDs
135
168
  unique_operands_number = len(tables_vids) + len(precondition_items)
@@ -268,12 +301,21 @@ class OperationScopeService:
268
301
  :param modules_vids: list with module version ids
269
302
  """
270
303
  for module_vid in modules_vids:
271
- from_date = modules_info[modules_info["ModuleVID"] == module_vid][
272
- "FromReferenceDate"
273
- ].values[0]
304
+ module_row = modules_info[modules_info["ModuleVID"] == module_vid].iloc[0]
305
+ from_date = module_row["FromReferenceDate"]
306
+ to_date = module_row["ToReferenceDate"]
307
+ module_code = module_row["ModuleCode"]
308
+ version_number = module_row["VersionNumber"]
274
309
  operation_scope = self.create_operation_scope(from_date)
275
310
  self.create_operation_scope_composition(
276
- operation_scope=operation_scope, module_vid=module_vid
311
+ operation_scope=operation_scope,
312
+ module_vid=module_vid,
313
+ module_info={
314
+ "code": module_code,
315
+ "version_number": version_number,
316
+ "from_reference_date": from_date,
317
+ "to_reference_date": to_date,
318
+ },
277
319
  )
278
320
 
279
321
  def process_cross_module(self, cross_modules, modules_dataframe):
@@ -313,8 +355,18 @@ class OperationScopeService:
313
355
  operation_scope = self.create_operation_scope(from_submission_date)
314
356
  combination = set(combination)
315
357
  for module in combination:
358
+ module_row = modules_dataframe[
359
+ modules_dataframe[MODULE_VID] == module
360
+ ].iloc[0]
316
361
  self.create_operation_scope_composition(
317
- operation_scope=operation_scope, module_vid=module
362
+ operation_scope=operation_scope,
363
+ module_vid=module,
364
+ module_info={
365
+ "code": module_row["ModuleCode"],
366
+ "version_number": module_row["VersionNumber"],
367
+ "from_reference_date": module_row[FROM_REFERENCE_DATE],
368
+ "to_reference_date": module_row[TO_REFERENCE_DATE],
369
+ },
318
370
  )
319
371
 
320
372
  def create_operation_scope(self, submission_date):
@@ -340,17 +392,21 @@ class OperationScopeService:
340
392
  self.session.add(operation_scope)
341
393
  return operation_scope
342
394
 
343
- def create_operation_scope_composition(self, operation_scope, module_vid):
395
+ def create_operation_scope_composition(self, operation_scope, module_vid, module_info=None):
344
396
  """
345
397
  Method to populate OperationScopeComposition table
346
398
  :param operation_scope: Operation scope data
347
399
  :param module_vid: Module version id
400
+ :param module_info: Optional dict with module info (code, from_reference_date, to_reference_date)
348
401
  """
349
402
  operation_scope_composition = OperationScopeComposition(
350
403
  operation_scope=operation_scope,
351
404
  modulevid=module_vid,
352
405
  rowguid=str(uuid.uuid4()),
353
406
  )
407
+ # Store module info as transient attribute for to_dict() access
408
+ if module_info:
409
+ operation_scope_composition._module_info = module_info
354
410
  self.session.add(operation_scope_composition)
355
411
 
356
412
  def get_scopes_with_status(self):
@@ -361,12 +361,14 @@ class ASTToJSONVisitor(NodeVisitor):
361
361
  'op': node.op,
362
362
  'operand': self.visit(node.operand),
363
363
  }
364
- # Add grouping_clause if present and has actual components
364
+ # Always include grouping_clause (null when not present or empty)
365
+ grouping_clause = None
365
366
  if hasattr(node, 'grouping_clause') and node.grouping_clause is not None:
366
367
  gc = self.visit(node.grouping_clause)
367
- # Only include grouping_clause if it has components
368
+ # Only set to actual value if it has components
368
369
  if gc and gc.get('components'):
369
- result['grouping_clause'] = gc
370
+ grouping_clause = gc
371
+ result['grouping_clause'] = grouping_clause
370
372
  return result
371
373
 
372
374
  def visit_GroupingClause(self, node):
@@ -169,6 +169,7 @@ class Instance:
169
169
  row_code=None,
170
170
  column_code=None,
171
171
  sheet_code=None,
172
+ module_code=instance_json["module_code"],
172
173
  date=ref_period,
173
174
  )
174
175
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pydpm_xl
3
- Version: 0.2.5rc3
3
+ Version: 0.2.6
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,27 +1,27 @@
1
- py_dpm/__init__.py,sha256=zPA7CdwYtnZIaZc8jniwDoBwlzur7Wj1qOl35ZvmcHo,1861
2
- py_dpm/api/__init__.py,sha256=n79vAD7qatlYaXaI2N5IAD9m_8Fgb00EOdapVXZYTpI,1081
1
+ py_dpm/__init__.py,sha256=EoSVcX1P4pvEC2vpV8uwhWNcq-jFuDPoUho2_yygUkA,1858
2
+ py_dpm/api/__init__.py,sha256=6ElO0NKEjuqiHNxK7pxkzLNlaUOrYKnY3N0fUDDobik,1021
3
3
  py_dpm/api/dpm/__init__.py,sha256=HQflgiRbs1eDi3KTadNhxS1NoaG6PGQDVMvFnuIEfXo,506
4
- py_dpm/api/dpm/data_dictionary.py,sha256=g0h6Yfschz7rboYly9LTbP-2SS5UxltU3AXu0v0tqrU,29457
5
- py_dpm/api/dpm/explorer.py,sha256=gW2RC59XwGl9YbEA-M4syHAs6MvqPWVw4wR_XdVFJ4Y,7888
4
+ py_dpm/api/dpm/data_dictionary.py,sha256=zLkHrprXMgdoUqhf-TWDg4FEdlkvefc7fMtkENh0s7c,29564
5
+ py_dpm/api/dpm/explorer.py,sha256=xgrSdh2D83RivypF26WWo20rbQifYBEH7PXvINoi07Y,10861
6
6
  py_dpm/api/dpm/hierarchical_queries.py,sha256=X4AbpsWy3iItOTVIdVbtaTmRgOHPf0Y64Ig-_377uns,4054
7
7
  py_dpm/api/dpm/instance.py,sha256=v3DWzdaM5gPCecLjwjZ49FGfqZzUR3dPC0U8zGwdttk,3795
8
8
  py_dpm/api/dpm/migration.py,sha256=9FT7zzz4QdUIRR6MD01gMODBtfq9HH_RF4hRgZqMcZc,2404
9
- py_dpm/api/dpm_xl/__init__.py,sha256=aRjaMAf_i2a33UAGTg-TF1BfO6miOOrbCydTUqAVvRU,910
10
- py_dpm/api/dpm_xl/ast_generator.py,sha256=GHu_F3YKaMpqvu16ABIvj8BwlmWXehvk0eUJVQkCphE,55204
11
- py_dpm/api/dpm_xl/complete_ast.py,sha256=VkmcBatrydu97Inwp3pHjz93F38q2JRo-4Lohdu30RY,7684
9
+ py_dpm/api/dpm_xl/__init__.py,sha256=cwqeYgmowGH6MK8kQMQkjQaTL9qKEnC8-M5rueqhrPI,850
10
+ py_dpm/api/dpm_xl/ast_generator.py,sha256=KblAXTRhRuzNHIAaXbDj6uCNwepNDo1BaM-Ir1oAjGc,94680
11
+ py_dpm/api/dpm_xl/complete_ast.py,sha256=_FSxA0FmNXuW0OLS3c8yzp14yjkmdR0rTebBAs1pg-E,8141
12
12
  py_dpm/api/dpm_xl/operation_scopes.py,sha256=7AyOFAn9h012JPF9H5EtZ3sPzv6DOxkoinpj5ArzVOc,48492
13
13
  py_dpm/api/dpm_xl/semantic.py,sha256=Buo_t-sEv65r6RmYDy1xkCWGlU2pB2WQsDM-X-FX4cc,13629
14
14
  py_dpm/api/dpm_xl/syntax.py,sha256=Ke_kKd9ModoJ6siL3GPT9j9QClmopryCRcdDAT3M5-E,5954
15
15
  py_dpm/cli/__init__.py,sha256=UrfGHoQ0sZLjWfA0hoOoI4iTrn-bjr2f9Q8wDWd5nMo,133
16
- py_dpm/cli/main.py,sha256=v8ZgIjg4Zqf6UWNv2bydYlZV6KfDLnPACyqplNIJyNE,22447
16
+ py_dpm/cli/main.py,sha256=LJ7JBk7lyWXe7ZYxnbxmohM1Dbha4sIdQzSTYKd9ZNo,22457
17
17
  py_dpm/cli/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
18
  py_dpm/dpm/__init__.py,sha256=moagUo5Gxf24-Tl9FL_3n2wmVoD_oXtpC-YIGktH_rc,212
19
19
  py_dpm/dpm/migration.py,sha256=ivO_ObvKzVomTns6qfo-o5FuciWxkXbMd_gJ4_tu7Xc,14110
20
- py_dpm/dpm/models.py,sha256=d70oZ_3wXsKBRGM2TJRlsuDrHWSVkzetLAZeMIoImwc,124821
20
+ py_dpm/dpm/models.py,sha256=Rt1b8zOSayXd9KhwyfkGJVhCai3YxUakmLYgwaiICWA,135660
21
21
  py_dpm/dpm/utils.py,sha256=JNdAeOXjzQtye94jLPRHHGUMcvkGtTsjA5HFl92rWig,12783
22
22
  py_dpm/dpm/queries/base.py,sha256=EddMeJMwtp63DyyIFO7_XxGvdlCtJQWWpeOVImlKp4I,3648
23
23
  py_dpm/dpm/queries/basic_objects.py,sha256=JOXC235lMDfVENrFAhZAl7_nqePJ4RrwJhFF0WDyk0M,955
24
- py_dpm/dpm/queries/explorer_queries.py,sha256=Co8CzdzlDrOL5-ZxY7_HoHPaP_j-xjLDSsB8EKT5aC8,13034
24
+ py_dpm/dpm/queries/explorer_queries.py,sha256=HcLfwpdGWX-q-i1L-7W0nwTxL_0OiDliqPUeoZ9zHZ4,17453
25
25
  py_dpm/dpm/queries/filters.py,sha256=fxC2KLYpIvtmuyuJFb0te2ULiyDnQBZfVM79VQnr6qA,4901
26
26
  py_dpm/dpm/queries/glossary.py,sha256=2SqKZghQTw-E8NWwHebDHuDC8BC389fGe-0UBIVfJ8Q,1571
27
27
  py_dpm/dpm/queries/hierarchical_queries.py,sha256=FYO2p_OxZioynXW4nGCQ3UG3p3uzE28KdsmMaQSk1wk,31538
@@ -68,17 +68,17 @@ py_dpm/dpm_xl/utils/__init__.py,sha256=4-jXa7AdHjx2DpikAzjZVKqBktdrHgSAx6pibb4sM
68
68
  py_dpm/dpm_xl/utils/data_handlers.py,sha256=a0E-IaP_-CDKLcj-Gt2ggAziKIOUiwnT2D9IkWCS68o,4402
69
69
  py_dpm/dpm_xl/utils/operands_mapping.py,sha256=LG0hPlUuTM2X2uWOtiD6HkmNeDEJkWJ8gV-Fxej_8QM,2241
70
70
  py_dpm/dpm_xl/utils/operator_mapping.py,sha256=BFgbVbSCSuutFNHJ4gtgm5VuG38pcl8Kmfi-sefg6JU,1913
71
- py_dpm/dpm_xl/utils/scopes_calculator.py,sha256=nCx2mz_qtw61BESp38ORQYlF2uRT8SyUKawSX9OQljM,17832
72
- py_dpm/dpm_xl/utils/serialization.py,sha256=LPcmudFfzHeEjIIr57kr5BvGPZbxshOAAeUYOrLl7XM,32482
71
+ py_dpm/dpm_xl/utils/scopes_calculator.py,sha256=do_emsUqD1TbrjguKlOOqFleaVhxzqm-NnlgdrdIb6I,20906
72
+ py_dpm/dpm_xl/utils/serialization.py,sha256=ouQpkmZWc6_T0hVzjwmxpHRu9yheNyyMBBaOZERe0qM,32558
73
73
  py_dpm/dpm_xl/utils/tokens.py,sha256=VRIrPDi5ttwgH-on5Qt4-l4ho4bLA755-nfTalponcA,3496
74
74
  py_dpm/exceptions/__init__.py,sha256=yDERfUxYW7NUUEiTQChGpuJx6abr7IDe2XUpwVFPtvM,416
75
75
  py_dpm/exceptions/exceptions.py,sha256=6S3p-_i5O1oStvSMixt_JQG0xwTeSfBcdzrwL8yBy6Q,2413
76
76
  py_dpm/exceptions/messages.py,sha256=UwY6QIK8c-POcDCc9HYbZFGArCIYAanUGNh2LNKPx3U,7534
77
77
  py_dpm/instance/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
78
- py_dpm/instance/instance.py,sha256=OPSEPgSYAxhgqhKuxbMpMPTfBnaFNzURTrUUT4kvGKc,10820
79
- pydpm_xl-0.2.5rc3.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
80
- pydpm_xl-0.2.5rc3.dist-info/METADATA,sha256=W-1lvyIWG91rZpsouuv4hzolwcUT6pksvJlj_9pl-dE,9305
81
- pydpm_xl-0.2.5rc3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
82
- pydpm_xl-0.2.5rc3.dist-info/entry_points.txt,sha256=6DDmBfw-AjtgvMHgq_I730i_LAAs_7-N3C95HD_bRr4,47
83
- pydpm_xl-0.2.5rc3.dist-info/top_level.txt,sha256=495PvWZRoKl2NvbQU25W7dqWIBHqY-mFMPt83uxPpcM,7
84
- pydpm_xl-0.2.5rc3.dist-info/RECORD,,
78
+ py_dpm/instance/instance.py,sha256=gRSg2dh1nEa0Srx9yKcN3bxiYidvZyRU_jsTNaKkP5I,10882
79
+ pydpm_xl-0.2.6.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
80
+ pydpm_xl-0.2.6.dist-info/METADATA,sha256=PaoWC3ApUcFBwRTcvr4TyMhdH3BAdt618N-EOou8cnk,9302
81
+ pydpm_xl-0.2.6.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
82
+ pydpm_xl-0.2.6.dist-info/entry_points.txt,sha256=6DDmBfw-AjtgvMHgq_I730i_LAAs_7-N3C95HD_bRr4,47
83
+ pydpm_xl-0.2.6.dist-info/top_level.txt,sha256=495PvWZRoKl2NvbQU25W7dqWIBHqY-mFMPt83uxPpcM,7
84
+ pydpm_xl-0.2.6.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (80.10.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5