Don't consider metaclass.__call__(cls, *args, **kwargs) as a possible constructor (PY-17877, PY-41380)

GitOrigin-RevId: de83bde719d08de70dcff7f3ad7dfa722a66af72
This commit is contained in:
Semyon Proshev
2020-04-28 21:08:25 +00:00
committed by intellij-monorepo-bot
parent e3d0698dab
commit 40c9d375e5
4 changed files with 55 additions and 3 deletions
@@ -80,6 +80,11 @@ public abstract class PyCommonResolveTest extends PyCommonResolveTestCase {
assertResolvesTo(LanguageLevel.getLatest(), PyFunction.class, PyNames.CALL);
}
// PY-17877, PY-41380
public void testInitializingNotToMetaclassSelfArgsKwargsDunderCall() {
assertResolvesTo(LanguageLevel.getLatest(), PyClass.class, "MyClass");
}
public void testInitOrNewReturnsInitWhenNewIsFirst() {
doTestInitOrNewReturnsInit();
}
@@ -921,7 +921,12 @@ public class PyCallExpressionHelper {
final Set<PsiElement> typeDunderCall =
ContainerUtil.map2Set(resolveDunderCall(typeType, null, resolveContext), ResolveResult::getElement);
return StreamEx.of(results).map(ResolveResult::getElement).remove(it -> typeDunderCall.contains(it)).toList();
return StreamEx
.of(results)
.map(ResolveResult::getElement)
.remove(it -> typeDunderCall.contains(it) || isSelfArgsKwargsCallable(it, context))
.toList();
}
@NotNull
@@ -932,6 +937,18 @@ public class PyCallExpressionHelper {
return ObjectUtils.notNull(type.resolveMember(PyNames.CALL, location, AccessDirection.READ, resolveContext), Collections.emptyList());
}
private static boolean isSelfArgsKwargsCallable(@Nullable PsiElement element, @NotNull TypeEvalContext context) {
if (element instanceof PyCallable) {
final List<PyCallableParameter> parameters = ((PyCallable)element).getParameters(context);
return parameters.size() == 3 &&
parameters.get(0).isSelf() &&
parameters.get(1).isPositionalContainer() &&
parameters.get(2).isKeywordContainer();
}
return false;
}
@NotNull
private static ArgumentMappingResults analyzeArguments(@NotNull List<PyExpression> arguments,
@NotNull List<PyCallableParameter> parameters) {
@@ -0,0 +1,9 @@
class MyMeta(type):
def __call__(cls, *args, **kwargs):
pass
class MyClass(metaclass=MyMeta):
pass
MyClass()
<ref>
@@ -418,7 +418,7 @@ public class PyArgumentListInspectionTest extends PyInspectionTestCase {
LanguageLevel.getLatest(),
() -> doTestByText("class MetaFoo(type):\n" +
" def __call__(cls, p3, p4):\n" +
" print(f'MetaFoo: {cls}, {p3}, {p4}')\n" +
" print(f'MetaFoo.__call__: {cls}, {p3}, {p4}')\n" +
"\n" +
"class Foo(metaclass=MetaFoo):\n" +
" pass\n" +
@@ -426,10 +426,31 @@ public class PyArgumentListInspectionTest extends PyInspectionTestCase {
"class SubFoo(Foo):\n" +
" def __new__(self, p1, p2):\n" +
" # This never gets called\n" +
" print(f'Foo.__new__: {p1}, {p2}')\n" +
" print(f'SubFoo.__new__: {p1}, {p2}')\n" +
"\n" +
"sub = SubFoo(1<warning descr=\"Parameter 'p4' unfilled\">)</warning>\n" +
"foo = Foo(3<warning descr=\"Parameter 'p4' unfilled\">)</warning>")
);
}
// PY-17877, PY-41380
public void testNotMetaclassHavingSelfArgsKwargsDunderCall() {
runWithLanguageLevel(
LanguageLevel.getLatest(),
() -> doTestByText("class MetaFoo(type):\n" +
" def __call__(cls, *args, **kwargs):\n" +
" print(f'MetaFoo.__call__: {cls}, {args}, {kwargs}')\n" +
" return super(MetaFoo, cls).__call__(*args, **kwargs)\n" +
"\n" +
"class Foo(metaclass=MetaFoo):\n" +
" pass\n" +
"\n" +
"class SubFoo(Foo):\n" +
" def __init__(self, p1, p2):\n" +
" print(f'SubFoo.__init__: {p1}, {p2}')\n" +
"\n" +
"foo = Foo()\n" +
"sub = SubFoo(1<warning descr=\"Parameter 'p2' unfilled\">)</warning>")
);
}
}