Liking cljdoc? Tell your friends :D

com.blockether.ruff

Clojure binding to ruff (https://github.com/astral-sh/ruff) for Python code FORMATTING and LINTING, through the JDK Foreign Function & Memory API.

ruff does not publish a C-ABI library — only a CLI. So this binds a tiny first-party cdylib, ruff-c (native/ruff-c, a thin extern "C" wrapper over ruff's ruff_python_formatter + ruff_linter crates), exactly the way clj-fff binds fff-c. Both run IN-PROCESS via a downcall — no subprocess, no CLI. format takes Python source and returns it reformatted (long calls/collections wrapped multiline, black-compatible style); lint returns ruff's diagnostics as plain Clojure maps.

Ruff CONFIGURATION FILES are first class: config-file finds the nearest .ruff.toml / ruff.toml / pyproject.toml with [tool.ruff] exactly the way the CLI does, and passing it as :config makes format/lint honour that file's real options (select/ignore, line-length, target-version, preview, [format] quote/indent/line-ending/docstring settings, extend chains). Discovery is never implicit: no :config, no file lookup.

Run the JVM with --enable-native-access=ALL-UNNAMED so the foreign linker may load the library without a restricted-method warning.

The library is resolved ONCE, lazily, the first time it's needed:

  1. RUFF_NATIVE_PATH env / com.blockether.ruff.native.path system property — an explicit path to the cdylib (used verbatim).
  2. A bundled classpath resource prebuilds/<platform>/<lib>, shipped by com.blockether/ruff-native-<platform> (extracted to the cache dir). This is the native-image path.
  3. A runtime download: the ruff-native-<platform> jar resolved through clojure.tools.deps (honouring Maven repos/mirrors/settings.xml), extracted + cached. Disable with RUFF_DISABLE_DOWNLOAD=1.

<platform> ∈ { linux-x64 linux-arm64 darwin-arm64 darwin-x64 windows-x64 }.

Clojure binding to ruff (https://github.com/astral-sh/ruff) for Python code
FORMATTING and LINTING, through the JDK Foreign Function & Memory API.

ruff does not publish a C-ABI library — only a CLI. So this binds a tiny
first-party cdylib, `ruff-c` (native/ruff-c, a thin `extern "C"` wrapper over
ruff's `ruff_python_formatter` + `ruff_linter` crates), exactly the way
clj-fff binds `fff-c`. Both run IN-PROCESS via a downcall — no subprocess, no
CLI. `format` takes Python source and returns it reformatted (long
calls/collections wrapped multiline, black-compatible style); `lint` returns
ruff's diagnostics as plain Clojure maps.

Ruff CONFIGURATION FILES are first class: `config-file` finds the nearest
`.ruff.toml` / `ruff.toml` / `pyproject.toml` with `[tool.ruff]` exactly the
way the CLI does, and passing it as `:config` makes `format`/`lint` honour
that file's real options (`select`/`ignore`, `line-length`, `target-version`,
`preview`, `[format]` quote/indent/line-ending/docstring settings, `extend`
chains). Discovery is never implicit: no `:config`, no file lookup.

Run the JVM with `--enable-native-access=ALL-UNNAMED` so the foreign linker
may load the library without a restricted-method warning.

The library is resolved ONCE, lazily, the first time it's needed:
  1. RUFF_NATIVE_PATH env / `com.blockether.ruff.native.path` system property
     — an explicit path to the cdylib (used verbatim).
  2. A bundled classpath resource `prebuilds/<platform>/<lib>`, shipped by
     `com.blockether/ruff-native-<platform>` (extracted to the cache dir).
     This is the native-image path.
  3. A runtime download: the `ruff-native-<platform>` jar resolved through
     `clojure.tools.deps` (honouring Maven repos/mirrors/settings.xml),
     extracted + cached. Disable with RUFF_DISABLE_DOWNLOAD=1.

`<platform>` ∈ { linux-x64 linux-arm64 darwin-arm64 darwin-x64 windows-x64 }.
raw docstring

available?clj

(available?)

True if the ruff native library can be resolved + linked on this platform.

True if the ruff native library can be resolved + linked on this platform.
sourceraw docstring

config-fileclj

(config-file path)

Nearest ruff configuration file governing path (a file or a directory), searched exactly the way the ruff CLI searches: .ruff.toml, then ruff.toml, then a pyproject.toml that actually has a [tool.ruff] table — in path's own directory, then every ancestor. Returns the absolute path as a String, or nil when the tree has no ruff configuration at all.

That nil is the signal to tell a user "this project has no ruff config"; format/lint fall back to ruff's built-in defaults when it happens.

Nearest ruff configuration file governing `path` (a file or a directory),
searched exactly the way the ruff CLI searches: `.ruff.toml`, then
`ruff.toml`, then a `pyproject.toml` that actually has a `[tool.ruff]`
table — in `path`'s own directory, then every ancestor. Returns the absolute
path as a String, or nil when the tree has no ruff configuration at all.

That nil is the signal to tell a user "this project has no ruff config";
`format`/`lint` fall back to ruff's built-in defaults when it happens.
sourceraw docstring

formatclj

(format code)
(format code {:keys [line-length config path]})

Format Python code and return the reformatted source as a String.

Options: :config path — a ruff configuration file (ruff.toml, .ruff.toml or a pyproject.toml with [tool.ruff]). Its [format] section is honoured in full: quote-style, indent-style, indent-width, line-ending, skip-magic-trailing-comma, docstring-code-format, docstring-code-line-length, line-length, target-version, preview — plus extend chains. Use config-file to discover it. :path path — the file the source came from. Selects the source type (.pyi stubs format differently) and resolves path-specific target-version overrides. :line-length int — explicit wrap width; OVERRIDES the configuration (0 / omitted => the config's, else ruff's 88).

Runs entirely in-process (no subprocess). With no :config the result depends only on code, :path and :line-length — ruff's defaults, no implicit discovery. Throws ex-info when ruff can't format the input (syntactically invalid Python, or an unreadable/invalid config); callers that want a verbatim fallback should use format-or or catch.

Format Python `code` and return the reformatted source as a String.

Options:
  :config       path — a ruff configuration file (`ruff.toml`, `.ruff.toml`
                       or a `pyproject.toml` with `[tool.ruff]`). Its
                       `[format]` section is honoured in full: `quote-style`,
                       `indent-style`, `indent-width`, `line-ending`,
                       `skip-magic-trailing-comma`, `docstring-code-format`,
                       `docstring-code-line-length`, `line-length`,
                       `target-version`, `preview` — plus `extend` chains.
                       Use `config-file` to discover it.
  :path         path — the file the source came from. Selects the source type
                       (`.pyi` stubs format differently) and resolves
                       path-specific `target-version` overrides.
  :line-length  int  — explicit wrap width; OVERRIDES the configuration
                       (0 / omitted => the config's, else ruff's 88).

Runs entirely in-process (no subprocess). With no `:config` the result
depends only on `code`, `:path` and `:line-length` — ruff's defaults, no
implicit discovery. Throws ex-info when ruff can't format the input
(syntactically invalid Python, or an unreadable/invalid config); callers that
want a verbatim fallback should use `format-or` or catch.
sourceraw docstring

format-orclj

(format-or code)
(format-or code opts)

Like format, but returns code unchanged if ruff is unavailable or fails (the convenient display-side default — never lose the original source).

Like `format`, but returns `code` unchanged if ruff is unavailable or fails
(the convenient display-side default — never lose the original source).
sourceraw docstring

lintclj

(lint code)
(lint code {:keys [line-length select ignore preview config path]})

Lint Python code with ruff and return a vector of diagnostic maps, in ruff's own order:

{:code "F401" :message "os imported but unused" :row 1 :col 1 :end-row 1 :end-col 10 :is-fixable true}

Rows and columns are 1-based; :end-row/:end-col are exclusive; :code is the noqa code (F401) when the rule has one, else the rule id.

Options: :config path — a ruff configuration file (ruff.toml, .ruff.toml, or a pyproject.toml carrying [tool.ruff]). Its [lint] section is honoured in full: select, extend-select, ignore, fixable, dummy-variable-rgx, per-rule sections ([lint.pydocstyle], [lint.isort], …), line-length, target-version, preview and extend chains. Use config-file to discover it; without one you get ruff's built-in default selection (E4, E7, E9, F). :path path — the file the source came from; reported in diagnostics and used for .pyi source typing. :line-length int — width for line-length rules; OVERRIDES config. :select selectors — REPLACE the selected rule set ("F,E501", :F401, ["F" "B"]…); OVERRIDES config. :ignore selectors — disable these on top of the selection. :preview boolean — also run preview rules; OVERRIDES config.

Runs entirely in-process. Inline # noqa comments in the source are always honoured. Not supported: per-file-ignores (there is no project file walk here — one source, one call) and exclude patterns; apply those at the call site. Throws ex-info when ruff cannot lint the input (unknown selector, unreadable/invalid config, or unparsable source); use lint-or for the never-throw variant.

Lint Python `code` with ruff and return a vector of diagnostic maps, in ruff's
own order:

  {:code "F401" :message "`os` imported but unused"
   :row 1 :col 1 :end-row 1 :end-col 10 :is-fixable true}

Rows and columns are 1-based; `:end-row`/`:end-col` are exclusive; `:code` is
the noqa code (`F401`) when the rule has one, else the rule id.

Options:
  :config       path       — a ruff configuration file (`ruff.toml`,
                             `.ruff.toml`, or a `pyproject.toml` carrying
                             `[tool.ruff]`). Its `[lint]` section is honoured
                             in full: `select`, `extend-select`, `ignore`,
                             `fixable`, `dummy-variable-rgx`, per-rule
                             sections (`[lint.pydocstyle]`, `[lint.isort]`,
                             …), `line-length`, `target-version`, `preview`
                             and `extend` chains. Use `config-file` to
                             discover it; without one you get ruff's built-in
                             default selection (E4, E7, E9, F).
  :path         path       — the file the source came from; reported in
                             diagnostics and used for `.pyi` source typing.
  :line-length  int        — width for line-length rules; OVERRIDES config.
  :select       selectors  — REPLACE the selected rule set ("F,E501", :F401,
                             ["F" "B"]…); OVERRIDES config.
  :ignore       selectors  — disable these on top of the selection.
  :preview      boolean    — also run preview rules; OVERRIDES config.

Runs entirely in-process. Inline `# noqa` comments in the source are always
honoured. Not supported: `per-file-ignores` (there is no project file walk
here — one source, one call) and `exclude` patterns; apply those at the call
site. Throws ex-info when ruff cannot lint the input (unknown selector,
unreadable/invalid config, or unparsable source); use `lint-or` for the
never-throw variant.
sourceraw docstring

lint-orclj

(lint-or code)
(lint-or code opts)
(lint-or code opts default)

Like lint, but returns default (nil unless given) if ruff is unavailable or fails — the display-side variant that never throws.

Like `lint`, but returns `default` (nil unless given) if ruff is unavailable
or fails — the display-side variant that never throws.
sourceraw docstring

versionclj

(version)

The bundled ruff release string (clj-ruff-cdylib (ruff X.Y.Z)).

The bundled ruff release string (`clj-ruff-cdylib (ruff X.Y.Z)`).
sourceraw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close