madduck's git repository
Every one of the projects in this repository is available at the canonical
URL git://git.madduck.net/madduck/pub/<projectpath> — see
each project's metadata for the exact URL.
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.
SSH access, as well as push access can be individually
arranged.
If you use my repositories frequently, consider adding the following
snippet to ~/.gitconfig and using the third clone URL listed for each
project:
[url "git://git.madduck.net/madduck/"]
insteadOf = madduck:
-from dataclasses import replace
import pathlib
import re
from contextlib import ExitStack as does_not_raise
import pathlib
import re
from contextlib import ExitStack as does_not_raise
+from dataclasses import replace
from typing import ContextManager
from typing import ContextManager
+import pytest
+from _pytest.monkeypatch import MonkeyPatch
from click.testing import CliRunner
from click.testing import CliRunner
-from black.handle_ipynb_magics import jupyter_dependencies_are_installed
NothingChanged,
format_cell,
format_file_contents,
format_file_in_place,
NothingChanged,
format_cell,
format_file_contents,
format_file_in_place,
-import pytest
-from black import Mode
-from _pytest.monkeypatch import MonkeyPatch
-from tests.util import DATA_DIR
+from black.handle_ipynb_magics import jupyter_dependencies_are_installed
+from tests.util import DATA_DIR, get_case_path, read_jupyter_notebook
+with contextlib.suppress(ModuleNotFoundError):
+ import IPython
pytestmark = pytest.mark.jupyter
pytest.importorskip("IPython", reason="IPython is an optional dependency")
pytest.importorskip("tokenize_rt", reason="tokenize-rt is an optional dependency")
JUPYTER_MODE = Mode(is_ipynb=True)
pytestmark = pytest.mark.jupyter
pytest.importorskip("IPython", reason="IPython is an optional dependency")
pytest.importorskip("tokenize_rt", reason="tokenize-rt is an optional dependency")
JUPYTER_MODE = Mode(is_ipynb=True)
+EMPTY_CONFIG = DATA_DIR / "empty_pyproject.toml"
+
[
pytest.param(JUPYTER_MODE, id="default mode"),
pytest.param(
[
pytest.param(JUPYTER_MODE, id="default mode"),
pytest.param(
- replace(JUPYTER_MODE, python_cell_magics={"cust1", "cust1"}),
+ replace(JUPYTER_MODE, python_cell_magics={"cust1", "cust2"}),
id="custom cell magics mode",
),
],
id="custom cell magics mode",
),
],
[
pytest.param(JUPYTER_MODE, id="default mode"),
pytest.param(
[
pytest.param(JUPYTER_MODE, id="default mode"),
pytest.param(
- replace(JUPYTER_MODE, python_cell_magics={"cust1", "cust1"}),
+ replace(JUPYTER_MODE, python_cell_magics={"cust1", "cust2"}),
id="custom cell magics mode",
),
],
id="custom cell magics mode",
),
],
format_cell(src, fast=True, mode=JUPYTER_MODE)
format_cell(src, fast=True, mode=JUPYTER_MODE)
+@pytest.mark.skipif(
+ IPython.version_info < (8, 3),
+ reason="Change in how TransformerManager transforms this input",
+)
def test_set_input() -> None:
src = "a = b??"
def test_set_input() -> None:
src = "a = b??"
- with pytest.raises(NothingChanged):
- format_cell(src, fast=True, mode=JUPYTER_MODE)
+ expected = "??b"
+ result = format_cell(src, fast=True, mode=JUPYTER_MODE)
+ assert result == expected
def test_input_already_contains_transformed_magic() -> None:
def test_input_already_contains_transformed_magic() -> None:
id="No change when cell magic not registered",
),
pytest.param(
id="No change when cell magic not registered",
),
pytest.param(
- replace(JUPYTER_MODE, python_cell_magics={"cust1", "cust1"}),
+ replace(JUPYTER_MODE, python_cell_magics={"cust1", "cust2"}),
"%%custom_python_magic -n1 -n2\nx=2",
pytest.raises(NothingChanged),
id="No change when other cell magics registered",
"%%custom_python_magic -n1 -n2\nx=2",
pytest.raises(NothingChanged),
id="No change when other cell magics registered",
def test_entire_notebook_empty_metadata() -> None:
def test_entire_notebook_empty_metadata() -> None:
- with open(DATA_DIR / "notebook_empty_metadata.ipynb", "rb") as fd:
- content_bytes = fd.read()
- content = content_bytes.decode()
+ content = read_jupyter_notebook("jupyter", "notebook_empty_metadata")
result = format_file_contents(content, fast=True, mode=JUPYTER_MODE)
expected = (
"{\n"
result = format_file_contents(content, fast=True, mode=JUPYTER_MODE)
expected = (
"{\n"
def test_entire_notebook_trailing_newline() -> None:
def test_entire_notebook_trailing_newline() -> None:
- with open(DATA_DIR / "notebook_trailing_newline.ipynb", "rb") as fd:
- content_bytes = fd.read()
- content = content_bytes.decode()
+ content = read_jupyter_notebook("jupyter", "notebook_trailing_newline")
result = format_file_contents(content, fast=True, mode=JUPYTER_MODE)
expected = (
"{\n"
result = format_file_contents(content, fast=True, mode=JUPYTER_MODE)
expected = (
"{\n"
def test_entire_notebook_no_trailing_newline() -> None:
def test_entire_notebook_no_trailing_newline() -> None:
- with open(DATA_DIR / "notebook_no_trailing_newline.ipynb", "rb") as fd:
- content_bytes = fd.read()
- content = content_bytes.decode()
+ content = read_jupyter_notebook("jupyter", "notebook_no_trailing_newline")
result = format_file_contents(content, fast=True, mode=JUPYTER_MODE)
expected = (
"{\n"
result = format_file_contents(content, fast=True, mode=JUPYTER_MODE)
expected = (
"{\n"
def test_entire_notebook_without_changes() -> None:
def test_entire_notebook_without_changes() -> None:
- with open(DATA_DIR / "notebook_without_changes.ipynb", "rb") as fd:
- content_bytes = fd.read()
- content = content_bytes.decode()
+ content = read_jupyter_notebook("jupyter", "notebook_without_changes")
with pytest.raises(NothingChanged):
format_file_contents(content, fast=True, mode=JUPYTER_MODE)
def test_non_python_notebook() -> None:
with pytest.raises(NothingChanged):
format_file_contents(content, fast=True, mode=JUPYTER_MODE)
def test_non_python_notebook() -> None:
- with open(DATA_DIR / "non_python_notebook.ipynb", "rb") as fd:
- content_bytes = fd.read()
- content = content_bytes.decode()
+ content = read_jupyter_notebook("jupyter", "non_python_notebook")
+
with pytest.raises(NothingChanged):
format_file_contents(content, fast=True, mode=JUPYTER_MODE)
with pytest.raises(NothingChanged):
format_file_contents(content, fast=True, mode=JUPYTER_MODE)
def test_unparseable_notebook() -> None:
def test_unparseable_notebook() -> None:
- path = DATA_DIR / "notebook_which_cant_be_parsed.ipynb"
+ path = get_case_path("jupyter", "notebook_which_cant_be_parsed.ipynb")
msg = rf"File '{re.escape(str(path))}' cannot be parsed as valid Jupyter notebook\."
with pytest.raises(ValueError, match=msg):
format_file_in_place(path, fast=True, mode=JUPYTER_MODE)
msg = rf"File '{re.escape(str(path))}' cannot be parsed as valid Jupyter notebook\."
with pytest.raises(ValueError, match=msg):
format_file_in_place(path, fast=True, mode=JUPYTER_MODE)
result = runner.invoke(
main,
[
result = runner.invoke(
main,
[
- str(DATA_DIR / "notebook_trailing_newline.ipynb"),
+ str(get_case_path("jupyter", "notebook_trailing_newline.ipynb")),
+ f"--config={EMPTY_CONFIG}",
- expected = "@@ -1,3 +1,3 @@\n %%time\n \n-print('foo')\n" '+print("foo")\n'
+ expected = "@@ -1,3 +1,3 @@\n %%time\n \n-print('foo')\n+print(\"foo\")\n"
assert expected in result.output
assert expected in result.output
result = runner.invoke(
main,
[
result = runner.invoke(
main,
[
- str(DATA_DIR / "notebook_without_changes.ipynb"),
+ str(get_case_path("jupyter", "notebook_without_changes.ipynb")),
+ f"--config={EMPTY_CONFIG}",
],
)
expected = "1 file would be left unchanged."
],
)
expected = "1 file would be left unchanged."
) -> None:
# Check that the cache isn't written to if Jupyter dependencies aren't installed.
jupyter_dependencies_are_installed.cache_clear()
) -> None:
# Check that the cache isn't written to if Jupyter dependencies aren't installed.
jupyter_dependencies_are_installed.cache_clear()
- nb = DATA_DIR / "notebook_trailing_newline.ipynb"
+ nb = get_case_path("jupyter", "notebook_trailing_newline.ipynb")
tmp_nb = tmp_path / "notebook.ipynb"
tmp_nb = tmp_path / "notebook.ipynb"
- with open(nb) as src, open(tmp_nb, "w") as dst:
- dst.write(src.read())
- monkeypatch.setattr(
- "black.jupyter_dependencies_are_installed", lambda verbose, quiet: False
+ tmp_nb.write_bytes(nb.read_bytes())
+ monkeypatch.setattr("black.jupyter_dependencies_are_installed", lambda warn: False)
+ result = runner.invoke(
+ main, [str(tmp_path / "notebook.ipynb"), f"--config={EMPTY_CONFIG}"]
- result = runner.invoke(main, [str(tmp_path / "notebook.ipynb")])
assert "No Python files are present to be formatted. Nothing to do" in result.output
jupyter_dependencies_are_installed.cache_clear()
assert "No Python files are present to be formatted. Nothing to do" in result.output
jupyter_dependencies_are_installed.cache_clear()
- monkeypatch.setattr(
- "black.jupyter_dependencies_are_installed", lambda verbose, quiet: True
+ monkeypatch.setattr("black.jupyter_dependencies_are_installed", lambda warn: True)
+ result = runner.invoke(
+ main, [str(tmp_path / "notebook.ipynb"), f"--config={EMPTY_CONFIG}"]
- result = runner.invoke(main, [str(tmp_path / "notebook.ipynb")])
assert "reformatted" in result.output
assert "reformatted" in result.output
) -> None:
# Check that the cache isn't written to if Jupyter dependencies aren't installed.
jupyter_dependencies_are_installed.cache_clear()
) -> None:
# Check that the cache isn't written to if Jupyter dependencies aren't installed.
jupyter_dependencies_are_installed.cache_clear()
- nb = DATA_DIR / "notebook_trailing_newline.ipynb"
+ nb = get_case_path("jupyter", "notebook_trailing_newline.ipynb")
tmp_nb = tmp_path / "notebook.ipynb"
tmp_nb = tmp_path / "notebook.ipynb"
- with open(nb) as src, open(tmp_nb, "w") as dst:
- dst.write(src.read())
+ tmp_nb.write_bytes(nb.read_bytes())
- "black.files.jupyter_dependencies_are_installed", lambda verbose, quiet: False
+ "black.files.jupyter_dependencies_are_installed", lambda warn: False
- result = runner.invoke(main, [str(tmp_path)])
+ result = runner.invoke(main, [str(tmp_path), f"--config={EMPTY_CONFIG}"])
assert "No Python files are present to be formatted. Nothing to do" in result.output
jupyter_dependencies_are_installed.cache_clear()
monkeypatch.setattr(
assert "No Python files are present to be formatted. Nothing to do" in result.output
jupyter_dependencies_are_installed.cache_clear()
monkeypatch.setattr(
- "black.files.jupyter_dependencies_are_installed", lambda verbose, quiet: True
+ "black.files.jupyter_dependencies_are_installed", lambda warn: True
- result = runner.invoke(main, [str(tmp_path)])
+ result = runner.invoke(main, [str(tmp_path), f"--config={EMPTY_CONFIG}"])
assert "reformatted" in result.output
def test_ipynb_flag(tmp_path: pathlib.Path) -> None:
assert "reformatted" in result.output
def test_ipynb_flag(tmp_path: pathlib.Path) -> None:
- nb = DATA_DIR / "notebook_trailing_newline.ipynb"
+ nb = get_case_path("jupyter", "notebook_trailing_newline.ipynb")
tmp_nb = tmp_path / "notebook.a_file_extension_which_is_definitely_not_ipynb"
tmp_nb = tmp_path / "notebook.a_file_extension_which_is_definitely_not_ipynb"
- with open(nb) as src, open(tmp_nb, "w") as dst:
- dst.write(src.read())
+ tmp_nb.write_bytes(nb.read_bytes())
result = runner.invoke(
main,
[
str(tmp_nb),
"--diff",
"--ipynb",
result = runner.invoke(
main,
[
str(tmp_nb),
"--diff",
"--ipynb",
+ f"--config={EMPTY_CONFIG}",
- expected = "@@ -1,3 +1,3 @@\n %%time\n \n-print('foo')\n" '+print("foo")\n'
+ expected = "@@ -1,3 +1,3 @@\n %%time\n \n-print('foo')\n+print(\"foo\")\n"
assert expected in result.output
def test_ipynb_and_pyi_flags() -> None:
assert expected in result.output
def test_ipynb_and_pyi_flags() -> None:
- nb = DATA_DIR / "notebook_trailing_newline.ipynb"
+ nb = get_case_path("jupyter", "notebook_trailing_newline.ipynb")
result = runner.invoke(
main,
[
result = runner.invoke(
main,
[
"--pyi",
"--ipynb",
"--diff",
"--pyi",
"--ipynb",
"--diff",
+ f"--config={EMPTY_CONFIG}",
],
)
assert isinstance(result.exception, SystemExit)
],
)
assert isinstance(result.exception, SystemExit)