diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7a7aaa2..5dd123a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,7 +18,7 @@ jobs: strategy: max-parallel: 4 matrix: - python: [3.8, 3.9, "3.10", "3.11", "3.12"] + python: ["3.8", "3.9", "3.10", "3.11", "3.12"] steps: - uses: actions/checkout@v2 diff --git a/setup.cfg b/setup.cfg index c6ed15c..f0a509f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -22,7 +22,8 @@ classifiers = [options] zip_safe = false -packages = find: +packages = + setuptools_grpc include_package_data = true python_requires = ~=3.8 install_requires = @@ -32,6 +33,8 @@ install_requires = [options.entry_points] distutils.commands = build_grpc = setuptools_grpc.build_grpc:build_grpc +setuptools.finalize_distribution_options = + setuptools_grpc = setuptools_grpc:inject_build [options.extras_require] quality = @@ -39,10 +42,13 @@ quality = doc8 flake8 isort -tests = +test = + build pytest pytest-cov testfixtures + wheel + wheel-inspect [isort] profile = black diff --git a/setuptools_grpc/__init__.py b/setuptools_grpc/__init__.py index ea60b39..d006389 100644 --- a/setuptools_grpc/__init__.py +++ b/setuptools_grpc/__init__.py @@ -1,3 +1,15 @@ """Setuptools grpc.""" +from setuptools import Command, Distribution + __version__ = "0.5" + + +def has_grpc(build: Command) -> bool: + build_grpc = build.get_finalized_command("build_grpc") + return bool(build_grpc.proto_files + build_grpc.grpc_files) + + +def inject_build(dist: Distribution) -> None: + build = dist.get_command_class("build") + build.sub_commands.insert(0, ("build_grpc", has_grpc)) diff --git a/setuptools_grpc/build_grpc.py b/setuptools_grpc/build_grpc.py index dfe119d..9bf2b1b 100644 --- a/setuptools_grpc/build_grpc.py +++ b/setuptools_grpc/build_grpc.py @@ -61,23 +61,28 @@ def run(self): args.extend("-I%s" % x for x in includes) # Generate protobuf modules - log.info("building protos") - for proto_file in self.proto_files: - log.info("generating %s → %s", proto_file, py_module_name(proto_file)) - if protoc_main( - args - + ["--python_out", self.output_path, "--pyi_out", self.output_path] - + [os.path.join(self.proto_path, proto_file) for proto_file in self.proto_files] - ): - raise RuntimeError("grpc_build failed") + if self.proto_files: + log.info("building protos") + for proto_file in self.proto_files: + log.info("generating %s → %s", proto_file, py_module_name(proto_file)) + + protoc_args = ( + args + + ["--python_out", self.output_path, "--pyi_out", self.output_path] + + [os.path.join(self.proto_path, proto_file) for proto_file in self.proto_files] + ) + if protoc_main(protoc_args): + raise RuntimeError("grpc_build failed") # Generate grpc modules - log.info("building grpc") - for grpc_file in self.grpc_files: - log.info("generating %s → %s", grpc_file, grpc_py_module_name(grpc_file)) - if protoc_main( - args - + ["--grpc_python_out", self.output_path] - + [os.path.join(self.proto_path, grpc_file) for grpc_file in self.grpc_files] - ): - raise RuntimeError("grpc_build failed") + if self.grpc_files: + log.info("building grpc") + for grpc_file in self.grpc_files: + log.info("generating %s → %s", grpc_file, grpc_py_module_name(grpc_file)) + grpc_protoc_args = ( + args + + ["--grpc_python_out", self.output_path] + + [os.path.join(self.proto_path, grpc_file) for grpc_file in self.grpc_files] + ) + if protoc_main(grpc_protoc_args): + raise RuntimeError("grpc_build failed") diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/project_no_config/example/__init__.py b/tests/project_no_config/example/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/project_no_config/pyproject.toml b/tests/project_no_config/pyproject.toml new file mode 100644 index 0000000..a4c1730 --- /dev/null +++ b/tests/project_no_config/pyproject.toml @@ -0,0 +1,10 @@ +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" + +[project] +name = "example" +version = "0" + +[tool.setuptools] +packages = ["example"] diff --git a/tests/project_no_protos/example/__init__.py b/tests/project_no_protos/example/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/project_no_protos/pyproject.toml b/tests/project_no_protos/pyproject.toml new file mode 100644 index 0000000..154e9a0 --- /dev/null +++ b/tests/project_no_protos/pyproject.toml @@ -0,0 +1,10 @@ +[build-system] +requires = ["setuptools", "setuptools_grpc"] +build-backend = "setuptools.build_meta" + +[project] +name = "example" +version = "0" + +[tool.setuptools] +packages = ["example"] diff --git a/tests/project_protos/example/__init__.py b/tests/project_protos/example/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/project_protos/example/service.proto b/tests/project_protos/example/service.proto new file mode 100644 index 0000000..4eef568 --- /dev/null +++ b/tests/project_protos/example/service.proto @@ -0,0 +1,3 @@ +syntax = "proto3"; + +message Example {} diff --git a/tests/project_protos/pyproject.toml b/tests/project_protos/pyproject.toml new file mode 100644 index 0000000..154e9a0 --- /dev/null +++ b/tests/project_protos/pyproject.toml @@ -0,0 +1,10 @@ +[build-system] +requires = ["setuptools", "setuptools_grpc"] +build-backend = "setuptools.build_meta" + +[project] +name = "example" +version = "0" + +[tool.setuptools] +packages = ["example"] diff --git a/tests/project_protos/setup.cfg b/tests/project_protos/setup.cfg new file mode 100644 index 0000000..c12763a --- /dev/null +++ b/tests/project_protos/setup.cfg @@ -0,0 +1,2 @@ +[build_grpc] +proto_files = **/*.proto diff --git a/tests/test_init.py b/tests/test_init.py new file mode 100644 index 0000000..59b4173 --- /dev/null +++ b/tests/test_init.py @@ -0,0 +1,53 @@ +import shutil +from pathlib import Path + +import pytest +from build import ProjectBuilder +from setuptools import Distribution +from wheel_inspect import inspect_wheel + +from setuptools_grpc import has_grpc, inject_build + + +@pytest.fixture +def project_no_config(tmp_path): + shutil.copytree(Path(__file__).parent / "project_no_config", tmp_path, dirs_exist_ok=True) + builder = ProjectBuilder(tmp_path) + yield builder.build("wheel", output_directory=tmp_path) + + +@pytest.fixture +def project_no_protos(tmp_path): + shutil.copytree(Path(__file__).parent / "project_no_protos", tmp_path, dirs_exist_ok=True) + builder = ProjectBuilder(tmp_path) + yield builder.build("wheel", output_directory=tmp_path) + + +@pytest.fixture +def project_protos(tmp_path): + shutil.copytree(Path(__file__).parent / "project_protos", tmp_path, dirs_exist_ok=True) + builder = ProjectBuilder(tmp_path) + yield builder.build("wheel", output_directory=tmp_path) + + +def test_no_config(project_no_config): + output = inspect_wheel(project_no_config) + assert output["derived"]["modules"] == ["example"] + + +def test_no_protos(project_no_protos): + output = inspect_wheel(project_no_protos) + assert output["derived"]["modules"] == ["example"] + + +def test_protos(project_protos): + output = inspect_wheel(project_protos) + assert output["derived"]["modules"] == ["example", "example.service_pb2"] + + +def test_inject_build(): + dist = Distribution() + build_cls = dist.get_command_class("build") + sub_commands = list(build_cls.sub_commands) + inject_build(dist) + assert build_cls.sub_commands == [("build_grpc", has_grpc)] + sub_commands diff --git a/tox.ini b/tox.ini index 4193424..cd03a60 100644 --- a/tox.ini +++ b/tox.ini @@ -1,18 +1,15 @@ [tox] -minversion = 3.7.0 +minversion = 4.4.0 envlist = quality py{38,39,310,311,312} skip_missing_interpreters = true -isolated_build = true [testenv] -constrain_package_deps = true -package = editable extras = - tests + test commands = - pytest -v --cov=setuptools_grpc + pytest -v --cov=./setuptools_grpc {posargs:} [testenv:quality] extras =