Skip to content

API Reference

Debugging tools for Python.

This module provides functions to set up debugging tools like PuDB and Rich Traceback. It checks for the availability of these tools and configures them accordingly.

Importing this module will install the debugging tools based on the configuration. Example usage:

1
2
3
import debug_dojo.install

b()

This will install the debugging tools and put debug breakpoint at this line.

Another way to use this module is to run the desired script or module with the dojo command-line interface.

$ dojo --verbose --config dojo.toml target_script.py --arg_1_for_script value1

Dependency Graph


```mermaid graph TD src.debug_dojo._installers –> src.debug_dojo._compare src.debug_dojo._installers –> src.debug_dojo._config_models src.debug_dojo._cli –> src.debug_dojo._installers src.debug_dojo._cli –> src.debug_dojo._config src.debug_dojo._cli –> src.debug_dojo._config_models src.debug_dojo._config –> src.debug_dojo._config_models src.debug_dojo.install –> src.debug_dojo._config src.debug_dojo.install –> src.debug_dojo._installers src.debug_dojo._config_models src.debug_dojo._compare

```


Module for installing and configuring various debugging tools and features.

This module provides functions to set up different debuggers (PDB, PuDB, IPDB, Debugpy) and to install enhanced debugging features like Rich Traceback, Rich Inspect, Rich Print, and a side-by-side object comparer. These installations are typically driven by the DebugDojoConfig.

install_breakpoint(mnemonic='b')

Inject thebreakpoint() function into builtins under the given mnemonic.

Parameters:

Name Type Description Default
mnemonic str

The name to use for the breakpoint function in builtins. If an empty string, the feature is not installed.

'b'

install_breakpoint() import builtins callable(builtins.b) True

Source code in src/debug_dojo/_installers.py
def install_breakpoint(mnemonic: str = "b") -> None:
    """Inject the`breakpoint()` function into builtins under the given mnemonic.

    Args:
        mnemonic (str): The name to use for the breakpoint function in builtins.
                        If an empty string, the feature is not installed.

    >>> install_breakpoint()
    >>> import builtins
    >>> callable(builtins.b)
    True

    """
    if not mnemonic:
        return

    builtins.__dict__[mnemonic] = breakpoint

install_by_config(config)

Installs all debugging tools and features based on the given configuration.

This is the main entry point for applying debug-dojo settings.

Parameters:

Name Type Description Default
config DebugDojoConfig

The complete debug-dojo configuration object.

required
Source code in src/debug_dojo/_installers.py
def install_by_config(config: DebugDojoConfig) -> None:
    """Installs all debugging tools and features based on the given configuration.

    This is the main entry point for applying `debug-dojo` settings.

    Args:
        config (DebugDojoConfig): The complete debug-dojo configuration object.

    """
    set_debugger(config.debuggers)
    set_exceptions(config.exceptions)
    install_features(config.features)

install_compare(mnemonic='c')

Injects the side-by-side object comparison function into builtins.

Parameters:

Name Type Description Default
mnemonic str

The name to use for the compare function in builtins. If an empty string, the feature is not installed.

'c'

install_compare() import builtins callable(builtins.c) True

Source code in src/debug_dojo/_installers.py
def install_compare(mnemonic: str = "c") -> None:
    """Injects the side-by-side object comparison function into builtins.

    Args:
        mnemonic (str): The name to use for the compare function in builtins.
                        If an empty string, the feature is not installed.

    >>> install_compare()
    >>> import builtins
    >>> callable(builtins.c)
    True

    """
    if not mnemonic:
        return

    builtins.__dict__[mnemonic] = inspect_objects_side_by_side

install_features(features)

Installs debugging features based on the provided configuration.

Parameters:

Name Type Description Default
features FeaturesConfig

Configuration object specifying which features to install and their mnemonics.

required
Source code in src/debug_dojo/_installers.py
def install_features(features: FeaturesConfig) -> None:
    """Installs debugging features based on the provided configuration.

    Args:
        features (FeaturesConfig): Configuration object specifying which features
                                   to install and their mnemonics.

    """
    install_inspect(features.rich_inspect)
    install_rich_print(features.rich_print)
    install_compare(features.comparer)
    install_breakpoint(features.breakpoint)

install_inspect(mnemonic='i')

Injects rich.inspect into builtins under the given mnemonic.

Parameters:

Name Type Description Default
mnemonic str

The name to use for the inspect function in builtins. If an empty string, the feature is not installed.

'i'
Source code in src/debug_dojo/_installers.py
def install_inspect(mnemonic: str = "i") -> None:
    """Injects `rich.inspect` into builtins under the given mnemonic.

    Args:
        mnemonic (str): The name to use for the inspect function in builtins.
                        If an empty string, the feature is not installed.

    """
    if not mnemonic:
        return

    from rich import inspect

    def inspect_with_defaults(obj: object, **kwargs: bool) -> None:
        """Inspect an object using Rich's inspect function."""
        if not kwargs:
            kwargs = {"methods": True, "private": True}
        return inspect(obj, console=None, title="", **kwargs)

    builtins.__dict__[mnemonic] = inspect_with_defaults

