From 065fe2ac018687c19850d6d07ac52feb0183a266 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Fri, 9 Nov 2012 14:15:09 +0400 Subject: [PATCH] fixed PY-7975 isTestFrameworkInstalled throws exception for remote interpreter --- .../src/com/jetbrains/python/PyNames.java | 3 +- .../PyIntegratedToolsConfigurable.java | 6 +- .../doctest/PyDocstringLexer.java | 5 ++ .../python/testing/PyTestRunnerUpdater.java | 10 +-- .../testing/VFSTestFrameworkListener.java | 73 ++++++++----------- .../attest/PythonAtTestRunConfiguration.java | 3 +- .../PythonNoseTestRunConfiguration.java | 3 +- .../pytest/PyTestRunConfiguration.java | 3 +- .../pytest/PyTestRunnableScriptFilter.java | 2 +- 9 files changed, 53 insertions(+), 55 deletions(-) diff --git a/python/psi-api/src/com/jetbrains/python/PyNames.java b/python/psi-api/src/com/jetbrains/python/PyNames.java index 4942774a6ac3..dece0ad2cac3 100644 --- a/python/psi-api/src/com/jetbrains/python/PyNames.java +++ b/python/psi-api/src/com/jetbrains/python/PyNames.java @@ -120,7 +120,8 @@ public class PyNames { public static final String NOSE_TEST = "nose"; public static final String PY_TEST = "pytest"; - public static final String AT_TEST = "attest"; + public static final String AT_TEST = "Attest"; + public static final String AT_TEST_IMPORT = "attest"; public static final String PYCACHE = "__pycache__"; diff --git a/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.java b/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.java index e385f35ed8ac..bc38e1d3a2e8 100644 --- a/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.java +++ b/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.java @@ -92,19 +92,19 @@ public class PyIntegratedToolsConfigurable implements SearchableConfigurable, No if (sdk != null) { final Object selectedItem = myTestRunnerComboBox.getSelectedItem(); if (PythonTestConfigurationsModel.PY_TEST_NAME.equals(selectedItem)) { - if (!VFSTestFrameworkListener.getInstance().isPyTestInstalled(sdk.getHomePath())) { + if (!VFSTestFrameworkListener.getInstance().isPyTestInstalled(sdk)) { return new ValidationResult(PyBundle.message("runcfg.testing.no.test.framework", "py.test"), createQuickFix(sdk, facetErrorPanel, PyNames.PY_TEST)); } } else if (PythonTestConfigurationsModel.PYTHONS_NOSETEST_NAME.equals(selectedItem)) { - if (!VFSTestFrameworkListener.getInstance().isNoseTestInstalled(sdk.getHomePath())) { + if (!VFSTestFrameworkListener.getInstance().isNoseTestInstalled(sdk)) { return new ValidationResult(PyBundle.message("runcfg.testing.no.test.framework", "nosetest"), createQuickFix(sdk, facetErrorPanel, PyNames.NOSE_TEST)); } } else if (PythonTestConfigurationsModel.PYTHONS_ATTEST_NAME.equals(selectedItem)) { - if (!VFSTestFrameworkListener.getInstance().isAtTestInstalled(sdk.getHomePath())) { + if (!VFSTestFrameworkListener.getInstance().isAtTestInstalled(sdk)) { return new ValidationResult(PyBundle.message("runcfg.testing.no.test.framework", "attest"), createQuickFix(sdk, facetErrorPanel, PyNames.AT_TEST)); } diff --git a/python/src/com/jetbrains/python/documentation/doctest/PyDocstringLexer.java b/python/src/com/jetbrains/python/documentation/doctest/PyDocstringLexer.java index 04b80d1906a7..9f71faa7a211 100644 --- a/python/src/com/jetbrains/python/documentation/doctest/PyDocstringLexer.java +++ b/python/src/com/jetbrains/python/documentation/doctest/PyDocstringLexer.java @@ -51,6 +51,11 @@ public class PyDocstringLexer extends PythonIndentingLexer { } advanceBase(); } + if (getBaseTokenType() == PyTokenTypes.LINE_BREAK) { + advanceBase(); + return 0; + } + if (getBaseTokenType() == null) { return 0; } diff --git a/python/src/com/jetbrains/python/testing/PyTestRunnerUpdater.java b/python/src/com/jetbrains/python/testing/PyTestRunnerUpdater.java index f4248e56c4f6..92e149f2f747 100644 --- a/python/src/com/jetbrains/python/testing/PyTestRunnerUpdater.java +++ b/python/src/com/jetbrains/python/testing/PyTestRunnerUpdater.java @@ -92,11 +92,11 @@ public class PyTestRunnerUpdater implements StartupActivity { final Sdk sdk = PythonSdkType.findPythonSdk(module); if (sdk != null && sdk.getSdkType() instanceof PythonSdkType && testRunner.isEmpty()) { String sdkHome = sdk.getHomePath(); - if (VFSTestFrameworkListener.isTestFrameworkInstalled(sdkHome, VFSTestFrameworkListener.NOSETESTSEARCHER)) + if (VFSTestFrameworkListener.isTestFrameworkInstalled(sdk, PyNames.NOSE_TEST)) testRunner = PythonTestConfigurationsModel.PYTHONS_NOSETEST_NAME; - else if (VFSTestFrameworkListener.isTestFrameworkInstalled(sdkHome, VFSTestFrameworkListener.PYTESTSEARCHER)) + else if (VFSTestFrameworkListener.isTestFrameworkInstalled(sdk, PyNames.PY_TEST)) testRunner = PythonTestConfigurationsModel.PY_TEST_NAME; - else if (VFSTestFrameworkListener.isTestFrameworkInstalled(sdkHome, VFSTestFrameworkListener.ATTESTSEARCHER)) + else if (VFSTestFrameworkListener.isTestFrameworkInstalled(sdk, PyNames.AT_TEST)) testRunner = PythonTestConfigurationsModel.PYTHONS_ATTEST_NAME; } @@ -140,7 +140,7 @@ public class PyTestRunnerUpdater implements StartupActivity { testRunner = PythonTestConfigurationsModel.PY_TEST_NAME; break; } - if (stringValue.contains(PyNames.AT_TEST)) { + if (stringValue.contains(PyNames.AT_TEST_IMPORT)) { testRunner = PythonTestConfigurationsModel.PYTHONS_ATTEST_NAME; break; } @@ -197,7 +197,7 @@ public class PyTestRunnerUpdater implements StartupActivity { if (PyNames.PY_TEST.equals(importElement.getVisibleName())) { return PythonTestConfigurationsModel.PY_TEST_NAME; } - if (PyNames.AT_TEST.equals(importElement.getVisibleName())) { + if (PyNames.AT_TEST_IMPORT.equals(importElement.getVisibleName())) { return PythonTestConfigurationsModel.PYTHONS_ATTEST_NAME; } } diff --git a/python/src/com/jetbrains/python/testing/VFSTestFrameworkListener.java b/python/src/com/jetbrains/python/testing/VFSTestFrameworkListener.java index 1fc16abc3bf3..00480374b637 100644 --- a/python/src/com/jetbrains/python/testing/VFSTestFrameworkListener.java +++ b/python/src/com/jetbrains/python/testing/VFSTestFrameworkListener.java @@ -1,6 +1,5 @@ package com.jetbrains.python.testing; -import com.intellij.execution.process.ProcessOutput; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.*; import com.intellij.openapi.diagnostic.Logger; @@ -17,12 +16,12 @@ import com.intellij.util.ui.update.MergingUpdateQueue; import com.intellij.util.ui.update.Update; import com.intellij.util.xmlb.XmlSerializerUtil; import com.jetbrains.python.PyNames; -import com.jetbrains.python.PythonHelpersLocator; -import com.jetbrains.python.sdk.PySdkUtil; +import com.jetbrains.python.packaging.PyExternalProcessException; +import com.jetbrains.python.packaging.PyPackageManager; +import com.jetbrains.python.packaging.PyPackageManagerImpl; import com.jetbrains.python.sdk.PythonSdkType; import org.jetbrains.annotations.NotNull; -import java.io.File; import java.util.List; import java.util.Map; @@ -39,9 +38,6 @@ import java.util.Map; public class VFSTestFrameworkListener implements ApplicationComponent, PersistentStateComponent { private static final Logger LOG = Logger.getInstance("#com.jetbrains.python.testing.VFSTestFrameworkListener"); - public static final String PYTESTSEARCHER = "pycharm/finders/find_pytest.py"; - public static final String NOSETESTSEARCHER = "pycharm/finders/find_nosetest.py"; - public static final String ATTESTSEARCHER = "pycharm/finders/find_attest.py"; private static final MergingUpdateQueue myQueue = new MergingUpdateQueue("TestFrameworkChecker", 5000, true, null); @@ -61,14 +57,14 @@ public class VFSTestFrameworkListener implements ApplicationComponent, Persisten for (String root : sdk.getRootProvider().getUrls(OrderRootType.CLASSES)) { if (path.contains(root)) { if (containsNose) { - updateTestFrameworks(sdk.getHomePath(), NOSETESTSEARCHER, PyNames.NOSE_TEST); + updateTestFrameworks(sdk, PyNames.NOSE_TEST); break SDKLOOP; } else if (containsPy) { - updateTestFrameworks(sdk.getHomePath(), PYTESTSEARCHER, PyNames.PY_TEST); + updateTestFrameworks(sdk, PyNames.PY_TEST); break SDKLOOP; } else { - updateTestFrameworks(sdk.getHomePath(), ATTESTSEARCHER, PyNames.AT_TEST); + updateTestFrameworks(sdk, PyNames.AT_TEST); break SDKLOOP; } } @@ -79,18 +75,18 @@ public class VFSTestFrameworkListener implements ApplicationComponent, Persisten }); } - public void updateAllTestFrameworks(final String sdkHome) { - updateTestFrameworks(sdkHome, PYTESTSEARCHER, PyNames.PY_TEST); - updateTestFrameworks(sdkHome, NOSETESTSEARCHER, PyNames.NOSE_TEST); - updateTestFrameworks(sdkHome, ATTESTSEARCHER, PyNames.AT_TEST); + public void updateAllTestFrameworks(final Sdk sdk) { + updateTestFrameworks(sdk, PyNames.PY_TEST); + updateTestFrameworks(sdk, PyNames.NOSE_TEST); + updateTestFrameworks(sdk, PyNames.AT_TEST); myQueue.flush(); } - public void updateTestFrameworks(final String sdkHome, final String searcher, final String sdkType) { - myQueue.queue(new Update(Pair.create(sdkHome, searcher)) { + public void updateTestFrameworks(final Sdk sdk, final String testPackageName) { + myQueue.queue(new Update(Pair.create(sdk, testPackageName)) { @Override public void run() { - testInstalled(isTestFrameworkInstalled(sdkHome, searcher), sdkHome, sdkType); + testInstalled(isTestFrameworkInstalled(sdk, testPackageName), sdk.getHomePath(), testPackageName); } }); } @@ -109,24 +105,17 @@ public class VFSTestFrameworkListener implements ApplicationComponent, Persisten return "VFSTestFrameworkListener"; } - public static boolean isTestFrameworkInstalled(String sdkHome, String searcher) { - if (StringUtil.isEmptyOrSpaces(sdkHome)) { - LOG.info("Searching test runner in empty sdkHome"); + public static boolean isTestFrameworkInstalled(Sdk sdk, String testPackageName) { + if (sdk == null || StringUtil.isEmptyOrSpaces(sdk.getHomePath())) { + LOG.info("Searching test runner in empty sdk"); return false; } - final String formatter = new File(PythonHelpersLocator.getHelpersRoot(), searcher).getAbsolutePath(); - ProcessOutput - output = PySdkUtil.getProcessOutput(new File(sdkHome).getParent(), - new String[]{ - sdkHome, - formatter - }, - null, - 2000); - if (output.getExitCode() != 0 || !output.getStderr().isEmpty()) { - LOG.info("Cannot find test runner in " + sdkHome + ". Use searcher " + formatter + ".\nGot exit code: " + output.getExitCode() + - ".\nError output: " + output.getStderr()); - return false; + final PyPackageManagerImpl packageManager = (PyPackageManagerImpl)PyPackageManager.getInstance(sdk); + try { + return packageManager.findPackage(testPackageName) != null; + } + catch (PyExternalProcessException e) { + LOG.info("Can't load package list " + e.getMessage()); } return true; } @@ -153,10 +142,10 @@ public class VFSTestFrameworkListener implements ApplicationComponent, Persisten SDK_TO_PYTEST.put(sdkHome, installed); } - public boolean isPyTestInstalled(final String sdkHome) { - Boolean isInstalled = SDK_TO_PYTEST.get(sdkHome); + public boolean isPyTestInstalled(final Sdk sdk) { + Boolean isInstalled = SDK_TO_PYTEST.get(sdk.getHomePath()); if (isInstalled == null) { - updateTestFrameworks(sdkHome, PYTESTSEARCHER, PyNames.PY_TEST); + updateTestFrameworks(sdk, PyNames.PY_TEST); return true; } return isInstalled; @@ -166,10 +155,10 @@ public class VFSTestFrameworkListener implements ApplicationComponent, Persisten SDK_TO_NOSETEST.put(sdkHome, installed); } - public boolean isNoseTestInstalled(final String sdkHome) { - Boolean isInstalled = SDK_TO_NOSETEST.get(sdkHome); + public boolean isNoseTestInstalled(final Sdk sdk) { + Boolean isInstalled = SDK_TO_NOSETEST.get(sdk.getHomePath()); if (isInstalled == null) { - updateTestFrameworks(sdkHome, NOSETESTSEARCHER, PyNames.NOSE_TEST); + updateTestFrameworks(sdk, PyNames.NOSE_TEST); return true; } return isInstalled; @@ -179,10 +168,10 @@ public class VFSTestFrameworkListener implements ApplicationComponent, Persisten SDK_TO_ATTEST.put(sdkHome, installed); } - public boolean isAtTestInstalled(final String sdkHome) { - Boolean isInstalled = SDK_TO_ATTEST.get(sdkHome); + public boolean isAtTestInstalled(final Sdk sdk) { + Boolean isInstalled = SDK_TO_ATTEST.get(sdk.getHomePath()); if (isInstalled == null) { - updateTestFrameworks(sdkHome, ATTESTSEARCHER, PyNames.AT_TEST); + updateTestFrameworks(sdk, PyNames.AT_TEST); return true; } return isInstalled; diff --git a/python/src/com/jetbrains/python/testing/attest/PythonAtTestRunConfiguration.java b/python/src/com/jetbrains/python/testing/attest/PythonAtTestRunConfiguration.java index f5064f1be4d5..5d0c708ad022 100644 --- a/python/src/com/jetbrains/python/testing/attest/PythonAtTestRunConfiguration.java +++ b/python/src/com/jetbrains/python/testing/attest/PythonAtTestRunConfiguration.java @@ -8,6 +8,7 @@ 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.sdk.PythonSdkType; import com.jetbrains.python.testing.AbstractPythonTestRunConfiguration; import com.jetbrains.python.testing.VFSTestFrameworkListener; import org.jdom.Element; @@ -68,7 +69,7 @@ public class PythonAtTestRunConfiguration extends AbstractPythonTestRunConfigura @Override public void checkConfiguration() throws RuntimeConfigurationException { super.checkConfiguration(); - if (!VFSTestFrameworkListener.getInstance().isAtTestInstalled(getInterpreterPath())) + if (!VFSTestFrameworkListener.getInstance().isAtTestInstalled(PythonSdkType.findSdkByPath(getInterpreterPath()))) throw new RuntimeConfigurationWarning(PyBundle.message("runcfg.testing.no.test.framework", "attest")); } } diff --git a/python/src/com/jetbrains/python/testing/nosetest/PythonNoseTestRunConfiguration.java b/python/src/com/jetbrains/python/testing/nosetest/PythonNoseTestRunConfiguration.java index 7fe92734df32..fbf9ad151d54 100644 --- a/python/src/com/jetbrains/python/testing/nosetest/PythonNoseTestRunConfiguration.java +++ b/python/src/com/jetbrains/python/testing/nosetest/PythonNoseTestRunConfiguration.java @@ -9,6 +9,7 @@ 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.sdk.PythonSdkType; import com.jetbrains.python.testing.AbstractPythonTestRunConfiguration; import com.jetbrains.python.testing.VFSTestFrameworkListener; import org.jdom.Element; @@ -85,7 +86,7 @@ public class PythonNoseTestRunConfiguration extends AbstractPythonTestRunConfigu @Override public void checkConfiguration() throws RuntimeConfigurationException { super.checkConfiguration(); - if (!VFSTestFrameworkListener.getInstance().isNoseTestInstalled(getInterpreterPath())) + if (!VFSTestFrameworkListener.getInstance().isNoseTestInstalled(PythonSdkType.findSdkByPath(getInterpreterPath()))) throw new RuntimeConfigurationWarning(PyBundle.message("runcfg.testing.no.test.framework", "nosetest")); } diff --git a/python/src/com/jetbrains/python/testing/pytest/PyTestRunConfiguration.java b/python/src/com/jetbrains/python/testing/pytest/PyTestRunConfiguration.java index 82e3f6bd6369..d169b58e0bb3 100644 --- a/python/src/com/jetbrains/python/testing/pytest/PyTestRunConfiguration.java +++ b/python/src/com/jetbrains/python/testing/pytest/PyTestRunConfiguration.java @@ -10,6 +10,7 @@ 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.sdk.PythonSdkType; import com.jetbrains.python.testing.AbstractPythonTestRunConfiguration; import com.jetbrains.python.testing.VFSTestFrameworkListener; import org.jdom.Element; @@ -119,7 +120,7 @@ public class PyTestRunConfiguration extends AbstractPythonTestRunConfiguration i if (StringUtil.isEmptyOrSpaces(myTestToRun)) { throw new RuntimeConfigurationError("Please specify target folder or script"); } - if (!VFSTestFrameworkListener.getInstance().isPyTestInstalled(getInterpreterPath())) + if (!VFSTestFrameworkListener.getInstance().isPyTestInstalled(PythonSdkType.findSdkByPath(getInterpreterPath()))) throw new RuntimeConfigurationWarning(PyBundle.message("runcfg.testing.no.test.framework", "py.test")); } diff --git a/python/src/com/jetbrains/python/testing/pytest/PyTestRunnableScriptFilter.java b/python/src/com/jetbrains/python/testing/pytest/PyTestRunnableScriptFilter.java index 48f69dc80e41..e195d6afed1b 100644 --- a/python/src/com/jetbrains/python/testing/pytest/PyTestRunnableScriptFilter.java +++ b/python/src/com/jetbrains/python/testing/pytest/PyTestRunnableScriptFilter.java @@ -28,7 +28,7 @@ public class PyTestRunnableScriptFilter implements RunnableScriptFilter { private static boolean isPyTestInstalled(Module module) { // TODO[yole] add caching to avoid disk I/O in findPyTestRunner()? final Sdk sdk = PythonSdkType.findPythonSdk(module); - return sdk != null && VFSTestFrameworkListener.getInstance().isPyTestInstalled(sdk.getHomePath()); + return sdk != null && VFSTestFrameworkListener.getInstance().isPyTestInstalled(sdk); } public static boolean isPyTestScript(PsiFile script) {