From f20fb4afa86e32469948720658b92581ecf3db36 Mon Sep 17 00:00:00 2001 From: Nate Jensen Date: Thu, 5 Feb 2015 18:03:47 -0600 Subject: [PATCH] Omaha #4089 harden safety of numpy dtypes in gfe arrays Change-Id: Ic77b459bc4d68930418ad66680ee86069c540c1f Former-commit-id: ac02fc3a8113d7fda361ae395dda25e933d036c0 [formerly b42dec0e4a0fa17ec53c0c82476088452ddd698f] [formerly ac02fc3a8113d7fda361ae395dda25e933d036c0 [formerly b42dec0e4a0fa17ec53c0c82476088452ddd698f] [formerly ea273e14bf9c298d0dd99a77d1ce2b335f7bcd95 [formerly ed77ff564520c8f6ad157dd115d37d69cbfab660]]] Former-commit-id: ea273e14bf9c298d0dd99a77d1ce2b335f7bcd95 Former-commit-id: eea6f68b543d084206c9b6d37f0b4ef1ba3c7062 [formerly 2346be4023ce95d305a92c72c49e03bb0a04a85e] Former-commit-id: e4edba9ee770eb2b6368459951d9c729bf92f5a8 --- .../raytheon/viz/gfe/BaseGfePyController.java | 107 ++++++++---------- 1 file changed, 47 insertions(+), 60 deletions(-) diff --git a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/BaseGfePyController.java b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/BaseGfePyController.java index 9f5597f5a6..e83b50aebf 100644 --- a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/BaseGfePyController.java +++ b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/BaseGfePyController.java @@ -51,6 +51,7 @@ import com.raytheon.viz.gfe.smartscript.FieldDefinition; * Oct 14, 2014 3676 njensen Moved getNumpyResult(GridType) here and * hardened it by separating jep.getValue() * calls from python copying/casting to correct types + * Feb 05, 2015 4089 njensen Replaced previous hardening with ensureResultType() * * * @@ -116,11 +117,11 @@ public abstract class BaseGfePyController extends PythonScriptController { } /** - * Processes a module's varDict (variable list inputs), or sets the varDict - * to an empty dictionary if there is not a variable list + * Sets a module's varDict (variable list inputs), or sets the varDict to + * None if there is not a variable list * - * @param moduleName - * the name of the module to process the varDict for + * @param varDict + * a string representation of a python dictionary * @throws JepException */ public void setVarDict(String varDict) throws JepException { @@ -203,59 +204,20 @@ public abstract class BaseGfePyController extends PythonScriptController { if (resultFound) { int xDim, yDim = 0; - /* - * correctType is just a memory optimization. A copy is made when we - * call getValue(numpyArray), but doing array.astype(dtype) or - * numpy.ascontiguousarray(array, dtype) will create yet another - * copy. - * - * Note that if you attempt jep.getValue(array.astype(dtype)) or - * jep.getValue(numpy.ascontiguousarray(array, dtype)) you can - * potentially crash the JVM. jep.getValue(variable) should - * primarily retrieve variables that are globally scoped in the - * python interpreter as opposed to created on the fly. - */ - boolean correctType = false; + + // this will safely alter the result dtypes in place if necessary + ensureResultType(type); + switch (type) { case SCALAR: - correctType = (boolean) jep.getValue(RESULT - + ".dtype.name == 'float32'"); - if (!correctType) { - /* - * the following line needs to be separate from - * jep.getValue() to be stable - */ - jep.eval(RESULT + " = numpy.ascontiguousarray(" + RESULT - + ", numpy.float32)"); - } + // don't make python func calls within a jep.getValue() call float[] scalarData = (float[]) jep.getValue(RESULT); xDim = (Integer) jep.getValue(RESULT + ".shape[1]"); yDim = (Integer) jep.getValue(RESULT + ".shape[0]"); result = new Grid2DFloat(xDim, yDim, scalarData); break; case VECTOR: - correctType = (boolean) jep.getValue(RESULT - + "[0].dtype.name == 'float32'"); - if (!correctType) { - /* - * the following line needs to be separate from - * jep.getValue() to be stable - */ - jep.eval(RESULT + "[0] = numpy.ascontiguousarray(" + RESULT - + "[0], numpy.float32)"); - } - - correctType = (boolean) jep.getValue(RESULT - + "[1].dtype.name == 'float32'"); - if (!correctType) { - /* - * the following line needs to be separate from - * jep.getValue() to be stable - */ - jep.eval(RESULT + "[1] = numpy.ascontiguousarray(" + RESULT - + "[1], numpy.float32)"); - } - + // don't make python func calls within a jep.getValue() call float[] mag = (float[]) jep.getValue(RESULT + "[0]"); float[] dir = (float[]) jep.getValue(RESULT + "[1]"); xDim = (Integer) jep.getValue(RESULT + "[0].shape[1]"); @@ -267,17 +229,7 @@ public abstract class BaseGfePyController extends PythonScriptController { break; case WEATHER: case DISCRETE: - correctType = (boolean) jep.getValue(RESULT - + "[0].dtype.name == 'int8'"); - if (!correctType) { - /* - * the following line needs to be separate from - * jep.getValue() to be stable - */ - jep.eval(RESULT + "[0] = numpy.ascontiguousarray(" + RESULT - + "[0], numpy.int8)"); - } - + // don't make python func calls within a jep.getValue() call byte[] bytes = (byte[]) jep.getValue(RESULT + "[0]"); String[] keys = (String[]) jep.getValue(RESULT + "[1]"); xDim = (Integer) jep.getValue(RESULT + "[0].shape[1]"); @@ -297,4 +249,39 @@ public abstract class BaseGfePyController extends PythonScriptController { return result; } + /** + * Checks that a result numpy array is of the correct dtype for the + * GridType, and if not, corrects the type to ensure it comes across to Java + * safely. + * + * If the correct type is found, nothing is done and therefore memory and + * speed is saved over the alternative of always calling astype(dtype) or + * ascontiguousarray(array, dtype), both of which will create a copy of the + * array. + * + * Note that if you attempt jep.getValue(array.astype(dtype)) or + * jep.getValue(numpy.ascontiguousarray(array, dtype)) you can potentially + * crash the JVM. jep.getValue(variable) should primarily retrieve variables + * that are globally scoped in the python interpreter as opposed to created + * on the fly. + * + * @param type + */ + protected void ensureResultType(GridType type) throws JepException { + String safeType = null; + switch (type) { + case SCALAR: + case VECTOR: + safeType = "'float32'"; + break; + case DISCRETE: + case WEATHER: + safeType = "'int8'"; + break; + } + String safetyCheck = RESULT + " = " + "NumpyJavaEnforcer.checkdTypes(" + + RESULT + ", " + safeType + ")"; + jep.eval("import NumpyJavaEnforcer"); + jep.eval(safetyCheck); + } }