def main(): app = connexion.App(__name__, specification_dir='./openapi/') app.app.json_encoder = encoder.JSONEncoder app.add_api('openapi.yaml', arguments={'title': 'pathoLogic'}, pythonic_params=True) # Serve results under /v1/result/PATH app.app.config['STATIC_URL_PATH'] = os.path.abspath( os.getenv('BASE_DIR', os.getcwd())) CORS(app.app) # enable CORS everywhere # Use dictionary as DB with app.app.app_context(): get_db() @app.app.teardown_appcontext def close_db(e=None): db = g.pop('db', None) if db is not None: pickle.dump( db, open( os.path.join(os.getenv('BASE_DIR', os.getcwd()), 'pathoLogic.db'), 'wb')) # Create route for nextflow weblog (assembly) @app.app.route('/v1/nf_assembly/<runid>', methods=['POST']) def nf_assembly(runid): req_data = request.get_json() db = get_db() db['status_hybridassembly'][runid] = req_data #print(json.dumps(db['status_assembly'][runid])) if req_data['event'] == 'process_completed': for sID in db['runs'][runid]: db['samples'][sID]['status'] = 'finished' return 'NF Request received' # Create route for nextflow weblog (plasmident) @app.app.route('/v1/nf_plasmident/<runid>', methods=['POST']) def nf_plasmident(runid): req_data = request.get_json() db = get_db() db['status_plasmident'][runid] = req_data #print(json.dumps(db['status_plasmident'][runid])) if req_data['event'] == 'process_completed': for sID in db['runs'][runid]: db['samples'][sID]['status'] = 'finished' return 'NF Request received' production = os.getenv('PRODUCTION', False) app.run(port=os.getenv('HTTP_PORT', 8080), debug=not production, use_debugger=not production, use_reloader=not production, passthrough_errors=not production)
def nf_plasmident(runid): req_data = request.get_json() db = get_db() db['status_plasmident'][runid] = req_data #print(json.dumps(db['status_plasmident'][runid])) if req_data['event'] == 'process_completed': for sID in db['runs'][runid]: db['samples'][sID]['status'] = 'finished' return 'NF Request received'
def status_get(): # noqa: E501 """Get list of all sample statuses # noqa: E501 :rtype: List[object] """ db = get_db() return [{ 'id': sample, 'status': db['samples'][sample]['status'] } for sample in db['samples'].keys()]
def samples_post(user, body=None): # noqa: E501 """Create new samples # noqa: E501 :param body: :type body: dict | bytes :rtype: Sample """ # Create samplepath samplepath = os.path.join(os.environ.get('BASE_DIR', os.getcwd()), 'samples') if not os.path.isdir(samplepath): os.mkdir(samplepath) # Save config and read files for each sample in new folder for s in body['samples']: conf = body['config'] if os.path.isdir(os.path.join(samplepath, s['id'])): raise BadRequest("Sample with ID: {} exists already.".format( s['id'])) os.mkdir(os.path.join(samplepath, s['id'])) with open(os.path.join(samplepath, s['id'], "nf_config.json"), 'w') as outfile: json.dump(conf, outfile) with open(os.path.join(samplepath, s['id'], "read_locations.tsv"), 'w') as outfile: if not "path_lr" in s: raise BadRequest( "Submitted incomplete sample {}, long run path is missing." .format(s['id'])) paths = [ join_read_path_with_data_dir(read_path, user) for read_path in [s['path_lr'], s.get('path_sr1', ""), s.get('path_sr2', "")] if len(read_path) ] outfile.write(s['id'] + '\t' + "\t".join(paths) + '\n') db = get_db() db['samples'][s['id']] = { 'user_id': user, 'id': s['id'], 'created': str(datetime.utcnow()), 'last_updated': str(datetime.utcnow()), 'status': "created", 'zip': None } return body['samples']
def samples_sample_iddelete(sample_id, user): # Get current database db = get_db() samples = sample_id.split(',') if not all(map(lambda sample: db['samples'][sample]['user_id'] == user, samples)): raise BadRequest("You are trying to start a sample for a different user. I am afraid I can't do that, Dave.") for sID in samples: sample_folder_path = os.path.join(os.getenv('DATA_DIR', os.getcwd()), user) if os.path.exists(sample_folder_path): shutil.rmtree(sample_folder_path) # remove samples from FS db['samples'].pop(sID) # remove samples from database return jsonify([{'id': sID} for sID in samples])
def samples_get(user): # noqa: E501 """List all samples # noqa: E501 :rtype: List[Sample] """ db = get_db() # filter samples without user id samples = [ sample for sample in db['samples'].keys() if 'user_id' in db['samples'][sample] ] return [ format_sample(db['samples'][sample]) for sample in samples if db['samples'][sample]['user_id'] == user ]
def result_sample_idget(sample_id): # noqa: E501 """Lists results for given sample # noqa: E501 :param sample_id: Comma seperated list of results to return :type sample_id: List[str] :rtype: InlineResponse2002 """ db = get_db() samples = sample_id.split(',') sample = [db['samples'][sample] for sample in db['samples'].keys() if sample in samples][0] return {'id':sample['id'], 'result': { 'statistics_path': 'mystats', 'zip_path': os.path.basename(sample['zip']) } }
def samples_sample_idput(sample_id, user): # noqa: E501 """Starts one or multiple sample via ID # noqa: E501 :param sample_id: :type sample_id: List[str] :rtype: jsonify """ # Get current database db = get_db() samples = sample_id.split(',') if not all(map(lambda sample: db['samples'][sample]['user_id'] == user, samples)): raise BadRequest("You are trying to start a sample for a different user. I am afraid I can't do that, Dave.") # Set sample status to started for sID in samples: db['samples'][sID]['status'] = 'started' #Try to run all this stuff # Create run folder runspath = os.path.join(os.environ.get('BASE_DIR', os.getcwd()), 'runs') if not os.path.isdir(runspath): os.mkdir(runspath) runid = str(uuid.uuid4()) runpath = os.path.join(runspath, runid) if not os.path.isdir(runpath): os.mkdir(runpath) # Get nextflow paths nfexecutable = os.path.join(os.environ.get('BASE_DIR', os.getcwd()), 'nextflow') nf_hybridassembly = os.path.join(os.environ.get('BASE_DIR', os.getcwd()), 'hybridassembly', 'main.nf') nf_plasmident = os.path.join(os.environ.get('BASE_DIR', os.getcwd()), 'plasmIDent', 'main.nf') # Set sample status to started for sID in samples: db['samples'][sID]['status'] = 'started' # Assign samples to run db['runs'][runid] = samples # Copy input and config files to run folder status = 0 status += os.system("cat " + " ".join([os.path.join(os.environ.get('BASE_DIR', os.getcwd()), 'samples', sID, 'read_locations.tsv') for sID in samples]) + " >> " + os.path.join(runpath, "read_locations.tsv")) status += os.system("cp " + os.path.join(os.environ.get('BASE_DIR', os.getcwd()), 'samples', sample_id, "nf_config.json") + " " + os.path.join(runpath, "nf_config.json")) # Run Hybrid assembly call_ha = ("cd " + runpath + " && " + nfexecutable + " run " + nf_hybridassembly + " -profile app " + " --outDir " + runpath + " --input read_locations.tsv " + "-params-file nf_config.json -with-weblog " + "http://localhost:"+os.environ.get('HTTP_PORT',"8080")+"/v1/nf_assembly/" + runid) print(call_ha) status += os.system("cd " + runpath + " && " + call_ha) # Run plasmident call_pi = (nfexecutable + " run " + nf_plasmident + " -profile app " + " --outDir " + runpath + " --input file_paths_plasmident.tsv " + "-params-file nf_config.json -with-weblog "+ "http://localhost:"+os.environ.get('HTTP_PORT',"8080")+"/v1/nf_plasmident/" + runid) print(call_pi) status += os.system("cd " + runpath + " && " + call_pi) if status == 0: for sID in samples: # Zip output folders zip_path = os.path.join(runpath, sID) zip_name = os.path.join(zip_path, sID + '_pathoLogic_results') shutil.make_archive(zip_name, 'zip', root_dir=zip_path, base_dir=zip_path) db['samples'][sID]['zip'] = zip_name + '.zip' # Store ref to summary statistics file in db stats_file = os.path.join(runpath, sID, "qc", "qc_summary_" + sID + '.json') db['samples'][sID]['assembly_stats'] = stats_file else: # Set sample status to errored for sID in samples: db['samples'][sID]['status'] = 'error' return jsonify([{'id': sID, 'status': 'error'} for sID in samples]) return jsonify([{'id': sID, 'status': 'started'} for sID in samples])