mirror of
https://github.com/microsoft/pyright.git
synced 2024-09-11 07:55:56 +03:00
Fixed false positive that occurs when overriding an abstract method (e.g. a property) with a field from a named tuple when both are used as base classes.
This commit is contained in:
parent
44b813c761
commit
50d56824c0
@ -264,7 +264,10 @@ export function createNamedTupleType(
|
||||
entryTypes.push(entryType);
|
||||
matchArgsNames.push(entryName);
|
||||
|
||||
const newSymbol = Symbol.createWithType(SymbolFlags.InstanceMember, entryType);
|
||||
const newSymbol = Symbol.createWithType(
|
||||
SymbolFlags.InstanceMember | SymbolFlags.NamedTupleMember,
|
||||
entryType
|
||||
);
|
||||
if (entryNameNode && entryNameNode.nodeType === ParseNodeType.StringList) {
|
||||
const declaration: VariableDeclaration = {
|
||||
type: DeclarationType.Variable,
|
||||
|
@ -52,6 +52,11 @@ export const enum SymbolFlags {
|
||||
|
||||
// Indicates that the symbol is an InitVar as specified in PEP 557.
|
||||
InitVar = 1 << 10,
|
||||
|
||||
// Indicates that the symbol is a field in a NamedTuple class, which
|
||||
// is modeled as an instance member but in some respects acts as a
|
||||
// class member.
|
||||
NamedTupleMember = 1 << 11,
|
||||
}
|
||||
|
||||
let nextSymbolId = 1;
|
||||
@ -167,6 +172,10 @@ export class Symbol {
|
||||
return !!(this._flags & SymbolFlags.PrivatePyTypedImport);
|
||||
}
|
||||
|
||||
isNamedTupleMemberMember() {
|
||||
return !!(this._flags & SymbolFlags.NamedTupleMember);
|
||||
}
|
||||
|
||||
addDeclaration(declaration: Declaration) {
|
||||
if (this._declarations) {
|
||||
// See if this node was already identified as a declaration. If so,
|
||||
|
@ -22986,7 +22986,11 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
|
||||
// We do a quick-and-dirty evaluation of methods based on
|
||||
// decorators to determine which ones are abstract. This allows
|
||||
// us to avoid evaluating the full function types.
|
||||
if (symbol.isClassMember()) {
|
||||
// Handle named tuple fields as though they are class members here.
|
||||
// We model them as instance variables, but they're actually implemented
|
||||
// using class variable descriptors, and these overwrite a class variable
|
||||
// abstract method.
|
||||
if (symbol.isClassMember() || symbol.isNamedTupleMemberMember()) {
|
||||
let isAbstract: boolean;
|
||||
|
||||
const decl = getLastTypedDeclaredForSymbol(symbol);
|
||||
|
@ -107,6 +107,12 @@ test('AbstractClass8', () => {
|
||||
TestUtils.validateResults(analysisResults, 1);
|
||||
});
|
||||
|
||||
test('AbstractClass9', () => {
|
||||
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['abstractClass9.py']);
|
||||
|
||||
TestUtils.validateResults(analysisResults, 0);
|
||||
});
|
||||
|
||||
test('Constants1', () => {
|
||||
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['constants1.py']);
|
||||
|
||||
|
@ -0,0 +1,21 @@
|
||||
# This sample tests that named tuple fields override abstract methods.
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import NamedTuple
|
||||
|
||||
|
||||
class ClassA(ABC):
|
||||
@property
|
||||
@abstractmethod
|
||||
def myproperty(self) -> str:
|
||||
...
|
||||
|
||||
|
||||
MixinB = NamedTuple("MixinB", [("myproperty", str)])
|
||||
|
||||
|
||||
class ClassB(MixinB, ClassA):
|
||||
pass
|
||||
|
||||
|
||||
ClassB(myproperty="myproperty")
|
Loading…
Reference in New Issue
Block a user