debug-dojo 0.4.0__tar.gz → 0.5.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- The MIT License (MIT)
1
+ # The MIT License (MIT)
2
2
 
3
3
  Copyright (c) 2025 to bwrob.
4
4
 
@@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
18
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
19
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
20
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
21
+ SOFTWARE.
@@ -0,0 +1,83 @@
1
+ Metadata-Version: 2.4
2
+ Name: debug-dojo
3
+ Version: 0.5.0
4
+ Summary: 🏣 debug dojo, a place for zen debugging
5
+ Author-email: bwrob <bartosz.marcin.wroblewski@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Changelog, https://bwrob.github.io/debug-dojo/changelog/
8
+ Project-URL: Documentation, https://bwrob.github.io/debug-dojo/
9
+ Project-URL: Homepage, https://bwrob.github.io/debug-dojo/
10
+ Project-URL: Source, https://github.com/bwrob/debug-dojo/
11
+ Keywords: debugging,inspection,tools,development
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Topic :: Software Development :: Debuggers
19
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
+ Requires-Python: <3.14,>=3.10
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: debugpy>=1.8.0
24
+ Requires-Dist: ipdb>=0.13.0
25
+ Requires-Dist: pudb>=2020.1
26
+ Requires-Dist: pydantic>=2.11.7
27
+ Requires-Dist: rich>=12.0.0
28
+ Requires-Dist: tomlkit>=0.13.3
29
+ Requires-Dist: typer>=0.15.0
30
+ Dynamic: license-file
31
+
32
+ # debug dojo
33
+
34
+ <p align="center">
35
+ <img src="https://github.com/bwrob/debug-dojo/blob/main/docs/logo/logo_python.png?raw=true" alt="debug dojo" style="width:50%; max-width:350px;"/>
36
+ </p>
37
+
38
+ <p align="center">
39
+ <em>🏣 debug dojo, a place for zen debugging</em>
40
+ </p>
41
+
42
+ [![PyPi Version](https://img.shields.io/pypi/v/debug-dojo.svg?style=flat-square)](https://pypi.org/project/debug-dojo)
43
+ [![PyPI pyversions](https://img.shields.io/pypi/pyversions/debug-dojo.svg?style=flat-square)](https://pypi.org/pypi/debug-dojo/)
44
+ [![downloads](https://static.pepy.tech/badge/debug-dojo/month)](https://pepy.tech/project/debug-dojo)
45
+ [![license](https://img.shields.io/github/license/bwrob/debug-dojo.svg)](https://github.com/bwrob/debug-dojo/blob/main/LICENSE)
46
+ [![pre-commit.ci status](https://results.pre-commit.ci/badge/github/bwrob/debug-dojo/main.svg)](https://results.pre-commit.ci/latest/github/bwrob/debug-dojo/main)
47
+
48
+ [**debug-dojo**](https://bwrob.github.io/debug-dojo/) is a Python package providing utilities for enhanced debugging and inspection in the terminal.
49
+ It leverages [`rich`](https://github.com/Textualize/rich) for beautiful output and offers helpers for side-by-side object comparison, improved tracebacks from `rich`, and easy integration with different debuggers -- `debugpy`, `pudb`, `pdb`, and `ipdb`.
50
+
51
+ ## CLI usage
52
+
53
+ Run your Python script with debugging tools enabled using the `debug-dojo` command:
54
+
55
+ ```console
56
+ dojo my_script.py
57
+ ```
58
+
59
+ You can optionally set configuration, verbose mode, and specify the debugger type. Both script files and modules are supported:
60
+
61
+ ```console
62
+ dojo --debugger ipdb --config dojo.toml --verbose --module my_module
63
+ ```
64
+
65
+ ## From the code
66
+
67
+ In the `PuDB` style, you can install all debugging tools and enter the debugging mode with a single command:
68
+
69
+ ```python
70
+ object_1 = {"foo": 1, "bar": 2}
71
+ object_2 = [1, 2, 3]
72
+
73
+ import debug_dojo.install; b()
74
+
75
+ p(object_1) # Pretty print an object with Rich.
76
+ i(object_1) # Inspect an object using Rich.
77
+ c(object_1, object_2) # Compare two objects side-by-side.
78
+
79
+ ```
80
+
81
+ ## Documentation
82
+
83
+ For instructions regarding installation, configuration and usage please visit [documentation](https://bwrob.github.io/debug-dojo/).
@@ -0,0 +1,52 @@
1
+ # debug dojo
2
+
3
+ <p align="center">
4
+ <img src="https://github.com/bwrob/debug-dojo/blob/main/docs/logo/logo_python.png?raw=true" alt="debug dojo" style="width:50%; max-width:350px;"/>
5
+ </p>
6
+
7
+ <p align="center">
8
+ <em>🏣 debug dojo, a place for zen debugging</em>
9
+ </p>
10
+
11
+ [![PyPi Version](https://img.shields.io/pypi/v/debug-dojo.svg?style=flat-square)](https://pypi.org/project/debug-dojo)
12
+ [![PyPI pyversions](https://img.shields.io/pypi/pyversions/debug-dojo.svg?style=flat-square)](https://pypi.org/pypi/debug-dojo/)
13
+ [![downloads](https://static.pepy.tech/badge/debug-dojo/month)](https://pepy.tech/project/debug-dojo)
14
+ [![license](https://img.shields.io/github/license/bwrob/debug-dojo.svg)](https://github.com/bwrob/debug-dojo/blob/main/LICENSE)
15
+ [![pre-commit.ci status](https://results.pre-commit.ci/badge/github/bwrob/debug-dojo/main.svg)](https://results.pre-commit.ci/latest/github/bwrob/debug-dojo/main)
16
+
17
+ [**debug-dojo**](https://bwrob.github.io/debug-dojo/) is a Python package providing utilities for enhanced debugging and inspection in the terminal.
18
+ It leverages [`rich`](https://github.com/Textualize/rich) for beautiful output and offers helpers for side-by-side object comparison, improved tracebacks from `rich`, and easy integration with different debuggers -- `debugpy`, `pudb`, `pdb`, and `ipdb`.
19
+
20
+ ## CLI usage
21
+
22
+ Run your Python script with debugging tools enabled using the `debug-dojo` command:
23
+
24
+ ```console
25
+ dojo my_script.py
26
+ ```
27
+
28
+ You can optionally set configuration, verbose mode, and specify the debugger type. Both script files and modules are supported:
29
+
30
+ ```console
31
+ dojo --debugger ipdb --config dojo.toml --verbose --module my_module
32
+ ```
33
+
34
+ ## From the code
35
+
36
+ In the `PuDB` style, you can install all debugging tools and enter the debugging mode with a single command:
37
+
38
+ ```python
39
+ object_1 = {"foo": 1, "bar": 2}
40
+ object_2 = [1, 2, 3]
41
+
42
+ import debug_dojo.install; b()
43
+
44
+ p(object_1) # Pretty print an object with Rich.
45
+ i(object_1) # Inspect an object using Rich.
46
+ c(object_1, object_2) # Compare two objects side-by-side.
47
+
48
+ ```
49
+
50
+ ## Documentation
51
+
52
+ For instructions regarding installation, configuration and usage please visit [documentation](https://bwrob.github.io/debug-dojo/).
@@ -0,0 +1,126 @@
1
+ [project]
2
+ authors = [ { name = "bwrob", email = "bartosz.marcin.wroblewski@gmail.com" } ]
3
+ classifiers = [
4
+ "Intended Audience :: Developers",
5
+ "Operating System :: OS Independent",
6
+ "Programming Language :: Python :: 3.10",
7
+ "Programming Language :: Python :: 3.11",
8
+ "Programming Language :: Python :: 3.12",
9
+ "Programming Language :: Python :: 3.13",
10
+ "Topic :: Software Development :: Debuggers",
11
+ "Topic :: Software Development :: Libraries :: Python Modules",
12
+ ]
13
+ dependencies = [
14
+ "debugpy>=1.8.0",
15
+ "ipdb>=0.13.0",
16
+ "pudb>=2020.1",
17
+ "pydantic>=2.11.7",
18
+ "rich>=12.0.0",
19
+ "tomlkit>=0.13.3",
20
+ "typer>=0.15.0",
21
+ ]
22
+ description = "🏣 debug dojo, a place for zen debugging"
23
+ keywords = [ "debugging", "inspection", "tools", "development" ]
24
+ license = 'MIT'
25
+ license-files = [ 'LICENSE' ]
26
+ name = "debug-dojo"
27
+ readme = "README.md"
28
+ requires-python = ">=3.10,<3.14"
29
+ version = "0.5.0"
30
+
31
+ [project.urls]
32
+ Changelog = "https://bwrob.github.io/debug-dojo/changelog/"
33
+ Documentation = "https://bwrob.github.io/debug-dojo/"
34
+ Homepage = "https://bwrob.github.io/debug-dojo/"
35
+ Source = "https://github.com/bwrob/debug-dojo/"
36
+
37
+ [project.scripts]
38
+ "dojo" = "debug_dojo._cli:main"
39
+
40
+
41
+ [dependency-groups]
42
+
43
+ dev = [
44
+ "basedpyright>=1.31.2",
45
+ "coverage>=7.10.4",
46
+ "poethepoet>=0.37.0",
47
+ "pytest>=8.4.1",
48
+ "ruff>=0.12.9",
49
+ ]
50
+ docs = [
51
+ "mkdocs>=1.6.1",
52
+ "mkdocs-git-authors-plugin>=0.10.0",
53
+ "mkdocs-git-committers-plugin-2>=2.5.0",
54
+ "mkdocs-git-revision-date-localized-plugin>=1.4.7",
55
+ "mkdocs-material>=9.6.17",
56
+ "mkdocs-typer2>=0.1.5",
57
+ "mkdocstrings-python>=1.17.0",
58
+ ]
59
+
60
+
61
+ [tool.uv]
62
+ default-groups = "all"
63
+ package = true
64
+ required-version = ">=0.8.0"
65
+
66
+
67
+ [tool.basedpyright]
68
+ ignore = [ "examples", "tests/assets" ]
69
+ pythonVersion = "3.10"
70
+ strict = [ "src/debug_dojo/*" ]
71
+ typeCheckingMode = "all"
72
+
73
+
74
+ [tool.ruff]
75
+ line-length = 88
76
+ target-version = "py310"
77
+
78
+ [tool.ruff.lint]
79
+ exclude = [ "examples" ]
80
+ ignore = [ "COM", "D203", "D211", "D213" ]
81
+ select = [ "ALL" ]
82
+
83
+ [tool.ruff.lint.per-file-ignores]
84
+ "examples/*" = [ "INP001" ]
85
+ "examples/test_target.py" = [ "F821" ]
86
+ "src/debug_dojo/_installers.py" = [ "PLC0415", "T100" ]
87
+ "tests/*" = [ "S101", "T201" ]
88
+ "tests/assets/*" = [ "T201", "INP001", "F821" ]
89
+
90
+ [tool.ruff.format]
91
+ docstring-code-format = true
92
+
93
+
94
+ [tool.poe.tasks]
95
+
96
+ format = { cmd = "ruff format --diff --config=pyproject.toml", help = "Check code formatting using ruff." }
97
+ lint = { cmd = "uv run ruff check --config=pyproject.toml", help = "Check code rules using ruff." }
98
+ precommit = { cmd = "pre-commit run --all-files", help = "Run all code quality checks." }
99
+ test = { cmd = "pytest --verbose --doctest-modules", help = "Run tests using pytest." }
100
+ type-check = { cmd = "basedpyright", help = "Check static typing using basedpyright." }
101
+
102
+ [tool.poe.tasks.code-quality]
103
+ help = "Run all code quality checks."
104
+ ignore_fail = "return_non_zero"
105
+ sequence = [ "fix", "precommit", "format", "lint", "type-check" ]
106
+
107
+ [tool.poe.tasks.fix]
108
+ default_item_type = "cmd"
109
+ help = "Code quality fixes using ruff."
110
+ ignore_fail = "return_non_zero"
111
+ sequence = [
112
+ "ruff check --fix --unsafe-fixes --config=pyproject.toml",
113
+ "ruff format --config=pyproject.toml",
114
+ ]
115
+
116
+ [tool.poe.tasks.publish]
117
+ sequence = [
118
+ "code-quality",
119
+ { cmd = "rm -rf dist" },
120
+ { cmd = "uv build" },
121
+ { cmd = "uv publish" },
122
+ ]
123
+
124
+ [tool.docformatter]
125
+ black = true
126
+ non-cap = [ "dojo" ]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -4,16 +4,29 @@ from __future__ import annotations
4
4
 
5
5
  import runpy
6
6
  import sys
7
+ import traceback
7
8
  from bdb import BdbQuit
9
+ from enum import Enum
8
10
  from pathlib import Path
11
+ from shutil import which
9
12
  from typing import Annotated
10
13
 
11
14
  import typer
12
15
  from rich import print as rich_print
13
16
 
14
- from ._config import DebugDojoConfig, DebuggerType, load_config
17
+ from ._config import load_config
18
+ from ._config_models import DebugDojoConfig, DebuggerType # noqa: TC001
15
19
  from ._installers import install_by_config
16
20
 
21
+
22
+ class ExecMode(Enum):
23
+ """Execution mode for the target."""
24
+
25
+ FILE = "file"
26
+ MODULE = "module"
27
+ EXECUTABLE = "executable"
28
+
29
+
17
30
  cli = typer.Typer(
18
31
  name="debug_dojo",
19
32
  help="Run a Python script or module with debugging tools installed.",
@@ -21,15 +34,15 @@ cli = typer.Typer(
21
34
  )
22
35
 
23
36
 
24
- def execute_with_debug( # noqa: C901
37
+ def __execute_with_debug( # noqa: C901
25
38
  target_name: str,
26
39
  target_args: list[str],
27
40
  *,
28
- target_is_module: bool,
41
+ target_mode: ExecMode,
29
42
  verbose: bool,
30
43
  config: DebugDojoConfig,
31
44
  ) -> None:
32
- """Execute a target script or module with installation of debugging tools."""
45
+ """Execute a target script or module with installed debugging tools."""
33
46
  sys.argv = [target_name, *target_args]
34
47
 
35
48
  if verbose:
@@ -38,35 +51,40 @@ def execute_with_debug( # noqa: C901
38
51
 
39
52
  install_by_config(config)
40
53
 
41
- if target_is_module:
54
+ if target_mode is ExecMode.MODULE:
42
55
  runner = runpy.run_module
43
56
  else:
57
+ if target_mode is ExecMode.EXECUTABLE:
58
+ target_name = which(target_name) or target_name
59
+
44
60
  if not Path(target_name).exists():
45
- sys.exit(1)
61
+ raise typer.Exit(1)
62
+
46
63
  runner = runpy.run_path
47
64
 
48
65
  try:
49
66
  _ = runner(target_name, run_name="__main__")
50
67
  except ImportError as e:
51
68
  rich_print(f"[red]Error importing {target_name}:[/red]\n{e}")
52
- sys.exit(1)
69
+ raise typer.Exit(1) from e
53
70
  except BdbQuit:
54
71
  rich_print("[red]Debugging session terminated by user.[/red]")
55
- sys.exit(0)
72
+ raise typer.Exit(0) from None
56
73
  except KeyboardInterrupt:
57
74
  rich_print("[red]Execution interrupted by user.[/red]")
58
- sys.exit(0)
75
+ raise typer.Exit(0) from None
59
76
  except SystemExit as e:
60
77
  if e.code:
61
78
  rich_print(f"[red]Script exited with code {e.code}.[/red]")
62
- except Exception as e: # noqa: BLE001
79
+ except Exception as e:
63
80
  rich_print(f"[red]Error while running {target_name}:[/red]\n{e}")
81
+ rich_print(traceback.format_exc())
64
82
  if config.exceptions.post_mortem:
65
- import pdb # noqa: PLC0415, T100
83
+ import ipdb # pyright: ignore[reportMissingTypeStubs] # noqa: PLC0415, T100
66
84
 
67
85
  rich_print("[blue]Entering post-mortem debugging session...[/blue]")
68
- pdb.post_mortem(e.__traceback__)
69
- sys.exit(1)
86
+ ipdb.post_mortem(e.__traceback__) # pyright: ignore[reportUnknownMemberType]
87
+ raise typer.Exit(1) from e
70
88
 
71
89
 
72
90
  def display_config(config: DebugDojoConfig) -> None:
@@ -95,23 +113,41 @@ def run_debug( # noqa: PLR0913
95
113
  ] = None,
96
114
  verbose: Annotated[
97
115
  bool,
98
- typer.Option("--verbose", "-v", is_flag=True, help="Enable verbose output"),
116
+ typer.Option("--verbose", "-v", help="Enable verbose output"),
99
117
  ] = False,
100
118
  module: Annotated[
101
119
  bool,
102
- typer.Option("--module", "-m", is_flag=True, help="Run as a module"),
120
+ typer.Option("--module", "-m", help="Run a module"),
121
+ ] = False,
122
+ executable: Annotated[
123
+ bool,
124
+ typer.Option("--exec", "-e", help="Run a command"),
103
125
  ] = False,
104
126
  ) -> None:
105
127
  """Run the command-line interface."""
128
+ if module and executable:
129
+ rich_print(
130
+ "[red]Error: --module and --command options are mutually exclusive.[/red]"
131
+ )
132
+ raise typer.Exit(1)
133
+
134
+ mode = (
135
+ ExecMode.EXECUTABLE
136
+ if executable
137
+ else ExecMode.MODULE
138
+ if module
139
+ else ExecMode.FILE
140
+ )
141
+
106
142
  config = load_config(config_path, verbose=verbose, debugger=debugger)
107
143
 
108
144
  if verbose:
109
145
  display_config(config)
110
146
 
111
147
  if target_name:
112
- execute_with_debug(
148
+ __execute_with_debug(
113
149
  target_name=target_name,
114
- target_is_module=module,
150
+ target_mode=mode,
115
151
  target_args=ctx.args,
116
152
  verbose=verbose,
117
153
  config=config,
@@ -1,7 +1,7 @@
1
- """Utilities for side-by-side inspection and comparison of Python objects using Rich.
1
+ """Utilities for side-by-side inspection and comparison of Python objects.
2
2
 
3
- This module provides functions to display attributes and methods of two objects
4
- in a visually appealing, side-by-side format in the terminal.
3
+ This module provides functions to display attributes and methods of two objects in a
4
+ visually appealing, side-by-side format in the terminal.
5
5
  """
6
6
 
7
7
  from __future__ import annotations
@@ -15,15 +15,7 @@ from rich.text import Text
15
15
 
16
16
 
17
17
  def _get_object_attributes(obj: object) -> list[str]:
18
- """Extract and format non-callable attributes of an object.
19
-
20
- Args:
21
- obj: The object to inspect.
22
-
23
- Returns:
24
- A list of strings, each representing an attribute in 'name=value' format.
25
-
26
- """
18
+ """Extract and format non-callable attributes of an object."""
27
19
  attributes: list[str] = []
28
20
  for attr_name in sorted(dir(obj)):
29
21
  # Safely get attribute, returning None if it doesn't exist
@@ -37,15 +29,7 @@ def _get_object_attributes(obj: object) -> list[str]:
37
29
 
38
30
 
39
31
  def _get_object_methods(obj: object) -> list[str]:
40
- """Extract and format public callable methods of an object.
41
-
42
- Args:
43
- obj: The object to inspect.
44
-
45
- Returns:
46
- A list of strings, each representing a method name.
47
-
48
- """
32
+ """Extract and format public callable methods of an object."""
49
33
  methods: list[str] = []
50
34
  for method_name in sorted(dir(obj)):
51
35
  # Safely get attribute, returning None if it doesn't exist
@@ -59,15 +43,8 @@ def _get_object_methods(obj: object) -> list[str]:
59
43
  def _get_simplified_object_info(obj: object) -> list[Text]:
60
44
  """Generate a simplified, Rich-formatted inspection output for an object.
61
45
 
62
- Handles basic Python types by displaying their value directly. For other
63
- objects, it lists their attributes and public methods.
64
-
65
- Args:
66
- obj: The object to generate info for.
67
-
68
- Returns:
69
- A list of Rich Text objects, each representing a line of information.
70
-
46
+ Handles basic Python types by displaying their value directly. For other objects, it
47
+ lists their attributes and public methods.
71
48
  """
72
49
  info_lines: list[Text] = []
73
50
  obj_type: str = type(obj).__name__
@@ -1,19 +1,20 @@
1
1
  """Debug Dojo configuration module.
2
2
 
3
- It includes configurations for different debuggers, exception handling,
4
- and features that can be enabled or disabled.
3
+ It includes configurations for different debuggers, exception handling, and features
4
+ that can be enabled or disabled.
5
5
  """
6
6
 
7
7
  from __future__ import annotations
8
8
 
9
- import sys
9
+ from collections.abc import Mapping, Sequence
10
10
  from pathlib import Path
11
- from typing import Any, cast
11
+ from typing import Any, TypeAlias, cast
12
12
 
13
13
  from pydantic import ValidationError
14
14
  from rich import print as rich_print
15
15
  from tomlkit import parse
16
16
  from tomlkit.exceptions import TOMLKitError
17
+ from typer import Exit
17
18
 
18
19
  from ._config_models import (
19
20
  DebugDojoConfig,
@@ -22,6 +23,10 @@ from ._config_models import (
22
23
  DebuggerType,
23
24
  )
24
25
 
26
+ JSON_ro: TypeAlias = (
27
+ Mapping[str, "JSON_ro"] | Sequence["JSON_ro"] | str | int | float | bool | None
28
+ )
29
+
25
30
 
26
31
  def __filter_pydantic_error_msg(error: ValidationError) -> str:
27
32
  """Filter out specific lines from a Pydantic validation error."""
@@ -32,8 +37,11 @@ def __filter_pydantic_error_msg(error: ValidationError) -> str:
32
37
  )
33
38
 
34
39
 
35
- def resolve_config_path(config_path: Path | None) -> Path | None:
36
- """Resolve the configuration path, returning a default if none is provided."""
40
+ def __resolve_config_path(config_path: Path | None) -> Path | None:
41
+ """Resolve the configuration path.
42
+
43
+ Returning a default if none is provided.
44
+ """
37
45
  if config_path:
38
46
  if not config_path.exists():
39
47
  msg = f"Configuration file not found:\n{config_path.resolve()}"
@@ -44,16 +52,16 @@ def resolve_config_path(config_path: Path | None) -> Path | None:
44
52
  for path in (Path("dojo.toml"), Path("pyproject.toml")):
45
53
  if path.exists():
46
54
  return path.resolve()
55
+
56
+ # None means - use default config values
47
57
  return None
48
58
 
49
59
 
50
- def load_raw_config(
51
- config_path: Path,
52
- ) -> dict[str, Any]: # pyright: ignore[reportExplicitAny]
60
+ def __load_raw_config(config_path: Path) -> JSON_ro:
53
61
  """Load the Debug Dojo configuration from a file.
54
62
 
55
- Currently supports 'dojo.toml' or 'pyproject.toml'.
56
- If no path is provided, it checks the current directory for these files.
63
+ Currently supports 'dojo.toml' or 'pyproject.toml'. If no path is provided, it
64
+ checks the current directory for these files.
57
65
  """
58
66
  config_str = config_path.read_text(encoding="utf-8")
59
67
 
@@ -66,7 +74,10 @@ def load_raw_config(
66
74
  # If config is in [tool.debug_dojo] (pyproject.toml), extract it.
67
75
  if config_path.name == "pyproject.toml":
68
76
  try:
69
- dojo_config = cast("dict[str, Any]", config_data["tool"]["debug_dojo"])
77
+ dojo_config = cast(
78
+ "dict[str, Any]", # pyright: ignore[reportExplicitAny]
79
+ config_data["tool"]["debug_dojo"],
80
+ )
70
81
  except KeyError:
71
82
  return {}
72
83
  else:
@@ -75,28 +86,11 @@ def load_raw_config(
75
86
  return config_data
76
87
 
77
88
 
78
- def load_config( # noqa: C901
79
- config_path: Path | None = None,
80
- *,
81
- verbose: bool = False,
82
- debugger: DebuggerType | None = None,
89
+ def __validated_and_updated_config(
90
+ raw_config: JSON_ro, *, verbose: bool
83
91
  ) -> DebugDojoConfig:
84
- """Load the Debug Dojo configuration and return a DebugDojoConfig instance."""
85
- resolved_path = resolve_config_path(config_path)
86
-
87
- if verbose:
88
- if resolved_path:
89
- msg = f"Using configuration file: {resolved_path}."
90
- else:
91
- msg = "No configuration file found, using default settings."
92
- rich_print(f"[blue]{msg}[/blue]")
93
-
94
- if not resolved_path:
95
- return DebugDojoConfig()
96
-
97
- raw_config = load_raw_config(resolved_path)
98
-
99
92
  config = None
93
+
100
94
  for model in (DebugDojoConfigV2, DebugDojoConfigV1):
101
95
  model_name = model.__name__
102
96
  try:
@@ -106,7 +100,6 @@ def load_config( # noqa: C901
106
100
  msg = (
107
101
  f"[yellow]Configuration validation error for {model_name}:\n"
108
102
  f"{__filter_pydantic_error_msg(e)}\n\n"
109
- f"Please check your configuration file {resolved_path}.[/yellow]"
110
103
  )
111
104
  rich_print(msg)
112
105
  else:
@@ -119,17 +112,45 @@ def load_config( # noqa: C901
119
112
  break
120
113
 
121
114
  if not config:
122
- msg = (
123
- f"[red]Unsupported configuration version in {resolved_path.resolve()}.\n"
124
- "Please update your configuration file.[/red]"
125
- )
115
+ msg = "[red]Unsupported configuration version or error.[/red]"
126
116
  rich_print(msg)
127
- sys.exit(1)
117
+ raise Exit(code=1)
128
118
 
129
119
  while not isinstance(config, DebugDojoConfig):
130
120
  config = config.update()
131
121
 
132
- # If a debugger is specified, update the config.
122
+ return config
123
+
124
+
125
+ def load_config(
126
+ config_path: Path | None = None,
127
+ *,
128
+ verbose: bool = False,
129
+ debugger: DebuggerType | None = None,
130
+ ) -> DebugDojoConfig:
131
+ """Load the Debug Dojo configuration.
132
+
133
+ Return a DebugDojoConfig instance with the loaded configuration.
134
+
135
+ If no configuration file is found, it returns a default configuration. If a debugger
136
+ is specified, it overrides the config.
137
+ """
138
+ resolved_path = __resolve_config_path(config_path)
139
+
140
+ if verbose:
141
+ if resolved_path:
142
+ msg = f"Using configuration file: {resolved_path}."
143
+ else:
144
+ msg = "No configuration file found, using default settings."
145
+ rich_print(f"[blue]{msg}[/blue]")
146
+
147
+ if not resolved_path:
148
+ return DebugDojoConfig()
149
+
150
+ raw_config = __load_raw_config(resolved_path)
151
+ config = __validated_and_updated_config(raw_config, verbose=verbose)
152
+
153
+ # If a debugger is specified, override the config.
133
154
  if debugger:
134
155
  config.debuggers.default = debugger
135
156