Skip to content

fix: [AI-1773] improve sqlfmt discovery for uv tool install locations#1852

Open
ralphstodomingo wants to merge 5 commits intomasterfrom
fix/1773-sqlfmt-discovery
Open

fix: [AI-1773] improve sqlfmt discovery for uv tool install locations#1852
ralphstodomingo wants to merge 5 commits intomasterfrom
fix/1773-sqlfmt-discovery

Conversation

@ralphstodomingo
Copy link
Copy Markdown
Contributor

@ralphstodomingo ralphstodomingo commented Mar 26, 2026

Summary

  • Add well-known tool binary locations to sqlfmt discovery (~/.local/bin/, Windows uv/pipx paths)
  • Respect UV_TOOL_BIN_DIR and PIPX_BIN_DIR environment variable overrides
  • Use async exec instead of blocking execSync for uv tool dir lookup
  • Cache discovered sqlfmt path with existence validation (re-discovers if binary is deleted)
  • Use correct uv package name (shandy-sqlfmt, not sqlfmt) for tool directory paths
  • Improve error message with actionable guidance

Context

Fixes #1773

When sqlfmt is installed via uv tool install "shandy-sqlfmt[jinjafmt]", the extension couldn't find it. The binary is placed at ~/.local/bin/sqlfmt but VS Code's process PATH is frozen at launch time.

Discovery order:

  1. Python venv bin directory (existing)
  2. UV_TOOL_BIN_DIR / PIPX_BIN_DIR env var overrides (new)
  3. ~/.local/bin/sqlfmt — default for uv/pipx on Linux/Mac (new)
  4. Windows-specific paths for uv/pipx (new)
  5. uv tool dir async discovery for custom locations (new, non-blocking)
  6. System PATH via which (existing)

Risk mitigations:

  • uv tool dir uses async exec (non-blocking) with 3s timeout
  • Discovered path is cached with fs.existsSync validation — cache auto-invalidates if binary is removed
  • UV_TOOL_BIN_DIR and PIPX_BIN_DIR respected for users with custom tool locations
  • Correct package name shandy-sqlfmt used in uv tool directory paths
  • Multi-layer discovery is robust: hiding ~/.local/bin/sqlfmt symlink still finds the binary via uv tool dir fallback

Test plan

  • Install sqlfmt via uv tool install — Format Document works
  • uv tool uninstall shandy-sqlfmt — formatting fails with improved error message
  • Reinstall sqlfmt — formatting works again without restarting F5 (cache re-discovers)
  • Webpack builds cleanly

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved detection of the sqlfmt formatter across multiple installation locations and platforms for more reliable resolution.
    • Added one-time caching and a multi-step discovery flow to speed up and stabilize subsequent formatter lookups.
    • Expanded user-facing error messages with concrete installation examples, guidance to set the formatter path explicitly, and a reminder to restart the editor to refresh PATH.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 26, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: dab04e34-e61b-4453-9a39-870e6f789870

📥 Commits

Reviewing files that changed from the base of the PR and between 746cf4a and 6888652.

📒 Files selected for processing (1)
  • src/document_formatting_edit_provider/dbtDocumentFormattingEditProvider.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/document_formatting_edit_provider/dbtDocumentFormattingEditProvider.ts

Walkthrough

Caches the resolved sqlfmt binary per configured Python interpreter and replaces a single which("sqlfmt") fallback with a multi-step discovery: platform-specific executable name, check next to configured Python, probe uv/pipx bin dirs (with env overrides), invoke uv tool dir (3s timeout) for shandy-sqlfmt, then guarded which fallback; expands error messaging.

Changes

Cohort / File(s) Summary
sqlfmt Path Resolution
src/document_formatting_edit_provider/dbtDocumentFormattingEditProvider.ts
Added caching (cachedSqlFmtPath, sqlFmtPathResolved) and new discoverSqlFmtPath() flow: choose platform executable, check adjacent to configured Python, probe known uv/pipx bin dirs and UV_TOOL_BIN_DIR/PIPX_BIN_DIR overrides, call uv tool dir with 3s timeout and platform-specific shandy-sqlfmt candidates, then fallback to which("sqlfmt") with error guarded handling. Expanded user-facing error message with install examples and restart guidance.

Sequence Diagram(s)

sequenceDiagram
  participant Editor as VS Code Extension
  participant Provider as DbtDocumentFormattingEditProvider
  participant PyFS as Python Interpreter FS
  participant Env as Environment (PATH / PIPX_BIN_DIR / UV_TOOL_BIN_DIR)
  participant UV as uv CLI
  participant Which as system which

  Editor->>Provider: Request sqlfmt path
  Provider->>Provider: return cached path if valid
  Provider->>PyFS: check for sqlfmt next to configured Python
  alt found
    PyFS-->>Provider: return path
  else not found
    Provider->>Env: probe known uv/pipx bin dirs & env overrides
    alt found
      Env-->>Provider: return path
    else not found
      Provider->>UV: run "uv tool dir" (async, 3s timeout)
      alt uv returns dir
        UV-->>Provider: tool dir
        Provider->>Provider: construct shandy-sqlfmt candidate path(s) and check
        alt found
          Provider-->>Editor: resolved path
        else
          Provider->>Which: which("sqlfmt")
          Which-->>Provider: path or undefined
          Provider-->>Editor: resolved path or undefined + enhanced error message
        end
      else uv fails/timeout
        Provider->>Which: which("sqlfmt")
        Which-->>Provider: path or undefined
        Provider-->>Editor: resolved path or undefined + enhanced error message
      end
    end
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: improving sqlfmt discovery for uv tool install locations.
Description check ✅ Passed The PR description is comprehensive, covering problem, solution, context, discovery order, risk mitigations, and a detailed test plan, though it lacks the template's checklist and README update section.
Linked Issues check ✅ Passed The code changes directly address all objectives from issue #1773: discovering sqlfmt in uv/pipx locations, honoring environment variable overrides, using non-blocking async exec with caching, and improving error messages.
Out of Scope Changes check ✅ Passed All changes are scoped to sqlfmt discovery logic in DbtDocumentFormattingEditProvider, directly addressing the linked issue with no extraneous modifications.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/1773-sqlfmt-discovery

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

