Fixed a bug that leads to a crash when --pythonversion and --threads CLI options are used together. This addresses #8775. (#8776)

This commit is contained in:
Eric Traut 2024-08-16 21:42:03 -07:00 committed by GitHub
parent c42a1587b4
commit bea4dc91b5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 194 additions and 154 deletions

View File

@ -10,7 +10,7 @@
import { DiagnosticRuleSet, ExecutionEnvironment } from '../common/configOptions';
import { TextRangeDiagnosticSink } from '../common/diagnosticSink';
import { pythonVersion3_14 } from '../common/pythonVersion';
import { PythonVersion, pythonVersion3_14 } from '../common/pythonVersion';
import { TextRange } from '../common/textRange';
import { TextRangeCollection } from '../common/textRangeCollection';
import { Uri } from '../common/uri/uri';
@ -78,7 +78,7 @@ export function isAnnotationEvaluationPostponed(fileInfo: AnalyzerFileInfo) {
// release to reduce the risk. As of May 8, 2024, the change did not make it into
// Python 3.13beta1, so it has been deferred to Python 3.14.
// https://discuss.python.org/t/pep-649-deferred-evaluation-of-annotations-tentatively-accepted/21331
if (fileInfo.executionEnvironment.pythonVersion.isGreaterOrEqualTo(pythonVersion3_14)) {
if (PythonVersion.isGreaterOrEqualTo(fileInfo.executionEnvironment.pythonVersion, pythonVersion3_14)) {
return true;
}

View File

@ -20,7 +20,7 @@ import { DiagnosticLevel } from '../common/configOptions';
import { assert, assertNever } from '../common/debug';
import { ActionKind, Diagnostic, DiagnosticAddendum, RenameShadowedFileAction } from '../common/diagnostic';
import { DiagnosticRule } from '../common/diagnosticRules';
import { pythonVersion3_12, pythonVersion3_5, pythonVersion3_6 } from '../common/pythonVersion';
import { PythonVersion, pythonVersion3_12, pythonVersion3_5, pythonVersion3_6 } from '../common/pythonVersion';
import { TextRange } from '../common/textRange';
import { Uri } from '../common/uri/uri';
import { DefinitionProvider } from '../languageService/definitionProvider';
@ -628,7 +628,7 @@ export class Checker extends ParseTreeWalker {
if (
this._fileInfo.diagnosticRuleSet.reportTypeCommentUsage !== 'none' &&
this._fileInfo.executionEnvironment.pythonVersion.isGreaterOrEqualTo(pythonVersion3_5)
PythonVersion.isGreaterOrEqualTo(this._fileInfo.executionEnvironment.pythonVersion, pythonVersion3_5)
) {
this._evaluator.addDiagnostic(
DiagnosticRule.reportTypeCommentUsage,
@ -1184,7 +1184,7 @@ export class Checker extends ParseTreeWalker {
if (
this._fileInfo.diagnosticRuleSet.reportTypeCommentUsage !== 'none' &&
this._fileInfo.executionEnvironment.pythonVersion.isGreaterOrEqualTo(pythonVersion3_6)
PythonVersion.isGreaterOrEqualTo(this._fileInfo.executionEnvironment.pythonVersion, pythonVersion3_6)
) {
this._evaluator.addDiagnostic(
DiagnosticRule.reportTypeCommentUsage,
@ -1361,7 +1361,7 @@ export class Checker extends ParseTreeWalker {
// associated with f-strings that we need to validate. Determine whether
// we're within an f-string (or multiple f-strings if nesting is used).
const fStringContainers: FormatStringNode[] = [];
if (this._fileInfo.executionEnvironment.pythonVersion.isLessThan(pythonVersion3_12)) {
if (PythonVersion.isLessThan(this._fileInfo.executionEnvironment.pythonVersion, pythonVersion3_12)) {
let curNode: ParseNode | undefined = node;
while (curNode) {
if (curNode.nodeType === ParseNodeType.FormatString) {
@ -4456,7 +4456,12 @@ export class Checker extends ParseTreeWalker {
(isInstantiableClass(type) && type.shared.fullName === deprecatedForm.fullName) ||
type.props?.typeAliasInfo?.fullName === deprecatedForm.fullName
) {
if (this._fileInfo.executionEnvironment.pythonVersion.isGreaterOrEqualTo(deprecatedForm.version)) {
if (
PythonVersion.isGreaterOrEqualTo(
this._fileInfo.executionEnvironment.pythonVersion,
deprecatedForm.version
)
) {
if (!deprecatedForm.typingImportOnly || isImportFromTyping) {
this._reportDeprecatedDiagnostic(
node,

View File

@ -11,7 +11,7 @@
import { assert } from '../common/debug';
import { DiagnosticAddendum } from '../common/diagnostic';
import { DiagnosticRule } from '../common/diagnosticRules';
import { pythonVersion3_13 } from '../common/pythonVersion';
import { PythonVersion, pythonVersion3_13 } from '../common/pythonVersion';
import { LocMessage } from '../localization/localize';
import {
ArgCategory,
@ -122,7 +122,12 @@ export function synthesizeDataClassMethods(
// For Python 3.13 and newer, synthesize a __replace__ method.
let replaceType: FunctionType | undefined;
if (AnalyzerNodeInfo.getFileInfo(node).executionEnvironment.pythonVersion >= pythonVersion3_13) {
if (
PythonVersion.isGreaterOrEqualTo(
AnalyzerNodeInfo.getFileInfo(node).executionEnvironment.pythonVersion,
pythonVersion3_13
)
) {
replaceType = FunctionType.createSynthesizedInstance('__replace__');
FunctionType.addParam(replaceType, selfParam);
FunctionType.addKeywordOnlyParamSeparator(replaceType);

View File

@ -8,7 +8,7 @@
*/
import { assert } from '../common/debug';
import { pythonVersion3_13 } from '../common/pythonVersion';
import { PythonVersion, pythonVersion3_13 } from '../common/pythonVersion';
import { ArgCategory, ExpressionNode, NameNode, ParseNode, ParseNodeType } from '../parser/parseNodes';
import { getFileInfo } from './analyzerNodeInfo';
import { VariableDeclaration } from './declaration';
@ -413,7 +413,10 @@ export function transformTypeForEnumMember(
// are treated as members.
if (isInstantiableClass(assignedType)) {
const fileInfo = getFileInfo(primaryDecl.node);
isMemberOfEnumeration = fileInfo.executionEnvironment.pythonVersion.isLessThan(pythonVersion3_13);
isMemberOfEnumeration = PythonVersion.isLessThan(
fileInfo.executionEnvironment.pythonVersion,
pythonVersion3_13
);
}
}
}

View File

@ -472,7 +472,7 @@ export class ImportResolver {
this._cachedTypeshedStdLibModuleVersionInfo.forEach((versionInfo, moduleName) => {
let shouldExcludeModule = false;
if (versionInfo.max !== undefined && pythonVersion.isGreaterThan(versionInfo.max)) {
if (versionInfo.max !== undefined && PythonVersion.isGreaterThan(pythonVersion, versionInfo.max)) {
shouldExcludeModule = true;
}
@ -1999,11 +1999,11 @@ export class ImportResolver {
const versionInfo = this._cachedTypeshedStdLibModuleVersionInfo.get(namePartsToConsider.join('.'));
if (versionInfo) {
if (pythonVersion.isLessThan(versionInfo.min)) {
if (PythonVersion.isLessThan(pythonVersion, versionInfo.min)) {
return false;
}
if (versionInfo.max !== undefined && pythonVersion.isGreaterThan(versionInfo.max)) {
if (versionInfo.max !== undefined && PythonVersion.isGreaterThan(pythonVersion, versionInfo.max)) {
return false;
}

View File

@ -10,7 +10,7 @@
import { DiagnosticAddendum } from '../common/diagnostic';
import { DiagnosticRule } from '../common/diagnosticRules';
import { pythonVersion3_10 } from '../common/pythonVersion';
import { PythonVersion, pythonVersion3_10 } from '../common/pythonVersion';
import { LocMessage } from '../localization/localize';
import {
AugmentedAssignmentNode,
@ -370,7 +370,7 @@ export function getTypeOfBinaryOperation(
const unionNotationSupported =
fileInfo.isStubFile ||
(flags & EvalFlags.ForwardRefs) !== 0 ||
fileInfo.executionEnvironment.pythonVersion.isGreaterOrEqualTo(pythonVersion3_10);
PythonVersion.isGreaterOrEqualTo(fileInfo.executionEnvironment.pythonVersion, pythonVersion3_10);
if (!unionNotationSupported) {
// If the left type is Any, we can't say for sure whether this

View File

@ -156,7 +156,7 @@ function findSitePackagesPath(
// version), prefer that over other python directories.
if (pythonVersion) {
const preferredDir = candidateDirs.find(
(dirName) => dirName.fileName === `python${pythonVersion.toMajorMinorString()}`
(dirName) => dirName.fileName === `python${PythonVersion.toMajorMinorString(pythonVersion)}`
);
if (preferredDir) {
const dirPath = preferredDir.combinePaths(pathConsts.sitePackages);

View File

@ -100,8 +100,8 @@ export function evaluateStaticBoolExpression(
// Handle the special case of "sys.version_info[0] >= X"
return _evaluateVersionBinaryOperation(
node.d.operator,
new PythonVersion(execEnv.pythonVersion.major, 0),
new PythonVersion(node.d.rightExpr.d.value, 0)
PythonVersion.create(execEnv.pythonVersion.major, 0),
PythonVersion.create(node.d.rightExpr.d.value, 0)
);
}
@ -238,12 +238,12 @@ function _convertTupleToVersion(node: TupleNode): PythonVersion | undefined {
serial = node.d.items[4].d.value;
}
return new PythonVersion(major, minor, micro, releaseLevel, serial);
return PythonVersion.create(major, minor, micro, releaseLevel, serial);
}
} else if (node.d.items.length === 1) {
const major = node.d.items[0] as NumberNode;
if (typeof major.d.value === 'number') {
return new PythonVersion(major.d.value, 0);
return PythonVersion.create(major.d.value, 0);
}
}
@ -257,27 +257,27 @@ function _evaluateVersionBinaryOperation(
): any | undefined {
if (leftValue !== undefined && rightValue !== undefined) {
if (operatorType === OperatorType.LessThan) {
return leftValue.isLessThan(rightValue);
return PythonVersion.isLessThan(leftValue, rightValue);
}
if (operatorType === OperatorType.LessThanOrEqual) {
return leftValue.isLessOrEqualTo(rightValue);
return PythonVersion.isLessOrEqualTo(leftValue, rightValue);
}
if (operatorType === OperatorType.GreaterThan) {
return leftValue.isGreaterThan(rightValue);
return PythonVersion.isGreaterThan(leftValue, rightValue);
}
if (operatorType === OperatorType.GreaterThanOrEqual) {
return leftValue.isGreaterOrEqualTo(rightValue);
return PythonVersion.isGreaterOrEqualTo(leftValue, rightValue);
}
if (operatorType === OperatorType.Equals) {
return leftValue.isEqualTo(rightValue);
return PythonVersion.isEqualTo(leftValue, rightValue);
}
if (operatorType === OperatorType.NotEquals) {
return !leftValue.isEqualTo(rightValue);
return !PythonVersion.isEqualTo(leftValue, rightValue);
}
}

View File

@ -5553,8 +5553,10 @@ export function createTypeEvaluator(
const getAttrSymbol = ModuleType.getField(baseType, '__getattr__');
if (getAttrSymbol) {
const isModuleGetAttrSupported =
fileInfo.executionEnvironment.pythonVersion.isGreaterOrEqualTo(pythonVersion3_7) ||
getAttrSymbol.getDeclarations().some((decl) => decl.uri.hasExtension('.pyi'));
PythonVersion.isGreaterOrEqualTo(
fileInfo.executionEnvironment.pythonVersion,
pythonVersion3_7
) || getAttrSymbol.getDeclarations().some((decl) => decl.uri.hasExtension('.pyi'));
if (isModuleGetAttrSupported) {
const getAttrTypeResult = getEffectiveTypeOfSymbolForUsage(getAttrSymbol);
@ -6583,7 +6585,7 @@ export function createTypeEvaluator(
const minPythonVersion = nonSubscriptableBuiltinTypes.get(baseTypeResult.type.shared.fullName);
if (
minPythonVersion !== undefined &&
fileInfo.executionEnvironment.pythonVersion.isLessThan(minPythonVersion) &&
PythonVersion.isLessThan(fileInfo.executionEnvironment.pythonVersion, minPythonVersion) &&
!fileInfo.isStubFile
) {
addDiagnostic(
@ -12359,7 +12361,7 @@ export function createTypeEvaluator(
const fileInfo = AnalyzerNodeInfo.getFileInfo(errorNode);
if (
!fileInfo.isStubFile &&
fileInfo.executionEnvironment.pythonVersion.isLessThan(pythonVersion3_13) &&
PythonVersion.isLessThan(fileInfo.executionEnvironment.pythonVersion, pythonVersion3_13) &&
classType.shared.moduleName !== 'typing_extensions'
) {
addDiagnostic(
@ -12518,7 +12520,7 @@ export function createTypeEvaluator(
const fileInfo = AnalyzerNodeInfo.getFileInfo(errorNode);
if (
!fileInfo.isStubFile &&
fileInfo.executionEnvironment.pythonVersion.isLessThan(pythonVersion3_13) &&
PythonVersion.isLessThan(fileInfo.executionEnvironment.pythonVersion, pythonVersion3_13) &&
classType.shared.moduleName !== 'typing_extensions'
) {
addDiagnostic(
@ -12608,7 +12610,7 @@ export function createTypeEvaluator(
const fileInfo = AnalyzerNodeInfo.getFileInfo(errorNode);
if (
!fileInfo.isStubFile &&
fileInfo.executionEnvironment.pythonVersion.isLessThan(pythonVersion3_13) &&
PythonVersion.isLessThan(fileInfo.executionEnvironment.pythonVersion, pythonVersion3_13) &&
classType.shared.moduleName !== 'typing_extensions'
) {
addDiagnostic(
@ -16635,7 +16637,10 @@ export function createTypeEvaluator(
if (
!fileInfo.isStubFile &&
!ClassType.isTypingExtensionClass(argType) &&
fileInfo.executionEnvironment.pythonVersion.isLessThan(pythonVersion3_7)
PythonVersion.isLessThan(
fileInfo.executionEnvironment.pythonVersion,
pythonVersion3_7
)
) {
addDiagnostic(
DiagnosticRule.reportInvalidTypeForm,
@ -16652,7 +16657,12 @@ export function createTypeEvaluator(
// If the class directly derives from NamedTuple (in Python 3.6 or
// newer), it's considered a (read-only) dataclass.
if (fileInfo.executionEnvironment.pythonVersion.isGreaterOrEqualTo(pythonVersion3_6)) {
if (
PythonVersion.isGreaterOrEqualTo(
fileInfo.executionEnvironment.pythonVersion,
pythonVersion3_6
)
) {
if (ClassType.isBuiltIn(argType, 'NamedTuple')) {
isNamedTupleSubclass = true;
classType.shared.flags |= ClassTypeFlags.ReadOnlyInstanceVariables;
@ -19094,7 +19104,10 @@ export function createTypeEvaluator(
// Handle PEP 562 support for module-level __getattr__ function,
// introduced in Python 3.7.
if (
fileInfo.executionEnvironment.pythonVersion.isGreaterOrEqualTo(pythonVersion3_7) ||
PythonVersion.isGreaterOrEqualTo(
fileInfo.executionEnvironment.pythonVersion,
pythonVersion3_7
) ||
fileInfo.isStubFile
) {
const getAttrSymbol = importLookupInfo.symbolTable.get('__getattr__');
@ -20174,7 +20187,7 @@ export function createTypeEvaluator(
const fileInfo = AnalyzerNodeInfo.getFileInfo(errorNode);
if (
fileInfo.isStubFile ||
fileInfo.executionEnvironment.pythonVersion.isGreaterOrEqualTo(pythonVersion3_9) ||
PythonVersion.isGreaterOrEqualTo(fileInfo.executionEnvironment.pythonVersion, pythonVersion3_9) ||
isAnnotationEvaluationPostponed(AnalyzerNodeInfo.getFileInfo(errorNode)) ||
(flags & EvalFlags.ForwardRefs) !== 0
) {

View File

@ -14,7 +14,6 @@ import { ConfigOptions } from './common/configOptions';
import { ConsoleInterface, LogLevel } from './common/console';
import { Disposable, isThenable } from './common/core';
import * as debug from './common/debug';
import { PythonVersion } from './common/pythonVersion';
import { createFromRealFileSystem, RealTempFile } from './common/realFileSystem';
import { ServiceKeys } from './common/serviceKeys';
import { ServiceProvider } from './common/serviceProvider';
@ -124,9 +123,6 @@ export function serializeReplacer(value: any) {
if (Uri.is(value) && value.toJsonObj !== undefined) {
return { __serialized_uri_val: value.toJsonObj() };
}
if (value instanceof PythonVersion) {
return { __serialized_version_val: value.toString() };
}
if (value instanceof Map) {
return { __serialized_map_val: [...value] };
}
@ -154,9 +150,6 @@ export function deserializeReviver(value: any) {
if (value.__serialized_uri_val !== undefined) {
return Uri.fromJsonObj(value.__serialized_uri_val);
}
if (value.__serialized_version_val) {
return PythonVersion.fromString(value.__serialized_version_val);
}
if (value.__serialized_map_val) {
return new Map(value.__serialized_map_val);
}

View File

@ -121,7 +121,7 @@ export class FullAccessHost extends LimitedAccessHost {
return undefined;
}
const version = new PythonVersion(
const version = PythonVersion.create(
versionJson[0],
versionJson[1],
versionJson[2],

View File

@ -9,77 +9,73 @@
export type PythonReleaseLevel = 'alpha' | 'beta' | 'candidate' | 'final';
export class PythonVersion {
constructor(
private _major: number,
private _minor: number,
private _micro?: number,
private _releaseLevel?: PythonReleaseLevel,
private _serial?: number
) {}
export interface PythonVersion {
major: number;
minor: number;
micro?: number;
releaseLevel?: PythonReleaseLevel;
serial?: number;
}
get major() {
return this._major;
export namespace PythonVersion {
export function create(
major: number,
minor: number,
micro?: number,
releaseLevel?: PythonReleaseLevel,
serial?: number
): PythonVersion {
return {
major,
minor,
micro,
releaseLevel,
serial,
};
}
get minor() {
return this._minor;
}
get micro() {
return this._micro;
}
get releaseLevel() {
return this._releaseLevel;
}
get serial() {
return this._serial;
}
isEqualTo(other: PythonVersion) {
if (this.major !== other.major || this.minor !== other.minor) {
export function isEqualTo(version: PythonVersion, other: PythonVersion) {
if (version.major !== other.major || version.minor !== other.minor) {
return false;
}
if (this._micro === undefined || other._micro === undefined) {
if (version.micro === undefined || other.micro === undefined) {
return true;
} else if (this._micro !== other._micro) {
} else if (version.micro !== other.micro) {
return false;
}
if (this._releaseLevel === undefined || other._releaseLevel === undefined) {
if (version.releaseLevel === undefined || other.releaseLevel === undefined) {
return true;
} else if (this._releaseLevel !== other._releaseLevel) {
} else if (version.releaseLevel !== other.releaseLevel) {
return false;
}
if (this._serial === undefined || other._serial === undefined) {
if (version.serial === undefined || other.serial === undefined) {
return true;
} else if (this._serial !== other._serial) {
} else if (version.serial !== other.serial) {
return false;
}
return true;
}
isGreaterThan(other: PythonVersion) {
if (this.major > other.major) {
export function isGreaterThan(version: PythonVersion, other: PythonVersion) {
if (version.major > other.major) {
return true;
} else if (this.major < other.major) {
} else if (version.major < other.major) {
return false;
}
if (this.minor > other.minor) {
if (version.minor > other.minor) {
return true;
} else if (this.minor < other.minor) {
} else if (version.minor < other.minor) {
return false;
}
if (this._micro === undefined || other._micro === undefined || this._micro < other._micro) {
if (version.micro === undefined || other.micro === undefined || version.micro < other.micro) {
return false;
} else if (this._micro > other._micro) {
} else if (version.micro > other.micro) {
return true;
}
@ -87,18 +83,18 @@ export class PythonVersion {
// of the release level designators are ordered by increasing
// release level.
if (
this._releaseLevel === undefined ||
other._releaseLevel === undefined ||
this._releaseLevel < other._releaseLevel
version.releaseLevel === undefined ||
other.releaseLevel === undefined ||
version.releaseLevel < other.releaseLevel
) {
return false;
} else if (this._releaseLevel > other._releaseLevel) {
} else if (version.releaseLevel > other.releaseLevel) {
return true;
}
if (this._serial === undefined || other._serial === undefined || this._serial < other._serial) {
if (version.serial === undefined || other.serial === undefined || version.serial < other.serial) {
return false;
} else if (this._serial > other._serial) {
} else if (version.serial > other.serial) {
return true;
}
@ -106,46 +102,46 @@ export class PythonVersion {
return false;
}
isGreaterOrEqualTo(other: PythonVersion) {
return this.isEqualTo(other) || this.isGreaterThan(other);
export function isGreaterOrEqualTo(version: PythonVersion, other: PythonVersion) {
return isEqualTo(version, other) || isGreaterThan(version, other);
}
isLessThan(other: PythonVersion) {
return !this.isGreaterOrEqualTo(other);
export function isLessThan(version: PythonVersion, other: PythonVersion) {
return !isGreaterOrEqualTo(version, other);
}
isLessOrEqualTo(other: PythonVersion) {
return !this.isGreaterThan(other);
export function isLessOrEqualTo(version: PythonVersion, other: PythonVersion) {
return !isGreaterThan(version, other);
}
toMajorMinorString(): string {
return `${this._major}.${this._minor}`;
export function toMajorMinorString(version: PythonVersion): string {
return `${version.major}.${version.minor}`;
}
toString(): string {
let version = this.toMajorMinorString();
export function toString(version: PythonVersion): string {
let versString = toMajorMinorString(version);
if (this._micro === undefined) {
return version;
if (version.micro === undefined) {
return versString;
}
version += `.${this._micro}`;
versString += `.${version.micro}`;
if (this._releaseLevel === undefined) {
return version;
if (version.releaseLevel === undefined) {
return versString;
}
version += `.${this._releaseLevel}`;
versString += `.${version.releaseLevel}`;
if (this._serial === undefined) {
return version;
if (version.serial === undefined) {
return versString;
}
version += `.${this._serial}`;
return version;
versString += `.${version.serial}`;
return versString;
}
static fromString(val: string): PythonVersion | undefined {
export function fromString(val: string): PythonVersion | undefined {
const split = val.split('.');
if (split.length < 2) {
@ -183,25 +179,25 @@ export class PythonVersion {
}
}
return new PythonVersion(major, minor, micro, releaseLevel, serial);
return create(major, minor, micro, releaseLevel, serial);
}
}
// Predefine some versions.
export const pythonVersion3_0 = new PythonVersion(3, 0);
export const pythonVersion3_1 = new PythonVersion(3, 1);
export const pythonVersion3_2 = new PythonVersion(3, 2);
export const pythonVersion3_3 = new PythonVersion(3, 3);
export const pythonVersion3_4 = new PythonVersion(3, 4);
export const pythonVersion3_5 = new PythonVersion(3, 5);
export const pythonVersion3_6 = new PythonVersion(3, 6);
export const pythonVersion3_7 = new PythonVersion(3, 7);
export const pythonVersion3_8 = new PythonVersion(3, 8);
export const pythonVersion3_9 = new PythonVersion(3, 9);
export const pythonVersion3_10 = new PythonVersion(3, 10);
export const pythonVersion3_11 = new PythonVersion(3, 11);
export const pythonVersion3_12 = new PythonVersion(3, 12);
export const pythonVersion3_13 = new PythonVersion(3, 13);
export const pythonVersion3_14 = new PythonVersion(3, 14);
export const pythonVersion3_0 = PythonVersion.create(3, 0);
export const pythonVersion3_1 = PythonVersion.create(3, 1);
export const pythonVersion3_2 = PythonVersion.create(3, 2);
export const pythonVersion3_3 = PythonVersion.create(3, 3);
export const pythonVersion3_4 = PythonVersion.create(3, 4);
export const pythonVersion3_5 = PythonVersion.create(3, 5);
export const pythonVersion3_6 = PythonVersion.create(3, 6);
export const pythonVersion3_7 = PythonVersion.create(3, 7);
export const pythonVersion3_8 = PythonVersion.create(3, 8);
export const pythonVersion3_9 = PythonVersion.create(3, 9);
export const pythonVersion3_10 = PythonVersion.create(3, 10);
export const pythonVersion3_11 = PythonVersion.create(3, 11);
export const pythonVersion3_12 = PythonVersion.create(3, 12);
export const pythonVersion3_13 = PythonVersion.create(3, 13);
export const pythonVersion3_14 = PythonVersion.create(3, 14);
export const latestStablePythonVersion = pythonVersion3_12;

View File

@ -175,10 +175,10 @@ namespace Keywords {
const python3_10: string[] = [...python3_5, 'case', 'match'];
export function forVersion(version: PythonVersion): string[] {
if (version.isGreaterOrEqualTo(pythonVersion3_10)) {
if (PythonVersion.isGreaterOrEqualTo(version, pythonVersion3_10)) {
return python3_10;
}
if (version.isGreaterOrEqualTo(pythonVersion3_5)) {
if (PythonVersion.isGreaterOrEqualTo(version, pythonVersion3_5)) {
return python3_5;
}
return base;

View File

@ -474,7 +474,7 @@ export class Parser {
private _parseTypeAliasStatement(): TypeAliasNode {
const typeToken = this._getKeywordToken(KeywordType.Type);
if (!this._parseOptions.isStubFile && this._getLanguageVersion().isLessThan(pythonVersion3_12)) {
if (!this._parseOptions.isStubFile && PythonVersion.isLessThan(this._getLanguageVersion(), pythonVersion3_12)) {
this._addSyntaxError(LocMessage.typeAliasStatementIllegal(), typeToken);
}
@ -577,7 +577,10 @@ export class Parser {
/* allowUnpack */ typeParamCategory === TypeParamKind.TypeVarTuple
);
if (!this._parseOptions.isStubFile && this._getLanguageVersion().isLessThan(pythonVersion3_13)) {
if (
!this._parseOptions.isStubFile &&
PythonVersion.isLessThan(this._getLanguageVersion(), pythonVersion3_13)
) {
this._addSyntaxError(LocMessage.typeVarDefaultIllegal(), defaultExpression);
}
}
@ -702,7 +705,7 @@ export class Parser {
}
// This feature requires Python 3.10.
if (this._getLanguageVersion().isLessThan(pythonVersion3_10)) {
if (PythonVersion.isLessThan(this._getLanguageVersion(), pythonVersion3_10)) {
this._addSyntaxError(LocMessage.matchIncompatible(), matchToken);
}
@ -1629,7 +1632,10 @@ export class Parser {
// Versions of Python earlier than 3.9 didn't allow unpack operators if the
// tuple wasn't enclosed in parentheses.
if (this._getLanguageVersion().isLessThan(pythonVersion3_9) && !this._parseOptions.isStubFile) {
if (
PythonVersion.isLessThan(this._getLanguageVersion(), pythonVersion3_9) &&
!this._parseOptions.isStubFile
) {
if (seqExpr.nodeType === ParseNodeType.Tuple && !seqExpr.d.hasParens) {
let sawStar = false;
seqExpr.d.items.forEach((expr) => {
@ -1805,7 +1811,10 @@ export class Parser {
const possibleStarToken = this._peekToken();
let isExceptGroup = false;
if (this._consumeTokenIfOperator(OperatorType.Multiply)) {
if (this._getLanguageVersion().isLessThan(pythonVersion3_11) && !this._parseOptions.isStubFile) {
if (
PythonVersion.isLessThan(this._getLanguageVersion(), pythonVersion3_11) &&
!this._parseOptions.isStubFile
) {
this._addSyntaxError(LocMessage.exceptionGroupIncompatible(), possibleStarToken);
}
isExceptGroup = true;
@ -1904,7 +1913,10 @@ export class Parser {
if (possibleOpenBracket.type === TokenType.OpenBracket) {
typeParameters = this._parseTypeParameterList();
if (!this._parseOptions.isStubFile && this._getLanguageVersion().isLessThan(pythonVersion3_12)) {
if (
!this._parseOptions.isStubFile &&
PythonVersion.isLessThan(this._getLanguageVersion(), pythonVersion3_12)
) {
this._addSyntaxError(LocMessage.functionTypeParametersIllegal(), typeParameters);
}
}
@ -2118,7 +2130,10 @@ export class Parser {
} else if (this._consumeTokenIfOperator(OperatorType.Power)) {
starCount = 2;
} else if (this._consumeTokenIfOperator(OperatorType.Divide)) {
if (this._getLanguageVersion().isLessThan(pythonVersion3_8) && !this._parseOptions.isStubFile) {
if (
PythonVersion.isLessThan(this._getLanguageVersion(), pythonVersion3_8) &&
!this._parseOptions.isStubFile
) {
this._addSyntaxError(LocMessage.positionOnlyIncompatible(), firstToken);
}
slashCount = 1;
@ -2222,7 +2237,7 @@ export class Parser {
if (isParenthesizedWithItemList) {
this._consumeTokenIfType(TokenType.OpenParenthesis);
if (this._getLanguageVersion().isLessThan(pythonVersion3_9)) {
if (PythonVersion.isLessThan(this._getLanguageVersion(), pythonVersion3_9)) {
this._addSyntaxError(LocMessage.parenthesizedContextManagerIllegal(), possibleParen);
}
}
@ -2331,7 +2346,7 @@ export class Parser {
// Versions of Python prior to 3.9 support a limited set of
// expression forms.
if (this._getLanguageVersion().isLessThan(pythonVersion3_9)) {
if (PythonVersion.isLessThan(this._getLanguageVersion(), pythonVersion3_9)) {
let isSupportedExpressionForm = false;
if (this._isNameOrMemberAccessExpression(expression)) {
isSupportedExpressionForm = true;
@ -2382,7 +2397,10 @@ export class Parser {
if (possibleOpenBracket.type === TokenType.OpenBracket) {
typeParameters = this._parseTypeParameterList();
if (!this._parseOptions.isStubFile && this._getLanguageVersion().isLessThan(pythonVersion3_12)) {
if (
!this._parseOptions.isStubFile &&
PythonVersion.isLessThan(this._getLanguageVersion(), pythonVersion3_12)
) {
this._addSyntaxError(LocMessage.classTypeParametersIllegal(), typeParameters);
}
}
@ -2848,7 +2866,7 @@ export class Parser {
const nextToken = this._peekToken();
if (this._consumeTokenIfKeyword(KeywordType.From)) {
if (this._getLanguageVersion().isLessThan(pythonVersion3_3)) {
if (PythonVersion.isLessThan(this._getLanguageVersion(), pythonVersion3_3)) {
this._addSyntaxError(LocMessage.yieldFromIllegal(), nextToken);
}
return YieldFromNode.create(yieldToken, this._parseTestExpression(/* allowAssignmentExpression */ false));
@ -3188,7 +3206,7 @@ export class Parser {
this._addSyntaxError(LocMessage.walrusNotAllowed(), walrusToken);
}
if (this._getLanguageVersion().isLessThan(pythonVersion3_8)) {
if (PythonVersion.isLessThan(this._getLanguageVersion(), pythonVersion3_8)) {
this._addSyntaxError(LocMessage.walrusIllegal(), walrusToken);
}
@ -3478,7 +3496,7 @@ export class Parser {
let awaitToken: KeywordToken | undefined;
if (this._peekKeywordType() === KeywordType.Await) {
awaitToken = this._getKeywordToken(KeywordType.Await);
if (this._getLanguageVersion().isLessThan(pythonVersion3_5)) {
if (PythonVersion.isLessThan(this._getLanguageVersion(), pythonVersion3_5)) {
this._addSyntaxError(LocMessage.awaitIllegal(), awaitToken);
}
}
@ -3671,7 +3689,10 @@ export class Parser {
valueExpr = this._parseTestExpression(/* allowAssignmentExpression */ true);
// Python 3.10 and newer allow assignment expressions to be used inside of a subscript.
if (!this._parseOptions.isStubFile && this._getLanguageVersion().isLessThan(pythonVersion3_10)) {
if (
!this._parseOptions.isStubFile &&
PythonVersion.isLessThan(this._getLanguageVersion(), pythonVersion3_10)
) {
this._addSyntaxError(LocMessage.assignmentExprInSubscript(), valueExpr);
}
}
@ -3698,7 +3719,7 @@ export class Parser {
const unpackListAllowed =
this._parseOptions.isStubFile ||
this._isParsingQuotedText ||
this._getLanguageVersion().isGreaterOrEqualTo(pythonVersion3_11);
PythonVersion.isGreaterOrEqualTo(this._getLanguageVersion(), pythonVersion3_11);
if (argType === ArgCategory.UnpackedList && !unpackListAllowed) {
this._addSyntaxError(LocMessage.unpackedSubscriptIllegal(), argNode);
@ -3752,7 +3773,8 @@ export class Parser {
if (nextTokenType !== TokenType.Colon) {
// Python 3.10 and newer allow assignment expressions to be used inside of a subscript.
const allowAssignmentExpression =
this._parseOptions.isStubFile || this._getLanguageVersion().isGreaterOrEqualTo(pythonVersion3_10);
this._parseOptions.isStubFile ||
PythonVersion.isGreaterOrEqualTo(this._getLanguageVersion(), pythonVersion3_10);
sliceExpressions[sliceIndex] = this._parseTestExpression(allowAssignmentExpression);
}
sliceIndex++;
@ -3861,7 +3883,7 @@ export class Parser {
) {
nameNode = NameNode.create(nameExpr.d.token);
if (this._getLanguageVersion().isLessThan(pythonVersion3_14)) {
if (PythonVersion.isLessThan(this._getLanguageVersion(), pythonVersion3_14)) {
this._addSyntaxError(LocMessage.keywordArgShortcutIllegal(), assignmentToken);
valueExpr = ErrorNode.create(assignmentToken, ErrorExpressionCategory.MissingKeywordArgValue);
} else {
@ -4187,7 +4209,7 @@ export class Parser {
// Allow walrus operators in this context only for Python 3.10 and newer.
// Older versions of Python generated a syntax error in this context.
let isWalrusAllowed = this._getLanguageVersion().isGreaterOrEqualTo(pythonVersion3_10);
let isWalrusAllowed = PythonVersion.isGreaterOrEqualTo(this._getLanguageVersion(), pythonVersion3_10);
if (this._consumeTokenIfType(TokenType.Colon)) {
valueExpression = this._parseTestExpression(/* allowAssignmentExpression */ false);
@ -4391,7 +4413,10 @@ export class Parser {
annotationExpr = this._parseTypeAnnotation();
leftExpr = TypeAnnotationNode.create(leftExpr, annotationExpr);
if (!this._parseOptions.isStubFile && this._getLanguageVersion().isLessThan(pythonVersion3_6)) {
if (
!this._parseOptions.isStubFile &&
PythonVersion.isLessThan(this._getLanguageVersion(), pythonVersion3_6)
) {
this._addSyntaxError(LocMessage.varAnnotationIllegal(), annotationExpr);
}
@ -4575,7 +4600,7 @@ export class Parser {
allowUnpack &&
!this._parseOptions.isStubFile &&
!this._isParsingQuotedText &&
this._getLanguageVersion().isLessThan(pythonVersion3_11)
PythonVersion.isLessThan(this._getLanguageVersion(), pythonVersion3_11)
) {
this._addSyntaxError(LocMessage.unpackedSubscriptIllegal(), startToken);
}
@ -4603,7 +4628,7 @@ export class Parser {
}
if (stringToken.flags & StringTokenFlags.Format) {
if (this._getLanguageVersion().isLessThan(pythonVersion3_6)) {
if (PythonVersion.isLessThan(this._getLanguageVersion(), pythonVersion3_6)) {
this._addSyntaxError(LocMessage.formatStringIllegal(), stringToken);
}
@ -4758,7 +4783,7 @@ export class Parser {
(nextToken as OperatorToken).operatorType === OperatorType.Assign
) {
// This feature requires Python 3.8 or newer.
if (this._parseOptions.pythonVersion.isLessThan(pythonVersion3_8)) {
if (PythonVersion.isLessThan(this._parseOptions.pythonVersion, pythonVersion3_8)) {
this._addSyntaxError(LocMessage.formatStringDebuggingIllegal(), nextToken);
}
@ -5019,7 +5044,7 @@ export class Parser {
return;
}
if (this._parseOptions.pythonVersion.isGreaterOrEqualTo(pythonVersion)) {
if (PythonVersion.isGreaterOrEqualTo(this._parseOptions.pythonVersion, pythonVersion)) {
return;
}