Path: blob/main/tools/contributed/sumopy/agilepy/lib_base/processes.py
169689 views
# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo1# Copyright (C) 2016-2025 German Aerospace Center (DLR) and others.2# SUMOPy module3# Copyright (C) 2012-2021 University of Bologna - DICAM4# This program and the accompanying materials are made available under the5# terms of the Eclipse Public License 2.0 which is available at6# https://www.eclipse.org/legal/epl-2.0/7# This Source Code may also be made available under the following Secondary8# Licenses when the conditions for such availability set forth in the Eclipse9# Public License 2.0 are satisfied: GNU General Public License, version 210# or later which is available at11# https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html12# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later1314# @file processes.py15# @author Joerg Schweizer16# @date 2012171819import subprocess20import os21import sys22import types23import pickle242526#SUMOPYDIR = os.path.join(os.path.dirname(__file__),"..")27#TOOLSDIR = os.path.join(SUMOPYDIR,"..")2829#APPDIR = os.path.join(os.path.dirname(__file__),"..")303132import classman as cm33from misc import filepathlist_to_filepathstring, filepathstring_to_filepathlist, ff, P343536# p = psutil.Process(the_pid_you_want) !!37# print p.status38# if p.status == psutil.STATUS_ZOMBIE:3940##processlist = psutil.get_process_list()41##42# for p in processlist:43# if psutil.pid_exists(p.pid):44# print ' pid = ',p.pid45# print ' name =',p.name46# print ' running =',p.is_running()47# print ' path =',p.path48# print ' cmdline',p.cmdline49##50##51##cmd = 'nohup sumo --no-step-log --no-duration-log --no-warnings --step-length %.3f -c %s'%(time_simstep, filepath_netconfig)52##53# print '\n Starting command:',cmd54##p = subprocess.Popen(cmd, shell=True)55# print "p.pid",p.pid, "p.poll=",p.poll()56# p.wait()57# print '\n\nreturncode',p.poll(),p.returncode58# print 'p.stdout=\n', p.stdout59# call(cmd)6061# in windows : start command3626364def call(cmd):65"""66Calls a sytem commend lime. Returns 1 if executed successfully.67"""68# ensure unix compatibility69print(cmd)70# if isinstance(cmd, str):71# cmd = filter(lambda a: a!='', cmd.split(' '))72# subprocess.call(cmd)73p = subprocess.Popen(cmd, shell=True)74p.wait()75return p.returncode == 0767778class Process(cm.BaseObjman):79def __init__(self, ident, **kwargs):80self._init_common(ident, **kwargs)8182def _init_common(self, ident, parent=None, name=None, **kwargs):83self._init_objman(ident=ident, parent=parent, name=name, **kwargs)84attrsman = self.set_attrsman(cm.Attrsman(self))85self.optiongroupnames = ['options']86#self.net = attrsman.add( cm.ObjConf( network.Network(self) ) )87self.status = attrsman.add(cm.AttrConf(88'status', 'preparation',89groupnames=['_private', 'parameters'],90perm='r',91name='Status',92info='Process status: preparation-> running -> success|error.'93))94#self._logger.w(self.get_name(), key='action')95#self._logger.w('Prepare', key='message')9697def _set_status(self, status):98self.status = status99100def get_status(self):101return self.status102103def get_kwoptions(self):104return self.get_attrsman().get_group_attrs('options')105106def run(self):107if self.is_ready():108logger = self.get_logger()109self.status = 'running'110logger.start('Run process: %s' % self.get_name())111112#logger.w('start', key='message')113#114ans = self.do()115#116#logger.w(self.status, key='message')117if ans == True:118self.status = 'success'119else:120self.status = 'error'121logger.stop('Finished %s with status %s.' % (self.get_name(), self.status))122123return self.status == 'success'124# f self.status == 'error':125# return True126# self.status = 'success' # self.status = 'error'127# return True128else:129logger.stop('Cannot start %s.' % (self.get_name(),))130return False131132def aboard(self):133self.status = 'aboarded'134135def do(self):136#self.status = 'success'137return True138139def update_params(self):140"""141Make all parameters consistent.142example: used by import OSM to calculate/update number of tiles143from process dialog144"""145pass146147def is_ready(self):148"""149Returns True if process is ready to run.150151"""152return True153154def save_options(self, filepath):155optiondata = {}156for attrconf in self.get_attrsman().get_configs(filtergroupnames=self.optiongroupnames):157optiondata[attrconf.attrname] = attrconf.get_value()158159cm.save_obj(optiondata, filepath, is_not_save_parent=False)160161try:162f = open(filepath, 'wb')163except:164print 'WARNING in save: could not open', filepath165return False166167# print ' before',is_not_save_parent,parent,obj.parent168pickle.dump(optiondata, f, protocol=2)169f.close()170171def load_options(self, filepath):172try:173f = open(filepath, 'rb')174except:175print 'WARNING in load_options: could not open', filepath176return None177178# try:179# print ' pickle.load...'180optiondata = pickle.load(f)181f.close()182183attrsman = self.get_attrsman()184for attrname, value in optiondata.iteritems():185if attrsman.has_attrname(attrname):186attrsman.get_config(attrname).set_value(value)187188189class Options:190"""191Dummy option class to fake option parsing192"""193194def __init__(self, **kwargs):195self._optionattrs = []196self._cmlvaluemaps = []197self._transdir = {}198self._filepathattrs = []199for attr, value in kwargs.iteritems():200self.add_option(attr, value)201202def add_option(self, attr='', value='', cml=None,203is_filepath=False, cmlvaluemap=None):204setattr(self, attr, value)205self._optionattrs.append(attr)206self._cmlvaluemaps.append(cmlvaluemap)207if cml is not None:208self._transdir[attr] = cml209if is_filepath:210self._filepathattrs.append(attr)211212def set_transdir(self, **transdir):213"""214Sets a dictionary to translate python compatible215option names into the command line optionnames,216only in case the command line options are not identical217with python attributes (for example if218command line options contain '.' or '-').219Format of transdir is python attribute as key and220command line option (as string, WITH preceeding'--') as value.221222"""223self._transdir = transdir224225def get_optionstring(self):226# print 'get_optionstring'227s = ''228for attr, cmlvaluemap in zip(self._optionattrs, self._cmlvaluemaps):229value = getattr(self, attr)230cmlattr = self._transdir.get(attr, attr)231is_continue = True232if cmlvaluemap is not None:233if cmlvaluemap.has_key(value):234is_continue = False # take value from mapping235if P == '"': # windows236s += ' '+cmlattr+' "%s"' % cmlvaluemap[value]237else:238s += ' '+cmlattr+" '%s'" % cmlvaluemap[value]239# print ' option',attr,cmlattr, 'cmlvaluemap',cmlvaluemap240241if is_continue:242243if attr in self._filepathattrs:244if value != '':245s += ' '+cmlattr+' %s' % filepathlist_to_filepathstring(value.split(','))246elif type(value) == types.BooleanType:247if value:248s += ' '+cmlattr249elif type(value) in [types.StringTypes, types.UnicodeType]:250if P == '"': # windows251s += ' '+cmlattr+' "%s"' % value252else:253s += ' '+cmlattr+" '%s'" % value254else:255s += ' '+cmlattr+' %s' % value256return s257258259class CmlMixin:260def init_cml(self, command, is_run_background=False, is_nohup=False, workdirpath=None):261262self.optiongroupname = 'cml-options'263self.optiongroupnames.append(self.optiongroupname)264attrsman = self.get_attrsman()265self.pathmetatypes = ['filepath', 'dirpath', 'filepaths', 'dirpaths']266self.workdirpath = workdirpath267self._command = attrsman.add(cm.AttrConf(268'_command', command,269groupnames=['_private'],270perm='r',271name='command',272info='Command to be executed.'273))274self.pid = attrsman.add(cm.AttrConf(275'pid', -1,276groupnames=['_private'],277perm='r',278name='Process ID',279info="The system's Process ID",280))281282self.is_run_background = attrsman.add(cm.AttrConf(283'is_run_background', is_run_background,284groupnames=['parameters', 'advanced'],285perm='rw',286name='Run in background',287info='If set, process will run in background.',288))289290self.is_nohup = attrsman.add(cm.AttrConf(291'is_nohup', is_nohup,292groupnames=['parameters', 'advanced', ],293perm='rw',294name='No hangup',295info="""If set, process will run in the background and will continue to run after logout. (Currently on UNIX platforms only.) """,296))297298def add_option(self, option, value, **kwargs):299kwargs0 = {'cml': None,300'groupnames': [],301'perm': 'rw',302'is_save': True,303'name': None,304'info': '',305}306307kwargs0.update(kwargs)308if not (self.optiongroupname in kwargs0['groupnames']):309kwargs0['groupnames'] += [self.optiongroupname]310311# print '\nadd_option', option, value,kwargs0312default = self.get_attrsman().add(cm.AttrConf(option, value, **kwargs0))313setattr(self, option, default)314315def get_options(self):316print '\nget_options'317options = Options()318for attrconfig in self.get_attrsman().get_configs(is_all=True):319if self.optiongroupname in attrconfig.groupnames:320print ' option', attrconfig.attrname, attrconfig.groupnames, 'is path', attrconfig.get_metatype() in self.pathmetatypes, 'has cmlmap', hasattr(attrconfig, 'cmlvaluemap')321is_enabled = True322if hasattr(attrconfig, 'is_enabled'):323print ' is_enabled=', attrconfig.is_enabled(self), attrconfig.get_value()324is_enabled = attrconfig.is_enabled(self)325if is_enabled: # disabeled options are simply not added326if hasattr(attrconfig, 'cmlvaluemap'):327cmlvaluemap = attrconfig.cmlvaluemap328else:329cmlvaluemap = None330is_filepath = attrconfig.get_metatype() in self.pathmetatypes331options.add_option(attrconfig.attrname, attrconfig.get_value(), attrconfig.cml,332is_filepath=is_filepath, cmlvaluemap=cmlvaluemap)333334return options335336def print_options(self):337print 'Options of process ident:', self.ident338print ' Keywordoptions:'339for attrconfig in self.get_attrsman().get_configs(filtergroupnames=[self.optiongroupname]):340print ' ', attrconfig.attrname, '=', attrconfig.get_value()341342def reset_cml(self, cml):343self._command = cml344345def get_cml(self, is_changecwd=False, is_without_command=False):346"""347Returns commandline with all options.348To be overridden by costum class.349"""350# is_changecwd is obsolete, chenge in different directory351# if self.workdirpath is not None352options = self.get_options()353optionstr = options.get_optionstring()354print 'get_cml command', self._command, 'workdirpath', self.workdirpath355if True: # self.workdirpath is None:356if is_without_command:357cml = optionstr358else:359cml = P+self._command+P + optionstr360else:361cml = 'cd '+P+self.workdirpath+P+' ;'\362+ P+self._command+P + optionstr363364# print ' now call get_optionstring',options.get_optionstring365return cml366367def run_cml(self, cml=None):368if cml is None:369cml = self.get_cml()370attrsman = self.get_attrsman()371if self.workdirpath is not None:372wd = self.workdirpath373# os.chdir(self.workdirpath)374self._subprocess = subprocess.Popen(cml, shell=True, cwd=wd)375376else:377wd = os.getcwd()378self._subprocess = subprocess.Popen(cml, shell=True)379380attrsman.pid.set(self._subprocess.pid)381attrsman.status.set('running')382print 'run_cml cml=', cml383print ' pid = ', self.pid, 'cwd', wd384if not self.is_run_background:385self._subprocess.wait()386# if self.workdirpath is not None:387# os.chdir(wd)388389if self._subprocess.returncode == 0:390attrsman.status.set('success')391return True392393else:394attrsman.status.set('error')395return False396397398# print '\n Starting command:',cmd399##p = subprocess.Popen(cmd, shell=True)400# print "p.pid",p.pid, "p.poll=",p.poll()401# p.wait()402# print '\n\nreturncode',p.poll(),p.returncode403# print 'p.stdout=\n', p.stdout404# call(cmd)405###############################################################################406if __name__ == '__main__':407"""408Test409"""410411# for testing only to get the object browser...412sys.path.append(os.path.join(APPDIR, "lib_meta_wx"))413414415