// Windows: uv puts tools in %APPDATA%\uv\data\tools\sqlfmt\...
const appData = process.env.APPDATA;
if (appData) {
candidates.push(

This comment was marked as outdated.

- Replace blocking execSync with async exec for uv tool dir lookup
- Cache discovered path after first successful resolution
- Respect UV_TOOL_BIN_DIR and PIPX_BIN_DIR env var overrides
- Use correct uv tool directory name (shandy-sqlfmt, not sqlfmt)
- Normalize exe name (sqlfmt vs sqlfmt.exe) based on platform

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/document_formatting_edit_provider/dbtDocumentFormattingEditProvider.ts`:
- Around line 115-119: The venv-adjacent lookup only checks for "sqlfmt" and
misses Windows executables; update the block that builds candidatePath (using
pythonPath and path.dirname(pythonPath)) to check for the Windows binary as
well—e.g. check for both path.join(path.dirname(pythonPath), "sqlfmt") and
path.join(path.dirname(pythonPath), "sqlfmt.exe") (or choose the
platform-specific name via process.platform === 'win32') and return the first
existing candidate; adjust the fs.existsSync checks accordingly so the function
(and symbol candidatePath) discovers sqlfmt on Windows venvs.
- Around line 149-169: The Windows/Linux candidate path push block in
dbtDocumentFormattingEditProvider.ts (the if (process.platform === "win32") {
... } else { ... } section that calls candidates.push and path.join) is
formatted in a way that violates the repo's ESLint/Prettier rules; reformat this
block to satisfy the project's formatter (wrap/indent arguments consistently and
remove the current line-wrapping style), then run the project's formatting
script (e.g., the repository's eslint/prettier or yarn/npm format command) to
apply the canonical formatting so ESLint/Prettier no longer flags the file.
- Around line 102-104: Update the error message string in
dbtDocumentFormattingEditProvider (the message built where it says "Could not
run sqlfmt...") to reference the correct PyPI package name "shandy-sqlfmt" and
the recommended install command (e.g. `uv tool install
"shandy-sqlfmt[jinjafmt]"`), replacing the incorrect `sqlfmt` reference while
keeping guidance about setting `dbt.sqlFmtPath` and restarting VS Code; locate
the message construction in the formatting provider code and update the text
accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f59f51f5-8baf-4871-82a2-787c7d002fcf

📥 Commits

Reviewing files that changed from the base of the PR and between 34afd0e and 7670d27.

📒 Files selected for processing (1)
  • src/document_formatting_edit_provider/dbtDocumentFormattingEditProvider.ts

If the cached binary is deleted (e.g. uv tool uninstall), re-run
discovery instead of silently failing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Comment on lines +129 to +132
const result = await this.discoverSqlFmtPath();
this.cachedSqlFmtPath = result;
this.sqlFmtPathResolved = true;
return result;

This comment was marked as outdated.

window.showErrorMessage(
extendErrorWithSupportLinks(
"Could not run sqlfmt. Did you install sqlfmt? Detailed error: " +
"Could not run sqlfmt. If sqlfmt is installed (e.g. via `uv tool install sqlfmt` or `pipx install sqlfmt`), " +

This comment was marked as outdated.

Reference `shandy-sqlfmt[jinjafmt]` instead of bare `sqlfmt` in the
install command suggestions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@ralphstodomingo ralphstodomingo self-assigned this Mar 26, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/document_formatting_edit_provider/dbtDocumentFormattingEditProvider.ts`:
- Around line 30-32: The cached binary path
(cachedSqlFmtPath/sqlFmtPathResolved) is not tied to the current Python
interpreter so switching interpreters can return a stale sqlfmt; modify
findSqlFmtPath() (and the other similar block around the second occurrence) to
include the interpreter context when caching — e.g., store the
lastSeenPythonPath (or incorporate this.pythonEnvironment.pythonPath) alongside
cachedSqlFmtPath and only reuse the cache if the stored interpreter path equals
the current this.pythonEnvironment.pythonPath; otherwise clear/refresh the cache
and call discoverSqlFmtPath() to resolve a new path.
- Around line 27-29: The class declaration wrapping violates Prettier; update
the declaration for DbtDocumentFormattingEditProvider so it adheres to project
formatting rules by placing the implements clause inline with the class
declaration (i.e., make the DbtDocumentFormattingEditProvider implements
DocumentFormattingEditProvider declaration a single line) ensuring consistent
spacing and braces to satisfy Prettier/ESLint.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: af6f4af7-6236-407f-a25c-fbbe253f654a

📥 Commits

Reviewing files that changed from the base of the PR and between a2a13c2 and 746cf4a.

📒 Files selected for processing (1)
  • src/document_formatting_edit_provider/dbtDocumentFormattingEditProvider.ts

…rmatting

Cache invalidates when Python interpreter changes (e.g. switching venvs),
ensuring the correct sqlfmt binary is discovered for the active environment.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

sqlfmt formatter doesn't work

1 participant