Added new VS Code setting "pyright.openFilesOnly", which is set to true.

This commit is contained in:
Eric Traut 2019-11-15 18:37:14 -08:00
parent 460239e7d5
commit 894cdbd52b
8 changed files with 73 additions and 50 deletions

View File

@ -87,6 +87,12 @@
"default": false, "default": false,
"description": "Disables type completion, definitions, and references.", "description": "Disables type completion, definitions, and references.",
"scope": "resource" "scope": "resource"
},
"pyright.openFilesOnly": {
"type": "boolean",
"default": true,
"description": "Report errors for all files in the workspace or only currently-open files?",
"scope": "resource"
} }
} }
}, },

View File

@ -4,6 +4,8 @@ The Pyright VS Code extension honors the following settings.
**pyright.disableLanguageServices** [boolean]: Disables all language services except for “hover”. This includes type completion, signature completion, find definition, find references, and find symbols in file. This option is useful if you want to use pyright only as a type checker but want to run another Python language server for langue service features. **pyright.disableLanguageServices** [boolean]: Disables all language services except for “hover”. This includes type completion, signature completion, find definition, find references, and find symbols in file. This option is useful if you want to use pyright only as a type checker but want to run another Python language server for langue service features.
**pyright.openFilesOnly** [boolean]: Determines whether pyright analyzes (and reports errors for) all files in the workspace, as indicated by the config file. If this option is set to true, pyright analyzes only open files.
**python.analysis.typeshedPaths** [array of paths]: Paths to look for typeshed modules. Pyright currently honors only the first path in the array. **python.analysis.typeshedPaths** [array of paths]: Paths to look for typeshed modules. Pyright currently honors only the first path in the array.
**python.pythonPath** [path]: Path to Python interpreter. **python.pythonPath** [path]: Path to Python interpreter.

View File

