informatica-python 1.1.0__tar.gz → 1.2.0__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.
- {informatica_python-1.1.0 → informatica_python-1.2.0}/PKG-INFO +1 -1
- {informatica_python-1.1.0 → informatica_python-1.2.0}/informatica_python/converter.py +30 -5
- {informatica_python-1.1.0 → informatica_python-1.2.0}/informatica_python/generators/error_log_gen.py +45 -19
- {informatica_python-1.1.0 → informatica_python-1.2.0}/informatica_python/generators/helper_gen.py +396 -0
- {informatica_python-1.1.0 → informatica_python-1.2.0}/informatica_python/generators/mapping_gen.py +137 -22
- informatica_python-1.2.0/informatica_python/utils/expression_converter.py +259 -0
- {informatica_python-1.1.0 → informatica_python-1.2.0}/informatica_python.egg-info/PKG-INFO +1 -1
- {informatica_python-1.1.0 → informatica_python-1.2.0}/pyproject.toml +1 -1
- informatica_python-1.2.0/tests/test_converter.py +551 -0
- informatica_python-1.1.0/informatica_python/utils/expression_converter.py +0 -128
- informatica_python-1.1.0/tests/test_converter.py +0 -260
- {informatica_python-1.1.0 → informatica_python-1.2.0}/README.md +0 -0
- {informatica_python-1.1.0 → informatica_python-1.2.0}/informatica_python/__init__.py +0 -0
- {informatica_python-1.1.0 → informatica_python-1.2.0}/informatica_python/cli.py +0 -0
- {informatica_python-1.1.0 → informatica_python-1.2.0}/informatica_python/generators/__init__.py +0 -0
- {informatica_python-1.1.0 → informatica_python-1.2.0}/informatica_python/generators/config_gen.py +0 -0
- {informatica_python-1.1.0 → informatica_python-1.2.0}/informatica_python/generators/sql_gen.py +0 -0
- {informatica_python-1.1.0 → informatica_python-1.2.0}/informatica_python/generators/workflow_gen.py +0 -0
- {informatica_python-1.1.0 → informatica_python-1.2.0}/informatica_python/models.py +0 -0
- {informatica_python-1.1.0 → informatica_python-1.2.0}/informatica_python/parser.py +0 -0
- {informatica_python-1.1.0 → informatica_python-1.2.0}/informatica_python/utils/__init__.py +0 -0
- {informatica_python-1.1.0 → informatica_python-1.2.0}/informatica_python/utils/datatype_map.py +0 -0
- {informatica_python-1.1.0 → informatica_python-1.2.0}/informatica_python.egg-info/SOURCES.txt +0 -0
- {informatica_python-1.1.0 → informatica_python-1.2.0}/informatica_python.egg-info/dependency_links.txt +0 -0
- {informatica_python-1.1.0 → informatica_python-1.2.0}/informatica_python.egg-info/entry_points.txt +0 -0
- {informatica_python-1.1.0 → informatica_python-1.2.0}/informatica_python.egg-info/requires.txt +0 -0
- {informatica_python-1.1.0 → informatica_python-1.2.0}/informatica_python.egg-info/top_level.txt +0 -0
- {informatica_python-1.1.0 → informatica_python-1.2.0}/setup.cfg +0 -0
|
@@ -235,7 +235,9 @@ class InformaticaConverter:
|
|
|
235
235
|
if tgt.xmlinfo:
|
|
236
236
|
d["xmlinfo"] = {"xml_type": tgt.xmlinfo.xml_type, "root_element": tgt.xmlinfo.root_element}
|
|
237
237
|
if tgt.groups:
|
|
238
|
-
d["groups"] = [{"name": g.name, "type": g.type} for g in tgt.groups]
|
|
238
|
+
d["groups"] = [{"name": g.name, "type": g.type, "fields": [self._field_to_dict(f) for f in g.fields]} for g in tgt.groups]
|
|
239
|
+
if tgt.keywords:
|
|
240
|
+
d["keywords"] = [{"name": k.name, "value": k.value} for k in tgt.keywords]
|
|
239
241
|
return d
|
|
240
242
|
|
|
241
243
|
def _transformation_to_dict(self, tx):
|
|
@@ -257,7 +259,9 @@ class InformaticaConverter:
|
|
|
257
259
|
if tx.erp_info:
|
|
258
260
|
d["erp_info"] = {"name": tx.erp_info.name, "erp_type": tx.erp_info.erp_type}
|
|
259
261
|
if tx.groups:
|
|
260
|
-
d["groups"] = [{"name": g.name, "type": g.type} for g in tx.groups]
|
|
262
|
+
d["groups"] = [{"name": g.name, "type": g.type, "fields": [self._field_to_dict(f) for f in g.fields]} for g in tx.groups]
|
|
263
|
+
if tx.metadata_extensions:
|
|
264
|
+
d["metadata_extensions"] = [self._meta_ext_to_dict(me) for me in tx.metadata_extensions]
|
|
261
265
|
if tx.sap_functions:
|
|
262
266
|
d["sap_functions"] = [self._sap_function_to_dict(sf) for sf in tx.sap_functions]
|
|
263
267
|
return d
|
|
@@ -322,7 +326,13 @@ class InformaticaConverter:
|
|
|
322
326
|
"transformations": [self._transformation_to_dict(tx) for tx in mapplet.transformations],
|
|
323
327
|
"connectors": [{"from_field": c.from_field, "from_instance": c.from_instance,
|
|
324
328
|
"to_field": c.to_field, "to_instance": c.to_instance} for c in mapplet.connectors],
|
|
325
|
-
"instances": [{"name": i.name, "type": i.type, "transformation_name": i.transformation_name
|
|
329
|
+
"instances": [{"name": i.name, "type": i.type, "transformation_name": i.transformation_name,
|
|
330
|
+
"associated_source_instances": [{"name": a.name, "source_instance": a.source_instance} for a in i.associated_source_instances]}
|
|
331
|
+
for i in mapplet.instances],
|
|
332
|
+
"metadata_extensions": [self._meta_ext_to_dict(me) for me in mapplet.metadata_extensions],
|
|
333
|
+
"map_dependencies": [{"name": md.name, "from_mapping": md.from_mapping, "to_mapping": md.to_mapping} for md in mapplet.map_dependencies],
|
|
334
|
+
"field_dependencies": [{"name": fd.name, "from_field": fd.from_field, "from_instance": fd.from_instance,
|
|
335
|
+
"to_field": fd.to_field, "to_instance": fd.to_instance, "expression": fd.expression} for fd in mapplet.field_dependencies],
|
|
326
336
|
}
|
|
327
337
|
|
|
328
338
|
def _session_to_dict(self, session):
|
|
@@ -350,6 +360,7 @@ class InformaticaConverter:
|
|
|
350
360
|
],
|
|
351
361
|
"config_references": session.config_references,
|
|
352
362
|
"components": session.components,
|
|
363
|
+
"metadata_extensions": [self._meta_ext_to_dict(me) for me in session.metadata_extensions],
|
|
353
364
|
}
|
|
354
365
|
|
|
355
366
|
def _task_to_dict(self, task):
|
|
@@ -360,13 +371,17 @@ class InformaticaConverter:
|
|
|
360
371
|
}
|
|
361
372
|
if task.timer:
|
|
362
373
|
d["timer"] = {"name": task.timer.name, "start_type": task.timer.start_type,
|
|
363
|
-
"start_date": task.timer.start_date, "start_time": task.timer.start_time
|
|
374
|
+
"start_date": task.timer.start_date, "start_time": task.timer.start_time,
|
|
375
|
+
"end_type": task.timer.end_type, "end_date": task.timer.end_date, "end_time": task.timer.end_time}
|
|
376
|
+
if task.metadata_extensions:
|
|
377
|
+
d["metadata_extensions"] = [self._meta_ext_to_dict(me) for me in task.metadata_extensions]
|
|
364
378
|
return d
|
|
365
379
|
|
|
366
380
|
def _config_to_dict(self, cfg):
|
|
367
381
|
return {
|
|
368
382
|
"name": cfg.name, "description": cfg.description, "is_valid": cfg.is_valid,
|
|
369
383
|
"attributes": [{"name": a.name, "value": a.value} for a in cfg.attributes],
|
|
384
|
+
"metadata_extensions": [self._meta_ext_to_dict(me) for me in cfg.metadata_extensions],
|
|
370
385
|
}
|
|
371
386
|
|
|
372
387
|
def _scheduler_to_dict(self, sched):
|
|
@@ -380,10 +395,18 @@ class InformaticaConverter:
|
|
|
380
395
|
d["start_options"] = sched.start_options.attributes
|
|
381
396
|
if sched.end_options:
|
|
382
397
|
d["end_options"] = sched.end_options.attributes
|
|
398
|
+
if sched.schedule_options:
|
|
399
|
+
d["schedule_options"] = sched.schedule_options.attributes
|
|
383
400
|
if sched.recurring:
|
|
384
401
|
d["recurring"] = sched.recurring.attributes
|
|
402
|
+
if sched.custom:
|
|
403
|
+
d["custom"] = sched.custom.attributes
|
|
385
404
|
if sched.daily_frequency:
|
|
386
405
|
d["daily_frequency"] = sched.daily_frequency.attributes
|
|
406
|
+
if sched.repeat:
|
|
407
|
+
d["repeat"] = sched.repeat.attributes
|
|
408
|
+
if sched.scheduler_filter:
|
|
409
|
+
d["filter"] = sched.scheduler_filter.attributes
|
|
387
410
|
return d
|
|
388
411
|
|
|
389
412
|
def _shortcut_to_dict(self, sc):
|
|
@@ -417,9 +440,11 @@ class InformaticaConverter:
|
|
|
417
440
|
for v in wf.variables
|
|
418
441
|
],
|
|
419
442
|
"events": [
|
|
420
|
-
{"name": e.name, "event_type": e.event_type, "description": e.description
|
|
443
|
+
{"name": e.name, "event_type": e.event_type, "description": e.description,
|
|
444
|
+
"attributes": [{"name": a.name, "value": a.value} for a in e.attributes]}
|
|
421
445
|
for e in wf.events
|
|
422
446
|
],
|
|
423
447
|
"attributes": [{"name": a.name, "value": a.value} for a in wf.attributes],
|
|
424
448
|
"metadata": wf.metadata,
|
|
449
|
+
"metadata_extensions": [self._meta_ext_to_dict(me) for me in wf.metadata_extensions],
|
|
425
450
|
}
|
{informatica_python-1.1.0 → informatica_python-1.2.0}/informatica_python/generators/error_log_gen.py
RENAMED
|
@@ -228,10 +228,36 @@ def generate_error_log(folder: FolderDef, parser_errors=None, parser_warnings=No
|
|
|
228
228
|
lines.append("-" * 70)
|
|
229
229
|
lines.append("")
|
|
230
230
|
|
|
231
|
+
all_transformations = list(folder.transformations)
|
|
232
|
+
for m in folder.mappings:
|
|
233
|
+
all_transformations.extend(m.transformations)
|
|
234
|
+
for mpl in folder.mapplets:
|
|
235
|
+
all_transformations.extend(mpl.transformations)
|
|
236
|
+
|
|
237
|
+
all_instances = []
|
|
238
|
+
for m in folder.mappings:
|
|
239
|
+
all_instances.extend(m.instances)
|
|
240
|
+
for mpl in folder.mapplets:
|
|
241
|
+
all_instances.extend(mpl.instances)
|
|
242
|
+
|
|
243
|
+
me_count = len(folder.metadata_extensions)
|
|
244
|
+
me_count += sum(len(s.metadata_extensions) for s in folder.sources)
|
|
245
|
+
me_count += sum(len(t.metadata_extensions) for t in folder.targets)
|
|
246
|
+
me_count += sum(len(m.metadata_extensions) for m in folder.mappings)
|
|
247
|
+
me_count += sum(len(mpl.metadata_extensions) for mpl in folder.mapplets)
|
|
248
|
+
me_count += sum(len(s.metadata_extensions) for s in folder.sessions)
|
|
249
|
+
me_count += sum(len(w.metadata_extensions) for w in folder.workflows)
|
|
250
|
+
me_count += sum(len(t.metadata_extensions) for t in folder.tasks)
|
|
251
|
+
me_count += sum(len(c.metadata_extensions) for c in folder.configs)
|
|
252
|
+
me_count += sum(len(tx.metadata_extensions) for tx in all_transformations)
|
|
253
|
+
|
|
254
|
+
group_count = (
|
|
255
|
+
sum(len(s.groups) for s in folder.sources)
|
|
256
|
+
+ sum(len(t.groups) for t in folder.targets)
|
|
257
|
+
+ sum(len(tx.groups) for tx in all_transformations)
|
|
258
|
+
)
|
|
259
|
+
|
|
231
260
|
tag_counts = {
|
|
232
|
-
"POWERMART": 1,
|
|
233
|
-
"REPOSITORY": sum(1 for _ in [1]),
|
|
234
|
-
"FOLDER": 1,
|
|
235
261
|
"FOLDERVERSION": len(folder.folder_versions),
|
|
236
262
|
"SOURCE": len(folder.sources),
|
|
237
263
|
"SOURCEFIELD": sum(len(s.fields) for s in folder.sources),
|
|
@@ -241,24 +267,24 @@ def generate_error_log(folder: FolderDef, parser_errors=None, parser_warnings=No
|
|
|
241
267
|
"TARGETINDEXFIELD": sum(len(idx.fields) for t in folder.targets for idx in t.indexes),
|
|
242
268
|
"FLATFILE": sum(1 for s in folder.sources if s.flatfile) + sum(1 for t in folder.targets if t.flatfile),
|
|
243
269
|
"XMLINFO": sum(1 for s in folder.sources if s.xmlinfo) + sum(1 for t in folder.targets if t.xmlinfo),
|
|
244
|
-
"GROUP":
|
|
245
|
-
"KEYWORD": sum(len(s.keywords) for s in folder.sources),
|
|
270
|
+
"GROUP": group_count,
|
|
271
|
+
"KEYWORD": sum(len(s.keywords) for s in folder.sources) + sum(len(t.keywords) for t in folder.targets),
|
|
246
272
|
"ERPSRCINFO": sum(1 for s in folder.sources if s.erp_src_info),
|
|
247
273
|
"MAPPING": len(folder.mappings),
|
|
248
274
|
"MAPPLET": len(folder.mapplets),
|
|
249
|
-
"TRANSFORMATION":
|
|
250
|
-
"TRANSFORMFIELD": sum(len(tx.fields) for
|
|
251
|
-
"TRANSFORMFIELDATTR": sum(len(tx.field_attrs) for
|
|
252
|
-
"TRANSFORMFIELDATTRDEF": sum(len(tx.field_attr_defs) for
|
|
253
|
-
"INITPROP": sum(len(tx.init_props) for
|
|
254
|
-
"ERPINFO": sum(1 for
|
|
255
|
-
"INSTANCE":
|
|
256
|
-
"ASSOCIATED_SOURCE_INSTANCE": sum(len(i.associated_source_instances) for
|
|
257
|
-
"CONNECTOR": sum(len(m.connectors) for m in folder.mappings),
|
|
275
|
+
"TRANSFORMATION": len(all_transformations),
|
|
276
|
+
"TRANSFORMFIELD": sum(len(tx.fields) for tx in all_transformations),
|
|
277
|
+
"TRANSFORMFIELDATTR": sum(len(tx.field_attrs) for tx in all_transformations),
|
|
278
|
+
"TRANSFORMFIELDATTRDEF": sum(len(tx.field_attr_defs) for tx in all_transformations),
|
|
279
|
+
"INITPROP": sum(len(tx.init_props) for tx in all_transformations),
|
|
280
|
+
"ERPINFO": sum(1 for tx in all_transformations if tx.erp_info),
|
|
281
|
+
"INSTANCE": len(all_instances),
|
|
282
|
+
"ASSOCIATED_SOURCE_INSTANCE": sum(len(i.associated_source_instances) for i in all_instances),
|
|
283
|
+
"CONNECTOR": sum(len(m.connectors) for m in folder.mappings) + sum(len(mpl.connectors) for mpl in folder.mapplets),
|
|
258
284
|
"TARGETLOADORDER": sum(len(m.target_load_orders) for m in folder.mappings),
|
|
259
285
|
"MAPPINGVARIABLE": sum(len(m.variables) for m in folder.mappings),
|
|
260
|
-
"MAPDEPENDENCY": sum(len(m.map_dependencies) for m in folder.mappings),
|
|
261
|
-
"FIELDDEPENDENCY": sum(len(m.field_dependencies) for m in folder.mappings),
|
|
286
|
+
"MAPDEPENDENCY": sum(len(m.map_dependencies) for m in folder.mappings) + sum(len(mpl.map_dependencies) for mpl in folder.mapplets),
|
|
287
|
+
"FIELDDEPENDENCY": sum(len(m.field_dependencies) for m in folder.mappings) + sum(len(mpl.field_dependencies) for mpl in folder.mapplets),
|
|
262
288
|
"SESSION": len(folder.sessions),
|
|
263
289
|
"SESSTRANSFORMATIONINST": sum(len(s.transform_instances) for s in folder.sessions),
|
|
264
290
|
"SESSTRANSFORMATIONGROUP": sum(len(s.transform_groups) for s in folder.sessions),
|
|
@@ -273,15 +299,15 @@ def generate_error_log(folder: FolderDef, parser_errors=None, parser_warnings=No
|
|
|
273
299
|
"TIMER": sum(1 for t in folder.tasks if t.timer),
|
|
274
300
|
"CONFIG": len(folder.configs),
|
|
275
301
|
"SCHEDULER": len(folder.schedulers),
|
|
276
|
-
"WORKFLOW":
|
|
302
|
+
"WORKFLOW": sum(1 for w in folder.workflows if w.metadata.get("is_worklet") != "YES"),
|
|
277
303
|
"WORKLET": sum(1 for w in folder.workflows if w.metadata.get("is_worklet") == "YES"),
|
|
278
304
|
"TASKINSTANCE": sum(len(w.task_instances) for w in folder.workflows),
|
|
279
305
|
"WORKFLOWLINK": sum(len(w.links) for w in folder.workflows),
|
|
280
306
|
"WORKFLOWVARIABLE": sum(len(w.variables) for w in folder.workflows),
|
|
281
307
|
"WORKFLOWEVENT": sum(len(w.events) for w in folder.workflows),
|
|
282
308
|
"SHORTCUT": len(folder.shortcuts),
|
|
283
|
-
"METADATAEXTENSION":
|
|
284
|
-
"SAPFUNCTION": sum(len(tx.sap_functions) for
|
|
309
|
+
"METADATAEXTENSION": me_count,
|
|
310
|
+
"SAPFUNCTION": sum(len(tx.sap_functions) for tx in all_transformations),
|
|
285
311
|
}
|
|
286
312
|
|
|
287
313
|
for tag, count in sorted(tag_counts.items()):
|
{informatica_python-1.1.0 → informatica_python-1.2.0}/informatica_python/generators/helper_gen.py
RENAMED
|
@@ -631,6 +631,402 @@ def _add_expression_helpers(lines):
|
|
|
631
631
|
lines.append(" return date_val")
|
|
632
632
|
lines.append("")
|
|
633
633
|
lines.append("")
|
|
634
|
+
lines.append("def initcap(value):")
|
|
635
|
+
lines.append(' """Informatica INITCAP equivalent."""')
|
|
636
|
+
lines.append(" return str(value).title() if value is not None else None")
|
|
637
|
+
lines.append("")
|
|
638
|
+
lines.append("")
|
|
639
|
+
lines.append("def reverse_str(value):")
|
|
640
|
+
lines.append(' """Informatica REVERSE equivalent."""')
|
|
641
|
+
lines.append(" return str(value)[::-1] if value is not None else None")
|
|
642
|
+
lines.append("")
|
|
643
|
+
lines.append("")
|
|
644
|
+
lines.append("def chr_func(code):")
|
|
645
|
+
lines.append(' """Informatica CHR equivalent."""')
|
|
646
|
+
lines.append(" return chr(int(code)) if code is not None else None")
|
|
647
|
+
lines.append("")
|
|
648
|
+
lines.append("")
|
|
649
|
+
lines.append("def ascii_func(value):")
|
|
650
|
+
lines.append(' """Informatica ASCII equivalent."""')
|
|
651
|
+
lines.append(" if value is None or str(value) == '':")
|
|
652
|
+
lines.append(" return None")
|
|
653
|
+
lines.append(" return ord(str(value)[0])")
|
|
654
|
+
lines.append("")
|
|
655
|
+
lines.append("")
|
|
656
|
+
lines.append("def left_str(value, n):")
|
|
657
|
+
lines.append(' """Return leftmost n characters."""')
|
|
658
|
+
lines.append(" return str(value)[:int(n)] if value is not None else None")
|
|
659
|
+
lines.append("")
|
|
660
|
+
lines.append("")
|
|
661
|
+
lines.append("def right_str(value, n):")
|
|
662
|
+
lines.append(' """Return rightmost n characters."""')
|
|
663
|
+
lines.append(" return str(value)[-int(n):] if value is not None else None")
|
|
664
|
+
lines.append("")
|
|
665
|
+
lines.append("")
|
|
666
|
+
lines.append("def trim_func(value):")
|
|
667
|
+
lines.append(' """Informatica TRIM equivalent."""')
|
|
668
|
+
lines.append(" return str(value).strip() if value is not None else None")
|
|
669
|
+
lines.append("")
|
|
670
|
+
lines.append("")
|
|
671
|
+
lines.append("def indexof(value, search, start=1):")
|
|
672
|
+
lines.append(' """Informatica INDEXOF equivalent (1-based)."""')
|
|
673
|
+
lines.append(" if value is None or search is None:")
|
|
674
|
+
lines.append(" return 0")
|
|
675
|
+
lines.append(" idx = str(value).find(str(search), max(start - 1, 0))")
|
|
676
|
+
lines.append(" return idx + 1 if idx >= 0 else 0")
|
|
677
|
+
lines.append("")
|
|
678
|
+
lines.append("")
|
|
679
|
+
lines.append("def metaphone_func(value):")
|
|
680
|
+
lines.append(' """Informatica METAPHONE equivalent (simplified)."""')
|
|
681
|
+
lines.append(" if value is None:")
|
|
682
|
+
lines.append(" return None")
|
|
683
|
+
lines.append(" try:")
|
|
684
|
+
lines.append(" import jellyfish")
|
|
685
|
+
lines.append(" return jellyfish.metaphone(str(value))")
|
|
686
|
+
lines.append(" except ImportError:")
|
|
687
|
+
lines.append(" return str(value).upper()[:4]")
|
|
688
|
+
lines.append("")
|
|
689
|
+
lines.append("")
|
|
690
|
+
lines.append("def soundex_func(value):")
|
|
691
|
+
lines.append(' """Informatica SOUNDEX equivalent (simplified)."""')
|
|
692
|
+
lines.append(" if value is None:")
|
|
693
|
+
lines.append(" return None")
|
|
694
|
+
lines.append(" try:")
|
|
695
|
+
lines.append(" import jellyfish")
|
|
696
|
+
lines.append(" return jellyfish.soundex(str(value))")
|
|
697
|
+
lines.append(" except ImportError:")
|
|
698
|
+
lines.append(" s = str(value).upper()")
|
|
699
|
+
lines.append(" if not s:")
|
|
700
|
+
lines.append(" return '0000'")
|
|
701
|
+
lines.append(" codes = {'B':'1','F':'1','P':'1','V':'1','C':'2','G':'2','J':'2','K':'2','Q':'2','S':'2','X':'2','Z':'2','D':'3','T':'3','L':'4','M':'5','N':'5','R':'6'}")
|
|
702
|
+
lines.append(" result = s[0]")
|
|
703
|
+
lines.append(" for ch in s[1:]:")
|
|
704
|
+
lines.append(" code = codes.get(ch, '0')")
|
|
705
|
+
lines.append(" if code != '0' and code != result[-1]:")
|
|
706
|
+
lines.append(" result += code")
|
|
707
|
+
lines.append(" return (result + '0000')[:4]")
|
|
708
|
+
lines.append("")
|
|
709
|
+
lines.append("")
|
|
710
|
+
lines.append("def compress_func(value):")
|
|
711
|
+
lines.append(' """Informatica COMPRESS equivalent - removes spaces."""')
|
|
712
|
+
lines.append(" return str(value).replace(' ', '') if value is not None else None")
|
|
713
|
+
lines.append("")
|
|
714
|
+
lines.append("")
|
|
715
|
+
lines.append("def decompress_func(value):")
|
|
716
|
+
lines.append(' """Informatica DECOMPRESS equivalent."""')
|
|
717
|
+
lines.append(" return value")
|
|
718
|
+
lines.append("")
|
|
719
|
+
lines.append("")
|
|
720
|
+
lines.append("def to_timestamp_func(value, fmt=None):")
|
|
721
|
+
lines.append(' """Informatica TO_TIMESTAMP equivalent."""')
|
|
722
|
+
lines.append(" return to_date(value, fmt)")
|
|
723
|
+
lines.append("")
|
|
724
|
+
lines.append("")
|
|
725
|
+
lines.append("def cast_func(value, datatype):")
|
|
726
|
+
lines.append(' """Informatica CAST equivalent."""')
|
|
727
|
+
lines.append(" if value is None:")
|
|
728
|
+
lines.append(" return None")
|
|
729
|
+
lines.append(" dt = str(datatype).upper()")
|
|
730
|
+
lines.append(" if 'INT' in dt:")
|
|
731
|
+
lines.append(" return int(float(str(value)))")
|
|
732
|
+
lines.append(" elif 'FLOAT' in dt or 'DOUBLE' in dt or 'DECIMAL' in dt or 'NUMBER' in dt:")
|
|
733
|
+
lines.append(" return float(str(value))")
|
|
734
|
+
lines.append(" elif 'CHAR' in dt or 'STRING' in dt or 'VARCHAR' in dt:")
|
|
735
|
+
lines.append(" return str(value)")
|
|
736
|
+
lines.append(" elif 'DATE' in dt or 'TIMESTAMP' in dt:")
|
|
737
|
+
lines.append(" return to_date(value)")
|
|
738
|
+
lines.append(" return value")
|
|
739
|
+
lines.append("")
|
|
740
|
+
lines.append("")
|
|
741
|
+
lines.append("def set_date_part(part, date_val, value):")
|
|
742
|
+
lines.append(' """Informatica SET_DATE_PART equivalent."""')
|
|
743
|
+
lines.append(" if date_val is None:")
|
|
744
|
+
lines.append(" return None")
|
|
745
|
+
lines.append(" if isinstance(date_val, str):")
|
|
746
|
+
lines.append(" date_val = datetime.fromisoformat(date_val)")
|
|
747
|
+
lines.append(" p = part.upper()")
|
|
748
|
+
lines.append(" if p in ('YYYY', 'YY', 'YEAR'):")
|
|
749
|
+
lines.append(" return date_val.replace(year=int(value))")
|
|
750
|
+
lines.append(" elif p in ('MM', 'MON', 'MONTH'):")
|
|
751
|
+
lines.append(" return date_val.replace(month=int(value))")
|
|
752
|
+
lines.append(" elif p in ('DD', 'DAY'):")
|
|
753
|
+
lines.append(" return date_val.replace(day=int(value))")
|
|
754
|
+
lines.append(" elif p in ('HH', 'HH24', 'HOUR'):")
|
|
755
|
+
lines.append(" return date_val.replace(hour=int(value))")
|
|
756
|
+
lines.append(" elif p in ('MI', 'MINUTE'):")
|
|
757
|
+
lines.append(" return date_val.replace(minute=int(value))")
|
|
758
|
+
lines.append(" elif p in ('SS', 'SECOND'):")
|
|
759
|
+
lines.append(" return date_val.replace(second=int(value))")
|
|
760
|
+
lines.append(" return date_val")
|
|
761
|
+
lines.append("")
|
|
762
|
+
lines.append("")
|
|
763
|
+
lines.append("def date_diff(date1, date2, part='DD'):")
|
|
764
|
+
lines.append(' """Informatica DATE_DIFF equivalent."""')
|
|
765
|
+
lines.append(" if date1 is None or date2 is None:")
|
|
766
|
+
lines.append(" return None")
|
|
767
|
+
lines.append(" if isinstance(date1, str):")
|
|
768
|
+
lines.append(" date1 = datetime.fromisoformat(date1)")
|
|
769
|
+
lines.append(" if isinstance(date2, str):")
|
|
770
|
+
lines.append(" date2 = datetime.fromisoformat(date2)")
|
|
771
|
+
lines.append(" delta = date1 - date2")
|
|
772
|
+
lines.append(" p = part.upper()")
|
|
773
|
+
lines.append(" if p in ('DD', 'DAY', 'D'):")
|
|
774
|
+
lines.append(" return delta.days")
|
|
775
|
+
lines.append(" elif p in ('HH', 'HOUR'):")
|
|
776
|
+
lines.append(" return int(delta.total_seconds() / 3600)")
|
|
777
|
+
lines.append(" elif p in ('MI', 'MINUTE'):")
|
|
778
|
+
lines.append(" return int(delta.total_seconds() / 60)")
|
|
779
|
+
lines.append(" elif p in ('SS', 'SECOND'):")
|
|
780
|
+
lines.append(" return int(delta.total_seconds())")
|
|
781
|
+
lines.append(" elif p in ('MM', 'MONTH'):")
|
|
782
|
+
lines.append(" return (date1.year - date2.year) * 12 + (date1.month - date2.month)")
|
|
783
|
+
lines.append(" elif p in ('YYYY', 'YEAR'):")
|
|
784
|
+
lines.append(" return date1.year - date2.year")
|
|
785
|
+
lines.append(" return delta.days")
|
|
786
|
+
lines.append("")
|
|
787
|
+
lines.append("")
|
|
788
|
+
lines.append("def date_compare(date1, date2):")
|
|
789
|
+
lines.append(' """Informatica DATE_COMPARE equivalent. Returns -1, 0, or 1."""')
|
|
790
|
+
lines.append(" if date1 is None and date2 is None:")
|
|
791
|
+
lines.append(" return 0")
|
|
792
|
+
lines.append(" if date1 is None:")
|
|
793
|
+
lines.append(" return -1")
|
|
794
|
+
lines.append(" if date2 is None:")
|
|
795
|
+
lines.append(" return 1")
|
|
796
|
+
lines.append(" if isinstance(date1, str):")
|
|
797
|
+
lines.append(" date1 = datetime.fromisoformat(date1)")
|
|
798
|
+
lines.append(" if isinstance(date2, str):")
|
|
799
|
+
lines.append(" date2 = datetime.fromisoformat(date2)")
|
|
800
|
+
lines.append(" if date1 < date2:")
|
|
801
|
+
lines.append(" return -1")
|
|
802
|
+
lines.append(" elif date1 > date2:")
|
|
803
|
+
lines.append(" return 1")
|
|
804
|
+
lines.append(" return 0")
|
|
805
|
+
lines.append("")
|
|
806
|
+
lines.append("")
|
|
807
|
+
lines.append("def last_day(date_val):")
|
|
808
|
+
lines.append(' """Informatica LAST_DAY equivalent."""')
|
|
809
|
+
lines.append(" if date_val is None:")
|
|
810
|
+
lines.append(" return None")
|
|
811
|
+
lines.append(" if isinstance(date_val, str):")
|
|
812
|
+
lines.append(" date_val = datetime.fromisoformat(date_val)")
|
|
813
|
+
lines.append(" import calendar")
|
|
814
|
+
lines.append(" last = calendar.monthrange(date_val.year, date_val.month)[1]")
|
|
815
|
+
lines.append(" return date_val.replace(day=last)")
|
|
816
|
+
lines.append("")
|
|
817
|
+
lines.append("")
|
|
818
|
+
lines.append("def make_date_time(year, month, day, hour=0, minute=0, second=0):")
|
|
819
|
+
lines.append(' """Informatica MAKE_DATE_TIME equivalent."""')
|
|
820
|
+
lines.append(" return datetime(int(year), int(month), int(day), int(hour), int(minute), int(second))")
|
|
821
|
+
lines.append("")
|
|
822
|
+
lines.append("")
|
|
823
|
+
lines.append("def trunc(value, precision=0):")
|
|
824
|
+
lines.append(' """Informatica TRUNC equivalent (numeric or date)."""')
|
|
825
|
+
lines.append(" if value is None:")
|
|
826
|
+
lines.append(" return None")
|
|
827
|
+
lines.append(" if hasattr(value, 'replace') and hasattr(value, 'year'):")
|
|
828
|
+
lines.append(" return value.replace(hour=0, minute=0, second=0, microsecond=0)")
|
|
829
|
+
lines.append(" import math")
|
|
830
|
+
lines.append(" factor = 10 ** int(precision)")
|
|
831
|
+
lines.append(" return math.trunc(float(value) * factor) / factor")
|
|
832
|
+
lines.append("")
|
|
833
|
+
lines.append("")
|
|
834
|
+
lines.append("def round_val(value, precision=0):")
|
|
835
|
+
lines.append(' """Informatica ROUND equivalent."""')
|
|
836
|
+
lines.append(" if value is None:")
|
|
837
|
+
lines.append(" return None")
|
|
838
|
+
lines.append(" return round(float(value), int(precision))")
|
|
839
|
+
lines.append("")
|
|
840
|
+
lines.append("")
|
|
841
|
+
lines.append("def abs_val(value):")
|
|
842
|
+
lines.append(' """Informatica ABS equivalent."""')
|
|
843
|
+
lines.append(" return abs(float(value)) if value is not None else None")
|
|
844
|
+
lines.append("")
|
|
845
|
+
lines.append("")
|
|
846
|
+
lines.append("def ceil_val(value):")
|
|
847
|
+
lines.append(' """Informatica CEIL equivalent."""')
|
|
848
|
+
lines.append(" import math")
|
|
849
|
+
lines.append(" return math.ceil(float(value)) if value is not None else None")
|
|
850
|
+
lines.append("")
|
|
851
|
+
lines.append("")
|
|
852
|
+
lines.append("def floor_val(value):")
|
|
853
|
+
lines.append(' """Informatica FLOOR equivalent."""')
|
|
854
|
+
lines.append(" import math")
|
|
855
|
+
lines.append(" return math.floor(float(value)) if value is not None else None")
|
|
856
|
+
lines.append("")
|
|
857
|
+
lines.append("")
|
|
858
|
+
lines.append("def mod_val(a, b):")
|
|
859
|
+
lines.append(' """Informatica MOD equivalent."""')
|
|
860
|
+
lines.append(" if a is None or b is None or float(b) == 0:")
|
|
861
|
+
lines.append(" return None")
|
|
862
|
+
lines.append(" return float(a) % float(b)")
|
|
863
|
+
lines.append("")
|
|
864
|
+
lines.append("")
|
|
865
|
+
lines.append("def power_val(base, exp):")
|
|
866
|
+
lines.append(' """Informatica POWER equivalent."""')
|
|
867
|
+
lines.append(" if base is None or exp is None:")
|
|
868
|
+
lines.append(" return None")
|
|
869
|
+
lines.append(" return float(base) ** float(exp)")
|
|
870
|
+
lines.append("")
|
|
871
|
+
lines.append("")
|
|
872
|
+
lines.append("def sqrt_val(value):")
|
|
873
|
+
lines.append(' """Informatica SQRT equivalent."""')
|
|
874
|
+
lines.append(" import math")
|
|
875
|
+
lines.append(" return math.sqrt(float(value)) if value is not None else None")
|
|
876
|
+
lines.append("")
|
|
877
|
+
lines.append("")
|
|
878
|
+
lines.append("def log_val(base, value):")
|
|
879
|
+
lines.append(' """Informatica LOG equivalent."""')
|
|
880
|
+
lines.append(" import math")
|
|
881
|
+
lines.append(" if value is None or base is None:")
|
|
882
|
+
lines.append(" return None")
|
|
883
|
+
lines.append(" return math.log(float(value), float(base))")
|
|
884
|
+
lines.append("")
|
|
885
|
+
lines.append("")
|
|
886
|
+
lines.append("def ln_val(value):")
|
|
887
|
+
lines.append(' """Informatica LN (natural log) equivalent."""')
|
|
888
|
+
lines.append(" import math")
|
|
889
|
+
lines.append(" return math.log(float(value)) if value is not None else None")
|
|
890
|
+
lines.append("")
|
|
891
|
+
lines.append("")
|
|
892
|
+
lines.append("def exp_val(value):")
|
|
893
|
+
lines.append(' """Informatica EXP equivalent."""')
|
|
894
|
+
lines.append(" import math")
|
|
895
|
+
lines.append(" return math.exp(float(value)) if value is not None else None")
|
|
896
|
+
lines.append("")
|
|
897
|
+
lines.append("")
|
|
898
|
+
lines.append("def sign_val(value):")
|
|
899
|
+
lines.append(' """Informatica SIGN equivalent."""')
|
|
900
|
+
lines.append(" if value is None:")
|
|
901
|
+
lines.append(" return None")
|
|
902
|
+
lines.append(" v = float(value)")
|
|
903
|
+
lines.append(" return 1 if v > 0 else (-1 if v < 0 else 0)")
|
|
904
|
+
lines.append("")
|
|
905
|
+
lines.append("")
|
|
906
|
+
lines.append("def rand_val(seed=None):")
|
|
907
|
+
lines.append(' """Informatica RAND equivalent."""')
|
|
908
|
+
lines.append(" import random")
|
|
909
|
+
lines.append(" if seed is not None:")
|
|
910
|
+
lines.append(" random.seed(seed)")
|
|
911
|
+
lines.append(" return random.random()")
|
|
912
|
+
lines.append("")
|
|
913
|
+
lines.append("")
|
|
914
|
+
lines.append("def greatest_val(*args):")
|
|
915
|
+
lines.append(' """Informatica GREATEST equivalent."""')
|
|
916
|
+
lines.append(" filtered = [a for a in args if a is not None]")
|
|
917
|
+
lines.append(" return max(filtered) if filtered else None")
|
|
918
|
+
lines.append("")
|
|
919
|
+
lines.append("")
|
|
920
|
+
lines.append("def least_val(*args):")
|
|
921
|
+
lines.append(' """Informatica LEAST equivalent."""')
|
|
922
|
+
lines.append(" filtered = [a for a in args if a is not None]")
|
|
923
|
+
lines.append(" return min(filtered) if filtered else None")
|
|
924
|
+
lines.append("")
|
|
925
|
+
lines.append("")
|
|
926
|
+
lines.append("def choose_expr(index, *values):")
|
|
927
|
+
lines.append(' """Informatica CHOOSE equivalent."""')
|
|
928
|
+
lines.append(" idx = int(index)")
|
|
929
|
+
lines.append(" if 1 <= idx <= len(values):")
|
|
930
|
+
lines.append(" return values[idx - 1]")
|
|
931
|
+
lines.append(" return None")
|
|
932
|
+
lines.append("")
|
|
933
|
+
lines.append("")
|
|
934
|
+
lines.append("def in_expr(value, *candidates):")
|
|
935
|
+
lines.append(' """Informatica IN equivalent."""')
|
|
936
|
+
lines.append(" return value in candidates")
|
|
937
|
+
lines.append("")
|
|
938
|
+
lines.append("")
|
|
939
|
+
lines.append("def max_val(*args):")
|
|
940
|
+
lines.append(' """Informatica MAX equivalent (row-level)."""')
|
|
941
|
+
lines.append(" filtered = [a for a in args if a is not None]")
|
|
942
|
+
lines.append(" return max(filtered) if filtered else None")
|
|
943
|
+
lines.append("")
|
|
944
|
+
lines.append("")
|
|
945
|
+
lines.append("def min_val(*args):")
|
|
946
|
+
lines.append(' """Informatica MIN equivalent (row-level)."""')
|
|
947
|
+
lines.append(" filtered = [a for a in args if a is not None]")
|
|
948
|
+
lines.append(" return min(filtered) if filtered else None")
|
|
949
|
+
lines.append("")
|
|
950
|
+
lines.append("")
|
|
951
|
+
lines.append("def sum_val(*args):")
|
|
952
|
+
lines.append(' """Informatica SUM equivalent (row-level)."""')
|
|
953
|
+
lines.append(" return sum(float(a) for a in args if a is not None)")
|
|
954
|
+
lines.append("")
|
|
955
|
+
lines.append("")
|
|
956
|
+
lines.append("def count_val(*args):")
|
|
957
|
+
lines.append(' """Informatica COUNT equivalent (row-level)."""')
|
|
958
|
+
lines.append(" return sum(1 for a in args if a is not None)")
|
|
959
|
+
lines.append("")
|
|
960
|
+
lines.append("")
|
|
961
|
+
lines.append("def avg_val(*args):")
|
|
962
|
+
lines.append(' """Informatica AVG equivalent (row-level)."""')
|
|
963
|
+
lines.append(" filtered = [float(a) for a in args if a is not None]")
|
|
964
|
+
lines.append(" return sum(filtered) / len(filtered) if filtered else None")
|
|
965
|
+
lines.append("")
|
|
966
|
+
lines.append("")
|
|
967
|
+
lines.append("def median_val(*args):")
|
|
968
|
+
lines.append(' """Informatica MEDIAN equivalent (row-level)."""')
|
|
969
|
+
lines.append(" import statistics")
|
|
970
|
+
lines.append(" filtered = [float(a) for a in args if a is not None]")
|
|
971
|
+
lines.append(" return statistics.median(filtered) if filtered else None")
|
|
972
|
+
lines.append("")
|
|
973
|
+
lines.append("")
|
|
974
|
+
lines.append("def stddev_val(*args):")
|
|
975
|
+
lines.append(' """Informatica STDDEV equivalent (row-level)."""')
|
|
976
|
+
lines.append(" import statistics")
|
|
977
|
+
lines.append(" filtered = [float(a) for a in args if a is not None]")
|
|
978
|
+
lines.append(" return statistics.stdev(filtered) if len(filtered) > 1 else 0")
|
|
979
|
+
lines.append("")
|
|
980
|
+
lines.append("")
|
|
981
|
+
lines.append("def variance_val(*args):")
|
|
982
|
+
lines.append(' """Informatica VARIANCE equivalent (row-level)."""')
|
|
983
|
+
lines.append(" import statistics")
|
|
984
|
+
lines.append(" filtered = [float(a) for a in args if a is not None]")
|
|
985
|
+
lines.append(" return statistics.variance(filtered) if len(filtered) > 1 else 0")
|
|
986
|
+
lines.append("")
|
|
987
|
+
lines.append("")
|
|
988
|
+
lines.append("def percentile_val(value, pct):")
|
|
989
|
+
lines.append(' """Informatica PERCENTILE equivalent."""')
|
|
990
|
+
lines.append(" return value")
|
|
991
|
+
lines.append("")
|
|
992
|
+
lines.append("")
|
|
993
|
+
lines.append("def first_val(*args):")
|
|
994
|
+
lines.append(' """Informatica FIRST equivalent."""')
|
|
995
|
+
lines.append(" for a in args:")
|
|
996
|
+
lines.append(" if a is not None:")
|
|
997
|
+
lines.append(" return a")
|
|
998
|
+
lines.append(" return None")
|
|
999
|
+
lines.append("")
|
|
1000
|
+
lines.append("")
|
|
1001
|
+
lines.append("def last_val(*args):")
|
|
1002
|
+
lines.append(' """Informatica LAST equivalent."""')
|
|
1003
|
+
lines.append(" result = None")
|
|
1004
|
+
lines.append(" for a in args:")
|
|
1005
|
+
lines.append(" if a is not None:")
|
|
1006
|
+
lines.append(" result = a")
|
|
1007
|
+
lines.append(" return result")
|
|
1008
|
+
lines.append("")
|
|
1009
|
+
lines.append("")
|
|
1010
|
+
lines.append("def moving_avg(value, window=3):")
|
|
1011
|
+
lines.append(' """Informatica MOVINGAVG equivalent."""')
|
|
1012
|
+
lines.append(" return value")
|
|
1013
|
+
lines.append("")
|
|
1014
|
+
lines.append("")
|
|
1015
|
+
lines.append("def moving_sum(value, window=3):")
|
|
1016
|
+
lines.append(' """Informatica MOVINGSUM equivalent."""')
|
|
1017
|
+
lines.append(" return value")
|
|
1018
|
+
lines.append("")
|
|
1019
|
+
lines.append("")
|
|
1020
|
+
lines.append("def cume(value):")
|
|
1021
|
+
lines.append(' """Informatica CUME equivalent."""')
|
|
1022
|
+
lines.append(" return value")
|
|
1023
|
+
lines.append("")
|
|
1024
|
+
lines.append("")
|
|
1025
|
+
lines.append("def set_count_variable(var_name, value=1):")
|
|
1026
|
+
lines.append(' """Informatica SETCOUNTVARIABLE equivalent."""')
|
|
1027
|
+
lines.append(" return set_variable(var_name, value)")
|
|
1028
|
+
lines.append("")
|
|
1029
|
+
lines.append("")
|
|
634
1030
|
lines.append("def raise_error(message):")
|
|
635
1031
|
lines.append(' """Informatica ERROR function equivalent."""')
|
|
636
1032
|
lines.append(" logger.error(f'INFORMATICA ERROR: {message}')")
|