install_rich_print(mnemonic='p')

Injects rich.print into builtins under the given mnemonic.

Parameters:

Name Type Description Default
mnemonic str

The name to use for the print function in builtins. If an empty string, the feature is not installed.

'p'

install_rich_print() import builtins callable(builtins.p) True p(“test”) test

Source code in src/debug_dojo/_installers.py
def install_rich_print(mnemonic: str = "p") -> None:
    """Injects `rich.print` into builtins under the given mnemonic.

    Args:
        mnemonic (str): The name to use for the print function in builtins.
                        If an empty string, the feature is not installed.

    >>> install_rich_print()
    >>> import builtins
    >>> callable(builtins.p)
    True
    >>> p("test")
    test

    """
    if not mnemonic:
        return

    from rich import print as rich_print

    builtins.__dict__[mnemonic] = rich_print

rich_traceback(*, locals_in_traceback)

Install Rich Traceback for enhanced error reporting.

Parameters:

Name Type Description Default
locals_in_traceback bool

Whether to include local variables in the traceback.

required
Source code in src/debug_dojo/_installers.py
def rich_traceback(*, locals_in_traceback: bool) -> None:
    """Install Rich Traceback for enhanced error reporting.

    Args:
        locals_in_traceback (bool): Whether to include local variables in the traceback.

    """
    from rich import traceback

    _ = traceback.install(show_locals=locals_in_traceback)

set_debugger(config)

Set the default debugger based on the provided configuration.

Parameters:

Name Type Description Default
config DebuggersConfig

Configuration object for debuggers.

required
Source code in src/debug_dojo/_installers.py
def set_debugger(config: DebuggersConfig) -> None:
    """Set the default debugger based on the provided configuration.

    Args:
        config (DebuggersConfig): Configuration object for debuggers.

    """
    debugger = config.default

    if debugger == DebuggerType.PDB:
        use_pdb(config.pdb)
    if debugger == DebuggerType.PUDB:
        use_pudb(config.pudb)
    if debugger == DebuggerType.IPDB:
        use_ipdb(config.ipdb)
    if debugger == DebuggerType.DEBUGPY:
        use_debugpy(config.debugpy)

    sys.ps1 = config.prompt_name

set_exceptions(exceptions)

Configure exception handling based on the provided configuration.

Parameters:

Name Type Description Default
exceptions ExceptionsConfig

Configuration object for exception handling.

required
Source code in src/debug_dojo/_installers.py
def set_exceptions(exceptions: ExceptionsConfig) -> None:
    """Configure exception handling based on the provided configuration.

    Args:
        exceptions (ExceptionsConfig): Configuration object for exception handling.

    """
    if exceptions.rich_traceback:
        rich_traceback(locals_in_traceback=exceptions.locals_in_traceback)

use_debugpy(config)

Set Debugpy as the default debugger.

Configures sys.breakpointhook to use debugpy.breakpoint, sets the PYTHONBREAKPOINT environment variable, and starts a debugpy server waiting for a client connection.

Source code in src/debug_dojo/_installers.py
def use_debugpy(config: DebugpyConfig) -> None:
    """Set Debugpy as the default debugger.

    Configures `sys.breakpointhook` to use `debugpy.breakpoint`, sets the
    `PYTHONBREAKPOINT` environment variable, and starts a debugpy server
    waiting for a client connection.
    """
    import debugpy  # pyright: ignore[reportMissingTypeStubs]

    os.environ[BREAKPOINT_ENV_VAR] = config.set_trace_hook
    sys.breakpointhook = debugpy.breakpoint

    launch_config = {
        "name": "debug-dojo",
        "type": "debugpy",
        "request": "attach",
        "connect": {
            "host": config.host,
            "port": config.port,
        },
    }
    rich_print(f"[blue]Connect your VSC debugger to port {config.port}.[/blue]")
    rich_print("[blue]Configuration:[/blue]")
    rich_print(json.dumps(launch_config, indent=4))

    _ = debugpy.listen((config.host, config.port))
    debugpy.wait_for_client()

use_ipdb(config)

Set IPDB as the default debugger.

Configures sys.breakpointhook to use ipdb.set_trace, sets the PYTHONBREAKPOINT environment variable, and configures IPDB_CONTEXT_SIZE.

Source code in src/debug_dojo/_installers.py
def use_ipdb(config: IpdbConfig) -> None:
    """Set IPDB as the default debugger.

    Configures `sys.breakpointhook` to use `ipdb.set_trace`, sets the
    `PYTHONBREAKPOINT` environment variable, and configures `IPDB_CONTEXT_SIZE`.
    """
    import ipdb  # pyright: ignore[reportMissingTypeStubs]

    os.environ[BREAKPOINT_ENV_VAR] = config.set_trace_hook
    os.environ[IPDB_CONTEXT_SIZE] = str(config.context_lines)
    sys.breakpointhook = ipdb.set_trace  # pyright: ignore[reportUnknownMemberType]

use_pdb(config)

Set PDB as the default debugger.

