-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Labels
medium-priorityMedium priority issuesMedium priority issuesuxUser experience and interface issuesUser experience and interface issues
Description
Title: Improve error messages to be more actionable and user-friendly
Problem Description
Error messages throughout the application are generic, unhelpful, and don't guide users toward solutions. Users receive cryptic error messages without context, suggestions, or examples of how to fix the problem.
Current Examples of Poor Error Messages
Example 1: Invalid filter condition
$ xl filter data.xlsx "age >> 30"
Invalid condition: ParseError
# What does this mean? How do I fix it?Example 2: Column not found
$ xl filter data.xlsx "ag > 30"
Invalid condition: ColumnNotFoundError
# Which column? What are available columns?Example 3: File not found
$ xl filter data.xlsx "age > 30"
File not found: data.xlsx
# Should I check the path? Did I misspell it?Example 4: Invalid aggregation
$ xl group sales.xlsx --by Region --aggregate "Amount:avrage"
Invalid function: InvalidFunctionError
# Did I misspell 'average'? What functions are available?What Makes Error Messages Poor
- No context: Don't explain WHAT went wrong
- No guidance: Don't explain HOW to fix it
- No examples: Don't show correct usage
- Technical jargon: Use class names instead of plain English
- No suggestions: Don't offer alternatives or similar commands
- Missing details: Don't show relevant information (line numbers, available values, etc.)
Real-World Impact
User Story 1: New user frustration
User: $ xl filter sales.xlsx "Amount > 1000"
Output: Invalid condition: QueryFailedError
User thoughts: "What's a QueryFailedError? What did I do wrong?
Is it the column name? The syntax? The value?"
User action: Gives up and uses Excel instead
User Story 2: Wasted time debugging
User: $ xl filter data.xlsx "user_id == 'ABC123'"
Output: Invalid condition: ColumnNotFoundError
User: "But user_id exists! Let me check..."
[10 minutes of debugging]
User: "Oh, it's 'UserID' not 'user_id'! Case sensitivity!"
Could have been saved if error said: "Column 'user_id' not found.
Did you mean 'UserID'?"
User Story 3: Documentation rabbit hole
User: $ xl transform data.xlsx --col "Amount" --expr "log(Amount)"
Output: Invalid expression: InvalidExpressionError
User: "What expressions are supported?"
[Has to search documentation for 10 minutes]
Could have been shown in error message!
Affected Areas
All commands and operations:
- Filter conditions
- Transform expressions
- Aggregation specifications
- File operations
- Column references
- Data validation errors
Proposed Solution
1. Create Error Message Builder
# excel_toolkit/core/errors.py
"""Enhanced error messages with context and guidance."""
from typing import Any, List, Optional
import pandas as pd
class UserFacingError(Exception):
"""Base class for user-facing errors with helpful messages."""
def __init__(
self,
message: str,
context: str = "",
suggestions: List[str] | None = None,
examples: List[str] | None = None
):
self.message = message
self.context = context
self.suggestions = suggestions or []
self.examples = examples or []
def __str__(self):
parts = [f"❌ {self.message}"]
if self.context:
parts.append(f"\n📋 Context: {self.context}")
if self.suggestions:
parts.append("\n💡 Suggestions:")
for i, suggestion in enumerate(self.suggestions, 1):
parts.append(f" {i}. {suggestion}")
if self.examples:
parts.append("\n✨ Examples:")
for example in self.examples:
parts.append(f" • {example}")
return "\n".join(parts)
class ColumnNotFoundError(UserFacingError):
"""Column not found with helpful suggestions."""
def __init__(self, column: str, available_columns: List[str]):
# Find similar columns
similar = find_similar_columns(column, available_columns)
suggestions = []
if similar:
suggestions.append(f"Did you mean: {', '.join(similar)}?")
suggestions.append(f"Available columns: {', '.join(available_columns[:10])}")
if len(available_columns) > 10:
suggestions.append(f"... and {len(available_columns) - 10} more")
examples = [
f'xl filter data.xlsx "{column[0].upper()}{column[1:]} > 100"',
]
super().__init__(
message=f"Column '{column}' not found",
context=f"The file has {len(available_columns)} columns",
suggestions=suggestions,
examples=examples
)
def find_similar_columns(target: str, columns: List[str], max_distance: int = 2) -> List[str]:
"""Find columns with similar names (for typo correction)."""
import difflib
matches = difflib.get_close_matches(
target.lower(),
[c.lower() for c in columns],
n=3,
cutoff=0.6
)
# Return original casing
return [c for c in columns if c.lower() in matches]2. Update Error Handling Throughout
# operations/filtering.py
def apply_filter(df: pd.DataFrame, condition: str) -> Result[pd.DataFrame, FilterError]:
"""Apply filter with enhanced error messages."""
# Validate columns exist
columns_in_condition = extract_columns(condition)
for col in columns_in_condition:
if col not in df.columns:
from excel_toolkit.core.errors import ColumnNotFoundError
raise ColumnNotFoundError(col, list(df.columns))
# Rest of filtering logic...3. Add Command-Specific Error Helpers
# commands/filter.py
def show_filter_error(error: Exception):
"""Show helpful error message for filter command."""
if isinstance(error, ColumnNotFoundError):
# Already formatted by ColumnNotFoundError
typer.echo(str(error), err=True)
elif isinstance(error, ParseError):
typer.echo("❌ Invalid filter condition syntax", err=True)
typer.echo("\n💡 Syntax tips:", err=True)
typer.echo(" • Comparisons: age > 30, price >= 100", err=True)
typer.echo(" • Strings: name == 'John'", err=True)
typer.echo(" • Logical: age > 25 and city == 'Paris'", err=True)
typer.echo(" • Null checks: value.isna(), value.notna()", err=True)
typer.echo("\n✨ Examples:", err=True)
typer.echo(" xl filter data.xlsx 'age > 30'", err=True)
typer.echo(" xl filter data.csv \"city == 'Paris'\"", err=True)
typer.echo(" xl filter data.xlsx 'amount > 1000 and status == \"active\"'", err=True)
elif isinstance(error, QueryFailedError):
typer.echo("❌ Failed to execute filter condition", err=True)
typer.echo(f"\n📋 Condition: {error.condition}", err=True)
# Try to give specific advice
if "SyntaxError" in str(error):
typer.echo("\n💡 Check for:", err=True)
typer.echo(" • Balanced quotes: name == 'John'", err=True)
typer.echo(" • Balanced parentheses: (age > 30) or (amount < 100)", err=True)4. Before/After Examples
Before:
$ xl filter data.xlsx "ag > 30"
Invalid condition: ColumnNotFoundErrorAfter:
$ xl filter data.xlsx "ag > 30"
❌ Column 'ag' not found
📋 Context: The file has 5 columns
💡 Suggestions:
1. Did you mean: age?
2. Available columns: id, age, name, city, amount
✨ Examples:
• xl filter data.xlsx "age > 100"Before:
$ xl transform data.xlsx --col Amount --expr "log(Amount)"
Invalid expression: InvalidExpressionErrorAfter:
$ xl transform data.xlsx --col Amount --expr "log(Amount)"
❌ Invalid expression: Function 'log' is not supported
📋 Context: Transform expressions support basic math operations
💡 Suggestions:
1. Use numpy functions: np.log(Amount)
2. Basic math: Amount * 2, Amount + 100
3. Available operators: +, -, *, /, **, %
✨ Examples:
• xl transform data.xlsx --col Amount --expr "Amount * 1.1"
• xl transform data.xlsx --col Price --expr "Price * 0.9 - 5"5. Add Verbose Error Mode
# cli.py
@app.command()
def filter(
file_path: str,
condition: str,
verbose: bool = typer.Option(False, "--verbose", "-v", help="Show detailed error messages")
):
"""Filter rows with optional verbose errors."""
try:
# ... filtering logic ...
pass
except Exception as e:
if verbose:
# Show stack trace and technical details
typer.echo(traceback.format_exc(), err=True)
else:
# Show user-friendly message
show_filter_error(e)Implementation Priority
- High Priority: Column not found (most common error)
- High Priority: Invalid filter condition syntax
- Medium Priority: Invalid aggregation functions
- Medium Priority: File operation errors
- Low Priority: All other error messages
Related Issues
- Missing help context (Join operations can create Cartesian products and crash systems #18)
- No input sanitization (Inconsistent option names across commands (--by, -c, -g, --columns, etc.) #13)
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
medium-priorityMedium priority issuesMedium priority issuesuxUser experience and interface issuesUser experience and interface issues