CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-taskipy

A task runner for Python projects that enables task definition and execution through pyproject.toml configuration.

Overview
Eval results
Files

error-handling.mddocs/

Error Handling

Comprehensive exception hierarchy for handling various error conditions with specific exit codes and descriptive error messages.

Capabilities

Base Exception Class

Root exception class for all taskipy-specific errors.

class TaskipyError(Exception):
    """Base exception class for all taskipy errors."""
    exit_code = 1

Configuration Errors

Errors related to pyproject.toml file handling and parsing.

class MissingPyProjectFileError(TaskipyError):
    """Raised when no pyproject.toml file is found in directory or parent directories."""

class MalformedPyProjectError(TaskipyError):
    """Raised when pyproject.toml file is malformed and cannot be parsed."""
    def __init__(self, reason: Optional[str] = None):
        """
        Initialize with optional reason for malformation.
        
        Args:
            reason: Specific reason for TOML parsing failure
        """

class MissingTaskipyTasksSectionError(TaskipyError):
    """Raised when [tool.taskipy.tasks] section is missing from pyproject.toml."""
    exit_code = 127

class MissingTaskipySettingsSectionError(TaskipyError):
    """Raised when [tool.taskipy.settings] section is expected but missing."""
    exit_code = 127

class EmptyTasksSectionError(TaskipyError):
    """Raised when tasks section exists but contains no tasks."""
    exit_code = 127

Task Execution Errors

Errors that occur during task discovery and execution.

class TaskNotFoundError(TaskipyError):
    """Raised when a requested task cannot be found."""
    exit_code = 127
    
    def __init__(self, task_name: str, suggestion: Optional[str] = None):
        """
        Initialize with task name and optional suggestion.
        
        Args:
            task_name: Name of the task that was not found
            suggestion: Suggested similar task name (from difflib)
        """

class MalformedTaskError(TaskipyError):
    """Raised when a task definition is invalid or malformed."""
    
    def __init__(self, task_name: str, reason: str):
        """
        Initialize with task name and specific reason.
        
        Args:
            task_name: Name of the malformed task
            reason: Specific reason for the malformation
        """

Variable and Settings Errors

Errors related to variable substitution and settings configuration.

class CircularVariableError(TaskipyError):
    """Raised when circular dependencies are detected in recursive variables."""
    exit_code = 127

class InvalidVariableError(TaskipyError):
    """Raised when a variable definition is invalid."""
    exit_code = 127
    
    def __init__(self, variable: str, reason: str):
        """
        Initialize with variable name and reason.
        
        Args:
            variable: Name of the invalid variable
            reason: Specific reason for invalidity
        """

class InvalidRunnerTypeError(TaskipyError):
    """Raised when runner setting is not a string."""

Usage Errors

Errors related to command-line usage and argument parsing.

class InvalidUsageError(TaskipyError):
    """Raised when command-line arguments are invalid."""
    exit_code = 127
    
    def __init__(self, parser: ArgumentParser):
        """
        Initialize with argument parser for usage message.
        
        Args:
            parser: ArgumentParser instance for generating usage help
        """

Usage Examples

Basic Error Handling

from taskipy.cli import run
from taskipy.exceptions import TaskipyError, TaskNotFoundError

try:
    exit_code = run(['nonexistent_task'])
except TaskNotFoundError as e:
    print(f"Task not found: {e}")
    if e.suggestion:
        print(f"Did you mean: {e.suggestion}")
    exit_code = e.exit_code
except TaskipyError as e:
    print(f"Taskipy error: {e}")
    exit_code = e.exit_code

Configuration Error Handling

from taskipy.pyproject import PyProject
from taskipy.exceptions import (
    MissingPyProjectFileError,
    MalformedPyProjectError,
    MissingTaskipyTasksSectionError
)
from pathlib import Path

try:
    project = PyProject(Path('/path/to/project'))
    tasks = project.tasks
except MissingPyProjectFileError:
    print("Error: No pyproject.toml file found")
    print("Make sure you're in a directory with a pyproject.toml file")
except MalformedPyProjectError as e:
    print(f"Error: Invalid pyproject.toml syntax")
    if e.reason:
        print(f"Reason: {e.reason}")
except MissingTaskipyTasksSectionError:
    print("Error: No [tool.taskipy.tasks] section found")
    print("Add tasks to your pyproject.toml file")

Variable Error Handling

from taskipy.task_runner import TaskRunner
from taskipy.exceptions import CircularVariableError, InvalidVariableError, MalformedTaskError
from pathlib import Path

try:
    runner = TaskRunner(Path('.'))
    exit_code = runner.run('my_task', [])
except CircularVariableError:
    print("Error: Circular dependency detected in variables")
    print("Check your [tool.taskipy.variables] for circular references")
