| 22 | 1 #!/usr/bin/python | 
|  | 2 | 
|  | 3 import argparse | 
|  | 4 import logging | 
|  | 5 import os | 
|  | 6 import re | 
|  | 7 import shutil | 
|  | 8 import subprocess | 
|  | 9 import sys | 
|  | 10 import tempfile | 
|  | 11 | 
|  | 12 def exit_and_explain(msg): | 
|  | 13     logging.critical(msg) | 
|  | 14     sys.exit(msg) | 
|  | 15 | 
|  | 16 def cleanup_before_exit(tmp_dir): | 
|  | 17     if tmp_dir and os.path.exists(tmp_dir): | 
|  | 18         shutil.rmtree(tmp_dir) | 
|  | 19 | 
|  | 20 def get_arg(): | 
|  | 21     parser = argparse.ArgumentParser() | 
|  | 22     parser.add_argument('--project_name', dest='project_name', action='store', nargs=1, metavar='project_name', type=str) | 
|  | 23     #Input 1: Annotation File | 
|  | 24     parser.add_argument('--index', dest='indexes', action='store', nargs=2, metavar=('stranded_index_filename', 'unstranded_index_filename'), type=str) | 
|  | 25     parser.add_argument('--bi_index', dest='bi_indexes', action='store', nargs=1, metavar='built_in_indexes_dir_path', type=str ) | 
|  | 26     parser.add_argument('--annotation', dest='annotation_file', action='store', nargs=1, metavar='annotation_gtf_file', type=str ) | 
|  | 27     #Input 2: Mapped Reads | 
|  | 28     parser.add_argument('--reads_format', dest='reads_format', action='store', nargs=1, choices=['bam', 'bedgraph'], metavar='reads_format', type=str) | 
|  | 29     parser.add_argument('--reads', dest='reads', action='store', nargs='+', metavar=('bam_file1 label1',""), type=str) | 
|  | 30     parser.add_argument('--strandness', dest='strandness', action='store', nargs=1, default=['unstranded'], choices=['unstranded', 'forward', 'reverse'], metavar='strandness', type=str) | 
|  | 31     #Output files | 
|  | 32     parser.add_argument('--output_pdf', dest='output_pdf', action='store', nargs=1, metavar='output_pdf_filename', type=str) | 
|  | 33     parser.add_argument('--output_svg', dest='output_svg', action='store', nargs=2, metavar=('categories_svg_filename', 'biotypes_svg_filename'), type=str) | 
|  | 34     parser.add_argument('--output_png', dest='output_png', action='store', nargs=2, metavar=('categories_png_filename', 'biotypes_png_filename'), type=str) | 
|  | 35     parser.add_argument('--output_count', dest='output_count', action='store', nargs=1, metavar='output_count_filename', type=str) | 
|  | 36     parser.add_argument('--output_index', dest='output_indexes', action='store', nargs=2, metavar=('output_stranded_index_filename', 'output_unstranded_index_filename'), type=str) | 
|  | 37     #Output Options | 
|  | 38     parser.add_argument('--categories_depth', dest='categories_depth', action='store', nargs=1, default=[3], choices=range(1,5), metavar='categories_depth', type=int) | 
|  | 39     parser.add_argument('--plot_format', dest='plot_format', action='store', nargs=1, choices=['pdf', 'png', 'svg'], metavar='plot_format', type=str) | 
|  | 40     parser.add_argument('--threshold', dest='threshold', action='store', nargs=2, metavar=('yMin', 'yMax'), type=float) | 
|  | 41     #Internal variables | 
|  | 42     parser.add_argument('--log_report', dest='log_report', action='store', nargs=1, metavar='log_filename', type=str) | 
|  | 43     parser.add_argument('--tool_dir', dest='GALAXY_TOOL_DIR', action='store', nargs=1, metavar='galaxy_tool_dir_path', type=str) | 
|  | 44     args = parser.parse_args() | 
|  | 45     return args | 
|  | 46 | 
| 28 | 47 def symlink_user_indexes(stranded_index, unstranded_index): | 
| 22 | 48     index='index' | 
| 28 | 49     os.symlink(stranded_index, index + '.stranded.index') | 
|  | 50     os.symlink(unstranded_index, index + '.unstranded.index') | 
| 22 | 51     return index | 
|  | 52 | 
|  | 53 def get_input2_args(reads_list, format): | 
|  | 54     n = len(reads_list) | 
|  | 55     if n%2 != 0: | 
|  | 56         exit_and_explain('Problem with pairing reads filename and reads label') | 
|  | 57     input2_args='-i' | 
| 30 | 58     k = 0 | 
| 22 | 59     reads_filenames = [''] * (n/2) | 
|  | 60     reads_labels = [''] * (n/2) | 
|  | 61     for i in range(0, n, 2): | 
|  | 62         reads_filenames[k] = reads_list[i].split('__fname__')[1] | 
|  | 63         reads_labels[k] = reads_list[i+1].split('__label__')[1] | 
|  | 64         if not reads_labels[k]: | 
| 29 | 65             reads_labels[k] = 'sample_%s' % str(k) | 
| 22 | 66         input2_args='%s %s %s' % (input2_args, reads_filenames[k], reads_labels[k]) | 
|  | 67         k += 1 | 
|  | 68     if format == 'bedgraph': | 
|  | 69         input2_args = input2_args + ' --bedgraph' | 
|  | 70     return input2_args, reads_filenames, reads_labels | 
|  | 71 | 
|  | 72 def redirect_errors(alfa_out, alfa_err): | 
|  | 73     # When the option --n is enabled, alfa prints '### End of the program' in stderr even if the process worked- | 
|  | 74     # The following lines to avoid the tool from crashing in this case | 
|  | 75     if alfa_err and not re.search('### End of program', alfa_err): | 
|  | 76         # When alfa prints '### End of program' in stdout, all the messages in stderr are considered | 
|  | 77         # as warnings and not as errors. | 
|  | 78         if re.search('### End of program', alfa_out): | 
|  | 79             logging.warning("The script ALFA.py encountered the following warning:\n\n%s" % alfa_err) | 
|  | 80             logging.info("\n******************************************************************\n") | 
|  | 81         # True errors make the script exits | 
|  | 82         else: | 
|  | 83             exit_and_explain("The script ALFA.py encountered the following error:\n\n%s" % alfa_err) | 
|  | 84 | 
|  | 85 def merge_count_files(reads_labels): | 
|  | 86     merged_count_file = open('count_file.txt', 'wb') | 
|  | 87     for i in range(0, len(reads_labels)): | 
|  | 88         current_count_file = open(reads_labels[i] + '.categories_counts', 'r') | 
| 30 | 89         merged_count_file.write('##LABEL: %s\n\n' % reads_labels[i]) | 
| 22 | 90         merged_count_file.write(current_count_file.read()) | 
|  | 91         merged_count_file.write('__________________________________________________________________\n') | 
|  | 92         current_count_file.close() | 
|  | 93     merged_count_file.close() | 
|  | 94     return 'count_file.txt' | 
|  | 95 | 
|  | 96 def main(): | 
|  | 97     args = get_arg() | 
|  | 98 | 
|  | 99     if not (args.output_pdf or args.output_png or args.output_svg or args.output_indexes or args.output_count): | 
|  | 100         exit_and_explain('Error: no output to return\nProcess Aborted\n') | 
| 26 | 101     tmp_dir = tempfile.mkdtemp(prefix='tmp', suffix='') | 
| 22 | 102     logging.basicConfig(level=logging.INFO, filename=args.log_report[0], filemode="a+", format='%(message)s') | 
|  | 103     alfa_path = os.path.join(args.GALAXY_TOOL_DIR[0], 'ALFA.py') | 
|  | 104 | 
|  | 105     #INPUT1: Annotation File | 
|  | 106     if args.indexes: | 
|  | 107         # The indexes submitted by the user must exhibit the suffix '.(un)stranded.index' and will be called by alfa by their prefix | 
| 28 | 108         index = symlink_user_indexes(args.indexes[0], args.indexes[1]) | 
| 22 | 109         input1_args = '-g %s' % index | 
|  | 110     elif args.bi_indexes: | 
|  | 111         input1_args = '-g %s' % args.bi_indexes[0] | 
|  | 112     elif args.annotation_file: | 
|  | 113         input1_args = '-a %s' % args.annotation_file[0] | 
|  | 114     else: | 
|  | 115         exit_and_explain('No annotation file submitted !') | 
|  | 116 | 
|  | 117     #INPUT 2: Mapped Reads | 
|  | 118     if args.reads: | 
|  | 119         input2_args, reads_filenames, reads_labels = get_input2_args(args.reads, args.reads_format[0]) | 
|  | 120         strandness = '-s %s' % args.strandness[0] | 
|  | 121     else: | 
|  | 122         exit_and_explain('No reads submitted !') | 
|  | 123 | 
|  | 124     ##Output options | 
|  | 125     categories_depth = '-d %s' % args.categories_depth[0] | 
|  | 126     if not (args.output_pdf or args.output_png or args.output_svg): | 
|  | 127         output_args = '--n' | 
|  | 128     else: | 
|  | 129         if args.output_pdf: | 
|  | 130             output_args = '--pdf plot.pdf' | 
|  | 131         if args.output_png: | 
|  | 132             output_args = '--png plot' | 
|  | 133         if args.output_svg: | 
|  | 134             output_args = '--svg plot' | 
|  | 135         if args.threshold: | 
|  | 136             output_args = '%s -t %.3f %.3f' % (output_args, args.threshold[0], args.threshold[1]) | 
|  | 137 | 
|  | 138     ##Run alfa | 
|  | 139     cmd = 'python %s %s %s %s %s %s' % (alfa_path, input1_args, input2_args, strandness, categories_depth, output_args) | 
|  | 140     logging.info("__________________________________________________________________\n") | 
|  | 141     logging.info("Alfa execution") | 
|  | 142     logging.info("__________________________________________________________________\n") | 
|  | 143     logging.info("Command Line:\n%s\n" % cmd) | 
|  | 144     logging.info("------------------------------------------------------------------\n") | 
|  | 145     alfa_result = subprocess.Popen(args=cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | 
|  | 146     alfa_out, alfa_err =  alfa_result.communicate() | 
|  | 147 | 
|  | 148     ##Handle stdout, warning, errors... | 
|  | 149     redirect_errors(alfa_out, alfa_err) | 
|  | 150 | 
|  | 151     logging.info("Alfa prompt:\n%s" % alfa_out) | 
|  | 152 | 
|  | 153     ##Redirect outputs | 
|  | 154     if args.output_pdf: | 
|  | 155         shutil.move('plot.pdf', args.output_pdf[0]) | 
|  | 156     if args.output_png: | 
|  | 157         shutil.move('plot' + '.categories.png', args.output_png[0]) | 
|  | 158         shutil.move('plot' + '.biotypes.png', args.output_png[1]) | 
|  | 159     if args.output_svg: | 
|  | 160         shutil.move('plot' + '.categories.svg', args.output_svg[0]) | 
|  | 161         shutil.move('plot' + '.biotypes.svg', args.output_svg[1]) | 
|  | 162     if args.output_count: | 
|  | 163         count_filename = merge_count_files(reads_labels) | 
|  | 164         shutil.move(count_filename, args.output_count[0]) | 
|  | 165     if args.output_indexes: | 
|  | 166         if args.annotation_file: | 
|  | 167             indexes_regex = re.compile('.*\.index') | 
|  | 168             indexes = filter(indexes_regex.search, os.listdir('.')) | 
|  | 169             indexes.sort() | 
|  | 170             shutil.move(indexes[0], args.output_indexes[0]) | 
|  | 171             shutil.move(indexes[1], args.output_indexes[1]) | 
|  | 172         if args.indexes: | 
|  | 173             shutil.move(index + '.stranded.index', args.output_indexes[0]) | 
|  | 174             shutil.move(index + '.unstranded.index', args.output_indexes[1]) | 
|  | 175         if args.bi_indexes: | 
|  | 176             shutil.move(args.bi_indexes[0] + '.stranded.index', args.output_index[0]) | 
|  | 177             shutil.move(args.bi_indexes[1] + '.unstranded.index', args.output_index[1]) | 
|  | 178 | 
|  | 179     cleanup_before_exit(tmp_dir) | 
| 29 | 180 main() |