From 158367bf913f5a5df2c36f0d160ac35f96b5364c Mon Sep 17 00:00:00 2001 From: Ofek Lev Date: Sun, 31 Dec 2023 07:11:26 -0500 Subject: [PATCH] Improve responsiveness when invoked via Python (#9315) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This saves a handful of milliseconds on Windows and even more on other platforms when running `python -m ruff`. On non-Windows systems the process is replaced directly (impossible on Windows unfortunately). ``` ❯ docker run --rm python:3.11 bash -c "for i in {1..15}; do python -m timeit -n 1 -r 1 'from pathlib import Path'; done" 1 loop, best of 1: 25.7 msec per loop 1 loop, best of 1: 3.07 msec per loop 1 loop, best of 1: 3.16 msec per loop 1 loop, best of 1: 3.06 msec per loop 1 loop, best of 1: 3.32 msec per loop 1 loop, best of 1: 3.93 msec per loop 1 loop, best of 1: 3.26 msec per loop 1 loop, best of 1: 3.73 msec per loop 1 loop, best of 1: 3.1 msec per loop 1 loop, best of 1: 3.29 msec per loop 1 loop, best of 1: 3.12 msec per loop 1 loop, best of 1: 3.05 msec per loop 1 loop, best of 1: 3.04 msec per loop 1 loop, best of 1: 3.19 msec per loop 1 loop, best of 1: 3.04 msec per loop ❯ docker run --rm python:3.11 bash -c "for i in {1..15}; do python -m timeit -n 1 -r 1 'import subprocess'; done" 1 loop, best of 1: 31.2 msec per loop 1 loop, best of 1: 3.75 msec per loop 1 loop, best of 1: 4.71 msec per loop 1 loop, best of 1: 3.88 msec per loop 1 loop, best of 1: 4.08 msec per loop 1 loop, best of 1: 4.35 msec per loop 1 loop, best of 1: 3.94 msec per loop 1 loop, best of 1: 4.06 msec per loop 1 loop, best of 1: 3.88 msec per loop 1 loop, best of 1: 3.85 msec per loop 1 loop, best of 1: 3.84 msec per loop 1 loop, best of 1: 4.01 msec per loop 1 loop, best of 1: 4.21 msec per loop 1 loop, best of 1: 4.07 msec per loop 1 loop, best of 1: 4.11 msec per loop ❯ python -m timeit -n 1 -r 1 "from pathlib import Path" 1 loop, best of 1: 5.25 msec per loop ❯ python -m timeit -n 1 -r 1 "import subprocess" 1 loop, best of 1: 7.61 msec per loop ``` --- python/ruff/__main__.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/python/ruff/__main__.py b/python/ruff/__main__.py index 44384bc14b4a8..be79913a2bfa9 100644 --- a/python/ruff/__main__.py +++ b/python/ruff/__main__.py @@ -1,17 +1,15 @@ import os -import subprocess import sys import sysconfig -from pathlib import Path -def find_ruff_bin() -> Path: +def find_ruff_bin() -> str: """Return the ruff binary path.""" ruff_exe = "ruff" + sysconfig.get_config_var("EXE") - path = Path(sysconfig.get_path("scripts")) / ruff_exe - if path.is_file(): + path = os.path.join(sysconfig.get_path("scripts"), ruff_exe) + if os.path.isfile(path): return path if sys.version_info >= (3, 10): @@ -23,7 +21,7 @@ def find_ruff_bin() -> Path: else: user_scheme = "posix_user" - path = Path(sysconfig.get_path("scripts", scheme=user_scheme)) / ruff_exe + path = os.path.join(sysconfig.get_path("scripts", scheme=user_scheme), ruff_exe) if path.is_file(): return path @@ -31,8 +29,11 @@ def find_ruff_bin() -> Path: if __name__ == "__main__": - ruff = find_ruff_bin() - # Passing a path-like to `subprocess.run()` on windows is only supported in 3.8+, - # but we also support 3.7 - completed_process = subprocess.run([os.fsdecode(ruff), *sys.argv[1:]]) - sys.exit(completed_process.returncode) + ruff = os.fsdecode(find_ruff_bin()) + if sys.platform == "win32": + import subprocess + + completed_process = subprocess.run([ruff, *sys.argv[1:]]) + sys.exit(completed_process.returncode) + else: + os.execvp(ruff, [ruff, *sys.argv[1:]])