except InvalidVariableError as e:
    print(f"Error: Invalid variable '{e.variable}'")
    print(f"Reason: {e.reason}")
except MalformedTaskError as e:
    print(f"Error: Task '{e.task}' is malformed")
    print(f"Reason: {e.reason}")

Complete Error Handling Pattern

from taskipy.cli import run
from taskipy.exceptions import *
import sys

def safe_task_runner(task_name, args=None):
    """Safely run a task with comprehensive error handling."""
    if args is None:
        args = []
    
    try:
        return run([task_name] + args)
    
    except TaskNotFoundError as e:
        print(f"❌ Task '{e.task}' not found", file=sys.stderr)
        if e.suggestion:
            print(f"💡 Did you mean '{e.suggestion}'?", file=sys.stderr)
        return e.exit_code
    
    except MissingPyProjectFileError:
        print("❌ No pyproject.toml file found", file=sys.stderr)
        print("💡 Make sure you're in a Python project directory", file=sys.stderr)
        return 1
    
    except MalformedPyProjectError as e:
        print("❌ Invalid pyproject.toml syntax", file=sys.stderr)
        if e.reason:
            print(f"📝 {e.reason}", file=sys.stderr)
        return 1
    
    except MissingTaskipyTasksSectionError:
        print("❌ No tasks defined", file=sys.stderr)
        print("💡 Add [tool.taskipy.tasks] section to pyproject.toml", file=sys.stderr)
        return 127
    
    except CircularVariableError:
        print("❌ Circular variable dependency detected", file=sys.stderr)
        print("💡 Check [tool.taskipy.variables] for circular references", file=sys.stderr)
        return 127
    
    except InvalidVariableError as e:
        print(f"❌ Invalid variable '{e.variable}': {e.reason}", file=sys.stderr)
        return 127
    
    except MalformedTaskError as e:
        print(f"❌ Task '{e.task}' is malformed: {e.reason}", file=sys.stderr)
        return 1
    
    except InvalidRunnerTypeError:
        print("❌ Runner setting must be a string", file=sys.stderr)
        print("💡 Check [tool.taskipy.settings.runner] in pyproject.toml", file=sys.stderr)
        return 1
    
    except TaskipyError as e:
        print(f"❌ Taskipy error: {e}", file=sys.stderr)
        return e.exit_code
    
    except Exception as e:
        print(f"❌ Unexpected error: {e}", file=sys.stderr)
        return 1

# Usage
if __name__ == "__main__":
    exit_code = safe_task_runner('test', ['--verbose'])
    sys.exit(exit_code)

Exit Codes

Taskipy uses specific exit codes to indicate different types of failures:

  • 0: Success
  • 1: General error (TaskipyError, configuration issues)
  • 127: Command not found or invalid usage (TaskNotFoundError, InvalidUsageError, missing sections)

Exit Code Usage

import subprocess
import sys

# Running taskipy as subprocess
result = subprocess.run(['task', 'test'], capture_output=True)

if result.returncode == 0:
    print("✅ Task completed successfully")
elif result.returncode == 127:
    print("❌ Task not found or invalid usage")
    print("Check task name and available tasks with 'task --list'")
else:
    print(f"❌ Task failed with exit code {result.returncode}")
    print("Check task output for details")

Error Messages

Task Not Found

could not find task "tets", did you mean "test"?

Missing Configuration

no pyproject.toml file found in this directory or parent directories

Malformed Configuration

pyproject.toml file is malformed and could not be read. reason: Invalid TOML syntax

Variable Errors

variable src_path is invalid. reason: expected variable to contain a string or be a table with a key "var"
cannot resolve variables, found variables that depend on each other.

Task Errors

the task "test" in the pyproject.toml file is malformed. reason: tasks must be strings, or dicts that contain { cmd, cwd, help, use_vars }

Debugging Tips

Enable Verbose Error Reporting

import logging
logging.basicConfig(level=logging.DEBUG)

# Now taskipy operations will show more detailed information

Common Error Scenarios

  1. Typo in Task Name: Use task --list to see available tasks
  2. Missing pyproject.toml: Ensure you're in the correct directory
  3. TOML Syntax Error: Validate TOML syntax using online validators
  4. Circular Variables: Draw variable dependency graph to identify cycles
  5. Missing Variable: Check variable names match exactly (case-sensitive)

Error Prevention

# Use descriptive task names to avoid typos
[tool.taskipy.tasks]
run_tests = "pytest"      # Clear and descriptive
test = "pytest"           # Short but clear

# Validate variable references
[tool.taskipy.variables]
src_dir = "src"
# Make sure variables exist before referencing them
package_dir = { var = "{src_dir}/mypackage", recursive = true }

Install with Tessl CLI

npx tessl i tessl/pypi-taskipy

docs

cli.md

configuration.md

error-handling.md

index.md

task-composition.md

task-execution.md

variables.md

tile.json