80 lines
2.3 KiB
Python
80 lines
2.3 KiB
Python
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()
|