🐛 fix(scripts): force LF for generated text files
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
import ast
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
SCRIPT_PATHS = sorted((ROOT / "scripts").glob("*.py")) + sorted(
|
||||
(ROOT / ".gitea" / "ci").glob("*.py")
|
||||
)
|
||||
|
||||
|
||||
class ScriptLineEndingTests(unittest.TestCase):
|
||||
def test_script_text_writes_pin_lf_newlines(self):
|
||||
offenders: list[str] = []
|
||||
for path in SCRIPT_PATHS:
|
||||
tree = ast.parse(path.read_text(encoding="utf-8"))
|
||||
for node in ast.walk(tree):
|
||||
if not isinstance(node, ast.Call):
|
||||
continue
|
||||
if is_write_text_without_lf_newline(node):
|
||||
offenders.append(f"{path.relative_to(ROOT)}:{node.lineno}")
|
||||
elif is_text_open_for_writing_without_newline(node):
|
||||
offenders.append(f"{path.relative_to(ROOT)}:{node.lineno}")
|
||||
|
||||
self.assertEqual(offenders, [])
|
||||
|
||||
|
||||
def has_lf_newline_keyword(node: ast.Call) -> bool:
|
||||
newline = next(
|
||||
(keyword for keyword in node.keywords if keyword.arg == "newline"),
|
||||
None,
|
||||
)
|
||||
return (
|
||||
newline is not None
|
||||
and isinstance(newline.value, ast.Constant)
|
||||
and newline.value.value == "\n"
|
||||
)
|
||||
|
||||
|
||||
def is_write_text_without_lf_newline(node: ast.Call) -> bool:
|
||||
func = node.func
|
||||
return (
|
||||
isinstance(func, ast.Attribute)
|
||||
and func.attr == "write_text"
|
||||
and not has_lf_newline_keyword(node)
|
||||
)
|
||||
|
||||
|
||||
def is_text_open_for_writing_without_newline(node: ast.Call) -> bool:
|
||||
func = node.func
|
||||
if isinstance(func, ast.Name):
|
||||
is_open = func.id == "open"
|
||||
elif isinstance(func, ast.Attribute):
|
||||
is_open = func.attr == "open"
|
||||
else:
|
||||
is_open = False
|
||||
if not is_open:
|
||||
return False
|
||||
|
||||
mode_node = None
|
||||
if len(node.args) >= 2:
|
||||
mode_node = node.args[1]
|
||||
for keyword in node.keywords:
|
||||
if keyword.arg == "mode":
|
||||
mode_node = keyword.value
|
||||
break
|
||||
|
||||
if mode_node is None:
|
||||
return False
|
||||
if not isinstance(mode_node, ast.Constant) or not isinstance(mode_node.value, str):
|
||||
return False
|
||||
|
||||
mode = mode_node.value
|
||||
writes_text = any(flag in mode for flag in ("w", "a", "x")) and "b" not in mode
|
||||
return writes_text and not has_lf_newline_keyword(node)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user