Metadata-Version: 2.5
Name: varview
Version: 1.0.0
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.
Author-email: Henry <osas2henry@gmail.com>
Keywords: data-validation,debug,debugging,logging,print,variables
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Debuggers
Classifier: Topic :: Utilities
Requires-Python: >=3.7
Description-Content-Type: text/markdown

# varview

A tiny, zero-dependency debug-printing helper for people who check their work, for clean automation.

```python
from varview import debug

count = 42
total = 137
status = "active"

debug(count, total, status)
```

```
count = 42

total = 137

status = active
```

## Why this exists

Most debugging habits start the same way: `print(f"count: {count}")`,
scattered through a script, forgotten about, and left in, or worse,
silently shaping a result nobody meant to ship.

`varview` grew out of a data analyst's day-to-day discipline: **if
you can't see your intermediate values clearly, you can't trust your
final ones.** The habit it's built for is simple: being able to see
every variable in your code, at the point it's actually computed, is
what lets you notice when something is wrong, a value that shifted
type, a filter that let too much or too little through, a join that
didn't do what you expected. Data leakage and other silent
corruption is usually invisible not because it's hard to catch, but
because nobody was looking at the value when it happened. Making
that look cheap and habitual, instead of a special debugging step
you only reach for once something already seems broken, is the whole
point.

That's the whole philosophy behind this package:

- **See it before you trust it.** Print the name and the value, side
  by side, with no risk of the label drifting out of sync with what
  it's labeling.
- **Validate loudly, not quietly.** Every parameter is checked up
  front. Bad input fails fast with a clear error instead of
  producing a confusing result three functions later.
- **Make leakage a choice, not an accident.** One global switch
  silences every debug call in a file at once, so nothing you used to
  sanity-check an intermediate value can slip into a shared notebook
  or a production run by accident.

`varview` doesn't detect leakage, drift, or corruption on its own,
it has no idea what your data means. What it does is make the habit
that catches those problems, actually looking at your intermediate
values, cheap enough to do every time instead of only after
something already looks wrong.

## Install

```bash
pip install varview
```

## Usage

### Basic

```python
from varview import debug

count = 42
debug(count)             # unquoted variable -> "count = 42"
debug("Checking count")  # a quoted string prints literally, as-is
```

### Multiple variables, comma-separated

Pass as many variables as you want, separated by commas. No need to
wrap them in a list:

```python
count = 42
total = 137
status = "active"

debug(count, total, status)
```

```
count = 42

total = 137

status = active
```

### Unquoted variables

You don't have to quote the name at all. `varview` reads the call's
own source code to recover the label, so the variable itself can be
passed directly:

```python
debug(count)             # prints "count = 42", no quotes needed
debug(count, total)      # prints both, labels taken straight from source
```

This is resolved from the source text of the call, not from the
runtime type of the value, so it stays correct even if a variable
happens to hold a string. `region = "north"` passed unquoted as
`debug(region)` still prints `region = north`, exactly like any
other variable, it is never confused with the literal-print behavior
that quoting triggers (see below).

If the source can't be recovered (for example, calls made from a REPL
or from `exec()`'d code), `varview` falls back to a best-effort
heuristic instead of failing.

### Quoted strings print literally

A quoted string isn't looked up anywhere, it's printed exactly as
written, the same as a plain `print()` statement. That makes it a
convenient way to drop a header or a note in between the variables
you're actually checking:

```python
blended_xg = 1.8
scorelines = ["1-2", "2-0"]

debug("Match stats:", blended_xg, scorelines)
```

```
Match stats:

blended_xg = 1.8

scorelines = ['1-2', '2-0']
```

Quoted vs. unquoted is determined from the call's own source code,
not from the runtime type of the value, so this stays correct even
when a variable's value happens to be a string.

### A variable holding a list or tuple is printed as one value

Each comma-separated argument is always treated as exactly one entry,
no matter what its runtime value turns out to be, including when
that value is itself a list or tuple:

```python
quarterly_revenue = [120000, 135000, 128000, 151000]
debug(quarterly_revenue)
```

```
quarterly_revenue = [120000, 135000, 128000, 151000]
```

This prints as a single line, the variable is never unpacked into
one entry per element. To see multiple entries, pass multiple
comma-separated arguments instead:

```python
monthly_churn_rate = 0.034
active_subscribers = 8421
quarterly_revenue = [120000, 135000, 128000, 151000]

debug(monthly_churn_rate, active_subscribers, quarterly_revenue)
```

```
monthly_churn_rate = 0.034

active_subscribers = 8421

quarterly_revenue = [120000, 135000, 128000, 151000]
```

### Seeing a value instead of assuming it

The pattern that motivated this package: a quick, visible check
right where a value is computed, left in place instead of deleted,
and silenced in one line before anything ships.

```python
raw_rows = len(df)
df = df.dropna(subset=["customer_id"])
clean_rows = len(df)
dropped = raw_rows - clean_rows

debug(raw_rows, clean_rows, dropped, color="red")
```

```
raw_rows = 10482

clean_rows = 10471

dropped = 11
```

