PY-20194: Use module root or test parent directory as working dir if not set explicitly.

Default workdir for PyCharm is its installation folder. Always never should it be used as working dir for script it runs. If user does not provide working dir, we must guess it. #getWorkingDirSafe() does this guess. It takes directory for script, directory for test or simply first module root. See its javadoc and usage for details.
This commit is contained in:
Ilya.Kazakevich
2016-07-28 23:53:19 +03:00
parent d3d1d297f8
commit b44bf60f0a
6 changed files with 109 additions and 22 deletions

View File

@@ -30,6 +30,7 @@ import com.intellij.openapi.options.SettingsEditor;
import com.intellij.openapi.options.SettingsEditorGroup;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.JDOMExternalizerUtil;
@@ -302,6 +303,7 @@ public abstract class AbstractPythonRunConfiguration<T extends AbstractPythonRun
mySdkHome = sdkHome;
}
@Nullable
public Module getModule() {
return getConfigurationModule().getModule();
}
@@ -451,16 +453,34 @@ public abstract class AbstractPythonRunConfiguration<T extends AbstractPythonRun
}
/**
* @return working directory to run, never null, does its best to return project dir if empty.
* Note to inheritors: Always check {@link #getWorkingDirectory()} first. You should return it, if it is not empty since
* user should be able to set dir explicitly. Then, do your guess and return super as last resort.
*
* @return working directory to run, never null, does its best to guess which dir to use.
* Unlike {@link #getWorkingDirectory()} it does not simply take directory from config.
*/
@NotNull
public String getWorkingDirectorySafe() {
final String result = StringUtil.isEmpty(myWorkingDirectory) ? getProject().getBasePath() : myWorkingDirectory;
if (result == null) {
return new File(".").getAbsolutePath();
if (result != null) {
return result;
}
return result;
final String firstModuleRoot = getFirstModuleRoot();
if (firstModuleRoot != null) {
return firstModuleRoot;
}
return new File(".").getAbsolutePath();
}
@Nullable
private String getFirstModuleRoot() {
final Module module = getModule();
if (module == null) {
return null;
}
final VirtualFile[] roots = ModuleRootManager.getInstance(module).getContentRoots();
return roots.length > 0 ? roots[0].getPath() : null;
}
@Override

View File

@@ -26,6 +26,7 @@ import com.intellij.openapi.util.JDOMExternalizerUtil;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiElement;
@@ -66,6 +67,28 @@ public abstract class AbstractPythonTestRunConfiguration extends AbstractPythonR
super(project, configurationFactory);
}
@NotNull
@Override
public String getWorkingDirectorySafe() {
final String workingDirectoryFromConfig = getWorkingDirectory();
if (StringUtil.isNotEmpty(workingDirectoryFromConfig)) {
return workingDirectoryFromConfig;
}
final String folderName = myFolderName;
if (!StringUtil.isEmptyOrSpaces(folderName)) {
return folderName;
}
final String scriptName = myScriptName;
if (!StringUtil.isEmptyOrSpaces(scriptName)) {
final VirtualFile script = LocalFileSystem.getInstance().findFileByPath(scriptName);
if (script != null) {
return script.getParent().getPath();
}
}
return super.getWorkingDirectorySafe();
}
@Override
public void readExternal(Element element) throws InvalidDataException {
super.readExternal(element);

View File

@@ -24,7 +24,6 @@ import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.execution.configurations.ParamsGroup;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.testframework.TestFrameworkRunningModel;
import com.intellij.execution.testframework.autotest.ToggleAutoTestAction;
import com.intellij.execution.testframework.sm.SMTestRunnerConnectionUtil;
import com.intellij.execution.testframework.sm.runner.ui.SMTRunnerConsoleView;
@@ -32,10 +31,7 @@ import com.intellij.execution.testframework.ui.BaseTestsOutputConsoleView;
import com.intellij.execution.ui.ConsoleView;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Getter;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.jetbrains.python.HelperPackage;
import com.jetbrains.python.PythonHelpersLocator;
import com.jetbrains.python.console.PythonDebugLanguageConsoleView;
@@ -112,20 +108,8 @@ public abstract class PythonTestCommandLineStateBase extends PythonCommandLineSt
cmd.withWorkDirectory(workingDirectory);
}
else if (myConfiguration instanceof AbstractPythonTestRunConfiguration) {
final String folderName = ((AbstractPythonTestRunConfiguration)myConfiguration).getFolderName();
if (!StringUtil.isEmptyOrSpaces(folderName)) {
cmd.withWorkDirectory(folderName);
}
else {
final String scriptName = ((AbstractPythonTestRunConfiguration)myConfiguration).getScriptName();
if (StringUtil.isEmptyOrSpaces(scriptName)) return;
final VirtualFile script = LocalFileSystem.getInstance().findFileByPath(scriptName);
if (script == null) return;
cmd.withWorkDirectory(script.getParent().getPath());
}
}
if (cmd.getWorkDirectory() == null) { // If current dir still not set, lets use project dir
cmd.setWorkDirectory(myConfiguration.getWorkingDirectorySafe());
final AbstractPythonTestRunConfiguration configuration = (AbstractPythonTestRunConfiguration)myConfiguration;
cmd.withWorkDirectory(configuration.getWorkingDirectorySafe());
}
}

