from contextlib import contextmanager
from dataclasses import replace
import inspect
-from io import BytesIO, TextIOWrapper
+from io import BytesIO
import os
from pathlib import Path
from platform import system
import types
from typing import (
Any,
- BinaryIO,
Callable,
Dict,
- Generator,
List,
Iterator,
TypeVar,
import black
from black import Feature, TargetVersion
+from black.cache import get_cache_file
+from black.debug import DebugVisitor
+from black.report import Report
+import black.files
from pathspec import PathSpec
ff,
dump_to_stderr,
)
-from .test_primer import PrimerCLITests # noqa: F401
THIS_FILE = Path(__file__)
cache_dir = Path(workspace)
if not exists:
cache_dir = cache_dir / "new"
- with patch("black.CACHE_DIR", cache_dir):
+ with patch("black.cache.CACHE_DIR", cache_dir):
yield cache_dir
class BlackRunner(CliRunner):
- """Modify CliRunner so that stderr is not merged with stdout.
-
- This is a hack that can be removed once we depend on Click 7.x"""
+ """Make sure STDOUT and STDERR are kept separate when testing Black via its CLI."""
def __init__(self) -> None:
- self.stderrbuf = BytesIO()
- self.stdoutbuf = BytesIO()
- self.stdout_bytes = b""
- self.stderr_bytes = b""
- super().__init__()
-
- @contextmanager
- def isolation(self, *args: Any, **kwargs: Any) -> Generator[BinaryIO, None, None]:
- with super().isolation(*args, **kwargs) as output:
- try:
- hold_stderr = sys.stderr
- sys.stderr = TextIOWrapper(self.stderrbuf, encoding=self.charset)
- yield output
- finally:
- self.stdout_bytes = sys.stdout.buffer.getvalue() # type: ignore
- self.stderr_bytes = sys.stderr.buffer.getvalue() # type: ignore
- sys.stderr = hold_stderr
+ super().__init__(mix_stderr=False)
class BlackTestCase(BlackBaseTestCase):
exit_code,
msg=(
f"Failed with args: {args}\n"
- f"stdout: {runner.stdout_bytes.decode()!r}\n"
- f"stderr: {runner.stderr_bytes.decode()!r}\n"
+ f"stdout: {result.stdout_bytes.decode()!r}\n"
+ f"stderr: {result.stderr_bytes.decode()!r}\n"
f"exception: {result.exception}"
),
)
)
self.assertEqual(result.exit_code, 0)
self.assertFormatEqual(expected, result.output)
- black.assert_equivalent(source, result.output)
- black.assert_stable(source, result.output, DEFAULT_MODE)
+ if source != result.output:
+ black.assert_equivalent(source, result.output)
+ black.assert_stable(source, result.output, DEFAULT_MODE)
def test_piping_diff(self) -> None:
diff_header = re.compile(
)
self.assertEqual(expected, actual, msg)
- @pytest.mark.without_python2
+ @pytest.mark.no_python2
def test_python2_should_fail_without_optional_install(self) -> None:
- # python 3.7 and below will install typed-ast and will be able to parse Python 2
if sys.version_info < (3, 8):
- return
+ self.skipTest(
+ "Python 3.6 and 3.7 will install typed-ast to work and as such will be"
+ " able to parse Python 2 syntax without explicitly specifying the"
+ " python2 extra"
+ )
+
source = "x = 1234l"
tmp_file = Path(black.dump_to_file(source))
try:
finally:
os.unlink(tmp_file)
actual = (
- runner.stderr_bytes.decode()
+ result.stderr_bytes.decode()
.replace("\n", "")
.replace("\\n", "")
.replace("\\r", "")
self.assertFormatEqual(contents_spc, fs(contents_tab))
def test_report_verbose(self) -> None:
- report = black.Report(verbose=True)
+ report = Report(verbose=True)
out_lines = []
err_lines = []
def err(msg: str, **kwargs: Any) -> None:
err_lines.append(msg)
- with patch("black.out", out), patch("black.err", err):
+ with patch("black.output._out", out), patch("black.output._err", err):
report.done(Path("f1"), black.Changed.NO)
self.assertEqual(len(out_lines), 1)
self.assertEqual(len(err_lines), 0)
)
def test_report_quiet(self) -> None:
- report = black.Report(quiet=True)
+ report = Report(quiet=True)
out_lines = []
err_lines = []
def err(msg: str, **kwargs: Any) -> None:
err_lines.append(msg)
- with patch("black.out", out), patch("black.err", err):
+ with patch("black.output._out", out), patch("black.output._err", err):
report.done(Path("f1"), black.Changed.NO)
self.assertEqual(len(out_lines), 0)
self.assertEqual(len(err_lines), 0)
def err(msg: str, **kwargs: Any) -> None:
err_lines.append(msg)
- with patch("black.out", out), patch("black.err", err):
+ with patch("black.output._out", out), patch("black.output._err", err):
report.done(Path("f1"), black.Changed.NO)
self.assertEqual(len(out_lines), 0)
self.assertEqual(len(err_lines), 0)
def err(msg: str, **kwargs: Any) -> None:
err_lines.append(msg)
- with patch("black.out", out), patch("black.err", err):
- black.DebugVisitor.show(source)
+ with patch("black.debug.out", out):
+ DebugVisitor.show(source)
actual = "\n".join(out_lines) + "\n"
log_name = ""
if expected != actual:
def err(msg: str, **kwargs: Any) -> None:
err_lines.append(msg)
- with patch("black.out", out), patch("black.err", err):
+ with patch("black.output._out", out), patch("black.output._err", err):
with self.assertRaises(AssertionError):
self.assertFormatEqual("j = [1, 2, 3]", "j = [1, 2, 3,]")
def test_cache_broken_file(self) -> None:
mode = DEFAULT_MODE
with cache_dir() as workspace:
- cache_file = black.get_cache_file(mode)
+ cache_file = get_cache_file(mode)
with cache_file.open("w") as fobj:
fobj.write("this is not a pickle")
self.assertEqual(black.read_cache(mode), {})
"black.write_cache"
) as write_cache:
self.invokeBlack([str(src), "--diff"])
- cache_file = black.get_cache_file(mode)
+ cache_file = get_cache_file(mode)
self.assertFalse(cache_file.exists())
write_cache.assert_not_called()
read_cache.assert_not_called()
"black.write_cache"
) as write_cache:
self.invokeBlack([str(src), "--diff", "--color"])
- cache_file = black.get_cache_file(mode)
+ cache_file = get_cache_file(mode)
self.assertFalse(cache_file.exists())
write_cache.assert_not_called()
read_cache.assert_not_called()
black.main, ["-"], input=BytesIO(b"print('hello')")
)
self.assertEqual(result.exit_code, 0)
- cache_file = black.get_cache_file(mode)
+ cache_file = get_cache_file(mode)
self.assertFalse(cache_file.exists())
def test_read_cache_no_cachefile(self) -> None:
)
self.assertEqual(sorted(expected), sorted(sources))
- def test_gitingore_used_as_default(self) -> None:
+ def test_gitignore_used_as_default(self) -> None:
path = Path(THIS_DIR / "data" / "include_exclude_tests")
include = re.compile(r"\.pyi?$")
extend_exclude = re.compile(r"/exclude/")
@patch("black.find_project_root", lambda *args: THIS_DIR.resolve())
def test_get_sources_with_stdin_filename_and_exclude(self) -> None:
- # Exclude shouldn't exclude stdin_filename since it is mimicing the
+ # Exclude shouldn't exclude stdin_filename since it is mimicking the
# file being passed directly. This is the same as
# test_exclude_for_issue_1572
path = THIS_DIR / "data" / "include_exclude_tests"
)
self.assertEqual(sorted(expected), sorted(sources))
+ def test_nested_gitignore(self) -> None:
+ path = Path(THIS_DIR / "data" / "nested_gitignore_tests")
+ include = re.compile(r"\.pyi?$")
+ exclude = re.compile(r"")
+ root_gitignore = black.files.get_gitignore(path)
+ report = black.Report()
+ expected: List[Path] = [
+ Path(path / "x.py"),
+ Path(path / "root/b.py"),
+ Path(path / "root/c.py"),
+ Path(path / "root/child/c.py"),
+ ]
+ this_abs = THIS_DIR.resolve()
+ sources = list(
+ black.gen_python_files(
+ path.iterdir(),
+ this_abs,
+ include,
+ exclude,
+ None,
+ None,
+ report,
+ root_gitignore,
+ )
+ )
+ self.assertEqual(sorted(expected), sorted(sources))
+
def test_empty_include(self) -> None:
path = THIS_DIR / "data" / "include_exclude_tests"
report = black.Report()
black.main, ["-", "--fast"], input=BytesIO(contents.encode("utf8"))
)
self.assertEqual(result.exit_code, 0)
- output = runner.stdout_bytes
+ output = result.stdout_bytes
self.assertIn(nl.encode("utf8"), output)
if nl == "\n":
self.assertNotIn(b"\r\n", output)
critical=fail,
log=fail,
):
- ff(THIS_FILE)
+ ff(THIS_DIR / "util.py")
def test_invalid_config_return_code(self) -> None:
tmp_file = Path(black.dump_to_file())
self.assertEqual(black.find_project_root((src_dir,)), src_dir.resolve())
self.assertEqual(black.find_project_root((src_python,)), src_dir.resolve())
- @patch("black.find_user_pyproject_toml", black.find_user_pyproject_toml.__wrapped__)
+ @patch(
+ "black.files.find_user_pyproject_toml",
+ black.files.find_user_pyproject_toml.__wrapped__,
+ )
def test_find_user_pyproject_toml_linux(self) -> None:
if system() == "Windows":
return
tmp_user_config = Path(workspace) / "black"
with patch.dict("os.environ", {"XDG_CONFIG_HOME": workspace}):
self.assertEqual(
- black.find_user_pyproject_toml(), tmp_user_config.resolve()
+ black.files.find_user_pyproject_toml(), tmp_user_config.resolve()
)
# Test fallback for XDG_CONFIG_HOME
os.environ.pop("XDG_CONFIG_HOME", None)
fallback_user_config = Path("~/.config").expanduser() / "black"
self.assertEqual(
- black.find_user_pyproject_toml(), fallback_user_config.resolve()
+ black.files.find_user_pyproject_toml(), fallback_user_config.resolve()
)
def test_find_user_pyproject_toml_windows(self) -> None:
return
user_config_path = Path.home() / ".black"
- self.assertEqual(black.find_user_pyproject_toml(), user_config_path.resolve())
+ self.assertEqual(
+ black.files.find_user_pyproject_toml(), user_config_path.resolve()
+ )
def test_bpo_33660_workaround(self) -> None:
if system() == "Windows":