debug-dojo 0.1.0__py3-none-any.whl

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.
debug_dojo/__init__.py ADDED
@@ -0,0 +1,20 @@
1
+ """Debugging tools for Python.
2
+
3
+ This module provides functions to set up debugging tools like PuDB and Rich Traceback.
4
+ It checks for the availability of these tools and configures them accordingly.
5
+ """
6
+
7
+ from .installers import install_inspect, use_pudb, use_rich_traceback
8
+
9
+ ii = install_inspect
10
+ pudb = use_pudb
11
+ rt = use_rich_traceback
12
+
13
+ __all__ = [
14
+ "ii",
15
+ "install_inspect",
16
+ "pudb",
17
+ "rt",
18
+ "use_pudb",
19
+ "use_rich_traceback",
20
+ ]
debug_dojo/all.py ADDED
@@ -0,0 +1,22 @@
1
+ """Install all debugging tools for the debug_dojo package."""
2
+
3
+ from .installers import (
4
+ install_breakpoint,
5
+ install_compare,
6
+ install_inspect,
7
+ use_pudb,
8
+ use_rich_traceback,
9
+ )
10
+
11
+
12
+ def install_all() -> None:
13
+ """Install debugging tools."""
14
+ use_pudb()
15
+ use_rich_traceback()
16
+
17
+ install_inspect()
18
+ install_compare()
19
+ install_breakpoint()
20
+
21
+
22
+ install_all()
@@ -0,0 +1,134 @@
1
+ """Utilities for side-by-side inspection and comparison of Python objects using Rich.
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.
5
+ """
6
+
7
+ import contextlib
8
+
9
+ from rich.columns import Columns
10
+ from rich.console import Console
11
+ from rich.panel import Panel
12
+ from rich.text import Text
13
+
14
+
15
+ def _get_object_attributes(obj: object) -> list[str]:
16
+ """Extract and format non-callable attributes of an object.
17
+
18
+ Args:
19
+ obj: The object to inspect.
20
+
21
+ Returns:
22
+ A list of strings, each representing an attribute in 'name=value' format.
23
+
24
+ """
25
+ attributes: list[str] = []
26
+ for attr_name in sorted(dir(obj)):
27
+ # Safely get attribute, returning None if it doesn't exist
28
+ attr = getattr(obj, attr_name, None)
29
+ # Exclude dunder methods and callable attributes
30
+ if not attr_name.startswith("__") and not callable(attr):
31
+ with contextlib.suppress(AttributeError):
32
+ # Use !r for robust string representation of the attribute value
33
+ attributes.append(f"{attr_name}={attr!r}")
34
+ return attributes
35
+
36
+
37
+ def _get_object_methods(obj: object) -> list[str]:
38
+ """Extract and format public callable methods of an object.
39
+
40
+ Args:
41
+ obj: The object to inspect.
42
+
43
+ Returns:
44
+ A list of strings, each representing a method name.
45
+
46
+ """
47
+ methods: list[str] = []
48
+ for method_name in sorted(dir(obj)):
49
+ # Safely get attribute, returning None if it doesn't exist
50
+ attr = getattr(obj, method_name, None)
51
+ # Exclude private/protected methods (starting with '_') and non-callable attributes
52
+ if not method_name.startswith("_") and callable(attr):
53
+ methods.append(method_name)
54
+ return methods
55
+
56
+
57
+ def _get_simplified_object_info(obj: object) -> list[Text]:
58
+ """Generate a simplified, Rich-formatted inspection output for an object.
59
+
60
+ Handles basic Python types by displaying their value directly. For other
61
+ objects, it lists their attributes and public methods.
62
+
63
+ Args:
64
+ obj: The object to generate info for.
65
+
66
+ Returns:
67
+ A list of Rich Text objects, each representing a line of information.
68
+
69
+ """
70
+ info_lines: list[Text] = []
71
+ obj_type: str = type(obj).__name__
72
+ info_lines.append(Text(f"<class '{obj_type}'>", style="cyan bold"))
73
+ info_lines.append(Text(""))
74
+
75
+ # Handle basic data types by displaying their value directly
76
+ if isinstance(obj, (str, int, float, list, dict, tuple, set, bool)) or obj is None:
77
+ info_lines.append(Text("Value:", style="bold"))
78
+ info_lines.append(Text(f" {obj!r}", style="yellow"))
79
+ info_lines.append(Text(""))
80
+ info_lines.append(
81
+ Text("No attributes or methods to display for this type.", style="dim")
82
+ )
83
+ return info_lines
84
+
85
+ # For other objects, list attributes
86
+ attributes = _get_object_attributes(obj)
87
+ if attributes:
88
+ info_lines.append(Text("Attributes:", style="bold"))
89
+ info_lines.extend([Text(f" {attr}") for attr in attributes])
90
+ else:
91
+ info_lines.append(Text("No attributes found.", style="dim"))
92
+ info_lines.append(Text(""))
93
+
94
+ # List methods
95
+ methods = _get_object_methods(obj)
96
+ if methods:
97
+ info_lines.append(Text("Methods:", style="bold"))
98
+ info_lines.extend([Text(f" {method}()") for method in methods])
99
+ else:
100
+ info_lines.append(Text("No public methods found.", style="dim"))
101
+
102
+ return info_lines
103
+
104
+
105
+ def inspect_objects_side_by_side(
106
+ obj1: object,
107
+ obj2: object,
108
+ ) -> None:
109
+ """Display two Python objects side-by-side in the terminal using Rich.
110
+
111
+ Showing their attributes and methods in a simplified, aligned format.
112
+ """
113
+ main_console: Console = Console()
114
+
115
+ lines1: list[Text] = _get_simplified_object_info(obj1)
116
+ lines2: list[Text] = _get_simplified_object_info(obj2)
117
+
118
+ # Determine the maximum number of lines to ensure consistent height
119
+ max_lines: int = max(len(lines1), len(lines2))
120
+
121
+ # Pad the shorter list of lines with empty Text objects to match the height
122
+ if len(lines1) < max_lines:
123
+ lines1.extend([Text("")] * (max_lines - len(lines1)))
124
+ if len(lines2) < max_lines:
125
+ lines2.extend([Text("")] * (max_lines - len(lines2)))
126
+
127
+ # Join the padded lines into a single Text object for the Panel content
128
+ padded_inspect_text1: Text = Text("\n").join(lines1)
129
+ padded_inspect_text2: Text = Text("\n").join(lines2)
130
+
131
+ panel1: Panel = Panel(padded_inspect_text1, border_style="green", expand=True)
132
+ panel2: Panel = Panel(padded_inspect_text2, border_style="green", expand=True)
133
+
134
+ main_console.print(Columns([panel1, panel2]))
@@ -0,0 +1,62 @@
1
+ """Debugging tools for Python.
2
+
3
+ This module provides functions to set up debugging tools like PuDB and Rich Traceback.
4
+ It checks for the availability of these tools and configures them accordingly.
5
+ """
6
+
7
+ import builtins
8
+ import os
9
+ import sys
10
+
11
+ import pudb # pyright: ignore[reportMissingTypeStubs]
12
+ from rich import (
13
+ inspect,
14
+ traceback,
15
+ )
16
+
17
+ from .compareres import inspect_objects_side_by_side
18
+
19
+ BREAKPOINT_ENV_VAR = "PYTHONBREAKPOINT"
20
+ PUDB_SET_TRACE = "pudb.set_trace"
21
+
22
+
23
+ def use_pudb() -> None:
24
+ """Check if PuDB is available and set it as the default debugger."""
25
+ # Set the environment variable. This will primarily affect child processes or later
26
+ # Python startup if the script is re-run.
27
+ os.environ[BREAKPOINT_ENV_VAR] = PUDB_SET_TRACE
28
+
29
+ # Crucially, to make `breakpoint()` work *immediately* in the current process,
30
+ # we need to explicitly set `sys.breakpointhook`.
31
+ sys.breakpointhook = pudb.set_trace
32
+
33
+
34
+ def use_rich_traceback() -> None:
35
+ """Check if Rich Traceback is available and set it as the default."""
36
+ # Install rich traceback to enhance the debugging experience
37
+ _ = traceback.install(show_locals=True)
38
+
39
+
40
+ def install_inspect() -> None:
41
+ """Print the object using a custom inspect function."""
42
+
43
+ def inspect_with_defaults(obj: object, **kwargs: object) -> None:
44
+ """Inspect an object using Rich's inspect function."""
45
+ if not kwargs:
46
+ kwargs = {"methods": True, "private": True}
47
+ return inspect(obj, **kwargs) # pyright: ignore[reportArgumentType]
48
+
49
+ # Inject the custom inspect function into builtins
50
+ builtins.i = inspect_with_defaults # pyright: ignore[reportAttributeAccessIssue]
51
+
52
+
53
+ def install_compare() -> None:
54
+ """Print the object using a custom inspect function."""
55
+ # Inject the custom side-by-side comparison function into builtins
56
+ builtins.c = inspect_objects_side_by_side # pyright: ignore[reportAttributeAccessIssue]
57
+
58
+
59
+ def install_breakpoint() -> None:
60
+ """Install the breakpoint function."""
61
+ # Set the breakpoint function to use PuDB's set_trace
62
+ builtins.b = pudb.set_trace # pyright: ignore[reportAttributeAccessIssue]
debug_dojo/py.typed ADDED
File without changes
@@ -0,0 +1,87 @@
1
+ Metadata-Version: 2.3
2
+ Name: debug-dojo
3
+ Version: 0.1.0
4
+ Summary: Debbugging dojo for Python developers
5
+ Author: bwrob
6
+ Author-email: bwrob <bartosz.marcin.wroblewski@gmail.com>
7
+ Requires-Dist: pudb>=2016.1
8
+ Requires-Dist: rich>=11.0.0
9
+ Requires-Python: >=3.10
10
+ Description-Content-Type: text/markdown
11
+
12
+ # debug-dojo
13
+
14
+ **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 PuDB. All tools can be installed at once or individually, allowing for flexible debugging setups.
15
+
16
+ ## Features
17
+
18
+ - **Simple API:** Install all tools or only what you need.
19
+ - **PuDB integration:** Quickly enable the PuDB TUI debugger.
20
+ - **Rich tracebacks:** Get readable, colorized tracebacks for easier debugging.
21
+ - **Side-by-side object inspection:** Visually compare Python objects, their attributes, and methods in the terminal.
22
+
23
+ ## Installation
24
+
25
+ ```sh
26
+ pip install debug-dojo
27
+ ```
28
+
29
+ ## Usage
30
+
31
+ ### Install all debugging tools
32
+
33
+ In the `PuDB` style, you can install all debugging tools and enter the debugging mode with a single command:
34
+
35
+ ```python
36
+ import debug_dojo.all; b()
37
+ ```
38
+
39
+ Where`b()` is a builtin-injected function that sets a breakpoint using PuDB's `set_trace()`.
40
+ In the PuDB interface, you can use the following functions:
41
+
42
+ - `i(object_1)` to inspect an object.
43
+ - `c(object_1, object_2)` to compare two objects side-by-side.
44
+
45
+
46
+ ### Use individual tools
47
+
48
+ ```python
49
+ from debug_dojo import install_inspect, use_pudb, use_rich_traceback
50
+
51
+ install_inspect() # Enable object inspection helpers
52
+ use_pudb() # Set up PuDB as the debugger
53
+ use_rich_traceback() # Enable Rich tracebacks
54
+ ```
55
+
56
+ ### Compare objects side-by-side
57
+
58
+ ```python
59
+ from debug_dojo.compareres import inspect_objects_side_by_side
60
+
61
+ a = {"foo": 1, "bar": 2}
62
+ b = [1, 2, 3]
63
+ inspect_objects_side_by_side(a, b)
64
+ ```
65
+
66
+ ## Development
67
+
68
+ ### Run tests
69
+
70
+ ```sh
71
+ pytest
72
+ ```
73
+
74
+ ### Lint and type check
75
+
76
+ ```sh
77
+ ruff check src/debug_dojo --fix
78
+ basedpyright src/debug_dojo
79
+ ```
80
+
81
+ ## License
82
+
83
+ MIT License
84
+
85
+ ---
86
+
87
+ *Debugging made delightful!*
@@ -0,0 +1,9 @@
1
+ debug_dojo/__init__.py,sha256=9d228c661b70e9f6c1859682cccf3ba7d2326dc7e5c944c680fd23408847aaf9,447
2
+ debug_dojo/all.py,sha256=3f29baf80236d01b49bf4aae859e34deb3ac0daee68a1abf81681ebf941c6111,385
3
+ debug_dojo/compareres.py,sha256=717d3e7676be4fbf1918b3e30c0e99544e891f9e0c3f1ebd0dea1bdebdfda6e7,4737
4
+ debug_dojo/installers.py,sha256=eaede2a3642d08a4d5ff2c30e1fef1ee5e1e14a930ed3a8269bea697e28dcd8d,2154
5
+ debug_dojo/py.typed,sha256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855,0
6
+ debug_dojo-0.1.0.dist-info/WHEEL,sha256=d10358abd5c217094bd40da9e447bd3c8979f6f95a2ce6e2da850cf9abfe7943,78
7
+ debug_dojo-0.1.0.dist-info/entry_points.txt,sha256=0e5c9888d0d9f8636622b36825f2ebe129eaf706916c356787b2930c6efbcf1e,48
8
+ debug_dojo-0.1.0.dist-info/METADATA,sha256=d879fe6d7672ded19a00635e7829237379f2d46b4c44c1940ab8e649ff1023e5,2215
9
+ debug_dojo-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: uv 0.8.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ debug-dojo = debug_dojo:main
3
+