效能最快的程式碼分析工具,Ruff 正在席捲 Python 圈!

2023-04-09 21:01:34

幾天前,Python 開源社群又出了一個不小的新聞:HTTPX 和 Starlette 在同一天將在用的程式碼分析工具(flake8、autoflake 和 isort)統一替換成了 Ruff。

HTTPX 是一個支援非同步的 HTTP 使用者端,Starlette 是一個輕量級的 ASGI 框架,它們都是 Python 社群裡的明星專案,目前加起來有近 20K star。它們都選擇了使用 Ruff,再次擴大了 Ruff 的應用版圖。

Ruff 是個誕生僅僅 8 個月的新興專案,但已呈現出一種席捲 Python 社群的趨勢!很多知名的開源專案已採納 Ruff,比如 Transformers、Pandas、FastAPI、Airflow、SciPy、Bokeh、Jupyter、LangChain、PaddlePaddle、Sphinx、Pydantic、LlamaIndex……

Ruff 是什麼?為什麼它能吸引大量的開源專案使用?相比於其它程式碼分析工具,它有哪些突出之處,是否還有一些侷限性?現在是否值得將專案在用的工具都替換成它呢?

帶著這些問題,本文將帶你全方位瞭解這個火爆的專案。

Ruff 加速 Rust 與 Python 的融合

Ruff 誕生於 2022 年 8 月,它是一個用 Rust 語言編寫的高效能的 Python 靜態程式碼分析工具,比其它分析工具快幾個數量級(10-100 倍),而且功能也很全面。

程式碼分析工具 即 Linter,用於檢查程式碼中的語法錯誤、編碼規範問題、潛在的邏輯問題和程式碼質量問題等,可以提供實時反饋和自動修復建議。

在 Ruff 出現之前,社群裡的程式碼分析工具呈現出百花齊放之勢,比如有 Pylint、Flake8、Autoflake、Pyflakes、Pycodestyle 等等,它們的共同點是都使用 Python 編寫而成。

Ruff 異軍突起,在效能方面立於不敗之地,主要得益於 Rust 天然的速度優勢。Ruff 的出現,就像基於大語言模型的 ChatGPT 橫空出世,所有競爭對手瞬間就黯淡失色了。

兩個月前,我翻譯了一篇《Python 2023 年的 3 個趨勢》,它預測的第一個趨勢就是 Rust 將加快融入到 Python 相關的專案和工具中,舉出的例子就有 Ruff。

我現在可以補充一個觀察了:用 Rust 開發的新工具將淘汰用其它語言開發的工具,而且新工具的普及速度可能比你的預想快得多!

Ruff 專案的成功,將刺激出更多 Python+Rust 的專案。它的作者 Charlie Marsh 立志於給 Python 構建高效能的開發工具,巧合的是我曾翻譯過他寫的《Using Mypy in production at Spring》,這篇文章恰好釋出於 Ruff 誕生的 2022 年 8 月!

因此,我有理由推測:在 Ruff 專案成熟後,他將用 Rust 開發高效能的 Python 型別檢查工具,到時候,目前流行的 Mypy、Pytype、Pyright 和 Pyre 等工具將迎來一大勁敵。(題外話:Python 社群紛亂繁多的虛擬環境管理工具和依賴包管理工具,也有望迎來變革了吧!)

這裡還必須介紹兩個 Rust 專案,因為 Ruff 的成功離不開它們:

  • RustPython :用 Rust 寫成的 Python 直譯器。Ruff 利用了它高效能的 AST 解析器,以此實現了自己的 AST 遍歷、存取器抽象和程式碼質量檢測邏輯
  • Maturin :用 Rust 寫成的打包工具,可以將 Rust 專案打包成 Python 可用的包,從而可以被我們「pip install」後使用,且不需要設定 Rust 環境

Ruff 的優點與侷限性

介紹完最關鍵的特性後(速度極快、支援 pip),我們接下來看看 Ruff 的其它方面。

總體而言,它具有這些特點:

  • 支援 pyproject.toml
  • 相容 Python 3.11
  • 超過 500 條內建規則,與 Flake8 內建的規則集近乎對等
  • 重新實現了數十個 Flake8 外掛,如 flake8-bugbear、flake8-comprehensions 等
  • 支援自動修復,可自動糾正錯誤(例如,刪除未使用的匯入)
  • 內建快取,可避免重複分析未更改的檔案
  • 支援 VS Code、Pycharm、Neovim、Sublime Text、Emacs 等編輯器
  • 對 monorepo 友好,具有分層和級聯設定

