diff --git a/spacy/__init__.py b/spacy/__init__.py index 1a18ad0d58..39032b331a 100644 --- a/spacy/__init__.py +++ b/spacy/__init__.py @@ -5,24 +5,41 @@ # set library-specific custom warning handling before doing anything else from .errors import setup_default_warnings -setup_default_warnings() # noqa: E402 +setup_default_warnings() # These are imported as part of the API -from thinc.api import Config, prefer_gpu, require_cpu, require_gpu # noqa: F401 +from thinc.api import Config, prefer_gpu, require_cpu, require_gpu -from . import pipeline # noqa: F401 -from . import util -from .about import __version__ # noqa: F401 -from .cli.info import info # noqa: F401 +from . import pipeline, util +from .about import __version__ from .errors import Errors -from .glossary import explain # noqa: F401 +from .glossary import explain from .language import Language -from .util import logger, registry # noqa: F401 +from .util import logger, registry from .vocab import Vocab if sys.maxunicode == 65535: raise SystemError(Errors.E130) +__all__ = [ + "__version__", + "blank", + "Config", + "Errors", + "explain", + "info", + "Language", + "load", + "logger", + "pipeline", + "prefer_gpu", + "registry", + "require_cpu", + "require_gpu", + "util", + "Vocab", +] + def load( name: Union[str, Path], @@ -77,3 +94,15 @@ def blank( # We should accept both dot notation and nested dict here for consistency config = util.dot_to_dict(config) return LangClass.from_config(config, vocab=vocab, meta=meta) + + +def __getattr__(name): + if name == "cli": + import importlib + + return importlib.import_module("." + name, __name__) + if name == "info": + from .cli.info import info + + return info + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/spacy/tests/test_misc.py b/spacy/tests/test_misc.py index d2a41ff0fe..7520fd83d0 100644 --- a/spacy/tests/test_misc.py +++ b/spacy/tests/test_misc.py @@ -495,3 +495,27 @@ def test_find_available_port(): with pytest.warns(UserWarning, match="already in use"): found_port = find_available_port(port, host, auto_select=True) assert found_port == port + 1, "Didn't find next port" + + +def test_lazy_load_cli(): + import subprocess + import sys + from textwrap import dedent + + subprocess.run( + [ + sys.executable, + "-c", + dedent( + """\ + import sys + import spacy + assert "spacy" in sys.modules + assert "spacy.cli" not in sys.modules + spacy.cli + assert "spacy.cli" in sys.modules + """ + ), + ], + check=True, + )