@ -35,8 +35,6 @@ import { createTypeEvaluator, TypeEvaluator } from './typeEvaluator';
import { TypeStubWriter } from './typeStubWriter'; import { TypeStubWriter } from './typeStubWriter';
const _maxImportDepth = 256; const _maxImportDepth = 256;
const _maxAnalysisTimeForCompletions = 500;
const _analyzeOnlyOpenFiles = false;
const _allowAllThirdPartyImports = true; const _allowAllThirdPartyImports = true;
export interface SourceFileInfo { export interface SourceFileInfo {
@ -146,7 +144,7 @@ export class Program {
fileInfo.sourceFile.isBindingRequired() || fileInfo.sourceFile.isBindingRequired() ||
fileInfo.sourceFile.isCheckingRequired()) { fileInfo.sourceFile.isCheckingRequired()) {
if ((!_analyzeOnlyOpenFiles && fileInfo.isTracked) || fileInfo.isOpenByClient) { if ((!this._configOptions.checkOnlyOpenFiles && fileInfo.isTracked) || fileInfo.isOpenByClient) {
sourceFileCount++; sourceFileCount++;
} }
} }
@ -155,6 +153,10 @@ export class Program {
return sourceFileCount; return sourceFileCount;
} }
isCheckingOnlyOpenFiles() {
return this._configOptions.checkOnlyOpenFiles;
}
addTrackedFiles(filePaths: string[]) { addTrackedFiles(filePaths: string[]) {
filePaths.forEach(filePath => { filePaths.forEach(filePath => {
this.addTrackedFile(filePath); this.addTrackedFile(filePath);
@ -295,7 +297,7 @@ export class Program {
} }
} }
if (!_analyzeOnlyOpenFiles) { if (!this._configOptions.checkOnlyOpenFiles) {
// Do type analysis of remaining files. // Do type analysis of remaining files.
const allFiles = this._sourceFileList; const allFiles = this._sourceFileList;
@ -700,7 +702,7 @@ export class Program {
const fileDiagnostics: FileDiagnostics[] = this._removeUnneededFiles(); const fileDiagnostics: FileDiagnostics[] = this._removeUnneededFiles();
this._sourceFileList.forEach(sourceFileInfo => { this._sourceFileList.forEach(sourceFileInfo => {
if ((!_analyzeOnlyOpenFiles && sourceFileInfo.isTracked) || sourceFileInfo.isOpenByClient) { if ((!options.checkOnlyOpenFiles && sourceFileInfo.isTracked) || sourceFileInfo.isOpenByClient) {
const diagnostics = sourceFileInfo.sourceFile.getDiagnostics( const diagnostics = sourceFileInfo.sourceFile.getDiagnostics(
options, sourceFileInfo.diagnosticsVersion); options, sourceFileInfo.diagnosticsVersion);
if (diagnostics !== undefined) { if (diagnostics !== undefined) {
@ -954,7 +956,7 @@ export class Program {
} else { } else {
// If we're showing the user errors only for open files, clear // If we're showing the user errors only for open files, clear
// out the errors for the now-closed file. // out the errors for the now-closed file.
if (_analyzeOnlyOpenFiles && !fileInfo.isOpenByClient) { if (this._configOptions.checkOnlyOpenFiles && !fileInfo.isOpenByClient) {
fileDiagnostics.push({ fileDiagnostics.push({
filePath: fileInfo.sourceFile.getFilePath(), filePath: fileInfo.sourceFile.getFilePath(),
diagnostics: [] diagnostics: []

View File

@ -37,6 +37,7 @@ export { MaxAnalysisTime } from './program';
export interface AnalysisResults { export interface AnalysisResults {
diagnostics: FileDiagnostics[]; diagnostics: FileDiagnostics[];
filesInProgram: number; filesInProgram: number;
checkingOnlyOpenFiles: boolean;
filesRequiringAnalysis: number; filesRequiringAnalysis: number;
fatalErrorOccurred: boolean; fatalErrorOccurred: boolean;
configParseErrorOccurred: boolean; configParseErrorOccurred: boolean;
@ -325,9 +326,8 @@ export class AnalyzerService {
} }
} }
if (commandLineOptions.verboseOutput) { configOptions.verboseOutput = !!commandLineOptions.verboseOutput;
configOptions.verboseOutput = true; configOptions.checkOnlyOpenFiles = !!commandLineOptions.checkOnlyOpenFiles;
}
// Do some sanity checks on the specified settings and report missing // Do some sanity checks on the specified settings and report missing
// or inconsistent information. // or inconsistent information.
@ -809,7 +809,7 @@ export class AnalyzerService {
// How long has it been since the user interacted with the service? // How long has it been since the user interacted with the service?
// If the user is actively typing, back off to let him or her finish. // If the user is actively typing, back off to let him or her finish.
const timeSinceLastUserInteractionInMs = Date.now() - this._lastUserInteractionTime; const timeSinceLastUserInteractionInMs = Date.now() - this._lastUserInteractionTime;
const minBackoffTimeInMs = 3000; const minBackoffTimeInMs = 1500;
// We choose a small non-zero value here. If this value // We choose a small non-zero value here. If this value
// is too small (like zero), the VS Code extension becomes // is too small (like zero), the VS Code extension becomes
@ -866,6 +866,7 @@ export class AnalyzerService {
diagnostics: this._program.getDiagnostics(this._configOptions), diagnostics: this._program.getDiagnostics(this._configOptions),
filesInProgram: this._program.getFileCount(), filesInProgram: this._program.getFileCount(),
filesRequiringAnalysis: filesLeftToAnalyze, filesRequiringAnalysis: filesLeftToAnalyze,
checkingOnlyOpenFiles: this._program.isCheckingOnlyOpenFiles(),
fatalErrorOccurred: false, fatalErrorOccurred: false,
configParseErrorOccurred: false, configParseErrorOccurred: false,
elapsedTime: duration.getDurationInSeconds() elapsedTime: duration.getDurationInSeconds()
@ -890,6 +891,7 @@ export class AnalyzerService {
diagnostics: [], diagnostics: [],
filesInProgram: 0, filesInProgram: 0,
filesRequiringAnalysis: 0, filesRequiringAnalysis: 0,
checkingOnlyOpenFiles: true,
fatalErrorOccurred: true, fatalErrorOccurred: true,
configParseErrorOccurred: false, configParseErrorOccurred: false,
elapsedTime: 0 elapsedTime: 0
@ -907,6 +909,7 @@ export class AnalyzerService {
diagnostics: fileDiags, diagnostics: fileDiags,
filesInProgram: this._program.getFileCount(), filesInProgram: this._program.getFileCount(),
filesRequiringAnalysis: this._program.getFilesToAnalyzeCount(), filesRequiringAnalysis: this._program.getFilesToAnalyzeCount(),
checkingOnlyOpenFiles: this._program.isCheckingOnlyOpenFiles(),
fatalErrorOccurred: false, fatalErrorOccurred: false,
configParseErrorOccurred: false, configParseErrorOccurred: false,
elapsedTime: 0 elapsedTime: 0
@ -921,6 +924,7 @@ export class AnalyzerService {
diagnostics: [], diagnostics: [],
filesInProgram: 0, filesInProgram: 0,
filesRequiringAnalysis: 0, filesRequiringAnalysis: 0,
checkingOnlyOpenFiles: true,
fatalErrorOccurred: false, fatalErrorOccurred: false,
configParseErrorOccurred: true, configParseErrorOccurred: true,
elapsedTime: 0 elapsedTime: 0

View File

@ -46,6 +46,9 @@ export class CommandLineOptions {
// Emit verbose information to console? // Emit verbose information to console?
verboseOutput?: boolean; verboseOutput?: boolean;
// Indicates that only open files should be checked.
checkOnlyOpenFiles?: boolean;
// Indicates that the settings came from VS Code rather than // Indicates that the settings came from VS Code rather than
// from the command-line. Useful for providing clearer error // from the command-line. Useful for providing clearer error
// messages. // messages.

View File

@ -323,6 +323,9 @@ export class ConfigOptions {
// Emit verbose information to console? // Emit verbose information to console?
verboseOutput: boolean; verboseOutput: boolean;
// Perform type checking and report diagnostics only for open files?
checkOnlyOpenFiles: boolean;
//--------------------------------------------------------------- //---------------------------------------------------------------
// Diagnostics Settings // Diagnostics Settings

View File

@ -109,6 +109,7 @@ function processArgs() {
} }
options.verboseOutput = !!args.verbose; options.verboseOutput = !!args.verbose;
options.checkOnlyOpenFiles = false;
const watch = args.watch !== undefined; const watch = args.watch !== undefined;
options.watch = watch; options.watch = watch;

View File

@ -32,6 +32,7 @@ interface PythonSettings {
interface PyrightSettings { interface PyrightSettings {
disableLanguageServices?: boolean; disableLanguageServices?: boolean;
openFilesOnly?: boolean;
} }
interface WorkspaceServiceInstance { interface WorkspaceServiceInstance {
@ -92,7 +93,8 @@ function _createAnalyzerService(name: string): AnalyzerService {
}); });
if (results.filesRequiringAnalysis > 0) { if (results.filesRequiringAnalysis > 0) {
if (!_isDisplayingProgress) { // Display a progress spinner if we're checking the entire program.
if (!_isDisplayingProgress && !results.checkingOnlyOpenFiles) {
_isDisplayingProgress = true; _isDisplayingProgress = true;
_connection.sendNotification('pyright/beginProgress'); _connection.sendNotification('pyright/beginProgress');
} }
@ -573,68 +575,72 @@ _connection.onDidCloseTextDocument(params => {
service.setFileClosed(filePath); service.setFileClosed(filePath);
}); });
function getConfiguration(workspace: WorkspaceServiceInstance, section: string) { function getConfiguration(workspace: WorkspaceServiceInstance, sections: string[]) {
if (workspace.rootUri) { const scopeUri = workspace.rootUri ? workspace.rootUri : undefined;
return _connection.workspace.getConfiguration({ return _connection.workspace.getConfiguration(
scopeUri: workspace.rootUri || undefined, sections.map(section => {
section return {
}); scopeUri,
} else { section
return _connection.workspace.getConfiguration(section); };
} })
);
}
function fetchSettingsForWorkspace(workspace: WorkspaceServiceInstance,
callback: (pythonSettings: PythonSettings, pyrightSettings: PyrightSettings) => void) {
const pythonSettingsPromise = getConfiguration(workspace, ['python', 'pyright']);
pythonSettingsPromise.then((settings: [PythonSettings, PyrightSettings]) => {
callback(settings[0], settings[1]);
}, () => {
// An error occurred trying to read the settings
// for this workspace, so ignore.
});
} }
function updateSettingsForAllWorkspaces() { function updateSettingsForAllWorkspaces() {
_workspaceMap.forEach(workspace => { _workspaceMap.forEach(workspace => {
const pythonSettingsPromise = getConfiguration(workspace, 'python'); fetchSettingsForWorkspace(workspace, (pythonSettings, pyrightSettings) => {
pythonSettingsPromise.then((settings: PythonSettings) => { updateOptionsAndRestartService(workspace, pythonSettings, pyrightSettings);
updateOptionsAndRestartService(workspace, settings);
}, () => {
// An error occurred trying to read the settings
// for this workspace, so ignore.
});
const pyrightSettingsPromise = getConfiguration(workspace, 'pyright'); workspace.disableLanguageServices = !!pyrightSettings.disableLanguageServices;
pyrightSettingsPromise.then((settings?: PyrightSettings) => {
workspace.disableLanguageServices = settings !== undefined &&
!!settings.disableLanguageServices;
}, () => {
// An error occurred trying to read the settings
// for this workspace, so ignore.
}); });
}); });
} }
function updateOptionsAndRestartService(workspace: WorkspaceServiceInstance, function updateOptionsAndRestartService(workspace: WorkspaceServiceInstance,
settings: PythonSettings, typeStubTargetImportName?: string) { pythonSettings: PythonSettings, pyrightSettings?: PyrightSettings,
typeStubTargetImportName?: string) {
const commandLineOptions = new CommandLineOptions(workspace.rootPath, true); const commandLineOptions = new CommandLineOptions(workspace.rootPath, true);
commandLineOptions.watch = true; commandLineOptions.watch = true;
commandLineOptions.checkOnlyOpenFiles = pyrightSettings ?
!!pyrightSettings.openFilesOnly : true;
if (settings.venvPath) { if (pythonSettings.venvPath) {
commandLineOptions.venvPath = combinePaths(workspace.rootPath || _rootPath, commandLineOptions.venvPath = combinePaths(workspace.rootPath || _rootPath,
normalizePath(_expandPathVariables(settings.venvPath))); normalizePath(_expandPathVariables(pythonSettings.venvPath)));
} }
if (settings.pythonPath) { if (pythonSettings.pythonPath) {
// The Python VS Code extension treats the value "python" specially. This means // The Python VS Code extension treats the value "python" specially. This means
// the local python interpreter should be used rather than interpreting the // the local python interpreter should be used rather than interpreting the
// setting value as a path to the interpreter. We'll simply ignore it in this case. // setting value as a path to the interpreter. We'll simply ignore it in this case.
if (settings.pythonPath.trim() !== 'python') { if (pythonSettings.pythonPath.trim() !== 'python') {
commandLineOptions.pythonPath = combinePaths(workspace.rootPath || _rootPath, commandLineOptions.pythonPath = combinePaths(workspace.rootPath || _rootPath,
normalizePath(_expandPathVariables(settings.pythonPath))); normalizePath(_expandPathVariables(pythonSettings.pythonPath)));
} }
} }
if (settings.analysis && if (pythonSettings.analysis &&
settings.analysis.typeshedPaths && pythonSettings.analysis.typeshedPaths &&
settings.analysis.typeshedPaths.length > 0) { pythonSettings.analysis.typeshedPaths.length > 0) {
// Pyright supports only one typeshed path currently, whereas the // Pyright supports only one typeshed path currently, whereas the
// official VS Code Python extension supports multiple typeshed paths. // official VS Code Python extension supports multiple typeshed paths.
// We'll use the first one specified and ignore the rest. // We'll use the first one specified and ignore the rest.
commandLineOptions.typeshedPath = commandLineOptions.typeshedPath =
_expandPathVariables(settings.analysis.typeshedPaths[0]); _expandPathVariables(pythonSettings.analysis.typeshedPaths[0]);
} }
if (typeStubTargetImportName) { if (typeStubTargetImportName) {
@ -712,12 +718,8 @@ _connection.onExecuteCommand((cmdParams: ExecuteCommandParams) => {
disableLanguageServices: true disableLanguageServices: true
}; };
const pythonSettingsPromise = getConfiguration(workspace, 'python'); fetchSettingsForWorkspace(workspace, (pythonSettings, pyrightSettings) => {
pythonSettingsPromise.then((settings: PythonSettings) => { updateOptionsAndRestartService(workspace, pythonSettings, pyrightSettings, importName);
updateOptionsAndRestartService(workspace, settings, importName);
}, () => {
// An error occurred trying to read the settings
// for this workspace, so ignore.
}); });
}); });