def cfilePage(cobj, deep, recurse_list=None) : """ Builds a page with CliMAF figures, computing associated crs Args: cobj (cpage object) Returns : the filename in CliMAF cache, which contains the result (and None if failure) """ if not isinstance(cobj,classes.cpage): raise Climaf_Driver_Error("cobj is not a cpage object") clogger.debug("Computing figure array for cpage %s"%(cobj.crs)) # # page size and creation if cobj.orientation == "portrait": page_width=800. ; page_height=1200. elif cobj.orientation == "landscape": page_width=1200. ; page_height=800. page_size="%dx%d"%(page_width, page_height) args=["convert", "-size", page_size, "xc:white"] # # margins x_left_margin=10. # Left shift at start and end of line y_top_margin=10. # Initial vertical shift for first line x_right_margin=10. # Right shift at start and end of line y_bot_margin=10. # Vertical shift for last line xmargin=20. # Horizontal shift between figures ymargin=20. # Vertical shift between figures # usable_height=page_height-ymargin*(len(cobj.heights)-1.)-y_top_margin -y_bot_margin usable_width =page_width -xmargin*(len(cobj.widths)-1.) -x_left_margin-x_right_margin # # page composition y=y_top_margin for line, rheight in zip(cobj.fig_lines, cobj.heights) : # Line height in pixels height=usable_height*rheight x=x_left_margin for fig, rwidth in zip(line, cobj.widths) : # Figure width in pixels width=usable_width*rwidth scaling="%dx%d+%d+%d" %(width,height,x,y) if fig : figfile=ceval(fig,format="file", deep=deep, recurse_list=recurse_list) else : figfile='xc:None' clogger.debug("Compositing figure %s",fig.crs if fig else 'None') args.extend([figfile , "-geometry", scaling, "-composite" ]) x+=width+xmargin y+=height+ymargin out_fig=cache.generateUniqueFileName(cobj.buildcrs(), format="png") args.append(out_fig) clogger.debug("Compositing figures : %s"%`args`) comm=subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) if comm.wait()!=0 : raise Climaf_Driver_Error("Compositing failed : %s" %comm.stderr.read()) if cache.register(out_fig,cobj.crs) : clogger.debug("Registering file %s for cpage %s"%(out_fig,cobj.crs)) return out_fig
def ceval_script (scriptCall,deep,recurse_list=[]): """ Actually applies a CliMAF-declared script on a script_call object Prepare operands as fiels and build command from operands and parameters list Assumes that scripts are described in dictionary 'scripts' by templates as documented in operators.cscript Returns a CLiMAF cache data filename """ script=operators.scripts[scriptCall.operator] template=Template(script.command) # Evaluate input data dict_invalues=dict() sizes=[] for op in scriptCall.operands : inValue=ceval(op,userflags=scriptCall.flags,format='file',deep=deep, recurse_list=recurse_list) if inValue is None or inValue is "" : raise Climaf_Driver_Error("When evaluating %s : value for %s is None"\ %(scriptCall.script,`op`)) if isinstance(inValue,list) : size=len(inValue) else : size=1 sizes.append(size) dict_invalues[op]=inValue # # Replace input data placeholders with filenames subdict=dict() opscrs="" if 0 in script.inputs : label,multiple,serie=script.inputs[0] op=scriptCall.operands[0] infile=dict_invalues[op] if not all(map(os.path.exists,infile.split(" "))) : raise Climaf_Driver_Error("Internal error : some input file does not exist among %s:"%(infile)) subdict[ label ]=infile #if scriptCall.flags.canSelectVar : subdict["var"]=varOf(op) if isinstance(op,classes.cdataset) and op.alias and scriptCall.flags.canAlias: filevar,scale,offset,units,filenameVar,missing=op.alias #if script=="select" and ((varOf(op) != filevar) or scale != 1.0 or offset != 0.) : if ((varOf(op) != filevar) or scale != 1.0 or offset != 0.) : subdict["alias"]="%s,%s,%.4g,%.4g"%(varOf(op),filevar,scale,offset) subdict["var"]=filevar if units : subdict["units"]=units if scriptCall.flags.canMissing and missing : subdict["missing"]=missing if isinstance(op,classes.cens) : if not multiple : raise Climaf_Driver_Error( "Script %s 's input #%s cannot accept ensemble %s"\ %(scriptCall.script,0,`op`)) #subdict["labels"]=r'"'+reduce(lambda x,y : "'"+x+"' '"+y+"'", op.labels)+r'"' subdict["labels"]=reduce(lambda x,y : x+"$"+y, op.labels) per=timePeriod(op) if not per.fx and str(per) != "" and scriptCall.flags.canSelectTime: subdict["period"]=str(per) subdict["period_iso"]=per.iso() if scriptCall.flags.canSelectDomain : subdict["domain"]=domainOf(op) i=0 for op in scriptCall.operands : opscrs += op.crs+" - " infile=dict_invalues[op] if not all(map(os.path.exists,infile.split(" "))) : raise Climaf_Driver_Error("Internal error : some input file does not exist among %s:"%(infile)) i+=1 if ( i> 1 or 1 in script.inputs) : label,multiple,serie=script.inputs[i] subdict[ label ]=infile # Provide the name of the variable in input file if script allows for subdict["var_%d"%i]=varOf(op) if isinstance(op,classes.cdataset) and op.alias : filevar,scale,offset,units,filenameVar,missing =op.alias if (varOf(op) != filevar) or (scale != 1.0) or (offset != 0.) : subdict["alias_%d"%i]="%s %s %f %f"%(varOf(op),filevar,scale,offset) subdict["var_%d"%i]=filevar if units : subdict["units_%d"%i]=units if missing : subdict["missing_%d"%i]=missing # Provide period selection if script allows for per=timePeriod(op) if not per.fx and per != "": subdict["period_%d"%i]=str(per) subdict["period_iso_%d"%i]=per.iso() subdict["domain_%d"%i]=domainOf(op) clogger.debug("subdict for operands is "+`subdict`) # substitution is deffered after scriptcall parameters evaluation, which may # redefine e.g period # # Provide one cache filename for each output and instantiates the command accordingly if script.outputFormat is not None : # Compute a filename for each ouptut # Un-named main output main_output_filename=cache.generateUniqueFileName(scriptCall.crs, format=script.outputFormat) subdict["out"]=main_output_filename subdict["out_"+scriptCall.variable]=main_output_filename # Named outputs for output in scriptCall.outputs: subdict["out_"+output]=cache.generateUniqueFileName(scriptCall.crs+"."+output,\ format=script.outputFormat) # Account for script call parameters for p in scriptCall.parameters : #clogger.debug("processing parameter %s=%s"%(p,scriptCall.parameters[p])) subdict[p]=scriptCall.parameters[p] if p=="period" : subdict["period_iso"]=init_period(scriptCall.parameters[p]).iso() subdict["crs"]=opscrs.replace("'","") # # Combine CRS and possibly member_label to provide/complement title if 'title' not in subdict : if 'member_label' in subdict : subdict["title"]=subdict['member_label'] else: subdict["title"]=subdict["crs"] else: if 'member_label' in subdict : subdict["title"]=subdict["title"]+" "+subdict['member_label'] subdict.pop('member_label') # # Substitute all args template=template.safe_substitute(subdict) # # Allowing for some formal parameters to be missing in the actual call: # # Discard remaining substrings looking like : # some_word='"${some_keyword}"' , or: # '"${some_keyword}"' template=re.sub(r'(\w*=)?(\'\")?\$\{\w*\}(\"\')?',r"",template) # # Discard remaining substrings looking like : # some_word=${some_keyword} , or # ${some_keyword} template=re.sub(r"(\w*=)?\$\{\w*\}",r"",template) # # Launch script using command, and check termination #command="PATH=$PATH:"+operators.scriptsPath+template+fileVariables #command="echo '\n\nstdout and stderr of script call :\n\t "+template+\ # "\n\n'> scripts.out ; "+ template+ " >> scripts.out 2>&1" tim1=time.time() clogger.info("Launching command:"+template) # command=subprocess.Popen(template, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True) command.wait() # logfile=open('last.out', 'w') logfile.write("\n\nstdout and stderr of script call :\n\t "+template+"\n\n") command_std="" for line in command.stdout: command_std+=line logfile.write(line) logfile.close() if ( command.wait() == 0 ): if script.outputFormat is not None : # Tagging output files with their CliMAF Reference Syntax definition # Un-named main output ok = cache.register(main_output_filename,scriptCall.crs) # Named outputs for output in scriptCall.outputs: ok = ok and cache.register(subdict["out_"+output],\ scriptCall.crs+"."+output) if ok : duration=time.time() - tim1 print("Done in %.1f s with script computation for %s "%\ (duration,`scriptCall`),file=sys.stderr) clogger.debug("Done in %.1f s with script computation for " "%s (command was :%s )"%\ (duration,`scriptCall`,template)) return main_output_filename else : raise Climaf_Driver_Error("Some output missing when executing " ": %s. \n See last.out"%template) else : clogger.debug("script %s has no output"%script.name) return None else: clogger.debug("Full script output:\n"+command_std) comm2=subprocess.Popen(["tail", "-n", "10", "last.out"], stdout=subprocess.PIPE) clogger.error("Last lines of script output:\n"+comm2.stdout.read()) raise Climaf_Driver_Error("Script failure for : %s. More details either in file " "./last.out or by re-runing with clog(\"debug\")" %template)