PY-16765 For sections inside Google code style docstring use indentation configured...
authorMikhail Golubev <mikhail.golubev@jetbrains.com>
Mon, 21 Sep 2015 12:16:10 +0000 (15:16 +0300)
committerMikhail Golubev <mikhail.golubev@jetbrains.com>
Wed, 23 Sep 2015 15:42:17 +0000 (18:42 +0300)
PyFunctionBuilder and PyDocstringGenerator require a PSI element to
use proper formatting and style for generated docstring.

51 files changed:
python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/GoogleDocStringSectionFixer.java
python/src/com/jetbrains/python/codeInsight/intentions/PyConvertLambdaToFunctionIntention.java
python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java
python/src/com/jetbrains/python/documentation/docstrings/GoogleCodeStyleDocStringBuilder.java
python/src/com/jetbrains/python/documentation/docstrings/GoogleCodeStyleDocStringUpdater.java
python/src/com/jetbrains/python/documentation/docstrings/NumpyDocStringUpdater.java
python/src/com/jetbrains/python/documentation/docstrings/PyDocstringGenerator.java
python/src/com/jetbrains/python/documentation/docstrings/SectionBasedDocStringUpdater.java
python/src/com/jetbrains/python/editor/PythonEnterHandler.java
python/src/com/jetbrains/python/inspections/quickfix/AddFunctionQuickFix.java
python/src/com/jetbrains/python/inspections/quickfix/AddMethodQuickFix.java
python/src/com/jetbrains/python/inspections/quickfix/UnresolvedRefCreateFunctionQuickFix.java
python/src/com/jetbrains/python/psi/PyIndentUtil.java
python/src/com/jetbrains/python/psi/impl/PyFunctionBuilder.java
python/src/com/jetbrains/python/refactoring/classes/membersManager/InstanceFieldsManager.java
python/src/com/jetbrains/python/refactoring/extractmethod/PyExtractMethodUtil.java
python/src/com/jetbrains/python/refactoring/introduce/field/PyIntroduceFieldHandler.java
python/testData/codeInsight/smartEnter/googleDocStringColonAndIndentAfterSection_after.py
python/testData/codeInsight/smartEnter/googleDocStringIndentAfterSectionCustomIndent.py [new file with mode: 0644]
python/testData/codeInsight/smartEnter/googleDocStringIndentAfterSectionCustomIndent_after.py [new file with mode: 0644]
python/testData/codeInsight/smartEnter/googleDocStringIndentAfterSection_after.py
python/testData/editing/sectionIndentInsideGoogleDocString.after.py
python/testData/editing/sectionIndentInsideGoogleDocStringCustomIndent.after.py [new file with mode: 0644]
python/testData/editing/sectionIndentInsideGoogleDocStringCustomIndent.py [new file with mode: 0644]
python/testData/inspections/GoogleDocStringAddKeywordVararg_after.py
python/testData/inspections/GoogleDocStringAddParam_after.py
python/testData/inspections/GoogleDocStringAddPositionalVararg_after.py
python/testData/intentions/afterAddMissingParamsInGoogleDocStringEmptyParamSection.py
python/testData/intentions/afterAddMissingParamsInGoogleDocStringEmptyParamSectionCustomCodeIndent.py [new file with mode: 0644]
python/testData/intentions/afterAddMissingParamsInGoogleDocStringNoParamSection.py
python/testData/intentions/afterAddMissingParamsInGoogleDocStringNoParamSectionCustomCodeIndent.py [new file with mode: 0644]
python/testData/intentions/afterGoogleDocStubCustomIndent.py [new file with mode: 0644]
python/testData/intentions/afterGoogleDocStubEmptyFunctionBody.py
python/testData/intentions/afterGoogleDocStubInlineFunctionBody.py
python/testData/intentions/afterGoogleDocStubInlineFunctionBodyMultilineParametersList.py
python/testData/intentions/afterGoogleDocStubInlineFunctionBodyNoSpaceBefore.py
python/testData/intentions/afterGoogleDocStubWithTypes.py
python/testData/intentions/afterParamTypeInEmptyGoogleDocString.py
python/testData/intentions/afterParamTypeInGoogleDocStringEmptyParamSection.py
python/testData/intentions/afterParamTypeInGoogleDocStringOnlySummary.py
python/testData/intentions/afterParamTypeInGoogleDocStringOnlySummaryOneLine.py
python/testData/intentions/afterParamTypeInNewGoogleDocString.py
python/testData/intentions/afterReturnTypeInEmptyGoogleDocString.py
python/testData/intentions/afterReturnTypeInGoogleDocStringEmptyReturnSection.py
python/testData/intentions/afterReturnTypeInNewGoogleDocString.py
python/testData/intentions/beforeAddMissingParamsInGoogleDocStringEmptyParamSectionCustomCodeIndent.py [new file with mode: 0644]
python/testData/intentions/beforeAddMissingParamsInGoogleDocStringNoParamSectionCustomCodeIndent.py [new file with mode: 0644]
python/testData/intentions/beforeGoogleDocStubCustomIndent.py [new file with mode: 0644]
python/testSrc/com/jetbrains/python/PyEditingTest.java
python/testSrc/com/jetbrains/python/PySmartEnterTest.java
python/testSrc/com/jetbrains/python/intentions/PyIntentionTest.java

