Skip to main content

A tool to format SQL code in Jupyter notebooks and Marimo notebooks.

Project description

sqlnbfmt

PyPI Tests License Python Versions

Quick start: pip install sqlnbfmt && sqlnbfmt notebook.ipynb

A SQL formatter for Jupyter Notebooks and Marimo notebooks. sqlnbfmt automatically formats SQL queries embedded in notebook cells — Python strings, SQL magic cells (%%sql), and Marimo mo.sql() calls — helping you maintain clean and consistent code.

Features

  • Zero-config: Works out of the box with sensible defaults — no config file needed
  • Jupyter + Marimo: Formats SQL in .ipynb notebooks and Marimo .py notebooks
  • Smart SQL Detection: Automatically identifies and formats SQL queries in code cells, magic SQL cells, and mo.sql() calls
  • AST-Powered: Uses Abstract Syntax Tree parsing for accurate SQL string identification
  • Safe Formatting: Preserves Python comments, query parameters (e.g., %s, ?), f-string placeholders, and SQL comments
  • CI-Friendly: --check mode exits non-zero when formatting is needed; --diff shows what would change
  • Skip Hints: Add # sqlnbfmt: skip to any cell to exclude it from formatting
  • Pre-commit Ready: Seamlessly integrates with pre-commit hooks
  • JupyterLab Plugin: Works with jupyterlab-code-formatter for interactive format-on-save
  • Lightweight: Only three runtime dependencies (sqlglot, nbformat, pyyaml)

Installation

pip install sqlnbfmt

Usage

Command Line

Format Jupyter notebooks:

sqlnbfmt path/to/your_notebook.ipynb

Format Marimo notebooks (or any Python file with SQL strings):

sqlnbfmt path/to/your_notebook.py

Mix both in a single invocation:

sqlnbfmt *.ipynb marimo_app.py

Check formatting without modifying files (useful in CI):

sqlnbfmt --check path/to/your_notebook.ipynb path/to/marimo_app.py

Show a diff of what would change:

sqlnbfmt --diff path/to/your_notebook.ipynb

Skipping Cells

Add a # sqlnbfmt: skip comment to skip formatting. In Jupyter notebooks this applies per-cell; in Python files it applies to the entire file.

# sqlnbfmt: skip
query = "select * from my_special_table where id = 1"

JupyterLab Integration

Format SQL cells interactively with jupyterlab-code-formatter:

  1. Install both packages:
pip install sqlnbfmt jupyterlab-code-formatter
  1. Register the formatter in ~/.jupyter/jupyter_notebook_config.py:
from sqlnbfmt.jupyterlab_integration import register
register()                       # or: register(dialect="postgres")
  1. In JupyterLab, use Edit > Format Cell or configure format-on-save in Settings > Code Formatter.

Pre-commit Integration

  1. Install pre-commit:
pip install pre-commit
  1. Add to .pre-commit-config.yaml:
repos:
  - repo: https://github.com/flyersworder/sqlnbfmt
    rev: v0.4.0
    hooks:
      - id: sqlnbfmt
        types: [jupyter]

To also format Marimo notebooks (Python files), add the Python hook:

      - id: sqlnbfmt-py
        files: '\.py$'  # optionally narrow with: files: 'marimo_.*\.py$'

All arguments are optional. To specify a dialect or custom config:

        args: [--dialect, postgres, --config, config.yaml]
  1. Install the hook:
pre-commit install
  1. (Optional) Run on all files:
pre-commit run --all-files

CI Usage

Use --check in GitHub Actions to enforce formatting:

