mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-CR-55284: PY-38412 Fix unstubbing in case of TypedDict creation with class-based syntax
GitOrigin-RevId: 3d165abaa22d6fa31d63964c8a7fa828fdefd1dd
This commit is contained in:
committed by
intellij-monorepo-bot
parent
32ae4f4b20
commit
03b5d990d8
+13
-8
@@ -143,21 +143,25 @@ class PyTypedDictTypeProvider : PyTypeProviderBase() {
|
||||
true
|
||||
}
|
||||
|
||||
val argumentList = cls.children.filterIsInstance<PyArgumentList>().firstOrNull()
|
||||
val totalityValue = argumentList?.getKeywordArgument("total")
|
||||
val fieldsRequired = if (totalityValue != null && totalityValue.valueExpression is PyBoolLiteralExpression)
|
||||
(totalityValue.valueExpression as PyBoolLiteralExpression).value
|
||||
else true
|
||||
|
||||
val totality = getTotality(cls)
|
||||
val toTDFields = Collectors.toMap<PyTargetExpression, String, PyTypedDictType.FieldTypeAndTotality, TDFields>(
|
||||
{ it.name },
|
||||
{ field -> PyTypedDictType.FieldTypeAndTotality(context.getType(field), fieldsRequired) },
|
||||
{ field -> PyTypedDictType.FieldTypeAndTotality(context.getType(field), totality) },
|
||||
{ _, v2 -> v2 },
|
||||
{ TDFields() })
|
||||
|
||||
return fields.stream().collect(toTDFields)
|
||||
}
|
||||
|
||||
private fun getTotality(cls: PyClass): Boolean {
|
||||
return if (cls.stub != null) {
|
||||
"total=False" !in cls.stub.superClassesText
|
||||
}
|
||||
else {
|
||||
(cls.superClassExpressionList?.getKeywordArgument("total")?.valueExpression as? PyBoolLiteralExpression)?.value ?: true
|
||||
}
|
||||
}
|
||||
|
||||
private fun getTypedDictTypeForTarget(target: PyTargetExpression, context: TypeEvalContext): PyTypedDictType? {
|
||||
val stub = target.stub
|
||||
|
||||
@@ -283,7 +287,8 @@ class PyTypedDictTypeProvider : PyTypeProviderBase() {
|
||||
PyTypedDictType.DefinitionLevel.INSTANCE,
|
||||
emptyList())
|
||||
}
|
||||
} else if (expression is PyCallExpression) {
|
||||
}
|
||||
else if (expression is PyCallExpression) {
|
||||
val resolvedQualifiedNames = if (expression.callee != null) resolveToQualifiedNames(expression.callee!!, context) else return null
|
||||
if (resolvedQualifiedNames.any { it == PyNames.DICT }) {
|
||||
val arguments = expression.arguments
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
avrora = {'name': 'Iskra', 'id': 42}
|
||||
rodina = {'name': 'Iskra'}
|
||||
luksor = <warning descr="Expected type 'Cinema', got 'Dict[str, str]' instead">{'name': 'Iskra', 'id': '42'}</warning>
|
||||
@@ -0,0 +1,11 @@
|
||||
from typing import TypedDict
|
||||
|
||||
|
||||
class Cinema(TypedDict, total=False):
|
||||
name: str
|
||||
id: int
|
||||
|
||||
|
||||
avrora: Cinema
|
||||
rodina: Cinema
|
||||
luksor: Cinema
|
||||
@@ -1083,4 +1083,9 @@ public class PyTypeCheckerInspectionTest extends PyInspectionTestCase {
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// PY-38412
|
||||
public void testTypedDictInStub() {
|
||||
runWithLanguageLevel(LanguageLevel.getLatest(), this::doMultiFileTest);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user