diff --git a/spyder_notebook/widgets/client.py b/spyder_notebook/widgets/client.py index 7aa0259e..0dae552c 100644 --- a/spyder_notebook/widgets/client.py +++ b/spyder_notebook/widgets/client.py @@ -153,6 +153,11 @@ class NotebookClient(QWidget): This is a widget composed of a NotebookWidget and a find dialog to render notebooks. + + Attributes + ---------- + server_url : str or None + URL to send requests to; set by register(). """ def __init__(self, parent, filename, actions=None, ini_message=None): @@ -229,7 +234,7 @@ def register(self, server_info): self.file_url = self.add_token(url) def go_to(self, url_or_text): - """Go to page utl.""" + """Go to page URL.""" if isinstance(url_or_text, str): url = QUrl(url_or_text) else: @@ -254,22 +259,29 @@ def get_short_name(self): def save(self): """ - Save current notebook. - - This function saves the current notebook by simulating a click on the - Save button in the notebook. The Save button is found by selecting the - first element of class `jp-ToolbarButtonComponent` whose `title` - attribute begins with the string "Save". + Save current notebook asynchronously. - NB: I am not sure whether the save is performed before the function - returns. + This function simulates a click on the Save button in the notebook + which will save the current notebook (but the function will return + before). The Save button is found by selecting the first element of + class `jp-ToolbarButtonComponent` whose `title` attribute begins with + the string "Save". """ self.notebookwidget.mousedown( '.jp-ToolbarButtonComponent[title^="Save"]') def get_session_url(self): - """Get the kernel sessions url of the client.""" - return self.add_token(url_path_join(self.server_url, 'api/sessions')) + """ + Get the kernel sessions URL of the client. + + Return a str with the URL or None, if no server is associated to + the client. + """ + if self.server_url: + session_url = url_path_join(self.server_url, 'api/sessions') + return self.add_token(session_url) + else: + return None def get_kernel_id(self): """ @@ -279,6 +291,9 @@ def get_kernel_id(self): box and return None. """ sessions_url = self.get_session_url() + if not sessions_url: + return None + try: sessions_response = requests.get(sessions_url) except requests.exceptions.RequestException as exception: diff --git a/spyder_notebook/widgets/tests/test_client.py b/spyder_notebook/widgets/tests/test_client.py index 624ed692..de4f8c13 100644 --- a/spyder_notebook/widgets/tests/test_client.py +++ b/spyder_notebook/widgets/tests/test_client.py @@ -18,10 +18,11 @@ class MockPlugin(QWidget): def get_plugin_actions(self): return [] + @pytest.fixture -def plugin(qtbot): +def plugin_without_server(qtbot): """ - Construct mock plugin with NotebookClient for use in tests. + Construct mock plugin with NotebookClient but no notebook server. Use `plugin.client` to access the client. """ @@ -29,11 +30,21 @@ def plugin(qtbot): qtbot.addWidget(plugin) client = NotebookClient(plugin, '/path/notebooks/ham.ipynb') plugin.client = client + return plugin + + +@pytest.fixture +def plugin(plugin_without_server): + """ + Construct mock plugin with NotebookClient with server registered. + + Use `plugin.client` to access the client. + """ server_info = {'notebook_dir': '/path/notebooks', 'url': 'fake_url', 'token': 'fake_token'} - client.register(server_info) - return plugin + plugin_without_server.client.register(server_info) + return plugin_without_server def test_notebookclient_get_kernel_id(plugin, mocker): @@ -48,6 +59,17 @@ def test_notebookclient_get_kernel_id(plugin, mocker): assert kernel_id == '42' +def test_notebookclient_get_kernel_id_without_server( + plugin_without_server, mocker): + """Test NotebookClient.get_kernel_id() if client has no server.""" + mock_get = mocker.patch('requests.get') + + kernel_id = plugin_without_server.client.get_kernel_id() + + assert kernel_id is None + mock_get.assert_not_called() + + def test_notebookclient_get_kernel_id_with_fields_missing(plugin, mocker): """Test NotebookClient.get_kernel_id() if response has fields missing.""" response = mocker.Mock()