ISCE_INSAR/components/iscesys/Component/Application.py

436 lines
15 KiB
Python
Raw Normal View History

2019-01-16 19:40:08 +00:00
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Copyright 2009 California Institute of Technology. ALL RIGHTS RESERVED.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# United States Government Sponsorship acknowledged. This software is subject to
# U.S. export control laws and regulations and has been classified as 'EAR99 NLR'
# (No [Export] License Required except when exporting to an embargoed country,
# end user, or in support of a prohibited end use). By downloading this software,
# the user agrees to comply with all applicable U.S. export laws and regulations.
# The user has the responsibility to obtain export licenses, or other export
# authority as may be required before exporting this software to any 'EAR99'
# embargoed foreign country or citizen of those countries.
#
# Authors: Eric Gurrola, Giangi Sacco
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from __future__ import print_function
import sys
import os
import operator
from iscesys.Component.Component import Component
from iscesys.DictUtils.DictUtils import DictUtils as DU
class CmdLinePropDict(object):
_instance = None
def __new__(cls):
if not cls._instance:
cls._instance = dict()
return cls._instance
class CmdLineFactDict(object):
_instance = None
def __new__(cls):
if not cls._instance:
cls._instance = dict()
return cls._instance
class CmdLineMiscDict(object):
_instance = None
def __new__(cls):
if not cls._instance:
cls._instance = dict()
return cls._instance
class CmdLineDocDict(object):
_instance = None
def __new__(cls):
if not cls._instance:
cls._instance = dict()
return cls._instance
class CmdLineUnitsDict(object):
_instance = None
def __new__(cls):
if not cls._instance:
cls._instance = dict()
return cls._instance
## A decorator that makes a function taking self as the 1st argument
def curried(func):
def curried_func(self, *args):
return func(self, *args)
return curried_func
class StepHelper(object):
"""This Mixin help sub class's _parameter_steps() methods
call functions.
"""
@staticmethod
def compose(f, g, fargs=(), gargs=(), fkwargs={}, gkwargs={}):
"""compose(f, g)() --> f(g())"""
from functools import partial
def fog(*args, **kwargs):
return (
partial(f, *fargs, **fkwargs)(
partial(g, *gargs, **gkwargs)(
*args, **kwargs
)
)
)
return fog
def attrgetter(self, attr, attribute=None):
inst = getattr(self, attribute) if attribute else self
return getattr(inst, attr)
def attrsetter(self, attr, value, attribute=None):
inst = getattr(self, attribute) if attribute else self
return setattr(inst, attr, value)
def delayed_attrgetter(self, attr, attribute=None):
return lambda : self.attrgetter(attr, attribute=attribute)
def delayed_attrsetter(self, attr, attribute=None):
return lambda value: self.attrsetter(self,
attr,
value,
attribute=attribute)
## self.delayed_attrsetter(attr, delayed_attr
def delayed_attrcopy_from_to(self, attri, attrf, attribute=None):
return lambda : self.attrsetter(
attrf,
self.attrgetter(
attri,
attribute=attribute
),
attribute=attribute
)
pass
## Application base class
class Application(Component, StepHelper):
cont_string = ''
def run(self, *cmdLine):
## Check not any occurance of a steps related command keyword
if any([operator.contains(
[y[0] for y in [x.split('=') for x in self.cmdline]], item) for
item in ("--steps", "--dostep", "--start", "--end", "--next")]
):
print("Step processing")
self._steps()
exitStatus = self._processSteps()
else:
exitStatus = self.main()
#Run the user's finalize method
self._finalize()
return exitStatus
# Method allows uses to pass cmdline externally as well
def _processCommandLine(self,cmdline=None):
from iscesys.Parsers.Parser import Parser
if cmdline:
if(isinstance(cmdline,str)):
#just in case a string is passed, turn it into a list
cmdline = [cmdline]
self.cmdline = cmdline
else:
self.cmdline = self._getCommandLine()
#process the command line and return a dictionary of dictionaries with
# components per each node.
# propDict contains the property for each component.
# factDict contains the info for the component factory.
# miscDict might contain doc and units. opts are the command lines
# preceeded by --
PA = Parser()
propDict, factDict, miscDict, self._argopts = PA.commandLineParser(
self.cmdline
)
CmdLinePropDict().update(propDict)
CmdLineFactDict().update(factDict)
CmdLineMiscDict().update(miscDict)
#extract doc from miscDict
docDict = DU.extractDict(miscDict, 'doc')
CmdLineDocDict().update(docDict)
#extract units from miscDict
unitsDict = DU.extractDict(miscDict, 'units')
CmdLineUnitsDict().update(unitsDict)
# self.catalog stores the properties for all configurable components
# as a dictionary of dictionaries which wil be used to recursively
# initialize the components
if propDict:
# propDict contains a only the Application dictionary at the top
# level
self.catalog = propDict[list(propDict.keys())[0]]
self._cmdLineDict = (factDict, docDict, unitsDict)
return None
def _getCommandLine(self):
# if len(sys.argv) < 2:
# print("An input file is required.")
# self.Usage()
# sys.exit(0)
argv = sys.argv[1:]
return argv
## "Virtual" Usage method
def Usage(self):
"""
Please provide a helpful Usage method.
"""
print("Please provide a Usage method for component, ",
self.__class__.__name__)
return
def help_steps(self):
"""
Method to print a helpful message when using steps
"""
def step(self, name, attr=None, local=None, func=None, args=(), delayed_args=(), kwargs={}, dostep=True,
doc="Please provide a helpful message in the step declaration"):
if not isinstance(name, str):
raise ValueError(("The step 'name', given as first argument of a 'step' "+
"declaration, is not given as a string"))
if args and delayed_args:
raise ValueError("Can only evaluate args or delayed args")
#add valid step names to the help list
if isinstance(name, str):
self.step_list_help.append(name)
#add valid step names for which dostep==True to the list of steps
if isinstance(name, str) and dostep:
self.step_list.append(name)
self.step_num = len(self.step_list)
self._dictionaryOfSteps[name] = {'step_index' : self.step_num,
'local' : local,
'attr' : attr,
'func' : func,
'args' : args,
'delayed_args' : delayed_args,
'kwargs' : kwargs,
'doc' : doc}
return None
## Dump Application._pickObj and renderProcDoc().
def dumpPickleObj(self, name):
import pickle
import os
self.renderProcDoc()
if not os.path.isdir(self.pickleDumpDir):
os.mkdir(self.pickleDumpDir)
if self.renderer == 'xml':
toDump = getattr(self, self._pickleObj)
toDump.dump(os.path.join(self.pickleDumpDir, name + '.xml'))
#dump the procDoc separately
with open(os.path.join(self.pickleDumpDir, name), 'wb') as PCKL:
print("Dumping the application's pickle object %s to file %s" %
(self._pickleObj, os.path.join(self.pickleLoadDir, name)))
pickle.dump(getattr(toDump, 'procDoc'), PCKL,
protocol=pickle.HIGHEST_PROTOCOL)
else:
with open(os.path.join(self.pickleDumpDir, name), 'wb') as PCKL:
print("Dumping the application's pickle object %s to file %s" %
(self._pickleObj, os.path.join(self.pickleLoadDir, name)))
pickle.dump(getattr(self, self._pickleObj), PCKL, protocol=pickle.HIGHEST_PROTOCOL)
return None
## Load Application._pickleObj from Appication.pickleLoadDir
def loadPickleObj(self, name):
import pickle
import os
try:
if self.renderer == 'xml':
toLoad = self._insarProcFact()
toLoad.load(os.path.join(self.pickleLoadDir, name + '.xml'))
setattr(self, self._pickleObj,toLoad)
with open(os.path.join(self.pickleLoadDir, name), 'rb') as PCKL:
setattr(getattr(self, self._pickleObj), 'procDoc',
pickle.load(PCKL))
else:
with open(os.path.join(self.pickleLoadDir, name), 'rb') as PCKL:
setattr(self, self._pickleObj, pickle.load(PCKL))
print(
"Loaded the application's pickle object, %s from file %s" %
(self._pickleObj, os.path.join(self.pickleLoadDir, name))
)
except IOError:
print("Cannot open %s", os.path.join(self.pickleLoadDir, name))
return None
def _processSteps(self):
import getopt
start = 0
startName = self.step_list[0]
end = self.step_num
endName = self.step_list[self.step_num-1]
opts, args = getopt.getopt(self._argopts, 's:e:d:',
['start=', 'end=', 'dostep=', 'steps', 'next'])
for o, a in opts:
if o in ('--start', '-s'):
startName = a
elif o in ('--end', '-e'):
endName = a
elif o in ('--dostep', '-d'):
startName = a
endName = a
elif o == "--steps":
pass
elif o == "--next":
#determine the name of the most recent pickle file that is in the step_list
import glob
pickle_files = glob.glob('PICKLE/*')
next_step_indx = 0
while len(pickle_files) > 0:
# get the name of the most recent file in the PICKLE directory
recent_pname = max(pickle_files, key=os.path.getctime).split('/')[1]
# check if pickle rendering is 'xml'
if self.renderer == 'xml' and '.xml' in recent_pname:
#get the name of the step corresponding to most recent pickle file
#with extension ".xml"
recent_pname == recent_pname.split(".xml")[0]
if recent_pname in self.step_list:
next_step_indx = self.step_list.index(recent_pname)+1
break
else:
#remove the filename from the list since it is not in the current step_list
pickle_files.pop(pickle_files.index(recent_pname))
#determine the name of the next step
if next_step_indx < len(self.step_list):
#if the next step index is in the range of possible steps
#set 'startName' and 'endName' to the next step
startName = self.step_list[next_step_indx]
endName = startName
else:
print("Steps has finished the final step. No next step to process.")
return
else:
print("unhandled option, arg ", o, a)
if startName in self.step_list:
start = self.step_list.index(startName)
else:
print("ERROR: start=%s is not one of the named steps" % startName)
return 1
if endName in self.step_list:
end = self.step_list.index(endName)
else:
print("ERROR: end=%s is not one of the named steps" % endName)
return 1
if start > end:
print(
"ERROR: start=%s, step number %d comes after end=%s, step number %d"
%
(startName, start, endName, end)
)
return 1
if start > 0:
name = self.step_list[start-1]
self.loadPickleObj(name)
# print("self._dictionaryOfSteps['filter'] = ",
# self._dictionaryOfSteps['filter'])
for s in self.step_list[start:end+1]:
print("Running step {}".format(s))
func = self._dictionaryOfSteps[s]['func']
args = self._dictionaryOfSteps[s]['args']
delayed_args = self._dictionaryOfSteps[s]['delayed_args']
kwargs = self._dictionaryOfSteps[s]['kwargs']
locvar = self._dictionaryOfSteps[s]['local']
attr = self._dictionaryOfSteps[s]['attr']
pargs = ()
if args:
for arg in args:
pargs += (arg,)
pass
pass
else:
for arg in delayed_args:
print("eval:",arg)
pargs += (eval(arg),)
pass
pass
result = func(*pargs, **kwargs)
if locvar:
locals()[locvar] = result
pass
if attr:
setattr(self, attr, result)
pass
self.dumpPickleObj(s)
if self.step_list.index(s) < len(self.step_list)-1:
print("The remaining steps are (in order): ",
self.step_list[self.step_list.index(s)+1:])
else:
print("The is the final step")
pass # steps loops ends here
return 0
def __init__(self, family='', name='',cmdline=None):
self.name = name
self._dictionaryOfSteps = {}
self._argopts = []
self.step_list = []
self.step_list_help = []
self._processCommandLine(cmdline)
super(Application, self).__init__(family=family, name=name)
return