def run(function_name=None, function_input=None): """Triggers the execution environment entry point processor. Use this function in the program entry point code: .. code-block:: python import dxpy @dxpy.entry_point('main') def hello(i): pass dxpy.run() This method may be used to invoke the program either in a production environment (inside the execution environment) or for local debugging (in the debug harness), as follows: If the environment variable *DX_JOB_ID* is set, the processor retrieves the job with that ID from the API server. The job's *function* field indicates the function name to be invoked. That function name is looked up in the table of all methods decorated with *@dxpy.entry_point('name')* in the module from which :func:`run()` was called, and the matching method is invoked (with the job's input supplied as parameters). This is the mode of operation used in the DNAnexus execution environment. .. warning:: The parameters *function_name* and *function_input* are disregarded in this mode of operation. If the environment variable *DX_JOB_ID* is not set, the function name may be given in *function_name*; if not set, it is set by the environment variable *DX_TEST_FUNCTION*. The function input may be given in *function_input*; if not set, it is set by the local file *job_input.json* which is expected to be present. The absence of *DX_JOB_ID* signals to :func:`run()` that execution is happening in the debug harness. In this mode of operation, all calls to :func:`dxpy.bindings.dxjob.new_dxjob()` (and higher level handler methods which use it) are intercepted, and :func:`run()` is invoked instead with appropriate inputs. """ global RUN_COUNT RUN_COUNT += 1 dx_working_dir = os.getcwd() if dxpy.JOB_ID is not None: logging.basicConfig() try: logging.getLogger().addHandler(dxpy.DXLogHandler()) except dxpy.exceptions.DXError: print( "TODO: FIXME: the EE client should die if logging is not available" ) job = dxpy.describe(dxpy.JOB_ID) else: if function_name is None: function_name = os.environ.get('DX_TEST_FUNCTION', 'main') if function_input is None: with open("job_input.json", "r") as fh: function_input = json.load(fh) job = {'function': function_name, 'input': function_input} with open("job_error_reserved_space", "w") as fh: fh.write( "This file contains reserved space for writing job errors in case the filesystem becomes full.\n" + " " * 1024 * 64) print("Invoking", job.get('function'), "with", job.get('input')) try: result = ENTRY_POINT_TABLE[job['function']](**job['input']) except dxpy.AppError as e: save_error(e, dx_working_dir, error_type="AppError") raise except Exception as e: save_error(e, dx_working_dir) raise if result is not None: # TODO: protect against client removing its original working directory os.chdir(dx_working_dir) with open("job_output.json", "wb") as fh: json.dump(result, fh, indent=2, cls=DXJSONEncoder) fh.write(b"\n") return result
# # See https://wiki.dnanexus.com/Developer-Portal for documentation and # tutorials on how to modify this file. # # DNAnexus Python Bindings (dxpy) documentation: # http://autodoc.dnanexus.com/bindings/python/current/ import subprocess import shlex from multiprocessing import cpu_count import dxpy import common import logging logger = logging.getLogger(__name__) logger.addHandler(dxpy.DXLogHandler()) logger.propagate = False logger.setLevel(logging.INFO) SPP_VERSION_MAP = { "1.10.1": "/phantompeakqualtools/spp_1.10.1.tar.gz", "1.14": "/phantompeakqualtools/spp-1.14.tar.gz" } def xcor_parse(fname): with open(fname, 'r') as xcor_file: if not xcor_file: return None lines = xcor_file.read().splitlines()
def run(function_name=None, function_input=None): ''' Triggers the execution environment entry point processor. Use this function in the program entry point code: import dxpy @dxpy.entry_point('main') def hello(i): pass dxpy.run() If the environment variable *DX_JOB_ID* is set, the processor retrieves the job with that ID from the API server. The job's *job.function* field is used to invoke the entry point function in the module from which run() has been called. The function name is looked up in the table of all functions decorated with *@dxpy.entry_point('name')*. This is the mode of operation used in the DNAnexus execution environment. WARNING: The parameters *function_name* and *function_input* are disregarded in this mode of operation. If the environment variable *DX_JOB_ID* is not set, the function name may be given in *function_name*; if not set, it is set by the environment variable *DX_TEST_FUNCTION*. The function input may be given in *function_input*; if not set, it is set by the local file *job_input.json* which is expected to be present. The absence of *DX_JOB_ID* signals to run() that execution is happening in the debug harness. In this mode of operation, all calls to *dxpy.bindings.DXJob.new* (and higher level handler methods which use it) are intercepted, and run() is invoked instead with appropriate inputs. The initial invocation of *dxpy.run()* (with no arguments) need not be changed; instead, use a local file *job_input.json*. With this, no program code requires changing between the two modes. ''' global RUN_COUNT RUN_COUNT += 1 dx_working_dir = os.getcwd() if dxpy.JOB_ID is not None: logging.basicConfig() try: logging.getLogger().addHandler(dxpy.DXLogHandler()) except dxpy.exceptions.DXError: print "TODO: FIXME: the EE client should die if logging is not available" job = dxpy.describe(dxpy.JOB_ID) else: if function_name is None: function_name = os.environ.get('DX_TEST_FUNCTION', 'main') if function_input is None: with open("job_input.json", "r") as fh: function_input = json.load(fh) job = {'function': function_name, 'input': function_input} with open("job_error_reserved_space", "w") as fh: fh.write( "This file contains reserved space for writing job errors in case the filesystem becomes full.\n" + " " * 1024 * 64) print "Invoking", job.get('function'), "with", job.get('input') try: result = ENTRY_POINT_TABLE[job['function']](**job['input']) except dxpy.AppError as e: if dxpy.JOB_ID is not None: os.chdir(dx_working_dir) with open("job_error.json", "w") as fh: fh.write( json.dumps({ "error": { "type": "AppError", "message": _format_exception_message(e) } }) + "\n") raise except Exception as e: if dxpy.JOB_ID is not None: os.chdir(dx_working_dir) try: os.unlink("job_error_reserved_space") except: pass with open("job_error.json", "w") as fh: fh.write( json.dumps({ "error": { "type": "AppInternalError", "message": _format_exception_message(e) } }) + "\n") raise result = convert_handlers_to_dxlinks(result) if result is not None: # TODO: protect against client removing its original working directory os.chdir(dx_working_dir) with open("job_output.json", "w") as fh: fh.write(json.dumps(result) + "\n") return result