PY-16766 Fix recognition of Google code style docstrings from docstring content
authorMikhail Golubev <mikhail.golubev@jetbrains.com>
Wed, 2 Sep 2015 12:04:13 +0000 (15:04 +0300)
committerMikhail Golubev <mikhail.golubev@jetbrains.com>
Wed, 2 Sep 2015 12:04:13 +0000 (15:04 +0300)
We should try all possible section headers inside docstring and confirm
Google code style once at least one of them turns out to be known.

Also I replaced predefined "\s" character group in internal regular
expressions intended for matching on single line with explicit [ \t],
because otherwise they match section headers with surrounding empty
lines.

python/src/com/jetbrains/python/documentation/DocStringUtil.java
python/src/com/jetbrains/python/documentation/GoogleCodeStyleDocString.java
python/src/com/jetbrains/python/documentation/NumpyDocString.java
python/testSrc/com/jetbrains/python/PySectionBasedDocStringTest.java

index 3203928603334d19deda6451032c53eafda0d971..c7879624b5d927c9316bcc6308875e57aa8b9f90 100644 (file)
@@ -38,7 +38,6 @@ import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import java.util.List;
-import java.util.regex.Matcher;
 
 /**
  * User: catherine
@@ -124,12 +123,12 @@ public class DocStringUtil {
   }
 
   public static boolean isGoogleDocString(@NotNull String text) {
-    final Matcher matcher = GoogleCodeStyleDocString.SECTION_HEADER_RE.matcher(text);
-    if (!matcher.find()) {
-      return false;
+    for (@NonNls String title : StringUtil.findMatches(text, GoogleCodeStyleDocString.SECTION_HEADER, 1)) {
+      if (SectionBasedDocString.SECTION_NAMES.contains(title.toLowerCase())) {
+        return true;
+      }
     }
-    @NonNls final String foundName = matcher.group(1).trim();
-    return SectionBasedDocString.SECTION_NAMES.contains(foundName.toLowerCase());
+    return false;
   }
 
   public static boolean isNumpyDocstring(@NotNull String text) {
index 830fccd6eaf6b560997cba0f24c0ef80c34f30e0..61f3a1a0184ace2fe38dbc9634ac871a210b1952 100644 (file)
@@ -31,8 +31,8 @@ import java.util.regex.Pattern;
  * @see <a href="http://google-styleguide.googlecode.com/svn/trunk/pyguide.html?showone=Comments#Comments">Google Python Style: Docstrings</a>
  */
 public class GoogleCodeStyleDocString extends SectionBasedDocString {
-  public static final Pattern SECTION_HEADER_RE = Pattern.compile("\\s*([\\w\\s]+):\\s*", Pattern.MULTILINE);
-  private static final Pattern FIELD_NAME_AND_TYPE_RE = Pattern.compile("\\s*(.+?)\\s*\\(\\s*(.*?)\\s*\\)\\s*");
+  public static final Pattern SECTION_HEADER = Pattern.compile("^[ \t]*([\\w \t]+):[ \t]*$", Pattern.MULTILINE);
+  private static final Pattern FIELD_NAME_AND_TYPE = Pattern.compile("^[ \t]*(.+?)[ \t]*\\([ \t]*(.*?)[ \t]*\\)[ \t]*$", Pattern.MULTILINE);
 
   public GoogleCodeStyleDocString(@NotNull Substring text) {
     super(text);
@@ -87,7 +87,7 @@ public class GoogleCodeStyleDocString extends SectionBasedDocString {
     final Substring textBeforeColon = colonSeparatedParts.get(0);
     name = textBeforeColon.trim();
     if (mayHaveType) {
-      final Matcher matcher = FIELD_NAME_AND_TYPE_RE.matcher(textBeforeColon);
+      final Matcher matcher = FIELD_NAME_AND_TYPE.matcher(textBeforeColon);
       if (matcher.matches()) {
         name = textBeforeColon.getMatcherGroup(matcher, 1).trim();
         type = textBeforeColon.getMatcherGroup(matcher, 2).trim();
@@ -115,7 +115,7 @@ public class GoogleCodeStyleDocString extends SectionBasedDocString {
   @Override
   protected Pair<Substring, Integer> parseSectionHeader(int lineNum) {
     final Substring line = getLine(lineNum);
-    final Matcher matcher = SECTION_HEADER_RE.matcher(line);
+    final Matcher matcher = SECTION_HEADER.matcher(line);
     if (matcher.matches()) {
       @NonNls final Substring title = line.getMatcherGroup(matcher, 1).trim();
       if (SECTION_NAMES.contains(title.toString().toLowerCase())) {
index 2ce118237ea24d7268de41d012cb120de202bef9..31767b4f0d880440f9cd73182907f71546b0614f 100644 (file)
@@ -29,8 +29,8 @@ import java.util.regex.Pattern;
  * @see <a href="http://sphinxcontrib-napoleon.readthedocs.org/en/latest/example_numpy.html#example-numpy">Napoleon: Example NumPy Style Python Docstrings</a>
  */
 public class NumpyDocString extends SectionBasedDocString {
-  private static final Pattern SIGNATURE = Pattern.compile("^\\s*([\\w., ]+=)?\\s*[\\w\\.]+\\(.*\\)\\s*$", Pattern.MULTILINE);
-  public static final Pattern SECTION_HEADER = Pattern.compile("^\\s*[-=]{2,}\\s*$", Pattern.MULTILINE);
+  private static final Pattern SIGNATURE = Pattern.compile("^[ \t]*([\\w., ]+=)?[ \t]*[\\w\\.]+\\(.*\\)[ \t]*$", Pattern.MULTILINE);
+  public static final Pattern SECTION_HEADER = Pattern.compile("^[ \t]*[-=]{2,}[ \t]*$", Pattern.MULTILINE);
 
   private Substring mySignature;
   public NumpyDocString(@NotNull Substring text) {
index 5555ba69c7ed3857d600defbb0429536c5633d49..0f1c61ada95b30c5ba0497b486ae549226068d2b 100644 (file)
@@ -18,6 +18,7 @@ package com.jetbrains.python;
 import com.intellij.psi.PsiElement;
 import com.intellij.psi.search.PsiElementProcessor;
 import com.intellij.psi.util.PsiTreeUtil;
+import com.jetbrains.python.documentation.DocStringUtil;
 import com.jetbrains.python.documentation.GoogleCodeStyleDocString;
 import com.jetbrains.python.documentation.NumpyDocString;
 import com.jetbrains.python.documentation.SectionBasedDocString;
@@ -290,6 +291,19 @@ public class PySectionBasedDocStringTest extends PyTestCase {
     assertEquals("keyword arguments", docString.getSections().get(0).getNormalizedTitle());
   }
 
+  // PY-16766
+  public void testGoogleDocStringContentDetection() {
+    assertTrue(DocStringUtil.isGoogleDocString(
+      "\n" +
+      "    My Section:\n" +
+      "        some user defined section\n" +
+      "    \n" +
+      "    Parameters:\n" +
+      "        param1: \n" +
+      "\n" +
+      "    Returns:\n"));
+  }
+
   @Override
   protected String getTestDataPath() {
     return super.getTestDataPath() + "/docstrings";