Configures sys.breakpointhook to use pdb.set_trace and sets the PYTHONBREAKPOINT environment variable.

Source code in src/debug_dojo/_installers.py
def use_pdb(config: PdbConfig) -> None:
    """Set PDB as the default debugger.

    Configures `sys.breakpointhook` to use `pdb.set_trace` and sets the
    `PYTHONBREAKPOINT` environment variable.
    """
    import pdb

    os.environ[BREAKPOINT_ENV_VAR] = config.set_trace_hook
    sys.breakpointhook = pdb.set_trace

use_pudb(config)

Set PuDB as the default debugger.

Configures sys.breakpointhook to use pudb.set_trace and sets the PYTHONBREAKPOINT environment variable.

Source code in src/debug_dojo/_installers.py
def use_pudb(config: PudbConfig) -> None:
    """Set PuDB as the default debugger.

    Configures `sys.breakpointhook` to use `pudb.set_trace` and sets the
    `PYTHONBREAKPOINT` environment variable.
    """
    import pudb  # pyright: ignore[reportMissingTypeStubs]

    os.environ[BREAKPOINT_ENV_VAR] = config.set_trace_hook
    sys.breakpointhook = pudb.set_trace

Utilities for side-by-side inspection and comparison of Python objects.

This module provides functions to display attributes and methods of two objects in a visually appealing, side-by-side format in the terminal.

get_object_attributes(obj)

Extract and format non-callable attributes of an object.

Parameters:

Name Type Description Default
obj object

The object to extract attributes from.

required

Returns:

Type Description
list[str]

list[str]: A list of formatted strings, each representing an attribute.

Source code in src/debug_dojo/_compare.py
def get_object_attributes(obj: object) -> list[str]:
    """Extract and format non-callable attributes of an object.

    Args:
        obj (object): The object to extract attributes from.

    Returns:
        list[str]: A list of formatted strings, each representing an attribute.

    """
    attributes: list[str] = []
    for attr_name in sorted(dir(obj)):
        # Safely get attribute, returning None if it doesn't exist
        attr = getattr(obj, attr_name, None)
        # Exclude dunder methods and callable attributes
        if not attr_name.startswith("__") and not callable(attr):
            with contextlib.suppress(AttributeError):
                # Use !r for robust string representation of the attribute value
                attributes.append(f"{attr_name}={attr!r}")
    return attributes

get_object_methods(obj)

Extract and format public callable methods of an object.

Parameters:

Name Type Description Default
obj object

The object to extract methods from.

required

Returns:

Type Description
list[str]

list[str]: A list of method names.

Source code in src/debug_dojo/_compare.py
def get_object_methods(obj: object) -> list[str]:
    """Extract and format public callable methods of an object.

    Args:
        obj (object): The object to extract methods from.

    Returns:
        list[str]: A list of method names.

    """
    methods: list[str] = []
    for method_name in sorted(dir(obj)):
        # Safely get attribute, returning None if it doesn't exist
        attr = getattr(obj, method_name, None)
        # Exclude private/protected methods (starting with '_') and non-callables.
        if not method_name.startswith("_") and callable(attr):
            methods.append(method_name)
    return methods

get_simplified_object_info(obj)

Generate a simplified, Rich-formatted inspection output for an object.

Handles basic Python types by displaying their value directly. For other objects, it lists their attributes and public methods.

Parameters:

Name Type Description Default
obj object

The object to generate info for.

required

Returns:

Type Description
list[Text]

list[Text]: A list of Rich Text objects representing the object’s information.

Source code in src/debug_dojo/_compare.py
def get_simplified_object_info(obj: object) -> list[Text]:
    """Generate a simplified, Rich-formatted inspection output for an object.

    Handles basic Python types by displaying their value directly. For other objects, it
    lists their attributes and public methods.

    Args:
        obj (object): The object to generate info for.

    Returns:
        list[Text]: A list of Rich Text objects representing the object's information.

    """
    info_lines: list[Text] = []
    obj_type: str = type(obj).__name__
    info_lines.append(Text(f"<class '{obj_type}'>", style="cyan bold"))
    info_lines.append(Text(""))

    # Handle basic data types by displaying their value directly
    if isinstance(obj, (str, int, float, list, dict, tuple, set, bool)) or obj is None:
        info_lines.append(Text("Value:", style="bold"))
        info_lines.append(Text(f"  {obj!r}", style="yellow"))
        info_lines.append(Text(""))
        info_lines.append(
            Text("No attributes or methods to display for this type.", style="dim")
        )
        return info_lines

    # For other objects, list attributes
    attributes = get_object_attributes(obj)
    if attributes:
        info_lines.append(Text("Attributes:", style="bold"))
        info_lines.extend([Text(f"  {attr}") for attr in attributes])
    else:
        info_lines.append(Text("No attributes found.", style="dim"))
    info_lines.append(Text(""))

    # List methods
    methods = get_object_methods(obj)
    if methods:
        info_lines.append(Text("Methods:", style="bold"))
        info_lines.extend([Text(f"  {method}()") for method in methods])
    else:
        info_lines.append(Text("No public methods found.", style="dim"))

    return info_lines

