Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions docs/benefits-over-pyright/baseline.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,25 @@

have you ever wanted to adopt a new tool or enable new checks in an existing project, only to be immediately bombarded with thousands of errors you'd have to fix? baseline solves this problem by allowing you to only report errors on new or modified code. it works by generating a baseline file keeping track of the existing errors in your project so that only errors in newly written or modified code get reported.

to enable baseline, run `basedpyright --writebaseline` in your terminal or run the _"basedpyright: Write new errors to baseline"_ task in your editor. this will generate a baseline file at `./.basedpyright/baseline.json` your project. you should commit this file so others working on your project can benefit from it too.
to enable baseline, run `basedpyright --writebaseline` in your terminal or run the _"basedpyright: Write new errors to baseline"_ task in your editor. this will generate a baseline file at `./.basedpyright/baseline.json` in your project. you should commit this file so others working on your project can benefit from it too.

you can customize the baseline file path [using the `baselineFile` setting](../configuration/config-files.md#baselineFile) or [using the `--baselinefile` CLI argument](../configuration/command-line.md#command-line).

## how often do i need to update the baseline file?

this file gets automatically updated as errors are removed over time in both the CLI and the language server. you should only manually run the write baseline command in the following scenarios:
by default, this file gets automatically updated as errors are removed over time in both the CLI and the language server. you should only manually run the write baseline command in the following scenarios:

- a baselined error incorrectly resurfaces when updating unrelated code
- you're enabling a new diagnostic rule and want to baseline all the new errors it reported

if you need to suppress a diagnostic for another reason, consider using [a `# pyright: ignore` comment](../configuration/comments.md#prefer-pyrightignore-comments) instead.

## disabling automatic updates for baselined error removals

if you want more control over when the baseline file is updated, use the `baselineMode` setting in either the [language server](../configuration/language-server-settings.md) or [the CLI](../configuration/command-line.md#option-2-baselinemode-experimental). for example, using the `discard` mode will prevent the baseline file from being automatically updated when baselined errors are removed.

if you stop automatic updates from the LSP, a potential alternative workflow for still having the baseline file updated with removed errors is to set up a pre-commit hook in your project to run the basedpyright CLI. this would take care of error removals at commit time instead of during editor saves.

## how does it work?

each baselined error is stored and matched by the following details:
Expand Down
2 changes: 2 additions & 0 deletions docs/configuration/language-server-settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ the following settings are exclusive to basedpyright

**basedpyright.analysis.configFilePath** [path]: Path to the directory or file containing the Pyright configuration (`pyrightconfig.json` or `pyproject.toml`). If a directory is specified, basedpyright will search for the config file in that directory. This is useful for monorepo structures where the config file is in a subdirectory rather than the workspace root. For example, if your Python code is in a `backend/` subdirectory with its own `pyproject.toml`, you can set this to `${workspaceFolder}/backend` to make basedpyright use that configuration file instead of searching from the workspace root.

**basedpyright.analysis.baselineMode** ["auto", "discard"]: Controls how the baseline file is updated when files are saved. Use `auto` to automatically remove fixed errors from the baseline (default), or `discard` to prevent automatic updates. [more info](../benefits-over-pyright/baseline.md)


### discouraged settings

Expand Down
6 changes: 5 additions & 1 deletion packages/pyright-internal/src/baseline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,12 @@ export interface BaselinedDiagnostic {
};
}

// baseline modes allowed in LSP server settings
// TODO: add 'ignore' mode https://github.com/DetachHead/basedpyright/issues/1524
export const baselineModes = ['discard', 'auto', 'lock'] as const;
export const serverBaselineModes = ['discard', 'auto'] as const;
export type ServerBaselineMode = (typeof serverBaselineModes)[number];

export const baselineModes = [...serverBaselineModes, 'lock'] as const;

// 'force' is not a real value for `--baselinemode`. we just use it to represent `--writebaseline`
export type BaselineMode = (typeof baselineModes)[number] | 'force';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import { MaxAnalysisTime } from '../analyzer/program';
import { IBackgroundAnalysis } from '../backgroundAnalysisBase';
import { ServerBaselineMode } from '../baseline';
import { InlayHintSettings, Workspace } from '../workspaceFactory';
import { DiagnosticBooleanOverridesMap, DiagnosticSeverityOverridesMap } from './commandLineOptions';
import { SignatureDisplayType } from './configOptions';
Expand All @@ -28,6 +29,7 @@ export interface ServerSettings {
typeCheckingMode?: string | undefined;
useLibraryCodeForTypes?: boolean | undefined;
baselineFile?: Uri | undefined;
baselineMode?: ServerBaselineMode | undefined;
configFilePath?: Uri | undefined;
disableLanguageServices?: boolean | undefined;
disableTaggedHints?: boolean | undefined;
Expand Down
9 changes: 7 additions & 2 deletions packages/pyright-internal/src/languageServerBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,7 @@ export abstract class LanguageServerBase implements LanguageServerInterface, Dis
workspace.useTypingExtensions = serverSettings.useTypingExtensions ?? false;
workspace.fileEnumerationTimeoutInSec = serverSettings.fileEnumerationTimeoutInSec ?? 10;
workspace.autoFormatStrings = serverSettings.autoFormatStrings ?? true;
workspace.baselineMode = serverSettings.baselineMode ?? 'auto';
} finally {
// Don't use workspace.isInitialized directly since it might have been
// reset due to pending config change event.
Expand Down Expand Up @@ -1864,10 +1865,14 @@ export abstract class LanguageServerBase implements LanguageServerInterface, Dis
filesRequiringBaselineUpdate.get(workspace)!.push(fileDiagnostics);
}
for (const [workspace, files] of filesRequiringBaselineUpdate.entries()) {
if (!workspace.rootUri) {
if (!workspace.rootUri || workspace.baselineMode === 'discard') {
continue;
}
const baselineDiffSummary = workspace.service.backgroundAnalysisProgram.writeBaseline('auto', false, files);
const baselineDiffSummary = workspace.service.backgroundAnalysisProgram.writeBaseline(
workspace.baselineMode,
false,
files
);
if (baselineDiffSummary) {
this.console.info(
`${baselineDiffSummary}. files: ${files.map((file) => file.fileUri.toString()).join(', ')}`
Expand Down
6 changes: 6 additions & 0 deletions packages/pyright-internal/src/realLanguageServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { AnalysisResults } from './analyzer/analysis';
import { CacheManager } from './analyzer/cacheManager';
import { ImportResolver } from './analyzer/importResolver';
import { isPythonBinary } from './analyzer/pythonPathUtils';
import { serverBaselineModes, ServerBaselineMode } from './baseline';
import { CommandController } from './commands/commandController';
import { ConfigOptions, SignatureDisplayType } from './common/configOptions';
import { ConsoleWithLogLevel, LogLevel, convertLogLevel } from './common/console';
Expand Down Expand Up @@ -173,6 +174,11 @@ export abstract class RealLanguageServer extends LanguageServerBase {
serverSettings.baselineFile = resolvePathWithEnvVariables(workspace, baselineFile, workspaces);
}

const baselineMode = pythonAnalysisSection.baselineMode;
if (serverBaselineModes.includes(baselineMode)) {
serverSettings.baselineMode = baselineMode as ServerBaselineMode;
}

const configFilePath = pythonAnalysisSection.configFilePath;
if (configFilePath && isString(configFilePath)) {
serverSettings.configFilePath = resolvePathWithEnvVariables(workspace, configFilePath, workspaces);
Expand Down
1 change: 1 addition & 0 deletions packages/pyright-internal/src/tests/envVarUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,5 +227,6 @@ function createWorkspace(rootUri: Uri | undefined): Workspace {
useTypingExtensions: false,
fileEnumerationTimeoutInSec: 10,
autoFormatStrings: true,
baselineMode: 'auto',
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ export class TestLanguageService implements LanguageServerInterface {
useTypingExtensions: false,
fileEnumerationTimeoutInSec: 10,
autoFormatStrings: true,
baselineMode: 'auto',
};
}
/** unlike the real one, this test implementation doesn't support notebook cells. TODO: language server tests for notebook cells */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ export class TestState {
useTypingExtensions: false,
fileEnumerationTimeoutInSec: 10,
autoFormatStrings: true,
baselineMode: 'auto',
};

if (!delayFileInitialization) {
Expand Down
3 changes: 3 additions & 0 deletions packages/pyright-internal/src/workspaceFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
} from 'vscode-languageserver';

import { AnalyzerService } from './analyzer/service';
import { ServerBaselineMode } from './baseline';
import { ConsoleInterface } from './common/console';
import { createDeferred } from './common/deferred';
import { ServiceProvider } from './common/serviceProvider';
Expand Down Expand Up @@ -103,6 +104,7 @@ export interface Workspace extends WorkspaceFolder {
useTypingExtensions: boolean;
fileEnumerationTimeoutInSec: number;
autoFormatStrings: boolean;
baselineMode: ServerBaselineMode;
}

export interface NormalWorkspace extends Workspace {
Expand Down Expand Up @@ -305,6 +307,7 @@ export class WorkspaceFactory implements IWorkspaceFactory {
useTypingExtensions: false,
fileEnumerationTimeoutInSec: 10,
autoFormatStrings: true,
baselineMode: 'auto',
};

// Stick in our map
Expand Down
14 changes: 14 additions & 0 deletions packages/vscode-pyright/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,20 @@
"markdownDescription": "Path to the baseline file. Defaults to `./.basedpyright/baseline.json`",
"scope": "resource"
},
"basedpyright.analysis.baselineMode": {
"type": "string",
"default": "auto",
"enum": [
"auto",
"discard"
],
"enumDescriptions": [
"Automatically update the baseline file when baselined errors are fixed.",
"Never update the baseline file automatically."
],
"markdownDescription": "Controls how the baseline file is updated when files are saved.",
"scope": "resource"
},
"basedpyright.analysis.configFilePath": {
"type": "string",
"default": "",
Expand Down
Loading