From 4db5717854c05f9fdd4cfbb81e8f3ce7efc691d4 Mon Sep 17 00:00:00 2001 From: Jakub Kuczys Date: Tue, 28 Mar 2023 04:54:55 +0200 Subject: [PATCH] Stop treating files with only line endings changed as doc-only --- src/label_doconly_changes/base_hooks.py | 5 +-- src/label_doconly_changes/hooks/python.py | 5 ++- tests/hooks/python_test.py | 38 ++++++++++++++++++++++- 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/src/label_doconly_changes/base_hooks.py b/src/label_doconly_changes/base_hooks.py index cbe699e..4b61639 100644 --- a/src/label_doconly_changes/base_hooks.py +++ b/src/label_doconly_changes/base_hooks.py @@ -49,11 +49,12 @@ class HookOutputDict(TypedDict): def _get_file_from_ref(*, ref: str, filename: str) -> str | None: try: + # this can't use `check_output()`'s encoding or text kwarg + # instead of `.decode("utf-8")` because that forces universal newline behavior return subprocess.check_output( ("git", "cat-file", "blob", f"{ref}:{filename}"), stderr=subprocess.PIPE, - encoding="utf-8", - ) + ).decode("utf-8") except subprocess.CalledProcessError as e: prefixes = tuple( f"fatal: path '{filename}' {error_msg} '" diff --git a/src/label_doconly_changes/hooks/python.py b/src/label_doconly_changes/hooks/python.py index e96f00d..4d8a3ac 100644 --- a/src/label_doconly_changes/hooks/python.py +++ b/src/label_doconly_changes/hooks/python.py @@ -19,6 +19,9 @@ _NodeT = TypeVar("_NodeT", bound=cst.CSTNode) _ExprParentT = TypeVar("_ExprParentT") _ExprT = TypeVar("_ExprT") +# ensure consistent default to avoid false positives +# caused by parser's detection mechanism for this value +PARSER_CONFIG = cst.PartialParserConfig(default_newline="\n") class DocstringLocation(NamedTuple, Generic[_ExprParentT, _ExprT]): @@ -69,7 +72,7 @@ def on_visit(self, node: cst.CSTNode) -> bool | None: @classmethod def from_contents(cls, contents: str) -> Self: - self = cls(cst.parse_module(contents)) + self = cls(cst.parse_module(contents, PARSER_CONFIG)) self.base_node.visit(self) return self diff --git a/tests/hooks/python_test.py b/tests/hooks/python_test.py index 649a942..cef1275 100644 --- a/tests/hooks/python_test.py +++ b/tests/hooks/python_test.py @@ -29,7 +29,7 @@ def leave_List( def simplify_list(nodes: list[cst.CSTNode], *, max_depth: int = 1) -> str: visitor = _ListSimplifier(max_depth=max_depth) - return cst.parse_module(repr(nodes)).visit(visitor).code + return cst.parse_module(repr(nodes), python.PARSER_CONFIG).visit(visitor).code def print_extractor_info(tracker: python.ModuleTracker) -> None: @@ -72,3 +72,39 @@ def test_is_doc_only_false(contents_before: str, contents_after: str) -> None: except Exception: print_analyzer_info(analyzer) raise + + +@pytest.mark.parametrize( + "contents_before,contents_after", + ( + ( + "x = 1\ny = 2\n", + "x = 1\r\ny = 2\r\n", + ), + # LibCST's native parser panics with this one :D + # + # ( + # "x = 1\ny = 2\n", + # "x = 1\ry = 2\r\n", + # ), + ( + "x = 1\ny = 2\n", + "x = 1\ry = 2\r", + ), + ( + "x = 1\ny = 2\n", + "x = 1\ny = 2\r\n", + ), + ( + "x = 1\r\ny = 2\n", + "x = 1\ny = 2\r\n", + ), + ), +) +def test_different_line_endings(contents_before: str, contents_after: str) -> None: + analyzer = python.PythonAnalyzer(contents_before, contents_after) + try: + assert not analyzer.is_docstring_only() + except Exception: + print_analyzer_info(analyzer) + raise