diff --git a/python/src/com/jetbrains/python/documentation/docstrings/GoogleCodeStyleDocString.java b/python/src/com/jetbrains/python/documentation/docstrings/GoogleCodeStyleDocString.java index f335aa877501..1cb57a177cd0 100644 --- a/python/src/com/jetbrains/python/documentation/docstrings/GoogleCodeStyleDocString.java +++ b/python/src/com/jetbrains/python/documentation/docstrings/GoogleCodeStyleDocString.java @@ -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, Integer> pair; diff --git a/python/src/com/jetbrains/python/documentation/docstrings/NumpyDocString.java b/python/src/com/jetbrains/python/documentation/docstrings/NumpyDocString.java index 16172ab27cfa..852d7f055372 100644 --- a/python/src/com/jetbrains/python/documentation/docstrings/NumpyDocString.java +++ b/python/src/com/jetbrains/python/documentation/docstrings/NumpyDocString.java @@ -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, Integer> parsedDescription = parseIndentedBlock(lineNum + 1, getLineIndentSize(lineNum)); diff --git a/python/src/com/jetbrains/python/documentation/docstrings/SectionBasedDocString.java b/python/src/com/jetbrains/python/documentation/docstrings/SectionBasedDocString.java index ea613e0c91eb..9ef308f74f87 100644 --- a/python/src/com/jetbrains/python/documentation/docstrings/SectionBasedDocString.java +++ b/python/src/com/jetbrains/python/documentation/docstrings/SectionBasedDocString.java @@ -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 SECTION_ALIASES = ImmutableMap.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 parsedField = parseSectionField(lineNum, normalized, sectionIndent); if (!isEmpty(lineNum)) { + final Pair 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 *

diff --git a/python/testData/docstrings/numpyMultipleReturns.py b/python/testData/docstrings/numpyMultipleReturns.py new file mode 100644 index 000000000000..7dfb04995fa8 --- /dev/null +++ b/python/testData/docstrings/numpyMultipleReturns.py @@ -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)``. + """ \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/PySectionBasedDocStringTest.java b/python/testSrc/com/jetbrains/python/PySectionBasedDocStringTest.java index 96234043b78f..5d98447bb01c 100644 --- a/python/testSrc/com/jetbrains/python/PySectionBasedDocStringTest.java +++ b/python/testSrc/com/jetbrains/python/PySectionBasedDocStringTest.java @@ -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";