PY-22525 Fixed: PyCharm complains that typing.Iterable "does not define __getitem__"

PY-22642 Fixed: Static typecheck resolution of `typing.Generic` is to the first assignment, not the effective

Mark `__getitem__` of `typing.Generic` itself and its descendants as ignored through PyTypingInspectionExtension.
This commit is contained in:
Semyon Proshev
2017-02-17 15:43:29 +03:00
committed by Semyon Proshev
parent 8a6de5742b
commit bdccd01940
8 changed files with 89 additions and 10 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -55,10 +55,32 @@ public abstract class PyInspectionExtension {
return false;
}
/**
* Checks if unresolved member could be ignored.
*
* @param type type whose member will be checked
* @param name member name
* @return true if the unresolved member with the specified name could be ignored
* @deprecated Use {@link PyInspectionExtension#ignoreUnresolvedMember(PyType, String, TypeEvalContext)} instead.
* This method will be removed in 2018.1.
*/
@Deprecated
public boolean ignoreUnresolvedMember(@NotNull PyType type, @NotNull String name) {
return false;
}
/**
* Checks if unresolved member could be ignored.
*
* @param type type whose member will be checked
* @param name member name
* @param context type evaluation context
* @return true if the unresolved member with the specified name could be ignored
*/
public boolean ignoreUnresolvedMember(@NotNull PyType type, @NotNull String name, @NotNull TypeEvalContext context) {
return ignoreUnresolvedMember(type, name);
}
/**
* Returns true if access to protected (the one started with "_") symbol should not be treated as violation.
*
@@ -690,6 +690,7 @@
<pyClassMembersProvider implementation="com.jetbrains.python.pyi.PyiClassMembersProvider"/>
<visitorFilter language="PythonStub" implementationClass="com.jetbrains.python.pyi.PyiVisitorFilter"/>
<inspectionExtension implementation="com.jetbrains.python.pyi.PyiInspectionExtension"/>
<inspectionExtension implementation="com.jetbrains.python.codeInsight.typing.PyTypingInspectionExtension"/>
<customPackageIdentifier implementation="com.jetbrains.python.pyi.PyiCustomPackageIdentifier"/>
<!-- User skeletons -->
@@ -0,0 +1,36 @@
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.python.codeInsight.typing
import com.jetbrains.python.PyNames
import com.jetbrains.python.inspections.PyInspectionExtension
import com.jetbrains.python.psi.types.PyClassLikeType
import com.jetbrains.python.psi.types.PyType
import com.jetbrains.python.psi.types.TypeEvalContext
class PyTypingInspectionExtension : PyInspectionExtension() {
override fun ignoreUnresolvedMember(type: PyType, name: String, context: TypeEvalContext): Boolean {
return name == PyNames.GETITEM && type is PyClassLikeType && type.isDefinition && isGenericItselfOrDescendant(type, context)
}
private fun isGenericItselfOrDescendant(type: PyClassLikeType,
context: TypeEvalContext): Boolean {
return type.classQName == PyTypingTypeProvider.GENERIC ||
type.getSuperClassTypes(context).any { it.classQName == PyTypingTypeProvider.GENERIC }
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -61,6 +61,7 @@ public class PyTypingTypeProvider extends PyTypeProviderBase {
public static final String ASYNC_GENERATOR = "typing.AsyncGenerator";
public static final String COROUTINE = "typing.Coroutine";
public static final String NAMEDTUPLE = "typing.NamedTuple";
public static final String GENERIC = "typing.Generic";
public static final Pattern TYPE_COMMENT_PATTERN = Pattern.compile("# *type: *(.*)");
@@ -80,7 +81,7 @@ public class PyTypingTypeProvider extends PyTypeProviderBase {
.build();
private static final ImmutableSet<String> GENERIC_CLASSES = ImmutableSet.<String>builder()
.add("typing.Generic")
.add(GENERIC)
.add("typing.AbstractGeneric")
.add("typing.Protocol")
.build();
@@ -89,7 +90,7 @@ public class PyTypingTypeProvider extends PyTypeProviderBase {
.add("typing.overload")
.add("typing.Any")
.add("typing.TypeVar")
.add("typing.Generic")
.add(GENERIC)
.add("typing.Tuple")
.add("typing.Callable")
.add("typing.Type")
@@ -107,7 +108,7 @@ public class PyTypingTypeProvider extends PyTypeProviderBase {
public PyType getReferenceExpressionType(@NotNull PyReferenceExpression referenceExpression, @NotNull TypeEvalContext context) {
// Check for the exact name in advance for performance reasons
if ("Generic".equals(referenceExpression.getName())) {
if (resolveToQualifiedNames(referenceExpression, context).contains("typing.Generic")) {
if (resolveToQualifiedNames(referenceExpression, context).contains(GENERIC)) {
return createTypingGenericType();
}
}
@@ -219,7 +220,7 @@ public class PyTypingTypeProvider extends PyTypeProviderBase {
@NotNull
private static PyType createTypingGenericType() {
return new PyCustomType("typing.Generic", null, false);
return new PyCustomType(GENERIC, null, false);
}
private static boolean omitFirstParamInTypeComment(@NotNull PyFunction func) {
@@ -304,7 +305,7 @@ public class PyTypingTypeProvider extends PyTypeProviderBase {
if (referenceTarget instanceof PyTargetExpression) {
final PyTargetExpression target = (PyTargetExpression)referenceTarget;
// Depends on typing.Generic defined as a target expression
if ("typing.Generic".equals(target.getQualifiedName())) {
if (GENERIC.equals(target.getQualifiedName())) {
return createTypingGenericType();
}
if (context.maySwitchToAST(target)) {
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -812,7 +812,7 @@ public class PyUnresolvedReferencesInspection extends PyInspection {
}
}
for (PyInspectionExtension extension : Extensions.getExtensions(PyInspectionExtension.EP_NAME)) {
if (extension.ignoreUnresolvedMember(type, name)) {
if (extension.ignoreUnresolvedMember(type, name, myTypeEvalContext)) {
return true;
}
}
@@ -0,0 +1,4 @@
import typing
class MyClass(typing.Generic[str]):
pass
@@ -0,0 +1,5 @@
import typing
def myfunc(seq: typing.Iterable[str]):
pass
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -195,4 +195,14 @@ public class Py3UnresolvedReferencesInspectionTest extends PyTestCase {
public void testMockPatchObject() {
doMultiFileTest(getTestName(true) + ".py");
}
// PY-22525
public void testTypingIterableDunderGetItem() {
doTest();
}
// PY-22642
public void testTypingGenericDunderGetItem() {
doTest();
}
}