debug-dojo 0.3.1__tar.gz → 0.4.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.
@@ -205,3 +205,4 @@ __marimo__/
205
205
  # IDE specific files
206
206
  .idea/
207
207
  .vscode/
208
+ .DS_Store
@@ -1,37 +1,37 @@
1
- ## v0.3.0 (2025-07-20)
1
+ ## v0.4.0 (2025-08-10)
2
2
 
3
- *release tag*: [v0.3.0]
3
+ *release tag*: [v0.4.0]
4
4
 
5
- ### What's Changed
5
+ - New configuration model `DebugDojoConfig` for better structure.
6
+ - Added support for `debugger` configuration in `dojo.toml`.
7
+ - Updated `dojo` command to include debugger type in command call.
8
+ - Configuration versioning allows for in-flight migration of old configurations.
9
+ - Improved error handling in configuration loading.
10
+ - Improved catching errors from target execution.
11
+
12
+ ## v0.3.2 (2025-07-28)
13
+
14
+ *release tag*: [v0.3.2]
6
15
 
7
16
  - New logo for the project.
8
17
  - Typer used for CLI implementation.
9
18
  - Dojo is configured via `dojo.toml` or `pyproject.toml`.
10
-
11
- #### Fixes
12
-
19
+ - Support for `debugpy` and `ipdb` for debugging.
13
20
  - Fixed documentation and history.
14
21
 
15
22
  ## v0.2.0 (2025-07-20)
16
23
 
17
24
  *release tag*: [v0.2.0]
18
25
 
19
- ### What's Changed
20
-
21
26
  - Added `dojo` command for easy debugging setup.
22
27
  - Added `p()` function for rich printing.
23
28
  - Added history file for tracking changes.
24
29
  - Moved to `hatch` for building and packaging.
25
-
26
- #### Fixes
27
-
28
30
  - Fixed `pyproject.toml` to point to GitHub repository as the homepage.
29
31
 
30
32
  ## v0.1.0 (2025-07-19)
31
33
 
32
34
  *release tag*: [v0.1.0]
33
35
 
34
- ### What's Changed
35
-
36
36
  - Initial module to install debugging tools.
37
37
  - Debug mode utilities for PuDB, rich tracebacks, and object inspection.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: debug-dojo
3
- Version: 0.3.1
3
+ Version: 0.4.0
4
4
  Summary: Debbugging dojo for Python developers
5
5
  Project-URL: Homepage, https://github.com/bwrob/debug-dojo
6
6
  Project-URL: Documentation, https://github.com/bwrob/debug-dojo/blob/main/README.md
@@ -8,6 +8,7 @@ Project-URL: Source, https://github.com/bwrob/debug-dojo/tree/main/src/debug_doj
8
8
  Project-URL: Changelog, https://github.com/bwrob/debug-dojo/blob/main/HISTORY.md
9
9
  Author-email: bwrob <bartosz.marcin.wroblewski@gmail.com>
10
10
  License-Expression: MIT
11
+ License-File: LICENSE
11
12
  Keywords: debugging,inspection,pudb,rich,tools,traceback
12
13
  Classifier: Development Status :: 3 - Alpha
13
14
  Classifier: Intended Audience :: Developers
@@ -30,7 +31,7 @@ Requires-Dist: typer>=0.15.0
30
31
  Description-Content-Type: text/markdown
31
32
 
32
33
  <p align="center">
33
- <img src="https://github.com/bwrob/debug-dojo/blob/main/logo/logo_white.png?raw=true" alt="debug dojo" style="width:50%; max-width:400px;"/>
34
+ <img src="https://github.com/bwrob/debug-dojo/blob/main/logo/logo_python.png?raw=true" alt="debug dojo" style="width:50%; max-width:300px;"/>
34
35
  </p>
35
36
 
36
37
  <p align="center">
