From bd2c17e2064528804eb33b75a85fd527da3baa03 Mon Sep 17 00:00:00 2001 From: Madeesh Kannan Date: Fri, 10 Nov 2023 08:05:07 +0100 Subject: [PATCH] Warn about reloading dependencies after downloading models (#13081) * Update the "Missing factory" error message This accounts for model installations that took place during the current Python session. * Add a note about Jupyter notebooks * Move error to `spacy.cli.download` Add extra message for Jupyter sessions * Add additional note for interactive sessions * Remove note about `spacy-transformers` from error message * `isort` * Improve checks for colab (also helps displacy) * Update warning messages * Improve flow for multiple checks --------- Co-authored-by: Adriane Boyd --- spacy/cli/download.py | 30 +++++++++++++++++++++++++++++- spacy/errors.py | 1 - spacy/util.py | 30 ++++++++++++++++++++++++------ 3 files changed, 53 insertions(+), 8 deletions(-) diff --git a/spacy/cli/download.py b/spacy/cli/download.py index de731b0fd..21c777f81 100644 --- a/spacy/cli/download.py +++ b/spacy/cli/download.py @@ -7,7 +7,14 @@ from wasabi import msg from .. import about from ..errors import OLD_MODEL_SHORTCUTS -from ..util import get_minor_version, is_package, is_prerelease_version, run_command +from ..util import ( + get_minor_version, + is_in_interactive, + is_in_jupyter, + is_package, + is_prerelease_version, + run_command, +) from ._util import SDIST_SUFFIX, WHEEL_SUFFIX, Arg, Opt, app @@ -77,6 +84,27 @@ def download( "Download and installation successful", f"You can now load the package via spacy.load('{model_name}')", ) + if is_in_jupyter(): + reload_deps_msg = ( + "If you are in a Jupyter or Colab notebook, you may need to " + "restart Python in order to load all the package's dependencies. " + "You can do this by selecting the 'Restart kernel' or 'Restart " + "runtime' option." + ) + msg.warn( + "Restart to reload dependencies", + reload_deps_msg, + ) + elif is_in_interactive(): + reload_deps_msg = ( + "If you are in an interactive Python session, you may need to " + "exit and restart Python to load all the package's dependencies. " + "You can exit with Ctrl-D (or Ctrl-Z and Enter on Windows)." + ) + msg.warn( + "Restart to reload dependencies", + reload_deps_msg, + ) def get_model_filename(model_name: str, version: str, sdist: bool = False) -> str: diff --git a/spacy/errors.py b/spacy/errors.py index dac07f804..8b290da6d 100644 --- a/spacy/errors.py +++ b/spacy/errors.py @@ -227,7 +227,6 @@ class Errors(metaclass=ErrorsWithCodes): E002 = ("Can't find factory for '{name}' for language {lang} ({lang_code}). " "This usually happens when spaCy calls `nlp.{method}` with a custom " "component name that's not registered on the current language class. " - "If you're using a Transformer, make sure to install 'spacy-transformers'. " "If you're using a custom component, make sure you've added the " "decorator `@Language.component` (for function components) or " "`@Language.factory` (for class components).\n\nAvailable " diff --git a/spacy/util.py b/spacy/util.py index 8464e411f..c127be03c 100644 --- a/spacy/util.py +++ b/spacy/util.py @@ -1077,20 +1077,38 @@ def make_tempdir() -> Generator[Path, None, None]: def is_in_jupyter() -> bool: - """Check if user is running spaCy from a Jupyter notebook by detecting the - IPython kernel. Mainly used for the displaCy visualizer. - RETURNS (bool): True if in Jupyter, False if not. + """Check if user is running spaCy from a Jupyter or Colab notebook by + detecting the IPython kernel. Mainly used for the displaCy visualizer. + RETURNS (bool): True if in Jupyter/Colab, False if not. """ # https://stackoverflow.com/a/39662359/6400719 + # https://stackoverflow.com/questions/15411967 try: - shell = get_ipython().__class__.__name__ # type: ignore[name-defined] - if shell == "ZMQInteractiveShell": + if get_ipython().__class__.__name__ == "ZMQInteractiveShell": # type: ignore[name-defined] return True # Jupyter notebook or qtconsole + if get_ipython().__class__.__module__ == "google.colab._shell": # type: ignore[name-defined] + return True # Colab notebook except NameError: - return False # Probably standard Python interpreter + pass # Probably standard Python interpreter + # additional check for Colab + try: + import google.colab + + return True # Colab notebook + except ImportError: + pass return False +def is_in_interactive() -> bool: + """Check if user is running spaCy from an interactive Python + shell. Will return True in Jupyter notebooks too. + RETURNS (bool): True if in interactive mode, False if not. + """ + # https://stackoverflow.com/questions/2356399/tell-if-python-is-in-interactive-mode + return hasattr(sys, "ps1") or hasattr(sys, "ps2") + + def get_object_name(obj: Any) -> str: """Get a human-readable name of a Python object, e.g. a pipeline component.