Skip to content

Commit

Permalink
Normalize whitespace to support cov_to_lint.py
Browse files Browse the repository at this point in the history
Indentation simplification would prevent matching `cov_to_lint` output
from different commits.
  • Loading branch information
akaihola committed Jan 4, 2023
1 parent dae220d commit 2232e2d
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 3 deletions.
48 changes: 45 additions & 3 deletions src/darker/linting.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import logging
import os
import re
import shlex
import sys
from collections import defaultdict
Expand All @@ -29,7 +30,18 @@
from pathlib import Path
from subprocess import PIPE, Popen # nosec
from tempfile import TemporaryDirectory
from typing import IO, Collection, Dict, Generator, Iterable, List, Set, Tuple, Union
from typing import (
IO,
Callable,
Collection,
Dict,
Generator,
Iterable,
List,
Set,
Tuple,
Union,
)

from darker.diff import map_unmodified_lines
from darker.git import (
Expand Down Expand Up @@ -110,6 +122,28 @@ def get(self, new_location: MessageLocation) -> MessageLocation:
return NO_MESSAGE_LOCATION


def normalize_whitespace(message: LinterMessage) -> LinterMessage:
"""Given a line of linter output, shortens runs of whitespace to a single space
Also removes any leading or trailing whitespace.
This is done to support comparison of different ``cov_to_lint.py`` runs. To make the
output more readable and compact, the tool adjusts whitespace. This is done to both
align runs of lines and to remove blocks of extra indentation. For differing sets of
coverage messages from ``pytest-cov`` runs of different versions of the code, these
whitespace adjustments can differ, so we need to normalize them to compare and match
them.
:param message: The linter message to normalize
:return: The normalized linter message with leading and trailing whitespace stripped
and runs of whitespace characters collapsed into single spaces
"""
return LinterMessage(
message.linter, re.sub(r"\s\s+", " ", message.description).strip()
)


def make_linter_env(root: Path, revision: str) -> Dict[str, str]:
"""Populate environment variables for running linters
Expand Down Expand Up @@ -375,25 +409,32 @@ def run_linters(
return _print_new_linter_messages(baseline, messages, diff_line_mapping, use_color)


def _identity_line_processor(message: LinterMessage) -> LinterMessage:
"""Default line processor which doesn't modify the line at all"""
return message


def _get_messages_from_linters(
linter_cmdlines: Iterable[Union[str, List[str]]],
root: Path,
paths: Collection[Path],
env: Dict[str, str],
line_processor: Callable[[LinterMessage], LinterMessage] = _identity_line_processor,
) -> Dict[MessageLocation, List[LinterMessage]]:
"""Run given linters for the given directory and return linting errors
:param linter_cmdlines: The command lines for running the linters
:param root: The common root of all files to lint
:param paths: Paths of files to check, relative to ``root``
:param env: The environment variables to pass to the linter
:param line_processor: Pre-processing callback for linter output lines
:return: Linter messages
"""
result = defaultdict(list)
for cmdline in linter_cmdlines:
for message_location, message in run_linter(cmdline, root, paths, env).items():
result[message_location].append(message)
result[message_location].append(line_processor(message))
return result


Expand All @@ -419,7 +460,7 @@ def _print_new_linter_messages(
is_modified_line = old_location == NO_MESSAGE_LOCATION
old_messages: List[LinterMessage] = baseline.get(old_location, [])
for message in messages:
if not is_modified_line and message in old_messages:
if not is_modified_line and normalize_whitespace(message) in old_messages:
# Only hide messages when
# - they occurred previously on the corresponding line
# - the line hasn't been modified
Expand Down Expand Up @@ -460,6 +501,7 @@ def _get_messages_from_linters_for_baseline(
clone_root,
paths,
make_linter_env(root, rev1_commit),
normalize_whitespace,
)


Expand Down
12 changes: 12 additions & 0 deletions src/darker/tests/test_linting.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,18 @@ def test_diff_line_mapping_ignores_column(
assert result == expect


def test_normalize_whitespace():
"""Whitespace runs and leading/trailing whitespace is normalized"""
description = "module.py:42: \t indented message, trailing spaces and tabs \t "
message = LinterMessage("mylinter", description)

result = linting.normalize_whitespace(message)

assert result == LinterMessage(
"mylinter", "module.py:42: indented message, trailing spaces and tabs"
)


@pytest.mark.kwparametrize(
dict(
line="module.py:42: Just a line number\n",
Expand Down

0 comments on commit 2232e2d

Please sign in to comment.