-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
VS Python analysis engine integration #1144
Conversation
Codecov Report
@@ Coverage Diff @@
## master #1144 +/- ##
==========================================
- Coverage 71.93% 71.91% -0.03%
==========================================
Files 260 260
Lines 11933 11951 +18
Branches 2121 2123 +2
==========================================
+ Hits 8584 8594 +10
- Misses 3220 3231 +11
+ Partials 129 126 -3
Continue to review full report at Codecov.
|
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.
Will need to run through the code one again to review this.
src/client/activation/analysis.ts
Outdated
synchronize: { | ||
configurationSection: PYTHON | ||
}, | ||
outputChannel: outputChannel, |
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.
Instead of outputChannel: outputChannel,
you can write outputChannel
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.
C# habits...
src/client/activation/analysis.ts
Outdated
outputChannel: outputChannel, | ||
initializationOptions: { | ||
interpreter: { | ||
properties: properties |
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.
Instead of properties: properties
you can write properties
src/client/activation/analysis.ts
Outdated
|
||
private async getInterpreterData(): Promise<InterpreterData> { | ||
const execService = await this.executionFactory.create(); | ||
const result = await execService.exec(['-c', 'import sys; print(sys.version); print(sys.prefix)'], {}); |
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.
Please remember, sys.version can contain strings. E.g. if using a beta version of Python or similar, the version could be 3.7.1Beta
.
Please confirm this is not a problem.
My suggestion is to use sys.version_info
(safest option).
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.
PTVS uses just major part, but yes, cleaner is better.
src/client/activation/analysis.ts
Outdated
|
||
// Microsoft Python code analysis engine needs full path to the interpreter | ||
const interpreterService = this.services.get<IInterpreterService>(IInterpreterService); | ||
const interpreter = await interpreterService.getActiveInterpreter(); |
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.
How does this analysis engine work with a multi root workspace?
E.g. workspace folder A & B contain two separate versions of Python.
Will we have only one analysis engine or two, will they all use the same version of python?
If these haven't been considered yet, please create an issue to track this so it gets resolved eventually.
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.
Yes, good point. So far VS project has same interpreter. But not per folder. However, solution can have multiple projects with different interpreters.
src/client/activation/analysis.ts
Outdated
} | ||
|
||
private async getSearchPaths(): Promise<string> { | ||
const execService = await this.executionFactory.create(); |
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.
We're assuming that we're always dealing with a single workspace here
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.
Yep. Same #1149
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.
Added comments
@@ -32,6 +39,10 @@ export class ConfigurationService implements IConfigurationService { | |||
return process.env.VSC_PYTHON_CI_TEST === '1'; | |||
} | |||
|
|||
public async checkDependencies(): Promise<boolean> { |
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.
I don't think checking dependencies should go into the ConfigurationService (configuration service deals with config settings)
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.
OK. Configuration
sounded like related to dependency checks. I'll separate.
src/test/autocomplete/base.test.ts
Outdated
@@ -95,6 +97,10 @@ suite('Autocomplete', () => { | |||
|
|||
// https://github.com/DonJayamanne/pythonVSCode/issues/630 | |||
test('For "abc.decorators"', async () => { | |||
// Disabled for MS Python Code Analysis, see https://github.com/Microsoft/PTVS/issues/3857 | |||
if (IS_ANALYSIS_ENGINE_TEST) { |
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.
Please can we add an issue in our Report to remove this condition. Else even if PTVS issue is resolved, we'll never end up removing this if
condition unless someone remembers to do so.
Having a github issue will remind of this.
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.
It is more to separate Jedi from PTVS rather than for a specific issue. Also to run PTVS tests separately on Appveyor. #1150
src/test/autocomplete/base.test.ts
Outdated
}).then(done, done); | ||
}); | ||
|
||
// https://github.com/Microsoft/vscode-python/issues/110 | ||
test('Suppress in strings/comments', async () => { | ||
// Excluded from MS Python Code Analysis b/c skipping of strings and comments | ||
// is not yet there. See https://github.com/Microsoft/PTVS/issues/3798 | ||
if (IS_ANALYSIS_ENGINE_TEST) { |
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.
Please can we add an issue in our Report to remove this condition. Else even if PTVS issue is resolved, we'll never end up removing this if
condition unless someone remembers to do so.
Having a github issue will remind of this.
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.
suiteSetup(async () => { | ||
suiteSetup(async function () { | ||
// https://github.com/Microsoft/PTVS/issues/3917 | ||
if (IS_ANALYSIS_ENGINE_TEST) { |
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.
Please can we add an issue in our Report to remove this condition. Else even if PTVS issue is resolved, we'll never end up removing this if
condition unless someone remembers to do so.
Having a github issue will remind of this.
suiteSetup(async () => { | ||
suiteSetup(async function () { | ||
// https://github.com/Microsoft/PTVS/issues/3917 | ||
if (IS_ANALYSIS_ENGINE_TEST) { |
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.
Please can we add an issue in our Report to remove this condition. Else even if PTVS issue is resolved, we'll never end up removing this if
condition unless someone remembers to do so.
Having a github issue will remind of this.
src/client/activation/analysis.ts
Outdated
if (settings.autoComplete) { | ||
const extraPaths = settings.autoComplete.extraPaths; | ||
if (extraPaths && extraPaths.length > 0) { | ||
searchPaths = `${searchPaths};${extraPaths.join(';')}`; |
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.
Isn't the path delimeter OS dependent. On Linx path seprators is :
You can use path.sep
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.
PTVS engine split paths by ;
. I believe ;
is universal for providing multiple paths. Alternative is to marshal array over to LS.
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.
is universal for providing multiple paths.
No, its not. Try the following in your terminal (linux/mac)
echo $PATH
src/client/activation/analysis.ts
Outdated
// tslint:disable-next-line:no-string-literal | ||
properties['PrefixPath'] = interpreterData.prefix; | ||
// tslint:disable-next-line:no-string-literal | ||
properties['DatabasePath'] = path.join(context.extensionPath, analysisEngineFolder); |
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.
- What is this folder path for?
- Are we creating files?
- Will having two instances of VS Code or multi root workspaces affect this adversely.
- This folder will get deleted everytime the user updates their extension.
- When storing files you're better off using context.storagePath
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.
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.
👍
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.
Spoke to @huguesv today about these directories. He mentioned that we won't need to create/delete them every time. According to him they will never change (unless of course the PTVS changes).
Possible he's not aware of some of the new changes.
Either way can we somehow try to minimize this or re-use folders rather than creating one per each interpreter.
This could result in a large number of directories (if using virtual envs or pyenv, then each workspace could potentially have a separate environment).
Or please create a separate issue for this (rather than trying to solve this in this PR).
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.
Does PTVS have the ability to re-create/rebuild this database?
I.e. do we need to consider adding the ability (later as a separate PR) for users to re-build this database?
I know a simple solution is to uninstall/re-install the extension, but that sounds like a hack and not very user friendly. But before we do, is such a feature necessary? If yes, lets do that in a separate PR/issue.
src/client/activation/analysis.ts
Outdated
const paths = result.stdout.split(',') | ||
.filter(p => this.isValidPath(p)) | ||
.map(p => this.pathCleanup(p)); | ||
return paths.join(';'); |
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.
The path separator OS dependent (if that's what this is).
You would want to use path.sep
instead of hard coding ;
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.
PTVS splits multiple paths by ;
while path.sep
is \
vs /
I believe
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.
sorry, I meant path.delimiter
src/client/activation/analysis.ts
Outdated
private async isDotNetInstalled(): Promise<boolean> { | ||
const ps = this.services.get<IProcessService>(IProcessService); | ||
const result = await ps.exec('dotnet', ['--version']); | ||
return result.stdout.trim().startsWith('2.'); |
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.
You would need a trycatch in case dotnet
crashes for some reason without returning errors in stderr
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.
const result = await ps.exec('dotnet', ['--version']).catch(()= > { return {stdout:''};})
src/client/activation/downloader.ts
Outdated
await this.unpackArchive(context.extensionPath, localTempFilePath); | ||
} finally { | ||
fs.unlink(localTempFilePath, noop); | ||
} | ||
} | ||
|
||
private async downloadFile(): Promise<string> { | ||
const platformString = this.getPlatformDesignator(); | ||
const platformString = this.platformData.getPlatformDesignator(); |
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.
You might want to display the progress in VS Code using the VS Code API:
https://code.visualstudio.com/docs/extensionAPI/vscode-api#ProgressOptions
Check out the withProgress
method.
.vscode/tasks.json
Outdated
"type": "gulp", | ||
"task": "watch", | ||
"task": "hygiene-watch", |
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.
Not sure this will improve performance, let me know.
The only other solution I can think of is to use tsc watch
and run hygiene
so it display errors ONLY
in terminal window and throw errors when trying to commit (problem with this is you won't see errors in problems
window, but faster).
Or the fastest approach is tsc --watch -p ./
& don't bother with hygiene
just let it complain during commit
src/client/activation/downloader.ts
Outdated
return true; | ||
} | ||
|
||
private reportDownloadSize(response: IncomingMessage): number { |
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.
Please use an existing package to download a file and report the progress (https://www.npmjs.com/package/request-progress).
This does exactly what you need.
src/client/activation/downloader.ts
Outdated
this.output.append('done.'); | ||
} | ||
|
||
private handleError(message: string) { |
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.
Please use request-progress
npm
src/client/activation/downloader.ts
Outdated
if (response.rawHeaders.length >= 2 && response.rawHeaders[0] === 'Content-Length') { | ||
const size = parseInt(response.rawHeaders[1], 10); | ||
if (size > 0) { | ||
this.output.append(` ${Math.round(size / 1024)} KB...`); |
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.
Please report download progress using VS Code api, so users too can see this.
src/client/activation/downloader.ts
Outdated
deferred.resolve(); | ||
}) | ||
.on('error', (err) => { | ||
this.handleError(`Unable to unpack downloaded file. Error ${err}.`); |
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.
You'll need to bubble up the error, (throwing exceptions inside handleError
will not work.
deferred.reject(err)
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.
I'd throw an exception here and call handleError
from catch
in downloadAnalysisEngine
.
src/client/activation/downloader.ts
Outdated
}); | ||
|
||
let firstResponse = true; | ||
https.get(uri, (response) => { |
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.
replace with npm package.
src/client/activation/downloader.ts
Outdated
deferred.resolve(); | ||
}) | ||
.on('error', (err) => { | ||
this.handleError(`Unable to unpack downloaded file. Error ${err}.`); |
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.
change to .on('error', deferred.reject.bind(deferred))
else it won't work
src/client/activation/downloader.ts
Outdated
this.output.append('Verifying download... '); | ||
const verifier = new HashVerifier(); | ||
if (!await verifier.verifyHash(filePath, this.platformData.getExpectedHash())) { | ||
this.handleError('Hash of the downloaded file does not match.'); |
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.
No need to call handleError
, just throw the exception here throw new Error(.....)
, let the calling method handle and log all exceptions.
if (this.platform.isLinux && this.platform.is64bit) { | ||
return 'linux-x64'; | ||
} | ||
throw new Error('Python Analysis Engine does not support 32-bit Linux.'); |
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.
I've created an issue for this, we need to document this limitation in our documentation https://github.com/Microsoft/vscode-python/issues/new
src/client/common/types.ts
Outdated
readonly terminal: ITerminalSettings; | ||
readonly sortImports: ISortImportSettings; | ||
readonly workspaceSymbols: IWorkspaceSymbolSettings; | ||
readonly linting: ILintingSettings | undefined; |
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.
No need to change anything (you can also use readonly linting?: ILintingSettings
)
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
export const analysis_engine_win_x86_sha512 = '6ce1f4a4a83ea7a662f2034de3f83ba8342863e9c1d97dfc23981931e69d1358b8953ae9fbec05be4d755118d695c974a39cd4fd1d6e4735bf5d60d58ab44fe9'; |
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.
Will this change for each build? If yes, then we might want to put this into package.json
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.
Yes. The file is generated and injected in VSTS. Default state is empty string which means 'dont check'
@@ -0,0 +1,20 @@ | |||
<Project Sdk="Microsoft.NET.Sdk"> |
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 file is for signing step only. VSTS task wants C# project.
Need to restore lost changes after rebase |
Fixes #1101
Fixes #1087
Fixes #1063
Fixes #1051
Fixes #1004
Fixes #998
Fixes #408
Fixes #82
python.jediEnabled
setting (default true)import *
This pull request: