Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build/ci/templates/globals.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ variables:
VSC_PYTHON_WEBVIEW_LOG_FILE: '$(Build.ArtifactStagingDirectory)/pvsc_webview.log'
CI_BRANCH_NAME: ${Build.SourceBranchName}
npm_config_cache: $(Pipeline.Workspace)/.npm
vmImageMacOS: 'macOS-10.15'
vmImageMacOS: 'macOS-latest'
TS_NODE_FILES: true # Temporarily enabled to allow using types from vscode.proposed.d.ts from ts-node (for tests).
1 change: 1 addition & 0 deletions news/1 Enhancements/14406.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Make data viewer openable from the variables window context menu while debugging.
17 changes: 17 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -927,6 +927,11 @@
"title": "DataScience.latestExtension",
"category": "Python"
},
{
"command": "python.datascience.showDataViewer",
"title": "%python.command.python.datascience.showDataViewer.title%",
"category": "Python"
},
{
"command": "python.analysis.restartLanguageServer",
"title": "%python.command.python.analysis.restartLanguageServer.title%",
Expand Down Expand Up @@ -1550,6 +1555,11 @@
"category": "Python",
"when": "false"
},
{
"command": "python.datascience.showDataViewer",
"category": "Python",
"when": "false"
},
{
"command": "python.datascience.export",
"title": "%DataScience.notebookExportAs%",
Expand Down Expand Up @@ -1655,6 +1665,13 @@
"when": "view == python_tests && viewItem == suite && !busyTests",
"group": "inline@0"
}
],
"debug/variables/context": [
{
"command": "python.datascience.showDataViewer",
"group": "1_view",
"when": "debugProtocolVariableMenuContext == 'viewableInDataViewer'"
}
]
},
"breakpoints": [
Expand Down
1 change: 1 addition & 0 deletions package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@
"Datascience.currentlySelectedJupyterInterpreterForPlaceholder": "current: {0}",
"python.command.python.analysis.clearCache.title": "Clear Module Analysis Cache",
"python.command.python.analysis.restartLanguageServer.title": "Restart Language Server",
"python.command.python.datascience.showDataViewer.title": "View Value in Data Viewer",
"python.snippet.launch.standard.label": "Python: Current File",
"python.snippet.launch.module.label": "Python: Module",
"python.snippet.launch.module.default": "enter-your-module-name",
Expand Down
2 changes: 2 additions & 0 deletions src/client/common/application/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import { CancellationToken, Position, TextDocument, Uri } from 'vscode';
import { Commands as LSCommands } from '../../activation/commands';
import { Commands as DSCommands } from '../../datascience/constants';
import { IShowDataViewerFromVariablePanel } from '../../datascience/interactive-common/interactiveWindowTypes';
import { KernelConnectionMetadata } from '../../datascience/jupyter/kernels/types';
import { INotebookModel, ISwitchKernelOptions } from '../../datascience/types';
import { PythonEnvironment } from '../../pythonEnvironments/info';
Expand Down Expand Up @@ -205,4 +206,5 @@ export interface ICommandNameArgumentTypeMapping extends ICommandNameWithoutArgu
[DSCommands.TrustNotebook]: [undefined | never | Uri];
[DSCommands.NotebookEditorExpandAllCells]: [];
[DSCommands.NotebookEditorCollapseAllCells]: [];
[DSCommands.ShowDataViewer]: [IShowDataViewerFromVariablePanel];
}
38 changes: 38 additions & 0 deletions src/client/datascience/commands/commandRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,28 @@

import { inject, injectable, multiInject, named, optional } from 'inversify';
import { CodeLens, ConfigurationTarget, env, Range, Uri } from 'vscode';
import { DebugProtocol } from 'vscode-debugprotocol';
import { ICommandNameArgumentTypeMapping } from '../../common/application/commands';
import { IApplicationShell, ICommandManager, IDebugService, IDocumentManager } from '../../common/application/types';
import { Commands as coreCommands } from '../../common/constants';
import { traceError } from '../../common/logger';

import { IStartPage } from '../../common/startPage/types';
import { IConfigurationService, IDisposable, IOutputChannel } from '../../common/types';
import { DataScience } from '../../common/utils/localize';
import { noop } from '../../common/utils/misc';
import { captureTelemetry, sendTelemetryEvent } from '../../telemetry';
import { Commands, JUPYTER_OUTPUT_CHANNEL, Telemetry } from '../constants';
import { IDataViewerFactory } from '../data-viewing/types';
import { DataViewerChecker } from '../interactive-common/dataViewerChecker';
import { IShowDataViewerFromVariablePanel } from '../interactive-common/interactiveWindowTypes';
import { convertDebugProtocolVariableToIJupyterVariable } from '../jupyter/debuggerVariables';
import {
ICodeWatcher,
IDataScienceCodeLensProvider,
IDataScienceCommandListener,
IDataScienceFileSystem,
IJupyterVariableDataProviderFactory,
INotebookEditorProvider
} from '../types';
import { JupyterCommandLineSelectorCommand } from './commandLineSelector';
Expand All @@ -30,6 +37,7 @@ import { JupyterServerSelectorCommand } from './serverSelector';
@injectable()
export class CommandRegistry implements IDisposable {
private readonly disposables: IDisposable[] = [];
private dataViewerChecker: DataViewerChecker;
constructor(
@inject(IDocumentManager) private documentManager: IDocumentManager,
@inject(IDataScienceCodeLensProvider) private dataScienceCodeLensProvider: IDataScienceCodeLensProvider,
Expand All @@ -48,10 +56,14 @@ export class CommandRegistry implements IDisposable {
@inject(IOutputChannel) @named(JUPYTER_OUTPUT_CHANNEL) private jupyterOutput: IOutputChannel,
@inject(IStartPage) private startPage: IStartPage,
@inject(ExportCommands) private readonly exportCommand: ExportCommands,
@inject(IJupyterVariableDataProviderFactory)
private readonly jupyterVariableDataProviderFactory: IJupyterVariableDataProviderFactory,
@inject(IDataViewerFactory) private readonly dataViewerFactory: IDataViewerFactory,
@inject(IDataScienceFileSystem) private readonly fs: IDataScienceFileSystem
) {
this.disposables.push(this.serverSelectedCommand);
this.disposables.push(this.notebookCommands);
this.dataViewerChecker = new DataViewerChecker(configService, appShell);
}
public register() {
this.commandLineCommand.register();
Expand Down Expand Up @@ -96,6 +108,7 @@ export class CommandRegistry implements IDisposable {
this.registerCommand(Commands.ViewJupyterOutput, this.viewJupyterOutput);
this.registerCommand(Commands.GatherQuality, this.reportGatherQuality);
this.registerCommand(Commands.LatestExtension, this.openPythonExtensionPage);
this.registerCommand(Commands.ShowDataViewer, this.onVariablePanelShowDataViewerRequest);
this.registerCommand(
Commands.EnableLoadingWidgetsFrom3rdPartySource,
this.enableLoadingWidgetScriptsFromThirdParty
Expand Down Expand Up @@ -466,4 +479,29 @@ export class CommandRegistry implements IDisposable {
private openPythonExtensionPage() {
env.openExternal(Uri.parse(`https://marketplace.visualstudio.com/items?itemName=ms-python.python`));
}

private async onVariablePanelShowDataViewerRequest(request: IShowDataViewerFromVariablePanel) {
sendTelemetryEvent(Telemetry.OpenDataViewerFromVariableWindowRequest);
if (this.debugService.activeDebugSession) {
const jupyterVariable = convertDebugProtocolVariableToIJupyterVariable(
request.variable as DebugProtocol.Variable
);
try {
const jupyterVariableDataProvider = await this.jupyterVariableDataProviderFactory.create(
jupyterVariable
);
const dataFrameInfo = await jupyterVariableDataProvider.getDataFrameInfo();
const columnSize = dataFrameInfo?.columns?.length;
if (columnSize && (await this.dataViewerChecker.isRequestedColumnSizeAllowed(columnSize))) {
const title: string = `${DataScience.dataExplorerTitle()} - ${jupyterVariable.name}`;
await this.dataViewerFactory.create(jupyterVariableDataProvider, title);
sendTelemetryEvent(Telemetry.OpenDataViewerFromVariableWindowSuccess);
}
} catch (e) {
sendTelemetryEvent(Telemetry.OpenDataViewerFromVariableWindowError);
traceError(e);
this.appShell.showErrorMessage(e.toString());
}
}
}
}
6 changes: 5 additions & 1 deletion src/client/datascience/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ export namespace Commands {
'python.datascience.enableLoadingWidgetScriptsFromThirdPartySource';
export const NotebookEditorExpandAllCells = 'python.datascience.notebookeditor.expandallcells';
export const NotebookEditorCollapseAllCells = 'python.datascience.notebookeditor.collapseallcells';
export const ShowDataViewer = 'python.datascience.showDataViewer';
}

export namespace CodeLensCommands {
Expand Down Expand Up @@ -409,7 +410,10 @@ export enum Telemetry {
TrustAllNotebooks = 'DATASCIENCE.TRUST_ALL_NOTEBOOKS',
TrustNotebook = 'DATASCIENCE.TRUST_NOTEBOOK',
DoNotTrustNotebook = 'DATASCIENCE.DO_NOT_TRUST_NOTEBOOK',
NotebookTrustPromptShown = 'DATASCIENCE.NOTEBOOK_TRUST_PROMPT_SHOWN'
NotebookTrustPromptShown = 'DATASCIENCE.NOTEBOOK_TRUST_PROMPT_SHOWN',
OpenDataViewerFromVariableWindowRequest = 'DATASCIENCE.OPEN_DATAVIEWER_FROM_VARIABLE_WINDOW_REQUEST',
OpenDataViewerFromVariableWindowError = 'DATASCIENCE.OPEN_DATAVIEWER_FROM_VARIABLE_WINDOW_ERROR',
OpenDataViewerFromVariableWindowSuccess = 'DATASCIENCE.OPEN_DATAVIEWER_FROM_VARIABLE_WINDOW_SUCCESS'
}

export enum NativeKeyboardCommandTelemetry {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,15 @@ export class JupyterVariableDataProvider implements IJupyterVariableDataProvider
return;
}

public setDependencies(variable: IJupyterVariable, notebook: INotebook): void {
public setDependencies(variable: IJupyterVariable, notebook?: INotebook): void {
this.notebook = notebook;
this.variable = variable;
}

public async getDataFrameInfo(): Promise<IDataFrameInfo> {
let dataFrameInfo: IDataFrameInfo = {};
await this.ensureInitialized();
if (this.variable && this.notebook) {
if (this.variable) {
dataFrameInfo = {
columns: this.variable.columns
? JupyterVariableDataProvider.getNormalizedColumns(this.variable.columns)
Expand All @@ -80,12 +80,12 @@ export class JupyterVariableDataProvider implements IJupyterVariableDataProvider
public async getAllRows() {
let allRows: IRowsResponse = [];
await this.ensureInitialized();
if (this.variable && this.variable.rowCount && this.notebook) {
if (this.variable && this.variable.rowCount) {
const dataFrameRows = await this.variableManager.getDataFrameRows(
this.variable,
this.notebook,
0,
this.variable.rowCount
this.variable.rowCount,
this.notebook
);
allRows = dataFrameRows && dataFrameRows.data ? (dataFrameRows.data as IRowsResponse) : [];
}
Expand All @@ -95,18 +95,18 @@ export class JupyterVariableDataProvider implements IJupyterVariableDataProvider
public async getRows(start: number, end: number) {
let rows: IRowsResponse = [];
await this.ensureInitialized();
if (this.variable && this.variable.rowCount && this.notebook) {
const dataFrameRows = await this.variableManager.getDataFrameRows(this.variable, this.notebook, start, end);
if (this.variable && this.variable.rowCount) {
const dataFrameRows = await this.variableManager.getDataFrameRows(this.variable, start, end, this.notebook);
rows = dataFrameRows && dataFrameRows.data ? (dataFrameRows.data as IRowsResponse) : [];
}
return rows;
}

private async ensureInitialized(): Promise<void> {
// Postpone pre-req and variable initialization until data is requested.
if (!this.initialized && this.variable && this.notebook) {
if (!this.initialized && this.variable) {
this.initialized = true;
await this.dependencyService.checkAndInstallMissingDependencies(this.notebook.getMatchingInterpreter());
await this.dependencyService.checkAndInstallMissingDependencies(this.notebook?.getMatchingInterpreter());
this.variable = await this.variableManager.getDataFrameInfo(this.variable, this.notebook);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
export class JupyterVariableDataProviderFactory implements IJupyterVariableDataProviderFactory {
constructor(@inject(IServiceContainer) private serviceContainer: IServiceContainer) {}

public async create(variable: IJupyterVariable, notebook: INotebook): Promise<IJupyterVariableDataProvider> {
public async create(variable: IJupyterVariable, notebook?: INotebook): Promise<IJupyterVariableDataProvider> {
const jupyterVariableDataProvider = this.serviceContainer.get<IJupyterVariableDataProvider>(
IJupyterVariableDataProvider
);
Expand Down
Loading