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
1 change: 1 addition & 0 deletions news/2 Fixes/10206.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix interactive window debugging after running cells in a notebook.
1 change: 1 addition & 0 deletions news/2 Fixes/10395.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix interactive window debugging when debugging the first cell to be run.
1 change: 1 addition & 0 deletions news/2 Fixes/10396.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix interactive window debugging for extra lines in a function.
24 changes: 18 additions & 6 deletions src/client/datascience/editor-integration/cellhashprovider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ export class CellHashProvider implements ICellHashProvider, IInteractiveWindowLi
return lines;
}

// tslint:disable-next-line: cyclomatic-complexity
public async addCellHash(cell: ICell, expectedCount: number): Promise<void> {
// Find the text document that matches. We need more information than
// the add code gives us
Expand Down Expand Up @@ -163,14 +164,25 @@ export class CellHashProvider implements ICellHashProvider, IInteractiveWindowLi
const endOffset = doc.offsetAt(endLine.rangeIncludingLineBreak.end);

// Jupyter also removes blank lines at the end. Make sure only one
let lastLine = stripped[stripped.length - 1];
while (lastLine !== undefined && (lastLine.length === 0 || lastLine === '\n')) {
stripped.splice(stripped.length - 1, 1);
lastLine = stripped[stripped.length - 1];
let lastLinePos = stripped.length - 1;
let nextToLastLinePos = stripped.length - 2;
while (nextToLastLinePos > 0) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fixes #10396

const lastLine = stripped[lastLinePos];
const nextToLastLine = stripped[nextToLastLinePos];
if (
(lastLine.length === 0 || lastLine === '\n') &&
(nextToLastLine.length === 0 || nextToLastLine === '\n')
) {
stripped.splice(lastLinePos, 1);
lastLinePos -= 1;
nextToLastLinePos -= 1;
} else {
break;
}
}
// Make sure the last line with actual content ends with a linefeed
if (!lastLine.endsWith('\n') && lastLine.length > 0) {
stripped[stripped.length - 1] = `${lastLine}\n`;
if (!stripped[lastLinePos].endsWith('\n') && stripped[lastLinePos].length > 0) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the only fix I can see, rest look like refactoring.

stripped[lastLinePos] = `${stripped[lastLinePos]}\n`;
}

// Compute the runtime line and adjust our cell/stripped source for debugging
Expand Down
4 changes: 2 additions & 2 deletions src/client/datascience/interactive-common/interactiveBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1159,11 +1159,11 @@ export abstract class InteractiveBase extends WebViewHost<IInteractiveWindowMapp
// Create a new notebook if we need to.
if (!this._notebook) {
// While waiting make the notebook look busy
await this.postMessage(InteractiveWindowMessages.UpdateKernel, {
this.postMessage(InteractiveWindowMessages.UpdateKernel, {
jupyterServerStatus: ServerStatus.Busy,
localizedUri: this.getServerUri(server),
displayName: ''
});
}).ignoreErrors();

this._notebook = await this.createNotebook(server);

Expand Down
34 changes: 19 additions & 15 deletions src/client/datascience/interactive-window/interactiveWindow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,20 +181,7 @@ export class InteractiveWindow extends InteractiveBase implements IInteractiveWi
}

public async addCode(code: string, file: string, line: number): Promise<boolean> {
if (this.lastFile && !this.fileSystem.arePathsSame(file, this.lastFile)) {
sendTelemetryEvent(Telemetry.NewFileForInteractiveWindow);
}
// Save the last file we ran with.
this.lastFile = file;

// Make sure our web panel opens.
await this.show();

// Tell the webpanel about the new directory.
this.updateCwd(path.dirname(file));

// Call the internal method.
return this.submitCode(code, file, line);
return this.addOrDebugCode(code, file, line, false);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addOrDebugCode [](start = 20, length = 14)

This fixes #10395 because it 'waits' for the window to show before adding the code.

}

public exportCells() {
Expand Down Expand Up @@ -252,7 +239,7 @@ export class InteractiveWindow extends InteractiveBase implements IInteractiveWi

// Call the internal method if we were able to save
if (saved) {
return this.submitCode(code, file, line, undefined, undefined, true);
return this.addOrDebugCode(code, file, line, true);
}

return false;
Expand Down Expand Up @@ -365,6 +352,23 @@ export class InteractiveWindow extends InteractiveBase implements IInteractiveWi
return super.ensureServerAndNotebook();
}

private async addOrDebugCode(code: string, file: string, line: number, debug: boolean): Promise<boolean> {
if (this.lastFile && !this.fileSystem.arePathsSame(file, this.lastFile)) {
sendTelemetryEvent(Telemetry.NewFileForInteractiveWindow);
}
// Save the last file we ran with.
this.lastFile = file;

// Make sure our web panel opens.
await this.show();

// Tell the webpanel about the new directory.
this.updateCwd(path.dirname(file));

// Call the internal method.
return this.submitCode(code, file, line, undefined, undefined, debug);
}

@captureTelemetry(Telemetry.ExportNotebook, undefined, false)
// tslint:disable-next-line: no-any no-empty
private async export(cells: ICell[]) {
Expand Down
10 changes: 4 additions & 6 deletions src/client/datascience/jupyter/jupyterNotebook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,6 @@ export class JupyterNotebookBase implements INotebook {
private _identity: Uri;
private _disposed: boolean = false;
private _workingDirectory: string | undefined;
private _loggers: INotebookExecutionLogger[] = [];
private onStatusChangedEvent: EventEmitter<ServerStatus> | undefined;
public get onKernelChanged(): Event<IJupyterKernelSpec | LiveKernelModel> {
return this.kernelChanged.event;
Expand All @@ -170,7 +169,7 @@ export class JupyterNotebookBase implements INotebook {
private disposableRegistry: IDisposableRegistry,
private owner: INotebookServer,
private launchInfo: INotebookServerLaunchInfo,
loggers: INotebookExecutionLogger[],
private loggers: INotebookExecutionLogger[],
resource: Resource,
identity: Uri,
private getDisposedError: () => Error,
Expand All @@ -188,7 +187,6 @@ export class JupyterNotebookBase implements INotebook {
this.sessionStatusChanged = this.session.onSessionStatusChanged(statusChangeHandler);
this._identity = identity;
this._resource = resource;
this._loggers = [...loggers];
// Save our interpreter and don't change it. Later on when kernel changes
// are possible, recompute it.
}
Expand Down Expand Up @@ -617,7 +615,7 @@ export class JupyterNotebookBase implements INotebook {
}

public getLoggers(): INotebookExecutionLogger[] {
return this._loggers;
return this.loggers;
}

private async initializeMatplotlib(cancelToken?: CancellationToken): Promise<void> {
Expand Down Expand Up @@ -1051,11 +1049,11 @@ export class JupyterNotebookBase implements INotebook {
}

private async logPreCode(cell: ICell, silent: boolean): Promise<void> {
await Promise.all(this._loggers.map(l => l.preExecute(cell, silent)));
await Promise.all(this.loggers.map(l => l.preExecute(cell, silent)));
}

private async logPostCode(cell: ICell, silent: boolean): Promise<void> {
await Promise.all(this._loggers.map(l => l.postExecute(cloneDeep(cell), silent)));
await Promise.all(this.loggers.map(l => l.postExecute(cloneDeep(cell), silent)));
}

private addToCellData = (
Expand Down
8 changes: 4 additions & 4 deletions src/client/datascience/jupyter/jupyterServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ import {
import { createDeferred, Deferred } from '../../common/utils/async';
import * as localize from '../../common/utils/localize';
import { noop } from '../../common/utils/misc';
import { IServiceContainer } from '../../ioc/types';
import {
IConnection,
IJupyterSession,
IJupyterSessionManager,
IJupyterSessionManagerFactory,
INotebook,
INotebookExecutionLogger,
INotebookServer,
INotebookServerLaunchInfo
} from '../types';
Expand All @@ -48,7 +48,7 @@ export class JupyterServerBase implements INotebookServer {
private disposableRegistry: IDisposableRegistry,
protected readonly configService: IConfigurationService,
private sessionManagerFactory: IJupyterSessionManagerFactory,
private loggers: INotebookExecutionLogger[],
private serviceContainer: IServiceContainer,
private jupyterOutputChannel: IOutputChannel
) {
this.asyncRegistry.push(this);
Expand Down Expand Up @@ -115,7 +115,7 @@ export class JupyterServerBase implements INotebookServer {
savedSession,
this.disposableRegistry,
this.configService,
this.loggers,
this.serviceContainer,
notebookMetadata,
cancelToken
).then(r => {
Expand Down Expand Up @@ -223,7 +223,7 @@ export class JupyterServerBase implements INotebookServer {
_savedSession: IJupyterSession | undefined,
_disposableRegistry: IDisposableRegistry,
_configService: IConfigurationService,
_loggers: INotebookExecutionLogger[],
_serviceContainer: IServiceContainer,
_notebookMetadata?: nbformat.INotebookMetadata,
_cancelToken?: CancellationToken
): Promise<INotebook> {
Expand Down
12 changes: 6 additions & 6 deletions src/client/datascience/jupyter/jupyterServerWrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Licensed under the MIT License.
'use strict';
import { nbformat } from '@jupyterlab/coreutils';
import { inject, injectable, multiInject, named, optional } from 'inversify';
import { inject, injectable, named } from 'inversify';
import * as uuid from 'uuid/v4';
import { Uri } from 'vscode';
import { CancellationToken } from 'vscode-jsonrpc';
Expand All @@ -18,13 +18,13 @@ import {
Resource
} from '../../common/types';
import { IInterpreterService } from '../../interpreter/contracts';
import { IServiceContainer } from '../../ioc/types';
import { JUPYTER_OUTPUT_CHANNEL } from '../constants';
import {
IConnection,
IDataScience,
IJupyterSessionManagerFactory,
INotebook,
INotebookExecutionLogger,
INotebookServer,
INotebookServerLaunchInfo
} from '../types';
Expand All @@ -46,7 +46,7 @@ type JupyterServerClassType = {
configService: IConfigurationService,
sessionManager: IJupyterSessionManagerFactory,
workspaceService: IWorkspaceService,
loggers: INotebookExecutionLogger[],
serviceContainer: IServiceContainer,
appShell: IApplicationShell,
fs: IFileSystem,
kernelSelector: KernelSelector,
Expand All @@ -73,12 +73,12 @@ export class JupyterServerWrapper implements INotebookServer, ILiveShareHasRole
@inject(IConfigurationService) configService: IConfigurationService,
@inject(IJupyterSessionManagerFactory) sessionManager: IJupyterSessionManagerFactory,
@inject(IWorkspaceService) workspaceService: IWorkspaceService,
@multiInject(INotebookExecutionLogger) @optional() loggers: INotebookExecutionLogger[] | undefined,
@inject(IApplicationShell) appShell: IApplicationShell,
@inject(IFileSystem) fs: IFileSystem,
@inject(IInterpreterService) interpreterService: IInterpreterService,
@inject(KernelSelector) kernelSelector: KernelSelector,
@inject(IOutputChannel) @named(JUPYTER_OUTPUT_CHANNEL) jupyterOutput: IOutputChannel
@inject(IOutputChannel) @named(JUPYTER_OUTPUT_CHANNEL) jupyterOutput: IOutputChannel,
@inject(IServiceContainer) serviceContainer: IServiceContainer
) {
// The server factory will create the appropriate HostJupyterServer or GuestJupyterServer based on
// the liveshare state.
Expand All @@ -93,7 +93,7 @@ export class JupyterServerWrapper implements INotebookServer, ILiveShareHasRole
configService,
sessionManager,
workspaceService,
loggers ? loggers : [],
serviceContainer,
appShell,
fs,
kernelSelector,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ import { ILiveShareApi, IWorkspaceService } from '../../../common/application/ty
import { IAsyncDisposableRegistry, IConfigurationService, IDisposableRegistry, Resource } from '../../../common/types';
import { createDeferred, Deferred } from '../../../common/utils/async';
import * as localize from '../../../common/utils/localize';
import { IServiceContainer } from '../../../ioc/types';
import { LiveShare, LiveShareCommands } from '../../constants';
import {
IConnection,
IDataScience,
IJupyterSessionManagerFactory,
INotebook,
INotebookExecutionLogger,
INotebookServer,
INotebookServerLaunchInfo
} from '../../types';
Expand All @@ -39,7 +39,7 @@ export class GuestJupyterServer
private configService: IConfigurationService,
_sessionManager: IJupyterSessionManagerFactory,
_workspaceService: IWorkspaceService,
_loggers: INotebookExecutionLogger[]
_serviceContainer: IServiceContainer
) {
super(liveShare);
}
Expand Down
17 changes: 13 additions & 4 deletions src/client/datascience/jupyter/liveshare/hostJupyterServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
} from '../../../common/types';
import * as localize from '../../../common/utils/localize';
import { IInterpreterService } from '../../../interpreter/contracts';
import { IServiceContainer } from '../../../ioc/types';
import { Identifiers, LiveShare, LiveShareCommands, RegExpValues } from '../../constants';
import {
IDataScience,
Expand Down Expand Up @@ -55,14 +56,22 @@ export class HostJupyterServer extends LiveShareParticipantHost(JupyterServerBas
configService: IConfigurationService,
sessionManager: IJupyterSessionManagerFactory,
private workspaceService: IWorkspaceService,
loggers: INotebookExecutionLogger[],
serviceContainer: IServiceContainer,
private appService: IApplicationShell,
private fs: IFileSystem,
private readonly kernelSelector: KernelSelector,
private readonly interpreterService: IInterpreterService,
outputChannel: IOutputChannel
) {
super(liveShare, asyncRegistry, disposableRegistry, configService, sessionManager, loggers, outputChannel);
super(
liveShare,
asyncRegistry,
disposableRegistry,
configService,
sessionManager,
serviceContainer,
outputChannel
);
}

public async dispose(): Promise<void> {
Expand Down Expand Up @@ -163,7 +172,7 @@ export class HostJupyterServer extends LiveShareParticipantHost(JupyterServerBas
possibleSession: IJupyterSession | undefined,
disposableRegistry: IDisposableRegistry,
configService: IConfigurationService,
loggers: INotebookExecutionLogger[],
serviceContainer: IServiceContainer,
notebookMetadata?: nbformat.INotebookMetadata,
cancelToken?: CancellationToken
): Promise<INotebook> {
Expand Down Expand Up @@ -208,7 +217,7 @@ export class HostJupyterServer extends LiveShareParticipantHost(JupyterServerBas
disposableRegistry,
this,
info,
loggers,
serviceContainer.getAll<INotebookExecutionLogger>(INotebookExecutionLogger),
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getAll [](start = 33, length = 6)

This fixes #10206 because it generates new loggers for each notebook instead of having a single set for all.

Copy link

@DonJayamanne DonJayamanne Mar 14, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This helps a lot, eg. tomorrow one can look at a PR and understand the need for the change.. (e.g. it wasn't obvious to me). Thanks

resource,
identity,
this.getDisposedError.bind(this),
Expand Down