Skip to content

Commit cb64ab2

Browse files
Check vars on execution count (microsoft#5214)
1 parent a7e9586 commit cb64ab2

File tree

9 files changed

+53
-32
lines changed

9 files changed

+53
-32
lines changed

news/1 Enhancements/4948.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Variable explorer handles new cell submissions

pythonFiles/datascience/getJupyterVariableList.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@
1212
print(_VSCODE_json.dumps([{'name': var,
1313
'type': type(eval(var)).__name__,
1414
'size': _VSCODE_getsizeof(var),
15-
'supportsDataExplorer': type(eval(var)).__name__ in _VSCode_supportsDataExplorer,
16-
'expensive': True
15+
'supportsDataExplorer': type(eval(var)).__name__ in _VSCode_supportsDataExplorer
1716
} for var in _VSCode_JupyterVars]))
1817

1918
del _VSCode_supportsDataExplorer

src/client/datascience/history/history.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ export class History extends WebViewHost<IHistoryMapping> implements IHistory {
228228
break;
229229

230230
case HistoryMessages.GetVariablesRequest:
231-
this.requestVariables().ignoreErrors();
231+
this.requestVariables(payload).ignoreErrors();
232232
break;
233233

234234
case HistoryMessages.GetVariableValueRequest:
@@ -918,10 +918,15 @@ export class History extends WebViewHost<IHistoryMapping> implements IHistory {
918918
}
919919
}
920920

921-
private requestVariables = async (): Promise<void> => {
921+
private requestVariables = async (executionCount: number): Promise<void> => {
922922
// Request our new list of variables
923923
let vars: IJupyterVariable[] = await this.jupyterVariables.getVariables();
924924

925+
// Tag all of our jupyter variables with the execution count of the request
926+
vars.forEach((value: IJupyterVariable) => {
927+
value.executionCount = executionCount;
928+
});
929+
925930
const settings = this.configuration.getSettings();
926931
const excludeString = settings.datascience.variableExplorerExclude;
927932

src/client/datascience/history/historyTypes.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ export class IHistoryMapping {
9696
public [HistoryMessages.RemoteAddCode]: IRemoteAddCode;
9797
public [HistoryMessages.Activate] : never | undefined;
9898
public [HistoryMessages.ShowDataViewer]: string;
99-
public [HistoryMessages.GetVariablesRequest]: never | undefined;
99+
public [HistoryMessages.GetVariablesRequest]: number;
100100
public [HistoryMessages.GetVariablesResponse]: IJupyterVariable[];
101101
public [HistoryMessages.GetVariableValueRequest]: IJupyterVariable;
102102
public [HistoryMessages.GetVariableValueResponse]: IJupyterVariable;

src/client/datascience/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,13 +262,13 @@ export interface IDataScienceExtraSettings extends IDataScienceSettings {
262262
export interface IJupyterVariable {
263263
name: string;
264264
value: string | undefined;
265+
executionCount?: number;
265266
supportsDataExplorer: boolean;
266267
type: string;
267268
size: number;
268269
shape: string;
269270
count: number;
270271
truncated: boolean;
271-
expensive: boolean;
272272
columns?: { key: string; type: string }[];
273273
rowCount?: number;
274274
}

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

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export class MainPanel extends React.Component<IMainPanelProps, IMainPanelState>
3535
private mainPanel: HTMLDivElement | null = null;
3636
private variableExplorerRef: React.RefObject<VariableExplorer>;
3737
private styleInjectorRef: React.RefObject<StyleInjector>;
38+
private currentExecutionCount: number = 0;
3839

3940
// tslint:disable-next-line:max-func-body-length
4041
constructor(props: IMainPanelProps, _state: IMainPanelState) {
@@ -667,8 +668,12 @@ export class MainPanel extends React.Component<IMainPanelProps, IMainPanelState>
667668
}
668669
}
669670

671+
// After the cell is finished update our current execution count
672+
this.currentExecutionCount = this.getCurrentExecutionCount(this.state.cellVMs);
673+
670674
// When a cell is finished refresh our variables
671-
if (getSettings && getSettings().showJupyterVariableExplorer) {
675+
// Use the ref here to maintain var explorer independence
676+
if (this.variableExplorerRef.current && this.variableExplorerRef.current.state.open) {
672677
this.refreshVariables();
673678
}
674679
}
@@ -693,9 +698,14 @@ export class MainPanel extends React.Component<IMainPanelProps, IMainPanelState>
693698
}
694699
}
695700

696-
private getInputExecutionCount(cellVMs: ICellViewModel[]) : number {
701+
// Check our list of cell vms to see what our current execution count is
702+
private getCurrentExecutionCount = (cellVMs: ICellViewModel[]): number => {
697703
const realCells = cellVMs.filter(c => c.cell.data.cell_type === 'code' && !c.editable && c.cell.data.execution_count);
698-
return realCells && realCells.length > 0 ? parseInt(realCells[realCells.length - 1].cell.data.execution_count!.toString(), 10) + 1 : 1;
704+
return realCells && realCells.length > 0 ? parseInt(realCells[realCells.length - 1].cell.data.execution_count!.toString(), 10) : 0;
705+
}
706+
707+
private getInputExecutionCount = (cellVMs: ICellViewModel[]) : number => {
708+
return this.getCurrentExecutionCount(cellVMs) + 1;
699709
}
700710

701711
private submitInput = (code: string) => {
@@ -747,7 +757,7 @@ export class MainPanel extends React.Component<IMainPanelProps, IMainPanelState>
747757

748758
// When the variable explorer wants to refresh state (say if it was expanded)
749759
private refreshVariables = () => {
750-
this.sendMessage(HistoryMessages.GetVariablesRequest);
760+
this.sendMessage(HistoryMessages.GetVariablesRequest, this.currentExecutionCount);
751761
}
752762

753763
// Find the display value for one specific variable
@@ -761,8 +771,11 @@ export class MainPanel extends React.Component<IMainPanelProps, IMainPanelState>
761771
if (payload) {
762772
const variable = payload as IJupyterVariable;
763773

764-
if (this.variableExplorerRef.current) {
765-
this.variableExplorerRef.current.newVariableData(variable);
774+
// Only send the updated variable data if we are on the same execution count as when we requsted it
775+
if (variable && variable.executionCount !== undefined && variable.executionCount === this.currentExecutionCount) {
776+
if (this.variableExplorerRef.current) {
777+
this.variableExplorerRef.current.newVariableData(variable);
778+
}
766779
}
767780
}
768781
}
@@ -773,12 +786,15 @@ export class MainPanel extends React.Component<IMainPanelProps, IMainPanelState>
773786
if (payload) {
774787
const variables = payload as IJupyterVariable[];
775788

776-
if (this.variableExplorerRef.current) {
777-
this.variableExplorerRef.current.newVariablesData(variables);
778-
}
789+
// Check to see if we have moved to a new execution count only send our update if we are on the same count as the request
790+
if (variables.length > 0 && variables[0].executionCount !== undefined && variables[0].executionCount === this.currentExecutionCount) {
791+
if (this.variableExplorerRef.current) {
792+
this.variableExplorerRef.current.newVariablesData(variables);
793+
}
779794

780-
// Now put out a request for all of the sub values for the variables
781-
variables.forEach(this.refreshVariable);
795+
// Now put out a request for all of the sub values for the variables
796+
variables.forEach(this.refreshVariable);
797+
}
782798
}
783799
}
784800
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ export class VariableExplorer extends React.Component<IVariableExplorerProps, IV
5454
{key: 'type', name: getLocString('DataScience.variableExplorerTypeColumn', 'Type'), type: 'string', width: 120},
5555
{key: 'size', name: getLocString('DataScience.variableExplorerSizeColumn', 'Size'), type: 'number', width: 120, formatter: <VariableExplorerCellFormatter cellStyle={CellStyle.numeric} />},
5656
{key: 'value', name: getLocString('DataScience.variableExplorerValueColumn', 'Value'), type: 'string', width: 300},
57-
{key: 'buttons', name: '', type: 'boolean', width: 32, formatter: <VariableExplorerButtonCellFormatter showDataExplorer={this.props.showDataExplorer} baseTheme={this.props.baseTheme} /> }
57+
{key: 'buttons', name: '', type: 'boolean', width: 34, formatter: <VariableExplorerButtonCellFormatter showDataExplorer={this.props.showDataExplorer} baseTheme={this.props.baseTheme} /> }
5858
];
5959
this.state = { open: false,
6060
gridColumns: columns,

src/datascience-ui/history-react/variableExplorerGrid.scss

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@
3636
#variable-explorer-data-grid .react-grid-HeaderCell {
3737
background-color: var(--vscode-editor-lineHighlightBorder);
3838
color: var(--vscode-editor-foreground);
39-
border-style: none none solid none;
40-
border-bottom-color: var(--vscode-badge-background);
41-
padding: 4px;
39+
border-style: solid;
40+
border-color: var(--vscode-badge-background);
41+
padding: 2px;
4242
}
4343

4444

src/test/datascience/jupyterVariables.unit.test.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ suite('JupyterVariables', () => {
7575

7676
fakeServer.setup(fs => fs.execute(typemoq.It.isAny(), typemoq.It.isAny(), typemoq.It.isAny(), typemoq.It.isAny(), undefined, typemoq.It.isAny()))
7777
.returns(() => Promise.resolve(generateCells(
78-
'[{"name": "big_dataframe", "type": "DataFrame", "size": 62, "expensive": true}, {"name": "big_dict", "type": "dict", "size": 57, "expensive": true}, {"name": "big_float", "type": "float", "size": 58, "expensive": true}, {"name": "big_int", "type": "int", "size": 56, "expensive": true}, {"name": "big_list", "type": "list", "size": 57, "expensive": true}, {"name": "big_nparray", "type": "ndarray", "size": 60, "expensive": true}, {"name": "big_series", "type": "Series", "size": 59, "expensive": true}, {"name": "big_string", "type": "str", "size": 59, "expensive": true}, {"name": "big_tuple", "type": "tuple", "size": 58, "expensive": true}]',
78+
'[{"name": "big_dataframe", "type": "DataFrame", "size": 62}, {"name": "big_dict", "type": "dict", "size": 57}, {"name": "big_float", "type": "float", "size": 58}, {"name": "big_int", "type": "int", "size": 56}, {"name": "big_list", "type": "list", "size": 57}, {"name": "big_nparray", "type": "ndarray", "size": 60}, {"name": "big_series", "type": "Series", "size": 59}, {"name": "big_string", "type": "str", "size": 59}, {"name": "big_tuple", "type": "tuple", "size": 58]',
7979
'stream'
8080
)))
8181
.verifiable(typemoq.Times.never());
@@ -157,7 +157,7 @@ suite('JupyterVariables', () => {
157157

158158
fakeServer.setup(fs => fs.execute(typemoq.It.isValue('test'), typemoq.It.isValue(Identifiers.EmptyFileName), typemoq.It.isValue(0), typemoq.It.isAnyString(), undefined, typemoq.It.isValue(true)))
159159
.returns(() => Promise.resolve(generateCells(
160-
'[{"name": "big_dataframe", "type": "DataFrame", "size": 62, "expensive": true}, {"name": "big_dict", "type": "dict", "size": 57, "expensive": true}, {"name": "big_int", "type": "int", "size": 56, "expensive": true}, {"name": "big_list", "type": "list", "size": 57, "expensive": true}, {"name": "big_nparray", "type": "ndarray", "size": 60, "expensive": true}, {"name": "big_string", "type": "str", "size": 59, "expensive": true}]',
160+
'[{"name": "big_dataframe", "type": "DataFrame", "size": 62}, {"name": "big_dict", "type": "dict", "size": 57}, {"name": "big_int", "type": "int", "size": 56}, {"name": "big_list", "type": "list", "size": 57}, {"name": "big_nparray", "type": "ndarray", "size": 60}, {"name": "big_string", "type": "str", "size": 59}]',
161161
'stream'
162162
)))
163163
.verifiable(typemoq.Times.once());
@@ -168,12 +168,12 @@ suite('JupyterVariables', () => {
168168
assert.equal(results.length, 6);
169169

170170
// Check our items (just the first few real items, no need to check all 19)
171-
assert.deepEqual(results[0], {name: 'big_dataframe', size: 62, type: 'DataFrame', expensive: true});
172-
assert.deepEqual(results[1], {name: 'big_dict', size: 57, type: 'dict', expensive: true});
173-
assert.deepEqual(results[2], {name: 'big_int', size: 56, type: 'int', expensive: true});
174-
assert.deepEqual(results[3], {name: 'big_list', size: 57, type: 'list', expensive: true});
175-
assert.deepEqual(results[4], {name: 'big_nparray', size: 60, type: 'ndarray', expensive: true});
176-
assert.deepEqual(results[5], {name: 'big_string', size: 59, type: 'str', expensive: true});
171+
assert.deepEqual(results[0], {name: 'big_dataframe', size: 62, type: 'DataFrame'});
172+
assert.deepEqual(results[1], {name: 'big_dict', size: 57, type: 'dict'});
173+
assert.deepEqual(results[2], {name: 'big_int', size: 56, type: 'int'});
174+
assert.deepEqual(results[3], {name: 'big_list', size: 57, type: 'list'});
175+
assert.deepEqual(results[4], {name: 'big_nparray', size: 60, type: 'ndarray'});
176+
assert.deepEqual(results[5], {name: 'big_string', size: 59, type: 'str'});
177177

178178
fakeServer.verifyAll();
179179
});
@@ -186,17 +186,17 @@ suite('JupyterVariables', () => {
186186

187187
fakeServer.setup(fs => fs.execute(typemoq.It.isValue('test'), typemoq.It.isValue(Identifiers.EmptyFileName), typemoq.It.isValue(0), typemoq.It.isAnyString(), undefined, typemoq.It.isValue(true)))
188188
.returns(() => Promise.resolve(generateCells(
189-
'{"name": "big_complex", "type": "complex", "size": 60, "expensive": true, "value": "(1+1j)"}',
189+
'{"name": "big_complex", "type": "complex", "size": 60, "value": "(1+1j)"}',
190190
'stream'
191191
)))
192192
.verifiable(typemoq.Times.once());
193193

194-
const testVariable: IJupyterVariable = { name: 'big_complex', type: 'complex', size: 60, expensive: true, truncated: false, count: 0, shape: '', value: '', supportsDataExplorer: false };
194+
const testVariable: IJupyterVariable = { name: 'big_complex', type: 'complex', size: 60, truncated: false, count: 0, shape: '', value: '', supportsDataExplorer: false };
195195

196196
const resultVariable = await jupyterVariables.getValue(testVariable);
197197

198198
// Verify the result value should be filled out from fake server result
199-
assert.deepEqual(resultVariable, {name: 'big_complex', size: 60, type: 'complex', expensive: true, value: '(1+1j)'});
199+
assert.deepEqual(resultVariable, {name: 'big_complex', size: 60, type: 'complex', value: '(1+1j)'});
200200
fakeServer.verifyAll();
201201
});
202202
});

0 commit comments

Comments
 (0)