varview 0.1.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.
- varview-0.1.0/.ipynb_checkpoints/Readme-checkpoint.md +144 -0
- varview-0.1.0/.ipynb_checkpoints/pyproject-checkpoint.toml +27 -0
- varview-0.1.0/.ipynb_checkpoints/setup-checkpoint.py +30 -0
- varview-0.1.0/PKG-INFO +164 -0
- varview-0.1.0/README.md +144 -0
- varview-0.1.0/Readme.md +144 -0
- varview-0.1.0/pyproject.toml +27 -0
- varview-0.1.0/setup.py +30 -0
- varview-0.1.0/varview/.ipynb_checkpoints/__init__-checkpoint.py +192 -0
- varview-0.1.0/varview/__init__.py +192 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# varview
|
|
2
|
+
|
|
3
|
+
A tiny, zero-dependency debug-printing helper for people who check their work, for clean automation.
|
|
4
|
+
|
|
5
|
+
```python
|
|
6
|
+
from varview import debug
|
|
7
|
+
|
|
8
|
+
count = 42
|
|
9
|
+
total = 137
|
|
10
|
+
status = "active"
|
|
11
|
+
|
|
12
|
+
debug(["count", "total", "status"])
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
count: 42
|
|
17
|
+
|
|
18
|
+
total: 137
|
|
19
|
+
|
|
20
|
+
status: active
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Why this exists
|
|
24
|
+
|
|
25
|
+
Most debugging habits start the same way: `print(f"count: {count}")`,
|
|
26
|
+
scattered through a script, forgotten about, and left in, or worse,
|
|
27
|
+
silently shaping a result nobody meant to ship.
|
|
28
|
+
|
|
29
|
+
`varview` was built out of a data analyst's day-to-day discipline: **if
|
|
30
|
+
you can't see your intermediate values clearly, you can't trust your
|
|
31
|
+
final ones.** Threshold sweeps, fold splits, feature combos, backtest
|
|
32
|
+
tables: every step that touches a metric is a step where leakage,
|
|
33
|
+
silent type coercion, or an off-by-one slice can quietly corrupt a
|
|
34
|
+
result. The habit that catches this isn't a debugger or a notebook
|
|
35
|
+
full of stray `print()` calls, it's making every checkpoint visible,
|
|
36
|
+
on purpose, every time, with a single flip to turn it all off before
|
|
37
|
+
anything ships.
|
|
38
|
+
|
|
39
|
+
That's the whole philosophy behind this package:
|
|
40
|
+
|
|
41
|
+
- **See it before you trust it.** Print the name *and* the value,
|
|
42
|
+
side by side, with no risk of the label drifting out of sync with
|
|
43
|
+
what it's labeling.
|
|
44
|
+
- **Validate loudly, not quietly.** Every parameter is checked up
|
|
45
|
+
front; bad input fails fast with a clear error instead of
|
|
46
|
+
producing a confusing result three functions later.
|
|
47
|
+
- **Make leakage a choice, not an accident.** One global switch
|
|
48
|
+
silences every debug call in a file at once, so nothing you used to
|
|
49
|
+
sanity-check a fold split or a train/test boundary can slip into
|
|
50
|
+
a shared notebook or a production run by accident.
|
|
51
|
+
|
|
52
|
+
## Install
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pip install varview
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Usage
|
|
59
|
+
|
|
60
|
+
### Basic
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
from varview import debug
|
|
64
|
+
|
|
65
|
+
count = 42
|
|
66
|
+
debug(["count"]) # list of names
|
|
67
|
+
debug("count") # a single string also works, no need to wrap it
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Color-code by what the value means to you
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
debug(["count"], color="green") # default, all good
|
|
74
|
+
debug(["count"], color="yellow") # worth a second look
|
|
75
|
+
debug(["count"], color="red") # flag it
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Lay it out the way you're scanning
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
debug(["count", "total", "status"]) # vertical (default)
|
|
82
|
+
debug(["count", "total", "status"], orientation="horizontal") # count: 42, total: 137, status: active
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Turn one call off without deleting it
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
debug(["count"], display=False)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Turn every call off at once, before you share or ship
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
from varview import debug_off, debug_on
|
|
95
|
+
|
|
96
|
+
debug_off() # every debug() call in the process goes silent, even display=True ones
|
|
97
|
+
# ... run the rest of your pipeline, notebook export, whatever needs to be clean ...
|
|
98
|
+
debug_on() # back to normal for your next debugging session
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
`debug_off()` is the one-line answer to "did I leave a debug print
|
|
102
|
+
in this notebook before I sent it to someone." Flip it at the top of
|
|
103
|
+
a cell, or right before a scheduled job runs, and every `debug()`
|
|
104
|
+
call downstream goes quiet, no hunting through the file for calls
|
|
105
|
+
you forgot about.
|
|
106
|
+
|
|
107
|
+
### Typos don't kill the whole block
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
debug(["count", "totall", "status"])
|
|
111
|
+
# count: 42
|
|
112
|
+
# totall: <not found>
|
|
113
|
+
# status: active
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
One bad name prints `<not found>` in place instead of raising and
|
|
117
|
+
losing every other value you wanted to see.
|
|
118
|
+
|
|
119
|
+
## API
|
|
120
|
+
|
|
121
|
+
### `debug(names, color="green", display=True, orientation="vertical")`
|
|
122
|
+
|
|
123
|
+
| Param | Type | Default | Notes |
|
|
124
|
+
|---|---|---|---|
|
|
125
|
+
| `names` | `str` or `list`/`tuple` of `str` | (required) | Variable names to look up in the *caller's* local scope |
|
|
126
|
+
| `color` | `"green"`, `"red"`, `"yellow"` | `"green"` | Label color only; values always print in black |
|
|
127
|
+
| `display` | `bool` | `True` | Silences this one call when `False` |
|
|
128
|
+
| `orientation` | `"vertical"`, `"horizontal"` | `"vertical"` | Layout of the printed pairs |
|
|
129
|
+
|
|
130
|
+
All four parameters are validated on every call: an invalid `color`
|
|
131
|
+
or `orientation` raises `ValueError`, an invalid `display` type raises
|
|
132
|
+
`TypeError`, and `names` must be a string or a list/tuple of strings
|
|
133
|
+
or it raises `TypeError`. Nothing gets a chance to fail silently or
|
|
134
|
+
print something misleading.
|
|
135
|
+
|
|
136
|
+
### `debug_off()` / `debug_on()`
|
|
137
|
+
|
|
138
|
+
Module-level switch. `debug_off()` silences every `debug()` call in
|
|
139
|
+
the running process, regardless of that call's own `display` value.
|
|
140
|
+
`debug_on()` restores normal behavior.
|
|
141
|
+
|
|
142
|
+
## License
|
|
143
|
+
|
|
144
|
+
MIT
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "varview"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "A tiny debug-printing helper that prints name: value pairs from the caller's scope, with a one-line kill switch to prevent leaked debug output."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.7"
|
|
11
|
+
authors = [
|
|
12
|
+
{ name = "Henry", email = "osas2henry@gmail.com" }
|
|
13
|
+
]
|
|
14
|
+
keywords = ["debug", "debugging", "print", "variables", "logging", "data-validation"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 4 - Beta",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Programming Language :: Python :: 3.7",
|
|
20
|
+
"Programming Language :: Python :: 3.8",
|
|
21
|
+
"Programming Language :: Python :: 3.9",
|
|
22
|
+
"Programming Language :: Python :: 3.10",
|
|
23
|
+
"Programming Language :: Python :: 3.11",
|
|
24
|
+
"Programming Language :: Python :: 3.12",
|
|
25
|
+
"Topic :: Software Development :: Debuggers",
|
|
26
|
+
"Topic :: Utilities",
|
|
27
|
+
]
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
with open("README.md", "r", encoding="utf-8") as f:
|
|
4
|
+
long_description = f.read()
|
|
5
|
+
|
|
6
|
+
setup(
|
|
7
|
+
name="varview",
|
|
8
|
+
version="0.1.0",
|
|
9
|
+
description="A tiny debug-printing helper that prints name: value pairs from the caller's scope, with a one-line kill switch to prevent leaked debug output.",
|
|
10
|
+
long_description=long_description,
|
|
11
|
+
long_description_content_type="text/markdown",
|
|
12
|
+
author="Henry",
|
|
13
|
+
author_email="osas2henry@gmail.com",
|
|
14
|
+
packages=find_packages(),
|
|
15
|
+
keywords=["debug", "debugging", "print", "variables", "logging", "data-validation"],
|
|
16
|
+
classifiers=[
|
|
17
|
+
"Development Status :: 4 - Beta",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"Programming Language :: Python :: 3.7",
|
|
21
|
+
"Programming Language :: Python :: 3.8",
|
|
22
|
+
"Programming Language :: Python :: 3.9",
|
|
23
|
+
"Programming Language :: Python :: 3.10",
|
|
24
|
+
"Programming Language :: Python :: 3.11",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
"Topic :: Software Development :: Debuggers",
|
|
27
|
+
"Topic :: Utilities",
|
|
28
|
+
],
|
|
29
|
+
python_requires=">=3.7",
|
|
30
|
+
)
|
varview-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: varview
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A tiny debug-printing helper that prints name: value pairs from the caller's scope, with a one-line kill switch to prevent leaked debug output.
|
|
5
|
+
Author-email: Henry <osas2henry@gmail.com>
|
|
6
|
+
Keywords: data-validation,debug,debugging,logging,print,variables
|
|
7
|
+
Classifier: Development Status :: 4 - Beta
|
|
8
|
+
Classifier: Intended Audience :: Developers
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Topic :: Software Development :: Debuggers
|
|
17
|
+
Classifier: Topic :: Utilities
|
|
18
|
+
Requires-Python: >=3.7
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# varview
|
|
22
|
+
|
|
23
|
+
A tiny, zero-dependency debug-printing helper for people who check their work, for clean automation.
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
from varview import debug
|
|
27
|
+
|
|
28
|
+
count = 42
|
|
29
|
+
total = 137
|
|
30
|
+
status = "active"
|
|
31
|
+
|
|
32
|
+
debug(["count", "total", "status"])
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
count: 42
|
|
37
|
+
|
|
38
|
+
total: 137
|
|
39
|
+
|
|
40
|
+
status: active
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Why this exists
|
|
44
|
+
|
|
45
|
+
Most debugging habits start the same way: `print(f"count: {count}")`,
|
|
46
|
+
scattered through a script, forgotten about, and left in, or worse,
|
|
47
|
+
silently shaping a result nobody meant to ship.
|
|
48
|
+
|
|
49
|
+
`varview` was built out of a data analyst's day-to-day discipline: **if
|
|
50
|
+
you can't see your intermediate values clearly, you can't trust your
|
|
51
|
+
final ones.** Threshold sweeps, fold splits, feature combos, backtest
|
|
52
|
+
tables: every step that touches a metric is a step where leakage,
|
|
53
|
+
silent type coercion, or an off-by-one slice can quietly corrupt a
|
|
54
|
+
result. The habit that catches this isn't a debugger or a notebook
|
|
55
|
+
full of stray `print()` calls, it's making every checkpoint visible,
|
|
56
|
+
on purpose, every time, with a single flip to turn it all off before
|
|
57
|
+
anything ships.
|
|
58
|
+
|
|
59
|
+
That's the whole philosophy behind this package:
|
|
60
|
+
|
|
61
|
+
- **See it before you trust it.** Print the name *and* the value,
|
|
62
|
+
side by side, with no risk of the label drifting out of sync with
|
|
63
|
+
what it's labeling.
|
|
64
|
+
- **Validate loudly, not quietly.** Every parameter is checked up
|
|
65
|
+
front; bad input fails fast with a clear error instead of
|
|
66
|
+
producing a confusing result three functions later.
|
|
67
|
+
- **Make leakage a choice, not an accident.** One global switch
|
|
68
|
+
silences every debug call in a file at once, so nothing you used to
|
|
69
|
+
sanity-check a fold split or a train/test boundary can slip into
|
|
70
|
+
a shared notebook or a production run by accident.
|
|
71
|
+
|
|
72
|
+
## Install
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
pip install varview
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Usage
|
|
79
|
+
|
|
80
|
+
### Basic
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
from varview import debug
|
|
84
|
+
|
|
85
|
+
count = 42
|
|
86
|
+
debug(["count"]) # list of names
|
|
87
|
+
debug("count") # a single string also works, no need to wrap it
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Color-code by what the value means to you
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
debug(["count"], color="green") # default, all good
|
|
94
|
+
debug(["count"], color="yellow") # worth a second look
|
|
95
|
+
debug(["count"], color="red") # flag it
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Lay it out the way you're scanning
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
debug(["count", "total", "status"]) # vertical (default)
|
|
102
|
+
debug(["count", "total", "status"], orientation="horizontal") # count: 42, total: 137, status: active
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Turn one call off without deleting it
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
debug(["count"], display=False)
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Turn every call off at once, before you share or ship
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
from varview import debug_off, debug_on
|
|
115
|
+
|
|
116
|
+
debug_off() # every debug() call in the process goes silent, even display=True ones
|
|
117
|
+
# ... run the rest of your pipeline, notebook export, whatever needs to be clean ...
|
|
118
|
+
debug_on() # back to normal for your next debugging session
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
`debug_off()` is the one-line answer to "did I leave a debug print
|
|
122
|
+
in this notebook before I sent it to someone." Flip it at the top of
|
|
123
|
+
a cell, or right before a scheduled job runs, and every `debug()`
|
|
124
|
+
call downstream goes quiet, no hunting through the file for calls
|
|
125
|
+
you forgot about.
|
|
126
|
+
|
|
127
|
+
### Typos don't kill the whole block
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
debug(["count", "totall", "status"])
|
|
131
|
+
# count: 42
|
|
132
|
+
# totall: <not found>
|
|
133
|
+
# status: active
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
One bad name prints `<not found>` in place instead of raising and
|
|
137
|
+
losing every other value you wanted to see.
|
|
138
|
+
|
|
139
|
+
## API
|
|
140
|
+
|
|
141
|
+
### `debug(names, color="green", display=True, orientation="vertical")`
|
|
142
|
+
|
|
143
|
+
| Param | Type | Default | Notes |
|
|
144
|
+
|---|---|---|---|
|
|
145
|
+
| `names` | `str` or `list`/`tuple` of `str` | (required) | Variable names to look up in the *caller's* local scope |
|
|
146
|
+
| `color` | `"green"`, `"red"`, `"yellow"` | `"green"` | Label color only; values always print in black |
|
|
147
|
+
| `display` | `bool` | `True` | Silences this one call when `False` |
|
|
148
|
+
| `orientation` | `"vertical"`, `"horizontal"` | `"vertical"` | Layout of the printed pairs |
|
|
149
|
+
|
|
150
|
+
All four parameters are validated on every call: an invalid `color`
|
|
151
|
+
or `orientation` raises `ValueError`, an invalid `display` type raises
|
|
152
|
+
`TypeError`, and `names` must be a string or a list/tuple of strings
|
|
153
|
+
or it raises `TypeError`. Nothing gets a chance to fail silently or
|
|
154
|
+
print something misleading.
|
|
155
|
+
|
|
156
|
+
### `debug_off()` / `debug_on()`
|
|
157
|
+
|
|
158
|
+
Module-level switch. `debug_off()` silences every `debug()` call in
|
|
159
|
+
the running process, regardless of that call's own `display` value.
|
|
160
|
+
`debug_on()` restores normal behavior.
|
|
161
|
+
|
|
162
|
+
## License
|
|
163
|
+
|
|
164
|
+
MIT
|
varview-0.1.0/README.md
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# varview
|
|
2
|
+
|
|
3
|
+
A tiny, zero-dependency debug-printing helper for people who check their work, for clean automation.
|
|
4
|
+
|
|
5
|
+
```python
|
|
6
|
+
from varview import debug
|
|
7
|
+
|
|
8
|
+
count = 42
|
|
9
|
+
total = 137
|
|
10
|
+
status = "active"
|
|
11
|
+
|
|
12
|
+
debug(["count", "total", "status"])
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
count: 42
|
|
17
|
+
|
|
18
|
+
total: 137
|
|
19
|
+
|
|
20
|
+
status: active
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Why this exists
|
|
24
|
+
|
|
25
|
+
Most debugging habits start the same way: `print(f"count: {count}")`,
|
|
26
|
+
scattered through a script, forgotten about, and left in, or worse,
|
|
27
|
+
silently shaping a result nobody meant to ship.
|
|
28
|
+
|
|
29
|
+
`varview` was built out of a data analyst's day-to-day discipline: **if
|
|
30
|
+
you can't see your intermediate values clearly, you can't trust your
|
|
31
|
+
final ones.** Threshold sweeps, fold splits, feature combos, backtest
|
|
32
|
+
tables: every step that touches a metric is a step where leakage,
|
|
33
|
+
silent type coercion, or an off-by-one slice can quietly corrupt a
|
|
34
|
+
result. The habit that catches this isn't a debugger or a notebook
|
|
35
|
+
full of stray `print()` calls, it's making every checkpoint visible,
|
|
36
|
+
on purpose, every time, with a single flip to turn it all off before
|
|
37
|
+
anything ships.
|
|
38
|
+
|
|
39
|
+
That's the whole philosophy behind this package:
|
|
40
|
+
|
|
41
|
+
- **See it before you trust it.** Print the name *and* the value,
|
|
42
|
+
side by side, with no risk of the label drifting out of sync with
|
|
43
|
+
what it's labeling.
|
|
44
|
+
- **Validate loudly, not quietly.** Every parameter is checked up
|
|
45
|
+
front; bad input fails fast with a clear error instead of
|
|
46
|
+
producing a confusing result three functions later.
|
|
47
|
+
- **Make leakage a choice, not an accident.** One global switch
|
|
48
|
+
silences every debug call in a file at once, so nothing you used to
|
|
49
|
+
sanity-check a fold split or a train/test boundary can slip into
|
|
50
|
+
a shared notebook or a production run by accident.
|
|
51
|
+
|
|
52
|
+
## Install
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pip install varview
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Usage
|
|
59
|
+
|
|
60
|
+
### Basic
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
from varview import debug
|
|
64
|
+
|
|
65
|
+
count = 42
|
|
66
|
+
debug(["count"]) # list of names
|
|
67
|
+
debug("count") # a single string also works, no need to wrap it
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Color-code by what the value means to you
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
debug(["count"], color="green") # default, all good
|
|
74
|
+
debug(["count"], color="yellow") # worth a second look
|
|
75
|
+
debug(["count"], color="red") # flag it
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Lay it out the way you're scanning
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
debug(["count", "total", "status"]) # vertical (default)
|
|
82
|
+
debug(["count", "total", "status"], orientation="horizontal") # count: 42, total: 137, status: active
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Turn one call off without deleting it
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
debug(["count"], display=False)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Turn every call off at once, before you share or ship
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
from varview import debug_off, debug_on
|
|
95
|
+
|
|
96
|
+
debug_off() # every debug() call in the process goes silent, even display=True ones
|
|
97
|
+
# ... run the rest of your pipeline, notebook export, whatever needs to be clean ...
|
|
98
|
+
debug_on() # back to normal for your next debugging session
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
`debug_off()` is the one-line answer to "did I leave a debug print
|
|
102
|
+
in this notebook before I sent it to someone." Flip it at the top of
|
|
103
|
+
a cell, or right before a scheduled job runs, and every `debug()`
|
|
104
|
+
call downstream goes quiet, no hunting through the file for calls
|
|
105
|
+
you forgot about.
|
|
106
|
+
|
|
107
|
+
### Typos don't kill the whole block
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
debug(["count", "totall", "status"])
|
|
111
|
+
# count: 42
|
|
112
|
+
# totall: <not found>
|
|
113
|
+
# status: active
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
One bad name prints `<not found>` in place instead of raising and
|
|
117
|
+
losing every other value you wanted to see.
|
|
118
|
+
|
|
119
|
+
## API
|
|
120
|
+
|
|
121
|
+
### `debug(names, color="green", display=True, orientation="vertical")`
|
|
122
|
+
|
|
123
|
+
| Param | Type | Default | Notes |
|
|
124
|
+
|---|---|---|---|
|
|
125
|
+
| `names` | `str` or `list`/`tuple` of `str` | (required) | Variable names to look up in the *caller's* local scope |
|
|
126
|
+
| `color` | `"green"`, `"red"`, `"yellow"` | `"green"` | Label color only; values always print in black |
|
|
127
|
+
| `display` | `bool` | `True` | Silences this one call when `False` |
|
|
128
|
+
| `orientation` | `"vertical"`, `"horizontal"` | `"vertical"` | Layout of the printed pairs |
|
|
129
|
+
|
|
130
|
+
All four parameters are validated on every call: an invalid `color`
|
|
131
|
+
or `orientation` raises `ValueError`, an invalid `display` type raises
|
|
132
|
+
`TypeError`, and `names` must be a string or a list/tuple of strings
|
|
133
|
+
or it raises `TypeError`. Nothing gets a chance to fail silently or
|
|
134
|
+
print something misleading.
|
|
135
|
+
|
|
136
|
+
### `debug_off()` / `debug_on()`
|
|
137
|
+
|
|
138
|
+
Module-level switch. `debug_off()` silences every `debug()` call in
|
|
139
|
+
the running process, regardless of that call's own `display` value.
|
|
140
|
+
`debug_on()` restores normal behavior.
|
|
141
|
+
|
|
142
|
+
## License
|
|
143
|
+
|
|
144
|
+
MIT
|
varview-0.1.0/Readme.md
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# varview
|
|
2
|
+
|
|
3
|
+
A tiny, zero-dependency debug-printing helper for people who check their work, for clean automation.
|
|
4
|
+
|
|
5
|
+
```python
|
|
6
|
+
from varview import debug
|
|
7
|
+
|
|
8
|
+
count = 42
|
|
9
|
+
total = 137
|
|
10
|
+
status = "active"
|
|
11
|
+
|
|
12
|
+
debug(["count", "total", "status"])
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
count: 42
|
|
17
|
+
|
|
18
|
+
total: 137
|
|
19
|
+
|
|
20
|
+
status: active
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Why this exists
|
|
24
|
+
|
|
25
|
+
Most debugging habits start the same way: `print(f"count: {count}")`,
|
|
26
|
+
scattered through a script, forgotten about, and left in, or worse,
|
|
27
|
+
silently shaping a result nobody meant to ship.
|
|
28
|
+
|
|
29
|
+
`varview` was built out of a data analyst's day-to-day discipline: **if
|
|
30
|
+
you can't see your intermediate values clearly, you can't trust your
|
|
31
|
+
final ones.** Threshold sweeps, fold splits, feature combos, backtest
|
|
32
|
+
tables: every step that touches a metric is a step where leakage,
|
|
33
|
+
silent type coercion, or an off-by-one slice can quietly corrupt a
|
|
34
|
+
result. The habit that catches this isn't a debugger or a notebook
|
|
35
|
+
full of stray `print()` calls, it's making every checkpoint visible,
|
|
36
|
+
on purpose, every time, with a single flip to turn it all off before
|
|
37
|
+
anything ships.
|
|
38
|
+
|
|
39
|
+
That's the whole philosophy behind this package:
|
|
40
|
+
|
|
41
|
+
- **See it before you trust it.** Print the name *and* the value,
|
|
42
|
+
side by side, with no risk of the label drifting out of sync with
|
|
43
|
+
what it's labeling.
|
|
44
|
+
- **Validate loudly, not quietly.** Every parameter is checked up
|
|
45
|
+
front; bad input fails fast with a clear error instead of
|
|
46
|
+
producing a confusing result three functions later.
|
|
47
|
+
- **Make leakage a choice, not an accident.** One global switch
|
|
48
|
+
silences every debug call in a file at once, so nothing you used to
|
|
49
|
+
sanity-check a fold split or a train/test boundary can slip into
|
|
50
|
+
a shared notebook or a production run by accident.
|
|
51
|
+
|
|
52
|
+
## Install
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pip install varview
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Usage
|
|
59
|
+
|
|
60
|
+
### Basic
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
from varview import debug
|
|
64
|
+
|
|
65
|
+
count = 42
|
|
66
|
+
debug(["count"]) # list of names
|
|
67
|
+
debug("count") # a single string also works, no need to wrap it
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Color-code by what the value means to you
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
debug(["count"], color="green") # default, all good
|
|
74
|
+
debug(["count"], color="yellow") # worth a second look
|
|
75
|
+
debug(["count"], color="red") # flag it
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Lay it out the way you're scanning
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
debug(["count", "total", "status"]) # vertical (default)
|
|
82
|
+
debug(["count", "total", "status"], orientation="horizontal") # count: 42, total: 137, status: active
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Turn one call off without deleting it
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
debug(["count"], display=False)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Turn every call off at once, before you share or ship
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
from varview import debug_off, debug_on
|
|
95
|
+
|
|
96
|
+
debug_off() # every debug() call in the process goes silent, even display=True ones
|
|
97
|
+
# ... run the rest of your pipeline, notebook export, whatever needs to be clean ...
|
|
98
|
+
debug_on() # back to normal for your next debugging session
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
`debug_off()` is the one-line answer to "did I leave a debug print
|
|
102
|
+
in this notebook before I sent it to someone." Flip it at the top of
|
|
103
|
+
a cell, or right before a scheduled job runs, and every `debug()`
|
|
104
|
+
call downstream goes quiet, no hunting through the file for calls
|
|
105
|
+
you forgot about.
|
|
106
|
+
|
|
107
|
+
### Typos don't kill the whole block
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
debug(["count", "totall", "status"])
|
|
111
|
+
# count: 42
|
|
112
|
+
# totall: <not found>
|
|
113
|
+
# status: active
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
One bad name prints `<not found>` in place instead of raising and
|
|
117
|
+
losing every other value you wanted to see.
|
|
118
|
+
|
|
119
|
+
## API
|
|
120
|
+
|
|
121
|
+
### `debug(names, color="green", display=True, orientation="vertical")`
|
|
122
|
+
|
|
123
|
+
| Param | Type | Default | Notes |
|
|
124
|
+
|---|---|---|---|
|
|
125
|
+
| `names` | `str` or `list`/`tuple` of `str` | (required) | Variable names to look up in the *caller's* local scope |
|
|
126
|
+
| `color` | `"green"`, `"red"`, `"yellow"` | `"green"` | Label color only; values always print in black |
|
|
127
|
+
| `display` | `bool` | `True` | Silences this one call when `False` |
|
|
128
|
+
| `orientation` | `"vertical"`, `"horizontal"` | `"vertical"` | Layout of the printed pairs |
|
|
129
|
+
|
|
130
|
+
All four parameters are validated on every call: an invalid `color`
|
|
131
|
+
or `orientation` raises `ValueError`, an invalid `display` type raises
|
|
132
|
+
`TypeError`, and `names` must be a string or a list/tuple of strings
|
|
133
|
+
or it raises `TypeError`. Nothing gets a chance to fail silently or
|
|
134
|
+
print something misleading.
|
|
135
|
+
|
|
136
|
+
### `debug_off()` / `debug_on()`
|
|
137
|
+
|
|
138
|
+
Module-level switch. `debug_off()` silences every `debug()` call in
|
|
139
|
+
the running process, regardless of that call's own `display` value.
|
|
140
|
+
`debug_on()` restores normal behavior.
|
|
141
|
+
|
|
142
|
+
## License
|
|
143
|
+
|
|
144
|
+
MIT
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "varview"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "A tiny debug-printing helper that prints name: value pairs from the caller's scope, with a one-line kill switch to prevent leaked debug output."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.7"
|
|
11
|
+
authors = [
|
|
12
|
+
{ name = "Henry", email = "osas2henry@gmail.com" }
|
|
13
|
+
]
|
|
14
|
+
keywords = ["debug", "debugging", "print", "variables", "logging", "data-validation"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 4 - Beta",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Programming Language :: Python :: 3.7",
|
|
20
|
+
"Programming Language :: Python :: 3.8",
|
|
21
|
+
"Programming Language :: Python :: 3.9",
|
|
22
|
+
"Programming Language :: Python :: 3.10",
|
|
23
|
+
"Programming Language :: Python :: 3.11",
|
|
24
|
+
"Programming Language :: Python :: 3.12",
|
|
25
|
+
"Topic :: Software Development :: Debuggers",
|
|
26
|
+
"Topic :: Utilities",
|
|
27
|
+
]
|
varview-0.1.0/setup.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
with open("README.md", "r", encoding="utf-8") as f:
|
|
4
|
+
long_description = f.read()
|
|
5
|
+
|
|
6
|
+
setup(
|
|
7
|
+
name="varview",
|
|
8
|
+
version="0.1.0",
|
|
9
|
+
description="A tiny debug-printing helper that prints name: value pairs from the caller's scope, with a one-line kill switch to prevent leaked debug output.",
|
|
10
|
+
long_description=long_description,
|
|
11
|
+
long_description_content_type="text/markdown",
|
|
12
|
+
author="Henry",
|
|
13
|
+
author_email="osas2henry@gmail.com",
|
|
14
|
+
packages=find_packages(),
|
|
15
|
+
keywords=["debug", "debugging", "print", "variables", "logging", "data-validation"],
|
|
16
|
+
classifiers=[
|
|
17
|
+
"Development Status :: 4 - Beta",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"Programming Language :: Python :: 3.7",
|
|
21
|
+
"Programming Language :: Python :: 3.8",
|
|
22
|
+
"Programming Language :: Python :: 3.9",
|
|
23
|
+
"Programming Language :: Python :: 3.10",
|
|
24
|
+
"Programming Language :: Python :: 3.11",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
"Topic :: Software Development :: Debuggers",
|
|
27
|
+
"Topic :: Utilities",
|
|
28
|
+
],
|
|
29
|
+
python_requires=">=3.7",
|
|
30
|
+
)
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"""
|
|
2
|
+
varview
|
|
3
|
+
~~~~~~~
|
|
4
|
+
|
|
5
|
+
A tiny debug-printing helper: pass variable names as strings and it
|
|
6
|
+
prints "name: value" pairs pulled straight from the caller's local
|
|
7
|
+
scope — no need to write out f"{name}: {value}" by hand.
|
|
8
|
+
|
|
9
|
+
Basic usage:
|
|
10
|
+
from varview import debug
|
|
11
|
+
|
|
12
|
+
count = 42
|
|
13
|
+
debug(["count"]) # green label, black value
|
|
14
|
+
debug("count") # single string also works
|
|
15
|
+
debug(["count"], color="red")
|
|
16
|
+
debug(["count"], orientation="horizontal")
|
|
17
|
+
|
|
18
|
+
Global kill switch (silence every debug() call in one line, e.g.
|
|
19
|
+
before sharing a notebook or shipping to prod):
|
|
20
|
+
from varview import debug_off, debug_on
|
|
21
|
+
debug_off()
|
|
22
|
+
debug_on()
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
import inspect
|
|
26
|
+
|
|
27
|
+
__all__ = ["debug", "debug_off", "debug_on"]
|
|
28
|
+
__version__ = "0.1.0"
|
|
29
|
+
|
|
30
|
+
_DEBUG_GLOBAL_ENABLED = True # flip via debug_off()/debug_on() to silence ALL debug() calls at once
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def debug(names, color="green", display=True, orientation="vertical"):
|
|
34
|
+
"""
|
|
35
|
+
Pass a list of variable name strings, or a single name as a plain
|
|
36
|
+
string, and this prints each one as "name: value" (name bolded in
|
|
37
|
+
the chosen color, value always black).
|
|
38
|
+
|
|
39
|
+
e.g. debug(["count", "total", "status"])
|
|
40
|
+
debug("count") <- single string also works, auto-wrapped
|
|
41
|
+
into a one-item list so it isn't split
|
|
42
|
+
into characters.
|
|
43
|
+
|
|
44
|
+
`color` picks the name/label color: "green", "red", or "yellow".
|
|
45
|
+
Defaults to "green". Raises ValueError if anything else is passed.
|
|
46
|
+
|
|
47
|
+
`display` toggles THIS SPECIFIC call. Defaults to True. Must be a
|
|
48
|
+
bool, or TypeError is raised.
|
|
49
|
+
|
|
50
|
+
Printing only happens if BOTH `display=True` for this call AND the
|
|
51
|
+
module-level global switch is enabled. Call `debug_off()` to
|
|
52
|
+
silence every debug() call in the file at once (e.g. before
|
|
53
|
+
sharing a notebook, to eliminate leakage), and `debug_on()` to
|
|
54
|
+
restore them — no need to touch individual call sites.
|
|
55
|
+
|
|
56
|
+
`orientation` picks the layout: "vertical" (default) prints one
|
|
57
|
+
"name: value" pair per line with a blank line between each pair.
|
|
58
|
+
"horizontal" prints all pairs on a single line, separated by ", ".
|
|
59
|
+
Raises ValueError if anything else is passed.
|
|
60
|
+
|
|
61
|
+
Looks up each name in the CALLER's local variables (via inspect) —
|
|
62
|
+
you don't need to pass the values yourself, just the names as
|
|
63
|
+
strings, in the order you want them printed.
|
|
64
|
+
`names` must be a string or a list/tuple of strings, or TypeError
|
|
65
|
+
is raised.
|
|
66
|
+
A name not found in the caller's locals prints as
|
|
67
|
+
"name: <not found>" (label still in the chosen color) instead of
|
|
68
|
+
raising, so one typo doesn't kill the whole debug block.
|
|
69
|
+
"""
|
|
70
|
+
VALID_COLORS = {"green", "red", "yellow"}
|
|
71
|
+
VALID_ORIENTATIONS = {"vertical", "horizontal"}
|
|
72
|
+
|
|
73
|
+
if not isinstance(display, bool):
|
|
74
|
+
raise TypeError(f"display must be a bool, got {type(display).__name__}")
|
|
75
|
+
|
|
76
|
+
if color not in VALID_COLORS:
|
|
77
|
+
raise ValueError(f"color must be one of {sorted(VALID_COLORS)}, got {color!r}")
|
|
78
|
+
|
|
79
|
+
if orientation not in VALID_ORIENTATIONS:
|
|
80
|
+
raise ValueError(f"orientation must be one of {sorted(VALID_ORIENTATIONS)}, got {orientation!r}")
|
|
81
|
+
|
|
82
|
+
if isinstance(names, str):
|
|
83
|
+
names = [names]
|
|
84
|
+
elif isinstance(names, (list, tuple)):
|
|
85
|
+
if not all(isinstance(n, str) for n in names):
|
|
86
|
+
raise TypeError("all items in names must be strings")
|
|
87
|
+
else:
|
|
88
|
+
raise TypeError(f"names must be a str or list/tuple of str, got {type(names).__name__}")
|
|
89
|
+
|
|
90
|
+
if not display or not _DEBUG_GLOBAL_ENABLED:
|
|
91
|
+
return
|
|
92
|
+
|
|
93
|
+
COLORS = {
|
|
94
|
+
"green": "\033[1;32m",
|
|
95
|
+
"red": "\033[1;91m", # bright red
|
|
96
|
+
"yellow": "\033[1;93m", # bright yellow
|
|
97
|
+
}
|
|
98
|
+
NAME_COLOR = COLORS[color]
|
|
99
|
+
BLACK = "\033[30m"
|
|
100
|
+
RESET = "\033[0m"
|
|
101
|
+
|
|
102
|
+
caller_locals = inspect.currentframe().f_back.f_locals
|
|
103
|
+
lines = []
|
|
104
|
+
for name in names:
|
|
105
|
+
if name in caller_locals:
|
|
106
|
+
value = caller_locals[name]
|
|
107
|
+
lines.append(f"{NAME_COLOR}{name}{RESET}: {BLACK}{value}{RESET}")
|
|
108
|
+
else:
|
|
109
|
+
lines.append(f"{NAME_COLOR}{name}{RESET}: {BLACK}<not found>{RESET}")
|
|
110
|
+
|
|
111
|
+
if orientation == "horizontal":
|
|
112
|
+
print(", ".join(lines))
|
|
113
|
+
else:
|
|
114
|
+
print("\n\n".join(lines))
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def debug_off():
|
|
118
|
+
"""Silence ALL debug() calls in this module (global kill switch)."""
|
|
119
|
+
global _DEBUG_GLOBAL_ENABLED
|
|
120
|
+
_DEBUG_GLOBAL_ENABLED = False
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def debug_on():
|
|
124
|
+
"""Re-enable debug() calls after debug_off()."""
|
|
125
|
+
global _DEBUG_GLOBAL_ENABLED
|
|
126
|
+
_DEBUG_GLOBAL_ENABLED = True
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
"""
|
|
130
|
+
if __name__ == "__main__":
|
|
131
|
+
count = 42
|
|
132
|
+
total = 137
|
|
133
|
+
status = "active"
|
|
134
|
+
|
|
135
|
+
print("--- default (vertical, green, display=True) ---")
|
|
136
|
+
debug(["count", "total", "status"])
|
|
137
|
+
|
|
138
|
+
print("\n--- single string, not a list ---")
|
|
139
|
+
debug("count")
|
|
140
|
+
|
|
141
|
+
print("\n--- color='red' ---")
|
|
142
|
+
debug(["count", "total"], color="red")
|
|
143
|
+
|
|
144
|
+
print("\n--- color='yellow' ---")
|
|
145
|
+
debug(["count", "total"], color="yellow")
|
|
146
|
+
|
|
147
|
+
print("\n--- orientation='horizontal' (comma-separated) ---")
|
|
148
|
+
debug(["count", "total", "status"], orientation="horizontal")
|
|
149
|
+
|
|
150
|
+
print("\n--- horizontal + color='red' ---")
|
|
151
|
+
debug(["count", "total", "status"], color="red", orientation="horizontal")
|
|
152
|
+
|
|
153
|
+
print("\n--- missing variable (typo) ---")
|
|
154
|
+
debug(["count", "totall", "status"])
|
|
155
|
+
|
|
156
|
+
print("\n--- display=False (should print nothing below this line) ---")
|
|
157
|
+
debug(["count", "total"], display=False)
|
|
158
|
+
print("(nothing printed above if display=False worked)")
|
|
159
|
+
|
|
160
|
+
print("\n--- global debug_off() silences everything, even display=True ---")
|
|
161
|
+
debug_off()
|
|
162
|
+
debug(["count", "total", "status"])
|
|
163
|
+
print("(nothing printed above if debug_off() worked)")
|
|
164
|
+
|
|
165
|
+
print("\n--- debug_on() restores normal behavior ---")
|
|
166
|
+
debug_on()
|
|
167
|
+
debug(["count", "total", "status"])
|
|
168
|
+
|
|
169
|
+
print("\n--- invalid color raises ValueError ---")
|
|
170
|
+
try:
|
|
171
|
+
debug(["count"], color="purple")
|
|
172
|
+
except ValueError as e:
|
|
173
|
+
print(f"Caught: {e}")
|
|
174
|
+
|
|
175
|
+
print("\n--- invalid orientation raises ValueError ---")
|
|
176
|
+
try:
|
|
177
|
+
debug(["count"], orientation="diagonal")
|
|
178
|
+
except ValueError as e:
|
|
179
|
+
print(f"Caught: {e}")
|
|
180
|
+
|
|
181
|
+
print("\n--- invalid display type raises TypeError ---")
|
|
182
|
+
try:
|
|
183
|
+
debug(["count"], display="yes")
|
|
184
|
+
except TypeError as e:
|
|
185
|
+
print(f"Caught: {e}")
|
|
186
|
+
|
|
187
|
+
print("\n--- invalid names type raises TypeError ---")
|
|
188
|
+
try:
|
|
189
|
+
debug(123)
|
|
190
|
+
"""
|
|
191
|
+
except TypeError as e:
|
|
192
|
+
print(f"Caught: {e}")
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"""
|
|
2
|
+
varview
|
|
3
|
+
~~~~~~~
|
|
4
|
+
|
|
5
|
+
A tiny debug-printing helper: pass variable names as strings and it
|
|
6
|
+
prints "name: value" pairs pulled straight from the caller's local
|
|
7
|
+
scope — no need to write out f"{name}: {value}" by hand.
|
|
8
|
+
|
|
9
|
+
Basic usage:
|
|
10
|
+
from varview import debug
|
|
11
|
+
|
|
12
|
+
count = 42
|
|
13
|
+
debug(["count"]) # green label, black value
|
|
14
|
+
debug("count") # single string also works
|
|
15
|
+
debug(["count"], color="red")
|
|
16
|
+
debug(["count"], orientation="horizontal")
|
|
17
|
+
|
|
18
|
+
Global kill switch (silence every debug() call in one line, e.g.
|
|
19
|
+
before sharing a notebook or shipping to prod):
|
|
20
|
+
from varview import debug_off, debug_on
|
|
21
|
+
debug_off()
|
|
22
|
+
debug_on()
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
import inspect
|
|
26
|
+
|
|
27
|
+
__all__ = ["debug", "debug_off", "debug_on"]
|
|
28
|
+
__version__ = "0.1.0"
|
|
29
|
+
|
|
30
|
+
_DEBUG_GLOBAL_ENABLED = True # flip via debug_off()/debug_on() to silence ALL debug() calls at once
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def debug(names, color="green", display=True, orientation="vertical"):
|
|
34
|
+
"""
|
|
35
|
+
Pass a list of variable name strings, or a single name as a plain
|
|
36
|
+
string, and this prints each one as "name: value" (name bolded in
|
|
37
|
+
the chosen color, value always black).
|
|
38
|
+
|
|
39
|
+
e.g. debug(["count", "total", "status"])
|
|
40
|
+
debug("count") <- single string also works, auto-wrapped
|
|
41
|
+
into a one-item list so it isn't split
|
|
42
|
+
into characters.
|
|
43
|
+
|
|
44
|
+
`color` picks the name/label color: "green", "red", or "yellow".
|
|
45
|
+
Defaults to "green". Raises ValueError if anything else is passed.
|
|
46
|
+
|
|
47
|
+
`display` toggles THIS SPECIFIC call. Defaults to True. Must be a
|
|
48
|
+
bool, or TypeError is raised.
|
|
49
|
+
|
|
50
|
+
Printing only happens if BOTH `display=True` for this call AND the
|
|
51
|
+
module-level global switch is enabled. Call `debug_off()` to
|
|
52
|
+
silence every debug() call in the file at once (e.g. before
|
|
53
|
+
sharing a notebook, to eliminate leakage), and `debug_on()` to
|
|
54
|
+
restore them — no need to touch individual call sites.
|
|
55
|
+
|
|
56
|
+
`orientation` picks the layout: "vertical" (default) prints one
|
|
57
|
+
"name: value" pair per line with a blank line between each pair.
|
|
58
|
+
"horizontal" prints all pairs on a single line, separated by ", ".
|
|
59
|
+
Raises ValueError if anything else is passed.
|
|
60
|
+
|
|
61
|
+
Looks up each name in the CALLER's local variables (via inspect) —
|
|
62
|
+
you don't need to pass the values yourself, just the names as
|
|
63
|
+
strings, in the order you want them printed.
|
|
64
|
+
`names` must be a string or a list/tuple of strings, or TypeError
|
|
65
|
+
is raised.
|
|
66
|
+
A name not found in the caller's locals prints as
|
|
67
|
+
"name: <not found>" (label still in the chosen color) instead of
|
|
68
|
+
raising, so one typo doesn't kill the whole debug block.
|
|
69
|
+
"""
|
|
70
|
+
VALID_COLORS = {"green", "red", "yellow"}
|
|
71
|
+
VALID_ORIENTATIONS = {"vertical", "horizontal"}
|
|
72
|
+
|
|
73
|
+
if not isinstance(display, bool):
|
|
74
|
+
raise TypeError(f"display must be a bool, got {type(display).__name__}")
|
|
75
|
+
|
|
76
|
+
if color not in VALID_COLORS:
|
|
77
|
+
raise ValueError(f"color must be one of {sorted(VALID_COLORS)}, got {color!r}")
|
|
78
|
+
|
|
79
|
+
if orientation not in VALID_ORIENTATIONS:
|
|
80
|
+
raise ValueError(f"orientation must be one of {sorted(VALID_ORIENTATIONS)}, got {orientation!r}")
|
|
81
|
+
|
|
82
|
+
if isinstance(names, str):
|
|
83
|
+
names = [names]
|
|
84
|
+
elif isinstance(names, (list, tuple)):
|
|
85
|
+
if not all(isinstance(n, str) for n in names):
|
|
86
|
+
raise TypeError("all items in names must be strings")
|
|
87
|
+
else:
|
|
88
|
+
raise TypeError(f"names must be a str or list/tuple of str, got {type(names).__name__}")
|
|
89
|
+
|
|
90
|
+
if not display or not _DEBUG_GLOBAL_ENABLED:
|
|
91
|
+
return
|
|
92
|
+
|
|
93
|
+
COLORS = {
|
|
94
|
+
"green": "\033[1;32m",
|
|
95
|
+
"red": "\033[1;91m", # bright red
|
|
96
|
+
"yellow": "\033[1;93m", # bright yellow
|
|
97
|
+
}
|
|
98
|
+
NAME_COLOR = COLORS[color]
|
|
99
|
+
BLACK = "\033[30m"
|
|
100
|
+
RESET = "\033[0m"
|
|
101
|
+
|
|
102
|
+
caller_locals = inspect.currentframe().f_back.f_locals
|
|
103
|
+
lines = []
|
|
104
|
+
for name in names:
|
|
105
|
+
if name in caller_locals:
|
|
106
|
+
value = caller_locals[name]
|
|
107
|
+
lines.append(f"{NAME_COLOR}{name}{RESET}: {BLACK}{value}{RESET}")
|
|
108
|
+
else:
|
|
109
|
+
lines.append(f"{NAME_COLOR}{name}{RESET}: {BLACK}<not found>{RESET}")
|
|
110
|
+
|
|
111
|
+
if orientation == "horizontal":
|
|
112
|
+
print(", ".join(lines))
|
|
113
|
+
else:
|
|
114
|
+
print("\n\n".join(lines))
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def debug_off():
|
|
118
|
+
"""Silence ALL debug() calls in this module (global kill switch)."""
|
|
119
|
+
global _DEBUG_GLOBAL_ENABLED
|
|
120
|
+
_DEBUG_GLOBAL_ENABLED = False
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def debug_on():
|
|
124
|
+
"""Re-enable debug() calls after debug_off()."""
|
|
125
|
+
global _DEBUG_GLOBAL_ENABLED
|
|
126
|
+
_DEBUG_GLOBAL_ENABLED = True
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
"""
|
|
130
|
+
if __name__ == "__main__":
|
|
131
|
+
count = 42
|
|
132
|
+
total = 137
|
|
133
|
+
status = "active"
|
|
134
|
+
|
|
135
|
+
print("--- default (vertical, green, display=True) ---")
|
|
136
|
+
debug(["count", "total", "status"])
|
|
137
|
+
|
|
138
|
+
print("\n--- single string, not a list ---")
|
|
139
|
+
debug("count")
|
|
140
|
+
|
|
141
|
+
print("\n--- color='red' ---")
|
|
142
|
+
debug(["count", "total"], color="red")
|
|
143
|
+
|
|
144
|
+
print("\n--- color='yellow' ---")
|
|
145
|
+
debug(["count", "total"], color="yellow")
|
|
146
|
+
|
|
147
|
+
print("\n--- orientation='horizontal' (comma-separated) ---")
|
|
148
|
+
debug(["count", "total", "status"], orientation="horizontal")
|
|
149
|
+
|
|
150
|
+
print("\n--- horizontal + color='red' ---")
|
|
151
|
+
debug(["count", "total", "status"], color="red", orientation="horizontal")
|
|
152
|
+
|
|
153
|
+
print("\n--- missing variable (typo) ---")
|
|
154
|
+
debug(["count", "totall", "status"])
|
|
155
|
+
|
|
156
|
+
print("\n--- display=False (should print nothing below this line) ---")
|
|
157
|
+
debug(["count", "total"], display=False)
|
|
158
|
+
print("(nothing printed above if display=False worked)")
|
|
159
|
+
|
|
160
|
+
print("\n--- global debug_off() silences everything, even display=True ---")
|
|
161
|
+
debug_off()
|
|
162
|
+
debug(["count", "total", "status"])
|
|
163
|
+
print("(nothing printed above if debug_off() worked)")
|
|
164
|
+
|
|
165
|
+
print("\n--- debug_on() restores normal behavior ---")
|
|
166
|
+
debug_on()
|
|
167
|
+
debug(["count", "total", "status"])
|
|
168
|
+
|
|
169
|
+
print("\n--- invalid color raises ValueError ---")
|
|
170
|
+
try:
|
|
171
|
+
debug(["count"], color="purple")
|
|
172
|
+
except ValueError as e:
|
|
173
|
+
print(f"Caught: {e}")
|
|
174
|
+
|
|
175
|
+
print("\n--- invalid orientation raises ValueError ---")
|
|
176
|
+
try:
|
|
177
|
+
debug(["count"], orientation="diagonal")
|
|
178
|
+
except ValueError as e:
|
|
179
|
+
print(f"Caught: {e}")
|
|
180
|
+
|
|
181
|
+
print("\n--- invalid display type raises TypeError ---")
|
|
182
|
+
try:
|
|
183
|
+
debug(["count"], display="yes")
|
|
184
|
+
except TypeError as e:
|
|
185
|
+
print(f"Caught: {e}")
|
|
186
|
+
|
|
187
|
+
print("\n--- invalid names type raises TypeError ---")
|
|
188
|
+
try:
|
|
189
|
+
debug(123)
|
|
190
|
+
"""
|
|
191
|
+
except TypeError as e:
|
|
192
|
+
print(f"Caught: {e}")
|