From e7ba381b77d24cdfbd1a1a8df9acd02db8e81e54 Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Tue, 3 Oct 2023 23:19:12 +0200 Subject: [PATCH] Add toml-sort linting tool for pyproject.toml (#2311) --- .github/workflows/build.yml | 2 +- Makefile | 11 +++- pyproject.toml | 46 +++++++++------- scripts/internal/git_pre_commit.py | 87 ++++++++++++++++++------------ 4 files changed, 92 insertions(+), 54 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c35eb7757..3f3ad76d9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -115,7 +115,7 @@ jobs: python-version: 3.x - name: 'Run linters' run: | - python3 -m pip install isort rstcheck flake8 flake8-blind-except flake8-bugbear flake8-debugger flake8-print flake8-quotes sphinx + python3 -m pip install isort rstcheck toml-sort flake8 flake8-blind-except flake8-bugbear flake8-debugger flake8-print flake8-quotes sphinx make lint-all # Check sanity of .tar.gz + wheel files diff --git a/Makefile b/Makefile index ecd2e17d5..95276f664 100644 --- a/Makefile +++ b/Makefile @@ -30,6 +30,7 @@ PY3_DEPS = \ setuptools \ sphinx_rtd_theme \ teyit \ + toml-sort \ twine \ virtualenv \ wheel @@ -205,7 +206,7 @@ flake8: ## Run flake8 linter. isort: ## Run isort linter. @git ls-files '*.py' | xargs $(PYTHON) -m isort --check-only --jobs=${NUM_WORKERS} -pylint: ## Python pylint (not mandatory, just run it from time to time) +_pylint: ## Python pylint (not mandatory, just run it from time to time) @git ls-files '*.py' | xargs $(PYTHON) -m pylint --rcfile=pyproject.toml --jobs=${NUM_WORKERS} lint-c: ## Run C linter. @@ -214,11 +215,15 @@ lint-c: ## Run C linter. lint-rst: ## Run C linter. @git ls-files '*.rst' | xargs rstcheck --config=pyproject.toml +lint-toml: ## Linter for pyproject.toml + @git ls-files '*.toml' | xargs toml-sort --check + lint-all: ## Run all linters ${MAKE} flake8 ${MAKE} isort ${MAKE} lint-c ${MAKE} lint-rst + ${MAKE} lint-toml # =================================================================== # Fixers @@ -234,10 +239,14 @@ fix-imports: ## Fix imports with isort. fix-unittests: ## Fix unittest idioms. @git ls-files '*test_*.py' | xargs $(PYTHON) -m teyit --show-stats +fix-toml: ## Fix pyproject.toml + @git ls-files '*.toml' | xargs toml-sort + fix-all: ## Run all code fixers. ${MAKE} fix-flake8 ${MAKE} fix-imports ${MAKE} fix-unittests + ${MAKE} fix-toml # =================================================================== # GIT diff --git a/pyproject.toml b/pyproject.toml index 25d436086..bf9435958 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,36 +3,36 @@ force_single_line = true # one import per line lines_after_imports = 2 # blank spaces after import section [tool.coverage.report] -omit = [ - "psutil/_compat.py", - "psutil/tests/*", - "setup.py", -] exclude_lines = [ "enum.IntEnum", "except ImportError:", "globals().update", - "if __name__ == .__main__.:", - "if _WINDOWS:", "if BSD", - "if enum is None:", - "if enum is not None:", "if FREEBSD", - "if has_enums:", "if LINUX", "if LITTLE_ENDIAN:", "if MACOS", "if NETBSD", "if OPENBSD", - "if ppid_map is None:", "if PY3:", "if SUNOS", - "if sys.platform.startswith", "if WINDOWS", + "if _WINDOWS:", + "if __name__ == .__main__.:", + "if enum is None:", + "if enum is not None:", + "if has_enums:", + "if ppid_map is None:", + "if sys.platform.startswith", "import enum", "pragma: no cover", "raise NotImplementedError", ] +omit = [ + "psutil/_compat.py", + "psutil/tests/*", + "setup.py", +] [tool.pylint.messages_control] # Important ones: @@ -79,17 +79,25 @@ ignore_messages = [ "Hyperlink target \".*?\" is not referenced", ] -[build-system] -requires = ["setuptools>=43", "wheel"] -build-backend = "setuptools.build_meta" +[tool.tomlsort] +in_place = true +no_sort_tables = true +sort_inline_arrays = true +spaces_before_inline_comment = 2 +spaces_indent_inline_array = 4 +trailing_comma_inline_array = true [tool.cibuildwheel] -skip = ["pp*", "*-musllinux*"] -test-extras = "test" +skip = ["*-musllinux*", "pp*"] test-command = [ "env PYTHONWARNINGS=always PYTHONUNBUFFERED=1 PSUTIL_DEBUG=1 PSUTIL_SCRIPTS_DIR={project}/scripts python {project}/psutil/tests/runner.py", - "env PYTHONWARNINGS=always PYTHONUNBUFFERED=1 PSUTIL_DEBUG=1 PSUTIL_SCRIPTS_DIR={project}/scripts python {project}/psutil/tests/test_memleaks.py" + "env PYTHONWARNINGS=always PYTHONUNBUFFERED=1 PSUTIL_DEBUG=1 PSUTIL_SCRIPTS_DIR={project}/scripts python {project}/psutil/tests/test_memleaks.py", ] +test-extras = "test" [tool.cibuildwheel.macos] -archs = ["x86_64", "arm64"] +archs = ["arm64", "x86_64"] + +[build-system] +build-backend = "setuptools.build_meta" +requires = ["setuptools>=43", "wheel"] diff --git a/scripts/internal/git_pre_commit.py b/scripts/internal/git_pre_commit.py index 7ace3c08b..40eaee980 100755 --- a/scripts/internal/git_pre_commit.py +++ b/scripts/internal/git_pre_commit.py @@ -16,6 +16,7 @@ - assert "isort" checks pass - assert C linter checks pass - assert RsT checks pass +- assert TOML checks pass - abort if files were added/renamed/removed and MANIFEST.in was not updated Install this with "make install-git-hooks". @@ -96,16 +97,61 @@ def git_commit_files(): os.path.exists(x)] rst_files = [x for x in out.split('\n') if x.endswith('.rst') and os.path.exists(x)] + toml_files = [ + x for x in out.split("\n") if x.endswith(".toml") and os.path.exists(x) + ] new_rm_mv = sh( ["git", "diff", "--name-only", "--diff-filter=ADR", "--cached"] ) # XXX: we should escape spaces and possibly other amenities here new_rm_mv = new_rm_mv.split() - return (py_files, c_files, rst_files, new_rm_mv) + return (py_files, c_files, rst_files, toml_files, new_rm_mv) + + +def flake8(files): + assert os.path.exists('.flake8') + print("running flake8 (%s files)" % len(files)) + cmd = [PYTHON, "-m", "flake8", "--config=.flake8"] + files + if subprocess.call(cmd) != 0: + return sys.exit( + "python code didn't pass 'flake8' style check; " + + "try running 'make fix-flake8'" + ) + + +def isort(files): + print("running isort (%s)" % len(files)) + cmd = [PYTHON, "-m", "isort", "--check-only"] + files + if subprocess.call(cmd) != 0: + return sys.exit( + "python code didn't pass 'isort' style check; " + + "try running 'make fix-imports'") + + +def c_linter(files): + print("running clinter (%s)" % len(files)) + # XXX: we should escape spaces and possibly other amenities here + cmd = [PYTHON, "scripts/internal/clinter.py"] + files + if subprocess.call(cmd) != 0: + return sys.exit("C code didn't pass style check") + + +def toml_sort(files): + print("running toml linter (%s)" % len(files)) + cmd = ["toml-sort", "--check"] + files + if subprocess.call(cmd) != 0: + return sys.exit("%s didn't pass style check" % ' '.join(files)) + + +def rstcheck(files): + print("running rst linter (%s)" % len(files)) + cmd = ["rstcheck", "--config=pyproject.toml"] + files + if subprocess.call(cmd) != 0: + return sys.exit("RST code didn't pass style check") def main(): - py_files, c_files, rst_files, new_rm_mv = git_commit_files() + py_files, c_files, rst_files, toml_files, new_rm_mv = git_commit_files() # Check file content. for path in py_files: if os.path.realpath(path) == THIS_SCRIPT: @@ -127,40 +173,15 @@ def main(): # print("%s:%s %s" % (path, lineno, line)) # return sys.exit("bare except clause") - # Python linters if py_files: - # flake8 - assert os.path.exists('.flake8') - print("running flake8 (%s files)" % len(py_files)) - cmd = [PYTHON, "-m", "flake8", "--config=.flake8"] + py_files - ret = subprocess.call(cmd) - if ret != 0: - return sys.exit("python code didn't pass 'flake8' style check; " - "try running 'make fix-flake8'") - # isort - print("running isort (%s files)" % len(py_files)) - cmd = [PYTHON, "-m", "isort", "--check-only"] + py_files - ret = subprocess.call(cmd) - if ret != 0: - return sys.exit("python code didn't pass 'isort' style check; " - "try running 'make fix-imports'") - # C linter + flake8(py_files) + isort(py_files) if c_files: - print("running clinter (%s files)" % len(c_files)) - # XXX: we should escape spaces and possibly other amenities here - cmd = [PYTHON, "scripts/internal/clinter.py"] + c_files - ret = subprocess.call(cmd) - if ret != 0: - return sys.exit("C code didn't pass style check") - - # RST linter + c_linter(c_files) if rst_files: - print("running rst linter (%s)" % len(rst_files)) - cmd = ["rstcheck", "--config=pyproject.toml"] + rst_files - ret = subprocess.call(cmd) - if ret != 0: - return sys.exit("RST code didn't pass style check") - + rstcheck(rst_files) + if toml_files: + toml_sort(toml_files) if new_rm_mv: out = sh([PYTHON, "scripts/internal/generate_manifest.py"]) with open_text('MANIFEST.in') as f: