diff --git a/pythonFiles/datascience/getJupyterVariableValue.py b/pythonFiles/datascience/getJupyterVariableValue.py
index d483eb5cba89..a302cf6df673 100644
--- a/pythonFiles/datascience/getJupyterVariableValue.py
+++ b/pythonFiles/datascience/getJupyterVariableValue.py
@@ -84,9 +84,9 @@ def __call__(self, obj):
return ''.join((x.encode('utf-8') if isinstance(x, unicode) else x) for x in self._repr(obj, 0))
else:
return ''.join(self._repr(obj, 0))
- except Exception:
+ except Exception as e:
try:
- return 'An exception was raised: %r' % sys.exc_info()[1]
+ return 'An exception was raised: ' + str(e)
except Exception:
return 'An exception was raised'
@@ -373,7 +373,7 @@ def _bytes_as_unicode_if_possible(self, obj_repr):
# locale.getpreferredencoding() and 'utf-8). If no encoding can decode
# the input, we return the original bytes.
try_encodings = []
- encoding = self.sys_stdout_encoding or getattr(sys.stdout, 'encoding', '')
+ encoding = self.sys_stdout_encoding or getattr(VC_sys.stdout, 'encoding', '')
if encoding:
try_encodings.append(encoding.lower())
diff --git a/src/client/datascience/interactive-common/interactiveWindowTypes.ts b/src/client/datascience/interactive-common/interactiveWindowTypes.ts
index 59b3be5b9fae..446563bcb4de 100644
--- a/src/client/datascience/interactive-common/interactiveWindowTypes.ts
+++ b/src/client/datascience/interactive-common/interactiveWindowTypes.ts
@@ -69,6 +69,7 @@ export namespace InteractiveWindowMessages {
export const NotebookClean = 'clean';
export const SaveAll = 'save_all';
export const NativeCommand = 'native_command';
+ export const VariablesComplete = 'variables_complete';
}
@@ -301,4 +302,5 @@ export class IInteractiveWindowMapping {
public [InteractiveWindowMessages.NotebookClean]: never | undefined;
public [InteractiveWindowMessages.SaveAll]: ISaveAll;
public [InteractiveWindowMessages.NativeCommand]: INativeCommand;
+ public [InteractiveWindowMessages.VariablesComplete]: never | undefined;
}
diff --git a/src/datascience-ui/interactive-common/mainStateController.ts b/src/datascience-ui/interactive-common/mainStateController.ts
index c766d2ae2947..a5d3258e2f83 100644
--- a/src/datascience-ui/interactive-common/mainStateController.ts
+++ b/src/datascience-ui/interactive-common/mainStateController.ts
@@ -636,6 +636,8 @@ export class MainStateController implements IMessageHandler {
}
public renderUpdate(newState: {}) {
+ const oldCount = this.state.pendingVariableCount;
+
// This method should be called during the render stage of anything
// using this state Controller. That's because after shouldComponentUpdate
// render is next and at this point the state has been set.
@@ -648,6 +650,11 @@ export class MainStateController implements IMessageHandler {
if ('cellVMs' in newState) {
this.sendInfo();
}
+
+ // If the new state includes pendingVariableCount and it's gone to zero, send a message
+ if (this.state.pendingVariableCount === 0 && oldCount !== 0) {
+ setTimeout(() => this.sendMessage(InteractiveWindowMessages.VariablesComplete), 1);
+ }
}
public getState(): IMainState {
diff --git a/src/test/datascience/nativeEditor.functional.test.tsx b/src/test/datascience/nativeEditor.functional.test.tsx
index a57af32ccc32..b2eb2bb71053 100644
--- a/src/test/datascience/nativeEditor.functional.test.tsx
+++ b/src/test/datascience/nativeEditor.functional.test.tsx
@@ -127,7 +127,7 @@ for _ in range(50):
await addCell(wrapper, matPlotLib, true, 5);
verifyHtmlOnCell(wrapper, 'NativeCell', matPlotLibResults, CellPosition.Last);
- await addCell(wrapper, spinningCursor, true, 3 + (ioc.mockJupyter ? (cursors.length * 3) : 0));
+ await addCell(wrapper, spinningCursor, true, 3 + (ioc.mockJupyter ? (cursors.length * 3) : 50));
verifyHtmlOnCell(wrapper, 'NativeCell', '
', CellPosition.Last);
}, () => { return ioc; });
diff --git a/src/test/datascience/variableexplorer.functional.test.tsx b/src/test/datascience/variableexplorer.functional.test.tsx
index 55c230c0f265..421a6a7effc8 100644
--- a/src/test/datascience/variableexplorer.functional.test.tsx
+++ b/src/test/datascience/variableexplorer.functional.test.tsx
@@ -8,6 +8,7 @@ import { parse } from 'node-html-parser';
import * as React from 'react';
import { Disposable } from 'vscode';
+import { InteractiveWindowMessages } from '../../client/datascience/interactive-common/interactiveWindowTypes';
import { IJupyterVariable } from '../../client/datascience/types';
import { InteractivePanel } from '../../datascience-ui/history-react/interactivePanel';
import { VariableExplorer } from '../../datascience-ui/interactive-common/variableExplorer';
@@ -16,7 +17,7 @@ import { DataScienceIocContainer } from './dataScienceIocContainer';
import { addCode } from './interactiveWindowTestHelpers';
import { addCell, createNewEditor } from './nativeEditorTestHelpers';
import { waitForUpdate } from './reactHelpers';
-import { runDoubleTest } from './testHelpers';
+import { runDoubleTest, waitForMessage } from './testHelpers';
// tslint:disable:max-func-body-length trailing-comma no-any no-multiline-string
suite('DataScience Interactive Window variable explorer tests', () => {
@@ -60,10 +61,17 @@ suite('DataScience Interactive Window variable explorer tests', () => {
// asyncDump();
//});
- async function addCodeImpartial(wrapper: ReactWrapper
, React.Component>, code: string, expectedRenderCount: number = 4, expectError: boolean = false): Promise, React.Component>> {
+ async function waitForVariablesUpdated(): Promise {
+ return waitForMessage(ioc, InteractiveWindowMessages.VariablesComplete);
+ }
+
+ async function addCodeImpartial(wrapper: ReactWrapper, React.Component>, code: string, waitForVariables: boolean = true, expectedRenderCount: number = 4, expectError: boolean = false): Promise, React.Component>> {
+ const variablesUpdated = waitForVariables ? waitForVariablesUpdated() : Promise.resolve();
const nodes = wrapper.find('InteractivePanel');
if (nodes.length > 0) {
- return addCode(ioc, wrapper, code, expectedRenderCount, expectError);
+ const result = await addCode(ioc, wrapper, code, expectedRenderCount, expectError);
+ await variablesUpdated;
+ return result;
} else {
// For the native editor case, we need to create an editor before hand.
if (!createdNotebook) {
@@ -72,6 +80,7 @@ suite('DataScience Interactive Window variable explorer tests', () => {
expectedRenderCount += 1;
}
await addCell(wrapper, code, true, expectedRenderCount);
+ await variablesUpdated;
return wrapper;
}
}
@@ -85,8 +94,7 @@ value = 'hello world'`;
openVariableExplorer(wrapper);
await addCodeImpartial(wrapper, 'a=1\na');
- await addCodeImpartial(wrapper, basicCode, 4);
- await waitForUpdate(wrapper, VariableExplorer, 3);
+ await addCodeImpartial(wrapper, basicCode, true, 4);
// We should show a string and show an int, the modules should be hidden
let targetVariables: IJupyterVariable[] = [
@@ -100,8 +108,7 @@ value = 'hello world'`;
ioc.getSettings().datascience.variableExplorerExclude = `${ioc.getSettings().datascience.variableExplorerExclude};str`;
// Add another string and check our vars, strings should be hidden
- await addCodeImpartial(wrapper, basicCode2, 4);
- await waitForUpdate(wrapper, VariableExplorer, 2);
+ await addCodeImpartial(wrapper, basicCode2, true, 4);
targetVariables = [
{name: 'a', value: '1', supportsDataExplorer: false, type: 'int', size: 54, shape: '', count: 0, truncated: false}
@@ -116,7 +123,6 @@ value = 'hello world'`;
openVariableExplorer(wrapper);
await addCodeImpartial(wrapper, 'a=1\na');
- await waitForUpdate(wrapper, VariableExplorer, 2);
// Check that we have just the 'a' variable
let targetVariables: IJupyterVariable[] = [
@@ -125,8 +131,7 @@ value = 'hello world'`;
verifyVariables(wrapper, targetVariables);
// Add another variable and check it
- await addCodeImpartial(wrapper, basicCode, 4);
- await waitForUpdate(wrapper, VariableExplorer, 3);
+ await addCodeImpartial(wrapper, basicCode, true, 4);
targetVariables = [
{name: 'a', value: '1', supportsDataExplorer: false, type: 'int', size: 54, shape: '', count: 0, truncated: false},
@@ -136,8 +141,7 @@ value = 'hello world'`;
verifyVariables(wrapper, targetVariables);
// Add a second variable and check it
- await addCodeImpartial(wrapper, basicCode2, 4);
- await waitForUpdate(wrapper, VariableExplorer, 4);
+ await addCodeImpartial(wrapper, basicCode2, true, 4);
targetVariables = [
{name: 'a', value: '1', supportsDataExplorer: false, type: 'int', size: 54, shape: '', count: 0, truncated: false},
@@ -155,7 +159,7 @@ value = 'hello world'`;
openVariableExplorer(wrapper);
await addCodeImpartial(wrapper, 'a=1\na');
- await addCodeImpartial(wrapper, basicCode, 4);
+ await addCodeImpartial(wrapper, basicCode, false, 4);
// Here we are only going to wait for two renders instead of the needed three
// a should have the value updated, but value should still be loading
@@ -187,11 +191,7 @@ myDict = {'a': 1}`;
openVariableExplorer(wrapper);
await addCodeImpartial(wrapper, 'a=1\na');
- await addCodeImpartial(wrapper, basicCode, 4);
-
- // Verify that we actually update the variable explorer
- // Count here is our main render + a render for each variable row as they come in
- await waitForUpdate(wrapper, VariableExplorer, 5);
+ await addCodeImpartial(wrapper, basicCode, true, 4);
const targetVariables: IJupyterVariable[] = [
{name: 'a', value: '1', supportsDataExplorer: false, type: 'int', size: 54, shape: '', count: 0, truncated: false},
@@ -219,11 +219,7 @@ myTuple = 1,2,3,4,5,6,7,8,9
openVariableExplorer(wrapper);
await addCodeImpartial(wrapper, 'a=1\na');
- await addCodeImpartial(wrapper, basicCode, 4);
-
- // Verify that we actually update the variable explorer
- // Count here is our main render + a render for each variable row as they come in
- await waitForUpdate(wrapper, VariableExplorer, 9);
+ await addCodeImpartial(wrapper, basicCode, true, 4);
const targetVariables: IJupyterVariable[] = [
{name: 'a', value: '1', supportsDataExplorer: false, type: 'int', size: 54, shape: '', count: 0, truncated: false},
@@ -255,9 +251,7 @@ strc = 'c'`;
openVariableExplorer(wrapper);
await addCodeImpartial(wrapper, 'a=1\na');
- await addCodeImpartial(wrapper, basicCode, 4);
-
- await waitForUpdate(wrapper, VariableExplorer, 7);
+ await addCodeImpartial(wrapper, basicCode, true, 4);
let targetVariables: IJupyterVariable[] = [
{name: 'a', value: '1', supportsDataExplorer: false, type: 'int', size: 54, shape: '', count: 0, truncated: false},
@@ -318,6 +312,10 @@ function sortVariableExplorer(wrapper: ReactWrapper, React.Com
// Verify a set of rows versus a set of expected variables
function verifyVariables(wrapper: ReactWrapper, React.Component>, targetVariables: IJupyterVariable[]) {
+ // Force an update so we render whatever the current state is
+ wrapper.update();
+
+ // Then search for results.
const foundRows = wrapper.find('div.react-grid-Row');
expect(foundRows.length).to.be.equal(targetVariables.length, 'Different number of variable explorer rows and target variables');