Source code for symforce.codegen.format_util

# ----------------------------------------------------------------------------
# SymForce - Copyright 2022, Skydio, Inc.
# This source code is under the Apache 2.0 license found in the LICENSE file.
# ----------------------------------------------------------------------------

import os
import shutil
import subprocess
from pathlib import Path

from ruff.__main__ import find_ruff_bin

from symforce import typing as T


[docs]def format_cpp(file_contents: str, filename: str) -> str: """ Autoformat a given C++ file using clang-format Args: file_contents: The unformatted contents of the file filename: A name that this file might have on disk; this does not have to be a real path, it's only used for clang-format to find the correct style file (by traversing upwards from this location) and to decide if an include is the corresponding .h file for a .cc file that's being formatted (this affects the include order) Returns: formatted_file_contents (str): The contents of the file after formatting """ try: import clang_format clang_format_path = str( Path(clang_format.__file__).parent / "data" / "bin" / "clang-format" ) except ImportError: clang_format_path = "clang-format" result = subprocess.run( [clang_format_path, f"-assume-filename={filename}"], input=file_contents, stdout=subprocess.PIPE, stderr=None, check=True, text=True, ) return result.stdout
_ruff_path: T.Optional[Path] = None def _find_ruff() -> Path: """ Find the ruff binary `find_ruff_bin` does not work in all environments, for example it does not work on debian when things are installed in `/usr/local/bin` and `sysconfig` only returns `/usr/bin`. Adding `shutil.which` should cover most cases, but not all, the better solution would require `ruff` putting the binary in `data` like `clang-format` does """ global _ruff_path # noqa: PLW0603 if _ruff_path is not None: return _ruff_path try: ruff = find_ruff_bin() except FileNotFoundError as ex: ruff = shutil.which("ruff") if ruff is None: raise FileNotFoundError("Could not find ruff") from ex _ruff_path = ruff return ruff
[docs]def format_py(file_contents: str, filename: str) -> str: """ Autoformat a given Python file using ruff Args: filename: A name that this file might have on disk; this does not have to be a real path, it's only used for ruff to find the correct style file (by traversing upwards from this location) """ result = subprocess.run( [_find_ruff(), "format", f"--stdin-filename={filename}", "-"], input=file_contents, stdout=subprocess.PIPE, check=True, # Disable the ruff cache. This is important for running in a hermetic context like a bazel # test, and shouldn't really hurt other use cases. If it does, we should work around this # differently. env=dict(os.environ, RUFF_NO_CACHE="true"), text=True, ) result = subprocess.run( [ _find_ruff(), "check", "--select=I", "--fix", "--quiet", f"--stdin-filename={filename}", "-", ], input=result.stdout, stdout=subprocess.PIPE, check=True, # Disable the ruff cache. This is important for running in a hermetic context like a bazel # test, and shouldn't really hurt other use cases. If it does, we should work around this # differently. env=dict(os.environ, RUFF_NO_CACHE="true"), text=True, ) return result.stdout
[docs]def format_py_dir(dirname: T.Openable) -> None: """ Autoformat python files in a directory (recursively) in-place """ subprocess.run( [_find_ruff(), "format", dirname], check=True, # Disable the ruff cache. This is important for running in a hermetic context like a bazel # test, and shouldn't really hurt other use cases. If it does, we should work around this # differently. env=dict(os.environ, RUFF_NO_CACHE="true"), text=True, )