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()
|