inspect_objects_side_by_side(obj1, obj2)

Display two Python objects side-by-side in the terminal using Rich.

Showing their attributes and methods in a simplified, aligned format.

Parameters:

Name Type Description Default
obj1 object

The first object to display.

required
obj2 object

The second object to display.

required
Source code in src/debug_dojo/_compare.py
def inspect_objects_side_by_side(
    obj1: object,
    obj2: object,
) -> None:
    """Display two Python objects side-by-side in the terminal using Rich.

    Showing their attributes and methods in a simplified, aligned format.

    Args:
        obj1 (object): The first object to display.
        obj2 (object): The second object to display.

    """
    main_console: Console = Console()

    lines1: list[Text] = get_simplified_object_info(obj1)
    lines2: list[Text] = get_simplified_object_info(obj2)

    # Determine the maximum number of lines to ensure consistent height
    max_lines: int = max(len(lines1), len(lines2))

    # Pad the shorter list of lines with empty Text objects to match the height
    if len(lines1) < max_lines:
        lines1.extend([Text("")] * (max_lines - len(lines1)))
    if len(lines2) < max_lines:
        lines2.extend([Text("")] * (max_lines - len(lines2)))

    # Join the padded lines into a single Text object for the Panel content
    padded_inspect_text1: Text = Text("\n").join(lines1)
    padded_inspect_text2: Text = Text("\n").join(lines2)

    panel1: Panel = Panel(padded_inspect_text1, border_style="green", expand=True)
    panel2: Panel = Panel(padded_inspect_text2, border_style="green", expand=True)

    main_console.print(Columns([panel1, panel2]))

Debug Dojo configuration module.

It includes configurations for different debuggers, exception handling, and features that can be enabled or disabled.

load_config(config_path=None, *, verbose=False, debugger=None)

Load the Debug Dojo configuration.

Return a DebugDojoConfig instance with the loaded configuration.

If no configuration file is found, it returns a default configuration. If a debugger is specified, it overrides the config.

Parameters:

Name Type Description Default
config_path Path | None

Optional path to a configuration file.

None
verbose bool

If True, print verbose messages during configuration loading.

False
debugger DebuggerType | None

Optional debugger type to override the default debugger specified in the configuration.

None

Returns:

Name Type Description
DebugDojoConfig DebugDojoConfig

The loaded and potentially overridden DebugDojoConfig instance.

Source code in src/debug_dojo/_config.py
def load_config(
    config_path: Path | None = None,
    *,
    verbose: bool = False,
    debugger: DebuggerType | None = None,
) -> DebugDojoConfig:
    """Load the Debug Dojo configuration.

    Return a DebugDojoConfig instance with the loaded configuration.

    If no configuration file is found, it returns a default configuration. If a debugger
    is specified, it overrides the config.

    Args:
        config_path (Path | None): Optional path to a configuration file.
        verbose (bool): If True, print verbose messages during configuration loading.
        debugger (DebuggerType | None): Optional debugger type to override the default
                                        debugger specified in the configuration.

    Returns:
        DebugDojoConfig: The loaded and potentially overridden DebugDojoConfig instance.

    """
    resolved_path = resolve_config_path(config_path)

    if verbose:
        if resolved_path:
            msg = f"Using configuration file: {resolved_path}."
        else:
            msg = "No configuration file found, using default settings."
        rich_print(f"[blue]{msg}[/blue]")

    if not resolved_path:
        return DebugDojoConfig()

    raw_config = load_raw_config(resolved_path)
    config = validated_and_updated_config(raw_config, verbose=verbose)

    # If a debugger is specified, override the config.
    if debugger:
        config.debuggers.default = debugger

    return config

load_raw_config(config_path)

Load the Debug Dojo configuration from a file.

Currently supports ‘dojo.toml’ or ‘pyproject.toml’. If no path is provided, it checks the current directory for these files.

Parameters:

Name Type Description Default
config_path Path

The absolute path to the configuration file.

required

Returns:

Name Type Description
JSON JSON

The raw configuration data as a JSON-like dictionary.

Raises:

Type Description
ValueError

If there is an error parsing the TOML file.

Source code in src/debug_dojo/_config.py
def load_raw_config(config_path: Path) -> JSON:
    """Load the Debug Dojo configuration from a file.

    Currently supports 'dojo.toml' or 'pyproject.toml'. If no path is provided, it
    checks the current directory for these files.

    Args:
        config_path (Path): The absolute path to the configuration file.

    Returns:
        JSON: The raw configuration data as a JSON-like dictionary.

    Raises:
        ValueError: If there is an error parsing the TOML file.

    """
    config_str = config_path.read_text(encoding="utf-8")

    try:
        config_data = parse(config_str).unwrap()
    except TOMLKitError as e:
        msg = f"Error parsing configuration file {config_path.resolve()}.."
        raise ValueError(msg) from e

    if config_path.name != "pyproject.toml":
        return config_data

    # If config is in [tool.debug_dojo] (pyproject.toml), extract it.
    try:
        dojo_config = cast("JSON", config_data["tool"]["debug_dojo"])
    except KeyError:
        return {}
    else:
        return dojo_config

