|
2 | 2 |
|
3 | 3 | from __future__ import annotations |
4 | 4 |
|
5 | | -import logging |
| 5 | +# only import built-ins at top level to avoid interpreter startup overhead |
6 | 6 | import os |
7 | | -from functools import cache |
8 | | -from importlib.metadata import version as _metadata_version |
9 | | -from typing import TYPE_CHECKING, cast |
| 7 | +import sys |
10 | 8 |
|
11 | | -from pre_commit import lang_base, main |
12 | | -from pre_commit.languages import python |
13 | | -from pre_commit.languages.python import in_env, norm_version |
14 | | -from pre_commit.util import CalledProcessError, cmd_output, cmd_output_b |
15 | | -from uv import find_uv_bin |
| 9 | +_original_main = None |
16 | 10 |
|
17 | | -if TYPE_CHECKING: |
18 | | - from collections.abc import Sequence |
19 | 11 |
|
20 | | - from pre_commit.prefix import Prefix |
| 12 | +def _patch() -> None: |
| 13 | + global _original_main |
| 14 | + if _original_main is not None: # already patched, nothing more to do |
| 15 | + return |
| 16 | + calling_pre_commit = "FORCE_PRE_COMMIT_UV_PATCH" in os.environ |
| 17 | + if not calling_pre_commit and sys.argv and sys.argv[0]: # must have arguments |
| 18 | + calling = sys.argv[1] if sys.argv[0] == sys.executable and len(sys.argv) >= 1 else sys.argv[0] |
| 19 | + if os.path.split(calling)[1] == f"pre-commit{'.exe' if sys.platform == 'win32' else ''}": |
| 20 | + calling_pre_commit = True |
21 | 21 |
|
| 22 | + if calling_pre_commit and os.environ.get("DISABLE_PRE_COMMIT_UV_PATCH") is None: |
| 23 | + from pre_commit import main # noqa: PLC0415 |
22 | 24 |
|
23 | | -__version__ = _metadata_version("pre-commit-uv") |
24 | | -_uv_version = _metadata_version("uv") |
25 | | -_original_main = main.main |
| 25 | + _original_main, main.main = main.main, _new_main |
26 | 26 |
|
27 | 27 |
|
28 | | -def _patch() -> None: |
29 | | - if os.environ.get("DISABLE_PRE_COMMIT_UV_PATCH") is None: |
30 | | - main.main = _new_main |
| 28 | +def _new_main(argv: list[str] | None = None) -> int: |
| 29 | + # imports applied locally to avoid patching import overhead cost |
| 30 | + from functools import cache # noqa: PLC0415 |
| 31 | + from typing import TYPE_CHECKING, cast # noqa: PLC0415 |
31 | 32 |
|
| 33 | + from pre_commit.languages import python # noqa: PLC0415 |
32 | 34 |
|
33 | | -def _new_main(argv: Sequence[str] | None = None) -> int: |
34 | | - python.install_environment = _install_environment |
35 | | - python._version_info = _version_info # noqa: SLF001 |
36 | | - return cast(int, _original_main(argv)) |
| 35 | + if TYPE_CHECKING: |
| 36 | + from collections.abc import Sequence # noqa: PLC0415 |
| 37 | + |
| 38 | + from pre_commit.prefix import Prefix # noqa: PLC0415 |
| 39 | + |
| 40 | + def _install_environment( |
| 41 | + prefix: Prefix, |
| 42 | + version: str, |
| 43 | + additional_dependencies: Sequence[str], |
| 44 | + ) -> None: |
| 45 | + import logging # noqa: PLC0415 |
37 | 46 |
|
| 47 | + from pre_commit.lang_base import environment_dir, setup_cmd # noqa: PLC0415 |
| 48 | + from pre_commit.util import cmd_output_b # noqa: PLC0415 |
38 | 49 |
|
39 | | -def _install_environment( |
40 | | - prefix: Prefix, |
41 | | - version: str, |
42 | | - additional_dependencies: Sequence[str], |
43 | | -) -> None: |
44 | | - logging.getLogger("pre_commit").info("Using pre-commit with uv %s via pre-commit-uv %s", _uv_version, __version__) |
45 | | - uv = find_uv_bin() |
| 50 | + logger = logging.getLogger("pre_commit") |
| 51 | + logger.info("Using pre-commit with uv %s via pre-commit-uv %s", uv_version(), self_version()) |
| 52 | + uv = _uv() |
| 53 | + venv_cmd = [uv, "venv", environment_dir(prefix, python.ENVIRONMENT_DIR, version)] |
| 54 | + py = python.norm_version(version) |
| 55 | + if py is not None: |
| 56 | + venv_cmd.extend(("-p", py)) |
| 57 | + cmd_output_b(*venv_cmd, cwd="/") |
46 | 58 |
|
47 | | - venv_cmd = [uv, "venv", lang_base.environment_dir(prefix, python.ENVIRONMENT_DIR, version)] |
48 | | - py = norm_version(version) |
49 | | - if py is not None: |
50 | | - venv_cmd.extend(("-p", py)) |
51 | | - cmd_output_b(*venv_cmd, cwd="/") |
| 59 | + with python.in_env(prefix, version): |
| 60 | + setup_cmd(prefix, (uv, "pip", "install", ".", *additional_dependencies)) |
52 | 61 |
|
53 | | - with in_env(prefix, version): |
54 | | - lang_base.setup_cmd(prefix, (uv, "pip", "install", ".", *additional_dependencies)) |
| 62 | + @cache |
| 63 | + def _uv() -> str: |
| 64 | + from uv import find_uv_bin # noqa: PLC0415 |
55 | 65 |
|
| 66 | + return find_uv_bin() |
56 | 67 |
|
57 | | -@cache |
58 | | -def _version_info(exe: str) -> str: |
59 | | - prog = 'import sys;print(".".join(str(p) for p in sys.version_info[0:3]))' |
60 | | - try: |
61 | | - return cast(str, cmd_output(exe, "-S", "-c", prog)[1].strip()) |
62 | | - except CalledProcessError: |
63 | | - return f"<<error retrieving version from {exe}>>" |
| 68 | + @cache |
| 69 | + def self_version() -> str: |
| 70 | + from importlib.metadata import version as _metadata_version # noqa: PLC0415 |
64 | 71 |
|
| 72 | + return _metadata_version("pre-commit-uv") |
65 | 73 |
|
66 | | -__all__ = [ |
67 | | - "__version__", |
68 | | -] |
| 74 | + @cache |
| 75 | + def uv_version() -> str: |
| 76 | + from importlib.metadata import version as _metadata_version # noqa: PLC0415 |
| 77 | + |
| 78 | + return _metadata_version("uv") |
| 79 | + |
| 80 | + @cache |
| 81 | + def _version_info(exe: str) -> str: |
| 82 | + from pre_commit.util import CalledProcessError, cmd_output # noqa: PLC0415 |
| 83 | + |
| 84 | + prog = 'import sys;print(".".join(str(p) for p in sys.version_info[0:3]))' |
| 85 | + try: |
| 86 | + return cast(str, cmd_output(exe, "-S", "-c", prog)[1].strip()) |
| 87 | + except CalledProcessError: |
| 88 | + return f"<<error retrieving version from {exe}>>" |
| 89 | + |
| 90 | + python.install_environment = _install_environment |
| 91 | + python._version_info = _version_info # noqa: SLF001 |
| 92 | + assert _original_main is not None # noqa: S101 |
| 93 | + return cast(int, _original_main(argv)) |
0 commit comments