Merge branch 'east825/google-code-style-docstrings'
authorMikhail Golubev <mikhail.golubev@jetbrains.com>
Tue, 15 Sep 2015 12:43:10 +0000 (15:43 +0300)
committerMikhail Golubev <mikhail.golubev@jetbrains.com>
Tue, 15 Sep 2015 13:13:22 +0000 (16:13 +0300)
Conflicts:
python/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java
python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java
python/src/com/jetbrains/python/psi/impl/PyFunctionBuilder.java
python/testData/quickdoc/NumPyOnesDoc.html

20 files changed:
1  2 
python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java
python/src/META-INF/python-core.xml
python/src/com/jetbrains/python/PyBundle.properties
python/src/com/jetbrains/python/codeInsight/imports/AddImportHelper.java
python/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java
python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java
python/src/com/jetbrains/python/inspections/quickfix/PyRemoveParameterQuickFix.java
python/src/com/jetbrains/python/psi/PyUtil.java
python/src/com/jetbrains/python/psi/impl/PyClassImpl.java
python/src/com/jetbrains/python/psi/impl/PyFunctionBuilder.java
python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java
python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java
python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java
python/testData/quickdoc/NumPyOnesDoc.html
python/testData/refactoring/move/moduleToNonPackage/after/src/nonp3/__init__.py
python/testData/refactoring/move/newModule/after/src/b.py
python/testSrc/com/jetbrains/python/PyQuickDocTest.java
python/testSrc/com/jetbrains/python/PyQuickFixTest.java
python/testSrc/com/jetbrains/python/PythonHighlightingTest.java
python/testSrc/com/jetbrains/python/PythonInspectionsTest.java

