PY-4717 If field contains type only, check that its not plain text using simple heuristic

Otherwise we can't distinguish between type and function description
in cases like the following:

Returns
-------

SomeType, optional
  value description

Continued function description.
This commit is contained in:
Mikhail Golubev
2015-09-17 13:01:29 +03:00
parent 9cc4364a52
commit a1a112b959
5 changed files with 35 additions and 5 deletions
@@ -17,7 +17,6 @@ package com.jetbrains.python.documentation.docstrings;
import com.intellij.openapi.util.Pair;
import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.toolbox.Substring;
import org.jetbrains.annotations.NotNull;
@@ -100,7 +99,7 @@ public class GoogleCodeStyleDocString extends SectionBasedDocString {
if (name != null) {
name = cleanUpName(name);
}
if (name != null ? !PyNames.isIdentifierString(name.toString()) : type.isEmpty()) {
if (name != null ? !isValidName(name.toString()) : !isValidType(type.toString())) {
return Pair.create(null, lineNum);
}
final Pair<List<Substring>, Integer> pair;
@@ -16,7 +16,6 @@
package com.jetbrains.python.documentation.docstrings;
import com.intellij.openapi.util.Pair;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.toolbox.Substring;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -86,7 +85,7 @@ public class NumpyDocString extends SectionBasedDocString {
if (name != null) {
name = cleanUpName(name);
}
if (name != null? !PyNames.isIdentifierString(name.toString()) : type.isEmpty()) {
if (name != null ? !isValidName(name.toString()) : !isValidType(type.toString())) {
return Pair.create(null, lineNum);
}
final Pair<List<Substring>, Integer> parsedDescription = parseIndentedBlock(lineNum + 1, getLineIndentSize(lineNum));
@@ -22,6 +22,7 @@ import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.psi.PyIndentUtil;
import com.jetbrains.python.psi.StructuredDocString;
import com.jetbrains.python.toolbox.Substring;
@@ -51,6 +52,8 @@ public abstract class SectionBasedDocString extends DocStringLineParser implemen
@NonNls public static final String METHODS_SECTION = "methods";
@NonNls public static final String OTHER_PARAMETERS_SECTION = "other parameters";
@NonNls public static final String YIELDS_SECTION = "yields";
private static final Pattern PLAIN_TEXT = Pattern.compile("\\w+(\\s+\\w+){2}"); // dumb heuristic - consecutive words
protected static final Map<String, String> SECTION_ALIASES =
ImmutableMap.<String, String>builder()
@@ -161,8 +164,8 @@ public abstract class SectionBasedDocString extends DocStringLineParser implemen
final int sectionIndent = getLineIndentSize(sectionStartLine);
int lineNum = consumeEmptyLines(parsedHeader.getSecond());
while (!isSectionBreak(lineNum, sectionIndent)) {
final Pair<SectionField, Integer> parsedField = parseSectionField(lineNum, normalized, sectionIndent);
if (!isEmpty(lineNum)) {
final Pair<SectionField, Integer> parsedField = parseSectionField(lineNum, normalized, sectionIndent);
if (parsedField.getFirst() != null) {
fields.add(parsedField.getFirst());
lineNum = parsedField.getSecond();
@@ -243,6 +246,14 @@ public abstract class SectionBasedDocString extends DocStringLineParser implemen
return isSectionStart(lineNum);
}
protected boolean isValidType(@NotNull String type) {
return !type.isEmpty() && !PLAIN_TEXT.matcher(type).find();
}
protected boolean isValidName(@NotNull String name) {
return PyNames.isIdentifierString(name.toString());
}
/**
* Properly partitions line by first colon taking into account possible Sphinx references inside
* <p/>
@@ -0,0 +1,14 @@
def f():
"""
Returns
-------
sign : (...) array_like
A number representing the sign of the determinant. For a real matrix,
this is 1, 0, or -1. For a complex matrix, this is a complex number
with absolute value 1 (i.e., it is on the unit circle), or else 0.
logdet : (...) array_like
The natural log of the absolute value of the determinant.
If the determinant is zero, then `sign` will be 0 and `logdet` will be
-Inf. In all cases, the determinant is equal to ``sign * np.exp(logdet)``.
"""
@@ -344,6 +344,13 @@ public class PySectionBasedDocStringTest extends PyTestCase {
assertEmpty(y.getDescription());
}
public void testNumpyMultipleReturns() {
final NumpyDocString docString = findAndParseNumpyStyleDocString();
assertSize(1, docString.getSections());
final Section returnSection = docString.getSections().get(0);
assertSize(2, returnSection.getFields());
}
@Override
protected String getTestDataPath() {
return super.getTestDataPath() + "/docstrings";