Use documentation from Python stubs for Quick Documentation view (PY-22685)

This commit is contained in:
Andrey Vlasovskikh
2017-03-31 20:28:39 +03:00
parent 9b114eee8f
commit eb4b3dd0ca
5 changed files with 29 additions and 10 deletions
@@ -42,6 +42,7 @@ import com.jetbrains.python.psi.resolve.QualifiedResolveResult;
import com.jetbrains.python.psi.resolve.RootVisitor;
import com.jetbrains.python.psi.resolve.RootVisitorHost;
import com.jetbrains.python.psi.types.*;
import com.jetbrains.python.pyi.PyiUtil;
import com.jetbrains.python.toolbox.ChainIterable;
import com.jetbrains.python.toolbox.Maybe;
import org.jetbrains.annotations.NotNull;
@@ -232,7 +233,7 @@ public class PyDocumentationBuilder {
final PyCallable getter = property.getGetter().valueOrNull();
if (getter != null && getter != myElement && getter instanceof PyFunction) {
// not in getter, getter's doc comment may be useful
final PyStringLiteralExpression docstring = ((PyFunction)getter).getDocStringExpression();
final PyStringLiteralExpression docstring = getEffectiveDocStringExpression((PyFunction)getter);
if (docstring != null) {
myProlog
.addItem(BR).addWith(TagItalic, $("Copied from getter:")).addItem(BR)
@@ -275,7 +276,7 @@ public class PyDocumentationBuilder {
private void buildFromDocstring(@NotNull final PsiElement elementDefinition, boolean isProperty) {
PyClass pyClass = null;
final PyStringLiteralExpression docStringExpression = ((PyDocStringOwner)elementDefinition).getDocStringExpression();
final PyStringLiteralExpression docStringExpression = getEffectiveDocStringExpression((PyDocStringOwner)elementDefinition);
if (elementDefinition instanceof PyClass) {
pyClass = (PyClass)elementDefinition;
@@ -363,7 +364,7 @@ public class PyDocumentationBuilder {
PyStringLiteralExpression docstringElement = null;
PyFunction inherited = null;
boolean isFromClass = false;
if (isConstructor) docstringElement = pyClass.getDocStringExpression();
if (isConstructor) docstringElement = getEffectiveDocStringExpression(pyClass);
if (docstringElement != null) {
isFromClass = true;
}
@@ -371,7 +372,7 @@ public class PyDocumentationBuilder {
inherited = ancestor.findMethodByName(methodName, false, null);
}
if (inherited != null) {
docstringElement = inherited.getDocStringExpression();
docstringElement = getEffectiveDocStringExpression(inherited);
}
if (docstringElement != null) {
final String inheritedDoc = docstringElement.getStringValue();
@@ -414,7 +415,7 @@ public class PyDocumentationBuilder {
final PyClass objectClass = objectType.getPyClass();
final PyFunction predefinedMethod = objectClass.findMethodByName(mothodName, false, null);
if (predefinedMethod != null) {
final PyStringLiteralExpression predefinedDocstring = predefinedMethod.getDocStringExpression();
final PyStringLiteralExpression predefinedDocstring = getEffectiveDocStringExpression(predefinedMethod);
final String predefinedDoc = predefinedDocstring != null ? predefinedDocstring.getStringValue() : null;
if (predefinedDoc != null && predefinedDoc.length() > 1) { // only a real-looking doc string counts
addFormattedDocString(fun, predefinedDoc, myBody, myBody);
@@ -472,7 +473,7 @@ public class PyDocumentationBuilder {
private boolean addTypeAndDescriptionFromDocstring(@NotNull final PyNamedParameter parameter) {
final PyFunction function = PsiTreeUtil.getParentOfType(parameter, PyFunction.class);
if (function != null) {
final String docString = PyPsiUtils.strValue(function.getDocStringExpression());
final String docString = PyPsiUtils.strValue(getEffectiveDocStringExpression(function));
final Pair<String, String> typeAndDescr = getTypeAndDescription(docString, parameter);
final String type = typeAndDescr.first;
@@ -518,7 +519,7 @@ public class PyDocumentationBuilder {
.addItem(type).addWith(TagBold, $().addWith(TagCode, $(((PyTargetExpression)myElement).getName())))
.addItem(" of class ").addWith(PythonDocumentationProvider.LinkMyClass, $().addWith(TagCode, $(cls.getName()))).addItem(BR);
final String docString = ((PyTargetExpression)myElement).getDocStringValue();
final String docString = PyPsiUtils.strValue(getEffectiveDocStringExpression((PyTargetExpression)myElement));
if (docString != null) {
addFormattedDocString(myElement, docString, myBody, myEpilog);
}
@@ -583,6 +584,17 @@ public class PyDocumentationBuilder {
}
}
@Nullable
static PyStringLiteralExpression getEffectiveDocStringExpression(@NotNull PyDocStringOwner owner) {
final PyStringLiteralExpression expression = owner.getDocStringExpression();
if (expression != null && StringUtil.isNotEmpty(PyPsiUtils.strValue(expression))) {
return expression;
}
final PsiElement original = PyiUtil.getOriginalElement(owner);
final PyDocStringOwner originalOwner = PyUtil.as(original, PyDocStringOwner.class);
return originalOwner != null ? originalOwner.getDocStringExpression() : null;
}
private static class RootFinder implements RootVisitor {
private String myResult;
private final String myPath;
@@ -91,7 +91,7 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i
// It would be nice to have class import info here, but we don't know the ctrl+hovered reference and context
}
String summary = "";
final PyStringLiteralExpression docStringExpression = func.getDocStringExpression();
final PyStringLiteralExpression docStringExpression = PyDocumentationBuilder.getEffectiveDocStringExpression(func);
if (docStringExpression != null) {
final StructuredDocString docString = DocStringUtil.parse(docStringExpression.getStringValue(), docStringExpression);
summary = docString.getSummary();
@@ -102,11 +102,11 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i
else if (element instanceof PyClass) {
final PyClass cls = (PyClass)element;
String summary = "";
PyStringLiteralExpression docStringExpression = cls.getDocStringExpression();
PyStringLiteralExpression docStringExpression = PyDocumentationBuilder.getEffectiveDocStringExpression(cls);
if (docStringExpression == null) {
final PyFunction initOrNew = cls.findInitOrNew(false, null);
if (initOrNew != null) {
docStringExpression = initOrNew.getDocStringExpression();
docStringExpression = PyDocumentationBuilder.getEffectiveDocStringExpression(initOrNew);
}
}
if (docStringExpression != null) {
+1
View File
@@ -0,0 +1 @@
<html><body><code>def <b>len</b>(o:&nbsp;Sized)<br>Inferred&nbsp;type:&nbsp;(o:&nbsp;Sized)&nbsp;-&gt;&nbsp;<a href="psi_element://#typename#int">int</a><br><br><br>len(object)&nbsp;-&gt;&nbsp;integer<br><br>Return&nbsp;the&nbsp;number&nbsp;of&nbsp;items&nbsp;of&nbsp;a&nbsp;sequence&nbsp;or&nbsp;collection.<br></code><br><b>External documentation:</b><br><a href="http://docs.python.org/2.7 Mock SDK/library/__builtin__.html#__builtin__.len">http://docs.python.org/2.7 Mock SDK/library/__builtin__.html#__builtin__.len</a></body></html>
+1
View File
@@ -0,0 +1 @@
<the_ref>len(0)
@@ -288,4 +288,9 @@ public class PyQuickDocTest extends LightMarkedTestCase {
myFixture.copyDirectoryToProject("typing", "");
runWithLanguageLevel(LanguageLevel.PYTHON36, this::checkHTMLOnly);
}
// PY-22685
public void testBuiltinLen() {
checkHTMLOnly();
}
}