def test_resolve_file_to_run_and_root_dir(prefix_path, root_dir, file_to_run, expected_output): # Verify that the Singleton instance is cleared before the test runs. ServerApp.clear_instance() # Setup the file_to_run path, in case the server checks # if the directory exists before initializing the server. file_to_run = prefix_path(file_to_run) if file_to_run.is_absolute(): file_to_run.parent.mkdir(parents=True, exist_ok=True) kwargs = {"file_to_run": str(file_to_run)} # Setup the root_dir path, in case the server checks # if the directory exists before initializing the server. if root_dir: root_dir = prefix_path(root_dir) if root_dir.is_absolute(): root_dir.parent.mkdir(parents=True, exist_ok=True) kwargs["root_dir"] = str(root_dir) # Create the notebook in the given location serverapp = ServerApp.instance(**kwargs) if expected_output is SystemExit: with pytest.raises(SystemExit): serverapp._resolve_file_to_run_and_root_dir() else: relpath = serverapp._resolve_file_to_run_and_root_dir() assert relpath == str(pathlib.Path(expected_output)) # Clear the singleton instance after each run. ServerApp.clear_instance()
def initialize_server(argv=[], **kwargs): """Get an instance of the Jupyter Server.""" # Get a jupyter server instance serverapp = ServerApp(**kwargs) # Initialize ServerApp config. # Parses the command line looking for # ServerApp configuration. serverapp.initialize(argv=argv) return serverapp
def test_load_ordered(ordered_server_extensions): app = ServerApp() app.jpserver_extensions = OrderedDict([('mockextension2', True), ('mockextension1', True)]) app.init_server_extensions() assert app.mockII is True, "Mock II should have been loaded" assert app.mockI is True, "Mock I should have been loaded" assert app.mock_shared == 'II', "Mock II should be loaded after Mock I"
def jupyter_server_app(jupyter_server_args, jupyter_server_config): jupyter_server_app = ServerApp.instance() # we monkey patch old_listen = httpserver.HTTPServer.listen httpserver.HTTPServer.listen = lambda *x, **y: None # NOTE: in voila's conftest.py we call config after initialize jupyter_server_config(jupyter_server_app) jupyter_server_app.initialize(jupyter_server_args) yield jupyter_server_app httpserver.HTTPServer.listen = old_listen ServerApp.clear_instance()
def _default_serverapp(self): # load the current global instance, if any if ServerApp.initialized(): try: return ServerApp.instance() except Exception: # error retrieving instance, e.g. MultipleInstanceError pass # serverapp accessed before it was defined, # declare an empty one return ServerApp()
def test_urls(config, public_url, local_url, connection_url): # Verify we're working with a clean instance. ServerApp.clear_instance() serverapp = ServerApp.instance(**config) # If a token is generated (not set by config), update # expected_url with token. if serverapp._token_generated: public_url = public_url.replace("<generated>", serverapp.token) local_url = local_url.replace("<generated>", serverapp.token) connection_url = connection_url.replace("<generated>", serverapp.token) assert serverapp.public_url == public_url assert serverapp.local_url == local_url assert serverapp.connection_url == connection_url # Cleanup singleton after test. ServerApp.clear_instance()
def test_password_required(identity_provider_class, password_set, password_required, ok): app = ServerApp() idp = identity_provider_class( parent=app, hashed_password="******" if password_set else "", password_required=password_required, ) app.identity_provider = idp if ok: ctx = nullcontext() else: ctx = pytest.raises(SystemExit) with ctx: idp.validate_security(app, ssl_options=None)
def _configurable_serverapp(config=jp_server_config, base_url=jp_base_url, argv=jp_argv, environ=jp_environ, http_port=jp_http_port, tmp_path=tmp_path, root_dir=jp_root_dir, **kwargs): c = Config(config) c.NotebookNotary.db_file = ":memory:" token = hexlify(os.urandom(4)).decode("ascii") app = ServerApp.instance( # Set the log level to debug for testing purposes log_level='DEBUG', port=http_port, port_retries=0, open_browser=False, root_dir=str(root_dir), base_url=base_url, config=c, allow_root=True, token=token, **kwargs) app.init_signal = lambda: None app.log.propagate = True app.log.handlers = [] # Initialize app without httpserver app.initialize(argv=argv, new_httpserver=False) app.log.propagate = True app.log.handlers = [] # Start app without ioloop app.start_app() return app
def initialize_server(cls, argv=None, load_other_extensions=True, **kwargs): """Creates an instance of ServerApp and explicitly sets this extension to enabled=True (i.e. superceding disabling found in other config from files). The `launch_instance` method uses this method to initialize and start a server. """ jpserver_extensions = {cls.get_extension_package(): True} find_extensions = cls.load_other_extensions if "jpserver_extensions" in cls.serverapp_config: jpserver_extensions.update( cls.serverapp_config["jpserver_extensions"]) cls.serverapp_config["jpserver_extensions"] = jpserver_extensions find_extensions = False serverapp = ServerApp.instance(jpserver_extensions=jpserver_extensions, **kwargs) serverapp.aliases.update(cls.aliases) serverapp.initialize( argv=argv or [], starter_extension=cls.name, find_extensions=find_extensions, ) return serverapp
def configurable_serverapp( environ, http_port, tmp_path, home_dir, data_dir, config_dir, runtime_dir, root_dir, io_loop ): def serverapp( config={}, argv=[], environ=environ, http_port=http_port, tmp_path=tmp_path, home_dir=home_dir, data_dir=data_dir, config_dir=config_dir, runtime_dir=runtime_dir, root_dir=root_dir, **kwargs ): c = Config(config) c.NotebookNotary.db_file = ":memory:" token = hexlify(os.urandom(4)).decode("ascii") url_prefix = "/" app = ServerApp.instance( port=http_port, port_retries=0, open_browser=False, config_dir=str(config_dir), data_dir=str(data_dir), runtime_dir=str(runtime_dir), root_dir=str(root_dir), base_url=url_prefix, config=c, allow_root=True, token=token, **kwargs ) app.init_signal = lambda: None app.log.propagate = True app.log.handlers = [] # Initialize app without httpserver app.initialize(argv=argv, new_httpserver=False) app.log.propagate = True app.log.handlers = [] # Start app without ioloop app.start_app() return app yield serverapp ServerApp.clear_instance()
def serverapp(environ, config, http_port, tmp_path, home_dir, data_dir, config_dir, runtime_dir, root_dir): config.NotebookNotary.db_file = ':memory:' token = hexlify(os.urandom(4)).decode('ascii') url_prefix = '/' app = ServerApp( port=http_port, port_retries=0, open_browser=False, config_dir=str(config_dir), data_dir=str(data_dir), runtime_dir=str(runtime_dir), root_dir=str(root_dir), base_url=url_prefix, config=config, allow_root=True, token=token, ) app.init_signal = lambda: None app.log.propagate = True app.log.handlers = [] # Initialize app without httpserver app.initialize(argv=[], new_httpserver=False) app.log.propagate = True app.log.handlers = [] # Start app without ioloop app.start_app() return app
def initialize_server(argv=[], load_other_extensions=True, **kwargs): """Get an instance of the Jupyter Server.""" # Get a jupyter server instance serverapp = ServerApp.instance(**kwargs) # Initialize ServerApp config. # Parses the command line looking for # ServerApp configuration. serverapp.initialize(argv=argv, load_extensions=load_other_extensions) return serverapp
def test_legacy_identity_config(jp_serverapp): # setting login_handler_class sets LegacyIdentityProvider app = ServerApp() idp = jp_serverapp.identity_provider assert type(idp) is LegacyIdentityProvider assert idp.login_available assert idp.auth_enabled assert idp.token assert idp.get_handlers() == [ ("/login", idp.login_handler_class), ("/logout", idp.logout_handler_class), ]
def test_merge_config(self): # enabled at sys level mock_sys = self._inject_mock_extension('mockext_sys') # enabled at sys, disabled at user mock_both = self._inject_mock_extension('mockext_both') # enabled at user mock_user = self._inject_mock_extension('mockext_user') # enabled at Python mock_py = self._inject_mock_extension('mockext_py') toggle_serverextension_python('mockext_sys', enabled=True, user=False) toggle_serverextension_python('mockext_user', enabled=True, user=True) toggle_serverextension_python('mockext_both', enabled=True, user=False) toggle_serverextension_python('mockext_both', enabled=False, user=True) app = ServerApp(jpserver_extensions={'mockext_py': True}) app.init_server_extensions() assert mock_user.loaded assert mock_sys.loaded assert mock_py.loaded assert not mock_both.loaded
def initialize_server(cls, argv=[], load_other_extensions=True, **kwargs): """Creates an instance of ServerApp where this extension is enabled (superceding disabling found in other config from files). This is necessary when launching the ExtensionApp directly from the `launch_instance` classmethod. """ # The ExtensionApp needs to add itself as enabled extension # to the jpserver_extensions trait, so that the ServerApp # initializes it. config = Config(cls._jupyter_server_config()) serverapp = ServerApp.instance(**kwargs, argv=[], config=config) serverapp.initialize(argv=argv, find_extensions=load_other_extensions) return serverapp
def _configurable_serverapp( config=jp_server_config, base_url=jp_base_url, argv=jp_argv, environ=jp_environ, http_port=jp_http_port, tmp_path=tmp_path, root_dir=jp_root_dir, **kwargs, ): c = Config(config) c.NotebookNotary.db_file = ":memory:" token = hexlify(os.urandom(4)).decode("ascii") c.IdentityProvider.token = token # Allow tests to configure root_dir via a file, argv, or its # default (cwd) by specifying a value of None. if root_dir is not None: kwargs["root_dir"] = str(root_dir) app = ServerApp.instance( # Set the log level to debug for testing purposes log_level="DEBUG", port=http_port, port_retries=0, open_browser=False, base_url=base_url, config=c, allow_root=True, **kwargs, ) app.init_signal = lambda: None app.log.propagate = True app.log.handlers = [] # Initialize app without httpserver app.initialize(argv=argv, new_httpserver=False) # Reroute all logging StreamHandlers away from stdin/stdout since pytest hijacks # these streams and closes them at unfortunate times. stream_handlers = [ h for h in app.log.handlers if isinstance(h, logging.StreamHandler) ] for handler in stream_handlers: handler.setStream(jp_logging_stream) app.log.propagate = True app.log.handlers = [] # Start app without ioloop app.start_app() return app
def test_validate_security( identity_provider_class, ip, token, ssl, warns, caplog, ): app = ServerApp(ip=ip, log=logging.getLogger()) idp = identity_provider_class(parent=app, token=token) app.identity_provider = idp with caplog.at_level(logging.WARNING): idp.validate_security(app, ssl_options=ssl) for record in caplog.records: print(record) if warns: assert len(caplog.records) > 0 if isinstance(warns, str): logged = "\n".join(record.msg for record in caplog.records) assert warns in logged else: assert len(caplog.records) == 0
def initialize_server(cls, argv=[], load_other_extensions=True, **kwargs): """Creates an instance of ServerApp and explicitly sets this extension to enabled=True (i.e. superceding disabling found in other config from files). The `launch_instance` method uses this method to initialize and start a server. """ serverapp = ServerApp.instance( jpserver_extensions={cls.get_extension_package(): True}, **kwargs) serverapp.initialize( argv=argv, starter_extension=cls.name, find_extensions=cls.load_other_extensions, ) return serverapp
def test_deprecated_config_priority(): cfg = Config() cfg.ServerApp.token = "ignored" cfg.IdentityProvider.token = token = "idp_token" cfg.ServerApp.password = passwd("ignored") cfg.PasswordIdentityProvider.hashed_password = password = passwd("used") app = ServerApp(config=cfg) app.initialize([]) app.init_configurables() assert app.identity_provider.token == token assert app.identity_provider.hashed_password == password
def test_deprecated_config(): cfg = Config() cfg.ServerApp.token = token = "asdf" cfg.ServerApp.password = password = passwd("secrets") app = ServerApp(config=cfg) app.initialize([]) app.init_configurables() assert app.identity_provider.token == token assert app.token == token assert app.identity_provider.hashed_password == password assert app.password == password
def initialize_server(cls, argv=[], load_other_extensions=True, **kwargs): """Creates an instance of ServerApp where this extension is enabled (superceding disabling found in other config from files). This is necessary when launching the ExtensionApp directly from the `launch_instance` classmethod. """ # The ExtensionApp needs to add itself as enabled extension # to the jpserver_extensions trait, so that the ServerApp # initializes it. config = Config({ "ServerApp": { "jpserver_extensions": { cls.extension_name: True }, "open_browser": True, "default_url": cls.extension_url } }) serverapp = ServerApp.instance(**kwargs, argv=[], config=config) serverapp.initialize(argv=argv, load_extensions=load_other_extensions) return serverapp
def jp_configurable_serverapp( jp_nbconvert_templates, # this fixture must preceed jp_environ jp_environ, jp_server_config, jp_argv, jp_http_port, jp_base_url, tmp_path, jp_root_dir, io_loop, jp_logging_stream, ): """Starts a Jupyter Server instance based on the provided configuration values. The fixture is a factory; it can be called like a function inside a unit test. Here's a basic example of how use this fixture: .. code-block:: python def my_test(jp_configurable_serverapp): app = jp_configurable_serverapp(...) ... """ ServerApp.clear_instance() # Inject jupyter_server_terminals into config unless it was # explicitly put in config. serverapp_config = jp_server_config.setdefault("ServerApp", {}) exts = serverapp_config.setdefault("jpserver_extensions", {}) if "jupyter_server_terminals" not in exts: exts["jupyter_server_terminals"] = True def _configurable_serverapp( config=jp_server_config, base_url=jp_base_url, argv=jp_argv, environ=jp_environ, http_port=jp_http_port, tmp_path=tmp_path, root_dir=jp_root_dir, **kwargs, ): c = Config(config) c.NotebookNotary.db_file = ":memory:" token = hexlify(os.urandom(4)).decode("ascii") # Allow tests to configure root_dir via a file, argv, or its # default (cwd) by specifying a value of None. if root_dir is not None: kwargs["root_dir"] = str(root_dir) app = ServerApp.instance( # Set the log level to debug for testing purposes log_level="DEBUG", port=http_port, port_retries=0, open_browser=False, base_url=base_url, config=c, allow_root=True, token=token, **kwargs, ) app.init_signal = lambda: None app.log.propagate = True app.log.handlers = [] # Initialize app without httpserver app.initialize(argv=argv, new_httpserver=False) # Reroute all logging StreamHandlers away from stdin/stdout since pytest hijacks # these streams and closes them at unfortunate times. stream_handlers = [h for h in app.log.handlers if isinstance(h, logging.StreamHandler)] for handler in stream_handlers: handler.setStream(jp_logging_stream) app.log.propagate = True app.log.handlers = [] # Start app without ioloop app.start_app() return app return _configurable_serverapp
def jp_configurable_serverapp( jp_nbconvert_templates, # this fixture must preceed jp_environ jp_environ, jp_server_config, jp_argv, jp_http_port, jp_base_url, tmp_path, jp_root_dir, io_loop, ): """Starts a Jupyter Server instance based on the provided configuration values. The fixture is a factory; it can be called like a function inside a unit test. Here's a basic example of how use this fixture: .. code-block:: python def my_test(jp_configurable_serverapp): app = jp_configurable_serverapp(...) ... """ ServerApp.clear_instance() def _configurable_serverapp(config=jp_server_config, base_url=jp_base_url, argv=jp_argv, environ=jp_environ, http_port=jp_http_port, tmp_path=tmp_path, root_dir=jp_root_dir, **kwargs): c = Config(config) c.NotebookNotary.db_file = ":memory:" token = hexlify(os.urandom(4)).decode("ascii") app = ServerApp.instance( # Set the log level to debug for testing purposes log_level='DEBUG', port=http_port, port_retries=0, open_browser=False, root_dir=str(root_dir), base_url=base_url, config=c, allow_root=True, token=token, **kwargs) app.init_signal = lambda: None app.log.propagate = True app.log.handlers = [] # Initialize app without httpserver app.initialize(argv=argv, new_httpserver=False) app.log.propagate = True app.log.handlers = [] # Start app without ioloop app.start_app() return app return _configurable_serverapp
def jp_asyncio_patch(): """Appropriately configures the event loop policy if running on Windows w/ Python >= 3.8.""" ServerApp()._init_asyncio_patch()
def shim_config_from_notebook_to_jupyter_server(self, config): """Reorganizes a config object to reroute traits to their expected destinations after the transition from NotebookApp to ServerApp. A detailed explanation of how traits are handled: 1. If the argument is prefixed with `ServerApp`, pass this trait to `ServerApp`. 2. If the argument is prefixed with `NotebookApp`, * If the argument is a trait of `NotebookApp` *and* `ServerApp`: 1. Raise a warning—**for the extension developers**—that there's redundant traits. 2. Pass trait to `NotebookApp`. * If the argument is a trait of just `ServerApp` only (i.e. the trait moved from `NotebookApp` to `ServerApp`): 1. Raise a "this trait has moved" **for the user**. 3. Pass trait to `ServerApp`. * If the argument is a trait of `NotebookApp` only, pass trait to `NotebookApp`. * If the argument is not found in any object, raise a `"Trait not found."` error. 3. If the argument is prefixed with `ExtensionApp`: * If the argument is a trait of `ExtensionApp`, `NotebookApp`, and `ServerApp`, 1. Raise a warning about redundancy. 2. Pass to the ExtensionApp * If the argument is a trait of `ExtensionApp` and `NotebookApp`, 1. Raise a warning about redundancy. 2. Pass to ExtensionApp. * If the argument is a trait of `ExtensionApp` and `ServerApp`, 1. Raise a warning about redundancy. 2. Pass to ExtensionApp. * If the argument is a trait of `ExtensionApp`. 1. Pass to ExtensionApp. * If the argument is a trait of `NotebookApp` but not `ExtensionApp`, 1. Raise a warning that trait has likely moved to NotebookApp. 2. Pass to NotebookApp * If the arguent is a trait of `ServerApp` but not `ExtensionApp`, 1. Raise a warning that the trait has likely moved to ServerApp. 2. Pass to ServerApp. * else * Raise a TraitError: "trait not found." """ extapp_name = self.__class__.__name__ # Pop out the various configurable objects that we need to evaluate. nbapp_config = config.pop('NotebookApp', {}) svapp_config = config.pop('ServerApp', {}) extapp_config = config.pop(extapp_name, {}) # Created shimmed configs. # Leave the rest of the config alone. config_shim = deepcopy(config) svapp_config_shim = {} nbapp_config_shim = {} extapp_config_shim = {} extapp_traits = ( self.__class__.class_trait_names() + ExtensionApp.class_trait_names() ) svapp_traits = ServerApp.class_trait_names() nbapp_traits = ( NotebookAppTraits.class_trait_names() + ExtensionApp.class_trait_names() ) # 1. Handle ServerApp traits. svapp_config_shim.update(svapp_config) # 2. Handle NotebookApp traits. warning_msg = None for trait_name, trait_value in nbapp_config.items(): in_svapp = trait_name in svapp_traits in_nbapp = trait_name in nbapp_traits if in_svapp and in_nbapp: warning_msg = NBAPP_AND_SVAPP_SHIM_MSG(trait_name) nbapp_config_shim.update({trait_name: trait_value}) elif in_svapp: warning_msg = NBAPP_TO_SVAPP_SHIM_MSG(trait_name) svapp_config_shim.update({trait_name: trait_value}) elif in_nbapp: nbapp_config_shim.update({trait_name: trait_value}) else: raise TraitError("Trait not found.") # Raise a warning if it's given. if warning_msg: self.log.warning(warning_msg) # 3. Handle ExtensionApp traits. warning_msg = None for trait_name, trait_value in extapp_config.items(): in_extapp = trait_name in extapp_traits in_svapp = trait_name in svapp_traits in_nbapp = trait_name in nbapp_traits if all([in_extapp, in_svapp, in_nbapp]): warning_msg = EXTAPP_AND_NBAPP_AND_SVAPP_SHIM_MSG( trait_name, extapp_name ) extapp_config_shim.update({trait_name: trait_value}) elif in_extapp and in_svapp: warning_msg = EXTAPP_AND_SVAPP_SHIM_MSG( trait_name, extapp_name ) extapp_config_shim.update({trait_name: trait_value}) elif in_extapp and in_nbapp: warning_msg = EXTAPP_AND_NBAPP_SHIM_MSG( trait_name, extapp_name ) extapp_config_shim.update({trait_name: trait_value}) elif in_extapp: extapp_config_shim.update({trait_name: trait_value}) elif in_svapp and in_nbapp: warning_msg = NOT_EXTAPP_NBAPP_AND_SVAPP_SHIM_MSG( trait_name, extapp_name ) svapp_config_shim.update({trait_name: trait_value}) elif in_svapp: warning_msg = EXTAPP_TO_SVAPP_SHIM_MSG( trait_name, extapp_name ) svapp_config_shim.update({trait_name: trait_value}) elif in_nbapp: warning_msg = EXTAPP_TO_NBAPP_SHIM_MSG( trait_name, extapp_name ) nbapp_config_shim.update({trait_name: trait_value}) else: raise TraitError("Trait not found.") # Raise warning if one is given if warning_msg: self.log.warning(warning_msg) # Build config for shimmed traits. new_config = Config({ 'NotebookApp': nbapp_config_shim, 'ServerApp': svapp_config_shim, }) if extapp_config_shim: new_config.update(Config({ self.__class__.__name__: extapp_config_shim })) # Update the full config with new values config_shim.update(new_config) return config_shim
Defaults for these options can also be set by creating a file named ``jupyter_server_config.py`` in your Jupyter folder. The Jupyter folder is in your home directory, ``~/.jupyter``. To create a ``jupyter_server_config.py`` file, with all the defaults commented out, you can use the following command line:: $ jupyter server --generate-config .. _options: Options ------- This list of options can be generated by running the following and hitting enter:: $ jupyter server --help-all """ try: destination = os.path.join(os.path.dirname(__file__), "source/other/full-config.rst") except: destination = os.path.join(os.getcwd(), "full-config.rst") with open(destination, "w") as f: f.write(header) f.write(ServerApp().document_config_options())
def jp_server_cleanup(): yield ServerApp.clear_instance()
from jupyter_server.serverapp import ServerApp success_msg = lambda name: """\n Congratulations! The server extension, {}, was successfully found and linked! """.format(name) if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument('extension_name') args = parser.parse_args() extension_name = args.extension_name app = ServerApp.instance( # Set the log level to debug for testing purposes port_retries=0, open_browser=False, ) app.initialize(argv=[]) extensions = app.extension_manager.extensions # Verify that the extension was found. assert extension_name in extensions # Verify that the extension is loaded and linked assert extension_name in app.extension_manager.linked_extensions # Print the success message. print(success_msg(extension_name))
def asyncio_patch(): ServerApp()._init_asyncio_patch()
def jp_server_cleanup(io_loop): yield app: ServerApp = ServerApp.instance() loop = io_loop.asyncio_loop loop.run_until_complete(app._cleanup()) ServerApp.clear_instance()