Python: Add docstrings to OpenAPI-generated dataclasses

Take the 'description' fields from the OpenAPI schema definition file,
and use those to generate docstrings for the dataclasses.

This adds another dependency to the generator's virtualenv:
docformatter. The generator already runs autopep8 via Blender's `make
format` command, but that doesn't rewrap long docstrings. That's what
docformatter now does.

No functional changes, just added developer comfort.

Pull Request: https://projects.blender.org/blender/blender/pulls/158598
This commit is contained in:
Sybren A. Stüvel 2026-05-14 16:19:10 +02:00
parent decc6161df
commit c06b5c1dbd
2 changed files with 203 additions and 7 deletions

View file

@ -45,6 +45,7 @@ YAML_PATHS = [
REQUIREMENTS = [
"datamodel-code-generator ~= 0.53.0",
"PyYAML ~= 6.0.2",
"docformatter ~= 1.7.8",
]
# These arguments are quite likely to be used for all code generated with this
@ -76,6 +77,9 @@ COMMON_ARGS = [
# Remove the "generated on" timestamp from the output, so that running the
# generator is idempotent.
"--disable-timestamp",
"--use-inline-field-description",
"--use-schema-description",
]
@ -124,13 +128,8 @@ def main() -> None:
sys.stdout.flush()
# Format the generated Python code.
print("Formatting Python files")
py_paths_as_str = [str(path) for path in py_paths]
subprocess.run(
["make", "format", "PATHS={}".format(" ".join(py_paths_as_str))],
cwd=root_path,
check=True,
)
_docformatter(py_paths)
_make_format(root_path, py_paths)
print("Done generating data model files!")
@ -169,6 +168,45 @@ def _generate_datamodel(in_path: Path, in_type: str, out_path: Path) -> None:
raise SystemExit(f"unknown result from code generation: {status}")
def _docformatter(py_paths: list[Path]) -> None:
"""Run 'docformatter' on generated Python files.
This is necessary because the generated docstrings are very long, and
'make format' doesn't automatically rewrap them.
"""
from docformatter import format
from docformatter import configuration
print("Formatting docstrings")
argv = ["docformatter", "--in-place", *(str(path) for path in py_paths)]
cfg = configuration.Configurater(argv)
cfg.do_parse_arguments()
formatter = format.Formatter(
cfg.args,
stderror=sys.stderr,
stdin=sys.stdin,
stdout=sys.stdout,
)
result = formatter.do_format_files()
if result not in {format.FormatResult.ok, format.FormatResult.format_required}:
raise RuntimeError(f"Error {result} running docformatter")
def _make_format(root_path: Path, py_paths: list[Path]) -> None:
"""Run 'make format' on generated Python files."""
print("Formatting Python files")
py_paths_as_str = [str(path) for path in py_paths]
subprocess.run(
["make", "format", "PATHS={}".format(" ".join(py_paths_as_str))],
cwd=root_path,
check=True,
)
# --------- Below this point is the self-bootstrapping logic ---------