diff --git a/lib/galaxy/config/sample/datatypes_conf.xml.sample b/lib/galaxy/config/sample/datatypes_conf.xml.sample index a2b068b1a4b..f3b9d767c86 100644 --- a/lib/galaxy/config/sample/datatypes_conf.xml.sample +++ b/lib/galaxy/config/sample/datatypes_conf.xml.sample @@ -398,6 +398,7 @@ + @@ -1125,6 +1126,7 @@ + diff --git a/lib/galaxy/datatypes/sniff.py b/lib/galaxy/datatypes/sniff.py index 5839b5a2927..9f557c85a2c 100644 --- a/lib/galaxy/datatypes/sniff.py +++ b/lib/galaxy/datatypes/sniff.py @@ -298,6 +298,12 @@ def guess_ext(fname_or_file_prefix: Union[str, "FilePrefix"], sniff_order, is_bi >>> fname = get_test_fname('megablast_xml_parser_test1.blastxml') >>> guess_ext(fname, sniff_order) 'blastxml' + >>> fname = get_test_fname('1.psl') + >>> guess_ext(fname, sniff_order) + 'psl' + >>> fname = get_test_fname('2.psl') + >>> guess_ext(fname, sniff_order) + 'psl' >>> fname = get_test_fname('interval.interval') >>> guess_ext(fname, sniff_order) 'interval' diff --git a/lib/galaxy/datatypes/tabular.py b/lib/galaxy/datatypes/tabular.py index 4422921ba7c..47044f022b4 100644 --- a/lib/galaxy/datatypes/tabular.py +++ b/lib/galaxy/datatypes/tabular.py @@ -1798,3 +1798,124 @@ class CMAP(TabularData): dataset.metadata.column_types = cleaned_column_types dataset.metadata.columns = number_of_columns dataset.metadata.delimiter = "\t" + + +@build_sniff_from_prefix +class Psl(Tabular): + """Tab delimited data in psl format.""" + + edam_format = "format_3007" + file_ext = "psl" + line_class = "assemblies" + data_sources = {"data": "tabix"} + + def __init__(self, **kwd): + """Initialize psl datatype""" + super().__init__(**kwd) + self.column_names = [ + "matches", + "misMatches", + "repMatches", + "nCount", + "qNumInsert", + "qBaseInsert", + "tNumInsert", + "tBaseInsert", + "strand", + "qName", + "qSize", + "qStart", + "qEnd", + "tName", + "tSize", + "tStart", + "tEnd", + "blockCount", + "blockSizes", + "qStarts", + "tStarts", + ] + + def sniff_prefix(self, file_prefix: FilePrefix): + """ + PSL lines represent alignments, and are typically generated + by BLAT. Each line consists of 21 required fields, and track + lines may optionally be used to provide more information. + + Fields are tab-separated, and all 21 are required. + Although not part of the formal PSL specification, track lines + may be used to further configure sets of features. Track lines + are placed at the beginning of the list of features they are + to affect. + + Rules for sniffing as True:: + + - There must be 21 columns on each fields line + - matches, misMatches repMatches, nCount, qNumInsert, + qBaseInsert, tNumInsert, tBaseInsert, strand, qSize, qStart, + qEnd, tName, tSize, tStart, tEnd, blockCount, blockSizes, + qStarts, tStarts must be correct + - We will only check that up to the first 10 alignments are + correctly formatted. + >>> from galaxy.datatypes.sniff import get_test_fname + >>> fname = get_test_fname( '1.psl' ) + >>> Psl().sniff( fname ) + True + >>> fname = get_test_fname( '2.psl' ) + >>> Psl().sniff( fname ) + True + >>> fname = get_test_fname( 'interval.interval' ) + >>> Psl().sniff( fname ) + False + >>> fname = get_test_fname( '2.txt' ) + >>> Psl().sniff( fname ) + False + >>> fname = get_test_fname( 'test_tab2.tabular' ) + >>> Psl().sniff( fname ) + False + >>> fname = get_test_fname( 'mothur_datatypetest_true.mothur.ref.taxonomy' ) + >>> Psl().sniff( fname ) + False + """ + + def check_items(s): + s_items = s.split(",") + for item in s_items: + if int(item) < 0: + raise Exception("Out of range") + + count = 0 + for line in file_prefix.line_iterator(): + line = line.strip() + if not line: + break + if line: + if line.startswith("browser") or line.startswith("track"): + # Skip track lines. + continue + items = line.split("\t") + if len(items) != 21: + return False + # tName is a string + items.pop(13) + # qName is a string + items.pop(9) + # strand + if items.pop(8) not in ["-", "+", "+-", "-+"]: + raise Exception("Invalid strand") + # blockSizes + s = items.pop(15).rstrip(",") + check_items(s) + # qStarts + s = items.pop(15).rstrip(",") + check_items(s) + # tStarts + s = items.pop(15).rstrip(",") + check_items(s) + if any(int(item) < 0 for item in items): + raise Exception("Out of range") + count += 1 + if count == 10: + break + if count > 0: + return True diff --git a/lib/galaxy/datatypes/test/1.psl b/lib/galaxy/datatypes/test/1.psl new file mode 100644 index 00000000000..c67415a6c1a --- /dev/null +++ b/lib/galaxy/datatypes/test/1.psl @@ -0,0 +1,6 @@ +browser position chr22:13073000-13074000 +browser hide all +track name=fishBlats description="Fish BLAT" visibility=2 useScore=1 +59 9 0 0 1 823 1 96 +- FS_CONTIG_48080_1 1955 171 1062 chr22 47748585 13073589 13073753 2 48,20, 171,1042, 34674832,34674976, +59 7 0 0 1 55 1 55 +- FS_CONTIG_26780_1 2825 2456 2577 chr22 47748585 13073626 13073747 2 21,45, 2456,2532, 34674838,34674914, +59 7 0 0 1 55 1 55 -+ FS_CONTIG_26780_1 2825 2455 2676 chr22 47748585 13073727 13073848 2 45,21, 249,349, 13073727,13073827 diff --git a/lib/galaxy/datatypes/test/2.psl b/lib/galaxy/datatypes/test/2.psl new file mode 100644 index 00000000000..d95570c67ef --- /dev/null +++ b/lib/galaxy/datatypes/test/2.psl @@ -0,0 +1,5 @@ +2890 41 0 0 25 41 25 32 + NZ_CP026740.1 98205 66320 69251 PS02056|SAMN29228906_5 3054 125 3047 51 72,57,4,9,13,13,86,4,44,4,19,2,1,52,7,8,4,181,108,189,50,41,3,231,2,3,19,3,5,61,136,1,8,30,18,1,42,26,55,119,2,380,3,109,5,566,2,2,45,11,34, 66320,66392,66449,66454,66464,66477,66490,66577,66581,66626,66630,66649,66653,66654,66706,66714,66723,66727,66908,67016,67206,67257,67298,67303,67540,67542,67545,67565,67569,67574,67635,67771,67774,67782,67813,67832,67834,67877,67903,67959,68079,68081,68462,68465,68575,68580,69154,69157,69159,69206,69217, 125,198,256,260,269,283,297,383,388,432,437,457,459,461,514,521,529,534,716,826,1015,1065,1108,1111,1342,1346,1351,1370,1373,1380,1442,1579,1580,1589,1619,1637,1638,1680,1708,1763,1882,1885,2265,2269,2378,2384,2950,2952,2955,3000,3013, +1513 16 0 0 12 16 14 20 - NZ_CP026740.1 98205 32103 33632 PS02056|SAMN29228906_6 1548 13 1546 27 94,6,159,153,17,2,74,7,6,28,147,6,1,7,202,4,3,164,1,1,2,276,3,83,4,21,42, 32103,32197,32203,32362,32515,32532,32535,32609,32618,32626,32654,32802,32808,32810,32818,33020,33026,33030,33194,33195,33197,33201,33477,33481,33565,33569,33590, 13,108,115,275,430,448,450,525,532,538,567,714,723,724,731,935,939,942,1107,1110,1111,1113,1390,1393,1476,1482,1504, +762 108 0 0 14 108 13 132 + NZ_CP026740.1 98205 69627 70497 PS02056|SAMN29228906_3 6215 1049 1943 28 81,1,45,4,35,2,66,1,2,99,41,2,5,4,40,76,3,3,72,4,3,2,7,71,5,11,3,74, 69627,69711,69713,69758,69762,69797,69799,69865,69868,69870,69969,70011,70014,70019,70023,70073,70150,70153,70157,70295,70304,70311,70314,70332,70404,70409,70420,70423, 1049,1130,1131,1177,1182,1218,1321,1388,1389,1392,1492,1533,1535,1543,1548,1588,1664,1669,1672,1744,1748,1751,1753,1760,1831,1837,1857,1869, +77 0 0 0 0 0 0 0 + NZ_CP026740.1 98205 70504 70581 PS02056|SAMN29228906_3 6215 134 211 1 77, 70504, 134, +2890 41 0 0 25 41 25 32 + CP026740.1 98205 66320 69251 PS02056|SAMN29228906_5 3054 125 3047 51 72,57,4,9,13,13,86,4,44,4,19,2,1,52,7,8,4,181,108,189,50,41,3,231,2,3,19,3,5,61,136,1,8,30,18,1,42,26,55,119,2,380,3,109,5,566,2,2,45,11,34, 66320,66392,66449,66454,66464,66477,66490,66577,66581,66626,66630,66649,66653,66654,66706,66714,66723,66727,66908,67016,67206,67257,67298,67303,67540,67542,67545,67565,67569,67574,67635,67771,67774,67782,67813,67832,67834,67877,67903,67959,68079,68081,68462,68465,68575,68580,69154,69157,69159,69206,69217, 125,198,256,260,269,283,297,383,388,432,437,457,459,461,514,521,529,534,716,826,1015,1065,1108,1111,1342,1346,1351,1370,1373,1380,1442,1579,1580,1589,1619,1637,1638,1680,1708,1763,1882,1885,2265,2269,2378,2384,2950,2952,2955,3000,3013,