|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Project overview |
| 6 | + |
| 7 | +sqlite_bro is a graphic SQLite browser/client implemented as a **single Python source file**: |
| 8 | +`sqlite_bro/sqlite_bro.py` (~2300 lines). Keeping the tool in one file is a deliberate design goal |
| 9 | +(see README.rst: "Easy to distribute : 1 Python source file") — it's meant to be copied to any |
| 10 | +machine and run directly with `python sqlite_bro.py`, or loaded remotely via |
| 11 | +`%load https://raw.githubusercontent.com/stonebig/sqlite_bro/master/sqlite_bro/sqlite_bro.py`. |
| 12 | +Avoid splitting it into multiple modules. |
| 13 | + |
| 14 | +Supports Python >= 3.3 and PyPy3. Uses Tkinter/ttk for the GUI (`from tkinter import *`, with a |
| 15 | +Python 2.7 fallback import path still present via `from __future__ import ...`). |
| 16 | + |
| 17 | +## Common commands |
| 18 | + |
| 19 | +Install in editable mode and run: |
| 20 | +``` |
| 21 | +pip install -e . |
| 22 | +sqlite_bro # launch the GUI |
| 23 | +sqlite_bro -h # see CLI options (-q/--quiet, -w/--wait, -db/--database, -sc/--scripts) |
| 24 | +python -m sqlite_bro.sqlite_bro # run directly without install |
| 25 | +``` |
| 26 | + |
| 27 | +Run tests (from repo root): |
| 28 | +``` |
| 29 | +pytest -v |
| 30 | +pytest -v sqlite_bro/tests/test_general.py::test_Basics # single test |
| 31 | +``` |
| 32 | + |
| 33 | +- `test_general.py` drives the real Tkinter GUI app (`App()`); on Linux CI this needs a virtual |
| 34 | + display (Xvfb) since there's no `DISPLAY` otherwise. |
| 35 | +- `test_general_no_gui.py` is the same test suite against `App(use_gui=False)`, exercising the |
| 36 | + command/query engine without Tkinter widgets. |
| 37 | + |
| 38 | +Lint (as run in CI, see `.github/workflows/tests.yml`): |
| 39 | +``` |
| 40 | +flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics |
| 41 | +flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics |
| 42 | +``` |
| 43 | + |
| 44 | +CI matrix: Python 3.8, 3.12, and pypy-3.10 (`.github/workflows/tests.yml`). `appveyor.yml` is legacy |
| 45 | +(Python 2.7/3.4, nosetests) and not the active CI. |
| 46 | + |
| 47 | +Build/publish uses `flit_core` (see `pyproject.toml`), not setuptools — version is read from |
| 48 | +`sqlite_bro/__init__.py`'s `__version__`. |
| 49 | + |
| 50 | +## Architecture |
| 51 | + |
| 52 | +Everything lives in `sqlite_bro/sqlite_bro.py`. The major pieces, in order of appearance: |
| 53 | + |
| 54 | +- **`App`** — the Tkinter application. Can run with or without a GUI (`use_gui` flag), which is |
| 55 | + what lets the query/script engine be tested headlessly. Owns the DB connection lifecycle |
| 56 | + (`new_db`, `open_db`, `backup_db`, `restore_db`, `attach_db`, `close_db`), the menu/toolbar, the |
| 57 | + font/tab UI (drag-reorder tabs via `btn_press`/`btn_Move`/`btn_release`), CSV import/export |
| 58 | + dialogs, and the DB-tree view (`feed_dbtree`). |
| 59 | +- **`App.create_and_add_results`** — the core script execution engine (the largest method, ~1000 |
| 60 | + lines). It splits a multi-statement script into individual instructions via |
| 61 | + `Baresql.get_sqlsplit`, then for each instruction dispatches on its shape: |
| 62 | + - `pydef ...` blocks → registers an embedded Python function as a SQLite function |
| 63 | + (`Baresql.createpydef`), so SQL can call user-defined Python (see the `.` command doc block in |
| 64 | + `_main()`'s `welcome_text` and the `py_hello`/`py_fib` examples). |
| 65 | + - `.` prefixed lines → **dot-commands** (sqlite3-CLI-style), parsed with `shlex.split`. Supported: |
| 66 | + `.backup`, `.cd`, `.dump`, `.excel`, `.headers`, `.import`, `.once`, `.open`, `.output`, |
| 67 | + `.print`, `.read`, `.restore`, `.separator`, `.shell`. This is what gives sqlite_bro its |
| 68 | + command-line scripting story independent of the GUI. |
| 69 | + - everything else → run as SQL against `Baresql.conn`, with results rendered into the tab's |
| 70 | + treeview (`NotebookForQueries.add_treeview`). |
| 71 | +- **`NotebookForQueries`** — manages the query-tab notebook: creating tabs (`new_query_tab`), |
| 72 | + attaching result treeviews to a tab, and sortable columns (`sortby`). |
| 73 | +- **`Baresql`** — thin wrapper around `sqlite3.Connection`. Handles: dump export tweaks |
| 74 | + (`iterdump`, forces a UTF-8 marker, toggles `PRAGMA foreign_keys` around dumps), SQL tokenizing |
| 75 | + and statement splitting (`get_tokens`, `get_sqlsplit` — this is what makes multi-statement |
| 76 | + scripts and dot-commands work inside one text blob), and CSV import/export row streaming |
| 77 | + (`insert_reader`, `export_writer`). |
| 78 | +- **`guess_csv`** / **`guess_encoding`** / **`guess_sql_creation`** — CSV format and file-encoding |
| 79 | + auto-detection used by import/export, independent of `Baresql`. |
| 80 | +- **`create_dialog`** — generic Tkinter modal-dialog builder reused by several features (rename |
| 81 | + tab, import CSV, export CSV, etc.) rather than each having bespoke dialog code. |
| 82 | +- **`_main()`** — CLI entry point (`sqlite_bro = "sqlite_bro.sqlite_bro:_main"` in |
| 83 | + `pyproject.toml`). Builds the built-in "Welcome" demo script (which doubles as living |
| 84 | + documentation of SQL features and dot-commands), parses argv with `argparse` (falls back to no |
| 85 | + CLI args pre-3.2), and boots `App`. |
| 86 | + |
| 87 | +When editing, keep in mind the GUI/no-GUI duality: any change to script/command execution |
| 88 | +(`create_and_add_results`, `Baresql`) must keep working under `use_gui=False`, since that's the |
| 89 | +path exercised by `test_general_no_gui.py` and by headless/CLI usage (`-q/--quiet`). |
0 commit comments