Skip to content

Index

enable_colors(enabled=None)

Enable or disable color output.

Parameters:

Name Type Description Default
enabled bool | None

True to enable, False to disable, None for auto-detection

None

Returns:

Type Description
bool

Current color enable status

Examples:

>>> enable_colors(False)  # Disable colors
False
>>> enable_colors(True)   # Force enable colors
True
>>> enable_colors()       # Auto-detect
True  # (if terminal supports it)
Source code in src/sparkwheel/errors/formatters.py
def enable_colors(enabled: bool | None = None) -> bool:
    """Enable or disable color output.

    Args:
        enabled: True to enable, False to disable, None for auto-detection

    Returns:
        Current color enable status

    Examples:
        >>> enable_colors(False)  # Disable colors
        False
        >>> enable_colors(True)   # Force enable colors
        True
        >>> enable_colors()       # Auto-detect
        True  # (if terminal supports it)
    """
    global _COLORS_ENABLED

    if enabled is None:
        _COLORS_ENABLED = _supports_color()
    else:
        _COLORS_ENABLED = enabled

    return _COLORS_ENABLED

format_available_keys(config, max_keys=10)

Format available keys for display in error messages.

Parameters:

Name Type Description Default
config dict[str, Any]

Configuration dictionary to extract keys from

required
max_keys int

Maximum number of keys to display (default: 10)

10

Returns:

Type Description
str

Formatted string with available keys and their values (truncated if needed)

Examples:

>>> config = {"_target_": "torch.nn.Linear", "in_features": 784, "out_features": 10}
>>> print(format_available_keys(config))
Available keys:
  - _target_: "torch.nn.Linear"
  - in_features: 784
  - out_features: 10
Source code in src/sparkwheel/errors/context.py
def format_available_keys(config: dict[str, Any], max_keys: int = 10) -> str:
    """Format available keys for display in error messages.

    Args:
        config: Configuration dictionary to extract keys from
        max_keys: Maximum number of keys to display (default: 10)

    Returns:
        Formatted string with available keys and their values (truncated if needed)

    Examples:
        >>> config = {"_target_": "torch.nn.Linear", "in_features": 784, "out_features": 10}
        >>> print(format_available_keys(config))
        Available keys:
          - _target_: "torch.nn.Linear"
          - in_features: 784
          - out_features: 10
    """
    if not config or not isinstance(config, dict):
        return ""

    lines = ["Available keys:"]

    keys_to_show = list(config.keys())[:max_keys]

    for key in keys_to_show:
        value = config[key]
        value_repr = _format_value_repr(value)
        lines.append(f"  - {key}: {value_repr}")

    if len(config) > max_keys:
        remaining = len(config) - max_keys
        lines.append(f"  ... and {remaining} more")

    return "\n".join(lines)

format_code(text)

Format text as code/metadata (blue).

Parameters:

Name Type Description Default
text str

Text to format

required

Returns:

Type Description
str

Formatted text

Source code in src/sparkwheel/errors/formatters.py
def format_code(text: str) -> str:
    """Format text as code/metadata (blue).

    Args:
        text: Text to format

    Returns:
        Formatted text
    """
    return _colorize(text, BLUE)

format_error(text)

Format text as an error (red).

Parameters:

Name Type Description Default
text str

Text to format

required

Returns:

Type Description
str

Formatted text

Examples:

>>> format_error("Error message")
'Error message'  # With colors enabled
>>> format_error("Error message")
'Error message'  # With colors disabled
Source code in src/sparkwheel/errors/formatters.py
def format_error(text: str) -> str:
    """Format text as an error (red).

    Args:
        text: Text to format

    Returns:
        Formatted text

    Examples:
        >>> format_error("Error message")
        '\x1b[31mError message\x1b[0m'  # With colors enabled
        >>> format_error("Error message")
        'Error message'  # With colors disabled
    """
    return _colorize(text, RED)

format_resolution_chain(chain, title='Resolution chain:')

Format a resolution chain for display in error messages.

Parameters:

Name Type Description Default
chain list[tuple[str, str, bool]]

List of (id, reference, success) tuples representing the resolution chain

required
title str

Title for the chain display

'Resolution chain:'

