@@ -576,50 +576,51 @@ def sanitize_dataset_column_names(spark: SparkSession, dataset_uri: str, context
576576 return sanitized_uri
577577
578578
579- def _exclude_problematic_columns (
580- spark : SparkSession ,
581- dataset_uri : str ,
582- context : BuildContext ,
583- config : Config ,
584- ) -> str :
585- """
586- Drop problematic columns identified during Phase 1 analysis.
579+ def _set_noop_filtered_dataset_uri (context : BuildContext , dataset_uri : str ) -> str :
580+ """Store no-op filtering result in context and return original URI."""
581+ context .excluded_columns = []
582+ context .scratch ["_filtered_dataset_uri" ] = dataset_uri
583+ return dataset_uri
587584
588- Args:
589- spark: SparkSession
590- dataset_uri: Dataset URI to filter (already sanitized)
591- context: Build context with problematic columns and targets
592- config: Configuration (reserved for future use)
593585
594- Returns:
595- URI of filtered dataset (or original if no exclusions needed)
596- """
597- _ = config
586+ def _get_problematic_columns_payload (context : BuildContext ) -> list [object ] | None :
587+ """Read and validate problematic columns payload from scratch."""
598588 problematic_columns = context .scratch .get (ScratchKeys .PROBLEMATIC_COLUMNS , [])
599-
600589 if not problematic_columns :
601590 logger .info ("No problematic columns flagged - skipping exclusion step" )
602- context .excluded_columns = []
603- context .scratch ["_filtered_dataset_uri" ] = dataset_uri
604- return dataset_uri
605-
591+ return None
606592 if not isinstance (problematic_columns , list ):
607593 logger .warning ("Problematic columns payload is not a list - skipping exclusion step" )
608- context .excluded_columns = []
609- context .scratch ["_filtered_dataset_uri" ] = dataset_uri
610- return dataset_uri
594+ return None
595+ return problematic_columns
611596
612- df = spark .read .parquet (dataset_uri )
613- available_columns = set (df .columns )
597+
598+ def _build_protected_columns_set (context : BuildContext ) -> set [str ]:
599+ """Build set of columns that can never be excluded."""
614600 protected_columns = set (context .output_targets or [])
615601 if context .group_column :
616602 protected_columns .add (context .group_column )
617603 if context .primary_input_column :
618604 protected_columns .add (context .primary_input_column )
605+ return protected_columns
606+
607+
608+ def _normalize_exclusion_reason (raw_reason : object ) -> str :
609+ """Normalize exclusion reason to a non-empty string."""
610+ if isinstance (raw_reason , str ) and raw_reason .strip ():
611+ return raw_reason
612+ if not raw_reason :
613+ return "unspecified"
614+ return str (raw_reason )
615+
619616
617+ def _filter_valid_exclusions (
618+ problematic_columns : list [object ], available_columns : set [str ], protected_columns : set [str ]
619+ ) -> tuple [list [str ], list [dict ], list [str ], list [str ], int ]:
620+ """Validate exclusion entries and return drop candidates + diagnostics."""
620621 columns_to_drop : list [str ] = []
621622 excluded_entries : list [dict ] = []
622- skipped_targets : list [str ] = []
623+ skipped_protected : list [str ] = []
623624 skipped_missing : list [str ] = []
624625 invalid_entries = 0
625626 seen : set [str ] = set ()
@@ -636,44 +637,71 @@ def _exclude_problematic_columns(
636637 continue
637638 seen .add (column )
638639 if column in protected_columns :
639- skipped_targets .append (column )
640+ skipped_protected .append (column )
640641 continue
641642 if column not in available_columns :
642643 skipped_missing .append (column )
643644 continue
644- reason = entry .get ("reason" ) or "unspecified"
645645 columns_to_drop .append (column )
646- excluded_entries .append ({"column" : column , "reason" : reason })
646+ excluded_entries .append ({"column" : column , "reason" : _normalize_exclusion_reason ( entry . get ( " reason" )) })
647647
648- if skipped_targets :
648+ return columns_to_drop , excluded_entries , skipped_protected , skipped_missing , invalid_entries
649+
650+
651+ def _exclude_problematic_columns (
652+ spark : SparkSession ,
653+ dataset_uri : str ,
654+ context : BuildContext ,
655+ config : Config | None ,
656+ ) -> str :
657+ """
658+ Drop problematic columns identified during Phase 1 analysis.
659+
660+ Args:
661+ spark: SparkSession
662+ dataset_uri: Dataset URI to filter (already sanitized)
663+ context: Build context with problematic columns and targets
664+ config: Configuration (reserved for future use)
665+
666+ Returns:
667+ URI of filtered dataset (or original if no exclusions needed)
668+ """
669+ _ = config
670+ problematic_columns = _get_problematic_columns_payload (context )
671+ if problematic_columns is None :
672+ return _set_noop_filtered_dataset_uri (context , dataset_uri )
673+
674+ df = spark .read .parquet (dataset_uri )
675+ columns_to_drop , excluded_entries , skipped_protected , skipped_missing , invalid_entries = _filter_valid_exclusions (
676+ problematic_columns = problematic_columns ,
677+ available_columns = set (df .columns ),
678+ protected_columns = _build_protected_columns_set (context ),
679+ )
680+
681+ if skipped_protected :
649682 logger .warning (
650- "Problematic columns include target/group columns; skipping exclusions for: "
651- + ", " .join (sorted (skipped_targets ))
683+ "Problematic columns include protected columns; skipping exclusions for: "
684+ + ", " .join (sorted (skipped_protected ))
652685 )
653686 if skipped_missing :
654687 logger .warning (
655688 "Problematic columns not found in dataset; skipping exclusions for: " + ", " .join (sorted (skipped_missing ))
656689 )
657690 if invalid_entries :
658691 logger .warning (f"Skipped { invalid_entries } malformed problematic column entries" )
659-
660692 if not columns_to_drop :
661693 logger .info ("No valid problematic columns to exclude after validation" )
662- context .excluded_columns = []
663- context .scratch ["_filtered_dataset_uri" ] = dataset_uri
664- return dataset_uri
694+ return _set_noop_filtered_dataset_uri (context , dataset_uri )
665695
666696 logger .info (f"Excluding { len (columns_to_drop )} problematic columns from dataset" )
667697 for entry in excluded_entries :
668698 logger .info (f" drop '{ entry ['column' ]} ': { entry ['reason' ]} " )
669699
670700 filtered_uri = f"{ context .work_dir } /{ DirNames .BUILD_DIR } /data/dataset_filtered.parquet"
671701 df .drop (* columns_to_drop ).write .mode ("overwrite" ).parquet (filtered_uri )
672-
673702 logger .info (f"✓ Filtered dataset saved: { filtered_uri } " )
674703 context .excluded_columns = excluded_entries
675704 context .scratch ["_filtered_dataset_uri" ] = filtered_uri
676-
677705 return filtered_uri
678706
679707
0 commit comments