debug-dojo 0.5.0__tar.gz → 0.7.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.
Files changed (29) hide show
  1. debug_dojo-0.7.0/PKG-INFO +138 -0
  2. debug_dojo-0.7.0/README.md +105 -0
  3. debug_dojo-0.7.0/pyproject.toml +87 -0
  4. {debug_dojo-0.5.0 → debug_dojo-0.7.0}/src/debug_dojo/_cli.py +42 -9
  5. {debug_dojo-0.5.0 → debug_dojo-0.7.0}/src/debug_dojo/_compare.py +37 -9
  6. {debug_dojo-0.5.0 → debug_dojo-0.7.0}/src/debug_dojo/_config.py +77 -36
  7. {debug_dojo-0.5.0 → debug_dojo-0.7.0}/src/debug_dojo/_config_models.py +45 -41
  8. debug_dojo-0.7.0/src/debug_dojo/_installers.py +271 -0
  9. debug_dojo-0.7.0/src/debug_dojo.egg-info/PKG-INFO +138 -0
  10. {debug_dojo-0.5.0 → debug_dojo-0.7.0}/src/debug_dojo.egg-info/SOURCES.txt +4 -1
  11. debug_dojo-0.7.0/src/debug_dojo.egg-info/requires.txt +9 -0
  12. debug_dojo-0.7.0/tests/test_compare.py +75 -0
  13. debug_dojo-0.7.0/tests/test_config.py +81 -0
  14. debug_dojo-0.7.0/tests/test_installers.py +161 -0
  15. debug_dojo-0.5.0/PKG-INFO +0 -83
  16. debug_dojo-0.5.0/README.md +0 -52
  17. debug_dojo-0.5.0/pyproject.toml +0 -126
  18. debug_dojo-0.5.0/src/debug_dojo/_installers.py +0 -182
  19. debug_dojo-0.5.0/src/debug_dojo.egg-info/PKG-INFO +0 -83
  20. debug_dojo-0.5.0/src/debug_dojo.egg-info/requires.txt +0 -7
  21. {debug_dojo-0.5.0 → debug_dojo-0.7.0}/LICENSE +0 -0
  22. {debug_dojo-0.5.0 → debug_dojo-0.7.0}/setup.cfg +0 -0
  23. {debug_dojo-0.5.0 → debug_dojo-0.7.0}/src/debug_dojo/__init__.py +0 -0
  24. {debug_dojo-0.5.0 → debug_dojo-0.7.0}/src/debug_dojo/__main__.py +0 -0
  25. {debug_dojo-0.5.0 → debug_dojo-0.7.0}/src/debug_dojo/install.py +0 -0
  26. {debug_dojo-0.5.0 → debug_dojo-0.7.0}/src/debug_dojo/py.typed +0 -0
  27. {debug_dojo-0.5.0 → debug_dojo-0.7.0}/src/debug_dojo.egg-info/dependency_links.txt +0 -0
  28. {debug_dojo-0.5.0 → debug_dojo-0.7.0}/src/debug_dojo.egg-info/entry_points.txt +0 -0
  29. {debug_dojo-0.5.0 → debug_dojo-0.7.0}/src/debug_dojo.egg-info/top_level.txt +0 -0
