"""Data loading, schema extraction, and safe code execution.""" import io import traceback import numpy as np import pandas as pd def load_dataframe(uploaded_file) -> tuple[pd.DataFrame, str]: """Load a CSV or Excel file into a DataFrame. Returns (df, error_message).""" try: filename = uploaded_file.name.lower() if filename.endswith(".csv"): df = pd.read_csv(uploaded_file) elif filename.endswith((".xlsx", ".xls")): df = pd.read_excel(uploaded_file) else: return None, f"Unsupported file type: {uploaded_file.name}. Use CSV or Excel." return df, None except Exception as e: return None, f"Failed to load file: {e}" def get_schema_info(df: pd.DataFrame) -> str: """Return a concise schema description for the LLM prompt.""" lines = [f"Shape: {df.shape[0]} rows × {df.shape[1]} columns", "", "Columns:"] for col in df.columns: dtype = str(df[col].dtype) n_unique = df[col].nunique() n_null = df[col].isnull().sum() if df[col].dtype in [np.int64, np.float64, "int64", "float64"]: stats = f"min={df[col].min():.0f}, max={df[col].max():.0f}, mean={df[col].mean():.0f}" elif n_unique <= 20: sample_vals = df[col].dropna().unique()[:8].tolist() stats = f"values: {sample_vals}" else: sample_vals = df[col].dropna().unique()[:5].tolist() stats = f"sample: {sample_vals}" null_info = f", {n_null} nulls" if n_null > 0 else "" lines.append(f" - {col} ({dtype}, {n_unique} unique{null_info}): {stats}") return "\n".join(lines) def get_sample_rows(df: pd.DataFrame, n: int = 5) -> str: """Return a string representation of the first n rows.""" return df.head(n).to_string(index=False) def _strip_imports(code: str) -> str: """Remove import statements — pd and np are already in the namespace.""" lines = [ line for line in code.splitlines() if not line.strip().startswith(("import ", "from ")) ] return "\n".join(lines) def execute_pandas_code(code: str, df: pd.DataFrame) -> tuple[pd.DataFrame, str]: """ Execute pandas code in a restricted namespace. Returns (result_df, error_message). """ code = _strip_imports(code) namespace = { "df": df.copy(), "pd": pd, "np": np, "__builtins__": { "len": len, "range": range, "list": list, "dict": dict, "str": str, "int": int, "float": float, "bool": bool, "print": print, "sorted": sorted, "zip": zip, "enumerate": enumerate, "min": min, "max": max, "sum": sum, "abs": abs, "round": round, "isinstance": isinstance, }, } try: exec(code, namespace) # noqa: S102 result_df = namespace.get("result_df") if result_df is None: return None, "Code did not create 'result_df'. Make sure your code assigns a DataFrame to 'result_df'." if not isinstance(result_df, pd.DataFrame): return None, f"'result_df' must be a pandas DataFrame, got {type(result_df).__name__}." return result_df, None except Exception: return None, f"Code execution error:\n{traceback.format_exc()}"