Skip to main content

pysonarlint

CI codecov Python License: MIT Ruff

The issues SonarQube for IDE (formerly SonarLint) would highlight, from your terminal.

$ pysonarlint src/
src/app/core/client.py
      98:9  warning  Refactor this function to reduce its Cognitive Complexity from 21 to the 15 allowed.  python:S3776
     218:16  warning  Enable server certificate validation on this SSL/TLS connection.  python:S4830

src/app/api/routes.py
     308:5  warning  Use "Annotated" type hints for FastAPI dependency injection  python:S8410
     542:15  warning  Document this HTTPException with status code 500 in the "responses" parameter.  python:S8415

31 issues in 10 of 32 files (31 warning)
standalone mode, engine 5.9.1, 31.2s

These are the real SonarSource rules, not an approximation. pysonarlint drives the same analyzers your IDE uses, so a finding here is a finding there.

Why not just use pylint or ruff?

They are excellent and you should use them too. Sonar's rule set is different in kind: framework-aware rules (S8410 on FastAPI dependency injection, S8415 on undocumented HTTPException responses), security rules (S4830 on disabled certificate validation), cognitive-complexity metrics, and ReDoS detection in regular expressions. If your team already gates merges on SonarQube, this is how you see those findings before you push.

Install

pip install pysonarlint

pysonarlint is pure Python with no dependencies. It does need the SonarSource analyzers, which are Java and not redistributable, so it reuses an existing SonarQube for IDE installation:

  1. Install the SonarQube for IDE extension in VS Code (or Cursor, Windsurf, VSCodium, Kiro, or a VS Code Server / devcontainer).
  2. That is all. The extension bundles its own Java runtime, so you do not need Java on your PATH.

Check what was found:

$ pysonarlint status
engine     5.9.1  ~/.vscode/extensions/sonarsource.sonarlint-vscode-5.9.1-win32-x64
java       ~/.vscode/extensions/.../jre/21.0.12.1-win32-x86_64.tar/bin/java.exe
analyzers  13 (sonarpython, sonarjs, sonarjava, sonariac, sonarhtml, ...)
root       ~/work/my-project
mode       standalone

Point it elsewhere with --sonarlint-home or PYSONARLINT_HOME, and override the JRE with PYSONARLINT_JAVA.

Usage

pysonarlint                          # analyze the current directory
pysonarlint src/ tests/              # specific paths
pysonarlint app/main.py              # a single file
pysonarlint --severity error         # only the worst
pysonarlint -f json                  # machine-readable
pysonarlint -f sarif -o results.sarif
pysonarlint --all-languages          # not just Python

Python only by default. Add --language js --language terraform, or --all-languages.

Exit codes

Code Meaning
0 No issues at or above the threshold
1 Issues found
2 The tool itself failed, or the analysis could not complete

2 is never used for "found issues", and a run that cannot finish never reports 0. Tune the threshold with --fail-on error (or --fail-on never to always exit 0).

Output formats

--format For
text humans (default; colour when the terminal supports it)
json agents and scripts; stable keys, includes a ruleUrl per issue
sarif GitHub code scanning and other SARIF 2.1.0 consumers
github inline ::warning file=... annotations in Actions

Connected mode

Standalone needs no configuration and no token. Connected mode additionally applies your server's quality profile and its resolved issues, and it turns on only when both a server URL and a token are available. Anything less stays standalone and says why:

$ pysonarlint
...
note: standalone: found server https://sonar.example.com (from sonar-project.properties)
      but no token. Set SONAR_TOKEN, or run 'pysonarlint login' to grant one.

Get a token through the browser, exactly as the IDE does:

$ pysonarlint login
server https://sonar.example.com is UP, version 2025.6.1.117629
opening https://sonar.example.com/sonarlint/auth?ideName=pysonarlint&port=64120
waiting for the browser...
token verified and saved to ~/AppData/Roaming/pysonarlint/credentials.json (DPAPI-encrypted)

Where tokens are stored. On Windows, encrypted with DPAPI and bound to your OS account. On macOS and Linux, as plaintext in a file with mode 0600 (owner-only) -- readable by anything running as you, and by root. If that is not acceptable, do not use login: set SONAR_TOKEN in your environment or a secrets manager instead, which pysonarlint prefers over stored credentials anyway. pysonarlint logout removes a stored token.

Use a User token. SonarQube's Global Analysis and Project Analysis tokens are restricted to submitting analysis reports and cannot read the project data connected mode needs. If you paste one, pysonarlint tells you so instead of failing obscurely. Mint one at <server>/account/security/ with Type: User.

Degradation is never a failure

Connected mode is an enhancement, so losing it costs you the server's rule set and nothing else. The analysis always runs:

Situation Behaviour
No token Standalone, with a note saying how to get one
Project key not found on the server Key dropped, connection kept, server defaults used
Server unreachable, or token rejected Standalone, with the reason
Server declines the binding Standalone, quoting the server's own explanation

In every case you still get issues and a normal exit code. --format json sets summary.degradedFromConnected so an agent can tell that the rule set was local, and the reason appears in notes.

Current limitation: connected mode does not yet apply a server profile in practice. The connection registers and preflight passes, but the language server reports No token for connection and analyzes with local rules. Runs are correctly labelled standalone when this happens rather than claiming otherwise, so results are never misrepresented; standalone analysis is unaffected.

Configuration discovery

Resolved in this order, first match winning. The source of every value is reported by pysonarlint status, so precedence is never a mystery.

