source: java2python/src/test/java/tudelft/utilities/j2p/PyTest.java@ 374

Last change on this file since 374 was 374, checked in by wouter, 2 years ago

#113 hacky workaround, modify original parsetree...

File size: 6.8 KB
Line 
1package tudelft.utilities.j2p;
2
3import java.io.BufferedOutputStream;
4import java.io.BufferedReader;
5import java.io.File;
6import java.io.FileNotFoundException;
7import java.io.FileOutputStream;
8import java.io.FileWriter;
9import java.io.IOException;
10import java.io.InputStream;
11import java.io.InputStreamReader;
12import java.nio.file.Files;
13import java.nio.file.Path;
14import java.util.Arrays;
15import java.util.LinkedList;
16import java.util.List;
17
18import com.github.javaparser.JavaParser;
19import com.github.javaparser.ParseResult;
20import com.github.javaparser.ParserConfiguration;
21import com.github.javaparser.ast.CompilationUnit;
22import com.github.javaparser.symbolsolver.JavaSymbolSolver;
23import com.github.javaparser.symbolsolver.resolution.typesolvers.CombinedTypeSolver;
24import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver;
25
26import tudelft.utilities.j2p.formatting.Block;
27import tudelft.utilities.j2p.t.Translator;
28import tudelft.utilities.pyrunner.Call;
29import tudelft.utilities.pyrunner.PythonError;
30import tudelft.utilities.pyrunner.PythonVenv;
31
32public class PyTest {
33 private static final String TESTFILE = "test.py";
34 private static final File TESTDIR = new File("test/");
35
36 /**
37 *
38 * @param pycode the python code to run.
39 * @param fullclaspath a "package/class/path/filename.py" name containing
40 * the full filename where the file should be placed.
41 * This must be a RELATIVE name, we will prefix it with
42 * {@link #TESTDIR} as needed
43 * @return the text lines that the code printed to stdout.
44 * @throws Exception
45 */
46 public List<String> runPython(Block pycode, String fullclaspath)
47 throws Exception {
48 TESTDIR.delete();
49 File f = TESTDIR.toPath().resolve(fullclaspath).toFile();
50 f.getParentFile().mkdirs();// create dir, massaging java...
51 FileOutputStream fos = new FileOutputStream(f);
52 BufferedOutputStream bos = new BufferedOutputStream(fos);
53 // convert string to byte array
54 byte[] bytes = pycode.toString().getBytes();
55 // write byte array to file
56 bos.write(bytes);
57 bos.close();
58 fos.close();
59
60 Process process = Runtime.getRuntime().exec("python " + fullclaspath,
61 new String[0], TESTDIR);
62 List<String> errors = readAll(process.getErrorStream());
63 if (!errors.isEmpty())
64 throw new IllegalStateException("Python failed. " + errors);
65
66 return readAll(process.getInputStream());
67 }
68
69 /**
70 *
71 * @param pycode the python code to be zipped as pip-installable zip. It
72 * is assumed that the code is just 1 file.
73 * @param modulename The name of the module. It is assumed there is just 1
74 * module, and this module is also a directory in the root
75 * folder, and only 1 level deep. The main program must be
76 * in this module. FIXME should be in pycode.
77 * @return a zip {@link File} containing all the code, as a python tar.gz
78 * package that can be pip install'ed .
79 * @throws IOException
80 * @throws PythonError if python code to build tar.gz fails for
81 * some reason
82 * @throws InterruptedException
83 */
84 public File zip(Block pycode, String modulename)
85 throws IOException, InterruptedException, PythonError {
86 Path tmppath = Files.createTempDirectory("j2p");
87 System.out.println(tmppath);
88
89 // write the translated file
90 File f = tmppath.resolve(modulename + ".py").toFile();
91 f.getParentFile().mkdirs();// create dirs
92 FileOutputStream fos = new FileOutputStream(f);
93 BufferedOutputStream bos = new BufferedOutputStream(fos);
94 // convert string to byte array
95 byte[] bytes = pycode.toString().getBytes();
96 // write byte array to file
97 bos.write(bytes);
98 bos.close();
99 fos.close();
100
101 List<String> requirements = pycode.getInstalls().stream()
102 .map(str -> "\"" + str + "\"").toList();
103 // we must provide many nonsense fields like url and author to get this
104 // working...
105 String setuppy = "from setuptools import setup, find_packages\n" + "\n"
106 + "setup(\n" + " name='" + modulename + "',\n"
107 + " version=1,\n" + " author='Whatever',\n"
108 + " author_email='Whatever',\n"
109 + " url='http://nonsense'," + " py_modules=['"
110 + modulename + "'],\n" + " install_requires=" + requirements
111 + ",\n" + "\n" + " classifiers=[\n"
112 + " 'Programming Language :: Python :: 3.8',\n"
113 + " 'Programming Language :: Python :: 3.9'\n"
114 + " ],\n" + ")\n" + "";
115
116 f = tmppath.resolve("setup.py").toFile();
117 FileWriter fw = new FileWriter(f);
118 fw.write(setuppy);
119 fw.close();
120
121 // without readme, python complains
122 f = tmppath.resolve("README").toFile();
123 fw = new FileWriter(f);
124 fw.write("");
125 fw.close();
126
127// String setuppy = "import os; chdir(" + tmppath + ");";
128
129 // call python to build the package to be sure we have a correct package
130 new Call(PythonVenv.PYTHON3, Arrays.asList("setup.py", "sdist"), 30000,
131 tmppath.toFile()).run();
132
133 // -1 is the version number added py setup.py to the file
134 return tmppath.resolve("dist/" + modulename + "-1.tar.gz").toFile();
135 }
136
137 private List<String> readAll(InputStream in) throws IOException {
138 BufferedReader Buffered_Reader = new BufferedReader(
139 new InputStreamReader(in));
140 List<String> lines = new LinkedList<>();
141
142 String line;
143 while ((line = Buffered_Reader.readLine()) != null) {
144 lines.add(line);
145 }
146 return lines;
147 }
148
149 /**
150 * @param javaFile a java file name to be translated
151 * @return a string containing python code translated from the java.
152 * @throws FileNotFoundException
153 */
154 public Block translate(String javaFile) throws FileNotFoundException {
155 ParserConfiguration conf = new ParserConfiguration();
156 CombinedTypeSolver typeSolver = new CombinedTypeSolver();
157 typeSolver.add(new ReflectionTypeSolver(false));
158 // FIXME add sources of jars source code etc
159 // typeSolver.add(new JavaParserTypeSolver(new File(SOURCE_PATH)));
160 // typeSolver.add(new JarTypeSolver(jarSourceFile));
161 JavaSymbolSolver symbolSolver = new JavaSymbolSolver(typeSolver);
162 conf.setSymbolResolver(symbolSolver);
163 JavaParser parser = new JavaParser(conf);
164
165 ParseResult<CompilationUnit> res = parser.parse(new File(javaFile));
166// fixparseissues(res.getResult().get());
167
168 Block translation = Translator.translate(res.getResult().get());
169 return translation;
170 }
171
172// /**
173// * Post-processor on parse tree. It seemed that some annotations did not get the proper parent node. But they do have the proper parent node after all.
174// *
175// * @param res
176// */
177//
178// private void fixparseissues(Node node) {
179// if (node instanceof NodeWithAnnotations) {
180// NodeWithAnnotations nwa = (NodeWithAnnotations) node;
181// for (Object anno : nwa.getAnnotations()) {
182// ((Node) anno).setParentNode(node);
183// }
184// }
185// for (Node child : node.getChildNodes()) {
186// fixparseissues(child);
187// }
188// }
189//
190}
Note: See TracBrowser for help on using the repository browser.