Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid double newlines with --stdout #605

Merged
merged 2 commits into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions src/darker/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
)
from darker.help import LINTING_GUIDE, get_extra_instruction
from darker.import_sorting import apply_isort, isort
from darker.terminal import output
from darker.utils import debug_dump, glob_any
from darker.verification import ASTVerifier, BinarySearch, NotEquivalentError
from darkgraylib.command_line import (
Expand Down Expand Up @@ -415,7 +416,7 @@ def print_diff(
n=5, # Black shows 5 lines of context, do the same
)
)
print(colorize(diff, "diff", use_color))
output(colorize(diff, "diff", use_color), end="\n")


def print_source(new: TextDocument, use_color: bool) -> None:
Expand All @@ -428,11 +429,11 @@ def print_source(new: TextDocument, use_color: bool) -> None:
PythonLexer,
) = _import_pygments() # type: ignore
except ImportError:
print(new.string, end="")
output(new.string)
else:
print(highlight(new.string, PythonLexer(), TerminalFormatter()), end="")
output(highlight(new.string, PythonLexer(), TerminalFormatter()))
else:
print(new.string, end="")
output(new.string)


def _import_pygments(): # type: ignore
Expand Down
10 changes: 10 additions & 0 deletions src/darker/terminal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"""Terminal output helpers."""

import sys


def output(*args: str, end: str = "") -> None:
"""Print encoded binary output to terminal, with no newline by default."""
sys.stdout.buffer.write(*[arg.encode() for arg in args])
if end:
sys.stdout.buffer.write(end.encode())
64 changes: 63 additions & 1 deletion src/darker/tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,25 @@
import random
import re
import string
import sys
from argparse import ArgumentError
from pathlib import Path
from subprocess import PIPE, CalledProcessError, run # nosec
from textwrap import dedent
from unittest.mock import patch

import pytest

import darker.__main__
import darker.import_sorting
from darker.git import EditedLinenumsDiffer
from darker.help import LINTING_GUIDE
from darker.terminal import output
from darker.tests.examples import A_PY, A_PY_BLACK, A_PY_BLACK_FLYNT, A_PY_BLACK_ISORT
from darker.tests.test_fstring import FLYNTED_SOURCE, MODIFIED_SOURCE, ORIGINAL_SOURCE
from darkgraylib.git import RevisionRange
from darkgraylib.testtools.highlighting_helpers import BLUE, CYAN, RESET, WHITE, YELLOW
from darkgraylib.utils import TextDocument, joinlines
from darkgraylib.utils import WINDOWS, TextDocument, joinlines

pytestmark = pytest.mark.usefixtures("find_project_root_cache_clear")

Expand Down Expand Up @@ -551,6 +555,64 @@ def test_stdout_path_resolution(git_repo, capsys):
assert capsys.readouterr().out == 'print("foo")\n'


@pytest.mark.parametrize("newline", ["\n", "\r\n"], ids=["unix", "windows"])
def test_stdout_newlines(git_repo, capsysbinary, newline):
"""When using ``--stdout``, newlines are not duplicated.

See: https://github.com/akaihola/darker/issues/604

The `git_repo` fixture is used to ensure that the test doesn't run in the Darker
repository clone in CI. It helps avoid the Git error message
"fatal: Not a valid object name origin/master" in the NixOS CI tests.

"""
if WINDOWS and sys.version_info < (3, 10):
# See https://bugs.python.org/issue38671
Path("new-file.py").touch()
code = f"import collections{newline}import sys{newline}".encode()
with patch("sys.stdin.buffer.read", return_value=code):

result = darker.__main__.main(
["--stdout", "--isort", "--stdin-filename=new-file.py", "-"],
)

assert result == 0
assert capsysbinary.readouterr().out == code


@pytest.mark.parametrize("newline", ["\n", "\r\n"], ids=["unix", "windows"])
def test_stdout_newlines_subprocess(git_repo, newline):
"""When using ``--stdout``, newlines are not duplicated.

See: https://github.com/akaihola/darker/issues/604

The `git_repo` fixture is used to ensure that the test doesn't run in the Darker
repository clone in CI. It helps avoid the Git error message
"fatal: Not a valid object name origin/master" in the NixOS CI tests.

"""
if WINDOWS and sys.version_info < (3, 10):
# See https://bugs.python.org/issue38671
Path("new-file.py").touch()
code = f"import collections{newline}import sys{newline}".encode()
try:

darker_subprocess = run( # nosec
["darker", "--stdout", "--isort", "--stdin-filename=new-file.py", "-"],
input=code,
stdout=PIPE,
check=True,
)

except CalledProcessError as e:
if e.stdout:
output(e.stdout, end="\n")
if e.stderr:
output(e.stderr, end="\n")
raise
assert darker_subprocess.stdout == code


def test_long_command_length(git_repo):
"""Large amount of changed files does not break Git invocation even on Windows"""
# For PR #542 - large character count for changed files
Expand Down
9 changes: 5 additions & 4 deletions src/darker/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from pathlib import Path
from typing import Collection, List

from darker.terminal import output
from darkgraylib.utils import DiffChunk

logger = logging.getLogger(__name__)
Expand All @@ -14,14 +15,14 @@ def debug_dump(black_chunks: List[DiffChunk], edited_linenums: List[int]) -> Non
if logger.getEffectiveLevel() > logging.DEBUG:
return
for offset, old_lines, new_lines in black_chunks:
print(80 * "-")
output(80 * "-", end="\n")
for delta, old_line in enumerate(old_lines):
linenum = offset + delta
edited = "*" if linenum in edited_linenums else " "
print(f"{edited}-{linenum:4} {old_line}")
output(f"{edited}-{linenum:4} {old_line}", end="\n")
for _, new_line in enumerate(new_lines):
print(f" + {new_line}")
print(80 * "-")
output(f" + {new_line}", end="\n")
output(80 * "-", end="\n")


def glob_any(path: Path, patterns: Collection[str]) -> bool:
Expand Down
Loading