mirror of
https://github.com/microsoft/pyright.git
synced 2024-09-11 07:55:56 +03:00
Did a pass over pyright source code to improve consistency of file header comments. No functional change.
This commit is contained in:
parent
47efdfcf2c
commit
5cf4aedbbf
@ -1,200 +0,0 @@
|
||||
/*
|
||||
* aliasDeclarationUtils.ts
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
* Licensed under the MIT license.
|
||||
*
|
||||
* Helper functions around alias declarations.
|
||||
*/
|
||||
|
||||
import { ImportLookup, ImportLookupResult } from './analyzerFileInfo';
|
||||
import { Declaration, DeclarationType } from './declaration';
|
||||
import { Symbol } from './symbol';
|
||||
|
||||
export interface ResolvedAliasInfo {
|
||||
declaration: Declaration | undefined;
|
||||
isPrivate: boolean;
|
||||
privatePyTypedImported?: string;
|
||||
privatePyTypedImporter?: string;
|
||||
}
|
||||
|
||||
// If the specified declaration is an alias declaration that points to a symbol,
|
||||
// it resolves the alias and looks up the symbol, then returns the a declaration
|
||||
// (typically the last) associated with that symbol. It does this recursively if
|
||||
// necessary. If a symbol lookup fails, undefined is returned. If resolveLocalNames
|
||||
// is true, the method resolves aliases through local renames ("as" clauses found
|
||||
// in import statements).
|
||||
export function resolveAliasDeclaration(
|
||||
importLookup: ImportLookup,
|
||||
declaration: Declaration,
|
||||
resolveLocalNames: boolean,
|
||||
allowExternallyHiddenAccess: boolean
|
||||
): ResolvedAliasInfo | undefined {
|
||||
let curDeclaration: Declaration | undefined = declaration;
|
||||
const alreadyVisited: Declaration[] = [];
|
||||
let isPrivate = false;
|
||||
|
||||
// These variables are used to find a transition from a non-py.typed to
|
||||
// a py.typed resolution chain. In this case, if the imported symbol
|
||||
// is a private symbol (i.e. not intended to be re-exported), we store
|
||||
// the name of the importer and imported modules so the caller can
|
||||
// report an error.
|
||||
let sawPyTypedTransition = false;
|
||||
let privatePyTypedImported: string | undefined;
|
||||
let privatePyTypedImporter: string | undefined;
|
||||
|
||||
while (true) {
|
||||
if (curDeclaration.type !== DeclarationType.Alias || !curDeclaration.symbolName) {
|
||||
return {
|
||||
declaration: curDeclaration,
|
||||
isPrivate,
|
||||
privatePyTypedImported,
|
||||
privatePyTypedImporter,
|
||||
};
|
||||
}
|
||||
|
||||
// If we are not supposed to follow local alias names and this
|
||||
// is a local name, don't continue to follow the alias.
|
||||
if (!resolveLocalNames && curDeclaration.usesLocalName) {
|
||||
return {
|
||||
declaration: curDeclaration,
|
||||
isPrivate,
|
||||
privatePyTypedImported,
|
||||
privatePyTypedImporter,
|
||||
};
|
||||
}
|
||||
|
||||
let lookupResult: ImportLookupResult | undefined;
|
||||
if (curDeclaration.path && curDeclaration.loadSymbolsFromPath) {
|
||||
lookupResult = importLookup(curDeclaration.path);
|
||||
}
|
||||
|
||||
const symbol: Symbol | undefined = lookupResult
|
||||
? lookupResult.symbolTable.get(curDeclaration.symbolName)
|
||||
: undefined;
|
||||
if (!symbol) {
|
||||
if (curDeclaration.submoduleFallback) {
|
||||
if (curDeclaration.symbolName) {
|
||||
// See if we are resolving a specific imported symbol name and the submodule
|
||||
// fallback cannot be resolved. For example, `from a import b`. If b is both
|
||||
// a symbol in `a/__init__.py` and a submodule `a/b.py` and we are not using
|
||||
// type information from this library (e.g. a non-py.typed library source file
|
||||
// when useLibraryCodeForTypes is disabled), b should be evaluated as Unknown,
|
||||
// not as a module.
|
||||
if (
|
||||
curDeclaration.submoduleFallback.type === DeclarationType.Alias &&
|
||||
curDeclaration.submoduleFallback.path
|
||||
) {
|
||||
const lookupResult = importLookup(curDeclaration.submoduleFallback.path);
|
||||
if (!lookupResult) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return resolveAliasDeclaration(
|
||||
importLookup,
|
||||
curDeclaration.submoduleFallback,
|
||||
resolveLocalNames,
|
||||
allowExternallyHiddenAccess
|
||||
);
|
||||
}
|
||||
|
||||
// If the symbol comes from a native library, we won't
|
||||
// be able to resolve its type directly.
|
||||
if (curDeclaration.isNativeLib) {
|
||||
return {
|
||||
declaration: undefined,
|
||||
isPrivate,
|
||||
};
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (symbol.isPrivateMember()) {
|
||||
isPrivate = true;
|
||||
}
|
||||
|
||||
if (symbol.isExternallyHidden() && !allowExternallyHiddenAccess) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Prefer declarations with specified types. If we don't have any of those,
|
||||
// fall back on declarations with inferred types.
|
||||
let declarations = symbol.getTypedDeclarations();
|
||||
|
||||
// Try not to use declarations within an except suite even if it's a typed
|
||||
// declaration. These are typically used for fallback exception handling.
|
||||
declarations = declarations.filter((decl) => !decl.isInExceptSuite);
|
||||
|
||||
if (declarations.length === 0) {
|
||||
declarations = symbol.getDeclarations();
|
||||
declarations = declarations.filter((decl) => !decl.isInExceptSuite);
|
||||
}
|
||||
|
||||
if (declarations.length === 0) {
|
||||
// Use declarations within except clauses if there are no alternatives.
|
||||
declarations = symbol.getDeclarations();
|
||||
}
|
||||
|
||||
if (declarations.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Prefer the last unvisited declaration in the list. This ensures that
|
||||
// we use all of the overloads if it's an overloaded function.
|
||||
const unvisitedDecls = declarations.filter((decl) => !alreadyVisited.includes(decl));
|
||||
if (unvisitedDecls.length > 0) {
|
||||
curDeclaration = unvisitedDecls[unvisitedDecls.length - 1];
|
||||
} else {
|
||||
curDeclaration = declarations[declarations.length - 1];
|
||||
}
|
||||
|
||||
if (lookupResult?.isInPyTypedPackage) {
|
||||
if (!sawPyTypedTransition) {
|
||||
if (symbol.isPrivatePyTypedImport()) {
|
||||
privatePyTypedImporter = curDeclaration?.moduleName;
|
||||
}
|
||||
|
||||
// Note that we've seen a transition from a non-py.typed to a py.typed
|
||||
// import. No further check is needed.
|
||||
sawPyTypedTransition = true;
|
||||
} else {
|
||||
// If we've already seen a transition, look for the first non-private
|
||||
// symbol that is resolved so we can tell the user to import from this
|
||||
// location instead.
|
||||
if (!symbol.isPrivatePyTypedImport()) {
|
||||
privatePyTypedImported = privatePyTypedImported ?? curDeclaration?.moduleName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure we don't follow a circular list indefinitely.
|
||||
if (alreadyVisited.find((decl) => decl === curDeclaration)) {
|
||||
// If the path path of the alias points back to the original path, use the submodule
|
||||
// fallback instead. This happens in the case where a module's __init__.py file
|
||||
// imports a submodule using itself as the import target. For example, if
|
||||
// the module is foo, and the foo.__init__.py file contains the statement
|
||||
// "from foo import bar", we want to import the foo/bar.py submodule.
|
||||
if (
|
||||
curDeclaration.path === declaration.path &&
|
||||
curDeclaration.type === DeclarationType.Alias &&
|
||||
curDeclaration.submoduleFallback
|
||||
) {
|
||||
return resolveAliasDeclaration(
|
||||
importLookup,
|
||||
curDeclaration.submoduleFallback,
|
||||
resolveLocalNames,
|
||||
allowExternallyHiddenAccess
|
||||
);
|
||||
}
|
||||
return {
|
||||
declaration,
|
||||
isPrivate,
|
||||
privatePyTypedImported,
|
||||
privatePyTypedImporter,
|
||||
};
|
||||
}
|
||||
alreadyVisited.push(curDeclaration);
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@
|
||||
* Licensed under the MIT license.
|
||||
* Author: Eric Traut
|
||||
*
|
||||
* A singleton that tracks the size of caches and empty them
|
||||
* A singleton that tracks the size of caches and empties them
|
||||
* if memory usage approaches the max heap space.
|
||||
*/
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
* and checked. It also performs some additional checks that
|
||||
* cannot (or should not be) performed lazily.
|
||||
*/
|
||||
|
||||
import { CancellationToken } from 'vscode-languageserver';
|
||||
|
||||
import { Commands } from '../commands/commands';
|
||||
@ -95,6 +96,7 @@ import { Declaration, DeclarationType, isAliasDeclaration } from './declaration'
|
||||
import { createImportedModuleDescriptor, ImportedModuleDescriptor, ImportResolver } from './importResolver';
|
||||
import { ImportResult, ImportType } from './importResult';
|
||||
import { getRelativeModuleName, getTopLevelImports } from './importStatementUtils';
|
||||
import { getParameterListDetails } from './parameterUtils';
|
||||
import * as ParseTreeUtils from './parseTreeUtils';
|
||||
import { ParseTreeWalker } from './parseTreeWalker';
|
||||
import { validateClassPattern } from './patternMatching';
|
||||
@ -158,7 +160,6 @@ import {
|
||||
getDeclaredGeneratorReturnType,
|
||||
getGeneratorTypeArgs,
|
||||
getGeneratorYieldType,
|
||||
getParameterListDetails,
|
||||
getProtocolSymbols,
|
||||
getTypeVarArgumentsRecursive,
|
||||
getTypeVarScopeId,
|
||||
|
@ -15,17 +15,16 @@ import { DiagnosticRule } from '../common/diagnosticRules';
|
||||
import { Localizer } from '../localization/localize';
|
||||
import { ArgumentCategory, ExpressionNode, ParameterCategory } from '../parser/parseNodes';
|
||||
import { getFileInfo } from './analyzerNodeInfo';
|
||||
import { getParameterListDetails, ParameterSource } from './parameterUtils';
|
||||
import { Symbol, SymbolFlags } from './symbol';
|
||||
import { FunctionArgument, FunctionResult, TypeEvaluator } from './typeEvaluatorTypes';
|
||||
import { ClassType, FunctionParameter, FunctionType, isClassInstance, isFunction, isTypeSame } from './types';
|
||||
import {
|
||||
applySolvedTypeVars,
|
||||
convertToInstance,
|
||||
getParameterListDetails,
|
||||
getTypeVarScopeId,
|
||||
lookUpObjectMember,
|
||||
makeInferenceContext,
|
||||
ParameterSource,
|
||||
} from './typeUtils';
|
||||
import { TypeVarContext } from './typeVarContext';
|
||||
|
||||
|
@ -9,8 +9,17 @@
|
||||
|
||||
import { getEmptyRange } from '../common/textRange';
|
||||
import { NameNode, ParseNodeType } from '../parser/parseNodes';
|
||||
import { ImportLookup, ImportLookupResult } from './analyzerFileInfo';
|
||||
import { AliasDeclaration, Declaration, DeclarationType, isAliasDeclaration, ModuleLoaderActions } from './declaration';
|
||||
import { getFileInfoFromNode } from './parseTreeUtils';
|
||||
import { Symbol } from './symbol';
|
||||
|
||||
export interface ResolvedAliasInfo {
|
||||
declaration: Declaration | undefined;
|
||||
isPrivate: boolean;
|
||||
privatePyTypedImported?: string;
|
||||
privatePyTypedImporter?: string;
|
||||
}
|
||||
|
||||
export function hasTypeForDeclaration(declaration: Declaration): boolean {
|
||||
switch (declaration.type) {
|
||||
@ -200,3 +209,185 @@ export function createSynthesizedAliasDeclaration(path: string): AliasDeclaratio
|
||||
isInExceptSuite: false,
|
||||
};
|
||||
}
|
||||
|
||||
// If the specified declaration is an alias declaration that points to a symbol,
|
||||
// it resolves the alias and looks up the symbol, then returns the a declaration
|
||||
// (typically the last) associated with that symbol. It does this recursively if
|
||||
// necessary. If a symbol lookup fails, undefined is returned. If resolveLocalNames
|
||||
// is true, the method resolves aliases through local renames ("as" clauses found
|
||||
// in import statements).
|
||||
export function resolveAliasDeclaration(
|
||||
importLookup: ImportLookup,
|
||||
declaration: Declaration,
|
||||
resolveLocalNames: boolean,
|
||||
allowExternallyHiddenAccess: boolean
|
||||
): ResolvedAliasInfo | undefined {
|
||||
let curDeclaration: Declaration | undefined = declaration;
|
||||
const alreadyVisited: Declaration[] = [];
|
||||
let isPrivate = false;
|
||||
|
||||
// These variables are used to find a transition from a non-py.typed to
|
||||
// a py.typed resolution chain. In this case, if the imported symbol
|
||||
// is a private symbol (i.e. not intended to be re-exported), we store
|
||||
// the name of the importer and imported modules so the caller can
|
||||
// report an error.
|
||||
let sawPyTypedTransition = false;
|
||||
let privatePyTypedImported: string | undefined;
|
||||
let privatePyTypedImporter: string | undefined;
|
||||
|
||||
while (true) {
|
||||
if (curDeclaration.type !== DeclarationType.Alias || !curDeclaration.symbolName) {
|
||||
return {
|
||||
declaration: curDeclaration,
|
||||
isPrivate,
|
||||
privatePyTypedImported,
|
||||
privatePyTypedImporter,
|
||||
};
|
||||
}
|
||||
|
||||
// If we are not supposed to follow local alias names and this
|
||||
// is a local name, don't continue to follow the alias.
|
||||
if (!resolveLocalNames && curDeclaration.usesLocalName) {
|
||||
return {
|
||||
declaration: curDeclaration,
|
||||
isPrivate,
|
||||
privatePyTypedImported,
|
||||
privatePyTypedImporter,
|
||||
};
|
||||
}
|
||||
|
||||
let lookupResult: ImportLookupResult | undefined;
|
||||
if (curDeclaration.path && curDeclaration.loadSymbolsFromPath) {
|
||||
lookupResult = importLookup(curDeclaration.path);
|
||||
}
|
||||
|
||||
const symbol: Symbol | undefined = lookupResult
|
||||
? lookupResult.symbolTable.get(curDeclaration.symbolName)
|
||||
: undefined;
|
||||
if (!symbol) {
|
||||
if (curDeclaration.submoduleFallback) {
|
||||
if (curDeclaration.symbolName) {
|
||||
// See if we are resolving a specific imported symbol name and the submodule
|
||||
// fallback cannot be resolved. For example, `from a import b`. If b is both
|
||||
// a symbol in `a/__init__.py` and a submodule `a/b.py` and we are not using
|
||||
// type information from this library (e.g. a non-py.typed library source file
|
||||
// when useLibraryCodeForTypes is disabled), b should be evaluated as Unknown,
|
||||
// not as a module.
|
||||
if (
|
||||
curDeclaration.submoduleFallback.type === DeclarationType.Alias &&
|
||||
curDeclaration.submoduleFallback.path
|
||||
) {
|
||||
const lookupResult = importLookup(curDeclaration.submoduleFallback.path);
|
||||
if (!lookupResult) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return resolveAliasDeclaration(
|
||||
importLookup,
|
||||
curDeclaration.submoduleFallback,
|
||||
resolveLocalNames,
|
||||
allowExternallyHiddenAccess
|
||||
);
|
||||
}
|
||||
|
||||
// If the symbol comes from a native library, we won't
|
||||
// be able to resolve its type directly.
|
||||
if (curDeclaration.isNativeLib) {
|
||||
return {
|
||||
declaration: undefined,
|
||||
isPrivate,
|
||||
};
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (symbol.isPrivateMember()) {
|
||||
isPrivate = true;
|
||||
}
|
||||
|
||||
if (symbol.isExternallyHidden() && !allowExternallyHiddenAccess) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Prefer declarations with specified types. If we don't have any of those,
|
||||
// fall back on declarations with inferred types.
|
||||
let declarations = symbol.getTypedDeclarations();
|
||||
|
||||
// Try not to use declarations within an except suite even if it's a typed
|
||||
// declaration. These are typically used for fallback exception handling.
|
||||
declarations = declarations.filter((decl) => !decl.isInExceptSuite);
|
||||
|
||||
if (declarations.length === 0) {
|
||||
declarations = symbol.getDeclarations();
|
||||
declarations = declarations.filter((decl) => !decl.isInExceptSuite);
|
||||
}
|
||||
|
||||
if (declarations.length === 0) {
|
||||
// Use declarations within except clauses if there are no alternatives.
|
||||
declarations = symbol.getDeclarations();
|
||||
}
|
||||
|
||||
if (declarations.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Prefer the last unvisited declaration in the list. This ensures that
|
||||
// we use all of the overloads if it's an overloaded function.
|
||||
const unvisitedDecls = declarations.filter((decl) => !alreadyVisited.includes(decl));
|
||||
if (unvisitedDecls.length > 0) {
|
||||
curDeclaration = unvisitedDecls[unvisitedDecls.length - 1];
|
||||
} else {
|
||||
curDeclaration = declarations[declarations.length - 1];
|
||||
}
|
||||
|
||||
if (lookupResult?.isInPyTypedPackage) {
|
||||
if (!sawPyTypedTransition) {
|
||||
if (symbol.isPrivatePyTypedImport()) {
|
||||
privatePyTypedImporter = curDeclaration?.moduleName;
|
||||
}
|
||||
|
||||
// Note that we've seen a transition from a non-py.typed to a py.typed
|
||||
// import. No further check is needed.
|
||||
sawPyTypedTransition = true;
|
||||
} else {
|
||||
// If we've already seen a transition, look for the first non-private
|
||||
// symbol that is resolved so we can tell the user to import from this
|
||||
// location instead.
|
||||
if (!symbol.isPrivatePyTypedImport()) {
|
||||
privatePyTypedImported = privatePyTypedImported ?? curDeclaration?.moduleName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure we don't follow a circular list indefinitely.
|
||||
if (alreadyVisited.find((decl) => decl === curDeclaration)) {
|
||||
// If the path path of the alias points back to the original path, use the submodule
|
||||
// fallback instead. This happens in the case where a module's __init__.py file
|
||||
// imports a submodule using itself as the import target. For example, if
|
||||
// the module is foo, and the foo.__init__.py file contains the statement
|
||||
// "from foo import bar", we want to import the foo/bar.py submodule.
|
||||
if (
|
||||
curDeclaration.path === declaration.path &&
|
||||
curDeclaration.type === DeclarationType.Alias &&
|
||||
curDeclaration.submoduleFallback
|
||||
) {
|
||||
return resolveAliasDeclaration(
|
||||
importLookup,
|
||||
curDeclaration.submoduleFallback,
|
||||
resolveLocalNames,
|
||||
allowExternallyHiddenAccess
|
||||
);
|
||||
}
|
||||
return {
|
||||
declaration,
|
||||
isPrivate,
|
||||
privatePyTypedImported,
|
||||
privatePyTypedImporter,
|
||||
};
|
||||
}
|
||||
alreadyVisited.push(curDeclaration);
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
* Author: Eric Traut
|
||||
*
|
||||
* Utility routines for summarizing and manipulating
|
||||
* import statements in a python source file.
|
||||
* import statements in a Python source file.
|
||||
*/
|
||||
|
||||
import { CancellationToken } from 'vscode-languageserver';
|
||||
|
@ -7,7 +7,17 @@
|
||||
*/
|
||||
|
||||
import { ParameterCategory } from '../parser/parseNodes';
|
||||
import { ClassType, FunctionParameter, isClassInstance, isUnpackedClass } from './types';
|
||||
import { isDunderName } from './symbolNameUtils';
|
||||
import {
|
||||
ClassType,
|
||||
FunctionParameter,
|
||||
FunctionType,
|
||||
isClassInstance,
|
||||
isUnpackedClass,
|
||||
isVariadicTypeVar,
|
||||
Type,
|
||||
} from './types';
|
||||
import { partiallySpecializeType } from './typeUtils';
|
||||
|
||||
export function isTypedKwargs(param: FunctionParameter): boolean {
|
||||
return (
|
||||
@ -18,3 +28,253 @@ export function isTypedKwargs(param: FunctionParameter): boolean {
|
||||
!!param.type.details.typedDictEntries
|
||||
);
|
||||
}
|
||||
|
||||
export enum ParameterSource {
|
||||
PositionOnly,
|
||||
PositionOrKeyword,
|
||||
KeywordOnly,
|
||||
}
|
||||
|
||||
export interface VirtualParameterDetails {
|
||||
param: FunctionParameter;
|
||||
type: Type;
|
||||
defaultArgType?: Type | undefined;
|
||||
index: number;
|
||||
source: ParameterSource;
|
||||
}
|
||||
|
||||
export interface ParameterListDetails {
|
||||
// Virtual parameter list that refers to original parameters
|
||||
params: VirtualParameterDetails[];
|
||||
|
||||
// Counts of virtual parameters
|
||||
positionOnlyParamCount: number;
|
||||
positionParamCount: number;
|
||||
|
||||
// Indexes into virtual parameter list
|
||||
kwargsIndex?: number;
|
||||
argsIndex?: number;
|
||||
firstKeywordOnlyIndex?: number;
|
||||
firstPositionOrKeywordIndex: number;
|
||||
|
||||
// Other information
|
||||
hasUnpackedVariadicTypeVar: boolean;
|
||||
hasUnpackedTypedDict: boolean;
|
||||
}
|
||||
|
||||
// Examines the input parameters within a function signature and creates a
|
||||
// "virtual list" of parameters, stripping out any markers and expanding
|
||||
// any *args with unpacked tuples.
|
||||
export function getParameterListDetails(type: FunctionType): ParameterListDetails {
|
||||
const result: ParameterListDetails = {
|
||||
firstPositionOrKeywordIndex: 0,
|
||||
positionParamCount: 0,
|
||||
positionOnlyParamCount: 0,
|
||||
params: [],
|
||||
hasUnpackedVariadicTypeVar: false,
|
||||
hasUnpackedTypedDict: false,
|
||||
};
|
||||
|
||||
let positionOnlyIndex = type.details.parameters.findIndex(
|
||||
(p) => p.category === ParameterCategory.Simple && !p.name
|
||||
);
|
||||
|
||||
// Handle the old (pre Python 3.8) way of specifying positional-only
|
||||
// parameters by naming them with "__".
|
||||
if (positionOnlyIndex < 0) {
|
||||
for (let i = 0; i < type.details.parameters.length; i++) {
|
||||
const p = type.details.parameters[i];
|
||||
if (p.category !== ParameterCategory.Simple) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!p.name) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (isDunderName(p.name) || !p.name.startsWith('__')) {
|
||||
break;
|
||||
}
|
||||
|
||||
positionOnlyIndex = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (positionOnlyIndex >= 0) {
|
||||
result.firstPositionOrKeywordIndex = positionOnlyIndex;
|
||||
}
|
||||
|
||||
for (let i = 0; i < positionOnlyIndex; i++) {
|
||||
if (type.details.parameters[i].hasDefault) {
|
||||
break;
|
||||
}
|
||||
|
||||
result.positionOnlyParamCount++;
|
||||
}
|
||||
|
||||
let sawKeywordOnlySeparator = false;
|
||||
|
||||
const addVirtualParameter = (
|
||||
param: FunctionParameter,
|
||||
index: number,
|
||||
typeOverride?: Type,
|
||||
defaultArgTypeOverride?: Type,
|
||||
sourceOverride?: ParameterSource
|
||||
) => {
|
||||
if (param.name) {
|
||||
let source: ParameterSource;
|
||||
if (sourceOverride !== undefined) {
|
||||
source = sourceOverride;
|
||||
} else if (param.category === ParameterCategory.VarArgList) {
|
||||
source = ParameterSource.PositionOnly;
|
||||
} else if (sawKeywordOnlySeparator) {
|
||||
source = ParameterSource.KeywordOnly;
|
||||
} else if (positionOnlyIndex >= 0 && index < positionOnlyIndex) {
|
||||
source = ParameterSource.PositionOnly;
|
||||
} else {
|
||||
source = ParameterSource.PositionOrKeyword;
|
||||
}
|
||||
|
||||
result.params.push({
|
||||
param,
|
||||
index,
|
||||
type: typeOverride ?? FunctionType.getEffectiveParameterType(type, index),
|
||||
defaultArgType: defaultArgTypeOverride,
|
||||
source,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
type.details.parameters.forEach((param, index) => {
|
||||
if (param.category === ParameterCategory.VarArgList) {
|
||||
// If this is an unpacked tuple, expand the entries.
|
||||
const paramType = FunctionType.getEffectiveParameterType(type, index);
|
||||
if (param.name && isUnpackedClass(paramType) && paramType.tupleTypeArguments) {
|
||||
const addToPositionalOnly = index < result.positionOnlyParamCount;
|
||||
|
||||
paramType.tupleTypeArguments.forEach((tupleArg, tupleIndex) => {
|
||||
const category =
|
||||
isVariadicTypeVar(tupleArg.type) || tupleArg.isUnbounded
|
||||
? ParameterCategory.VarArgList
|
||||
: ParameterCategory.Simple;
|
||||
|
||||
if (category === ParameterCategory.VarArgList) {
|
||||
result.argsIndex = result.params.length;
|
||||
}
|
||||
|
||||
if (isVariadicTypeVar(param.type)) {
|
||||
result.hasUnpackedVariadicTypeVar = true;
|
||||
}
|
||||
|
||||
addVirtualParameter(
|
||||
{
|
||||
category,
|
||||
name: `${param.name}[${tupleIndex.toString()}]`,
|
||||
isNameSynthesized: true,
|
||||
type: tupleArg.type,
|
||||
hasDeclaredType: true,
|
||||
},
|
||||
index,
|
||||
tupleArg.type,
|
||||
/* defaultArgTypeOverride */ undefined,
|
||||
ParameterSource.PositionOnly
|
||||
);
|
||||
|
||||
if (category === ParameterCategory.Simple) {
|
||||
result.positionParamCount++;
|
||||
}
|
||||
|
||||
if (tupleIndex > 0 && addToPositionalOnly) {
|
||||
result.positionOnlyParamCount++;
|
||||
}
|
||||
});
|
||||
|
||||
// Normally, a VarArgList parameter (either named or as an unnamed separator)
|
||||
// would signify the start of keyword-only parameters. However, we can construct
|
||||
// callable signatures that defy this rule by using Callable and TypeVarTuples
|
||||
// or unpacked tuples.
|
||||
if (!sawKeywordOnlySeparator && (positionOnlyIndex < 0 || index >= positionOnlyIndex)) {
|
||||
result.firstKeywordOnlyIndex = result.params.length;
|
||||
sawKeywordOnlySeparator = true;
|
||||
}
|
||||
} else {
|
||||
if (param.name && result.argsIndex === undefined) {
|
||||
result.argsIndex = result.params.length;
|
||||
|
||||
if (isVariadicTypeVar(param.type)) {
|
||||
result.hasUnpackedVariadicTypeVar = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Normally, a VarArgList parameter (either named or as an unnamed separator)
|
||||
// would signify the start of keyword-only parameters. However, we can construct
|
||||
// callable signatures that defy this rule by using Callable and TypeVarTuples
|
||||
// or unpacked tuples.
|
||||
if (!sawKeywordOnlySeparator && (positionOnlyIndex < 0 || index >= positionOnlyIndex)) {
|
||||
result.firstKeywordOnlyIndex = result.params.length;
|
||||
if (param.name) {
|
||||
result.firstKeywordOnlyIndex++;
|
||||
}
|
||||
sawKeywordOnlySeparator = true;
|
||||
}
|
||||
|
||||
addVirtualParameter(param, index);
|
||||
}
|
||||
} else if (param.category === ParameterCategory.VarArgDictionary) {
|
||||
sawKeywordOnlySeparator = true;
|
||||
|
||||
const paramType = FunctionType.getEffectiveParameterType(type, index);
|
||||
|
||||
// Is this an unpacked TypedDict? If so, expand the entries.
|
||||
if (isClassInstance(paramType) && isUnpackedClass(paramType) && paramType.details.typedDictEntries) {
|
||||
if (result.firstKeywordOnlyIndex === undefined) {
|
||||
result.firstKeywordOnlyIndex = result.params.length;
|
||||
}
|
||||
|
||||
const typedDictType = paramType;
|
||||
paramType.details.typedDictEntries.forEach((entry, name) => {
|
||||
const specializedParamType = partiallySpecializeType(entry.valueType, typedDictType);
|
||||
|
||||
addVirtualParameter(
|
||||
{
|
||||
category: ParameterCategory.Simple,
|
||||
name,
|
||||
type: specializedParamType,
|
||||
hasDeclaredType: true,
|
||||
hasDefault: !entry.isRequired,
|
||||
},
|
||||
index,
|
||||
specializedParamType
|
||||
);
|
||||
});
|
||||
|
||||
result.hasUnpackedTypedDict = true;
|
||||
} else if (param.name) {
|
||||
if (result.kwargsIndex === undefined) {
|
||||
result.kwargsIndex = result.params.length;
|
||||
}
|
||||
|
||||
if (result.firstKeywordOnlyIndex === undefined) {
|
||||
result.firstKeywordOnlyIndex = result.params.length;
|
||||
}
|
||||
|
||||
addVirtualParameter(param, index);
|
||||
}
|
||||
} else if (param.category === ParameterCategory.Simple) {
|
||||
if (param.name && !sawKeywordOnlySeparator) {
|
||||
result.positionParamCount++;
|
||||
}
|
||||
|
||||
addVirtualParameter(
|
||||
param,
|
||||
index,
|
||||
/* typeOverride */ undefined,
|
||||
type.specializedTypes?.parameterDefaultArgs
|
||||
? type.specializedTypes?.parameterDefaultArgs[index]
|
||||
: undefined
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Licensed under the MIT license.
|
||||
* Author: Eric Traut
|
||||
*
|
||||
* Utility routines used to resolve various paths in python.
|
||||
* Utility routines used to resolve various paths in Python.
|
||||
*/
|
||||
|
||||
import { ConfigOptions } from '../common/configOptions';
|
||||
|
@ -41,8 +41,8 @@ export function getRegionComments(parseResults: ParseResults): RegionComment[] {
|
||||
|
||||
// A comment starting with "region" or "endregion" is only treated as a region/endregion
|
||||
// if it is not followed by an identifier character.
|
||||
const StartRegionRegx = /^\s*region\b/;
|
||||
const EndRegionRegex = /^\s*endregion\b/;
|
||||
const StartRegionRegEx = /^\s*region\b/;
|
||||
const EndRegionRegEx = /^\s*endregion\b/;
|
||||
|
||||
function getRegionCommentType(comment: Comment, parseResults: ParseResults): RegionCommentType | undefined {
|
||||
const hashOffset = comment.start - 1;
|
||||
@ -58,8 +58,8 @@ function getRegionCommentType(comment: Comment, parseResults: ParseResults): Reg
|
||||
}
|
||||
}
|
||||
|
||||
const startRegionMatch = StartRegionRegx.exec(comment.value);
|
||||
const endRegionMatch = EndRegionRegex.exec(comment.value);
|
||||
const startRegionMatch = StartRegionRegEx.exec(comment.value);
|
||||
const endRegionMatch = EndRegionRegEx.exec(comment.value);
|
||||
|
||||
if (startRegionMatch) {
|
||||
return RegionCommentType.Region;
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Licensed under the MIT license.
|
||||
* Author: Eric Traut
|
||||
*
|
||||
* A persistent service that is able to analyze a collection of
|
||||
* A service that is able to analyze a collection of
|
||||
* Python files.
|
||||
*/
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Licensed under the MIT license.
|
||||
* Author: Eric Traut
|
||||
*
|
||||
* Class that represents a single python source file.
|
||||
* Class that represents a single Python source or stub file.
|
||||
*/
|
||||
|
||||
import {
|
||||
|
@ -3,7 +3,7 @@
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
* Licensed under the MIT license.
|
||||
*
|
||||
* Collection of functions that operate on SourceFileInfo objects.
|
||||
* Functions that operate on SourceFileInfo objects.
|
||||
*/
|
||||
|
||||
import { SourceFileInfo } from './program';
|
||||
|
@ -3,7 +3,7 @@
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
* Licensed under the MIT license.
|
||||
*
|
||||
* Logic that maps a (.pyi) stub to its (.py) implementation source file.
|
||||
* Logic that maps a ".pyi" stub to its ".py" source file.
|
||||
*/
|
||||
|
||||
import { CancellationToken } from 'vscode-jsonrpc';
|
||||
|
@ -12,6 +12,22 @@ class NumberReference {
|
||||
value = 0;
|
||||
}
|
||||
|
||||
// Builds an array of imports from the 'from' to the 'to' entry where 'from'
|
||||
// is on the front of the array and the item just before 'to' is on the
|
||||
// back of the array.
|
||||
export function buildImportTree(
|
||||
to: string,
|
||||
from: string,
|
||||
next: (from: string) => string[],
|
||||
token: CancellationToken
|
||||
): string[] {
|
||||
const totalCountRef = new NumberReference();
|
||||
const results = _buildImportTreeImpl(to, from, next, [], totalCountRef, token);
|
||||
|
||||
// Result should always have the 'from' node in it.
|
||||
return results.length > 0 ? results : [from];
|
||||
}
|
||||
|
||||
function _buildImportTreeImpl(
|
||||
to: string,
|
||||
from: string,
|
||||
@ -29,47 +45,23 @@ function _buildImportTreeImpl(
|
||||
if (from === to) {
|
||||
// At the top, previous should have our way into this recursion.
|
||||
return previous.length ? previous : [from];
|
||||
} else if (previous.length > 1 && previous.find((s) => s === from)) {
|
||||
}
|
||||
|
||||
if (previous.length > 1 && previous.find((s) => s === from)) {
|
||||
// Fail the search, we're stuck in a loop.
|
||||
return [];
|
||||
} else {
|
||||
const nextEntries = next(from);
|
||||
for (let i = 0; i < nextEntries.length && !token.isCancellationRequested; i++) {
|
||||
// Do a search through the next level to get to the 'to' entry.
|
||||
const subentries = _buildImportTreeImpl(
|
||||
to,
|
||||
nextEntries[i],
|
||||
next,
|
||||
[...previous, from],
|
||||
totalSearched,
|
||||
token
|
||||
);
|
||||
if (subentries.length > 0) {
|
||||
return subentries;
|
||||
}
|
||||
}
|
||||
|
||||
const nextEntries = next(from);
|
||||
for (let i = 0; i < nextEntries.length && !token.isCancellationRequested; i++) {
|
||||
// Do a search through the next level to get to the 'to' entry.
|
||||
const subentries = _buildImportTreeImpl(to, nextEntries[i], next, [...previous, from], totalSearched, token);
|
||||
|
||||
if (subentries.length > 0) {
|
||||
return subentries;
|
||||
}
|
||||
}
|
||||
// Search failed on this tree, fail so we can exit recursion.
|
||||
|
||||
// Search failed on this tree. Fail so we can exit recursion.
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an array of imports from the 'from' to the 'to' entry where 'from' is on the front of the array and
|
||||
* the item just before 'to' is on the back of the array
|
||||
* @param to
|
||||
* @param from
|
||||
* @param next
|
||||
* @returns
|
||||
*/
|
||||
export function buildImportTree(
|
||||
to: string,
|
||||
from: string,
|
||||
next: (from: string) => string[],
|
||||
token: CancellationToken
|
||||
): string[] {
|
||||
const totalCountRef = new NumberReference();
|
||||
const results = _buildImportTreeImpl(to, from, next, [], totalCountRef, token);
|
||||
|
||||
// Result should always have the 'from' node in it.
|
||||
return results.length > 0 ? results : [from];
|
||||
}
|
||||
|
@ -4,8 +4,8 @@
|
||||
* Licensed under the MIT license.
|
||||
* Author: Eric Traut
|
||||
*
|
||||
* Collection of static methods that operate on expressions
|
||||
* (parse node trees).
|
||||
* Functions that operate on expressions (parse node trees)
|
||||
* whose values can be evaluated statically.
|
||||
*/
|
||||
|
||||
import { ExecutionEnvironment, PythonPlatform } from '../common/configOptions';
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Licensed under the MIT license.
|
||||
* Author: Eric Traut
|
||||
*
|
||||
* Collection of functions that operate on Symbol objects.
|
||||
* Functions that operate on Symbol objects.
|
||||
*/
|
||||
|
||||
import { Declaration, DeclarationType } from './declaration';
|
||||
|
@ -1,5 +1,8 @@
|
||||
/*
|
||||
* testWalker.ts
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
* Licensed under the MIT license.
|
||||
* Author: Eric Traut
|
||||
*
|
||||
* Walks a parse tree to validate internal consistency and completeness.
|
||||
*/
|
||||
|
@ -3,7 +3,7 @@
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
* Licensed under the MIT license.
|
||||
*
|
||||
* Converts various types into a string representation.
|
||||
* Converts various types into string representations.
|
||||
*/
|
||||
|
||||
import { isNumber, isString } from '../common/core';
|
||||
|
@ -82,7 +82,6 @@ import {
|
||||
} from '../parser/parseNodes';
|
||||
import { ParseOptions, Parser } from '../parser/parser';
|
||||
import { KeywordType, OperatorType, StringTokenFlags } from '../parser/tokenizerTypes';
|
||||
import * as DeclarationUtils from './aliasDeclarationUtils';
|
||||
import { AnalyzerFileInfo, ImportLookup, isAnnotationEvaluationPostponed } from './analyzerFileInfo';
|
||||
import * as AnalyzerNodeInfo from './analyzerNodeInfo';
|
||||
import { CodeFlowAnalyzer, FlowNodeTypeOptions, FlowNodeTypeResult, getCodeFlowEngine } from './codeFlowEngine';
|
||||
@ -114,6 +113,8 @@ import {
|
||||
createSynthesizedAliasDeclaration,
|
||||
getDeclarationsWithUsesLocalNameRemoved,
|
||||
getNameNodeForDeclaration,
|
||||
resolveAliasDeclaration as resolveAliasDeclarationUtil,
|
||||
ResolvedAliasInfo,
|
||||
} from './declarationUtils';
|
||||
import {
|
||||
createEnumType,
|
||||
@ -125,6 +126,12 @@ import {
|
||||
} from './enums';
|
||||
import { applyFunctionTransform } from './functionTransform';
|
||||
import { createNamedTupleType } from './namedTuples';
|
||||
import {
|
||||
getParameterListDetails,
|
||||
ParameterListDetails,
|
||||
ParameterSource,
|
||||
VirtualParameterDetails,
|
||||
} from './parameterUtils';
|
||||
import * as ParseTreeUtils from './parseTreeUtils';
|
||||
import { assignTypeToPatternTargets, checkForUnusedPattern, narrowTypeBasedOnPattern } from './patternMatching';
|
||||
import {
|
||||
@ -257,7 +264,6 @@ import {
|
||||
getGeneratorTypeArgs,
|
||||
getGeneratorYieldType,
|
||||
getLiteralTypeClassName,
|
||||
getParameterListDetails,
|
||||
getSpecializedTupleType,
|
||||
getTypeCondition,
|
||||
getTypeVarArgumentsRecursive,
|
||||
@ -285,8 +291,6 @@ import {
|
||||
lookUpObjectMember,
|
||||
makeInferenceContext,
|
||||
mapSubtypes,
|
||||
ParameterListDetails,
|
||||
ParameterSource,
|
||||
partiallySpecializeType,
|
||||
preserveUnknown,
|
||||
removeParamSpecVariadicsFromFunction,
|
||||
@ -301,7 +305,6 @@ import {
|
||||
synthesizeTypeVarForSelfCls,
|
||||
transformPossibleRecursiveTypeAlias,
|
||||
validateTypeVarDefault,
|
||||
VirtualParameterDetails,
|
||||
} from './typeUtils';
|
||||
import { TypeVarContext, TypeVarSignatureContext } from './typeVarContext';
|
||||
|
||||
@ -21166,25 +21169,16 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
|
||||
resolveLocalNames: boolean,
|
||||
allowExternallyHiddenAccess = false
|
||||
): Declaration | undefined {
|
||||
return DeclarationUtils.resolveAliasDeclaration(
|
||||
importLookup,
|
||||
declaration,
|
||||
resolveLocalNames,
|
||||
allowExternallyHiddenAccess
|
||||
)?.declaration;
|
||||
return resolveAliasDeclarationUtil(importLookup, declaration, resolveLocalNames, allowExternallyHiddenAccess)
|
||||
?.declaration;
|
||||
}
|
||||
|
||||
function resolveAliasDeclarationWithInfo(
|
||||
declaration: Declaration,
|
||||
resolveLocalNames: boolean,
|
||||
allowExternallyHiddenAccess = false
|
||||
): DeclarationUtils.ResolvedAliasInfo | undefined {
|
||||
return DeclarationUtils.resolveAliasDeclaration(
|
||||
importLookup,
|
||||
declaration,
|
||||
resolveLocalNames,
|
||||
allowExternallyHiddenAccess
|
||||
);
|
||||
): ResolvedAliasInfo | undefined {
|
||||
return resolveAliasDeclarationUtil(importLookup, declaration, resolveLocalNames, allowExternallyHiddenAccess);
|
||||
}
|
||||
|
||||
// Returns the type of the symbol. If the type is explicitly declared, that type
|
||||
|
@ -5,7 +5,6 @@
|
||||
* Author: Eric Traut
|
||||
*
|
||||
* Abstract interface and other helper types for type evaluator module.
|
||||
*
|
||||
*/
|
||||
|
||||
import { CancellationToken } from 'vscode-languageserver-protocol';
|
||||
@ -30,10 +29,10 @@ import {
|
||||
RaiseNode,
|
||||
StringNode,
|
||||
} from '../parser/parseNodes';
|
||||
import * as DeclarationUtils from './aliasDeclarationUtils';
|
||||
import { AnalyzerFileInfo } from './analyzerFileInfo';
|
||||
import { CodeFlowReferenceExpressionNode, FlowNode } from './codeFlowTypes';
|
||||
import { Declaration } from './declaration';
|
||||
import * as DeclarationUtils from './declarationUtils';
|
||||
import { SymbolWithScope } from './scope';
|
||||
import { Symbol } from './symbol';
|
||||
import { PrintTypeFlags } from './typePrinter';
|
||||
|
@ -5,9 +5,7 @@
|
||||
* Licensed under the MIT license.
|
||||
* Author: Eric Traut
|
||||
*
|
||||
* This wraps real type evaluator to track performance information such
|
||||
* as which type inferring takes most of time, what files are read most of times
|
||||
* and etc.
|
||||
* Wraps type evaluator to track performance of internal calls.
|
||||
*/
|
||||
|
||||
import { LogLevel } from '../common/console';
|
||||
@ -26,8 +24,8 @@ export function createTypeEvaluatorWithTracker(
|
||||
printer?: TracePrinter
|
||||
) {
|
||||
function wrapWithLogger<T extends (...args: any[]) => any>(func: T): (...args: Parameters<T>) => ReturnType<T> {
|
||||
// Only wrap the function if told to do so and the log level is high enough for it
|
||||
// to actually log something.
|
||||
// Wrap the function only if told to do so and the log level is high
|
||||
// enough for it to log something.
|
||||
if (evaluatorOptions.logCalls && logger.logLevel === LogLevel.Log) {
|
||||
return (...args: Parameters<T>): ReturnType<T> => {
|
||||
return logger.log(
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Licensed under the MIT license.
|
||||
* Author: Eric Traut
|
||||
*
|
||||
* Collection of functions that operate on Type objects.
|
||||
* Functions that operate on Type objects.
|
||||
*/
|
||||
|
||||
import { appendArray } from '../common/collectionUtils';
|
||||
@ -12,7 +12,6 @@ import { assert } from '../common/debug';
|
||||
import { ParameterCategory } from '../parser/parseNodes';
|
||||
import { DeclarationType } from './declaration';
|
||||
import { Symbol, SymbolFlags, SymbolTable } from './symbol';
|
||||
import { isDunderName } from './symbolNameUtils';
|
||||
import { isTypedDictMemberAccessedThroughIndex } from './symbolUtils';
|
||||
import {
|
||||
AnyType,
|
||||
@ -37,7 +36,6 @@ import {
|
||||
isUnbound,
|
||||
isUnion,
|
||||
isUnknown,
|
||||
isUnpackedClass,
|
||||
isUnpackedVariadicTypeVar,
|
||||
isVariadicTypeVar,
|
||||
maxTypeRecursionCount,
|
||||
@ -191,39 +189,6 @@ export const enum AssignTypeFlags {
|
||||
PopulatingExpectedType = 1 << 10,
|
||||
}
|
||||
|
||||
export enum ParameterSource {
|
||||
PositionOnly,
|
||||
PositionOrKeyword,
|
||||
KeywordOnly,
|
||||
}
|
||||
|
||||
export interface VirtualParameterDetails {
|
||||
param: FunctionParameter;
|
||||
type: Type;
|
||||
defaultArgType?: Type | undefined;
|
||||
index: number;
|
||||
source: ParameterSource;
|
||||
}
|
||||
|
||||
export interface ParameterListDetails {
|
||||
// Virtual parameter list that refers to original parameters
|
||||
params: VirtualParameterDetails[];
|
||||
|
||||
// Counts of virtual parameters
|
||||
positionOnlyParamCount: number;
|
||||
positionParamCount: number;
|
||||
|
||||
// Indexes into virtual parameter list
|
||||
kwargsIndex?: number;
|
||||
argsIndex?: number;
|
||||
firstKeywordOnlyIndex?: number;
|
||||
firstPositionOrKeywordIndex: number;
|
||||
|
||||
// Other information
|
||||
hasUnpackedVariadicTypeVar: boolean;
|
||||
hasUnpackedTypedDict: boolean;
|
||||
}
|
||||
|
||||
export interface ApplyTypeVarOptions {
|
||||
unknownIfNotFound?: boolean;
|
||||
useUnknownOverDefault?: boolean;
|
||||
@ -238,223 +203,6 @@ export interface InferenceContext {
|
||||
typeVarContext?: TypeVarContext;
|
||||
}
|
||||
|
||||
// Examines the input parameters within a function signature and creates a
|
||||
// "virtual list" of parameters, stripping out any markers and expanding
|
||||
// any *args with unpacked tuples.
|
||||
export function getParameterListDetails(type: FunctionType): ParameterListDetails {
|
||||
const result: ParameterListDetails = {
|
||||
firstPositionOrKeywordIndex: 0,
|
||||
positionParamCount: 0,
|
||||
positionOnlyParamCount: 0,
|
||||
params: [],
|
||||
hasUnpackedVariadicTypeVar: false,
|
||||
hasUnpackedTypedDict: false,
|
||||
};
|
||||
|
||||
let positionOnlyIndex = type.details.parameters.findIndex(
|
||||
(p) => p.category === ParameterCategory.Simple && !p.name
|
||||
);
|
||||
|
||||
// Handle the old (pre Python 3.8) way of specifying positional-only
|
||||
// parameters by naming them with "__".
|
||||
if (positionOnlyIndex < 0) {
|
||||
for (let i = 0; i < type.details.parameters.length; i++) {
|
||||
const p = type.details.parameters[i];
|
||||
if (p.category !== ParameterCategory.Simple) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!p.name) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (isDunderName(p.name) || !p.name.startsWith('__')) {
|
||||
break;
|
||||
}
|
||||
|
||||
positionOnlyIndex = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (positionOnlyIndex >= 0) {
|
||||
result.firstPositionOrKeywordIndex = positionOnlyIndex;
|
||||
}
|
||||
|
||||
for (let i = 0; i < positionOnlyIndex; i++) {
|
||||
if (type.details.parameters[i].hasDefault) {
|
||||
break;
|
||||
}
|
||||
|
||||
result.positionOnlyParamCount++;
|
||||
}
|
||||
|
||||
let sawKeywordOnlySeparator = false;
|
||||
|
||||
const addVirtualParameter = (
|
||||
param: FunctionParameter,
|
||||
index: number,
|
||||
typeOverride?: Type,
|
||||
defaultArgTypeOverride?: Type,
|
||||
sourceOverride?: ParameterSource
|
||||
) => {
|
||||
if (param.name) {
|
||||
let source: ParameterSource;
|
||||
if (sourceOverride !== undefined) {
|
||||
source = sourceOverride;
|
||||
} else if (param.category === ParameterCategory.VarArgList) {
|
||||
source = ParameterSource.PositionOnly;
|
||||
} else if (sawKeywordOnlySeparator) {
|
||||
source = ParameterSource.KeywordOnly;
|
||||
} else if (positionOnlyIndex >= 0 && index < positionOnlyIndex) {
|
||||
source = ParameterSource.PositionOnly;
|
||||
} else {
|
||||
source = ParameterSource.PositionOrKeyword;
|
||||
}
|
||||
|
||||
result.params.push({
|
||||
param,
|
||||
index,
|
||||
type: typeOverride ?? FunctionType.getEffectiveParameterType(type, index),
|
||||
defaultArgType: defaultArgTypeOverride,
|
||||
source,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
type.details.parameters.forEach((param, index) => {
|
||||
if (param.category === ParameterCategory.VarArgList) {
|
||||
// If this is an unpacked tuple, expand the entries.
|
||||
const paramType = FunctionType.getEffectiveParameterType(type, index);
|
||||
if (param.name && isUnpackedClass(paramType) && paramType.tupleTypeArguments) {
|
||||
const addToPositionalOnly = index < result.positionOnlyParamCount;
|
||||
|
||||
paramType.tupleTypeArguments.forEach((tupleArg, tupleIndex) => {
|
||||
const category =
|
||||
isVariadicTypeVar(tupleArg.type) || tupleArg.isUnbounded
|
||||
? ParameterCategory.VarArgList
|
||||
: ParameterCategory.Simple;
|
||||
|
||||
if (category === ParameterCategory.VarArgList) {
|
||||
result.argsIndex = result.params.length;
|
||||
}
|
||||
|
||||
if (isVariadicTypeVar(param.type)) {
|
||||
result.hasUnpackedVariadicTypeVar = true;
|
||||
}
|
||||
|
||||
addVirtualParameter(
|
||||
{
|
||||
category,
|
||||
name: `${param.name}[${tupleIndex.toString()}]`,
|
||||
isNameSynthesized: true,
|
||||
type: tupleArg.type,
|
||||
hasDeclaredType: true,
|
||||
},
|
||||
index,
|
||||
tupleArg.type,
|
||||
/* defaultArgTypeOverride */ undefined,
|
||||
ParameterSource.PositionOnly
|
||||
);
|
||||
|
||||
if (category === ParameterCategory.Simple) {
|
||||
result.positionParamCount++;
|
||||
}
|
||||
|
||||
if (tupleIndex > 0 && addToPositionalOnly) {
|
||||
result.positionOnlyParamCount++;
|
||||
}
|
||||
});
|
||||
|
||||
// Normally, a VarArgList parameter (either named or as an unnamed separator)
|
||||
// would signify the start of keyword-only parameters. However, we can construct
|
||||
// callable signatures that defy this rule by using Callable and TypeVarTuples
|
||||
// or unpacked tuples.
|
||||
if (!sawKeywordOnlySeparator && (positionOnlyIndex < 0 || index >= positionOnlyIndex)) {
|
||||
result.firstKeywordOnlyIndex = result.params.length;
|
||||
sawKeywordOnlySeparator = true;
|
||||
}
|
||||
} else {
|
||||
if (param.name && result.argsIndex === undefined) {
|
||||
result.argsIndex = result.params.length;
|
||||
|
||||
if (isVariadicTypeVar(param.type)) {
|
||||
result.hasUnpackedVariadicTypeVar = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Normally, a VarArgList parameter (either named or as an unnamed separator)
|
||||
// would signify the start of keyword-only parameters. However, we can construct
|
||||
// callable signatures that defy this rule by using Callable and TypeVarTuples
|
||||
// or unpacked tuples.
|
||||
if (!sawKeywordOnlySeparator && (positionOnlyIndex < 0 || index >= positionOnlyIndex)) {
|
||||
result.firstKeywordOnlyIndex = result.params.length;
|
||||
if (param.name) {
|
||||
result.firstKeywordOnlyIndex++;
|
||||
}
|
||||
sawKeywordOnlySeparator = true;
|
||||
}
|
||||
|
||||
addVirtualParameter(param, index);
|
||||
}
|
||||
} else if (param.category === ParameterCategory.VarArgDictionary) {
|
||||
sawKeywordOnlySeparator = true;
|
||||
|
||||
const paramType = FunctionType.getEffectiveParameterType(type, index);
|
||||
|
||||
// Is this an unpacked TypedDict? If so, expand the entries.
|
||||
if (isClassInstance(paramType) && isUnpackedClass(paramType) && paramType.details.typedDictEntries) {
|
||||
if (result.firstKeywordOnlyIndex === undefined) {
|
||||
result.firstKeywordOnlyIndex = result.params.length;
|
||||
}
|
||||
|
||||
const typedDictType = paramType;
|
||||
paramType.details.typedDictEntries.forEach((entry, name) => {
|
||||
const specializedParamType = partiallySpecializeType(entry.valueType, typedDictType);
|
||||
|
||||
addVirtualParameter(
|
||||
{
|
||||
category: ParameterCategory.Simple,
|
||||
name,
|
||||
type: specializedParamType,
|
||||
hasDeclaredType: true,
|
||||
hasDefault: !entry.isRequired,
|
||||
},
|
||||
index,
|
||||
specializedParamType
|
||||
);
|
||||
});
|
||||
|
||||
result.hasUnpackedTypedDict = true;
|
||||
} else if (param.name) {
|
||||
if (result.kwargsIndex === undefined) {
|
||||
result.kwargsIndex = result.params.length;
|
||||
}
|
||||
|
||||
if (result.firstKeywordOnlyIndex === undefined) {
|
||||
result.firstKeywordOnlyIndex = result.params.length;
|
||||
}
|
||||
|
||||
addVirtualParameter(param, index);
|
||||
}
|
||||
} else if (param.category === ParameterCategory.Simple) {
|
||||
if (param.name && !sawKeywordOnlySeparator) {
|
||||
result.positionParamCount++;
|
||||
}
|
||||
|
||||
addVirtualParameter(
|
||||
param,
|
||||
index,
|
||||
/* typeOverride */ undefined,
|
||||
type.specializedTypes?.parameterDefaultArgs
|
||||
? type.specializedTypes?.parameterDefaultArgs[index]
|
||||
: undefined
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export function isOptionalType(type: Type): boolean {
|
||||
if (isUnion(type)) {
|
||||
return findSubtype(type, (subtype) => isNoneInstance(subtype)) !== undefined;
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Licensed under the MIT license.
|
||||
* Author: Eric Traut
|
||||
*
|
||||
* Class that represents errors and warnings.
|
||||
* Class that collects and deduplicates diagnostics.
|
||||
*/
|
||||
|
||||
import { appendArray } from './collectionUtils';
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* envVarUtils.ts
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
* Licensed under the MIT license.
|
||||
*
|
||||
* Utils functions that handles environment variables.
|
||||
*/
|
||||
|
||||
import * as os from 'os';
|
||||
|
||||
import {
|
||||
@ -7,14 +15,6 @@ import {
|
||||
hasTrailingDirectorySeparator,
|
||||
} from './pathUtils';
|
||||
|
||||
/*
|
||||
* envVarUtils.ts
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
* Licensed under the MIT license.
|
||||
*
|
||||
* Utils functions that handles environment variables.
|
||||
*/
|
||||
|
||||
// Expands certain predefined variables supported within VS Code settings.
|
||||
// Ideally, VS Code would provide an API for doing this expansion, but
|
||||
// it doesn't. We'll handle the most common variables here as a convenience.
|
||||
|
@ -3,7 +3,7 @@
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
* Licensed under the MIT license.
|
||||
*
|
||||
* Helper methods relating to file based cancellation.
|
||||
* Helper methods relating to file-based cancellation.
|
||||
*/
|
||||
|
||||
import * as fs from 'fs';
|
||||
|
@ -3,7 +3,7 @@
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
* Licensed under the MIT license.
|
||||
*
|
||||
* Provides accesses to the host the language service runs on
|
||||
* Provides access to the host environment the language service is running on.
|
||||
*/
|
||||
|
||||
import { PythonPathResult } from '../analyzer/pythonPathUtils';
|
||||
|
@ -2,7 +2,7 @@
|
||||
* lspUtils.ts
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Helper functions around Language Server Protocol (LSP).
|
||||
* Helper functions related to the Language Server Protocol (LSP).
|
||||
*/
|
||||
|
||||
import { LSPAny } from 'vscode-languageserver';
|
||||
|
@ -1,7 +1,10 @@
|
||||
/*
|
||||
* progressReporter.ts
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
* Licensed under the MIT license.
|
||||
* Author: Eric Traut
|
||||
*
|
||||
* Implements progress reporter.
|
||||
* Implements a mechanism for reporting progress in a language server client.
|
||||
*/
|
||||
|
||||
export interface ProgressReporter {
|
||||
|
@ -4,8 +4,7 @@
|
||||
* Licensed under the MIT license.
|
||||
* Author: Eric Traut
|
||||
*
|
||||
* Types and functions that relate to the Python language version
|
||||
* and features within them.
|
||||
* Types and functions that relate to the Python language version.
|
||||
*/
|
||||
|
||||
export enum PythonVersion {
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* realFileSystem.ts
|
||||
*
|
||||
* Collection of helper functions that require real fs access.
|
||||
* Helper functions that require real filesystem access.
|
||||
*/
|
||||
|
||||
import { FakeFS, NativePath, PortablePath, PosixFS, ppath, VirtualFS, ZipFS, ZipOpenFS } from '@yarnpkg/fslib';
|
||||
|
@ -3,7 +3,7 @@
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
* Licensed under the MIT license.
|
||||
*
|
||||
* Track text edits per files.
|
||||
* Tracks text edits on a per-file basis.
|
||||
*/
|
||||
|
||||
import { CancellationToken } from 'vscode-languageserver';
|
||||
|
@ -3,7 +3,7 @@
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
* Licensed under the MIT license.
|
||||
*
|
||||
* Convert Pyright's FileEditActions to LanguageServer's WorkspaceEdits.
|
||||
* Convert pyright's FileEditActions to LanguageServer's WorkspaceEdits.
|
||||
*/
|
||||
|
||||
import {
|
||||
|
@ -7,6 +7,7 @@
|
||||
* Runs the analyzer service of a given workspace service instance
|
||||
* with a specified set of options.
|
||||
*/
|
||||
|
||||
import { isPythonBinary } from '../analyzer/pythonPathUtils';
|
||||
import { AnalyzerService, getNextServiceId } from '../analyzer/service';
|
||||
import { CommandLineOptions } from '../common/commandLineOptions';
|
||||
|
@ -3,6 +3,7 @@
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
* Licensed under the MIT license.
|
||||
*
|
||||
* Logic for performing auto-import completions.
|
||||
*/
|
||||
|
||||
import { CancellationToken, CompletionItemKind, SymbolKind } from 'vscode-languageserver';
|
||||
|
@ -5,6 +5,7 @@
|
||||
*
|
||||
* Helper functions for providing completions
|
||||
*/
|
||||
|
||||
import { InsertTextFormat, MarkupContent, MarkupKind, TextEdit } from 'vscode-languageserver-types';
|
||||
|
||||
import { Declaration, DeclarationType } from '../analyzer/declaration';
|
||||
|
@ -18,11 +18,10 @@ import {
|
||||
} from 'vscode-languageserver';
|
||||
import { URI } from 'vscode-uri';
|
||||
|
||||
import { resolveAliasDeclaration } from '../analyzer/aliasDeclarationUtils';
|
||||
import { AnalyzerFileInfo, ImportLookup } from '../analyzer/analyzerFileInfo';
|
||||
import * as AnalyzerNodeInfo from '../analyzer/analyzerNodeInfo';
|
||||
import { AliasDeclaration, Declaration, DeclarationType } from '../analyzer/declaration';
|
||||
import { getNameFromDeclaration } from '../analyzer/declarationUtils';
|
||||
import { getNameFromDeclaration, resolveAliasDeclaration } from '../analyzer/declarationUtils';
|
||||
import { getLastTypedDeclaredForSymbol, isVisibleExternally } from '../analyzer/symbolUtils';
|
||||
import { TypeEvaluator } from '../analyzer/typeEvaluatorTypes';
|
||||
import { isMaybeDescriptorInstance } from '../analyzer/typeUtils';
|
||||
|
@ -5,7 +5,7 @@
|
||||
* Author: Eric Traut
|
||||
*
|
||||
* Provides code that sorts and formats import statements within a
|
||||
* python source file.
|
||||
* Python source file.
|
||||
*/
|
||||
|
||||
import { CancellationToken } from 'vscode-languageserver';
|
||||
|
@ -3,7 +3,8 @@
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
* Licensed under the MIT license.
|
||||
*
|
||||
* Provides code to get indentation and re-indent code to the given indentation.
|
||||
* Provides code to get indentation and re-indent code for the
|
||||
* given indentation.
|
||||
*/
|
||||
|
||||
import Char from 'typescript-char';
|
||||
|
@ -4,8 +4,8 @@
|
||||
* Licensed under the MIT license.
|
||||
* Author: Eric Traut
|
||||
*
|
||||
* Tooltip helper methods that can be shared between multiple language server features such as
|
||||
* hover and completion tooltip.
|
||||
* Helper functions for formatting text that can appear in hover text,
|
||||
* completion suggestions, etc.
|
||||
*/
|
||||
|
||||
import { Declaration, DeclarationType, VariableDeclaration } from '../analyzer/declaration';
|
||||
|
Loading…
Reference in New Issue
Block a user