mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Fix provided type for namedtuple._replace when receiver is namedtuple definition (PY-27148)
This commit is contained in:
@@ -221,10 +221,14 @@ class PyNamedTupleTypeProvider : PyTypeProviderBase() {
|
||||
else null
|
||||
}
|
||||
|
||||
private fun createTypedNamedTupleReplaceType(anchor: PsiElement, fields: ImmutableNTFields, resultType: PyType): PyCallableType {
|
||||
private fun createTypedNamedTupleReplaceType(anchor: PsiElement, fields: ImmutableNTFields, qualifierType: PyClassLikeType): PyCallableType {
|
||||
val parameters = mutableListOf<PyCallableParameter>()
|
||||
val resultType = qualifierType.toInstance()
|
||||
val elementGenerator = PyElementGenerator.getInstance(anchor.project)
|
||||
|
||||
if (qualifierType.isDefinition) {
|
||||
parameters.add(PyCallableParameterImpl.nonPsi(PyNames.CANONICAL_SELF, resultType))
|
||||
}
|
||||
parameters.add(PyCallableParameterImpl.psi(elementGenerator.createSingleStarParameter()))
|
||||
|
||||
val ellipsis = elementGenerator.createEllipsis()
|
||||
@@ -238,11 +242,15 @@ class PyNamedTupleTypeProvider : PyTypeProviderBase() {
|
||||
|
||||
private fun createUntypedNamedTupleReplaceType(call: PyCallExpression,
|
||||
fields: ImmutableNTFields,
|
||||
resultType: PyType,
|
||||
qualifierType: PyClassLikeType,
|
||||
context: TypeEvalContext): PyCallableType {
|
||||
val parameters = mutableListOf<PyCallableParameter>()
|
||||
val resultType = qualifierType.toInstance()
|
||||
val elementGenerator = PyElementGenerator.getInstance(call.project)
|
||||
|
||||
if (qualifierType.isDefinition) {
|
||||
parameters.add(PyCallableParameterImpl.nonPsi(PyNames.CANONICAL_SELF, resultType))
|
||||
}
|
||||
parameters.add(PyCallableParameterImpl.psi(elementGenerator.createSingleStarParameter()))
|
||||
|
||||
val ellipsis = elementGenerator.createEllipsis()
|
||||
|
||||
+28
-6
@@ -6,22 +6,33 @@ mt1 = MyTup1(1, 2)
|
||||
|
||||
# empty
|
||||
mt1._replace()
|
||||
MyTup1._replace(mt1)
|
||||
|
||||
# one
|
||||
mt1._replace(bar=2)
|
||||
mt1._replace(baz=1)
|
||||
mt1._replace(<warning descr="Unexpected argument">foo=1</warning>)
|
||||
mt1._replace(<warning descr="Unexpected argument">1</warning>)
|
||||
mt1._replace(<warning descr="Unexpected argument">1</warning>)
|
||||
MyTup1._replace(mt1, bar=2)
|
||||
MyTup1._replace(mt1, baz=1)
|
||||
MyTup1._replace(mt1, <warning descr="Unexpected argument">foo=1</warning>)
|
||||
MyTup1._replace(mt1, <warning descr="Unexpected argument">1</warning>)
|
||||
|
||||
# two
|
||||
mt1._replace(bar=1, baz=2)
|
||||
mt1._replace(baz=2, bar=1)
|
||||
mt1._replace(baz=2, <warning descr="Unexpected argument">foo=1</warning>)
|
||||
mt1._replace(<warning descr="Unexpected argument">2</warning>, <warning descr="Unexpected argument">1</warning>)
|
||||
mt1._replace(<warning descr="Unexpected argument">2</warning>, <warning descr="Unexpected argument">1</warning>)
|
||||
MyTup1._replace(mt1, bar=1, baz=2)
|
||||
MyTup1._replace(mt1, baz=2, bar=1)
|
||||
MyTup1._replace(mt1, baz=2, <warning descr="Unexpected argument">foo=1</warning>)
|
||||
MyTup1._replace(mt1, <warning descr="Unexpected argument">2</warning>, <warning descr="Unexpected argument">1</warning>)
|
||||
|
||||
# two
|
||||
mt1._replace(bar=1, baz=2, <warning descr="Unexpected argument">foo=3</warning>)
|
||||
mt1._replace(<warning descr="Unexpected argument">1</warning>, <warning descr="Unexpected argument">2</warning>, <warning descr="Unexpected argument">3</warning>)
|
||||
mt1._replace(<warning descr="Unexpected argument">1</warning>, <warning descr="Unexpected argument">2</warning>, <warning descr="Unexpected argument">3</warning>)
|
||||
MyTup1._replace(mt1, bar=1, baz=2, <warning descr="Unexpected argument">foo=3</warning>)
|
||||
MyTup1._replace(mt1, <warning descr="Unexpected argument">1</warning>, <warning descr="Unexpected argument">2</warning>, <warning descr="Unexpected argument">3</warning>)
|
||||
|
||||
|
||||
class MyTup2(namedtuple("MyTup2", "bar baz")):
|
||||
@@ -30,19 +41,30 @@ mt2 = MyTup2(1, 2)
|
||||
|
||||
# empty
|
||||
mt2._replace()
|
||||
MyTup2._replace(mt2)
|
||||
|
||||
# one
|
||||
mt2._replace(bar=2)
|
||||
mt2._replace(baz=1)
|
||||
mt2._replace(<warning descr="Unexpected argument">foo=1</warning>)
|
||||
mt2._replace(<warning descr="Unexpected argument">1</warning>)
|
||||
mt2._replace(<warning descr="Unexpected argument">1</warning>)
|
||||
MyTup2._replace(mt2, bar=2)
|
||||
MyTup2._replace(mt2, baz=1)
|
||||
MyTup2._replace(mt2, <warning descr="Unexpected argument">foo=1</warning>)
|
||||
MyTup2._replace(mt2, <warning descr="Unexpected argument">1</warning>)
|
||||
|
||||
# two
|
||||
mt2._replace(bar=1, baz=2)
|
||||
mt2._replace(baz=2, bar=1)
|
||||
mt2._replace(baz=2, <warning descr="Unexpected argument">foo=1</warning>)
|
||||
mt2._replace(<warning descr="Unexpected argument">2</warning>, <warning descr="Unexpected argument">1</warning>)
|
||||
mt2._replace(<warning descr="Unexpected argument">2</warning>, <warning descr="Unexpected argument">1</warning>)
|
||||
MyTup2._replace(mt2, bar=1, baz=2)
|
||||
MyTup2._replace(mt2, baz=2, bar=1)
|
||||
MyTup2._replace(mt2, baz=2, <warning descr="Unexpected argument">foo=1</warning>)
|
||||
MyTup2._replace(mt2, <warning descr="Unexpected argument">2</warning>, <warning descr="Unexpected argument">1</warning>)
|
||||
|
||||
# two
|
||||
mt2._replace(bar=1, baz=2, <warning descr="Unexpected argument">foo=3</warning>)
|
||||
mt2._replace(<warning descr="Unexpected argument">1</warning>, <warning descr="Unexpected argument">2</warning>, <warning descr="Unexpected argument">3</warning>)
|
||||
mt2._replace(<warning descr="Unexpected argument">1</warning>, <warning descr="Unexpected argument">2</warning>, <warning descr="Unexpected argument">3</warning>)
|
||||
MyTup2._replace(mt2, bar=1, baz=2, <warning descr="Unexpected argument">foo=3</warning>)
|
||||
MyTup2._replace(mt2, <warning descr="Unexpected argument">1</warning>, <warning descr="Unexpected argument">2</warning>, <warning descr="Unexpected argument">3</warning>)
|
||||
@@ -6,22 +6,33 @@ mt1 = MyTup1(1, 2)
|
||||
|
||||
# empty
|
||||
mt1._replace()
|
||||
MyTup1._replace(mt1)
|
||||
|
||||
# one
|
||||
mt1._replace(bar=2)
|
||||
mt1._replace(baz=1)
|
||||
mt1._replace(<warning descr="Unexpected argument">foo=1</warning>)
|
||||
mt1._replace(<warning descr="Unexpected argument">1</warning>)
|
||||
mt1._replace(<warning descr="Unexpected argument">1</warning>)
|
||||
MyTup1._replace(mt1, bar=2)
|
||||
MyTup1._replace(mt1, baz=1)
|
||||
MyTup1._replace(mt1, <warning descr="Unexpected argument">foo=1</warning>)
|
||||
MyTup1._replace(mt1, <warning descr="Unexpected argument">1</warning>)
|
||||
|
||||
# two
|
||||
mt1._replace(bar=1, baz=2)
|
||||
mt1._replace(baz=2, bar=1)
|
||||
mt1._replace(baz=2, <warning descr="Unexpected argument">foo=1</warning>)
|
||||
mt1._replace(<warning descr="Unexpected argument">2</warning>, <warning descr="Unexpected argument">1</warning>)
|
||||
mt1._replace(<warning descr="Unexpected argument">2</warning>, <warning descr="Unexpected argument">1</warning>)
|
||||
MyTup1._replace(mt1, bar=1, baz=2)
|
||||
MyTup1._replace(mt1, baz=2, bar=1)
|
||||
MyTup1._replace(mt1, baz=2, <warning descr="Unexpected argument">foo=1</warning>)
|
||||
MyTup1._replace(mt1, <warning descr="Unexpected argument">2</warning>, <warning descr="Unexpected argument">1</warning>)
|
||||
|
||||
# two
|
||||
mt1._replace(bar=1, baz=2, <warning descr="Unexpected argument">foo=3</warning>)
|
||||
mt1._replace(<warning descr="Unexpected argument">1</warning>, <warning descr="Unexpected argument">2</warning>, <warning descr="Unexpected argument">3</warning>)
|
||||
mt1._replace(<warning descr="Unexpected argument">1</warning>, <warning descr="Unexpected argument">2</warning>, <warning descr="Unexpected argument">3</warning>)
|
||||
MyTup1._replace(mt1, bar=1, baz=2, <warning descr="Unexpected argument">foo=3</warning>)
|
||||
MyTup1._replace(mt1, <warning descr="Unexpected argument">1</warning>, <warning descr="Unexpected argument">2</warning>, <warning descr="Unexpected argument">3</warning>)
|
||||
|
||||
|
||||
class MyTup2(typing.NamedTuple):
|
||||
@@ -31,19 +42,30 @@ mt2 = MyTup2(1, 2)
|
||||
|
||||
# empty
|
||||
mt2._replace()
|
||||
MyTup2._replace(mt2)
|
||||
|
||||
# one
|
||||
mt2._replace(bar=2)
|
||||
mt2._replace(baz=1)
|
||||
mt2._replace(<warning descr="Unexpected argument">foo=1</warning>)
|
||||
mt2._replace(<warning descr="Unexpected argument">1</warning>)
|
||||
mt2._replace(<warning descr="Unexpected argument">1</warning>)
|
||||
MyTup2._replace(mt2, bar=2)
|
||||
MyTup2._replace(mt2, baz=1)
|
||||
MyTup2._replace(mt2, <warning descr="Unexpected argument">foo=1</warning>)
|
||||
MyTup2._replace(mt2, <warning descr="Unexpected argument">1</warning>)
|
||||
|
||||
# two
|
||||
mt2._replace(bar=1, baz=2)
|
||||
mt2._replace(baz=2, bar=1)
|
||||
mt2._replace(baz=2, <warning descr="Unexpected argument">foo=1</warning>)
|
||||
mt2._replace(<warning descr="Unexpected argument">2</warning>, <warning descr="Unexpected argument">1</warning>)
|
||||
mt2._replace(<warning descr="Unexpected argument">2</warning>, <warning descr="Unexpected argument">1</warning>)
|
||||
MyTup2._replace(mt2, bar=1, baz=2)
|
||||
MyTup2._replace(mt2, baz=2, bar=1)
|
||||
MyTup2._replace(mt2, baz=2, <warning descr="Unexpected argument">foo=1</warning>)
|
||||
MyTup2._replace(mt2, <warning descr="Unexpected argument">2</warning>, <warning descr="Unexpected argument">1</warning>)
|
||||
|
||||
# two
|
||||
mt2._replace(bar=1, baz=2, <warning descr="Unexpected argument">foo=3</warning>)
|
||||
mt2._replace(<warning descr="Unexpected argument">1</warning>, <warning descr="Unexpected argument">2</warning>, <warning descr="Unexpected argument">3</warning>)
|
||||
mt2._replace(<warning descr="Unexpected argument">1</warning>, <warning descr="Unexpected argument">2</warning>, <warning descr="Unexpected argument">3</warning>)
|
||||
MyTup2._replace(mt2, bar=1, baz=2, <warning descr="Unexpected argument">foo=3</warning>)
|
||||
MyTup2._replace(mt2, <warning descr="Unexpected argument">1</warning>, <warning descr="Unexpected argument">2</warning>, <warning descr="Unexpected argument">3</warning>)
|
||||
@@ -9,4 +9,7 @@ class MyTup2(namedtuple("MyTup2", "bar baz")):
|
||||
|
||||
|
||||
MyTup1(1, 2)._replace(<arg1>)
|
||||
MyTup2(1, 2)._replace(<arg2>)
|
||||
MyTup2(1, 2)._replace(<arg2>)
|
||||
|
||||
MyTup1._replace(MyTup1(1, 2), <arg3>)
|
||||
MyTup2._replace(MyTup2(1, 2), <arg4>)
|
||||
@@ -1,7 +1,7 @@
|
||||
import typing
|
||||
|
||||
|
||||
MyTup1 = typing.NamedTuple("MyTup2", bar=int, baz=str)
|
||||
MyTup1 = typing.NamedTuple("MyTup1", bar=int, baz=str)
|
||||
|
||||
|
||||
class MyTup2(typing.NamedTuple):
|
||||
@@ -10,4 +10,7 @@ class MyTup2(typing.NamedTuple):
|
||||
|
||||
|
||||
MyTup1(1, "")._replace(<arg1>)
|
||||
MyTup2(1, "")._replace(<arg2>)
|
||||
MyTup2(1, "")._replace(<arg2>)
|
||||
|
||||
MyTup1._replace(MyTup1(1, ""), <arg3>)
|
||||
MyTup2._replace(MyTup2(1, ""), <arg4>)
|
||||
@@ -38,8 +38,8 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Tests parameter info available via ^P at call sites.
|
||||
@@ -105,11 +105,11 @@ public class PyParameterInfoTest extends LightMarkedTestCase {
|
||||
PsiElement arg1 = marks.get("<arg1>");
|
||||
feignCtrlP(arg1.getTextOffset()).check("a, b, *c", new String[]{"a, "});
|
||||
feignCtrlP(arg1.getTextOffset()+1).check("a, b, *c", new String[]{"a, "});
|
||||
|
||||
|
||||
PsiElement arg2 = marks.get("<arg2>");
|
||||
feignCtrlP(arg2.getTextOffset()).check("a, b, *c", new String[]{"b, "});
|
||||
feignCtrlP(arg2.getTextOffset()+1).check("a, b, *c", new String[]{"b, "});
|
||||
|
||||
|
||||
PsiElement arg3 = marks.get("<arg3>");
|
||||
feignCtrlP(arg3.getTextOffset()).check("a, b, *c", new String[]{"*c"});
|
||||
feignCtrlP(arg3.getTextOffset()+1).check("a, b, *c", new String[]{"*c"});
|
||||
@@ -692,11 +692,14 @@ public class PyParameterInfoTest extends LightMarkedTestCase {
|
||||
|
||||
// PY-27148
|
||||
public void testCollectionsNamedTupleReplace() {
|
||||
final Map<String, PsiElement> test = loadTest(2);
|
||||
final Map<String, PsiElement> test = loadTest(4);
|
||||
|
||||
for (int offset : StreamEx.of(test.values()).map(PsiElement::getTextOffset)) {
|
||||
for (int offset : StreamEx.of("<arg1>", "<arg2>").map(test::get).map(PsiElement::getTextOffset)) {
|
||||
feignCtrlP(offset).check("*, bar=..., baz=...", ArrayUtil.EMPTY_STRING_ARRAY);
|
||||
}
|
||||
|
||||
feignCtrlP(test.get("<arg3>").getTextOffset()).check("self: MyTup1, *, bar=..., baz=...", ArrayUtil.EMPTY_STRING_ARRAY);
|
||||
feignCtrlP(test.get("<arg4>").getTextOffset()).check("self: MyTup2, *, bar=..., baz=...", ArrayUtil.EMPTY_STRING_ARRAY);
|
||||
}
|
||||
|
||||
// PY-27148
|
||||
@@ -704,11 +707,14 @@ public class PyParameterInfoTest extends LightMarkedTestCase {
|
||||
runWithLanguageLevel(
|
||||
LanguageLevel.PYTHON36,
|
||||
() -> {
|
||||
final Map<String, PsiElement> test = loadTest(2);
|
||||
final Map<String, PsiElement> test = loadTest(4);
|
||||
|
||||
for (int offset : StreamEx.of(test.values()).map(PsiElement::getTextOffset)) {
|
||||
for (int offset : StreamEx.of("<arg1>", "<arg2>").map(test::get).map(PsiElement::getTextOffset)) {
|
||||
feignCtrlP(offset).check("*, bar: int=..., baz: str=...", ArrayUtil.EMPTY_STRING_ARRAY);
|
||||
}
|
||||
|
||||
feignCtrlP(test.get("<arg3>").getTextOffset()).check("self: MyTup1, *, bar: int=..., baz: str=...", ArrayUtil.EMPTY_STRING_ARRAY);
|
||||
feignCtrlP(test.get("<arg4>").getTextOffset()).check("self: MyTup2, *, bar: int=..., baz: str=...", ArrayUtil.EMPTY_STRING_ARRAY);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3070,6 +3070,12 @@ public class PyTypeTest extends PyTestCase {
|
||||
"from collections import namedtuple\n" +
|
||||
"Cat = namedtuple(\"Cat\", \"name age\")\n" +
|
||||
"expr = Cat(\"name\", 5)._replace(age=\"five\").age");
|
||||
|
||||
doTest("Cat",
|
||||
"from collections import namedtuple\n" +
|
||||
"class Cat(namedtuple(\"Cat\", \"name age\")):\n" +
|
||||
" pass\n" +
|
||||
"expr = Cat._replace(Cat(\"name\", 5), name=\"newname\")");
|
||||
}
|
||||
|
||||
// PY-27148
|
||||
@@ -3099,6 +3105,16 @@ public class PyTypeTest extends PyTestCase {
|
||||
"Cat = NamedTuple(\"Cat\", name=str, age=int)\n" +
|
||||
"expr = Cat(\"name\", 5)._replace(age=\"give\").age")
|
||||
);
|
||||
|
||||
runWithLanguageLevel(
|
||||
LanguageLevel.PYTHON36,
|
||||
() -> doTest("Cat",
|
||||
"from typing import NamedTuple\n" +
|
||||
"class Cat(NamedTuple):\n" +
|
||||
" name: str\n" +
|
||||
" age: int\n" +
|
||||
"expr = Cat._replace(Cat(\"name\", 5), name=\"newname\")")
|
||||
);
|
||||
}
|
||||
|
||||
// PY-21302
|
||||
|
||||
Reference in New Issue
Block a user