Introduce method to determine if decorator updates attributes (PY-27964)

This commit is contained in:
Semyon Proshev
2018-02-20 15:20:51 +03:00
parent 3d4afa3e58
commit d38fa20a2a
4 changed files with 38 additions and 1 deletions
@@ -826,7 +826,8 @@ public class PyUnresolvedReferencesInspection extends PyInspection {
}
if (type instanceof PyFunctionTypeImpl) {
final PyCallable callable = ((PyFunctionTypeImpl)type).getCallable();
if (callable instanceof PyFunction && PyKnownDecoratorUtil.hasUnknownDecorator((PyFunction)callable, myTypeEvalContext)) {
if (callable instanceof PyFunction &&
PyKnownDecoratorUtil.hasUnknownOrUpdatingAttributesDecorator((PyFunction)callable, myTypeEvalContext)) {
return true;
}
}
@@ -219,6 +219,21 @@ public class PyKnownDecoratorUtil {
return !allDecoratorsAreKnown(decoratable, decorators) || decorators.contains(UNITTEST_MOCK_PATCH);
}
public static boolean hasUnknownOrUpdatingAttributesDecorator(@NotNull PyDecoratable decoratable, @NotNull TypeEvalContext context) {
final List<KnownDecorator> decorators = getKnownDecorators(decoratable, context);
if (!allDecoratorsAreKnown(decoratable, decorators)) {
return true;
}
return ContainerUtil.exists(
decorators,
d ->
d == FUNCTOOLS_LRU_CACHE || // cache_clear, cache_info
d == FUNCTOOLS_SINGLEDISPATCH // dispatch, register, registry
);
}
private static boolean allDecoratorsAreKnown(@NotNull PyDecoratable element, @NotNull List<KnownDecorator> decorators) {
final PyDecoratorList decoratorList = element.getDecoratorList();
return decoratorList == null ? decorators.isEmpty() : decoratorList.getDecorators().length == decorators.size();
@@ -0,0 +1,16 @@
from functools import singledispatch
@singledispatch
def to_description(ob):
return str(ob)
@to_description.register(type(None))
def none_to_description(_):
return '–'
@to_description.register(bool)
def bool_to_description(b):
return '✓' if b else ''
@@ -265,4 +265,9 @@ public class Py3UnresolvedReferencesInspectionTest extends PyInspectionTestCase
public void testNamespacePackageRedundantUnion() {
doMultiFileTest("a.py", Arrays.asList("root1", "root2"));
}
// PY-27964
public void testUsingFunctoolsSingledispatch() {
doTest();
}
}