- name: Check SQL notebook formatting
  run: |
    pip install sqlnbfmt
    sqlnbfmt --check **/*.ipynb
    sqlnbfmt --check marimo_*.py  # if using Marimo

Configuration

sqlnbfmt works without any configuration file. A config.yaml is only needed to override defaults.

Create a config.yaml file to customize formatting behavior. Here is a template.

Configuration Options

Option Description Default
sql_keywords SQL keywords to recognize and format Common SQL keywords
function_names Python functions containing SQL code read_sql, execute, etc.
sql_decorators Decorators indicating SQL code query, sql_query, etc.
single_line_threshold Maximum length before splitting SQL 80
indent_width Number of spaces for indentation 4

Examples

Jupyter Notebook

Before formatting:

execute_sql("""SELECT a.col1, b.col2 FROM table_a a JOIN table_b b ON a.id = b.a_id WHERE a.status = 'active' ORDER BY a.created_at DESC""")

After formatting:

execute_sql("""
SELECT
  a.col1,
  b.col2
FROM
  table_a AS a
JOIN
  table_b AS b
  ON a.id = b.a_id
WHERE
  a.status = 'active'
ORDER BY
  a.created_at DESC
""")

Marimo Notebook

Before formatting:

@app.cell
def _(mo):
    _df = mo.sql(f"select id, name from users where active = 1 order by name")
    return

After formatting:

@app.cell
def _(mo):
    _df = mo.sql(
    f"""
    SELECT
      id,
      name
    FROM users
    WHERE
      active = 1
    ORDER BY
      name
    """
)
    return

Troubleshooting

SQL not being formatted?

  • Ensure the string contains at least 2 SQL keywords or a recognizable pattern like SELECT...FROM
  • Check that the function name is in the recognized list (use --config to add custom ones)

Comments being modified?

  • Python comments (#) are preserved. SQL comments (--) inside strings are converted to /* */ block comments by sqlglot.

Pre-commit hook fails?

  • Make sure the rev matches the installed version
  • Run pre-commit autoupdate to get the latest version

Contributing

We welcome contributions! Here's how to get started:

  1. Clone the repository:
git clone https://github.com/flyersworder/sqlnbfmt.git
cd sqlnbfmt
  1. Use uv to sync the environment:
uv sync
source .venv/bin/activate  # On Windows: .venv\Scripts\activate
  1. Run tests:
pytest
  1. Add eval cases: see tests/eval/generate_fixtures.py for examples. Run python tests/eval/generate_fixtures.py to regenerate fixtures.

  2. Install dev pre-commit hooks:

pre-commit install

License

This project is licensed under the MIT License - see the LICENSE file for details.

Acknowledgments

  • sqlglot - SQL parsing and formatting engine
  • All contributors and early adopters who helped shape this tool

Made with ♥️ by the sqlnbfmt team

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sqlnbfmt-0.4.1.tar.gz (21.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sqlnbfmt-0.4.1-py3-none-any.whl (13.4 kB view details)

Uploaded Python 3

File details

Details for the file sqlnbfmt-0.4.1.tar.gz.

File metadata

  • Download URL: sqlnbfmt-0.4.1.tar.gz
  • Upload date:
  • Size: 21.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for sqlnbfmt-0.4.1.tar.gz
Algorithm Hash digest
SHA256 0aa1533bc0c174f38daa8fb8a42b699be5e91c3728566c06bf4666829c664dd9
MD5 c1c3e5fd97eec1cdfd320815e25ab045
BLAKE2b-256 3729bc35b55048864ec2f1eab3c827aecab645e6e62b5c6a47407c233b0b6a5c

See more details on using hashes here.

Provenance

The following attestation bundles were made for sqlnbfmt-0.4.1.tar.gz:

Publisher: ci-and-publish.yml on flyersworder/sqlnbfmt

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file sqlnbfmt-0.4.1-py3-none-any.whl.

File metadata

  • Download URL: sqlnbfmt-0.4.1-py3-none-any.whl
  • Upload date:
  • Size: 13.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for sqlnbfmt-0.4.1-py3-none-any.whl
Algorithm Hash digest
SHA256 52707aa495e9551a54d7acaf962ac087d51b75d6296eeb47a0835034553e2914
MD5 0bf9da4ce23ecc76d4ea00b24db6bb6c
BLAKE2b-256 4b9f401df8a6e9de1ce68cd54d4b327e4cdd583897d6164e21d44e7fa4381a6b

See more details on using hashes here.

Provenance

The following attestation bundles were made for sqlnbfmt-0.4.1-py3-none-any.whl:

Publisher: ci-and-publish.yml on flyersworder/sqlnbfmt

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page