[core] Enable ruff PTH (flake8-use-pathlib) lint family (#16661)

This commit is contained in:
J. Nick Koston
2026-05-26 00:14:42 -05:00
committed by GitHub
parent ae814cff5c
commit ae74920b81
54 changed files with 162 additions and 155 deletions

View File

@@ -3163,7 +3163,7 @@ def main() -> None:
defines_content += "\n"
defines_content += "\nnamespace esphome::api {} // namespace esphome::api\n"
with open(root / "api_pb2_defines.h", "w", encoding="utf-8") as f:
with (root / "api_pb2_defines.h").open("w", encoding="utf-8") as f:
f.write(defines_content)
content = FILE_HEADER
@@ -3448,13 +3448,13 @@ static void dump_bytes_field(DumpBuffer &out, const char *field_name, const uint
#endif // HAS_PROTO_MESSAGE_DUMP
"""
with open(root / "api_pb2.h", "w", encoding="utf-8") as f:
with (root / "api_pb2.h").open("w", encoding="utf-8") as f:
f.write(content)
with open(root / "api_pb2.cpp", "w", encoding="utf-8") as f:
with (root / "api_pb2.cpp").open("w", encoding="utf-8") as f:
f.write(cpp)
with open(root / "api_pb2_dump.cpp", "w", encoding="utf-8") as f:
with (root / "api_pb2_dump.cpp").open("w", encoding="utf-8") as f:
f.write(dump_cpp)
hpp = FILE_HEADER
@@ -3641,10 +3641,10 @@ static const char *const TAG = "api.service";
} // namespace esphome::api
"""
with open(root / "api_pb2_service.h", "w", encoding="utf-8") as f:
with (root / "api_pb2_service.h").open("w", encoding="utf-8") as f:
f.write(hpp)
with open(root / "api_pb2_service.cpp", "w", encoding="utf-8") as f:
with (root / "api_pb2_service.cpp").open("w", encoding="utf-8") as f:
f.write(cpp)
prot_file.unlink()

View File

@@ -195,7 +195,7 @@ def load_component_yaml_configs(components: list[str], tests_dir: Path) -> dict:
yaml_path = tests_dir / component / BENCHMARK_YAML_FILENAME
if not yaml_path.is_file():
continue
with open(yaml_path) as f:
with yaml_path.open() as f:
component_config = yaml.safe_load(f)
if component_config and isinstance(component_config, dict):
for key, value in component_config.items():

View File

@@ -2,6 +2,7 @@
import argparse
from dataclasses import dataclass
from pathlib import Path
import re
import sys
@@ -39,12 +40,12 @@ class Version:
def sub(path, pattern, repl, expected_count=1):
with open(path, encoding="utf-8") as fh:
with Path(path).open(encoding="utf-8") as fh:
content = fh.read()
content, count = re.subn(pattern, repl, content, flags=re.MULTILINE)
if expected_count is not None:
assert count == expected_count, f"Pattern {pattern} replacement failed!"
with open(path, "w", encoding="utf-8") as fh:
with Path(path).open("w", encoding="utf-8") as fh:
fh.write(content)

View File

@@ -14,7 +14,7 @@ import time
import colorama
from helpers import filter_changed, git_ls_files, print_error_for_file, styled
sys.path.append(os.path.dirname(__file__))
sys.path.append(str(Path(__file__).parent))
def find_all(a_str, sub):

View File

@@ -44,7 +44,7 @@ def main() -> int:
return 1
try:
with open(json_path, encoding="utf-8") as f:
with Path(json_path).open(encoding="utf-8") as f:
data = json.load(f)
except (json.JSONDecodeError, OSError) as e:
print(f"Error loading JSON: {e}", file=sys.stderr)
@@ -74,7 +74,7 @@ def main() -> int:
# Write back
try:
with open(json_path, "w", encoding="utf-8") as f:
with Path(json_path).open("w", encoding="utf-8") as f:
json.dump(data, f, indent=2)
print(f"Added metadata to {args.json_file}", file=sys.stderr)
except OSError as e:

View File

@@ -3,6 +3,7 @@
from __future__ import annotations
import os
from pathlib import Path
def write_github_output(outputs: dict[str, str | int]) -> None:
@@ -16,7 +17,7 @@ def write_github_output(outputs: dict[str, str | int]) -> None:
"""
github_output = os.environ.get("GITHUB_OUTPUT")
if github_output:
with open(github_output, "a", encoding="utf-8") as f:
with Path(github_output).open("a", encoding="utf-8") as f:
f.writelines(f"{key}={value}\n" for key, value in outputs.items())
else:
for key, value in outputs.items():

View File

@@ -91,7 +91,7 @@ def load_analysis_json(json_path: str) -> dict | None:
return None
try:
with open(json_file, encoding="utf-8") as f:
with Path(json_file).open(encoding="utf-8") as f:
return json.load(f)
except (json.JSONDecodeError, OSError) as e:
print(f"Failed to load analysis JSON: {e}", file=sys.stderr)

View File

@@ -127,7 +127,7 @@ def run_detailed_analysis(build_dir: str) -> dict | None:
if not idedata_path.exists():
continue
try:
with open(idedata_path, encoding="utf-8") as f:
with idedata_path.open(encoding="utf-8") as f:
raw_data = json.load(f)
idedata = IDEData(raw_data)
print(f"Loaded idedata from: {idedata_path}", file=sys.stderr)
@@ -264,7 +264,7 @@ def main() -> int:
output_path = Path(args.output_json)
output_path.parent.mkdir(parents=True, exist_ok=True)
with open(output_path, "w", encoding="utf-8") as f:
with output_path.open("w", encoding="utf-8") as f:
json.dump(output_data, f, indent=2)
print(f"Saved analysis to {args.output_json}", file=sys.stderr)

View File

@@ -2,6 +2,7 @@
import argparse
import os
from pathlib import Path
import queue
import re
import subprocess
@@ -70,7 +71,7 @@ def main():
)
args = parser.parse_args()
cwd = os.getcwd()
cwd = Path.cwd()
files = [
os.path.relpath(path, cwd) for path in git_ls_files(["*.cpp", "*.h", "*.tcc"])
]

View File

@@ -2,6 +2,7 @@
import argparse
import os
from pathlib import Path
import queue
import re
import shutil
@@ -32,7 +33,7 @@ def clang_options(idedata):
cmd = []
# extract target architecture from triplet in g++ filename
triplet = os.path.basename(idedata["cxx_path"])[:-4]
triplet = Path(idedata["cxx_path"]).name[:-4]
if triplet.startswith("xtensa-"):
# clang doesn't support Xtensa (yet?), so compile in 32-bit mode and pretend we're the Xtensa compiler
cmd.append("-m32")
@@ -153,8 +154,8 @@ def run_tidy(executable, args, options, tmpdir, path_queue, lock, failed_files):
if sys.stdout.isatty():
invocation.append("--use-color")
invocation.append(f"--header-filter={os.path.abspath(basepath)}/.*")
invocation.append(os.path.abspath(path))
invocation.append(f"--header-filter={Path(basepath).resolve()}/.*")
invocation.append(str(Path(path).resolve()))
invocation.append("--")
invocation.extend(options)
@@ -229,7 +230,7 @@ def main():
)
args = parser.parse_args()
cwd = os.getcwd()
cwd = Path.cwd()
files = [os.path.relpath(path, cwd) for path in git_ls_files(["*.cpp"])]
# Exclude benchmark files — they require google benchmark headers not
# available in the ESP32 toolchain and use different naming conventions.

View File

@@ -16,7 +16,7 @@ sys.path.insert(0, str(script_dir))
def read_file_lines(path: Path) -> list[str]:
"""Read lines from a file."""
with open(path) as f:
with path.open() as f:
return f.readlines()
@@ -65,7 +65,7 @@ def get_clang_tidy_version_from_requirements(repo_root: Path | None = None) -> s
def read_file_bytes(path: Path) -> bytes:
"""Read bytes from a file."""
with open(path, "rb") as f:
with path.open("rb") as f:
return f.read()
@@ -120,7 +120,7 @@ def read_stored_hash(repo_root: Path | None = None) -> str | None:
def write_file_content(path: Path, content: str) -> None:
"""Write content to a file."""
with open(path, "w") as f:
with path.open("w") as f:
f.write(content)

View File

@@ -306,7 +306,7 @@ def _is_clang_tidy_full_scan() -> bool:
"""
try:
result = subprocess.run(
[os.path.join(root_path, "script", "clang_tidy_hash.py"), "--check"],
[str(Path(root_path) / "script" / "clang_tidy_hash.py"), "--check"],
capture_output=True,
check=False,
)

View File

@@ -17,10 +17,10 @@ from typing import Any
import colorama
root_path = os.path.abspath(os.path.normpath(os.path.join(__file__, "..", "..")))
basepath = os.path.join(root_path, "esphome")
temp_folder = os.path.join(root_path, ".temp")
temp_header_file = os.path.join(temp_folder, "all-include.cpp")
root_path = str(Path(__file__).resolve().parent.parent)
basepath = str(Path(root_path) / "esphome")
temp_folder = str(Path(root_path) / ".temp")
temp_header_file = str(Path(temp_folder) / "all-include.cpp")
# C++ file extensions used for clang-tidy and clang-format checks
CPP_FILE_EXTENSIONS = (".cpp", ".h", ".hpp", ".cc", ".cxx", ".c", ".tcc")
@@ -339,8 +339,8 @@ def _get_github_event_data() -> dict | None:
Parsed event data dictionary, or None if not available
"""
github_event_path = os.environ.get("GITHUB_EVENT_PATH")
if github_event_path and os.path.exists(github_event_path):
with open(github_event_path) as f:
if github_event_path and Path(github_event_path).exists():
with Path(github_event_path).open() as f:
return json.load(f)
return None
@@ -464,7 +464,8 @@ def _get_changed_files_from_command(command: list[str]) -> list[str]:
raise Exception(f"Command failed: {' '.join(command)}\nstderr: {proc.stderr}")
changed_files = splitlines_no_ends(proc.stdout)
changed_files = [os.path.relpath(f, os.getcwd()) for f in changed_files if f]
cwd = Path.cwd()
changed_files = [os.path.relpath(f, cwd) for f in changed_files if f] # noqa: PTH109
changed_files.sort()
return changed_files
@@ -499,7 +500,7 @@ def get_changed_components() -> list[str] | None:
return None
# Use list-components.py to get changed components
script_path = os.path.join(root_path, "script", "list-components.py")
script_path = str(Path(root_path) / "script" / "list-components.py")
cmd = [script_path, "--changed"]
try:
@@ -619,7 +620,7 @@ def filter_changed(files: list[str]) -> list[str]:
def filter_grep(files: list[str], value: list[str]) -> list[str]:
matched = []
for file in files:
with open(file, encoding="utf-8") as handle:
with Path(file).open(encoding="utf-8") as handle:
contents = handle.read()
if any(v in contents for v in value):
matched.append(file)

View File

@@ -2,6 +2,7 @@
import argparse
import os
from pathlib import Path
import re
import sys
@@ -66,11 +67,12 @@ def main():
args = parser.parse_args()
files = []
cwd = Path.cwd()
for path in git_ls_files():
filetypes = (".py",)
ext = os.path.splitext(path)[1]
ext = Path(path).suffix
if ext in filetypes and path.startswith("esphome"):
path = os.path.relpath(path, os.getcwd())
path = os.path.relpath(path, cwd)
files.append(path)
# Match against re
file_name_re = re.compile("|".join(args.files))

View File

@@ -1,5 +1,6 @@
#!/usr/bin/env python3
from pathlib import Path
import re
# pylint: disable=import-error
@@ -34,10 +35,10 @@ DOMAINS = {
def sub(path, pattern, repl):
with open(path, encoding="utf-8") as handle:
with Path(path).open(encoding="utf-8") as handle:
content = handle.read()
content = re.sub(pattern, repl, content, flags=re.MULTILINE)
with open(path, "w", encoding="utf-8") as handle:
with Path(path).open("w", encoding="utf-8") as handle:
handle.write(content)

View File

@@ -297,7 +297,7 @@ def write_github_summary(
test_results: List of all test results
"""
summary_content = format_github_summary(test_results, toolchain)
with open(os.environ["GITHUB_STEP_SUMMARY"], "a", encoding="utf-8") as f:
with Path(os.environ["GITHUB_STEP_SUMMARY"]).open("a", encoding="utf-8") as f:
f.write(summary_content)