From 9845e65ba1e245e59249e72313a2f8cb80ab48da Mon Sep 17 00:00:00 2001
From: Christian Clauss <cclauss@me.com>
Date: Fri, 14 Apr 2023 18:49:01 +0200
Subject: [PATCH] build: replace Python linter flake8 with ruff

PR-URL: https://github.com/nodejs/node/pull/47519
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Richard Lau <rlau@redhat.com>
Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
Reviewed-By: Jiawen Geng <technicalcute@gmail.com>
---
 .flake8                       |  3 ---
 .github/workflows/linters.yml |  2 +-
 .gitignore                    |  1 -
 Makefile                      | 18 ++++++-------
 pyproject.toml                | 48 +++++++++++++++++++++++++++++++++++
 5 files changed, 58 insertions(+), 14 deletions(-)
 delete mode 100644 .flake8
 create mode 100644 pyproject.toml

diff --git a/.flake8 b/.flake8
deleted file mode 100644
index eee7c33b89d262..00000000000000
--- a/.flake8
+++ /dev/null
@@ -1,3 +0,0 @@
-[flake8]
-exclude=.git,deps,lib,src,tools/gyp,tools/inspector_protocol,tools/pip,tools/v8_gypfiles/broken
-ignore=E1,E2,E3,E4,E5,E7,W5,W6
diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml
index 96eb4604a20b70..e9b2f776de26a5 100644
--- a/.github/workflows/linters.yml
+++ b/.github/workflows/linters.yml
@@ -129,7 +129,7 @@ jobs:
         run: npx envinfo
       - name: Lint Python
         run: |
-          make lint-py-build || true
+          make lint-py-build
           make lint-py
   lint-yaml:
     if: github.event.pull_request.draft == false
diff --git a/.gitignore b/.gitignore
index 9881176886826b..df8616d14a8909 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,7 +14,6 @@
 !.eslintignore
 !.eslintrc.js
 !.eslintrc.yaml
-!.flake8
 !.gitattributes
 !.github
 !.gitignore
diff --git a/Makefile b/Makefile
index 85222f00ce5b86..5564cfd7778ff9 100644
--- a/Makefile
+++ b/Makefile
@@ -1514,22 +1514,22 @@ cpplint: lint-cpp
 	$(warning Please use lint-cpp instead of cpplint)
 
 .PHONY: lint-py-build
-# python -m pip install flake8
+# python -m pip install ruff
 # Try with '--system' if it fails without; the system may have set '--user'
 lint-py-build:
-	$(info Pip installing flake8 linter on $(shell $(PYTHON) --version)...)
-	$(PYTHON) -m pip install --upgrade -t tools/pip/site-packages flake8 || \
-		$(PYTHON) -m pip install --upgrade --system -t tools/pip/site-packages flake8
+	$(info Pip installing ruff on $(shell $(PYTHON) --version)...)
+	$(PYTHON) -m pip install --upgrade --target tools/pip/site-packages ruff || \
+		$(PYTHON) -m pip install --upgrade --system --target tools/pip/site-packages ruff
 
 .PHONY: lint-py
-ifneq ("","$(wildcard tools/pip/site-packages/flake8)")
-# Lints the Python code with flake8.
-# Flag the build if there are Python syntax errors or undefined names
+ifneq ("","$(wildcard tools/pip/site-packages/ruff)")
+# Lint the Python code with ruff.
 lint-py:
-	PYTHONPATH=tools/pip $(PYTHON) -m flake8 --count --show-source --statistics .
+	tools/pip/site-packages/bin/ruff --version
+	tools/pip/site-packages/bin/ruff .
 else
 lint-py:
-	$(warning Python linting with flake8 is not available)
+	$(warning Python linting with ruff is not available)
 	$(warning Run 'make lint-py-build')
 endif
 
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 00000000000000..6b51197ad66c2e
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,48 @@
+[tool.ruff]
+select = [
+  "C90",    # McCabe cyclomatic complexity
+  "E",      # pycodestyle
+  "F",      # Pyflakes
+  "ICN",    # flake8-import-conventions
+  "INT",    # flake8-gettext
+  "PLC",    # Pylint conventions
+  "PLE",    # Pylint errors
+  "PLR09",  # Pylint refactoring: max-args, max-branches, max returns, max-statements
+  "PYI",    # flake8-pyi
+  "RSE",    # flake8-raise
+  "RUF",    # Ruff-specific rules
+  "T10",    # flake8-debugger
+  "TCH",    # flake8-type-checking
+  "TID",    # flake8-tidy-imports
+  "W",      # pycodestyle
+  "YTT",    # flake8-2020
+]
+exclude = [
+  "deps",
+  "tools/inspector_protocol",
+]
+ignore = [
+  "E401",
+  "E402",
+  "E7",
+  "PLC1901",
+  "RUF005",
+  "RUF100",
+]
+line-length = 172
+target-version = "py37"
+
+[tool.ruff.mccabe]
+max-complexity = 100
+
+[tool.ruff.per-file-ignores]
+"tools/checkimports.py" = ["W605"]
+"tools/gyp/pylib/gyp/xcodeproj_file.py" = ["PLE0101"]
+"tools/icu/shrink-icu-src.py" = ["W605"]
+"tools/mkssldef.py" = ["W605"]
+
+[tool.ruff.pylint]
+max-args = 12
+max-branches = 110
+max-returns = 12
+max-statements = 289