-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Update gather functionality to support 0.4.1 of python-program-analysis #8219
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 44 commits
704135a
d803bdb
ed0ebd2
dfc4319
a807f70
6b4e1ea
b827c1a
30f1fcc
338361f
af781c1
4e2d305
4a01d0a
7b13a51
839a75d
0e1b8fc
a0094e5
03df1b0
b58fe0e
c96acd6
643e17c
6a3ca5a
5039dee
17001d6
9282b31
2f0b7a7
92ac7f9
dbfacb3
6cedfde
d9696d6
b2ee0ca
d11f679
db2600f
d33ae55
ff1a43d
0dc45b2
b380304
549d4d1
7bc674c
c5eb676
19fe23e
6d92142
0bfb438
361bd23
27c79c2
21eed9d
38aea3c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,29 +1,22 @@ | ||
import { DataflowAnalyzer } from '@msrvida/python-program-analysis'; | ||
import { Cell as ICell, LogCell } from '@msrvida/python-program-analysis/dist/es5/cell'; | ||
import { CellSlice } from '@msrvida/python-program-analysis/dist/es5/cellslice'; | ||
import { ExecutionLogSlicer } from '@msrvida/python-program-analysis/dist/es5/log-slicer'; | ||
import { CellSlice, DataflowAnalyzer, ExecutionLogSlicer } from '@msrvida/python-program-analysis'; | ||
import { Cell as IGatherCell } from '@msrvida/python-program-analysis/dist/es5/cell'; | ||
|
||
import { inject, injectable } from 'inversify'; | ||
// tslint:disable-next-line: no-require-imports | ||
import cloneDeep = require('lodash/cloneDeep'); | ||
import { IApplicationShell, ICommandManager } from '../../common/application/types'; | ||
import { traceInfo } from '../../common/logger'; | ||
import { IConfigurationService, IDisposableRegistry } from '../../common/types'; | ||
import * as localize from '../../common/utils/localize'; | ||
// tslint:disable-next-line: no-duplicate-imports | ||
import { Common } from '../../common/utils/localize'; | ||
import { noop } from '../../common/utils/misc'; | ||
import { CellMatcher } from '../cellMatcher'; | ||
import { concatMultilineStringInput } from '../common'; | ||
import { Identifiers } from '../constants'; | ||
import { CellState, ICell as IVscCell, IGatherExecution, INotebookExecutionLogger } from '../types'; | ||
import { CellState, ICell as IVscCell, IGatherExecution } from '../types'; | ||
|
||
/** | ||
* An adapter class to wrap the code gathering functionality from [microsoft/python-program-analysis](https://www.npmjs.com/package/@msrvida/python-program-analysis). | ||
*/ | ||
@injectable() | ||
export class GatherExecution implements IGatherExecution, INotebookExecutionLogger { | ||
private _executionSlicer: ExecutionLogSlicer; | ||
export class GatherExecution implements IGatherExecution { | ||
private _executionSlicer: ExecutionLogSlicer<IGatherCell>; | ||
private dataflowAnalyzer: DataflowAnalyzer; | ||
private _enabled: boolean; | ||
|
||
|
@@ -44,52 +37,36 @@ export class GatherExecution implements IGatherExecution, INotebookExecutionLogg | |
|
||
traceInfo('Gathering tools have been activated'); | ||
} | ||
public logExecution(vscCell: IVscCell): void { | ||
const gatherCell = convertVscToGatherCell(vscCell); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So I'm a bit nervous that we lost our cloneDeep here. Technically convert should not change the vscCell, but I'm worried someone else might tweak it. Was it a perf issue? #ByDesign There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Talked with Rich, we'll take care of this before calling postExecute, so disregard this. In reply to: 342290179 [](ancestors = 342290179) |
||
|
||
public async preExecute(_vscCell: IVscCell, _silent: boolean): Promise<void> { | ||
// This function is just implemented here for compliance with the INotebookExecutionLogger interface | ||
noop(); | ||
if (gatherCell) { | ||
this._executionSlicer.logExecution(gatherCell); | ||
} | ||
} | ||
|
||
public async postExecute(vscCell: IVscCell, _silent: boolean): Promise<void> { | ||
if (this._enabled) { | ||
// Don't log if vscCell.data.source is an empty string or if it was | ||
// silently executed. Original Jupyter extension also does this. | ||
if (vscCell.data.source !== '' && !_silent) { | ||
// First make a copy of this cell, as we are going to modify it | ||
const cloneCell: IVscCell = cloneDeep(vscCell); | ||
|
||
// Strip first line marker. We can't do this at JupyterServer.executeCodeObservable because it messes up hashing | ||
const cellMatcher = new CellMatcher(this.configService.getSettings().datascience); | ||
cloneCell.data.source = cellMatcher.stripFirstMarker(concatMultilineStringInput(vscCell.data.source)); | ||
|
||
// Convert IVscCell to IGatherCell | ||
const cell = convertVscToGatherCell(cloneCell) as LogCell; | ||
|
||
// Call internal logging method | ||
this._executionSlicer.logExecution(cell); | ||
} | ||
} | ||
public async resetLog(): Promise<void> { | ||
this._executionSlicer.reset(); | ||
} | ||
|
||
/** | ||
* For a given code cell, returns a string representing a program containing all the code it depends on. | ||
*/ | ||
public gatherCode(vscCell: IVscCell): string { | ||
// sliceAllExecutions does a lookup based on executionEventId | ||
const cell = convertVscToGatherCell(vscCell); | ||
if (cell === undefined) { | ||
const gatherCell = convertVscToGatherCell(vscCell); | ||
if (!gatherCell) { | ||
return ''; | ||
} | ||
|
||
// Get the default cell marker as we need to replace #%% with it. | ||
const defaultCellMarker = this.configService.getSettings().datascience.defaultCellMarker || Identifiers.DefaultCodeCellMarker; | ||
|
||
// Call internal slice method | ||
const slices = this._executionSlicer.sliceAllExecutions(cell); | ||
const slices = this._executionSlicer.sliceAllExecutions(gatherCell.persistentId); | ||
const program = slices.length > 0 ? slices[0].cellSlices.reduce(concat, '').replace(/#%%/g, defaultCellMarker) : ''; | ||
|
||
// Add a comment at the top of the file explaining what gather does | ||
const descriptor = '# This file contains the minimal amount of code required to produce the code cell you gathered.\n'; | ||
const descriptor = localize.DataScience.gatheredScriptDescription(); | ||
return descriptor.concat(program); | ||
} | ||
|
||
|
@@ -122,7 +99,7 @@ export class GatherExecution implements IGatherExecution, INotebookExecutionLogg | |
/** | ||
* Accumulator to concatenate cell slices for a sliced program, preserving cell structures. | ||
*/ | ||
function concat(existingText: string, newText: CellSlice) { | ||
function concat(existingText: string, newText: CellSlice): string { | ||
// Include our cell marker so that cell slices are preserved | ||
return `${existingText}#%%\n${newText.textSliceLines}\n\n`; | ||
} | ||
|
@@ -131,14 +108,11 @@ function concat(existingText: string, newText: CellSlice) { | |
* This is called to convert VS Code ICells to Gather ICells for logging. | ||
* @param cell A cell object conforming to the VS Code cell interface | ||
*/ | ||
function convertVscToGatherCell(cell: IVscCell): ICell | undefined { | ||
function convertVscToGatherCell(cell: IVscCell): IGatherCell | undefined { | ||
// This should always be true since we only want to log code cells. Putting this here so types match for outputs property | ||
if (cell.data.cell_type === 'code') { | ||
const result: ICell = { | ||
const result: IGatherCell = { | ||
// tslint:disable-next-line no-unnecessary-local-variable | ||
id: cell.id, | ||
gathered: false, | ||
dirty: false, | ||
text: cell.data.source, | ||
|
||
// This may need to change for native notebook support since in the original Gather code this refers to the number of times that this same cell was executed | ||
|
@@ -147,9 +121,7 @@ function convertVscToGatherCell(cell: IVscCell): ICell | undefined { | |
|
||
// This may need to change for native notebook support, since this is intended to persist in the metadata for a notebook that is saved and then re-loaded | ||
persistentId: cell.id, | ||
outputs: cell.data.outputs, | ||
hasError: cell.state === CellState.error, | ||
is_cell: true | ||
hasError: cell.state === CellState.error | ||
// tslint:disable-next-line: no-any | ||
} as any; | ||
return result; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems weird. Why not just always open a notebook if coming from a notebook and always open a file if coming from a file? For interactive window users, they'd never find this command and would be put off by us opening a notebook