Allow `Final` and `ClassVar` to be combined in both directions within a dataclass. Previously, the `Final` qualifier needed to be the outermost. This addresses #8676. (#8678)

This commit is contained in:
Eric Traut 2024-08-06 11:44:51 -06:00 коммит произвёл GitHub
Родитель 08e02e450b
Коммит c285825dea
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
3 изменённых файлов: 20 добавлений и 10 удалений

Просмотреть файл

@ -7607,24 +7607,30 @@ export function createTypeEvaluator(
const typeArgs: TypeResultWithNode[] = [];
let adjFlags = flags | EvalFlags.NoConvertSpecialForm;
if (options?.isFinalAnnotation) {
adjFlags |= EvalFlags.NoClassVar | EvalFlags.NoFinal;
} else if (options?.isClassVarAnnotation) {
adjFlags |= EvalFlags.NoClassVar;
const allowFinalClassVar = () => {
// If the annotation is a variable within the body of a dataclass, a
// Final is allowed within the ClassVar annotation. In all other cases,
// Final is allowed with a ClassVar annotation. In all other cases,
// it's disallowed.
let disallowFinal = true;
const enclosingClassNode = ParseTreeUtils.getEnclosingClass(node, /* stopeAtFunction */ true);
if (enclosingClassNode) {
const classTypeInfo = getTypeOfClass(enclosingClassNode);
if (classTypeInfo && ClassType.isDataClass(classTypeInfo.classType)) {
disallowFinal = false;
return true;
}
}
return false;
};
if (disallowFinal) {
if (options?.isFinalAnnotation) {
adjFlags |= EvalFlags.NoFinal;
if (!allowFinalClassVar()) {
adjFlags |= EvalFlags.NoClassVar;
}
} else if (options?.isClassVarAnnotation) {
adjFlags |= EvalFlags.NoClassVar;
if (!allowFinalClassVar()) {
adjFlags |= EvalFlags.NoFinal;
}
} else {

Просмотреть файл

@ -11,6 +11,7 @@ class A:
b: Final[str] = ""
c: ClassVar[Final[int]] = 0
d: ClassVar[Final] = 0
e: Final[ClassVar[int]] = 0
a = A(1)
@ -29,3 +30,6 @@ A.c = 0
# This should generate an error.
A.d = 0
# This should generate an error.
A.e = 0

Просмотреть файл

@ -363,7 +363,7 @@ test('DataClass16', () => {
test('DataClass17', () => {
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['dataclass17.py']);
TestUtils.validateResults(analysisResults, 5);
TestUtils.validateResults(analysisResults, 6);
});
test('DataClassReplace1', () => {