mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-20 13:31:28 +07:00
PY-33341, PY-56416, PY-28900: Render attributes and init params description in the class documentation
PY-33341: Now we render the “Attributes” section in the class documentation, it also allows to describe inherited attributes. (Previously we didn’t render it at all) PY-56416: In the attribute documentation popup we are able to render attribute description from class docstring. (Previously we took documentation only explicitly from attribute one-line docstring) PY-33341: We render the “Parameters” section in the class documentation for init parameters, described in the class docstring. (Previously user couldn't use class docstring to describe init parameters) PY-28900: For the init parameter documentation we take the description from the class docstring if init doesn't have its own docstring. (Previously we took parameter description only from init docstring) GitOrigin-RevId: d67bf49c72cf7a3634805a6e310c943f1ea848d1
This commit is contained in:
committed by
intellij-monorepo-bot
parent
6e8d9adaf8
commit
cb8edc622b
@@ -95,12 +95,20 @@ public interface StructuredDocString {
|
||||
@Nullable
|
||||
String getRaisedExceptionDescription(@Nullable String exceptionName); // for formatter
|
||||
|
||||
// getAttributes
|
||||
// getAttributeSubstrings
|
||||
// getAttributeType(name)
|
||||
// getAttributeTypeSubstring(name)
|
||||
@Nullable
|
||||
String getAttributeDescription(); // for formatter
|
||||
|
||||
@Nullable
|
||||
String getAttributeDescription(@Nullable String name);
|
||||
|
||||
@NotNull
|
||||
List<String> getAttributes();
|
||||
|
||||
@NotNull
|
||||
List<Substring> getAttributeSubstrings();
|
||||
|
||||
// getAttributeType(name)
|
||||
// getAttributeTypeSubstring(name)
|
||||
|
||||
// Tags related methods
|
||||
}
|
||||
|
||||
@@ -244,6 +244,7 @@ QDOC.raises=Raises:
|
||||
QDOC.keyword.args=Keyword args:
|
||||
QDOC.returns=Returns:
|
||||
QDOC.params=Params:
|
||||
QDOC.attributes=Attributes:
|
||||
|
||||
### Formatter
|
||||
formatter.panel.dict.alignment.do.not.align=Do not align
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.intellij.lang.documentation.DocumentationMarkup;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.LineTokenizer;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.util.text.Strings;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
@@ -20,7 +21,6 @@ import com.jetbrains.python.*;
|
||||
import com.jetbrains.python.documentation.docstrings.DocStringUtil;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.impl.PyBuiltinCache;
|
||||
import com.jetbrains.python.psi.impl.PyPsiUtils;
|
||||
import com.jetbrains.python.psi.resolve.PyResolveContext;
|
||||
import com.jetbrains.python.psi.resolve.QualifiedNameFinder;
|
||||
import com.jetbrains.python.psi.resolve.QualifiedResolveResult;
|
||||
@@ -96,7 +96,8 @@ public class PyDocumentationBuilder {
|
||||
|
||||
if (!mySectionsMap.isEmpty()) {
|
||||
mySections.addItem(DocumentationMarkup.SECTIONS_START);
|
||||
final List<String> firstSections = Lists.newArrayList(PyPsiBundle.message("QDOC.params"),
|
||||
final List<String> firstSections = Lists.newArrayList(PyPsiBundle.message("QDOC.attributes"),
|
||||
PyPsiBundle.message("QDOC.params"),
|
||||
PyPsiBundle.message("QDOC.keyword.args"),
|
||||
PyPsiBundle.message("QDOC.returns"),
|
||||
PyPsiBundle.message("QDOC.raises"));
|
||||
@@ -207,7 +208,11 @@ public class PyDocumentationBuilder {
|
||||
}
|
||||
|
||||
if (func != null) {
|
||||
final PyStringLiteralExpression docString = getEffectiveDocStringExpression(func);
|
||||
final PyClass containingClass = func.getContainingClass();
|
||||
final PyStringLiteralExpression functionDocstring = getEffectiveDocStringExpression(func);
|
||||
final PyStringLiteralExpression docString = functionDocstring == null && containingClass != null ?
|
||||
addFunctionInheritedDocString(func, containingClass) :
|
||||
functionDocstring;
|
||||
if (docString != null) {
|
||||
final StructuredDocString structuredDocString = DocStringUtil.parse(docString.getStringValue());
|
||||
final String description = structuredDocString.getParamDescription(parameter.getName());
|
||||
@@ -328,20 +333,15 @@ public class PyDocumentationBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
if (elementDefinition instanceof PyClass) {
|
||||
final PyClass pyClass = (PyClass)elementDefinition;
|
||||
if (elementDefinition instanceof PyClass pyClass) {
|
||||
myBody.add(PythonDocumentationProvider.describeDecorators(pyClass, WRAP_IN_ITALIC, ESCAPE_AND_SAVE_NEW_LINES_AND_SPACES, BR, BR));
|
||||
myBody
|
||||
.add(PythonDocumentationProvider.describeClass(pyClass, WRAP_IN_BOLD, ESCAPE_AND_SAVE_NEW_LINES_AND_SPACES, false, true, myContext));
|
||||
if (docStringExpression == null) {
|
||||
final PyFunction constructor = pyClass.findMethodByName(PyNames.INIT, false, myContext);
|
||||
if (constructor != null) {
|
||||
docStringExpression = constructor.getDocStringExpression();
|
||||
}
|
||||
}
|
||||
myBody.add(
|
||||
PythonDocumentationProvider.describeClass(pyClass, WRAP_IN_BOLD, ESCAPE_AND_SAVE_NEW_LINES_AND_SPACES, false, true, myContext));
|
||||
docStringExpression = addClassDocumentation(docStringExpression, pyClass);
|
||||
}
|
||||
else if (elementDefinition instanceof PyFunction) {
|
||||
final PyFunction pyFunction = (PyFunction)elementDefinition;
|
||||
else if (elementDefinition instanceof PyFunction pyFunction) {
|
||||
myBody.add(PythonDocumentationProvider.describeDecorators(pyFunction, WRAP_IN_ITALIC, ESCAPE_AND_SAVE_NEW_LINES_AND_SPACES, BR, BR));
|
||||
myBody.add(PythonDocumentationProvider.describeFunction(pyFunction, myContext, false));
|
||||
final PyClass pyClass = pyFunction.getContainingClass();
|
||||
if (!isProperty && pyClass != null) {
|
||||
final String link = getLinkToClass(pyClass, true);
|
||||
@@ -349,30 +349,13 @@ public class PyDocumentationBuilder {
|
||||
myProlog.addItem(link);
|
||||
}
|
||||
}
|
||||
myBody.add(PythonDocumentationProvider.describeDecorators(pyFunction, WRAP_IN_ITALIC, ESCAPE_AND_SAVE_NEW_LINES_AND_SPACES, BR, BR));
|
||||
myBody.add(PythonDocumentationProvider.describeFunction(pyFunction, myContext, false));
|
||||
if (docStringExpression == null && pyClass != null && !isProperty) {
|
||||
docStringExpression = addInheritedDocString(pyFunction, pyClass);
|
||||
}
|
||||
if (docStringExpression != null) {
|
||||
addFunctionSpecificSections(docStringExpression, pyFunction);
|
||||
}
|
||||
docStringExpression = addFunctionDocumentation(docStringExpression, pyFunction, pyClass, isProperty);
|
||||
}
|
||||
else if (elementDefinition instanceof PyFile) {
|
||||
addModulePath((PyFile)elementDefinition);
|
||||
else if (elementDefinition instanceof PyFile pyFile) {
|
||||
addModulePath(pyFile);
|
||||
}
|
||||
else if (elementDefinition instanceof PyTargetExpression) {
|
||||
final PyTargetExpression target = (PyTargetExpression)elementDefinition;
|
||||
if (isAttribute() && !isProperty) {
|
||||
@SuppressWarnings("ConstantConditions") final String link = getLinkToClass(target.getContainingClass(), true);
|
||||
if (link != null) {
|
||||
myProlog.addItem(PyUtil.isInstanceAttribute(target) ? "Instance attribute " : "Class attribute ")
|
||||
.addWith(TagBold, $(elementDefinition.getName()))
|
||||
.addItem(" of ")
|
||||
.addItem(link);
|
||||
}
|
||||
}
|
||||
myBody.add(PythonDocumentationProvider.describeTarget(target, myContext));
|
||||
else if (elementDefinition instanceof PyTargetExpression target) {
|
||||
addTargetDocumentation(target, isProperty);
|
||||
}
|
||||
|
||||
if (docStringExpression != null && !isProperty) {
|
||||
@@ -380,6 +363,91 @@ public class PyDocumentationBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
private void addTargetDocumentation(@NotNull PyTargetExpression target, boolean isProperty) {
|
||||
if (isAttribute() && !isProperty) {
|
||||
final PyClass containingClass = target.getContainingClass();
|
||||
@SuppressWarnings("ConstantConditions") final String link = getLinkToClass(containingClass, true);
|
||||
if (link != null) {
|
||||
myProlog.addItem(PyUtil.isInstanceAttribute(target) ? "Instance attribute " : "Class attribute ")
|
||||
.addWith(TagBold, $(target.getName()))
|
||||
.addItem(" of ")
|
||||
.addItem(link);
|
||||
}
|
||||
// if there is no separate doc for attribute we will try to take it from class doc
|
||||
if (getEffectiveDocStringExpression(target) == null) {
|
||||
final PyStringLiteralExpression docString = getEffectiveDocStringExpression(containingClass);
|
||||
if (docString != null) {
|
||||
final StructuredDocString structuredDocString = DocStringUtil.parse(docString.getStringValue());
|
||||
final String description = structuredDocString.getAttributeDescription(target.getName());
|
||||
if (StringUtil.isNotEmpty(description)) {
|
||||
myContent.add($(description));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
myBody.add(PythonDocumentationProvider.describeTarget(target, myContext));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private PyStringLiteralExpression addFunctionDocumentation(@Nullable PyStringLiteralExpression docStringExpression,
|
||||
@NotNull PyFunction pyFunction,
|
||||
@Nullable PyClass pyClass,
|
||||
boolean isProperty) {
|
||||
// if we have containing class, but don't have a function doc
|
||||
if (docStringExpression == null && pyClass != null) {
|
||||
if (!isProperty) {
|
||||
// add docstring from the parent class or function
|
||||
docStringExpression = addFunctionInheritedDocString(pyFunction, pyClass);
|
||||
}
|
||||
if (PyUtil.isInitOrNewMethod(pyFunction)) {
|
||||
final PyStringLiteralExpression classDocstring = getEffectiveDocStringExpression(pyClass);
|
||||
if (classDocstring != null) {
|
||||
// we should add attributes section from class doc because it won't be added with function sections in the end
|
||||
addAttributesSection(classDocstring, pyClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (docStringExpression != null) {
|
||||
addFunctionSpecificSections(docStringExpression, pyFunction);
|
||||
}
|
||||
return docStringExpression;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private PyStringLiteralExpression addClassDocumentation(@Nullable PyStringLiteralExpression docStringExpression,
|
||||
@NotNull PyClass pyClass) {
|
||||
final PyFunction init = pyClass.findMethodByName(PyNames.INIT, false, myContext);
|
||||
if (docStringExpression != null) {
|
||||
addAttributesSection(docStringExpression, pyClass);
|
||||
if (init != null) {
|
||||
// add init parameters described in the class doc
|
||||
addFunctionSpecificSections(docStringExpression, init);
|
||||
}
|
||||
return docStringExpression;
|
||||
}
|
||||
// if class doesn't have any doc add init doc without other sections
|
||||
if (init != null) {
|
||||
return getEffectiveDocStringExpression(init);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void addAttributesSection(@NotNull PyStringLiteralExpression docstring, @NotNull PyClass cls) {
|
||||
final StructuredDocString structured = DocStringUtil.parseDocString(docstring);
|
||||
final List<String> documentedAttributes = structured.getAttributes();
|
||||
|
||||
final String allAttributes = StreamEx.of(documentedAttributes)
|
||||
.map(name -> {
|
||||
final String description = structured.getAttributeDescription(name);
|
||||
return "<p><code>" + name + "</code> – " + Strings.notNullize(description) + "</p>";
|
||||
})
|
||||
.joining();
|
||||
|
||||
if (!allAttributes.isEmpty()) {
|
||||
mySectionsMap.get(PyPsiBundle.message("QDOC.attributes")).addItem(allAttributes);
|
||||
}
|
||||
}
|
||||
|
||||
private void addFunctionSpecificSections(@NotNull PyStringLiteralExpression docstring, @NotNull PyFunction function) {
|
||||
final StructuredDocString structured = DocStringUtil.parseDocString(docstring);
|
||||
|
||||
@@ -387,13 +455,12 @@ public class PyDocumentationBuilder {
|
||||
final List<String> actualNames = ContainerUtil.mapNotNull(parameters, PyCallableParameter::getName);
|
||||
// Retain the actual order of parameters
|
||||
final String paramList = StreamEx.of(actualNames)
|
||||
.filter(name -> structured.getParamDescription(name) != null)
|
||||
.map(name -> {
|
||||
final String description = structured.getParamDescription(name);
|
||||
return "<p><code>" + name + "</code> – " + description + "</p>";
|
||||
})
|
||||
.joining();
|
||||
|
||||
.filter(name -> structured.getParamDescription(name) != null)
|
||||
.map(name -> {
|
||||
final String description = structured.getParamDescription(name);
|
||||
return "<p><code>" + name + "</code> – " + Strings.notNullize(description) + "</p>";
|
||||
})
|
||||
.joining();
|
||||
|
||||
if (!paramList.isEmpty()) {
|
||||
mySectionsMap.get(PyPsiBundle.message("QDOC.params")).addItem(paramList);
|
||||
@@ -404,26 +471,27 @@ public class PyDocumentationBuilder {
|
||||
allKeywordArgs.retainAll(new HashSet<>(actualNames));
|
||||
}
|
||||
final String keywordArgsList = StreamEx.of(allKeywordArgs)
|
||||
.map(name -> {
|
||||
final String description = structured.getKeywordArgumentDescription(name);
|
||||
return "<p><code>" + name + "</code> – " + StringUtil.notNullize(description) + "</p>";
|
||||
})
|
||||
.joining();
|
||||
.map(name -> {
|
||||
final String description = structured.getKeywordArgumentDescription(name);
|
||||
return "<p><code>" + name + "</code> – " + StringUtil.notNullize(description) + "</p>";
|
||||
})
|
||||
.joining();
|
||||
if (!keywordArgsList.isEmpty()) {
|
||||
mySectionsMap.get(PyPsiBundle.message("QDOC.keyword.args")).addItem(keywordArgsList);
|
||||
}
|
||||
|
||||
final String returnDescription = structured.getReturnDescription();
|
||||
if (returnDescription != null) {
|
||||
mySectionsMap.get(PyPsiBundle.message("QDOC.returns")).addItem(returnDescription);
|
||||
if (returnDescription != null && !mySectionsMap.containsKey(PyPsiBundle.message("QDOC.returns"))) {
|
||||
mySectionsMap.get(PyPsiBundle.message("QDOC.returns")).addItem(Strings.notNullize(returnDescription));
|
||||
}
|
||||
|
||||
final String exceptionList = StreamEx.of(structured.getRaisedExceptions())
|
||||
.map(name -> {
|
||||
final String description = structured.getRaisedExceptionDescription(name);
|
||||
return "<p><code>" + name + "</code>" +(StringUtil.isNotEmpty(description) ? " – " + description : "") + "</p>";
|
||||
})
|
||||
.joining();
|
||||
.map(name -> {
|
||||
final String description = structured.getRaisedExceptionDescription(name);
|
||||
return "<p><code>" + name + "</code>" +
|
||||
(StringUtil.isNotEmpty(description) ? " – " + description : "") + "</p>";
|
||||
})
|
||||
.joining();
|
||||
|
||||
if (!exceptionList.isEmpty()) {
|
||||
mySectionsMap.get(PyPsiBundle.message("QDOC.raises")).addItem(exceptionList);
|
||||
@@ -465,7 +533,7 @@ public class PyDocumentationBuilder {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private PyStringLiteralExpression addInheritedDocString(@NotNull PyFunction pyFunction, @NotNull PyClass pyClass) {
|
||||
private PyStringLiteralExpression addFunctionInheritedDocString(@NotNull PyFunction pyFunction, @NotNull PyClass pyClass) {
|
||||
final String methodName = pyFunction.getName();
|
||||
if (methodName == null) {
|
||||
return null;
|
||||
@@ -632,7 +700,7 @@ public class PyDocumentationBuilder {
|
||||
@Nullable
|
||||
static PyStringLiteralExpression getEffectiveDocStringExpression(@NotNull PyDocStringOwner owner) {
|
||||
final PyStringLiteralExpression expression = owner.getDocStringExpression();
|
||||
if (expression != null && StringUtil.isNotEmpty(PyPsiUtils.strValue(expression))) {
|
||||
if (expression != null) {
|
||||
return expression;
|
||||
}
|
||||
final PsiElement original = PyiUtil.getOriginalElement(owner);
|
||||
|
||||
@@ -173,10 +173,11 @@ public final class DocStringUtil {
|
||||
|
||||
public static boolean isLikeSphinxDocString(@NotNull String text) {
|
||||
return text.contains(":param ") ||
|
||||
text.contains(":key ") || text.contains(":keyword ") ||
|
||||
text.contains(":key ") || text.contains(":keyword ") ||
|
||||
text.contains(":return:") || text.contains(":returns:") ||
|
||||
text.contains(":raise ") || text.contains(":raises ") || text.contains(":except ") || text.contains(":exception ") ||
|
||||
text.contains(":rtype") || text.contains(":type");
|
||||
text.contains(":rtype") || text.contains(":type") ||
|
||||
text.contains(":var") || text.contains(":ivar") || text.contains(":cvar");
|
||||
}
|
||||
|
||||
public static boolean isLikeEpydocDocString(@NotNull String text) {
|
||||
@@ -184,7 +185,8 @@ public final class DocStringUtil {
|
||||
text.contains("@kwarg ") || text.contains("@keyword ") || text.contains("@kwparam ") ||
|
||||
text.contains("@raise ") || text.contains("@raises ") || text.contains("@except ") || text.contains("@exception ") ||
|
||||
text.contains("@return:") ||
|
||||
text.contains("@rtype") || text.contains("@type");
|
||||
text.contains("@rtype") || text.contains("@type") ||
|
||||
text.contains("@var") || text.contains("@ivar") || text.contains("@cvar");
|
||||
}
|
||||
|
||||
public static boolean isLikeGoogleDocString(@NotNull String text) {
|
||||
|
||||
@@ -42,12 +42,6 @@ public class EpydocString extends TagBasedDocString {
|
||||
return html;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<String> getParameters() {
|
||||
return toUniqueStrings(getParameterSubstrings());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<String> getKeywordArguments() {
|
||||
@@ -289,4 +283,10 @@ public class EpydocString extends TagBasedDocString {
|
||||
public Substring getParamTypeSubstring(@Nullable String paramName) {
|
||||
return paramName == null ? getTagValue("type") : getTagValue("type", paramName);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getAttributeDescription(@Nullable String attrName) {
|
||||
return attrName != null ? inlineMarkupToHTML(getTagValue(VARIABLE_TAGS, attrName)) : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,4 +151,20 @@ public class PlainDocString extends DocStringLineParser implements StructuredDoc
|
||||
public String getAttributeDescription() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getAttributeDescription(@Nullable String name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull List<String> getAttributes() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull List<Substring> getAttributeSubstrings() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -520,6 +520,39 @@ public abstract class SectionBasedDocString extends DocStringLineParser implemen
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getAttributeDescription(@Nullable String name) {
|
||||
if (name != null) {
|
||||
final SectionField field = getFirstFieldForAttribute(name);
|
||||
if (field != null) {
|
||||
return field.getDescription();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SectionField getFirstFieldForAttribute(@NotNull String name) {
|
||||
return ContainerUtil.find(getAttributeFields(), field -> field.getNames().contains(name));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<String> getAttributes() {
|
||||
return ContainerUtil.map(getAttributeSubstrings(), substring -> substring.toString());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<Substring> getAttributeSubstrings() {
|
||||
final List<Substring> result = new ArrayList<>();
|
||||
for (SectionField field : getAttributeFields()) {
|
||||
ContainerUtil.addAllNotNull(result, field.getNamesAsSubstrings());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected static Substring cleanUpName(@NotNull Substring name) {
|
||||
int firstNotStar = 0;
|
||||
|
||||
@@ -38,12 +38,6 @@ public class SphinxDocString extends TagBasedDocString {
|
||||
return s != null ? s.concatTrimmedLines(" ") : null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<String> getParameters() {
|
||||
return toUniqueStrings(getParameterSubstrings());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<String> getKeywordArguments() {
|
||||
@@ -126,4 +120,10 @@ public class SphinxDocString extends TagBasedDocString {
|
||||
public String getDescription() {
|
||||
return myDescription.replaceAll("\n", "<br/>");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getAttributeDescription(@Nullable String attrName) {
|
||||
return attrName != null ? concatTrimmedLines(getTagValue(VARIABLE_TAGS, attrName)) : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,6 +201,12 @@ public abstract class TagBasedDocString extends DocStringLineParser implements S
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<String> getParameters() {
|
||||
return toUniqueStrings(getParameterSubstrings());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<Substring> getParameterSubstrings() {
|
||||
@@ -210,6 +216,16 @@ public abstract class TagBasedDocString extends DocStringLineParser implements S
|
||||
return results;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull List<String> getAttributes() {
|
||||
return toUniqueStrings(getAttributeSubstrings());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull List<Substring> getAttributeSubstrings() {
|
||||
return new ArrayList<>(getTagArguments(VARIABLE_TAGS));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isBlockEnd(int lineNum) {
|
||||
return getLine(lineNum).trimLeft().startsWith(myTagPrefix);
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<html><body><div class='definition'><pre><a href="psi_element://#module#ArgsDescriptionFromClassAndInitNotMixedGoogle">ArgsDescriptionFromClassAndInitNotMixedGoogle</a><br>class <b>MyClass</b></pre></div><div class='content'>Unittest placeholder</div><table class='sections'><tr><td valign='top' class='section'><p>Params:</td><td valign='top'><p><code>param1</code> – param1 description</p><p><code>param2</code> – param2 description</p></td><tr><td valign='top' class='section'><p>Keyword args:</td><td valign='top'><p><code>kw</code> – kw description</p></td></table></body></html>
|
||||
@@ -0,0 +1,17 @@
|
||||
class My<the_ref>Class:
|
||||
"""
|
||||
Args:
|
||||
param1: param1 description
|
||||
param2: param2 description
|
||||
Keyword Args:
|
||||
kw: kw description
|
||||
"""
|
||||
def __init__(self, param1, param2, **kw):
|
||||
"""
|
||||
Args:
|
||||
param1: param1 description from init
|
||||
param2: param2 description from init
|
||||
Keyword Args:
|
||||
kw: kw description from init
|
||||
"""
|
||||
pass
|
||||
@@ -0,0 +1,4 @@
|
||||
<html><body><div class='definition'><pre><a href="psi_element://#typename#ArgsDescriptionFromClassDocstringGoogle.Parent">ArgsDescriptionFromClassDocstringGoogle.Parent</a><br>def <b>__init__</b>(self,
|
||||
p1: Any,
|
||||
p2: Any,
|
||||
**kwargs: Any) -> None</pre></div><div class='content'>Unittest placeholder</div><table class='sections'><tr><td valign='top' class='section'><p>Params:</td><td valign='top'><p><code>p1</code> – p1 doc from class</p><p><code>p2</code> – p2 doc from class</p></td><tr><td valign='top' class='section'><p>Keyword args:</td><td valign='top'><p><code>k</code> – k doc from class</p></td><tr><td valign='top' class='section'><p>Documentation is copied from:</td><td valign='top'><code><a href="psi_element://#typename#ArgsDescriptionFromClassDocstringGoogle.Parent">Parent</a></code></td></table></body></html>
|
||||
@@ -0,0 +1,11 @@
|
||||
class Parent:
|
||||
"""
|
||||
Args:
|
||||
p1: p1 doc from class
|
||||
p2: p2 doc from class
|
||||
Keyword Args:
|
||||
k: k doc from class
|
||||
"""
|
||||
|
||||
def __in<the_ref>it__(self, p1, p2, **kwargs):
|
||||
pass
|
||||
@@ -0,0 +1 @@
|
||||
<html><body><div class='definition'><pre><a href="psi_element://#module#ArgsFromInitNotTakenInClassDocstringGoogle">ArgsFromInitNotTakenInClassDocstringGoogle</a><br>class <b>Parent</b></pre></div><div class='content'>Unittest placeholder</div></body></html>
|
||||
@@ -0,0 +1,10 @@
|
||||
class Par<the_ref>ent:
|
||||
def __init__(self, p1, p2, **kwargs):
|
||||
"""
|
||||
Args:
|
||||
p1: p1 doc from class
|
||||
p2: p2 doc from class
|
||||
Keyword Args:
|
||||
k: k doc from class
|
||||
"""
|
||||
pass
|
||||
1
python/testData/quickdoc/ArgsInClassDocGoogle.html
Normal file
1
python/testData/quickdoc/ArgsInClassDocGoogle.html
Normal file
@@ -0,0 +1 @@
|
||||
<html><body><div class='definition'><pre><a href="psi_element://#module#ArgsInClassDocGoogle">ArgsInClassDocGoogle</a><br>class <b>Parent</b></pre></div><div class='content'>Unittest placeholder</div><table class='sections'><tr><td valign='top' class='section'><p>Params:</td><td valign='top'><p><code>p1</code> – p1 doc from class</p><p><code>p2</code> – p2 doc from class</p></td><tr><td valign='top' class='section'><p>Keyword args:</td><td valign='top'><p><code>k</code> – k doc from class</p></td></table></body></html>
|
||||
11
python/testData/quickdoc/ArgsInClassDocGoogle.py
Normal file
11
python/testData/quickdoc/ArgsInClassDocGoogle.py
Normal file
@@ -0,0 +1,11 @@
|
||||
class Par<the_ref>ent:
|
||||
"""
|
||||
Args:
|
||||
p1: p1 doc from class
|
||||
p2: p2 doc from class
|
||||
Keyword Args:
|
||||
k: k doc from class
|
||||
"""
|
||||
|
||||
def __init__(self, p1, p2, **kwargs):
|
||||
pass
|
||||
@@ -0,0 +1 @@
|
||||
<html><body><div class='definition'><pre><a href="psi_element://#module#AttributeDescriptionEmptyGoogle">AttributeDescriptionEmptyGoogle</a><br>class <b>MyClass</b></pre></div><div class='content'>Unittest placeholder</div><table class='sections'><tr><td valign='top' class='section'><p>Attributes:</td><td valign='top'><p><code>attr</code> – </p></td></table></body></html>
|
||||
@@ -0,0 +1,7 @@
|
||||
class My<the_ref>Class:
|
||||
"""
|
||||
Attributes:
|
||||
attr (int) :
|
||||
"""
|
||||
|
||||
attr = 1
|
||||
1
python/testData/quickdoc/AttributeDocsNotMixed.html
Normal file
1
python/testData/quickdoc/AttributeDocsNotMixed.html
Normal file
@@ -0,0 +1 @@
|
||||
<html><body><div class='definition'><pre>Class attribute <b>attr</b> of <a href="psi_element://#typename#AttributeDocsNotMixed.MyClass">AttributeDocsNotMixed.MyClass</a><br>attr: <a href="psi_element://#typename#int">int</a> = 1</pre></div><div class='content'>Docstring from attr</div></body></html>
|
||||
9
python/testData/quickdoc/AttributeDocsNotMixed.py
Normal file
9
python/testData/quickdoc/AttributeDocsNotMixed.py
Normal file
@@ -0,0 +1,9 @@
|
||||
class MyClass:
|
||||
"""This is the class docstring.
|
||||
|
||||
Attributes:
|
||||
attr: Docstring from class
|
||||
"""
|
||||
|
||||
a<the_ref>ttr = 1
|
||||
"""Docstring from attr"""
|
||||
@@ -0,0 +1 @@
|
||||
<html><body><div class='definition'><pre><a href="psi_element://#typename#AttributesDescriptionFromClassDocstringGoogle.Parent">AttributesDescriptionFromClassDocstringGoogle.Parent</a><br>def <b>__init__</b>(self) -> None</pre></div><div class='content'>Unittest placeholder</div><table class='sections'><tr><td valign='top' class='section'><p>Attributes:</td><td valign='top'><p><code>a1</code> – a1 doc from parent</p><p><code>a2</code> – a2 doc from parent</p></td><tr><td valign='top' class='section'><p>Documentation is copied from:</td><td valign='top'><code><a href="psi_element://#typename#AttributesDescriptionFromClassDocstringGoogle.Parent">Parent</a></code></td></table></body></html>
|
||||
@@ -0,0 +1,11 @@
|
||||
class Parent:
|
||||
"""
|
||||
Attributes:
|
||||
a1: a1 doc from parent
|
||||
a2: a2 doc from parent
|
||||
"""
|
||||
|
||||
a1 = 0
|
||||
|
||||
def __in<the_ref>it__(self):
|
||||
self.a2 = 0
|
||||
1
python/testData/quickdoc/AttributesOrderGoogle.html
Normal file
1
python/testData/quickdoc/AttributesOrderGoogle.html
Normal file
@@ -0,0 +1 @@
|
||||
<html><body><div class='definition'><pre><a href="psi_element://#module#AttributesOrderGoogle">AttributesOrderGoogle</a><br>class <b>Parent</b></pre></div><div class='content'>Unittest placeholder</div><table class='sections'><tr><td valign='top' class='section'><p>Attributes:</td><td valign='top'><p><code>a1</code> – a1 doc</p><p><code>a2</code> – a2 doc</p><p><code>a3</code> – a3 doc</p><p><code>a4</code> – a4 doc</p></td></table></body></html>
|
||||
15
python/testData/quickdoc/AttributesOrderGoogle.py
Normal file
15
python/testData/quickdoc/AttributesOrderGoogle.py
Normal file
@@ -0,0 +1,15 @@
|
||||
class Par<the_ref>ent:
|
||||
"""
|
||||
Attributes:
|
||||
a1: a1 doc
|
||||
a2: a2 doc
|
||||
a3: a3 doc
|
||||
a4: a4 doc
|
||||
"""
|
||||
|
||||
a4 = 0
|
||||
a3 = 0
|
||||
|
||||
def __init__(self):
|
||||
self.a2 = 0
|
||||
self.a1 = 0
|
||||
@@ -0,0 +1 @@
|
||||
<html><body><div class='definition'><pre><a href="psi_element://#module#ClassAndInstanceAttributesInOneSectionEpydoc">ClassAndInstanceAttributesInOneSectionEpydoc</a><br>class <b>MyClass</b></pre></div><div class='content'>Unittest placeholder</div><table class='sections'><tr><td valign='top' class='section'><p>Attributes:</td><td valign='top'><p><code>msg</code> – Message</p><p><code>code</code> – Code</p><p><code>state</code> – State</p></td></table></body></html>
|
||||
@@ -0,0 +1,12 @@
|
||||
class My<the_ref>Class:
|
||||
"""
|
||||
@ivar msg: Message
|
||||
@cvar code: Code
|
||||
@var state: State
|
||||
"""
|
||||
|
||||
code = 404
|
||||
|
||||
def __init__(self):
|
||||
self.msg = 'test'
|
||||
self.state = 0
|
||||
@@ -0,0 +1 @@
|
||||
<html><body><div class='definition'><pre><a href="psi_element://#module#ClassAndInstanceAttributesInOneSectionGoogle">ClassAndInstanceAttributesInOneSectionGoogle</a><br>class <b>MyClass</b></pre></div><div class='content'>Unittest placeholder</div><table class='sections'><tr><td valign='top' class='section'><p>Attributes:</td><td valign='top'><p><code>msg</code> – Message</p><p><code>code</code> – Code</p></td></table></body></html>
|
||||
@@ -0,0 +1,11 @@
|
||||
class My<the_ref>Class:
|
||||
"""
|
||||
Attributes:
|
||||
msg: Message
|
||||
code: Code
|
||||
"""
|
||||
|
||||
code = 404
|
||||
|
||||
def __init__(self):
|
||||
self.msg = 'test'
|
||||
@@ -0,0 +1 @@
|
||||
<html><body><div class='definition'><pre><a href="psi_element://#module#ClassAndInstanceAttributesInOneSectionNumpy">ClassAndInstanceAttributesInOneSectionNumpy</a><br>class <b>MyClass</b></pre></div><div class='content'>Unittest placeholder</div><table class='sections'><tr><td valign='top' class='section'><p>Attributes:</td><td valign='top'><p><code>msg</code> – Message</p><p><code>code</code> – Code</p></td></table></body></html>
|
||||
@@ -0,0 +1,14 @@
|
||||
class My<the_ref>Class:
|
||||
"""
|
||||
Attributes
|
||||
----------
|
||||
msg:
|
||||
Message
|
||||
code:
|
||||
Code
|
||||
"""
|
||||
|
||||
code = 404
|
||||
|
||||
def __init__(self):
|
||||
self.msg = 'test'
|
||||
@@ -0,0 +1 @@
|
||||
<html><body><div class='definition'><pre><a href="psi_element://#module#ClassAndInstanceAttributesInOneSectionRest">ClassAndInstanceAttributesInOneSectionRest</a><br>class <b>MyClass</b></pre></div><div class='content'>Unittest placeholder</div><table class='sections'><tr><td valign='top' class='section'><p>Attributes:</td><td valign='top'><p><code>msg</code> – Message</p><p><code>code</code> – Code</p><p><code>state</code> – State</p></td></table></body></html>
|
||||
@@ -0,0 +1,12 @@
|
||||
class My<the_ref>Class:
|
||||
"""
|
||||
:ivar msg: Message
|
||||
:cvar code: Code
|
||||
:var state: State
|
||||
"""
|
||||
|
||||
code = 404
|
||||
|
||||
def __init__(self):
|
||||
self.msg = 'test'
|
||||
self.state = 0
|
||||
@@ -0,0 +1 @@
|
||||
<html><body><div class='definition'><pre><a href="psi_element://#module#ClassAndInstanceAttributesWithSameNameNotDuplicatedGoogle">ClassAndInstanceAttributesWithSameNameNotDuplicatedGoogle</a><br>class <b>MyClass</b></pre></div><div class='content'>Unittest placeholder</div><table class='sections'><tr><td valign='top' class='section'><p>Attributes:</td><td valign='top'><p><code>a1</code> – attr1 doc</p><p><code>a2</code> – attr2 doc</p></td></table></body></html>
|
||||
@@ -0,0 +1,15 @@
|
||||
class My<the_ref>Class:
|
||||
"""
|
||||
Class doc
|
||||
|
||||
Attributes:
|
||||
a1: attr1 doc
|
||||
a2: attr2 doc
|
||||
"""
|
||||
|
||||
a1 = 0
|
||||
a2 = 0
|
||||
|
||||
def __init__(self, a1, a2):
|
||||
self.a1 = a1
|
||||
self.a2 = a2
|
||||
@@ -0,0 +1 @@
|
||||
<html><body><div class='definition'><pre>Class attribute <b>a1</b> of <a href="psi_element://#typename#ClassAttributeDescriptionFromClassDocstringGoogle.Parent">ClassAttributeDescriptionFromClassDocstringGoogle.Parent</a><br>a1: <a href="psi_element://#typename#int">int</a> = 0</pre></div><div class='content'>a1 doc</div></body></html>
|
||||
@@ -0,0 +1,7 @@
|
||||
class Parent:
|
||||
"""
|
||||
Attributes:
|
||||
a1: a1 doc
|
||||
"""
|
||||
|
||||
a<the_ref>1 = 0
|
||||
@@ -0,0 +1 @@
|
||||
<html><body><div class='definition'><pre>Class attribute <b>attr</b> of <a href="psi_element://#typename#ClassAttributeDescriptionFromClassDocstringRest.MyClass">ClassAttributeDescriptionFromClassDocstringRest.MyClass</a><br>attr: <a href="psi_element://#typename#int">int</a> = 0</pre></div><div class='content'>attr description</div></body></html>
|
||||
@@ -0,0 +1,5 @@
|
||||
class MyClass:
|
||||
"""
|
||||
:cvar attr: attr description
|
||||
"""
|
||||
attr<the_ref> = 0
|
||||
1
python/testData/quickdoc/InheritedAttributesGoogle.html
Normal file
1
python/testData/quickdoc/InheritedAttributesGoogle.html
Normal file
@@ -0,0 +1 @@
|
||||
<html><body><div class='definition'><pre><a href="psi_element://#module#InheritedAttributesGoogle">InheritedAttributesGoogle</a><br>class <b>Child</b>(<a href="psi_element://#typename#InheritedAttributesGoogle.Parent">Parent</a>)</pre></div><div class='content'>Unittest placeholder</div><table class='sections'><tr><td valign='top' class='section'><p>Attributes:</td><td valign='top'><p><code>a1</code> – a1 doc from child</p><p><code>a2</code> – a2 doc from child</p></td></table></body></html>
|
||||
21
python/testData/quickdoc/InheritedAttributesGoogle.py
Normal file
21
python/testData/quickdoc/InheritedAttributesGoogle.py
Normal file
@@ -0,0 +1,21 @@
|
||||
class Parent:
|
||||
"""
|
||||
Attributes:
|
||||
a1: a1 doc from parent
|
||||
a2: a2 doc from parent
|
||||
"""
|
||||
|
||||
a1 = 0
|
||||
|
||||
def __init__(self):
|
||||
self.a2 = 0
|
||||
|
||||
|
||||
class Chi<the_ref>ld(Parent):
|
||||
"""
|
||||
Attributes:
|
||||
a1: a1 doc from child
|
||||
a2: a2 doc from child
|
||||
"""
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
@@ -0,0 +1 @@
|
||||
<html><body><div class='definition'><pre><a href="psi_element://#typename#InitEmptyDocstringOverClassDocstringGoogle.MyClass">InitEmptyDocstringOverClassDocstringGoogle.MyClass</a><br>def <b>__init__</b>(self) -> None</pre></div><div class='content'></div></body></html>
|
||||
@@ -0,0 +1,10 @@
|
||||
class MyClass:
|
||||
"""
|
||||
Attributes:
|
||||
a1: a1 doc
|
||||
a2: a2 doc
|
||||
"""
|
||||
def __in<the_ref>it__(self):
|
||||
""""""
|
||||
self.a1 = 0
|
||||
self.a2 = 0
|
||||
@@ -0,0 +1 @@
|
||||
<html><body><div class='definition'><pre>Instance attribute <b>a1</b> of <a href="psi_element://#typename#InstanceAttributeDescriptionFromClassDocstringGoogle.Parent">InstanceAttributeDescriptionFromClassDocstringGoogle.Parent</a><br>a1: <a href="psi_element://#typename#int">int</a> = 0</pre></div><div class='content'>a1 doc</div></body></html>
|
||||
@@ -0,0 +1,9 @@
|
||||
class Parent:
|
||||
"""
|
||||
Attributes:
|
||||
a1: a1 doc
|
||||
"""
|
||||
def __init__(self):
|
||||
self.a1 = 0
|
||||
|
||||
Parent().a<the_ref>1
|
||||
@@ -0,0 +1 @@
|
||||
<html><body><div class='definition'><pre>Instance attribute <b>attr</b> of <a href="psi_element://#typename#InstanceAttributeDescriptionFromClassDocstringRest.MyClass">InstanceAttributeDescriptionFromClassDocstringRest.MyClass</a><br>attr: <a href="psi_element://#typename#int">int</a> = 0</pre></div><div class='content'>attr description</div></body></html>
|
||||
@@ -0,0 +1,7 @@
|
||||
class MyClass:
|
||||
"""
|
||||
:ivar attr: attr description
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.attr<the_ref> = 0
|
||||
@@ -0,0 +1 @@
|
||||
<html><body><div class='definition'><pre>Parameter <b>name</b> of <a href="psi_element://#func#ParameterDescriptionFromClassDocstringGoogle.MyClass.__init__">ParameterDescriptionFromClassDocstringGoogle.MyClass.__init__</a><br>name: Any</pre></div><div class='content'>parameter doc example</div><table class='sections'><tr><td valign='top' class='section'><p>Documentation is copied from:</td><td valign='top'><code><a href="psi_element://#typename#ParameterDescriptionFromClassDocstringGoogle.MyClass">MyClass</a></code></td></table></body></html>
|
||||
@@ -0,0 +1,8 @@
|
||||
class MyClass:
|
||||
"""
|
||||
Args:
|
||||
name: parameter doc example
|
||||
"""
|
||||
|
||||
def __init__(self, nam<the_ref>e):
|
||||
pass
|
||||
@@ -0,0 +1 @@
|
||||
<html><body><div class='definition'><pre>Parameter <b>name</b> of <a href="psi_element://#func#ParameterDescriptionFromInitDocstringOverClassDocstringGoogle.MyClass.__init__">ParameterDescriptionFromInitDocstringOverClassDocstringGoogle.MyClass.__init__</a><br>name: Any</pre></div><div class='content'>parameter doc example from init</div></body></html>
|
||||
@@ -0,0 +1,12 @@
|
||||
class MyClass:
|
||||
"""
|
||||
Args:
|
||||
name: parameter doc example from class
|
||||
"""
|
||||
|
||||
def __init__(self, nam<the_ref>e):
|
||||
"""
|
||||
Args:
|
||||
name: parameter doc example from init
|
||||
"""
|
||||
pass
|
||||
@@ -738,6 +738,111 @@ public class PyQuickDocTest extends LightMarkedTestCase {
|
||||
runWithLanguageLevel(LanguageLevel.getLatest(), this::checkHTMLOnly);
|
||||
}
|
||||
|
||||
// PY-33341
|
||||
public void testClassAndInstanceAttributesInOneSectionGoogle() {
|
||||
checkHTMLOnly();
|
||||
}
|
||||
|
||||
// PY-33341
|
||||
public void testClassAndInstanceAttributesInOneSectionNumpy() {
|
||||
checkHTMLOnly();
|
||||
}
|
||||
|
||||
// PY-33341
|
||||
public void testClassAndInstanceAttributesInOneSectionRest() {
|
||||
runWithDocStringFormat(DocStringFormat.REST, () -> checkHTMLOnly());
|
||||
}
|
||||
|
||||
// PY-33341
|
||||
public void testClassAndInstanceAttributesInOneSectionEpydoc() {
|
||||
runWithDocStringFormat(DocStringFormat.EPYTEXT, () -> checkHTMLOnly());
|
||||
}
|
||||
|
||||
// PY-33341
|
||||
public void testAttributesOrderGoogle() {
|
||||
checkHTMLOnly();
|
||||
}
|
||||
|
||||
// PY-33341
|
||||
public void testClassAndInstanceAttributesWithSameNameNotDuplicatedGoogle() {
|
||||
checkHTMLOnly();
|
||||
}
|
||||
|
||||
// PY-33341
|
||||
public void testInheritedAttributesGoogle() {
|
||||
checkHTMLOnly();
|
||||
}
|
||||
|
||||
// PY-33341
|
||||
public void testAttributesDescriptionFromClassDocstringGoogle() {
|
||||
checkHTMLOnly();
|
||||
}
|
||||
|
||||
// PY-33341
|
||||
public void testArgsDescriptionFromClassAndInitNotMixedGoogle() {
|
||||
checkHTMLOnly();
|
||||
}
|
||||
|
||||
// PY-33341
|
||||
public void testArgsDescriptionFromClassDocstringGoogle() {
|
||||
checkHTMLOnly();
|
||||
}
|
||||
|
||||
// PY-33341
|
||||
public void testArgsFromInitNotTakenInClassDocstringGoogle() {
|
||||
checkHTMLOnly();
|
||||
}
|
||||
|
||||
// PY-33341
|
||||
public void testArgsInClassDocGoogle() {
|
||||
checkHTMLOnly();
|
||||
}
|
||||
|
||||
// PY-33341
|
||||
public void testInitEmptyDocstringOverClassDocstringGoogle() {
|
||||
checkHTMLOnly();
|
||||
}
|
||||
|
||||
// PY-33341
|
||||
public void testAttributeDescriptionEmptyGoogle() {
|
||||
checkHTMLOnly();
|
||||
}
|
||||
|
||||
// PY-56416
|
||||
public void testInstanceAttributeDescriptionFromClassDocstringGoogle() {
|
||||
checkHTMLOnly();
|
||||
}
|
||||
|
||||
// PY-56416
|
||||
public void testClassAttributeDescriptionFromClassDocstringGoogle() {
|
||||
checkHTMLOnly();
|
||||
}
|
||||
|
||||
// PY-56416
|
||||
public void testClassAttributeDescriptionFromClassDocstringRest() {
|
||||
checkHTMLOnly();
|
||||
}
|
||||
|
||||
// PY-56416
|
||||
public void testInstanceAttributeDescriptionFromClassDocstringRest() {
|
||||
checkHTMLOnly();
|
||||
}
|
||||
|
||||
// PY-56416
|
||||
public void testAttributeDocsNotMixed() {
|
||||
checkHTMLOnly();
|
||||
}
|
||||
|
||||
// PY-28900
|
||||
public void testParameterDescriptionFromClassDocstringGoogle() {
|
||||
checkHTMLOnly();
|
||||
}
|
||||
|
||||
// PY-28900
|
||||
public void testParameterDescriptionFromInitDocstringOverClassDocstringGoogle() {
|
||||
checkHTMLOnly();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTestDataPath() {
|
||||
return super.getTestDataPath() + "/quickdoc/";
|
||||
|
||||
Reference in New Issue
Block a user