From 72a85fe1891ce171d99a5d6646344d27df034d9c Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 2 Aug 2016 14:03:46 -0700 Subject: [PATCH 1/3] Load extension in predictable order. Not doing this can lead to subtle incomprehensible issues when 2 extensions (eg, jupyterlab and jupyterlab_extensions) both register the same handlers, that will randomly at each start get a different extension take precedence. --- notebook/notebookapp.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/notebook/notebookapp.py b/notebook/notebookapp.py index a0972475c..d13d9be8a 100644 --- a/notebook/notebookapp.py +++ b/notebook/notebookapp.py @@ -902,7 +902,8 @@ class NotebookApp(JupyterApp): nbserver_extensions = Dict({}, config=True, help=("Dict of Python modules to load as notebook server extensions." "Entry values can be used to enable and disable the loading of" - "the extensions.") + "the extensions. The extensions will be loaded in alphabetical " + "order.") ) reraise_server_extension_failures = Bool( @@ -1156,7 +1157,7 @@ class NotebookApp(JupyterApp): if not modulename in self.nbserver_extensions: self.nbserver_extensions[modulename] = True - for modulename in self.nbserver_extensions: + for modulename in sorted(self.nbserver_extensions): if self.nbserver_extensions[modulename]: try: mod = importlib.import_module(modulename) From 5210701803dc38a829a2073a6fab7a668406129d Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 29 Sep 2016 10:47:09 -0700 Subject: [PATCH 2/3] Add test for predictable extension loading. --- notebook/tests/test_serverextensions.py | 46 +++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/notebook/tests/test_serverextensions.py b/notebook/tests/test_serverextensions.py index 4c5a68c08..bfac5f8b5 100644 --- a/notebook/tests/test_serverextensions.py +++ b/notebook/tests/test_serverextensions.py @@ -1,4 +1,5 @@ import os +import sys from unittest import TestCase try: from unittest.mock import patch @@ -13,9 +14,14 @@ from traitlets.tests.utils import check_help_all_output from notebook.serverextensions import toggle_serverextension_python from notebook import nbextensions +from notebook.notebookapp import NotebookApp from notebook.nbextensions import _get_config_dir +from types import SimpleNamespace +from collections import OrderedDict + + def test_help_output(): check_help_all_output('notebook.serverextensions') check_help_all_output('notebook.serverextensions', ['enable']) @@ -87,3 +93,43 @@ class TestInstallServerExtension(TestCase): config = self._get_config() assert not config['mockextension'] + + +class TestOrderedServerExtension(TestCase): + """ + Test that Server Extensions are loaded _in order_ + """ + + def setUp(self): + mockextension1 = SimpleNamespace() + mockextension2 = SimpleNamespace() + + def load_jupyter_server_extension(obj): + obj.mockI = True + obj.mock_shared = 'I' + + mockextension1.load_jupyter_server_extension = load_jupyter_server_extension + + def load_jupyter_server_extension(obj): + obj.mockII = True + obj.mock_shared = 'II' + + mockextension2.load_jupyter_server_extension = load_jupyter_server_extension + + sys.modules['mockextension2'] = mockextension2 + sys.modules['mockextension1'] = mockextension1 + + def tearDown(self): + del sys.modules['mockextension2'] + del sys.modules['mockextension1'] + + + def test_load_ordered(self): + app = NotebookApp() + app.nbserver_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" From 26471897efb5766767072a281b7839afe99b8fd9 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 29 Sep 2016 11:28:15 -0700 Subject: [PATCH 3/3] Define SimpleNamespace on python 2 --- notebook/tests/test_serverextensions.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/notebook/tests/test_serverextensions.py b/notebook/tests/test_serverextensions.py index bfac5f8b5..b24754dda 100644 --- a/notebook/tests/test_serverextensions.py +++ b/notebook/tests/test_serverextensions.py @@ -17,8 +17,12 @@ from notebook import nbextensions from notebook.notebookapp import NotebookApp from notebook.nbextensions import _get_config_dir +if sys.version_info > (3,): + from types import SimpleNamespace +else: + class SimpleNamespace(object): + pass -from types import SimpleNamespace from collections import OrderedDict