imgui_debugger 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.
@@ -0,0 +1,130 @@
1
+ """One-line renderings of arbitrary Python values for the tree's right column.
2
+
3
+ Examples
4
+ --------
5
+ >>> from imgui_debugger.format import fmt_value, type_label
6
+ >>> fmt_value(3.5)
7
+ '3.5'
8
+ >>> type_label([1, 2, 3])
9
+ 'list[3]'
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ from collections.abc import Mapping, Sequence
15
+
16
+ MAX_STR = 256
17
+ MAX_INLINE = 8
18
+
19
+
20
+ def is_container(value) -> bool:
21
+ """True when a value is a mapping or a non-string sequence.
22
+
23
+ Examples
24
+ --------
25
+ >>> from imgui_debugger.format import is_container
26
+ >>> is_container({"a": 1}), is_container("abc"), is_container([1])
27
+ (True, False, True)
28
+ """
29
+ if isinstance(value, Mapping):
30
+ return True
31
+ return isinstance(value, Sequence) and not isinstance(value, (str, bytes, bytearray))
32
+
33
+
34
+ def type_label(value) -> str:
35
+ """The type name, with a length or shape suffix when the value has one.
36
+
37
+ Examples
38
+ --------
39
+ >>> from imgui_debugger.format import type_label
40
+ >>> type_label({"a": 1})
41
+ 'dict[1]'
42
+ >>> type_label(2.0)
43
+ 'float'
44
+ """
45
+ name = type(value).__name__
46
+ shape = getattr(value, "shape", None)
47
+ if shape is not None and not callable(shape):
48
+ try:
49
+ return f"{name}{tuple(shape)}"
50
+ except TypeError:
51
+ return name
52
+ if is_container(value):
53
+ try:
54
+ return f"{name}[{len(value)}]"
55
+ except TypeError:
56
+ return name
57
+ return name
58
+
59
+
60
+ def fmt_value(value, max_str: int = MAX_STR) -> str:
61
+ """Format a value as one short line, never raising on a hostile ``__repr__``.
62
+
63
+ Parameters
64
+ ----------
65
+ value : object
66
+ Anything.
67
+ max_str : int
68
+ Longest string rendered verbatim before truncation.
69
+
70
+ Examples
71
+ --------
72
+ >>> from imgui_debugger.format import fmt_value
73
+ >>> fmt_value(None), fmt_value(True), fmt_value(b"ab")
74
+ ('None', 'True', '<2 bytes>')
75
+ >>> fmt_value([1, 2, 3])
76
+ '[1, 2, 3]'
77
+ """
78
+ if value is None or isinstance(value, bool):
79
+ return repr(value)
80
+ if isinstance(value, str):
81
+ return repr(value if len(value) <= max_str else value[: max_str - 3] + "...")
82
+ if isinstance(value, (int, float, complex)):
83
+ return repr(value)
84
+ if isinstance(value, (bytes, bytearray)):
85
+ return f"<{len(value)} bytes>"
86
+ if hasattr(value, "shape") and hasattr(value, "dtype"):
87
+ return _fmt_array(value)
88
+ if isinstance(value, (tuple, list, set, frozenset)):
89
+ try:
90
+ if len(value) <= MAX_INLINE and all(
91
+ isinstance(v, (int, float, bool, str, type(None))) for v in value
92
+ ):
93
+ return repr(value)
94
+ return f"<{type_label(value)}>"
95
+ except TypeError:
96
+ return f"<{type(value).__name__}>"
97
+ if isinstance(value, Mapping):
98
+ return f"<{type_label(value)}>"
99
+ if callable(value):
100
+ return f"<{type(value).__name__} {getattr(value, '__name__', '')}>".replace(" >", ">")
101
+ return f"<{type(value).__name__}>"
102
+
103
+
104
+ def _fmt_array(value) -> str:
105
+ """Summarize a numpy-like array, inlining only tiny scalar-dtype ones.
106
+
107
+ Examples
108
+ --------
109
+ >>> import numpy as np # doctest: +SKIP
110
+ >>> _fmt_array(np.zeros((4, 4))) # doctest: +SKIP
111
+ '<shape=(4, 4), dtype=float64>'
112
+ """
113
+ try:
114
+ if value.size <= MAX_INLINE and getattr(value.dtype, "kind", "") in "biufcSU":
115
+ return repr(value.tolist())
116
+ return f"<shape={tuple(value.shape)}, dtype={value.dtype}>"
117
+ except Exception:
118
+ return f"<{type(value).__name__}>"
119
+
120
+
121
+ def fmt_error(exc: BaseException) -> str:
122
+ """Format an exception raised while reading a value.
123
+
124
+ Examples
125
+ --------
126
+ >>> from imgui_debugger.format import fmt_error
127
+ >>> fmt_error(ValueError("bad shape"))
128
+ '<ValueError: bad shape>'
129
+ """
130
+ return f"<{type(exc).__name__}: {exc}>"
File without changes
@@ -0,0 +1,91 @@
1
+ """One-shot harness: open the debugger in its own window and block until closed.
2
+
3
+ Examples
4
+ --------
5
+ >>> from imgui_debugger import run_debugger
6
+ >>> run_debugger({"fs": 9.6, "dz": 5.0}) # doctest: +SKIP
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import os
12
+ from typing import Optional
13
+
14
+ from ._assets import default_ini_path, ensure_assets
15
+ from .debugger import Debugger, DebuggerConfig
16
+ from .theme import to_vec4
17
+
18
+
19
+ def run_debugger(
20
+ target=None,
21
+ config: Optional[DebuggerConfig] = None,
22
+ runner_params=None,
23
+ **kwargs,
24
+ ) -> Debugger:
25
+ """Show the debugger in its own OS window, blocking until it is closed.
26
+
27
+ Parameters
28
+ ----------
29
+ target : object | None
30
+ The object to inspect.
31
+ config : DebuggerConfig | None
32
+ A prebuilt config; ``target`` and ``kwargs`` override its fields.
33
+ runner_params : hello_imgui.RunnerParams | None
34
+ Supply your own params, e.g. a null backend for headless tests. Window
35
+ title, size and ``.ini`` are filled in from the config only when unset.
36
+ **kwargs
37
+ Any :class:`~imgui_debugger.DebuggerConfig` field.
38
+
39
+ Returns
40
+ -------
41
+ Debugger
42
+ The widget that was rendered, so its final state can be read back.
43
+
44
+ Examples
45
+ --------
46
+ >>> from imgui_debugger import run_debugger
47
+ >>> class Settings:
48
+ ... def __init__(self):
49
+ ... self.threshold = 0.4
50
+ >>> run_debugger(Settings(), title="Settings") # doctest: +SKIP
51
+ >>> run_debugger({"a": 1}, private=True, editable=False) # doctest: +SKIP
52
+ """
53
+ from imgui_bundle import hello_imgui, immapp
54
+
55
+ cfg = config or DebuggerConfig()
56
+ if target is not None:
57
+ cfg.target = target
58
+ for key, value in kwargs.items():
59
+ if not hasattr(cfg, key):
60
+ raise TypeError(f"DebuggerConfig has no field {key!r}")
61
+ setattr(cfg, key, value)
62
+
63
+ ensure_assets(cfg.assets_folder)
64
+ dbg = Debugger(cfg, frame_depth=2)
65
+
66
+ params = runner_params if runner_params is not None else hello_imgui.RunnerParams()
67
+ params.app_window_params.window_title = cfg.window_title or cfg.title or "Debugger"
68
+ if cfg.window_size:
69
+ params.app_window_params.window_geometry.size = tuple(cfg.window_size)
70
+ params.app_window_params.window_geometry.size_auto = False
71
+ params.app_window_params.resizable = cfg.resizable
72
+ # hello_imgui resolves ini_filename against the cwd by default, which drops
73
+ # a layout file wherever the app was launched; pin it to an absolute path.
74
+ if not params.ini_filename:
75
+ ini = cfg.ini_path or default_ini_path()
76
+ params.ini_filename = ini
77
+ if os.path.isabs(ini):
78
+ params.ini_folder_type = hello_imgui.IniFolderType.absolute_path
79
+ parent = os.path.dirname(ini)
80
+ if parent:
81
+ os.makedirs(parent, exist_ok=True)
82
+ bg = to_vec4(cfg.theme.bg)
83
+ params.imgui_window_params.background_color = bg
84
+ params.callbacks.show_gui = dbg.render
85
+
86
+ addons = immapp.AddOnsParams()
87
+ addons.with_markdown = False
88
+ addons.with_implot = False
89
+ addons.with_implot3d = False
90
+ immapp.run(runner_params=params, add_ons_params=addons)
91
+ return dbg