index 6974ae8a13cd052290a2b2204c61195be3020edb..e72de9f39effd2397c7ba15ef1593ef94ab2c700 100644 (file)
@@ -56,7 +56,7 @@ public class GoogleDocStringSectionFixer extends PyFixer<PyStringLiteralExpressi
       if (SectionBasedDocString.isValidSectionTitle(header)) {
         final String patch = (trimmedLine.endsWith(":") ? "\n" : ":\n") +
                              PyIndentUtil.getLineIndent(line) +
-                             GoogleCodeStyleDocStringBuilder.DEFAULT_SECTION_INDENT;
+                             GoogleCodeStyleDocStringBuilder.getDefaultSectionIndent(pyString.getProject());
         final int insertionOffset = lineStart + StringUtil.trimTrailing(line).length();
         document.replaceString(insertionOffset, lineEnd, patch);
         processor.registerUnresolvedError(insertionOffset + patch.length());
index 7cf910dc80f54a6939c389a91a2229f08222b638..5c768169f5a52ed09de5b291537cc74c0e8224d4 100644 (file)
@@ -87,7 +87,7 @@ public class PyConvertLambdaToFunctionIntention extends BaseIntentionAction {
 
       if (name.isEmpty()) return;
       PyExpression body = lambdaExpression.getBody();
-      PyFunctionBuilder functionBuilder = new PyFunctionBuilder(name);
+      PyFunctionBuilder functionBuilder = new PyFunctionBuilder(name, lambdaExpression);
       for (PyParameter param : lambdaExpression.getParameterList().getParameters()) {
         functionBuilder.parameter(param.getText());
       }
index 6d85d760207d113b5dddc9ff8629580beaef51ba..10dfe9ed464ea6d8edb84b09b6dcf0b1e4fa6ca5 100644 (file)
@@ -40,7 +40,10 @@ import com.jetbrains.python.PyNames;
 import com.jetbrains.python.psi.*;
 import com.jetbrains.python.psi.impl.PyFunctionBuilder;
 import com.jetbrains.python.psi.impl.PyPsiUtils;
-import com.jetbrains.python.psi.types.*;
+import com.jetbrains.python.psi.types.PyClassLikeType;
+import com.jetbrains.python.psi.types.PyClassLikeTypeUtil;
+import com.jetbrains.python.psi.types.PyNoneType;
+import com.jetbrains.python.psi.types.TypeEvalContext;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -189,7 +192,7 @@ public class PyOverrideImplementUtil {
 
   private static PyFunctionBuilder buildOverriddenFunction(PyClass pyClass, PyFunction baseFunction, boolean implement) {
     final boolean overridingNew = PyNames.NEW.equals(baseFunction.getName());
-    PyFunctionBuilder pyFunctionBuilder = new PyFunctionBuilder(baseFunction.getName());
+    PyFunctionBuilder pyFunctionBuilder = new PyFunctionBuilder(baseFunction.getName(), baseFunction);
     final PyDecoratorList decorators = baseFunction.getDecoratorList();
     boolean baseMethodIsStatic = false;
     if (decorators != null) {
index 23e007ec86c45eccdb59f6309af14be8fd83d170..30369f933377319f24395d50bf999dc7c7ce6403 100644 (file)
@@ -15,7 +15,9 @@
  */
 package com.jetbrains.python.documentation.docstrings;
 
+import com.intellij.openapi.project.Project;
 import com.intellij.openapi.util.text.StringUtil;
+import com.jetbrains.python.psi.PyIndentUtil;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -23,12 +25,20 @@ import org.jetbrains.annotations.Nullable;
  * @author Mikhail Golubev
  */
 public class GoogleCodeStyleDocStringBuilder extends SectionBasedDocStringBuilder {
-  public static final String DEFAULT_SECTION_INDENT = "  ";
-  public static final String DEFAULT_CONTINUATION_INDENT = "  ";
+  public static final String DEFAULT_CONTINUATION_INDENT = PyIndentUtil.FOUR_SPACES;
 
-  public GoogleCodeStyleDocStringBuilder() {
-    // Two spaces according to Google Code Style
-    super(DEFAULT_SECTION_INDENT, DEFAULT_CONTINUATION_INDENT);
+  @NotNull
+  public static String getDefaultSectionIndent(@NotNull Project project) {
+    return PyIndentUtil.getIndentFromSettings(project);
+  }
+
+  @NotNull
+  public static GoogleCodeStyleDocStringBuilder forProject(@NotNull Project project) {
+    return new GoogleCodeStyleDocStringBuilder(getDefaultSectionIndent(project)); 
+  }
+
+  public GoogleCodeStyleDocStringBuilder(@NotNull String sectionIndent) {
+    super(sectionIndent, DEFAULT_CONTINUATION_INDENT);
   }
 
   @Override
index 390b1b01a299c4e33ca0db17f28e36484e193721..287417e5fda5c1aa37f3b815a4a55347b20a5b3d 100644 (file)
@@ -15,6 +15,7 @@
  */
 package com.jetbrains.python.documentation.docstrings;
 
+import com.intellij.openapi.project.Project;
 import com.jetbrains.python.toolbox.Substring;
 import org.jetbrains.annotations.NotNull;
 
@@ -22,8 +23,19 @@ import org.jetbrains.annotations.NotNull;
  * @author Mikhail Golubev
  */
 public class GoogleCodeStyleDocStringUpdater extends SectionBasedDocStringUpdater {
-  public GoogleCodeStyleDocStringUpdater(@NotNull SectionBasedDocString docString, @NotNull String minContentIndent) {
+  private final String myFallbackSectionIndent;
+
+  public static GoogleCodeStyleDocStringUpdater forProject(@NotNull GoogleCodeStyleDocString docString,
+                                                           @NotNull String minContentIndent,
+                                                           @NotNull Project project) {
+    return new GoogleCodeStyleDocStringUpdater(docString, minContentIndent, GoogleCodeStyleDocStringBuilder.getDefaultSectionIndent(project));
+  }
+
+  public GoogleCodeStyleDocStringUpdater(@NotNull GoogleCodeStyleDocString docString,
+                                         @NotNull String minContentIndent,
+                                         @NotNull String fallbackSectionIndent) {
     super(docString, minContentIndent);
+    myFallbackSectionIndent = fallbackSectionIndent;
   }
 
   @Override
@@ -31,8 +43,9 @@ public class GoogleCodeStyleDocStringUpdater extends SectionBasedDocStringUpdate
     insert(nameSubstring.getEndOffset(), " (" + type + ")");
   }
 
+  @NotNull
   @Override
   protected SectionBasedDocStringBuilder createBuilder() {
-    return new GoogleCodeStyleDocStringBuilder();
+    return new GoogleCodeStyleDocStringBuilder(myFallbackSectionIndent);
   }
 }
index b75d3f3f471c81fa98210412ab2aea3422ebbab9..966b89967d7f140fede292fd3c7916fa0fdc9184 100644 (file)
@@ -38,6 +38,7 @@ public class NumpyDocStringUpdater extends SectionBasedDocStringUpdater {
     return getSectionStartLine(section) + 1;
   }
 
+  @NotNull
   @Override
   protected SectionBasedDocStringBuilder createBuilder() {
     return new NumpyDocStringBuilder();
index 9f32cd3091ca692474ac8f90af62e460e6233096..b319b1b775d999320c8fc99995d3196f27f95fea 100644 (file)
@@ -60,11 +60,11 @@ public class PyDocstringGenerator {
   private final List<DocstringParam> myAddedParams = Lists.newArrayList();
   private final List<DocstringParam> myRemovedParams = Lists.newArrayList();
   private final String myDocStringText;
-
   // Updated after buildAndInsert()
   @Nullable private PyDocStringOwner myDocStringOwner;
-  private String myDocStringIndent;
-  private DocStringFormat myDocStringFormat;
+  private final String myDocStringIndent;
+  private final DocStringFormat myDocStringFormat;
+  private final PsiElement mySettingsAnchor;
 
   private boolean myUseTypesFromDebuggerSignature = true;
   private boolean myNewMode = false; // true - generate new string, false - update existing
@@ -75,12 +75,14 @@ public class PyDocstringGenerator {
   private PyDocstringGenerator(@Nullable PyDocStringOwner docStringOwner,
                                @Nullable String docStringText,
                                @NotNull DocStringFormat format,
-                               @NotNull String indentation) {
+                               @NotNull String indentation,
+                               @NotNull PsiElement settingsAnchor) {
     myDocStringOwner = docStringOwner;
     myDocStringIndent = indentation;
     myDocStringFormat = format;
     myDocStringText = docStringText;
     myNewMode = myDocStringText == null;
+    mySettingsAnchor = settingsAnchor;
   }
 
   @NotNull
@@ -90,26 +92,28 @@ public class PyDocstringGenerator {
       indentation = PyIndentUtil.getElementIndent(((PyStatementListContainer)owner).getStatementList());
     }
     final String docStringText = owner.getDocStringExpression() == null ? null : owner.getDocStringExpression().getText();
-    return new PyDocstringGenerator(owner, docStringText, DocStringUtil.getConfiguredDocStringFormat(owner), indentation);
+    return new PyDocstringGenerator(owner, docStringText, DocStringUtil.getConfiguredDocStringFormat(owner), indentation, owner);
   }
   
   @NotNull
-  public static PyDocstringGenerator create(@NotNull DocStringFormat format, @NotNull String indentation) {
-    return new PyDocstringGenerator(null, null, format, indentation);
+  public static PyDocstringGenerator create(@NotNull DocStringFormat format, @NotNull String indentation, @NotNull PsiElement settingsAnchor) {
+    return new PyDocstringGenerator(null, null, format, indentation, settingsAnchor);
   }
 
   @NotNull
   public static PyDocstringGenerator update(@NotNull PyStringLiteralExpression docString) {
     return new PyDocstringGenerator(PsiTreeUtil.getParentOfType(docString, PyDocStringOwner.class),
-                                    docString.getText(), DocStringUtil.getConfiguredDocStringFormat(docString),
-                                    PyIndentUtil.getElementIndent(docString));
+                                    docString.getText(), 
+                                    DocStringUtil.getConfiguredDocStringFormat(docString),
+                                    PyIndentUtil.getElementIndent(docString), 
+                                    docString);
   }
 
   @NotNull
   public static PyDocstringGenerator update(@NotNull DocStringFormat format,
                                             @NotNull String indentation,
-                                            @NotNull String text) {
-    return new PyDocstringGenerator(null, text, format, indentation);
+                                            @NotNull String text, PsiElement settingsAnchor) {
+    return new PyDocstringGenerator(null, text, format, indentation, settingsAnchor);
   }
 
   @NotNull
@@ -208,19 +212,11 @@ public class PyDocstringGenerator {
     return myDocStringIndent;
   }
 
-  public void setDocStringFormat(@NotNull DocStringFormat format) {
-    myDocStringFormat = format;
-  }
-
   @NotNull
   public DocStringFormat getDocStringFormat() {
     return myDocStringFormat;
   }
 
-  public void setDocStringIndent(@NotNull String docStringIndent) {
-    myDocStringIndent = docStringIndent;
-  }
-
   public boolean isNewMode() {
     return myNewMode;
   }
@@ -412,7 +408,7 @@ public class PyDocstringGenerator {
       }
     }
     else if (myDocStringFormat == DocStringFormat.GOOGLE || myDocStringFormat == DocStringFormat.NUMPY) {
-      builder = myDocStringFormat == DocStringFormat.GOOGLE ? new GoogleCodeStyleDocStringBuilder() : new NumpyDocStringBuilder();
+      builder = myDocStringFormat == DocStringFormat.GOOGLE ? GoogleCodeStyleDocStringBuilder.forProject(mySettingsAnchor.getProject()) : new NumpyDocStringBuilder();
       final SectionBasedDocStringBuilder sectionBuilder = (SectionBasedDocStringBuilder)builder;
       if (myAddFirstEmptyLine) {
         sectionBuilder.addEmptyLine();
@@ -467,7 +463,9 @@ public class PyDocstringGenerator {
     }
     else if (myDocStringFormat == DocStringFormat.GOOGLE) {
       //noinspection ConstantConditions
-      updater = new GoogleCodeStyleDocStringUpdater((SectionBasedDocString)getStructuredDocString(), myDocStringIndent);
+      updater = GoogleCodeStyleDocStringUpdater.forProject((GoogleCodeStyleDocString)getStructuredDocString(), 
+                                                           myDocStringIndent, 
+                                                           mySettingsAnchor.getProject());
     }
     else if (myDocStringFormat == DocStringFormat.NUMPY) {
       //noinspection ConstantConditions
index 7216492f08cb3099cb41f6410bba2e847984cdc1..69bbf2b9296c1b304a367bb5e6ad604b1b6d38c7 100644 (file)
@@ -274,6 +274,7 @@ public abstract class SectionBasedDocStringUpdater extends DocStringUpdater<Sect
 
   protected abstract void updateParamDeclarationWithType(@NotNull Substring nameSubstring, @NotNull String type);
 
+  @NotNull
   protected abstract SectionBasedDocStringBuilder createBuilder();
 
   @Nullable
index 8d6f8315d1d3cc3804174cdfb60d4534fff6f38e..f4184c6ae65c07d0fb48c2c449d59903a3b38108 100644 (file)
@@ -371,7 +371,7 @@ public class PythonEnterHandler extends EnterHandlerDelegateAdapter {
           final TextRange lineRange = TextRange.create(document.getLineStartOffset(lineNum - 1), document.getLineEndOffset(lineNum - 1));
           final Matcher matcher = GoogleCodeStyleDocString.SECTION_HEADER.matcher(document.getText(lineRange));
           if (matcher.matches() && SectionBasedDocString.isValidSectionTitle(matcher.group(1))) {
-            document.insertString(offset, GoogleCodeStyleDocStringBuilder.DEFAULT_SECTION_INDENT);
+            document.insertString(offset, GoogleCodeStyleDocStringBuilder.getDefaultSectionIndent(file.getProject()));
             editor.getCaretModel().moveCaretRelatively(2, 0, false, false, false);
           }
         }
index 3efa2eb12e2de7f1bac9587553b882ad1d9a2702..60b4890e4f304f3880f3e6e0efe3baee54d8022f 100644 (file)
@@ -85,7 +85,7 @@ public class AddFunctionQuickFix  implements LocalQuickFix {
       sure(FileModificationService.getInstance().preparePsiElementForWrite(file));
       // try to at least match parameter count
       // TODO: get parameter style from code style
-      PyFunctionBuilder builder = new PyFunctionBuilder(myIdentifier);
+      PyFunctionBuilder builder = new PyFunctionBuilder(myIdentifier, problemElement);
       PsiElement problemParent = problemElement.getParent();
       if (problemParent instanceof PyCallExpression) {
         PyArgumentList arglist = ((PyCallExpression)problemParent).getArgumentList();
index 37883dd5feba539c2edafa909c4aa099a1a98175..a560d2002d06db2938d0987d3b51c82a12059722 100644 (file)
@@ -84,7 +84,7 @@ public class AddMethodQuickFix implements LocalQuickFix {
       sure(FileModificationService.getInstance().preparePsiElementForWrite(clsStmtList));
       // try to at least match parameter count
       // TODO: get parameter style from code style
-      PyFunctionBuilder builder = new PyFunctionBuilder(myIdentifier);
+      PyFunctionBuilder builder = new PyFunctionBuilder(myIdentifier, cls);
       PsiElement pe = problemElement.getParent();
       String decoratorName = null; // set to non-null to add a decorator
       PyExpression[] args = new PyExpression[0];
index ae73e49d84eb07beca241ce889264c97037b23ed..33a2bd13765b0a407e06e2eb552a34b25c1bcc99 100644 (file)
@@ -58,7 +58,7 @@ public class UnresolvedRefCreateFunctionQuickFix implements LocalQuickFix {
   public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
     if (!myElement.isValid() || !FileModificationService.getInstance().preparePsiElementForWrite(myElement)) return;
 
-    PyFunctionBuilder functionBuilder = new PyFunctionBuilder(myReference.getText());
+    PyFunctionBuilder functionBuilder = new PyFunctionBuilder(myReference.getText(), myElement);
 
     // if function is actually an argument of a call, don't use other arguments of the call to create parameter list of new function
     final PyArgumentList argumentList = myElement.getArgumentList();
index 8f5d337530d542a9e98a79561cd01dbfdc48b765..c168e3773194f39cad8f47094ad25701d65cf5bb 100644 (file)
@@ -28,6 +28,7 @@ import com.intellij.psi.util.PsiTreeUtil;
 import com.intellij.util.Function;
 import com.intellij.util.containers.ContainerUtil;
 import com.jetbrains.python.PythonFileType;
+import org.jetbrains.annotations.NonNls;
 import org.jetbrains.annotations.NotNull;
 
 import java.util.Collections;
@@ -37,6 +38,9 @@ import java.util.List;
  * @author Mikhail Golubev
  */
 public class PyIndentUtil {
+  @NonNls public static final String TWO_SPACES = "  ";
+  @NonNls public static final String FOUR_SPACES = "    ";
+
   private PyIndentUtil() {
   }
 
index d6f37cc5bff84eb3e2c667d25dd06d23888175f8..344185608f505ab539bf6ca2af313a5e5ef797d6 100644 (file)
@@ -20,7 +20,7 @@ import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.psi.PsiElement;
 import com.intellij.util.ArrayUtil;
 import com.jetbrains.python.PyNames;
-import com.jetbrains.python.documentation.docstrings.DocStringFormat;
+import com.jetbrains.python.documentation.docstrings.DocStringUtil;
 import com.jetbrains.python.documentation.docstrings.PyDocstringGenerator;
 import com.jetbrains.python.psi.*;
 import org.jetbrains.annotations.NotNull;
@@ -39,7 +39,7 @@ public class PyFunctionBuilder {
   @NotNull
   private final Map<String, String> myDecoratorValues = new HashMap<String, String>();
   private boolean myAsync = false;
-  private PyDocstringGenerator myDocStringGenerator = PyDocstringGenerator.create(DocStringFormat.REST, "    ");
+  private PyDocstringGenerator myDocStringGenerator;
 
   /**
    * Creates builder copying signature and doc from another one.
@@ -51,7 +51,7 @@ public class PyFunctionBuilder {
   @NotNull
   public static PyFunctionBuilder copySignature(@NotNull final PyFunction source, @NotNull final String... decoratorsToCopyIfExist) {
     final String name = source.getName();
-    final PyFunctionBuilder functionBuilder = new PyFunctionBuilder((name != null) ? name : "");
+    final PyFunctionBuilder functionBuilder = new PyFunctionBuilder((name != null) ? name : "", source);
     for (final PyParameter parameter : source.getParameterList().getParameters()) {
       final String parameterName = parameter.getName();
       if (parameterName != null) {
@@ -73,22 +73,22 @@ public class PyFunctionBuilder {
     return functionBuilder;
   }
 
-  public PyFunctionBuilder(@NotNull String name) {
+  public PyFunctionBuilder(@NotNull String name, @NotNull PsiElement settingsAnchor) {
     myName = name;
+    myDocStringGenerator = PyDocstringGenerator.create(DocStringUtil.getConfiguredDocStringFormat(settingsAnchor), 
+                                                       PyIndentUtil.getIndentFromSettings(settingsAnchor.getProject()), 
+                                                       settingsAnchor);
   }
 
   /**
    * Adds param and its type to doc
+   * @param format what docstyle to use to doc param type
    * @param name param name
    * @param type param type
-   * @param format what docstyle to use to doc param type
    */
   @NotNull
-  public PyFunctionBuilder parameterWithType(@NotNull final String name,
-                                             @NotNull final String type,
-                                             @NotNull final DocStringFormat format) {
+  public PyFunctionBuilder parameterWithType(@NotNull String name, @NotNull String type) {
     parameter(name);
-    myDocStringGenerator.setDocStringFormat(format);
     myDocStringGenerator.withParamTypedByName(name, type);
     return this;
   }
@@ -158,7 +158,6 @@ public class PyFunctionBuilder {
     List<String> statements = myStatements.isEmpty() ? Collections.singletonList(PyNames.PASS) : myStatements;
 
     final String indent = PyIndentUtil.getIndentFromSettings(project);
-    myDocStringGenerator.setDocStringIndent(indent);
     // There was original docstring or some parameters were added via parameterWithType()
     if (!myDocStringGenerator.isNewMode() || myDocStringGenerator.hasParametersToAdd()) {
       final String docstring = PyIndentUtil.changeIndent(myDocStringGenerator.buildDocString(), true, indent);
index 0ca143d6eb913cd6335f57060f817898e9b750d7..26cefef51cc02449a41d5e6989bc40f50db0f808 100644 (file)
@@ -93,7 +93,7 @@ class InstanceFieldsManager extends FieldsManager {
   //TODO: Move to utils?
   @NotNull
   private static PyFunction createInitMethod(@NotNull final PyClass to) {
-    final PyFunctionBuilder functionBuilder = new PyFunctionBuilder(PyNames.INIT);
+    final PyFunctionBuilder functionBuilder = new PyFunctionBuilder(PyNames.INIT, to);
     functionBuilder.parameter(PyNames.CANONICAL_SELF); //TODO: Take param from codestyle?
     final PyFunction function = functionBuilder.buildFunction(to.getProject(), LanguageLevel.forElement(to));
     return PyClassRefactoringUtil.addMethods(to, true, function).get(0);
index 23b4243aee7d656b953776abeed0109d12bc6c30..b0ffe97eec0bedffad0b568885b4c5a19d8352f4 100644 (file)
@@ -455,7 +455,7 @@ public class PyExtractMethodUtil {
       }
     }
     // Change signature according to pass settings and
-    final PyFunctionBuilder builder = new PyFunctionBuilder("foo");
+    final PyFunctionBuilder builder = new PyFunctionBuilder("foo", generatedMethod);
     if (isClassMethod) {
       builder.parameter("cls");
     }
@@ -517,7 +517,7 @@ public class PyExtractMethodUtil {
                                                          @NotNull final AbstractVariableData[] variableData,
                                                          @NotNull final PsiElement expression,
                                                          @Nullable final PyUtil.MethodFlags flags, boolean isAsync) {
-    final PyFunctionBuilder builder = new PyFunctionBuilder(methodName);
+    final PyFunctionBuilder builder = new PyFunctionBuilder(methodName, expression);
     addDecorators(builder, flags);
     addFakeParameters(builder, variableData);
     if (isAsync) {
@@ -543,7 +543,7 @@ public class PyExtractMethodUtil {
                                                        boolean isAsync) {
     assert !elementsRange.isEmpty() : "Empty statements list was selected!";
 
-    final PyFunctionBuilder builder = new PyFunctionBuilder(methodName);
+    final PyFunctionBuilder builder = new PyFunctionBuilder(methodName, elementsRange.get(0));
     if (isAsync) {
       builder.makeAsync();
     }
index 26e009d7c5dfa3b6061ddcc196086a65c1e415f0..a3e579d9e268be2cf6e8f93418073f9e20dee460 100644 (file)
@@ -187,7 +187,7 @@ public class PyIntroduceFieldHandler extends IntroduceHandler {
     if (init != null) {
       return AddFieldQuickFix.appendToMethod(init, callback);
     }
-    final PyFunctionBuilder builder = new PyFunctionBuilder(PythonUnitTestUtil.TESTCASE_SETUP_NAME);
+    final PyFunctionBuilder builder = new PyFunctionBuilder(PythonUnitTestUtil.TESTCASE_SETUP_NAME, clazz);
     builder.parameter(PyNames.CANONICAL_SELF);
     PyFunction setUp = builder.buildFunction(clazz.getProject(), LanguageLevel.getDefault());
     final PyStatementList statements = clazz.getStatementList();
index c03317d64030c0db776c0d8d6ce06f2c07c21fbc..76d66ad6c23dc365d366d527e2de57008b8d5031 100644 (file)
@@ -1,5 +1,5 @@
 def func():
     """
     Args:
-      <caret>  
+        <caret>  
     """
\ No newline at end of file
diff --git a/python/testData/codeInsight/smartEnter/googleDocStringIndentAfterSectionCustomIndent.py b/python/testData/codeInsight/smartEnter/googleDocStringIndentAfterSectionCustomIndent.py
new file mode 100644 (file)
index 0000000..49e6c16
--- /dev/null
@@ -0,0 +1,4 @@
+def f():
+    """
+    Raises:<caret>
+    """
\ No newline at end of file
diff --git a/python/testData/codeInsight/smartEnter/googleDocStringIndentAfterSectionCustomIndent_after.py b/python/testData/codeInsight/smartEnter/googleDocStringIndentAfterSectionCustomIndent_after.py
new file mode 100644 (file)
index 0000000..cb37058
--- /dev/null
@@ -0,0 +1,5 @@
+def f():
+    """
+    Raises:
+      <caret>
+    """
\ No newline at end of file
index cb370585781cfd0c0759caef11625dcf23187d55..a7a684b4d95365bca15b9ea47cf13b35db11a46b 100644 (file)
@@ -1,5 +1,5 @@
 def f():
     """
     Raises:
-      <caret>
+        <caret>
     """
\ No newline at end of file
index 2d6842087f9e38be608a861116600456973f43da..234f7967875a6606958f99375df1e17d1ba1dd03 100644 (file)
@@ -1,5 +1,5 @@
 def f(param):
     """
     Args:
-      param
+        param
     """
\ No newline at end of file
diff --git a/python/testData/editing/sectionIndentInsideGoogleDocStringCustomIndent.after.py b/python/testData/editing/sectionIndentInsideGoogleDocStringCustomIndent.after.py
new file mode 100644 (file)
index 0000000..0eacef0
--- /dev/null
@@ -0,0 +1,5 @@
+def f(param):
+    """
+    Args:
+      param<caret>
+    """
\ No newline at end of file
diff --git a/python/testData/editing/sectionIndentInsideGoogleDocStringCustomIndent.py b/python/testData/editing/sectionIndentInsideGoogleDocStringCustomIndent.py
new file mode 100644 (file)
index 0000000..f7b48b4
--- /dev/null
@@ -0,0 +1,4 @@
+def f(param):
+    """
+    Args:<caret>
+    """
\ No newline at end of file
index d9e705879c76afe57b7c704347d8a87f2deea397..e150cacae22b7b873238ac7f9fc94e2e57ef3977 100644 (file)
@@ -1,5 +1,5 @@
 def f(**kwargs):
     """
     Args:
-      **kwargs: 
+        **kwargs: 
     """
\ No newline at end of file
index aa1e26fdaa629a88504bff5efaf14e0f1119da11..921473a44d2d691e80448230de02103894299357 100644 (file)
@@ -1,5 +1,5 @@
 def f(b):
     """
     Args:
-      b: 
+        b: 
     """
\ No newline at end of file
index 6a8042fd12d5549e763dbf1e1874d00a1a0df2d8..dfe21ec7ad036f3fc341deb89d6206555594d7e5 100644 (file)
@@ -1,5 +1,5 @@
 def f(*args):
     """
     Args:
-      *args: 
+        *args: 
     """
\ No newline at end of file
index e146af3c186fdaaf6d2aebf2e33b5d9b24fe80ef..ed4172f6762248ef69a1534cc02564882ff0473e 100644 (file)
@@ -1,7 +1,7 @@
 def f(x, y, z):
     """
     Parameters:
-      x: 
-      y: 
-      z: 
+        x: 
+        y: 
+        z: 
     """
\ No newline at end of file
diff --git a/python/testData/intentions/afterAddMissingParamsInGoogleDocStringEmptyParamSectionCustomCodeIndent.py b/python/testData/intentions/afterAddMissingParamsInGoogleDocStringEmptyParamSectionCustomCodeIndent.py
new file mode 100644 (file)
index 0000000..8daba24
--- /dev/null
@@ -0,0 +1,7 @@
+def f(x, y, z):
+  """
+  Parameters:
+    x: 
+    y: 
+    z: 
+  """
\ No newline at end of file
index d39babd82abca345c2556473f18f8cfd515c89cc..2e873cc249903f54ba06df10b43c0c7f399c8fb9 100644 (file)
@@ -1,7 +1,7 @@
 def f(x, y, z):
     """
     Args:
-      x: 
-      y: 
-      z: 
+        x: 
+        y: 
+        z: 
     """
\ No newline at end of file
diff --git a/python/testData/intentions/afterAddMissingParamsInGoogleDocStringNoParamSectionCustomCodeIndent.py b/python/testData/intentions/afterAddMissingParamsInGoogleDocStringNoParamSectionCustomCodeIndent.py
new file mode 100644 (file)
index 0000000..7bbbfb3
--- /dev/null
@@ -0,0 +1,7 @@
+def f(x, y, z):
+  """
+  Args:
+    x: 
+    y: 
+    z: 
+  """
\ No newline at end of file
diff --git a/python/testData/intentions/afterGoogleDocStubCustomIndent.py b/python/testData/intentions/afterGoogleDocStubCustomIndent.py
new file mode 100644 (file)
index 0000000..1321e8b
--- /dev/null
@@ -0,0 +1,11 @@
+def f(x, y):
+  """
+
+  Args:
+    x:
+    y:
+
+  Returns:
+
+  """
+  return 42
\ No newline at end of file
index ed96a75bbbb244225c742f6c804192ae93f2c708..85127682e40308e68fc1c330e1e6073be8a2e82a 100644 (file)
@@ -2,8 +2,8 @@ def f(x, y):
     """
 
     Args:
-      x:
-      y:
+        x:
+        y:
     """
 
 
index b4a3cdf9aea1d8002f8b31377d0cfa37a2e9cb97..b30fbfa064e337a7577fdff2d8e5b3d81693b0e0 100644 (file)
@@ -2,8 +2,8 @@ def f(x, y):
     """
 
     Args:
-      x:
-      y:
+        x:
+        y:
 
     Returns:
 
index 62c1fc58fae6ad22e22261172e743867cc2486a2..2f29800d4b0388eef885c3dbefc402bd64679233 100644 (file)
@@ -3,8 +3,8 @@ def f(x,
     """
 
     Args:
-      x:
-      y:
+        x:
+        y:
 
     Returns:
 
index b4a3cdf9aea1d8002f8b31377d0cfa37a2e9cb97..b30fbfa064e337a7577fdff2d8e5b3d81693b0e0 100644 (file)
@@ -2,8 +2,8 @@ def f(x, y):
     """
 
     Args:
-      x:
-      y:
+        x:
+        y:
 
     Returns:
 
index d98dffbfa73b9d170de2a4f446c4ad60877e70bf..c58f8bd27d16b61394353048a704538cfe4fd5ee 100644 (file)
@@ -2,8 +2,8 @@ def f(x, y):
     """
 
     Args:
-      x ():
-      y ():
+        x ():
+        y ():
 
     Returns:
 
index 0446fcb10aac0cda49ba780b59107c6e3709d9a8..1831028cfe75a74ffda46f0c1ba1fa06bbefe763 100644 (file)
@@ -1,5 +1,5 @@
 def f(x, y):
     """
     Args:
-      x (object): 
+        x (object): 
     """
\ No newline at end of file
index c16661b5e76b4662525fb5a09cc061f13d392b91..ae8aafb7abbdccb1fb73bad087998ff071e1649c 100644 (file)
@@ -3,5 +3,5 @@ def f(x, y):
     Summary.
     
     Parameters:
-      x (object): 
+        x (object): 
     """
\ No newline at end of file
index dfd0e9914bf3cdf89d8c53a23c7f0b7caf85db19..62e44c46b073d8934181974a37732f3efa0bcb84 100644 (file)
@@ -3,5 +3,5 @@ def f(x, y):
     Summary.
 
     Args:
-      x (object): 
+        x (object): 
     """
\ No newline at end of file
index 9418ac11257fa35178246a1cf565dd2ac3f82556..105675dc72e0c8f3eb74b7d50ca81b5d201a720f 100644 (file)
@@ -2,5 +2,5 @@ def f(x, y):
     """Summary.
 
     Args:
-      x (object): 
+        x (object): 
     """
\ No newline at end of file
index b31f12026c63cda5361020d7f1ddb1b629016568..3427a1256e77f475bfd6c4f3b8559264e3ec496b 100644 (file)
@@ -2,6 +2,6 @@ def f(x):
     """
 
     Args:
-      x (object): 
+        x (object): 
     """
     return 42
\ No newline at end of file
index 17c07c7231824b79bfcd2e0de823438bff4d98eb..96bc72c1c6b611c803fc2e3b4b3e075dbae78cb8 100644 (file)
@@ -1,5 +1,5 @@
 def f(x, y):
     """
     Returns:
-      object: 
+        object: 
     """
\ No newline at end of file
index 630e5a2168c8c48a8c70383afd997e267c2d1ce9..e5a8056258f94212409170bca241f78520702f22 100644 (file)
@@ -3,5 +3,5 @@ def f(x, y):
     Summary.
     
     Returns:
-      object: 
+        object: 
     """
\ No newline at end of file
index 9417a926bd414e09c2dc1dbd88200f510da5d02f..cccff17f2f14ced2a5943722f9c64099a8d9e59c 100644 (file)
@@ -2,6 +2,6 @@ def f(x):
     """
 
     Returns:
-      object: 
+        object: 
     """
     return 42
\ No newline at end of file
diff --git a/python/testData/intentions/beforeAddMissingParamsInGoogleDocStringEmptyParamSectionCustomCodeIndent.py b/python/testData/intentions/beforeAddMissingParamsInGoogleDocStringEmptyParamSectionCustomCodeIndent.py
new file mode 100644 (file)
index 0000000..1fd5341
--- /dev/null
@@ -0,0 +1,4 @@
+def <caret>f(x, y, z):
+  """
+  Parameters:
+  """
\ No newline at end of file
diff --git a/python/testData/intentions/beforeAddMissingParamsInGoogleDocStringNoParamSectionCustomCodeIndent.py b/python/testData/intentions/beforeAddMissingParamsInGoogleDocStringNoParamSectionCustomCodeIndent.py
new file mode 100644 (file)
index 0000000..dd2501b
--- /dev/null
@@ -0,0 +1,3 @@
+def <caret>f(x, y, z):
+  """
+  """
\ No newline at end of file
diff --git a/python/testData/intentions/beforeGoogleDocStubCustomIndent.py b/python/testData/intentions/beforeGoogleDocStubCustomIndent.py
new file mode 100644 (file)
index 0000000..c57c31a
--- /dev/null
@@ -0,0 +1,2 @@
+def <caret>f(x, y):
+    return 42
\ No newline at end of file
index f397dcec4e01b66101ad80e8a6fcf2ba619b1174..3428a30fe8b34255822c585bb6f5dea8d5124c5b 100644 (file)
@@ -251,6 +251,12 @@ public class PyEditingTest extends PyTestCase {
     doDocStringTypingTest("\nparam", DocStringFormat.GOOGLE);
   }
 
+  // PY-16765
+  public void testSectionIndentInsideGoogleDocStringCustomIndent() {
+    getCommonCodeStyleSettings().getIndentOptions().INDENT_SIZE = 2;
+    doDocStringTypingTest("\nparam", DocStringFormat.GOOGLE);
+  }
+
   public void testEnterInString() {  // PY-1738
     doTestEnter("a = \"some <caret>string\"", "a = \"some \" \\\n" +
                                               "    \"string\"");
index 893bd425d89d673159a2c95661ca857395a73dc5..ac609850a7b66273b200b7b7dc8c5aaf8555e19a 100644 (file)
@@ -234,4 +234,14 @@ public class PySmartEnterTest extends PyTestCase {
       }
     });
   }
+
+  // PY-16765
+  public void testGoogleDocStringIndentAfterSectionCustomIndent() {
+    getCommonCodeStyleSettings().getIndentOptions().INDENT_SIZE = 2;
+    runWithDocStringFormat(DocStringFormat.GOOGLE, new Runnable() {
+      public void run() {
+        doTest();
+      }
+    });
+  }
 }
index 976b98f8e2ed0f7c04a56e574de2b7a2a535f0f5..a551418fcb16770001dc9664b1df689ead2a112f 100644 (file)
@@ -419,6 +419,12 @@ public class  PyIntentionTest extends PyTestCase {
     });
   }
 
+  // PY-16765
+  public void testGoogleDocStubCustomIndent() {
+    getCommonCodeStyleSettings().getIndentOptions().INDENT_SIZE = 2;
+    doDocStubTest(DocStringFormat.GOOGLE);
+  }
+
   // PY-9795
   public void testGoogleDocStubInlineFunctionBody() {
     doDocStubTest(DocStringFormat.GOOGLE);
@@ -565,10 +571,22 @@ public class  PyIntentionTest extends PyTestCase {
     doDocAddMissingParamsTest(DocStringFormat.GOOGLE);
   }
   
+  // PY-16765
+  public void testAddMissingParamsInGoogleDocStringNoParamSectionCustomCodeIndent() {
+    getCommonCodeStyleSettings().getIndentOptions().INDENT_SIZE = 2;
+    doDocAddMissingParamsTest(DocStringFormat.GOOGLE);
+  }
+  
   // PY-9795
   public void testAddMissingParamsInGoogleDocStringEmptyParamSection() {
     doDocAddMissingParamsTest(DocStringFormat.GOOGLE);
   }
+  
+  // PY-16765
+  public void testAddMissingParamsInGoogleDocStringEmptyParamSectionCustomCodeIndent() {
+    getCommonCodeStyleSettings().getIndentOptions().INDENT_SIZE = 2;
+    doDocAddMissingParamsTest(DocStringFormat.GOOGLE);
+  }
 
   // PY-4717
   public void testReturnTypeInNewNumpyDocString() {