Source code for omfit_tree

import warnings

import time

_t0 = time.time()

import sys
import os as _os

# ensure that any `import` refers to this installation of OMFIT
sys.path.insert(0, _os.path.dirname(_os.path.abspath(__file__)))
from omfit_classes.startup_framework import *

# import utilities
from utils import _available_to_user_math, _available_to_user_util, _available_to_user_plot, _available_to_user_fusion

# ---------------------
# classes under the `class` folder and starting with OMFIT
# ---------------------
_loaded_omfit_class_files = []

import omfit_classes.omfit_base
from omfit_classes.omfit_base import *
from omfit_classes.omfit_base import _moduleAttrs, itemTagsValues
from omfit_classes import unix_os as os

# override sys.exit to prevent external packages from quitting the session
_exit = sys.exit
sys.exit = lambda *args, **kw: None

import omfit_classes.omfit_python
from omfit_classes.omfit_python import *

_k = 0
for _file in sorted(glob.glob(OMFITsrc + '/omfit_classes/omfit_*.py')):
    _python_module = os.path.splitext(os.path.split(_file)[1])[0]
        exec("import omfit_classes." + _python_module, globals(), locals())
            getattr(omfit_classes, _python_module).__all__
        except AttributeError:
            raise OMFITexception(
                'Exception in omfit/%s: OMFIT does not allow modules under omfit/classes'
                'not to have an __all__ attribute which explicitly specifies what symbols '
                'will be exported when from <module> import * is used on the module' % _python_module

        # all classes must be available in omfit_base and omfit_python since that's where the OMFITtree is defined
        if _python_module != 'omfit_base':
            for item in getattr(omfit_classes, _python_module).__all__:
                setattr(omfit_classes.omfit_base, item, getattr(getattr(omfit_classes, _python_module), item))

        if _python_module != 'omfit_python':
            for item in getattr(omfit_classes, _python_module).__all__:
                setattr(omfit_classes.omfit_python, item, getattr(getattr(omfit_classes, _python_module), item))

        exec("from omfit_classes import " + _python_module, globals(), locals())
        exec("from omfit_classes." + _python_module + ' import *', globals(), locals())
        _k += 1
        _loaded_omfit_class_files.append(('%2d)%s' % (_k, _python_module.replace('omfit_', ''))).ljust(20))
    except Exception:
        printe('Offending module: ' + _python_module)
sys.exit = _exit

for item in omfit_classes.omfit_python.__all__:
    setattr(omfit_classes.omfit_base, item, getattr(omfit_python, item))

# backward compatibility with old classes location in `classes` folder instead of `omfit_classes`
for item in list(sys.modules.keys()):
    if item.startswith('omfit_classes.'):
        # allow `import classes.omfit_classname` # how Python environment with local OMFIT installation can use OMFIT classes
        sys.modules[re.sub('^omfit_classes\.', 'classes.', item)] = sys.modules[item]

print('Loaded OMFIT classes:')
while len(_loaded_omfit_class_files):
    _loaded_omfit_class_files = _loaded_omfit_class_files[4:]

[docs]def reload_python(moduleName, quiet=False): """ This function extends the Python builtin `reload` function to easily reload OMFIT classes >>> reload_python(omfit_classes.omfit_onetwo) :param moduleName: module or module name :param quiet: bool Suppress print statements listing reloaded objects """ from matplotlib.cbook.deprecation import MatplotlibDeprecationWarning warnings.filterwarnings('ignore', category=MatplotlibDeprecationWarning) if not isinstance(moduleName, str): moduleName = moduleName.__name__ if not (moduleName.startswith('omfit_') or moduleName.startswith('omfit_classes.omfit_')): printe('reload_python is meant for class containing modules (in omfit_classes) that start with `omfit_`') printe('Try instead:\n\nreload({0})\nfrom {0} import *'.format(moduleName)) return if moduleName in ['omfit_tree', 'omfit_gui']: printe('Can not reload omfit_tree or omfit_gui') return tmp = {} exec("import %s" % moduleName, tmp) from importlib import reload reload(eval(moduleName)) exec("from " + moduleName + " import *", tmp) # Keep track of reloaded objects to avoid storing them in the persistent OMFITconsoleDict namespace OMFITreloadedDict.update(tmp) # Find objects in the OMFIT tree that should be reloaded OMtr = traverse(OMFIT, string='OMFIT', onlyDict=True, skipDynaLoad=True) OMtr_cls = {} for loc in OMtr: if hasattr(eval(loc), '__class__') and eval(loc).__class__.__name__ in list(tmp.keys()): OMtr_cls.setdefault(eval(loc).__class__.__name__, []).append(loc) # Select only the items that should be reloaded items = list(tmp.keys()) if hasattr(eval(moduleName), '__all__'): items = eval(moduleName).__all__ if '__builtins__' in items: items.remove('__builtins__') # Loop through items to reload updated = {} for item in items: # Loop through python modules for mod in list(sys.modules.keys()): if hasattr(sys.modules[mod], '__dict__') and item in sys.modules[mod].__dict__: sys.modules[mod].__dict__[item] = tmp[item] updated.setdefault(mod, []).append(item) # Loop through OMFIT objects if item in OMtr_cls: for loc in OMtr_cls[item]: if not quiet: print(loc) eval(loc).__class__ = tmp[item] # Update OMFIT data types omfit_classes.omfit_base._updateTypes() if not quiet: printi('*' * 20) printi('Updated python modules') printi('*' * 20) pprinti(updated) printi('') printi('*' * 20) printi('Updated OMFIT tree entries') printi('*' * 20) pprinti(OMtr_cls) return
omfit_classes.omfit_python.reload_python = reload_python # --------------------- # OMFIT main tree # --------------------- _availableModulesCache = {}
[docs]class OMFITmaintree(OMFITproject): _save_method = '_save_with_info' def __init__(self, filename=''): OMFITproject.__init__(self, filename) self._OMFITparent = None self._OMFITkeyName = '' self.prj_options = {}
[docs] def start(self, filename=''): self.clear() self.filename = filename self.reset() self.onlyRunningCopy() OMFIT['MainSettings'].sort()
[docs] def projectName(self): if not len(self.filename): return '' if re.findall('OMFITsave.txt', self.filename): return os.path.split(self.filename.split(os.sep + 'OMFITsave.txt')[0])[1] else: return os.path.splitext(os.path.split(self.filename)[1])[0]
[docs] def onlyRunningCopy(self, deletePID=False): """ :param delete: whether to remove PID from list of running OMFIT processes (this should be done only at exit) :return: return True/False wether this is the only running copy of OMFIT on this computer """ filename = os.sep.join([OMFITsessionsDir, str(os.getpid())]) # OMFITsessionsDir should always exist! -- if not return False if not os.path.exists(OMFITsessionsDir): printe('Something is wrong! OMFITsessionsDir (%s) has been deleted!' % OMFITsessionsDir) return False else: try: # this is in a try/except because # in some extreme circumstances there can be # errors if the system cannot allocate memory if not os.path.exists(filename): open(filename, 'w').close() pids = [] for file in glob.glob(os.sep.join([OMFITsessionsDir, '*'])): pid = os.path.split(file)[1] if is_running(pid): pids.append(pid) elif deletePID: try: os.remove(file) except OSError: pass if deletePID and os.path.exists(filename): os.remove(filename) return len(pids) == 1 except OSError: return False
[docs] def reset(self): # always use saving as .zip as the default = True # clear self.clear() OMFITconsoleDict.clear() OMFITscriptsDict.clear() # remove all files under current temporary directory try: shutil.rmtree(OMFITcwd) except Exception: pass if not os.path.exists(OMFITcwd): os.makedirs(OMFITcwd) os.chdir(OMFITcwd) # fill special locations super().__setitem__('scratch', OMFITmainscratch()) super().__setitem__('commandBox', OMFITconsoleDict) super().__setitem__('scriptsRun', OMFITscriptsDict) super().__setitem__('shotBookmarks', OMFITshotBookmarks) # create main settings self.addMainSettings(restore='user') OMFIT['MainSettings']['EXPERIMENT']['runid'] = 'sim1' self['MainSettings']['SETUP']['version'] = repo_active_branch_commit self['MainSettings']['SETUP']['python_environment'] = SortedDict(python_environment()) # initialize main scratch self['scratch'].initialize() # set the localhost SERVER.setLocalhost()
[docs] def newProvenanceID(self): self['MainSettings']['EXPERIMENT']['provenanceID'] = omfit_hash("%Y-%m-%d_%H_%M_%S_%f"))
[docs] def newProjectID(self): self['MainSettings']['EXPERIMENT']['projectID'] = 'projectID__' self['MainSettings']['EXPERIMENT']['projectID'] += repo_active_branch_commit + '__' self['MainSettings']['EXPERIMENT']['projectID'] +="%Y-%m-%d_%H_%M_%S_%f") self['MainSettings']['EXPERIMENT']['projectID'] = self['MainSettings']['EXPERIMENT']['projectID'].replace(' ', '')
[docs] def addMainSettings(self, updateUserSettings=False, restore=''): # read the user namelist file self.userMainSettings = OMFITsettingsDir + os.sep + 'MainSettings.txt' self.userMainSettingsNamelistDump = OMFITsettingsDir + os.sep + 'MainSettingsNamelistDump.txt' self.userMainSettingsNamelist = OMFITsettingsDir + os.sep + 'MainSettingsNamelist.txt' if not os.path.exists(os.path.split(self.userMainSettings)[0]): os.makedirs(os.path.split(self.userMainSettings)[0]) if not os.path.exists(self.userMainSettings): open(self.userMainSettings, 'w').close() updateUserSettings = True if not os.path.exists(self.userMainSettingsNamelist): open(self.userMainSettingsNamelist, 'w').close() updateUserSettings = True # keep project options for k in list(OMFIT.prj_options_choices.keys()): if k not in self.prj_options: if k == 'persistent_projectID': self.prj_options[k] = False else: self.prj_options[k] = '' # force restore of skel main settings if necessary self.apply_bindings() if 'MainSettings' not in self or restore != '': # skeleton settings skelMainSettings = OMFITsrc + os.sep + 'omfit_classes' + os.sep + 'skeleton' + os.sep + 'skeletonMainSettings.txt' self.tmpSkel = OMFITtree(skelMainSettings, quiet=True) if platform.system() == 'Darwin': skelMainSettings = ( OMFITsrc + os.sep + 'omfit_classes' + os.sep + 'skeleton' + os.sep + 'skeletonMainSettingsNamelistOSX.txt' ) else: skelMainSettings = ( OMFITsrc + os.sep + 'omfit_classes' + os.sep + 'skeleton' + os.sep + 'skeletonMainSettingsNamelistUNIX.txt' ) self.tmpSkel['MainSettings'].recursiveUpdate(namelist.NamelistFile(skelMainSettings), overwrite=True) # institution settings if os.path.exists(os.environ.get('OMFIT_INSTITUTION_FILE', '/does not exist')): tmp = namelist.NamelistFile(os.environ['OMFIT_INSTITUTION_FILE']) else: filename = os.sep.join([OMFITsrc, '..', 'institution']) if os.path.exists(filename): tmp = namelist.NamelistFile(filename) else: institution_files = glob.glob(os.sep.join([OMFITsrc, '..', 'institutions', '']) + '*') institution_files.append(None) for filename in institution_files: tmp = namelist.NamelistFile(filename) if 'SETUP' in tmp and 'stats_file' in tmp['SETUP'] and os.path.exists(tmp['SETUP']['stats_file']): break self.tmpSkel['MainSettings'].recursiveUpdate(tmp, overwrite=True) # user settings self.tmpUser = OMFITtree(self.userMainSettings, quiet=True) if 'MainSettings' not in self: self['MainSettings'] = OMFITmainSettings() self['MainSettings'].filename = OMFITcwd + os.sep + os.path.split(self.userMainSettingsNamelist)[1] if not len(self.tmpUser): restore = 'skel' updateUserSettings = True # The main settings are built starting from the skeleton, the user local preference in ~/.OMFIT/ and the edits that the users have made if restore == '': self['MainSettings'].recursiveUpdate(self.tmpSkel['MainSettings']) def f_traverse(me): for kid in list(me.keys()): if isinstance(me[kid], dict): f_traverse(me[kid]) if re.match(hide_ptrn, kid): del me[kid] f_traverse(self['MainSettings']) self.add_bindings_to_main_settings() elif restore.startswith('diff_'): restore = restore[5:] tmp = OMFITmainSettings() if restore == 'skel': tmp.recursiveUpdate(self.tmpSkel['MainSettings']) elif restore == 'user' and 'MainSettings' in self.tmpUser: tmp.recursiveUpdate(self.tmpSkel['MainSettings']) tmp.recursiveUpdate(self.tmpUser['MainSettings'], overwrite=True) elif restore == 'S3': tmp.recursiveUpdate(self.tmpSkel['MainSettings']) tmp.recursiveUpdate(self.tmpUser['MainSettings'], overwrite=True) tmp1 = OMFITobject_fromS3(tmp['SETUP']['email'] + "_" + 'MainSettings.txt', s3bucket='omfit') tmp2 = OMFITobject_fromS3(tmp['SETUP']['email'] + "_" + 'MainSettingsNamelist.txt', s3bucket='omfit') shutil.copy2(tmp2.filename, os.path.split(tmp1.filename)[0] + os.sep + os.path.split(tmp2.filename)[1]) tmp0 = OMFITtree(tmp1.filename, quiet=True) tmp.recursiveUpdate(tmp0['MainSettings'], overwrite=True) printi('Loaded MainSettings from the cloud') diffTreeGUI(OMFIT['MainSettings'], tmp) else: self['MainSettings'].clear() if restore == 'skel': self['MainSettings'].recursiveUpdate(self.tmpSkel['MainSettings']) elif restore == 'user' and 'MainSettings' in self.tmpUser: self['MainSettings'].recursiveUpdate(self.tmpSkel['MainSettings']) self['MainSettings'].recursiveUpdate(self.tmpUser['MainSettings'], overwrite=True) elif restore == 'S3': self['MainSettings'].recursiveUpdate(self.tmpSkel['MainSettings']) self['MainSettings'].recursiveUpdate(self.tmpUser['MainSettings'], overwrite=True) tmp1 = OMFITobject_fromS3(self['MainSettings']['SETUP']['email'] + "_" + 'MainSettings.txt', s3bucket='omfit') tmp2 = OMFITobject_fromS3(self['MainSettings']['SETUP']['email'] + "_" + 'MainSettingsNamelist.txt', s3bucket='omfit') shutil.copy2(tmp2.filename, os.path.split(tmp1.filename)[0] + os.sep + os.path.split(tmp2.filename)[1]) tmp = OMFITtree(tmp1.filename, quiet=True) self['MainSettings'].recursiveUpdate(tmp['MainSettings'], overwrite=True) printi('Restored MainSettings from the cloud') self.apply_bindings() # generate unique projectID if that's not already there if 'projectID' not in self['MainSettings']['EXPERIMENT']: self.newProjectID() # generate unique provenanceID if that's not already there if 'provenanceID' not in self['MainSettings']['EXPERIMENT']: self.newProvenanceID() # make sure auto-save is not more often than 15 minutes try: self['MainSettings']['SETUP']['autosave_minutes'] = int(self['MainSettings']['SETUP']['autosave_minutes']) if self['MainSettings']['SETUP']['autosave_minutes'] < 15: raise OMFITexception('Auto-save time must be >= than 15 minutes') except Exception as _excp: printe('Error in setting Auto-save time\n' + repr(_excp)) self['MainSettings']['SETUP']['autosave_minutes'] = 15 # if default_tunnel is None, then set it based on what servers the user has access if self['MainSettings']['SERVER']['default_tunnel'] is None: favorite_tunnels = ['cybele', 'portal', 'cmodws', 'shenma', 'itm_gateway', 'iter_login', 'cfetr'] default_tunnel = 'cybele' if os.path.exists(os.environ['HOME'] + '/.ssh/known_hosts'): with open(os.environ['HOME'] + '/.ssh/known_hosts', 'r') as f: lines = [_f for _f in'\n') if _f] known_tunnels = [] for line in lines: try: for server in line.split()[0].split(','): try: SERVER[server] if SERVER(server) in favorite_tunnels: known_tunnels.append(SERVER(server)) except Exception: pass except IndexError: pass for tunnel in favorite_tunnels: if tunnel in known_tunnels: default_tunnel = tunnel break self['MainSettings']['SERVER']['default_tunnel'] = default_tunnel if updateUserSettings: # find differences of current MainSettings with respect to skeleton tmpU = OMFITtree() tmpU['MainSettings'] = copy.deepcopy(OMFIT['MainSettings']) ptrn = self.tmpSkel.pretty_diff(tmpU) # do not store projectID, provenanceID, or runid for k in ['projectID', 'provenanceID', 'runid']: if k in list(ptrn['MainSettings']['EXPERIMENT'].keys()): del ptrn['MainSettings']['EXPERIMENT'][k] # keep only differences tmpU = prune_mask(tmpU, ptrn) # remove entries that are deprecated _clearDeprecatedMainSettings(tmpU['MainSettings']) # remove entries that are not in the skeleton for item in list(tmpU['MainSettings'].keys()): if item in list(tmpU['MainSettings'].keys()) and item not in self.tmpSkel['MainSettings']: del tmpU['MainSettings'][item] if item in list(tmpU['MainSettings'].keys()) and item != 'SERVER': for subitem in list(tmpU['MainSettings'][item].keys()): if ( subitem in list(tmpU['MainSettings'][item].keys()) and subitem not in self.tmpSkel['MainSettings'][item] and subitem != 'KeyBindings' ): del tmpU['MainSettings'][item][subitem] elif subitem == 'KeyBindings': for desc, event in list(tmpU['MainSettings'][item][subitem].items()): if ( desc in global_event_bindings.default_desc_event and global_event_bindings.default_desc_event[desc] == event ): del tmpU['MainSettings'][item][subitem][desc] # save only differences (if there are any) if len(tmpU): tmpU._save(filename=self.userMainSettings, only="['MainSettings']", onlyOMFITsave=True) global OMFITexpressionsReturnNone tmpExp = OMFITexpressionsReturnNone OMFITexpressionsReturnNone = True try: tmpU['MainSettings'].saveas(self.userMainSettingsNamelist) finally: OMFITexpressionsReturnNone = tmpExp self.tmpUser = tmpU printi(self.userMainSettings + ' has been updated') if updateUserSettings == 'S3': OMFITascii(OMFITsettingsDir + os.sep + 'MainSettings.txt').deploy( self['MainSettings']['SETUP']['email'] + "_" + 'MainSettings.txt', s3bucket='omfit' ) OMFITascii(OMFITsettingsDir + os.sep + 'MainSettingsNamelist.txt').deploy( self['MainSettings']['SETUP']['email'] + "_" + 'MainSettingsNamelist.txt', s3bucket='omfit' ) printi('Saved user MainSettings in the cloud') # save a version of MainSettings in plain text if updateUserSettings or not os.path.exists(self.userMainSettingsNamelistDump): self['MainSettings'].deploy(self.userMainSettingsNamelistDump)
def __setitem__(self, key, value): # TODO: handle 'MainSettings' the same way if key in ['scratch', 'commandBox', 'scriptsRun', 'shotBookmarks']: raise RuntimeError(f"OMFIT['{key}'] is write-protected") else: super().__setitem__(key, value) def __delitem__(self, key): if key in ['scratch', 'commandBox', 'scriptsRun', 'shotBookmarks', 'MainSettings']: raise RuntimeError(f"OMFIT['{key}'] is delete-protected") else: super().__delitem__(key)
[docs] def add_bindings_to_main_settings(self): """ Take the descriptions and events from global_events_bindings and insert them in self['MainSettings']['SETUP']['KeyBindings'][desc] = <event> """ printd('Calling add_bindings_to_main_settings', level=2, topic='keybindings') if 'KeyBindings' not in self['MainSettings']['SETUP']: self['MainSettings']['SETUP']['KeyBindings'] = namelist.NamelistName() for di, d in enumerate(global_event_bindings.descs): self['MainSettings']['SETUP']['KeyBindings'][d.replace(' ', '_')] =[di]
[docs] def apply_bindings(self): """ Take the descriptions and events from self['MainSettings']['SETUP']['KeyBindings'] and use them to update the global_event_bindings """ if ('MainSettings' not in self) or ('SETUP' not in self['MainSettings']) or ('KeyBindings' not in self['MainSettings']['SETUP']): printd("No key bindings in MainSettings['SETUP']['KeyBindings'] -> unable to update", topic='keybindings') return for d, e in list(self['MainSettings']['SETUP']['KeyBindings'].items()): try: global_event_bindings.set(d.replace('_', ' '), e) except ValueError: del self['MainSettings']['SETUP']['KeyBindings'][d] self.add_bindings_to_main_settings()
[docs] def save(self, quiet=False, skip_save_errors=False): """ Writes the content of the OMFIT tree to the filesystem using the same filename and zip options of the last saveas :param quiet: whether to print save progress to screen :param skip_save_errors: skip errors when saving objects """ self.filename = self._save_with_info(self.filename,, quiet=quiet, skip_save_errors=skip_save_errors) return self.filename
def _save_with_info(self, filename, zip=False, quiet=False, updateExistingDir=False, skip_save_errors=False): """ Wrapper function around the OMFITtree._save method which handles the prj_options dictionary that is only part of the main OMFIT tree """ # this method should have the same signature of the ._save() method if filename: # by default the first time the projects directory is created, # assign permissions so that it is readeable but not writeable # by other users. Users can always override these default permissions # once the directory is created. projpath = os.path.split(os.path.split(filename)[0])[0] if not os.path.exists(projpath): # create projects directory os.makedirs(projpath) # by default, remove group and others write permission for perm in [stat.S_IWGRP, stat.S_IWOTH]: st_mode = os.lstat(projpath).st_mode os.chmod(projpath, st_mode & ~perm) # by default, add group and others read and browse permission for perm in [stat.S_IRGRP, stat.S_IROTH, stat.S_IXGRP, stat.S_IXOTH]: st_mode = os.lstat(projpath).st_mode os.chmod(projpath, st_mode | perm) # update list of shots/times from mainSettings and modules settings modules = self.moduleDict() for k in ['device', 'shot', 'time']: self.prj_options[k] = [] for k in ['device', 'shot', 'shots', 'time', 'times']: self.prj_options[k.rstrip('s')].extend(tolist(evalExpr(self['MainSettings']['EXPERIMENT'][k]))) try: for module in list(modules.keys()): mod = eval('OMFIT' + module) self.prj_options.setdefault(k.rstrip('s'), []).extend( tolist(evalExpr(mod['SETTINGS'].get('EXPERIMENT', {}).get(k, None))) ) self.prj_options[k.rstrip('s')] = list([_f for _f in self.prj_options[k.rstrip('s')] if _f]) except Exception as _excp: printe('Error accessing `%s` of module `OMFIT%s` : %s' % (k, module, repr(_excp))) for k in ['device', 'shot', 'time']: self.prj_options[k] = np.unique(list([_f for _f in self.prj_options[k.rstrip('s')] if _f])).tolist() # if the GUI is open update the GUI elements info if OMFITaux['GUI']: commands = [] commandNames = [] for k in range(len(OMFITaux['GUI'].command)): tmp = OMFITaux['GUI'].command[k].get(1.0, tk.END).strip() if len(tmp): commands.append(OMFITaux['GUI'].command[k].get(1.0, tk.END)) commandNames.append(OMFITaux['GUI'].commandNames[k]) if not len(commands): commands.append('') commandNames.append('1') OMFIT.prj_options['commands'] = commands OMFIT.prj_options['commandNames'] = commandNames OMFIT.prj_options['namespace'] = OMFITaux['GUI'].commandBoxNamespace OMFIT.prj_options['notes'] = OMFITaux['GUI'].notes.get(1.0, tk.END).strip() OMFIT.prj_options['console'] = OMFITaux['console'].get() OMFIT.prj_options.setdefault('color', '') if OMFIT.prj_options['color'] not in list(OMFIT.prj_options_choices['color'].keys()): OMFIT.prj_options['color'] = '' if OMFIT.prj_options['type'] not in OMFIT.prj_options_choices['type']: OMFIT.prj_options['type'] = '' try: OMFITaux['hardLinks'] = True self['__GUISAVE__'] = self.prj_options cb = OMFITtree() for k, v in enumerate(self['__GUISAVE__']['commands']): if not v.strip(): continue try: cb['' % (k + 1)] = OMFITascii(filename='' % (k + 1), fromString=v.rstrip()) except Exception as _excp: printe(_excp) if list(cb.keys()): self['__COMMANDBOX__'] = cb orig_version = self['MainSettings']['SETUP']['version'] orig_environ = self['MainSettings']['SETUP']['python_environment'] self['MainSettings']['SETUP']['version'] = repo_active_branch_commit self['MainSettings']['SETUP']['python_environment'] = SortedDict(python_environment()) return self._save( filename, zip=zip, quiet=quiet, skipStorage=False, updateExistingDir=updateExistingDir, skip_save_errors=skip_save_errors, ) except Exception: self['MainSettings']['SETUP']['version'] = orig_version self['MainSettings']['SETUP']['python_environment'] = orig_environ raise finally: if '__GUISAVE__' in self: del self['__GUISAVE__'] if '__COMMANDBOX__' in self: del self['__COMMANDBOX__'] OMFITaux['hardLinks'] = False else: raise IOError('Last saved directory was not defined')
[docs] def saveas(self, filename, zip=None, quiet=False, skip_save_errors=False): """ Writes the content of the OMFIT tree to the filesystem and permanently changes the name of the project :param filename: project filename to save to :param zip: whether the save should occur as a zip file :param quiet: whether to print save progress to screen :param skip_save_errors: skip errors when saving objects """ oldZip = oldFilename = self.filename oldPrj_options = self.prj_options if zip is not None: = zip self.filename = filename try: return, skip_save_errors=skip_save_errors) except Exception: = oldZip self.filename = oldFilename self.prj_options = oldPrj_options raise
[docs] def loadModule( self, filename, location=None, withSubmodules=True, availableModulesList=None, checkLicense=True, developerMode=None, depth=0, quiet=False, startup_lib=None, **kw, ): r""" Load a module in OMFIT :param filename: * full path to the module to be loaded * if just the module name is provided, this will be loaded from the public modules * remote/branch:module format will load a module from a specific git remote and branch * module:remote/branch format will load a module from a specific git remote and branch :param location: string with the location where to place the module in the OMFIT tree :param withSubmodules: load submodules or not :param availableModulesList: list of available modules generated by ``OMFIT.availableModules()`` If this list is not passed, then the availableModulesList is generated internally :param checkLicense: Check license files at load :param developerMode: Load module with developer mode option (ie. scripts loaded as modifyOriginal) if None then default behavior is set by ``OMFIT['MainSettings']['SETUP']['developer_mode_by_default']`` Note: public OMFIT installation cannot be loaded in developer mode :param depth: parameter used internally by for keeping track of the recursion depth :param quiet: load modules silently or not :param startup_lib: Used internally for executing OMFITlib_startup scripts :param \**kw: additional keywords passed to OMFITmodule() class :return: instance of the loaded module """ if os.sep not in filename or ':' in filename: # if there is a semicolumn in the filename, then a specific remote/branch is been requested if ':' in filename: work_repo = repo.clone() remote, branch = [x for x in filename.split(':') if '/' in x][0].split('/') filename = [x for x in filename.split(':') if '/' not in x][0] work_repo.switch_branch(branch, remote) filename = os.sep.join([work_repo.git_dir, 'modules', filename, 'OMFITsave.txt']) else: # if it's just a module name, load it from the first of the OMFITmodule directories filename = os.sep.join([OMFITmodule.directories()[0], filename, 'OMFITsave.txt']) filename = os.path.abspath(filename) # get list of available modules if availableModulesList is None: availableModulesList = self.availableModules(quiet=True, same_path_as=filename) # handle developerMode switch OMFITsrc = os.path.split(os.path.split(os.path.split(filename)[0])[0])[0] + os.sep + 'omfit' if os.path.exists(os.sep.join([OMFITsrc, '..', 'public'])): developerMode = False if developerMode is None: developerMode = OMFIT['MainSettings']['SETUP']['developer_mode_by_default'] # load the module moduleName ='ID', 'unknown_module') if location is None: location = "self['" + moduleName + "']" # handle printing kw.pop('quiet', None) quiet_module = True if not quiet: quiet_module = { 'newline': False, 'clean': False, 'quiet': False, 'style': ' [{sfill}{svoid}] {perc:3.2f}% ' + '*' * (depth + 1) + ' ' + moduleName + '{mess}', } # load module tmp = OMFITmodule(filename, developerMode=developerMode, quiet=quiet_module, **kw) # remove the module filename as there is no point of keeping it once it's loaded from the repo # OMFITtree (and derived classes) filenames are used for saving them external to the project tmp.filename = '' # if loading as a submodule, then place at the top loc = parseLocation(location) if isinstance(eval(buildLocation(loc[:-1])), OMFITmodule): eval(buildLocation(loc[:-1])).insert(0, loc[-1], tmp) else: eval(buildLocation(loc[:-1]))[loc[-1]] = tmp # add extra commit info to MODULE if filename in availableModulesList: for k in _moduleAttrs: if k in availableModulesList[filename]: tmp['SETTINGS']['MODULE'][k] = availableModulesList[filename][k] # fill in missing infos (e.g. when starting a new module) if not tmp['SETTINGS']['MODULE']['commit']: tmp['SETTINGS']['MODULE']['commit'] = repo.get_hash('HEAD') if tmp['SETTINGS']['MODULE']['contact'] is None: tmp['SETTINGS']['MODULE']['contact'] = [] if not len(tmp['SETTINGS']['MODULE']['contact']) and OMFIT['MainSettings']['SETUP']['email']: tmp['SETTINGS']['MODULE']['contact'].append(OMFIT['MainSettings']['SETUP']['email']) # Check license if checkLicense and 'license' in eval(location): license = eval(location)['license'] email_dict = {} with open(license.filename, 'r') as f: for k in f.readlines(): k = str(k) if 'OMFIT_license_email_notify' in k: notify = [x.strip() for x in re.sub(r'OMFIT_license_email_notify\:(.*)', r'\1', k).strip().split(',')] email_dict = { 'email_address': notify, 'email_prompt': 'Please describe planned research using ' + moduleName, 'fromm': self['MainSettings']['SETUP']['email'], } break try: OMFITlicenses[moduleName] = License(moduleName, license.filename, email_dict=email_dict, rootGUI=OMFITaux['rootGUI']) if OMFITaux['rootGUI']: OMFITlicenses[moduleName].check() except LicenseException: exec('del ' + location, globals(), locals()) raise except tk.TclError: # If there is no DISPLAY, allow access pass except IndexError: # If gui element fails to load, allow access pass # load the submodules (will set DEPENDENCIES, SETTINGS['EXPERIMENT'], and honor LIB['OMFITlib_startup'] scripts) if withSubmodules: # find the submodules (one level deep) moduleDict = eval(location).moduleDict(level=0) # save the dependencies depsDict = {} for subMod in moduleDict: depsDict[subMod] = eval(location + subMod)['SETTINGS']['DEPENDENCIES'] # load the submodules if startup_lib is None: startup_lib = [] for subMod in moduleDict: found = False for avMod in availableModulesList: if moduleDict[subMod]['ID'] == availableModulesList[avMod]['ID']: OMFIT.loadModule( availableModulesList[avMod]['path'], location + subMod, withSubmodules=True, availableModulesList=availableModulesList, checkLicense=checkLicense, developerMode=developerMode, depth=depth + 1, quiet=quiet, startup_lib=startup_lib, **kw, ) found = True break if not found: raise IOError( 'Module %s is a submodule of %s, and it could not found in %s' % (moduleDict[subMod]['ID'], moduleName, os.path.split(os.path.split(filename)[0])[0]) ) # restore the dependencies for subMod in moduleDict: for avMod in availableModulesList: if moduleDict[subMod]['ID'] == availableModulesList[avMod]['ID']: eval(location + subMod)['SETTINGS']['DEPENDENCIES'].update(depsDict[subMod]) break # freeze the root['SETTINGS']['EXPERIMENT'] entries if this is a top-level import that is not a submodule if depth == 0 and 'SETTINGS' in eval(location) and 'EXPERIMENT' in eval(location)['SETTINGS']: freeze = True for tmpName in reversed(traverseLocation(location)[:-1]): if eval(tmpName).__class__ is OMFITmodule and tmpName != 'OMFIT': freeze = False if freeze: for item in list(OMFITaux['moduleSkeletonCache']['SETTINGS']['EXPERIMENT'].keys()): eval(location)['SETTINGS']['EXPERIMENT'][item] = evalExpr(eval(location)['SETTINGS']['EXPERIMENT'][item]) # execute startup script (the OMFITmodulePath variable is setup to point to the OMFITsave.txt file of the module that is being loaded) if 'LIB' in eval(location) and 'OMFITlib_startup' in eval(location)['LIB']: startup_lib.append((moduleName, location, eval(location)['LIB']['OMFITlib_startup'])) if depth == 0: for k, (mname, loc, st_lib) in enumerate(startup_lib): if not quiet: if k == 0: printi("Running OMFITlib_startup:", end='') printi(f' {mname}', end='') try: with quiet_environment(): st_lib.runNoGUI() except Exception as _excp: printe("Error in %s['LIB']['OMFITlib_startup'] : " % (loc) + repr(_excp)) if not quiet: printi('') # store settings at load time # NOTE: this is done both here and in OMFITmodule.__init__ because this one will get execution of OMFITlib_startup and the other instead is needed when reloading a module eval(location)._save_settings_at_import() # return the module return eval(location)
[docs] def load(self, filename, persistent_projectID=False): """ loads an OMFITproject in OMFIT :param filename: filename of the project to load (if `-1` then the most recent project is loaded) :param persistent_projectID: whether the projectID should remain the same """ try: # open the last project if filename == '-1': projects = OMFIT.recentProjects() if len(projects): filename = list(projects.keys())[0] persistent_projectID = projects[filename].get('persistent_projectID', False) # keep aside user 'SETUP','SERVER' tmp = {} for item in ['SETUP', 'SERVER']: if item in self['MainSettings']: tmp[item] = copy.deepcopy(self['MainSettings'][item]) self.filename = os.path.abspath(filename) oldDir = os.getcwd() TMPnoCopyToCWD = OMFITaux['noCopyToCWD'] OMFITaux['noCopyToCWD'] = False try: self._load(filename) finally: os.chdir(oldDir) OMFITaux['noCopyToCWD'] = TMPnoCopyToCWD if zipfile.is_zipfile(self.filename): = True projectName = os.path.split(self.filename)[1] else: = False projectName = os.path.split(os.path.split(self.filename)[0])[1] # for older projects we calculate provenanceID based on institution and projectName # very old projects do not even have institution info if 'provenanceID' not in self['MainSettings']['EXPERIMENT']: self['MainSettings']['EXPERIMENT']['provenanceID'] = omfit_hash( self['MainSettings']['SETUP'].get('institution', 'old_project') + '_' + projectName ) # SETUP is overwritten (but not version nor python_environment) project_version = self['MainSettings']['SETUP'].get('version', '?') project_environ = self['MainSettings']['SETUP'].get('python_environment', {}) self['MainSettings']['SETUP'] = tmp['SETUP'] self['MainSettings']['SETUP']['version'] = project_version self['MainSettings']['SETUP']['python_environment'] = project_environ # SERVER is updated self['MainSettings'].setdefault('SERVER', NamelistName()).update(tmp.get('SERVER', {})) # load project options self.prj_options.clear() tmp = for k in OMFIT.prj_options_choices: self.prj_options[k] = tmp.get(k, '') for whereSave in ['__GUISAVE__', '__COMMANDBOX__']: if whereSave in OMFIT: del OMFIT[whereSave] if self.prj_options['color'] not in list(self.prj_options_choices['color'].keys()): self.prj_options['color'] = '' if self.prj_options['type'] not in self.prj_options_choices['type']: self.prj_options['type'] = '' if 'namespace' not in self.prj_options or not self.prj_options['namespace']: self.prj_options['namespace'] = 'OMFIT' # update projectID self.prj_options['persistent_projectID'] = persistent_projectID if not persistent_projectID: self.newProjectID() # keep MainSettings in check self.updateMainSettings() self['MainSettings'].sort() # set the localhost SERVER.setLocalhost() # remote projects are loaded in OMFITtmpDir # reset the filename to force users to decide how/where to save it if OMFITtmpDir in self.filename: self.filename = '' except Exception: self.start() raise
[docs] def updateCWD(self): global OMFITcwd self._save(filename=OMFITcwd + os.sep + 'OMFITsave.txt', skipStorage=False)
[docs] def updateMainSettings(self): self.addMainSettings() self.keyOrder.remove('scratch') self.keyOrder.append('scratch') self.keyOrder.remove('commandBox') self.keyOrder.append('commandBox') self.keyOrder.remove('scriptsRun') self.keyOrder.append('scriptsRun') self.keyOrder.remove('shotBookmarks') self.keyOrder.append('shotBookmarks') self.keyOrder.remove('MainSettings') self.keyOrder.append('MainSettings')
[docs] def saveMainSettingsSkeleton(self): """ This utility function updates the MainSettingsSkeleton for the current OMFIT installation """ self['MainSettings'].sort() tmp = copy.deepcopy(self['MainSettings']) self.addMainSettings(restore='skel') keys = self['MainSettings'].keys() for k in keys: if k.startswith('__comment'): del self['MainSettings'][k] self['MainSettings'].sort() try: self['MainSettings'].filename = self['MainSettings']['SETUP']['workDir'] + '../' + 'skeletonMainSettingsNamelist.txt' self['MainSettings']['SETUP']['version'] = '?' self['MainSettings']['SETUP']['python_environment'] = {} del self['MainSettings']['EXPERIMENT']['projectID'] del self['MainSettings']['EXPERIMENT']['provenanceID'] self['MainSettings']['SETUP']['browser'] = None self['MainSettings']['SETUP']['Extensions'].clear() # Avoid changes made by institution file self['MainSettings']['SETUP']['stats_file'] = OMFITexpression("os.path.abspath(OMFITsettingsDir+'/OMFITstats.txt')") self['MainSettings']['SETUP']['institution'] = 'PERSONAL' if 'institutionProjectsDir' in self['MainSettings']['SETUP']: del self['MainSettings']['SETUP']['institutionProjectsDir'] self['MainSettings']['EXPERIMENT']['device'] = None for k in tmp['SERVER']: if k not in self['MainSettings']['SERVER']: self['MainSettings']['SERVER'][k] = tmp['SERVER'][k] if isinstance(tmp['SERVER'][k], namelist.NamelistName): self['MainSettings']['SERVER'][k].update(tmp['SERVER'][k]) self['MainSettings']['SERVER']['localhost'] = namelist.NamelistName() self['MainSettings']['SERVER']['localhost']['workDir'] = OMFITexpression("OMFITcwd+os.sep+'remote_runs'+os.sep") self['MainSettings']['SERVER']['localhost']['server'] = 'localhost' self['MainSettings']['SERVER']['localhost']['tunnel'] = '' self['MainSettings']['SERVER']['localhost']['idl'] = '' self['MainSettings']['SERVER']['localhost']['matlab'] = '' self['MainSettings']['SERVER']['default_tunnel'] = None finally: self['MainSettings'].sort() self._save( filename=OMFITsrc + os.sep + 'omfit_classes' + os.sep + 'skeleton' + os.sep + 'skeletonMainSettings.txt', only="['MainSettings']", updateExistingDir=True, ) self['MainSettings'] = tmp
[docs] def availableModules(self=None, quiet=None, directories=None, same_path_as=None, force=False): """ Index available OMFIT modules in directories :param quiet: verbosity :param directories: list of directories to index. If `None` this is taken from OMFIT['MainSettings']['SETUP']['modulesDir'] :param same_path_as: sample OMFITsave.txt path to set directory to index :param force: force rebuild of .modulesInfoCache file :return: This method returns a dictionary with the available OMFIT modules. Each element in the dictionary is a dictionary itself with the details of the available modules. """ if directories is None: directories = OMFITmodule.directories() else: directories = tolist(directories) if same_path_as is None: pass elif 'OMFITsave.txt' in same_path_as and os.path.exists(same_path_as): directories = [os.path.split(os.path.split(same_path_as)[0])[0]] else: raise IOError('%s file is not a valid OMFITsave.txt file' % same_path_as) updatePersistentCache = [] moduleDict = {} for directory in directories: # the user inputs the directory where the modules are if not quiet: tmp = 'Modules directory: ' + directory printi('=' * len(tmp)) printi(tmp) printi('=' * len(tmp)) print('', end='') if not force and os.path.exists(directory + os.sep + '.modulesInfoCache'): try: with open(directory + os.sep + '.modulesInfoCache', 'rb') as f: _availableModulesCache[directory] = pickle.load(f) except Exception: _availableModulesCache[directory] = {} printw('-- Failed to load persistent git modules cache --') else: _availableModulesCache[directory] = {} # modules in directory modules_list_in_dir = sorted( [os.path.abspath(x) for x in glob.glob(os.sep.join([directory, '*', 'OMFITsave.txt']))], key=lambda x: x.lower() ) # try handling git repository of modules twice # first as if git root directory parent directory of modules directory # second as if git root directory is modules directory cases_errors = [] cases = [] if os.path.split(directory)[1] == 'modules': cases.append([os.path.split(directory)[0], 'modules']) cases.append([directory, '']) for repo_dir, modules_subpath in cases: try: # try to access as a git repository repo = OMFITgit(repo_dir) commit = repo("log -1 --pretty='%H'") branch = repo('rev-parse --abbrev-ref HEAD') remote = repo.get_branches().get(branch, {'remote': ''})['remote'] changed_modules = [] # if same remote/branch and commit if ( np.all([k in _availableModulesCache[directory] for k in ['branch', 'remote', commit]]) and _availableModulesCache[directory]['remote'] == remote and _availableModulesCache[directory]['branch'] == branch ): changes = list([_f for _f in repo("ls-files -m --others --exclude-standard " + directory).split('\n') if _f]) for mod_path in modules_list_in_dir: if ( mod_path not in _availableModulesCache[directory][commit] or len(_availableModulesCache[directory][commit][mod_path]['modified']) or len(_availableModulesCache[directory][commit][mod_path]['untracked']) ): changes.append(os.sep.join(mod_path.split(os.sep)[[-2, -3][len(modules_subpath) > 0] :])) if len(changes): if not quiet: printi('-- some modules changes are not part of git --') for mod in tolist(np.unique([x.split(os.sep)[[0, 1][len(modules_subpath) > 0]] for x in changes])): mod_path = directory + os.sep + mod if not os.path.exists(mod_path): raise Exception(mod_path + ' does not exist') tmp = repo.get_module_params(quiet=quiet, path=modules_subpath, key='path', modules=[mod_path]) _availableModulesCache[directory][commit].update(tmp) changed_modules.append(os.path.abspath(mod_path + os.sep + 'OMFITsave.txt')) elif not quiet: printi('-- modules cache is valid --') else: # if same remote/branch then try to update since recorded commit (faster: only need to loop over modules that changed) if ( np.all([k in _availableModulesCache[directory] for k in ['branch', 'remote']]) and len(_availableModulesCache[directory]) == 3 and _availableModulesCache[directory]['remote'] == remote and _availableModulesCache[directory]['branch'] == branch ): printi('-- updating modules cache since last commit --') try: old_commit = [ item for item in list(_availableModulesCache[directory].keys()) if item not in ['branch', 'remote'] ][0] changes = np.unique( [ modules_subpath + '/' + re.sub('^' + modules_subpath + '/', '', x).split(os.sep)[0] for x in repo('diff --name-only %s %s -- %s' % (old_commit, commit, modules_subpath)).split() ] ).tolist() changed_modules = [os.sep.join([repo_dir, x, 'OMFITsave.txt']) for x in changes] _availableModulesCache[directory][commit] = _availableModulesCache[directory][old_commit] del _availableModulesCache[directory][old_commit] _availableModulesCache[directory][commit].update( repo.get_module_params(quiet=quiet, path=modules_subpath, key='path', modules=changed_modules) ) except Exception as _excp: printw('Failed to update available modules cache: ' + repr(_excp)) del _availableModulesCache[directory] else: printi('-- rebuilding modules cache from scratch --') if directory in _availableModulesCache: del _availableModulesCache[directory] # if directory is not in _availableModulesCache then must build everything from scratch if directory not in _availableModulesCache: _availableModulesCache[directory] = {} _availableModulesCache[directory]['branch'] = branch _availableModulesCache[directory]['remote'] = remote _availableModulesCache[directory][commit] = repo.get_module_params( quiet=quiet, path=modules_subpath, key='path' ) updatePersistentCache.append(directory) # delete modules from cache if these are not found on hard drive for mod_path in list(_availableModulesCache[directory][commit].keys()): if not os.path.exists(_availableModulesCache[directory][commit][mod_path]['path']): del _availableModulesCache[directory][commit][mod_path] # update list of modules moduleDict.update(_availableModulesCache[directory][commit]) # do not try 2nd case if 1st one worked break except Exception as _excp: cases_errors.append(_excp) if len(cases_errors) == len(cases): _availableModulesCache[directory].clear() # if the path is not a valid git repository or the data was modified then get modules by hand for mod_path in modules_list_in_dir: if mod_path in moduleDict: continue mod = os.path.split(mod_path)[0] mod_name = os.path.split(mod)[1] if not quiet: printi(mod_name.ljust(20) + ' (untracked)') moduleDict[mod_path] = {} moduleDict[mod_path]['path'] = mod_path moduleDict[mod_path]['untracked'] = mod_path # just for compatibility with data returned by `get_module_params` moduleDict[mod_path]['modified'] = mod_path # just for compatibility with data returned by `get_module_params` moduleDict[mod_path]['edited_by'] = os.environ['USER'] moduleDict[mod_path]['date'] = convertDateFormat(time.time()) moduleDict[mod_path]['commit'] = '' moduleDict[mod_path]['description'] = '' info =[mod_path]['path']) info.pop('date', None) info.pop('edited_by', None) info.pop('commit', None) moduleDict[mod_path].update(info) # save modules info cache if directory in updatePersistentCache or not os.path.exists(directory + os.sep + '.modulesInfoCache'): try: with open(directory + os.sep + '.modulesInfoCache', 'wb') as f: pickle.dump(_availableModulesCache[directory], f, pickle.OMFIT_PROTOCOL) printi('-- Updated persistent git modules cache --') except IOError: pass return moduleDict
[docs] def quit(self, deepClean=False): """ Cleanup current OMFIT session directory `OMFITsessionDir` and PID from `OMFITsessionsDir` Also close all SSH related tunnels and connections :param deepClean: if deepClean is True, then the `OMFITtmpDir` and `OMFITsessionsDir` get deleted """ if OMFITcwd is None: return onlyRunningCopy = OMFIT.onlyRunningCopy(deletePID=True) if onlyRunningCopy: OMFIT.reset_connections() # reset_connections() will also close_mds_connections() else: omfit_classes.omfit_mds.close_mds_connections() try: if os.path.exists(OMFITsessionDir): shutil.rmtree(OMFITsessionDir) except Exception: printw('Some files and directories could not be deleted!') if deepClean: if os.path.exists(OMFITsessionsDir): try: shutil.rmtree(OMFITsessionsDir) os.makedirs(OMFITsessionsDir) except OSError: printw('Some files and directories under %s could not be deleted!' % OMFITsessionsDir) if os.path.exists(OMFITtmpDir): try: shutil.rmtree(OMFITtmpDir) except Exception: printw('Some files and directories under %s could not be deleted!' % OMFITtmpDir) return onlyRunningCopy
[docs] def reset_connections(self, server=None, mds_cache=True): """ Reset connections, stored passwords, and MDS+ cache :param server: only reset SSH connections to this server """ import utils_widgets serverPicker = '' if server is None: printi('Reset OMFIT stored passwords') utils_widgets.stored_passwords.clear() printi('Reset OMFIT server cache') SERVER_cache.clear() if mds_cache: printi('Purge OMFIT MDS+ cache') OMFITmdsCache().purge() else: printi('OMFIT MDS+ cache not purged; use OMFITmdsCache().purge() to purge it') printi('Reset OMFIT SSH connections') printi('Reset OMFIT MDS+ connections') omfit_classes.omfit_mds.close_mds_connections() printi('Reset OMFIT SQL connections') for k in ['MDSserverReachable', 'RDBserverReachable', 'batch_js', 'sshTunnel', 'sysinfo']: OMFITaux[k] = copy.deepcopy(OMFITaux.defaults[k]) else: if server: serverPicker = parse_server(SERVER[server]['server'])[2] printi('Reset OMFIT SSH connections to %s' % serverPicker) sshServices = ['OMFITssh', 'OMFITsshTunnel', 'OMFITsshControlmaster', 'OMFITsshGit'] # Have to create tmpdir since OMFIT tmp directory may have been cleaned up already import tempfile, shutil tmpdir = tempfile.mkdtemp() s = subprocess.Popen("ps xw", stdout=subprocess.PIPE, shell=True, cwd=tmpdir) std_out, std_err = s.communicate() shutil.rmtree(tmpdir) for item in b2s(std_out).split('\n'): service = [s for s in sshServices if, item)] if len(service) and, item): pid = int([_f for _f in item.split(' ') if _f][0]) try: printi('kill %s' % (item)) os.kill(int(pid), signal.SIGKILL) except OSError as e: printw('Failed! %s' % repr(e))
[docs] def recentProjects(self, only_read=False): """ This routine keeps track of the recent projects and is also in charge of deleting auto-saves if they do not appear in the project list. :param read_only: only read projects file (don't do any maintenance on it) """ # do not log projects that are in OMFITtmpDir if OMFITtmpDir in OMFIT.filename: return filename_old = OMFITsettingsDir + os.sep + 'OMFITrecentProjects.txt' filename = OMFITsettingsDir + os.sep + 'OMFITprojects.txt' autoSaveLinkDir = os.path.abspath(OMFIT['MainSettings']['SETUP']['projectsDir'].rstrip('/\\')) + os.sep + 'auto-save' + os.sep if not os.path.exists(filename) and os.path.exists(filename_old): shutil.copyfile(filename_old, filename) # read the projects projects = SortedDict() if os.path.exists(filename): with open(filename, 'r') as f: lines = f.readlines() for k, line in enumerate(lines): line = line.strip() tmp = line.split('{') if len(tmp) == 1: path = tmp[0].strip() opts = {} else: path = tmp[0].strip() opts = eval('{' + '{'.join(tmp[1:])) if os.path.exists(path): projects[path] = opts # add extra info (eg. file size) for item in list(projects.keys()): if 'size' not in projects[item] and os.path.exists(item) and item.endswith('.zip') and zipfile.is_zipfile(item): projects[item]['size'] = os.stat(item).st_size if only_read: return projects # this switch will be set to True if the recent projects file needs to be updated doWrite = False # delete `Self-Destruct` projects that have not been accessed in more than 30 days for item in list(projects.keys()): if projects[item].get('type', '') == 'Self-Destruct' and os.stat(item).st_atime < (time.time() - 30 * 86400): if os.path.isdir(item): shutil.rmtree(item) else: os.remove(item) del projects[item] doWrite = True # add projects which for some reason were not already there at the bottom of the list if os.path.exists(os.path.abspath(evalExpr(OMFIT['MainSettings']['SETUP']['projectsDir']))): for item in glob.glob(os.path.abspath(evalExpr(OMFIT['MainSettings']['SETUP']['projectsDir'])) + os.sep + '*'): if os.path.isdir(item): if os.path.exists(item + os.sep + 'OMFITsave.txt'): item = item + os.sep + 'OMFITsave.txt' else: continue if item not in projects: projects[item] = {} doWrite = True # try to read prj_options for the projects which do not have them for item in list(projects.keys()): if 'device' not in projects[item]: try: tmp = except Exception as _excp: printe('%s looks like an invalid OMFIT project' % (item)) del projects[item] continue tmp.setdefault('notes', '') for opt in OMFIT.prj_options_choices: if opt in tmp: projects[item][opt] = tmp[opt] doWrite = True # if the current project has been saved put it at the top of the list if ( OMFIT.filename is not None and len(OMFIT.filename) and autoSaveLinkDir not in OMFIT.filename and OMFITautosaveDir not in OMFIT.filename ): item = os.path.abspath(OMFIT.filename) if item in list(projects.keys()): del projects[item] projects.insert(0, item, copy.deepcopy(OMFIT.prj_options)) if item.endswith('.zip') and zipfile.is_zipfile(item): projects[item]['size'] = os.stat(item).st_size elif item.endswith('OMFITsave.txt'): projects[item]['size'] = size_of_dir(os.path.split(item)[0]) doWrite = True # do not store console output, commands, and namespace in OMFITprojects.txt for item in list(projects.keys()): for opt in ['console', 'commands', 'namespace']: if opt in projects[item]: del projects[item][opt] doWrite = True # only store modules locations for item in list(projects.keys()): if isinstance(projects[item]['modules'], dict): projects[item]['modules'] = list(projects[item]['modules'].keys()) # write OMFITprojects.txt~ then move to OMFITprojects.txt if successful # this is to have as much of an atomic operation as possible if doWrite: with open(filename_old + '~', 'w') as f_old, open(filename + '~', 'w') as f: for item in list(projects.keys()): f.write('%s %s\n' % (item, projects[item])) f_old.write('%s\n' % (item)) shutil.move(filename + '~', filename) shutil.move(filename_old + '~', filename_old) # delete auto-saves that are older than one week # process one old auto-save at the time ones that were accessed first (deleting large auto-saves can take some time) for dir in [OMFITautosaveDir, autoSaveLinkDir]: # sort auto-saves by time files = glob.glob(dir + os.sep + '*') # delete broken links (otherwise getatime will fail) remove = [] for path in files: if os.path.islink(path) and not os.path.exists(path): os.remove(path) remove.append(path) files = list(set(files).difference(set(remove))) # sort files files.sort(key=lambda x: os.path.getatime(x)) for path in files: # delete auto-saves that have not been accessed in more than one week if not os.path.islink(path) and os.path.isdir(path) and os.stat(path).st_atime < (time.time() - 7 * 86400): shutil.rmtree(path) break # delete one old auto-save at the time # delete broken links if os.path.islink(path) and not os.path.exists(path): os.remove(path) return projects
[docs] def showExecDiag(self): """ display execution diagram """ def printMe(tmp, depth): for child in tmp: filename = re.sub('', '', os.path.split(child['filename'])[1]) printi('* ' * (depth + 1) + " %s %3.3fs [%s]" % (filename, child['time'], sizeof_fmt(child['memory']))) printMe(child['child'], depth + 1) printi('\nExecution diagram:\n------------------') from omfit_classes.omfit_python import ExecDiagPtr printMe(ExecDiagPtr, 0)
[docs]class OMFITmainscratch(OMFITtmp): def __init__(self): self.required = list(map(lambda x: os.path.splitext(os.path.basename(x))[0], glob.glob(OMFITsrc + '/framework_guis/*.py')))
[docs] def initialize(self): for item in self.required: self.load_framework_gui(item)
[docs] def load_framework_gui(self, item): dev_acceptable = os.access(OMFITsrc + os.sep + 'framework_guis' + os.sep + item + '.py', os.W_OK) and not os.path.exists( os.sep.join([OMFITsrc, '..', 'public']) ) self[f'__{item}__'] = OMFITpythonGUI( OMFITsrc + os.sep + 'framework_guis' + os.sep + item + '.py', modifyOriginal=OMFIT['MainSettings']['SETUP']['developer_mode_by_default'] & dev_acceptable, )
def __delitem__(self, key): if key in self.required: self.load_framework_gui(key) else: super().__delitem__(key)
# -------------------------------- # Setup the global variable OMFIT # -------------------------------- OMFIT.__class__ = OMFITmaintree # root of the OMFIT tree OMFIT.modifyOriginal = False OMFIT.readOnly = False OMFIT._OMFITkeyName = 'OMFIT' OMFIT.prj_options = {} OMFIT.prj_options_choices = { 'notes': '', 'commands': '', 'commandNames': [], 'namespace': '', 'console': '', 'shot': '', 'time': '', 'device': '', 'modules': '', 'type': ['Self-Destruct', 'Test', 'Working', 'Done', 'VIP'], 'persistent_projectID': False, 'color': OrderedDict( ( ('red', 'red2'), ('orange', 'dark orange'), ('yellow', 'orange'), ('green', 'forest green'), ('blue', 'mediumblue'), ('purple', 'medium orchid'), ('gray', 'gray25'), ) ), } atexit.register(OMFIT.quit) # Register final automatic cleanup # ------------------------------------ # location from root requires knowing what `OMFIT` is # ------------------------------------
[docs]def locationFromRoot(location): """ :param location: tree location :return: tree location from the closest root """ tmp = location location = parseBuildLocation(location) for k in 1 + np.array(list(range(len(location) - 1))): loc = eval('OMFIT' + parseBuildLocation(location[:k])) if loc.__class__ is OMFITmodule: tmp = "root" + parseBuildLocation(location[k:]) return tmp
[docs]def rootLocation(location, *args, **kw): """ :param location: tree location :return: tree location of the root """ if len(args) >= 1: OMFIT = args[0] if len(args) >= 2: kw['rootName'] = args[1] rootName = kw.setdefault('rootName', 'OMFIT') location = parseBuildLocation(location) root = 'OMFIT' for k in 1 + np.array(list(range(len(location) - 1))): loc = eval('OMFIT' + parseBuildLocation(location[:k])) if loc.__class__ is OMFITmodule: root = 'OMFIT' + parseBuildLocation(location[:k]) root = rootName + root[5:] return root
# --------------------- # Import OMFIT APIs # and make it available to users Python scripts and expressions # --------------------- from omfit_classes import OMFITx setattr(omfit_classes.omfit_python, 'OMFITx', OMFITx) setattr(omfit_classes.omfit_base, 'OMFITx', OMFITx) # --------------------- # graphics # --------------------- from omfit_plot import * # --------------------- # update classes # --------------------- omfit_classes.omfit_base._updateTypes() # --------------------- # S3 # ---------------------
[docs]def OMFITobject_fromS3(filename, s3bucket): """ Recovers OMFITobject from S3 and reloads it with the right class and original keyword parameters :return: object loaded from S3 """ s3connection = boto3.resource('s3', **boto_credentials()) obj = s3connection.Object(s3bucket, filename) cls = eval(eval(obj.metadata.get('__class__', "'OMFITobject'"))) orig_filename = eval(obj.metadata.get('__filename__', filename)) tmp = cls(filename, s3bucket=s3bucket, **{k: eval(obj.metadata[k]) for k in obj.metadata if k not in ['__class__', '__filename__']}) if os.path.split(tmp.filename)[1] != orig_filename: shutil.move(tmp.filename, os.path.split(tmp.filename)[0] + os.sep + os.path.split(orig_filename)[1]) tmp.filename = os.path.split(tmp.filename)[0] + os.sep + os.path.split(orig_filename)[1] tmp.originalFilename = tmp.filename = tmp.filename return tmp
# --------------------- # backwards compatibility # --------------------- isNone = is_none
[docs]class OMFITfileASCII(OMFITascii): """ Use of this class is deprecated: use OMFITascii instead """
[docs]class OMFIT_Ufile(OMFITuFile): """ Use of this class is deprecated: use OMFITuFile instead """
[docs]class OMFITdict(SortedDict): """ Use of this class is deprecated: use SortedDict instead """
expr_value = evalExpr
[docs]class chebyfit(omfit_classes.utils_fit.fitCH): """ Use of this class is deprecated: use fitCH instead """
[docs]class OMFITdependenceException(RuntimeError): """ Use of this class is deprecated: use RuntimeError instead """
# ------------------ # this version time (follows last version time in # ------------------ _filename = OMFITsettingsDir + os.sep + 'OMFITlastRun.txt' if float(thisVersionTime) > float(latestVersionTime): with open(_filename, 'w') as _f: _f.write(str(thisVersionTime)) # -------------------------------------- # load main settings and override / fix # older versions of users main settings # NOTE: after this point on OMFIT['MainSettings'] is available and can be accessed # -------------------------------------- def _clearDeprecatedMainSettings(MainSettings): # keep track if there has been a change updated = False keep = {} # clear if last version is before given time or if `tmpDir` is found within one month after given time # (this is done to manage transition between versions of OMFIT that are already running) if latestVersionTime < 1427916944 or ( 'SETUP' in MainSettings and 'tmpDir' in MainSettings['SETUP'] and thisVersionTime < (1427916944 + 60 * 60 * 24 * 30) ): keep['SETUP'] = {} keep['SETUP']['email'] = '' keep['SETUP']['modulesDir'] = '' keep['SETUP']['editor'] = '' keep['SETUP']['browser'] = '' keep['SETUP']['error_report'] = '' for k in ['Extensions', 'KeyBindings', 'GUIappearance']: if k in MainSettings['SETUP']: keep['SETUP'][k] = copy.deepcopy(MainSettings['SETUP'][k]) keep['EXPERIMENT'] = {} keep['EXPERIMENT']['device'] = '' keep['EXPERIMENT']['shot'] = '' keep['EXPERIMENT']['time'] = '' keep['SERVER'] = {} keep['SERVER']['GA_username'] = '' keep['SERVER']['PPPL_username'] = '' keep['SERVER']['NERSC_username'] = '' keep['SERVER']['UCSD_username'] = '' keep['SERVER']['ITM_username'] = '' keep['SERVER']['MIT_username'] = '' keep['SERVER']['default'] = '' keep['SERVER']['idl'] = '' keep['SERVER']['matlab'] = '' tmp = prune_mask(MainSettings, keep) MainSettings.clear() MainSettings.update(tmp) updated = True if 'SERVER' in MainSettings: # delete deprecated servers and localhost (localhost entry will be re-created) for server in ( ['thea', 'harvest', 'venus', 'venus_tmp', 'venus_scratch', 'hopper', 'zeus', 'lohan', 'philos', 'edison'] + list(['lohan%d' % x for x in range(20)]) + ['localhost'] ): if server in list(MainSettings['SERVER'].keys()): del MainSettings['SERVER'][server] if server != 'localhost': updated = '1. deprecated_server:' + server # delete references to the deprecated servers for item in list(MainSettings['SERVER'].keys()): if ( 'localhost' not in [item, server] and isinstance(MainSettings['SERVER'][item], str) and MainSettings['SERVER'][item] == server ): del MainSettings['SERVER'][item] updated = '2. deprecated_server: (%s,%s)' % (server, item) # delete servers if any of their entries is set to None for server in list(MainSettings['SERVER'].keys()): if isinstance(MainSettings['SERVER'][server], namelist.NamelistName): for item in list(MainSettings['SERVER'][server].keys()): if MainSettings['SERVER'][server][item] == None: del MainSettings['SERVER'][server] updated = 'none_server' break # freeze usernames username_keys = [item for item in MainSettings['SERVER'] if item.endswith('_username')] for username_key in username_keys: # if OMFIT is running at a recognized institution set username to match os.environ['USER'] if OMFITexpression or empty string if ( (isinstance(MainSettings['SERVER'][username_key], OMFITexpression) or not MainSettings['SERVER'][username_key]) and ('institution' in MainSettings['SETUP']) and username_key == (MainSettings['SETUP']['institution'] + '_username') ): MainSettings['SERVER'][username_key] = os.environ['USER'] updated = 'freeze_username_institution' # for all other servers set username to empty string if username is an OMFITexpression elif isinstance(MainSettings['SERVER'][username_key], OMFITexpression): MainSettings['SERVER'][username_key] = '' updated = 'freeze_username_expression' # NFRI renamed themselves to KFE if ( 'KFE_username' in MainSettings['SERVER'] and not MainSettings['SERVER']['KFE_username'] and 'NFRI_username' in MainSettings['SERVER'] and MainSettings['SERVER']['NFRI_username'] ): MainSettings['SERVER']['KFE_username'] = MainSettings['SERVER']['NFRI_username'] # prevent users to change workDir in bad ways if 'SETUP' in MainSettings and 'workDir' in MainSettings['SETUP'] and OMFITcwd not in str(MainSettings['SETUP']['workDir']): MainSettings['SETUP']['workDir'] = OMFITexpression("OMFITcwd+os.sep+'runs'+os.sep") updated = 'workdir' if ( 'SETUP' in MainSettings and 'GUIappearance' in MainSettings['SETUP'] and 'persistent_projectID' in MainSettings['SETUP']['GUIappearance'] ): del MainSettings['SETUP']['GUIappearance']['persistent_projectID'] updated = 'persistent_project_id' if 'EXPERIMENT' in MainSettings and 'runid' in MainSettings['EXPERIMENT'] and MainSettings['EXPERIMENT']['runid'] == None: MainSettings['EXPERIMENT']['runid'] = 'sim1' updated = 'experiment' return updated OMFIT.reset() _updated = _clearDeprecatedMainSettings(OMFIT['MainSettings']) if _updated: OMFIT.addMainSettings(updateUserSettings=True) # set OMFIT repos directory where the users projects are stored # rationale: home directory have quotas, scratch directories get automatically cleaned omfit_classes.utils_base.OMFITreposDir = ( os.path.split(os.path.abspath(evalExpr(OMFIT['MainSettings']['SETUP']['projectsDir'])))[0] + os.sep + '.repos' ) # ------------------------------------ # Initialize OMFIT tree # ------------------------------------ if not np.any([('sphinx' in k and not 'sphinxcontrib' in k) for k in sys.modules]): OMFIT.start() print('Time to load omfit_tree: %g seconds' % (time.time() - _t0)) # ------------------------------------ # Set new modules skeleton # ------------------------------------ if os.path.exists(OMFITsessionDir + os.sep + 'NEW_MODULE_skeleton'): shutil.rmtree(OMFITsessionDir + os.sep + 'NEW_MODULE_skeleton', ignore_errors=True) shutil.copytree( OMFITsrc + os.sep + 'omfit_classes' + os.sep + 'skeleton' + os.sep + 'NEW_MODULE', OMFITsessionDir + os.sep + 'NEW_MODULE_skeleton' ) OMFITaux['moduleSkeletonCache'] = OMFITtree( OMFITsessionDir + os.sep + 'NEW_MODULE_skeleton' + os.sep + 'OMFITsave.txt', quiet=True, modifyOriginal=True, readOnly=True )