Skip to content

Commit dcc695c

Browse files
rchiodoIanMatthewHuffDonJayamanne
authored
Port fixes for second point release. (#10146)
* Better messaging on notebook fail (#10056) * Install jupyter instead of installing kernel spec (#10080) * Install jupyter instead of installing kernel spec For #10071 * Eliminate variable value when computing data frame info (#10081) * Fix ndarray types to be viewable again (#10093) * Eliminate variable value when computing data frame info * Fix ndarrays to work again Add test to make sure we don't regress this again * Rchiodo/kernel telemetry (#10115) * Add duration to select local/remote kernel * Add notebook language telemetry * Add news entries * #9883 telemetry * News entry * Another spot for kernel spec failure * Add telemetry on product install * Fix install telemetry * Undo launch.json change * Handle other cases * Better way to handle case * Wrong event for jupyter install * Fix unit tests * Clear variables when restarting regardless if visible or not (#10117) * Use different method for checking if kernelspec is available (#10114) * Use different method for checking if kernelspec is available * Fix unit tests * More logging for kernelspec problems (#10132) * More logging for kernelspec problems * Actually capture the exception on the new code * Not actually using output if first exception still there. * Actually only return output on one of the expected calls. * Fix nightly flake * Check our saved jupyter interpreters before allowing any of them to be used as active interpreters (#10113) * Update changelog and package.json * Missing part of changelog * Fix tests and linter problems Co-authored-by: Ian Huff <[email protected]> Co-authored-by: Don Jayamanne <[email protected]>
1 parent 5066319 commit dcc695c

34 files changed

+648
-192
lines changed

CHANGELOG.md

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,82 @@
11
# Changelog
22

3+
## 2020.2.2 (18 February 2020)
4+
5+
### Fixes
6+
7+
1. Improve error messaging when the jupyter notebook cannot be started.
8+
([#9904](https://github.com/Microsoft/vscode-python/issues/9904))
9+
1. Clear variables in notebooks and interactive-window when restarting.
10+
([#9991](https://github.com/Microsoft/vscode-python/issues/9991))
11+
1. Re-install `Jupyter` instead of installing `kernelspec` if `kernelspec` cannot be found in the python environment.
12+
([#10071](https://github.com/Microsoft/vscode-python/issues/10071))
13+
1. Fixes problem with showing ndarrays in the data viewer.
14+
([#10074](https://github.com/Microsoft/vscode-python/issues/10074))
15+
1. Fix data viewer not opening on certain data frames.
16+
([#10075](https://github.com/Microsoft/vscode-python/issues/10075))
17+
18+
### Code Health
19+
20+
1. Add telemetry to track notebook languages
21+
([#9819](https://github.com/Microsoft/vscode-python/issues/9819))
22+
1. Telemetry around kernels not working and installs not working.
23+
([#9883](https://github.com/Microsoft/vscode-python/issues/9883))
24+
1. Change select kernel telemetry to track duration till quick pick appears.
25+
([#10049](https://github.com/Microsoft/vscode-python/issues/10049))
26+
27+
### Thanks
28+
29+
Thanks to the following projects which we fully rely on to provide some of
30+
our features:
31+
32+
- [isort](https://pypi.org/project/isort/)
33+
- [jedi](https://pypi.org/project/jedi/)
34+
and [parso](https://pypi.org/project/parso/)
35+
- [Microsoft Python Language Server](https://github.com/microsoft/python-language-server)
36+
- [ptvsd](https://pypi.org/project/ptvsd/)
37+
- [exuberant ctags](http://ctags.sourceforge.net/) (user-installed)
38+
- [rope](https://pypi.org/project/rope/) (user-installed)
39+
40+
Also thanks to the various projects we provide integrations with which help
41+
make this extension useful:
42+
43+
- Debugging support:
44+
[Django](https://pypi.org/project/Django/),
45+
[Flask](https://pypi.org/project/Flask/),
46+
[gevent](https://pypi.org/project/gevent/),
47+
[Jinja](https://pypi.org/project/Jinja/),
48+
[Pyramid](https://pypi.org/project/pyramid/),
49+
[PySpark](https://pypi.org/project/pyspark/),
50+
[Scrapy](https://pypi.org/project/Scrapy/),
51+
[Watson](https://pypi.org/project/Watson/)
52+
- Formatting:
53+
[autopep8](https://pypi.org/project/autopep8/),
54+
[black](https://pypi.org/project/black/),
55+
[yapf](https://pypi.org/project/yapf/)
56+
- Interpreter support:
57+
[conda](https://conda.io/),
58+
[direnv](https://direnv.net/),
59+
[pipenv](https://pypi.org/project/pipenv/),
60+
[pyenv](https://github.com/pyenv/pyenv),
61+
[venv](https://docs.python.org/3/library/venv.html#module-venv),
62+
[virtualenv](https://pypi.org/project/virtualenv/)
63+
- Linting:
64+
[bandit](https://pypi.org/project/bandit/),
65+
[flake8](https://pypi.org/project/flake8/),
66+
[mypy](https://pypi.org/project/mypy/),
67+
[prospector](https://pypi.org/project/prospector/),
68+
[pylint](https://pypi.org/project/pylint/),
69+
[pydocstyle](https://pypi.org/project/pydocstyle/),
70+
[pylama](https://pypi.org/project/pylama/)
71+
- Testing:
72+
[nose](https://pypi.org/project/nose/),
73+
[pytest](https://pypi.org/project/pytest/),
74+
[unittest](https://docs.python.org/3/library/unittest.html#module-unittest)
75+
76+
And finally thanks to the [Python](https://www.python.org/) development team and
77+
community for creating a fantastic programming language and community to be a
78+
part of!
79+
380
## 2020.2.1 (12 February 2020)
481

582
### Fixes

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:

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "python",
33
"displayName": "Python",
44
"description": "Linting, Debugging (multi-threaded, remote), Intellisense, Jupyter Notebooks, code formatting, refactoring, unit tests, snippets, and more.",
5-
"version": "2020.2.1",
5+
"version": "2020.2.2",
66
"languageServerVersion": "0.5.30",
77
"publisher": "ms-python",
88
"author": {

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",
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Check whether kernelspec module exists.
2+
import sys
3+
import jupyter_client
4+
import jupyter_client.kernelspec
5+
6+
sys.stdout.write(jupyter_client.__version__)
7+
sys.stdout.flush()

resources/InstallJupyter.png

14.4 KB
Loading

src/client/common/installer/productInstaller.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import * as os from 'os';
55
import { CancellationToken, OutputChannel, Uri } from 'vscode';
66
import '../../common/extensions';
77
import * as localize from '../../common/utils/localize';
8+
import { Telemetry } from '../../datascience/constants';
89
import { IInterpreterService } from '../../interpreter/contracts';
910
import { IServiceContainer } from '../../ioc/types';
1011
import { LinterId } from '../../linters/types';
@@ -18,6 +19,7 @@ import { IProcessServiceFactory, IPythonExecutionFactory } from '../process/type
1819
import { ITerminalServiceFactory } from '../terminal/types';
1920
import { IConfigurationService, IInstaller, InstallerResponse, IOutputChannel, IPersistentStateFactory, ModuleNamePurpose, Product, ProductType } from '../types';
2021
import { isResource } from '../utils/misc';
22+
import { StopWatch } from '../utils/stopWatch';
2123
import { ProductNames } from './productNames';
2224
import { IInstallationChannelManager, InterpreterUri, IProductPathService, IProductService } from './types';
2325

@@ -278,7 +280,21 @@ export class DataScienceInstaller extends BaseInstaller {
278280
protected async promptToInstallImplementation(product: Product, resource?: InterpreterUri, cancel?: CancellationToken): Promise<InstallerResponse> {
279281
const productName = ProductNames.get(product)!;
280282
const item = await this.appShell.showErrorMessage(localize.DataScience.libraryNotInstalled().format(productName), 'Yes', 'No');
281-
return item === 'Yes' ? this.install(product, resource, cancel) : InstallerResponse.Ignore;
283+
if (item === 'Yes') {
284+
const stopWatch = new StopWatch();
285+
try {
286+
const response = await this.install(product, resource, cancel);
287+
const event = product === Product.jupyter ? Telemetry.UserInstalledJupyter : Telemetry.UserInstalledModule;
288+
sendTelemetryEvent(event, stopWatch.elapsedTime, { product: productName });
289+
return response;
290+
} catch (e) {
291+
if (product === Product.jupyter) {
292+
sendTelemetryEvent(Telemetry.JupyterInstallFailed);
293+
}
294+
throw e;
295+
}
296+
}
297+
return InstallerResponse.Ignore;
282298
}
283299
}
284300

src/client/common/process/types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,8 @@ export interface IPythonExecutionFactory {
113113
create(options: ExecutionFactoryCreationOptions): Promise<IPythonExecutionService>;
114114
/**
115115
* Creates a daemon Python Process.
116-
* On windows its cheapter to create a daemon and use that than spin up Python Processes everytime.
117-
* If something cannot be executed within the daemin, it will resort to using the stanard IPythonExecutionService.
116+
* On windows it's cheaper to create a daemon and use that than spin up Python Processes everytime.
117+
* If something cannot be executed within the daemon, it will resort to using the standard IPythonExecutionService.
118118
* Note: The returned execution service is always using an activated environment.
119119
*
120120
* @param {ExecutionFactoryCreationOptions} options

src/client/common/utils/localize.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,14 @@ export namespace DataScience {
211211
'DataScience.librariesRequiredToLaunchJupyterNotInstalled',
212212
'Data Science libraries {0} are not installed.'
213213
);
214+
export const libraryRequiredToLaunchJupyterNotInstalledInterpreter = localize(
215+
'DataScience.libraryRequiredToLaunchJupyterNotInstalledInterpreter',
216+
'Data Science library {1} is not installed in interpreter {0}.'
217+
);
218+
export const librariesRequiredToLaunchJupyterNotInstalledInterpreter = localize(
219+
'DataScience.librariesRequiredToLaunchJupyterNotInstalledInterpreter',
220+
'Data Science libraries {1} are not installed in interpreter {0}.'
221+
);
214222
export const selectJupyterInterpreter = localize('DataScience.selectJupyterInterpreter', 'Select an Interpreter to start Jupyter');
215223
export const jupyterInstall = localize('DataScience.jupyterInstall', 'Install');
216224
export const currentlySelectedJupyterInterpreterForPlaceholder = localize('Datascience.currentlySelectedJupyterInterpreterForPlaceholder', 'current: {0}');

src/client/datascience/activation.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ export class Activation implements IExtensionSingleActivationService {
2828
public async activate(): Promise<void> {
2929
this.disposables.push(this.notebookProvider.onDidOpenNotebookEditor(this.onDidOpenNotebookEditor, this));
3030
this.disposables.push(this.jupyterInterpreterService.onDidChangeInterpreter(this.onDidChangeInterpreter, this));
31+
// Warm up our selected interpreter for the extension
32+
this.jupyterInterpreterService.setInitialInterpreter().ignoreErrors();
3133
await this.contextService.activate();
3234
}
3335

src/client/datascience/constants.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ export const JUPYTER_OUTPUT_CHANNEL = 'JUPYTER_OUTPUT_CHANNEL';
1414
// Python Module to be used when instantiating the Python Daemon.
1515
export const PythonDaemonModule = 'datascience.jupyter_daemon';
1616

17+
// List of 'language' names that we know about. All should be lower case as that's how we compare.
18+
export const KnownNotebookLanguages: string[] = ['python', 'r', 'julia', 'c++', 'c#', 'f#', 'scala', 'haskell', 'bash', 'cling', 'sas'];
19+
1720
export namespace Commands {
1821
export const RunAllCells = 'python.datascience.runallcells';
1922
export const RunAllCellsAbove = 'python.datascience.runallcellsabove';
@@ -147,7 +150,7 @@ export enum Telemetry {
147150
CollapseAll = 'DATASCIENCE.COLLAPSE_ALL',
148151
SelectJupyterURI = 'DATASCIENCE.SELECT_JUPYTER_URI',
149152
SelectLocalJupyterKernel = 'DATASCIENCE.SELECT_LOCAL_JUPYTER_KERNEL',
150-
SelectRemoteJupyuterKernel = 'DATASCIENCE.SELECT_REMOTE_JUPYTER_KERNEL',
153+
SelectRemoteJupyterKernel = 'DATASCIENCE.SELECT_REMOTE_JUPYTER_KERNEL',
151154
SetJupyterURIToLocal = 'DATASCIENCE.SET_JUPYTER_URI_LOCAL',
152155
SetJupyterURIToUserSpecified = 'DATASCIENCE.SET_JUPYTER_URI_USER_SPECIFIED',
153156
Interrupt = 'DATASCIENCE.INTERRUPT',
@@ -239,7 +242,14 @@ export enum Telemetry {
239242
OpenedInteractiveWindow = 'DATASCIENCE.OPENED_INTERACTIVE',
240243
FindKernelForLocalConnection = 'DS_INTERNAL.FIND_KERNEL_FOR_LOCAL_CONNECTION',
241244
CompletionTimeFromLS = 'DS_INTERNAL.COMPLETION_TIME_FROM_LS',
242-
CompletionTimeFromJupyter = 'DS_INTERNAL.COMPLETION_TIME_FROM_JUPYTER'
245+
CompletionTimeFromJupyter = 'DS_INTERNAL.COMPLETION_TIME_FROM_JUPYTER',
246+
NotebookLanguage = 'DATASCIENCE.NOTEBOOK_LANGUAGE',
247+
KernelSpecNotFound = 'DS_INTERNAL.KERNEL_SPEC_NOT_FOUND',
248+
KernelRegisterFailed = 'DS_INTERNAL.KERNEL_REGISTER_FAILED',
249+
KernelEnumeration = 'DS_INTERNAL.KERNEL_ENUMERATION',
250+
JupyterInstallFailed = 'DS_INTERNAL.JUPYTER_INSTALL_FAILED',
251+
UserInstalledModule = 'DATASCIENCE.USER_INSTALLED_MODULE',
252+
JupyterCommandLineNonDefault = 'DS_INTERNAL.JUPYTER_CUSTOM_COMMAND_LINE'
243253
}
244254

245255
export enum NativeKeyboardCommandTelemetry {

src/client/datascience/interactive-ipynb/nativeEditor.ts

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import { StopWatch } from '../../common/utils/stopWatch';
2424
import { EXTENSION_ROOT_DIR } from '../../constants';
2525
import { IInterpreterService } from '../../interpreter/contracts';
2626
import { captureTelemetry, sendTelemetryEvent } from '../../telemetry';
27-
import { EditorContexts, Identifiers, NativeKeyboardCommandTelemetryLookup, NativeMouseCommandTelemetryLookup, Telemetry } from '../constants';
27+
import { EditorContexts, Identifiers, KnownNotebookLanguages, NativeKeyboardCommandTelemetryLookup, NativeMouseCommandTelemetryLookup, Telemetry } from '../constants';
2828
import { InteractiveBase } from '../interactive-common/interactiveBase';
2929
import {
3030
IEditCell,
@@ -327,7 +327,12 @@ export class NativeEditor extends InteractiveBase implements INotebookEditor {
327327
return this.setDirty();
328328
}
329329

330-
protected addSysInfo(_reason: SysInfoReason): Promise<void> {
330+
protected addSysInfo(reason: SysInfoReason): Promise<void> {
331+
// We need to send a message when restarting
332+
if (reason === SysInfoReason.Restart || reason === SysInfoReason.New) {
333+
this.postMessage(InteractiveWindowMessages.RestartKernel).ignoreErrors();
334+
}
335+
331336
// These are not supported.
332337
return Promise.resolve();
333338
}
@@ -398,7 +403,7 @@ export class NativeEditor extends InteractiveBase implements INotebookEditor {
398403
}
399404
}
400405

401-
@captureTelemetry(Telemetry.ExecuteNativeCell, undefined, false)
406+
@captureTelemetry(Telemetry.ExecuteNativeCell, undefined, true)
402407
// tslint:disable-next-line:no-any
403408
protected async reexecuteCell(info: ISubmitNewCell): Promise<void> {
404409
try {
@@ -588,6 +593,9 @@ export class NativeEditor extends InteractiveBase implements INotebookEditor {
588593
// Then save the contents. We'll stick our cells back into this format when we save
589594
if (json) {
590595
this.notebookJson = json;
596+
597+
// Log language or kernel telemetry
598+
this.sendLanguageTelemetry(this.notebookJson);
591599
}
592600
this.contentsLoadedPromise.resolve();
593601

@@ -609,6 +617,27 @@ export class NativeEditor extends InteractiveBase implements INotebookEditor {
609617
);
610618
}
611619

620+
private sendLanguageTelemetry(notebookJson: Partial<nbformat.INotebookContent>) {
621+
try {
622+
// See if we have a language
623+
let language = '';
624+
if (notebookJson.metadata?.language_info?.name) {
625+
language = notebookJson.metadata?.language_info?.name;
626+
} else if (notebookJson.metadata?.kernelspec?.language) {
627+
language = notebookJson.metadata?.kernelspec?.language.toString();
628+
}
629+
if (language && !KnownNotebookLanguages.includes(language.toLowerCase())) {
630+
language = 'unknown';
631+
}
632+
if (language) {
633+
sendTelemetryEvent(Telemetry.NotebookLanguage, undefined, { language });
634+
}
635+
} catch {
636+
// If this fails, doesn't really matter
637+
noop();
638+
}
639+
}
640+
612641
private async loadCells(cells: ICell[], forceDirty: boolean): Promise<void> {
613642
// Make sure cells have at least 1
614643
if (cells.length === 0) {

0 commit comments

Comments
 (0)