Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use dmypy instead of mypy #58

Closed
wants to merge 12 commits into from
10 changes: 10 additions & 0 deletions src/main/java/com/leinardi/pycharm/mypy/MypyConfigService.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,13 @@ public class MypyConfigService implements PersistentStateComponent<MypyConfigSer
private String mypyConfigFilePath;
private String mypyArguments;
private boolean scanBeforeCheckin;
private boolean useDaemon;

public MypyConfigService() {
customMypyPath = "";
mypyArguments = "";
mypyConfigFilePath = "";
useDaemon = false;
}

public String getCustomMypyPath() {
Expand Down Expand Up @@ -70,6 +72,14 @@ public void setScanBeforeCheckin(boolean scanBeforeCheckin) {
this.scanBeforeCheckin = scanBeforeCheckin;
}

public boolean isUseDaemon() {
return useDaemon;
}

public void setUseDaemon(boolean useDaemon) {
this.useDaemon = useDaemon;
}

@Nullable
@Override
public MypyConfigService getState() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ public void reset() {
public boolean isModified() {
boolean result = !configPanel.getMypyPath().equals(mypyConfigService.getCustomMypyPath())
|| !configPanel.getMypyConfigFilePath().equals(mypyConfigService.getMypyConfigFilePath())
|| !configPanel.getMypyArguments().equals(mypyConfigService.getMypyArguments());
|| !configPanel.getMypyArguments().equals(mypyConfigService.getMypyArguments())
|| !configPanel.getUseDaemon() == (mypyConfigService.isUseDaemon());
if (LOG.isDebugEnabled()) {
LOG.debug("Has config changed? " + result);
}
Expand All @@ -80,6 +81,7 @@ public void apply() {
mypyConfigService.setCustomMypyPath(configPanel.getMypyPath());
mypyConfigService.setMypyConfigFilePath(configPanel.getMypyConfigFilePath());
mypyConfigService.setMypyArguments(configPanel.getMypyArguments());
mypyConfigService.setUseDaemon(configPanel.getUseDaemon());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ private File relativePathToModuleContentRoots(final @NotNull PsiFile file, final
}

private File prepareBaseTmpDirFor(final PsiFile tempPsiFile) {
final File baseTmpDir = new File(new TempDirProvider().forPersistedPsiFile(tempPsiFile),
final File baseTmpDir = new File(new TempDirProvider(tempPsiFile.getProject()).forPersistedPsiFile(tempPsiFile),
tempFileDirectoryName());
baseTmpDir.deleteOnExit();
return baseTmpDir;
Expand Down
61 changes: 41 additions & 20 deletions src/main/java/com/leinardi/pycharm/mypy/mpapi/MypyRunner.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.InterruptedIOException;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
Expand Down Expand Up @@ -87,12 +88,9 @@ public static boolean isMypyPathValid(String mypyPath, Project project) {
return false;
}
GeneralCommandLine cmd = getMypyCommandLine(project, mypyPath);
boolean daemon = false;
if (daemon) {
cmd.addParameter("status");
} else {
cmd.addParameter("-V");
}

cmd.addParameter("-V");

final Process process;
try {
process = cmd.createProcess();
Expand Down Expand Up @@ -272,19 +270,23 @@ private static List<Issue> runMypy(Project project, Set<String> filesToScan, Str
if (filesToScan.isEmpty()) {
return Collections.emptyList();
}
boolean daemon = false;

if (mypyConfigService.isUseDaemon()) {
// build path to dmypy by assuming that it sits right next to the selected mypy executable
// with the only difference being that the name has "dmypy" in it rather than just "mypy"
Path p = Paths.get(mypyPath);
String dFile = p.getFileName().toString().replace("mypy", "dmypy");
mypyPath = Paths.get(p.getParent().toString(), dFile).toString();
}

GeneralCommandLine cmd = new GeneralCommandLine(mypyPath);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The daemon has its own executable called "dmypy" which is next to "mypy" in the same folder. If useDaemon is true we would need to change that here.

cmd.setCharset(Charset.forName("UTF-8"));
if (daemon) {
cmd.setCharset(UTF_8);
if (mypyConfigService.isUseDaemon()) {
cmd.addParameter("run");
cmd.addParameter("--");
cmd.addParameter("``--show-column-numbers");
} else {
cmd.addParameter("--show-column-numbers");
}
cmd.addParameter("--follow-imports");
cmd.addParameter("silent");

cmd.addParameter("--show-column-numbers");

injectEnvironmentVariables(project, cmd);

Expand All @@ -300,12 +302,31 @@ private static List<Issue> runMypy(Project project, Set<String> filesToScan, Str
cmd.addParameter(file);
}
cmd.setWorkDirectory(project.getBasePath());
final Process process;

LOG.debug("Command Line string: " + cmd.getCommandLineString());
try {
process = cmd.createProcess();
InputStream inputStream = process.getInputStream();
//TODO check stderr for errors
// process.waitFor();
final int retryLimit = 5;
InputStream inputStream = null;
for (int retryCount = 1; retryCount <= retryLimit; retryCount++) {
final Process process = cmd.createProcess();
inputStream = process.getInputStream();

String error = new BufferedReader(new InputStreamReader(process.getErrorStream(), UTF_8))
.lines().collect(Collectors.joining("\n"));
if (StringUtil.isEmpty(error)) {
break;
} else {
LOG.info("Command Line string: " + cmd.getCommandLineString());
// the daemon sometimes fails when idea invokes the inspection multiple times
if (mypyConfigService.isUseDaemon() && error.equals("The connection is busy.")) {
LOG.warn(error + " attempt #" + retryCount);
} else {
throw new MypyToolException("Error while running Mypy: " + error);
}
}
}

// process.waitFor();
return parseMypyOutput(inputStream);
} catch (InterruptedIOException e) {
LOG.info("Command Line string: " + cmd.getCommandLineString());
Expand Down
12 changes: 10 additions & 2 deletions src/main/java/com/leinardi/pycharm/mypy/ui/MypyConfigPanel.form
Original file line number Diff line number Diff line change
@@ -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.leinardi.pycharm.mypy.ui.MypyConfigPanel">
<grid id="27dc6" binding="rootPanel" layout-manager="GridLayoutManager" row-count="4" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<grid id="27dc6" binding="rootPanel" layout-manager="GridLayoutManager" row-count="5" column-count="3" 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="667" height="184"/>
Expand Down Expand Up @@ -37,7 +37,7 @@
</component>
<vspacer id="1b350">
<constraints>
<grid row="3" 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="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"/>
</constraints>
</vspacer>
<component id="90410" class="com.intellij.ui.components.JBLabel">
Expand Down Expand Up @@ -70,6 +70,14 @@
</constraints>
<properties/>
</component>
<component id="14b64" class="com.intellij.ui.components.JBCheckBox" binding="useDaemonCheckBox">
<constraints>
<grid row="3" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Use Daemon"/>
</properties>
</component>
</children>
</grid>
</form>
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.TextComponentAccessor;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.ui.components.JBCheckBox;
import com.intellij.ui.components.JBTextField;
import com.leinardi.pycharm.mypy.MypyBundle;
import com.leinardi.pycharm.mypy.MypyConfigService;
Expand All @@ -39,6 +40,7 @@ public class MypyConfigPanel {
private com.intellij.openapi.ui.TextFieldWithBrowseButton mypyPathField;
private com.intellij.openapi.ui.TextFieldWithBrowseButton mypyConfigFilePathField;
private JBTextField argumentsField;
private JBCheckBox useDaemonCheckBox;
private Project project;

public MypyConfigPanel(Project project) {
Expand Down Expand Up @@ -66,6 +68,7 @@ public MypyConfigPanel(Project project) {
TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT);
argumentsField.setText(mypyConfigService.getMypyArguments());
argumentsField.getEmptyText().setText(MypyBundle.message("config.optional"));
useDaemonCheckBox.setSelected(mypyConfigService.isUseDaemon());
}

public JPanel getPanel() {
Expand All @@ -92,6 +95,8 @@ public String getMypyArguments() {
return argumentsField.getText();
}

public boolean getUseDaemon() { return useDaemonCheckBox.isSelected(); }

private void createUIComponents() {
JBTextField autodetectTextField = new JBTextField();
autodetectTextField.getEmptyText()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.leinardi.pycharm.mypy.MypyConfigService;
import org.jdesktop.swingx.util.OS;
import org.jetbrains.annotations.NotNull;

Expand All @@ -34,9 +35,16 @@
* Locate and/or create temporary directories for use by this plugin.
*/
public class TempDirProvider {
public TempDirProvider(Project project) {
this.mypyConfigService = MypyConfigService.getInstance(project);
}

private final MypyConfigService mypyConfigService;

public String forPersistedPsiFile(final PsiFile tempPsiFile) {
String systemTempDir = System.getProperty("java.io.tmpdir");
if (OS.isWindows() && driveLetterOf(systemTempDir) != driveLetterOf(pathOf(tempPsiFile))) {
if (mypyConfigService.isUseDaemon() || (OS.isWindows() && driveLetterOf(systemTempDir) != driveLetterOf(pathOf(tempPsiFile)))) {
// for some reason the daemon reports no errors unless the file is in the project directory
// Some tool on Windows requires the files to be on the same drive
final File projectTempDir = temporaryDirectoryLocationFor(tempPsiFile.getProject());
if (projectTempDir.exists() || projectTempDir.mkdirs()) {
Expand Down