Seeing `dropped` here is the difference between knowing exactly what
a cleaning step did and just assuming it did what you meant.

> **Note:** older versions of `varview` used a list-bracket calling
> convention, `debug(["count", "total"])`. That form is no longer
> treated specially, `debug([a, b])` is now one argument whose value
> is a 2-element list, printed as a single line, not unpacked into
> two. Use plain comma-separated arguments instead: `debug(a, b)`.
>
> Even older versions also looked up quoted strings by name in the
> caller's local scope (`debug("count")` would find and print the
> variable `count`). That lookup no longer happens. A quoted string
> is now printed literally, as-is, like a plain `print()` statement.

### Color-code by what the value means to you

```python
debug(count, color="green")   # default, all good
debug(count, color="yellow")  # worth a second look
debug(count, color="red")     # flag it
```

Color only applies to the label of an unquoted variable's line. A
quoted, literal-print line always prints as plain, uncolored text,
same as `print()`.

### Lay it out the way you're scanning

```python
debug(count, total, status)                              # vertical (default)
debug(count, total, status, orientation="horizontal")     # count = 42, total = 137, status = active
```

### Push a line to the right with `pad`

`pad` adds spaces to the left of a line, and it works the same way
in either orientation:

```python
debug(count, total, pad=4)      # both lines get 4 leading spaces
```

```
    count = 42

    total = 137
```

Give it a list instead of a single number to control each argument's
padding individually. The list has to have exactly one entry per
argument passed:

```python
debug(count, total, pad=[2, 6])
```

```
  count = 42

      total = 137
```

```python
debug(count, total, pad=[2])   # only 1 value for 2 arguments
# ValueError: pad list must have exactly 2 value(s) to match the
# 2 argument(s) passed to debug(), got 1
```

For padding just one argument without spelling out a value for every
other one too, wrap that single argument in `pad(value, spaces)`
instead, from the same import:

```python
from varview import debug, pad

debug(pad(count, 4), total)
```

```
    count = 42

total = 137
```

Here `count` gets 4 leading spaces and `total` gets none, since it
wasn't touched. A `pad(...)`-wrapped argument's own spacing always
wins over the call-level `pad=` value for that one argument:

```python
debug(pad(count, 4), total, status, pad=1)
```

```
    count = 42

 total = 137

 status = active
```

`pad()` works on quoted, literal-print lines too, not just variables:

```python
debug(pad("Result:", 2), count)
```

```
  Result:

count = 42
```

### Trim the surrounding whitespace

```python
debug(count, total, margin=False)
```

By default, `debug()` prints a blank line before and after its
output so it stands out in a busy terminal or log. Set `margin=False`
for tightly packed output with nothing extra around it.

### Turn one call off without deleting it

```python
debug(count, display=False)
```

### Turn every call off at once, before you share or ship

```python
from varview import debug_off, debug_on

debug_off()   # every debug() call in the process goes silent, even display=True ones
# ... run the rest of your pipeline, notebook export, whatever needs to be clean ...
debug_on()    # back to normal for your next debugging session
```

`debug_off()` is the one-line answer to "did I leave a debug print
in this notebook before I sent it to someone." Flip it at the top of
a cell, or right before a scheduled job runs, and every `debug()`
call downstream goes quiet, no hunting through the file for calls
you forgot about.

## API

### `debug(*names, color="green", display=True, orientation="vertical", margin=True, pad=0)`

| Param | Type | Default | Notes |
|---|---|---|---|
| `*names` | one or more `str` literals, or unquoted variables, comma-separated | (required, at least one) | Quoted strings print literally, as-is, no lookup; unquoted variables have their label recovered from source and their value used directly, even if that value is a list or tuple |
| `color` | `"green"`, `"red"`, `"yellow"` | `"green"` | Label color for unquoted variables only, values always print in black; quoted literal-print lines are always plain, uncolored text |
| `display` | `bool` | `True` | Silences this one call when `False` |
| `orientation` | `"vertical"`, `"horizontal"` | `"vertical"` | Layout of the printed lines |
| `margin` | `bool` | `True` | Blank line before and after the printed output |
| `pad` | `int` or `list[int]` | `0` | Spaces added to the left of each line. A single `int` applies to every line; a list must have exactly one entry per argument passed. Wrap a single argument in `pad(value, spaces)` (imported alongside `debug`) to override its padding individually, one argument at a time |

All parameters are validated on every call: an invalid `color`,
`orientation`, or `pad` raises `ValueError` or `TypeError` as
appropriate; an invalid `display` or `margin` type raises
`TypeError`. Nothing gets a chance to fail silently or print
something misleading.

### `pad(value, spaces)`

Wraps a single `debug()` argument so it can have its own left-padding
without affecting any other argument in the same call. Works on both
unquoted variables and quoted, literal-print strings. `spaces` must
be a non-negative `int`.

### `debug_off()` / `debug_on()`

Module-level switch. `debug_off()` silences every `debug()` call in
the running process, regardless of that call's own `display` value.
`debug_on()` restores normal behavior.

## License

MIT