Returns:

Type Description
str

Formatted string with the resolution chain visualization

Examples:

>>> chain = [
...     ("training::optimizer", "@optimizer", True),
...     ("optimizer::lr", "@base::learning_rate", True),
...     ("base::learning_rate", "", False),
... ]
>>> print(format_resolution_chain(chain))
Resolution chain:
  1. training::optimizer = "@optimizer" ✓
  2. optimizer::lr = "@base::learning_rate" ✓
  3. base::learning_rate = ❌ NOT FOUND
Source code in src/sparkwheel/errors/context.py
def format_resolution_chain(
    chain: list[tuple[str, str, bool]],
    title: str = "Resolution chain:",
) -> str:
    """Format a resolution chain for display in error messages.

    Args:
        chain: List of (id, reference, success) tuples representing the resolution chain
        title: Title for the chain display

    Returns:
        Formatted string with the resolution chain visualization

    Examples:
        >>> chain = [
        ...     ("training::optimizer", "@optimizer", True),
        ...     ("optimizer::lr", "@base::learning_rate", True),
        ...     ("base::learning_rate", "", False),
        ... ]
        >>> print(format_resolution_chain(chain))
        Resolution chain:
          1. training::optimizer = "@optimizer" ✓
          2. optimizer::lr = "@base::learning_rate" ✓
          3. base::learning_rate = ❌ NOT FOUND
    """
    if not chain:
        return ""

    lines = [title]

    for i, (id_str, reference, success) in enumerate(chain, 1):
        if success:
            if reference:
                status = "✓"
                lines.append(f'  {i}. {id_str} = "{reference}" {status}')
            else:
                lines.append(f"  {i}. {id_str} ✓")
        else:
            lines.append(f"  {i}. {id_str} = ❌ NOT FOUND")

    # Add suggestion
    if chain and not chain[-1][2]:  # Last item failed
        lines.append("")
        lines.append(f"💡 The reference chain failed at step {len(chain)}.")

    return "\n".join(lines)

format_suggestion(text)

Format text as a suggestion (yellow).

Parameters:

Name Type Description Default
text str

Text to format

required

Returns:

Type Description
str

Formatted text

Source code in src/sparkwheel/errors/formatters.py
def format_suggestion(text: str) -> str:
    """Format text as a suggestion (yellow).

    Args:
        text: Text to format

    Returns:
        Formatted text
    """
    return _colorize(text, YELLOW)

format_suggestions(suggestions)

Format suggestion list for display in error messages.

Parameters:

Name Type Description Default
suggestions list[tuple[str, float]]

List of (suggestion, similarity_score) tuples

required

Returns:

Type Description
str

Formatted string with suggestions, or empty string if no suggestions

Examples:

>>> format_suggestions([('parameters', 0.9), ('param_groups', 0.54)])
'💡 Did you mean one of these?\n    - parameters ✓ (90% match)\n    - param_groups (54% match)'
Source code in src/sparkwheel/errors/suggestions.py
def format_suggestions(suggestions: list[tuple[str, float]]) -> str:
    """Format suggestion list for display in error messages.

    Args:
        suggestions: List of (suggestion, similarity_score) tuples

    Returns:
        Formatted string with suggestions, or empty string if no suggestions

    Examples:
        >>> format_suggestions([('parameters', 0.9), ('param_groups', 0.54)])
        '💡 Did you mean one of these?\\n    - parameters ✓ (90% match)\\n    - param_groups (54% match)'
    """
    if not suggestions:
        return ""

    lines = ["💡 Did you mean one of these?"]
    for suggestion, score in suggestions:
        # Add checkmark for very close matches (>80% similarity)
        check = " ✓" if score > 0.8 else ""
        percentage = int(score * 100)
        lines.append(f"    - {suggestion}{check} ({percentage}% match)")

    return "\n".join(lines)

get_suggestions(key, available_keys, max_suggestions=3, similarity_threshold=0.6)

Get suggestions for a potentially misspelled key.

Uses Levenshtein distance to find similar keys and ranks them by similarity.

Parameters:

Name Type Description Default
key str

The key that wasn't found

required
available_keys Sequence[str]

List of available keys to compare against

required
max_suggestions int

