sqlnbfmt 0.4.0__tar.gz → 0.4.2__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.
Files changed (84) hide show
  1. sqlnbfmt-0.4.2/.github/workflows/ci-and-publish.yml +42 -0
  2. sqlnbfmt-0.4.2/.gitignore +163 -0
  3. sqlnbfmt-0.4.2/.pre-commit-config.yaml +41 -0
  4. sqlnbfmt-0.4.2/.pre-commit-hooks.yaml +35 -0
  5. sqlnbfmt-0.4.2/.python-version +1 -0
  6. sqlnbfmt-0.4.2/CHANGELOG.md +143 -0
  7. {sqlnbfmt-0.4.0/sqlnbfmt.egg-info → sqlnbfmt-0.4.2}/PKG-INFO +25 -9
  8. {sqlnbfmt-0.4.0 → sqlnbfmt-0.4.2}/README.md +17 -0
  9. sqlnbfmt-0.4.2/config.yaml +49 -0
  10. sqlnbfmt-0.4.2/jupyter-config/sqlnbfmt.json +7 -0
  11. {sqlnbfmt-0.4.0 → sqlnbfmt-0.4.2}/pyproject.toml +6 -6
  12. sqlnbfmt-0.4.2/sqlnbfmt/__init__.py +15 -0
  13. {sqlnbfmt-0.4.0 → sqlnbfmt-0.4.2}/sqlnbfmt/formatter.py +89 -92
  14. sqlnbfmt-0.4.2/sqlnbfmt/jupyterlab_integration.py +74 -0
  15. sqlnbfmt-0.4.2/tests/eval/README.md +103 -0
  16. sqlnbfmt-0.4.2/tests/eval/basic_select/expected.ipynb +26 -0
  17. sqlnbfmt-0.4.2/tests/eval/basic_select/input.ipynb +17 -0
  18. sqlnbfmt-0.4.2/tests/eval/case_expression/expected.ipynb +22 -0
  19. sqlnbfmt-0.4.2/tests/eval/case_expression/input.ipynb +17 -0
  20. sqlnbfmt-0.4.2/tests/eval/comment_preservation/expected.ipynb +27 -0
  21. sqlnbfmt-0.4.2/tests/eval/comment_preservation/input.ipynb +19 -0
  22. sqlnbfmt-0.4.2/tests/eval/cte/expected.ipynb +29 -0
  23. sqlnbfmt-0.4.2/tests/eval/cte/input.ipynb +17 -0
  24. sqlnbfmt-0.4.2/tests/eval/fstring_variables/expected.ipynb +42 -0
  25. sqlnbfmt-0.4.2/tests/eval/fstring_variables/input.ipynb +30 -0
  26. sqlnbfmt-0.4.2/tests/eval/generate_fixtures.py +306 -0
  27. sqlnbfmt-0.4.2/tests/eval/group_by_having/expected.ipynb +29 -0
  28. sqlnbfmt-0.4.2/tests/eval/group_by_having/input.ipynb +17 -0
  29. sqlnbfmt-0.4.2/tests/eval/idempotency/expected.ipynb +24 -0
  30. sqlnbfmt-0.4.2/tests/eval/idempotency/input.ipynb +24 -0
  31. sqlnbfmt-0.4.2/tests/eval/in_function_sql/expected.ipynb +44 -0
  32. sqlnbfmt-0.4.2/tests/eval/in_function_sql/input.ipynb +27 -0
  33. sqlnbfmt-0.4.2/tests/eval/joins/expected.ipynb +27 -0
  34. sqlnbfmt-0.4.2/tests/eval/joins/input.ipynb +17 -0
  35. sqlnbfmt-0.4.2/tests/eval/magic_commands/expected.ipynb +50 -0
  36. sqlnbfmt-0.4.2/tests/eval/magic_commands/input.ipynb +40 -0
  37. sqlnbfmt-0.4.2/tests/eval/marimo_basic_sql/expected.py +31 -0
  38. sqlnbfmt-0.4.2/tests/eval/marimo_basic_sql/input.py +20 -0
  39. sqlnbfmt-0.4.2/tests/eval/marimo_comment_preservation/expected.py +50 -0
  40. sqlnbfmt-0.4.2/tests/eval/marimo_comment_preservation/input.py +30 -0
  41. sqlnbfmt-0.4.2/tests/eval/marimo_complex_sql/expected.py +63 -0
  42. sqlnbfmt-0.4.2/tests/eval/marimo_complex_sql/input.py +27 -0
  43. sqlnbfmt-0.4.2/tests/eval/marimo_fstring_interpolation/expected.py +47 -0
  44. sqlnbfmt-0.4.2/tests/eval/marimo_fstring_interpolation/input.py +28 -0
  45. sqlnbfmt-0.4.2/tests/eval/marimo_idempotency/expected.py +31 -0
  46. sqlnbfmt-0.4.2/tests/eval/marimo_idempotency/input.py +31 -0
  47. sqlnbfmt-0.4.2/tests/eval/marimo_multi_cell_mixed/expected.py +66 -0
  48. sqlnbfmt-0.4.2/tests/eval/marimo_multi_cell_mixed/input.py +44 -0
  49. sqlnbfmt-0.4.2/tests/eval/marimo_multi_statement/expected.py +34 -0
  50. sqlnbfmt-0.4.2/tests/eval/marimo_multi_statement/input.py +20 -0
  51. sqlnbfmt-0.4.2/tests/eval/marimo_non_sql_unchanged/expected.py +39 -0
  52. sqlnbfmt-0.4.2/tests/eval/marimo_non_sql_unchanged/input.py +39 -0
  53. sqlnbfmt-0.4.2/tests/eval/marimo_skip_hint/expected.py +21 -0
  54. sqlnbfmt-0.4.2/tests/eval/marimo_skip_hint/input.py +21 -0
  55. sqlnbfmt-0.4.2/tests/eval/multi_cell_mixed/expected.ipynb +76 -0
  56. sqlnbfmt-0.4.2/tests/eval/multi_cell_mixed/input.ipynb +65 -0
  57. sqlnbfmt-0.4.2/tests/eval/multi_statement/expected.ipynb +29 -0
  58. sqlnbfmt-0.4.2/tests/eval/multi_statement/input.ipynb +18 -0
  59. sqlnbfmt-0.4.2/tests/eval/non_sql_unchanged/expected.ipynb +44 -0
  60. sqlnbfmt-0.4.2/tests/eval/non_sql_unchanged/input.ipynb +44 -0
  61. sqlnbfmt-0.4.2/tests/eval/skip_hint/expected.ipynb +35 -0
  62. sqlnbfmt-0.4.2/tests/eval/skip_hint/input.ipynb +28 -0
  63. sqlnbfmt-0.4.2/tests/eval/subquery/expected.ipynb +29 -0
  64. sqlnbfmt-0.4.2/tests/eval/subquery/input.ipynb +17 -0
  65. sqlnbfmt-0.4.2/tests/eval/union/expected.ipynb +31 -0
  66. sqlnbfmt-0.4.2/tests/eval/union/input.ipynb +17 -0
  67. sqlnbfmt-0.4.2/tests/eval/window_function/expected.ipynb +23 -0
  68. sqlnbfmt-0.4.2/tests/eval/window_function/input.ipynb +17 -0
  69. {sqlnbfmt-0.4.0 → sqlnbfmt-0.4.2}/tests/test_formatter.py +53 -1
  70. sqlnbfmt-0.4.2/tests/test_jupyterlab_integration.py +76 -0
  71. sqlnbfmt-0.4.2/tests/test_notebook.ipynb +358 -0
  72. sqlnbfmt-0.4.2/tests/test_notebook_copy.ipynb +311 -0
  73. sqlnbfmt-0.4.2/uv.lock +455 -0
  74. sqlnbfmt-0.4.0/PKG-INFO +0 -270
  75. sqlnbfmt-0.4.0/setup.cfg +0 -4
  76. sqlnbfmt-0.4.0/sqlnbfmt.egg-info/SOURCES.txt +0 -14
  77. sqlnbfmt-0.4.0/sqlnbfmt.egg-info/dependency_links.txt +0 -1
  78. sqlnbfmt-0.4.0/sqlnbfmt.egg-info/entry_points.txt +0 -2
  79. sqlnbfmt-0.4.0/sqlnbfmt.egg-info/requires.txt +0 -3
  80. sqlnbfmt-0.4.0/sqlnbfmt.egg-info/top_level.txt +0 -1
  81. {sqlnbfmt-0.4.0 → sqlnbfmt-0.4.2}/LICENSE +0 -0
  82. {sqlnbfmt-0.4.0/sqlnbfmt → sqlnbfmt-0.4.2/tests}/__init__.py +0 -0
  83. {sqlnbfmt-0.4.0 → sqlnbfmt-0.4.2}/tests/test_eval.py +0 -0
  84. {sqlnbfmt-0.4.0 → sqlnbfmt-0.4.2}/tests/test_marimo.py +0 -0
