Automation tool that brings the power of build-tools to execute any kind of task with efficient DAG-based execution and plugin architecture
—
Comprehensive exception hierarchy for task failures, configuration errors, execution problems, and user input validation with detailed error reporting.
Exceptions raised for invalid user input, command line arguments, and configuration problems.
class InvalidCommand(Exception):
"""
Invalid command line argument or command usage.
Raised when user provides invalid command line arguments, unknown commands,
or invalid task/target names. Provides contextual error messages.
"""
def __init__(self, *args, **kwargs):
"""
Initialize command error.
Args:
*args: Standard exception arguments
not_found (str, optional): Name of command/task/target not found
"""
self.not_found = kwargs.pop('not_found', None)
self.cmd_used = None # Set by CLI when command is known
self.bin_name = 'doit' # Binary name for error messages
def __str__(self):
"""Return formatted error message with usage hints"""class InvalidDodoFile(Exception):
"""
Invalid dodo file or dodo file loading error.
Raised when dodo file cannot be found, imported, or contains invalid
configuration or task definitions.
"""class InvalidTask(Exception):
"""
Invalid task instance or task definition.
Raised when task definition contains invalid attributes, missing required
fields, or violates task specification rules.
"""Exception hierarchy for different types of task execution problems and failures.
class BaseFail(CatchedException):
"""
Base class for task failures and errors.
Contains information about task failures including exception details,
traceback information, and reporting flags. Used to save failure info
and might contain a caught Exception.
"""class TaskFailed(BaseFail):
"""
Task execution was not successful.
Raised when a task's action execution fails (non-zero exit code for shell
commands, raised exception for Python actions, etc.). Indicates the task
itself failed, not an error in doit's execution.
"""class TaskError(BaseFail):
"""
Error while trying to execute task.
Raised when there's an error in doit's task execution machinery rather
than in the task action itself. Examples: missing dependencies,
action setup failures, internal doit errors.
"""class UnmetDependency(TaskError):
"""
Task was not executed because a dependent task failed or is ignored.
Raised when task cannot run due to dependency failures. Prevents execution
cascade when prerequisite tasks fail or are explicitly ignored.
"""class SetupError(TaskError):
"""
Error while trying to execute setup object.
Raised when task setup actions (executed before main actions) fail
or cannot be properly initialized and executed.
"""class DependencyError(TaskError):
"""
Error while checking if task is up-to-date or saving task status.
Raised when dependency checking fails due to file system errors,
database problems, or issues with uptodate checkers.
"""Deprecated exception classes maintained for backward compatibility.
class CatchedException:
"""
DEPRECATED: Use BaseFail instead (deprecated 2022-04-22, 0.36.0 release).
Legacy base class for caught exceptions. Contains poor grammar and
doesn't handle all BaseFail cases properly. Maintained for compatibility.
"""
def __init__(self, msg, exception=None, report=True):
"""
Initialize caught exception.
Args:
msg (str): Error message
exception (Exception, optional): Original exception
report (bool): Whether failure should be reported
"""
self.message = msg
self.traceback = ''
self.report = report
def get_msg(self):
"""Return full exception description including traceback"""
def get_name(self):
"""Get failure kind name"""
def __str__(self):
"""Return formatted exception string"""from doit.exceptions import InvalidCommand
def validate_task_name(task_name, available_tasks):
"""Validate that task name exists"""
if task_name not in available_tasks:
raise InvalidCommand(
f"Task '{task_name}' not found",
not_found=task_name
)
# Error message will include helpful suggestions:
# "Invalid parameter: 'nonexistent'. Must be a command, task, or a target.
# Type 'doit help' to see available commands.
# Type 'doit list' to see available tasks."from doit.exceptions import InvalidTask
def validate_task_definition(task_dict):
"""Validate task definition dictionary"""
if 'actions' not in task_dict and 'task_dep' not in task_dict:
raise InvalidTask(
"Task must contain either 'actions' or 'task_dep'"
)
if 'name' in task_dict and task_dict['name'].startswith('_'):
raise InvalidTask(
"Task names cannot start with underscore"
)
def task_invalid_example():
"""This will raise InvalidTask"""
return {
'name': '_private', # Invalid name
# Missing actions or task_dep
}from doit.exceptions import TaskFailed, TaskError
def failing_action():
"""Action that might fail"""
import random
if random.random() < 0.5:
# Task logic failure
raise TaskFailed("Business logic failed")
else:
# System/infrastructure error
raise TaskError("Database connection failed")
def task_with_error_handling():
"""Task with custom error handling"""
def safe_action():
try:
# Some risky operation
result = risky_operation()
return result
except ValueError as e:
# Convert to doit exception
raise TaskFailed(f"Invalid input data: {e}")
except ConnectionError as e:
# Infrastructure error
raise TaskError(f"Service unavailable: {e}")
return {
'actions': [safe_action],
'verbosity': 2
}from doit.exceptions import UnmetDependency, DependencyError
def task_primary():
"""Primary task that might fail"""
return {
'actions': ['exit 1'], # Will fail
}
def task_dependent():
"""Task that depends on primary"""
return {
'actions': ['echo "This will not run"'],
'task_dep': ['primary'] # UnmetDependency if primary fails
}
def check_file_dependency():
"""Custom uptodate checker that might error"""
try:
import os
return os.path.exists('required_file.txt')
except PermissionError:
# File system access error
raise DependencyError("Cannot access dependency file")
def task_with_dep_check():
return {
'actions': ['echo "Running with dependency check"'],
'uptodate': [check_file_dependency]
}from doit.exceptions import BaseFail
def handle_task_failure(exception):
"""Handle task failure with detailed information"""
if isinstance(exception, BaseFail):
print(f"Failure type: {exception.get_name()}")
print(f"Message: {exception.message}")
if exception.traceback:
print("Traceback:")
print(''.join(exception.traceback))
if not exception.report:
print("(This failure was marked as non-reportable)")
return exception.get_msg() # Full descriptionInstall with Tessl CLI
npx tessl i tessl/pypi-doit