Maximum number of suggestions to return (default: 3)

3
similarity_threshold float

Minimum similarity score (0-1) for suggestions (default: 0.6) Lower values are more lenient, higher values are stricter

0.6

Returns:

Type Description
list[tuple[str, float]]

List of (suggestion, similarity_score) tuples, sorted by similarity (best first)

Examples:

>>> keys = ["parameters", "param_groups", "learning_rate", "weight_decay"]
>>> get_suggestions("paramters", keys)
[('parameters', 0.9), ('param_groups', 0.54)]
>>> get_suggestions("lr", keys)
[]  # No matches above threshold
Source code in src/sparkwheel/errors/suggestions.py
def get_suggestions(
    key: str,
    available_keys: Sequence[str],
    max_suggestions: int = 3,
    similarity_threshold: float = 0.6,
) -> list[tuple[str, float]]:
    """Get suggestions for a potentially misspelled key.

    Uses Levenshtein distance to find similar keys and ranks them by similarity.

    Args:
        key: The key that wasn't found
        available_keys: List of available keys to compare against
        max_suggestions: Maximum number of suggestions to return (default: 3)
        similarity_threshold: Minimum similarity score (0-1) for suggestions (default: 0.6)
                             Lower values are more lenient, higher values are stricter

    Returns:
        List of (suggestion, similarity_score) tuples, sorted by similarity (best first)

    Examples:
        >>> keys = ["parameters", "param_groups", "learning_rate", "weight_decay"]
        >>> get_suggestions("paramters", keys)
        [('parameters', 0.9), ('param_groups', 0.54)]
        >>> get_suggestions("lr", keys)
        []  # No matches above threshold
    """
    if not key or not available_keys:
        return []

    scored_suggestions = []

    for candidate in available_keys:
        # Calculate similarity score (1.0 = perfect match, 0.0 = completely different)
        max_len = max(len(key), len(candidate))
        if max_len == 0:
            continue

        distance = levenshtein_distance(key.lower(), candidate.lower())
        similarity = 1.0 - (distance / max_len)

        # Only include suggestions above threshold
        if similarity >= similarity_threshold:
            scored_suggestions.append((candidate, similarity))

    # Sort by similarity (best first) and limit to max_suggestions
    scored_suggestions.sort(key=lambda x: x[1], reverse=True)
    return scored_suggestions[:max_suggestions]

levenshtein_distance(s1, s2)

Calculate the Levenshtein distance between two strings.

The Levenshtein distance is the minimum number of single-character edits (insertions, deletions, or substitutions) required to change one word into another.

Parameters:

Name Type Description Default
s1 str

First string

required
s2 str

Second string

required

Returns:

Type Description
int

Integer representing the edit distance between s1 and s2

Examples:

>>> levenshtein_distance("kitten", "sitting")
3
>>> levenshtein_distance("hello", "hello")
0
>>> levenshtein_distance("hello", "helo")
1
Source code in src/sparkwheel/errors/suggestions.py
def levenshtein_distance(s1: str, s2: str) -> int:
    """Calculate the Levenshtein distance between two strings.

    The Levenshtein distance is the minimum number of single-character edits
    (insertions, deletions, or substitutions) required to change one word into another.

    Args:
        s1: First string
        s2: Second string

    Returns:
        Integer representing the edit distance between s1 and s2

    Examples:
        >>> levenshtein_distance("kitten", "sitting")
        3
        >>> levenshtein_distance("hello", "hello")
        0
        >>> levenshtein_distance("hello", "helo")
        1
    """
    if len(s1) < len(s2):
        return levenshtein_distance(s2, s1)

    if len(s2) == 0:
        return len(s1)

    # Create distance matrix
    previous_row: list[int] = list(range(len(s2) + 1))

    for i, c1 in enumerate(s1):
        current_row: list[int] = [i + 1]
        for j, c2 in enumerate(s2):
            # Cost of insertions, deletions, or substitutions
            insertions = previous_row[j + 1] + 1
            deletions = current_row[j] + 1
            substitutions = previous_row[j] + (c1 != c2)
            current_row.append(min(insertions, deletions, substitutions))
        previous_row = current_row

    return previous_row[-1]