getGetParams( Reader reader ) throws IOException, PySyntaxError {
return getGetParams( readScript(reader) );
}
/**
* read all the lines of a script into a string
* @param reader
* @return
* @throws IOException
*/
public static String readScript( Reader reader ) throws IOException {
String s;
StringBuilder build= new StringBuilder();
try ( BufferedReader breader= new BufferedReader(reader) ) {
s= breader.readLine();
while (s != null) {
build.append(s).append("\n");
s = breader.readLine();
}
}
return build.toString();
}
/**
* scrape through the script looking for getParam calls. These are executed, and we
* get labels and infer types from the defaults. For example,
* getParam( 'foo', 3.0 ) will always return a real and
* getParam( 'foo', 3 ) will always return an integer.
*
* Other examples include:
* getParam( 'foo', 'A', '', [ 'A', 'B' ] ) constrains the values to A or B
*
*
* Thinking about the future, people have asked that human-ready labels be fixed to list selections.
* Constraints should be added to number parameters to specify ranges. And last it would
* be nice to specify when a parameter is ignored by the script (dA is not used is mode B is active).
*
* getParam( 'foo', 3, '', { 'min':0, 'max':10 } ) might (Not implemented) constrain ranges
* getParam( 'sc', 'A', '', [ 'A', 'B' ], { 'A':'big one', 'B':'little one' } ) might (Not implemented) allow labels
* getParam( 'foo', 'dA', '', [], { '_ignoreIf':'sc==B' } ) might (Not implemented) allow groups to be disabled when not active
*
* A few things the Autoplot script developer must know:
*
* - getParam calls can only contain literals, and each must be executable as if it were the only line of code. This may be relaxed in the future.
*
- the entire getParam line must be on one line. This too may be relaxed.
*
*
*
* @param script A string containing the entire Jython program.
* @return list of parameter descriptions, in the order they were encountered in the file.
* @throws PyException
*/
public static List getGetParams( String script ) throws PyException {
return getGetParams(script,new HashMap());
}
/**
* look through the script, removing expensive calls to make a script
* that can be executed to get a list of getParam calls. The user
* can provide a list of current settings, so that the thread of execution
* is matched.
* @param script any jython script.
* @param params user-specified values.
* @return a list of parameters.
* @throws PyException
*/
public static List getGetParams( String script, Mapparams ) throws PyException {
return getGetParams( null, script, params );
}
/**
* look through the script, removing expensive calls to make a script
* that can be executed to get a list of getParam calls. The user
* can provide a list of current settings, so that the thread of execution
* is matched.
* Each parameter is given a type code:
**{@code
* R resourceURI, special string
* T timerange, special string
* A string
* F float, double, or int
* U URI
* L URL
* D Datum
* S DatumRange
*
*}
* note "arg_0" "arg_1" are used to refer to positional (unnamed) parameters.
*
* @param env any values which may be defined already, such as "dom" and "monitor"
* @param script any jython script.
* @param params user-specified values.
* @return a list of parameters.
* @throws PyException
*/
public static List getGetParams( Map env, String script, Mapparams ) throws PyException {
String prog= simplifyScriptToGetParams(script, true); // removes calls to slow methods, and gets the essence of the controls of the script.
logger.log(Level.FINER, "Simplified script: {0}", prog);
PythonInterpreter interp;
try {
interp= createInterpreter(true);
} catch ( IOException ex ) {
return new ArrayList();
}
if ( env!=null ) {
for ( Entry ent: env.entrySet() ) {
if ( ent.getKey()==null ) {
logger.log( Level.WARNING, "parameter name was null" );
} else if ( ent.getValue()==null ) {
if ( ent.getKey().equals("dom") ) {
logger.log( Level.FINE, "parameter \"dom\" value was set to null" ); // Some scripts don't use dom.
} else {
logger.log( Level.WARNING, "parameter value was null" );
}
} else {
interp.set( ent.getKey(), ent.getValue() );
}
}
}
setParams( interp, params );
try {
prog= JythonRefactory.fixImports(prog);
} catch (IOException ex) {
Logger.getLogger(JythonUtil.class.getName()).log(Level.SEVERE, null, ex);
}
interp.exec(prog);
interp.exec("import autoplot2017 as autoplot\n");
PyList sort= (PyList) interp.eval( "autoplot._paramSort" );
boolean altWhy= false; // I don't know why things are suddenly showing up in this other space.
if ( sort.isEmpty() ) {
try {
sort= (PyList) interp.eval( "_paramSort" );
if ( sort.size()>0 ) {
logger.warning("things are suddenly in the wrong space. This is because things are incorrectly imported.");
altWhy= true;
}
} catch ( PyException ex ) {
// good...
}
}
List result= new ArrayList();
for ( int i=0; i enums= new ArrayList(pyList.size());
for ( int j=0; j getGetDataSet( Map env, String script, Mapparams ) throws PyException {
String[] ss= script.split("\n");
for ( int i=ss.length-1; i>=0; i-- ) {
if ( !ss[i].contains("getDataSet") ) {
ss[i]= "";
} else {
break;
}
}
StringBuilder prog1= new StringBuilder(ss[0]);
prog1.append("\n");
for ( int i=1; i ent: env.entrySet() ) {
if ( ent.getKey()==null ) {
logger.log( Level.WARNING, "parameter name was null" );
} else if ( ent.getValue()==null ) {
logger.log( Level.WARNING, "parameter value was null" );
} else {
interp.set( ent.getKey(), ent.getValue() );
}
}
}
if ( params!=null ) setParams( interp, params );
interp.set( "timerange", "timerange" );
String redefineGDS= "gds={}\nngds=0\ndef getDataSet( uri, timerange='', map=0 ):\n global ngds\n global gdsi\n gds[ngds]=uri+' '+timerange\n ngds=ngds+1\n";
interp.exec( redefineGDS );
try {
interp.exec(prog);
} catch ( PyException ex ) {
logger.log( Level.WARNING, null, ex );
throw ex;
}
Map result= new LinkedHashMap<>();
PyDictionary r= (PyDictionary)interp.get("gds");
for ( Object k : r.keys() ) {
result.put( k.toString(), r.get(Py.java2py(k)).toString() );
}
//for ( Entry e : r.entrySet() ) {
// result.put( e.getKey().toString(), e.getValue().toString() );
//}
return result;
}
/**
* scrape script for local variables, looking for assignments. The reader is closed
* after reading.
* @param reader the source for the script. It is closed when the code executes properly.
* @return a map of the local variable name to the line containing it.
* @throws java.io.IOException
*/
public static Map getLocals( BufferedReader reader ) throws IOException {
try {
String s = reader.readLine();
Pattern assignPattern= Pattern.compile("\\s*([_a-zA-Z][_a-zA-Z0-9]*)\\s*=.*(#(.*))?");
Pattern defPattern= Pattern.compile("def .*");
boolean inDef= false;
Map result= new LinkedHashMap<>(); // from ID to description
while (s != null) {
if ( inDef==false ) {
Matcher defm= defPattern.matcher(s);
if ( defm.matches() ) {
inDef= true;
}
} else {
if ( s.length()>0 && !Character.isWhitespace(s.charAt(0)) ) {
Matcher defm= defPattern.matcher(s);
inDef= defm.matches();
}
}
if ( !inDef ) {
Matcher m= assignPattern.matcher(s);
if ( m.matches() ) {
if ( m.group(3)!=null ) {
result.put(m.group(1), m.group(3) );
} else {
result.put(m.group(1), s );
}
}
}
s = reader.readLine();
}
return result;
} finally {
reader.close();
}
}
/**
* return python code that is equivalent, except it has no side-effects like plotting.
* This code is not exact, for example (a,b)= (1,2) is not supported. This
* code is run to support completions.
* @param eval string containing the entire program.
* @return the script as a string, with side-effects removed.
* @deprecated this should not be used, because newer codes use the fully-implemented Jython parser.
*/
public static String removeSideEffects( String eval ) {
BufferedReader reader= new BufferedReader( new StringReader( eval ) ) ;
StringBuilder result= new StringBuilder();
try {
String s = reader.readLine();
Pattern assignPattern= Pattern.compile("\\s*([_a-zA-Z][_a-zA-Z0-9]*)\\s*=.*(#(.*))?");
Pattern defPattern= Pattern.compile("def .*");
Pattern importPattern1= Pattern.compile("from .*");
Pattern importPattern2= Pattern.compile("import .*");
boolean inDef= false;
while (s != null) {
int comment= s.indexOf("#");
if ( comment>-1 ) {
s= s.substring(0,comment);
}
boolean sideEffect= true;
if ( s.length()>1 && Character.isWhitespace( s.charAt(0) ) ) { // just skip over routines.
s = reader.readLine();
continue;
}
if ( inDef==false ) {
Matcher defm= defPattern.matcher(s);
if ( defm.matches() ) {
inDef= true;
sideEffect= false;
}
} else {
Matcher defm= defPattern.matcher(s);
if ( defm.matches() ) {
if ( sideEffect ) {
result.append(" pass\n");
}
}
if ( s.length()>0 && !Character.isWhitespace(s.charAt(0)) ) {
inDef= defm.matches();
if ( inDef ) sideEffect= false; //TODO: what about blank line, this isn't an "END"
}
if ( inDef && s.trim().equals("pass") ) { // syntax error otherwise.
sideEffect= false;
}
}
if ( !inDef ) {
Matcher m= assignPattern.matcher(s);
if ( m.matches() ) {
sideEffect= false;
} else if ( importPattern1.matcher(s).matches() ) {
sideEffect= false;
} else if ( importPattern2.matcher(s).matches() ) {
sideEffect= false;
}
}
if ( !sideEffect ) {
result.append( s ).append("\n");
}
s = reader.readLine();
}
if ( inDef ) {
result.append(" pass\n");
}
} catch ( IOException ex ) {
logger.log(Level.SEVERE, ex.getMessage(), ex);
} finally {
try {
reader.close();
} catch ( IOException ex ) {
logger.log(Level.SEVERE, ex.getMessage(), ex);
}
}
return result.toString();
}
/**
* join the array using the delimiter
* join( ['a','b'], '_' ) -> a_b
* Note Java 8 finally has a join, and this should be used when Java 8 is available.
* @param list strings to join
* @param delim
* @return the joined string
*/
public static String join(String[] list, String delim) {
return join(Arrays.asList(list), delim);
}
/**
* join the array using the delimiter
* join( ['a','b'], '_' ) -> a_b
* Note Java 8 finally has a join, and this should be used when Java 8 is available.
* @param list strings to join
* @param delim
* @return the joined string
*/
public static String join(List list, String delim) {
if (list.isEmpty()) {
return "";
} else {
StringBuilder result = new StringBuilder(list.get(0));
for (int i = 1; i < list.size(); i++) {
result.append(delim).append(list.get(i));
}
return result.toString();
}
}
// public static void main( String[] args ) throws IOException {
// main_test1(args);
// }
//
// /**
// * test the getGetParams for a script, seeing if we can reduce
// * and run the script within interactive time.
// *
// * @param file
// * @throws Exception
// */
// private static void doTestGetParams( String testId, String file ) {
// long t0= System.currentTimeMillis();
// System.err.println("== test "+testId+": "+ file + " ==" );
//
// try {
// String script= JythonUtil.readScript( new FileReader(file) );
// String scrip= org.autoplot.jythonsupport.JythonUtil.simplifyScriptToGetParams(script,true);
// File f= new File(file);
// String fout= "./test038_"+f.getName();
// try ( FileWriter fw= new FileWriter(fout) ) {
// fw.append(scrip);
// }
// List parms= org.autoplot.jythonsupport.JythonUtil.getGetParams( script );
// for ( Param p: parms ) {
// System.err.println(p);
// }
// System.err.println( String.format( "read params in %d millis: %s\n", System.currentTimeMillis()-t0, file ) );
// } catch ( Exception ex ) {
// logger.log(Level.WARNING,null,ex);
// System.err.println( String.format( "failed within %d millis: %s\n", System.currentTimeMillis()-t0, file ) );
// }
//
// }
//
// public static void main_test1(String[] args ) throws FileNotFoundException {
// doTestGetParams("006","/home/jbf/ct/hudson/script/test038/yab_20131003.jy"); //TODO: needs fixing
// doTestGetParams("000","/home/jbf/ct/hudson/script/test038/trivial.jy");
// doTestGetParams("001","/home/jbf/ct/hudson/script/test038/demoParms0.jy");
// doTestGetParams("002","/home/jbf/ct/hudson/script/test038/demoParms1.jy");
// doTestGetParams("003","/home/jbf/ct/hudson/script/test038/demoParms.jy");
// doTestGetParams("004","/home/jbf/ct/hudson/script/test038/rbsp/emfisis/background_removal_wfr.jyds");
// }
}