resolve_config_path(config_path)

Resolve the configuration path.

Returning a default if none is provided.

Parameters:

Name Type Description Default
config_path Path | None

The explicit path to the configuration file, or None.

required

Returns:

Type Description
Path | None

Path | None: The resolved absolute path to the configuration file, or None if no configuration file is found and no explicit path was given.

Raises:

Type Description
FileNotFoundError

If an explicit config_path is provided but the file does not exist.

Source code in src/debug_dojo/_config.py
def resolve_config_path(config_path: Path | None) -> Path | None:
    """Resolve the configuration path.

    Returning a default if none is provided.

    Args:
        config_path (Path | None): The explicit path to the configuration file, or None.

    Returns:
        Path | None: The resolved absolute path to the configuration file, or None if no
                     configuration file is found and no explicit path was given.

    Raises:
        FileNotFoundError: If an explicit `config_path` is provided but the file
                           does not exist.

    """
    if config_path:
        if not config_path.exists():
            msg = f"Configuration file not found:\n{config_path.resolve()}"
            raise FileNotFoundError(msg)
        return config_path.resolve()

    # Default configuration path
    for path in (Path("dojo.toml"), Path("pyproject.toml")):
        if path.exists():
            return path.resolve()

    # None means - use default config values
    return None

validated_and_updated_config(raw_config, *, verbose)

Validate and update the raw configuration to the latest DebugDojoConfig version.

Parameters:

Name Type Description Default
raw_config JSON

The raw configuration data loaded from a file.

required
verbose bool

If True, print verbose messages during validation and update.

required

Returns:

Name Type Description
DebugDojoConfig DebugDojoConfig

A validated and updated DebugDojoConfig instance.

Raises:

Type Description
Exit

If the configuration cannot be validated against any known version.

Source code in src/debug_dojo/_config.py
def validated_and_updated_config(raw_config: JSON, *, verbose: bool) -> DebugDojoConfig:
    """Validate and update the raw configuration to the latest DebugDojoConfig version.

    Args:
        raw_config (JSON): The raw configuration data loaded from a file.
        verbose (bool): If True, print verbose messages during validation and update.

    Returns:
        DebugDojoConfig: A validated and updated DebugDojoConfig instance.

    Raises:
        typer.Exit: If the configuration cannot be validated against any known version.

    """
    config: DebugDojoConfigV1 | DebugDojoConfigV2 | None = None

    for model in (DebugDojoConfigV2, DebugDojoConfigV1):
        model_name = model.__name__
        try:
            config = _validate_model(model, raw_config)
        except (DaciteError, TypeError, ValueError) as e:
            if verbose:
                msg = (
                    f"[yellow]Configuration validation error for {model_name}:\n{e}\n\n"
                )
                rich_print(msg)
        else:
            if verbose or model_name != DebugDojoConfig.__name__:
                msg = (
                    f"[blue]Using configuration model: {model_name}.\n"
                    f"Current configuration model {DebugDojoConfig.__name__}. [/blue]"
                )
                rich_print(msg)
            break

    if not config:
        msg = "[red]Unsupported configuration version or error.[/red]"
        rich_print(msg)
        raise Exit(code=1)

    while not isinstance(config, DebugDojoConfig):
        config = config.update()

    return config

Dataclass models for Debug Dojo’s configuration.

This module defines the data structures used to validate and manage the configuration of debug-dojo, including settings for debuggers, exception handling, and features.

DebugDojoConfigV1 dataclass

Legacy configuration for Debug Dojo (version 1).

Source code in src/debug_dojo/_config_models.py
@dataclass
class DebugDojoConfigV1:
    """Legacy configuration for Debug Dojo (version 1)."""

    debugger: DebuggerType = DebuggerType.PUDB
    """The type of debugger to use."""
    features: Features = field(default_factory=Features)
    """Features to install for debugging."""

    def update(self) -> DebugDojoConfigV2:
        """Update the configuration to the latest version."""
        v2_exceptions = ExceptionsConfig(
            rich_traceback=self.features.rich_traceback,
        )
        v2_debuggers = DebuggersConfig(default=self.debugger)
        v2_features = FeaturesConfig(
            rich_inspect="i" if self.features.rich_inspect else "",
            rich_print="p" if self.features.rich_print else "",
            comparer="c" if self.features.comparer else "",
            breakpoint="b" if self.features.breakpoint else "",
        )
        return DebugDojoConfigV2(
            exceptions=v2_exceptions,
            debuggers=v2_debuggers,
            features=v2_features,
        )

debugger = DebuggerType.PUDB class-attribute instance-attribute

The type of debugger to use.

features = field(default_factory=Features) class-attribute instance-attribute

Features to install for debugging.

update()

Update the configuration to the latest version.

