Skip to content

Commit 161afed

Browse files
authored
Merge pull request #485 from krassowski/various-fixes
Various fixes
2 parents 3f0f540 + 9dde59c commit 161afed

File tree

10 files changed

+84
-30
lines changed

10 files changed

+84
-30
lines changed

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
11
## CHANGELOG
22

3+
### `@krassowski/jupyterlab-lsp 3.1.1` (unreleased)
4+
5+
- bug fixes:
6+
7+
- diagnostics panel works after kernel restart properly ([#485])
8+
- workaround was added to enable `jedi-language-server` diagnostics ([#485])
9+
10+
### `jupyter-lsp 1.1.1` (unreleased)
11+
12+
- bug fixes:
13+
14+
- `PythonModuleSpec` no longer raises exception when the server module does not exist ([#485])
15+
16+
[#485]: https://github.com/krassowski/jupyterlab-lsp/pull/485
17+
318
### `@krassowski/jupyterlab-lsp 3.1.0` (2021-01-17)
419

520
- features

atest/04_Interface/DiagnosticsPanel.robot

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,16 @@ Diagnostics Panel Works After Rename
2828
Wait Until Keyword Succeeds 10 x 1s Should Have Expected Rows Count ${EXPECTED_COUNT}
2929
Clean Up After Working With File PanelRenamed.ipynb
3030

31+
Diagnostics Panel Works After Kernel Restart
32+
[Documentation] Test for #475 bug
33+
Close Diagnostics Panel
34+
Lab Command Restart Kernel…
35+
Wait For Dialog
36+
Accept Default Dialog Option
37+
Wait Until Page Contains Element css:.cm-lsp-diagnostic[title*="${DIAGNOSTIC}"] timeout=20s
38+
Open Diagnostics Panel
39+
Wait Until Keyword Succeeds 10 x 1s Should Have Expected Rows Count ${EXPECTED_COUNT}
40+
3141
Diagnostics Panel Can Be Restored
3242
Close Diagnostics Panel
3343
Open Diagnostics Panel

atest/05_Features/Completion.robot

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ Completes Large Namespaces
223223
[Setup] Prepare File for Editing R completion completion.R
224224
Place Cursor In File Editor At 6 7
225225
Wait Until Fully Initialized
226-
Wait Until Keyword Succeeds 3x 2s Trigger Completer timeout=45s
226+
Wait Until Keyword Succeeds 3x 2s Trigger Completer timeout=90s
227227
Completer Should Suggest abs timeout=30s
228228
[Teardown] Clean Up After Working With File completion.R
229229

packages/jupyterlab-lsp/schema/syntax_highlighting.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"title": "Threshold of foreign code coverage for changing the mode in an editor",
1010
"type": "number",
1111
"default": 0.5,
12-
"description": "If a code editor includes a code fragment in another language (for example a %%markdown magic in IPython) with appropriate foreign code extractor defined , and the extend of this code (coverage of the editor) passes the threshold, the syntax highlighting (i.e. the mode) will change to provide highlighting for the language of the foreign code."
12+
"description": "If a code editor includes a code fragment in another language (for example a %%markdown magic in IPython) with appropriate foreign code extractor defined, and the extend of this code (coverage of the editor) passes the threshold, the syntax highlighting (i.e. the mode) will change to provide highlighting for the language of the foreign code."
1313
}
1414
},
1515
"jupyter.lab.shortcuts": []

packages/jupyterlab-lsp/src/adapters/adapter.ts

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -167,20 +167,8 @@ export abstract class WidgetAdapter<T extends IDocumentWidget> {
167167
this.widget.context.saveState.disconnect(this.on_save_state, this);
168168
this.connection_manager.closed.disconnect(this.on_connection_closed, this);
169169
this.widget.disposed.disconnect(this.dispose, this);
170-
this.widget.context.model.contentChanged.disconnect(
171-
this.onContentChanged,
172-
this
173-
);
174170

175-
for (let adapter of this.adapters.values()) {
176-
adapter.dispose();
177-
}
178-
this.adapters.clear();
179-
180-
this.connection_manager.disconnect_document_signals(
181-
this.virtual_editor.virtual_document
182-
);
183-
this.virtual_editor.dispose();
171+
this.disconnect();
184172

185173
// just to be sure
186174
this.virtual_editor = null;
@@ -224,6 +212,23 @@ export abstract class WidgetAdapter<T extends IDocumentWidget> {
224212

225213
abstract get language_file_extension(): string;
226214

215+
disconnect() {
216+
this.connection_manager.unregister_document(
217+
this.virtual_editor.virtual_document
218+
);
219+
this.widget.context.model.contentChanged.disconnect(
220+
this.onContentChanged,
221+
this
222+
);
223+
224+
for (let adapter of this.adapters.values()) {
225+
adapter.dispose();
226+
}
227+
this.adapters.clear();
228+
229+
this.virtual_editor.dispose();
230+
}
231+
227232
// equivalent to triggering didClose and didOpen, as per syncing specification,
228233
// but also reloads the connection; used during file rename (or when it was moved)
229234
protected reload_connection() {
@@ -233,16 +238,12 @@ export abstract class WidgetAdapter<T extends IDocumentWidget> {
233238
}
234239

235240
// disconnect all existing connections (and dispose adapters)
236-
this.connection_manager.unregister_document(
237-
this.virtual_editor.virtual_document
238-
);
241+
this.disconnect();
239242

240243
// recreate virtual document using current path and language
241244
// as virtual editor assumes it gets the virtual document at init,
242245
// just dispose virtual editor (which disposes virtual document too)
243246
// and re-initialize both virtual editor and document
244-
this.virtual_editor.dispose();
245-
246247
this.init_virtual();
247248

248249
// reconnect

packages/jupyterlab-lsp/src/components/statusbar.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -489,7 +489,7 @@ export namespace LSPStatus {
489489
server => server.spec.languages.indexOf(language) !== -1
490490
);
491491
if (servers.length > 1) {
492-
console.warn('More than one server per language for' + language);
492+
console.warn('More than one server per language for', language);
493493
}
494494
if (servers.length === 0) {
495495
continue;

packages/jupyterlab-lsp/src/connection_manager.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ export class DocumentConnectionManager {
306306
);
307307
} catch {
308308
this.console.warn(
309-
`LSP: Connection to ${virtual_document.uri} timed out after ${firstTimeoutSeconds} seconds, will continue retrying for another ${secondTimeoutMinutes} minutes`
309+
`Connection to ${virtual_document.uri} timed out after ${firstTimeoutSeconds} seconds, will continue retrying for another ${secondTimeoutMinutes} minutes`
310310
);
311311
try {
312312
await until_ready(
@@ -316,7 +316,7 @@ export class DocumentConnectionManager {
316316
);
317317
} catch {
318318
this.console.warn(
319-
`LSP: Connection to ${virtual_document.uri} timed out again after ${secondTimeoutMinutes} minutes, giving up`
319+
`Connection to ${virtual_document.uri} timed out again after ${secondTimeoutMinutes} minutes, giving up`
320320
);
321321
return;
322322
}

packages/jupyterlab-lsp/src/features/diagnostics/diagnostics.ts

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -275,11 +275,10 @@ export class DiagnosticsCM extends CodeMirrorIntegration {
275275
this.connection_handlers.set('diagnostic', this.handleDiagnostic);
276276
this.wrapper_handlers.set('focusin', this.switchDiagnosticsPanelSource);
277277
this.unique_editor_ids = new DefaultMap(() => this.unique_editor_ids.size);
278-
if (!diagnostics_databases.has(this.virtual_editor)) {
279-
diagnostics_databases.set(this.virtual_editor, new DiagnosticsDatabase());
280-
}
281-
this.diagnostics_db = diagnostics_databases.get(this.virtual_editor);
282278
this.settings.changed.connect(this.refreshDiagnostics, this);
279+
this.adapter.adapterConnected.connect(() =>
280+
this.switchDiagnosticsPanelSource()
281+
);
283282
super.register();
284283
}
285284

@@ -294,11 +293,18 @@ export class DiagnosticsCM extends CodeMirrorIntegration {
294293
*
295294
* Maps virtual_document.uri to IEditorDiagnostic[].
296295
*/
297-
public diagnostics_db: DiagnosticsDatabase;
296+
public get diagnostics_db(): DiagnosticsDatabase {
297+
// Note that virtual_editor can change at runtime (kernel restart)
298+
if (!diagnostics_databases.has(this.virtual_editor)) {
299+
diagnostics_databases.set(this.virtual_editor, new DiagnosticsDatabase());
300+
}
301+
return diagnostics_databases.get(this.virtual_editor);
302+
}
298303

299304
switchDiagnosticsPanelSource = () => {
300305
if (
301-
diagnostics_panel.content.model.virtual_editor === this.virtual_editor
306+
diagnostics_panel.content.model.virtual_editor === this.virtual_editor &&
307+
diagnostics_panel.content.model.diagnostics == this.diagnostics_db
302308
) {
303309
return;
304310
}
@@ -378,6 +384,12 @@ export class DiagnosticsCM extends CodeMirrorIntegration {
378384
let code = diagnostic.code;
379385
if (
380386
typeof code !== 'undefined' &&
387+
// pygls servers return code null if value is missing (rather than undefined)
388+
// which is a departure from the LSP specs: https://microsoft.github.io/language-server-protocol/specification#diagnostic
389+
// there is an open issue: https://github.com/openlawlibrary/pygls/issues/124
390+
// and PR: https://github.com/openlawlibrary/pygls/pull/132
391+
// this also affects hover tooltips.
392+
code !== null &&
381393
ignoredDiagnosticsCodes.has(code.toString())
382394
) {
383395
return false;
@@ -588,7 +600,9 @@ export class DiagnosticsCM extends CodeMirrorIntegration {
588600
};
589601

590602
public refreshDiagnostics() {
591-
this.setDiagnostics(this.last_response);
603+
if (this.last_response) {
604+
this.setDiagnostics(this.last_response);
605+
}
592606
diagnostics_panel.update();
593607
}
594608

python_packages/jupyter_lsp/jupyter_lsp/specs/utils.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ class PythonModuleSpec(SpecBase):
9393
def __call__(self, mgr: LanguageServerManagerAPI) -> KeyedLanguageServerSpecs:
9494
spec = __import__("importlib").util.find_spec(self.python_module)
9595

96+
if not spec:
97+
return {}
98+
9699
if not spec.origin: # pragma: no cover
97100
return {}
98101

python_packages/jupyter_lsp/jupyter_lsp/tests/test_detect.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import shutil
22

33
from jupyter_lsp.specs.r_languageserver import RLanguageServer
4+
from jupyter_lsp.specs.utils import PythonModuleSpec
45

56

67
def test_no_detect(manager):
@@ -28,3 +29,13 @@ class NonInstalledRServer(RLanguageServer):
2829

2930
non_installed_server = NonInstalledRServer()
3031
assert non_installed_server.is_installed(cmd=existing_runner) is False
32+
33+
34+
def test_missing_python_module_spec():
35+
"""Prevent failure in module detection raising error"""
36+
37+
class NonInstalledPythonServer(PythonModuleSpec):
38+
python_module = "not_installed_python_module"
39+
40+
not_installed_server = NonInstalledPythonServer()
41+
assert not_installed_server(mgr=None) == {}

0 commit comments

Comments
 (0)