首先最值得介紹的是它支援的規則。Ruff 借鑑了流行的工具如 Flake8、autoflake、isort、pyupgrade、yesqa 等等,然後用 Rust 重新實現了超過 500 條規則。它本身不支援外掛,但是吸收了數十個常用的 Flake8 外掛的設計,使得已囊括的規則範圍比其它任何工具都大。

Ruff 的作者還非常熟悉其它語言的分析工具,比如 Rust 的 Clippy 和 JavaScript 的 ESLint,並從這些專案上得到了設計上的啟發。

Ruff 站在了多個工具/外掛的肩膀上,重新實現了它們驗證過的規則,也借鑑了它們的 API 和實現細節,這使得它扮演了一種「集大成」的角色,很方便使用者們作工具的順滑遷移。

Ruff 第二個值得介紹的特點是,它沒有侷限於 Linter 的定位,而是借鑑 Rome、Prettier 和 Black 這些程式碼格式化工具(Formatter),也實現了程式碼格式化的功能。借鑑了 Autoflake、ESLint、Fixit 等工具,實現了程式碼自動糾錯的功能。另外,它還借鑑了使用很廣泛的 isort,支援對 import 作快速排序。

這些表明作者的目標並不只是開發一款優秀的程式碼分析工具,而是在靜態程式碼分析的核心功能外,要創造出更多的可能性。此舉是開發者的福音啊,以後一個工具就能滿足多種訴求,再也不必糾結於不同工具的選型、共同作業與維護了!

Ruff 還有其它的優點,例如支援 pyproject.toml 、支援 Python 3.11、支援只分析變更的檔案,等等。另外,它也有著一些侷限性:

  • 支援的 lint 規則還有不夠
  • 不支援使用外掛,擴充套件性不強
  • 用 Rust 開發的,因此不便於在出錯時 debug,也不便於 Python 開發者給它貢獻程式碼

關於第一點,畢竟 Ruff 只是 8 個月大的新生專案,支援更多的規則,只是時間問題。至於外掛帶來的擴充套件性和程式語言的開發者生態,原因也是 Rust,屬於「有得必有失」了。

Ruff 的使用

介紹完 Ruff 的整體情況後,我們接著看看該如何使用它吧。

首先是安裝,可以用 Conda 和其它包管理工具,也可以直接用 pip:

pip install ruff

可以通過以下命令執行:

ruff check .                        # 分析當前及子目錄內的所有檔案
ruff check path/to/code/            # 分析指定目錄及子目錄內的所有檔案
ruff check path/to/code/*.py        # 分析指定目錄內的所有py檔案
ruff check path/to/code/to/file.py  # 分析 file.py

可以用作預提交的勾點:

- repo: https://github.com/charliermarsh/ruff-pre-commit
  # Ruff version.
  rev: 'v0.0.261'
  hooks:
    - id: ruff

可以通過 pyproject.toml ,ruff.toml 或 .ruff.toml 檔案進行設定,預設設定已能滿足基本使用,詳細設定可以參見檔案的 Configuration

Ruff 提供了官方的 VS Code 外掛,可以快速上手:

Ruff 官方沒有提供 Pycharm 的外掛,社群中有人釋出了一個 Ruff 外掛。

另外,它還提供了ruff-lsp ,可以被整合到任何支援 Language Server Protocol 的編輯器中,例如 Neovim、Sublime Text、Emacs 等等。

小結

本文從 HTTPX 和 Starlette 採納 Ruff 的新聞開始,向讀者介紹了這個僅誕生 8 個月卻俘獲了一大批知名開源專案。它最突出的特點是使用 Rust 開發,因此在效能方面遠遠超越同類工具,此外,它借鑑了眾多工具和外掛的設計,不僅靜態程式碼分析的規則全面,而且還具備程式碼格式化、程式碼自動糾錯和 import 排序等非其它 linter 所擁有的功能。

Ruff 的成功為 Python 社群提供了一個鮮活的榜樣,可以預見,我們將迎來一波用 Rust 開發的高效能工具。Ruff 的成功,與最近火爆的 ChatGPT 一樣,它們傳遞出了一個「這事兒能成」的訊號,從而會引爆一場使用新技術的變革!(非常巧合的是:Rust 1.0 在 2015 年 5 月釋出,而 OpenAI 在 2015 年 12 月成立。)

總體而言,Ruff 非常強大,憑實力而風靡 Python 社群,絕對推薦使用!它的使用檔案很友好,如果你想了解更多細節,可以去翻查。