diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 662a6a00..7b013bbf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -140,6 +140,9 @@ jobs: - "3.10" buf: - buf + click-version: + - "7.1.2" + - "latest" include: - os: ubuntu-latest python-version: "3.9" @@ -169,8 +172,11 @@ jobs: with: python-version: ${{ matrix.python-version }} - - name: Install poetry2conda - run: pip3 install poetry2conda + - name: Install poetry and poetry2conda + run: pip3 install poetry2conda poetry + + - name: Set click version + run: poetry add 'click@{{ matrix.click-version }}' - name: Generate conda environment file run: | diff --git a/poetry.lock b/poetry.lock index bff7fab4..5b3d7c0f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -441,7 +441,7 @@ testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytes [metadata] lock-version = "1.1" python-versions = ">=3.7,<3.11" -content-hash = "700eb4f96399592a7471888e3b86a17de8f9c238c9a9b9aa102791fcd51631db" +content-hash = "700f73776eef0393b918f2771a2decd32f2af394f39b72ab75df4cbd0037abe1" [metadata.files] astunparse = [ diff --git a/protoletariat/__main__.py b/protoletariat/__main__.py index 5af94aa6..2d8c76d7 100644 --- a/protoletariat/__main__.py +++ b/protoletariat/__main__.py @@ -2,6 +2,7 @@ from __future__ import annotations +import os import sys from pathlib import Path from typing import IO @@ -89,7 +90,7 @@ def main( ctx.obj.update( dict( - python_out=python_out, + python_out=Path(os.fsdecode(python_out)), create_package=create_package, overwrite_callback=_overwrite if in_place else _echo, module_suffixes=module_suffixes, @@ -99,9 +100,19 @@ def main( @main.command(help="Use protoc to generate the FileDescriptorSet blob") +@click.option( + "--protoc-path", + envvar="PROTOC_PATH", + type=str, + default="protoc", + show_default=True, + show_envvar=True, + help="Path to the `protoc` executable", +) @click.option( "-p", "--proto-path", + "proto_paths", multiple=True, required=True, type=click.Path( @@ -123,23 +134,18 @@ def main( path_type=Path, ), ) -@click.option( - "--protoc-path", - envvar="PROTOC_PATH", - type=str, - default="protoc", - show_default=True, - show_envvar=True, - help="Path to the `protoc` executable", -) @click.pass_context def protoc( ctx: click.Context, - proto_path: list[Path], - proto_files: list[Path], protoc_path: str, + proto_paths: list[Path], + proto_files: list[Path], ) -> None: - Protoc(protoc_path, proto_files, proto_path).fix_imports(**ctx.obj) + Protoc( + protoc_path=os.fsdecode(protoc_path), + proto_files=[Path(os.fsdecode(proto_file)) for proto_file in proto_files], + proto_paths=[Path(os.fsdecode(proto_path)) for proto_path in proto_paths], + ).fix_imports(**ctx.obj) @main.command(help="Use buf to generate the FileDescriptorSet blob") @@ -154,7 +160,7 @@ def protoc( ) @click.pass_context def buf(ctx: click.Context, buf_path: str) -> None: - Buf(buf_path).fix_imports(**ctx.obj) + Buf(buf_path=os.fsdecode(buf_path)).fix_imports(**ctx.obj) @main.command(help="Rewrite imports using FileDescriptorSet bytes from a file or stdin") diff --git a/protoletariat/fdsetgen.py b/protoletariat/fdsetgen.py index 60d00766..b689f040 100644 --- a/protoletariat/fdsetgen.py +++ b/protoletariat/fdsetgen.py @@ -2,7 +2,6 @@ import abc import fnmatch -import os import re import subprocess import tempfile @@ -52,6 +51,7 @@ def generate_file_descriptor_set_bytes(self) -> bytes: def fix_imports( self, + *, python_out: Path, create_package: bool, overwrite_callback: Callable[[Path, str], None], @@ -59,15 +59,13 @@ def fix_imports( exclude_imports_glob: Sequence[str], ) -> None: """Fix imports from protoc/buf generated code.""" - python_out = Path(os.fsdecode(python_out)) fdset = FileDescriptorSet.FromString(self.generate_file_descriptor_set_bytes()) for fd in fdset.file: - name = os.fsdecode(fd.name) - if _should_ignore(name, exclude_imports_glob): + if _should_ignore(fd.name, exclude_imports_glob): continue - fd_name = _remove_proto_suffix(name) + fd_name = _remove_proto_suffix(fd.name) rewriter = ASTImportRewriter() # services live outside of the corresponding generated Python # module, but they import it so we register a rewrite for the @@ -109,13 +107,14 @@ class Protoc(FileDescriptorSetGenerator): def __init__( self, + *, protoc_path: str, proto_files: Iterable[Path], proto_paths: Iterable[Path], ) -> None: - self.protoc_path = os.fsdecode(protoc_path) - self.proto_files = [os.fsdecode(file) for file in proto_files] - self.proto_paths = [os.fsdecode(path) for path in proto_paths] + self.protoc_path = protoc_path + self.proto_files = proto_files + self.proto_paths = proto_paths def generate_file_descriptor_set_bytes(self) -> bytes: with tempfile.NamedTemporaryFile(delete=False) as f: @@ -124,9 +123,9 @@ def generate_file_descriptor_set_bytes(self) -> bytes: [ self.protoc_path, "--include_imports", - "--descriptor_set_out=" + os.fsdecode(filename), - *["--proto_path=" + path for path in self.proto_paths], - *self.proto_files, + f"--descriptor_set_out={filename}", + *map("--proto_path={}".format, self.proto_paths), + *map(str, self.proto_files), ] ) @@ -139,7 +138,14 @@ def generate_file_descriptor_set_bytes(self) -> bytes: class Buf(FileDescriptorSetGenerator): """Generate the FileDescriptorSet using `buf`.""" - def __init__(self, buf_path: str) -> None: + def __init__(self, *, buf_path: str) -> None: + """Construct a `buf`-based `FileDescriptorSetGenerator`. + + Parameters + ---------- + buf_path + Path to buf executable + """ self.buf_path = buf_path def generate_file_descriptor_set_bytes(self) -> bytes: diff --git a/pyproject.toml b/pyproject.toml index 0e59c0f0..c06b3c0b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,7 +18,7 @@ classifiers = [ [tool.poetry.dependencies] python = ">=3.7,<3.11" astunparse = { version = "^1.6.3", python = "<3.9" } -click = "^8.0.1" +click = ">=7.1.2,<9" protobuf = "^3.19.1" [tool.poetry.dev-dependencies]