Skip to content

Commit c8e7e5e

Browse files
Better messaging on notebook fail (#10056)
1 parent 649156a commit c8e7e5e

12 files changed

+86
-33
lines changed

PYTHON_INTERACTIVE_TROUBLESHOOTING.md

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
# Trouble shooting the Python Interactive Window
1+
# Troubleshooting Jupyter issues in the Python Interactive Window or Notebook Editor
22

3-
This document is intended to help troubleshoot problems in the Python Interactive Window.
3+
This document is intended to help troubleshoot problems with starting Jupyter in the Python Interactive Window or Notebook Editor.
44

55
---
66
## Jupyter Not Starting
@@ -10,12 +10,21 @@ This error can happen when
1010
* Jupyter is not installed
1111
* You picked the wrong Python environment (one that doesn't have Jupyter installed).
1212

13-
### The first step is to verify you are running the Python environment you want.
13+
### The first step is to verify you are running the Python environment that you have Jupyter installed into.
1414

15-
The Python you're using is picked with the selection dropdown on the bottom left of the VS Code window:
15+
The first time that you start the Interactive Window or the Notebook Editor VS Code will attempt to locate a Python environment that has Jupyter installed in it and can start a notebook.
16+
17+
The first Python interpreter to check will be the one selected with the selection dropdown on the bottom left of the VS Code window:
1618

1719
![selector](resources/PythonSelector.png)
1820

21+
Once a suitable interpreter with Jupyter has been located, VS Code will continue to use that interpreter for starting up Jupyter servers.
22+
If no interpreters are found with Jupyter installed a popup message will ask if you would like to install Jupyter into the current interpreter.
23+
24+
![install Jupyter](resources/InstallJupyter.png)
25+
26+
If you would like to change from using the saved Python interpreter to a new interpreter for launching Jupyter just use the "Python: Select interpreter to start Jupyter server" VS Code command to change it.
27+
1928
### The second step is to check that jupyter isn't giving any errors on startup.
2029

2130
Run the following command from an environment that matches the Python you selected:

news/2 Fixes/9904.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Improve error messaging when the jupyter notebook cannot be started.

package.nls.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,8 @@
193193
"DataScience.libraryNotInstalled": "Data Science library {0} is not installed. Install?",
194194
"DataScience.libraryRequiredToLaunchJupyterNotInstalled": "Data Science library {0} is not installed.",
195195
"DataScience.librariesRequiredToLaunchJupyterNotInstalled": "Data Science libraries {0} are not installed.",
196+
"DataScience.libraryRequiredToLaunchJupyterNotInstalledInterpreter": "Data Science library {1} is not installed in interpreter {0}.",
197+
"DataScience.librariesRequiredToLaunchJupyterNotInstalledInterpreter": "Data Science libraries {1} are not installed in interpreter {0}.",
196198
"DataScience.jupyterInstall": "Install",
197199
"DataScience.jupyterSelectURIPrompt": "Enter the URI of the running Jupyter server",
198200
"DataScience.jupyterSelectURIInvalidURI": "Invalid URI specified",

resources/InstallJupyter.png

14.4 KB
Loading

src/client/common/utils/localize.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,14 @@ export namespace DataScience {
292292
'DataScience.librariesRequiredToLaunchJupyterNotInstalled',
293293
'Data Science libraries {0} are not installed.'
294294
);
295+
export const libraryRequiredToLaunchJupyterNotInstalledInterpreter = localize(
296+
'DataScience.libraryRequiredToLaunchJupyterNotInstalledInterpreter',
297+
'Data Science library {1} is not installed in interpreter {0}.'
298+
);
299+
export const librariesRequiredToLaunchJupyterNotInstalledInterpreter = localize(
300+
'DataScience.librariesRequiredToLaunchJupyterNotInstalledInterpreter',
301+
'Data Science libraries {1} are not installed in interpreter {0}.'
302+
);
295303
export const selectJupyterInterpreter = localize(
296304
'DataScience.selectJupyterInterpreter',
297305
'Select an Interpreter to start Jupyter'

src/client/datascience/jupyter/interpreter/jupyterInterpreterDependencyService.ts

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { Common, DataScience } from '../../../common/utils/localize';
1414
import { noop } from '../../../common/utils/misc';
1515
import { PythonInterpreter } from '../../../interpreter/contracts';
1616
import { sendTelemetryEvent } from '../../../telemetry';
17-
import { Telemetry } from '../../constants';
17+
import { HelpLinks, Telemetry } from '../../constants';
1818
import { JupyterInstallError } from '../jupyterInstallError';
1919

2020
export enum JupyterInterpreterDependencyResponse {
@@ -56,7 +56,7 @@ function sortProductsInOrderForInstallation(products: Product[]) {
5656
* @param {Product[]} products
5757
* @returns {string}
5858
*/
59-
export function getMessageForLibrariesNotInstalled(products: Product[]): string {
59+
export function getMessageForLibrariesNotInstalled(products: Product[], interpreterName?: string): string {
6060
const names = products
6161
// Ignore kernelspec as it not something that can be installed.
6262
.filter(product => product !== Product.kernelspec)
@@ -68,12 +68,19 @@ export function getMessageForLibrariesNotInstalled(products: Product[]): string
6868
case 0:
6969
return '';
7070
case 1:
71-
return DataScience.libraryRequiredToLaunchJupyterNotInstalled().format(names[0]);
71+
return interpreterName
72+
? DataScience.libraryRequiredToLaunchJupyterNotInstalledInterpreter().format(interpreterName, names[0])
73+
: DataScience.libraryRequiredToLaunchJupyterNotInstalled().format(names[0]);
7274
default: {
7375
const lastItem = names.pop();
74-
return DataScience.librariesRequiredToLaunchJupyterNotInstalled().format(
75-
`${names.join(', ')} ${Common.and()} ${lastItem}`
76-
);
76+
return interpreterName
77+
? DataScience.librariesRequiredToLaunchJupyterNotInstalledInterpreter().format(
78+
interpreterName,
79+
`${names.join(', ')} ${Common.and()} ${lastItem}`
80+
)
81+
: DataScience.librariesRequiredToLaunchJupyterNotInstalled().format(
82+
`${names.join(', ')} ${Common.and()} ${lastItem}`
83+
);
7784
}
7885
}
7986
}
@@ -132,15 +139,14 @@ export class JupyterInterpreterDependencyService {
132139
return JupyterInterpreterDependencyResponse.ok;
133140
}
134141

135-
const message = getMessageForLibrariesNotInstalled(productsToInstall);
142+
const message = getMessageForLibrariesNotInstalled(productsToInstall, interpreter.displayName);
136143

137144
sendTelemetryEvent(Telemetry.JupyterNotInstalledErrorShown);
138145
const selection = await this.applicationShell.showErrorMessage(
139-
// tslint:disable-next-line: messages-must-be-localized
140-
`${message}\r\n${DataScience.markdownHelpInstallingMissingDependencies()}`,
146+
message,
141147
DataScience.jupyterInstall(),
142148
DataScience.selectDifferentJupyterInterpreter(),
143-
Common.cancel()
149+
DataScience.pythonInteractiveHelpLink()
144150
);
145151

146152
if (Cancellation.isCanceled(token)) {
@@ -181,6 +187,12 @@ export class JupyterInterpreterDependencyService {
181187
return JupyterInterpreterDependencyResponse.selectAnotherInterpreter;
182188
}
183189

190+
case DataScience.pythonInteractiveHelpLink(): {
191+
this.applicationShell.openUrl(HelpLinks.PythonInteractiveHelpLink);
192+
sendTelemetryEvent(Telemetry.UserDidNotInstallJupyter);
193+
return JupyterInterpreterDependencyResponse.cancel;
194+
}
195+
184196
default:
185197
sendTelemetryEvent(Telemetry.UserDidNotInstallJupyter);
186198
return JupyterInterpreterDependencyResponse.cancel;

src/client/datascience/jupyter/interpreter/jupyterInterpreterSubCommandExecutionService.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ export class JupyterInterpreterSubCommandExecutionService
9494
return DataScience.jupyterKernelSpecModuleNotFound();
9595
}
9696

97-
return getMessageForLibrariesNotInstalled(productsNotInstalled);
97+
return getMessageForLibrariesNotInstalled(productsNotInstalled, interpreter.displayName);
9898
}
9999
public async getSelectedInterpreter(token?: CancellationToken): Promise<PythonInterpreter | undefined> {
100100
return this.jupyterInterpreter.getSelectedInterpreter(token);

src/datascience-ui/history-react/interactivePanel.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,12 @@ export class InteractivePanel extends React.Component<IInteractivePanelProps> {
7474
>
7575
{this.renderVariablePanel(this.props.baseTheme)}
7676
</section>
77-
<main id="main-panel-content" onClick={this.contentPanelClick} onScroll={this.handleScroll}>
77+
<main id="main-panel-content" onScroll={this.handleScroll}>
7878
{this.renderContentPanel(this.props.baseTheme)}
7979
</main>
8080
<section
8181
id="main-panel-footer"
82+
onClick={this.footerPanelClick}
8283
aria-label={getLocString('DataScience.editSection', 'Input new cells here')}
8384
>
8485
{this.renderFooterPanel(this.props.baseTheme)}
@@ -87,8 +88,8 @@ export class InteractivePanel extends React.Component<IInteractivePanelProps> {
8788
);
8889
}
8990

90-
// If click is not handled by something else, focus our input box
91-
private contentPanelClick = (_event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
91+
// Make the entire footer focus our input, instead of having to click directly on the monaco editor
92+
private footerPanelClick = (_event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
9293
this.props.focusInput();
9394
};
9495

src/test/datascience/interactiveWindow.functional.test.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -238,10 +238,8 @@ for i in range(10):
238238
domDiv.tabIndex = -1;
239239
domDiv.focus();
240240

241-
// Click in content-panel-div, since this doesn't click on any valid click handlers this
242-
// should set input back to the input box
243241
wrapper
244-
.find('div#content-panel-div')
242+
.find('section#main-panel-footer')
245243
.first()
246244
.simulate('click');
247245

src/test/datascience/jupyter/interpreter/jupyterInterpreterDependencyService.unit.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { PythonExecutionFactory } from '../../../../client/common/process/python
1212
import { PythonExecutionService } from '../../../../client/common/process/pythonProcess';
1313
import { IPythonExecutionService } from '../../../../client/common/process/types';
1414
import { IInstaller, InstallerResponse, Product } from '../../../../client/common/types';
15-
import { Common, DataScience } from '../../../../client/common/utils/localize';
15+
import { DataScience } from '../../../../client/common/utils/localize';
1616
import { Architecture } from '../../../../client/common/utils/platform';
1717
import {
1818
JupyterInterpreterDependencyResponse,
@@ -75,7 +75,7 @@ suite('Data Science - Jupyter Interpreter Configuration', () => {
7575
anything(),
7676
DataScience.jupyterInstall(),
7777
DataScience.selectDifferentJupyterInterpreter(),
78-
Common.cancel()
78+
DataScience.pythonInteractiveHelpLink()
7979
)
8080
).once();
8181
assert.equal(response, JupyterInterpreterDependencyResponse.cancel);

src/test/datascience/jupyter/interpreter/jupyterInterpreterSubCommandExecutionService.unit.test.ts

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,8 @@ suite('Data Science - Jupyter InterpreterSubCommandExecutionService', () => {
116116
assert.equal(reason, DataScience.selectJupyterInterpreter());
117117
});
118118
test('Jupyter cannot be started because jupyter is not installed', async () => {
119-
const expectedReason = DataScience.libraryRequiredToLaunchJupyterNotInstalled().format(
119+
const expectedReason = DataScience.libraryRequiredToLaunchJupyterNotInstalledInterpreter().format(
120+
activePythonInterpreter.displayName!,
120121
ProductNames.get(Product.jupyter)!
121122
);
122123
when(jupyterDependencyService.getDependenciesNotInstalled(activePythonInterpreter, undefined)).thenResolve([
@@ -128,7 +129,8 @@ suite('Data Science - Jupyter InterpreterSubCommandExecutionService', () => {
128129
assert.equal(reason, expectedReason);
129130
});
130131
test('Jupyter cannot be started because notebook is not installed', async () => {
131-
const expectedReason = DataScience.libraryRequiredToLaunchJupyterNotInstalled().format(
132+
const expectedReason = DataScience.libraryRequiredToLaunchJupyterNotInstalledInterpreter().format(
133+
activePythonInterpreter.displayName!,
132134
ProductNames.get(Product.notebook)!
133135
);
134136
when(jupyterDependencyService.getDependenciesNotInstalled(activePythonInterpreter, undefined)).thenResolve([
@@ -146,7 +148,10 @@ suite('Data Science - Jupyter InterpreterSubCommandExecutionService', () => {
146148
]);
147149

148150
await expect(promise).to.eventually.be.rejectedWith(
149-
DataScience.libraryRequiredToLaunchJupyterNotInstalled().format(ProductNames.get(Product.notebook)!)
151+
DataScience.libraryRequiredToLaunchJupyterNotInstalledInterpreter().format(
152+
activePythonInterpreter.displayName!,
153+
ProductNames.get(Product.notebook)!
154+
)
150155
);
151156
});
152157
test('Cannot launch notebook file in jupyter notebook', async () => {
@@ -156,7 +161,10 @@ suite('Data Science - Jupyter InterpreterSubCommandExecutionService', () => {
156161
]);
157162

158163
await expect(promise).to.eventually.be.rejectedWith(
159-
DataScience.libraryRequiredToLaunchJupyterNotInstalled().format(ProductNames.get(Product.notebook)!)
164+
DataScience.libraryRequiredToLaunchJupyterNotInstalledInterpreter().format(
165+
activePythonInterpreter.displayName!,
166+
ProductNames.get(Product.notebook)!
167+
)
160168
);
161169
});
162170
test('Cannot export notebook to python', async () => {
@@ -166,7 +174,10 @@ suite('Data Science - Jupyter InterpreterSubCommandExecutionService', () => {
166174
]);
167175

168176
await expect(promise).to.eventually.be.rejectedWith(
169-
DataScience.libraryRequiredToLaunchJupyterNotInstalled().format(ProductNames.get(Product.notebook)!)
177+
DataScience.libraryRequiredToLaunchJupyterNotInstalledInterpreter().format(
178+
activePythonInterpreter.displayName!,
179+
ProductNames.get(Product.notebook)!
180+
)
170181
);
171182
});
172183
test('Cannot get a list of running jupyter servers', async () => {
@@ -176,7 +187,10 @@ suite('Data Science - Jupyter InterpreterSubCommandExecutionService', () => {
176187
]);
177188

178189
await expect(promise).to.eventually.be.rejectedWith(
179-
DataScience.libraryRequiredToLaunchJupyterNotInstalled().format(ProductNames.get(Product.notebook)!)
190+
DataScience.libraryRequiredToLaunchJupyterNotInstalledInterpreter().format(
191+
activePythonInterpreter.displayName!,
192+
ProductNames.get(Product.notebook)!
193+
)
180194
);
181195
});
182196
test('Cannot get kernelspecs', async () => {
@@ -186,7 +200,10 @@ suite('Data Science - Jupyter InterpreterSubCommandExecutionService', () => {
186200
]);
187201

188202
await expect(promise).to.eventually.be.rejectedWith(
189-
DataScience.libraryRequiredToLaunchJupyterNotInstalled().format(ProductNames.get(Product.notebook)!)
203+
DataScience.libraryRequiredToLaunchJupyterNotInstalledInterpreter().format(
204+
activePythonInterpreter.displayName!,
205+
ProductNames.get(Product.notebook)!
206+
)
190207
);
191208
});
192209
});
@@ -226,7 +243,8 @@ suite('Data Science - Jupyter InterpreterSubCommandExecutionService', () => {
226243
verify(jupyterDependencyService.installMissingDependencies(selectedJupyterInterpreter, undefined)).once();
227244
});
228245
test('Jupyter cannot be started because jupyter is not installed', async () => {
229-
const expectedReason = DataScience.libraryRequiredToLaunchJupyterNotInstalled().format(
246+
const expectedReason = DataScience.libraryRequiredToLaunchJupyterNotInstalledInterpreter().format(
247+
selectedJupyterInterpreter.displayName!,
230248
ProductNames.get(Product.jupyter)!
231249
);
232250
when(
@@ -240,7 +258,8 @@ suite('Data Science - Jupyter InterpreterSubCommandExecutionService', () => {
240258
assert.equal(reason, expectedReason);
241259
});
242260
test('Jupyter cannot be started because notebook is not installed', async () => {
243-
const expectedReason = DataScience.libraryRequiredToLaunchJupyterNotInstalled().format(
261+
const expectedReason = DataScience.libraryRequiredToLaunchJupyterNotInstalledInterpreter().format(
262+
selectedJupyterInterpreter.displayName!,
244263
ProductNames.get(Product.notebook)!
245264
);
246265
when(

src/test/datascience/notebook.functional.test.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1441,7 +1441,10 @@ plt.show()`,
14411441
threw = true;
14421442
// When using old command finder, the error is `Not Supported` (directly from stdout). - can be deprecated when jupyterCommandFinder.ts is deleted.
14431443
// When using new approach, we inform user that some packages are not installed.
1444-
const expectedErrorMsg = getMessageForLibrariesNotInstalled([Product.jupyter, Product.notebook]);
1444+
const expectedErrorMsg = getMessageForLibrariesNotInstalled(
1445+
[Product.jupyter, Product.notebook],
1446+
'Python'
1447+
);
14451448

14461449
assert.ok(
14471450
e.message.includes('Not supported') || e.message.includes(expectedErrorMsg),

0 commit comments

Comments
 (0)