@@ -40,15 +41,17 @@ Description-Content-Type: text/markdown
40
41
  [![PyPi Version](https://img.shields.io/pypi/v/debug-dojo.svg?style=flat-square)](https://pypi.org/project/debug-dojo)
41
42
  [![PyPI pyversions](https://img.shields.io/pypi/pyversions/debug-dojo.svg?style=flat-square)](https://pypi.org/pypi/debug-dojo/)
42
43
 
43
- **debug-dojo** is a Python package providing utilities for enhanced debugging and inspection in the terminal. 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. All tools can be installed at once or individually, allowing for flexible debugging setups.
44
+ **debug-dojo** is a Python package providing utilities for enhanced debugging and inspection in the terminal.
45
+ 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`.
44
46
 
45
47
  ## Features
46
48
 
47
49
  - **Convenient CLI** Quickly run your code with debugging tools enabled.
48
50
  - **Simple API:** Install all tools or only what you need.
49
- - **Debugger integration:** Quickly enable Debugpy, PuDB, PDB, or IPDB as your default debugger.
51
+ - **Debugger integration:** Quickly enable Debugpy, PuDB, PDB, or IPDB as your default pre-configured debugger.
50
52
  - **Rich tracebacks:** Get readable, colorized tracebacks for easier debugging.
51
53
  - **Side-by-side object inspection:** Visually compare Python objects, their attributes, and methods in the terminal.
54
+ - **Configuration:** Easily configure the debugging tools using `dojo.toml` or `pyproject.toml`.
52
55
 
53
56
  ## Usage
54
57
 
@@ -60,10 +63,10 @@ Run your Python script with debugging tools enabled using the `debug-dojo` comma
60
63
  dojo my_script.py
61
64
  ```
62
65
 
63
- You can optionally set configuration file and verbose mode:
66
+ You can optionally set configuration, verbose mode, and specify the debugger type. Both script files and modules are supported:
64
67
 
65
68
  ```console
66
- dojo --config dojo.toml --verbose my_script.py
69
+ dojo --debugger ipdb --config dojo.toml --verbose --module my_module
67
70
  ```
68
71
 
69
72
  ### From the code
@@ -71,19 +74,18 @@ dojo --config dojo.toml --verbose my_script.py
71
74
  In the `PuDB` style, you can install all debugging tools and enter the debugging mode with a single command:
72
75
 
73
76
  ```python
74
- import debug_dojo.install; b()
75
-
76
77
  object_1 = {"foo": 1, "bar": 2}
77
78
  object_2 = [1, 2, 3]
78
79
 
80
+ import debug_dojo.install; b()
79
81
  p(object_1) # Pretty print an object with Rich
80
- i(object_1) # Inspect an object
81
- c(object_1, object_2) # Compare two objects side-by-side
82
82
  ```
83
83
 
84
- Where:
84
+ ### Features in debugging mode
85
+
86
+ The following functions are available in the debugging mode, injected into builtins:
85
87
 
86
- - `b()` is a builtin-injected function that sets a breakpoint using PuDB's `set_trace()`.
88
+ - `b()` is a hook that sets a breakpoint using the configured debugger.
87
89
  - `p(object_1)` is pretty printing of an object using Rich.
88
90
  - `i(object_1)` to inspect an object using Rich.
89
91
  - `c(object_1, object_2)` to compare two objects side-by-side.
@@ -95,12 +97,23 @@ You can configure the debugging tools using a `dojo.toml` or `pyproject.toml` fi
95
97
  **Example `dojo.toml`:**
96
98
 
97
99
  ```toml
98
- debugger = "ipdb"
100
+ [debuggers]
101
+ default = "ipdb"
102
+
103
+ debugpy = { port = 1992 }
104
+ ipdb = { context_lines = 20 }
105
+
106
+ [exceptions]
107
+ locals_in_traceback = false
108
+ post_mortem = true
109
+ rich_traceback = true
99
110
 
100
111
  [features]
101
- rich_inspect = true
102
- rich_print = true
103
- comparer = false
112
+ breakpoint = "b"
113
+ # Empty string means disable the feature
114
+ comparer = ""
115
+ rich_inspect = "i"
116
+ rich_print = "p"
104
117
  ```
105
118
 
106
119
  ## Installation
@@ -130,45 +143,50 @@ Note that dojo most likely will not work when installed via `pipx` or `uvx`, as
130
143
  ```console
131
144
  ruff check src/debug_dojo --fix
132
145
  basedpyright src/debug_dojo
146
+
147
+ poe code-quality
133
148
  ```
134
149
 
150
+ ### Tests
151
+
152
+ TBA
135
153
 
136
154
  ## Changelog
137
155
 
138
- ## v0.3.0 (2025-07-20)
156
+ ## v0.4.0 (2025-08-10)
139
157
 
140
- *release tag*: [v0.3.0]
158
+ *release tag*: [v0.4.0]
141
159
 
142
- ### What's Changed
160
+ - New configuration model `DebugDojoConfig` for better structure.
161
+ - Added support for `debugger` configuration in `dojo.toml`.
162
+ - Updated `dojo` command to include debugger type in command call.
163
+ - Configuration versioning allows for in-flight migration of old configurations.
164
+ - Improved error handling in configuration loading.
165
+ - Improved catching errors from target execution.
166
+
167
+ ## v0.3.2 (2025-07-28)
168
+
169
+ *release tag*: [v0.3.2]
143
170
 
144
171
  - New logo for the project.
145
172
  - Typer used for CLI implementation.
146
173
  - Dojo is configured via `dojo.toml` or `pyproject.toml`.
147
-
148
- #### Fixes
149
-
174
+ - Support for `debugpy` and `ipdb` for debugging.
150
175
  - Fixed documentation and history.
151
176
 
152
177
  ## v0.2.0 (2025-07-20)
153
178
 
154
179
  *release tag*: [v0.2.0]
155
180
 
156
- ### What's Changed
157
-
158
181
  - Added `dojo` command for easy debugging setup.
159
182
  - Added `p()` function for rich printing.
160
183
  - Added history file for tracking changes.
161
184
  - Moved to `hatch` for building and packaging.
162
-
163
- #### Fixes
164
-
165
185
  - Fixed `pyproject.toml` to point to GitHub repository as the homepage.
166
186
 
167
187
  ## v0.1.0 (2025-07-19)
168
188
 
169
189
  *release tag*: [v0.1.0]
170
190
 
171
- ### What's Changed
172
-
173
191
  - Initial module to install debugging tools.
174
192
  - Debug mode utilities for PuDB, rich tracebacks, and object inspection.
@@ -1,5 +1,5 @@
1
1
  <p align="center">
2
- <img src="https://github.com/bwrob/debug-dojo/blob/main/logo/logo_white.png?raw=true" alt="debug dojo" style="width:50%; max-width:400px;"/>
2
+ <img src="https://github.com/bwrob/debug-dojo/blob/main/logo/logo_python.png?raw=true" alt="debug dojo" style="width:50%; max-width:300px;"/>
3
3
  </p>
4
4
 
5
5
  <p align="center">
@@ -9,15 +9,17 @@
9
9
  [![PyPi Version](https://img.shields.io/pypi/v/debug-dojo.svg?style=flat-square)](https://pypi.org/project/debug-dojo)
10
10
  [![PyPI pyversions](https://img.shields.io/pypi/pyversions/debug-dojo.svg?style=flat-square)](https://pypi.org/pypi/debug-dojo/)
11
11
 
12
- **debug-dojo** is a Python package providing utilities for enhanced debugging and inspection in the terminal. 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. All tools can be installed at once or individually, allowing for flexible debugging setups.
12
+ **debug-dojo** is a Python package providing utilities for enhanced debugging and inspection in the terminal.
13
+ 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`.
13
14
 
14
15
  ## Features
15
16
 
16
17
  - **Convenient CLI** Quickly run your code with debugging tools enabled.
17
18
  - **Simple API:** Install all tools or only what you need.
18
- - **Debugger integration:** Quickly enable Debugpy, PuDB, PDB, or IPDB as your default debugger.
19
+ - **Debugger integration:** Quickly enable Debugpy, PuDB, PDB, or IPDB as your default pre-configured debugger.
19
20
  - **Rich tracebacks:** Get readable, colorized tracebacks for easier debugging.
20
21
  - **Side-by-side object inspection:** Visually compare Python objects, their attributes, and methods in the terminal.
22
+ - **Configuration:** Easily configure the debugging tools using `dojo.toml` or `pyproject.toml`.
21
23
 
22
24
  ## Usage
23
25
 
@@ -29,10 +31,10 @@ Run your Python script with debugging tools enabled using the `debug-dojo` comma
29
31
  dojo my_script.py
30
32
  ```
31
33
 
32
- You can optionally set configuration file and verbose mode:
34
+ You can optionally set configuration, verbose mode, and specify the debugger type. Both script files and modules are supported:
33
35
 
34
36
  ```console
35
- dojo --config dojo.toml --verbose my_script.py
37
+ dojo --debugger ipdb --config dojo.toml --verbose --module my_module
36
38
  ```
37
39
 
38
40
  ### From the code
@@ -40,19 +42,18 @@ dojo --config dojo.toml --verbose my_script.py
40
42
  In the `PuDB` style, you can install all debugging tools and enter the debugging mode with a single command:
41
43
 
42
44
  ```python
43
- import debug_dojo.install; b()
44
-
45
45
  object_1 = {"foo": 1, "bar": 2}
46
46
  object_2 = [1, 2, 3]
47
47
 
48
+ import debug_dojo.install; b()
48
49
  p(object_1) # Pretty print an object with Rich
49
- i(object_1) # Inspect an object
50
- c(object_1, object_2) # Compare two objects side-by-side
51
50
  ```
52
51
 
53
- Where:
52
+ ### Features in debugging mode
54
53
 
55
- - `b()` is a builtin-injected function that sets a breakpoint using PuDB's `set_trace()`.
54
+ The following functions are available in the debugging mode, injected into builtins:
55
+
56
+ - `b()` is a hook that sets a breakpoint using the configured debugger.
56
57
  - `p(object_1)` is pretty printing of an object using Rich.
57
58
  - `i(object_1)` to inspect an object using Rich.
58
59
  - `c(object_1, object_2)` to compare two objects side-by-side.
@@ -64,12 +65,23 @@ You can configure the debugging tools using a `dojo.toml` or `pyproject.toml` fi
64
65
  **Example `dojo.toml`:**
65
66
 
66
67
  ```toml
67
- debugger = "ipdb"
68
+ [debuggers]
69
+ default = "ipdb"
70
+
71
+ debugpy = { port = 1992 }
72
+ ipdb = { context_lines = 20 }
73
+
74
+ [exceptions]
75
+ locals_in_traceback = false
76
+ post_mortem = true
77
+ rich_traceback = true
68
78
 
69
79
  [features]
70
- rich_inspect = true
71
- rich_print = true
72
- comparer = false
80
+ breakpoint = "b"
81
+ # Empty string means disable the feature
82
+ comparer = ""
83
+ rich_inspect = "i"
84
+ rich_print = "p"
73
85
  ```
74
86
 
75
87
  ## Installation
@@ -99,4 +111,10 @@ Note that dojo most likely will not work when installed via `pipx` or `uvx`, as
99
111
  ```console
100
112
  ruff check src/debug_dojo --fix
101
113
  basedpyright src/debug_dojo
114
+
115
+ poe code-quality
102
116
  ```
117
+
118
+ ### Tests
119
+
120
+ TBA
@@ -13,7 +13,7 @@
13
13
  "rich>=12.0.0",
14
14
  "tomlkit>=0.13.3",
15
15
  "typer>=0.15.0",
16
- ]
16
+ ]
17
17
  license = 'MIT'
18
18
  license-files = ['LICENSE']
19
19
  keywords = [
@@ -36,7 +36,7 @@
36
36
  "Topic :: Software Development :: Debuggers",
37
37
  "Topic :: Software Development :: Libraries :: Python Modules",
38
38
  ]
39
- version = "0.3.1"
39
+ version = "0.4.0"
40
40
  dynamic = ['readme']
41
41
 
42
42
  [project.urls]
@@ -46,8 +46,6 @@ version = "0.3.1"
46
46
  Changelog = "https://github.com/bwrob/debug-dojo/blob/main/HISTORY.md"
47
47
 
48
48
  [project.scripts]
49
- # This defines your command-line script!
50
- # It points to the 'main' function in your 'cli' module.
51
49
  "dojo" = "debug_dojo._cli:main"
52
50
 
53
51
  [dependency-groups]
@@ -56,7 +54,7 @@ version = "0.3.1"
56
54
  "jupyter>=1.1.1",
57
55
  "poethepoet>=0.36.0",
58
56
  "ruff>=0.12.4",
59
- ]
57
+ ]
60
58
 
61
59
  [build-system]
62
60
  requires = [
@@ -65,10 +63,6 @@ version = "0.3.1"
65
63
  ]
66
64
  build-backend = "hatchling.build"
67
65
 
68
-
69
- [tool.hatch.version]
70
- path = "src/debug_dojo/version.py"
71
-
72
66
  [tool.hatch.metadata]
73
67
  allow-direct-references = true
74
68
 
@@ -81,15 +75,28 @@ version = "0.3.1"
81
75
  { path = 'HISTORY.md' },
82
76
  ]
83
77
 
78
+
79
+ [tool.hatch.build.targets.sdist]
80
+ include = [
81
+ "/README.md",
82
+ "/HISTORY.md",
83
+ "/src/debug_dojo",
84
+ ]
85
+
84
86
  [tool.basedpyright]
85
- typeCheckingMode = "all"
87
+ typeCheckingMode = "basic"
86
88
  pythonVersion = "3.10"
87
89
  strict = ["src/debug_dojo/*"]
88
90
  ignore = ["examples"]
89
91
 
90
92
  [tool.poe.tasks]
91
- # Define your tasks here
92
93
  lint = "ruff check --fix src"
93
94
  format = "ruff format src"
94
- type-check = "basedpyright"
95
+ type-check = "basedpyright --project pyproject.toml src/debug_dojo"
95
96
  code-quality = ["format", "lint", "type-check"]
97
+ publish = [
98
+ "code-quality",
99
+ { cmd = "rm -rf dist" },
100
+ { cmd = "uv build" },
101
+ { cmd = "uv publish" },
102
+ ]
@@ -2,7 +2,6 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- import os
6
5
  import runpy
7
6
  import sys
8
7
  from bdb import BdbQuit
@@ -10,10 +9,9 @@ from pathlib import Path
10
9
  from typing import Annotated
11
10
 
12
11
  import typer
13
- from pydantic import ValidationError
14
12
  from rich import print as rich_print
15
13
 
16
- from ._config import DebugDojoConfig, load_config
14
+ from ._config import DebugDojoConfig, DebuggerType, load_config
17
15
  from ._installers import install_by_config
18
16
 
19
17
  cli = typer.Typer(
@@ -23,11 +21,13 @@ cli = typer.Typer(
23
21
  )
24
22
 
25
23
 
26
- def execute_with_debug(
24
+ def execute_with_debug( # noqa: C901
27
25
  target_name: str,
28
26
  target_args: list[str],
29
27
  *,
28
+ target_is_module: bool,
30
29
  verbose: bool,
30
+ config: DebugDojoConfig,
31
31
  ) -> None:
32
32
  """Execute a target script or module with installation of debugging tools."""
33
33
  sys.argv = [target_name, *target_args]
@@ -36,21 +36,37 @@ def execute_with_debug(
36
36
  rich_print(f"[blue]Installing debugging tools for {target_name}.[/blue]")
37
37
  rich_print(f"[blue]Arguments for target: {target_args}[/blue]")
38
38
 
39
- config = load_config()
40
39
  install_by_config(config)
41
40
 
42
- if (
43
- Path(target_name).exists()
44
- or target_name.endswith(".py")
45
- or os.sep in target_name
46
- ):
41
+ if target_is_module:
42
+ runner = runpy.run_module
43
+ else:
47
44
  if not Path(target_name).exists():
48
45
  sys.exit(1)
49
46
  runner = runpy.run_path
50
- else:
51
- runner = runpy.run_module
52
47
 
53
- _ = runner(target_name, run_name="__main__")
48
+ try:
49
+ _ = runner(target_name, run_name="__main__")
50
+ except ImportError as e:
51
+ rich_print(f"[red]Error importing {target_name}:[/red]\n{e}")
52
+ sys.exit(1)
53
+ except BdbQuit:
54
+ rich_print("[red]Debugging session terminated by user.[/red]")
55
+ sys.exit(0)
56
+ except KeyboardInterrupt:
57
+ rich_print("[red]Execution interrupted by user.[/red]")
58
+ sys.exit(0)
59
+ except SystemExit as e:
60
+ if e.code:
61
+ rich_print(f"[red]Script exited with code {e.code}.[/red]")
62
+ except Exception as e: # noqa: BLE001
63
+ rich_print(f"[red]Error while running {target_name}:[/red]\n{e}")
64
+ if config.exceptions.post_mortem:
65
+ import pdb # noqa: PLC0415, T100
66
+
67
+ rich_print("[blue]Entering post-mortem debugging session...[/blue]")
68
+ pdb.post_mortem(e.__traceback__)
69
+ sys.exit(1)
54
70
 
55
71
 
56
72
  def display_config(config: DebugDojoConfig) -> None:
@@ -64,36 +80,42 @@ def display_config(config: DebugDojoConfig) -> None:
64
80
  no_args_is_help=True,
65
81
  context_settings={"allow_extra_args": True, "ignore_unknown_options": True},
66
82
  )
67
- def run_debug(
83
+ def run_debug( # noqa: PLR0913
68
84
  ctx: typer.Context,
69
85
  target_name: Annotated[
70
86
  str | None, typer.Argument(help="The target script or module to debug.")
71
87
  ] = None,
88
+ *,
72
89
  config_path: Annotated[
73
90
  Path | None, typer.Option("--config", "-c", help="Show configuration")
74
91
  ] = None,
75
- *,
92
+ debugger: Annotated[
93
+ DebuggerType | None,
94
+ typer.Option("--debugger", "-d", help="Specify the debugger to use"),
95
+ ] = None,
76
96
  verbose: Annotated[
77
97
  bool,
78
98
  typer.Option("--verbose", "-v", is_flag=True, help="Enable verbose output"),
79
99
  ] = False,
100
+ module: Annotated[
101
+ bool,
102
+ typer.Option("--module", "-m", is_flag=True, help="Run as a module"),
103
+ ] = False,
80
104
  ) -> None:
81
105
  """Run the command-line interface."""
82
- try:
83
- config = load_config(config_path, verbose=verbose)
84
- except ValidationError as e:
85
- rich_print(f"[red]Configuration error:\n{e}[/red]")
86
- sys.exit(1)
106
+ config = load_config(config_path, verbose=verbose, debugger=debugger)
87
107
 
88
108
  if verbose:
89
109
  display_config(config)
90
110
 
91
111
  if target_name:
92
- try:
93
- execute_with_debug(target_name, ctx.args, verbose=verbose)
94
- except BdbQuit:
95
- rich_print("[red]Debugging session terminated by user.[/red]")
96
- sys.exit(0)
112
+ execute_with_debug(
113
+ target_name=target_name,
114
+ target_is_module=module,
115
+ target_args=ctx.args,
116
+ verbose=verbose,
117
+ config=config,
118
+ )
97
119
 
98
120
 
99
121
  def main() -> None:
@@ -0,0 +1,136 @@
1
+ """Debug Dojo configuration module.
2
+
3
+ It includes configurations for different debuggers, exception handling,
4
+ and features that can be enabled or disabled.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import sys
10
+ from pathlib import Path
11
+ from typing import Any, cast
12
+
13
+ from pydantic import ValidationError
14
+ from rich import print as rich_print
15
+ from tomlkit import parse
16
+ from tomlkit.exceptions import TOMLKitError
17
+
18
+ from ._config_models import (
19
+ DebugDojoConfig,
20
+ DebugDojoConfigV1,
21
+ DebugDojoConfigV2,
22
+ DebuggerType,
23
+ )
24
+
25
+
26
+ def __filter_pydantic_error_msg(error: ValidationError) -> str:
27
+ """Filter out specific lines from a Pydantic validation error."""
28
+ return "\n".join(
29
+ line
30
+ for line in str(error).splitlines()
31
+ if not line.startswith("For further information visit")
32
+ )
33
+
34
+
35
+ def resolve_config_path(config_path: Path | None) -> Path | None:
36
+ """Resolve the configuration path, returning a default if none is provided."""
37
+ if config_path:
38
+ if not config_path.exists():
39
+ msg = f"Configuration file not found:\n{config_path.resolve()}"
40
+ raise FileNotFoundError(msg)
41
+ return config_path.resolve()
42
+
43
+ # Default configuration path
44
+ for path in (Path("dojo.toml"), Path("pyproject.toml")):
45
+ if path.exists():
46
+ return path.resolve()
47
+ return None
48
+
49
+
50
+ def load_raw_config(
51
+ config_path: Path,
52
+ ) -> dict[str, Any]: # pyright: ignore[reportExplicitAny]
53
+ """Load the Debug Dojo configuration from a file.
54
+
55
+ Currently supports 'dojo.toml' or 'pyproject.toml'.
56
+ If no path is provided, it checks the current directory for these files.
57
+ """
58
+ config_str = config_path.read_text(encoding="utf-8")
59
+
60
+ try:
61
+ config_data = parse(config_str).unwrap()
62
+ except TOMLKitError as e:
63
+ msg = f"Error parsing configuration file {config_path.resolve()}."
64
+ raise ValueError(msg) from e
65
+
66
+ # If config is in [tool.debug_dojo] (pyproject.toml), extract it.
67
+ if config_path.name == "pyproject.toml":
68
+ try:
69
+ dojo_config = cast("dict[str, Any]", config_data["tool"]["debug_dojo"])
70
+ except KeyError:
71
+ return {}
72
+ else:
73
+ return dojo_config
74
+
75
+ return config_data
76
+
77
+
78
+ def load_config( # noqa: C901
79
+ config_path: Path | None = None,
80
+ *,
81
+ verbose: bool = False,
82
+ debugger: DebuggerType | None = None,
83
+ ) -> 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
+ config = None
100
+ for model in (DebugDojoConfigV2, DebugDojoConfigV1):
101
+ model_name = model.__name__
102
+ try:
103
+ config = model.model_validate(raw_config)
104
+ except ValidationError as e:
105
+ if verbose:
106
+ msg = (
107
+ f"[yellow]Configuration validation error for {model_name}:\n"
108
+ f"{__filter_pydantic_error_msg(e)}\n\n"
109
+ f"Please check your configuration file {resolved_path}.[/yellow]"
110
+ )
111
+ rich_print(msg)
112
+ else:
113
+ if verbose or model_name != DebugDojoConfig.__name__:
114
+ msg = (
115
+ f"[blue]Using configuration model: {model_name}.\n"
116
+ f"Current configuration model {DebugDojoConfig.__name__}. [/blue]"
117
+ )
118
+ rich_print(msg)
119
+ break
120
+
121
+ if not config:
122
+ msg = (
123
+ f"[red]Unsupported configuration version in {resolved_path.resolve()}.\n"
124
+ "Please update your configuration file.[/red]"
125
+ )
126
+ rich_print(msg)
127
+ sys.exit(1)
128
+
129
+ while not isinstance(config, DebugDojoConfig):
130
+ config = config.update()
131
+
132
+ # If a debugger is specified, update the config.
133
+ if debugger:
134
+ config.debuggers.default = debugger
135
+
136
+ return config