Source Supplies
1 --server-url, --token, --project-key, --organization everything
2 SONAR_TOKEN / SONARQUBE_TOKEN, SONAR_HOST_URL / SONARQUBE_URL, SONARQUBE_ORG, SONAR_REGION everything
3 .sonarlint/connectedMode.json URL, project key, organization
4 sonar-project.properties, .sonarcloud.properties URL, project key, exclusions
5 .vscode/settings.json + editor user settings project key, URL, token
6 pyproject.toml [tool.pysonarlint] URL, project key, exclusions
7 stored credentials from pysonarlint login token

Config is searched from the target up to the repository root, so it works from any subdirectory. [tool.pysonarlint] is our own table: no Sonar tool reads pyproject.toml for IDE bindings, and [tool.sonar] belongs to the pysonar CI scanner, so we do not touch it.

Behind a corporate proxy, the standard HTTP_PROXY / HTTPS_PROXY / NO_PROXY variables are honoured. Internal Sonar hosts usually need to be in NO_PROXY. For a private CA, point SSL_CERT_FILE at a PEM bundle.

Use with Claude Code and other agents

The json format is designed for this. Add a rule to CLAUDE.md:

After changing Python files, run `pysonarlint -f json --severity warning` and fix
what it reports. Each issue includes a `ruleUrl` explaining the rule. Do not suppress
issues to make the output clean.

Or wire it into a hook so it runs automatically after edits. The payload is stable:

{
  "version": 1,
  "mode": "standalone",
  "summary": { "issues": 2, "filesAnalyzed": 32, "incomplete": false },
  "issues": [
    {
      "file": "app/core/client.py",
      "line": 218,
      "column": 16,
      "rule": "python:S4830",
      "severity": "warning",
      "message": "Enable server certificate validation on this SSL/TLS connection.",
      "ruleUrl": "https://rules.sonarsource.com/python/RSPEC-4830/"
    }
  ]
}

Always check summary.incomplete. If it is true, the issue list is partial and should not be treated as authoritative.

Performance

Each run boots a JVM, which costs a few seconds; a 32-file project takes roughly 30 seconds end to end. Analysis is genuinely finished when the tool exits: completion is read from the analyzer's own signal rather than inferred from a quiet period, because a timing heuristic happily reports zero issues on a file that simply took a moment.

Prefer passing specific paths over analyzing a whole repository on every save.

Prior art

sonarlint-ls-cli explored the same idea. pysonarlint differs in ways that matter in practice: it discovers the engine and JRE itself, waits for a real completion signal instead of an idle timer, treats an unfinishable run as an error rather than a clean result, supports connected mode with a browser token grant, and emits JSON and SARIF.

sonar-scanner-cli is not an alternative for local use: it contains no analysis engine, requires a server and a token even to start, and computes results server-side rather than printing them.

Trademarks and affiliation

pysonarlint is an independent, unofficial, community-maintained project. It is not a Sonar product and is not affiliated with, sponsored by, endorsed by, or supported by SonarSource SA.

Sonar™, SonarSource™, SonarQube™, SonarQube for IDE™ and SonarLint™ are trademarks of SonarSource SA. All other trademarks are the property of their respective owners. These marks appear here solely to describe, factually, the third-party software this tool interoperates with.

This project bundles, redistributes and mirrors no SonarSource code, binaries or analyzers. It locates and invokes a copy of SonarQube for IDE that you installed yourself. The SonarSource language server is licensed under LGPL-3.0; the SonarSource analyzers are licensed under the Sonar Source-Available License v1, and your use of them is governed by that licence directly between you and SonarSource.

For code-quality analysis in a supported, officially maintained form, use SonarQube Cloud, Server or for IDE.

A note if you pipe this into an AI tool. SSALv1 restricts using non-Sonar artificial-intelligence technology to "ingest, interpret, analyze, train on, or interact with the data provided by the Program". pysonarlint itself contains no AI and only formats the analyzer's output, but feeding that output to an LLM is your decision and your responsibility under that licence. Read it before wiring this into an agent.

Licence

MIT for pysonarlint's own code -- see LICENSE. It only invokes the SonarSource analyzers, which carry their own licences; it does not redistribute them.

Download files

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

Source Distribution

pysonarlint-0.1.0.tar.gz (47.4 kB view details)

Uploaded Source

Built Distribution

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

pysonarlint-0.1.0-py3-none-any.whl (53.3 kB view details)

Uploaded Python 3

File details

Details for the file pysonarlint-0.1.0.tar.gz.

File metadata

  • Download URL: pysonarlint-0.1.0.tar.gz
  • Upload date:
  • Size: 47.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for pysonarlint-0.1.0.tar.gz
Algorithm Hash digest
SHA256 f44328ee556e0cc6d49647da03074a9e2321d856d8347665f6548266f3a5d19d
MD5 930e46cf1a70cdd03f29793ad2d67ca6
BLAKE2b-256 cfd64e242e3e28a3e19e8cdb8a4a9f907fe5491784935101df5005be88705422

See more details on using hashes here.

Provenance

The following attestation bundles were made for pysonarlint-0.1.0.tar.gz:

Publisher: publish.yml on budaesandrei/pysonarlint

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

File details

Details for the file pysonarlint-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: pysonarlint-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 53.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for pysonarlint-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e68a468171997adb760d5fb45e955d6a016f0a189c08efc2b7cecac9d3ac9825
MD5 fcc716d4c385c7ef802cc0a8b55d998d
BLAKE2b-256 a30e95f938122eefd5c150f7567817f395a6adb57e405c9908b2dee03e236f9b

See more details on using hashes here.

Provenance

The following attestation bundles were made for pysonarlint-0.1.0-py3-none-any.whl:

Publisher: publish.yml on budaesandrei/pysonarlint

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

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page