package de.mpicbg.knime.scripting.python.snippet;
import org.eclipse.jface.preference.IPreferenceStore;
import org.knime.core.node.BufferedDataTable;
import org.knime.core.node.ExecutionContext;
import org.knime.core.node.port.PortObject;
import org.knime.core.node.port.PortType;
import de.mpicbg.knime.scripting.core.AbstractScriptingNodeModel;
import de.mpicbg.knime.scripting.core.exceptions.KnimeScriptingException;
import de.mpicbg.knime.scripting.python.AbstractPythonScriptingNodeModel;
import de.mpicbg.knime.scripting.python.PythonScriptingBundleActivator;
import de.mpicbg.knime.scripting.python.PythonTableConverter;
import de.mpicbg.knime.scripting.python.prefs.PythonPreferenceInitializer;
import de.mpicbg.knime.scripting.python.srv.CommandOutput;
import de.mpicbg.knime.scripting.python.srv.LocalPythonClient;
import de.mpicbg.knime.scripting.python.srv.PythonClient;
/**
* This is the model implementation of PythonSnippet. Python integration for Knime.
*
* @author Tom Haux (MPI-CBG)
*/
public class PythonSnippetNodeModel extends AbstractPythonScriptingNodeModel {
public static final String DEFAULT_SCRIPT = "pyOut = kIn # both are assumed to be dictionaries";
public PythonSnippetNodeModel() {
super(createPorts(1), createPorts(1));
}
/**
* Constructor for the node model.
*/
protected PythonSnippetNodeModel(PortType[] inPorts, PortType[] outports) {
super(inPorts, outports);
}
@Override
public String getDefaultScript(String defaultScript) {
return super.getDefaultScript(DEFAULT_SCRIPT);
}
/**
* {@inheritDoc}
*/
@Override
protected PortObject[] executeImpl(PortObject[] inData,
ExecutionContext exec) throws Exception {
IPreferenceStore preferences = PythonScriptingBundleActivator.getDefault().getPreferenceStore();
boolean local = preferences.getBoolean(PythonPreferenceInitializer.PYTHON_LOCAL);
String host = preferences.getString(PythonPreferenceInitializer.PYTHON_HOST);
int port = preferences.getInt(PythonPreferenceInitializer.PYTHON_PORT);
// If the host is empty use a local client, otherwise use the server values
python = local ? new LocalPythonClient() : new PythonClient(host, port);
createTempFiles();
BufferedDataTable[] inTables = AbstractScriptingNodeModel.castToBDT(inData);
// Write data into csv
logger.info("Writing table to CSV file");
PythonTableConverter.convertTableToCSV(exec, inTables[0], kInFile.getClientFile(), logger);
kInFile.upload();
// Execute script
logger.info("Creating and executing python script: " + scriptFile.getClientPath());
String script = prepareScript();
try {
// Get the path to the python executable
String pythonExecPath = local ? preferences.getString(PythonPreferenceInitializer.PYTHON_EXECUTABLE) : "python";
CommandOutput output = python.executeCommand(new String[]{pythonExecPath, script});
for (String o : output.getStandardOutput()) {
logger.info(o);
}
for (String o : output.getErrorOutput()) {
logger.error(o);
}
} catch (Throwable t) {
throw new RuntimeException(t);
}
// If an output file wasn't created, error out
pyOutFile.fetch();
if (!pyOutFile.getClientFile().exists()) {
throw new RuntimeException(pyOutFile.getClientPath() + ": file not found");
}
// Parse result, if any, back into table
boolean hasOutput = pyOutFile.getClientFile().exists() && pyOutFile.getClientFile().length() != 0;
if (!hasOutput) throw new RuntimeException("No python output table found, check script output");
logger.info("Reading python output into Knime table");
BufferedDataTable[] resultTable = new BufferedDataTable[]{PythonTableConverter.convertCSVToTable(exec, pyOutFile.getClientFile(), logger)};
deleteTempFiles();
return resultTable;
}
/**
* {@inheritDoc}
*/
@Override
protected void openIn(PortObject[] inData, ExecutionContext exec)
throws KnimeScriptingException {
openInPython(inData, exec, logger);
setWarningMessage("To push the node's input to R again, you need to reset and re-execute it.");
}
}