mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-15 11:53:49 +07:00
Make return type weak for functions decorated with unknown decorator (PY-28626)
Or decorator that could change return type.
This commit is contained in:
@@ -67,10 +67,7 @@ public class PyNoneFunctionAssignmentInspection extends PyInspection {
|
|||||||
}
|
}
|
||||||
if (callable instanceof PyFunction) {
|
if (callable instanceof PyFunction) {
|
||||||
final PyFunction function = (PyFunction)callable;
|
final PyFunction function = (PyFunction)callable;
|
||||||
// Currently we don't infer types returned by decorators
|
if (hasInheritors(function) || PyKnownDecoratorUtil.hasAbstractDecorator(function, myTypeEvalContext)) {
|
||||||
if (hasInheritors(function) ||
|
|
||||||
PyKnownDecoratorUtil.hasUnknownOrChangingReturnTypeDecorator(function, myTypeEvalContext) ||
|
|
||||||
PyKnownDecoratorUtil.hasAbstractDecorator(function, myTypeEvalContext)) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -216,7 +216,12 @@ public class PyKnownDecoratorUtil {
|
|||||||
|
|
||||||
public static boolean hasUnknownOrChangingReturnTypeDecorator(@NotNull PyDecoratable decoratable, @NotNull TypeEvalContext context) {
|
public static boolean hasUnknownOrChangingReturnTypeDecorator(@NotNull PyDecoratable decoratable, @NotNull TypeEvalContext context) {
|
||||||
final List<KnownDecorator> decorators = getKnownDecorators(decoratable, context);
|
final List<KnownDecorator> decorators = getKnownDecorators(decoratable, context);
|
||||||
return !allDecoratorsAreKnown(decoratable, decorators) || decorators.contains(UNITTEST_MOCK_PATCH);
|
|
||||||
|
if (!allDecoratorsAreKnown(decoratable, decorators)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ContainerUtil.exists(decorators, d -> d == UNITTEST_MOCK_PATCH || d == CONTEXTLIB_CONTEXTMANAGER);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean hasUnknownOrUpdatingAttributesDecorator(@NotNull PyDecoratable decoratable, @NotNull TypeEvalContext context) {
|
public static boolean hasUnknownOrUpdatingAttributesDecorator(@NotNull PyDecoratable decoratable, @NotNull TypeEvalContext context) {
|
||||||
|
|||||||
@@ -217,6 +217,10 @@ public class PyFunctionImpl extends PyBaseElementImpl<PyFunctionStub> implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (getProperty() == null && PyKnownDecoratorUtil.hasUnknownOrChangingReturnTypeDecorator(this, context)) {
|
||||||
|
inferredType = PyUnionType.createWeakType(inferredType);
|
||||||
|
}
|
||||||
|
|
||||||
return PyTypingTypeProvider.toAsyncIfNeeded(this, inferredType);
|
return PyTypingTypeProvider.toAsyncIfNeeded(this, inferredType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
from contextlib import contextmanager
|
||||||
|
|
||||||
|
|
||||||
|
@contextmanager
|
||||||
|
def mycm():
|
||||||
|
pass
|
||||||
|
yield
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@mycm()
|
||||||
|
def decorated_func():
|
||||||
|
pass
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
def contextmanager(func):
|
||||||
|
pass
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
|
from abc import abstractmethod
|
||||||
|
|
||||||
|
|
||||||
class Abstract(object):
|
class Abstract(object):
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
from abc import abstractmethod
|
||||||
|
|
||||||
|
|
||||||
class Abstract(object):
|
class Abstract(object):
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
@decorator1, @decorator2
|
@decorator1, @decorator2
|
||||||
def foo(param)
|
def foo(param)
|
||||||
Inferred type: (param: Any) -> None
|
Inferred type: (param: Any) -> Optional[Any]
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
@decorator
|
@decorator
|
||||||
def foo(param)
|
def foo(param)
|
||||||
Inferred type: (param: Any) -> None
|
Inferred type: (param: Any) -> Optional[Any]
|
||||||
@@ -1 +1 @@
|
|||||||
<html><body><code>@<i>decorator1</i><br>@<i>decorator2</i><br>def <b>foo</b>(param)<br>Inferred type: (param: Any) -> None</code></body></html>
|
<html><body><code>@<i>decorator1</i><br>@<i>decorator2</i><br>def <b>foo</b>(param)<br>Inferred type: (param: Any) -> Optional[Any]</code></body></html>
|
||||||
@@ -1 +1 @@
|
|||||||
<html><body><code><small>class <a href="psi_element://#class#">Foo</a></small><br><br>@<i>deco</i><br>def <b>meth</b>(self)<br>Inferred type: (self: <a href="psi_element://#typename#Foo">Foo</a>) -> None<br><br>Doc of meth.<br></code></body></html>
|
<html><body><code><small>class <a href="psi_element://#class#">Foo</a></small><br><br>@<i>deco</i><br>def <b>meth</b>(self)<br>Inferred type: (self: <a href="psi_element://#typename#Foo">Foo</a>) -> Optional[Any]<br><br>Doc of meth.<br></code></body></html>
|
||||||
@@ -1 +1 @@
|
|||||||
<html><body><code>@<i>decorator</i><br>def <b>foo</b>(param)<br>Inferred type: (param: Any) -> None</code></body></html>
|
<html><body><code>@<i>decorator</i><br>def <b>foo</b>(param)<br>Inferred type: (param: Any) -> Optional[Any]</code></body></html>
|
||||||
@@ -108,6 +108,11 @@ public class PyCallingNonCallableInspectionTest extends PyInspectionTestCase {
|
|||||||
doTest();
|
doTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PY-28626
|
||||||
|
public void testFunctionDecoratedAsContextManager() {
|
||||||
|
doMultiFileTest();
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
protected Class<? extends PyInspection> getInspectionClass() {
|
protected Class<? extends PyInspection> getInspectionClass() {
|
||||||
|
|||||||
Reference in New Issue
Block a user