Properly format unified diff

Previously we weren't using timestamps.
This commit is contained in:
Łukasz Langa 2018-06-04 17:10:32 -07:00
parent 041ec995e5
commit 728e5a2f1e
4 changed files with 25 additions and 9 deletions

View File

@ -717,6 +717,8 @@ More details can be found in [CONTRIBUTING](CONTRIBUTING.md).
* added `--verbose` (#283) * added `--verbose` (#283)
* the header output in `--diff` now actually conforms to the unified diff spec
* fixed stdin handling not working correctly if an old version of Click was * fixed stdin handling not working correctly if an old version of Click was
used (#276) used (#276)

View File

@ -1,6 +1,7 @@
import asyncio import asyncio
from asyncio.base_events import BaseEventLoop from asyncio.base_events import BaseEventLoop
from concurrent.futures import Executor, ProcessPoolExecutor from concurrent.futures import Executor, ProcessPoolExecutor
from datetime import datetime
from enum import Enum, Flag from enum import Enum, Flag
from functools import partial, wraps from functools import partial, wraps
import io import io
@ -469,6 +470,7 @@ def format_file_in_place(
if src.suffix == ".pyi": if src.suffix == ".pyi":
mode |= FileMode.PYI mode |= FileMode.PYI
then = datetime.utcfromtimestamp(src.stat().st_mtime)
with open(src, "rb") as buf: with open(src, "rb") as buf:
src_contents, encoding, newline = decode_bytes(buf.read()) src_contents, encoding, newline = decode_bytes(buf.read())
try: try:
@ -482,8 +484,9 @@ def format_file_in_place(
with open(src, "w", encoding=encoding, newline=newline) as f: with open(src, "w", encoding=encoding, newline=newline) as f:
f.write(dst_contents) f.write(dst_contents)
elif write_back == write_back.DIFF: elif write_back == write_back.DIFF:
src_name = f"{src} (original)" now = datetime.utcnow()
dst_name = f"{src} (formatted)" src_name = f"{src}\t{then} +0000"
dst_name = f"{src}\t{now} +0000"
diff_contents = diff(src_contents, dst_contents, src_name, dst_name) diff_contents = diff(src_contents, dst_contents, src_name, dst_name)
if lock: if lock:
lock.acquire() lock.acquire()
@ -514,6 +517,7 @@ def format_stdin_to_stdout(
`line_length`, `fast`, `is_pyi`, and `force_py36` arguments are passed to `line_length`, `fast`, `is_pyi`, and `force_py36` arguments are passed to
:func:`format_file_contents`. :func:`format_file_contents`.
""" """
then = datetime.utcnow()
src, encoding, newline = decode_bytes(sys.stdin.buffer.read()) src, encoding, newline = decode_bytes(sys.stdin.buffer.read())
dst = src dst = src
try: try:
@ -530,8 +534,9 @@ def format_stdin_to_stdout(
if write_back == WriteBack.YES: if write_back == WriteBack.YES:
f.write(dst) f.write(dst)
elif write_back == WriteBack.DIFF: elif write_back == WriteBack.DIFF:
src_name = "<stdin> (original)" now = datetime.utcnow()
dst_name = "<stdin> (formatted)" src_name = f"STDIN\t{then} +0000"
dst_name = f"STDOUT\t{now} +0000"
f.write(diff(src, dst, src_name, dst_name)) f.write(diff(src, dst, src_name, dst_name))
f.detach() f.detach()

View File

@ -1,5 +1,5 @@
--- <stdin> (original) --- [Deterministic header]
+++ <stdin> (formatted) +++ [Deterministic header]
@@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
... ...
-'some_string' -'some_string'

View File

@ -6,18 +6,19 @@
from io import BytesIO, TextIOWrapper from io import BytesIO, TextIOWrapper
import os import os
from pathlib import Path from pathlib import Path
import re
import sys import sys
from tempfile import TemporaryDirectory from tempfile import TemporaryDirectory
from typing import Any, List, Tuple, Iterator from typing import Any, List, Tuple, Iterator
import unittest import unittest
from unittest.mock import patch from unittest.mock import patch
import re
from click import unstyle from click import unstyle
from click.testing import CliRunner from click.testing import CliRunner
import black import black
ll = 88 ll = 88
ff = partial(black.format_file_in_place, line_length=ll, fast=True) ff = partial(black.format_file_in_place, line_length=ll, fast=True)
fs = partial(black.format_str, line_length=ll) fs = partial(black.format_str, line_length=ll)
@ -136,18 +137,22 @@ def test_piping(self) -> None:
black.assert_stable(source, actual, line_length=ll) black.assert_stable(source, actual, line_length=ll)
def test_piping_diff(self) -> None: def test_piping_diff(self) -> None:
diff_header = re.compile(
rf"(STDIN|STDOUT)\t\d\d\d\d-\d\d-\d\d "
rf"\d\d:\d\d:\d\d\.\d\d\d\d\d\d \+\d\d\d\d"
)
source, _ = read_data("expression.py") source, _ = read_data("expression.py")
expected, _ = read_data("expression.diff") expected, _ = read_data("expression.diff")
hold_stdin, hold_stdout = sys.stdin, sys.stdout hold_stdin, hold_stdout = sys.stdin, sys.stdout
try: try:
sys.stdin = TextIOWrapper(BytesIO(source.encode("utf8")), encoding="utf8") sys.stdin = TextIOWrapper(BytesIO(source.encode("utf8")), encoding="utf8")
sys.stdout = TextIOWrapper(BytesIO(), encoding="utf8") sys.stdout = TextIOWrapper(BytesIO(), encoding="utf8")
sys.stdin.buffer.name = "<stdin>" # type: ignore
black.format_stdin_to_stdout( black.format_stdin_to_stdout(
line_length=ll, fast=True, write_back=black.WriteBack.DIFF line_length=ll, fast=True, write_back=black.WriteBack.DIFF
) )
sys.stdout.seek(0) sys.stdout.seek(0)
actual = sys.stdout.read() actual = sys.stdout.read()
actual = diff_header.sub("[Deterministic header]", actual)
finally: finally:
sys.stdin, sys.stdout = hold_stdin, hold_stdout sys.stdin, sys.stdout = hold_stdin, hold_stdout
actual = actual.rstrip() + "\n" # the diff output has a trailing space actual = actual.rstrip() + "\n" # the diff output has a trailing space
@ -204,13 +209,17 @@ def test_expression_diff(self) -> None:
source, _ = read_data("expression.py") source, _ = read_data("expression.py")
expected, _ = read_data("expression.diff") expected, _ = read_data("expression.diff")
tmp_file = Path(black.dump_to_file(source)) tmp_file = Path(black.dump_to_file(source))
diff_header = re.compile(
rf"{re.escape(str(tmp_file))}\t\d\d\d\d-\d\d-\d\d "
rf"\d\d:\d\d:\d\d\.\d\d\d\d\d\d \+\d\d\d\d"
)
hold_stdout = sys.stdout hold_stdout = sys.stdout
try: try:
sys.stdout = TextIOWrapper(BytesIO(), encoding="utf8") sys.stdout = TextIOWrapper(BytesIO(), encoding="utf8")
self.assertTrue(ff(tmp_file, write_back=black.WriteBack.DIFF)) self.assertTrue(ff(tmp_file, write_back=black.WriteBack.DIFF))
sys.stdout.seek(0) sys.stdout.seek(0)
actual = sys.stdout.read() actual = sys.stdout.read()
actual = actual.replace(str(tmp_file), "<stdin>") actual = diff_header.sub("[Deterministic header]", actual)
finally: finally:
sys.stdout = hold_stdout sys.stdout = hold_stdout
os.unlink(tmp_file) os.unlink(tmp_file)