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

Black pyi files #308

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@
import java.util.List;
import java.util.Set;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.python.pydev.core.IPyEdit;
import org.python.pydev.core.IPyFormatStdProvider;
import org.python.pydev.core.IPythonNature;
import org.python.pydev.core.MisconfigurationException;
Expand Down Expand Up @@ -806,9 +808,9 @@ public static void formatSelection(IDocument doc, int[] regionsForSave, IPyForma
String formattedAsStr;
try {
boolean allowChangingBlankLines = false;
IFile file = edit instanceof IPyEdit ? ((IPyEdit) edit).getIFile() : null;
formattedAsStr = formatStrAutopep8OrPyDev(edit != null ? edit.getPythonNature() : null, formatStd, true,
doc,
delimiter, allowChangingBlankLines);
file, doc, delimiter, allowChangingBlankLines);
formatted = new Document(formattedAsStr);
} catch (SyntaxErrorException e) {
return;
Expand Down Expand Up @@ -909,7 +911,8 @@ public static void formatSelection(IDocument doc, int[] regionsForSave, IPyForma
* @return a new (formatted) string
* @throws SyntaxErrorException
*/
/*default*/public static String formatStrAutopep8OrPyDev(IPythonNature nature, IDocument doc, FormatStd std,
/*default*/public static String formatStrAutopep8OrPyDev(IPythonNature nature, IDocument doc, IFile file,
FormatStd std,
String delimiter, boolean throwSyntaxError, boolean allowChangingBlankLines, File workingDir)
throws SyntaxErrorException {
switch (std.formatterStyle) {
Expand All @@ -924,7 +927,7 @@ public static void formatSelection(IDocument doc, int[] regionsForSave, IPyForma

return formatted;
case BLACK:
formatted = BlackRunner.formatWithBlack(nature, doc, std, workingDir);
formatted = BlackRunner.formatWithBlack(nature, file, doc, std, workingDir);
if (formatted == null) {
formatted = doc.get();
}
Expand All @@ -946,7 +949,7 @@ public static void formatSelection(IDocument doc, int[] regionsForSave, IPyForma
}

public static String formatStrAutopep8OrPyDev(IPythonNature nature, FormatStd formatStd, boolean throwSyntaxError,
IDocument doc, String delimiter, boolean allowChangingBlankLines)
IFile file, IDocument doc, String delimiter, boolean allowChangingBlankLines)
throws SyntaxErrorException {
File workingDir = null;
if (nature != null) {
Expand All @@ -959,16 +962,16 @@ public static String formatStrAutopep8OrPyDev(IPythonNature nature, FormatStd fo
}
}
return formatStrAutopep8OrPyDev(nature, formatStd, throwSyntaxError,
doc, delimiter, allowChangingBlankLines, workingDir);
file, doc, delimiter, allowChangingBlankLines, workingDir);
}

/**
* @param nature may be null (used for formatting with black).
*/
public static String formatStrAutopep8OrPyDev(IPythonNature nature, FormatStd formatStd, boolean throwSyntaxError,
IDocument doc, String delimiter, boolean allowChangingBlankLines, File workingDir)
IFile file, IDocument doc, String delimiter, boolean allowChangingBlankLines, File workingDir)
throws SyntaxErrorException {
String formatted = formatStrAutopep8OrPyDev(nature, doc, formatStd, delimiter, throwSyntaxError,
String formatted = formatStrAutopep8OrPyDev(nature, doc, file, formatStd, delimiter, throwSyntaxError,
allowChangingBlankLines, workingDir);
//To finish, check the end of line.
if (formatStd.addNewLineAtEndOfFile) {
Expand All @@ -992,8 +995,9 @@ public static void formatAll(IDocument doc, IPyFormatStdProvider edit, boolean i
String delimiter = PySelection.getDelimiter(doc);
String formatted;
try {
IFile file = (edit instanceof IPyEdit) ? ((IPyEdit) edit).getIFile() : null;
formatted = formatStrAutopep8OrPyDev(edit != null ? edit.getPythonNature() : null, formatStd,
throwSyntaxError, doc, delimiter, allowChangingLines);
throwSyntaxError, file, doc, delimiter, allowChangingLines);
} catch (MisconfigurationException e) {
Log.log(e);
return;
Expand Down Expand Up @@ -1086,8 +1090,8 @@ public static void main(String[] args) {
boolean allowChangingLines = true;
String newDocContents = "";
try {
newDocContents = PyFormatter.formatStrAutopep8OrPyDev(null, formatStd, true, newDoc, delimiter,
allowChangingLines);
newDocContents = PyFormatter.formatStrAutopep8OrPyDev(null, formatStd, true, null, newDoc,
delimiter, allowChangingLines);
} catch (SyntaxErrorException e) {
// Don't format: syntax is not Ok.
System.out.write(("Content-Length: 0\r\n").getBytes());
Expand Down Expand Up @@ -1124,8 +1128,8 @@ public static void main(String[] args) {
boolean allowChangingLines = true;
String newDocContents = "";
try {
newDocContents = PyFormatter.formatStrAutopep8OrPyDev(null, formatStd, true, newDoc, delimiter,
allowChangingLines);
newDocContents = PyFormatter.formatStrAutopep8OrPyDev(null, formatStd, true, null, newDoc,
delimiter, allowChangingLines);
} catch (SyntaxErrorException e) {
// Don't format: syntax is not Ok.
System.exit(1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.io.File;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jface.text.IDocument;
import org.python.pydev.ast.interpreter_managers.InterpreterManagersAPI;
Expand All @@ -20,17 +21,31 @@

public class BlackRunner {

public static String formatWithBlack(IPythonNature nature, IDocument doc, FormatStd std, File workingDir) {
public static String formatWithBlack(IPythonNature nature, IFile file, IDocument doc, FormatStd std,
File workingDir) {
try {
Process process;
String[] parseArguments = ProcessUtils.parseArguments(std.blackParameters);
String cmdarrayAsStr;

String ext;
if (file == null) {
Log.log("BlackRunner: File not supplied");
} else {
Log.logInfo("BlackRunner: Running for file: " + file);
}
boolean isPyi = file != null && (ext = file.getFileExtension()) != null & ext.equalsIgnoreCase("pyi");

String executableLocation = std.blackExecutableLocation;

//TEMP
System.out.println(std);

if (!std.searchBlackInInterpreter && executableLocation != null && !executableLocation.isEmpty()
&& new File(executableLocation).exists()) {
SimpleRunner simpleRunner = new SimpleRunner();
String[] args = ArrayUtils.concatArrays(new String[] { executableLocation, "-" }, parseArguments);
String[] args = ArrayUtils.concatArrays(isPyi ? new String[] { executableLocation, "-", "--pyi" }
: new String[] { executableLocation, "-" }, parseArguments);
Tuple<Process, String> r = simpleRunner.run(args, workingDir, null, null);
process = r.o1;
cmdarrayAsStr = r.o2;
Expand All @@ -44,8 +59,11 @@ && new File(executableLocation).exists()) {
}
}
PythonRunner pythonRunner = new PythonRunner(nature);
String[] args = ArrayUtils.concatArrays(
isPyi ? new String[] { "-", "--pyi" } : new String[] { "-" },
parseArguments);
Tuple<Process, String> processInfo = pythonRunner.createProcessFromModuleName("black",
ArrayUtils.concatArrays(new String[] { "-" }, parseArguments),
args,
workingDir, new NullProgressMonitor());
process = processInfo.o1;
cmdarrayAsStr = processInfo.o2;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package org.python.pydev.editor.actions;

import org.eclipse.jface.text.Document;
import org.python.pydev.ast.formatter.PyFormatter;
import org.python.pydev.core.docutils.SyntaxErrorException;
import org.python.pydev.core.formatter.FormatStd;
import org.python.pydev.core.formatter.FormatStd.FormatterEnum;
import org.python.pydev.shared_core.resource_stubs.AbstractIFileStub;

import junit.framework.TestCase;

public class PyFormatBlackTest extends TestCase {
private final class MockIFile extends AbstractIFileStub {
private final String ext;

private MockIFile(String ext) {
this.ext = ext;
}

@Override
public String getFileExtension() {
return ext;
}
}

static final String SRC = "from typing import (\n"
+ " Union, Dict\n"
+ " )\n"
+ "def a()->None: \n"
+ " ...\n"
+ "def b(_:Union[Dict[str,str],str])->int: \n"
+ " ...\n"
+ "d = [1, 2, 3]";

private static boolean DEBUG = false;

public static void main(String[] args) {
try {
PyFormatBlackTest n = new PyFormatBlackTest();
junit.textui.TestRunner.run(PyFormatBlackTest.class);
} catch (Throwable e) {
e.printStackTrace();
}

}

private FormatStd black;

private void checkFormat(String ext, String expected) {
try {
Document doc = new Document(SRC);
PyFormatter.formatAll(doc, new MockPyEdit(new MockIFile(ext)), true, black, false, true);
String formattedStr = doc.get();

assertEquals(expected, formattedStr);
} catch (SyntaxErrorException e) {
throw new RuntimeException(e);
}
}

/**
* @see junit.framework.TestCase#setUp()
*/
@Override
protected void setUp() throws Exception {
super.setUp();
black = new FormatStd();
black.formatterStyle = FormatterEnum.BLACK;
black.searchBlackInInterpreter = false;

//TODO: get black location from config?
black.blackExecutableLocation = System.getenv("LOCALAPPDATA")
+ "\\Programs\\Python\\Python37\\Scripts\\black.exe";
Comment on lines +71 to +73
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure the best way to get black executable when running unit tests

Copy link
Owner

Choose a reason for hiding this comment

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

This should be based on something from org.python.pydev.core.TestDependent.

The values there are computed when TestDependent is imported.

You can create a file custom for your machine by setting the environment variable "PYDEV_TEST_PLATFORM" to some value -- say: zeckie -- and then create a TestDependent.zeckie.properties file based on the values of one of the existing templates there.

Ideally it should be a new entry there with a default value computed based on the TestDependent.PYTHON_INSTALL (to do that, change the static{} block on TestDependent to fill the value if it wasn't loaded).


System.out.println(black);
}

/**
* Check that py file is formatted using Black's standard format
* @throws Exception
*/
public void testPyFormat() throws Exception {
checkFormat("py", "from typing import Union, Dict\n"
+ "\n"
+ "\n"
+ "def a() -> None:\n"
+ " ...\n"
+ "\n"
+ "\n"
+ "def b(_: Union[Dict[str, str], str]) -> int:\n"
+ " ...\n"
+ "\n"
+ "\n"
+ "d = [1, 2, 3]\n");
}

/**
* Check that pyi (python stub) file is formatted using Black's more compact format
* @throws Exception
*/
public void testPyiFormat() throws Exception {
checkFormat("py", "from typing import Union, Dict\n"
+ "\n"
+ "def a() -> None: ...\n"
+ "def b(_: Union[Dict[str, str], str]) -> int: ...\n"
+ "\n"
+ "d = [1, 2, 3]\n");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -1070,7 +1070,8 @@ private void checkFormatResults(String s, String expected) {
formatStr = doc.get();
assertEquals(expected, formatStr);

formatStr = PyFormatter.formatStrAutopep8OrPyDev(null, new Document(s2), std, "\r", false, true, null);
formatStr = PyFormatter.formatStrAutopep8OrPyDev(null, new Document(s2), null, std, "\r", false, true,
null);
if (expected2.endsWith("\r") && !formatStr.endsWith("\r")) {
expected2 = expected2.substring(0, expected2.length() - 1);
}
Expand All @@ -1080,7 +1081,8 @@ private void checkFormatResults(String s, String expected) {
String s3 = StringUtils.replaceAll(s, "\n", "\r\n");
String expected3 = StringUtils.replaceAll(expected, "\n", "\r\n");

formatStr = PyFormatter.formatStrAutopep8OrPyDev(null, new Document(s3), std, "\r\n", false, true, null);
formatStr = PyFormatter.formatStrAutopep8OrPyDev(null, new Document(s3), null, std, "\r\n", false, true,
null);
if (expected3.endsWith("\r\n") && !formatStr.endsWith("\r\n")) {
expected3 = expected3.substring(0, expected3.length() - 2);
}
Expand Down