[PylanceBot] Pull Pylance with Pyright 1.1.265 (#3783)

Co-authored-by: HeeJae Chang <hechang@microsoft.com>
This commit is contained in:
PylanceBot 2022-08-03 14:14:43 -07:00 committed by GitHub
parent cdba65d4c8
commit e4a0f2088c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 3098 additions and 3046 deletions

5850
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -23,16 +23,16 @@
"@types/glob": "^7.2.0",
"@types/node": "^17.0.45",
"@types/yargs": "^16.0.4",
"@typescript-eslint/eslint-plugin": "^5.31.0",
"@typescript-eslint/parser": "^5.31.0",
"@typescript-eslint/eslint-plugin": "^5.32.0",
"@typescript-eslint/parser": "^5.32.0",
"detect-indent": "^6.1.0",
"eslint": "^8.20.0",
"eslint": "^8.21.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-simple-import-sort": "^7.0.0",
"glob": "^7.2.3",
"jsonc-parser": "^3.1.0",
"lerna": "^5.2.0",
"npm-check-updates": "^12.5.12",
"lerna": "^5.3.0",
"npm-check-updates": "^16.0.5",
"p-queue": "^6.6.2",
"prettier": "2.7.1",
"syncpack": "^5.8.15",

View File

@ -38,7 +38,6 @@ import { ParseResults } from '../parser/parser';
import * as AnalyzerNodeInfo from './analyzerNodeInfo';
import { ModuleNameAndType } from './importResolver';
import { ImportResult, ImportType } from './importResult';
import { ParseTreeWalker } from './parseTreeWalker';
import * as SymbolNameUtils from './symbolNameUtils';
export interface ImportStatement {
@ -72,6 +71,12 @@ export interface ImportNameInfo {
export interface ImportNameWithModuleInfo extends ImportNameInfo {
module: ModuleNameAndType;
nameForImportFrom?: string;
}
export interface ModuleNameInfo {
name: string;
nameForImportFrom?: string;
}
// Determines which import grouping should be used when sorting imports.
@ -110,10 +115,6 @@ export function compareImportStatements(a: ImportStatement, b: ImportStatement)
return a.moduleName < b.moduleName ? -1 : 1;
}
export function getAllImports(root: ModuleNode, token: CancellationToken) {
return ImportCollector.collect(root, token);
}
// Looks for top-level 'import' and 'import from' statements and provides
// an ordered list and a map (by file path).
export function getTopLevelImports(parseTree: ModuleNode, includeImplicitImports = false): ImportStatements {
@ -338,13 +339,13 @@ export function getTextEditsForAutoImportInsertions(
return [];
}
const map = createMapFromItems(importNameInfo, (i) => i.module.moduleName);
const map = createMapFromItems(importNameInfo, (i) => `${i.module.moduleName}-${i.nameForImportFrom ?? ''}`);
for (const importInfo of map.values()) {
insertionEdits.push(
..._getInsertionEditsForAutoImportInsertion(
importInfo,
{ name: importInfo[0].module.moduleName, nameForImportFrom: importInfo[0].nameForImportFrom },
importStatements,
importInfo[0].module.moduleName,
getImportGroupFromModuleNameAndType(importInfo[0].module),
parseResults,
invocationPosition
@ -357,16 +358,16 @@ export function getTextEditsForAutoImportInsertions(
export function getTextEditsForAutoImportInsertion(
importNameInfo: ImportNameInfo[] | ImportNameInfo,
moduleNameInfo: ModuleNameInfo,
importStatements: ImportStatements,
moduleName: string,
importGroup: ImportGroup,
parseResults: ParseResults,
invocationPosition: Position
): TextEditAction[] {
const insertionEdits = _getInsertionEditsForAutoImportInsertion(
importNameInfo,
moduleNameInfo,
importStatements,
moduleName,
importGroup,
parseResults,
invocationPosition
@ -423,8 +424,8 @@ function _convertInsertionEditsToTextEdits(parseResults: ParseResults, insertion
function _getInsertionEditsForAutoImportInsertion(
importNameInfo: ImportNameInfo[] | ImportNameInfo,
moduleNameInfo: ModuleNameInfo,
importStatements: ImportStatements,
moduleName: string,
importGroup: ImportGroup,
parseResults: ParseResults,
invocationPosition: Position
@ -449,7 +450,10 @@ function _getInsertionEditsForAutoImportInsertion(
// Add from import statements next.
const fromImports = map.get('from');
if (fromImports) {
appendToEdits(fromImports, (names) => `from ${moduleName} import ${names.join(', ')}`);
appendToEdits(
fromImports,
(names) => `from ${moduleNameInfo.nameForImportFrom ?? moduleNameInfo.name} import ${names.join(', ')}`
);
}
return insertionEdits;
@ -464,7 +468,7 @@ function _getInsertionEditsForAutoImportInsertion(
function appendToEdits(importNameInfo: ImportNameInfo[], importStatementGetter: (n: string[]) => string) {
const importNames = importNameInfo
.map((i) => getImportAsText(i, moduleName))
.map((i) => getImportAsText(i, moduleNameInfo.name))
.sort((a, b) => _compareImportNames(a.sortText, b.sortText))
.reduce((set, v) => addIfUnique(set, v.text), [] as string[]);
@ -472,7 +476,7 @@ function _getInsertionEditsForAutoImportInsertion(
_getInsertionEditForAutoImportInsertion(
importStatementGetter(importNames),
importStatements,
moduleName,
moduleNameInfo.name,
importGroup,
parseResults,
invocationPosition
@ -897,34 +901,3 @@ export function getResolvedFilePath(importResult: ImportResult | undefined) {
// Regular case.
return importResult.resolvedPaths[importResult.resolvedPaths.length - 1];
}
class ImportCollector extends ParseTreeWalker {
private readonly _imports: (ImportNode | ImportFromNode)[] = [];
private constructor(private _token: CancellationToken) {
super();
}
public static collect(root: ModuleNode, token: CancellationToken) {
const collector = new ImportCollector(token);
collector.walk(root);
return collector._imports;
}
override walk(node: ParseNode): void {
throwIfCancellationRequested(this._token);
super.walk(node);
}
override visitImport(node: ImportNode) {
this._imports.push(node);
return true;
}
override visitImportFrom(node: ImportFromNode) {
this._imports.push(node);
return true;
}
}

View File

@ -47,6 +47,7 @@ import { DocumentRange, doesRangeContain, doRangesIntersect, Position, Range } f
import { Duration, timingStats } from '../common/timing';
import {
AutoImporter,
AutoImportOptions,
AutoImportResult,
buildModuleSymbolsMap,
ModuleSymbolMap,
@ -1254,9 +1255,7 @@ export class Program {
range: Range,
similarityLimit: number,
nameMap: AbbreviationMap | undefined,
libraryMap: Map<string, IndexResults> | undefined,
lazyEdit: boolean,
allowVariableInAll: boolean,
options: AutoImportOptions,
token: CancellationToken
): AutoImportResult[] {
const sourceFileInfo = this._getSourceFileInfoFromPath(filePath);
@ -1288,10 +1287,14 @@ export class Program {
const writtenWord = fileContents.substr(textRange.start, textRange.length);
const map = this._buildModuleSymbolsMap(
sourceFileInfo,
!!libraryMap,
!!options.libraryMap,
/* includeIndexUserSymbols */ true,
token
);
options.patternMatcher =
options.patternMatcher ?? ((p, t) => computeCompletionSimilarity(p, t) > similarityLimit);
const autoImporter = new AutoImporter(
this._configOptions.findExecEnvironment(filePath),
this._importResolver,
@ -1299,12 +1302,7 @@ export class Program {
range.start,
new CompletionMap(),
map,
{
lazyEdit,
allowVariableInAll,
libraryMap,
patternMatcher: (p, t) => computeCompletionSimilarity(p, t) > similarityLimit,
}
options
);
// Filter out any name that is already defined in the current scope.

View File

@ -55,6 +55,7 @@ import {
} from '../common/pathUtils';
import { DocumentRange, Position, Range } from '../common/textRange';
import { timingStats } from '../common/timing';
import { AutoImportOptions } from '../languageService/autoImporter';
import { AbbreviationMap, CompletionOptions, CompletionResultsList } from '../languageService/completionProvider';
import { DefinitionFilter } from '../languageService/definitionProvider';
import { IndexResults, WorkspaceSymbolCallback } from '../languageService/documentSymbolProvider';
@ -316,20 +317,11 @@ export class AnalyzerService {
range: Range,
similarityLimit: number,
nameMap: AbbreviationMap | undefined,
lazyEdit: boolean,
allowVariableInAll: boolean,
options: AutoImportOptions,
token: CancellationToken
) {
return this._program.getAutoImports(
filePath,
range,
similarityLimit,
nameMap,
this._backgroundAnalysisProgram.getIndexing(filePath),
lazyEdit,
allowVariableInAll,
token
);
options.libraryMap = options.libraryMap ?? this._backgroundAnalysisProgram.getIndexing(filePath);
return this._program.getAutoImports(filePath, range, similarityLimit, nameMap, options, token);
}
getDefinitionForPosition(

View File

@ -107,6 +107,7 @@ import { DocumentRange, Position, Range } from './common/textRange';
import { UriParser } from './common/uriParser';
import { convertWorkspaceDocumentEdits } from './common/workspaceEditUtils';
import { AnalyzerServiceExecutor } from './languageService/analyzerServiceExecutor';
import { ImportFormat } from './languageService/autoImporter';
import { CompletionItemData, CompletionOptions, CompletionResultsList } from './languageService/completionProvider';
import { DefinitionFilter } from './languageService/definitionProvider';
import { convertToFlatSymbols, WorkspaceSymbolCallback } from './languageService/documentSymbolProvider';
@ -1317,6 +1318,7 @@ export abstract class LanguageServerBase implements LanguageServerInterface {
lazyEdit: this.client.completionItemResolveSupportsAdditionalTextEdits,
autoImport: true,
extraCommitChars: false,
importFormat: ImportFormat.Absolute,
};
}

View File

@ -7,17 +7,21 @@
import { CancellationToken, CompletionItemKind, SymbolKind } from 'vscode-languageserver';
import { getFileInfo } from '../analyzer/analyzerNodeInfo';
import { DeclarationType } from '../analyzer/declaration';
import { ImportResolver, ModuleNameAndType } from '../analyzer/importResolver';
import { ImportType } from '../analyzer/importResult';
import {
getImportGroup,
getImportGroupFromModuleNameAndType,
getRelativeModuleName,
getTextEditsForAutoImportInsertion,
getTextEditsForAutoImportSymbolAddition,
getTopLevelImports,
ImportGroup,
ImportNameInfo,
ImportStatements,
ModuleNameInfo,
} from '../analyzer/importStatementUtils';
import { SourceFileInfo } from '../analyzer/program';
import { isUserCode } from '../analyzer/sourceFileInfoUtils';
@ -36,11 +40,16 @@ import { ParseResults } from '../parser/parser';
import { CompletionMap } from './completionProvider';
import { IndexAliasData, IndexResults } from './documentSymbolProvider';
export const enum ImportFormat {
Absolute = 'absolute',
Relative = 'relative',
}
export interface AutoImportSymbol {
readonly importAlias?: IndexAliasData | undefined;
readonly symbol?: Symbol | undefined;
readonly kind?: SymbolKind | undefined;
readonly itemKind?: CompletionItemKind | undefined;
readonly importAlias?: IndexAliasData;
readonly symbol?: Symbol;
readonly kind?: SymbolKind;
readonly itemKind?: CompletionItemKind;
}
export interface ModuleSymbolTable {
@ -50,31 +59,32 @@ export interface ModuleSymbolTable {
export type ModuleSymbolMap = Map<string, ModuleSymbolTable>;
export interface AbbreviationInfo {
importFrom?: string | undefined;
importFrom?: string;
importName: string;
}
export interface AutoImportResult {
name: string;
symbol?: Symbol | undefined;
source?: string | undefined;
symbol?: Symbol;
source?: string;
insertionText: string;
edits?: TextEditAction[] | undefined;
alias?: string | undefined;
kind?: CompletionItemKind | undefined;
edits?: TextEditAction[];
alias?: string;
kind?: CompletionItemKind;
}
export interface AutoImportOptions {
libraryMap?: Map<string, IndexResults> | undefined;
patternMatcher?: ((pattern: string, name: string) => boolean) | undefined;
allowVariableInAll?: boolean | undefined;
lazyEdit?: boolean | undefined;
libraryMap?: Map<string, IndexResults>;
patternMatcher?: (pattern: string, name: string) => boolean;
allowVariableInAll?: boolean;
lazyEdit?: boolean;
importFormat?: ImportFormat;
}
interface ImportParts {
importName: string;
symbolName?: string | undefined;
importFrom?: string | undefined;
symbolName?: string;
importFrom?: string;
filePath: string;
dotCount: number;
moduleNameAndType: ModuleNameAndType;
@ -83,9 +93,9 @@ interface ImportParts {
interface ImportAliasData {
importParts: ImportParts;
importGroup: ImportGroup;
symbol?: Symbol | undefined;
kind?: SymbolKind | undefined;
itemKind?: CompletionItemKind | undefined;
symbol?: Symbol;
kind?: SymbolKind;
itemKind?: CompletionItemKind;
}
type AutoImportResultMap = Map<string, AutoImportResult[]>;
@ -148,7 +158,7 @@ export function buildModuleSymbolsMap(
!declaration.isFinal
? SymbolKind.Variable
: undefined;
callbackfn({ symbol, kind: variableKind }, name, /* library */ false);
callbackfn({ symbol, kind: variableKind }, name, /* library */ !isUserCode(file));
});
},
});
@ -167,11 +177,12 @@ export function buildModuleSymbolsMap(
}
export class AutoImporter {
private _importStatements: ImportStatements;
private readonly _filePath: string;
private readonly _importStatements: ImportStatements;
// Track some auto import internal perf numbers.
private _stopWatch = new Duration();
private _perfInfo = {
private readonly _stopWatch = new Duration();
private readonly _perfInfo = {
indexUsed: false,
totalInMs: 0,
@ -193,6 +204,7 @@ export class AutoImporter {
private _moduleSymbolMap: ModuleSymbolMap,
private _options: AutoImportOptions
) {
this._filePath = getFileInfo(_parseResults.parseTree).filePath;
this._importStatements = getTopLevelImports(this._parseResults.parseTree, /* includeImplicitImports */ true);
this._perfInfo.indexUsed = !!this._options.libraryMap;
@ -321,7 +333,7 @@ export class AutoImporter {
private _processModuleSymbolTable(
topLevelSymbols: ModuleSymbolTable,
filePath: string,
moduleFilePath: string,
word: string,
similarityLimit: number,
isStubOrHasInit: { isStub: boolean; hasInit: boolean },
@ -332,7 +344,7 @@ export class AutoImporter {
) {
throwIfCancellationRequested(token);
const [importSource, importGroup, moduleNameAndType] = this._getImportPartsForSymbols(filePath);
const [importSource, importGroup, moduleNameAndType] = this._getImportPartsForSymbols(moduleFilePath);
if (!importSource) {
return;
}
@ -367,7 +379,7 @@ export class AutoImporter {
symbolName: name,
importName: name,
importFrom: importSource,
filePath,
filePath: moduleFilePath,
dotCount,
moduleNameAndType,
},
@ -381,13 +393,17 @@ export class AutoImporter {
return;
}
const nameForImportFrom =
this._options.importFormat === ImportFormat.Relative && !library
? getRelativeModuleName(this._importResolver.fileSystem, this._filePath, moduleFilePath)
: undefined;
const autoImportTextEdits = this._getTextEditsForAutoImportByFilePath(
importSource,
name,
abbrFromUsers,
{ name, alias: abbrFromUsers },
{ name: importSource, nameForImportFrom },
name,
importGroup,
filePath
moduleFilePath
);
this._addResult(results, {
@ -408,7 +424,7 @@ export class AutoImporter {
return;
}
const importParts = this._getImportParts(filePath);
const importParts = this._getImportParts(moduleFilePath);
if (!importParts) {
return;
}
@ -425,7 +441,7 @@ export class AutoImporter {
this._addToImportAliasMap(
{
modulePath: filePath,
modulePath: moduleFilePath,
originalName: importParts.importName,
kind: SymbolKind.Module,
itemKind: CompletionItemKind.Module,
@ -510,9 +526,10 @@ export class AutoImporter {
}
const autoImportTextEdits = this._getTextEditsForAutoImportByFilePath(
importAliasData.importParts.importFrom ?? importAliasData.importParts.importName,
importAliasData.importParts.symbolName,
abbrFromUsers,
{ name: importAliasData.importParts.symbolName, alias: abbrFromUsers },
{
name: importAliasData.importParts.importFrom ?? importAliasData.importParts.importName,
},
importAliasData.importParts.importName,
importAliasData.importGroup,
importAliasData.importParts.filePath
@ -685,9 +702,8 @@ export class AutoImporter {
}
private _getTextEditsForAutoImportByFilePath(
moduleName: string,
importName: string | undefined,
abbrFromUsers: string | undefined,
importNameInfo: ImportNameInfo,
moduleNameInfo: ModuleNameInfo,
insertionText: string,
importGroup: ImportGroup,
filePath: string
@ -700,11 +716,11 @@ export class AutoImporter {
// For now, we don't check whether alias or moduleName got overwritten at
// given position
const importAlias = importStatement.subnode?.alias?.value;
if (importName) {
if (importNameInfo.name) {
// ex) import module
// method | <= auto-import
return {
insertionText: `${importAlias ?? importStatement.moduleName}.${importName}`,
insertionText: `${importAlias ?? importStatement.moduleName}.${importNameInfo.name}`,
edits: [],
};
} else if (importAlias) {
@ -719,18 +735,18 @@ export class AutoImporter {
// Does an 'import from' statement already exist?
if (
importName &&
importNameInfo.name &&
importStatement.node.nodeType === ParseNodeType.ImportFrom &&
!importStatement.node.isWildcardImport
) {
// If so, see whether what we want already exist.
const importNode = importStatement.node.imports.find((i) => i.name.value === importName);
const importNode = importStatement.node.imports.find((i) => i.name.value === importNameInfo.name);
if (importNode) {
// For now, we don't check whether alias or moduleName got overwritten at
// given position
const importAlias = importNode.alias?.value;
return {
insertionText: `${importAlias ?? importName}`,
insertionText: `${importAlias ?? importNameInfo.name}`,
edits: [],
};
}
@ -738,25 +754,25 @@ export class AutoImporter {
// If not, add what we want at the existing 'import from' statement as long as
// what is imported is not module itself.
// ex) don't add "path" to existing "from os.path import dirname" statement.
if (moduleName === importStatement.moduleName) {
if (moduleNameInfo.name === importStatement.moduleName) {
return {
insertionText: abbrFromUsers ?? insertionText,
insertionText: importNameInfo.alias ?? insertionText,
edits: this._options.lazyEdit
? undefined
: getTextEditsForAutoImportSymbolAddition(
{ name: importName, alias: abbrFromUsers },
importNameInfo,
importStatement,
this._parseResults
),
};
}
}
} else if (importName) {
} else if (importNameInfo.name) {
// If it is the module itself that got imported, make sure we don't import it again.
// ex) from module import submodule
const imported = this._importStatements.orderedImports.find((i) => i.moduleName === moduleName);
const imported = this._importStatements.orderedImports.find((i) => i.moduleName === moduleNameInfo.name);
if (imported && imported.node.nodeType === ParseNodeType.ImportFrom && !imported.node.isWildcardImport) {
const importFrom = imported.node.imports.find((i) => i.name.value === importName);
const importFrom = imported.node.imports.find((i) => i.name.value === importNameInfo.name);
if (importFrom) {
// For now, we don't check whether alias or moduleName got overwritten at
// given position. only move to alias, but not the other way around
@ -770,14 +786,10 @@ export class AutoImporter {
} else {
// If not, add what we want at the existing import from statement.
return {
insertionText: abbrFromUsers ?? insertionText,
insertionText: importNameInfo.alias ?? insertionText,
edits: this._options.lazyEdit
? undefined
: getTextEditsForAutoImportSymbolAddition(
{ name: importName, alias: abbrFromUsers },
imported,
this._parseResults
),
: getTextEditsForAutoImportSymbolAddition(importNameInfo, imported, this._parseResults),
};
}
}
@ -789,20 +801,20 @@ export class AutoImporter {
// given position
const importAlias = importFrom.alias?.value;
return {
insertionText: `${importAlias ?? importFrom.name.value}.${importName}`,
insertionText: `${importAlias ?? importFrom.name.value}.${importNameInfo.name}`,
edits: [],
};
}
}
return {
insertionText: abbrFromUsers ?? insertionText,
insertionText: importNameInfo.alias ?? insertionText,
edits: this._options.lazyEdit
? undefined
: getTextEditsForAutoImportInsertion(
{ name: importName, alias: abbrFromUsers },
importNameInfo,
moduleNameInfo,
this._importStatements,
moduleName,
importGroup,
this._parseResults,
this._invocationPosition

View File

@ -112,7 +112,7 @@ import {
} from '../parser/parseNodes';
import { ParseResults } from '../parser/parser';
import { StringToken, StringTokenFlags, Token, TokenType } from '../parser/tokenizerTypes';
import { AbbreviationInfo, AutoImporter, AutoImportResult, ModuleSymbolMap } from './autoImporter';
import { AbbreviationInfo, AutoImporter, AutoImportResult, ImportFormat, ModuleSymbolMap } from './autoImporter';
import { DocumentSymbolCollector } from './documentSymbolCollector';
import { IndexResults } from './documentSymbolProvider';
import {
@ -282,6 +282,7 @@ export interface CompletionOptions {
lazyEdit: boolean;
autoImport: boolean;
extraCommitChars: boolean;
importFormat: ImportFormat;
}
export type AbbreviationMap = Map<string, AbbreviationInfo>;
@ -2241,7 +2242,11 @@ export class CompletionProvider {
this._position,
completionResults.completionMap,
moduleSymbolMap,
{ libraryMap: this._autoImportMaps.libraryMap, lazyEdit }
{
libraryMap: this._autoImportMaps.libraryMap,
lazyEdit,
importFormat: this._options.importFormat,
}
);
const results: AutoImportResult[] = [];

View File

@ -52,6 +52,7 @@ import { convertOffsetToPosition } from '../common/positionUtils';
import { TextRange } from '../common/textRange';
import { ModuleNameNode, NameNode, ParseNode, ParseNodeType } from '../parser/parseNodes';
import { ParseResults } from '../parser/parser';
import { ImportFormat } from './autoImporter';
export interface ImportData {
containsUnreferenceableSymbols: boolean;
@ -79,6 +80,7 @@ export class ImportAdder {
result: ImportData,
parseResults: ParseResults,
insertionPosition: number,
importFormat: ImportFormat,
token: CancellationToken
): TextEditAction[] {
throwIfCancellationRequested(token);
@ -94,6 +96,7 @@ export class ImportAdder {
continue;
}
const relativePath = getRelativeModuleName(this._importResolver.fileSystem, filePath, importInfo.filePath);
const moduleAndType = this._importResolver.getModuleNameForImport(importInfo.filePath, execEnv);
if (!moduleAndType.moduleName) {
if (!importInfo.nameInfo.name) {
@ -103,16 +106,17 @@ export class ImportAdder {
// module can't be addressed by absolute path in "from import" statement.
// ex) namespace package at [workspace root] or [workspace root]\__init__.py(i)
// use relative path
moduleAndType.moduleName = getRelativeModuleName(
this._importResolver.fileSystem,
filePath,
importInfo.filePath
);
importFormat = ImportFormat.Relative;
}
addIfUnique(
importNameInfo,
{ module: moduleAndType, name: importInfo.nameInfo.name, alias: importInfo.nameInfo.alias },
{
name: importInfo.nameInfo.name,
alias: importInfo.nameInfo.alias,
module: moduleAndType,
nameForImportFrom: importFormat === ImportFormat.Relative ? relativePath : undefined,
},
(a, b) => this._areSame(a, b)
);
}

View File

@ -100,8 +100,8 @@ function _addMissingOptionalToParam(
} else {
const additionalEditActions = getTextEditsForAutoImportInsertion(
{ name: 'Optional' },
{ name: 'typing' },
importStatements,
'typing',
ImportGroup.BuiltIn,
parseResults,
startPos

View File

@ -486,8 +486,8 @@ export class RenameModuleProvider {
this._addResultEdits(
getTextEditsForAutoImportInsertion(
[],
{ name: this._newModuleName },
importStatements,
this._newModuleName,
getImportGroupFromModuleNameAndType(this._newModuleNameAndType),
parseResults,
convertOffsetToPosition(parseResults.parseTree.length, parseResults.tokenizerOutput.lines)
@ -1324,8 +1324,8 @@ export class RenameModuleProvider {
return getTextEditsForAutoImportInsertion(
importNameInfo,
{ name: moduleName },
importStatements,
moduleName,
getImportGroupFromModuleNameAndType(this._newModuleNameAndType),
parseResults,
convertOffsetToPosition(parseResults.parseTree.length, parseResults.tokenizerOutput.lines)

View File

@ -17,6 +17,7 @@ import { ConfigOptions } from '../common/configOptions';
import { NullConsole } from '../common/console';
import { normalizeSlashes } from '../common/pathUtils';
import { convertOffsetsToRange, convertOffsetToPosition } from '../common/positionUtils';
import { ImportFormat } from '../languageService/autoImporter';
import { parseTestData } from './harness/fourslash/fourSlashParser';
import { TestAccessHost } from './harness/testAccessHost';
import * as host from './harness/testHost';
@ -54,6 +55,7 @@ test('check chained files', async () => {
snippet: false,
autoImport: false,
extraCommitChars: false,
importFormat: ImportFormat.Absolute,
},
undefined,
CancellationToken.None
@ -100,6 +102,7 @@ test('modify chained files', async () => {
snippet: false,
autoImport: false,
extraCommitChars: false,
importFormat: ImportFormat.Absolute,
},
undefined,
CancellationToken.None

View File

@ -65,7 +65,7 @@ import {
WellKnownWorkspaceKinds,
WorkspaceServiceInstance,
} from '../../../languageServerBase';
import { AbbreviationInfo } from '../../../languageService/autoImporter';
import { AbbreviationInfo, ImportFormat } from '../../../languageService/autoImporter';
import { CompletionOptions } from '../../../languageService/completionProvider';
import { DefinitionFilter } from '../../../languageService/definitionProvider';
import { convertHoverResults } from '../../../languageService/hoverProvider';
@ -1099,6 +1099,7 @@ export class TestState {
lazyEdit: true,
autoImport: true,
extraCommitChars: true,
importFormat: ImportFormat.Absolute,
};
const nameMap = abbrMap ? new Map<string, AbbreviationInfo>(Object.entries(abbrMap)) : undefined;
const result = await this.workspace.serviceInstance.getCompletionsForPosition(

View File

@ -10,6 +10,7 @@ import assert from 'assert';
import { CancellationToken } from 'vscode-languageserver';
import { rangesAreEqual, TextRange } from '../common/textRange';
import { ImportFormat } from '../languageService/autoImporter';
import { ImportAdder } from '../languageService/importAdder';
import { parseAndGetTestState } from './harness/fourslash/testState';
@ -1319,7 +1320,23 @@ test('move into the same file from import statement for submodule', () => {
testImportMove(code);
});
function testImportMove(code: string) {
test('use relative import format', () => {
const code = `
// @filename: test1.py
//// from nested import module
////
//// [|/*src*/module.foo()|]
// @filename: nested/__init__.py
//// [|{|"r":"from . import module!n!!n!!n!"|}|][|/*dest*/|]
// @filename: nested/module.py
//// def foo(): pass
`;
testImportMove(code, ImportFormat.Relative);
});
function testImportMove(code: string, importFormat = ImportFormat.Absolute) {
const state = parseAndGetTestState(code).state;
const src = state.getRangeByMarkerName('src')!;
@ -1336,6 +1353,7 @@ function testImportMove(code: string) {
importData,
state.program.getBoundSourceFile(dest.fileName)!.getParseResults()!,
dest.position,
importFormat,
CancellationToken.None
);