@@ -0,0 +1,138 @@
1
+ Metadata-Version: 2.4
2
+ Name: debug-dojo
3
+ Version: 0.7.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: Programming Language :: Python :: 3.14
19
+ Classifier: Topic :: Software Development :: Debuggers
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Requires-Python: <3.15,>=3.10
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: dacite>=1.0.0
25
+ Requires-Dist: rich>=10.0.0
26
+ Requires-Dist: tomlkit>=0.7.0
27
+ Requires-Dist: typer>=0.3.0
28
+ Provides-Extra: all-debuggers
29
+ Requires-Dist: debugpy>=1.0.0; extra == "all-debuggers"
30
+ Requires-Dist: ipdb>=0.12.0; extra == "all-debuggers"
31
+ Requires-Dist: pudb>=2020.1; extra == "all-debuggers"
32
+ Dynamic: license-file
33
+
34
+ #
35
+
36
+ <p align="center">
37
+ <img src="https://github.com/bwrob/debug-dojo/blob/main/docs/logo/banner.png?raw=true" alt="debug dojo" style="width:100%;"/>
38
+ </p>
39
+
40
+ <p align="center">
41
+ <em>🏣 debug dojo, a place for zen debugging</em>
42
+ </p>
43
+
44
+ <p align="center">
45
+ <a href="https://pypi.org/project/debug-dojo">
46
+ <img src="https://img.shields.io/pypi/v/debug-dojo.svg?style=flat-square" alt="PyPi Version">
47
+ </a>
48
+ <a href="https://pypi.org/pypi/debug-dojo/">
49
+ <img src="https://img.shields.io/pypi/pyversions/debug-dojo.svg?style=flat-square" alt="PyPI pyversions">
50
+ </a>
51
+ <a href="https://pepy.tech/project/debug-dojo">
52
+ <img src="https://static.pepy.tech/badge/debug-dojo/month" alt="downloads">
53
+ </a>
54
+ <a href="https://github.com/bwrob/debug-dojo/blob/main/LICENSE">
55
+ <img src="https://img.shields.io/github/license/bwrob/debug-dojo.svg" alt="license">
56
+ </a>
57
+ <a href="https://results.pre-commit.ci/latest/github/bwrob/debug-dojo/main">
58
+ <img src="https://results.pre-commit.ci/badge/github/bwrob/debug-dojo/main.svg" alt="pre-commit.ci status">
59
+ </a>
60
+ </p>
61
+
62
+ [**debug-dojo**](https://bwrob.github.io/debug-dojo/) is a powerful Python package designed to streamline your debugging workflow directly from the terminal. It integrates seamlessly with popular debuggers and enhances your inspection capabilities with beautiful, readable output.
63
+
64
+ ## ✨ Features
65
+
66
+ * **Unified Debugging Interface:** Easily launch your scripts or modules with your preferred debugger (`debugpy`, `pudb`, `pdb`, `ipdb`).
67
+ * **Enhanced Output with Rich:** Leverages [`rich`](https://github.com/Textualize/rich) for stunning, syntax-highlighted code, pretty-printed objects, and improved tracebacks.
68
+ * **Side-by-Side Object Comparison:** Quickly identify differences between two Python objects.
69
+ * **Interactive Object Inspection:** Dive deep into object structures with a powerful `inspect` utility.
70
+ * **Simplified Breakpoints:** Set breakpoints effortlessly with a concise helper function.
71
+
72
+ ## 🚀 Installation
73
+
74
+ Install `debug-dojo` using `pip`:
75
+
76
+ ```bash
77
+ pip install debug-dojo
78
+ ```
79
+
80
+ For full debugger support, you might want to install optional dependencies:
81
+
82
+ ```bash
83
+ pip install "debug-dojo[all-debuggers]"
84
+ ```
85
+
86
+ ## 💻 CLI Usage
87
+
88
+ Run your Python script or module with `debug-dojo`:
89
+
90
+ ```console
91
+ dojo my_script.py
92
+ ```
93
+
94
+ Specify a debugger, configuration file, or enable verbose output:
95
+
96
+ ```console
97
+ dojo --debugger ipdb --config dojo.toml --verbose --module my_module
98
+ ```
99
+
100
+ Run an executable command with debugging tools:
101
+
102
+ ```console
103
+ dojo --exec pytest
104
+ ```
105
+
106
+ ## 🐍 Usage in Code
107
+
108
+ Integrate `debug-dojo` directly into your Python code for on-demand debugging and inspection utilities:
109
+
110
+ ```python
111
+ import debug_dojo.install
112
+
113
+ # Set a breakpoint and enter the debugger
114
+ # debug_dojo.install.b() # Equivalent to breakpoint()
115
+
116
+ object_1 = {"foo": 1, "bar": 2}
117
+ object_2 = [1, 2, 3]
118
+
119
+ # Pretty print an object with Rich
120
+ debug_dojo.install.p(object_1)
121
+
122
+ # Inspect an object using Rich
123
+ debug_dojo.install.i(object_1)
124
+
125
+ # Compare two objects side-by-side
126
+ debug_dojo.install.c(object_1, object_2)
127
+
128
+ # Enter the debugger (e.g., ipdb, pudb, pdb, debugpy based on config)
129
+ # debug_dojo.install.b()
130
+ ```
131
+
132
+ ## 📚 Documentation
133
+
134
+ For comprehensive instructions on installation, configuration, advanced usage, and API reference, please visit the [official documentation](https://bwrob.github.io/debug-dojo/).
135
+
136
+ ## 🤝 Contributing
137
+
138
+ Contributions are welcome! Please refer to the [development guidelines](https://bwrob.github.io/debug-dojo/development/) for details on how to set up your development environment and submit changes.
@@ -0,0 +1,105 @@
1
+ #
2
+
3
+ <p align="center">
4
+ <img src="https://github.com/bwrob/debug-dojo/blob/main/docs/logo/banner.png?raw=true" alt="debug dojo" style="width:100%;"/>
5
+ </p>
6
+
7
+ <p align="center">
8
+ <em>🏣 debug dojo, a place for zen debugging</em>
9
+ </p>
10
+
11
+ <p align="center">
12
+ <a href="https://pypi.org/project/debug-dojo">
13
+ <img src="https://img.shields.io/pypi/v/debug-dojo.svg?style=flat-square" alt="PyPi Version">
14
+ </a>
15
+ <a href="https://pypi.org/pypi/debug-dojo/">
16
+ <img src="https://img.shields.io/pypi/pyversions/debug-dojo.svg?style=flat-square" alt="PyPI pyversions">
17
+ </a>
18
+ <a href="https://pepy.tech/project/debug-dojo">
19
+ <img src="https://static.pepy.tech/badge/debug-dojo/month" alt="downloads">
20
+ </a>
21
+ <a href="https://github.com/bwrob/debug-dojo/blob/main/LICENSE">
22
+ <img src="https://img.shields.io/github/license/bwrob/debug-dojo.svg" alt="license">
23
+ </a>
24
+ <a href="https://results.pre-commit.ci/latest/github/bwrob/debug-dojo/main">
25
+ <img src="https://results.pre-commit.ci/badge/github/bwrob/debug-dojo/main.svg" alt="pre-commit.ci status">
26
+ </a>
27
+ </p>
28
+
29
+ [**debug-dojo**](https://bwrob.github.io/debug-dojo/) is a powerful Python package designed to streamline your debugging workflow directly from the terminal. It integrates seamlessly with popular debuggers and enhances your inspection capabilities with beautiful, readable output.
30
+
31
+ ## ✨ Features
32
+
33
+ * **Unified Debugging Interface:** Easily launch your scripts or modules with your preferred debugger (`debugpy`, `pudb`, `pdb`, `ipdb`).
34
+ * **Enhanced Output with Rich:** Leverages [`rich`](https://github.com/Textualize/rich) for stunning, syntax-highlighted code, pretty-printed objects, and improved tracebacks.
35
+ * **Side-by-Side Object Comparison:** Quickly identify differences between two Python objects.
36
+ * **Interactive Object Inspection:** Dive deep into object structures with a powerful `inspect` utility.
37
+ * **Simplified Breakpoints:** Set breakpoints effortlessly with a concise helper function.
38
+
39
+ ## 🚀 Installation
40
+
41
+ Install `debug-dojo` using `pip`:
42
+
43
+ ```bash
44
+ pip install debug-dojo
45
+ ```
46
+
47
+ For full debugger support, you might want to install optional dependencies:
48
+
49
+ ```bash
50
+ pip install "debug-dojo[all-debuggers]"
51
+ ```
52
+
53
+ ## 💻 CLI Usage
54
+
55
+ Run your Python script or module with `debug-dojo`:
56
+
57
+ ```console
58
+ dojo my_script.py
59
+ ```
60
+
61
+ Specify a debugger, configuration file, or enable verbose output:
62
+
63
+ ```console
64
+ dojo --debugger ipdb --config dojo.toml --verbose --module my_module
65
+ ```
66
+
67
+ Run an executable command with debugging tools:
68
+
69
+ ```console
70
+ dojo --exec pytest
71
+ ```
72
+
73
+ ## 🐍 Usage in Code
74
+
75
+ Integrate `debug-dojo` directly into your Python code for on-demand debugging and inspection utilities:
76
+
77
+ ```python
78
+ import debug_dojo.install
79
+
80
+ # Set a breakpoint and enter the debugger
81
+ # debug_dojo.install.b() # Equivalent to breakpoint()
82
+
83
+ object_1 = {"foo": 1, "bar": 2}
84
+ object_2 = [1, 2, 3]
85
+
86
+ # Pretty print an object with Rich
87
+ debug_dojo.install.p(object_1)
88
+
89
+ # Inspect an object using Rich
90
+ debug_dojo.install.i(object_1)
91
+
92
+ # Compare two objects side-by-side
93
+ debug_dojo.install.c(object_1, object_2)
94
+
95
+ # Enter the debugger (e.g., ipdb, pudb, pdb, debugpy based on config)
96
+ # debug_dojo.install.b()
97
+ ```
98
+
99
+ ## 📚 Documentation
100
+
101
+ For comprehensive instructions on installation, configuration, advanced usage, and API reference, please visit the [official documentation](https://bwrob.github.io/debug-dojo/).
102
+
103
+ ## 🤝 Contributing
104
+
105
+ Contributions are welcome! Please refer to the [development guidelines](https://bwrob.github.io/debug-dojo/development/) for details on how to set up your development environment and submit changes.
@@ -0,0 +1,87 @@
1
+ [project]
2
+ authors = [
3
+ { name = "bwrob", email = "bartosz.marcin.wroblewski@gmail.com" },
4
+ ]
5
+ classifiers = [
6
+ "Intended Audience :: Developers",
7
+ "Operating System :: OS Independent",
8
+ "Programming Language :: Python :: 3.10",
9
+ "Programming Language :: Python :: 3.11",
10
+ "Programming Language :: Python :: 3.12",
11
+ "Programming Language :: Python :: 3.13",
12
+ "Programming Language :: Python :: 3.14",
13
+ "Topic :: Software Development :: Debuggers",
14
+ "Topic :: Software Development :: Libraries :: Python Modules",
15
+ ]
16
+ dependencies = [
17
+ "dacite>=1.0.0",
18
+ "rich>=10.0.0",
19
+ "tomlkit>=0.7.0",
20
+ "typer>=0.3.0",
21
+ ]
22
+ description = "🏣 debug dojo, a place for zen debugging"
23
+ keywords = [
24
+ "debugging",
25
+ "inspection",
26
+ "tools",
27
+ "development",
28
+ ]
29
+ license = 'MIT'
30
+ license-files = ['LICENSE']
31
+ name = "debug-dojo"
32
+ readme = "README.md"
33
+ requires-python = ">=3.10,<3.15"
34
+ version = "0.7.0"
35
+
36
+ [project.urls]
37
+ Changelog = "https://bwrob.github.io/debug-dojo/changelog/"
38
+ Documentation = "https://bwrob.github.io/debug-dojo/"
39
+ Homepage = "https://bwrob.github.io/debug-dojo/"
40
+ Source = "https://github.com/bwrob/debug-dojo/"
41
+
42
+ [project.scripts]
43
+ "dojo" = "debug_dojo._cli:main"
44
+
45
+ [project.optional-dependencies]
46
+ all-debuggers = [
47
+ "debugpy>=1.0.0",
48
+ "ipdb>=0.12.0",
49
+ "pudb>=2020.1",
50
+ ]
51
+
52
+
53
+ [dependency-groups]
54
+
55
+ dev = [
56
+ "basedpyright>=1.31.2",
57
+ "coverage>=7.10.4",
58
+ "debug-dojo[all-debuggers]",
59
+ "diff-cover>=9.6.0",
60
+ "poethepoet>=0.37.0",
61
+ "pytest>=8.4.1",
62
+ "pytest-cov>=6.2.1",
63
+ "ruff>=0.12.9",
64
+ "tach>=0.29.0",
65
+ ]
66
+ docs = [
67
+ "mkdocs>=1.6.1",
68
+ "mkdocs-git-authors-plugin>=0.10.0",
69
+ "mkdocs-git-committers-plugin-2>=2.5.0",
70
+ "mkdocs-git-revision-date-localized-plugin>=1.4.7",
71
+ "mkdocs-material>=9.6.17",
72
+ "mkdocs-typer2>=0.1.5",
73
+ "mkdocstrings-python>=1.17.0",
74
+ "pymdown-extensions>=10.16.1",
75
+ "typst>=0.14.2",
76
+ ]
77
+
78
+
79
+ [tool.uv]
80
+ package = true
81
+ required-version = ">=0.8.0"
82
+
83
+ [tool.uv.workspace]
84
+ members = ["."]
85
+
86
+ [tool.uv.sources]
87
+ debug-dojo = { workspace = true }
@@ -42,7 +42,20 @@ def __execute_with_debug( # noqa: C901
42
42
  verbose: bool,
43
43
  config: DebugDojoConfig,
44
44
  ) -> None:
45
- """Execute a target script or module with installed debugging tools."""
45
+ """Execute a target script or module with installed debugging tools.
46
+
47
+ Args:
48
+ target_name (str): The name of the script, module, or executable to run.
49
+ target_args (list[str]): Arguments to pass to the target.
50
+ target_mode (ExecMode): The execution mode (FILE, MODULE, or EXECUTABLE).
51
+ verbose (bool): If True, print verbose output.
52
+ config (DebugDojoConfig): The debug-dojo configuration.
53
+
54
+ Raises:
55
+ typer.Exit: If the target file is not found, or if an import error occurs,
56
+ or if the script exits with a non-zero code.
57
+
58
+ """
46
59
  sys.argv = [target_name, *target_args]
47
60
 
48
61
  if verbose:
@@ -87,12 +100,6 @@ def __execute_with_debug( # noqa: C901
87
100
  raise typer.Exit(1) from e
88
101
 
89
102
 
90
- def display_config(config: DebugDojoConfig) -> None:
91
- """Display the configuration for the debug dojo."""
92
- rich_print("[blue]Using debug-dojo configuration:[/blue]")
93
- rich_print(config.model_dump_json(indent=4))
94
-
95
-
96
103
  @cli.command(
97
104
  help="Run a Python script or module with debugging tools installed.",
98
105
  no_args_is_help=True,
@@ -124,7 +131,33 @@ def run_debug( # noqa: PLR0913
124
131
  typer.Option("--exec", "-e", help="Run a command"),
125
132
  ] = False,
126
133
  ) -> None:
127
- """Run the command-line interface."""
134
+ """Run a Python script, module, or executable with debug-dojo tools.
135
+
136
+ This command acts as the main entry point for `debug-dojo`, allowing users to
137
+ execute their code while automatically installing and configuring debugging tools
138
+ based on the provided options or configuration file.
139
+
140
+ Args:
141
+ ctx (typer.Context): The Typer context object.
142
+ target_name (str | None): The path to the script, name of the module, or
143
+ name of the executable to run. If not provided,
144
+ the command will exit.
145
+ config_path (Path | None): Path to a custom configuration file
146
+ (e.g., `dojo.toml`).
147
+ debugger (DebuggerType | None): Override the default debugger specified
148
+ in the config.
149
+ verbose (bool): Enable verbose output, showing loaded configuration
150
+ and installation steps.
151
+ module (bool): Treat `target_name` as a Python module to run
152
+ (e.g., `dojo -m my_package.my_module`).
153
+ executable (bool): Treat `target_name` as an executable command to run
154
+ (e.g., `dojo -e pytest`).
155
+
156
+ Raises:
157
+ typer.Exit: If `--module` and `--exec` are used together, or if the target
158
+ cannot be executed, or if an error occurs during execution.
159
+
160
+ """
128
161
  if module and executable:
129
162
  rich_print(
130
163
  "[red]Error: --module and --command options are mutually exclusive.[/red]"
@@ -142,7 +175,7 @@ def run_debug( # noqa: PLR0913
142
175
  config = load_config(config_path, verbose=verbose, debugger=debugger)
143
176
 
144
177
  if verbose:
145
- display_config(config)
178
+ rich_print(f"[blue]Using debug-dojo configuration: {config} [/blue]")
146
179
 
147
180
  if target_name:
148
181
  __execute_with_debug(
@@ -14,8 +14,16 @@ from rich.panel import Panel
14
14
  from rich.text import Text
15
15
 
16
16
 
17
- def _get_object_attributes(obj: object) -> list[str]:
18
- """Extract and format non-callable attributes of an object."""
17
+ def get_object_attributes(obj: object) -> list[str]:
18
+ """Extract and format non-callable attributes of an object.
19
+
20
+ Args:
21
+ obj (object): The object to extract attributes from.
22
+
23
+ Returns:
24
+ list[str]: A list of formatted strings, each representing an attribute.
25
+
26
+ """
19
27
  attributes: list[str] = []
20
28
  for attr_name in sorted(dir(obj)):
21
29
  # Safely get attribute, returning None if it doesn't exist
@@ -28,8 +36,16 @@ def _get_object_attributes(obj: object) -> list[str]:
28
36
  return attributes
29
37
 
30
38
 
31
- def _get_object_methods(obj: object) -> list[str]:
32
- """Extract and format public callable methods of an object."""
39
+ def get_object_methods(obj: object) -> list[str]:
40
+ """Extract and format public callable methods of an object.
41
+
42
+ Args:
43
+ obj (object): The object to extract methods from.
44
+
45
+ Returns:
46
+ list[str]: A list of method names.
47
+
48
+ """
33
49
  methods: list[str] = []
34
50
  for method_name in sorted(dir(obj)):
35
51
  # Safely get attribute, returning None if it doesn't exist
@@ -40,11 +56,18 @@ def _get_object_methods(obj: object) -> list[str]:
40
56
  return methods
41
57
 
42
58
 
43
- def _get_simplified_object_info(obj: object) -> list[Text]:
59
+ def get_simplified_object_info(obj: object) -> list[Text]:
44
60
  """Generate a simplified, Rich-formatted inspection output for an object.
45
61
 
46
62
  Handles basic Python types by displaying their value directly. For other objects, it
47
63
  lists their attributes and public methods.
64
+
65
+ Args:
66
+ obj (object): The object to generate info for.
67
+
68
+ Returns:
69
+ list[Text]: A list of Rich Text objects representing the object's information.
70
+
48
71
  """
49
72
  info_lines: list[Text] = []
50
73
  obj_type: str = type(obj).__name__
@@ -62,7 +85,7 @@ def _get_simplified_object_info(obj: object) -> list[Text]:
62
85
  return info_lines
63
86
 
64
87
  # For other objects, list attributes
65
- attributes = _get_object_attributes(obj)
88
+ attributes = get_object_attributes(obj)
66
89
  if attributes:
67
90
  info_lines.append(Text("Attributes:", style="bold"))
68
91
  info_lines.extend([Text(f" {attr}") for attr in attributes])
@@ -71,7 +94,7 @@ def _get_simplified_object_info(obj: object) -> list[Text]:
71
94
  info_lines.append(Text(""))
72
95
 
73
96
  # List methods
74
- methods = _get_object_methods(obj)
97
+ methods = get_object_methods(obj)
75
98
  if methods:
76
99
  info_lines.append(Text("Methods:", style="bold"))
77
100
  info_lines.extend([Text(f" {method}()") for method in methods])
@@ -88,11 +111,16 @@ def inspect_objects_side_by_side(
88
111
  """Display two Python objects side-by-side in the terminal using Rich.
89
112
 
90
113
  Showing their attributes and methods in a simplified, aligned format.
114
+
115
+ Args:
116
+ obj1 (object): The first object to display.
117
+ obj2 (object): The second object to display.
118
+
91
119
  """
92
120
  main_console: Console = Console()
93
121
 
94
- lines1: list[Text] = _get_simplified_object_info(obj1)
95
- lines2: list[Text] = _get_simplified_object_info(obj2)
122
+ lines1: list[Text] = get_simplified_object_info(obj1)
123
+ lines2: list[Text] = get_simplified_object_info(obj2)
96
124
 
97
125
  # Determine the maximum number of lines to ensure consistent height
98
126
  max_lines: int = max(len(lines1), len(lines2))
@@ -8,39 +8,53 @@ from __future__ import annotations
8
8
 
9
9
  from collections.abc import Mapping, Sequence
10
10
  from pathlib import Path
11
- from typing import Any, TypeAlias, cast
11
+ from typing import TypeAlias, cast
12
12
 
13
- from pydantic import ValidationError
13
+ from dacite import DaciteError, from_dict
14
14
  from rich import print as rich_print
15
15
  from tomlkit import parse
16
16
  from tomlkit.exceptions import TOMLKitError
17
17
  from typer import Exit
18
18
 
19
19
  from ._config_models import (
20
+ DACITE_CONFIG,
20
21
  DebugDojoConfig,
21
22
  DebugDojoConfigV1,
22
23
  DebugDojoConfigV2,
23
24
  DebuggerType,
24
25
  )
25
26
 
26
- JSON_ro: TypeAlias = (
27
- Mapping[str, "JSON_ro"] | Sequence["JSON_ro"] | str | int | float | bool | None
27
+ JSON: TypeAlias = (
28
+ Mapping[str, "JSON"] | Sequence["JSON"] | str | int | float | bool | None
28
29
  )
29
30
 
30
31
 
31
- def __filter_pydantic_error_msg(error: ValidationError) -> str:
32
- """Filter out specific lines from a Pydantic validation error."""
33
- return "\n".join(
34
- line
35
- for line in str(error).splitlines()
36
- if not line.startswith("For further information visit")
37
- )
32
+ def _validate_model(
33
+ model: type[DebugDojoConfigV1 | DebugDojoConfigV2],
34
+ raw_config: JSON,
35
+ ) -> DebugDojoConfigV1 | DebugDojoConfigV2:
36
+ if not isinstance(raw_config, dict):
37
+ msg = "Configuration must be a dictionary."
38
+ raise DaciteError(msg)
39
+ return from_dict(data_class=model, data=raw_config, config=DACITE_CONFIG)
38
40
 
39
41
 
40
- def __resolve_config_path(config_path: Path | None) -> Path | None:
42
+ def resolve_config_path(config_path: Path | None) -> Path | None:
41
43
  """Resolve the configuration path.
42
44
 
43
45
  Returning a default if none is provided.
46
+
47
+ Args:
48
+ config_path (Path | None): The explicit path to the configuration file, or None.
49
+
50
+ Returns:
51
+ Path | None: The resolved absolute path to the configuration file, or None if no
52
+ configuration file is found and no explicit path was given.
53
+
54
+ Raises:
55
+ FileNotFoundError: If an explicit `config_path` is provided but the file
56
+ does not exist.
57
+
44
58
  """
45
59
  if config_path:
46
60
  if not config_path.exists():
@@ -57,49 +71,66 @@ def __resolve_config_path(config_path: Path | None) -> Path | None:
57
71
  return None
58
72
 
59
73
 
60
- def __load_raw_config(config_path: Path) -> JSON_ro:
74
+ def load_raw_config(config_path: Path) -> JSON:
61
75
  """Load the Debug Dojo configuration from a file.
62
76
 
63
77
  Currently supports 'dojo.toml' or 'pyproject.toml'. If no path is provided, it
64
78
  checks the current directory for these files.
79
+
80
+ Args:
81
+ config_path (Path): The absolute path to the configuration file.
82
+
83
+ Returns:
84
+ JSON: The raw configuration data as a JSON-like dictionary.
85
+
86
+ Raises:
87
+ ValueError: If there is an error parsing the TOML file.
88
+
65
89
  """
66
90
  config_str = config_path.read_text(encoding="utf-8")
67
91
 
68
92
  try:
69
93
  config_data = parse(config_str).unwrap()
70
94
  except TOMLKitError as e:
71
- msg = f"Error parsing configuration file {config_path.resolve()}."
95
+ msg = f"Error parsing configuration file {config_path.resolve()}.."
72
96
  raise ValueError(msg) from e
73
97
 
98
+ if config_path.name != "pyproject.toml":
99
+ return config_data
100
+
74
101
  # If config is in [tool.debug_dojo] (pyproject.toml), extract it.
75
- if config_path.name == "pyproject.toml":
76
- try:
77
- dojo_config = cast(
78
- "dict[str, Any]", # pyright: ignore[reportExplicitAny]
79
- config_data["tool"]["debug_dojo"],
80
- )
81
- except KeyError:
82
- return {}
83
- else:
84
- return dojo_config
102
+ try:
103
+ dojo_config = cast("JSON", config_data["tool"]["debug_dojo"])
104
+ except KeyError:
105
+ return {}
106
+ else:
107
+ return dojo_config
85
108
 
86
- return config_data
87
109
 
110
+ def validated_and_updated_config(raw_config: JSON, *, verbose: bool) -> DebugDojoConfig:
111
+ """Validate and update the raw configuration to the latest DebugDojoConfig version.
88
112
 
89
- def __validated_and_updated_config(
90
- raw_config: JSON_ro, *, verbose: bool
91
- ) -> DebugDojoConfig:
92
- config = None
113
+ Args:
114
+ raw_config (JSON): The raw configuration data loaded from a file.
115
+ verbose (bool): If True, print verbose messages during validation and update.
116
+
117
+ Returns:
118
+ DebugDojoConfig: A validated and updated DebugDojoConfig instance.
119
+
120
+ Raises:
121
+ typer.Exit: If the configuration cannot be validated against any known version.
122
+
123
+ """
124
+ config: DebugDojoConfigV1 | DebugDojoConfigV2 | None = None
93
125
 
94
126
  for model in (DebugDojoConfigV2, DebugDojoConfigV1):
95
127
  model_name = model.__name__
96
128
  try:
97
- config = model.model_validate(raw_config)
98
- except ValidationError as e:
129
+ config = _validate_model(model, raw_config)
130
+ except (DaciteError, TypeError, ValueError) as e:
99
131
  if verbose:
100
132
  msg = (
101
- f"[yellow]Configuration validation error for {model_name}:\n"
102
- f"{__filter_pydantic_error_msg(e)}\n\n"
133
+ f"[yellow]Configuration validation error for {model_name}:\n{e}\n\n"
103
134
  )
104
135
  rich_print(msg)
105
136
  else:
@@ -134,8 +165,18 @@ def load_config(
134
165
 
135
166
  If no configuration file is found, it returns a default configuration. If a debugger
136
167
  is specified, it overrides the config.
168
+
169
+ Args:
170
+ config_path (Path | None): Optional path to a configuration file.
171
+ verbose (bool): If True, print verbose messages during configuration loading.
172
+ debugger (DebuggerType | None): Optional debugger type to override the default
173
+ debugger specified in the configuration.
174
+
175
+ Returns:
176
+ DebugDojoConfig: The loaded and potentially overridden DebugDojoConfig instance.
177
+
137
178
  """
138
- resolved_path = __resolve_config_path(config_path)
179
+ resolved_path = resolve_config_path(config_path)
139
180
 
140
181
  if verbose:
141
182
  if resolved_path:
@@ -147,8 +188,8 @@ def load_config(
147
188
  if not resolved_path:
148
189
  return DebugDojoConfig()
149
190
 
150
- raw_config = __load_raw_config(resolved_path)
151
- config = __validated_and_updated_config(raw_config, verbose=verbose)
191
+ raw_config = load_raw_config(resolved_path)
192
+ config = validated_and_updated_config(raw_config, verbose=verbose)
152
193
 
153
194
  # If a debugger is specified, override the config.
154
195
  if debugger: