From a096eb159d77ea0440756faf5f1d5ccf3da209ca Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Wed, 5 Aug 2015 16:55:29 +0300 Subject: [PATCH] PY-9795 Handle colons in Shpinx references inside docstring as Napoleon does --- .../GoogleCodeStyleDocString.java | 17 ++++++- python/testData/docstrings/typeReferences.py | 8 ++++ .../PyGoogleCodeStyleDocStringTest.java | 46 +++++++++++++++---- 3 files changed, 60 insertions(+), 11 deletions(-) create mode 100644 python/testData/docstrings/typeReferences.py diff --git a/python/src/com/jetbrains/python/documentation/GoogleCodeStyleDocString.java b/python/src/com/jetbrains/python/documentation/GoogleCodeStyleDocString.java index b98ee7d51a6a..6f519ed9a54d 100644 --- a/python/src/com/jetbrains/python/documentation/GoogleCodeStyleDocString.java +++ b/python/src/com/jetbrains/python/documentation/GoogleCodeStyleDocString.java @@ -20,6 +20,8 @@ import com.intellij.util.containers.ContainerUtil; import com.jetbrains.python.toolbox.Substring; import org.jetbrains.annotations.NotNull; +import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -73,7 +75,6 @@ public class GoogleCodeStyleDocString extends SectionBasedDocString { type = textBeforeColon.trim(); } else { - // TODO skip references in types like Napoleon does final Matcher matcher = FIELD_NAME_AND_TYPE_RE.matcher(textBeforeColon); if (matcher.matches()) { name = Substring.fromMatcherGroup(textBeforeColon, matcher, 1).trim(); @@ -103,7 +104,19 @@ public class GoogleCodeStyleDocString extends SectionBasedDocString { * */ @NotNull - private List splitFieldStartLineByColon(@NotNull Substring line) { + private static List splitFieldStartLineByColon(@NotNull Substring line) { + final List parts = line.split(SPHINX_REFERENCE_RE); + if (parts.size() > 1) { + for (Substring part : parts) { + final int i = part.indexOf(":"); + if (i >= 0){ + final Substring beforeColon = new Substring(line.getSuperString(), line.getStartOffset(), part.getStartOffset() + i); + final Substring afterColon = new Substring(line.getSuperString(), part.getStartOffset() + i + 1, line.getEndOffset()); + return Arrays.asList(beforeColon, afterColon); + } + } + return Collections.singletonList(line); + } return line.split(":", 1); } diff --git a/python/testData/docstrings/typeReferences.py b/python/testData/docstrings/typeReferences.py new file mode 100644 index 000000000000..9a17688ee8b4 --- /dev/null +++ b/python/testData/docstrings/typeReferences.py @@ -0,0 +1,8 @@ +def func(a1): + """ + Parameters: + a1 (:class:`MyClass`): used to call :def:`my_function` and access :attr:`my_attr` + + Raises: + :class:`MyException`: thrown in case of any error + """ \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/PyGoogleCodeStyleDocStringTest.java b/python/testSrc/com/jetbrains/python/PyGoogleCodeStyleDocStringTest.java index 3b923329d56b..0ef244912701 100644 --- a/python/testSrc/com/jetbrains/python/PyGoogleCodeStyleDocStringTest.java +++ b/python/testSrc/com/jetbrains/python/PyGoogleCodeStyleDocStringTest.java @@ -34,11 +34,7 @@ import java.util.List; public class PyGoogleCodeStyleDocStringTest extends PyTestCase { public void testSimpleFunctionDocString() { - myFixture.configureByFile(getTestName(true) + ".py"); - final String docStringText = findFirstDocString(); - - assertNotNull(docStringText); - final GoogleCodeStyleDocString docString = new GoogleCodeStyleDocString(docStringText); + final GoogleCodeStyleDocString docString = findAndParseDocString(); assertEquals("Summary", docString.getSummary()); final List
sections = docString.getSections(); assertSize(3, sections); @@ -83,6 +79,15 @@ public class PyGoogleCodeStyleDocStringTest extends PyTestCase { assertEquals("always", firstReturnField.getDescription().toString()); } + @NotNull + private GoogleCodeStyleDocString findAndParseDocString() { + myFixture.configureByFile(getTestName(true) + ".py"); + final String docStringText = findFirstDocString(); + + assertNotNull(docStringText); + return new GoogleCodeStyleDocString(docStringText); + } + @Nullable private String findFirstDocString() { final PsiElementProcessor.FindElement processor = new PsiElementProcessor.FindElement() { @@ -104,10 +109,7 @@ public class PyGoogleCodeStyleDocStringTest extends PyTestCase { } public void testSectionStartAfterQuotes() { - myFixture.configureByFile(getTestName(true) + ".py"); - final String docStringText = findFirstDocString(); - assertNotNull(docStringText); - final GoogleCodeStyleDocString docString = new GoogleCodeStyleDocString(docStringText); + final GoogleCodeStyleDocString docString = findAndParseDocString(); assertEmpty(docString.getSummary()); assertSize(2, docString.getSections()); @@ -128,10 +130,36 @@ public class PyGoogleCodeStyleDocStringTest extends PyTestCase { final SectionField firstNotesField = notesSection.getFields().get(0); assertNull(firstNotesField.getName()); assertNull(firstNotesField.getType()); + assertNotNull(firstNotesField.getDescription()); assertEquals(" some\n" + " notes", firstNotesField.getDescription().toString()); } + public void testTypeReferences() { + final GoogleCodeStyleDocString docString = findAndParseDocString(); + assertEmpty(docString.getSummary()); + assertSize(2, docString.getSections()); + + final Section paramSection = docString.getSections().get(0); + assertSize(1, paramSection.getFields()); + final SectionField param1 = paramSection.getFields().get(0); + assertNotNull(param1.getName()); + assertEquals("a1", param1.getName().toString()); + assertNotNull(param1.getType()); + assertEquals(":class:`MyClass`", param1.getType().toString()); + assertNotNull(param1.getDescription()); + assertEquals("used to call :def:`my_function` and access :attr:`my_attr`", param1.getDescription().toString()); + + final Section raisesSection = docString.getSections().get(1); + assertSize(1, raisesSection.getFields()); + final SectionField exception1 = raisesSection.getFields().get(0); + assertNull(exception1.getName()); + assertNotNull(exception1.getType()); + assertEquals(":class:`MyException`", exception1.getType().toString()); + assertNotNull(exception1.getDescription()); + assertEquals("thrown in case of any error", exception1.getDescription().toString()); + } + @Override protected String getTestDataPath() { return super.getTestDataPath() + "/docstrings";