Source code in src/debug_dojo/_config_models.py
def update(self) -> DebugDojoConfigV2:
    """Update the configuration to the latest version."""
    v2_exceptions = ExceptionsConfig(
        rich_traceback=self.features.rich_traceback,
    )
    v2_debuggers = DebuggersConfig(default=self.debugger)
    v2_features = FeaturesConfig(
        rich_inspect="i" if self.features.rich_inspect else "",
        rich_print="p" if self.features.rich_print else "",
        comparer="c" if self.features.comparer else "",
        breakpoint="b" if self.features.breakpoint else "",
    )
    return DebugDojoConfigV2(
        exceptions=v2_exceptions,
        debuggers=v2_debuggers,
        features=v2_features,
    )

DebugDojoConfigV2 dataclass

Configuration for Debug Dojo.

Source code in src/debug_dojo/_config_models.py
@dataclass
class DebugDojoConfigV2:
    """Configuration for Debug Dojo."""

    exceptions: ExceptionsConfig = field(default_factory=ExceptionsConfig)
    """Better exception messages."""
    debuggers: DebuggersConfig = field(default_factory=DebuggersConfig)
    """Default debugger and configs."""
    features: FeaturesConfig = field(default_factory=FeaturesConfig)
    """Features mnemonics."""

debuggers = field(default_factory=DebuggersConfig) class-attribute instance-attribute

Default debugger and configs.

exceptions = field(default_factory=ExceptionsConfig) class-attribute instance-attribute

Better exception messages.

features = field(default_factory=FeaturesConfig) class-attribute instance-attribute

Features mnemonics.

DebuggerType

Bases: Enum

Enum for different types of debuggers.

Source code in src/debug_dojo/_config_models.py
class DebuggerType(Enum):
    """Enum for different types of debuggers."""

    DEBUGPY = "debugpy"
    IPDB = "ipdb"
    PDB = "pdb"
    PUDB = "pudb"

DebuggersConfig dataclass

Configuration for debuggers.

Source code in src/debug_dojo/_config_models.py
@dataclass
class DebuggersConfig:
    """Configuration for debuggers."""

    default: DebuggerType = DebuggerType.IPDB
    """Default debugger to use."""
    prompt_name: str = "debug-dojo> "
    """Prompt name for the debugger, used in the REPL."""

    debugpy: DebugpyConfig = field(default_factory=DebugpyConfig)
    """Configuration for debugpy debugger."""
    ipdb: IpdbConfig = field(default_factory=IpdbConfig)
    """Configuration for ipdb debugger."""
    pdb: PdbConfig = field(default_factory=PdbConfig)
    """Configuration for pdb debugger."""
    pudb: PudbConfig = field(default_factory=PudbConfig)
    """Configuration for pudb debugger."""

debugpy = field(default_factory=DebugpyConfig) class-attribute instance-attribute

Configuration for debugpy debugger.

default = DebuggerType.IPDB class-attribute instance-attribute

Default debugger to use.

ipdb = field(default_factory=IpdbConfig) class-attribute instance-attribute

Configuration for ipdb debugger.

pdb = field(default_factory=PdbConfig) class-attribute instance-attribute

Configuration for pdb debugger.

prompt_name = 'debug-dojo> ' class-attribute instance-attribute

Prompt name for the debugger, used in the REPL.

pudb = field(default_factory=PudbConfig) class-attribute instance-attribute

Configuration for pudb debugger.

DebugpyConfig dataclass

Configuration for debugpy debugger.

Source code in src/debug_dojo/_config_models.py
@dataclass
class DebugpyConfig:
    """Configuration for debugpy debugger."""

    host: str = "localhost"
    """Host for debugpy debugger."""
    log_to_file: bool = False
    """Whether to log debugpy output to a file."""
    port: int = 1992
    """Port for debugpy debugger."""
    wait_for_client: bool = True
    """Whether to wait for the client to connect before starting debugging."""

    @property
    def set_trace_hook(self) -> str:
        return "debugpy.breakpoint"

host = 'localhost' class-attribute instance-attribute

Host for debugpy debugger.

log_to_file = False class-attribute instance-attribute

Whether to log debugpy output to a file.

port = 1992 class-attribute instance-attribute

Port for debugpy debugger.

wait_for_client = True class-attribute instance-attribute

Whether to wait for the client to connect before starting debugging.

ExceptionsConfig dataclass

Configuration for exceptions handling.

Source code in src/debug_dojo/_config_models.py
@dataclass
class ExceptionsConfig:
    """Configuration for exceptions handling."""

    locals_in_traceback: bool = False
    """Include local variables in traceback."""
    post_mortem: bool = True
    """Enable post-mortem debugging after an exception."""
    rich_traceback: bool = True
    """Enable rich traceback for better error reporting."""

locals_in_traceback = False class-attribute instance-attribute

Include local variables in traceback.

post_mortem = True class-attribute instance-attribute

Enable post-mortem debugging after an exception.

rich_traceback = True class-attribute instance-attribute

Enable rich traceback for better error reporting.

Features dataclass

Legacy configuration for installing debug features (used in V1 config).

