Source code for fyrd.submission_scripts

# -*- coding: utf-8 -*-
"""
Classes to build submission scripts.
"""
import os  as _os
import sys as _sys
import inspect as _inspect
import dill as _pickle

###############################################################################
#                               Import Ourself                                #
###############################################################################

from . import run as _run
from . import logme as _logme
from . import script_runners as _scrpts


[docs]class Script(object): """A script string plus a file name.""" written = False def __init__(self, file_name, script): """Initialize the script and file name.""" self.script = script self.file_name = _os.path.abspath(file_name)
[docs] def write(self, overwrite=True): """Write the script file.""" _logme.log('Script: Writing {}'.format(self.file_name), 'debug') pth = _os.path.split(_os.path.abspath(self.file_name))[0] if not _os.path.isdir(pth): raise OSError('{} Does not exist, cannot write scripts' .format(pth)) if overwrite or not _os.path.exists(self.file_name): with open(self.file_name, 'w') as fout: fout.write(self.script + '\n') self.written = True return self.file_name else: return None
[docs] def clean(self, delete_output=None): """Delete any files made by us.""" if delete_output: _logme.log('delete_output not implemented in Script', 'debug') if self.written and self.exists: _logme.log('Script: Deleting {}'.format(self.file_name), 'debug') _os.remove(self.file_name)
@property def exists(self): """True if file is on disk, False if not.""" return _os.path.exists(self.file_name) def __repr__(self): """Display simple info.""" return "Script<{}(exists: {}; written: {})>".format( self.file_name, self.exists, self.written) def __str__(self): """Print the script.""" return repr(self) + '::\n\n' + self.script + '\n'
[docs]class Function(Script): """A special Script used to run a function.""" def __init__(self, file_name, function, args=None, kwargs=None, imports=None, syspaths=None, pickle_file=None, outfile=None): """Create a function wrapper. NOTE: Function submission will fail if the parent file's code is not wrapped in an if __main__ wrapper. Args: file_name (str): A root name to the outfiles function (callable): Function handle. args (tuple): Arguments to the function as a tuple. kwargs (dict): Named keyword arguments to pass in the function call imports (list): A list of imports, if not provided, defaults to all current imports, which may not work if you use complex imports. The list can include the import call, or just be a name, e.g ['from os import path', 'sys'] syspaths (list): Paths to be included in submitted function pickle_file (str): The file to hold the function. outfile (str): The file to hold the output. """ _logme.log('Building Function for {}'.format(function), 'debug') self.function = function self.parent = _inspect.getmodule(function) self.args = args self.kwargs = kwargs ########################## # Take care of imports # ########################## filtered_imports = _run.get_all_imports( function, {'imports': imports}, prot=True ) # Get rid of duplicates and join imports impts = _run.indent('\n'.join(set(filtered_imports)), ' ') # Import the function itself func_import = _run.indent(_run.import_function(function), ' ') # sys paths if syspaths: _logme.log('Syspaths: {}'.format(syspaths), 'debug') impts = (_run.indent(_run.syspath_fmt(syspaths), ' ') + '\n\n' + impts) # Set file names self.pickle_file = pickle_file if pickle_file else file_name + '.pickle.in' self.outfile = outfile if outfile else file_name + '.pickle.out' # Create script text script = '#!{}\n'.format(_sys.executable) script += _scrpts.FUNC_RUNNER.format(name=file_name, modimpstr=func_import, imports=impts, pickle_file=self.pickle_file, out_file=self.outfile) super(Function, self).__init__(file_name, script)
[docs] def write(self, overwrite=True): """Write the pickle file and call the parent Script write function.""" _logme.log('Writing pickle file {}'.format(self.pickle_file), 'debug') with open(self.pickle_file, 'wb') as fout: _pickle.dump((self.function, self.args, self.kwargs), fout) super(Function, self).write(overwrite)
[docs] def clean(self, delete_output=False): """Delete the input pickle file and any scripts. Args: delete_output (bool): Delete the output pickle file too. """ if self.written: if _os.path.isfile(self.pickle_file): _logme.log('Function: Deleting {}'.format(self.pickle_file), 'debug') _os.remove(self.pickle_file) else: _logme.log('Function: {} already gone' .format(self.pickle_file), 'debug') if delete_output: if _os.path.isfile(self.outfile): _logme.log('Function: Deleting {}'.format(self.outfile), 'debug') _os.remove(self.outfile) else: _logme.log('Function: {} already gone' .format(self.outfile), 'debug') super(Function, self).clean(None)