All patches and comments are welcome. Please squash your changes to logical
commits before using git-format-patch and git-send-email to
patches@git.madduck.net.
If you'd read over the Git project's submission guidelines and adhered to them,
I'd be especially grateful.
   4 from concurrent.futures import ThreadPoolExecutor
 
   5 from contextlib import contextmanager
 
   6 from functools import partial
 
   7 from io import BytesIO, TextIOWrapper
 
   9 from pathlib import Path
 
  12 from tempfile import TemporaryDirectory
 
  13 from typing import Any, BinaryIO, Generator, List, Tuple, Iterator, TypeVar
 
  15 from unittest.mock import patch, MagicMock
 
  17 from click import unstyle
 
  18 from click.testing import CliRunner
 
  21 from black import Feature, TargetVersion
 
  25     from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop
 
  26     from aiohttp import web
 
  28     has_blackd_deps = False
 
  30     has_blackd_deps = True
 
  32 from pathspec import PathSpec
 
  34 ff = partial(black.format_file_in_place, mode=black.FileMode(), fast=True)
 
  35 fs = partial(black.format_str, mode=black.FileMode())
 
  36 THIS_FILE = Path(__file__)
 
  37 THIS_DIR = THIS_FILE.parent
 
  38 DETERMINISTIC_HEADER = "[Deterministic header]"
 
  39 EMPTY_LINE = "# EMPTY LINE WITH WHITESPACE" + " (this comment will be removed)"
 
  41     f"--target-version={version.name.lower()}" for version in black.PY36_VERSIONS
 
  47 def dump_to_stderr(*output: str) -> str:
 
  48     return "\n" + "\n".join(output) + "\n"
 
  51 def read_data(name: str, data: bool = True) -> Tuple[str, str]:
 
  52     """read_data('test_name') -> 'input', 'output'"""
 
  53     if not name.endswith((".py", ".pyi", ".out", ".diff")):
 
  55     _input: List[str] = []
 
  56     _output: List[str] = []
 
  57     base_dir = THIS_DIR / "data" if data else THIS_DIR
 
  58     with open(base_dir / name, "r", encoding="utf8") as test:
 
  59         lines = test.readlines()
 
  62         line = line.replace(EMPTY_LINE, "")
 
  63         if line.rstrip() == "# output":
 
  68     if _input and not _output:
 
  69         # If there's no output marker, treat the entire file as already pre-formatted.
 
  71     return "".join(_input).strip() + "\n", "".join(_output).strip() + "\n"
 
  75 def cache_dir(exists: bool = True) -> Iterator[Path]:
 
  76     with TemporaryDirectory() as workspace:
 
  77         cache_dir = Path(workspace)
 
  79             cache_dir = cache_dir / "new"
 
  80         with patch("black.CACHE_DIR", cache_dir):
 
  85 def event_loop(close: bool) -> Iterator[None]:
 
  86     policy = asyncio.get_event_loop_policy()
 
  87     loop = policy.new_event_loop()
 
  88     asyncio.set_event_loop(loop)
 
  98 def skip_if_exception(e: str) -> Iterator[None]:
 
 101     except Exception as exc:
 
 102         if exc.__class__.__name__ == e:
 
 103             unittest.skip(f"Encountered expected exception {exc}, skipping")
 
 108 class BlackRunner(CliRunner):
 
 109     """Modify CliRunner so that stderr is not merged with stdout.
 
 111     This is a hack that can be removed once we depend on Click 7.x"""
 
 113     def __init__(self) -> None:
 
 114         self.stderrbuf = BytesIO()
 
 115         self.stdoutbuf = BytesIO()
 
 116         self.stdout_bytes = b""
 
 117         self.stderr_bytes = b""
 
 121     def isolation(self, *args: Any, **kwargs: Any) -> Generator[BinaryIO, None, None]:
 
 122         with super().isolation(*args, **kwargs) as output:
 
 124                 hold_stderr = sys.stderr
 
 125                 sys.stderr = TextIOWrapper(self.stderrbuf, encoding=self.charset)
 
 128                 self.stdout_bytes = sys.stdout.buffer.getvalue()  # type: ignore
 
 129                 self.stderr_bytes = sys.stderr.buffer.getvalue()  # type: ignore
 
 130                 sys.stderr = hold_stderr
 
 133 class BlackTestCase(unittest.TestCase):
 
 136     def assertFormatEqual(self, expected: str, actual: str) -> None:
 
 137         if actual != expected and not os.environ.get("SKIP_AST_PRINT"):
 
 138             bdv: black.DebugVisitor[Any]
 
 139             black.out("Expected tree:", fg="green")
 
 141                 exp_node = black.lib2to3_parse(expected)
 
 142                 bdv = black.DebugVisitor()
 
 143                 list(bdv.visit(exp_node))
 
 144             except Exception as ve:
 
 146             black.out("Actual tree:", fg="red")
 
 148                 exp_node = black.lib2to3_parse(actual)
 
 149                 bdv = black.DebugVisitor()
 
 150                 list(bdv.visit(exp_node))
 
 151             except Exception as ve:
 
 153         self.assertEqual(expected, actual)
 
 156         self, args: List[str], exit_code: int = 0, ignore_config: bool = True
 
 158         runner = BlackRunner()
 
 160             args = ["--config", str(THIS_DIR / "empty.toml"), *args]
 
 161         result = runner.invoke(black.main, args)
 
 162         self.assertEqual(result.exit_code, exit_code, msg=runner.stderr_bytes.decode())
 
 164     @patch("black.dump_to_file", dump_to_stderr)
 
 165     def checkSourceFile(self, name: str) -> None:
 
 166         path = THIS_DIR.parent / name
 
 167         source, expected = read_data(str(path), data=False)
 
 169         self.assertFormatEqual(expected, actual)
 
 170         black.assert_equivalent(source, actual)
 
 171         black.assert_stable(source, actual, black.FileMode())
 
 172         self.assertFalse(ff(path))
 
 174     @patch("black.dump_to_file", dump_to_stderr)
 
 175     def test_empty(self) -> None:
 
 176         source = expected = ""
 
 178         self.assertFormatEqual(expected, actual)
 
 179         black.assert_equivalent(source, actual)
 
 180         black.assert_stable(source, actual, black.FileMode())
 
 182     def test_empty_ff(self) -> None:
 
 184         tmp_file = Path(black.dump_to_file())
 
 186             self.assertFalse(ff(tmp_file, write_back=black.WriteBack.YES))
 
 187             with open(tmp_file, encoding="utf8") as f:
 
 191         self.assertFormatEqual(expected, actual)
 
 193     def test_self(self) -> None:
 
 194         self.checkSourceFile("tests/test_black.py")
 
 196     def test_black(self) -> None:
 
 197         self.checkSourceFile("black.py")
 
 199     def test_pygram(self) -> None:
 
 200         self.checkSourceFile("blib2to3/pygram.py")
 
 202     def test_pytree(self) -> None:
 
 203         self.checkSourceFile("blib2to3/pytree.py")
 
 205     def test_conv(self) -> None:
 
 206         self.checkSourceFile("blib2to3/pgen2/conv.py")
 
 208     def test_driver(self) -> None:
 
 209         self.checkSourceFile("blib2to3/pgen2/driver.py")
 
 211     def test_grammar(self) -> None:
 
 212         self.checkSourceFile("blib2to3/pgen2/grammar.py")
 
 214     def test_literals(self) -> None:
 
 215         self.checkSourceFile("blib2to3/pgen2/literals.py")
 
 217     def test_parse(self) -> None:
 
 218         self.checkSourceFile("blib2to3/pgen2/parse.py")
 
 220     def test_pgen(self) -> None:
 
 221         self.checkSourceFile("blib2to3/pgen2/pgen.py")
 
 223     def test_tokenize(self) -> None:
 
 224         self.checkSourceFile("blib2to3/pgen2/tokenize.py")
 
 226     def test_token(self) -> None:
 
 227         self.checkSourceFile("blib2to3/pgen2/token.py")
 
 229     def test_setup(self) -> None:
 
 230         self.checkSourceFile("setup.py")
 
 232     def test_piping(self) -> None:
 
 233         source, expected = read_data("../black", data=False)
 
 234         result = BlackRunner().invoke(
 
 236             ["-", "--fast", f"--line-length={black.DEFAULT_LINE_LENGTH}"],
 
 237             input=BytesIO(source.encode("utf8")),
 
 239         self.assertEqual(result.exit_code, 0)
 
 240         self.assertFormatEqual(expected, result.output)
 
 241         black.assert_equivalent(source, result.output)
 
 242         black.assert_stable(source, result.output, black.FileMode())
 
 244     def test_piping_diff(self) -> None:
 
 245         diff_header = re.compile(
 
 246             rf"(STDIN|STDOUT)\t\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d\.\d\d\d\d\d\d "
 
 249         source, _ = read_data("expression.py")
 
 250         expected, _ = read_data("expression.diff")
 
 251         config = THIS_DIR / "data" / "empty_pyproject.toml"
 
 255             f"--line-length={black.DEFAULT_LINE_LENGTH}",
 
 257             f"--config={config}",
 
 259         result = BlackRunner().invoke(
 
 260             black.main, args, input=BytesIO(source.encode("utf8"))
 
 262         self.assertEqual(result.exit_code, 0)
 
 263         actual = diff_header.sub(DETERMINISTIC_HEADER, result.output)
 
 264         actual = actual.rstrip() + "\n"  # the diff output has a trailing space
 
 265         self.assertEqual(expected, actual)
 
 267     def test_piping_diff_with_color(self) -> None:
 
 268         source, _ = read_data("expression.py")
 
 269         config = THIS_DIR / "data" / "empty_pyproject.toml"
 
 273             f"--line-length={black.DEFAULT_LINE_LENGTH}",
 
 276             f"--config={config}",
 
 278         result = BlackRunner().invoke(
 
 279             black.main, args, input=BytesIO(source.encode("utf8"))
 
 281         actual = result.output
 
 282         # Again, the contents are checked in a different test, so only look for colors.
 
 283         self.assertIn("\033[1;37m", actual)
 
 284         self.assertIn("\033[36m", actual)
 
 285         self.assertIn("\033[32m", actual)
 
 286         self.assertIn("\033[31m", actual)
 
 287         self.assertIn("\033[0m", actual)
 
 289     @patch("black.dump_to_file", dump_to_stderr)
 
 290     def test_function(self) -> None:
 
 291         source, expected = read_data("function")
 
 293         self.assertFormatEqual(expected, actual)
 
 294         black.assert_equivalent(source, actual)
 
 295         black.assert_stable(source, actual, black.FileMode())
 
 297     @patch("black.dump_to_file", dump_to_stderr)
 
 298     def test_function2(self) -> None:
 
 299         source, expected = read_data("function2")
 
 301         self.assertFormatEqual(expected, actual)
 
 302         black.assert_equivalent(source, actual)
 
 303         black.assert_stable(source, actual, black.FileMode())
 
 305     @patch("black.dump_to_file", dump_to_stderr)
 
 306     def test_function_trailing_comma(self) -> None:
 
 307         source, expected = read_data("function_trailing_comma")
 
 309         self.assertFormatEqual(expected, actual)
 
 310         black.assert_equivalent(source, actual)
 
 311         black.assert_stable(source, actual, black.FileMode())
 
 313     @patch("black.dump_to_file", dump_to_stderr)
 
 314     def test_expression(self) -> None:
 
 315         source, expected = read_data("expression")
 
 317         self.assertFormatEqual(expected, actual)
 
 318         black.assert_equivalent(source, actual)
 
 319         black.assert_stable(source, actual, black.FileMode())
 
 321     @patch("black.dump_to_file", dump_to_stderr)
 
 322     def test_pep_572(self) -> None:
 
 323         source, expected = read_data("pep_572")
 
 325         self.assertFormatEqual(expected, actual)
 
 326         black.assert_stable(source, actual, black.FileMode())
 
 327         if sys.version_info >= (3, 8):
 
 328             black.assert_equivalent(source, actual)
 
 330     def test_pep_572_version_detection(self) -> None:
 
 331         source, _ = read_data("pep_572")
 
 332         root = black.lib2to3_parse(source)
 
 333         features = black.get_features_used(root)
 
 334         self.assertIn(black.Feature.ASSIGNMENT_EXPRESSIONS, features)
 
 335         versions = black.detect_target_versions(root)
 
 336         self.assertIn(black.TargetVersion.PY38, versions)
 
 338     def test_expression_ff(self) -> None:
 
 339         source, expected = read_data("expression")
 
 340         tmp_file = Path(black.dump_to_file(source))
 
 342             self.assertTrue(ff(tmp_file, write_back=black.WriteBack.YES))
 
 343             with open(tmp_file, encoding="utf8") as f:
 
 347         self.assertFormatEqual(expected, actual)
 
 348         with patch("black.dump_to_file", dump_to_stderr):
 
 349             black.assert_equivalent(source, actual)
 
 350             black.assert_stable(source, actual, black.FileMode())
 
 352     def test_expression_diff(self) -> None:
 
 353         source, _ = read_data("expression.py")
 
 354         expected, _ = read_data("expression.diff")
 
 355         tmp_file = Path(black.dump_to_file(source))
 
 356         diff_header = re.compile(
 
 357             rf"{re.escape(str(tmp_file))}\t\d\d\d\d-\d\d-\d\d "
 
 358             r"\d\d:\d\d:\d\d\.\d\d\d\d\d\d \+\d\d\d\d"
 
 361             result = BlackRunner().invoke(black.main, ["--diff", str(tmp_file)])
 
 362             self.assertEqual(result.exit_code, 0)
 
 365         actual = result.output
 
 366         actual = diff_header.sub(DETERMINISTIC_HEADER, actual)
 
 367         actual = actual.rstrip() + "\n"  # the diff output has a trailing space
 
 368         if expected != actual:
 
 369             dump = black.dump_to_file(actual)
 
 371                 "Expected diff isn't equal to the actual. If you made changes to"
 
 372                 " expression.py and this is an anticipated difference, overwrite"
 
 373                 f" tests/data/expression.diff with {dump}"
 
 375             self.assertEqual(expected, actual, msg)
 
 377     def test_expression_diff_with_color(self) -> None:
 
 378         source, _ = read_data("expression.py")
 
 379         expected, _ = read_data("expression.diff")
 
 380         tmp_file = Path(black.dump_to_file(source))
 
 382             result = BlackRunner().invoke(
 
 383                 black.main, ["--diff", "--color", str(tmp_file)]
 
 387         actual = result.output
 
 388         # We check the contents of the diff in `test_expression_diff`. All
 
 389         # we need to check here is that color codes exist in the result.
 
 390         self.assertIn("\033[1;37m", actual)
 
 391         self.assertIn("\033[36m", actual)
 
 392         self.assertIn("\033[32m", actual)
 
 393         self.assertIn("\033[31m", actual)
 
 394         self.assertIn("\033[0m", actual)
 
 396     @patch("black.dump_to_file", dump_to_stderr)
 
 397     def test_fstring(self) -> None:
 
 398         source, expected = read_data("fstring")
 
 400         self.assertFormatEqual(expected, actual)
 
 401         black.assert_equivalent(source, actual)
 
 402         black.assert_stable(source, actual, black.FileMode())
 
 404     @patch("black.dump_to_file", dump_to_stderr)
 
 405     def test_pep_570(self) -> None:
 
 406         source, expected = read_data("pep_570")
 
 408         self.assertFormatEqual(expected, actual)
 
 409         black.assert_stable(source, actual, black.FileMode())
 
 410         if sys.version_info >= (3, 8):
 
 411             black.assert_equivalent(source, actual)
 
 413     def test_detect_pos_only_arguments(self) -> None:
 
 414         source, _ = read_data("pep_570")
 
 415         root = black.lib2to3_parse(source)
 
 416         features = black.get_features_used(root)
 
 417         self.assertIn(black.Feature.POS_ONLY_ARGUMENTS, features)
 
 418         versions = black.detect_target_versions(root)
 
 419         self.assertIn(black.TargetVersion.PY38, versions)
 
 421     @patch("black.dump_to_file", dump_to_stderr)
 
 422     def test_string_quotes(self) -> None:
 
 423         source, expected = read_data("string_quotes")
 
 425         self.assertFormatEqual(expected, actual)
 
 426         black.assert_equivalent(source, actual)
 
 427         black.assert_stable(source, actual, black.FileMode())
 
 428         mode = black.FileMode(string_normalization=False)
 
 429         not_normalized = fs(source, mode=mode)
 
 430         self.assertFormatEqual(source.replace("\\\n", ""), not_normalized)
 
 431         black.assert_equivalent(source, not_normalized)
 
 432         black.assert_stable(source, not_normalized, mode=mode)
 
 434     @patch("black.dump_to_file", dump_to_stderr)
 
 435     def test_docstring(self) -> None:
 
 436         source, expected = read_data("docstring")
 
 438         self.assertFormatEqual(expected, actual)
 
 439         black.assert_equivalent(source, actual)
 
 440         black.assert_stable(source, actual, black.FileMode())
 
 442     def test_long_strings(self) -> None:
 
 443         """Tests for splitting long strings."""
 
 444         source, expected = read_data("long_strings")
 
 446         self.assertFormatEqual(expected, actual)
 
 447         black.assert_equivalent(source, actual)
 
 448         black.assert_stable(source, actual, black.FileMode())
 
 450     @patch("black.dump_to_file", dump_to_stderr)
 
 451     def test_long_strings__edge_case(self) -> None:
 
 452         """Edge-case tests for splitting long strings."""
 
 453         source, expected = read_data("long_strings__edge_case")
 
 455         self.assertFormatEqual(expected, actual)
 
 456         black.assert_equivalent(source, actual)
 
 457         black.assert_stable(source, actual, black.FileMode())
 
 459     @patch("black.dump_to_file", dump_to_stderr)
 
 460     def test_long_strings__regression(self) -> None:
 
 461         """Regression tests for splitting long strings."""
 
 462         source, expected = read_data("long_strings__regression")
 
 464         self.assertFormatEqual(expected, actual)
 
 465         black.assert_equivalent(source, actual)
 
 466         black.assert_stable(source, actual, black.FileMode())
 
 468     @patch("black.dump_to_file", dump_to_stderr)
 
 469     def test_slices(self) -> None:
 
 470         source, expected = read_data("slices")
 
 472         self.assertFormatEqual(expected, actual)
 
 473         black.assert_equivalent(source, actual)
 
 474         black.assert_stable(source, actual, black.FileMode())
 
 476     @patch("black.dump_to_file", dump_to_stderr)
 
 477     def test_comments(self) -> None:
 
 478         source, expected = read_data("comments")
 
 480         self.assertFormatEqual(expected, actual)
 
 481         black.assert_equivalent(source, actual)
 
 482         black.assert_stable(source, actual, black.FileMode())
 
 484     @patch("black.dump_to_file", dump_to_stderr)
 
 485     def test_comments2(self) -> None:
 
 486         source, expected = read_data("comments2")
 
 488         self.assertFormatEqual(expected, actual)
 
 489         black.assert_equivalent(source, actual)
 
 490         black.assert_stable(source, actual, black.FileMode())
 
 492     @patch("black.dump_to_file", dump_to_stderr)
 
 493     def test_comments3(self) -> None:
 
 494         source, expected = read_data("comments3")
 
 496         self.assertFormatEqual(expected, actual)
 
 497         black.assert_equivalent(source, actual)
 
 498         black.assert_stable(source, actual, black.FileMode())
 
 500     @patch("black.dump_to_file", dump_to_stderr)
 
 501     def test_comments4(self) -> None:
 
 502         source, expected = read_data("comments4")
 
 504         self.assertFormatEqual(expected, actual)
 
 505         black.assert_equivalent(source, actual)
 
 506         black.assert_stable(source, actual, black.FileMode())
 
 508     @patch("black.dump_to_file", dump_to_stderr)
 
 509     def test_comments5(self) -> None:
 
 510         source, expected = read_data("comments5")
 
 512         self.assertFormatEqual(expected, actual)
 
 513         black.assert_equivalent(source, actual)
 
 514         black.assert_stable(source, actual, black.FileMode())
 
 516     @patch("black.dump_to_file", dump_to_stderr)
 
 517     def test_comments6(self) -> None:
 
 518         source, expected = read_data("comments6")
 
 520         self.assertFormatEqual(expected, actual)
 
 521         black.assert_equivalent(source, actual)
 
 522         black.assert_stable(source, actual, black.FileMode())
 
 524     @patch("black.dump_to_file", dump_to_stderr)
 
 525     def test_comments7(self) -> None:
 
 526         source, expected = read_data("comments7")
 
 528         self.assertFormatEqual(expected, actual)
 
 529         black.assert_equivalent(source, actual)
 
 530         black.assert_stable(source, actual, black.FileMode())
 
 532     @patch("black.dump_to_file", dump_to_stderr)
 
 533     def test_comment_after_escaped_newline(self) -> None:
 
 534         source, expected = read_data("comment_after_escaped_newline")
 
 536         self.assertFormatEqual(expected, actual)
 
 537         black.assert_equivalent(source, actual)
 
 538         black.assert_stable(source, actual, black.FileMode())
 
 540     @patch("black.dump_to_file", dump_to_stderr)
 
 541     def test_cantfit(self) -> None:
 
 542         source, expected = read_data("cantfit")
 
 544         self.assertFormatEqual(expected, actual)
 
 545         black.assert_equivalent(source, actual)
 
 546         black.assert_stable(source, actual, black.FileMode())
 
 548     @patch("black.dump_to_file", dump_to_stderr)
 
 549     def test_import_spacing(self) -> None:
 
 550         source, expected = read_data("import_spacing")
 
 552         self.assertFormatEqual(expected, actual)
 
 553         black.assert_equivalent(source, actual)
 
 554         black.assert_stable(source, actual, black.FileMode())
 
 556     @patch("black.dump_to_file", dump_to_stderr)
 
 557     def test_composition(self) -> None:
 
 558         source, expected = read_data("composition")
 
 560         self.assertFormatEqual(expected, actual)
 
 561         black.assert_equivalent(source, actual)
 
 562         black.assert_stable(source, actual, black.FileMode())
 
 564     @patch("black.dump_to_file", dump_to_stderr)
 
 565     def test_empty_lines(self) -> None:
 
 566         source, expected = read_data("empty_lines")
 
 568         self.assertFormatEqual(expected, actual)
 
 569         black.assert_equivalent(source, actual)
 
 570         black.assert_stable(source, actual, black.FileMode())
 
 572     @patch("black.dump_to_file", dump_to_stderr)
 
 573     def test_remove_parens(self) -> None:
 
 574         source, expected = read_data("remove_parens")
 
 576         self.assertFormatEqual(expected, actual)
 
 577         black.assert_equivalent(source, actual)
 
 578         black.assert_stable(source, actual, black.FileMode())
 
 580     @patch("black.dump_to_file", dump_to_stderr)
 
 581     def test_string_prefixes(self) -> None:
 
 582         source, expected = read_data("string_prefixes")
 
 584         self.assertFormatEqual(expected, actual)
 
 585         black.assert_equivalent(source, actual)
 
 586         black.assert_stable(source, actual, black.FileMode())
 
 588     @patch("black.dump_to_file", dump_to_stderr)
 
 589     def test_numeric_literals(self) -> None:
 
 590         source, expected = read_data("numeric_literals")
 
 591         mode = black.FileMode(target_versions=black.PY36_VERSIONS)
 
 592         actual = fs(source, mode=mode)
 
 593         self.assertFormatEqual(expected, actual)
 
 594         black.assert_equivalent(source, actual)
 
 595         black.assert_stable(source, actual, mode)
 
 597     @patch("black.dump_to_file", dump_to_stderr)
 
 598     def test_numeric_literals_ignoring_underscores(self) -> None:
 
 599         source, expected = read_data("numeric_literals_skip_underscores")
 
 600         mode = black.FileMode(target_versions=black.PY36_VERSIONS)
 
 601         actual = fs(source, mode=mode)
 
 602         self.assertFormatEqual(expected, actual)
 
 603         black.assert_equivalent(source, actual)
 
 604         black.assert_stable(source, actual, mode)
 
 606     @patch("black.dump_to_file", dump_to_stderr)
 
 607     def test_numeric_literals_py2(self) -> None:
 
 608         source, expected = read_data("numeric_literals_py2")
 
 610         self.assertFormatEqual(expected, actual)
 
 611         black.assert_stable(source, actual, black.FileMode())
 
 613     @patch("black.dump_to_file", dump_to_stderr)
 
 614     def test_python2(self) -> None:
 
 615         source, expected = read_data("python2")
 
 617         self.assertFormatEqual(expected, actual)
 
 618         black.assert_equivalent(source, actual)
 
 619         black.assert_stable(source, actual, black.FileMode())
 
 621     @patch("black.dump_to_file", dump_to_stderr)
 
 622     def test_python2_print_function(self) -> None:
 
 623         source, expected = read_data("python2_print_function")
 
 624         mode = black.FileMode(target_versions={TargetVersion.PY27})
 
 625         actual = fs(source, mode=mode)
 
 626         self.assertFormatEqual(expected, actual)
 
 627         black.assert_equivalent(source, actual)
 
 628         black.assert_stable(source, actual, mode)
 
 630     @patch("black.dump_to_file", dump_to_stderr)
 
 631     def test_python2_unicode_literals(self) -> None:
 
 632         source, expected = read_data("python2_unicode_literals")
 
 634         self.assertFormatEqual(expected, actual)
 
 635         black.assert_equivalent(source, actual)
 
 636         black.assert_stable(source, actual, black.FileMode())
 
 638     @patch("black.dump_to_file", dump_to_stderr)
 
 639     def test_stub(self) -> None:
 
 640         mode = black.FileMode(is_pyi=True)
 
 641         source, expected = read_data("stub.pyi")
 
 642         actual = fs(source, mode=mode)
 
 643         self.assertFormatEqual(expected, actual)
 
 644         black.assert_stable(source, actual, mode)
 
 646     @patch("black.dump_to_file", dump_to_stderr)
 
 647     def test_async_as_identifier(self) -> None:
 
 648         source_path = (THIS_DIR / "data" / "async_as_identifier.py").resolve()
 
 649         source, expected = read_data("async_as_identifier")
 
 651         self.assertFormatEqual(expected, actual)
 
 652         major, minor = sys.version_info[:2]
 
 653         if major < 3 or (major <= 3 and minor < 7):
 
 654             black.assert_equivalent(source, actual)
 
 655         black.assert_stable(source, actual, black.FileMode())
 
 656         # ensure black can parse this when the target is 3.6
 
 657         self.invokeBlack([str(source_path), "--target-version", "py36"])
 
 658         # but not on 3.7, because async/await is no longer an identifier
 
 659         self.invokeBlack([str(source_path), "--target-version", "py37"], exit_code=123)
 
 661     @patch("black.dump_to_file", dump_to_stderr)
 
 662     def test_python37(self) -> None:
 
 663         source_path = (THIS_DIR / "data" / "python37.py").resolve()
 
 664         source, expected = read_data("python37")
 
 666         self.assertFormatEqual(expected, actual)
 
 667         major, minor = sys.version_info[:2]
 
 668         if major > 3 or (major == 3 and minor >= 7):
 
 669             black.assert_equivalent(source, actual)
 
 670         black.assert_stable(source, actual, black.FileMode())
 
 671         # ensure black can parse this when the target is 3.7
 
 672         self.invokeBlack([str(source_path), "--target-version", "py37"])
 
 673         # but not on 3.6, because we use async as a reserved keyword
 
 674         self.invokeBlack([str(source_path), "--target-version", "py36"], exit_code=123)
 
 676     @patch("black.dump_to_file", dump_to_stderr)
 
 677     def test_python38(self) -> None:
 
 678         source, expected = read_data("python38")
 
 680         self.assertFormatEqual(expected, actual)
 
 681         major, minor = sys.version_info[:2]
 
 682         if major > 3 or (major == 3 and minor >= 8):
 
 683             black.assert_equivalent(source, actual)
 
 684         black.assert_stable(source, actual, black.FileMode())
 
 686     @patch("black.dump_to_file", dump_to_stderr)
 
 687     def test_fmtonoff(self) -> None:
 
 688         source, expected = read_data("fmtonoff")
 
 690         self.assertFormatEqual(expected, actual)
 
 691         black.assert_equivalent(source, actual)
 
 692         black.assert_stable(source, actual, black.FileMode())
 
 694     @patch("black.dump_to_file", dump_to_stderr)
 
 695     def test_fmtonoff2(self) -> None:
 
 696         source, expected = read_data("fmtonoff2")
 
 698         self.assertFormatEqual(expected, actual)
 
 699         black.assert_equivalent(source, actual)
 
 700         black.assert_stable(source, actual, black.FileMode())
 
 702     @patch("black.dump_to_file", dump_to_stderr)
 
 703     def test_fmtonoff3(self) -> None:
 
 704         source, expected = read_data("fmtonoff3")
 
 706         self.assertFormatEqual(expected, actual)
 
 707         black.assert_equivalent(source, actual)
 
 708         black.assert_stable(source, actual, black.FileMode())
 
 710     @patch("black.dump_to_file", dump_to_stderr)
 
 711     def test_fmtonoff4(self) -> None:
 
 712         source, expected = read_data("fmtonoff4")
 
 714         self.assertFormatEqual(expected, actual)
 
 715         black.assert_equivalent(source, actual)
 
 716         black.assert_stable(source, actual, black.FileMode())
 
 718     @patch("black.dump_to_file", dump_to_stderr)
 
 719     def test_remove_empty_parentheses_after_class(self) -> None:
 
 720         source, expected = read_data("class_blank_parentheses")
 
 722         self.assertFormatEqual(expected, actual)
 
 723         black.assert_equivalent(source, actual)
 
 724         black.assert_stable(source, actual, black.FileMode())
 
 726     @patch("black.dump_to_file", dump_to_stderr)
 
 727     def test_new_line_between_class_and_code(self) -> None:
 
 728         source, expected = read_data("class_methods_new_line")
 
 730         self.assertFormatEqual(expected, actual)
 
 731         black.assert_equivalent(source, actual)
 
 732         black.assert_stable(source, actual, black.FileMode())
 
 734     @patch("black.dump_to_file", dump_to_stderr)
 
 735     def test_bracket_match(self) -> None:
 
 736         source, expected = read_data("bracketmatch")
 
 738         self.assertFormatEqual(expected, actual)
 
 739         black.assert_equivalent(source, actual)
 
 740         black.assert_stable(source, actual, black.FileMode())
 
 742     @patch("black.dump_to_file", dump_to_stderr)
 
 743     def test_tuple_assign(self) -> None:
 
 744         source, expected = read_data("tupleassign")
 
 746         self.assertFormatEqual(expected, actual)
 
 747         black.assert_equivalent(source, actual)
 
 748         black.assert_stable(source, actual, black.FileMode())
 
 750     @patch("black.dump_to_file", dump_to_stderr)
 
 751     def test_beginning_backslash(self) -> None:
 
 752         source, expected = read_data("beginning_backslash")
 
 754         self.assertFormatEqual(expected, actual)
 
 755         black.assert_equivalent(source, actual)
 
 756         black.assert_stable(source, actual, black.FileMode())
 
 758     def test_tab_comment_indentation(self) -> None:
 
 759         contents_tab = "if 1:\n\tif 2:\n\t\tpass\n\t# comment\n\tpass\n"
 
 760         contents_spc = "if 1:\n    if 2:\n        pass\n    # comment\n    pass\n"
 
 761         self.assertFormatEqual(contents_spc, fs(contents_spc))
 
 762         self.assertFormatEqual(contents_spc, fs(contents_tab))
 
 764         contents_tab = "if 1:\n\tif 2:\n\t\tpass\n\t\t# comment\n\tpass\n"
 
 765         contents_spc = "if 1:\n    if 2:\n        pass\n        # comment\n    pass\n"
 
 766         self.assertFormatEqual(contents_spc, fs(contents_spc))
 
 767         self.assertFormatEqual(contents_spc, fs(contents_tab))
 
 769         # mixed tabs and spaces (valid Python 2 code)
 
 770         contents_tab = "if 1:\n        if 2:\n\t\tpass\n\t# comment\n        pass\n"
 
 771         contents_spc = "if 1:\n    if 2:\n        pass\n    # comment\n    pass\n"
 
 772         self.assertFormatEqual(contents_spc, fs(contents_spc))
 
 773         self.assertFormatEqual(contents_spc, fs(contents_tab))
 
 775         contents_tab = "if 1:\n        if 2:\n\t\tpass\n\t\t# comment\n        pass\n"
 
 776         contents_spc = "if 1:\n    if 2:\n        pass\n        # comment\n    pass\n"
 
 777         self.assertFormatEqual(contents_spc, fs(contents_spc))
 
 778         self.assertFormatEqual(contents_spc, fs(contents_tab))
 
 780     def test_report_verbose(self) -> None:
 
 781         report = black.Report(verbose=True)
 
 785         def out(msg: str, **kwargs: Any) -> None:
 
 786             out_lines.append(msg)
 
 788         def err(msg: str, **kwargs: Any) -> None:
 
 789             err_lines.append(msg)
 
 791         with patch("black.out", out), patch("black.err", err):
 
 792             report.done(Path("f1"), black.Changed.NO)
 
 793             self.assertEqual(len(out_lines), 1)
 
 794             self.assertEqual(len(err_lines), 0)
 
 795             self.assertEqual(out_lines[-1], "f1 already well formatted, good job.")
 
 796             self.assertEqual(unstyle(str(report)), "1 file left unchanged.")
 
 797             self.assertEqual(report.return_code, 0)
 
 798             report.done(Path("f2"), black.Changed.YES)
 
 799             self.assertEqual(len(out_lines), 2)
 
 800             self.assertEqual(len(err_lines), 0)
 
 801             self.assertEqual(out_lines[-1], "reformatted f2")
 
 803                 unstyle(str(report)), "1 file reformatted, 1 file left unchanged."
 
 805             report.done(Path("f3"), black.Changed.CACHED)
 
 806             self.assertEqual(len(out_lines), 3)
 
 807             self.assertEqual(len(err_lines), 0)
 
 809                 out_lines[-1], "f3 wasn't modified on disk since last run."
 
 812                 unstyle(str(report)), "1 file reformatted, 2 files left unchanged."
 
 814             self.assertEqual(report.return_code, 0)
 
 816             self.assertEqual(report.return_code, 1)
 
 818             report.failed(Path("e1"), "boom")
 
 819             self.assertEqual(len(out_lines), 3)
 
 820             self.assertEqual(len(err_lines), 1)
 
 821             self.assertEqual(err_lines[-1], "error: cannot format e1: boom")
 
 823                 unstyle(str(report)),
 
 824                 "1 file reformatted, 2 files left unchanged, 1 file failed to"
 
 827             self.assertEqual(report.return_code, 123)
 
 828             report.done(Path("f3"), black.Changed.YES)
 
 829             self.assertEqual(len(out_lines), 4)
 
 830             self.assertEqual(len(err_lines), 1)
 
 831             self.assertEqual(out_lines[-1], "reformatted f3")
 
 833                 unstyle(str(report)),
 
 834                 "2 files reformatted, 2 files left unchanged, 1 file failed to"
 
 837             self.assertEqual(report.return_code, 123)
 
 838             report.failed(Path("e2"), "boom")
 
 839             self.assertEqual(len(out_lines), 4)
 
 840             self.assertEqual(len(err_lines), 2)
 
 841             self.assertEqual(err_lines[-1], "error: cannot format e2: boom")
 
 843                 unstyle(str(report)),
 
 844                 "2 files reformatted, 2 files left unchanged, 2 files failed to"
 
 847             self.assertEqual(report.return_code, 123)
 
 848             report.path_ignored(Path("wat"), "no match")
 
 849             self.assertEqual(len(out_lines), 5)
 
 850             self.assertEqual(len(err_lines), 2)
 
 851             self.assertEqual(out_lines[-1], "wat ignored: no match")
 
 853                 unstyle(str(report)),
 
 854                 "2 files reformatted, 2 files left unchanged, 2 files failed to"
 
 857             self.assertEqual(report.return_code, 123)
 
 858             report.done(Path("f4"), black.Changed.NO)
 
 859             self.assertEqual(len(out_lines), 6)
 
 860             self.assertEqual(len(err_lines), 2)
 
 861             self.assertEqual(out_lines[-1], "f4 already well formatted, good job.")
 
 863                 unstyle(str(report)),
 
 864                 "2 files reformatted, 3 files left unchanged, 2 files failed to"
 
 867             self.assertEqual(report.return_code, 123)
 
 870                 unstyle(str(report)),
 
 871                 "2 files would be reformatted, 3 files would be left unchanged, 2 files"
 
 872                 " would fail to reformat.",
 
 877                 unstyle(str(report)),
 
 878                 "2 files would be reformatted, 3 files would be left unchanged, 2 files"
 
 879                 " would fail to reformat.",
 
 882     def test_report_quiet(self) -> None:
 
 883         report = black.Report(quiet=True)
 
 887         def out(msg: str, **kwargs: Any) -> None:
 
 888             out_lines.append(msg)
 
 890         def err(msg: str, **kwargs: Any) -> None:
 
 891             err_lines.append(msg)
 
 893         with patch("black.out", out), patch("black.err", err):
 
 894             report.done(Path("f1"), black.Changed.NO)
 
 895             self.assertEqual(len(out_lines), 0)
 
 896             self.assertEqual(len(err_lines), 0)
 
 897             self.assertEqual(unstyle(str(report)), "1 file left unchanged.")
 
 898             self.assertEqual(report.return_code, 0)
 
 899             report.done(Path("f2"), black.Changed.YES)
 
 900             self.assertEqual(len(out_lines), 0)
 
 901             self.assertEqual(len(err_lines), 0)
 
 903                 unstyle(str(report)), "1 file reformatted, 1 file left unchanged."
 
 905             report.done(Path("f3"), black.Changed.CACHED)
 
 906             self.assertEqual(len(out_lines), 0)
 
 907             self.assertEqual(len(err_lines), 0)
 
 909                 unstyle(str(report)), "1 file reformatted, 2 files left unchanged."
 
 911             self.assertEqual(report.return_code, 0)
 
 913             self.assertEqual(report.return_code, 1)
 
 915             report.failed(Path("e1"), "boom")
 
 916             self.assertEqual(len(out_lines), 0)
 
 917             self.assertEqual(len(err_lines), 1)
 
 918             self.assertEqual(err_lines[-1], "error: cannot format e1: boom")
 
 920                 unstyle(str(report)),
 
 921                 "1 file reformatted, 2 files left unchanged, 1 file failed to"
 
 924             self.assertEqual(report.return_code, 123)
 
 925             report.done(Path("f3"), black.Changed.YES)
 
 926             self.assertEqual(len(out_lines), 0)
 
 927             self.assertEqual(len(err_lines), 1)
 
 929                 unstyle(str(report)),
 
 930                 "2 files reformatted, 2 files left unchanged, 1 file failed to"
 
 933             self.assertEqual(report.return_code, 123)
 
 934             report.failed(Path("e2"), "boom")
 
 935             self.assertEqual(len(out_lines), 0)
 
 936             self.assertEqual(len(err_lines), 2)
 
 937             self.assertEqual(err_lines[-1], "error: cannot format e2: boom")
 
 939                 unstyle(str(report)),
 
 940                 "2 files reformatted, 2 files left unchanged, 2 files failed to"
 
 943             self.assertEqual(report.return_code, 123)
 
 944             report.path_ignored(Path("wat"), "no match")
 
 945             self.assertEqual(len(out_lines), 0)
 
 946             self.assertEqual(len(err_lines), 2)
 
 948                 unstyle(str(report)),
 
 949                 "2 files reformatted, 2 files left unchanged, 2 files failed to"
 
 952             self.assertEqual(report.return_code, 123)
 
 953             report.done(Path("f4"), black.Changed.NO)
 
 954             self.assertEqual(len(out_lines), 0)
 
 955             self.assertEqual(len(err_lines), 2)
 
 957                 unstyle(str(report)),
 
 958                 "2 files reformatted, 3 files left unchanged, 2 files failed to"
 
 961             self.assertEqual(report.return_code, 123)
 
 964                 unstyle(str(report)),
 
 965                 "2 files would be reformatted, 3 files would be left unchanged, 2 files"
 
 966                 " would fail to reformat.",
 
 971                 unstyle(str(report)),
 
 972                 "2 files would be reformatted, 3 files would be left unchanged, 2 files"
 
 973                 " would fail to reformat.",
 
 976     def test_report_normal(self) -> None:
 
 977         report = black.Report()
 
 981         def out(msg: str, **kwargs: Any) -> None:
 
 982             out_lines.append(msg)
 
 984         def err(msg: str, **kwargs: Any) -> None:
 
 985             err_lines.append(msg)
 
 987         with patch("black.out", out), patch("black.err", err):
 
 988             report.done(Path("f1"), black.Changed.NO)
 
 989             self.assertEqual(len(out_lines), 0)
 
 990             self.assertEqual(len(err_lines), 0)
 
 991             self.assertEqual(unstyle(str(report)), "1 file left unchanged.")
 
 992             self.assertEqual(report.return_code, 0)
 
 993             report.done(Path("f2"), black.Changed.YES)
 
 994             self.assertEqual(len(out_lines), 1)
 
 995             self.assertEqual(len(err_lines), 0)
 
 996             self.assertEqual(out_lines[-1], "reformatted f2")
 
 998                 unstyle(str(report)), "1 file reformatted, 1 file left unchanged."
 
1000             report.done(Path("f3"), black.Changed.CACHED)
 
1001             self.assertEqual(len(out_lines), 1)
 
1002             self.assertEqual(len(err_lines), 0)
 
1003             self.assertEqual(out_lines[-1], "reformatted f2")
 
1005                 unstyle(str(report)), "1 file reformatted, 2 files left unchanged."
 
1007             self.assertEqual(report.return_code, 0)
 
1009             self.assertEqual(report.return_code, 1)
 
1010             report.check = False
 
1011             report.failed(Path("e1"), "boom")
 
1012             self.assertEqual(len(out_lines), 1)
 
1013             self.assertEqual(len(err_lines), 1)
 
1014             self.assertEqual(err_lines[-1], "error: cannot format e1: boom")
 
1016                 unstyle(str(report)),
 
1017                 "1 file reformatted, 2 files left unchanged, 1 file failed to"
 
1020             self.assertEqual(report.return_code, 123)
 
1021             report.done(Path("f3"), black.Changed.YES)
 
1022             self.assertEqual(len(out_lines), 2)
 
1023             self.assertEqual(len(err_lines), 1)
 
1024             self.assertEqual(out_lines[-1], "reformatted f3")
 
1026                 unstyle(str(report)),
 
1027                 "2 files reformatted, 2 files left unchanged, 1 file failed to"
 
1030             self.assertEqual(report.return_code, 123)
 
1031             report.failed(Path("e2"), "boom")
 
1032             self.assertEqual(len(out_lines), 2)
 
1033             self.assertEqual(len(err_lines), 2)
 
1034             self.assertEqual(err_lines[-1], "error: cannot format e2: boom")
 
1036                 unstyle(str(report)),
 
1037                 "2 files reformatted, 2 files left unchanged, 2 files failed to"
 
1040             self.assertEqual(report.return_code, 123)
 
1041             report.path_ignored(Path("wat"), "no match")
 
1042             self.assertEqual(len(out_lines), 2)
 
1043             self.assertEqual(len(err_lines), 2)
 
1045                 unstyle(str(report)),
 
1046                 "2 files reformatted, 2 files left unchanged, 2 files failed to"
 
1049             self.assertEqual(report.return_code, 123)
 
1050             report.done(Path("f4"), black.Changed.NO)
 
1051             self.assertEqual(len(out_lines), 2)
 
1052             self.assertEqual(len(err_lines), 2)
 
1054                 unstyle(str(report)),
 
1055                 "2 files reformatted, 3 files left unchanged, 2 files failed to"
 
1058             self.assertEqual(report.return_code, 123)
 
1061                 unstyle(str(report)),
 
1062                 "2 files would be reformatted, 3 files would be left unchanged, 2 files"
 
1063                 " would fail to reformat.",
 
1065             report.check = False
 
1068                 unstyle(str(report)),
 
1069                 "2 files would be reformatted, 3 files would be left unchanged, 2 files"
 
1070                 " would fail to reformat.",
 
1073     def test_lib2to3_parse(self) -> None:
 
1074         with self.assertRaises(black.InvalidInput):
 
1075             black.lib2to3_parse("invalid syntax")
 
1077         straddling = "x + y"
 
1078         black.lib2to3_parse(straddling)
 
1079         black.lib2to3_parse(straddling, {TargetVersion.PY27})
 
1080         black.lib2to3_parse(straddling, {TargetVersion.PY36})
 
1081         black.lib2to3_parse(straddling, {TargetVersion.PY27, TargetVersion.PY36})
 
1083         py2_only = "print x"
 
1084         black.lib2to3_parse(py2_only)
 
1085         black.lib2to3_parse(py2_only, {TargetVersion.PY27})
 
1086         with self.assertRaises(black.InvalidInput):
 
1087             black.lib2to3_parse(py2_only, {TargetVersion.PY36})
 
1088         with self.assertRaises(black.InvalidInput):
 
1089             black.lib2to3_parse(py2_only, {TargetVersion.PY27, TargetVersion.PY36})
 
1091         py3_only = "exec(x, end=y)"
 
1092         black.lib2to3_parse(py3_only)
 
1093         with self.assertRaises(black.InvalidInput):
 
1094             black.lib2to3_parse(py3_only, {TargetVersion.PY27})
 
1095         black.lib2to3_parse(py3_only, {TargetVersion.PY36})
 
1096         black.lib2to3_parse(py3_only, {TargetVersion.PY27, TargetVersion.PY36})
 
1098     def test_get_features_used(self) -> None:
 
1099         node = black.lib2to3_parse("def f(*, arg): ...\n")
 
1100         self.assertEqual(black.get_features_used(node), set())
 
1101         node = black.lib2to3_parse("def f(*, arg,): ...\n")
 
1102         self.assertEqual(black.get_features_used(node), {Feature.TRAILING_COMMA_IN_DEF})
 
1103         node = black.lib2to3_parse("f(*arg,)\n")
 
1105             black.get_features_used(node), {Feature.TRAILING_COMMA_IN_CALL}
 
1107         node = black.lib2to3_parse("def f(*, arg): f'string'\n")
 
1108         self.assertEqual(black.get_features_used(node), {Feature.F_STRINGS})
 
1109         node = black.lib2to3_parse("123_456\n")
 
1110         self.assertEqual(black.get_features_used(node), {Feature.NUMERIC_UNDERSCORES})
 
1111         node = black.lib2to3_parse("123456\n")
 
1112         self.assertEqual(black.get_features_used(node), set())
 
1113         source, expected = read_data("function")
 
1114         node = black.lib2to3_parse(source)
 
1115         expected_features = {
 
1116             Feature.TRAILING_COMMA_IN_CALL,
 
1117             Feature.TRAILING_COMMA_IN_DEF,
 
1120         self.assertEqual(black.get_features_used(node), expected_features)
 
1121         node = black.lib2to3_parse(expected)
 
1122         self.assertEqual(black.get_features_used(node), expected_features)
 
1123         source, expected = read_data("expression")
 
1124         node = black.lib2to3_parse(source)
 
1125         self.assertEqual(black.get_features_used(node), set())
 
1126         node = black.lib2to3_parse(expected)
 
1127         self.assertEqual(black.get_features_used(node), set())
 
1129     def test_get_future_imports(self) -> None:
 
1130         node = black.lib2to3_parse("\n")
 
1131         self.assertEqual(set(), black.get_future_imports(node))
 
1132         node = black.lib2to3_parse("from __future__ import black\n")
 
1133         self.assertEqual({"black"}, black.get_future_imports(node))
 
1134         node = black.lib2to3_parse("from __future__ import multiple, imports\n")
 
1135         self.assertEqual({"multiple", "imports"}, black.get_future_imports(node))
 
1136         node = black.lib2to3_parse("from __future__ import (parenthesized, imports)\n")
 
1137         self.assertEqual({"parenthesized", "imports"}, black.get_future_imports(node))
 
1138         node = black.lib2to3_parse(
 
1139             "from __future__ import multiple\nfrom __future__ import imports\n"
 
1141         self.assertEqual({"multiple", "imports"}, black.get_future_imports(node))
 
1142         node = black.lib2to3_parse("# comment\nfrom __future__ import black\n")
 
1143         self.assertEqual({"black"}, black.get_future_imports(node))
 
1144         node = black.lib2to3_parse('"""docstring"""\nfrom __future__ import black\n')
 
1145         self.assertEqual({"black"}, black.get_future_imports(node))
 
1146         node = black.lib2to3_parse("some(other, code)\nfrom __future__ import black\n")
 
1147         self.assertEqual(set(), black.get_future_imports(node))
 
1148         node = black.lib2to3_parse("from some.module import black\n")
 
1149         self.assertEqual(set(), black.get_future_imports(node))
 
1150         node = black.lib2to3_parse(
 
1151             "from __future__ import unicode_literals as _unicode_literals"
 
1153         self.assertEqual({"unicode_literals"}, black.get_future_imports(node))
 
1154         node = black.lib2to3_parse(
 
1155             "from __future__ import unicode_literals as _lol, print"
 
1157         self.assertEqual({"unicode_literals", "print"}, black.get_future_imports(node))
 
1159     def test_debug_visitor(self) -> None:
 
1160         source, _ = read_data("debug_visitor.py")
 
1161         expected, _ = read_data("debug_visitor.out")
 
1165         def out(msg: str, **kwargs: Any) -> None:
 
1166             out_lines.append(msg)
 
1168         def err(msg: str, **kwargs: Any) -> None:
 
1169             err_lines.append(msg)
 
1171         with patch("black.out", out), patch("black.err", err):
 
1172             black.DebugVisitor.show(source)
 
1173         actual = "\n".join(out_lines) + "\n"
 
1175         if expected != actual:
 
1176             log_name = black.dump_to_file(*out_lines)
 
1180             f"AST print out is different. Actual version dumped to {log_name}",
 
1183     def test_format_file_contents(self) -> None:
 
1185         mode = black.FileMode()
 
1186         with self.assertRaises(black.NothingChanged):
 
1187             black.format_file_contents(empty, mode=mode, fast=False)
 
1189         with self.assertRaises(black.NothingChanged):
 
1190             black.format_file_contents(just_nl, mode=mode, fast=False)
 
1191         same = "j = [1, 2, 3]\n"
 
1192         with self.assertRaises(black.NothingChanged):
 
1193             black.format_file_contents(same, mode=mode, fast=False)
 
1194         different = "j = [1,2,3]"
 
1196         actual = black.format_file_contents(different, mode=mode, fast=False)
 
1197         self.assertEqual(expected, actual)
 
1198         invalid = "return if you can"
 
1199         with self.assertRaises(black.InvalidInput) as e:
 
1200             black.format_file_contents(invalid, mode=mode, fast=False)
 
1201         self.assertEqual(str(e.exception), "Cannot parse: 1:7: return if you can")
 
1203     def test_endmarker(self) -> None:
 
1204         n = black.lib2to3_parse("\n")
 
1205         self.assertEqual(n.type, black.syms.file_input)
 
1206         self.assertEqual(len(n.children), 1)
 
1207         self.assertEqual(n.children[0].type, black.token.ENDMARKER)
 
1209     @unittest.skipIf(os.environ.get("SKIP_AST_PRINT"), "user set SKIP_AST_PRINT")
 
1210     def test_assertFormatEqual(self) -> None:
 
1214         def out(msg: str, **kwargs: Any) -> None:
 
1215             out_lines.append(msg)
 
1217         def err(msg: str, **kwargs: Any) -> None:
 
1218             err_lines.append(msg)
 
1220         with patch("black.out", out), patch("black.err", err):
 
1221             with self.assertRaises(AssertionError):
 
1222                 self.assertFormatEqual("j = [1, 2, 3]", "j = [1, 2, 3,]")
 
1224         out_str = "".join(out_lines)
 
1225         self.assertTrue("Expected tree:" in out_str)
 
1226         self.assertTrue("Actual tree:" in out_str)
 
1227         self.assertEqual("".join(err_lines), "")
 
1229     def test_cache_broken_file(self) -> None:
 
1230         mode = black.FileMode()
 
1231         with cache_dir() as workspace:
 
1232             cache_file = black.get_cache_file(mode)
 
1233             with cache_file.open("w") as fobj:
 
1234                 fobj.write("this is not a pickle")
 
1235             self.assertEqual(black.read_cache(mode), {})
 
1236             src = (workspace / "test.py").resolve()
 
1237             with src.open("w") as fobj:
 
1238                 fobj.write("print('hello')")
 
1239             self.invokeBlack([str(src)])
 
1240             cache = black.read_cache(mode)
 
1241             self.assertIn(src, cache)
 
1243     def test_cache_single_file_already_cached(self) -> None:
 
1244         mode = black.FileMode()
 
1245         with cache_dir() as workspace:
 
1246             src = (workspace / "test.py").resolve()
 
1247             with src.open("w") as fobj:
 
1248                 fobj.write("print('hello')")
 
1249             black.write_cache({}, [src], mode)
 
1250             self.invokeBlack([str(src)])
 
1251             with src.open("r") as fobj:
 
1252                 self.assertEqual(fobj.read(), "print('hello')")
 
1254     @event_loop(close=False)
 
1255     def test_cache_multiple_files(self) -> None:
 
1256         mode = black.FileMode()
 
1257         with cache_dir() as workspace, patch(
 
1258             "black.ProcessPoolExecutor", new=ThreadPoolExecutor
 
1260             one = (workspace / "one.py").resolve()
 
1261             with one.open("w") as fobj:
 
1262                 fobj.write("print('hello')")
 
1263             two = (workspace / "two.py").resolve()
 
1264             with two.open("w") as fobj:
 
1265                 fobj.write("print('hello')")
 
1266             black.write_cache({}, [one], mode)
 
1267             self.invokeBlack([str(workspace)])
 
1268             with one.open("r") as fobj:
 
1269                 self.assertEqual(fobj.read(), "print('hello')")
 
1270             with two.open("r") as fobj:
 
1271                 self.assertEqual(fobj.read(), 'print("hello")\n')
 
1272             cache = black.read_cache(mode)
 
1273             self.assertIn(one, cache)
 
1274             self.assertIn(two, cache)
 
1276     @patch("black.ProcessPoolExecutor", autospec=True)
 
1277     def test_works_in_mono_process_only_environment(self, mock_executor) -> None:
 
1278         mock_executor.side_effect = OSError()
 
1279         mode = black.FileMode()
 
1280         with cache_dir() as workspace:
 
1281             one = (workspace / "one.py").resolve()
 
1282             with one.open("w") as fobj:
 
1283                 fobj.write("print('hello')")
 
1284             two = (workspace / "two.py").resolve()
 
1285             with two.open("w") as fobj:
 
1286                 fobj.write("print('hello')")
 
1287             black.write_cache({}, [one], mode)
 
1288             self.invokeBlack([str(workspace)])
 
1289             with one.open("r") as fobj:
 
1290                 self.assertEqual(fobj.read(), "print('hello')")
 
1291             with two.open("r") as fobj:
 
1292                 self.assertEqual(fobj.read(), 'print("hello")\n')
 
1293             cache = black.read_cache(mode)
 
1294             self.assertIn(one, cache)
 
1295             self.assertIn(two, cache)
 
1297     def test_no_cache_when_writeback_diff(self) -> None:
 
1298         mode = black.FileMode()
 
1299         with cache_dir() as workspace:
 
1300             src = (workspace / "test.py").resolve()
 
1301             with src.open("w") as fobj:
 
1302                 fobj.write("print('hello')")
 
1303             self.invokeBlack([str(src), "--diff"])
 
1304             cache_file = black.get_cache_file(mode)
 
1305             self.assertFalse(cache_file.exists())
 
1307     def test_no_cache_when_stdin(self) -> None:
 
1308         mode = black.FileMode()
 
1310             result = CliRunner().invoke(
 
1311                 black.main, ["-"], input=BytesIO(b"print('hello')")
 
1313             self.assertEqual(result.exit_code, 0)
 
1314             cache_file = black.get_cache_file(mode)
 
1315             self.assertFalse(cache_file.exists())
 
1317     def test_read_cache_no_cachefile(self) -> None:
 
1318         mode = black.FileMode()
 
1320             self.assertEqual(black.read_cache(mode), {})
 
1322     def test_write_cache_read_cache(self) -> None:
 
1323         mode = black.FileMode()
 
1324         with cache_dir() as workspace:
 
1325             src = (workspace / "test.py").resolve()
 
1327             black.write_cache({}, [src], mode)
 
1328             cache = black.read_cache(mode)
 
1329             self.assertIn(src, cache)
 
1330             self.assertEqual(cache[src], black.get_cache_info(src))
 
1332     def test_filter_cached(self) -> None:
 
1333         with TemporaryDirectory() as workspace:
 
1334             path = Path(workspace)
 
1335             uncached = (path / "uncached").resolve()
 
1336             cached = (path / "cached").resolve()
 
1337             cached_but_changed = (path / "changed").resolve()
 
1340             cached_but_changed.touch()
 
1341             cache = {cached: black.get_cache_info(cached), cached_but_changed: (0.0, 0)}
 
1342             todo, done = black.filter_cached(
 
1343                 cache, {uncached, cached, cached_but_changed}
 
1345             self.assertEqual(todo, {uncached, cached_but_changed})
 
1346             self.assertEqual(done, {cached})
 
1348     def test_write_cache_creates_directory_if_needed(self) -> None:
 
1349         mode = black.FileMode()
 
1350         with cache_dir(exists=False) as workspace:
 
1351             self.assertFalse(workspace.exists())
 
1352             black.write_cache({}, [], mode)
 
1353             self.assertTrue(workspace.exists())
 
1355     @event_loop(close=False)
 
1356     def test_failed_formatting_does_not_get_cached(self) -> None:
 
1357         mode = black.FileMode()
 
1358         with cache_dir() as workspace, patch(
 
1359             "black.ProcessPoolExecutor", new=ThreadPoolExecutor
 
1361             failing = (workspace / "failing.py").resolve()
 
1362             with failing.open("w") as fobj:
 
1363                 fobj.write("not actually python")
 
1364             clean = (workspace / "clean.py").resolve()
 
1365             with clean.open("w") as fobj:
 
1366                 fobj.write('print("hello")\n')
 
1367             self.invokeBlack([str(workspace)], exit_code=123)
 
1368             cache = black.read_cache(mode)
 
1369             self.assertNotIn(failing, cache)
 
1370             self.assertIn(clean, cache)
 
1372     def test_write_cache_write_fail(self) -> None:
 
1373         mode = black.FileMode()
 
1374         with cache_dir(), patch.object(Path, "open") as mock:
 
1375             mock.side_effect = OSError
 
1376             black.write_cache({}, [], mode)
 
1378     @event_loop(close=False)
 
1379     def test_check_diff_use_together(self) -> None:
 
1381             # Files which will be reformatted.
 
1382             src1 = (THIS_DIR / "data" / "string_quotes.py").resolve()
 
1383             self.invokeBlack([str(src1), "--diff", "--check"], exit_code=1)
 
1384             # Files which will not be reformatted.
 
1385             src2 = (THIS_DIR / "data" / "composition.py").resolve()
 
1386             self.invokeBlack([str(src2), "--diff", "--check"])
 
1387             # Multi file command.
 
1388             self.invokeBlack([str(src1), str(src2), "--diff", "--check"], exit_code=1)
 
1390     def test_no_files(self) -> None:
 
1392             # Without an argument, black exits with error code 0.
 
1393             self.invokeBlack([])
 
1395     def test_broken_symlink(self) -> None:
 
1396         with cache_dir() as workspace:
 
1397             symlink = workspace / "broken_link.py"
 
1399                 symlink.symlink_to("nonexistent.py")
 
1400             except OSError as e:
 
1401                 self.skipTest(f"Can't create symlinks: {e}")
 
1402             self.invokeBlack([str(workspace.resolve())])
 
1404     def test_read_cache_line_lengths(self) -> None:
 
1405         mode = black.FileMode()
 
1406         short_mode = black.FileMode(line_length=1)
 
1407         with cache_dir() as workspace:
 
1408             path = (workspace / "file.py").resolve()
 
1410             black.write_cache({}, [path], mode)
 
1411             one = black.read_cache(mode)
 
1412             self.assertIn(path, one)
 
1413             two = black.read_cache(short_mode)
 
1414             self.assertNotIn(path, two)
 
1416     def test_tricky_unicode_symbols(self) -> None:
 
1417         source, expected = read_data("tricky_unicode_symbols")
 
1419         self.assertFormatEqual(expected, actual)
 
1420         black.assert_equivalent(source, actual)
 
1421         black.assert_stable(source, actual, black.FileMode())
 
1423     def test_single_file_force_pyi(self) -> None:
 
1424         reg_mode = black.FileMode()
 
1425         pyi_mode = black.FileMode(is_pyi=True)
 
1426         contents, expected = read_data("force_pyi")
 
1427         with cache_dir() as workspace:
 
1428             path = (workspace / "file.py").resolve()
 
1429             with open(path, "w") as fh:
 
1431             self.invokeBlack([str(path), "--pyi"])
 
1432             with open(path, "r") as fh:
 
1434             # verify cache with --pyi is separate
 
1435             pyi_cache = black.read_cache(pyi_mode)
 
1436             self.assertIn(path, pyi_cache)
 
1437             normal_cache = black.read_cache(reg_mode)
 
1438             self.assertNotIn(path, normal_cache)
 
1439         self.assertEqual(actual, expected)
 
1441     @event_loop(close=False)
 
1442     def test_multi_file_force_pyi(self) -> None:
 
1443         reg_mode = black.FileMode()
 
1444         pyi_mode = black.FileMode(is_pyi=True)
 
1445         contents, expected = read_data("force_pyi")
 
1446         with cache_dir() as workspace:
 
1448                 (workspace / "file1.py").resolve(),
 
1449                 (workspace / "file2.py").resolve(),
 
1452                 with open(path, "w") as fh:
 
1454             self.invokeBlack([str(p) for p in paths] + ["--pyi"])
 
1456                 with open(path, "r") as fh:
 
1458                 self.assertEqual(actual, expected)
 
1459             # verify cache with --pyi is separate
 
1460             pyi_cache = black.read_cache(pyi_mode)
 
1461             normal_cache = black.read_cache(reg_mode)
 
1463                 self.assertIn(path, pyi_cache)
 
1464                 self.assertNotIn(path, normal_cache)
 
1466     def test_pipe_force_pyi(self) -> None:
 
1467         source, expected = read_data("force_pyi")
 
1468         result = CliRunner().invoke(
 
1469             black.main, ["-", "-q", "--pyi"], input=BytesIO(source.encode("utf8"))
 
1471         self.assertEqual(result.exit_code, 0)
 
1472         actual = result.output
 
1473         self.assertFormatEqual(actual, expected)
 
1475     def test_single_file_force_py36(self) -> None:
 
1476         reg_mode = black.FileMode()
 
1477         py36_mode = black.FileMode(target_versions=black.PY36_VERSIONS)
 
1478         source, expected = read_data("force_py36")
 
1479         with cache_dir() as workspace:
 
1480             path = (workspace / "file.py").resolve()
 
1481             with open(path, "w") as fh:
 
1483             self.invokeBlack([str(path), *PY36_ARGS])
 
1484             with open(path, "r") as fh:
 
1486             # verify cache with --target-version is separate
 
1487             py36_cache = black.read_cache(py36_mode)
 
1488             self.assertIn(path, py36_cache)
 
1489             normal_cache = black.read_cache(reg_mode)
 
1490             self.assertNotIn(path, normal_cache)
 
1491         self.assertEqual(actual, expected)
 
1493     @event_loop(close=False)
 
1494     def test_multi_file_force_py36(self) -> None:
 
1495         reg_mode = black.FileMode()
 
1496         py36_mode = black.FileMode(target_versions=black.PY36_VERSIONS)
 
1497         source, expected = read_data("force_py36")
 
1498         with cache_dir() as workspace:
 
1500                 (workspace / "file1.py").resolve(),
 
1501                 (workspace / "file2.py").resolve(),
 
1504                 with open(path, "w") as fh:
 
1506             self.invokeBlack([str(p) for p in paths] + PY36_ARGS)
 
1508                 with open(path, "r") as fh:
 
1510                 self.assertEqual(actual, expected)
 
1511             # verify cache with --target-version is separate
 
1512             pyi_cache = black.read_cache(py36_mode)
 
1513             normal_cache = black.read_cache(reg_mode)
 
1515                 self.assertIn(path, pyi_cache)
 
1516                 self.assertNotIn(path, normal_cache)
 
1518     def test_collections(self) -> None:
 
1519         source, expected = read_data("collections")
 
1521         self.assertFormatEqual(expected, actual)
 
1522         black.assert_equivalent(source, actual)
 
1523         black.assert_stable(source, actual, black.FileMode())
 
1525     def test_pipe_force_py36(self) -> None:
 
1526         source, expected = read_data("force_py36")
 
1527         result = CliRunner().invoke(
 
1529             ["-", "-q", "--target-version=py36"],
 
1530             input=BytesIO(source.encode("utf8")),
 
1532         self.assertEqual(result.exit_code, 0)
 
1533         actual = result.output
 
1534         self.assertFormatEqual(actual, expected)
 
1536     def test_include_exclude(self) -> None:
 
1537         path = THIS_DIR / "data" / "include_exclude_tests"
 
1538         include = re.compile(r"\.pyi?$")
 
1539         exclude = re.compile(r"/exclude/|/\.definitely_exclude/")
 
1540         report = black.Report()
 
1541         gitignore = PathSpec.from_lines("gitwildmatch", [])
 
1542         sources: List[Path] = []
 
1544             Path(path / "b/dont_exclude/a.py"),
 
1545             Path(path / "b/dont_exclude/a.pyi"),
 
1547         this_abs = THIS_DIR.resolve()
 
1549             black.gen_python_files_in_dir(
 
1550                 path, this_abs, include, exclude, report, gitignore
 
1553         self.assertEqual(sorted(expected), sorted(sources))
 
1555     def test_gitignore_exclude(self) -> None:
 
1556         path = THIS_DIR / "data" / "include_exclude_tests"
 
1557         include = re.compile(r"\.pyi?$")
 
1558         exclude = re.compile(r"")
 
1559         report = black.Report()
 
1560         gitignore = PathSpec.from_lines(
 
1561             "gitwildmatch", ["exclude/", ".definitely_exclude"]
 
1563         sources: List[Path] = []
 
1565             Path(path / "b/dont_exclude/a.py"),
 
1566             Path(path / "b/dont_exclude/a.pyi"),
 
1568         this_abs = THIS_DIR.resolve()
 
1570             black.gen_python_files_in_dir(
 
1571                 path, this_abs, include, exclude, report, gitignore
 
1574         self.assertEqual(sorted(expected), sorted(sources))
 
1576     def test_empty_include(self) -> None:
 
1577         path = THIS_DIR / "data" / "include_exclude_tests"
 
1578         report = black.Report()
 
1579         gitignore = PathSpec.from_lines("gitwildmatch", [])
 
1580         empty = re.compile(r"")
 
1581         sources: List[Path] = []
 
1583             Path(path / "b/exclude/a.pie"),
 
1584             Path(path / "b/exclude/a.py"),
 
1585             Path(path / "b/exclude/a.pyi"),
 
1586             Path(path / "b/dont_exclude/a.pie"),
 
1587             Path(path / "b/dont_exclude/a.py"),
 
1588             Path(path / "b/dont_exclude/a.pyi"),
 
1589             Path(path / "b/.definitely_exclude/a.pie"),
 
1590             Path(path / "b/.definitely_exclude/a.py"),
 
1591             Path(path / "b/.definitely_exclude/a.pyi"),
 
1593         this_abs = THIS_DIR.resolve()
 
1595             black.gen_python_files_in_dir(
 
1599                 re.compile(black.DEFAULT_EXCLUDES),
 
1604         self.assertEqual(sorted(expected), sorted(sources))
 
1606     def test_empty_exclude(self) -> None:
 
1607         path = THIS_DIR / "data" / "include_exclude_tests"
 
1608         report = black.Report()
 
1609         gitignore = PathSpec.from_lines("gitwildmatch", [])
 
1610         empty = re.compile(r"")
 
1611         sources: List[Path] = []
 
1613             Path(path / "b/dont_exclude/a.py"),
 
1614             Path(path / "b/dont_exclude/a.pyi"),
 
1615             Path(path / "b/exclude/a.py"),
 
1616             Path(path / "b/exclude/a.pyi"),
 
1617             Path(path / "b/.definitely_exclude/a.py"),
 
1618             Path(path / "b/.definitely_exclude/a.pyi"),
 
1620         this_abs = THIS_DIR.resolve()
 
1622             black.gen_python_files_in_dir(
 
1625                 re.compile(black.DEFAULT_INCLUDES),
 
1631         self.assertEqual(sorted(expected), sorted(sources))
 
1633     def test_invalid_include_exclude(self) -> None:
 
1634         for option in ["--include", "--exclude"]:
 
1635             self.invokeBlack(["-", option, "**()(!!*)"], exit_code=2)
 
1637     def test_preserves_line_endings(self) -> None:
 
1638         with TemporaryDirectory() as workspace:
 
1639             test_file = Path(workspace) / "test.py"
 
1640             for nl in ["\n", "\r\n"]:
 
1641                 contents = nl.join(["def f(  ):", "    pass"])
 
1642                 test_file.write_bytes(contents.encode())
 
1643                 ff(test_file, write_back=black.WriteBack.YES)
 
1644                 updated_contents: bytes = test_file.read_bytes()
 
1645                 self.assertIn(nl.encode(), updated_contents)
 
1647                     self.assertNotIn(b"\r\n", updated_contents)
 
1649     def test_preserves_line_endings_via_stdin(self) -> None:
 
1650         for nl in ["\n", "\r\n"]:
 
1651             contents = nl.join(["def f(  ):", "    pass"])
 
1652             runner = BlackRunner()
 
1653             result = runner.invoke(
 
1654                 black.main, ["-", "--fast"], input=BytesIO(contents.encode("utf8"))
 
1656             self.assertEqual(result.exit_code, 0)
 
1657             output = runner.stdout_bytes
 
1658             self.assertIn(nl.encode("utf8"), output)
 
1660                 self.assertNotIn(b"\r\n", output)
 
1662     def test_assert_equivalent_different_asts(self) -> None:
 
1663         with self.assertRaises(AssertionError):
 
1664             black.assert_equivalent("{}", "None")
 
1666     def test_symlink_out_of_root_directory(self) -> None:
 
1670         include = re.compile(black.DEFAULT_INCLUDES)
 
1671         exclude = re.compile(black.DEFAULT_EXCLUDES)
 
1672         report = black.Report()
 
1673         gitignore = PathSpec.from_lines("gitwildmatch", [])
 
1674         # `child` should behave like a symlink which resolved path is clearly
 
1675         # outside of the `root` directory.
 
1676         path.iterdir.return_value = [child]
 
1677         child.resolve.return_value = Path("/a/b/c")
 
1678         child.as_posix.return_value = "/a/b/c"
 
1679         child.is_symlink.return_value = True
 
1682                 black.gen_python_files_in_dir(
 
1683                     path, root, include, exclude, report, gitignore
 
1686         except ValueError as ve:
 
1687             self.fail(f"`get_python_files_in_dir()` failed: {ve}")
 
1688         path.iterdir.assert_called_once()
 
1689         child.resolve.assert_called_once()
 
1690         child.is_symlink.assert_called_once()
 
1691         # `child` should behave like a strange file which resolved path is clearly
 
1692         # outside of the `root` directory.
 
1693         child.is_symlink.return_value = False
 
1694         with self.assertRaises(ValueError):
 
1696                 black.gen_python_files_in_dir(
 
1697                     path, root, include, exclude, report, gitignore
 
1700         path.iterdir.assert_called()
 
1701         self.assertEqual(path.iterdir.call_count, 2)
 
1702         child.resolve.assert_called()
 
1703         self.assertEqual(child.resolve.call_count, 2)
 
1704         child.is_symlink.assert_called()
 
1705         self.assertEqual(child.is_symlink.call_count, 2)
 
1707     def test_shhh_click(self) -> None:
 
1709             from click import _unicodefun  # type: ignore
 
1710         except ModuleNotFoundError:
 
1711             self.skipTest("Incompatible Click version")
 
1712         if not hasattr(_unicodefun, "_verify_python3_env"):
 
1713             self.skipTest("Incompatible Click version")
 
1714         # First, let's see if Click is crashing with a preferred ASCII charset.
 
1715         with patch("locale.getpreferredencoding") as gpe:
 
1716             gpe.return_value = "ASCII"
 
1717             with self.assertRaises(RuntimeError):
 
1718                 _unicodefun._verify_python3_env()
 
1719         # Now, let's silence Click...
 
1721         # ...and confirm it's silent.
 
1722         with patch("locale.getpreferredencoding") as gpe:
 
1723             gpe.return_value = "ASCII"
 
1725                 _unicodefun._verify_python3_env()
 
1726             except RuntimeError as re:
 
1727                 self.fail(f"`patch_click()` failed, exception still raised: {re}")
 
1729     def test_root_logger_not_used_directly(self) -> None:
 
1730         def fail(*args: Any, **kwargs: Any) -> None:
 
1731             self.fail("Record created with root logger")
 
1733         with patch.multiple(
 
1744     @unittest.skipUnless(has_blackd_deps, "blackd's dependencies are not installed")
 
1745     def test_blackd_main(self) -> None:
 
1746         with patch("blackd.web.run_app"):
 
1747             result = CliRunner().invoke(blackd.main, [])
 
1748             if result.exception is not None:
 
1749                 raise result.exception
 
1750             self.assertEqual(result.exit_code, 0)
 
1752     def test_invalid_config_return_code(self) -> None:
 
1753         tmp_file = Path(black.dump_to_file())
 
1755             tmp_config = Path(black.dump_to_file())
 
1757             args = ["--config", str(tmp_config), str(tmp_file)]
 
1758             self.invokeBlack(args, exit_code=2, ignore_config=False)
 
1763 class BlackDTestCase(AioHTTPTestCase):
 
1764     async def get_application(self) -> web.Application:
 
1765         return blackd.make_app()
 
1767     # TODO: remove these decorators once the below is released
 
1768     # https://github.com/aio-libs/aiohttp/pull/3727
 
1769     @skip_if_exception("ClientOSError")
 
1770     @unittest.skipUnless(has_blackd_deps, "blackd's dependencies are not installed")
 
1772     async def test_blackd_request_needs_formatting(self) -> None:
 
1773         response = await self.client.post("/", data=b"print('hello world')")
 
1774         self.assertEqual(response.status, 200)
 
1775         self.assertEqual(response.charset, "utf8")
 
1776         self.assertEqual(await response.read(), b'print("hello world")\n')
 
1778     @skip_if_exception("ClientOSError")
 
1779     @unittest.skipUnless(has_blackd_deps, "blackd's dependencies are not installed")
 
1781     async def test_blackd_request_no_change(self) -> None:
 
1782         response = await self.client.post("/", data=b'print("hello world")\n')
 
1783         self.assertEqual(response.status, 204)
 
1784         self.assertEqual(await response.read(), b"")
 
1786     @skip_if_exception("ClientOSError")
 
1787     @unittest.skipUnless(has_blackd_deps, "blackd's dependencies are not installed")
 
1789     async def test_blackd_request_syntax_error(self) -> None:
 
1790         response = await self.client.post("/", data=b"what even ( is")
 
1791         self.assertEqual(response.status, 400)
 
1792         content = await response.text()
 
1794             content.startswith("Cannot parse"),
 
1795             msg=f"Expected error to start with 'Cannot parse', got {repr(content)}",
 
1798     @skip_if_exception("ClientOSError")
 
1799     @unittest.skipUnless(has_blackd_deps, "blackd's dependencies are not installed")
 
1801     async def test_blackd_unsupported_version(self) -> None:
 
1802         response = await self.client.post(
 
1803             "/", data=b"what", headers={blackd.PROTOCOL_VERSION_HEADER: "2"}
 
1805         self.assertEqual(response.status, 501)
 
1807     @skip_if_exception("ClientOSError")
 
1808     @unittest.skipUnless(has_blackd_deps, "blackd's dependencies are not installed")
 
1810     async def test_blackd_supported_version(self) -> None:
 
1811         response = await self.client.post(
 
1812             "/", data=b"what", headers={blackd.PROTOCOL_VERSION_HEADER: "1"}
 
1814         self.assertEqual(response.status, 200)
 
1816     @skip_if_exception("ClientOSError")
 
1817     @unittest.skipUnless(has_blackd_deps, "blackd's dependencies are not installed")
 
1819     async def test_blackd_invalid_python_variant(self) -> None:
 
1820         async def check(header_value: str, expected_status: int = 400) -> None:
 
1821             response = await self.client.post(
 
1822                 "/", data=b"what", headers={blackd.PYTHON_VARIANT_HEADER: header_value}
 
1824             self.assertEqual(response.status, expected_status)
 
1827         await check("ruby3.5")
 
1828         await check("pyi3.6")
 
1829         await check("py1.5")
 
1831         await check("py2.8")
 
1833         await check("pypy3.0")
 
1834         await check("jython3.4")
 
1836     @skip_if_exception("ClientOSError")
 
1837     @unittest.skipUnless(has_blackd_deps, "blackd's dependencies are not installed")
 
1839     async def test_blackd_pyi(self) -> None:
 
1840         source, expected = read_data("stub.pyi")
 
1841         response = await self.client.post(
 
1842             "/", data=source, headers={blackd.PYTHON_VARIANT_HEADER: "pyi"}
 
1844         self.assertEqual(response.status, 200)
 
1845         self.assertEqual(await response.text(), expected)
 
1847     @skip_if_exception("ClientOSError")
 
1848     @unittest.skipUnless(has_blackd_deps, "blackd's dependencies are not installed")
 
1850     async def test_blackd_diff(self) -> None:
 
1851         diff_header = re.compile(
 
1852             rf"(In|Out)\t\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d\.\d\d\d\d\d\d \+\d\d\d\d"
 
1855         source, _ = read_data("blackd_diff.py")
 
1856         expected, _ = read_data("blackd_diff.diff")
 
1858         response = await self.client.post(
 
1859             "/", data=source, headers={blackd.DIFF_HEADER: "true"}
 
1861         self.assertEqual(response.status, 200)
 
1863         actual = await response.text()
 
1864         actual = diff_header.sub(DETERMINISTIC_HEADER, actual)
 
1865         self.assertEqual(actual, expected)
 
1867     @skip_if_exception("ClientOSError")
 
1868     @unittest.skipUnless(has_blackd_deps, "blackd's dependencies are not installed")
 
1870     async def test_blackd_python_variant(self) -> None:
 
1873             "    and_has_a_bunch_of,\n"
 
1874             "    very_long_arguments_too,\n"
 
1875             "    and_lots_of_them_as_well_lol,\n"
 
1876             "    **and_very_long_keyword_arguments\n"
 
1881         async def check(header_value: str, expected_status: int) -> None:
 
1882             response = await self.client.post(
 
1883                 "/", data=code, headers={blackd.PYTHON_VARIANT_HEADER: header_value}
 
1886                 response.status, expected_status, msg=await response.text()
 
1889         await check("3.6", 200)
 
1890         await check("py3.6", 200)
 
1891         await check("3.6,3.7", 200)
 
1892         await check("3.6,py3.7", 200)
 
1893         await check("py36,py37", 200)
 
1894         await check("36", 200)
 
1895         await check("3.6.4", 200)
 
1897         await check("2", 204)
 
1898         await check("2.7", 204)
 
1899         await check("py2.7", 204)
 
1900         await check("3.4", 204)
 
1901         await check("py3.4", 204)
 
1902         await check("py34,py36", 204)
 
1903         await check("34", 204)
 
1905     @skip_if_exception("ClientOSError")
 
1906     @unittest.skipUnless(has_blackd_deps, "blackd's dependencies are not installed")
 
1908     async def test_blackd_line_length(self) -> None:
 
1909         response = await self.client.post(
 
1910             "/", data=b'print("hello")\n', headers={blackd.LINE_LENGTH_HEADER: "7"}
 
1912         self.assertEqual(response.status, 200)
 
1914     @skip_if_exception("ClientOSError")
 
1915     @unittest.skipUnless(has_blackd_deps, "blackd's dependencies are not installed")
 
1917     async def test_blackd_invalid_line_length(self) -> None:
 
1918         response = await self.client.post(
 
1919             "/", data=b'print("hello")\n', headers={blackd.LINE_LENGTH_HEADER: "NaN"}
 
1921         self.assertEqual(response.status, 400)
 
1923     @skip_if_exception("ClientOSError")
 
1924     @unittest.skipUnless(has_blackd_deps, "blackd's dependencies are not installed")
 
1926     async def test_blackd_response_black_version_header(self) -> None:
 
1927         response = await self.client.post("/")
 
1928         self.assertIsNotNone(response.headers.get(blackd.BLACK_VERSION_HEADER))
 
1931 if __name__ == "__main__":
 
1932     unittest.main(module="test_black")