Source code in src/debug_dojo/_config_models.py
@dataclass
class Features:
    """Legacy configuration for installing debug features (used in V1 config)."""

    rich_inspect: bool = True
    """Install rich inspect as 'i' for enhanced object inspection."""
    rich_print: bool = True
    """Install rich print as 'p' for enhanced printing."""
    rich_traceback: bool = True
    """Install rich traceback for better error reporting."""
    comparer: bool = True
    """Install comparer as 'c' for side-by-side object comparison."""
    breakpoint: bool = True
    """Install breakpoint as 'b' for setting breakpoints in code."""

breakpoint = True class-attribute instance-attribute

Install breakpoint as ‘b’ for setting breakpoints in code.

comparer = True class-attribute instance-attribute

Install comparer as ‘c’ for side-by-side object comparison.

rich_inspect = True class-attribute instance-attribute

Install rich inspect as ‘i’ for enhanced object inspection.

rich_print = True class-attribute instance-attribute

Install rich print as ‘p’ for enhanced printing.

rich_traceback = True class-attribute instance-attribute

Install rich traceback for better error reporting.

FeaturesConfig dataclass

Configuration for installing debug features.

Source code in src/debug_dojo/_config_models.py
@dataclass
class FeaturesConfig:
    """Configuration for installing debug features."""

    breakpoint: str = "b"
    """Install breakpoint as 'b' for setting breakpoints in code."""
    comparer: str = "c"
    """Install comparer as 'c' for side-by-side object comparison."""
    rich_inspect: str = "i"
    """Install rich inspect as 'i' for enhanced object inspection."""
    rich_print: str = "p"
    """Install rich print as 'p' for enhanced printing."""

breakpoint = 'b' class-attribute instance-attribute

Install breakpoint as ‘b’ for setting breakpoints in code.

comparer = 'c' class-attribute instance-attribute

Install comparer as ‘c’ for side-by-side object comparison.

rich_inspect = 'i' class-attribute instance-attribute

Install rich inspect as ‘i’ for enhanced object inspection.

rich_print = 'p' class-attribute instance-attribute

Install rich print as ‘p’ for enhanced printing.

IpdbConfig dataclass

Configuration for ipdb debugger.

Source code in src/debug_dojo/_config_models.py
@dataclass
class IpdbConfig:
    """Configuration for ipdb debugger."""

    context_lines: int = 20
    """Number of context lines to show in ipdb."""

    @property
    def set_trace_hook(self) -> str:
        return "ipdb.set_trace"

context_lines = 20 class-attribute instance-attribute

Number of context lines to show in ipdb.

PdbConfig dataclass

Configuration for pdb debugger.

Source code in src/debug_dojo/_config_models.py
@dataclass
class PdbConfig:
    """Configuration for pdb debugger."""

    @property
    def set_trace_hook(self) -> str:
        return "pdb.set_trace"

PudbConfig dataclass

Configuration for pudb debugger.

Source code in src/debug_dojo/_config_models.py
@dataclass
class PudbConfig:
    """Configuration for pudb debugger."""

    @property
    def set_trace_hook(self) -> str:
        return "pudb.set_trace"

Command-line interface for running Python scripts or modules with debugging tools.

ExecMode

Bases: Enum

Execution mode for the target.

Source code in src/debug_dojo/_cli.py
class ExecMode(Enum):
    """Execution mode for the target."""

    FILE = "file"
    MODULE = "module"
    EXECUTABLE = "executable"

__execute_with_debug(target_name, target_args, *, target_mode, verbose, config)

Execute a target script or module with installed debugging tools.

Parameters:

Name Type Description Default
target_name str

The name of the script, module, or executable to run.

required
target_args list[str]

Arguments to pass to the target.

required
target_mode ExecMode

The execution mode (FILE, MODULE, or EXECUTABLE).

required
verbose bool

If True, print verbose output.

required
config DebugDojoConfig

The debug-dojo configuration.

required

Raises:

Type Description
Exit

If the target file is not found, or if an import error occurs, or if the script exits with a non-zero code.

Source code in src/debug_dojo/_cli.py
def __execute_with_debug(  # noqa: C901
    target_name: str,
    target_args: list[str],
    *,
    target_mode: ExecMode,
    verbose: bool,
    config: DebugDojoConfig,
) -> None:
    """Execute a target script or module with installed debugging tools.

    Args:
        target_name (str): The name of the script, module, or executable to run.
        target_args (list[str]): Arguments to pass to the target.
        target_mode (ExecMode): The execution mode (FILE, MODULE, or EXECUTABLE).
        verbose (bool): If True, print verbose output.
        config (DebugDojoConfig): The debug-dojo configuration.

    Raises:
        typer.Exit: If the target file is not found, or if an import error occurs,
                    or if the script exits with a non-zero code.

    """
    sys.argv = [target_name, *target_args]

    if verbose:
        rich_print(f"[blue]Installing debugging tools for {target_name}.[/blue]")
        rich_print(f"[blue]Arguments for target: {target_args}[/blue]")

    install_by_config(config)

    if target_mode is ExecMode.MODULE:
        runner = runpy.run_module
    else:
        if target_mode is ExecMode.EXECUTABLE:
            target_name = which(target_name) or target_name

        if not Path(target_name).exists():
            raise typer.Exit(1)

        runner = runpy.run_path

    try:
        _ = runner(target_name, run_name="__main__")
    except ImportError as e:
        rich_print(f"[red]Error importing {target_name}:[/red]\n{e}")
        raise typer.Exit(1) from e
    except BdbQuit:
        rich_print("[red]Debugging session terminated by user.[/red]")
        raise typer.Exit(0) from None
    except KeyboardInterrupt:
        rich_print("[red]Execution interrupted by user.[/red]")
        raise typer.Exit(0) from None
    except SystemExit as e:
        if e.code:
            rich_print(f"[red]Script exited with code {e.code}.[/red]")
    except Exception as e:
        rich_print(f"[red]Error while running {target_name}:[/red]\n{e}")
        rich_print(traceback.format_exc())
        if config.exceptions.post_mortem:
            import ipdb  # pyright: ignore[reportMissingTypeStubs]  # noqa: PLC0415, T100

            rich_print("[blue]Entering post-mortem debugging session...[/blue]")
            ipdb.post_mortem(e.__traceback__)  # pyright: ignore[reportUnknownMemberType]
        raise typer.Exit(1) from e

