mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-05-06 05:10:22 +07:00
PY-16747, PY-16770 generated abstract methods preserve formatting and prefix of original docstring
This commit is contained in:
committed by
Mikhail Golubev
parent
9213f503e3
commit
fc8ea56374
@@ -67,8 +67,7 @@ public class PyGenerateDocstringIntention extends BaseIntentionAction {
|
||||
|
||||
private boolean isAvailableForFunction(PyFunction function) {
|
||||
if (function.getDocStringValue() != null) {
|
||||
final PyDocstringGenerator docstringGenerator = PyDocstringGenerator.forDocStringOwner(function);
|
||||
if (docstringGenerator.hasParametersToAdd()) {
|
||||
if (PyDocstringGenerator.forDocStringOwner(function).withInferredParameters(false).hasParametersToAdd()) {
|
||||
myText = PyBundle.message("INTN.add.parameters.to.docstring");
|
||||
return true;
|
||||
}
|
||||
@@ -101,8 +100,10 @@ public class PyGenerateDocstringIntention extends BaseIntentionAction {
|
||||
if (!DocStringUtil.ensureNotPlainDocstringFormat(docStringOwner)) {
|
||||
return;
|
||||
}
|
||||
final PyDocstringGenerator docstringGenerator = PyDocstringGenerator.forDocStringOwner(docStringOwner);
|
||||
docstringGenerator.addFirstEmptyLine();
|
||||
final PyDocstringGenerator docstringGenerator = PyDocstringGenerator
|
||||
.forDocStringOwner(docStringOwner)
|
||||
.withInferredParameters(false)
|
||||
.addFirstEmptyLine();
|
||||
final PyStringLiteralExpression updated = docstringGenerator.buildAndInsert().getDocStringExpression();
|
||||
if (updated != null && editor != null) {
|
||||
final int offset = updated.getTextOffset();
|
||||
|
||||
@@ -79,7 +79,6 @@ public class SpecifyTypeInDocstringIntention extends TypeIntention {
|
||||
final boolean isReturn = "rtype".equals(kind);
|
||||
|
||||
final PyDocstringGenerator docstringGenerator = PyDocstringGenerator.forDocStringOwner(pyFunction);
|
||||
docstringGenerator.addFirstEmptyLine();
|
||||
final PySignature signature = PySignatureCacheManager.getInstance(pyFunction.getProject()).findSignature(pyFunction);
|
||||
final String name = isReturn ? "" : StringUtil.notNullize(problemElement.getName());
|
||||
final String type;
|
||||
@@ -96,7 +95,7 @@ public class SpecifyTypeInDocstringIntention extends TypeIntention {
|
||||
docstringGenerator.withReturnValue(type);
|
||||
}
|
||||
|
||||
docstringGenerator.buildAndInsert();
|
||||
docstringGenerator.addFirstEmptyLine().buildAndInsert();
|
||||
docstringGenerator.startTemplate();
|
||||
}
|
||||
|
||||
|
||||
@@ -64,25 +64,24 @@ public class PyDocstringGenerator {
|
||||
|
||||
// Updated after buildAndInsert()
|
||||
@Nullable private PyDocStringOwner myDocStringOwner;
|
||||
private final String myDocStringIndent;
|
||||
private final DocStringFormat myDocStringFormat;
|
||||
private String myDocStringIndent;
|
||||
private DocStringFormat myDocStringFormat;
|
||||
|
||||
private boolean myUseTypesFromDebuggerSignature = true;
|
||||
private boolean myNewMode = false; // true - generate new string, false - update existing
|
||||
private boolean myAddFirstEmptyLine = false;
|
||||
private boolean myParametersPrepared = false;
|
||||
private boolean myAlwaysGenerateReturn;
|
||||
private String myQuotes = TRIPLE_DOUBLE_QUOTES;
|
||||
|
||||
private PyDocstringGenerator(@Nullable PyDocStringOwner docStringOwner,
|
||||
@NotNull DocStringFormat format,
|
||||
@NotNull String indentation,
|
||||
@NotNull String docStringText) {
|
||||
@Nullable String docStringText,
|
||||
@NotNull DocStringFormat format,
|
||||
@NotNull String indentation) {
|
||||
myDocStringOwner = docStringOwner;
|
||||
myDocStringIndent = indentation;
|
||||
myDocStringFormat = format;
|
||||
myDocStringText = docStringText;
|
||||
myNewMode = StringUtil.isEmpty(myDocStringText);
|
||||
myNewMode = myDocStringText == null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -91,27 +90,27 @@ public class PyDocstringGenerator {
|
||||
if (owner instanceof PyStatementListContainer) {
|
||||
indentation = PyIndentUtil.getElementIndent(((PyStatementListContainer)owner).getStatementList());
|
||||
}
|
||||
final String docStringText = owner.getDocStringExpression() == null ? "" : owner.getDocStringExpression().getText();
|
||||
return new PyDocstringGenerator(owner, DocStringUtil.getDocStringFormat(owner), indentation, docStringText);
|
||||
final String docStringText = owner.getDocStringExpression() == null ? null : owner.getDocStringExpression().getText();
|
||||
return new PyDocstringGenerator(owner, docStringText, DocStringUtil.getDocStringFormat(owner), indentation);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static PyDocstringGenerator create(@NotNull DocStringFormat format, @NotNull String indentation) {
|
||||
return new PyDocstringGenerator(null, format, indentation, "");
|
||||
return new PyDocstringGenerator(null, null, format, indentation);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static PyDocstringGenerator update(@NotNull PyStringLiteralExpression docString) {
|
||||
return new PyDocstringGenerator(PsiTreeUtil.getParentOfType(docString, PyDocStringOwner.class),
|
||||
DocStringUtil.getDocStringFormat(docString),
|
||||
PyIndentUtil.getElementIndent(docString), docString.getText());
|
||||
return new PyDocstringGenerator(PsiTreeUtil.getParentOfType(docString, PyDocStringOwner.class),
|
||||
docString.getText(), DocStringUtil.getDocStringFormat(docString),
|
||||
PyIndentUtil.getElementIndent(docString));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static PyDocstringGenerator update(@NotNull DocStringFormat format,
|
||||
@NotNull String indentation,
|
||||
@NotNull String text) {
|
||||
return new PyDocstringGenerator(null, format, indentation, text);
|
||||
return new PyDocstringGenerator(null, text, format, indentation);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -149,16 +148,6 @@ public class PyDocstringGenerator {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* By default return declaration is added only if function body contains return statement. Sometimes it's not possible, e.g.
|
||||
* in {@link com.jetbrains.python.editor.PythonEnterHandler} where unclosed docstring literal "captures" whole function body
|
||||
* including return statements.
|
||||
*/
|
||||
@NotNull
|
||||
public PyDocstringGenerator forceAddReturn() {
|
||||
myAlwaysGenerateReturn = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PyDocstringGenerator addFirstEmptyLine() {
|
||||
@@ -173,34 +162,65 @@ public class PyDocstringGenerator {
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate parameters for function if nothing was specified.
|
||||
* Order parameters, remove duplicates and merge parameters with and without type according to docstring format.
|
||||
* @param alwaysAddReturn by default return declaration is added only if function body contains return statement. Sometimes it's not
|
||||
* possible, e.g. in {@link com.jetbrains.python.editor.PythonEnterHandler} where unclosed docstring literal
|
||||
* "captures" whole function body including return statements.
|
||||
*/
|
||||
private void prepareParameters() {
|
||||
// Populate parameter list, if no one was specified explicitly to either add or remove
|
||||
if (!myParametersPrepared && myAddedParams.isEmpty() && myRemovedParams.isEmpty()) {
|
||||
if (myDocStringOwner instanceof PyFunction) {
|
||||
for (PyParameter param : ((PyFunction)myDocStringOwner).getParameterList().getParameters()) {
|
||||
final String paramName = param.getName();
|
||||
final StructuredDocString docString = getStructuredDocString();
|
||||
if (StringUtil.isEmpty(paramName) || param.isSelf() || docString != null && docString.getParameters().contains(paramName)) {
|
||||
continue;
|
||||
}
|
||||
withParam(paramName);
|
||||
@NotNull
|
||||
public PyDocstringGenerator withInferredParameters(boolean alwaysAddReturn) {
|
||||
if (myDocStringOwner instanceof PyFunction) {
|
||||
for (PyParameter param : ((PyFunction)myDocStringOwner).getParameterList().getParameters()) {
|
||||
final String paramName = param.getName();
|
||||
final StructuredDocString docString = getStructuredDocString();
|
||||
if (StringUtil.isEmpty(paramName) || param.isSelf() || docString != null && docString.getParameters().contains(paramName)) {
|
||||
continue;
|
||||
}
|
||||
final RaiseVisitor visitor = new RaiseVisitor();
|
||||
final PyStatementList statementList = ((PyFunction)myDocStringOwner).getStatementList();
|
||||
statementList.accept(visitor);
|
||||
if (visitor.myHasReturn || myAlwaysGenerateReturn) {
|
||||
// will add :return: placeholder in Sphinx/Epydoc docstrings
|
||||
myAddedParams.add(new DocstringParam("", null, true));
|
||||
if (PyCodeInsightSettings.getInstance().INSERT_TYPE_DOCSTUB) {
|
||||
withReturnValue("");
|
||||
}
|
||||
withParam(paramName);
|
||||
}
|
||||
final RaiseVisitor visitor = new RaiseVisitor();
|
||||
final PyStatementList statementList = ((PyFunction)myDocStringOwner).getStatementList();
|
||||
statementList.accept(visitor);
|
||||
if (visitor.myHasReturn || alwaysAddReturn) {
|
||||
// will add :return: placeholder in Sphinx/Epydoc docstrings
|
||||
myAddedParams.add(new DocstringParam("", null, true));
|
||||
if (PyCodeInsightSettings.getInstance().INSERT_TYPE_DOCSTUB) {
|
||||
withReturnValue("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getDocStringIndent() {
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate parameters for function if nothing was specified.
|
||||
* Order parameters, remove duplicates and merge parameters with and without type according to docstring format.
|
||||
*/
|
||||
private void prepareParameters() {
|
||||
if (myParametersPrepared) {
|
||||
return;
|
||||
}
|
||||
final Set<Pair<String, Boolean>> withoutType = Sets.newHashSet();
|
||||
final Map<Pair<String, Boolean>, String> paramTypes = Maps.newHashMap();
|
||||
for (DocstringParam param : myAddedParams) {
|
||||
@@ -278,7 +298,7 @@ public class PyDocstringGenerator {
|
||||
|
||||
@Nullable
|
||||
private StructuredDocString getStructuredDocString() {
|
||||
return myDocStringText.isEmpty() ? null : DocStringUtil.parseDocString(myDocStringFormat, myDocStringText);
|
||||
return myDocStringText == null ? null : DocStringUtil.parseDocString(myDocStringFormat, myDocStringText);
|
||||
}
|
||||
|
||||
public void startTemplate() {
|
||||
|
||||
@@ -29,7 +29,6 @@ import com.intellij.util.xmlb.annotations.Transient;
|
||||
import com.jetbrains.python.PyNames;
|
||||
import com.jetbrains.python.psi.PyFile;
|
||||
import com.jetbrains.python.psi.PyTargetExpression;
|
||||
import com.jetbrains.python.psi.StructuredDocString;
|
||||
import com.jetbrains.python.psi.impl.PyPsiUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -135,21 +134,4 @@ public class PyDocumentationSettings implements PersistentStateComponent<PyDocum
|
||||
public void loadState(PyDocumentationSettings state) {
|
||||
XmlSerializerUtil.copyBean(state, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Use this factory for the whole document infrastructure to simplify new documentation engine support
|
||||
* Factory that returns appropriate instance of {@link StructuredDocString} if specificed
|
||||
*
|
||||
* @return instance or null if no doctype os set
|
||||
*/
|
||||
@Nullable
|
||||
public StructuredDocString getDocString() {
|
||||
if (myDocStringFormat.equals(DocStringFormat.EPYTEXT)) {
|
||||
return DocStringUtil.parseDocStringContent(DocStringFormat.EPYTEXT, "");
|
||||
}
|
||||
if (myDocStringFormat.equals(DocStringFormat.REST)) {
|
||||
return DocStringUtil.parseDocStringContent(DocStringFormat.REST, "");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,7 +262,7 @@ public class PythonEnterHandler extends EnterHandlerDelegateAdapter {
|
||||
final int caretOffset = editor.getCaretModel().getOffset();
|
||||
final String quotes = editor.getDocument().getText(TextRange.from(caretOffset - 3, 3));
|
||||
final String docString = PyDocstringGenerator.forDocStringOwner(docOwner)
|
||||
.forceAddReturn()
|
||||
.withInferredParameters(true)
|
||||
.withQuotes(quotes)
|
||||
.forceNewMode()
|
||||
.buildDocString();
|
||||
|
||||
@@ -51,8 +51,8 @@ public class PythonSpaceHandler extends TypedHandlerDelegate {
|
||||
final String quotes = document.getText(TextRange.from(expectedStringStart, 3));
|
||||
final String docString = PyDocstringGenerator.forDocStringOwner(docOwner)
|
||||
.forceNewMode()
|
||||
.withInferredParameters(true)
|
||||
.withQuotes(quotes)
|
||||
.forceAddReturn()
|
||||
.buildDocString();
|
||||
document.insertString(offset, docString.substring(3));
|
||||
if (!StringUtil.isEmptyOrSpaces(docString.substring(3, docString.length() - 3))) {
|
||||
|
||||
@@ -18,31 +18,27 @@ package com.jetbrains.python.psi.impl;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettings;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.jetbrains.python.PyNames;
|
||||
import com.jetbrains.python.PythonFileType;
|
||||
import com.jetbrains.python.documentation.DocStringFormat;
|
||||
import com.jetbrains.python.documentation.PyDocstringGenerator;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class PyFunctionBuilder {
|
||||
private static final String COMMENTS_BOUNDARY = "\"\"\"";
|
||||
private static final Pattern INDENT_REMOVE_PATTERN = Pattern.compile("^\\s+", Pattern.MULTILINE);
|
||||
private final String myName;
|
||||
private final List<String> myParameters = new ArrayList<String>();
|
||||
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 PyDocstringGenerator myDocStringGenerator = PyDocstringGenerator.create(DocStringFormat.REST, " ");
|
||||
|
||||
/**
|
||||
* Creates builder copying signature and doc from another one.
|
||||
@@ -72,35 +68,11 @@ public class PyFunctionBuilder {
|
||||
}
|
||||
}
|
||||
}
|
||||
final String docString = source.getDocStringValue();
|
||||
if (docString != null) {
|
||||
functionBuilder.docString(docString);
|
||||
}
|
||||
functionBuilder.myDocStringGenerator = PyDocstringGenerator.forDocStringOwner(source);
|
||||
return functionBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds docstring to function. Provide doc with out of comment blocks.
|
||||
*
|
||||
*
|
||||
* @param docString doc
|
||||
*/
|
||||
public void docString(@NotNull final String docString) {
|
||||
final String[] stringsToAdd = StringUtil.splitByLines(removeIndent(docString));
|
||||
if (myDocStringLines == null) {
|
||||
myDocStringLines = stringsToAdd;
|
||||
}
|
||||
else {
|
||||
myDocStringLines = ArrayUtil.mergeArrays(myDocStringLines, stringsToAdd);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String removeIndent(@NotNull final String string) {
|
||||
return INDENT_REMOVE_PATTERN.matcher(string).replaceAll("");
|
||||
}
|
||||
|
||||
public PyFunctionBuilder(String name) {
|
||||
public PyFunctionBuilder(@NotNull String name) {
|
||||
myName = name;
|
||||
}
|
||||
|
||||
@@ -108,14 +80,15 @@ public class PyFunctionBuilder {
|
||||
* Adds param and its type to doc
|
||||
* @param name param name
|
||||
* @param type param type
|
||||
* @param docStyle what docstyle to use to doc 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 StructuredDocString docStyle) {
|
||||
@NotNull final DocStringFormat format) {
|
||||
parameter(name);
|
||||
docString(docStyle.createParameterType(name, type));
|
||||
myDocStringGenerator.setDocStringFormat(format);
|
||||
myDocStringGenerator.withParamTypedByName(name, type);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -175,20 +148,15 @@ public class PyFunctionBuilder {
|
||||
builder.append(":");
|
||||
List<String> statements = myStatements.isEmpty() ? Collections.singletonList(PyNames.PASS) : myStatements;
|
||||
|
||||
if (myDocStringLines != null) {
|
||||
final List<String> comments = new ArrayList<String>(myDocStringLines.length + 2);
|
||||
comments.add(COMMENTS_BOUNDARY);
|
||||
comments.addAll(Arrays.asList(myDocStringLines));
|
||||
comments.add(COMMENTS_BOUNDARY);
|
||||
statements = new ArrayList<String>(statements);
|
||||
statements.addAll(0, comments);
|
||||
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);
|
||||
builder.append('\n').append(indent).append(docstring);
|
||||
}
|
||||
|
||||
final CodeStyleSettings codeStyleSettings = CodeStyleSettingsManager.getInstance(project).getCurrentSettings();
|
||||
int indentSize = codeStyleSettings.getIndentOptions(PythonFileType.INSTANCE).INDENT_SIZE;
|
||||
String indent = StringUtil.repeatSymbol(' ', indentSize);
|
||||
for (String statement : statements) {
|
||||
builder.append("\n").append(indent).append(statement);
|
||||
builder.append('\n').append(indent).append(statement);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
@@ -207,11 +175,4 @@ public class PyFunctionBuilder {
|
||||
public void decorate(String decoratorName) {
|
||||
myDecorators.add(decoratorName);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String getIndent(@NotNull final Project project) {
|
||||
final CodeStyleSettings codeStyleSettings = CodeStyleSettingsManager.getInstance(project).getCurrentSettings();
|
||||
final int indentSize = codeStyleSettings.getIndentOptions(PythonFileType.INSTANCE).INDENT_SIZE;
|
||||
return StringUtil.repeatSymbol(' ', indentSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
from abc import abstractmethod, ABCMeta
|
||||
|
||||
|
||||
class A:
|
||||
__metaclass__ = ABCMeta
|
||||
|
||||
@abstractmethod
|
||||
def m(self, x):
|
||||
"""
|
||||
Parameters:
|
||||
x (int): number
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class B(A):
|
||||
def m(self, x):
|
||||
"""
|
||||
Parameters:
|
||||
x (int): number
|
||||
"""
|
||||
return x
|
||||
@@ -0,0 +1,7 @@
|
||||
class B:
|
||||
def m(self, x):
|
||||
"""
|
||||
Parameters:
|
||||
x (int): number
|
||||
"""
|
||||
return x
|
||||
@@ -0,0 +1,17 @@
|
||||
# coding=utf-8
|
||||
from abc import abstractmethod, ABCMeta
|
||||
|
||||
|
||||
class A:
|
||||
__metaclass__ = ABCMeta
|
||||
|
||||
@abstractmethod
|
||||
def m(self, x):
|
||||
u"""Юникод"""
|
||||
pass
|
||||
|
||||
|
||||
class B(A):
|
||||
def m(self, x):
|
||||
u"""Юникод"""
|
||||
return x
|
||||
@@ -0,0 +1,6 @@
|
||||
# coding=utf-8
|
||||
|
||||
class B:
|
||||
def m(self, x):
|
||||
u"""Юникод"""
|
||||
return x
|
||||
@@ -0,0 +1,22 @@
|
||||
from abc import abstractmethod, ABCMeta
|
||||
|
||||
|
||||
class A:
|
||||
__metaclass__ = ABCMeta
|
||||
|
||||
@abstractmethod
|
||||
def m(self, x):
|
||||
"""
|
||||
Parameters:
|
||||
x (int): number
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class B(A):
|
||||
def m(self, x):
|
||||
"""
|
||||
Parameters:
|
||||
x (int): number
|
||||
"""
|
||||
return x
|
||||
@@ -0,0 +1,11 @@
|
||||
class A:
|
||||
pass
|
||||
|
||||
|
||||
class B(A):
|
||||
def m(self, x):
|
||||
"""
|
||||
Parameters:
|
||||
x (int): number
|
||||
"""
|
||||
return x
|
||||
@@ -0,0 +1,17 @@
|
||||
# coding=utf-8
|
||||
from abc import abstractmethod, ABCMeta
|
||||
|
||||
|
||||
class A:
|
||||
__metaclass__ = ABCMeta
|
||||
|
||||
@abstractmethod
|
||||
def m(self, x):
|
||||
u"""Юникод"""
|
||||
pass
|
||||
|
||||
|
||||
class B(A):
|
||||
def m(self, x):
|
||||
u"""Юникод"""
|
||||
return x
|
||||
@@ -0,0 +1,10 @@
|
||||
# coding=utf-8
|
||||
|
||||
class A:
|
||||
pass
|
||||
|
||||
|
||||
class B(A):
|
||||
def m(self, x):
|
||||
u"""Юникод"""
|
||||
return x
|
||||
@@ -95,25 +95,25 @@ public class PyExtractSuperclassTest extends PyClassRefactoringTest {
|
||||
}
|
||||
|
||||
public void testSimple() throws Exception {
|
||||
doSimpleTest("Foo", "Suppa", null, true, ".foo");
|
||||
doSimpleTest("Foo", "Suppa", null, true, false, ".foo");
|
||||
}
|
||||
|
||||
public void testInstanceNotDeclaredInInit() throws Exception {
|
||||
doSimpleTest("Child", "Parent", null, true, "#eggs");
|
||||
doSimpleTest("Child", "Parent", null, true, false, "#eggs");
|
||||
}
|
||||
|
||||
public void testWithSuper() throws Exception {
|
||||
doSimpleTest("Foo", "Suppa", null, true, ".foo");
|
||||
doSimpleTest("Foo", "Suppa", null, true, false, ".foo");
|
||||
}
|
||||
|
||||
public void testWithImport() throws Exception {
|
||||
doSimpleTest("A", "Suppa", null, false, ".foo");
|
||||
doSimpleTest("A", "Suppa", null, false, false, ".foo");
|
||||
}
|
||||
|
||||
// PY-12175
|
||||
public void testImportNotBroken() throws Exception {
|
||||
myFixture.copyFileToProject("/refactoring/extractsuperclass/shared.py", "shared.py");
|
||||
doSimpleTest("Source", "DestClass", null, true, "SharedClass");
|
||||
doSimpleTest("Source", "DestClass", null, true, false, "SharedClass");
|
||||
}
|
||||
|
||||
// PY-12175 but between several files
|
||||
@@ -122,19 +122,29 @@ public class PyExtractSuperclassTest extends PyClassRefactoringTest {
|
||||
}
|
||||
|
||||
public void testMoveFields() throws Exception {
|
||||
doSimpleTest("FromClass", "ToClass", null, true, "#instance_field", "#CLASS_FIELD");
|
||||
doSimpleTest("FromClass", "ToClass", null, true, false, "#instance_field", "#CLASS_FIELD");
|
||||
}
|
||||
|
||||
|
||||
public void testProperties() throws Exception {
|
||||
doSimpleTest("FromClass", "ToClass", null, true, "#C", "#a", "._get", ".foo");
|
||||
doSimpleTest("FromClass", "ToClass", null, true, false, "#C", "#a", "._get", ".foo");
|
||||
}
|
||||
|
||||
// PY-16747
|
||||
public void testAbstractMethodDocStringIndentationPreserved() throws Exception {
|
||||
doSimpleTest("B", "A", null, true, true, ".m");
|
||||
}
|
||||
|
||||
// PY-16770
|
||||
public void testAbstractMethodDocStringPrefixPreserved() throws Exception {
|
||||
doSimpleTest("B", "A", null, true, true, ".m");
|
||||
}
|
||||
|
||||
private void doSimpleTest(final String className,
|
||||
final String superclassName,
|
||||
final String expectedError,
|
||||
final boolean sameFile,
|
||||
final String... membersName) throws Exception {
|
||||
boolean asAbstract, final String... membersName) throws Exception {
|
||||
try {
|
||||
String baseName = "/refactoring/extractsuperclass/" + getTestName(true);
|
||||
myFixture.configureByFile(baseName + ".before.py");
|
||||
@@ -142,7 +152,9 @@ public class PyExtractSuperclassTest extends PyClassRefactoringTest {
|
||||
final List<PyMemberInfo<PyElement>> members = new ArrayList<PyMemberInfo<PyElement>>();
|
||||
for (String memberName : membersName) {
|
||||
final PyElement member = findMember(className, memberName);
|
||||
members.add(MembersManager.findMember(clazz, member));
|
||||
final PyMemberInfo<PyElement> memberInfo = MembersManager.findMember(clazz, member);
|
||||
memberInfo.setToAbstract(asAbstract);
|
||||
members.add(memberInfo);
|
||||
}
|
||||
|
||||
new WriteCommandAction.Simple(myFixture.getProject()) {
|
||||
|
||||
@@ -111,6 +111,20 @@ public class PyPullUpTest extends PyClassRefactoringTest {
|
||||
checkMultiFile(modules);
|
||||
}
|
||||
|
||||
// PY-16747
|
||||
public void testAbstractMethodDocStringIndentationPreserved() {
|
||||
myFixture.configureByFile(getMultiFileBaseName() + ".py");
|
||||
doPullUp("B", "A", true, ".m");
|
||||
myFixture.checkResultByFile(getMultiFileBaseName() + ".after.py");
|
||||
}
|
||||
|
||||
// PY-16770
|
||||
public void testAbstractMethodDocStringPrefixPreserved() {
|
||||
myFixture.configureByFile(getMultiFileBaseName() + ".py");
|
||||
doPullUp("B", "A", true, ".m");
|
||||
myFixture.checkResultByFile(getMultiFileBaseName() + ".after.py");
|
||||
}
|
||||
|
||||
private void doMultiFileTest() {
|
||||
final String[] modules = {"Class", "SuperClass"};
|
||||
configureMultiFile(modules);
|
||||
|
||||
Reference in New Issue
Block a user