informatica-python 1.9.3__py3-none-any.whl → 1.9.4__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.
@@ -7,7 +7,7 @@ Licensed under the MIT License.
7
7
 
8
8
  from informatica_python.converter import InformaticaConverter
9
9
 
10
- __version__ = "1.9.3"
10
+ __version__ = "1.9.4"
11
11
  __author__ = "Nick"
12
12
  __license__ = "MIT"
13
13
  __all__ = ["InformaticaConverter"]
@@ -757,7 +757,7 @@ def _generate_transformation(lines, tx, connector_graph, source_dfs, transform_m
757
757
  elif tx_type in ("joiner",):
758
758
  _gen_joiner_transform(lines, tx, tx_safe, input_df, input_sources, source_dfs, connector_graph, data_lib)
759
759
  elif tx_type in ("lookup procedure", "lookup"):
760
- _gen_lookup_transform(lines, tx, tx_safe, input_df, source_dfs, data_lib)
760
+ _gen_lookup_transform(lines, tx, tx_safe, input_df, source_dfs, connector_graph, data_lib)
761
761
  elif tx_type == "router":
762
762
  _gen_router_transform(lines, tx, tx_safe, input_df, source_dfs)
763
763
  elif tx_type in ("union",):
@@ -982,7 +982,7 @@ def _gen_joiner_transform(lines, tx, tx_safe, input_df, input_sources, source_df
982
982
  source_dfs[tx.name] = f"df_{tx_safe}"
983
983
 
984
984
 
985
- def _gen_lookup_transform(lines, tx, tx_safe, input_df, source_dfs, data_lib="pandas"):
985
+ def _gen_lookup_transform(lines, tx, tx_safe, input_df, source_dfs, connector_graph=None, data_lib="pandas"):
986
986
  lookup_table = ""
987
987
  lookup_sql = ""
988
988
  lookup_condition = ""
@@ -1012,6 +1012,11 @@ def _gen_lookup_transform(lines, tx, tx_safe, input_df, source_dfs, data_lib="pa
1012
1012
 
1013
1013
  all_output_fields = return_fields + lookup_output_fields
1014
1014
 
1015
+ port_to_col = {}
1016
+ if connector_graph and tx.name in connector_graph.get("to", {}):
1017
+ for conn in connector_graph["to"][tx.name]:
1018
+ port_to_col[conn.to_field.lower()] = conn.from_field
1019
+
1015
1020
  lines.append(f" # Lookup: {lookup_table or tx.name}")
1016
1021
  if lookup_sql:
1017
1022
  _emit_sql_with_params(lines, f"lkp_sql_{tx_safe}", lookup_sql)
@@ -1020,10 +1025,13 @@ def _gen_lookup_transform(lines, tx, tx_safe, input_df, source_dfs, data_lib="pa
1020
1025
  lines.append(f" df_lkp_{tx_safe} = read_from_db(config, 'SELECT * FROM {lookup_table}', 'default')")
1021
1026
  else:
1022
1027
  empty_expr = lib_empty_df(data_lib)
1023
- lines.append(f" df_lkp_{tx_safe} = {empty_expr}")
1028
+ lines.append(f" df_lkp_{tx_safe} = {empty_expr} # WARNING: no lookup table/SQL override found")
1024
1029
 
1025
1030
  input_keys, lookup_keys = parse_lookup_condition(lookup_condition)
1026
1031
 
1032
+ if input_keys and port_to_col:
1033
+ input_keys = [port_to_col.get(k.lower(), k) for k in input_keys]
1034
+
1027
1035
  if input_keys and lookup_keys:
1028
1036
  lines.append(f" # Lookup condition: {lookup_condition}")
1029
1037
 
@@ -1078,12 +1086,23 @@ def _gen_router_transform(lines, tx, tx_safe, input_df, source_dfs):
1078
1086
  if "Group Filter Condition" in attr.name:
1079
1087
  group_conditions[attr.name] = attr.value
1080
1088
 
1089
+ remaining_mask_parts = []
1081
1090
  if group_conditions:
1082
1091
  for i, (gname, cond) in enumerate(group_conditions.items()):
1083
- expr_py = convert_expression(cond) if cond else "True"
1084
- lines.append(f" df_{tx_safe}_group{i} = {input_df}[{expr_py}].copy() # {gname}")
1092
+ if cond and cond.strip():
1093
+ expr_py = convert_filter_vectorized(cond, input_df)
1094
+ else:
1095
+ expr_py = f"pd.Series(True, index={input_df}.index)"
1096
+ mask_var = f"_router_mask_{tx_safe}_{i}"
1097
+ lines.append(f" {mask_var} = {expr_py} # {gname}")
1098
+ lines.append(f" df_{tx_safe}_group{i} = {input_df}[{mask_var}].copy()")
1085
1099
  source_dfs[f"{tx.name}_group{i}"] = f"df_{tx_safe}_group{i}"
1086
- lines.append(f" df_{tx_safe} = {input_df}.copy() # Default group")
1100
+ remaining_mask_parts.append(f"~{mask_var}")
1101
+ if remaining_mask_parts:
1102
+ lines.append(f" _router_default_mask = {' & '.join(remaining_mask_parts)}")
1103
+ lines.append(f" df_{tx_safe} = {input_df}[_router_default_mask].copy() # Default group")
1104
+ else:
1105
+ lines.append(f" df_{tx_safe} = {input_df}.copy() # Default group")
1087
1106
  source_dfs[tx.name] = f"df_{tx_safe}"
1088
1107
 
1089
1108
 
@@ -248,6 +248,7 @@ def _convert_infa_date_format(fmt_str):
248
248
  fmt = fmt.replace("Mon", "%b").replace("MON", "%b")
249
249
  fmt = fmt.replace("HH24", "%H").replace("HH12", "%I").replace("HH", "%H")
250
250
  fmt = fmt.replace("MI", "%M").replace("SS", "%S")
251
+ fmt = fmt.replace("US", "%f").replace("NS", "%f").replace("MS", "%f")
251
252
  return fmt
252
253
 
253
254
 
@@ -548,7 +549,7 @@ def _vec_recursive(expr, df_var):
548
549
  'RTRIM': f'.str.rstrip("{char_arg}")',
549
550
  'TRIM': f'.str.strip("{char_arg}")',
550
551
  }
551
- return f'{inner_val}{method_map[func_name.upper()]}'
552
+ return f'{inner_val}.astype(str){method_map[func_name.upper()]}'
552
553
 
553
554
  upper_result = _find_func_call(cleaned, 'UPPER')
554
555
  if upper_result and upper_result[0] == 0 and upper_result[1] == len(cleaned):
@@ -584,7 +585,7 @@ def _vec_recursive(expr, df_var):
584
585
  if len(args) >= 2:
585
586
  field_val = _vec_recursive(args[0], df_var)
586
587
  try:
587
- start = int(args[1].strip()) - 1
588
+ start = max(int(args[1].strip()) - 1, 0)
588
589
  except ValueError:
589
590
  start_val = _vec_recursive(args[1], df_var)
590
591
  if len(args) >= 3:
@@ -722,7 +723,11 @@ def _vec_recursive(expr, df_var):
722
723
  field_val = _vec_recursive(args[0], df_var)
723
724
  pattern_val = args[1].strip().strip("'\"")
724
725
  if func_name == 'REG_EXTRACT':
725
- return f'{field_val}.str.extract(r"({pattern_val})", expand=False)'
726
+ if re.search(r'(?<!\\)\((?!\?)', pattern_val):
727
+ extract_pat = pattern_val
728
+ else:
729
+ extract_pat = f'({pattern_val})'
730
+ return f'{field_val}.str.extract(r"{extract_pat}", expand=False)'
726
731
  elif func_name == 'REG_REPLACE':
727
732
  replace_val = args[2].strip().strip("'\"") if len(args) >= 3 else ''
728
733
  return f'{field_val}.str.replace(r"{pattern_val}", "{replace_val}", regex=True)'
@@ -894,7 +899,8 @@ def _vec_recursive(expr, df_var):
894
899
  'True', 'False', 'None', 'and', 'or', 'not', 'np', 'pd', 'get_variable',
895
900
  'str', 'int', 'float', 'bool', 'len', 'abs', 'round',
896
901
  'fillna', 'astype', 'isna', 'notna', 'where', 'errors', 'coerce',
897
- 'lookup_func',
902
+ 'lookup_func', 'expand', 'extract', 'regex', 'contains', 'replace',
903
+ 'upper', 'lower', 'strip', 'lstrip', 'rstrip', 'dt', 'copy',
898
904
  }
899
905
  converted = _substitute_fields(converted, df_var, skip_words)
900
906
 
@@ -904,6 +910,8 @@ def _vec_recursive(expr, df_var):
904
910
  converted = re.sub(r'<>', '!=', converted)
905
911
  converted = re.sub(r'(?<![<>!=])=(?!=)', '==', converted)
906
912
  converted = re.sub(r'\berrors\s*==\s*(["\'])', r'errors=\1', converted)
913
+ converted = re.sub(r'\bexpand\s*==\s*', 'expand=', converted)
914
+ converted = re.sub(r'\bregex\s*==\s*', 'regex=', converted)
907
915
 
908
916
  converted = re.sub(r'\s+', ' ', converted).strip()
909
917
 
@@ -1044,8 +1052,14 @@ def _vectorize_simple(part, df_var):
1044
1052
  'True', 'False', 'None', 'and', 'or', 'not', 'np', 'pd',
1045
1053
  'str', 'int', 'float', 'isna', 'notna', 'fillna',
1046
1054
  'get_variable', 'lookup_func', 'isin', 'eq',
1055
+ 'expand', 'extract', 'astype', 'errors', 'coerce', 'regex',
1056
+ 'contains', 'replace', 'upper', 'lower', 'strip', 'lstrip', 'rstrip',
1057
+ 'dt', 'len', 'copy', 'abs', 'round', 'where', 'bool',
1047
1058
  }
1048
1059
  c = _substitute_fields(c, df_var, skip_words)
1060
+ c = re.sub(r'\bexpand\s*==\s*', 'expand=', c)
1061
+ c = re.sub(r'\berrors\s*==\s*', 'errors=', c)
1062
+ c = re.sub(r'\bregex\s*==\s*', 'regex=', c)
1049
1063
 
1050
1064
  return c
1051
1065
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: informatica-python
3
- Version: 1.9.3
3
+ Version: 1.9.4
4
4
  Summary: Convert Informatica PowerCenter workflow XML to Python/PySpark code
5
5
  Author: Nick
6
6
  License: MIT
@@ -430,7 +430,7 @@ The generated `helper_functions.py` provides a complete runtime library:
430
430
  - **Generated code formatting**: Consistent `# ---` section headers for Source Qualifiers, Transforms, and Target Writes; metadata comments (database type, field lists); column mapping and write operation comments; clean blank line handling
431
431
  - **Source/target detection**: Case-insensitive instance type matching
432
432
  - **Session→mapping inference**: Longest-suffix-match strategy for ambiguous mapping names
433
- - **646 tests** across unit, integration, expression, and formatting test suites
433
+ - **663 tests** across unit, integration, expression, and formatting test suites
434
434
 
435
435
  ### v1.9.2 (Phase 8)
436
436
  - Mapping output files now use real mapping names (e.g., `mapping_m_customer_load.py`) instead of generic numeric indices (`mapping_1.py`)
@@ -495,7 +495,7 @@ The generated `helper_functions.py` provides a complete runtime library:
495
495
  cd informatica_python
496
496
  pip install -e ".[dev]"
497
497
 
498
- # Run tests (646 tests)
498
+ # Run tests (663 tests)
499
499
  pytest tests/ -v
500
500
  ```
501
501
 
@@ -1,4 +1,4 @@
1
- informatica_python/__init__.py,sha256=o9kEVkHnEwXAD7hhY8YbN6G8RP4Mqby_q8CpjfbiknQ,337
1
+ informatica_python/__init__.py,sha256=UiVcrgRjgo439mxIWb1Oz1caKLcmgl0DTlz5-GrgKjs,337
2
2
  informatica_python/cli.py,sha256=gFwg0O99vKM-OLO0HoHA4emd-6qrgjMNqa9T59e4e_s,2905
3
3
  informatica_python/converter.py,sha256=xCuWrYzDji0yN72D3QqOgZCVVM2j3k2_CvlGplCWxLU,22779
4
4
  informatica_python/models.py,sha256=G_C2WfQL-ykKjNj23m8vKFtLZYrQozp99HJzrLTKG1Y,17293
@@ -7,17 +7,17 @@ informatica_python/generators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5N
7
7
  informatica_python/generators/config_gen.py,sha256=4tqcNKTB06kyGZIiM4yl0q97q_i3zeCHXTjuE1dNFKY,5726
8
8
  informatica_python/generators/error_log_gen.py,sha256=2cc0rEcblydHkb9VAMXlrH7WdSQ-CNqAXcwVk3FYZeM,21319
9
9
  informatica_python/generators/helper_gen.py,sha256=D6-UqNh09Qy2V7RimNgP-SzK_uB9YqAlsa0-cgLhf5o,72209
10
- informatica_python/generators/mapping_gen.py,sha256=gBVArcb8uODbgY3epdsldCbUywS-qo8CiKr7hcNjMnc,70654
10
+ informatica_python/generators/mapping_gen.py,sha256=TPcd9tIAhOAIZMbzPslUgPvF-FY_XkI7EfvCVf-yU50,71610
11
11
  informatica_python/generators/sql_gen.py,sha256=O8Y-aJz9EyFJ0DXeuISRt5yKwC3wlp2K3B0BHrmxrXw,4872
12
12
  informatica_python/generators/workflow_gen.py,sha256=_uSlBg31ZRMhMlCYk4hWDRBPaBROrepD8_v3QGEWJxE,18089
13
13
  informatica_python/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
14
  informatica_python/utils/datatype_map.py,sha256=iLOYg-iBKT4rMecGbrFkTpJj4yqs5S9HeBOTLUIWhX0,2809
15
- informatica_python/utils/expression_converter.py,sha256=CqkkTESMKxcYmVsDpNfn7VcZZe771uCIMy_0YQYq6pc,45946
15
+ informatica_python/utils/expression_converter.py,sha256=f8sNAhE0Yo8sdcVIPDjrw_uGfd5UTD8k1SN8NYApmhI,46846
16
16
  informatica_python/utils/lib_adapters.py,sha256=1ZtuMbgDg9Ukf-OF_EG1L_BeeR-6JQk8Kx3WwMfvNRU,6516
17
17
  informatica_python/utils/sql_dialect.py,sha256=_IHJbfu8a3mT_OvHpybgSfZKqz6mwVy5ItTKDRChqnU,5461
18
- informatica_python-1.9.3.dist-info/licenses/LICENSE,sha256=77RaRDdXgey1D90YZAjXqEQdBxWfvUQqLQX3pC1qjUE,1061
19
- informatica_python-1.9.3.dist-info/METADATA,sha256=VbfZWdzKE382RnkR7F2rs7PNL397g3PfglvugN4XVTw,26097
20
- informatica_python-1.9.3.dist-info/WHEEL,sha256=PovZm1ExVWmrRefZoXCfejlbKLnQI5SVIf1SWRV4QQI,97
21
- informatica_python-1.9.3.dist-info/entry_points.txt,sha256=030jjTrx-1oRRQ16HZz52rdcKS8R8_llnymsTUtn_Xc,67
22
- informatica_python-1.9.3.dist-info/top_level.txt,sha256=Dngg-WNteYi22XAJU2XKAQS8aZ52yM2LYC0tzxrlbVQ,19
23
- informatica_python-1.9.3.dist-info/RECORD,,
18
+ informatica_python-1.9.4.dist-info/licenses/LICENSE,sha256=77RaRDdXgey1D90YZAjXqEQdBxWfvUQqLQX3pC1qjUE,1061
19
+ informatica_python-1.9.4.dist-info/METADATA,sha256=0KXrQZPNvGQB-47LSGQDZv1hm_nN6YWBlhB8WtBCV4I,26097
20
+ informatica_python-1.9.4.dist-info/WHEEL,sha256=PovZm1ExVWmrRefZoXCfejlbKLnQI5SVIf1SWRV4QQI,97
21
+ informatica_python-1.9.4.dist-info/entry_points.txt,sha256=030jjTrx-1oRRQ16HZz52rdcKS8R8_llnymsTUtn_Xc,67
22
+ informatica_python-1.9.4.dist-info/top_level.txt,sha256=Dngg-WNteYi22XAJU2XKAQS8aZ52yM2LYC0tzxrlbVQ,19
23
+ informatica_python-1.9.4.dist-info/RECORD,,