main()

Run the command-line interface.

Source code in src/debug_dojo/_cli.py
def main() -> None:
    """Run the command-line interface."""
    cli()

run_debug(ctx, target_name=None, *, config_path=None, debugger=None, verbose=False, module=False, executable=False)

Run a Python script, module, or executable with debug-dojo tools.

This command acts as the main entry point for debug-dojo, allowing users to execute their code while automatically installing and configuring debugging tools based on the provided options or configuration file.

Parameters:

Name Type Description Default
ctx Context

The Typer context object.

required
target_name str | None

The path to the script, name of the module, or name of the executable to run. If not provided, the command will exit.

None
config_path Path | None

Path to a custom configuration file (e.g., dojo.toml).

None
debugger DebuggerType | None

Override the default debugger specified in the config.

None
verbose bool

Enable verbose output, showing loaded configuration and installation steps.

False
module bool

Treat target_name as a Python module to run (e.g., dojo -m my_package.my_module).

False
executable bool

Treat target_name as an executable command to run (e.g., dojo -e pytest).

False

Raises:

Type Description
Exit

If --module and --exec are used together, or if the target cannot be executed, or if an error occurs during execution.

Source code in src/debug_dojo/_cli.py
@cli.command(
    help="Run a Python script or module with debugging tools installed.",
    no_args_is_help=True,
    context_settings={"allow_extra_args": True, "ignore_unknown_options": True},
)
def run_debug(  # noqa: PLR0913
    ctx: typer.Context,
    target_name: Annotated[
        str | None, typer.Argument(help="The target script or module to debug.")
    ] = None,
    *,
    config_path: Annotated[
        Path | None, typer.Option("--config", "-c", help="Show configuration")
    ] = None,
    debugger: Annotated[
        DebuggerType | None,
        typer.Option("--debugger", "-d", help="Specify the debugger to use"),
    ] = None,
    verbose: Annotated[
        bool,
        typer.Option("--verbose", "-v", help="Enable verbose output"),
    ] = False,
    module: Annotated[
        bool,
        typer.Option("--module", "-m", help="Run a module"),
    ] = False,
    executable: Annotated[
        bool,
        typer.Option("--exec", "-e", help="Run a command"),
    ] = False,
) -> None:
    """Run a Python script, module, or executable with debug-dojo tools.

    This command acts as the main entry point for `debug-dojo`, allowing users to
    execute their code while automatically installing and configuring debugging tools
    based on the provided options or configuration file.

    Args:
        ctx (typer.Context): The Typer context object.
        target_name (str | None): The path to the script, name of the module, or
                                  name of the executable to run. If not provided,
                                  the command will exit.
        config_path (Path | None): Path to a custom configuration file
                                   (e.g., `dojo.toml`).
        debugger (DebuggerType | None): Override the default debugger specified
                                        in the config.
        verbose (bool): Enable verbose output, showing loaded configuration
                        and installation steps.
        module (bool): Treat `target_name` as a Python module to run
                       (e.g., `dojo -m my_package.my_module`).
        executable (bool): Treat `target_name` as an executable command to run
                           (e.g., `dojo -e pytest`).

    Raises:
        typer.Exit: If `--module` and `--exec` are used together, or if the target
                    cannot be executed, or if an error occurs during execution.

    """
    if module and executable:
        rich_print(
            "[red]Error: --module and --command options are mutually exclusive.[/red]"
        )
        raise typer.Exit(1)

    mode = (
        ExecMode.EXECUTABLE
        if executable
        else ExecMode.MODULE
        if module
        else ExecMode.FILE
    )

    config = load_config(config_path, verbose=verbose, debugger=debugger)

    if verbose:
        rich_print(f"[blue]Using debug-dojo configuration: {config} [/blue]")

    if target_name:
        __execute_with_debug(
            target_name=target_name,
            target_mode=mode,
            target_args=ctx.args,
            verbose=verbose,
            config=config,
        )