Skip to content

Commit 28b3d17

Browse files
fix: address review feedback
1 parent 476481e commit 28b3d17

4 files changed

Lines changed: 71 additions & 43 deletions

File tree

plexe/CODE_INDEX.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Code Index: plexe
22

3-
> Generated on 2026-02-27 15:18:20
3+
> Generated on 2026-02-27 15:32:05
44
55
Code structure and public interface documentation for the **plexe** package.
66

plexe/workflow.py

Lines changed: 68 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -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

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "plexe"
3-
version = "1.3.0"
3+
version = "1.3.3"
44
description = "An agentic framework for building ML models from natural language"
55
authors = [
66
"Marcello De Bernardi <mdebernardi@plexe.ai>",

tests/CODE_INDEX.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Code Index: tests
22

3-
> Generated on 2026-02-27 15:18:20
3+
> Generated on 2026-02-27 15:32:05
44
55
Test suite structure and test case documentation.
66

0 commit comments

Comments
 (0)