From cdb1c2bd97df1c19d7e3407694bf414de7b28d41 Mon Sep 17 00:00:00 2001 From: phi Date: Sun, 25 Aug 2024 22:53:06 +0900 Subject: [PATCH] fix: uv --- src/sync_uv_pre_commit/cli.py | 19 +++++++--- src/sync_uv_pre_commit/toml.py | 63 ++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 5 deletions(-) create mode 100644 src/sync_uv_pre_commit/toml.py diff --git a/src/sync_uv_pre_commit/cli.py b/src/sync_uv_pre_commit/cli.py index 13b9303..17d04c5 100644 --- a/src/sync_uv_pre_commit/cli.py +++ b/src/sync_uv_pre_commit/cli.py @@ -3,7 +3,6 @@ import argparse import logging import re -import shutil import subprocess import sys import tempfile @@ -15,6 +14,7 @@ from pre_commit.clientlib import InvalidConfigError, load_config from sync_uv_pre_commit.log import ColorFormatter +from sync_uv_pre_commit.toml import combine_dev_dependencies if TYPE_CHECKING: from collections.abc import Generator @@ -61,16 +61,25 @@ def resolve_pyproject( ) -> Path: origin_pyproject, temp_directory = Path(pyproject), Path(temp_directory) new_pyproject = temp_directory / "pyproject.toml" - shutil.copy(origin_pyproject, new_pyproject) + + key, new_pyproject = combine_dev_dependencies(origin_pyproject, new_pyproject) uv_process = subprocess.run( # noqa: S603 - ["uv", "lock"], # noqa: S607 + [ # noqa: S607 + "uv", + "pip", + "compile", + new_pyproject.name, + "-o", + "requirements.txt", + "--extra", + key, + ], cwd=temp_directory, check=False, capture_output=True, text=True, ) - shutil.rmtree(temp_directory / ".venv") try: uv_process.check_returncode() except subprocess.CalledProcessError as exc: @@ -81,7 +90,7 @@ def resolve_pyproject( sys.exit(ExitCode.PARSING) sys.exit(ExitCode.UNKNOWN) - return temp_directory / "requirements-dev.lock" + return temp_directory / "requirements.txt" @lru_cache diff --git a/src/sync_uv_pre_commit/toml.py b/src/sync_uv_pre_commit/toml.py new file mode 100644 index 0000000..a1cfefe --- /dev/null +++ b/src/sync_uv_pre_commit/toml.py @@ -0,0 +1,63 @@ +from __future__ import annotations + +from pathlib import Path +from typing import TYPE_CHECKING, Any + +import toml + +if TYPE_CHECKING: + from os import PathLike + +__all__ = [] + + +def combine_dev_dependencies( + pyproject: str | PathLike[str], destination: str | PathLike[str] +) -> tuple[str, Path]: + pyproject = Path(pyproject) + destination = Path(destination) + + pyproject_obj = read_pyproject(pyproject) + key, new_pyproject = dev_dependencies_to_dependencies(pyproject_obj) + write_pyproject(new_pyproject, destination) + + return key, destination + + +def read_pyproject(pyproject: str | PathLike[str]) -> dict[str, Any]: + pyproject = Path(pyproject) + with pyproject.open() as f: + return toml.load(f) + + +def write_pyproject( + pyproject: dict[str, Any], pyproject_path: str | PathLike[str] +) -> Path: + pyproject_path = Path(pyproject_path) + with pyproject_path.open("w") as f: + toml.dump(pyproject, f) + return pyproject_path + + +def dev_dependencies_to_dependencies( + pyproject: str | PathLike[str] | dict[str, Any], +) -> tuple[str, dict[str, Any]]: + if not isinstance(pyproject, dict): + pyproject = read_pyproject(pyproject) + + key = "dev_dependencies" + project: dict[str, Any] = pyproject["project"] + + optional_dependencies: dict[str, list[str]] = project.setdefault( + "optional-dependencies", {} + ) + if key in optional_dependencies: + key = f"new_{key}" + + uv_config: dict[str, Any] = pyproject.setdefault("uv", {}) + dev_dependencies: list[str] = uv_config.setdefault("dev-dependencies", []) + + optional_dependencies[key] = dev_dependencies + pyproject["project"]["optional-dependencies"] = optional_dependencies + + return key, pyproject