Source code for cursus.steps.configs.config_package_step

from pydantic import Field, model_validator
from typing import Dict, List, Optional, TYPE_CHECKING

from .config_processing_step_base import ProcessingStepConfigBase

# Import for type hints only
if TYPE_CHECKING:
    pass


[docs] class PackageConfig(ProcessingStepConfigBase): """ Configuration for a model packaging step. This configuration follows the three-tier field categorization: 1. Tier 1: Essential User Inputs - fields that users must explicitly provide 2. Tier 2: System Inputs with Defaults - fields with reasonable defaults that users can override 3. Tier 3: Derived Fields - fields calculated from other fields, stored in private attributes """ # ===== System Inputs with Defaults (Tier 2) ===== # These are fields with reasonable defaults that users can override processing_entry_point: str = Field( default="package.py", description="Entry point script for packaging." ) # Update to Pydantic V2 style model_config model_config = { "arbitrary_types_allowed": True, "validate_assignment": True, "extra": "allow", # Allow extra fields like __model_type__ and __model_module__ for type-aware serialization }
[docs] @model_validator(mode="after") def validate_config(self) -> "PackageConfig": """ Validate configuration and ensure defaults are set. This validator ensures that: 1. Entry point is provided 2. Script contract is available and valid 3. Required input paths are defined in the script contract """ # Basic validation if not self.processing_entry_point: raise ValueError("packaging step requires a processing_entry_point") # Validate script contract - this will be the source of truth contract = self.get_script_contract() if not contract: raise ValueError("Failed to load script contract") if "model_input" not in contract.expected_input_paths: raise ValueError("Script contract missing required input path: model_input") if "inference_scripts_input" not in contract.expected_input_paths: raise ValueError( "Script contract missing required input path: inference_scripts_input" ) return self
[docs] def get_environment_variables( self, declared_env_vars: Optional[List[str]] = None ) -> Dict[str, str]: """Packaging env vars (the single env source; moved here from the builder, FZ 31e1d3g). ``declared_env_vars`` accepted for the builder's names-driven contract but ignored — these are config-derived names (PIPELINE_NAME, REGION, …) emitted only when the underlying field is present, preserving the builder's original conditional-add behavior. """ env_vars: Dict[str, str] = {} if getattr(self, "pipeline_name", None) is not None: env_vars["PIPELINE_NAME"] = self.pipeline_name if getattr(self, "region", None) is not None: env_vars["REGION"] = self.region for attr, env_key in [ ("model_type", "MODEL_TYPE"), ("bucket", "BUCKET_NAME"), ("pipeline_version", "PIPELINE_VERSION"), ("model_objective", "MODEL_OBJECTIVE"), ]: value = getattr(self, attr, None) if value is not None: env_vars[env_key] = str(value) return env_vars
[docs] def inference_scripts_source(self) -> str: """Local source for the packaging step's ``inference_scripts_input`` (FZ 31e1d3i). The packaging step always mounts inference scripts from a LOCAL path (overriding any dependency-resolved value). Delegates to ``effective_source_dir`` — the single comprehensive source-dir resolver (hybrid ``processing_source_dir`` → hybrid ``source_dir`` → legacy values) on ProcessingStepConfigBase — falling back to the literal ``"inference"`` only when no source dir is configured. NOTE: the original builder used ``resolved_source_dir or source_dir or "inference"``, which reimplemented a PARTIAL version of this resolution and silently IGNORED ``processing_source_dir`` (falling through to ``"inference"`` when only that was set — a latent bug). Using ``effective_source_dir`` fixes that and removes the duplicated chain. """ return self.effective_source_dir or "inference"
# Removed get_script_path override - now inherits modernized version from ProcessingStepConfigBase # which includes hybrid resolution and comprehensive fallbacks # The contract fallback logic was deemed unnecessary since processing_entry_point has a default value