Repository navigation
Some fixes for nightly #11802
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
Some fixes for nightly #11802
Changes from 7 commits
3414a6b
32f1483
46f4432
d523a42
3bb2a06
f55faf0
5f20294
c97a5c0
4e4cc34
3052fcf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,3 +2,4 @@ pandas | |
| jupyter | ||
| numpy | ||
| matplotlib | ||
| pip | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,3 +5,4 @@ dependencies: | |
| - jupyter | ||
| - numpy | ||
| - matplotlib | ||
| - pip | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,3 +5,4 @@ dependencies: | |
| - jupyter | ||
| - numpy | ||
| - matplotlib | ||
| - pip | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -161,7 +161,7 @@ steps: | |
| # Run the pip installs in the 3 environments (windows) | ||
| - script: | | ||
| call activate base | ||
| conda install --quiet -y --file build/ci/conda_base.yml | ||
| call conda install --quiet -y --file build/ci/conda_base.yml | ||
|
Author
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.
Seems that on windows, conda will create a new command shell if you call it directly. This actually prevents the other commands after this point from running. This was the first bug in our flake tests. |
||
| python -m pip install --upgrade -r build/conda-functional-requirements.txt | ||
| call activate conda_env_1 | ||
| python -m pip install --upgrade -r build/conda-functional-requirements.txt | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,7 +8,6 @@ black ; python_version>='3.6' | |
| yapf | ||
| pylint | ||
| pycodestyle | ||
| prospector | ||
|
Author
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. I don't believe this is used anywhere and it was failing to install anyway. |
||
| pydocstyle | ||
| nose | ||
| pytest==4.6.9 # Last version of pytest with Python 2.7 support | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -577,8 +577,8 @@ export class FileSystem implements IFileSystem { | |
| public async search(globPattern: string, cwd?: string): Promise<string[]> { | ||
| return this.utils.search(globPattern, cwd); | ||
| } | ||
| public async createTemporaryFile(suffix: string): Promise<TemporaryFile> { | ||
| return this.utils.tmp.createFile(suffix); | ||
| public async createTemporaryFile(suffix: string, mode?: number): Promise<TemporaryFile> { | ||
| return this.utils.tmp.createFile(suffix, mode); | ||
|
Author
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. added an optional mode parameter to try and fix problems with the direct kernel on windows |
||
| } | ||
| public async isDirReadonly(dirname: string): Promise<boolean> { | ||
| return this.utils.isDirReadonly(dirname); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -358,7 +358,9 @@ export abstract class BaseJupyterSession implements IJupyterSession { | |
| try { | ||
| suppressShutdownErrors(session.kernel); | ||
| // Shutdown may fail if the process has been killed | ||
| await waitForPromise(session.shutdown(), 1000); | ||
| if (!session.isDisposed) { | ||
|
Author
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. Not necessary to wait for shutdown if the session is already disposed |
||
| await waitForPromise(session.shutdown(), 1000); | ||
| } | ||
| } catch { | ||
| noop(); | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1080,7 +1080,11 @@ export abstract class InteractiveBase extends WebViewHost<IInteractiveWindowMapp | |
| ]); | ||
| try { | ||
| notebook = identity | ||
| ? await this.notebookProvider.getOrCreateNotebook({ identity: identity.resource, metadata }) | ||
| ? await this.notebookProvider.getOrCreateNotebook({ | ||
| identity: identity.resource, | ||
| resource, | ||
|
Author
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. Seems we weren't passing in the resource for creating the notebook. This is what broke picking an interpreter based on a resource.
Member
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. If I'm reading this right it seems like this would have been broken for a while for both raw and jupyter then. I'm having trouble mapping this to the actual user scenario that would trigger this issue. Just surprised we've not run into this at all.
Author
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. Yes it would have been broken. The user scenario is you
That's what the test was supposed to verify. In reply to: 424795255 [](ancestors = 424795255)
Member
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. Glad we had a test for it then. Maybe I need to play around with multiroot more often. |
||
| metadata | ||
| }) | ||
| : undefined; | ||
| if (notebook) { | ||
| const executionActivation = { ...identity, owningResource: resource }; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -151,9 +151,6 @@ export class InteractiveWindow extends InteractiveBase implements IInteractiveWi | |
|
|
||
| // Send a telemetry event to indicate window is opening | ||
| sendTelemetryEvent(Telemetry.OpenedInteractiveWindow); | ||
|
|
||
| // Start the server as soon as we open | ||
| this.ensureConnectionAndNotebook().ignoreErrors(); | ||
|
Author
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. Additionally this was breaking the create notebook with a resource because for the interactive window, it frequently can't compute the resource until after a user submits code. So starting the notebook before showing the window makes this a race. Moved this to 'show' and now it will always happen after the user adds code. |
||
| } | ||
|
|
||
| public dispose() { | ||
|
|
@@ -170,6 +167,9 @@ export class InteractiveWindow extends InteractiveBase implements IInteractiveWi | |
| } | ||
|
|
||
| public async show(): Promise<void> { | ||
| // Start the server as soon as we open | ||
| this.ensureConnectionAndNotebook().ignoreErrors(); | ||
|
|
||
| // When showing we have to load the web panel. Make sure | ||
| // we use the last file sent through add code. | ||
| await this.loadWebPanel(this.lastFile ? path.dirname(this.lastFile) : process.cwd()); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -248,7 +248,7 @@ export class DebuggerVariables implements IConditionalJupyterVariables, DebugAda | |
| // tslint:disable-next-line: no-any | ||
| (variable as any).frameId | ||
| ); | ||
| if (results) { | ||
| if (results && results.result) { | ||
|
Author
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. This was unnecessarily crashing sometimes (when debugpy doesn't return anything because the value may not evaluate). Checking this here lets the value just exist as is. |
||
| // Results should be the updated variable. | ||
| return { | ||
| ...variable, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -337,8 +337,11 @@ export class JupyterDebugService implements IJupyterDebugService, IDisposable { | |
|
|
||
| private sendMessage(command: string, args?: any): Promise<any> { | ||
| const response = createDeferred<any>(); | ||
| const disposable = this.sessionTerminatedEvent.event(() => response.resolve()); | ||
| this.protocolParser.once(`response_${command}`, (resp: any) => { | ||
| this.sendToTrackers(resp); | ||
| traceInfo(`Received response from debugger: ${JSON.stringify(args)}`); | ||
|
Author
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. Added this to trace random failures in debugging. Still working on this. |
||
| disposable.dispose(); | ||
| response.resolve(resp.body); | ||
| }); | ||
| this.socket!.on('error', (err) => response.reject(err)); // NOSONAR | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -145,7 +145,7 @@ export class KernelProcess implements IKernelProcess { | |
| } | ||
|
|
||
| private async createAndUpdateConnectionFile() { | ||
| this.connectionFile = await this.file.createTemporaryFile('.json'); | ||
| this.connectionFile = await this.file.createTemporaryFile('.json', 0o777); | ||
|
Author
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. I should put a comment here. Not sure if this fixes the direct kernel problem or not, but going to wait and see.
Member
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. That's odd. So the permission on the temp connection file were preventing the delete and recreate?
Author
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. Not sure. But the failure point was when it attempted to open it with a restricted set of permissions. After I made this change I haven't seen the failure again, but it could be just luck In reply to: 424792220 [](ancestors = 424792220) |
||
| await this.file.writeFile(this.connectionFile.filePath, JSON.stringify(this._connection), { | ||
| encoding: 'utf-8', | ||
| flag: 'w' | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -196,9 +196,6 @@ export class FSFixture extends CleanupFixture { | |
| try { | ||
| await fsextra.remove(filename); | ||
| } catch (err) { | ||
| if (!(await fsextra.pathExists(filename))) { | ||
|
Author
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. I think this is causing random failures on windows for functional tests. But it's not necessary. |
||
| return; | ||
| } | ||
| console.log(`failure while deleting ${filename}: ${err}`); | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1235,18 +1235,24 @@ export class DataScienceIocContainer extends UnitTestIocContainer { | |
| if (!this.mockJupyter) { | ||
| const interpreterService = this.serviceManager.get<IInterpreterService>(IInterpreterService); | ||
| const activeInterpreter = await interpreterService.getActiveInterpreter(); | ||
| if (!activeInterpreter || !(await this.hasJupyter(activeInterpreter))) { | ||
| const list = await this.getJupyterInterpreters(); | ||
| this.forceSettingsChanged(undefined, list[0].path); | ||
|
|
||
| // Log this all the time. Useful in determining why a test may not pass. | ||
| // tslint:disable-next-line: no-console | ||
| console.log(`Setting interpreter to ${list[0].displayName || list[0].path}`); | ||
|
|
||
| // Also set this as the interpreter to use for jupyter | ||
| await this.serviceManager | ||
| .get<JupyterInterpreterService>(JupyterInterpreterService) | ||
| .setAsSelectedInterpreter(list[0]); | ||
| if (!activeInterpreter || !(await this.hasFunctionalDependencies(activeInterpreter))) { | ||
| const list = await this.getFunctionalTestInterpreters(); | ||
| if (list.length) { | ||
| this.forceSettingsChanged(undefined, list[0].path); | ||
|
|
||
| // Log this all the time. Useful in determining why a test may not pass. | ||
| // tslint:disable-next-line: no-console | ||
| console.log(`Setting interpreter to ${list[0].displayName || list[0].path} -> ${list[0].path}`); | ||
|
|
||
| // Also set this as the interpreter to use for jupyter | ||
| await this.serviceManager | ||
| .get<JupyterInterpreterService>(JupyterInterpreterService) | ||
| .setAsSelectedInterpreter(list[0]); | ||
| } else { | ||
| throw new Error( | ||
| 'No jupyter capable interpreter found. Make sure you install all of the functional requirements before running a test' | ||
| ); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
@@ -1315,17 +1321,17 @@ export class DataScienceIocContainer extends UnitTestIocContainer { | |
| } | ||
|
|
||
| public async getJupyterCapableInterpreter(): Promise<PythonInterpreter | undefined> { | ||
| const list = await this.getJupyterInterpreters(); | ||
| const list = await this.getFunctionalTestInterpreters(); | ||
| return list ? list[0] : undefined; | ||
| } | ||
|
|
||
| public async getJupyterInterpreters(): Promise<PythonInterpreter[]> { | ||
| public async getFunctionalTestInterpreters(): Promise<PythonInterpreter[]> { | ||
| // This should be cacheable as we don't install new interpreters during tests | ||
| if (DataScienceIocContainer.jupyterInterpreters.length > 0) { | ||
| return DataScienceIocContainer.jupyterInterpreters; | ||
| } | ||
| const list = await this.get<IInterpreterService>(IInterpreterService).getInterpreters(undefined); | ||
| const promises = list.map((f) => this.hasJupyter(f).then((b) => (b ? f : undefined))); | ||
| const promises = list.map((f) => this.hasFunctionalDependencies(f).then((b) => (b ? f : undefined))); | ||
| const resolved = await Promise.all(promises); | ||
| DataScienceIocContainer.jupyterInterpreters = resolved.filter((r) => r) as PythonInterpreter[]; | ||
| return DataScienceIocContainer.jupyterInterpreters; | ||
|
|
@@ -1587,12 +1593,22 @@ export class DataScienceIocContainer extends UnitTestIocContainer { | |
| return ''; | ||
| } | ||
|
|
||
| private async hasJupyter(interpreter: PythonInterpreter): Promise<boolean | undefined> { | ||
|
Author
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. Turns out having jupyter is too lenient. When testing we want only those interpreters that have everything installed that we need. (Seems azure machines can have jupyter in other environments too). |
||
| private async hasFunctionalDependencies(interpreter: PythonInterpreter): Promise<boolean | undefined> { | ||
| try { | ||
| const dependencyChecker = this.serviceManager.get<JupyterInterpreterDependencyService>( | ||
| JupyterInterpreterDependencyService | ||
| ); | ||
| return dependencyChecker.areDependenciesInstalled(interpreter); | ||
| if (await dependencyChecker.areDependenciesInstalled(interpreter)) { | ||
| // Functional tests require livelossplot too. Make sure this interpreter has that value as well | ||
| const pythonProcess = await this.serviceContainer | ||
| .get<IPythonExecutionFactory>(IPythonExecutionFactory) | ||
| .createActivatedEnvironment({ | ||
| resource: undefined, | ||
| interpreter, | ||
| allowEnvironmentFetchExceptions: true | ||
| }); | ||
| return pythonProcess.isModuleInstalled('livelossplot'); // Should we check all dependencies? | ||
|
Member
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. I'm guessing the comment here is since livelossplot is standing in for everything in conda-functional-requirements.txt? Seems ok for test code, having to check them all seems like a bit of overkill.
Author
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. Yeah. Livelossplot seemed uncommon for other things to install, so seemed like a good candidate for checking. This does mean that if you run the functional tests locally, you'll have to install livelossplot into a least one environment for most of the tests to pass with real jupyter. In reply to: 424793927 [](ancestors = 424793927)
Member
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. Since we're on the topic, what do you do for setting up your local test env to run all the real python tests? Just this: in a Conda env? Wasn't as sure since there were multiple conda envs getting set up as well in the test steps.
Author
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. No I do it more manually.
In reply to: 424799830 [](ancestors = 424799830) |
||
| } | ||
| } catch (ex) { | ||
| return false; | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -365,7 +365,8 @@ suite('DataScience notebook tests', () => { | |
| runTest('Remote Self Certs', async (_this: Mocha.Context) => { | ||
| const pythonService = await createPythonService(2); | ||
|
|
||
| if (pythonService) { | ||
| // Skip test for older python and on windows. Getting E_PROTO on windows. | ||
| if (pythonService && os.platform() !== 'win32') { | ||
|
Author
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. For now self certs seems to always fail on windows. |
||
| // We will only connect if we allow for self signed cert connections | ||
| ioc.getSettings().datascience.allowUnauthorizedRemoteConnection = true; | ||
|
|
||
|
|
||
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.
Making sure pip comes from the conda directory