X-Git-Url: https://git.madduck.net/etc/vim.git/blobdiff_plain/d1ad8730e36819f787c720d1917de22b59806a75..e3ccabb23c5dc5495bd8f96b5c90c1db6a350d6d:/tests/test_black.py diff --git a/tests/test_black.py b/tests/test_black.py index 3c76633..edcf720 100644 --- a/tests/test_black.py +++ b/tests/test_black.py @@ -1,16 +1,31 @@ #!/usr/bin/env python3 +import multiprocessing import asyncio import logging from concurrent.futures import ThreadPoolExecutor from contextlib import contextmanager +from dataclasses import replace from functools import partial +import inspect from io import BytesIO, TextIOWrapper import os from pathlib import Path +from platform import system import regex as re import sys from tempfile import TemporaryDirectory -from typing import Any, BinaryIO, Dict, Generator, List, Tuple, Iterator, TypeVar +import types +from typing import ( + Any, + BinaryIO, + Callable, + Dict, + Generator, + List, + Tuple, + Iterator, + TypeVar, +) import unittest from unittest.mock import patch, MagicMock @@ -36,8 +51,9 @@ from pathspec import PathSpec from .test_primer import PrimerCLITests # noqa: F401 -ff = partial(black.format_file_in_place, mode=black.FileMode(), fast=True) -fs = partial(black.format_str, mode=black.FileMode()) +DEFAULT_MODE = black.FileMode(experimental_string_processing=True) +ff = partial(black.format_file_in_place, mode=DEFAULT_MODE, fast=True) +fs = partial(black.format_str, mode=DEFAULT_MODE) THIS_FILE = Path(__file__) THIS_DIR = THIS_FILE.parent PROJECT_ROOT = THIS_DIR.parent @@ -151,6 +167,7 @@ class BlackRunner(CliRunner): class BlackTestCase(unittest.TestCase): maxDiff = None + _diffThreshold = 2 ** 20 def assertFormatEqual(self, expected: str, actual: str) -> None: if actual != expected and not os.environ.get("SKIP_AST_PRINT"): @@ -169,7 +186,7 @@ class BlackTestCase(unittest.TestCase): list(bdv.visit(exp_node)) except Exception as ve: black.err(str(ve)) - self.assertEqual(expected, actual) + self.assertMultiLineEqual(expected, actual) def invokeBlack( self, args: List[str], exit_code: int = 0, ignore_config: bool = True @@ -190,13 +207,13 @@ class BlackTestCase(unittest.TestCase): ) @patch("black.dump_to_file", dump_to_stderr) - def checkSourceFile(self, name: str) -> None: + def checkSourceFile(self, name: str, mode: black.FileMode = DEFAULT_MODE) -> None: path = THIS_DIR.parent / name source, expected = read_data(str(path), data=False) - actual = fs(source) + actual = fs(source, mode=mode) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, mode) self.assertFalse(ff(path)) @patch("black.dump_to_file", dump_to_stderr) @@ -205,7 +222,7 @@ class BlackTestCase(unittest.TestCase): actual = fs(source) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) def test_empty_ff(self) -> None: expected = "" @@ -267,7 +284,7 @@ class BlackTestCase(unittest.TestCase): self.assertEqual(result.exit_code, 0) self.assertFormatEqual(expected, result.output) black.assert_equivalent(source, result.output) - black.assert_stable(source, result.output, black.FileMode()) + black.assert_stable(source, result.output, DEFAULT_MODE) def test_piping_diff(self) -> None: diff_header = re.compile( @@ -320,7 +337,7 @@ class BlackTestCase(unittest.TestCase): actual = fs(source) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) @patch("black.dump_to_file", dump_to_stderr) def test_function2(self) -> None: @@ -328,6 +345,21 @@ class BlackTestCase(unittest.TestCase): actual = fs(source) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) + black.assert_stable(source, actual, DEFAULT_MODE) + + @patch("black.dump_to_file", dump_to_stderr) + def _test_wip(self) -> None: + source, expected = read_data("wip") + sys.settrace(tracefunc) + mode = replace( + DEFAULT_MODE, + experimental_string_processing=False, + target_versions={black.TargetVersion.PY38}, + ) + actual = fs(source, mode=mode) + sys.settrace(None) + self.assertFormatEqual(expected, actual) + black.assert_equivalent(source, actual) black.assert_stable(source, actual, black.FileMode()) @patch("black.dump_to_file", dump_to_stderr) @@ -336,7 +368,28 @@ class BlackTestCase(unittest.TestCase): actual = fs(source) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) + + @unittest.expectedFailure + @patch("black.dump_to_file", dump_to_stderr) + def test_trailing_comma_optional_parens_stability1(self) -> None: + source, _expected = read_data("trailing_comma_optional_parens1") + actual = fs(source) + black.assert_stable(source, actual, DEFAULT_MODE) + + @unittest.expectedFailure + @patch("black.dump_to_file", dump_to_stderr) + def test_trailing_comma_optional_parens_stability2(self) -> None: + source, _expected = read_data("trailing_comma_optional_parens2") + actual = fs(source) + black.assert_stable(source, actual, DEFAULT_MODE) + + @unittest.expectedFailure + @patch("black.dump_to_file", dump_to_stderr) + def test_trailing_comma_optional_parens_stability3(self) -> None: + source, _expected = read_data("trailing_comma_optional_parens3") + actual = fs(source) + black.assert_stable(source, actual, DEFAULT_MODE) @patch("black.dump_to_file", dump_to_stderr) def test_expression(self) -> None: @@ -344,14 +397,14 @@ class BlackTestCase(unittest.TestCase): actual = fs(source) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) @patch("black.dump_to_file", dump_to_stderr) def test_pep_572(self) -> None: source, expected = read_data("pep_572") actual = fs(source) self.assertFormatEqual(expected, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) if sys.version_info >= (3, 8): black.assert_equivalent(source, actual) @@ -375,7 +428,7 @@ class BlackTestCase(unittest.TestCase): self.assertFormatEqual(expected, actual) with patch("black.dump_to_file", dump_to_stderr): black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) def test_expression_diff(self) -> None: source, _ = read_data("expression.py") @@ -427,14 +480,14 @@ class BlackTestCase(unittest.TestCase): actual = fs(source) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) @patch("black.dump_to_file", dump_to_stderr) def test_pep_570(self) -> None: source, expected = read_data("pep_570") actual = fs(source) self.assertFormatEqual(expected, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) if sys.version_info >= (3, 8): black.assert_equivalent(source, actual) @@ -452,8 +505,8 @@ class BlackTestCase(unittest.TestCase): actual = fs(source) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) - mode = black.FileMode(string_normalization=False) + black.assert_stable(source, actual, DEFAULT_MODE) + mode = replace(DEFAULT_MODE, string_normalization=False) not_normalized = fs(source, mode=mode) self.assertFormatEqual(source.replace("\\\n", ""), not_normalized) black.assert_equivalent(source, not_normalized) @@ -465,7 +518,17 @@ class BlackTestCase(unittest.TestCase): actual = fs(source) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) + + @patch("black.dump_to_file", dump_to_stderr) + def test_docstring_no_string_normalization(self) -> None: + """Like test_docstring but with string normalization off.""" + source, expected = read_data("docstring_no_string_normalization") + mode = replace(DEFAULT_MODE, string_normalization=False) + actual = fs(source, mode=mode) + self.assertFormatEqual(expected, actual) + black.assert_equivalent(source, actual) + black.assert_stable(source, actual, mode) def test_long_strings(self) -> None: """Tests for splitting long strings.""" @@ -473,7 +536,15 @@ class BlackTestCase(unittest.TestCase): actual = fs(source) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) + + def test_long_strings_flag_disabled(self) -> None: + """Tests for turning off the string processing logic.""" + source, expected = read_data("long_strings_flag_disabled") + mode = replace(DEFAULT_MODE, experimental_string_processing=False) + actual = fs(source, mode=mode) + self.assertFormatEqual(expected, actual) + black.assert_stable(expected, actual, mode) @patch("black.dump_to_file", dump_to_stderr) def test_long_strings__edge_case(self) -> None: @@ -482,7 +553,7 @@ class BlackTestCase(unittest.TestCase): actual = fs(source) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) @patch("black.dump_to_file", dump_to_stderr) def test_long_strings__regression(self) -> None: @@ -491,7 +562,7 @@ class BlackTestCase(unittest.TestCase): actual = fs(source) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) @patch("black.dump_to_file", dump_to_stderr) def test_slices(self) -> None: @@ -499,7 +570,7 @@ class BlackTestCase(unittest.TestCase): actual = fs(source) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) @patch("black.dump_to_file", dump_to_stderr) def test_percent_precedence(self) -> None: @@ -507,7 +578,7 @@ class BlackTestCase(unittest.TestCase): actual = fs(source) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) @patch("black.dump_to_file", dump_to_stderr) def test_comments(self) -> None: @@ -515,7 +586,7 @@ class BlackTestCase(unittest.TestCase): actual = fs(source) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) @patch("black.dump_to_file", dump_to_stderr) def test_comments2(self) -> None: @@ -523,7 +594,7 @@ class BlackTestCase(unittest.TestCase): actual = fs(source) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) @patch("black.dump_to_file", dump_to_stderr) def test_comments3(self) -> None: @@ -531,7 +602,7 @@ class BlackTestCase(unittest.TestCase): actual = fs(source) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) @patch("black.dump_to_file", dump_to_stderr) def test_comments4(self) -> None: @@ -539,7 +610,7 @@ class BlackTestCase(unittest.TestCase): actual = fs(source) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) @patch("black.dump_to_file", dump_to_stderr) def test_comments5(self) -> None: @@ -547,7 +618,7 @@ class BlackTestCase(unittest.TestCase): actual = fs(source) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) @patch("black.dump_to_file", dump_to_stderr) def test_comments6(self) -> None: @@ -555,15 +626,16 @@ class BlackTestCase(unittest.TestCase): actual = fs(source) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) @patch("black.dump_to_file", dump_to_stderr) def test_comments7(self) -> None: source, expected = read_data("comments7") - actual = fs(source) + mode = replace(DEFAULT_MODE, target_versions={black.TargetVersion.PY38}) + actual = fs(source, mode=mode) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) @patch("black.dump_to_file", dump_to_stderr) def test_comment_after_escaped_newline(self) -> None: @@ -571,7 +643,7 @@ class BlackTestCase(unittest.TestCase): actual = fs(source) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) @patch("black.dump_to_file", dump_to_stderr) def test_cantfit(self) -> None: @@ -579,7 +651,7 @@ class BlackTestCase(unittest.TestCase): actual = fs(source) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) @patch("black.dump_to_file", dump_to_stderr) def test_import_spacing(self) -> None: @@ -587,7 +659,7 @@ class BlackTestCase(unittest.TestCase): actual = fs(source) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) @patch("black.dump_to_file", dump_to_stderr) def test_composition(self) -> None: @@ -595,7 +667,16 @@ class BlackTestCase(unittest.TestCase): actual = fs(source) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) + + @patch("black.dump_to_file", dump_to_stderr) + def test_composition_no_trailing_comma(self) -> None: + source, expected = read_data("composition_no_trailing_comma") + mode = replace(DEFAULT_MODE, target_versions={black.TargetVersion.PY38}) + actual = fs(source, mode=mode) + self.assertFormatEqual(expected, actual) + black.assert_equivalent(source, actual) + black.assert_stable(source, actual, DEFAULT_MODE) @patch("black.dump_to_file", dump_to_stderr) def test_empty_lines(self) -> None: @@ -603,7 +684,7 @@ class BlackTestCase(unittest.TestCase): actual = fs(source) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) @patch("black.dump_to_file", dump_to_stderr) def test_remove_parens(self) -> None: @@ -611,7 +692,7 @@ class BlackTestCase(unittest.TestCase): actual = fs(source) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) @patch("black.dump_to_file", dump_to_stderr) def test_string_prefixes(self) -> None: @@ -619,12 +700,12 @@ class BlackTestCase(unittest.TestCase): actual = fs(source) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) @patch("black.dump_to_file", dump_to_stderr) def test_numeric_literals(self) -> None: source, expected = read_data("numeric_literals") - mode = black.FileMode(target_versions=black.PY36_VERSIONS) + mode = replace(DEFAULT_MODE, target_versions=black.PY36_VERSIONS) actual = fs(source, mode=mode) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) @@ -633,7 +714,7 @@ class BlackTestCase(unittest.TestCase): @patch("black.dump_to_file", dump_to_stderr) def test_numeric_literals_ignoring_underscores(self) -> None: source, expected = read_data("numeric_literals_skip_underscores") - mode = black.FileMode(target_versions=black.PY36_VERSIONS) + mode = replace(DEFAULT_MODE, target_versions=black.PY36_VERSIONS) actual = fs(source, mode=mode) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) @@ -644,7 +725,7 @@ class BlackTestCase(unittest.TestCase): source, expected = read_data("numeric_literals_py2") actual = fs(source) self.assertFormatEqual(expected, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) @patch("black.dump_to_file", dump_to_stderr) def test_python2(self) -> None: @@ -652,12 +733,12 @@ class BlackTestCase(unittest.TestCase): actual = fs(source) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) @patch("black.dump_to_file", dump_to_stderr) def test_python2_print_function(self) -> None: source, expected = read_data("python2_print_function") - mode = black.FileMode(target_versions={TargetVersion.PY27}) + mode = replace(DEFAULT_MODE, target_versions={TargetVersion.PY27}) actual = fs(source, mode=mode) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) @@ -669,11 +750,11 @@ class BlackTestCase(unittest.TestCase): actual = fs(source) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) @patch("black.dump_to_file", dump_to_stderr) def test_stub(self) -> None: - mode = black.FileMode(is_pyi=True) + mode = replace(DEFAULT_MODE, is_pyi=True) source, expected = read_data("stub.pyi") actual = fs(source, mode=mode) self.assertFormatEqual(expected, actual) @@ -688,7 +769,7 @@ class BlackTestCase(unittest.TestCase): major, minor = sys.version_info[:2] if major < 3 or (major <= 3 and minor < 7): black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) # ensure black can parse this when the target is 3.6 self.invokeBlack([str(source_path), "--target-version", "py36"]) # but not on 3.7, because async/await is no longer an identifier @@ -703,7 +784,7 @@ class BlackTestCase(unittest.TestCase): major, minor = sys.version_info[:2] if major > 3 or (major == 3 and minor >= 7): black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) # ensure black can parse this when the target is 3.7 self.invokeBlack([str(source_path), "--target-version", "py37"]) # but not on 3.6, because we use async as a reserved keyword @@ -717,7 +798,7 @@ class BlackTestCase(unittest.TestCase): major, minor = sys.version_info[:2] if major > 3 or (major == 3 and minor >= 8): black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) @patch("black.dump_to_file", dump_to_stderr) def test_fmtonoff(self) -> None: @@ -725,7 +806,7 @@ class BlackTestCase(unittest.TestCase): actual = fs(source) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) @patch("black.dump_to_file", dump_to_stderr) def test_fmtonoff2(self) -> None: @@ -733,7 +814,7 @@ class BlackTestCase(unittest.TestCase): actual = fs(source) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) @patch("black.dump_to_file", dump_to_stderr) def test_fmtonoff3(self) -> None: @@ -741,7 +822,7 @@ class BlackTestCase(unittest.TestCase): actual = fs(source) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) @patch("black.dump_to_file", dump_to_stderr) def test_fmtonoff4(self) -> None: @@ -749,7 +830,7 @@ class BlackTestCase(unittest.TestCase): actual = fs(source) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) @patch("black.dump_to_file", dump_to_stderr) def test_remove_empty_parentheses_after_class(self) -> None: @@ -757,7 +838,7 @@ class BlackTestCase(unittest.TestCase): actual = fs(source) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) @patch("black.dump_to_file", dump_to_stderr) def test_new_line_between_class_and_code(self) -> None: @@ -765,7 +846,7 @@ class BlackTestCase(unittest.TestCase): actual = fs(source) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) @patch("black.dump_to_file", dump_to_stderr) def test_bracket_match(self) -> None: @@ -773,7 +854,7 @@ class BlackTestCase(unittest.TestCase): actual = fs(source) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) @patch("black.dump_to_file", dump_to_stderr) def test_tuple_assign(self) -> None: @@ -781,7 +862,7 @@ class BlackTestCase(unittest.TestCase): actual = fs(source) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) @patch("black.dump_to_file", dump_to_stderr) def test_beginning_backslash(self) -> None: @@ -789,7 +870,7 @@ class BlackTestCase(unittest.TestCase): actual = fs(source) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) def test_tab_comment_indentation(self) -> None: contents_tab = "if 1:\n\tif 2:\n\t\tpass\n\t# comment\n\tpass\n" @@ -1218,7 +1299,7 @@ class BlackTestCase(unittest.TestCase): def test_format_file_contents(self) -> None: empty = "" - mode = black.FileMode() + mode = DEFAULT_MODE with self.assertRaises(black.NothingChanged): black.format_file_contents(empty, mode=mode, fast=False) just_nl = "\n" @@ -1263,7 +1344,7 @@ class BlackTestCase(unittest.TestCase): self.assertEqual("".join(err_lines), "") def test_cache_broken_file(self) -> None: - mode = black.FileMode() + mode = DEFAULT_MODE with cache_dir() as workspace: cache_file = black.get_cache_file(mode) with cache_file.open("w") as fobj: @@ -1277,7 +1358,7 @@ class BlackTestCase(unittest.TestCase): self.assertIn(src, cache) def test_cache_single_file_already_cached(self) -> None: - mode = black.FileMode() + mode = DEFAULT_MODE with cache_dir() as workspace: src = (workspace / "test.py").resolve() with src.open("w") as fobj: @@ -1289,7 +1370,7 @@ class BlackTestCase(unittest.TestCase): @event_loop() def test_cache_multiple_files(self) -> None: - mode = black.FileMode() + mode = DEFAULT_MODE with cache_dir() as workspace, patch( "black.ProcessPoolExecutor", new=ThreadPoolExecutor ): @@ -1310,17 +1391,63 @@ class BlackTestCase(unittest.TestCase): self.assertIn(two, cache) def test_no_cache_when_writeback_diff(self) -> None: - mode = black.FileMode() + mode = DEFAULT_MODE with cache_dir() as workspace: src = (workspace / "test.py").resolve() with src.open("w") as fobj: fobj.write("print('hello')") - self.invokeBlack([str(src), "--diff"]) - cache_file = black.get_cache_file(mode) - self.assertFalse(cache_file.exists()) + with patch("black.read_cache") as read_cache, patch( + "black.write_cache" + ) as write_cache: + self.invokeBlack([str(src), "--diff"]) + cache_file = black.get_cache_file(mode) + self.assertFalse(cache_file.exists()) + write_cache.assert_not_called() + read_cache.assert_not_called() + + def test_no_cache_when_writeback_color_diff(self) -> None: + mode = DEFAULT_MODE + with cache_dir() as workspace: + src = (workspace / "test.py").resolve() + with src.open("w") as fobj: + fobj.write("print('hello')") + with patch("black.read_cache") as read_cache, patch( + "black.write_cache" + ) as write_cache: + self.invokeBlack([str(src), "--diff", "--color"]) + cache_file = black.get_cache_file(mode) + self.assertFalse(cache_file.exists()) + write_cache.assert_not_called() + read_cache.assert_not_called() + + @event_loop() + def test_output_locking_when_writeback_diff(self) -> None: + with cache_dir() as workspace: + for tag in range(0, 4): + src = (workspace / f"test{tag}.py").resolve() + with src.open("w") as fobj: + fobj.write("print('hello')") + with patch("black.Manager", wraps=multiprocessing.Manager) as mgr: + self.invokeBlack(["--diff", str(workspace)], exit_code=0) + # this isn't quite doing what we want, but if it _isn't_ + # called then we cannot be using the lock it provides + mgr.assert_called() + + @event_loop() + def test_output_locking_when_writeback_color_diff(self) -> None: + with cache_dir() as workspace: + for tag in range(0, 4): + src = (workspace / f"test{tag}.py").resolve() + with src.open("w") as fobj: + fobj.write("print('hello')") + with patch("black.Manager", wraps=multiprocessing.Manager) as mgr: + self.invokeBlack(["--diff", "--color", str(workspace)], exit_code=0) + # this isn't quite doing what we want, but if it _isn't_ + # called then we cannot be using the lock it provides + mgr.assert_called() def test_no_cache_when_stdin(self) -> None: - mode = black.FileMode() + mode = DEFAULT_MODE with cache_dir(): result = CliRunner().invoke( black.main, ["-"], input=BytesIO(b"print('hello')") @@ -1330,12 +1457,12 @@ class BlackTestCase(unittest.TestCase): self.assertFalse(cache_file.exists()) def test_read_cache_no_cachefile(self) -> None: - mode = black.FileMode() + mode = DEFAULT_MODE with cache_dir(): self.assertEqual(black.read_cache(mode), {}) def test_write_cache_read_cache(self) -> None: - mode = black.FileMode() + mode = DEFAULT_MODE with cache_dir() as workspace: src = (workspace / "test.py").resolve() src.touch() @@ -1361,7 +1488,7 @@ class BlackTestCase(unittest.TestCase): self.assertEqual(done, {cached}) def test_write_cache_creates_directory_if_needed(self) -> None: - mode = black.FileMode() + mode = DEFAULT_MODE with cache_dir(exists=False) as workspace: self.assertFalse(workspace.exists()) black.write_cache({}, [], mode) @@ -1369,7 +1496,7 @@ class BlackTestCase(unittest.TestCase): @event_loop() def test_failed_formatting_does_not_get_cached(self) -> None: - mode = black.FileMode() + mode = DEFAULT_MODE with cache_dir() as workspace, patch( "black.ProcessPoolExecutor", new=ThreadPoolExecutor ): @@ -1385,7 +1512,7 @@ class BlackTestCase(unittest.TestCase): self.assertIn(clean, cache) def test_write_cache_write_fail(self) -> None: - mode = black.FileMode() + mode = DEFAULT_MODE with cache_dir(), patch.object(Path, "open") as mock: mock.side_effect = OSError black.write_cache({}, [], mode) @@ -1428,8 +1555,8 @@ class BlackTestCase(unittest.TestCase): self.invokeBlack([str(workspace.resolve())]) def test_read_cache_line_lengths(self) -> None: - mode = black.FileMode() - short_mode = black.FileMode(line_length=1) + mode = DEFAULT_MODE + short_mode = replace(DEFAULT_MODE, line_length=1) with cache_dir() as workspace: path = (workspace / "file.py").resolve() path.touch() @@ -1444,11 +1571,11 @@ class BlackTestCase(unittest.TestCase): actual = fs(source) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) def test_single_file_force_pyi(self) -> None: - reg_mode = black.FileMode() - pyi_mode = black.FileMode(is_pyi=True) + reg_mode = DEFAULT_MODE + pyi_mode = replace(DEFAULT_MODE, is_pyi=True) contents, expected = read_data("force_pyi") with cache_dir() as workspace: path = (workspace / "file.py").resolve() @@ -1466,8 +1593,8 @@ class BlackTestCase(unittest.TestCase): @event_loop() def test_multi_file_force_pyi(self) -> None: - reg_mode = black.FileMode() - pyi_mode = black.FileMode(is_pyi=True) + reg_mode = DEFAULT_MODE + pyi_mode = replace(DEFAULT_MODE, is_pyi=True) contents, expected = read_data("force_pyi") with cache_dir() as workspace: paths = [ @@ -1499,8 +1626,8 @@ class BlackTestCase(unittest.TestCase): self.assertFormatEqual(actual, expected) def test_single_file_force_py36(self) -> None: - reg_mode = black.FileMode() - py36_mode = black.FileMode(target_versions=black.PY36_VERSIONS) + reg_mode = DEFAULT_MODE + py36_mode = replace(DEFAULT_MODE, target_versions=black.PY36_VERSIONS) source, expected = read_data("force_py36") with cache_dir() as workspace: path = (workspace / "file.py").resolve() @@ -1518,8 +1645,8 @@ class BlackTestCase(unittest.TestCase): @event_loop() def test_multi_file_force_py36(self) -> None: - reg_mode = black.FileMode() - py36_mode = black.FileMode(target_versions=black.PY36_VERSIONS) + reg_mode = DEFAULT_MODE + py36_mode = replace(DEFAULT_MODE, target_versions=black.PY36_VERSIONS) source, expected = read_data("force_py36") with cache_dir() as workspace: paths = [ @@ -1546,7 +1673,7 @@ class BlackTestCase(unittest.TestCase): actual = fs(source) self.assertFormatEqual(expected, actual) black.assert_equivalent(source, actual) - black.assert_stable(source, actual, black.FileMode()) + black.assert_stable(source, actual, DEFAULT_MODE) def test_pipe_force_py36(self) -> None: source, expected = read_data("force_py36") @@ -1827,9 +1954,7 @@ class BlackTestCase(unittest.TestCase): def test_read_pyproject_toml(self) -> None: test_toml_file = THIS_DIR / "test.toml" fake_ctx = FakeContext() - black.read_pyproject_toml( - fake_ctx, FakeParameter(), str(test_toml_file), - ) + black.read_pyproject_toml(fake_ctx, FakeParameter(), str(test_toml_file)) config = fake_ctx.default_map self.assertEqual(config["verbose"], "1") self.assertEqual(config["check"], "no") @@ -1862,6 +1987,23 @@ class BlackTestCase(unittest.TestCase): self.assertEqual(black.find_project_root((src_dir,)), src_dir.resolve()) self.assertEqual(black.find_project_root((src_python,)), src_dir.resolve()) + def test_bpo_33660_workaround(self) -> None: + if system() == "Windows": + return + + # https://bugs.python.org/issue33660 + + old_cwd = Path.cwd() + try: + root = Path("/") + os.chdir(str(root)) + path = Path("workspace") / "project" + report = black.Report(verbose=True) + normalized_path = black.normalize_path_maybe_ignore(path, root, report) + self.assertEqual(normalized_path, "workspace/project") + finally: + os.chdir(str(old_cwd)) + class BlackDTestCase(AioHTTPTestCase): async def get_application(self) -> web.Application: @@ -2031,5 +2173,31 @@ class BlackDTestCase(AioHTTPTestCase): self.assertIsNotNone(response.headers.get(blackd.BLACK_VERSION_HEADER)) +with open(black.__file__, "r", encoding="utf-8") as _bf: + black_source_lines = _bf.readlines() + + +def tracefunc(frame: types.FrameType, event: str, arg: Any) -> Callable: + """Show function calls `from black/__init__.py` as they happen. + + Register this with `sys.settrace()` in a test you're debugging. + """ + if event != "call": + return tracefunc + + stack = len(inspect.stack()) - 19 + stack *= 2 + filename = frame.f_code.co_filename + lineno = frame.f_lineno + func_sig_lineno = lineno - 1 + funcname = black_source_lines[func_sig_lineno].strip() + while funcname.startswith("@"): + func_sig_lineno += 1 + funcname = black_source_lines[func_sig_lineno].strip() + if "black/__init__.py" in filename: + print(f"{' ' * stack}{lineno}:{funcname}") + return tracefunc + + if __name__ == "__main__": unittest.main(module="test_black")