mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-22730 Don't render Optional[Any] as Union[None, Any]
Specifically, handle "weak" union type only after checking that a union can be displayed as Optional.
This commit is contained in:
@@ -17,6 +17,7 @@ package com.jetbrains.python.documentation;
|
||||
|
||||
import com.google.common.collect.Collections2;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.jetbrains.python.PyNames;
|
||||
@@ -268,7 +269,11 @@ public class PyTypeModelBuilder {
|
||||
else if (type instanceof PyUnionType && allowUnions) {
|
||||
final PyUnionType unionType = (PyUnionType)type;
|
||||
final Collection<PyType> unionMembers = unionType.getMembers();
|
||||
if (type instanceof PyDynamicallyEvaluatedType || PyTypeChecker.isUnknown(type, false)) {
|
||||
final Ref<PyType> optionalType = getOptionalType(unionType);
|
||||
if (optionalType != null) {
|
||||
result = new OptionalType(build(optionalType.get(), true));
|
||||
}
|
||||
else if (type instanceof PyDynamicallyEvaluatedType || PyTypeChecker.isUnknown(type, false)) {
|
||||
result = new UnknownType(build(unionType.excludeNull(myContext), true));
|
||||
}
|
||||
else if (unionMembers.stream().allMatch(t -> t instanceof PyClassType && ((PyClassType)t).isDefinition())) {
|
||||
@@ -276,10 +281,7 @@ public class PyTypeModelBuilder {
|
||||
result = new ClassObjectType(new OneOf(instanceTypes));
|
||||
}
|
||||
else {
|
||||
result = Optional
|
||||
.ofNullable(getOptionalType(unionType))
|
||||
.<TypeModel>map(optionalType -> new OptionalType(build(optionalType, true)))
|
||||
.orElseGet(() -> new OneOf(Collections2.transform(unionMembers, t -> build(t, false))));
|
||||
result = new OneOf(Collections2.transform(unionMembers, t -> build(t, false)));
|
||||
}
|
||||
}
|
||||
else if (type instanceof PyCallableType && !(type instanceof PyClassLikeType)) {
|
||||
@@ -318,7 +320,7 @@ public class PyTypeModelBuilder {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PyType getOptionalType(@NotNull PyUnionType type) {
|
||||
private static Ref<PyType> getOptionalType(@NotNull PyUnionType type) {
|
||||
final Collection<PyType> members = type.getMembers();
|
||||
if (members.size() == 2) {
|
||||
boolean foundNone = false;
|
||||
@@ -332,7 +334,7 @@ public class PyTypeModelBuilder {
|
||||
}
|
||||
}
|
||||
if (foundNone) {
|
||||
return optional;
|
||||
return Ref.create(optional);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -31,6 +31,6 @@ def expects_myclass_descendant_or_none(x: Optional[Type[T2]]):
|
||||
pass
|
||||
|
||||
expects_myclass_descendant_or_none(MyClass)
|
||||
expects_myclass_descendant_or_none(<weak_warning descr="Expected type 'Union[None, Any]' (matched generic type 'Optional[Type[TypeVar('T2', MyClass)]]'), got 'MyClass' instead">MyClass()</weak_warning>)
|
||||
expects_myclass_descendant_or_none(<weak_warning descr="Expected type 'Union[None, Any]' (matched generic type 'Optional[Type[TypeVar('T2', MyClass)]]'), got 'Type[object]' instead">object</weak_warning>)
|
||||
expects_myclass_descendant_or_none(<weak_warning descr="Expected type 'Union[None, Any]' (matched generic type 'Optional[Type[TypeVar('T2', MyClass)]]'), got 'object' instead">object()</weak_warning>)
|
||||
expects_myclass_descendant_or_none(<weak_warning descr="Expected type 'Optional[Any]' (matched generic type 'Optional[Type[TypeVar('T2', MyClass)]]'), got 'MyClass' instead">MyClass()</weak_warning>)
|
||||
expects_myclass_descendant_or_none(<weak_warning descr="Expected type 'Optional[Any]' (matched generic type 'Optional[Type[TypeVar('T2', MyClass)]]'), got 'Type[object]' instead">object</weak_warning>)
|
||||
expects_myclass_descendant_or_none(<weak_warning descr="Expected type 'Optional[Any]' (matched generic type 'Optional[Type[TypeVar('T2', MyClass)]]'), got 'object' instead">object()</weak_warning>)
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
from typing import Optional, TypeVar
|
||||
|
||||
|
||||
T = TypeVar('T', int)
|
||||
|
||||
|
||||
def expects_int_subclass_or_none(x: Optional[T]):
|
||||
pass
|
||||
|
||||
|
||||
expects_int_subclass_or_none(<weak_warning descr="Expected type 'Optional[Any]' (matched generic type 'Optional[TypeVar('T', int)]'), got 'str' instead">'foo'</weak_warning>)
|
||||
@@ -450,7 +450,7 @@ public class Py3TypeTest extends PyTestCase {
|
||||
|
||||
// PY-20757
|
||||
public void testMinElseNone() {
|
||||
doTest("Union[None, Any]",
|
||||
doTest("Optional[Any]",
|
||||
"def get_value(v):\n" +
|
||||
" if v:\n" +
|
||||
" return min(v)\n" +
|
||||
|
||||
@@ -1496,14 +1496,14 @@ public class PyTypeTest extends PyTestCase {
|
||||
|
||||
// PY-20409
|
||||
public void testGetFromDictWithDefaultNoneValue() {
|
||||
doTest("Union[None, Any]",
|
||||
doTest("Optional[Any]",
|
||||
"d = {}\n" +
|
||||
"expr = d.get(\"abc\", None)");
|
||||
}
|
||||
|
||||
// PY-20757
|
||||
public void testMinOrNone() {
|
||||
doTest("Union[None, Any]",
|
||||
doTest("Optional[Any]",
|
||||
"def get_value(v):\n" +
|
||||
" if v:\n" +
|
||||
" return min(v)\n" +
|
||||
|
||||
@@ -213,4 +213,9 @@ public class Py3TypeCheckerInspectionTest extends PyTestCase {
|
||||
public void testClassObjectTypeWithUnion() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-22730
|
||||
public void testOptionalOfBoundTypeVarInWarnings() {
|
||||
doTest();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user