| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- """Extension utilities."""
- import importlib
- import time
- import warnings
- class ExtensionLoadingError(Exception):
- """An extension loading error."""
- class ExtensionMetadataError(Exception):
- """An extension metadata error."""
- class ExtensionModuleNotFound(Exception):
- """An extension module not found error."""
- class NotAnExtensionApp(Exception):
- """An error raised when a module is not an extension."""
- def get_loader(obj, logger=None):
- """Looks for _load_jupyter_server_extension as an attribute
- of the object or module.
- Adds backwards compatibility for old function name missing the
- underscore prefix.
- """
- try:
- return obj._load_jupyter_server_extension
- except AttributeError:
- pass
- try:
- func = obj.load_jupyter_server_extension
- except AttributeError:
- msg = "_load_jupyter_server_extension function was not found."
- raise ExtensionLoadingError(msg) from None
- warnings.warn(
- "A `_load_jupyter_server_extension` function was not "
- f"found in {obj!s}. Instead, a `load_jupyter_server_extension` "
- "function was found and will be used for now. This function "
- "name will be deprecated in future releases "
- "of Jupyter Server.",
- DeprecationWarning,
- stacklevel=2,
- )
- return func
- def get_metadata(package_name, logger=None):
- """Find the extension metadata from an extension package.
- This looks for a `_jupyter_server_extension_points` function
- that returns metadata about all extension points within a Jupyter
- Server Extension package.
- If it doesn't exist, return a basic metadata packet given
- the module name.
- """
- start_time = time.perf_counter()
- module = importlib.import_module(package_name)
- end_time = time.perf_counter()
- duration = end_time - start_time
- # Sometimes packages can take a *while* to import, so we report how long
- # each module took to import. This makes it much easier for users to report
- # slow loading modules upstream, as slow loading modules will block server startup
- if logger:
- log = logger.info if duration > 0.1 else logger.debug
- log(f"Extension package {package_name} took {duration:.4f}s to import")
- try:
- return module, module._jupyter_server_extension_points()
- except AttributeError:
- pass
- # For backwards compatibility, we temporarily allow
- # _jupyter_server_extension_paths. We will remove in
- # a later release of Jupyter Server.
- try:
- extension_points = module._jupyter_server_extension_paths()
- if logger:
- logger.warning(
- "A `_jupyter_server_extension_points` function was not "
- f"found in {package_name}. Instead, a `_jupyter_server_extension_paths` "
- "function was found and will be used for now. This function "
- "name will be deprecated in future releases "
- "of Jupyter Server."
- )
- return module, extension_points
- except AttributeError:
- pass
- # Dynamically create metadata if the package doesn't
- # provide it.
- if logger:
- logger.debug(
- "A `_jupyter_server_extension_points` function was "
- f"not found in {package_name}, so Jupyter Server will look "
- "for extension points in the extension pacakge's "
- "root."
- )
- return module, [{"module": package_name, "name": package_name}]
- def validate_extension(name):
- """Raises an exception is the extension is missing a needed
- hook or metadata field.
- An extension is valid if:
- 1) name is an importable Python package.
- 1) the package has a _jupyter_server_extension_points function
- 2) each extension path has a _load_jupyter_server_extension function
- If this works, nothing should happen.
- """
- from .manager import ExtensionPackage
- return ExtensionPackage(name=name)
|