@@ -0,0 +1,42 @@
1
+ name: Python CI and Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ release:
8
+ types: [created]
9
+ workflow_dispatch:
10
+ inputs:
11
+ run_publish:
12
+ description: 'Set to true to run the publish job'
13
+ required: false
14
+ default: 'false'
15
+
16
+ jobs:
17
+ test:
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ - uses: astral-sh/setup-uv@v3
22
+ with:
23
+ enable-cache: true
24
+ cache-dependency-glob: "pyproject.toml"
25
+ - run: uv python install 3.12
26
+ - run: uv sync --all-extras --dev
27
+ - run: uv run pytest
28
+
29
+ publish:
30
+ needs: test
31
+ if: github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.run_publish == 'true')
32
+ runs-on: ubuntu-latest
33
+ permissions:
34
+ id-token: write
35
+ steps:
36
+ - uses: actions/checkout@v4
37
+ - uses: astral-sh/setup-uv@v3
38
+ with:
39
+ enable-cache: true
40
+ - run: uv python install 3.12
41
+ - run: uv build --no-sources
42
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,163 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py,cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ #Pipfile.lock
96
+
97
+ # poetry
98
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102
+ #poetry.lock
103
+
104
+ # pdm
105
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106
+ #pdm.lock
107
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108
+ # in version control.
109
+ # https://pdm.fming.dev/latest/usage/project/#working-with-version-control
110
+ .pdm.toml
111
+ .pdm-python
112
+ .pdm-build/
113
+
114
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
115
+ __pypackages__/
116
+
117
+ # Celery stuff
118
+ celerybeat-schedule
119
+ celerybeat.pid
120
+
121
+ # SageMath parsed files
122
+ *.sage.py
123
+
124
+ # Environments
125
+ .env
126
+ .venv
127
+ env/
128
+ venv/
129
+ ENV/
130
+ env.bak/
131
+ venv.bak/
132
+
133
+ # Spyder project settings
134
+ .spyderproject
135
+ .spyproject
136
+
137
+ # Rope project settings
138
+ .ropeproject
139
+
140
+ # mkdocs documentation
141
+ /site
142
+
143
+ # mypy
144
+ .mypy_cache/
145
+ .dmypy.json
146
+ dmypy.json
147
+
148
+ # Pyre type checker
149
+ .pyre/
150
+
151
+ # pytype static type analyzer
152
+ .pytype/
153
+
154
+ # Cython debug symbols
155
+ cython_debug/
156
+
157
+ # PyCharm
158
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
159
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
160
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
161
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
162
+ #.idea/
163
+ .DS_STORE
@@ -0,0 +1,41 @@
1
+ repos:
2
+ # Linting + formatting (Astral)
3
+ - repo: https://github.com/astral-sh/ruff-pre-commit
4
+ rev: v0.15.6
5
+ hooks:
6
+ - id: ruff
7
+ args: [--fix]
8
+ - id: ruff-format
9
+
10
+ # File quality + security
11
+ - repo: https://github.com/pre-commit/pre-commit-hooks
12
+ rev: v6.0.0
13
+ hooks:
14
+ - id: check-ast
15
+ - id: check-yaml
16
+ - id: check-toml
17
+ - id: check-json
18
+ - id: check-merge-conflict
19
+ - id: check-added-large-files
20
+ - id: debug-statements
21
+ - id: detect-private-key
22
+ - id: trailing-whitespace
23
+ - id: end-of-file-fixer
24
+
25
+ # Validate pyproject.toml against PEP 621
26
+ - repo: https://github.com/abravalheri/validate-pyproject
27
+ rev: v0.25
28
+ hooks:
29
+ - id: validate-pyproject
30
+
31
+ # Local hooks
32
+ - repo: local
33
+ hooks:
34
+ # Fast unit tests
35
+ - id: pytest-fast
36
+ name: pytest (fast)
37
+ entry: uv run pytest tests/ -x -q --timeout=10
38
+ language: system
39
+ types: [python]
40
+ pass_filenames: false
41
+ stages: [pre-push]
@@ -0,0 +1,35 @@
1
+ - id: sqlnbfmt
2
+ name: SQL Notebook Formatter
3
+ description: Format SQL queries in Jupyter notebooks
4
+ entry: sqlnbfmt
5
+ language: python
6
+ types: [jupyter]
7
+ require_serial: true
8
+ minimum_pre_commit_version: '3.0.0'
9
+
10
+ - id: sqlnbfmt-check
11
+ name: SQL Notebook Formatter (check)
12
+ description: Check SQL formatting in Jupyter notebooks without modifying files
13
+ entry: sqlnbfmt --check
14
+ language: python
15
+ types: [jupyter]
16
+ require_serial: true
17
+ minimum_pre_commit_version: '3.0.0'
18
+
19
+ - id: sqlnbfmt-py
20
+ name: SQL Python File Formatter
21
+ description: Format SQL queries in Python files (e.g. Marimo notebooks)
22
+ entry: sqlnbfmt
23
+ language: python
24
+ types: [python]
25
+ require_serial: true
26
+ minimum_pre_commit_version: '3.0.0'
27
+
28
+ - id: sqlnbfmt-py-check
29
+ name: SQL Python File Formatter (check)
30
+ description: Check SQL formatting in Python files without modifying files
31
+ entry: sqlnbfmt --check
32
+ language: python
33
+ types: [python]
34
+ require_serial: true
35
+ minimum_pre_commit_version: '3.0.0'
@@ -0,0 +1 @@
1
+ 3.12
@@ -0,0 +1,143 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.4.2] - Unreleased
9
+
10
+ ### Added
11
+
12
+ - **Jupyter server extension**: `pip install sqlnbfmt` now auto-registers with jupyterlab-code-formatter — no manual config needed
13
+
14
+ ### Changed
15
+
16
+ - Switched build system from setuptools to hatchling
17
+ - Updated JupyterLab docs to use `jupyter_server_config.py` (modern) instead of `jupyter_notebook_config.py` (legacy)
18
+
19
+ ## [0.4.0] - 2026-03-24
20
+
21
+ ### Added
22
+
23
+ - **Marimo notebook support**: format SQL in Marimo `.py` notebooks via `mo.sql()` calls — same `sqlnbfmt` command, auto-detected by file extension
24
+ - **Python file support**: `sqlnbfmt` now accepts `.py` files alongside `.ipynb` — works on any Python file containing SQL strings
25
+ - **JupyterLab integration**: `sqlnbfmt.jupyterlab_integration.register()` for use with `jupyterlab-code-formatter`
26
+ - `format_cell_source()` public API for formatting a single cell's source code
27
+ - `_format_python_source()`, `process_python_file()`, `diff_python_file()` public API for programmatic use
28
+ - `sql` added to default recognized function names (matches `mo.sql()`, etc.)
29
+ - `sqlnbfmt-py` and `sqlnbfmt-py-check` pre-commit hooks for Python files
30
+ - Marimo eval fixtures: `marimo_basic_sql`, `marimo_fstring_interpolation`, `marimo_complex_sql`, `marimo_multi_cell_mixed`, `marimo_comment_preservation`, `marimo_multi_statement`, `marimo_skip_hint`, `marimo_non_sql_unchanged`, `marimo_idempotency`
31
+
32
+ ### Fixed
33
+
34
+ - Idempotency: already-formatted SQL in triple-quoted strings (with leading whitespace/indentation) is no longer re-formatted on every run
35
+
36
+ ### Changed
37
+
38
+ - CLI description and help text updated to reflect multi-format support
39
+ - Project description and keywords updated for Marimo discoverability
40
+
41
+ ## [0.3.2] - 2026-03-16
42
+
43
+ ### Fixed
44
+
45
+ - Multiple SQL statements in a single cell are no longer concatenated on one line — each statement now starts on its own line after the `;` separator ([#3](https://github.com/flyersworder/sqlnbfmt/issues/3))
46
+
47
+ ### Changed
48
+
49
+ - SQL parsing switched from `sqlglot.parse_one()` to `sqlglot.parse()` to correctly handle multi-statement inputs
50
+
51
+ ### Added
52
+
53
+ - `multi_statement` eval fixture case covering `DROP TABLE` + `CREATE TABLE` sequences
54
+
55
+ ## [0.3.1] - 2026-03-15
56
+
57
+ ### Fixed
58
+
59
+ - `diff_notebook()` no longer duplicates cell-processing logic — extracted shared `_format_cells()` helper to prevent future divergence
60
+ - `--check --diff` combined mode no longer double-counts notebooks or processes them twice
61
+ - Skip hint (`# sqlnbfmt: skip`) no longer triggers on string literals containing the directive — only dedicated comment lines are recognised
62
+ - `load_config()` with a partial config file (missing keys) now falls back to built-in defaults instead of empty sets
63
+ - `load_config()` with an empty YAML file no longer raises `AttributeError`
64
+ - In-function SQL indentation now respects `indent_width` config instead of hardcoded 4 spaces
65
+
66
+ ### Added
67
+
68
+ - `main()` integration tests for `--diff`, `--check`, and `--check --diff` exit code behavior
69
+ - Docstring on `_has_skip_hint()` clarifying that inline trailing comments are intentionally ignored
70
+
71
+ ## [0.3.0] - 2026-03-15
72
+
73
+ ### Added
74
+
75
+ - **Zero-config defaults**: sqlnbfmt now works out of the box without a `config.yaml` file — built-in defaults for SQL keywords, function names, and decorators
76
+ - **`--check` mode**: verify formatting without modifying files; exits with code 1 if changes are needed (CI-friendly)
77
+ - **`--diff` mode**: print a unified diff of formatting changes without modifying files
78
+ - **Skip hints**: add `# sqlnbfmt: skip` to any cell to skip formatting
79
+ - **`sqlnbfmt-check` pre-commit hook**: a read-only hook variant for CI pipelines
80
+ - Cell index in all warning/debug messages for easier debugging
81
+ - PyPI keywords and project URLs in package metadata
82
+ - `skip_hint` eval fixture case
83
+
84
+ ### Changed
85
+
86
+ - `--config` argument is now optional (defaults to built-in settings instead of requiring `config.yaml`)
87
+ - `load_config()` accepts `None` to return defaults; passing a missing path still raises `FileNotFoundError`
88
+ - Version bumped to 0.3.0
89
+
90
+ ## [0.2.0] - 2026-03-15
91
+
92
+ ### Fixed
93
+
94
+ - Python comments in code cells are no longer stripped during formatting ([#2](https://github.com/flyersworder/sqlnbfmt/issues/2))
95
+
96
+ ### Changed
97
+
98
+ - Replaced AST-mutation approach (`ast.NodeTransformer` + `astor` + `black`) with surgical string replacement (`ast.NodeVisitor` + offset-based text splicing), preserving all non-SQL content exactly
99
+ - Removed `astor` and `black` from dependencies — fewer install requirements
100
+ - CI publish now uses PyPI Trusted Publishers (OIDC) instead of API tokens
101
+ - Migrated `tool.uv.dev-dependencies` to `dependency-groups.dev` (PEP 735)
102
+ - Updated `actions/checkout` from v3 to v4
103
+
104
+ ### Added
105
+
106
+ - Python 3.13 classifier
107
+ - Comment-preservation test case
108
+
109
+ ### Fixed
110
+
111
+ - Typo in config.yaml: `exeucte_query` → `execute_query`
112
+
113
+ ## [0.1.9] - 2025-01-01
114
+
115
+ ### Changed
116
+
117
+ - Updated dependencies (attrs, black, referencing, sqlglot, typing-extensions)
118
+
119
+ ## [0.1.8] - 2024-12-01
120
+
121
+ ### Fixed
122
+
123
+ - First-line indentation error for in-function SQL
124
+ - New-line handling issues in formatted output
125
+ - Introduced `black` formatter to resolve in-function SQL formatting edge cases
126
+
127
+ ## [0.1.7] - 2024-11-01
128
+
129
+ ### Added
130
+
131
+ - Pre-commit hook support
132
+ - F-string SQL formatting (with and without variables)
133
+ - In-function SQL formatting (e.g., `pd.read_sql(...)`)
134
+
135
+ ## [0.1.0] - 2024-10-01
136
+
137
+ ### Added
138
+
139
+ - Initial release
140
+ - SQL formatting in Jupyter notebook code cells using sqlglot
141
+ - Support for `%sql` / `%%sql` magic commands
142
+ - Configurable SQL keywords, function names, and formatting options
143
+ - GitHub Actions CI pipeline
@@ -1,31 +1,30 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlnbfmt
3
- Version: 0.4.0
3
+ Version: 0.4.2
4
4
  Summary: A tool to format SQL code in Jupyter notebooks and Marimo notebooks.
5
- Author-email: Qing <qingye779@gmail.com>
6
- License: MIT
7
5
  Project-URL: Homepage, https://github.com/flyersworder/sqlnbfmt
8
6
  Project-URL: Repository, https://github.com/flyersworder/sqlnbfmt
9
7
  Project-URL: Changelog, https://github.com/flyersworder/sqlnbfmt/blob/main/CHANGELOG.md
10
8
  Project-URL: Issues, https://github.com/flyersworder/sqlnbfmt/issues
11
- Keywords: sql,jupyter,marimo,notebook,formatter,sqlglot,pre-commit
9
+ Author-email: Qing <qingye779@gmail.com>
10
+ License: MIT
11
+ License-File: LICENSE
12
+ Keywords: formatter,jupyter,marimo,notebook,pre-commit,sql,sqlglot
12
13
  Classifier: Development Status :: 4 - Beta
14
+ Classifier: Framework :: Jupyter
13
15
  Classifier: Intended Audience :: Developers
14
16
  Classifier: Intended Audience :: Science/Research
15
17
  Classifier: License :: OSI Approved :: MIT License
16
18
  Classifier: Programming Language :: Python :: 3
17
19
  Classifier: Programming Language :: Python :: 3.12
18
20
  Classifier: Programming Language :: Python :: 3.13
19
- Classifier: Topic :: Software Development :: Quality Assurance
20
21
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
- Classifier: Framework :: Jupyter
22
+ Classifier: Topic :: Software Development :: Quality Assurance
22
23
  Requires-Python: >=3.12
23
- Description-Content-Type: text/markdown
24
- License-File: LICENSE
25
24
  Requires-Dist: nbformat>=5.10.4
26
25
  Requires-Dist: pyyaml>=6.0.2
27
26
  Requires-Dist: sqlglot>=25.27.0
28
- Dynamic: license-file
27
+ Description-Content-Type: text/markdown
29
28
 
30
29
  # sqlnbfmt
31
30
 
@@ -48,6 +47,7 @@ A SQL formatter for Jupyter Notebooks and Marimo notebooks. `sqlnbfmt` automatic
48
47
  - **CI-Friendly**: `--check` mode exits non-zero when formatting is needed; `--diff` shows what would change
49
48
  - **Skip Hints**: Add `# sqlnbfmt: skip` to any cell to exclude it from formatting
50
49
  - **Pre-commit Ready**: Seamlessly integrates with pre-commit hooks
50
+ - **JupyterLab Plugin**: Works with `jupyterlab-code-formatter` for interactive format-on-save
51
51
  - **Lightweight**: Only three runtime dependencies (sqlglot, nbformat, pyyaml)
52
52
 
53
53
  ## Installation
@@ -94,6 +94,22 @@ Add a `# sqlnbfmt: skip` comment to skip formatting. In Jupyter notebooks this a
94
94
  query = "select * from my_special_table where id = 1"
95
95
  ```
96
96
 
97
+ ### JupyterLab Integration
98
+
99
+ Format SQL cells interactively with [jupyterlab-code-formatter](https://github.com/jupyterlab-contrib/jupyterlab_code_formatter):
100
+
101
+ ```bash
102
+ pip install sqlnbfmt jupyterlab-code-formatter
103
+ ```
104
+
105
+ That's it — sqlnbfmt auto-registers as a Jupyter server extension. In JupyterLab, use **Edit > Format Cell** or configure format-on-save in Settings > Code Formatter, and select "Apply SQL Notebook Formatter".
106
+
107
+ To customize the dialect, add this to `~/.jupyter/jupyter_server_config.py`:
108
+ ```python
109
+ from sqlnbfmt.jupyterlab_integration import register
110
+ register(dialect="postgres")
111
+ ```
112
+
97
113
  ### Pre-commit Integration
98
114
 
99
115
  1. Install pre-commit:
@@ -19,6 +19,7 @@ A SQL formatter for Jupyter Notebooks and Marimo notebooks. `sqlnbfmt` automatic
19
19
  - **CI-Friendly**: `--check` mode exits non-zero when formatting is needed; `--diff` shows what would change
20
20
  - **Skip Hints**: Add `# sqlnbfmt: skip` to any cell to exclude it from formatting
21
21
  - **Pre-commit Ready**: Seamlessly integrates with pre-commit hooks
22
+ - **JupyterLab Plugin**: Works with `jupyterlab-code-formatter` for interactive format-on-save
22
23
  - **Lightweight**: Only three runtime dependencies (sqlglot, nbformat, pyyaml)
23
24
 
24
25
  ## Installation
@@ -65,6 +66,22 @@ Add a `# sqlnbfmt: skip` comment to skip formatting. In Jupyter notebooks this a
65
66
  query = "select * from my_special_table where id = 1"
66
67
  ```
67
68
 
69
+ ### JupyterLab Integration
70
+
71
+ Format SQL cells interactively with [jupyterlab-code-formatter](https://github.com/jupyterlab-contrib/jupyterlab_code_formatter):
72
+
73
+ ```bash
74
+ pip install sqlnbfmt jupyterlab-code-formatter
75
+ ```
76
+
77
+ That's it — sqlnbfmt auto-registers as a Jupyter server extension. In JupyterLab, use **Edit > Format Cell** or configure format-on-save in Settings > Code Formatter, and select "Apply SQL Notebook Formatter".
78
+
79
+ To customize the dialect, add this to `~/.jupyter/jupyter_server_config.py`:
80
+ ```python
81
+ from sqlnbfmt.jupyterlab_integration import register
82
+ register(dialect="postgres")
83
+ ```
84
+
68
85
  ### Pre-commit Integration
69
86
 
70
87
  1. Install pre-commit:
@@ -0,0 +1,49 @@
1
+ # Optional — sqlnbfmt works without this file using built-in defaults.
2
+ # Use this file only to override specific settings.
3
+ # config.yaml
4
+
5
+ sql_keywords:
6
+ - SELECT
7
+ - FROM
8
+ - WHERE
9
+ - INSERT
10
+ - UPDATE
11
+ - DELETE
12
+ - WITH
13
+ - JOIN
14
+ - CREATE
15
+ - DROP
16
+ - ALTER
17
+ - TRUNCATE
18
+ - UNION
19
+ - EXCEPT
20
+ - INTERSECT
21
+ - GROUP BY
22
+ - ORDER BY
23
+ - HAVING
24
+ - LIMIT
25
+ - OFFSET
26
+ - DISTINCT
27
+
28
+ function_names:
29
+ - read_sql
30
+ - read_sql_query
31
+ - read_sql_table
32
+ - execute
33
+ - executescript
34
+ - fetchall
35
+ - fetchone
36
+ - fetchmany
37
+ - execute_query
38
+
39
+ # Decorator names that contain SQL
40
+ sql_decorators:
41
+ - sql_decorator
42
+ - query
43
+ - sql_query
44
+ - db_query
45
+
46
+ # Formatting options
47
+ formatting_options:
48
+ single_line_threshold: 80 # Maximum length for single-line SQL
49
+ indent_width: 4 # Number of spaces for indentation
@@ -0,0 +1,7 @@
1
+ {
2
+ "ServerApp": {
3
+ "jpserver_extensions": {
4
+ "sqlnbfmt": true
5
+ }
6
+ }
7
+ }
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "sqlnbfmt"
3
- version = "0.4.0"
3
+ version = "0.4.2"
4
4
  description = "A tool to format SQL code in Jupyter notebooks and Marimo notebooks."
5
5
  authors = [
6
6
  { name = "Qing", email = "qingye779@gmail.com" }
@@ -44,16 +44,16 @@ dev = [
44
44
  ]
45
45
 
46
46
  [build-system]
47
- requires = ["setuptools>=61.0", "wheel"]
48
- build-backend = "setuptools.build_meta"
47
+ requires = ["hatchling"]
48
+ build-backend = "hatchling.build"
49
49
 
50
50
  [tool.pytest.ini_options]
51
51
  markers = [
52
52
  "integration: mark a test as an integration test."
53
53
  ]
54
54
 
55
+ [tool.hatch.build.targets.wheel.shared-data]
56
+ "jupyter-config/sqlnbfmt.json" = "etc/jupyter/jupyter_server_config.d/sqlnbfmt.json"
57
+
55
58
  [tool.ruff]
56
59
  extend-exclude = ["tests/eval/*/"]
57
-
58
- [tool.setuptools.package-data]
59
- sqlnbfmt = [".pre-commit-hooks.yaml"]
@@ -0,0 +1,15 @@
1
+ def _jupyter_server_extension_points():
2
+ return [{"module": "sqlnbfmt"}]
3
+
4
+
5
+ def _load_jupyter_server_extension(server_app):
6
+ try:
7
+ from sqlnbfmt.jupyterlab_integration import register
8
+
9
+ register()
10
+ server_app.log.info(
11
+ "sqlnbfmt: registered SQL formatter with jupyterlab-code-formatter"
12
+ )
13
+ except Exception:
14
+ # jupyterlab-code-formatter not installed — silently skip
15
+ pass