mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote branch 'origin/master'
This commit is contained in:
@@ -694,6 +694,10 @@
|
||||
<lang.elementManipulator forClass="com.jetbrains.mako.psi.impl.MakoTagAttribute"
|
||||
implementationClass="com.jetbrains.mako.psi.MakoTagAttributeManipulator"/>
|
||||
|
||||
<localInspection language="Python" shortName="MakoArgumentListInspection" displayName="Incorrect call arguments"
|
||||
groupKey="INSP.GROUP.mako" enabledByDefault="true" level="WARNING"
|
||||
implementationClass="com.jetbrains.mako.inspection.MakoArgumentListInspection"/>
|
||||
|
||||
<moduleService serviceInterface="com.jetbrains.python.templateLanguages.TemplatesService"
|
||||
serviceImplementation="com.jetbrains.python.templateLanguages.TemplatesService"/>
|
||||
|
||||
|
||||
@@ -194,6 +194,7 @@ surround.with.try.except.template=try / except
|
||||
|
||||
### Inspections: INSP ###
|
||||
INSP.GROUP.python=Python
|
||||
INSP.GROUP.mako=Mako
|
||||
|
||||
# PyArgumentListInspection
|
||||
INSP.NAME.incorrect.call.arguments=Incorrect call arguments
|
||||
@@ -600,6 +601,8 @@ sdk.error.invalid.interpreter.name.$0=Invalid Python interpeter name '{0}'!
|
||||
sdk.select.path=Select Python Interpreter
|
||||
runcfg.unittest.dlg.pattern=Pattern:
|
||||
|
||||
runcfg.testing.no.test.framework=No {0} runner found in selected interpreter
|
||||
|
||||
# Consoles messages
|
||||
python.console=Python Console
|
||||
django.console=Django Console
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.jetbrains.python.configuration.PyIntegratedToolsConfigurable">
|
||||
<grid id="27dc6" binding="myMainPanel" layout-manager="GridLayoutManager" row-count="5" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<grid id="27dc6" binding="myMainPanel" layout-manager="GridLayoutManager" row-count="6" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<xy x="20" y="20" width="657" height="302"/>
|
||||
@@ -56,7 +56,7 @@
|
||||
</component>
|
||||
<vspacer id="fc19e">
|
||||
<constraints>
|
||||
<grid row="4" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
|
||||
<grid row="5" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
</vspacer>
|
||||
<component id="40acf" class="com.intellij.ui.components.JBLabel">
|
||||
@@ -76,6 +76,14 @@
|
||||
<text value=""/>
|
||||
</properties>
|
||||
</component>
|
||||
<grid id="728f8" binding="myErrorPanel" layout-manager="BorderLayout" hgap="0" vgap="0">
|
||||
<constraints>
|
||||
<grid row="4" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children/>
|
||||
</grid>
|
||||
</children>
|
||||
</grid>
|
||||
</form>
|
||||
|
||||
@@ -1,39 +1,34 @@
|
||||
package com.jetbrains.python.configuration;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.ex.EditorEx;
|
||||
import com.intellij.openapi.editor.highlighter.EditorHighlighter;
|
||||
import com.intellij.openapi.editor.highlighter.EditorHighlighterFactory;
|
||||
import com.intellij.openapi.editor.impl.EditorFactoryImpl;
|
||||
import com.intellij.facet.impl.ui.FacetErrorPanel;
|
||||
import com.intellij.facet.ui.FacetEditorValidator;
|
||||
import com.intellij.facet.ui.ValidationResult;
|
||||
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
|
||||
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
|
||||
import com.intellij.openapi.options.Configurable;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleManager;
|
||||
import com.intellij.openapi.options.ConfigurationException;
|
||||
import com.intellij.openapi.options.NonDefaultProjectConfigurable;
|
||||
import com.intellij.openapi.options.SearchableConfigurable;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ContentIterator;
|
||||
import com.intellij.openapi.roots.ProjectRootManager;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.ui.CollectionComboBoxModel;
|
||||
import com.intellij.util.FileContentUtil;
|
||||
import com.jetbrains.django.lang.template.DjangoTemplateFileType;
|
||||
import com.jetbrains.python.templateLanguages.TemplatesConfigurationsModel;
|
||||
import com.jetbrains.python.templateLanguages.TemplatesService;
|
||||
import com.jetbrains.python.PyBundle;
|
||||
import com.jetbrains.python.documentation.DocStringFormat;
|
||||
import com.jetbrains.python.documentation.PyDocumentationSettings;
|
||||
import com.jetbrains.python.sdk.PythonSdkType;
|
||||
import com.jetbrains.python.testing.PythonTestConfigurationsModel;
|
||||
import com.jetbrains.python.testing.TestRunnerService;
|
||||
import com.jetbrains.python.testing.VFSTestFrameworkListener;
|
||||
import com.jetbrains.rest.ReSTService;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -48,6 +43,7 @@ public class PyIntegratedToolsConfigurable implements SearchableConfigurable, No
|
||||
private final PyDocumentationSettings myDocumentationSettings;
|
||||
private TextFieldWithBrowseButton myWorkDir;
|
||||
private JCheckBox txtIsRst;
|
||||
private JPanel myErrorPanel;
|
||||
|
||||
public PyIntegratedToolsConfigurable(Project project) {
|
||||
myProject = project;
|
||||
@@ -59,8 +55,41 @@ public class PyIntegratedToolsConfigurable implements SearchableConfigurable, No
|
||||
ReSTService service = ReSTService.getInstance(myProject);
|
||||
myWorkDir.setText(service.getWorkdir());
|
||||
txtIsRst.setSelected(service.txtIsRst());
|
||||
initErrorValidation();
|
||||
}
|
||||
|
||||
private void initErrorValidation() {
|
||||
FacetErrorPanel facetErrorPanel = new FacetErrorPanel();
|
||||
myErrorPanel.add(facetErrorPanel.getComponent(), BorderLayout.CENTER);
|
||||
|
||||
facetErrorPanel.getValidatorsManager().registerValidator(new FacetEditorValidator() {
|
||||
@Override
|
||||
public ValidationResult check() {
|
||||
Module[] modules = ModuleManager.getInstance(myProject).getModules();
|
||||
if (modules.length == 0) return ValidationResult.OK;
|
||||
final Sdk sdk = PythonSdkType.findPythonSdk(modules[0]);
|
||||
if (sdk != null) {
|
||||
if (myTestRunnerComboBox.getSelectedItem() == PythonTestConfigurationsModel.PY_TEST_NAME) {
|
||||
if (!VFSTestFrameworkListener.getInstance().isPyTestInstalled(sdk.getHomePath()))
|
||||
return new ValidationResult(PyBundle.message("runcfg.testing.no.test.framework", "py.test"));
|
||||
}
|
||||
else if (myTestRunnerComboBox.getSelectedItem() == PythonTestConfigurationsModel.PYTHONS_NOSETEST_NAME) {
|
||||
if (!VFSTestFrameworkListener.getInstance().isNoseTestInstalled(sdk.getHomePath()))
|
||||
return new ValidationResult(PyBundle.message("runcfg.testing.no.test.framework", "nosetest"));
|
||||
}
|
||||
else if (myTestRunnerComboBox.getSelectedItem() == PythonTestConfigurationsModel.PYTHONS_ATTEST_NAME) {
|
||||
if (!VFSTestFrameworkListener.getInstance().isAtTestInstalled(sdk.getHomePath()))
|
||||
return new ValidationResult(PyBundle.message("runcfg.testing.no.test.framework", "attest"));
|
||||
}
|
||||
}
|
||||
return ValidationResult.OK;
|
||||
}
|
||||
}, myTestRunnerComboBox);
|
||||
|
||||
facetErrorPanel.getValidatorsManager().validate();
|
||||
}
|
||||
|
||||
|
||||
@Nls
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.jetbrains.cython.CythonLanguageDialect;
|
||||
import com.jetbrains.mako.MakoLanguage;
|
||||
import com.jetbrains.python.PyBundle;
|
||||
import com.jetbrains.python.PyNames;
|
||||
import com.jetbrains.python.PyTokenTypes;
|
||||
@@ -43,7 +44,7 @@ public class PyArgumentListInspection extends PyInspection {
|
||||
|
||||
@Override
|
||||
public void visitPyArgumentList(final PyArgumentList node) {
|
||||
if (CythonLanguageDialect._isDisabledFor(node)) {
|
||||
if (CythonLanguageDialect._isDisabledFor(node) || MakoLanguage._isDisabledFor(node)) {
|
||||
return;
|
||||
}
|
||||
// analyze
|
||||
@@ -87,14 +88,18 @@ public class PyArgumentListInspection extends PyInspection {
|
||||
|
||||
}
|
||||
|
||||
public static void inspectPyArgumentList(PyArgumentList node, ProblemsHolder holder, final TypeEvalContext context) {
|
||||
public static void inspectPyArgumentList(PyArgumentList node, ProblemsHolder holder, final TypeEvalContext context, int implicitOffset) {
|
||||
if (node.getParent() instanceof PyClass) return; // class Foo(object) is also an arg list
|
||||
CallArgumentsMapping result = node.analyzeCall(PyResolveContext.noImplicits().withTypeEvalContext(context));
|
||||
CallArgumentsMapping result = node.analyzeCall(PyResolveContext.noImplicits().withTypeEvalContext(context), implicitOffset);
|
||||
highlightIncorrectArguments(holder, result);
|
||||
highlightMissingArguments(node, holder, result);
|
||||
highlightStarArgumentTypeMismatch(node, holder, context);
|
||||
}
|
||||
|
||||
public static void inspectPyArgumentList(PyArgumentList node, ProblemsHolder holder, final TypeEvalContext context) {
|
||||
inspectPyArgumentList(node, holder, context, 0);
|
||||
}
|
||||
|
||||
private static void highlightIncorrectArguments(ProblemsHolder holder, CallArgumentsMapping result) {
|
||||
for (Map.Entry<PyExpression, EnumSet<CallArgumentsMapping.ArgFlag>> arg_entry : result.getArgumentFlags().entrySet()) {
|
||||
EnumSet<CallArgumentsMapping.ArgFlag> flags = arg_entry.getValue();
|
||||
|
||||
@@ -6,9 +6,13 @@ import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.colors.EditorColorsScheme;
|
||||
import com.intellij.openapi.editor.event.DocumentEvent;
|
||||
import com.intellij.openapi.editor.ex.util.LexerEditorHighlighter;
|
||||
import com.intellij.openapi.editor.highlighter.HighlighterClient;
|
||||
import com.intellij.openapi.fileTypes.SyntaxHighlighter;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.jetbrains.python.PyNames;
|
||||
import com.jetbrains.python.PythonFileType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -25,6 +29,9 @@ public class PythonEditorHighlighter extends LexerEditorHighlighter {
|
||||
scheme);
|
||||
}
|
||||
|
||||
private Boolean hadUnicodeImport = false;
|
||||
|
||||
public static final Key<Boolean> KEY = new Key<Boolean>("python.future.import");
|
||||
@Override
|
||||
public void documentChanged(DocumentEvent e) {
|
||||
synchronized (this) {
|
||||
@@ -34,10 +41,14 @@ public class PythonEditorHighlighter extends LexerEditorHighlighter {
|
||||
// we should update the whole document
|
||||
if (l instanceof LayeredLexer) {
|
||||
Lexer delegate = ((LayeredLexer)l).getDelegate();
|
||||
int offset = e.getOffset();
|
||||
int lineNumber = document.getLineNumber(offset);
|
||||
TextRange tr = new TextRange(document.getLineStartOffset(lineNumber), document.getLineEndOffset(lineNumber));
|
||||
document.putUserData(KEY, document.getText(tr).indexOf(PyNames.UNICODE_LITERALS) == -1);
|
||||
Boolean hasUnicodeImport = document.getUserData(KEY);
|
||||
if (delegate instanceof PythonHighlightingLexer &&
|
||||
(((PythonHighlightingLexer)delegate).getImportOffset() > e.getOffset()
|
||||
|| ((PythonHighlightingLexer)delegate).getImportOffset() == -1)) {
|
||||
|
||||
|| hasUnicodeImport != hadUnicodeImport)) {
|
||||
((PythonHighlightingLexer)delegate).clearState(e.getDocument().getTextLength());
|
||||
setText(document.getCharsSequence());
|
||||
}
|
||||
@@ -46,4 +57,19 @@ public class PythonEditorHighlighter extends LexerEditorHighlighter {
|
||||
else super.documentChanged(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeDocumentChange(DocumentEvent e) {
|
||||
final Document document = e.getDocument();
|
||||
hadUnicodeImport = document.getUserData(KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEditor(HighlighterClient editor) {
|
||||
Lexer l = getLexer();
|
||||
if (l instanceof LayeredLexer) {
|
||||
editor.getDocument().putUserData(KEY, editor.getDocument().getText().indexOf(PyNames.UNICODE_LITERALS) == -1);
|
||||
}
|
||||
super.setEditor(editor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,10 +30,15 @@ public interface PyArgumentList extends PyElement {
|
||||
* Tries to map the argument list to callee's idea of parameters.
|
||||
* @return a result object with mappings and diagnostic flags.
|
||||
* @param resolveContext the reference resolution context
|
||||
* @param implicitOffset known from the context implicit offset
|
||||
*/
|
||||
@NotNull
|
||||
CallArgumentsMapping analyzeCall(PyResolveContext resolveContext, int implicitOffset);
|
||||
|
||||
@NotNull
|
||||
CallArgumentsMapping analyzeCall(PyResolveContext resolveContext);
|
||||
|
||||
|
||||
@Nullable
|
||||
ASTNode getClosingParen();
|
||||
}
|
||||
|
||||
@@ -55,6 +55,14 @@ public interface PyCallExpression extends PyExpression {
|
||||
@Nullable
|
||||
PyMarkedCallee resolveCallee(PyResolveContext resolveContext);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param resolveContext the reference resolve context
|
||||
* @param implicitOffset known from the context implicit offset
|
||||
*/
|
||||
@Nullable
|
||||
PyMarkedCallee resolveCallee(PyResolveContext resolveContext, int implicitOffset);
|
||||
|
||||
/**
|
||||
* Checks if the unqualified name of the callee matches any of the specified names
|
||||
*
|
||||
|
||||
@@ -238,6 +238,11 @@ public class PyArgumentListImpl extends PyElementImpl implements PyArgumentList
|
||||
|
||||
@NotNull
|
||||
public CallArgumentsMapping analyzeCall(PyResolveContext resolveContext) {
|
||||
return analyzeCall(resolveContext, 0);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public CallArgumentsMapping analyzeCall(PyResolveContext resolveContext, int offset) {
|
||||
final CallArgumentsMappingImpl ret = new CallArgumentsMappingImpl(this);
|
||||
// declaration-based checks
|
||||
// proper arglist is: [positional,...][name=value,...][*tuple,][**dict]
|
||||
@@ -245,7 +250,7 @@ public class PyArgumentListImpl extends PyElementImpl implements PyArgumentList
|
||||
// following the spec: http://docs.python.org/ref/calls.html
|
||||
PyCallExpression call = getCallExpression();
|
||||
if (call != null) {
|
||||
PyCallExpression.PyMarkedCallee resolved_callee = call.resolveCallee(resolveContext);
|
||||
PyCallExpression.PyMarkedCallee resolved_callee = call.resolveCallee(resolveContext, offset);
|
||||
if (resolved_callee != null) ret.mapArguments(resolved_callee, resolveContext.getTypeEvalContext());
|
||||
}
|
||||
return ret;
|
||||
|
||||
@@ -104,6 +104,11 @@ public class PyCallExpressionHelper {
|
||||
|
||||
@Nullable
|
||||
public static PyCallExpression.PyMarkedCallee resolveCallee(PyCallExpression us, PyResolveContext resolveContext) {
|
||||
return resolveCallee(us, resolveContext, 0);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PyCallExpression.PyMarkedCallee resolveCallee(PyCallExpression us, PyResolveContext resolveContext, int implicitOffset) {
|
||||
PyFunction.Flag wrappedFlag = null;
|
||||
boolean isConstructorCall = false;
|
||||
|
||||
@@ -152,8 +157,8 @@ public class PyCallExpressionHelper {
|
||||
PyExpression lastQualifier = qualifiers != null && qualifiers.isEmpty() ? null : qualifiers.get(qualifiers.size()-1);
|
||||
boolean isByClass = lastQualifier == null ? false : isQualifiedByClass((Callable)resolved, lastQualifier, resolveContext.getTypeEvalContext());
|
||||
final Callable callable = (Callable)resolved;
|
||||
|
||||
int implicitOffset = getImplicitArgumentCount(callable, flags, isConstructorCall, isByInstance, isByClass);
|
||||
|
||||
implicitOffset += getImplicitArgumentCount(callable, flags, isConstructorCall, isByInstance, isByClass);
|
||||
implicitOffset = implicitOffset < 0? 0: implicitOffset; // wrong source can trigger strange behaviour
|
||||
return new PyCallExpression.PyMarkedCallee(callable, flags, implicitOffset,
|
||||
resolveResult != null ? resolveResult.isImplicit() : false);
|
||||
|
||||
@@ -64,6 +64,10 @@ public class PyCallExpressionImpl extends PyElementImpl implements PyCallExpress
|
||||
return PyCallExpressionHelper.resolveCallee(this, resolveContext);
|
||||
}
|
||||
|
||||
public PyMarkedCallee resolveCallee(PyResolveContext resolveContext, int offset) {
|
||||
return PyCallExpressionHelper.resolveCallee(this, resolveContext, offset);
|
||||
}
|
||||
|
||||
public boolean isCalleeText(@NotNull String... nameCandidates) {
|
||||
return PyCallExpressionHelper.isCalleeText(this, nameCandidates);
|
||||
}
|
||||
|
||||
@@ -112,6 +112,9 @@ public class PyDecoratorImpl extends PyPresentableElementImpl<PyDecoratorStub> i
|
||||
}
|
||||
|
||||
public PyMarkedCallee resolveCallee(PyResolveContext resolveContext) {
|
||||
return resolveCallee(resolveContext, 0);
|
||||
}
|
||||
public PyMarkedCallee resolveCallee(PyResolveContext resolveContext, int offset) {
|
||||
PyMarkedCallee callee = PyCallExpressionHelper.resolveCallee(this, resolveContext);
|
||||
if (callee == null) return null;
|
||||
if (!hasArgumentList()) {
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.intellij.execution.runners.ExecutionEnvironment;
|
||||
import com.intellij.openapi.options.SettingsEditor;
|
||||
import com.intellij.openapi.util.InvalidDataException;
|
||||
import com.intellij.openapi.util.WriteExternalException;
|
||||
import com.jetbrains.python.PyBundle;
|
||||
import com.jetbrains.python.testing.AbstractPythonTestRunConfiguration;
|
||||
import com.jetbrains.python.testing.VFSTestFrameworkListener;
|
||||
import org.jdom.Element;
|
||||
@@ -62,6 +63,6 @@ public class PythonAtTestRunConfiguration extends AbstractPythonTestRunConfigura
|
||||
public void checkConfiguration() throws RuntimeConfigurationException {
|
||||
super.checkConfiguration();
|
||||
if (!VFSTestFrameworkListener.getInstance().isAtTestInstalled(getSdkHome()))
|
||||
throw new RuntimeConfigurationWarning("No attest runner found in selected interpreter");
|
||||
throw new RuntimeConfigurationWarning(PyBundle.message("runcfg.testing.no.test.framework", "attest"));
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -8,6 +8,7 @@ import com.intellij.openapi.options.SettingsEditor;
|
||||
import com.intellij.openapi.util.InvalidDataException;
|
||||
import com.intellij.openapi.util.JDOMExternalizerUtil;
|
||||
import com.intellij.openapi.util.WriteExternalException;
|
||||
import com.jetbrains.python.PyBundle;
|
||||
import com.jetbrains.python.testing.AbstractPythonTestRunConfiguration;
|
||||
import com.jetbrains.python.testing.VFSTestFrameworkListener;
|
||||
import org.jdom.Element;
|
||||
@@ -79,7 +80,7 @@ public class PythonNoseTestRunConfiguration extends AbstractPythonTestRunConfigu
|
||||
public void checkConfiguration() throws RuntimeConfigurationException {
|
||||
super.checkConfiguration();
|
||||
if (!VFSTestFrameworkListener.getInstance().isNoseTestInstalled(getSdkHome()))
|
||||
throw new RuntimeConfigurationWarning("No nosetest runner found in selected interpreter");
|
||||
throw new RuntimeConfigurationWarning(PyBundle.message("runcfg.testing.no.test.framework", "nosetest"));
|
||||
}
|
||||
|
||||
public boolean useParam() {
|
||||
|
||||
@@ -9,6 +9,7 @@ import com.intellij.openapi.util.InvalidDataException;
|
||||
import com.intellij.openapi.util.JDOMExternalizerUtil;
|
||||
import com.intellij.openapi.util.WriteExternalException;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.jetbrains.python.PyBundle;
|
||||
import com.jetbrains.python.testing.AbstractPythonTestRunConfiguration;
|
||||
import com.jetbrains.python.testing.VFSTestFrameworkListener;
|
||||
import org.jdom.Element;
|
||||
@@ -115,7 +116,7 @@ public class PyTestRunConfiguration extends AbstractPythonTestRunConfiguration i
|
||||
throw new RuntimeConfigurationError("Please specify target folder or script");
|
||||
}
|
||||
if (!VFSTestFrameworkListener.getInstance().isPyTestInstalled(getSdkHome()))
|
||||
throw new RuntimeConfigurationWarning("No py.test runner found in selected interpreter");
|
||||
throw new RuntimeConfigurationWarning(PyBundle.message("runcfg.testing.no.test.framework", "py.test"));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user