Skip to content

Commit 49c727a

Browse files
committed
Allow configuring via pyproject.toml
Compilation of protocol buffer files sometimes need some extra configuration, like location of include files for external dependencies. These are available via command-line, but this is extremely inconvenient. This commit allow users to configure the compilation of protocol buffer files using pyproject.toml. Signed-off-by: Leandro Lucarella <[email protected]>
1 parent b62a259 commit 49c727a

File tree

2 files changed

+78
-7
lines changed

2 files changed

+78
-7
lines changed

src/frequenz/repo/config/__init__.py

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -224,9 +224,26 @@
224224
recursive-include submodules/api-common-protos/google *.proto
225225
```
226226
227-
For now there is no way to customize where the protocol files are located,
228-
where the generated files should be placed, or which extra directories must be
229-
included when compiling the protocol files.
227+
If the defaults are not suitable for you (for example you need to use more or less
228+
submodules or your proto files are located somewhere else, you can customize how
229+
the protocol files are generated by adding the following section to your
230+
`pyproject.toml` file:
231+
232+
```toml
233+
[tool.frequenz_repo_config.setuptools.grpc_tools]
234+
# Location of the proto files relative to the root of the repository (default: "proto")
235+
proto_path = "proto_files"
236+
# Glob pattern to use to find the proto files in the proto_path (default: "*.proto")
237+
proto_glob = "*.prt" # Default: "*.proto"
238+
# List of paths to pass to the protoc compiler as include paths (default:
239+
# ["submodules/api-common-protos"])
240+
include_paths = []
241+
# Path where to generate the Python files (default: "py")
242+
py_path = "generated"
243+
```
244+
245+
Please adapt the instructions above to your project structure if you need to change the
246+
defaults.
230247
"""
231248

232249
from . import nox, setuptools

src/frequenz/repo/config/setuptools/grpc_tools.py

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import pathlib as _pathlib
1414
import subprocess as _subprocess
1515
import sys as _sys
16+
import tomllib as _tomllib
1617

1718
import setuptools as _setuptools
1819

@@ -58,16 +59,69 @@ class CompileProto(_setuptools.Command):
5859
]
5960
"""Options of the command."""
6061

62+
DEFAULT_OPTIONS: dict[str, str] = {
63+
"proto_path": "proto",
64+
"proto_glob": "*.proto",
65+
"include_paths": "submodules/api-common-protos",
66+
"py_path": "py",
67+
}
68+
6169
def initialize_options(self) -> None:
6270
"""Initialize options."""
63-
self.proto_path = "proto"
64-
self.proto_glob = "*.proto"
65-
self.include_paths = "submodules/api-common-protos"
66-
self.py_path = "py"
71+
options = self._get_options_from_pyproject_toml(self.DEFAULT_OPTIONS)
72+
73+
self.proto_path = options["proto_path"]
74+
self.proto_glob = options["proto_glob"]
75+
self.include_paths = options["include_paths"]
76+
self.py_path = options["py_path"]
6777

6878
def finalize_options(self) -> None:
6979
"""Finalize options."""
7080

81+
def _get_options_from_pyproject_toml(
82+
self, defaults: dict[str, str]
83+
) -> dict[str, str]:
84+
"""Get the options from the pyproject.toml file.
85+
86+
The options are read from the `[tool.frequenz-repo-config.setuptools.grpc_tools]`
87+
section of the pyproject.toml file.
88+
89+
Args:
90+
defaults: The default values for the options.
91+
92+
Returns:
93+
The options read from the pyproject.toml file.
94+
"""
95+
try:
96+
with _pathlib.Path("pyproject.toml").open("rb") as toml_file:
97+
pyproject_toml = _tomllib.load(toml_file)
98+
except FileNotFoundError:
99+
return defaults
100+
except (IOError, OSError) as err:
101+
print(f"WARNING: Failed to load pyproject.toml: {err}")
102+
return defaults
103+
104+
try:
105+
config = pyproject_toml["tool"]["frequenz-repo-config"]["setuptools"][
106+
"grpc_tools"
107+
]
108+
except KeyError:
109+
return defaults
110+
111+
known_keys = frozenset(defaults.keys())
112+
config_keys = frozenset(config.keys())
113+
if unknown_keys := config_keys - known_keys:
114+
print(
115+
"WARNING: There are some configuration keys in pyproject.toml we don't "
116+
"know about and will be ignored: "
117+
+ ", ".join(f"'{k}'" for k in unknown_keys)
118+
)
119+
120+
if "include_paths" in config:
121+
config["include_paths"] = ",".join(config["include_paths"])
122+
123+
return dict(defaults, **{k: config[k] for k in (known_keys & config_keys)})
124+
71125
def run(self) -> None:
72126
"""Compile the Python protobuf files."""
73127
include_paths = self.include_paths.split(",")

0 commit comments

Comments
 (0)