Metadata-Version: 2.4
Name: prttprint
Version: 2.0.2
Summary: PRTTprint is the best library to bring life to your terminal!
Author-email: Your Name <you@example.com>
License: MIT
Project-URL: Homepage, https://github.com/username/prttprint
Project-URL: Repository, https://github.com/username/prttprint
Project-URL: Issues, https://github.com/username/prttprint/issues
Project-URL: Changelog, https://github.com/username/prttprint/blob/main/CHANGELOG.md
Keywords: cli,terminal,colors,ansi,pretty,print,spinner,progress,tables,animation,sound,hud,console,text,formatting
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Terminals
Classifier: Topic :: Text Processing
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE.txt
Provides-Extra: full
Requires-Dist: wcwidth; extra == "full"
Dynamic: license-file

# 🎨 PRTTprint

### The best library to bring life to your terminal!

*Pretty Text Print — beautiful colors, sounds, spinners, tables and animations for the CLI.*

[![Python](https://img.shields.io/badge/python-3.10%2B-blue?logo=python&logoColor=white)](https://www.python.org/)
[![Version](https://img.shields.io/badge/version-2.0.1-brightgreen)](https://github.com/)
[![License](https://img.shields.io/badge/license-MIT-green)](LICENSE)
[![PyPI](https://img.shields.io/badge/pypi-prttprint-orange)](https://pypi.org/)

---

## What is PRTTprint

PRTTprint is a **single-file Python library** that turns boring console output into something beautiful, colorful and interactive. It's designed for CLI tools, scripts, games, and dashboards.

No pip install required — just drop `PRTTprint.py` into your project and import it. Everything is in one file.

### What it does

- **Colors** — 16 named colors, RGB, hex, gradients, auto-highlighting
- **Sounds** — 20 built-in sound effects, cross-platform
- **Spinners** — 55+ presets, smooth animations, no frame drift
- **Tables** — 6 border styles, alignment, highlight, footer, formatters
- **Progress** — 5 bar types, animated wave, 3-color gradient, multi-bar
- **HUD** — HP/MP/XP bars, status lines, live widgets
- **Animations** — glow, rain, fireworks, typewriter, stars, hearts
- **Interactive** — prompts, confirms, menus, wizards, arrow-key selection
- **Storage** — JSON store, key-value database, CSV helpers
- **Debug** — smart `dbg()`, colored traceback, timers, retries
- **Advanced** — keyboard handler, streams, dashboards, CLI parser
- **Meta** — built-in cheatsheet, docs generator, self-test, project scaffolder

### Design principles

1. **One file** — copy and use, no install
2. **Zero dependencies** — pure Python (except optional `wcwidth` for emoji)
3. **Works everywhere** — Windows, Linux, macOS
4. **No magic** — everything transparent, easy to modify
5. **Self-documenting** — `cheatsheet()`, `docs()`, `test_all()` inside

---

## Requirements

| Item | Minimum | Recommended |
|---|---|---|
| Python | 3.10 | 3.11+ |
| Terminal | any | Windows Terminal / iTerm / Kitty |
| Emoji | — | any Unicode support |
| wcwidth | optional | `pip install wcwidth` |

### Terminal support

Some features (spinners, progress bars, live widgets) require `\r` (carriage return) support:

| Terminal | Works | Notes |
|---|---|---|
| Windows Terminal | Yes | Full support |
| PowerShell 7 | Yes | Full support |
| Git Bash | Yes | Full support |
| iTerm / Kitty | Yes | Full support |
| PyCharm terminal | Yes | Full support |
| PyCharm Run | Partial | Enable `Emulate terminal in output console` |
| VS Code terminal | Yes | Full support |
| cmd.exe | Partial | Slow `\r`, may stutter |
| Jupyter | No | `\r` not supported |
| IDLE | No | No ANSI |

**For best experience:** use Windows Terminal, iTerm, Kitty, or Git Bash. In PyCharm — enable "Emulate terminal" in run configuration.

---

## Installation

### Option 1: From PyPI

```bash
pip install prttprint
```

Then:

```python
from PRTTprint import *
```

### Option 2: From source

```bash
git clone https://github.com/username/prttprint
cd prttprint
pip install -e .
```

### Option 3: Single file (recommended)

Just copy `PRTTprint.py` into your project folder:

```
myproject/
├── PRTTprint.py
├── main.py
└── ...
```

Then in `main.py`:

```python
from PRTTprint import *
```

That's it. No installation, no dependencies.

### Optional: wcwidth

For proper table alignment with emoji and CJK characters:

```bash
pip install wcwidth
```

Without it, everything works — but tables with emoji may break alignment.

---

## Quick Start

Here's a minimal working example:

```python
from PRTTprint import *

# 1. Initialize (once at start)
init()

# 2. Use the library
ok('Operation completed')
info('Loaded 42 records')
warn('Port busy, using 8080')
err('Failed to connect')

# 3. Spinner with a task
step_run('Loading config', load_config)

# 4. Pretty table
table([
    {'name': 'Ann',   'score': 1500},
    {'name': 'Boris', 'score': 900},
], style='double')

# 5. Sound
sound('success')
```

That's the entire workflow. Now let's go deeper.

---

## Core Basics — the foundation

> **This is the core of the library. Everything else is built on top of these 8 concepts.**

If you read only one section of this README — read this one. It will teach you 90% of what you need to build a beautiful CLI.

### Concept 1: Initialization

**Every program starts with `init()`.** It sets up colors, sounds, spinner defaults, and prints a small "ready" state.

```python
from PRTTprint import *

init()
```

**What it does:**

- Enables/disables colors based on terminal support
- Enables/disables sounds
- Sets default spinner color, speed, and preset
- Configures the icons for `ok`, `info`, `warn`, `err`, `debug`

**Full form:**

```python
init(
    colors=True,                 # enable/disable colors
    sounds=True,                 # enable/disable sounds
    spinner_color='cyan',        # default spinner color
    spinner_show_time=False,     # show seconds in spinner
    spinner_preset=None,         # None = random from `kind`
    spinner_kind='fancy',        # category for random picker
    spinner_speed=0.08,          # seconds per frame
    wcwidth_hint=True,           # warn if wcwidth missing
    level_styles={               # customize icons and colors
        'ok':    ('OK', 'green',  'bold'),
        'info':  ('i',  'cyan',   ''),
        'warn':  ('!',  'yellow', 'bold'),
        'err':   ('X',  'red',    'bold'),
        'debug': ('·',  'gray',   'dim'),
    },
)
```

**All parameters are optional.** The simple `init()` is enough for most cases.

**If you want a banner too** — use `bootstrap('MY APP')`. It calls `init()` and then prints a banner:

```python
bootstrap('MY TOOL v1.0', spinner_color='yellow')
```

**Rule of thumb:**

- `init()` — set up only, no output
- `bootstrap('NAME')` — set up + big banner
- Then use the library

### Concept 2: Print with levels

The library has **5 print-level functions**. They look like normal `print()` but with icons, colors, and auto-highlighting.

```python
ok('Everything worked')          # ✓ green — success
info('Loaded 42 records')        # i cyan — information
warn('Port busy')                # ! yellow — warning
err('Connection failed')         # X red — error
debug('x=42, y=[1,2,3]')         # · gray — debug
```

**Each function:**

| Function | Icon | Color | Sound | Stream |
|---|---|---|---|---|
| `ok()` | ✓ | green | Yes | stdout |
| `info()` | ℹ | cyan | No | stdout |
| `warn()` | ⚠ | yellow | Yes | stdout |
| `err()` | ✗ | red | Yes | stderr |
| `debug()` | · | gray | No | stdout |

**Auto-highlighting** — каждая функция ищет ключевые слова в тексте и подсвечивает их:

```python
err('File not found')      # "not found" highlighted red
warn('Low disk space')     # "low" highlighted yellow
ok('Build succeeded')      # "succeeded" highlighted green
```

**When to use what:**

- `ok()` — операция завершилась успешно
- `info()` — просто сообщение пользователю
- `warn()` — что-то не так, но не критично
- `err()` — ошибка (идёт в stderr, можно перенаправить)
- `debug()` — отладочный вывод (можно отключить)

### Concept 3: Print with colors

**The main color function is `c()`.** It returns a string with ANSI codes:

```python
c('text', color='red', bold=True)
```

**Shortcut — print with color directly:**

```python
cprint('bold red', color='red', bold=True)
cprint('hex color', color='#ff8800')
cprint('RGB', color=(100, 200, 255))
cprint('badge', color='black', bg='bright_yellow')
cprint('italic underline', italic=True, underline=True)
```

**Named colors available:**

```
black       red         green       yellow
blue        magenta     cyan        white
gray        grey
bright_red  bright_green  bright_yellow  bright_blue
bright_magenta  bright_cyan
```

**RGB and hex:**

```python
c('text', color=(255, 100, 100))     # RGB tuple
c('text', color='#ff6444')           # hex
c('text', color='#f84')              # 3-digit hex
```

**Backgrounds:**

```python
c('text', color='white', bg='blue')
c('text', color='black', bg='bright_yellow')
```

**Styles:**

```python
c('text', bold=True)
c('text', italic=True)
c('text', underline=True)
c('text', dim=True)
# Or as positional:
c('text', 'red', 'bold', 'underline')
```

**Gradients:**

```python
gprint('2-color gradient', 'red', 'blue')       # print
gprint3('3-color gradient', 'red', 'yellow', 'green')

# As strings:
gradient('text', 'red', 'blue')
gradient3('text', 'red', 'yellow', 'green')
```

**Shimmering text (animated):**

```python
glow_print('★ SHIMMERING ★', 'cyan', 'magenta', duration=1.5)
glow_print3('★ 3 COLORS ★', 'red', 'yellow', 'green', duration=2)
```

### Concept 4: Spinners and tasks — one line

**The most used feature of PRTTprint** is `step_run()`. It runs a function with a spinner and prints ✓ or ✗ when done.

```python
step_run('Loading config', load_config)
```

**Output:**

```
⠋ Loading config
⠙ Loading config
⠹ Loading config
...
✓ Loading config (0.42s)
```

**Multiple steps in one call:**

```python
step_run(
    'Downloading', download,
    'Extracting',  extract,
    'Installing',  install,
)
```

**Output:**

```
✓ Downloading (1.20s)
✓ Extracting (0.80s)
✓ Installing (0.50s)
```

**With function arguments:**

```python
step_run('Waiting for network', time.sleep, 2)
```

**Handling errors:**

```python
step_run('Risky operation', risky_fn)
# If risky_fn raises — prints ✗ with error and stops
```

**Shortcuts:**

```python
do('Computing', sum, [1, 2, 3])    # same as step_run
pause('Waiting', 2)                 # step_run with time.sleep
wait(5, 'Please wait')              # simple countdown, no spinner
```

**With-block spinner (for custom code):**

```python
with spinner('Loading', preset='circle'):
    data = fetch()
    process(data)
```

**F-string spinner (for interactive use):**

```python
print(f'{spin("Downloading")}', end='')
time.sleep(3)
spin_done()

# On failure:
print(f'{spin("Checking")}', end='')
time.sleep(2)
spin_fail('checksum mismatch')
```

**Spinner presets** — 55+ presets in categories:

- **Dots** — `dots`, `dots_dense`, `smooth`, `pulse`, `bars`, `grow`
- **Circles** — `circle`, `circle_thin`, `circle_dot`, `clock`, `breathe`
- **Emoji** — `moon`, `rocket`, `sparkle`, `star`, `hearts`, `music`
- **Arrows** — `arrow`, `compass`, `radar`, `gauge`
- **ASCII** — `line`, `ascii_dots`, `ascii_light`

**See all:**

```python
list(SPINNER_FRAMES.keys())
```

**Random preset from a category:**

```python
pick_preset('circle')   # random circle preset
```

**Default preset for all spinners:**

```python
init(spinner_preset='dots_dense')
```

### Concept 5: Tables

**Basic table:**

```python
table(users, style='double', highlight=lambda r: r['age'] > 30)
```

**Output:**

```
╔═══════╦═════╦════════════════╗
║ name  ║ age ║ city           ║
╠═══════╬═════╬════════════════╣
║ Ann   ║ 25  ║ Moscow         ║
║ Boris ║ 30  ║ London         ║
╚═══════╩═════╩════════════════╝
```

**Fluent API:**

```python
(Table(users)
    .style('double')
    .align('age', 'center')
    .format('score', lambda v: f'{v:,}')
    .highlight(lambda r: r['status'] == 'vip')
    .footer({'name': 'Total', 'score': 5000})
    .show())
```

**Styles:** `simple`, `rounded`, `double`, `ascii`, `markdown`, `none`.

**Full parameters:**

```python
table(
    rows,                           # list of dicts
    headers=['name', 'age'],        # optional
    style='rounded',                # border style
    align={'age': 'center'},        # per-column alignment
    colors={'header': 'cyan', 'zebra': 'gray'},
    highlight=lambda r: r['age'] > 30,
    formatters={'score': lambda v: f'{v:,}'},
    footer={'name': 'Total', 'score': 5000},
    max_width=30,                   # truncate long cells
    auto_width=True,                # auto-fit to terminal
    padding=1,                      # cell padding
)
```

**From CSV:**

```python
table_from_csv('users.csv', style='double')
```

### Concept 6: Bars and HUD

**Simple bar:**

```python
bar(75, 100, width=30, color='green')          # returns string
print(f'HP [{bar(75, 100, 30)}] 75/100')
```

**HP/MP/XP bars with auto color:**

```python
hp_bar(75, 100, 30)     # green > 60%, yellow > 30%, red < 30%
mp_bar(30, 50, 30)      # blue
xp_bar(45, 200, 30)     # yellow
```

**3-color gradient bar:**

```python
bar3(75, 100, 30, 'red', 'yellow', 'green')
```

**HUD — all-in-one:**

```python
hud({'HP': (75, 100), 'MP': (30, 50), 'XP': (45, 200)})
```

**Output:**

```
HP [███████████████░░░░░░] 75/100  MP [████████░░░░░░░░░░░░] 30/50  XP [█████░░░░░░░░░░░░░] 45/200
```

**Status line:**

```python
status_line({'City': 'Moscow', 'Temp': '+15°C'})
```

**Progress bars (loop):**

```python
# Basic
for x in progress(range(100), prefix='Loading'):
    time.sleep(0.01)

# 3-color
for x in progress3(range(100), colors=('red', 'yellow', 'green')):
    ...

# Manual
bar = PBar(100, prefix='Loading')
for i in range(1, 101):
    bar.update(i)
bar.close()

# Animated wave
bw = bar_wave(100, prefix='Wave', color='bright_cyan')
for i in range(1, 101):
    bw.update(i)
bw.close()

# Circle
cb = circle_bar(100, prefix='Loading', width=15)
for i in range(1, 101):
    cb.update(i)
cb.close()
```

### Concept 7: Sounds

**20 built-in effects:**

```python
sound('click')       # short click
sound('ok')          # success
sound('error')       # error
sound('level_up')    # level-up jingle
sound('coin')        # coin
sound('explosion')   # big boom
sound('hit')         # hit
sound('game_over')   # game over
```

**Full list:**

```
click      tick      type      toggle    switch
ok         success   done      notify    message
error      fail      denied    warning
hit        explosion coin      level_up  game_over
```

**Repeat:**

```python
sound('coin', repeat=3)
```

**Custom tone:**

```python
sound(freq=880, duration=200)   # 880 Hz, 200 ms
```

**List all:**

```python
sound_list()
```

**Disable globally:**

```python
sound_off()
init(sounds=False)
```

**Enable again:**

```python
sound_on()
```

**Platform notes:**

- **Windows** — uses `winsound.Beep` (real tones)
- **Linux/macOS** — falls back to `\a` (system beep)

### Concept 8: Everything else

Once you know the above, you can build almost anything. But PRTTprint has much more:

**Storage** — persistent key-value storage, JSON, CSV:

```python
db = Store('config.json')
db.set('theme', 'dark')
```

**Animations** — typewriter, glow, rain, stars, hearts, fireworks:

```python
typewriter('Hello!', delay=0.03)
rain('★☆✦', count=20, duration=2)
fireworks(3)
```

**Interactive** — prompts, confirms, wizards:

```python
name = ask('Name', 'Ann')
if confirm('Continue?'): ...
```

**Advanced** — keyboard, streams, dashboards, parsers:

```python
with Dashboard() as db:
    db.panel('CPU', lambda: chart(cpu_vals))
```

**Debug** — smart prints, timers, retries:

```python
dbg(x, y, name)
@retry(times=3, delay=1.0)
def fetch(): ...
```

**Meta** — cheatsheet, docs, tests:

```python
cheatsheet()      # interactive help
test_all()        # check everything works
```

All of these are covered in the **Full Feature Reference** below.

---

## Cheatsheet — your built-in help

> **This is the single most important tool in PRTTprint.**

`cheatsheet()` is a **built-in interactive reference** that shows every function with examples, grouped by topic. You never have to Google the API again.

### Why use it

- **No Googling** — everything in your terminal
- **Copy-paste ready** — each entry is a working example
- **Grouped by topic** — find what you need fast
- **Works in REPL** — try, then use, immediately
- **Always up to date** — since it lives in the same file as the code

### How to use it

**Step 1. Import and call:**

```python
from PRTTprint import *
cheatsheet()
```

**What you see:**

```
PRTTprint v2.0.1 — cheatsheet

Sections:
  colors         — Colors and gradients
  spinner        — Spinners
  bars           — Progress and bars
  tables         — Tables
  sound          — Sounds
  input          — Interactive
  frames         — Frames and decorations
  animations     — Animations
  data           — Data
  advanced       — Advanced
  misc           — Miscellaneous

Use: cheatsheet("spinner") or cheatsheet(search="table")
```

**Step 2. Pick a section:**

```python
cheatsheet('spinner')
```

**What you see:**

```
> Spinners
----------------------------------------------------
  with spinner(text, preset=..)
      with spinner('Loading', preset='circle'): ...
  spin / spin_done / spin_fail
      print(f'{spin("X")}', end=''); spin_done()
  step_run(text, fn, ...)
      step_run('A', f1, 'B', f2)
  do(text, fn) / pause(text, sec)
      do('Computing', sum, [1,2,3]); pause('Wait', 2)
  SPINNER_FRAMES.keys()
      list(SPINNER_FRAMES.keys())  # 55+ presets
  pick_preset(kind)
      pick_preset('circle')
```

**Step 3. Copy the example:**

```python
step_run('Loading config', load_config)
```

Done. No docs, no Google, no guesswork.

### All sections

| Section | What it shows |
|---|---|
| `colors` | c, cprint, gprint, gprint3, ok/info/warn/err, glow_print |
| `spinner` | spinner, spin, spin_done, step_run, do, pause, presets |
| `bars` | progress, progress3, PBar, bar_wave, circle_bar, bar, bar3, hud |
| `tables` | table, Table, table_from_csv, highlight, footer |
| `sound` | sound + 20 built-in effects |
| `input` | ask, confirm, prompt, password, Ask, wizard, spinner_selection |
| `frames` | box, banner, kv, box_center, notify_center, section |
| `animations` | typewriter, glow, rain, stars_rain, fireworks |
| `data` | tree, diff, chart, columns, chunk, pick, uniq |
| `advanced` | Keyboard, Stream, Dashboard, Parser, Log |
| `misc` | human_time, timer, retry, dbg, dice, slugify |

### Search across all sections

```python
cheatsheet(search='table')
```

Finds **everything** containing "table" — in any section.

**Output:**

```
> Tables
----------------------------------------------------
  table(rows, style='rounded')
      table(users, style='double')
  Table(rows).style().show()
      Table(users).style('double').show()
  ...

> Storage
----------------------------------------------------
  table_from_csv(path)
      table_from_csv('users.csv')
  ...
```

### Dump everything

```python
cheatsheet('*')
```

Prints all sections at once — useful for saving to a file:

```bash
python -c "from PRTTprint import *; cheatsheet('*')" > cheatsheet.txt
```

### Cheatsheet vs docs

| | `cheatsheet()` | `docs()` |
|---|---|---|
| Format | Terminal (ANSI) | Markdown file |
| Length | Brief (one line per function) | Full (with examples) |
| Purpose | Quick lookup during coding | Publish / share / wiki |
| When to use | While developing | For README, GitHub, wiki |
| Output | Colored text | Plain `.md` file |

**Rule of thumb:**

- **Quick glance** while coding → `cheatsheet('spinner')`
- **Full documentation** for team → `docs('docs/API.md')`

### Try it in your next project

Instead of opening documentation in browser, just type in Python:

```python
>>> cheatsheet('bars')
```

**You'll see the API in a second** — right where you write code.

---

## Storage — the foundation for state

> **Everything that needs to survive between runs.**

PRTTprint has three levels of storage, depending on your needs.

### Level 1: Store — key-value storage on JSON

**The main tool.** Simple, persistent, transparent.

```python
from PRTTprint import *

db = Store('settings.json')
```

**Store saves everything to a JSON file** that you can open in any editor.

**Write:**

```python
db.set('theme', 'dark')             # single key
db.update(volume=80, lang='ru')     # multiple keys
```

**Read:**

```python
db.get('theme')                     # 'dark'
db.get('volume')                    # 80
db.get('missing', 'default')        # 'default' — no KeyError
db.keys()                           # ['theme', 'volume', 'lang']
'volume' in db                      # True
db['theme']                         # 'dark' — dict-like
```

**Delete:**

```python
db.delete('volume')                 # remove one key
db.clear()                          # remove all keys
```

**History tracking** — every change is remembered:

```python
db.set('theme', 'dark')
db.set('theme', 'light')
db.set('theme', 'auto')

db.history('theme')                 # ['dark', 'light', 'auto']
```

**Full API:**

| Method | Description |
|---|---|
| `db.set(key, value)` | Save a value |
| `db.get(key, default)` | Read a value |
| `db.delete(key)` | Remove a key |
| `db.update(**kwargs)` | Bulk update |
| `db.keys()` | List all keys |
| `db.clear()` | Remove everything |
| `db.history(key)` | Get change history |
| `key in db` | Check existence |
| `db[key]` / `db[key] = v` | Dict-like access |
| `repr(db)` | `Store(path, N keys)` |

**Where stored:** `Store('settings.json')` writes to a real JSON file in the current directory.

### Level 2: Raw JSON helpers

**When you don't need a key-value store** — just save/load one object.

```python
save_json('data.json', {'name': 'Ann', 'age': 25})
data = load_json('data.json')
print(data)   # {'name': 'Ann', 'age': 25}
```

**Features:**

- Creates parent directories automatically
- `ensure_ascii=False` — Cyrillic stays Cyrillic
- `default=str` — non-serializable objects become strings
- Safe load — no exception if file missing

**Safe load with default:**

```python
data = load_json('missing.json', default={'empty': True})
# No exception — returns {'empty': True}
```

**Useful for:**

- Config files
- Save/load one object
- API responses
- Cached data

### Level 3: CSV helpers

**For tabular data.**

```python
# Read
rows = read_csv('users.csv')
# [{'name': 'Ann', 'age': '25'}, ...]

# Write
write_csv('out.csv', [
    {'name': 'Ann', 'score': 1500},
    {'name': 'Boris', 'score': 900},
])

# Print directly as table
table_from_csv('users.csv', style='double')
```

### When to use what

| Task | Best tool |
|---|---|
| Simple config file | `Store` |
| Save/load one object | `save_json` / `load_json` |
| Tabular data | `read_csv` / `write_csv` |
| Print CSV as table | `table_from_csv` |
| Environment variables | `env()` / `env_all()` |

### Example 1: Persistent app settings

**Save user preferences between runs:**

```python
from PRTTprint import *

db = Store('config.json')

# Load with defaults
theme = db.get('theme', 'dark')
volume = db.get('volume', 80)
lang = db.get('lang', 'en')

info(f'Theme: {theme}, Volume: {volume}, Lang: {lang}')

# Ask user
if confirm('Change theme?', default=False):
    new_theme = prompt_choice('New theme', ['dark', 'light', 'auto'])
    db.set('theme', new_theme)
    ok(f'Theme set to {new_theme}')
```

### Example 2: Simple game save

**Save and load game state:**

```python
save = Store('save.json')

# Save
save.set('level', 3)
save.set('score', 1500)
save.update(hp=80, mp=45, gold=250)

# Load
level = save.get('level', 1)
score = save.get('score', 0)
hp = save.get('hp', 100)

print(f'Level {level}, score {score}, HP {hp}')
```

### Example 3: History tracking

**Track changes to a value:**

```python
db = Store('history.json')

db.set('status', 'starting')
db.set('status', 'running')
db.set('status', 'stopping')
db.set('status', 'stopped')

print(db.history('status'))
# ['starting', 'running', 'stopping', 'stopped']
```

**Useful for:**

- Undo functionality
- Debugging state changes
- Audit trails

---

## Documentation Generator

Need a full markdown reference? Use `docs()`:

```python
docs()                # prints markdown to stdout
docs('PRTTprint.md')  # saves to file
```

Generates a complete documentation from the same data as `cheatsheet()`.

**Difference from cheatsheet:**

| | `cheatsheet()` | `docs()` |
|---|---|---|
| Format | Terminal (ANSI) | Markdown file |
| Length | Brief | Full with examples |
| Purpose | Quick lookup | Publish / share |
| When | During development | For README, GitHub, wiki |
| Output | Colored text | Plain `.md` |

**Rule of thumb:**

- Quick glance → `cheatsheet('spinner')`
- Save for team → `docs('docs/API.md')`

---

## Self-Test

Check that everything works:

```python
test_all()
```

**Output:**

```
=== Smoke test PRTTprint ===
  OK c
  OK ok
  OK gradient
  OK gradient3
  OK bar
  OK bar3
  OK hp_bar
  OK human_time
  OK human_size
  OK money
  OK plural
  OK chunk
  OK pick
  OK uniq
  OK slugify
  OK clamp
  OK flatten
  OK dice
  OK chance
  OK sound

All 20 tests passed
```

Useful after installation or updates.

---

## Full Feature Reference

### Colors and gradients

```python
cprint('bold red', color='red', bold=True)
cprint('hex', color='#ff8800')
cprint('RGB', color=(100, 200, 255))
cprint('badge', color='black', bg='bright_yellow')

gprint('2-color', 'red', 'blue')
gprint3('3-color', 'red', 'yellow', 'green')
glow_print('SHIMMERING', duration=1.5)
glow_print3('3 COLORS', 'cyan', 'magenta', 'yellow', duration=2)
```

### Sounds — 20 effects

```python
sound('click')
sound('ok')
sound('error')
sound('level_up')
sound('coin', repeat=3)
sound(freq=880, duration=200)

sound_list()         # list all
sound_off()          # disable all
```

### Spinners

```python
# With-block
with spinner('Loading', preset='circle'):
    time.sleep(3)

# F-string
print(f'{spin("Loading")}', end='')
time.sleep(3)
spin_done()

# step_run
step_run('Loading config', load_config)

# Multiple steps
step_run(
    'Downloading', download,
    'Extracting',  extract,
    'Installing',  install,
)

# Pause
pause('Waiting for network', 2)

# Shortcuts
do('Computing', sum, [1, 2, 3])
wait(5, 'Please wait')
```

### Tables

```python
# Basic
table(users, style='double', highlight=lambda r: r['age'] > 30)

# Fluent
(Table(users)
    .style('double')
    .align('age', 'center')
    .format('score', lambda v: f'{v:,}')
    .highlight(lambda r: r['status'] == 'vip')
    .footer({'name': 'Total', 'score': 5000})
    .show())
```

### Progress and bars

```python
# Progress
for x in progress(range(100), prefix='Loading'):
    time.sleep(0.01)

# 3-color
for x in progress3(range(100), colors=('red', 'yellow', 'green')):
    ...

# Multiple bars
with progress_multi(['Download', 'Extract', 'Install']) as pm:
    pm.update('Download', 50)
    pm.update('Extract', 30)

# Animated wave
bar = bar_wave(100, prefix='Wave')
for i in range(1, 101):
    bar.update(i); time.sleep(0.03)
bar.close()

# Circle
cb = circle_bar(100, prefix='Loading', width=15)
for i in range(1, 101):
    cb.update(i)
cb.close()

# HUD
hud({'HP': (75, 100), 'MP': (30, 50)})
```

### Animations

```python
typewriter('Hello!', delay=0.03)
animate('Loading', 2)
glow('LOADING')
rain('***', count=20, duration=2)
rain_line('*', width=40, cycles=2)
rain_multi('*', cols=8, height=5, duration=2)
stars_rain(15)
hearts_rain(10)
fireworks(3)
```

### Frames and decorations

```python
box('Message', style='rounded', color='cyan', title='Info')
banner('MY APP', style='double')
kv({'Host': 'localhost', 'Port': 5432})
box_center(['Line 1', 'Line 2'], style='double')
notify_center('Saved!', level='ok', duration=1.5)
section('Chapter 1')
double_rule()
rainbow_rule()
```

### Interactive

```python
name = ask('Name', 'Ann')
if confirm('Are you sure?', default=False): ...
pwd = password('Password')

idx = spinner_selection('What to do?', ['Create', 'Open', 'Exit'])

answers = (Ask()
    .text('Name', 'Ann')
    .choice('Class', ['Warrior', 'Mage'])
    .confirm('Start?')
    .number('Age', 25, min=1, max=120)
    .run())

config = wizard([
    ('Project name', 'text',    {'default': 'myapp'}),
    ('Port',         'number',  {'default': 8080, 'min': 1024, 'max': 65535}),
    ('Debug',        'confirm', {'default': False}),
])
```

### Advanced

```python
# Keyboard handler
kb = Keyboard()
kb.on('q', lambda: exit_game())
kb.on('space', toggle_pause)
kb.start()

# Stream processing
with Stream('Reading logs') as s:
    for line in open('app.log'):
        s.update(line)
        if 'ERROR' in line:
            s.warn(line)

# Multi-panel dashboard
with Dashboard(refresh=0.5) as db:
    db.panel('CPU', lambda: chart(cpu_vals))
    db.panel('RAM', lambda: chart(ram_vals))
    time.sleep(5)

# CLI parser
cli = Parser('mytool')
cli.flag('--verbose', '-v')
cli.option('--output',
