You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			122 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Python
		
	
			
		
		
	
	
			122 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Python
		
	
"""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)
 |