View File

@@ -30,6 +30,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.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.sdk.PythonSdkType;
@@ -76,6 +77,26 @@ public class PyTestRunConfiguration extends AbstractPythonTestRunConfiguration i
return myTestToRun;
}
@NotNull
@Override
public String getWorkingDirectorySafe() {
final String workingDirectoryFromConfig = getWorkingDirectory();
if (StringUtil.isNotEmpty(workingDirectoryFromConfig)) {
return workingDirectoryFromConfig;
}
final String testToRun = myTestToRun;
if (testToRun != null) {
final VirtualFile path = LocalFileSystem.getInstance().findFileByPath(testToRun);
if (path != null) {
if (path.isDirectory()) {
return path.getPath();
}
return path.getParent().getPath();
}
}
return super.getWorkingDirectorySafe();
}
public void setTestToRun(String testToRun) {
myTestToRun = testToRun;
}

View File

@@ -0,0 +1,4 @@
import os
def test_test():
print("Directory {0}".format(os.getcwd()))

View File

@@ -2,6 +2,7 @@ package com.jetbrains.env.python.testing;
import com.intellij.execution.testframework.AbstractTestProxy;
import com.intellij.execution.testframework.sm.runner.ui.MockPrinter;
import com.intellij.openapi.vfs.VirtualFile;
import com.jetbrains.env.EnvTestTagsRequired;
import com.jetbrains.env.PyEnvTestCase;
import com.jetbrains.env.PyProcessWithConsoleTestTask;
@@ -9,11 +10,13 @@ import com.jetbrains.env.ut.PyTestTestProcessRunner;
import com.jetbrains.python.sdkTools.SdkCreationType;
import com.jetbrains.python.testing.PythonTestConfigurationsModel;
import com.jetbrains.python.testing.pytest.PyTestConfigurationProducer;
import com.jetbrains.python.testing.pytest.PyTestRunConfiguration;
import org.hamcrest.Matchers;
import org.jetbrains.annotations.NotNull;
import org.junit.Assert;
import org.junit.Test;
import java.io.IOException;
import java.util.List;
import static org.junit.Assert.assertEquals;
@@ -52,6 +55,38 @@ public class PythonPyTestingTest extends PyEnvTestCase {
});
}
/**
* Ensure project dir is used as curdir even if not set explicitly
*/
@Test
public void testCurrentDir() throws Exception {
runPythonTest(new PyProcessWithConsoleTestTask<PyTestTestProcessRunner>("/testRunner/env/pytest/", SdkCreationType.EMPTY_SDK) {
@NotNull
@Override
protected PyTestTestProcessRunner createProcessRunner() throws Exception {
return new PyTestTestProcessRunner("", 0) {
@Override
protected void configurationCreatedAndWillLaunch(@NotNull final PyTestRunConfiguration configuration) throws IOException {
super.configurationCreatedAndWillLaunch(configuration);
configuration.setWorkingDirectory(null);
final VirtualFile fullFilePath = myFixture.getTempDirFixture().getFile("dir_test.py");
assert fullFilePath != null : String.format("No dir_test.py in %s", myFixture.getTempDirFixture().getTempDirPath());
configuration.setTestToRun(fullFilePath.getPath());
}
};
}
@Override
protected void checkTestResults(@NotNull final PyTestTestProcessRunner runner,
@NotNull final String stdout,
@NotNull final String stderr,
@NotNull final String all) {
Assert.assertThat("No directory found in output", stdout,
Matchers.containsString(String.format("Directory %s", myFixture.getTempDirPath())));
}
});
}
@Test
public void testPytestRunner() {