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 <adrianeboyd@gmail.com>
This commit is contained in:
Madeesh Kannan 2023-11-10 08:05:07 +01:00 committed by GitHub
parent 513bbd5fa3
commit bd2c17e206
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 53 additions and 8 deletions

View File

@ -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:

View File

@ -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 "

View File

@ -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.