From 92e0f5b96500459b232a927fb26b0c990800b586 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Robert?= Date: Mon, 17 Jul 2023 03:09:26 +0200 Subject: [PATCH] Avoid importing `IPython` if notebook cells do not contain magics (#3782) Co-authored-by: hauntsaninja Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com> --- CHANGES.md | 2 ++ src/black/__init__.py | 2 +- src/black/files.py | 2 +- src/black/handle_ipynb_magics.py | 31 ++++++++++++------------------- tests/test_ipynb.py | 12 ++++-------- 5 files changed, 20 insertions(+), 29 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index c61ee698c5d..709c767b329 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -30,6 +30,8 @@ +- Avoid importing `IPython` if notebook cells do not contain magics (#3782) + ### Output diff --git a/src/black/__init__.py b/src/black/__init__.py index 301c18f7338..923a51867b5 100644 --- a/src/black/__init__.py +++ b/src/black/__init__.py @@ -668,7 +668,7 @@ def get_sources( p = Path(f"{STDIN_PLACEHOLDER}{str(p)}") if p.suffix == ".ipynb" and not jupyter_dependencies_are_installed( - verbose=verbose, quiet=quiet + warn=verbose or not quiet ): continue diff --git a/src/black/files.py b/src/black/files.py index ef6895ee3af..368e4170d47 100644 --- a/src/black/files.py +++ b/src/black/files.py @@ -384,7 +384,7 @@ def gen_python_files( elif child.is_file(): if child.suffix == ".ipynb" and not jupyter_dependencies_are_installed( - verbose=verbose, quiet=quiet + warn=verbose or not quiet ): continue include_match = include.search(normalized_path) if include else True diff --git a/src/black/handle_ipynb_magics.py b/src/black/handle_ipynb_magics.py index 2a2d62220e2..55ef2267df8 100644 --- a/src/black/handle_ipynb_magics.py +++ b/src/black/handle_ipynb_magics.py @@ -6,6 +6,7 @@ import secrets import sys from functools import lru_cache +from importlib.util import find_spec from typing import Dict, List, Optional, Tuple if sys.version_info >= (3, 10): @@ -56,25 +57,17 @@ class Replacement: @lru_cache -def jupyter_dependencies_are_installed(*, verbose: bool, quiet: bool) -> bool: - try: - # isort: off - # tokenize_rt is less commonly installed than IPython - # and IPython is expensive to import - import tokenize_rt # noqa:F401 - import IPython # noqa:F401 - - # isort: on - except ModuleNotFoundError: - if verbose or not quiet: - msg = ( - "Skipping .ipynb files as Jupyter dependencies are not installed.\n" - 'You can fix this by running ``pip install "black[jupyter]"``' - ) - out(msg) - return False - else: - return True +def jupyter_dependencies_are_installed(*, warn: bool) -> bool: + installed = ( + find_spec("tokenize_rt") is not None and find_spec("IPython") is not None + ) + if not installed and warn: + msg = ( + "Skipping .ipynb files as Jupyter dependencies are not installed.\n" + 'You can fix this by running ``pip install "black[jupyter]"``' + ) + out(msg) + return installed def remove_trailing_semicolon(src: str) -> Tuple[str, bool]: diff --git a/tests/test_ipynb.py b/tests/test_ipynb.py index a74f8ad5690..59897190304 100644 --- a/tests/test_ipynb.py +++ b/tests/test_ipynb.py @@ -440,17 +440,13 @@ def test_cache_isnt_written_if_no_jupyter_deps_single( nb = get_case_path("jupyter", "notebook_trailing_newline.ipynb") tmp_nb = tmp_path / "notebook.ipynb" tmp_nb.write_bytes(nb.read_bytes()) - monkeypatch.setattr( - "black.jupyter_dependencies_are_installed", lambda verbose, quiet: False - ) + monkeypatch.setattr("black.jupyter_dependencies_are_installed", lambda warn: False) result = runner.invoke( main, [str(tmp_path / "notebook.ipynb"), 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( - "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}"] ) @@ -466,13 +462,13 @@ def test_cache_isnt_written_if_no_jupyter_deps_dir( tmp_nb = tmp_path / "notebook.ipynb" tmp_nb.write_bytes(nb.read_bytes()) monkeypatch.setattr( - "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), 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( - "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), f"--config={EMPTY_CONFIG}"]) assert "reformatted" in result.output