index 3e65dd536d86fc36597db086b2d533d312fb147d,56a08a01ac50944fd14881e84083910d690b33ea..cd01a4037866afeb2b48ce769e406e657c99df27
@@@ -319,35 -313,23 +315,17 @@@ public class PyActiveSdkConfigurable im
    }
  
    private void setSdk(final Sdk item) {
 -    DumbService.allowStartingDumbModeInside(DumbModePermission.MAY_START_BACKGROUND, new Runnable() {
 +    ApplicationManager.getApplication().runWriteAction(new Runnable() {
        @Override
        public void run() {
 -        ApplicationManager.getApplication().runWriteAction(new Runnable() {
 -          @Override
 -          public void run() {
 -            ProjectRootManager.getInstance(myProject).setProjectSdk(item);
 -          }
 -        });
 -        if (myModule != null) {
 -          ModuleRootModificationUtil.setModuleSdk(myModule, item);
 -        }
 +        ProjectRootManager.getInstance(myProject).setProjectSdk(item);
        }
      });
 -
 +    if (myModule != null) {
 +      ModuleRootModificationUtil.setModuleSdk(myModule, item);
 +    }
    }
  
-   public static void rehighlightStrings(final @NotNull Project project) {
-     ApplicationManager.getApplication().runWriteAction(new Runnable() {
-       @Override
-       public void run() {
-         for (Editor editor : EditorFactory.getInstance().getAllEditors()) {
-           if (editor instanceof EditorEx && editor.getProject() == project) {
-             final VirtualFile vFile = ((EditorEx)editor).getVirtualFile();
-             if (vFile != null) {
-               final EditorHighlighter highlighter = EditorHighlighterFactory.getInstance().createEditorHighlighter(project, vFile);
-               ((EditorEx)editor).setHighlighter(highlighter);
-             }
-           }
-         }
-       }
-     });
-   }
    @Override
    public void reset() {
      resetSdkList();
Simple merge
index db780a670a170c6c357bd0426f684f2872ef0140,1eff3fd8ac3b34b4eaf1457e95fa705d619c560b..ccda8a5b987e08869ff58902dda7ccc2b27f5bd3
@@@ -940,3 -943,7 +940,7 @@@ formatter.align.when.multiline=Align wh
  formatter.collections.and.comprehensions=Collections and Comprehensions
  formatter.import.statements=Import Statements
  formatter.dictionary.literals=Dictionary literals
 -smartKeys.insert.type.placeholder.in.docstring.stub=Insert type placeholders in the documentation comment stub
+ smartKeys.insert.backslash.in.statement.on.enter=Insert backslash when pressing Enter inside a statement
+ smartKeys.insert.self.in.method=Insert 'self' when defining a method
++smartKeys.insert.type.placeholder.in.docstring.stub=Insert type placeholders in the documentation comment stub
index f34984022128c86894d6d9d21b469b7c6afb26d8,071a1a9e9bdbfe54010700ea22666bd2e7270c4d..c00cf762e446a5f016ea27aeed0fdad40184770e
@@@ -28,9 -28,8 +28,9 @@@ import com.intellij.psi.util.PsiTreeUti
  import com.intellij.psi.util.QualifiedName;
  import com.intellij.util.ArrayUtil;
  import com.intellij.util.IncorrectOperationException;
 +import com.intellij.util.containers.ContainerUtil;
  import com.jetbrains.python.codeInsight.PyCodeInsightSettings;
- import com.jetbrains.python.documentation.DocStringUtil;
+ import com.jetbrains.python.documentation.docstrings.DocStringUtil;
  import com.jetbrains.python.formatter.PyBlock;
  import com.jetbrains.python.psi.*;
  import com.jetbrains.python.psi.resolve.QualifiedNameFinder;
index 54382198d8c3610ba17540be6f5d16f94e5ec093,3ee468448962b445a644e38d310ad18c47491151..50293d957c1f526299e31620279259cd22908b0f
@@@ -28,8 -27,12 +28,10 @@@ import com.intellij.psi.PsiElement
  import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
  import com.intellij.psi.util.PsiTreeUtil;
  import com.intellij.util.ArrayUtil;
 -import com.jetbrains.python.PyBundle;
 -import com.jetbrains.python.PyNames;
 -import com.jetbrains.python.PythonFileType;
 +import com.jetbrains.python.*;
  import com.jetbrains.python.console.PyConsoleUtil;
+ import com.jetbrains.python.documentation.docstrings.DocStringUtil;
+ import com.jetbrains.python.documentation.docstrings.PyStructuredDocstringFormatter;
  import com.jetbrains.python.psi.*;
  import com.jetbrains.python.psi.impl.PyBuiltinCache;
  import com.jetbrains.python.psi.impl.PyCallExpressionHelper;
@@@ -58,12 -58,11 +60,12 @@@ public class PyDocumentationBuilder 
    private final PsiElement myElement;
    private final PsiElement myOriginalElement;
    private ChainIterable<String> myResult;
-   private ChainIterable<String> myProlog;      // sequence for reassignment info, etc
-   private ChainIterable<String> myBody;        // sequence for doc string
-   private ChainIterable<String> myEpilog;      // sequence for doc "copied from" notices and such
+   private final ChainIterable<String> myProlog;      // sequence for reassignment info, etc
+   private final ChainIterable<String> myBody;        // sequence for doc string
+   private final ChainIterable<String> myEpilog;      // sequence for doc "copied from" notices and such
  
    private static final Pattern ourSpacesPattern = Pattern.compile("^\\s+");
-   private ChainIterable<String> myReassignmentChain;
++  private final ChainIterable<String> myReassignmentChain;
  
    public PyDocumentationBuilder(PsiElement element, PsiElement originalElement) {
      myElement = element;
  
      myResult.add(myProlog).addWith(TagCode, myBody).add(myEpilog); // pre-assemble; then add stuff to individual cats as needed
      myResult = wrapInTag("html", wrapInTag("body", myResult));
 +    myReassignmentChain = new ChainIterable<String>();
    }
  
+   @Nullable
    public String build() {
 -    final ChainIterable<String> reassignCat = new ChainIterable<String>(); // sequence for reassignment info, etc
 -    PsiElement followed = resolveToDocStringOwner(reassignCat);
 -
 -    // check if we got a property ref.
 -    // if so, element is an accessor, and originalElement if an identifier
 -    // TODO: use messages from resources!
 -    PyClass cls;
 -    PsiElement outer = null;
 -    boolean isProperty = false;
 -    String accessorKind = "None";
      final TypeEvalContext context = TypeEvalContext.userInitiated(myElement.getProject(), myElement.getContainingFile());
 -    if (myOriginalElement != null) {
 -      final String elementName = myOriginalElement.getText();
 -      if (PyUtil.isPythonIdentifier(elementName)) {
 -        outer = myOriginalElement.getParent();
 -        if (outer instanceof PyQualifiedExpression) {
 -          final PyExpression qual = ((PyQualifiedExpression)outer).getQualifier();
 -          if (qual != null) {
 -            final PyType type = context.getType(qual);
 -            if (type instanceof PyClassType) {
 -              cls = ((PyClassType)type).getPyClass();
 -              final Property property = cls.findProperty(elementName, true, null);
 -              if (property != null) {
 -                isProperty = true;
 -                final AccessDirection dir = AccessDirection.of((PyElement)outer);
 -                final Maybe<PyCallable> accessor = property.getByDirection(dir);
 -                myProlog
 -                  .addItem("property ").addWith(TagBold, $().addWith(TagCode, $(elementName)))
 -                  .addItem(" of ").add(PythonDocumentationProvider.describeClass(cls, TagCode, true, true));
 -                if (accessor.isDefined() && property.getDoc() != null) {
 -                  myBody.addItem(": ").addItem(property.getDoc()).addItem(BR);
 -                }
 -                else {
 -                  final PyCallable getter = property.getGetter().valueOrNull();
 -                  if (getter != null && getter != myElement && getter instanceof PyFunction) {
 -                    // not in getter, getter's doc comment may be useful
 -                    final PyStringLiteralExpression docstring = ((PyFunction)getter).getDocStringExpression();
 -                    if (docstring != null) {
 -                      myProlog
 -                        .addItem(BR).addWith(TagItalic, $("Copied from getter:")).addItem(BR)
 -                        .addItem(docstring.getStringValue());
 -                    }
 -                  }
 -                  myBody.addItem(BR);
 -                }
 -                myBody.addItem(BR);
 -                if (accessor.isDefined() && accessor.value() == null) followed = null;
 -                if (dir == AccessDirection.READ) {
 -                  accessorKind = "Getter";
 -                }
 -                else if (dir == AccessDirection.WRITE) {
 -                  accessorKind = "Setter";
 -                }
 -                else {
 -                  accessorKind = "Deleter";
 -                }
 -                if (followed != null) myEpilog.addWith(TagSmall, $(BR, BR, accessorKind, " of property")).addItem(BR);
 -              }
 -            }
 -          }
 -        }
 -      }
 -    }
 +    final PsiElement outerElement = myOriginalElement != null ? myOriginalElement.getParent() : null;
 +
 +    final PsiElement elementDefinition = resolveToDocStringOwner();
 +    final boolean isProperty = buildFromProperty(elementDefinition, outerElement, context);
  
      if (myProlog.isEmpty() && !isProperty && !isAttribute()) {
 -      myProlog.add(reassignCat);
 -    }
 -
 -    // now followed may contain a doc string
 -    if (followed instanceof PyDocStringOwner) {
 -      String docString = null;
 -      final PyStringLiteralExpression docExpr = ((PyDocStringOwner)followed).getDocStringExpression();
 -      if (docExpr != null) docString = docExpr.getStringValue();
 -      // doc of what?
 -      if (followed instanceof PyClass) {
 -        cls = (PyClass)followed;
 -        myBody.add(PythonDocumentationProvider.describeDecorators(cls, TagItalic, BR, LCombUp));
 -        myBody.add(PythonDocumentationProvider.describeClass(cls, TagBold, true, false));
 +      myProlog.add(myReassignmentChain);
 +    }
 +
 +    if (elementDefinition instanceof PyDocStringOwner) {
 +      buildFromDocstring(elementDefinition, isProperty);
 +    }
 +    else if (isAttribute()) {
 +      buildFromAttributeDoc();
 +    }
 +    else if (elementDefinition instanceof PyNamedParameter) {
 +      buildFromParameter(context, outerElement, elementDefinition);
 +    }
 +    else if (elementDefinition != null && outerElement instanceof PyReferenceExpression) {
 +      myBody.addItem(combUp("\nInferred type: "));
 +      PythonDocumentationProvider.describeExpressionTypeWithLinks(myBody, (PyReferenceExpression)outerElement, context);
 +    }
 +
 +    if (elementDefinition != null &&
 +        PythonDialectsTokenSetProvider.INSTANCE.getKeywordTokens().contains(elementDefinition.getNode().getElementType())) {
 +      buildForKeyword(elementDefinition.getText());
 +    }
 +    final String url = PythonDocumentationProvider.getUrlFor(myElement, myOriginalElement, true);
 +    if (url != null) {
 +      myEpilog.addItem(BR);
 +      myEpilog.addWith(TagBold, $("External documentation:"));
 +      myEpilog.addItem(BR);
 +      myEpilog.addItem("<a href=\"").addItem(url).addItem("\">").addItem(url).addItem("</a>");
 +    }
 +
 +    if (myBody.isEmpty() && myEpilog.isEmpty()) {
 +      return null; // got nothing substantial to say!
 +    }
 +    else {
 +      return myResult.toString();
 +    }
 +  }
 +
 +  private void buildForKeyword(@NotNull final String name) {
 +    try {
 +      final FileReader reader = new FileReader(PythonHelpersLocator.getHelperPath("/tools/python_keywords/" + name));
 +      try {
 +        final String text = FileUtil.loadTextAndClose(reader);
 +        myEpilog.addItem(text);
        }
 -      else if (followed instanceof PyFunction) {
 -        final PyFunction fun = (PyFunction)followed;
 -        if (!isProperty) {
 -          cls = fun.getContainingClass();
 -          if (cls != null) {
 -            myBody.addWith(TagSmall, PythonDocumentationProvider.describeClass(cls, TagCode, true, true)).addItem(BR).addItem(BR);
 -          }
 -        }
 -        else {
 -          cls = null;
 +      catch (IOException ignored) {
 +      }
 +      finally {
 +        try {
 +          reader.close();
          }
 -        myBody
 -          .add(PythonDocumentationProvider.describeDecorators(fun, TagItalic, BR, LCombUp))
 -          .add(PythonDocumentationProvider.describeFunction(fun, TagBold, LCombUp));
 -        if (docString == null) {
 -          addInheritedDocString(fun, cls);
 +        catch (IOException ignored) {
          }
        }
 -      else if (followed instanceof PyFile) {
 -        addModulePath((PyFile)followed);
 -      }
 -      if (docString != null) {
 -        myBody.addItem(BR);
 -        addFormattedDocString(myElement, docString, myBody, myEpilog);
 -      }
      }
 -    else if (isProperty) {
 -      // if it was a normal accessor, ti would be a function, handled by previous branch
 -      final String accessorMessage;
 -      if (followed != null) {
 -        accessorMessage = "Declaration: ";
 -      }
 -      else {
 -        accessorMessage = accessorKind + " is not defined.";
 -      }
 -      myBody.addWith(TagItalic, $(accessorMessage)).addItem(BR);
 -      if (followed != null) myBody.addItem(combUp(PyUtil.getReadableRepr(followed, false)));
 +    catch (FileNotFoundException ignored) {
      }
 -    else if (isAttribute()) {
 -      addAttributeDoc();
 -    }
 -    else if (followed instanceof PyNamedParameter) {
 -      myBody.addItem(combUp("Parameter " + PyUtil.getReadableRepr(followed, false)));
 -      final boolean typeFromDocstringAdded = addTypeAndDescriptionFromDocstring((PyNamedParameter)followed);
 -      if (outer instanceof PyExpression) {
 -        final PyType type = context.getType((PyExpression)outer);
 -        if (type != null) {
 -          String s = null;
 -          if (type instanceof PyDynamicallyEvaluatedType) {
 -            if (!typeFromDocstringAdded) {
 -              //don't add dynamic type if docstring type specified
 -              s = "\nDynamically inferred type: ";
 -            }
 +  }
 +
 +  private void buildFromParameter(@NotNull final TypeEvalContext context, @Nullable final PsiElement outerElement,
 +                                  @NotNull final PsiElement elementDefinition) {
 +    myBody.addItem(combUp("Parameter " + PyUtil.getReadableRepr(elementDefinition, false)));
-     boolean typeFromDocstringAdded = addTypeAndDescriptionFromDocstring((PyNamedParameter)elementDefinition);
++    final boolean typeFromDocstringAdded = addTypeAndDescriptionFromDocstring((PyNamedParameter)elementDefinition);
 +    if (outerElement instanceof PyExpression) {
-       PyType type = context.getType((PyExpression)outerElement);
++      final PyType type = context.getType((PyExpression)outerElement);
 +      if (type != null) {
 +        String typeString = null;
 +        if (type instanceof PyDynamicallyEvaluatedType) {
 +          if (!typeFromDocstringAdded) {
 +            typeString = "\nDynamically inferred type: ";
            }
 -          else {
 -            if (outer.getReference() != null) {
 -              final PsiElement target = outer.getReference().resolve();
 +        }
 +        else {
 +          if (outerElement.getReference() != null) {
-             PsiElement target = outerElement.getReference().resolve();
++            final PsiElement target = outerElement.getReference().resolve();
  
 -              if (target instanceof PyTargetExpression &&
 -                  ((PyTargetExpression)target).getName().equals(((PyNamedParameter)followed).getName())) {
 -                s = "\nReassigned value has type: ";
 +            if (target instanceof PyTargetExpression) {
 +              final String targetName = ((PyTargetExpression)target).getName();
 +              if (targetName != null && targetName.equals(((PyNamedParameter)elementDefinition).getName())) {
 +                typeString = "\nReassigned value has type: ";
                }
              }
            }
          }
        }
      }
 -    else if (followed != null && outer instanceof PyReferenceExpression) {
 -      myBody.addItem(combUp("\nInferred type: "));
 -      PythonDocumentationProvider.describeExpressionTypeWithLinks(myBody, (PyReferenceExpression)outer, context);
 +  }
 +
 +  private boolean buildFromProperty(PsiElement elementDefinition, @Nullable final PsiElement outerElement,
 +                                    @NotNull final TypeEvalContext context) {
 +    if (myOriginalElement == null) {
 +      return false;
      }
 -    if (myBody.isEmpty() && myEpilog.isEmpty()) {
 -      return null; // got nothing substantial to say!
 +    final String elementName = myOriginalElement.getText();
 +    if (!PyNames.isIdentifier(elementName)) {
 +      return false;
 +    }
 +    if (!(outerElement instanceof PyQualifiedExpression)) {
 +      return false;
 +    }
 +    final PyExpression qualifier = ((PyQualifiedExpression)outerElement).getQualifier();
 +    if (qualifier == null) {
 +      return false;
 +    }
 +    final PyType type = context.getType(qualifier);
 +    if (!(type instanceof PyClassType)) {
 +      return false;
 +    }
 +    final PyClass cls = ((PyClassType)type).getPyClass();
 +    final Property property = cls.findProperty(elementName, true, null);
 +    if (property == null) {
 +      return false;
 +    }
 +
 +    final AccessDirection direction = AccessDirection.of((PyElement)outerElement);
 +    final Maybe<PyCallable> accessor = property.getByDirection(direction);
 +    myProlog.addItem("property ").addWith(TagBold, $().addWith(TagCode, $(elementName)))
 +      .addItem(" of ").add(PythonDocumentationProvider.describeClass(cls, TagCode, true, true));
 +    if (accessor.isDefined() && property.getDoc() != null) {
 +      myBody.addItem(": ").addItem(property.getDoc()).addItem(BR);
      }
      else {
 -      return myResult.toString();
 +      final PyCallable getter = property.getGetter().valueOrNull();
 +      if (getter != null && getter != myElement && getter instanceof PyFunction) {
 +        // not in getter, getter's doc comment may be useful
 +        final PyStringLiteralExpression docstring = ((PyFunction)getter).getDocStringExpression();
 +        if (docstring != null) {
 +          myProlog
 +            .addItem(BR).addWith(TagItalic, $("Copied from getter:")).addItem(BR)
 +            .addItem(docstring.getStringValue())
 +          ;
 +        }
 +      }
 +      myBody.addItem(BR);
 +    }
 +    myBody.addItem(BR);
 +    if (accessor.isDefined() && accessor.value() == null) elementDefinition = null;
 +    final String accessorKind = getAccessorKind(direction);
 +    if (elementDefinition != null) {
 +      myEpilog.addWith(TagSmall, $(BR, BR, accessorKind, " of property")).addItem(BR);
 +    }
 +
 +    if (!(elementDefinition instanceof PyDocStringOwner)) {
 +      myBody.addWith(TagItalic, elementDefinition != null ? $("Declaration: ") : $(accessorKind + " is not defined.")).addItem(BR);
 +      if (elementDefinition != null) {
 +        myBody.addItem(combUp(PyUtil.getReadableRepr(elementDefinition, false)));
 +      }
 +    }
 +    return true;
 +  }
 +
 +  @NotNull
 +  private static String getAccessorKind(@NotNull final AccessDirection dir) {
 +    final String accessorKind;
 +    if (dir == AccessDirection.READ) {
 +      accessorKind = "Getter";
 +    }
 +    else if (dir == AccessDirection.WRITE) {
 +      accessorKind = "Setter";
 +    }
 +    else {
 +      accessorKind = "Deleter";
 +    }
 +    return accessorKind;
 +  }
 +
 +  private void buildFromDocstring(@NotNull final PsiElement elementDefinition, boolean isProperty) {
 +    PyClass pyClass = null;
 +    final PyStringLiteralExpression docStringExpression = ((PyDocStringOwner)elementDefinition).getDocStringExpression();
 +
 +    if (elementDefinition instanceof PyClass) {
 +      pyClass = (PyClass)elementDefinition;
 +      myBody.add(PythonDocumentationProvider.describeDecorators(pyClass, TagItalic, BR, LCombUp));
 +      myBody.add(PythonDocumentationProvider.describeClass(pyClass, TagBold, true, false));
 +    }
 +    else if (elementDefinition instanceof PyFunction) {
-       PyFunction pyFunction = (PyFunction)elementDefinition;
++      final PyFunction pyFunction = (PyFunction)elementDefinition;
 +      if (!isProperty) {
 +        pyClass = pyFunction.getContainingClass();
 +        if (pyClass != null) {
 +          myBody.addWith(TagSmall, PythonDocumentationProvider.describeClass(pyClass, TagCode, true, true)).addItem(BR).addItem(BR);
 +        }
 +      }
 +      myBody.add(PythonDocumentationProvider.describeDecorators(pyFunction, TagItalic, BR, LCombUp))
 +            .add(PythonDocumentationProvider.describeFunction(pyFunction, TagBold, LCombUp));
 +      if (docStringExpression == null) {
 +        addInheritedDocString(pyFunction, pyClass);
 +      }
 +    }
 +    else if (elementDefinition instanceof PyFile) {
 +      addModulePath((PyFile)elementDefinition);
 +    }
 +    if (docStringExpression != null) {
 +      myBody.addItem(BR);
 +      addFormattedDocString(myElement, docStringExpression.getStringValue(), myBody, myEpilog);
      }
    }
  
        final PyCallExpression call = (PyCallExpression)myElement;
        final Pair<String, PyFunction> wrapInfo = PyCallExpressionHelper.interpretAsModifierWrappingCall(call, myOriginalElement);
        if (wrapInfo != null) {
-         String wrapperName = wrapInfo.getFirst();
-         PyFunction wrappedFunction = wrapInfo.getSecond();
+         final String wrapperName = wrapInfo.getFirst();
 -        final PyFunction wrappedFunc = wrapInfo.getSecond();
 -        //prologCat.addWith(TagSmall, $("Wrapped in ").addWith(TagCode, $(wrapperName)).add(BR));
 -        prologCat.addWith(TagSmall, $(PyBundle.message("QDOC.wrapped.in.$0", wrapperName)).addItem(BR));
 -        return wrappedFunc;
++        final PyFunction wrappedFunction = wrapInfo.getSecond();
 +        myReassignmentChain.addWith(TagSmall, $(PyBundle.message("QDOC.wrapped.in.$0", wrapperName)).addItem(BR));
 +        return wrappedFunction;
        }
      }
      return myElement;
      return resolveResult.isImplicit() ? null : resolveResult.getElement();
    }
  
 -  private void addInheritedDocString(@NotNull PyFunction fun, @Nullable PyClass cls) {
 +  private void addInheritedDocString(@NotNull final PyFunction pyFunction, @Nullable final PyClass pyClass) {
      boolean notFound = true;
 -    final String methName = fun.getName();
 -    if (cls != null && methName != null) {
 -      final boolean isConstructor = PyNames.INIT.equals(methName);
 -      // look for inherited and its doc
 -      Iterable<PyClass> classes = cls.getAncestorClasses(null);
 -      if (isConstructor) {
 -        // look at our own class again and maybe inherit class's doc
 -        classes = new ChainIterable<PyClass>(cls).add(classes);
 +    final String methodName = pyFunction.getName();
 +    if (pyClass == null || methodName == null) {
 +      return;
 +    }
 +    final boolean isConstructor = PyNames.INIT.equals(methodName);
 +    Iterable<PyClass> classes = pyClass.getAncestorClasses(null);
 +    if (isConstructor) {
 +      // look at our own class again and maybe inherit class's doc
 +      classes = new ChainIterable<PyClass>(pyClass).add(classes);
 +    }
 +    for (PyClass ancestor : classes) {
 +      PyStringLiteralExpression docstringElement = null;
 +      PyFunction inherited = null;
 +      boolean isFromClass = false;
 +      if (isConstructor) docstringElement = pyClass.getDocStringExpression();
 +      if (docstringElement != null) {
 +        isFromClass = true;
        }
 -      for (PyClass ancestor : classes) {
 -        PyStringLiteralExpression docElt = null;
 -        PyFunction inherited = null;
 -        boolean isFromClass = false;
 -        if (isConstructor) docElt = cls.getDocStringExpression();
 -        if (docElt != null) {
 -          isFromClass = true;
 -        }
 -        else {
 -          inherited = ancestor.findMethodByName(methName, false);
 -        }
 -        if (inherited != null) {
 -          docElt = inherited.getDocStringExpression();
 -        }
 -        if (docElt != null) {
 -          final String inheritedDoc = docElt.getStringValue();
 -          if (inheritedDoc.length() > 1) {
 -            myEpilog.addItem(BR).addItem(BR);
 -            final String ancestorName = ancestor.getName();
 -            final String marker =
 -              (cls == ancestor) ? PythonDocumentationProvider.LINK_TYPE_CLASS : PythonDocumentationProvider.LINK_TYPE_PARENT;
 -            final String ancestorLink =
 -              $().addWith(new LinkWrapper(marker + ancestorName), $(ancestorName)).toString();
 -            if (isFromClass) {
 -              myEpilog.addItem(PyBundle.message("QDOC.copied.from.class.$0", ancestorLink));
 -            }
 -            else {
 -              myEpilog.addItem(PyBundle.message("QDOC.copied.from.$0.$1", ancestorLink, methName));
 -            }
 -            myEpilog.addItem(BR).addItem(BR);
 -            final ChainIterable<String> formatted = new ChainIterable<String>();
 -            final ChainIterable<String> unformatted = new ChainIterable<String>();
 -            addFormattedDocString(fun, inheritedDoc, formatted, unformatted);
 -            myEpilog.addWith(TagCode, formatted).add(unformatted);
 -            notFound = false;
 -            break;
 +      else {
 +        inherited = ancestor.findMethodByName(methodName, false);
 +      }
 +      if (inherited != null) {
 +        docstringElement = inherited.getDocStringExpression();
 +      }
 +      if (docstringElement != null) {
 +        final String inheritedDoc = docstringElement.getStringValue();
 +        if (inheritedDoc.length() > 1) {
 +          myEpilog.addItem(BR).addItem(BR);
-           String ancestor_name = ancestor.getName();
-           String marker = (pyClass == ancestor) ? PythonDocumentationProvider.LINK_TYPE_CLASS : PythonDocumentationProvider.LINK_TYPE_PARENT;
-           final String ancestor_link =
-             $().addWith(new LinkWrapper(marker + ancestor_name), $(ancestor_name)).toString();
++          final String ancestorName = ancestor.getName();
++          final String marker = (pyClass == ancestor) ? PythonDocumentationProvider.LINK_TYPE_CLASS : PythonDocumentationProvider.LINK_TYPE_PARENT;
++          final String ancestorLink =
++            $().addWith(new LinkWrapper(marker + ancestorName), $(ancestorName)).toString();
 +          if (isFromClass) {
-             myEpilog.addItem(PyBundle.message("QDOC.copied.from.class.$0", ancestor_link));
++            myEpilog.addItem(PyBundle.message("QDOC.copied.from.class.$0", ancestorLink));
 +          }
 +          else {
-             myEpilog.addItem(PyBundle.message("QDOC.copied.from.$0.$1", ancestor_link, methodName));
++            myEpilog.addItem(PyBundle.message("QDOC.copied.from.$0.$1", ancestorLink, methodName));
            }
-           ChainIterable<String> formatted = new ChainIterable<String>();
-           ChainIterable<String> unformatted = new ChainIterable<String>();
 +          myEpilog.addItem(BR).addItem(BR);
++          final ChainIterable<String> formatted = new ChainIterable<String>();
++          final ChainIterable<String> unformatted = new ChainIterable<String>();
 +          addFormattedDocString(pyFunction, inheritedDoc, formatted, unformatted);
 +          myEpilog.addWith(TagCode, formatted).add(unformatted);
 +          notFound = false;
 +          break;
          }
        }
 +    }
  
 -      if (notFound) {
 -        // above could have not worked because inheritance is not searched down to 'object'.
 -        // for well-known methods, copy built-in doc string.
 -        // TODO: also handle predefined __xxx__ that are not part of 'object'.
 -        if (PyNames.UnderscoredAttributes.contains(methName)) {
 -          addPredefinedMethodDoc(fun, methName);
 -        }
 +    if (notFound) {
 +      // above could have not worked because inheritance is not searched down to 'object'.
 +      // for well-known methods, copy built-in doc string.
 +      // TODO: also handle predefined __xxx__ that are not part of 'object'.
 +      if (PyNames.UnderscoredAttributes.contains(methodName)) {
 +        addPredefinedMethodDoc(pyFunction, methodName);
        }
      }
    }
  
 -  private void addPredefinedMethodDoc(@NotNull PyFunction fun, String methName) {
 -    final PyClassType objtype = PyBuiltinCache.getInstance(fun).getObjectType(); // old- and new-style classes share the __xxx__ stuff
 -    if (objtype != null) {
 -      final PyClass objcls = objtype.getPyClass();
 -      final PyFunction objUnderscored = objcls.findMethodByName(methName, false);
 -      if (objUnderscored != null) {
 -        final PyStringLiteralExpression predefinedDocExpr = objUnderscored.getDocStringExpression();
 -        final String predefinedDoc = predefinedDocExpr != null ? predefinedDocExpr.getStringValue() : null;
 +  private void addPredefinedMethodDoc(PyFunction fun, String mothodName) {
-     PyClassType objectType = PyBuiltinCache.getInstance(fun).getObjectType(); // old- and new-style classes share the __xxx__ stuff
++    final PyClassType objectType = PyBuiltinCache.getInstance(fun).getObjectType(); // old- and new-style classes share the __xxx__ stuff
 +    if (objectType != null) {
-       PyClass objectClass = objectType.getPyClass();
-       PyFunction predefinedMethod = objectClass.findMethodByName(mothodName, false);
++      final PyClass objectClass = objectType.getPyClass();
++      final PyFunction predefinedMethod = objectClass.findMethodByName(mothodName, false);
 +      if (predefinedMethod != null) {
-         PyStringLiteralExpression predefinedDocstring = predefinedMethod.getDocStringExpression();
-         String predefinedDoc = predefinedDocstring != null ? predefinedDocstring.getStringValue() : null;
++        final PyStringLiteralExpression predefinedDocstring = predefinedMethod.getDocStringExpression();
++        final String predefinedDoc = predefinedDocstring != null ? predefinedDocstring.getStringValue() : null;
          if (predefinedDoc != null && predefinedDoc.length() > 1) { // only a real-looking doc string counts
            addFormattedDocString(fun, predefinedDoc, myBody, myBody);
            myEpilog.addItem(BR).addItem(BR).addItem(PyBundle.message("QDOC.copied.from.builtin"));
      return false;
    }
  
 -  private static Pair<String, String> getTypeAndDescr(String docString, @NotNull PyNamedParameter followed) {
 -    final StructuredDocString structuredDocString = docString != null ? DocStringUtil.parse(docString, followed) : null;
 +  private static Pair<String, String> getTypeAndDescription(@Nullable final String docString, @NotNull final PyNamedParameter followed) {
-     StructuredDocString structuredDocString = DocStringUtil.parse(docString);
      String type = null;
      String desc = null;
--    if (structuredDocString != null) {
++    if (docString != null) {
++      final StructuredDocString structuredDocString = DocStringUtil.parse(docString);
        final String name = followed.getName();
        type = structuredDocString.getParamType(name);
--
        desc = structuredDocString.getParamDescription(name);
      }
--
      return Pair.create(type, desc);
    }
  
 -  private void addAttributeDoc() {
 +  private void buildFromAttributeDoc() {
-     PyClass cls = PsiTreeUtil.getParentOfType(myElement, PyClass.class);
+     final PyClass cls = PsiTreeUtil.getParentOfType(myElement, PyClass.class);
      assert cls != null;
-     String type = PyUtil.isInstanceAttribute((PyExpression)myElement) ? "Instance attribute " : "Class attribute ";
+     final String type = PyUtil.isInstanceAttribute((PyExpression)myElement) ? "Instance attribute " : "Class attribute ";
      myProlog
        .addItem(type).addWith(TagBold, $().addWith(TagCode, $(((PyTargetExpression)myElement).getName())))
-       .addItem(" of class ").addWith(PythonDocumentationProvider.LinkMyClass, $().addWith(TagCode, $(cls.getName()))).addItem(BR)
-     ;
+       .addItem(" of class ").addWith(PythonDocumentationProvider.LinkMyClass, $().addWith(TagCode, $(cls.getName()))).addItem(BR);
  
      final String docString = ((PyTargetExpression)myElement).getDocStringValue();
      if (docString != null) {
      }
    }
  
 -  public static String[] removeCommonIndentation(String docstring) {
 +  public static String[] removeCommonIndentation(@NotNull final String docstring) {
      // detect common indentation
-     String[] lines = LineTokenizer.tokenize(docstring, false);
+     final String[] lines = LineTokenizer.tokenize(docstring, false);
      boolean isFirst = true;
      int cutWidth = Integer.MAX_VALUE;
      int firstIndentedLine = 0;
index a7c2d8eb5ba1d4bc98b09ac9a42af576e6b3fb06,c5e17bb0613baca37fb344c7b0a4f840978c82a8..4ee90b7aad7d016bb19d9cd8267cdcb06f958f9c
@@@ -20,10 -21,8 +20,9 @@@ import com.intellij.lang.documentation.
  import com.intellij.lang.documentation.ExternalDocumentationProvider;
  import com.intellij.openapi.application.ApplicationManager;
  import com.intellij.openapi.application.ModalityState;
+ import com.intellij.openapi.editor.Document;
 +import com.intellij.openapi.editor.Editor;
  import com.intellij.openapi.extensions.Extensions;
- import com.intellij.openapi.module.Module;
- import com.intellij.openapi.module.ModuleUtilCore;
  import com.intellij.openapi.project.Project;
  import com.intellij.openapi.projectRoots.Sdk;
  import com.intellij.openapi.roots.ProjectRootManager;
@@@ -35,13 -34,9 +34,11 @@@ import com.intellij.psi.util.PsiTreeUti
  import com.intellij.psi.util.QualifiedName;
  import com.intellij.util.Function;
  import com.jetbrains.python.PyNames;
 +import com.jetbrains.python.PythonDialectsTokenSetProvider;
 +import com.jetbrains.python.codeInsight.PyCodeInsightSettings;
  import com.jetbrains.python.console.PydevConsoleRunner;
  import com.jetbrains.python.console.PydevDocumentationProvider;
- import com.jetbrains.python.debugger.PySignature;
- import com.jetbrains.python.debugger.PySignatureCacheManager;
- import com.jetbrains.python.debugger.PySignatureUtil;
+ import com.jetbrains.python.documentation.docstrings.DocStringUtil;
  import com.jetbrains.python.psi.*;
  import com.jetbrains.python.psi.impl.PyBuiltinCache;
  import com.jetbrains.python.psi.resolve.QualifiedNameFinder;
@@@ -320,8 -314,30 +316,8 @@@ public class PythonDocumentationProvide
      return new PyDocumentationBuilder(element, originalElement).build();
    }
  
 -  @Nullable
 -  private static PsiElement findRealOriginalElement(@Nullable PsiElement element) {
 -    if (element == null) {
 -      return null;
 -    }
 -    final PsiFile file = element.getContainingFile();
 -    if (file == null) {
 -      return element;
 -    }
 -    final Document document = PsiDocumentManager.getInstance(element.getProject()).getDocument(file);
 -    if (document == null) {
 -      return element;
 -    }
 -    final int newOffset = TargetElementUtil.adjustOffset(file, document, element.getTextOffset());
 -    final PsiElement newElement = file.findElementAt(newOffset);
 -    return newElement != null ? newElement : element;
 -  }
 -
    @Override
-   public PsiElement getDocumentationElementForLink(PsiManager psiManager, String link, PsiElement context) {
+   public PsiElement getDocumentationElementForLink(PsiManager psiManager, @NotNull String link, @NotNull PsiElement context) {
      if (link.equals(LINK_TYPE_CLASS)) {
        return inferContainingClassOf(context);
      }
index 8be9348542560f666601a71d4d43ff0845464931,1ea473310d3aeafa6092ec5df8d9a28172067270..d6f37cc5bff84eb3e2c667d25dd06d23888175f8
@@@ -41,10 -36,9 +36,10 @@@ public class PyFunctionBuilder 
    private final List<String> myStatements = new ArrayList<String>();
    private final List<String> myDecorators = new ArrayList<String>();
    private String myAnnotation = null;
-   private String[] myDocStringLines = null;
    @NotNull
    private final Map<String, String> myDecoratorValues = new HashMap<String, String>();
 +  private boolean myAsync = false;
+   private PyDocstringGenerator myDocStringGenerator = PyDocstringGenerator.create(DocStringFormat.REST, "    ");
  
    /**
     * Creates builder copying signature and doc from another one.
index bb8387789260504ab7a5b487a2c14a9b0aee68c7,cdf338ee18cf837133fd1db14f1c81fd183fee38..a88555bff68eb3426a98ef1808e0ad6e93b5a174
@@@ -41,9 -41,8 +41,9 @@@ import com.jetbrains.python.PyTokenType
  import com.jetbrains.python.codeInsight.controlflow.ControlFlowCache;
  import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
  import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
- import com.jetbrains.python.documentation.DocStringUtil;
+ import com.jetbrains.python.documentation.docstrings.DocStringUtil;
  import com.jetbrains.python.psi.*;
 +import com.jetbrains.python.psi.resolve.PyResolveContext;
  import com.jetbrains.python.psi.resolve.QualifiedNameFinder;
  import com.jetbrains.python.psi.stubs.PyClassStub;
  import com.jetbrains.python.psi.stubs.PyFunctionStub;
index edea7b565a85e0749824e7f9921d675a3dbfea08,af608115f70b4eb73cdcbacb79de28062c65fe5e..2f67013327cd2aa8887fd9d0a71bf04f14ff7950
@@@ -1,2 -1,4 +1,4 @@@
  def ones(shape, dtype=None, order='C')
- Inferred type: (shape:&nbsp;Union[<a href="psi_element://#typename#int">int</a>,&nbsp;Iterable[<a href="psi_element://#typename#int">int</a>]],&nbsp;dtype:&nbsp;Optional[<a href="psi_element://#typename#object">object</a>],&nbsp;order:&nbsp;Optional[<a href="psi_element://#typename#str">str</a>])&nbsp;-&gt;&nbsp;ndarray<br>
 -Inferred type: (shape:&nbsp;Union[<a href="psi_element://#typename#int">int</a>,&nbsp;Iterable[<a href="psi_element://#typename#int">int</a>]],&nbsp;dtype:&nbsp;<a href="psi_element://#typename#object">object</a>,&nbsp;order:&nbsp;<a href="psi_element://#typename#str">str</a>)&nbsp;-&gt;&nbsp;ndarray<br>
++Inferred type: (shape:&nbsp;Union[<a href="psi_element://#typename#int">int</a>,&nbsp;Iterable[<a href="psi_element://#typename#int">int</a>]],&nbsp;dtype:&nbsp;Optional[<a href="psi_element://#typename#object">object</a>],&nbsp;order:&nbsp;Optional[<a href="psi_element://#typename#str">str</a>])&nbsp;-&gt;&nbsp;ndarray<br>
+ **Test docstring**
+ Return a new array of given shape and type, filled with ones.
index aaf94453e78cc76a8d07c3819581f9a1196ddf47,aaf94453e78cc76a8d07c3819581f9a1196ddf47..70ea8554e628ecb9336d29c4f24f9c01e7fdeace
@@@ -1,6 -1,6 +1,3 @@@
--__author__ = 'user1'
--
--
  def f(url):
      '''Return the representation available at the URL.
  
index 8fc2d8b2eca90976796949d661f75cb91e2a0f8a,99293512d117b4b8b4b3c95a34b226006128bd02..eebdd4e3262f6a288882d0f9a43ed26ffaacc7e2
@@@ -148,17 -147,28 +147,24 @@@ public class PythonInspectionsTest exte
      doTest(getTestName(false), inspection);
    }
  
-   public void testPyDocstringParametersInspection() {     //PY-3373
-     PyDocumentationSettings documentationSettings = PyDocumentationSettings.getInstance(myFixture.getModule());
-     documentationSettings.setFormat(DocStringFormat.EPYTEXT);
-     try {
-       doHighlightingTest(PyDocstringInspection.class, LanguageLevel.PYTHON33);
-     }
-     finally {
-       documentationSettings.setFormat(DocStringFormat.PLAIN);
-     }
+   //PY-3373
+   public void testPyDocstringParametersInspection() {     
+     runWithDocStringFormat(DocStringFormat.EPYTEXT, new Runnable() {
+       public void run() {
+         doHighlightingTest(PyDocstringInspection.class, LanguageLevel.PYTHON33);
+       }
+     });
+   }
+   
+   // PY-9795
+   public void testGoogleDocstringParametersInspection() {     
+     runWithDocStringFormat(DocStringFormat.GOOGLE, new Runnable() {
+       public void run() {
+         doHighlightingTest(PyDocstringInspection.class, LanguageLevel.PYTHON33);
+       }
+     });
    }
  
 -  public void testPyStatementEffectInspection() {
 -    doHighlightingTest(PyStatementEffectInspection.class, LanguageLevel.PYTHON26);
 -  }
 -
    public void testPySimplifyBooleanCheckInspection() {
      doHighlightingTest(PySimplifyBooleanCheckInspection.class, LanguageLevel.PYTHON26);
    }