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

Jython 2.7 compatibility #250

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion nodel-jyhost/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ dependencies {
compile project(':nodel-framework')
compile 'commons-daemon:commons-daemon:1.0.15'
compile 'org.slf4j:slf4j-api:1.7.10'
compile 'org.python:jython-standalone:2.5.4-rc1'
compile 'org.python:jython-standalone:2.7.2'

// for the Nodel HTTP client:
compile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.5'
Expand Down
88 changes: 59 additions & 29 deletions nodel-jyhost/src/main/java/org/nodel/jyhost/PyNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
import org.python.core.PyDictionary;
import org.python.core.PyException;
import org.python.core.PyFunction;
import org.python.core.PyInteger;
import org.python.core.PyObject;
import org.python.core.PyString;
import org.python.core.PySystemState;
Expand Down Expand Up @@ -625,10 +626,16 @@ private void applyConfig0(NodeConfig config) throws Exception {
lock = getAReentrantLock();

trackFunction("(toolkit injection)");

// use this import to provide a toolkit directly into the script
_python.exec("from nodetoolkit import *");

if (((PyInteger) _python.eval("'nodetoolkit' in dir(__import__('sys'))")).asInt() > 0) {
Copy link
Author

Choose a reason for hiding this comment

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

There's maybe a nicer way of getting a boolean back from the interpreter but AFAICT this works.

// Jython 2.7 exposes system state through sys
_python.exec("from sys.nodetoolkit import *");
} else {
// Jython 2.5 exposes system state at top-level
_python.exec("from nodetoolkit import *");
}

} finally {
untrackFunction("(toolkit injection)");

Expand Down Expand Up @@ -742,28 +749,33 @@ private void applyConfig0(NodeConfig config) throws Exception {
List<String> commentary = new ArrayList<>(3);

trackFunction("mains");

// handle @before_main functions (if present)
PyFunction processBeforeMainFunctions = (PyFunction) _globals.get(Py.java2py("processBeforeMainFunctions"));
long beforeFnCount = processBeforeMainFunctions.__call__().asLong();

if (beforeFnCount > 0)
if (_globals.get(Py.java2py("processBeforeMainFunctions")) instanceof PyFunction) {
PyFunction processBeforeMainFunctions = (PyFunction) _globals.get(Py.java2py("processBeforeMainFunctions"));
long beforeFnCount = processBeforeMainFunctions.__call__().asLong();

if (beforeFnCount > 0)
commentary.add("'@before_main' function" + (beforeFnCount == 1 ? "" : "s"));

// call 'main' if it exists
PyFunction mainFunction = (PyFunction) _python.get("main");
if (mainFunction != null) {
}

if (_python.get("main") instanceof PyFunction) {
PyFunction mainFunction = (PyFunction) _python.get("main");
if (mainFunction != null) {
mainFunction.__call__();

commentary.add("'main'");
}
}

// handle @after_main functions (if present)
PyFunction processAfterMainFunctions = (PyFunction) _globals.get(Py.java2py("processAfterMainFunctions"));
long afterFnCount = processAfterMainFunctions.__call__().asLong();
if (afterFnCount > 0)
if (_globals.get(Py.java2py("processAfterMainFunctions")) instanceof PyFunction) {
PyFunction processAfterMainFunctions = (PyFunction) _globals.get(Py.java2py("processAfterMainFunctions"));
long afterFnCount = processAfterMainFunctions.__call__().asLong();
if (afterFnCount > 0)
commentary.add("'@after_main' function" + (afterFnCount == 1 ? "" : "s"));

}


// nothing went wrong, kick off toolkit
_toolkit.enable();
Expand Down Expand Up @@ -904,21 +916,23 @@ private void cleanupInterpreter() {

_logger.info(message);
_outReader.inject(message);

try {
PyFunction processCleanupFunctions = (PyFunction) _globals.get(Py.java2py("processCleanupFunctions"));
long cleanupFnCount = processCleanupFunctions.__call__().asLong();

if (cleanupFnCount > 0) {
message = "('@at_cleanup' function" + (cleanupFnCount == 1 ? "" : "s") + " completed.)";
_logger.info(message);
_outReader.inject(message);
if (_globals.get(Py.java2py("processCleanupFunctions")) instanceof PyFunction) {
PyFunction processCleanupFunctions = (PyFunction) _globals.get(Py.java2py("processCleanupFunctions"));
long cleanupFnCount = processCleanupFunctions.__call__().asLong();

if (cleanupFnCount > 0) {
message = "('@at_cleanup' function" + (cleanupFnCount == 1 ? "" : "s") + " completed.)";
_logger.info(message);
_outReader.inject(message);
}
}
} catch (Exception exc) {
// upstream exception handling should mean we never get here, but just in case
_logger.warn("Unexpected exception during cleaning up; should be safe to ignore", exc);
}

_python.cleanup();

message = "(clean up complete)";
Expand Down Expand Up @@ -1062,9 +1076,17 @@ protected Object handleActionRequest(SimpleName action, Object arg) {

throw new IllegalStateException("Action call failure (internal server error) - '" + functionName + "'");
}

PyFunction pyFunction = (PyFunction) pyObject;
PyBaseCode code = (PyBaseCode) pyFunction.func_code;
PyBaseCode code = null;
Class<?> objectClass = pyFunction.getClass();
try {
// Jython 2.5
code = (PyBaseCode) objectClass.getField("func_code").get(pyFunction);
} catch (NoSuchFieldException e) {
// Jython 2.7
code = (PyBaseCode) objectClass.getField("__code__").get(pyFunction);
}

// only support either 0 or 1 args
PyObject pyResult;
Expand Down Expand Up @@ -1332,7 +1354,15 @@ private void handleRemoteEventArrival(SimpleName alias, NodelClientEvent nodelCl
}

PyFunction pyFunction = (PyFunction) pyObject;
PyBaseCode code = (PyBaseCode) pyFunction.func_code;
PyBaseCode code = null;
Class<?> objectClass = pyFunction.getClass();
try {
// Jython 2.5
code = (PyBaseCode) objectClass.getField("func_code").get(pyFunction);
} catch (NoSuchFieldException e) {
// Jython 2.7
code = (PyBaseCode) objectClass.getField("__code__").get(pyFunction);
}

// only support either 0 or 1 args
if (code.co_argcount == 0)
Expand Down