Compare commits

...

74 Commits

Author SHA1 Message Date
6819d04615 Testing RAM instead of mmap for blob alignment 2023-11-29 16:24:31 +13:00
8a1f844645 obi import: fixed bug caused by new behaviour of StopIteration
exceptions in Python>=3.7
2023-09-21 17:47:40 +12:00
791ccfb92e Fixed include bug in previous version and switch to version 3.0.1b24 2023-05-15 11:35:42 +12:00
1c9a906f5b ngsfilter and ecopcr: now check for primers too long for apat library to
handle (31bp max) and switch to version 3.0.1b23
2023-05-12 17:04:21 +12:00
55b2679b23 New command obi rm and switch to version 3.0.1b22 2023-05-08 17:48:50 +12:00
9ea2124adc Switch to version 3.0.1b21 2023-02-13 11:00:01 +13:00
2130a949c7 New command: obi taxonomy to add local taxa (closes #64) 2023-02-13 10:59:20 +13:00
eeb93afa7d import: now automatically renames scientific_name tag to
`SCIENTIFIC_NAME`, and suggests using `--input-na-string` when a
sequence import fails
2023-02-13 10:40:38 +13:00
755ce179ad head: added output format options 2023-02-13 10:31:26 +13:00
7e492578b3 Switch to version 3.0.1b20 2022-09-21 11:33:03 +12:00
02e9df3ad1 alignpairedend and ngsfilter: ids of original sequences are now kept 2022-09-21 11:32:19 +12:00
55ada80500 import: made ngsfilter file parsing more resilient and switching to
version 3.0.1b19
2022-07-15 16:02:21 +12:00
ef9d9674b0 obi import: added SINTAX format import and switch to version 3.0.1b18 2022-05-17 09:36:33 +12:00
4f39bb2418 switch to version 3.0.1b17 2022-05-03 10:55:36 +12:00
0a2b8adb50 import: added import of UNITE fasta format 2022-05-03 10:54:41 +12:00
f9b99a9397 annotate: fixed a bug where a column type could be wrongly guessed and
switch to version 3.0.1b16
2022-03-30 16:32:07 +13:00
ce2833c04b switch to version v3.0.1b15 2022-02-25 17:48:44 +13:00
f64b3da30b split command 2022-02-25 17:44:18 +13:00
388b3e0410 removed a trace 2021-11-11 15:53:27 +13:00
c9db990b83 switch to version 3.0.1b14 2021-11-11 15:28:00 +13:00
3f253feb5e Cython: View: fixed keys method to get list of view keys 2021-11-11 15:27:32 +13:00
85d2bab607 small fix 2021-11-11 15:26:48 +13:00
53b3d81137 small fixes and improvements 2021-11-11 15:26:09 +13:00
f6353fbf28 obi export: added options to export to metabaR compatible format 2021-11-11 15:24:12 +13:00
5a8b9dca5d goes with previous commit 2021-11-11 15:12:04 +13:00
8bd6d6c8e9 Python: URI decoding: now properly checking that paths can be encoded in
ASCII (issue #89)
2021-11-02 11:17:59 +13:00
405e6ef420 Python: URI decoding: added metabaR output 2021-11-02 11:16:29 +13:00
fedacfafe7 switch to version 3.0.1b13 2021-09-13 11:46:17 +12:00
2d66e0e965 python: genbank parser: better handling of white spaces 2021-09-13 11:44:38 +12:00
f43856b712 switch to version 3.0.1b12 2021-09-08 10:56:55 +12:00
9e0c319806 Cython: fixed rewriting of column when rewriting a 1 element dict column 2021-09-08 10:54:23 +12:00
58b42cd977 C: views: now correctly parses view names containing '.' when cleaning
unfinished views. Closes #115
2021-09-08 10:52:42 +12:00
34de90bce6 ngsfilter: checks better if there is an associated sequencing quality 2021-09-08 10:30:11 +12:00
4be9f36f99 stats: fixed the computation of variance when it is equal to 0 2021-08-05 11:32:16 +12:00
f10e78ba3c C: fixed the printing of view informations from a DMS (fixes #114) 2021-08-05 11:31:24 +12:00
88c8463ed7 Cython: taxonomy: improved logging 2021-08-05 11:29:20 +12:00
89168271ef ecopcr: now accepting taxonomy from a different DMS than the reference
sequences
2021-08-05 11:28:57 +12:00
82d2642000 Switch to version 3.0.1b11 2021-07-22 09:25:39 +12:00
99c1cd60d6 export: now exports header for tabular files by default and added option
to only export specific columns
2021-07-22 09:23:18 +12:00
ce7ae4ac55 export: fixed 'only' option printing one too many if printing header 2021-07-21 15:23:04 +12:00
0b4283bb58 cat: improved error handling 2021-07-21 15:22:08 +12:00
747f3efbb2 Improved taxonomy reading information display 2021-07-21 15:20:44 +12:00
6c1a3aff47 Fixed the handling of sample names that are numbers (forcing conversion) 2021-07-21 15:19:24 +12:00
e2932b05f2 Implements #108 export integer missing values as 0 for tables by default 2021-07-21 14:41:54 +12:00
32345b9ec4 Addresses #111 2021-07-19 15:55:25 +12:00
9334cf6cc6 import: improved genbank parser and switch to version 3.0.1.b10 2021-06-17 08:42:01 +12:00
8ec13a294c Switch to version 3.0.1b9 2021-06-01 09:21:43 +12:00
3e45c34491 import: now imports and adds taxids for SILVA and RDP files, added
import of lists, fixed skipping of errors (was not overwriting), and
fixed --no-progress-bar option
2021-06-01 09:21:07 +12:00
c2f3d90dc1 build_ref_db: set default threshold to 0.99 2021-06-01 09:11:17 +12:00
6b732d11d3 align: fixed column URI parsing 2021-06-01 09:10:21 +12:00
9eb833a0af typo fix 2021-06-01 09:09:16 +12:00
6b7b0e3bd1 cat: fixed the handling of dictionary columns 2021-06-01 09:06:13 +12:00
47691a8f58 count: added option to specify the count column 2021-06-01 09:05:14 +12:00
b908b581c8 clean: hid not implemented option 2021-06-01 09:04:22 +12:00
03c174fd7a grep: added taxonomy check 2021-05-31 17:03:39 +12:00
2156588ff6 added TODO comment 2021-05-31 17:01:57 +12:00
6ff29c6a6a Increased maximum line count to 10E12 2021-05-31 17:00:55 +12:00
51a3c68fb5 C: build_reference_db: fixed gcc warning/error 2021-05-31 16:59:17 +12:00
da91ffc2c7 URI decoding: fixed reading a taxonomy before any view 2021-05-31 16:57:20 +12:00
c884615522 obi stats: various fixes and improvements 2021-05-31 16:51:06 +12:00
cb53381863 ecotag: BEST_MATCH_TAXIDS now dereplicated (no repeated taxids in the
list) and switch to version 3.0.1b8
2021-05-10 16:02:06 +12:00
72b3e5d872 switch to version 3.0.1b7 2021-04-07 10:31:54 +12:00
238e9f70f3 alignpairedend: fixed bug that would cut out sequence ends when it
should not have
2021-04-07 10:31:12 +12:00
e099a16624 small fixes 2021-04-07 10:28:02 +12:00
847c9c816d import: fixed count estimation for tabular files with header 2021-03-30 09:07:14 +13:00
6026129ca8 Fixes 101 2021-03-30 09:06:08 +13:00
169b6514b4 small doc fixes 2021-03-29 13:07:48 +13:00
89b0c48141 switch to version 3.0.1b6 2021-03-29 11:18:44 +13:00
7c02782e3c import/export: workaround for issue where flake8(?) reads '\t' as
'\'+'t' when parsing an option value
2021-03-29 11:18:19 +13:00
ecc4c2c78b stats: improved the tabular display 2021-03-29 09:03:32 +13:00
f5413381fd C: taxonomy: fixed a bug where some taxa would not be stored in the
merged index
2021-03-29 09:02:18 +13:00
3e93cfff7b import: Columns are now rewritten in OBI_FLOAT if a value is > INT32_MAX 2021-03-29 09:00:52 +13:00
6d445fe3ad switch to version 3.0.1b5 2021-03-22 09:41:01 +13:00
824deb7e21 new command: obi rm: deletes any view (for now the user deleting a view
accepts that there will be missing information when running obi history
if other views came from the deleted view)
2021-03-18 09:17:06 +13:00
58 changed files with 1483 additions and 379 deletions

View File

@ -1,3 +1,9 @@
import codecs
def unescaped_str(arg_str):
return arg_str.encode('latin-1', 'backslashreplace').decode('unicode-escape')
def __addInputOption(optionManager):
optionManager.add_argument(
@ -43,7 +49,25 @@ def __addImportInputOption(optionManager):
action="store_const", dest="obi:inputformat",
default=None,
const=b'silva',
help="Input file is in SILVA fasta format")
help="Input file is in SILVA fasta format. If NCBI taxonomy provided with --taxonomy, taxid and scientific name will be added for each sequence.")
group.add_argument('--rdp-input',
action="store_const", dest="obi:inputformat",
default=None,
const=b'rdp',
help="Input file is in RDP training set fasta format. If NCBI taxonomy provided with --taxonomy, taxid and scientific name will be added for each sequence.")
group.add_argument('--unite-input',
action="store_const", dest="obi:inputformat",
default=None,
const=b'unite',
help="Input file is in UNITE fasta format. If NCBI taxonomy provided with --taxonomy, taxid and scientific name will be added for each sequence.")
group.add_argument('--sintax-input',
action="store_const", dest="obi:inputformat",
default=None,
const=b'sintax',
help="Input file is in SINTAX fasta format. If NCBI taxonomy provided with --taxonomy, taxid and scientific name will be added for each sequence.")
group.add_argument('--embl-input',
action="store_const", dest="obi:inputformat",
@ -125,15 +149,15 @@ def __addImportInputOption(optionManager):
def __addTabularOption(optionManager):
group = optionManager.add_argument_group("Input and output format options for tabular files")
group.add_argument('--header',
action="store_true", dest="obi:header",
default=False,
help="First line of tabular file contains column names")
group.add_argument('--no-header',
action="store_false", dest="obi:header",
default=True,
help="Don't print the header (first line with column names")
group.add_argument('--sep',
action="store", dest="obi:sep",
default="\t",
type=str,
type=unescaped_str,
help="Column separator")
@ -165,6 +189,16 @@ def __addTabularInputOption(optionManager):
help="Lines starting by this char are considered as comment")
def __addTabularOutputOption(optionManager):
group = optionManager.add_argument_group("Output format options for tabular files")
__addTabularOption(optionManager)
group.add_argument('--na-int-stay-na',
action="store_false", dest="obi:na_int_to_0",
help="NA (Non available) integer values should be exported as NA in tabular output (default: they are converted to 0 for tabular output).") # TODO
def __addTaxdumpInputOption(optionManager): # TODO maybe not the best way to do it
group = optionManager.add_argument_group("Input format options for taxdump")
@ -198,6 +232,10 @@ def addTabularInputOption(optionManager):
__addTabularInputOption(optionManager)
def addTabularOutputOption(optionManager):
__addTabularOutputOption(optionManager)
def addTaxonomyOption(optionManager):
__addTaxonomyOption(optionManager)
@ -210,6 +248,7 @@ def addAllInputOption(optionManager):
__addInputOption(optionManager)
__addImportInputOption(optionManager)
__addTabularInputOption(optionManager)
__addTabularOutputOption(optionManager)
__addTaxonomyOption(optionManager)
__addTaxdumpInputOption(optionManager)
@ -270,6 +309,35 @@ def __addExportOutputOption(optionManager):
const=b'tabular',
help="Output file is in tabular format")
group.add_argument('--metabaR-output',
action="store_const", dest="obi:outputformat",
default=None,
const=b'metabaR',
help="Export the files needed by the obifiles_to_metabarlist function of the metabaR package")
group.add_argument('--metabaR-prefix',
action="store", dest="obi:metabarprefix",
type=str,
help="Prefix for the files when using --metabaR-output option")
group.add_argument('--metabaR-ngsfilter',
action="store", dest="obi:metabarngsfilter",
type=str,
default=None,
help="URI to the ngsfilter view when using --metabaR-output option (if not provided, it is not exported)")
group.add_argument('--metabaR-samples',
action="store", dest="obi:metabarsamples",
type=str,
default=None,
help="URI to the sample metadata view when using --metabaR-output option (if not provided, it is built as just a list of the sample names)")
group.add_argument('--only-keys',
action="append", dest="obi:only_keys",
type=str,
default=[],
help="Only export the given keys (columns).")
group.add_argument('--print-na',
action="store_true", dest="obi:printna",
default=False,
@ -302,14 +370,14 @@ def addTabularOutputOption(optionManager):
def addExportOutputOption(optionManager):
__addExportOutputOption(optionManager)
__addTabularOption(optionManager)
__addTabularOutputOption(optionManager)
def addAllOutputOption(optionManager):
__addOutputOption(optionManager)
__addDMSOutputOption(optionManager)
__addExportOutputOption(optionManager)
__addTabularOption(optionManager)
__addTabularOutputOption(optionManager)
def addNoProgressBarOption(optionManager):

View File

@ -26,7 +26,7 @@ import sys
from cpython.exc cimport PyErr_CheckSignals
__title__="Annotate sequences with their corresponding NCBI taxid found from the taxon scientific name."
__title__="Annotate sequences with their corresponding NCBI taxid found from the taxon scientific name"
@ -45,7 +45,7 @@ def addOptions(parser):
metavar="<TAXID_TAG>",
default=b"TAXID",
help="Name of the tag to store the found taxid "
"(default: 'TAXID'.")
"(default: 'TAXID').")
group.add_argument('-n', '--taxon-name-tag',
action="store",
@ -53,7 +53,7 @@ def addOptions(parser):
metavar="<SCIENTIFIC_NAME_TAG>",
default=b"SCIENTIFIC_NAME",
help="Name of the tag giving the scientific name of the taxon "
"(default: 'SCIENTIFIC_NAME'.")
"(default: 'SCIENTIFIC_NAME').")
group.add_argument('-g', '--try-genus-match',
action="store_true", dest="addtaxids:try_genus_match",
@ -174,6 +174,7 @@ def run(config):
taxid_column[i] = taxon.taxid
found_count+=1
elif try_genus: # try finding genus or other parent taxon from the first word
#print(i, o_view[i].id)
taxon_name_sp = taxon_name.split(b" ")
taxon = taxo.get_taxon_by_name(taxon_name_sp[0], res_anc)
if taxon is not None:

View File

@ -19,7 +19,7 @@ import time
import sys
__title__="Aligns one sequence column with itself or two sequence columns"
__title__="Align one sequence column with itself or two sequence columns"
def addOptions(parser):
@ -158,7 +158,7 @@ def run(config):
i_view_name = i_uri.split(b"/")[0]
i_column_name = b""
i_element_name = b""
if len(i_uri.split(b"/")) == 2:
if len(i_uri.split(b"/")) >= 2:
i_column_name = i_uri.split(b"/")[1]
if len(i_uri.split(b"/")) == 3:
i_element_name = i_uri.split(b"/")[2]
@ -181,7 +181,7 @@ def run(config):
i_dms_name_2 = i_dms_2.name
i_uri_2 = input_2[1]
original_i_view_name_2 = i_uri_2.split(b"/")[0]
if len(i_uri_2.split(b"/")) == 2:
if len(i_uri_2.split(b"/")) >= 2:
i_column_name_2 = i_uri_2.split(b"/")[1]
if len(i_uri_2.split(b"/")) == 3:
i_element_name_2 = i_uri_2.split(b"/")[2]

View File

@ -23,7 +23,7 @@ import os
from cpython.exc cimport PyErr_CheckSignals
__title__="Aligns paired-ended reads"
__title__="Align paired-ended reads"
@ -233,6 +233,10 @@ def run(config):
PyErr_CheckSignals()
consensus = o_view[i]
if two_views:
consensus[b"R1_parent"] = forward[i].id
consensus[b"R2_parent"] = reverse[i].id
if not two_views:
seqF = entries[i]

View File

@ -16,6 +16,8 @@ from obitools3.dms.capi.obiview cimport NUC_SEQUENCE_COLUMN, \
QUALITY_COLUMN, \
COUNT_COLUMN, \
TAXID_COLUMN
from obitools3.dms.capi.obitypes cimport OBI_STR
from obitools3.dms.column.column cimport Column
import time
import math
@ -187,6 +189,8 @@ def sequenceTaggerGenerator(config, taxo=None):
else:
scn=None
seq[rank]=rtaxid
if "%s_name"%rank not in seq.view:
Column.new_column(seq.view, "%s_name"%rank, OBI_STR)
seq["%s_name"%rank]=scn
if add_rank:

View File

@ -16,7 +16,7 @@ import sys
from cpython.exc cimport PyErr_CheckSignals
__title__="Tag a set of sequences for PCR and sequencing errors identification"
__title__="Build a reference database for ecotag"
def addOptions(parser):
@ -31,10 +31,9 @@ def addOptions(parser):
group.add_argument('--threshold','-t',
action="store", dest="build_ref_db:threshold",
metavar='<THRESHOLD>',
default=0.0,
default=0.99,
type=float,
help="Score threshold as a normalized identity, e.g. 0.95 for an identity of 95%%. Default: 0.00"
" (no threshold).")
help="Score threshold as a normalized identity, e.g. 0.95 for an identity of 95%%. Default: 0.99.")
def run(config):

View File

@ -22,7 +22,7 @@ import sys
from cpython.exc cimport PyErr_CheckSignals
__title__="Concatenate views."
__title__="Concatenate views"
def addOptions(parser):
@ -97,7 +97,7 @@ def run(config):
Column.new_column(o_view, REVERSE_QUALITY_COLUMN, OBI_QUAL, associated_column_name=REVERSE_SEQUENCE_COLUMN, associated_column_version=o_view[REVERSE_SEQUENCE_COLUMN].version)
# Initialize multiple elements columns
if type(output_0)==BufferedWriter:
if type(output_0)!=BufferedWriter:
dict_cols = {}
for v_uri in config["cat"]["views_to_cat"]:
v = open_uri(v_uri)[1]
@ -134,7 +134,11 @@ def run(config):
rep = repr(entry)
output_0.write(str2bytes(rep)+b"\n")
else:
o_view[i] = entry
try:
o_view[i] = entry
except:
print("\nError with entry:", repr(entry))
print(repr(o_view))
i+=1
v.close()

View File

@ -54,11 +54,11 @@ def addOptions(parser):
default=False,
help="Only sequences labeled as heads are kept in the output. Default: False")
group.add_argument('--cluster-tags', '-C',
action="store_true",
dest="clean:cluster-tags",
default=False,
help="Adds tags for each sequence giving its cluster's head and weight for each sample.")
# group.add_argument('--cluster-tags', '-C',
# action="store_true",
# dest="clean:cluster-tags",
# default=False,
# help="Adds tags for each sequence giving its cluster's head and weight for each sample.")
group.add_argument('--thread-count','-p', # TODO should probably be in a specific option group
action="store", dest="clean:thread-count",
@ -142,4 +142,5 @@ def run(config):
i_dms.close(force=True)
logger("info", "Done.")
logger("info", "Done.")

View File

@ -10,7 +10,7 @@ from obitools3.dms.capi.obiview cimport COUNT_COLUMN
from cpython.exc cimport PyErr_CheckSignals
__title__="Counts sequence records"
__title__="Count sequence records"
def addOptions(parser):
@ -29,6 +29,12 @@ def addOptions(parser):
default=False,
help="Prints only the total count of sequence records (if a sequence has no `count` attribute, its default count is 1) (default: False).")
group.add_argument('-c','--count-tag',
action="store", dest="count:countcol",
default='COUNT',
type=str,
help="Name of the tag/column associated with the count information (default: COUNT).")
def run(config):
@ -41,18 +47,20 @@ def run(config):
if input is None:
raise Exception("Could not read input")
entries = input[1]
countcol = config['count']['countcol']
count1 = len(entries)
count2 = 0
if COUNT_COLUMN in entries and ((config['count']['sequence'] == config['count']['all']) or (config['count']['all'])) :
if countcol in entries and ((config['count']['sequence'] == config['count']['all']) or (config['count']['all'])) :
for e in entries:
PyErr_CheckSignals()
count2+=e[COUNT_COLUMN]
count2+=e[countcol]
if COUNT_COLUMN in entries and (config['count']['sequence'] == config['count']['all']):
if countcol in entries and (config['count']['sequence'] == config['count']['all']):
print(count1,count2)
elif COUNT_COLUMN in entries and config['count']['all']:
elif countcol in entries and config['count']['all']:
print(count2)
else:
print(count1)

View File

@ -175,6 +175,14 @@ def run(config):
o_dms_name = output[0].name
o_view_name = output[1]
# Open the taxonomy DMS
taxdms = open_uri(config['obi']['taxoURI'],
dms_only=True)
if taxdms is None:
raise Exception("Could not open taxonomy DMS")
tax_dms = taxdms[0]
tax_dms_name = taxdms[0].name
# Read taxonomy name
taxonomy_name = config['obi']['taxoURI'].split("/")[-1] # Robust in theory
@ -197,7 +205,8 @@ def run(config):
# TODO: primers in comments?
if obi_ecopcr(i_dms.name_with_full_path, tobytes(i_view_name), tobytes(taxonomy_name), \
if obi_ecopcr(i_dms.name_with_full_path, tobytes(i_view_name),
tax_dms.name_with_full_path, tobytes(taxonomy_name), \
o_dms.name_with_full_path, tobytes(o_view_name), comments, \
tobytes(config['ecopcr']['primer1']), tobytes(config['ecopcr']['primer2']), \
config['ecopcr']['error'], \

View File

@ -6,6 +6,9 @@ from obitools3.apps.config import logger
from obitools3.dms import DMS
from obitools3.dms.obiseq import Nuc_Seq
from obitools3.dms.capi.obiview cimport QUALITY_COLUMN
from obitools3.writers.tab import TabWriter
from obitools3.format.tab import TabFormat
from obitools3.utils cimport tobytes, tostr
from obitools3.apps.optiongroups import addMinimalInputOption, \
addExportOutputOption, \
@ -76,6 +79,13 @@ def run(config):
else:
pb = ProgressBar(withoutskip - skip, config)
if config['obi']['outputformat'] == b'metabaR':
# Check prefix
if "metabarprefix" not in config["obi"]:
raise Exception("Prefix needed when exporting for metabaR (--metabaR-prefix option)")
else:
metabaRprefix = config["obi"]["metabarprefix"]
i=0
for seq in iview :
PyErr_CheckSignals()
@ -91,6 +101,81 @@ def run(config):
pb(i, force=True)
print("", file=sys.stderr)
if config['obi']['outputformat'] == b'metabaR':
# Export ngsfilter file if view provided
if 'metabarngsfilter' in config['obi']:
ngsfilter_input = open_uri(config['obi']['metabarngsfilter'])
if ngsfilter_input is None:
raise Exception("Could not read ngsfilter view for metabaR output")
ngsfilter_view = ngsfilter_input[1]
ngsfilter_output = open(config['obi']['metabarprefix']+'.ngsfilter', 'w')
for line in ngsfilter_view:
line_to_print = b""
line_to_print += line[b'experiment']
line_to_print += b"\t"
line_to_print += line[b'sample']
line_to_print += b"\t"
line_to_print += line[b'forward_tag']
line_to_print += b":"
line_to_print += line[b'reverse_tag']
line_to_print += b"\t"
line_to_print += line[b'forward_primer']
line_to_print += b"\t"
line_to_print += line[b'reverse_primer']
line_to_print += b"\t"
line_to_print += line[b'additional_info']
print(tostr(line_to_print), file=ngsfilter_output)
if ngsfilter_input[0] != input[0]:
ngsfilter_input[0].close()
ngsfilter_output.close()
# Export sample metadata
samples_output = open(config['obi']['metabarprefix']+'_samples.csv', 'w')
# Export sample metadata file if view provided
if 'metabarsamples' in config['obi']:
samples_input = open_uri(config['obi']['metabarsamples'])
if samples_input is None:
raise Exception("Could not read sample view for metabaR output")
samples_view = samples_input[1]
# Export with tab formatter
TabWriter(TabFormat(header=True, sep='\t',),
samples_output,
header=True)
if samples_input[0] != input[0]:
samples_input[0].close()
# Else export just sample names from main view
else:
sample_list = []
if 'MERGED_sample' in iview:
sample_list = iview['MERGED_sample'].keys()
elif 'sample' not in iview:
for seq in iview:
sample = seq['sample']
if sample not in sample_list:
sample_list.append(sample)
else:
logger("warning", "Can not read sample list from main view for metabaR sample list export")
print("sample_id", file=samples_output)
for sample in sample_list:
line_to_print = b""
line_to_print += sample
line_to_print += b"\t"
print(tostr(line_to_print), file=samples_output)
samples_output.close()
# TODO save command in input dms?
if not BrokenPipeError and not IOError:

View File

@ -91,7 +91,7 @@ def addOptions(parser):
metavar="<ATTRIBUTE_NAME>",
help="Select records with the attribute <ATTRIBUTE_NAME> "
"defined (not set to NA value). "
"Several -a options can be used on the same "
"Several -A options can be used on the same "
"command line.")
group.add_argument("-L", "--lmax",
@ -258,6 +258,13 @@ def Filter_generator(options, tax_filter, i_view):
def Taxonomy_filter_generator(taxo, options):
if (("required_ranks" in options and options["required_ranks"]) or \
("required_taxids" in options and options["required_taxids"]) or \
("ignored_taxids" in options and options["ignored_taxids"])) and \
(taxo is None):
raise RollbackException("obi grep error: can't use taxonomy options without providing a taxonomy. Rollbacking view")
if taxo is not None:
def tax_filter(seq):
good = True

View File

@ -8,6 +8,7 @@ from obitools3.apps.optiongroups import addMinimalInputOption, addMinimalOutputO
from obitools3.dms.view import RollbackException
from obitools3.apps.config import logger
from obitools3.utils cimport str2bytes
from obitools3.apps.optiongroups import addExportOutputOption
import time
import sys
@ -16,13 +17,14 @@ from io import BufferedWriter
from cpython.exc cimport PyErr_CheckSignals
__title__="Keep the N first lines of a view."
__title__="Keep the N first lines of a view"
def addOptions(parser):
addMinimalInputOption(parser)
addMinimalOutputOption(parser)
addExportOutputOption(parser)
addNoProgressBarOption(parser)
group=parser.add_argument_group('obi head specific options')

View File

@ -2,6 +2,7 @@
import sys
import os
import re
from obitools3.apps.progress cimport ProgressBar # @UnresolvedImport
from obitools3.dms.view.view cimport View
@ -34,14 +35,17 @@ from obitools3.dms.capi.obidms cimport obi_import_view
from obitools3.dms.capi.obitypes cimport obitype_t, \
OBI_VOID, \
OBI_QUAL, \
OBI_STR
OBI_STR, \
OBI_INT
from obitools3.dms.capi.obierrno cimport obi_errno
from obitools3.apps.optiongroups import addImportInputOption, \
addTabularInputOption, \
addTaxdumpInputOption, \
addMinimalOutputOption
addMinimalOutputOption, \
addNoProgressBarOption, \
addTaxonomyOption
from obitools3.uri.decode import open_uri
@ -50,9 +54,10 @@ from obitools3.apps.config import logger
from cpython.exc cimport PyErr_CheckSignals
from io import BufferedWriter
import ast
__title__="Imports sequences from different formats into a DMS"
__title__="Import sequences from different formats into a DMS"
default_config = { 'destview' : None,
@ -69,7 +74,9 @@ def addOptions(parser):
addImportInputOption(parser)
addTabularInputOption(parser)
addTaxdumpInputOption(parser)
addTaxonomyOption(parser)
addMinimalOutputOption(parser)
addNoProgressBarOption(parser)
group = parser.add_argument_group('obi import specific options')
@ -85,6 +92,10 @@ def addOptions(parser):
help="If importing a view into another DMS, do it by importing each line, saving disk space if the original view "
"has a line selection associated.")
# group.add_argument('--only-id',
# action="store", dest="import:onlyid",
# help="only id")
def run(config):
cdef tuple input
@ -97,6 +108,9 @@ def run(config):
cdef bint get_quality
cdef bint NUC_SEQS_view
cdef bint silva
cdef bint rdp
cdef bint unite
cdef bint sintax
cdef int nb_elts
cdef object d
cdef View view
@ -180,6 +194,16 @@ def run(config):
logger("info", "Done.")
return
# Open taxonomy if there is one
if 'taxoURI' in config['obi'] and config['obi']['taxoURI'] is not None:
taxo_uri = open_uri(config['obi']['taxoURI'])
if taxo_uri is None or taxo_uri[2] == bytes:
raise Exception("Couldn't open taxonomy")
taxo = taxo_uri[1]
else :
taxo = None
# If importing a view between two DMS and not wanting to save space if line selection in original view, use C API
if isinstance(input[1], View) and not config['import']['space_priority']:
if obi_import_view(input[0].name_with_full_path, o_dms.name_with_full_path, input[1].name, tobytes((config['obi']['outputURI'].split('/'))[-1])) < 0 :
@ -192,8 +216,11 @@ def run(config):
logger("info", "Done.")
return
if entry_count >= 0:
# Reinitialize the progress bar
if entry_count >= 0 and config['obi']['noprogressbar'] == False:
pb = ProgressBar(entry_count, config)
else:
pb = None
NUC_SEQS_view = False
if isinstance(output[1], View) :
@ -202,20 +229,36 @@ def run(config):
NUC_SEQS_view = True
else:
raise NotImplementedError()
# Save basic columns in variables for optimization
if NUC_SEQS_view :
id_col = view[ID_COLUMN]
def_col = view[DEFINITION_COLUMN]
seq_col = view[NUC_SEQUENCE_COLUMN]
# Prepare taxon scientific name if SILVA file
if 'inputformat' in config['obi'] and config['obi']['inputformat'] == b"silva":
silva = True
# Prepare taxon scientific name and taxid refs if RDP/SILVA/UNITE/SINTAX formats
silva = False
rdp = False
unite = False
sintax=False
if 'inputformat' in config['obi'] and (config['obi']['inputformat'] == b"silva" or \
config['obi']['inputformat'] == b"rdp" or \
config['obi']['inputformat'] == b"unite" or \
config['obi']['inputformat'] == b"sintax"):
#if taxo is None:
# raise Exception("A taxonomy (as built by 'obi import --taxdump') must be provided for SILVA and RDP files")
if config['obi']['inputformat'] == b"silva":
silva = True
elif config['obi']['inputformat'] == b"rdp":
rdp = True
elif config['obi']['inputformat'] == b"unite":
unite = True
elif config['obi']['inputformat'] == b"sintax":
sintax = True
sci_name_col = Column.new_column(view, SCIENTIFIC_NAME_COLUMN, OBI_STR)
else:
silva = False
if taxo is not None:
taxid_col = Column.new_column(view, TAXID_COLUMN, OBI_INT)
dcols = {}
# First read through the entries to prepare columns with dictionaries as they are very time-expensive to rewrite
@ -265,8 +308,13 @@ def run(config):
# Reinitialize the input
if isinstance(input[0], CompressedFile):
input_is_file = True
if entry_count >= 0:
# Reinitialize the progress bar
if entry_count >= 0 and config['obi']['noprogressbar'] == False:
pb = ProgressBar(entry_count, config)
else:
pb = None
try:
input[0].close()
except AttributeError:
@ -275,6 +323,11 @@ def run(config):
if input is None:
raise Exception("Could not open input URI")
# if 'onlyid' in config['import']:
# onlyid = tobytes(config['import']['onlyid'])
# else:
# onlyid = None
entries = input[1]
i = 0
for entry in entries :
@ -292,6 +345,9 @@ def run(config):
elif not i%50000:
logger("info", "Imported %d entries", i)
# if onlyid is not None and entry.id != onlyid:
# continue
try:
if NUC_SEQS_view:
@ -307,43 +363,86 @@ def run(config):
if get_quality:
qual_col[i] = entry.quality
# Parse taxon scientific name if SILVA file
if silva:
sci_name = entry.definition.split(b";")[-1]
sci_name_col[i] = sci_name
# Parse taxon scientific name if RDP or Silva or Unite file
if (rdp or silva or unite or sintax):
if rdp or silva:
sci_names = entry.definition.split(b";")
sci_name_col[i] = sci_names[-1]
elif unite:
sci_names = entry.id.split(b'|')[-1].split(b';')
sci_name_col[i] = re.sub(b'[a-zA-Z]__', b'', sci_names[-1])
elif sintax:
reconstructed_line = entry.id+b' '+entry.definition[:-1]
splitted_reconstructed_line = reconstructed_line.split(b';')
taxa = splitted_reconstructed_line[1].split(b'=')[1]
taxa = splitted_reconstructed_line[1].split(b',')
sci_names = []
for t in taxa:
tf = t.split(b':')[1]
sci_names.append(tf)
sci_name_col[i] = sci_names[-1]
id_col[i] = reconstructed_line.split(b';')[0]
def_col[i] = reconstructed_line
# Fond taxid if taxonomy provided
if taxo is not None :
for sci_name in reversed(sci_names):
if unite:
sci_name = re.sub(b'[a-zA-Z]__', b'', sci_name)
if sci_name.split()[0] != b'unidentified' and sci_name.split()[0] != b'uncultured' and sci_name.split()[0] != b'metagenome':
taxon = taxo.get_taxon_by_name(sci_name)
if taxon is not None:
sci_name_col[i] = taxon.name
taxid_col[i] = taxon.taxid
#print(taxid_col[i], sci_name_col[i])
break
for tag in entry :
if tag != ID_COLUMN and tag != DEFINITION_COLUMN and tag != NUC_SEQUENCE_COLUMN and tag != QUALITY_COLUMN : # TODO dirty
value = entry[tag]
if tag == b"taxid":
tag = TAXID_COLUMN
if tag == b"count":
tag = COUNT_COLUMN
if tag == b"scientific_name":
tag = SCIENTIFIC_NAME_COLUMN
if tag[:7] == b"merged_":
tag = MERGED_PREFIX+tag[7:]
if type(value) == bytes and value[:1]==b"[" :
try:
if type(eval(value)) == list:
value = eval(value)
#print(value)
except:
pass
if tag not in dcols :
value_type = type(value)
nb_elts = 1
value_obitype = OBI_VOID
dict_col = False
if value_type == dict or value_type == list :
if value_type == dict :
nb_elts = len(value)
elt_names = list(value)
if value_type == dict :
dict_col = True
dict_col = True
else :
nb_elts = 1
elt_names = None
if value_type == list :
tuples = True
else:
tuples = False
value_obitype = get_obitype(value)
if value_obitype != OBI_VOID :
dcols[tag] = (Column.new_column(view, tag, value_obitype, nb_elements_per_line=nb_elts, elements_names=elt_names, dict_column=dict_col), value_obitype)
dcols[tag] = (Column.new_column(view, tag, value_obitype, nb_elements_per_line=nb_elts, elements_names=elt_names, dict_column=dict_col, tuples=tuples), value_obitype)
# Fill value
dcols[tag][0][i] = value
@ -371,8 +470,8 @@ def run(config):
# Fill value
dcols[tag][0][i] = value
except IndexError :
except (IndexError, OverflowError):
value_type = type(value)
old_column = dcols[tag][0]
old_nb_elements_per_line = old_column.nb_elements_per_line
@ -419,18 +518,19 @@ def run(config):
dcols[tag][0][i] = value
except Exception as e:
print("\nCould not import sequence id:", entry.id, "(error raised:", e, ")")
print("\nCould not import sequence:\n", repr(entry), "\nError raised:", e, "\n/!\ Check if '--input-na-string' option needs to be set")
if 'skiperror' in config['obi'] and not config['obi']['skiperror']:
raise e
else:
pass
i-=1 # overwrite problematic entry
i+=1
if pb is not None:
pb(i, force=True)
print("", file=sys.stderr)
logger("info", "Imported %d entries", i)
logger("info", "Imported %d entries", len(view))
# Save command config in View and DMS comments
command_line = " ".join(sys.argv[1:])

19
python/obitools3/commands/ngsfilter.pyx Normal file → Executable file
View File

@ -24,7 +24,10 @@ from cpython.exc cimport PyErr_CheckSignals
from io import BufferedWriter
__title__="Assigns sequence records to the corresponding experiment/sample based on DNA tags and primers"
MAX_PAT_LEN = 31
__title__="Assign sequence records to the corresponding experiment/sample based on DNA tags and primers"
def addOptions(parser):
@ -84,6 +87,8 @@ class Primer:
@type direct:
'''
assert len(sequence) <= MAX_PAT_LEN, "Primer %s is too long, 31 bp max" % sequence
assert sequence not in Primer.collection \
or Primer.collection[sequence]==taglength, \
"Primer %s must always be used with tags of the same length" % sequence
@ -264,14 +269,18 @@ cdef tuple annotate(sequences, infos, no_tags, verbose=False):
not_aligned = len(sequences) > 1
sequences[0] = sequences[0].clone()
if not_aligned:
sequences[0][b"R1_parent"] = sequences[0].id
sequences[0][b"R2_parent"] = sequences[1].id
if not_aligned:
sequences[1] = sequences[1].clone()
sequences[0][REVERSE_SEQUENCE_COLUMN] = sequences[1].seq # used by alignpairedend tool
sequences[0][REVERSE_SEQUENCE_COLUMN] = sequences[1].seq # used by alignpairedend tool
sequences[0][REVERSE_QUALITY_COLUMN] = sequences[1].quality # used by alignpairedend tool
for seq in sequences:
if hasattr(seq, "quality_array"):
if hasattr(seq, "quality_array") and seq.quality_array is not None:
q = -reduce(lambda x,y:x+y,(math.log10(z) for z in seq.quality_array),0)/len(seq.quality_array)*10
seq[b'avg_quality']=q
q = -reduce(lambda x,y:x+y,(math.log10(z) for z in seq.quality_array[0:10]),0)
@ -295,7 +304,7 @@ cdef tuple annotate(sequences, infos, no_tags, verbose=False):
directmatch.append((p, p(seq, same_sequence=not new_seq, pattern=pattern), seq, p))
new_seq = False
pattern+=1
# Choose match closer to the start of (one of the) sequence(s)
directmatch = sorted(directmatch, key=sortMatch)
all_direct_matches = directmatch
@ -450,7 +459,7 @@ cdef tuple annotate(sequences, infos, no_tags, verbose=False):
sequences[1] = sequences[1][reversematch[1][2]:]
if not directmatch[0].forward:
sequences[1] = sequences[1].reverse_complement
sequences[0][REVERSE_SEQUENCE_COLUMN] = sequences[1].seq # used by alignpairedend tool
sequences[0][REVERSE_SEQUENCE_COLUMN] = sequences[1].seq # used by alignpairedend tool
sequences[0][REVERSE_QUALITY_COLUMN] = sequences[1].quality # used by alignpairedend tool
else:
sequences[0] = sequences[0][reversematch[1][2]:]

View File

@ -0,0 +1,87 @@
#cython: language_level=3
from obitools3.uri.decode import open_uri
from obitools3.apps.config import logger
from obitools3.dms import DMS
from obitools3.apps.optiongroups import addMinimalInputOption
from obitools3.dms.view.view cimport View
from obitools3.utils cimport tostr
import os
import shutil
__title__="Delete a view"
def addOptions(parser):
addMinimalInputOption(parser)
def run(config):
DMS.obi_atexit()
logger("info", "obi rm")
# Open the input
input = open_uri(config['obi']['inputURI'])
if input is None:
raise Exception("Could not read input")
# Check that it's a view
if isinstance(input[1], View) :
view = input[1]
else:
raise NotImplementedError()
dms = input[0]
# Get the path to the view file to remove
path = dms.full_path # dms path
view_path=path+b"/VIEWS/"
view_path+=view.name
view_path+=b".obiview"
to_remove = {}
# For each column:
for col_alias in view.keys():
col = view[col_alias]
col_name = col.original_name
col_version = col.version
col_type = col.data_type
col_ref = (col_name, col_version)
# build file name and AVL file names
col_file_name = f"{tostr(path)}/{tostr(col.original_name)}.obicol/{tostr(col.original_name)}@{col.version}.odc"
if col_type in [b'OBI_CHAR', b'OBI_QUAL', b'OBI_STR', b'OBI_SEQ']:
avl_file_name = f"{tostr(path)}/OBIBLOB_INDEXERS/{tostr(col.original_name)}_{col.version}_indexer"
else:
avl_file_name = None
to_remove[col_ref] = [col_file_name, avl_file_name]
# For each view:
do_not_remove = []
for vn in dms:
v = dms[vn]
# ignore the one being deleted
if v.name != view.name:
# check that none of the column is referenced, if referenced, remove from list to remove
cols = [(v[c].original_name, v[c].version) for c in v.keys()]
for col_ref in to_remove:
if col_ref in cols:
do_not_remove.append(col_ref)
for nr in do_not_remove:
to_remove.pop(nr)
# Close the view and the DMS
view.close()
input[0].close(force=True)
#print(to_remove)
# rm AFTER view and DMS close
os.remove(view_path)
for col in to_remove:
os.remove(to_remove[col][0])
if to_remove[col][1] is not None:
shutil.rmtree(to_remove[col][1])

View File

@ -36,7 +36,7 @@ NULL_VALUE = {OBI_BOOL: OBIBool_NA,
OBI_STR: b""}
__title__="Sort view lines according to the value of a given attribute."
__title__="Sort view lines according to the value of a given attribute"
def addOptions(parser):

View File

@ -0,0 +1,105 @@
#cython: language_level=3
from obitools3.apps.progress cimport ProgressBar # @UnresolvedImport
from obitools3.dms import DMS
from obitools3.dms.view.view cimport View, Line_selection
from obitools3.uri.decode import open_uri
from obitools3.apps.optiongroups import addMinimalInputOption, addTaxonomyOption, addMinimalOutputOption, addNoProgressBarOption
from obitools3.dms.view import RollbackException
from obitools3.apps.config import logger
from obitools3.utils cimport tobytes
import sys
from cpython.exc cimport PyErr_CheckSignals
__title__="Split"
def addOptions(parser):
addMinimalInputOption(parser)
addNoProgressBarOption(parser)
group=parser.add_argument_group("obi split specific options")
group.add_argument('-p','--prefix',
action="store", dest="split:prefix",
metavar="<PREFIX>",
help="Prefix added to each subview name (included undefined)")
group.add_argument('-t','--tag-name',
action="store", dest="split:tagname",
metavar="<TAG_NAME>",
help="Attribute/tag used to split the input")
group.add_argument('-u','--undefined',
action="store", dest="split:undefined",
default=b'UNDEFINED',
metavar="<VIEW_NAME>",
help="Name of the view where undefined sequenced are stored (will be PREFIX_VIEW_NAME)")
def run(config):
DMS.obi_atexit()
logger("info", "obi split")
# Open the input
input = open_uri(config["obi"]["inputURI"])
if input is None:
raise Exception("Could not read input view")
i_dms = input[0]
i_view = input[1]
# Initialize the progress bar
if config['obi']['noprogressbar'] == False:
pb = ProgressBar(len(i_view), config)
else:
pb = None
tag_to_split = config["split"]["tagname"]
undefined = tobytes(config["split"]["undefined"])
selections = {}
# Go through input view and split
for i in range(len(i_view)):
PyErr_CheckSignals()
if pb is not None:
pb(i)
line = i_view[i]
if tag_to_split not in line or line[tag_to_split] is None or len(line[tag_to_split])==0:
value = undefined
else:
value = line[tag_to_split]
if value not in selections:
selections[value] = Line_selection(i_view)
selections[value].append(i)
if pb is not None:
pb(len(i_view), force=True)
print("", file=sys.stderr)
# Create output views with the line selection
try:
for cat in selections:
o_view_name = config["split"]["prefix"].encode()+cat
o_view = selections[cat].materialize(o_view_name)
# Save command config in View and DMS comments
command_line = " ".join(sys.argv[1:])
input_dms_name=[input[0].name]
input_view_name=[input[1].name]
if 'taxoURI' in config['obi'] and config['obi']['taxoURI'] is not None:
input_dms_name.append(config['obi']['taxoURI'].split("/")[-3])
input_view_name.append("taxonomy/"+config['obi']['taxoURI'].split("/")[-1])
o_view.write_config(config, "split", command_line, input_dms_name=input_dms_name, input_view_name=input_view_name)
o_view.close()
except Exception, e:
raise RollbackException("obi split error, rollbacking view: "+str(e), o_view)
i_dms.record_command_line(command_line)
i_dms.close(force=True)
logger("info", "Done.")

View File

@ -16,7 +16,7 @@ import sys
from cpython.exc cimport PyErr_CheckSignals
__title__="Compute basic statistics for attribute values."
__title__="Compute basic statistics for attribute values"
'''
`obi stats` computes basic statistics for attribute values of sequence records.
@ -119,9 +119,12 @@ def mean(values, options):
def variance(v):
if len(v)==1:
return 0
return 0
s = reduce(lambda x,y:(x[0]+y,x[1]+y**2),v,(0.,0.))
return s[1]/(len(v)-1) - s[0]**2/len(v)/(len(v)-1)
var = round(s[1]/(len(v)-1) - s[0]**2/len(v)/(len(v)-1), 5) # round to go around shady python rounding stuff when var is actually 0
if var == -0.0: # then fix -0 to +0 if was rounded to -0
var = 0.0
return var
def varpop(values, options):
@ -154,7 +157,7 @@ def run(config):
else :
taxo = None
statistics = set(config['stats']['minimum']) | set(config['stats']['maximum']) | set(config['stats']['mean'])
statistics = set(config['stats']['minimum']) | set(config['stats']['maximum']) | set(config['stats']['mean']) | set(config['stats']['var']) | set(config['stats']['sd'])
total = 0
catcount={}
totcount={}
@ -195,7 +198,7 @@ def run(config):
except KeyError:
totcount[category]=totcount.get(category,0)+1
for var in statistics:
if var in line:
if var in line and line[var] is not None:
v = line[var]
if var not in values:
values[var]={}
@ -238,14 +241,34 @@ def run(config):
else:
sdvar= "%s"
hcat = "\t".join([pcat % x for x in config['stats']['categories']]) + "\t" +\
"\t".join([minvar % x for x in config['stats']['minimum']]) + "\t" +\
"\t".join([maxvar % x for x in config['stats']['maximum']]) + "\t" +\
"\t".join([meanvar % x for x in config['stats']['mean']]) + "\t" +\
"\t".join([varvar % x for x in config['stats']['var']]) + "\t" +\
"\t".join([sdvar % x for x in config['stats']['sd']]) + \
"\t count" + \
"\t total"
hcat = ""
for x in config['stats']['categories']:
hcat += pcat % x
hcat += "\t"
for x in config['stats']['minimum']:
hcat += minvar % x
hcat += "\t"
for x in config['stats']['maximum']:
hcat += maxvar % x
hcat += "\t"
for x in config['stats']['mean']:
hcat += meanvar % x
hcat += "\t"
for x in config['stats']['var']:
hcat += varvar % x
hcat += "\t"
for x in config['stats']['sd']:
hcat += sdvar % x
hcat += "\t"
hcat += "count\ttotal"
print(hcat)
sorted_stats = sorted(catcount.items(), key = lambda kv:(totcount[kv[0]]), reverse=True)
for i in range(len(sorted_stats)):
@ -265,8 +288,8 @@ def run(config):
print((("%%%df" % lvarp[m]) % varp[m][c])+"\t", end="")
for m in config['stats']['sd']:
print((("%%%df" % lsigma[m]) % sigma[m][c])+"\t", end="")
print("%7d" %catcount[c], end="")
print("%9d" %totcount[c])
print("%d" %catcount[c]+"\t", end="")
print("%d" %totcount[c]+"\t")
input[0].close(force=True)

View File

@ -15,7 +15,7 @@ from cpython.exc cimport PyErr_CheckSignals
from io import BufferedWriter
__title__="Keep the N last lines of a view."
__title__="Keep the N last lines of a view"
def addOptions(parser):

View File

@ -0,0 +1,230 @@
#cython: language_level=3
from obitools3.apps.progress cimport ProgressBar # @UnresolvedImport
from obitools3.dms import DMS
from obitools3.dms.view.view cimport View, Line_selection
from obitools3.uri.decode import open_uri
from obitools3.apps.optiongroups import addMinimalInputOption, addTaxonomyOption, addMinimalOutputOption, addNoProgressBarOption
from obitools3.dms.view import RollbackException
from obitools3.dms.column.column cimport Column
from functools import reduce
from obitools3.apps.config import logger
from obitools3.utils cimport tobytes, str2bytes, tostr
from io import BufferedWriter
from obitools3.dms.capi.obiview cimport NUC_SEQUENCE_COLUMN, \
ID_COLUMN, \
DEFINITION_COLUMN, \
QUALITY_COLUMN, \
COUNT_COLUMN, \
TAXID_COLUMN
from obitools3.dms.capi.obitypes cimport OBI_INT
from obitools3.dms.capi.obitaxonomy cimport MIN_LOCAL_TAXID
import time
import math
import sys
from cpython.exc cimport PyErr_CheckSignals
__title__="Add taxa with a new generated taxid to an NCBI taxonomy database"
def addOptions(parser):
addMinimalInputOption(parser)
addTaxonomyOption(parser)
addMinimalOutputOption(parser)
addNoProgressBarOption(parser)
group=parser.add_argument_group('obi taxonomy specific options')
group.add_argument('-n', '--taxon-name-tag',
action="store",
dest="taxonomy:taxon_name_tag",
metavar="<SCIENTIFIC_NAME_TAG>",
default=b"SCIENTIFIC_NAME",
help="Name of the tag giving the scientific name of the taxon "
"(default: 'SCIENTIFIC_NAME').")
# group.add_argument('-g', '--try-genus-match',
# action="store_true", dest="taxonomy:try_genus_match",
# default=False,
# help="Try matching the first word of <SCIENTIFIC_NAME_TAG> when can't find corresponding taxid for a taxon. "
# "If there is a match it is added in the 'parent_taxid' tag. (Can be used by 'obi taxonomy' to add the taxon under that taxid).")
group.add_argument('-a', '--restricting-ancestor',
action="store",
dest="taxonomy:restricting_ancestor",
metavar="<RESTRICTING_ANCESTOR>",
default=None,
help="Enables to restrict the addition of taxids under an ancestor specified by its taxid.")
group.add_argument('-t', '--taxid-tag',
action="store",
dest="taxonomy:taxid_tag",
metavar="<TAXID_TAG>",
default=b"TAXID",
help="Name of the tag to store the new taxid "
"(default: 'TAXID').")
group.add_argument('-l', '--log-file',
action="store",
dest="taxonomy:log_file",
metavar="<LOG_FILE>",
default='',
help="Path to a log file to write informations about added taxids.")
def run(config):
DMS.obi_atexit()
logger("info", "obi taxonomy")
# Open the input
input = open_uri(config['obi']['inputURI'])
if input is None:
raise Exception("Could not read input view")
i_dms = input[0]
i_view = input[1]
i_view_name = input[1].name
# Open the output: only the DMS, as the output view is going to be created by cloning the input view
# (could eventually be done via an open_uri() argument)
output = open_uri(config['obi']['outputURI'],
input=False,
dms_only=True)
if output is None:
raise Exception("Could not create output view")
o_dms = output[0]
output_0 = output[0]
o_view_name = output[1]
# stdout output: create temporary view
if type(output_0)==BufferedWriter:
o_dms = i_dms
i=0
o_view_name = b"temp"
while o_view_name in i_dms: # Making sure view name is unique in output DMS
o_view_name = o_view_name+b"_"+str2bytes(str(i))
i+=1
imported_view_name = o_view_name
# If the input and output DMS are not the same, import the input view in the output DMS before cloning it to modify it
# (could be the other way around: clone and modify in the input DMS then import the new view in the output DMS)
if i_dms != o_dms:
imported_view_name = i_view_name
i=0
while imported_view_name in o_dms: # Making sure view name is unique in output DMS
imported_view_name = i_view_name+b"_"+str2bytes(str(i))
i+=1
View.import_view(i_dms.full_path[:-7], o_dms.full_path[:-7], i_view_name, imported_view_name)
i_view = o_dms[imported_view_name]
# Clone output view from input view
o_view = i_view.clone(o_view_name)
if o_view is None:
raise Exception("Couldn't create output view")
i_view.close()
# Open taxonomy
taxo_uri = open_uri(config['obi']['taxoURI'])
if taxo_uri is None or taxo_uri[2] == bytes:
raise Exception("Couldn't open taxonomy")
taxo = taxo_uri[1]
# Initialize the progress bar
if config['obi']['noprogressbar'] == False:
pb = ProgressBar(len(o_view), config)
else:
pb = None
try:
if config['taxonomy']['log_file']:
logfile = open(config['taxonomy']['log_file'], 'w')
else:
logfile = sys.stdout
if 'restricting_ancestor' in config['taxonomy']:
res_anc = int(config['taxonomy']['restricting_ancestor'])
else:
res_anc = None
taxid_column_name = config['taxonomy']['taxid_tag']
parent_taxid_column_name = "PARENT_TAXID" # TODO macro
taxon_name_column_name = config['taxonomy']['taxon_name_tag']
taxid_column = Column.new_column(o_view, taxid_column_name, OBI_INT)
if parent_taxid_column_name in o_view:
parent_taxid_column = o_view[parent_taxid_column_name]
else:
parent_taxid_column = None
#parent_taxid_column = Column.new_column(o_view, parent_taxid_column_name, OBI_INT)
taxon_name_column = o_view[taxon_name_column_name]
for i in range(len(o_view)):
PyErr_CheckSignals()
#if pb is not None:
# pb(i)
taxon_name = taxon_name_column[i]
taxon = taxo.get_taxon_by_name(taxon_name, res_anc)
if taxon is not None:
taxid_column[i] = taxon.taxid
if logfile:
print(f"Found taxon '{tostr(taxon_name)}' already existing with taxid {taxid_column[i]}", file=logfile)
else: # try finding genus or other parent taxon from the first word
#print(i, o_view[i].id)
if parent_taxid_column is not None and parent_taxid_column[i] is not None:
taxid_column[i] = taxo.add_taxon(taxon_name, 'species', parent_taxid_column[i])
if logfile:
print(f"Adding taxon '{tostr(taxon_name)}' under provided parent {parent_taxid_column[i]} with taxid {taxid_column[i]}", file=logfile)
else:
taxon_name_sp = taxon_name.split(b" ")
taxon = taxo.get_taxon_by_name(taxon_name_sp[0], res_anc)
if taxon is not None:
parent_taxid_column[i] = taxon.taxid
taxid_column[i] = taxo.add_taxon(taxon_name, 'species', taxon.taxid)
if logfile:
print(f"Adding taxon '{tostr(taxon_name)}' under '{tostr(taxon.name)}' ({taxon.taxid}) with taxid {taxid_column[i]}", file=logfile)
else:
taxid_column[i] = taxo.add_taxon(taxon_name, 'species', res_anc)
if logfile:
print(f"Adding taxon '{tostr(taxon_name)}' under provided restricting ancestor {res_anc} with taxid {taxid_column[i]}", file=logfile)
taxo.write(taxo.name, update=True)
except Exception, e:
raise RollbackException("obi taxonomy error, rollbacking view: "+str(e), o_view)
#if pb is not None:
# pb(i, force=True)
# print("", file=sys.stderr)
#logger("info", "\nTaxa already in the taxonomy: "+str(found_count)+"/"+str(len(o_view))+" ("+str(round(found_count*100.0/len(o_view), 2))+"%)")
#logger("info", "\nParent taxids found: "+str(parent_found_count)+"/"+str(len(o_view))+" ("+str(round(parent_found_count*100.0/len(o_view), 2))+"%)")
#logger("info", "\nTaxids not found: "+str(not_found_count)+"/"+str(len(o_view))+" ("+str(round(not_found_count*100.0/len(o_view), 2))+"%)")
# Save command config in View and DMS comments
command_line = " ".join(sys.argv[1:])
input_dms_name=[input[0].name]
input_view_name=[i_view_name]
if 'taxoURI' in config['obi'] and config['obi']['taxoURI'] is not None:
input_dms_name.append(config['obi']['taxoURI'].split("/")[-3])
input_view_name.append("taxonomy/"+config['obi']['taxoURI'].split("/")[-1])
o_view.write_config(config, "taxonomy", command_line, input_dms_name=input_dms_name, input_view_name=input_view_name)
o_dms.record_command_line(command_line)
#print("\n\nOutput view:\n````````````", file=sys.stderr)
#print(repr(o_view), file=sys.stderr)
# stdout output: write to buffer
if type(output_0)==BufferedWriter:
logger("info", "Printing to output...")
o_view.print_to_output(output_0, noprogressbar=config['obi']['noprogressbar'])
o_view.close()
# If the input and the output DMS are different or if stdout output, delete the temporary imported view used to create the final view
if i_dms != o_dms or type(output_0)==BufferedWriter:
View.delete_view(o_dms, imported_view_name)
o_dms.close(force=True)
i_dms.close(force=True)
logger("info", "Done.")

View File

@ -39,7 +39,7 @@ COL_COMMENTS_MAX_LEN = 2048
MAX_INT = 2147483647 # used to generate random float values
__title__="Tests if the obitools are working properly"
__title__="Test if the obitools are working properly"
default_config = {

View File

@ -8,6 +8,7 @@ cdef extern from "obi_ecopcr.h" nogil:
int obi_ecopcr(const char* input_dms_name,
const char* i_view_name,
const char* tax_dms_name,
const char* taxonomy_name,
const char* output_dms_name,
const char* o_view_name,

View File

@ -58,7 +58,7 @@ cdef extern from "obidms_taxonomy.h" nogil:
OBIDMS_taxonomy_p obi_read_taxdump(const_char_p taxdump)
int obi_write_taxonomy(OBIDMS_p dms, OBIDMS_taxonomy_p tax, const_char_p tax_name)
int obi_write_taxonomy(OBIDMS_p dms, OBIDMS_taxonomy_p tax, const_char_p tax_name, bint update)
int obi_close_taxonomy(OBIDMS_taxonomy_p taxonomy)

View File

@ -53,6 +53,8 @@ cdef extern from "obitypes.h" nogil:
extern const_char_p OBIQual_char_NA
extern uint8_t* OBIQual_int_NA
extern void* OBITuple_NA
extern obiint_t OBI_INT_MAX
const_char_p name_data_type(int data_type)

View File

@ -7,7 +7,8 @@ __OBIDMS_COLUMN_CLASS__ = {}
from ..capi.obitypes cimport name_data_type, \
obitype_t, \
obiversion_t, \
OBI_QUAL
OBI_QUAL, \
OBI_STR
from ..capi.obidms cimport obi_import_column
@ -128,6 +129,10 @@ cdef class Column(OBIWrapper) :
else:
elements_names_p = NULL
if column_name_b == b"SAMPLE" or column_name_b == b"sample":
# force str type
data_type = OBI_STR
if data_type == OBI_QUAL:
if associated_column_name_b == b"":
if column_name == QUALITY_COLUMN:

View File

@ -74,6 +74,9 @@ cdef class Column_str(Column_idx):
if value is None :
value_b = <char*>OBIStr_NA
else :
if self.name == b'sample' or self.name == b'SAMPLE':
if type(value) == int:
value = str(value) # force sample ids to be str
value_bytes = tobytes(value)
value_b = <char*>value_bytes
@ -137,6 +140,9 @@ cdef class Column_multi_elts_str(Column_multi_elts_idx):
if value is None :
value_b = <char*>OBIStr_NA
else :
if self.name == b'sample' or self.name == b'SAMPLE':
if type(value) == int:
value = str(value) # force sample ids to be str
value_bytes = tobytes(value)
value_b = <char*>value_bytes
@ -206,6 +212,9 @@ cdef class Column_tuples_str(Column_idx):
i = 0
for elt in value :
if elt is not None and elt != '':
if self.name == b'sample' or self.name == b'SAMPLE':
if type(elt) == int:
elt = str(elt) # force sample ids to be str
elt_b = tobytes(elt)
strcpy(array+i, <char*>elt_b)
i = i + len(elt_b) + 1

View File

@ -19,8 +19,8 @@ cdef class Taxonomy(OBIWrapper) :
cpdef Taxon get_taxon_by_idx(self, int idx)
cpdef Taxon get_taxon_by_taxid(self, int taxid)
cpdef Taxon get_taxon_by_name(self, object taxon_name, object restricting_taxid=*)
cpdef write(self, object prefix)
cpdef int add_taxon(self, str name, str rank_name, int parent_taxid, int min_taxid=*)
cpdef write(self, object prefix, bint update=*)
cpdef int add_taxon(self, object name, object rank_name, int parent_taxid, int min_taxid=*)
cpdef object get_species(self, int taxid)
cpdef object get_genus(self, int taxid)
cpdef object get_family(self, int taxid)

View File

@ -1,5 +1,7 @@
#cython: language_level=3
import sys
from obitools3.utils cimport str2bytes, bytes2str, tobytes, tostr
from ..capi.obidms cimport OBIDMS_p, obi_dms_get_full_path
@ -34,7 +36,7 @@ cdef class Taxonomy(OBIWrapper) :
return <OBIDMS_taxonomy_p>(self._pointer)
cdef fill_name_dict(self):
print("Indexing taxon names...")
print("Indexing taxon names...", file=sys.stderr)
cdef OBIDMS_taxonomy_p pointer = self.pointer()
cdef ecotx_t* taxon_p
@ -91,6 +93,8 @@ cdef class Taxonomy(OBIWrapper) :
raise RuntimeError("Error : Cannot read taxonomy %s"
% tostr(name))
print("Taxonomy read", file=sys.stderr)
taxo = OBIWrapper.new_wrapper(Taxonomy, pointer)
dms.register(taxo)
@ -146,7 +150,9 @@ cdef class Taxonomy(OBIWrapper) :
taxo._ranks = []
for r in range((<OBIDMS_taxonomy_p>pointer).ranks.count) :
taxo._ranks.append(obi_taxo_rank_index_to_label(r, (<OBIDMS_taxonomy_p>pointer).ranks))
print('Read %d taxa' % len(taxo), file=sys.stderr)
return taxo
@ -168,6 +174,7 @@ cdef class Taxonomy(OBIWrapper) :
cpdef Taxon get_taxon_by_name(self, object taxon_name, object restricting_taxid=None):
#print(taxon_name)
taxon = self._name_dict.get(tobytes(taxon_name), None)
if not taxon:
return None
@ -276,12 +283,12 @@ cdef class Taxonomy(OBIWrapper) :
yield Taxon(taxon_capsule, self)
cpdef write(self, object prefix) :
if obi_write_taxonomy(self._dms.pointer(), self.pointer(), tobytes(prefix)) < 0 :
cpdef write(self, object prefix, bint update=False) :
if obi_write_taxonomy(self._dms.pointer(), self.pointer(), tobytes(prefix), update) < 0 :
raise Exception("Error writing the taxonomy to binary files")
cpdef int add_taxon(self, str name, str rank_name, int parent_taxid, int min_taxid=10000000) :
cpdef int add_taxon(self, object name, object rank_name, int parent_taxid, int min_taxid=10000000) :
cdef int taxid
taxid = obi_taxo_add_local_taxon(self.pointer(), tobytes(name), tobytes(rank_name), parent_taxid, min_taxid)
if taxid < 0 :
@ -304,6 +311,11 @@ cdef class Taxonomy(OBIWrapper) :
def name(self):
return self._name
# ranks property getter
@property
def ranks(self):
return self._ranks
def parental_tree_iterator(self, int taxid):
"""
@ -318,6 +330,7 @@ cdef class Taxonomy(OBIWrapper) :
if taxon is not None:
while taxon.taxid != 1:
yield taxon
#print(taxon.taxid)
taxon = taxon.parent
yield taxon
else:

View File

@ -77,7 +77,7 @@ cdef class View(OBIWrapper) :
@staticmethod
def import_view(object dms_1, object dms_2, object view_name_1, object view_name_2):
def import_view(object dms_1, object dms_2, object view_name_1, object view_name_2): # TODO argument to import line by line to avoid huge AVL copy
if obi_import_view(tobytes(dms_1), tobytes(dms_2), tobytes(view_name_1), tobytes(view_name_2)) < 0 :
raise Exception("Error importing a view")
@ -345,7 +345,7 @@ cdef class View(OBIWrapper) :
nb_elements_per_line=new_nb_elements_per_line, elements_names=new_elements_names,
dict_column=(new_nb_elements_per_line>1), comments=old_column.comments, alias=column_name_b+tobytes('___new___'))
switch_to_dict = old_column.nb_elements_per_line == 1 and new_nb_elements_per_line > 1
switch_to_dict = not old_column.dict_column and new_nb_elements_per_line > 1
ori_key = old_column._elements_names[0]
for i in range(length) :
@ -600,7 +600,8 @@ cdef class View(OBIWrapper) :
if element is not None:
if element.comments[b"input_dms_name"] is not None :
for i in range(len(element.comments[b"input_dms_name"])) :
if element.comments[b"input_dms_name"][i] == element.dms.name and b"/" not in element.comments[b"input_view_name"][i]: # Same DMS and not a special element like a taxonomy
if b"/" not in element.comments[b"input_view_name"][i] and element.comments[b"input_view_name"][i] in element.dms \
and element.comments[b"input_dms_name"][i] == element.dms.name : # Same DMS and not a special element like a taxonomy and view was not deleted
top_level.append(element.dms[element.comments[b"input_view_name"][i]])
else:
top_level.append(None)
@ -798,7 +799,8 @@ cdef class Line :
def keys(self):
return self._view.keys()
cdef bytes key
return [key for key in self._view.keys()]
def __contains__(self, object column_name):

View File

@ -7,11 +7,12 @@ from obitools3.utils cimport bytes2str
cdef class FastaFormat:
def __init__(self, list tags=[], bint printNAKeys=False, bytes NAString=b"NA"):
def __init__(self, list tags=[], bint printNAKeys=False, bytes NAString=b"NA", bint NAIntTo0=False):
self.headerFormatter = HeaderFormat("fasta",
tags=tags,
printNAKeys=printNAKeys,
NAString=NAString)
NAString=NAString,
NAIntTo0=NAIntTo0)
@cython.boundscheck(False)
def __call__(self, object data):

View File

@ -8,11 +8,12 @@ from obitools3.utils cimport bytes2str, str2bytes, tobytes
# TODO quality offset option?
cdef class FastqFormat:
def __init__(self, list tags=[], bint printNAKeys=False, bytes NAString=b"NA"):
def __init__(self, list tags=[], bint printNAKeys=False, bytes NAString=b"NA", bint NAIntTo0=False):
self.headerFormatter = HeaderFormat("fastq",
tags=tags,
printNAKeys=printNAKeys,
NAString=NAString)
NAString=NAString,
NAIntTo0=NAIntTo0)
@cython.boundscheck(False)
def __call__(self, object data):

View File

@ -4,5 +4,6 @@ cdef class HeaderFormat:
cdef set tags
cdef bint printNAKeys
cdef bytes NAString
cdef bint NAIntTo0
cdef size_t headerBufferLength

View File

@ -8,13 +8,14 @@ from obitools3.dms.capi.obiview cimport NUC_SEQUENCE_COLUMN, \
from obitools3.utils cimport str2bytes, bytes2str_object
from obitools3.dms.column.column cimport Column_line
from obitools3.dms.column.typed_column.int cimport Column_int, Column_multi_elts_int
cdef class HeaderFormat:
SPECIAL_KEYS = [NUC_SEQUENCE_COLUMN, ID_COLUMN, DEFINITION_COLUMN, QUALITY_COLUMN]
def __init__(self, str format="fasta", list tags=[], bint printNAKeys=False, bytes NAString=b"NA"):
def __init__(self, str format="fasta", list tags=[], bint printNAKeys=False, bytes NAString=b"NA", bint NAIntTo0=False):
'''
@param format:
@type format: `str`
@ -32,6 +33,7 @@ cdef class HeaderFormat:
self.tags = set(tags)
self.printNAKeys = printNAKeys
self.NAString = NAString
self.NAIntTo0 = NAIntTo0
if format=="fasta":
self.start=b">"
@ -57,17 +59,25 @@ cdef class HeaderFormat:
if k in tags:
value = data[k]
if value is None or (isinstance(value, Column_line) and value.is_NA()):
if self.printNAKeys:
if isinstance(data.view[k], Column_int) and self.NAIntTo0: # people want missing int values to be 0
value = b'0'
elif self.printNAKeys:
value = self.NAString
else:
value = None
else:
if type(value) == Column_line:
value = value.bytes()
if isinstance(data.view[k], Column_multi_elts_int) and self.NAIntTo0:
value = dict(value)
for key in data.view[k].keys():
if key not in value or value[key]:
value[key] = 0
else:
value = value.bytes()
else:
if type(value) == tuple:
value=list(value)
value = str2bytes(str(bytes2str_object(value))) # genius programming
value = str2bytes(str(bytes2str_object(value))) # genius programming
if value is not None:
lines.append(k + b"=" + value + b";")

View File

@ -4,5 +4,8 @@ cdef class TabFormat:
cdef bint header
cdef bint first_line
cdef bytes NAString
cdef list tags
cdef bytes sep
cdef set tags
cdef bytes sep
cdef bint NAIntTo0
cdef bint metabaR
cdef bint ngsfilter

View File

@ -4,57 +4,80 @@ cimport cython
from obitools3.dms.view.view cimport Line
from obitools3.utils cimport bytes2str_object, str2bytes, tobytes
from obitools3.dms.column.column cimport Column_line, Column_multi_elts
from obitools3.dms.column.typed_column.int cimport Column_int, Column_multi_elts_int
import sys
cdef class TabFormat:
def __init__(self, header=True, bytes NAString=b"NA", bytes sep=b"\t"):
def __init__(self, list tags=[], header=True, bytes NAString=b"NA", bytes sep=b"\t", bint NAIntTo0=True, metabaR=False, ngsfilter=False):
self.tags = set(tags)
self.header = header
self.first_line = True
self.NAString = NAString
self.sep = sep
self.NAIntTo0 = NAIntTo0
self.metabaR = metabaR
self.ngsfilter = ngsfilter
@cython.boundscheck(False)
def __call__(self, object data):
cdef set ktags
cdef list tags = [key for key in data]
line = []
if self.first_line:
self.tags = [k for k in data.keys()]
if self.tags is not None and self.tags:
ktags = self.tags
else:
ktags = set(tags)
if self.header and self.first_line:
for k in self.tags:
if isinstance(data.view[k], Column_multi_elts):
keys = data.view[k].keys()
keys.sort()
for k2 in keys:
line.append(tobytes(k)+b':'+tobytes(k2))
else:
line.append(tobytes(k))
for k in ktags:
if k in tags:
if self.metabaR:
if k == b'NUC_SEQ':
ktoprint = b'sequence'
else:
ktoprint = k.lower()
ktoprint = ktoprint.replace(b'merged_', b'')
else:
ktoprint = k
if isinstance(data.view[k], Column_multi_elts):
keys = data.view[k].keys()
keys.sort()
for k2 in keys:
line.append(tobytes(ktoprint)+b':'+tobytes(k2))
else:
line.append(tobytes(ktoprint))
r = self.sep.join(value for value in line)
r += b'\n'
line = []
for k in self.tags:
value = data[k]
if isinstance(data.view[k], Column_multi_elts):
keys = data.view[k].keys()
keys.sort()
if value is None: # all keys at None
for k2 in keys: # TODO could be much more efficient
line.append(self.NAString)
else:
for k2 in keys: # TODO could be much more efficient
if value[k2] is not None:
line.append(str2bytes(str(bytes2str_object(value[k2])))) # genius programming
else:
for k in ktags:
if k in tags:
value = data[k]
if isinstance(data.view[k], Column_multi_elts):
keys = data.view[k].keys()
keys.sort()
if value is None: # all keys at None
for k2 in keys: # TODO could be much more efficient
line.append(self.NAString)
else:
if value is not None:
line.append(str2bytes(str(bytes2str_object(value))))
else:
for k2 in keys: # TODO could be much more efficient
if value[k2] is not None:
line.append(str2bytes(str(bytes2str_object(value[k2])))) # genius programming
else:
if self.NAIntTo0 and isinstance(data.view[k], Column_multi_elts_int):
line.append(b"0")
else:
line.append(self.NAString)
else:
line.append(self.NAString)
if value is not None or (self.NAIntTo0 and isinstance(data.view[k], Column_int)):
line.append(str2bytes(str(bytes2str_object(value))))
else:
line.append(self.NAString)
if self.header and self.first_line:
r += self.sep.join(value for value in line)

View File

@ -103,7 +103,11 @@ def fastqWithQualityIterator(lineiterator,
yield seq
read+=1
hline = next(i)
try:
hline = next(i)
except StopIteration:
return
def fastqWithoutQualityIterator(lineiterator,
@ -174,5 +178,7 @@ def fastqWithoutQualityIterator(lineiterator,
yield seq
read+=1
hline = next(i)
try:
hline = next(i)
except StopIteration:
return

View File

@ -22,11 +22,11 @@ from libc.stdlib cimport free, malloc, realloc
from libc.string cimport strcpy, strlen
_featureMatcher = re.compile(b'^FEATURES.+\n(?=ORIGIN )',re.DOTALL + re.M)
_featureMatcher = re.compile(b'^FEATURES.+\n(?=ORIGIN(\s*))',re.DOTALL + re.M)
_headerMatcher = re.compile(b'^LOCUS.+(?=\nFEATURES)', re.DOTALL + re.M)
_seqMatcher = re.compile(b'ORIGIN .+(?=//\n)', re.DOTALL + re.M)
_cleanSeq1 = re.compile(b'ORIGIN.+\n')
_seqMatcher = re.compile(b'^ORIGIN.+(?=//\n)', re.DOTALL + re.M)
_cleanSeq1 = re.compile(b'ORIGIN(\s*)\n')
_cleanSeq2 = re.compile(b'[ \n0-9]+')
_acMatcher = re.compile(b'(?<=^ACCESSION ).+',re.M)
_deMatcher = re.compile(b'(?<=^DEFINITION ).+\n( .+\n)*',re.M)
@ -155,10 +155,10 @@ def genbankIterator_file(lineiterator,
yield seq
read+=1
# Last sequence
seq = genbankParser(entry)
yield seq
# Last sequence if not empty lines
if entry.strip():
seq = genbankParser(entry)
yield seq
free(entry)

View File

@ -48,24 +48,25 @@ def ngsfilterIterator(lineiterator,
all_lines.insert(0, firstline)
# Insert header for column names
column_names = [b"experiment", b"sample", b"forward_tag", b"reverse_tag", b"forward_primer", b"reverse_primer"]
column_names = [b"experiment", b"sample", b"forward_tag", b"reverse_tag", b"forward_primer", b"reverse_primer"] #,b"additional_info"]
header = out_sep.join(column_names)
new_lines.append(header)
for line in all_lines:
split_line = line.split()
tags = split_line.pop(2)
tags = tags.split(b":")
for t_idx in range(len(tags)):
if tags[t_idx]==b"-" or tags[t_idx]==b"None" or tags[t_idx]==b"":
tags[t_idx] = nastring
if len(tags) == 1: # Forward and reverse tags are the same
tags.append(tags[0])
split_line.insert(2, tags[0])
split_line.insert(3, tags[1])
new_lines.append(out_sep.join(split_line[0:6]))
split_line = line.split(maxsplit=5)
if split_line:
tags = split_line.pop(2)
tags = tags.split(b":")
for t_idx in range(len(tags)):
if tags[t_idx]==b"-" or tags[t_idx]==b"None" or tags[t_idx]==b"":
tags[t_idx] = nastring
if len(tags) == 1: # Forward and reverse tags are the same
tags.append(tags[0])
split_line.insert(2, tags[0])
split_line.insert(3, tags[1])
new_lines.append(out_sep.join(split_line[0:6]))
return tabIterator(iter(new_lines),
header = True,
sep = out_sep,

View File

@ -99,7 +99,10 @@ def tabIterator(lineiterator,
read+=1
line = next(iterator)
try:
line = next(iterator)
except StopIteration:
return

View File

@ -173,7 +173,10 @@ def open_uri(uri,
type newviewtype=View,
dms_only=False,
force_file=False):
if type(uri) == str and not uri.isascii():
raise Exception("Paths must be ASCII characters only")
cdef bytes urib = tobytes(uri)
cdef bytes scheme
cdef tuple dms
@ -192,7 +195,7 @@ def open_uri(uri,
config = getConfiguration()
urip = urlparse(urib)
if 'obi' not in config:
config['obi']={}
@ -209,13 +212,14 @@ def open_uri(uri,
scheme = urip.scheme
error = None
if urib != b"-" and \
if b'/taxonomy/' in urib or \
(urib != b"-" and \
(scheme==b"dms" or \
(scheme==b"" and \
(((not input) and "outputformat" not in config["obi"]) or \
(input and "inputformat" not in config["obi"])))): # TODO maybe not best way
(input and "inputformat" not in config["obi"]))))): # TODO maybe not best way
if default_dms is not None and b"/" not in urip.path: # assuming view to open in default DMS (TODO discuss)
dms=(default_dms, urip.path)
else:
@ -223,7 +227,7 @@ def open_uri(uri,
if dms is None and default_dms is not None:
dms=(default_dms, urip.path)
if dms is not None:
if dms_only:
return (dms[0],
@ -248,7 +252,7 @@ def open_uri(uri,
if default_dms is None:
config["obi"]["defaultdms"]=resource[0]
return (resource[0],
resource[1],
type(resource[1]),
@ -276,7 +280,12 @@ def open_uri(uri,
iseq = urib
objclass = bytes
else: # TODO update uopen to be able to write?
if not urip.path or urip.path == b'-':
if config['obi']['outputformat'] == b'metabaR':
if 'metabarprefix' not in config['obi']:
raise Exception("Prefix needed when exporting for metabaR (--metabaR-prefix option)")
else:
file = open(config['obi']['metabarprefix']+'.tab', 'wb')
elif not urip.path or urip.path == b'-':
file = sys.stdout.buffer
else:
file = open(urip.path, 'wb')
@ -298,11 +307,11 @@ def open_uri(uri,
format=config["obi"][formatkey]
except KeyError:
format=None
if b'seqtype' in qualifiers:
seqtype=qualifiers[b'seqtype'][0]
else:
if format == b"ngsfilter" or format == b"tabular": # TODO discuss
if format == b"ngsfilter" or format == b"tabular" or format == b"metabaR": # TODO discuss
seqtype=None
else:
try:
@ -386,10 +395,10 @@ def open_uri(uri,
raise MalformedURIException('Malformed header argument in URI')
if b"sep" in qualifiers:
sep=tobytes(qualifiers[b"sep"][0][0])
sep = tobytes(qualifiers[b"sep"][0][0])
else:
try:
sep=tobytes(config["obi"]["sep"])
sep = tobytes(config["obi"]["sep"])
except KeyError:
sep=None
@ -426,7 +435,21 @@ def open_uri(uri,
nastring=tobytes(config["obi"][nakey])
except KeyError:
nastring=b'NA'
if b"na_int_to_0" in qualifiers:
try:
na_int_to_0=eval(qualifiers[b"na_int_to_0"][0])
except Exception as e:
raise MalformedURIException("Malformed 'NA_int_to_0' argument in URI")
else:
try:
na_int_to_0=config["obi"]["na_int_to_0"]
except KeyError:
if format==b"tabular" or format==b"metabaR":
na_int_to_0=True
else:
na_int_to_0=False
if b"stripwhite" in qualifiers:
try:
stripwhite=eval(qualifiers[b"stripwhite"][0])
@ -461,17 +484,36 @@ def open_uri(uri,
except KeyError:
commentchar=b'#'
if b"only_keys" in qualifiers:
only_keys=qualifiers[b"only_keys"][0] # not sure that works but no one ever uses qualifiers
else:
try:
only_keys_str=config["obi"]["only_keys"]
only_keys=[]
for key in only_keys_str:
only_keys.append(tobytes(key))
except KeyError:
only_keys=[]
if b"metabaR_prefix" in qualifiers:
metabaR_prefix = tobytes(qualifiers[b"metabaR_prefix"][0][0])
else:
try:
metabaR_prefix = tobytes(config["obi"]["metabarprefix"])
except KeyError:
metabaR_prefix=None
if format is not None:
if seqtype==b"nuc":
objclass = Nuc_Seq # Nuc_Seq_Stored? TODO
if format==b"fasta" or format==b"silva":
if format==b"fasta" or format==b"silva" or format==b"rdp" or format == b"unite" or format == b"sintax":
if input:
iseq = fastaNucIterator(file,
skip=skip,
only=only,
nastring=nastring)
else:
iseq = FastaNucWriter(FastaFormat(printNAKeys=printna, NAString=nastring),
iseq = FastaNucWriter(FastaFormat(tags=only_keys, printNAKeys=printna, NAString=nastring),
file,
skip=skip,
only=only)
@ -484,7 +526,7 @@ def open_uri(uri,
noquality=noquality,
nastring=nastring)
else:
iseq = FastqWriter(FastqFormat(printNAKeys=printna, NAString=nastring),
iseq = FastqWriter(FastqFormat(tags=only_keys, printNAKeys=printna, NAString=nastring),
file,
skip=skip,
only=only)
@ -520,7 +562,17 @@ def open_uri(uri,
skip = skip,
only = only)
else:
iseq = TabWriter(TabFormat(header=header, NAString=nastring, sep=sep),
iseq = TabWriter(TabFormat(tags=only_keys, header=header, NAString=nastring, sep=sep, NAIntTo0=na_int_to_0),
file,
skip=skip,
only=only,
header=header)
elif format==b"metabaR":
objclass = dict
if input:
raise NotImplementedError('Input data file format not implemented')
else:
iseq = TabWriter(TabFormat(tags=only_keys, header=header, NAString=nastring, sep=sep, NAIntTo0=na_int_to_0, metabaR=True),
file,
skip=skip,
only=only,
@ -538,7 +590,7 @@ def open_uri(uri,
skip = skip,
only = only)
else:
raise NotImplementedError('Output sequence file format not implemented')
raise NotImplementedError('Output data file format not implemented')
else:
if input:
iseq, objclass, format = entryIteratorFactory(file,
@ -556,7 +608,7 @@ def open_uri(uri,
commentchar)
else: # default export is in fasta? or tab? TODO
objclass = Nuc_Seq # Nuc_Seq_Stored? TODO
iseq = FastaNucWriter(FastaFormat(printNAKeys=printna, NAString=nastring),
iseq = FastaNucWriter(FastaFormat(tags=only_keys, printNAKeys=printna, NAString=nastring),
file,
skip=skip,
only=only)
@ -565,6 +617,6 @@ def open_uri(uri,
entry_count = -1
if input:
entry_count = count_entries(file, format)
entry_count = count_entries(file, format, header)
return (file, iseq, objclass, urib, entry_count)

View File

@ -3,7 +3,7 @@
from obitools3.dms.capi.obitypes cimport obitype_t, index_t
cpdef bytes format_uniq_pattern(bytes format)
cpdef int count_entries(file, bytes format)
cpdef int count_entries(file, bytes format, bint header)
cdef obi_errno_to_exception(index_t line_nb=*, object elt_id=*, str error_message=*)
@ -18,7 +18,7 @@ cdef object clean_empty_values_from_object(object value, exclude=*)
cdef obitype_t get_obitype_single_value(object value)
cdef obitype_t update_obitype(obitype_t obitype, object new_value)
cdef obitype_t get_obitype_iterable_value(object value)
cdef obitype_t get_obitype_iterable_value(object value, type t)
cdef obitype_t get_obitype(object value)
cdef object __etag__(bytes x, bytes nastring=*)

View File

@ -9,7 +9,8 @@ from obitools3.dms.capi.obitypes cimport is_a_DNA_seq, \
OBI_QUAL, \
OBI_SEQ, \
OBI_STR, \
index_t
index_t, \
OBI_INT_MAX
from obitools3.dms.capi.obierrno cimport OBI_LINE_IDX_ERROR, \
OBI_ELT_IDX_ERROR, \
@ -39,7 +40,7 @@ cpdef bytes format_uniq_pattern(bytes format):
return None
cpdef int count_entries(file, bytes format):
cpdef int count_entries(file, bytes format, bint header):
try:
sep = format_uniq_pattern(format)
@ -74,6 +75,8 @@ cpdef int count_entries(file, bytes format):
total_count += len(re.findall(sep, mmapped_file))
if format != b"ngsfilter" and format != b"tabular" and format != b"embl" and format != b"genbank" and format != b"fastq":
total_count += 1 # adding +1 for 1st entry because separators include \n (ngsfilter and tabular already count one more because of last \n)
if format == b"tabular" and header: # not counting header as an entry
total_count -= 1
except:
if len(files) > 1:
@ -257,38 +260,51 @@ cdef obitype_t update_obitype(obitype_t obitype, object new_value) :
new_type = type(new_value)
if obitype == OBI_INT :
if new_type == float :
return OBI_FLOAT
# TODO BOOL vers INT/FLOAT
elif new_type == str or new_type == bytes :
#if new_type == NoneType: # doesn't work because Cython sucks
if new_value == None or new_type==list or new_type==dict or new_type==tuple:
return obitype
# TODO BOOL to INT/FLOAT
if new_type == str or new_type == bytes :
if obitype == OBI_SEQ and is_a_DNA_seq(tobytes(new_value)) :
pass
else :
return OBI_STR
elif obitype == OBI_INT :
if new_type == float or new_value > OBI_INT_MAX :
return OBI_FLOAT
return obitype
cdef obitype_t get_obitype_iterable_value(object value) :
cdef obitype_t get_obitype_iterable_value(object value, type t) :
cdef obitype_t value_obitype
value_obitype = OBI_VOID
for k in value :
if value_obitype == OBI_VOID :
value_obitype = get_obitype_single_value(value[k])
else :
value_obitype = update_obitype(value_obitype, value[k])
if t == dict:
for k in value :
if value_obitype == OBI_VOID :
value_obitype = get_obitype_single_value(value[k])
else :
value_obitype = update_obitype(value_obitype, value[k])
elif t == list or t == tuple:
for v in value :
if value_obitype == OBI_VOID :
value_obitype = get_obitype_single_value(v)
else :
value_obitype = update_obitype(value_obitype, v)
return value_obitype
cdef obitype_t get_obitype(object value) :
if type(value) == dict or type(value) == list or type(value) == tuple :
return get_obitype_iterable_value(value)
t = type(value)
if t == dict or t == list or t == tuple :
return get_obitype_iterable_value(value, t)
else :
return get_obitype_single_value(value)

View File

@ -1,5 +1,5 @@
major = 3
minor = 0
serial= '1b4'
serial= '1b25'
version ="%d.%d.%s" % (major,minor,serial)

View File

@ -20,8 +20,6 @@ cdef class TabWriter:
self.only = -1
else:
self.only = int(only)
if header:
self.only += 1
self.formatter = formatter
self.output = output_object

1
src/.gitignore vendored
View File

@ -3,3 +3,4 @@
/cmake_install.cmake
/libcobitools3.dylib
/Makefile
/build/

View File

@ -77,6 +77,7 @@ static inline ecotx_t* get_lca_from_merged_taxids(Obiview_p view, OBIDMS_column_
{
ecotx_t* taxon = NULL;
ecotx_t* lca = NULL;
ecotx_t* lca1 = NULL;
int32_t taxid;
index_t taxid_idx;
int64_t taxid_str_idx;
@ -108,10 +109,11 @@ static inline ecotx_t* get_lca_from_merged_taxids(Obiview_p view, OBIDMS_column_
else
{
// Compute LCA
lca1 = lca;
lca = obi_taxo_get_lca(taxon, lca);
if (lca == NULL)
{
obidebug(1, "\nError getting the last common ancestor of two taxa when building a reference database");
obidebug(1, "\nError getting the last common ancestor of two taxa when building a reference database, %d %d", taxid, lca1->taxid);
return NULL;
}
}
@ -185,7 +187,7 @@ int build_reference_db(const char* dms_name,
matrix_view_name = strcpy(matrix_view_name, o_view_name);
strcat(matrix_view_name, "_matrix");
fprintf(stderr, "Aligning queries with reference database...\n");
fprintf(stderr, "Aligning sequences...\n");
if (obi_lcs_align_one_column(dms_name,
refs_view_name,
"",
@ -863,7 +865,8 @@ int build_reference_db(const char* dms_name,
fprintf(stderr,"\rDone : 100 %% \n");
// Add information about the threshold used to build the DB
snprintf(threshold_str, 5, "%f", threshold);
#define snprintf_nowarn(...) (snprintf(__VA_ARGS__) < 0 ? abort() : (void)0)
snprintf_nowarn(threshold_str, 5, "%f", threshold);
new_comments = obi_add_comment((o_view->infos)->comments, DB_THRESHOLD_KEY_IN_COMMENTS, threshold_str);
if (new_comments == NULL)

View File

@ -77,7 +77,6 @@ Obi_ali_p kmer_similarity(Obiview_p view1, OBIDMS_column_p column1, index_t idx1
int32_t* shift_count_array;
Obi_ali_p ali = NULL;
int i, j;
bool switched_seqs;
bool reversed;
int score = 0;
Obi_blob_p blob1 = NULL;
@ -124,6 +123,8 @@ Obi_ali_p kmer_similarity(Obiview_p view1, OBIDMS_column_p column1, index_t idx1
bool keep_seq2_start;
bool keep_seq1_end;
bool keep_seq2_end;
bool left_ali;
bool rev_quals = false;
// Check kmer size
if ((kmer_size < 1) || (kmer_size > 4))
@ -148,19 +149,8 @@ Obi_ali_p kmer_similarity(Obiview_p view1, OBIDMS_column_p column1, index_t idx1
}
// Choose the shortest sequence to save kmer positions in array
switched_seqs = false;
len1 = blob1->length_decoded_value;
len2 = blob2->length_decoded_value;
if (len2 < len1)
{
switched_seqs = true;
temp_len = len1;
len1 = len2;
len2 = temp_len;
temp_blob = blob1;
blob1 = blob2;
blob2 = temp_blob;
}
// Force encoding on 2 bits by replacing ambiguous nucleotides by 'a's
if (blob1->element_size == 4)
@ -196,7 +186,47 @@ Obi_ali_p kmer_similarity(Obiview_p view1, OBIDMS_column_p column1, index_t idx1
else
reversed = false;
if (reversed)
switched_seqs = !switched_seqs;
// unreverse to make cases simpler. Costly but rare (direct match is reverse primer match)
{
if (seq2 == NULL)
seq2 = obi_blob_to_seq(blob2);
seq2 = reverse_complement_sequence(seq2);
blob2 = obi_seq_to_blob(seq2);
if (seq1 == NULL)
seq1 = obi_blob_to_seq(blob1);
seq1 = reverse_complement_sequence(seq1);
blob1 = obi_seq_to_blob(seq1);
free_blob1 = true;
// Get the quality arrays
qual1 = obi_get_qual_int_with_elt_idx_and_col_p_in_view(view1, qual_col1, idx1, 0, &qual1_len);
if (qual1 == NULL)
{
obidebug(1, "\nError getting the quality of the 1st sequence when computing the kmer similarity between two sequences");
return NULL;
}
qual2 = obi_get_qual_int_with_elt_idx_and_col_p_in_view(view2, qual_col2, idx2, 0, &qual2_len);
if (qual2 == NULL)
{
obidebug(1, "\nError getting the quality of the 2nd sequence when computing the kmer similarity between two sequences");
return NULL;
}
uint8_t* newqual1 = malloc(qual1_len*sizeof(uint8_t));
uint8_t* newqual2 = malloc(qual2_len*sizeof(uint8_t));
for (i=0;i<qual1_len;i++)
newqual1[i] = qual1[qual1_len-1-i];
for (i=0;i<qual2_len;i++)
newqual2[i] = qual2[qual2_len-1-i];
qual1 = newqual1;
qual2 = newqual2;
rev_quals = true;
}
// Save total length for the shift counts array
total_len = len1 + len2 + 1; // +1 for shift 0
@ -237,7 +267,7 @@ Obi_ali_p kmer_similarity(Obiview_p view1, OBIDMS_column_p column1, index_t idx1
return NULL;
}
}
else if (len1 >= shift_array_height)
else if (total_len >= shift_array_height)
{
shift_array_height = total_len;
*shift_array_p = (int32_t*) realloc(*shift_array_p, ARRAY_LENGTH * shift_array_height * sizeof(int32_t));
@ -291,7 +321,7 @@ Obi_ali_p kmer_similarity(Obiview_p view1, OBIDMS_column_p column1, index_t idx1
*shift_array_height_p = shift_array_height;
*shift_count_array_length_p = shift_count_array_length;
// Fill array with positions of kmers in the shortest sequence
// Fill array with positions of kmers in the first sequence
encoding = blob1->element_size;
kmer_count = len1 - kmer_size + 1;
for (kmer_idx=0; kmer_idx < kmer_count; kmer_idx++)
@ -310,7 +340,7 @@ Obi_ali_p kmer_similarity(Obiview_p view1, OBIDMS_column_p column1, index_t idx1
kmer_pos_array[(kmer*kmer_pos_array_height)+i] = kmer_idx;
}
// Compare positions of kmers between both sequences and store shifts
// Compare positions of kmers between both sequences and store shifts (a shift corresponds to pos2 - pos1)
kmer_count = blob2->length_decoded_value - kmer_size + 1;
for (kmer_idx=0; kmer_idx < kmer_count; kmer_idx++)
{
@ -374,35 +404,42 @@ Obi_ali_p kmer_similarity(Obiview_p view1, OBIDMS_column_p column1, index_t idx1
// The 873863 cases of hell
if (best_shift > 0)
{
left_ali = false;
overlap_len = len2 - best_shift;
if (len1 <= overlap_len)
{
overlap_len = len1;
if (! switched_seqs)
keep_seq2_end = true;
else
keep_seq2_start = true;
}
else if (switched_seqs)
{
keep_seq2_start = true;
keep_seq1_end = true;
keep_seq2_end = true;
}
}
else if (best_shift < 0)
{
left_ali = true;
overlap_len = len1 + best_shift;
if (!switched_seqs)
{
keep_seq1_start = true;
keep_seq2_end = true;
}
}
else
{
overlap_len = len1;
if ((!switched_seqs) && (len2 > len1))
if (len2 <= overlap_len)
{
overlap_len = len2;
keep_seq1_start = true;
}
else
{
keep_seq1_start = true;
keep_seq2_end = true;
}
}
else // if (best_shift == 0)
{
if (len2 >= len1)
{
overlap_len = len1;
keep_seq2_end = true;
left_ali = true;
}
else
{
overlap_len = len2;
left_ali = false; // discussable
}
}
ali = (Obi_ali_p) malloc(sizeof(Obi_ali_t));
@ -433,7 +470,7 @@ Obi_ali_p kmer_similarity(Obiview_p view1, OBIDMS_column_p column1, index_t idx1
ali->direction[0] = '\0';
else
{
if (((best_shift <= 0) && (!switched_seqs)) || ((best_shift > 0) && switched_seqs))
if (left_ali)
strcpy(ali->direction, "left");
else
strcpy(ali->direction, "right");
@ -442,28 +479,28 @@ Obi_ali_p kmer_similarity(Obiview_p view1, OBIDMS_column_p column1, index_t idx1
// Build the consensus sequence if asked
if (build_consensus)
{
// Get the quality arrays
qual1 = obi_get_qual_int_with_elt_idx_and_col_p_in_view(view1, qual_col1, idx1, 0, &qual1_len);
if (qual1 == NULL)
if (! rev_quals)
{
obidebug(1, "\nError getting the quality of the 1st sequence when computing the kmer similarity between two sequences");
return NULL;
}
qual2 = obi_get_qual_int_with_elt_idx_and_col_p_in_view(view2, qual_col2, idx2, 0, &qual2_len);
if (qual2 == NULL)
{
obidebug(1, "\nError getting the quality of the 2nd sequence when computing the kmer similarity between two sequences");
return NULL;
// Get the quality arrays
qual1 = obi_get_qual_int_with_elt_idx_and_col_p_in_view(view1, qual_col1, idx1, 0, &qual1_len);
if (qual1 == NULL)
{
obidebug(1, "\nError getting the quality of the 1st sequence when computing the kmer similarity between two sequences");
return NULL;
}
qual2 = obi_get_qual_int_with_elt_idx_and_col_p_in_view(view2, qual_col2, idx2, 0, &qual2_len);
if (qual2 == NULL)
{
obidebug(1, "\nError getting the quality of the 2nd sequence when computing the kmer similarity between two sequences");
return NULL;
}
}
// Decode the first sequence if not already done
if (seq1 == NULL)
seq1 = obi_blob_to_seq(blob1);
if (! switched_seqs)
consensus_len = len2 - best_shift;
else
consensus_len = len1 + best_shift;
consensus_len = len2 - best_shift;
// Allocate memory for consensus sequence
consensus_seq = (char*) malloc(consensus_len + 1 * sizeof(char)); // TODO keep malloced too maybe
@ -557,6 +594,12 @@ Obi_ali_p kmer_similarity(Obiview_p view1, OBIDMS_column_p column1, index_t idx1
free(seq2);
free(blob2);
if (rev_quals)
{
free(qual1);
free(qual2);
}
return ali;
}

View File

@ -365,8 +365,6 @@ static int print_seq(Obiview_p i_view, Obiview_p o_view,
int32_t i;
// TODO add check for primer longer than MAX_PAT_LEN (32)
// Get sequence id
seq_id = obi_get_str_with_elt_idx_and_col_p_in_view(i_view, i_id_column, i_idx, 0);
@ -645,7 +643,8 @@ static int print_seq(Obiview_p i_view, Obiview_p o_view,
int obi_ecopcr(const char* i_dms_name,
const char* i_view_name,
const char* taxonomy_name, // TODO discuss that input dms assumed
const char* tax_dms_name,
const char* taxonomy_name,
const char* o_dms_name,
const char* o_view_name,
const char* o_view_comments,
@ -678,6 +677,7 @@ int obi_ecopcr(const char* i_dms_name,
OBIDMS_p i_dms = NULL;
OBIDMS_p o_dms = NULL;
OBIDMS_p tax_dms = NULL;
OBIDMS_taxonomy_p taxonomy = NULL;
Obiview_p i_view = NULL;
Obiview_p o_view = NULL;
@ -749,6 +749,20 @@ int obi_ecopcr(const char* i_dms_name,
o1c = complementPattern(o1);
o2c = complementPattern(o2);
// check for primers equal or longer than MAX_PAT_LEN (32)
if (strlen(primer1) >= MAX_PAT_LEN)
{
obi_set_errno(OBI_ECOPCR_ERROR);
obidebug(1, "\nError: first primer is too long, needs to be < 32bp (%s)", primer1);
return -1;
}
if (strlen(primer2) >= MAX_PAT_LEN)
{
obi_set_errno(OBI_ECOPCR_ERROR);
obidebug(1, "\nError: second primer is too long, needs to be < 32bp (%s)", primer2);
return -1;
}
// Open input DMS
i_dms = obi_open_dms(i_dms_name, false);
if (i_dms == NULL)
@ -965,8 +979,16 @@ int obi_ecopcr(const char* i_dms_name,
return -1;
}
// Open taxonomy DMS
tax_dms = obi_open_dms(tax_dms_name, false);
if (tax_dms == NULL)
{
obidebug(1, "\nError opening the taxonomy DMS");
return -1;
}
// Open the taxonomy
taxonomy = obi_read_taxonomy(i_dms, taxonomy_name, false);
taxonomy = obi_read_taxonomy(tax_dms, taxonomy_name, false);
if (taxonomy == NULL)
{
obidebug(1, "\nError opening the taxonomy");

View File

@ -77,7 +77,8 @@
*
* @param i_dms_name The path to the input DMS.
* @param i_view_name The name of the input view.
* @param taxonomy_name The name of the taxonomy in the input DMS.
* @param tax_dms_name The path to the DMS containing the taxonomy.
* @param taxonomy_name The name of the taxonomy.
* @param o_dms_name The path to the output DMS.
* @param o_view_name The name of the output view.
* @param o_view_comments The comments to associate with the output view.
@ -106,6 +107,7 @@
*/
int obi_ecopcr(const char* i_dms_name,
const char* i_view_name,
const char* tax_dms_name,
const char* taxonomy_name,
const char* o_dms_name,
const char* o_view_name,

View File

@ -233,7 +233,7 @@ int obi_ecotag(const char* dms_name,
// Write result (max score, threshold, LCA assigned, list of the ids of the best matches)
index_t i, j, k;
index_t i, j, k, t;
ecotx_t* lca;
ecotx_t* lca_in_array;
ecotx_t* best_match;
@ -259,16 +259,20 @@ int obi_ecotag(const char* dms_name,
int32_t* best_match_taxids;
int32_t* best_match_taxids_to_store;
int best_match_count;
int best_match_taxid_count;
int buffer_size;
int best_match_ids_buffer_size;
index_t best_match_idx;
int32_t lca_array_length;
int32_t lca_taxid;
int32_t taxid_best_match;
int32_t taxid;
int32_t taxid_to_store;
bool assigned;
const char* lca_name;
const char* id;
int id_len;
bool already_in;
OBIDMS_p dms = NULL;
OBIDMS_p ref_dms = NULL;
@ -488,10 +492,11 @@ int obi_ecotag(const char* dms_name,
for (i=0; i < query_count; i++)
{
if (i%1000 == 0)
if (i%10 == 0)
fprintf(stderr,"\rDone : %f %% ", (i / (float) query_count)*100);
best_match_count = 0;
best_match_taxid_count = 0;
best_match_ids_length = 0;
threshold = ecotag_threshold;
best_score = 0.0;
@ -543,6 +548,7 @@ int obi_ecotag(const char* dms_name,
// Reset the array with that match
best_match_ids_length = 0;
best_match_count = 0;
best_match_taxid_count = 0;
}
// Store in best match array
@ -585,8 +591,27 @@ int obi_ecotag(const char* dms_name,
// Save match
best_match_array[best_match_count] = j;
best_match_taxids[best_match_count] = obi_get_int_with_elt_idx_and_col_p_in_view(ref_view, ref_taxid_column, j, 0);
best_match_count++;
// Save best match taxid only if not already in array
taxid_to_store = obi_get_int_with_elt_idx_and_col_p_in_view(ref_view, ref_taxid_column, j, 0);
already_in = false;
for (t=0; t<best_match_taxid_count; t++)
{
taxid = best_match_taxids[t];
//fprintf(stderr, "\ntaxid %d, taxid_to_store %d\n", taxid, taxid_to_store);
if (taxid == taxid_to_store)
{
already_in = true;
break;
}
}
if (! already_in)
{
best_match_taxids[best_match_taxid_count] = taxid_to_store;
best_match_taxid_count++;
}
strcpy(best_match_ids+best_match_ids_length, id);
best_match_ids_length = best_match_ids_length + id_len + 1;
}
@ -693,7 +718,7 @@ int obi_ecotag(const char* dms_name,
assigned_name_column, lca_name,
assigned_status_column, assigned,
best_match_ids_column, best_match_ids_to_store, best_match_ids_length,
best_match_taxids_column, best_match_taxids_to_store, best_match_count,
best_match_taxids_column, best_match_taxids_to_store, best_match_taxid_count,
score_column, best_score
) < 0)
return -1;

75
src/obi_lcs.c Executable file → Normal file
View File

@ -10,8 +10,9 @@
*/
//#define OMP_SUPPORT // TODO
#ifdef OMP_SUPPORT
#ifdef _OPENMP
#include <omp.h>
#include <pthread.h>
#endif
#include <stdlib.h>
@ -407,10 +408,15 @@ int obi_lcs_align_one_column(const char* dms_name,
int lcs_length;
int ali_length;
Kmer_table_p ktable;
Obi_blob_p blob1_mapped;
Obi_blob_p blob2_mapped;
Obi_blob_p blob1;
Obi_blob_p blob2;
Obi_blob_p blob2;
int blob1_size;
int blob2_size;
int lcs_min;
index_t seq_elt_idx;
bool stop = false;
OBIDMS_p dms = NULL;
Obiview_p seq_view = NULL;
@ -568,10 +574,16 @@ int obi_lcs_align_one_column(const char* dms_name,
seq_count = (seq_view->infos)->line_count;
#ifdef OMP_SUPPORT
omp_set_num_threads(thread_count);
#pragma omp parallel for
#endif
// #ifdef _OPENMP
// int max_threads = omp_get_max_threads();
// if ((thread_count == -1) || (thread_count > max_threads))
// thread_count = max_threads;
// omp_set_num_threads(thread_count);
// fprintf(stderr, "Running on %d thread(s)\n", thread_count);
// pthread_mutex_t mutex;
// if (pthread_mutex_init(&mutex, NULL) < 0)
// return -1;
// #endif
for (i=0; i < (seq_count - 1); i++)
{
@ -585,23 +597,45 @@ int obi_lcs_align_one_column(const char* dms_name,
id1_idx = obi_get_index_with_elt_idx_and_col_p_in_view(seq_view, id_column, i, 0); // TODO Could there be multiple IDs per line?
// Get first sequence and its index
seq1_idx = obi_get_index_with_elt_idx_and_col_p_in_view(seq_view, iseq_column, i, seq_elt_idx);
blob1 = obi_get_blob_with_elt_idx_and_col_p_in_view(seq_view, iseq_column, i, seq_elt_idx);
blob1_mapped = obi_get_blob_with_elt_idx_and_col_p_in_view(seq_view, iseq_column, i, seq_elt_idx);
if (blob1_mapped == NULL)
{
obidebug(1, "\nError retrieving sequences to align");
return -1;
}
blob1_size = obi_blob_sizeof(blob1_mapped);
blob1 = (Obi_blob_p) malloc(blob1_size);
if (blob1 == NULL)
{
obidebug(1, "\nError retrieving sequences to align");
return -1;
}
blob1 = memcpy(blob1, blob1_mapped, blob1_size);
//#pragma omp parallel shared(blob1_mapped, blob1, blob1_size, id1_idx, seq1_idx, stop, seq_count, output_view, k, ktable, \
// idx1_column, idx2_column, i, id1_column, id2_column, print_seq, seq1_column, seq2_column, \
// print_count, count1_column, count2_column, ali_length_column, lcs_length_column, score_column, reference, normalize, similarity_mode) \
// private(blob2_mapped, blob2, blob2_size, j, id2_idx, seq2_idx, count2, count1, score, ali_length, lcs_length)
//{
// #pragma omp for schedule(dynamic, seq_count/thread_count + (seq_count % thread_count != 0)) // Avoid 0 which blocks the program
for (j=i+1; j < seq_count; j++)
{
// Get second sequence and its index
seq2_idx = obi_get_index_with_elt_idx_and_col_p_in_view(seq_view, iseq_column, j, seq_elt_idx);
blob2 = obi_get_blob_with_elt_idx_and_col_p_in_view(seq_view, iseq_column, j, seq_elt_idx);
blob2_mapped = obi_get_blob_with_elt_idx_and_col_p_in_view(seq_view, iseq_column, j, seq_elt_idx);
if (blob2_mapped == NULL)
{
obidebug(1, "\nError retrieving sequences to align");
stop = true;
}
blob2_size = obi_blob_sizeof(blob2_mapped);
blob2 = (Obi_blob_p) malloc(blob2_size);
if (blob2 == NULL)
{
obidebug(1, "\nError retrieving sequences to align");
return -1;
stop = true;
}
blob2 = memcpy(blob2, blob2_mapped, blob2_size);
// Check if the sequences are identical in a quick way (same index in the same indexer)
if (obi_get_index_with_elt_idx_and_col_p_in_view(seq_view, iseq_column, i, seq_elt_idx) == obi_get_index_with_elt_idx_and_col_p_in_view(seq_view, iseq_column, j, seq_elt_idx))
@ -624,6 +658,8 @@ int obi_lcs_align_one_column(const char* dms_name,
score = obiblob_sse_banded_lcs_align(blob1, blob2, threshold, normalize, reference, similarity_mode, &lcs_length, &ali_length);
}
free(blob2);
if ((score >= 0) && (((normalize || similarity_mode) && (score >= threshold)) || ((!similarity_mode && !normalize) && (score <= threshold))))
{ // Print result
@ -637,6 +673,10 @@ int obi_lcs_align_one_column(const char* dms_name,
count2 = obi_get_int_with_elt_idx_and_col_p_in_view(seq_view, i_count_column, j, 0);
}
// #ifdef _OPENMP
// if (pthread_mutex_lock(&mutex) < 0)
// stop = true;
// #endif
if (print_alignment_result(output_view, k,
idx1_column, idx2_column, i, j,
id1_column, id2_column, id1_idx, id2_idx,
@ -646,15 +686,24 @@ int obi_lcs_align_one_column(const char* dms_name,
lcs_length_column, lcs_length,
score_column, score,
reference, normalize, similarity_mode) < 0)
return -1;
stop = true;
// #ifdef _OPENMP
// if (pthread_mutex_unlock(&mutex) < 0)
// stop = true;
// #endif
k++;
}
}
//}
free(blob1);
}
fprintf(stderr,"\rDone : 100 %% \n");
//fprintf(stderr,"\nstop=%d\n", stop);
// Close views
if (obi_save_and_close_view(seq_view) < 0)
{
@ -675,6 +724,11 @@ int obi_lcs_align_one_column(const char* dms_name,
free_kmer_tables(ktable, seq_count);
// #ifdef _OPENMP
// if (pthread_mutex_destroy(&mutex) < 0)
// return -1;
// #endif
return 0;
}
@ -1087,4 +1141,3 @@ int obi_lcs_align_two_columns(const char* dms_name,
return 0;
}

View File

@ -1417,7 +1417,7 @@ char* obi_dms_formatted_infos(OBIDMS_p dms, bool detailed)
char* view_name = NULL;
char* tax_name = NULL;
char* all_tax_dir_path = NULL;
int i;
int i, last_dot_pos;
struct dirent* dp;
Obiview_p view;
@ -1439,17 +1439,21 @@ char* obi_dms_formatted_infos(OBIDMS_p dms, bool detailed)
if ((dp->d_name)[0] == '.')
continue;
i=0;
while ((dp->d_name)[i] != '.')
while (i < strlen(dp->d_name))
{
if ((dp->d_name)[i] == '.')
last_dot_pos = i;
i++;
view_name = (char*) malloc((i+1) * sizeof(char));
}
view_name = (char*) malloc((last_dot_pos+1) * sizeof(char));
if (view_name == NULL)
{
obi_set_errno(OBI_MALLOC_ERROR);
obidebug(1, "\nError allocating memory for a view name when getting formatted DMS infos: file %s", dp->d_name);
return NULL;
}
strncpy(view_name, dp->d_name, i);
view_name[i] = '\0';
strncpy(view_name, dp->d_name, last_dot_pos);
view_name[last_dot_pos] = '\0';
view = obi_open_view(dms, view_name);
if (view == NULL)
{

View File

@ -873,7 +873,7 @@ static ecotxidx_t* read_taxonomy_idx(const char* taxa_file_name, const char* loc
taxa_index->buffer_size = taxa_index->count;
taxa_index->max_taxid = 0;
printf("Reading %d taxa...\n", count_taxa);
fprintf(stderr, "Reading %d taxa...\n", count_taxa);
for (i=0; i<count_taxa; i++)
{
readnext_ecotaxon(f_taxa, &(taxa_index->taxon[i]));
@ -886,9 +886,9 @@ static ecotxidx_t* read_taxonomy_idx(const char* taxa_file_name, const char* loc
}
if (count_local_taxa > 0)
printf("Reading %d local taxa...\n", count_local_taxa);
fprintf(stderr, "Reading %d local taxa...\n", count_local_taxa);
else
printf("No local taxa\n");
fprintf(stderr, "No local taxa\n");
count_taxa = taxa_index->count;
@ -1092,7 +1092,7 @@ static int write_ranks_idx(OBIDMS_p dms, OBIDMS_taxonomy_p tax, const char* taxo
free(taxonomy_path);
// Create file
file_descriptor = open(file_name, O_RDWR | O_CREAT | O_EXCL, 0777);
file_descriptor = open(file_name, O_RDWR | O_CREAT, 0777);
if (file_descriptor < 0)
{
obi_set_errno(OBI_TAXONOMY_ERROR);
@ -1196,7 +1196,7 @@ static int write_taxonomy_idx(OBIDMS_p dms, OBIDMS_taxonomy_p tax, const char* t
free(taxonomy_path);
// Create file
file_descriptor = open(file_name, O_RDWR | O_CREAT | O_EXCL, 0777);
file_descriptor = open(file_name, O_RDWR | O_CREAT, 0777);
if (file_descriptor < 0)
{
obi_set_errno(OBI_TAXONOMY_ERROR);
@ -1472,7 +1472,7 @@ static int write_names_idx(OBIDMS_p dms, OBIDMS_taxonomy_p tax, const char* taxo
free(taxonomy_path);
// Create file
file_descriptor = open(file_name, O_RDWR | O_CREAT | O_EXCL, 0777);
file_descriptor = open(file_name, O_RDWR | O_CREAT, 0777);
if (file_descriptor < 0)
{
obi_set_errno(OBI_TAXONOMY_ERROR);
@ -1760,7 +1760,7 @@ static int write_merged_idx(OBIDMS_p dms, OBIDMS_taxonomy_p tax, const char* tax
free(taxonomy_path);
// Create file
file_descriptor = open(file_name, O_RDWR | O_CREAT | O_EXCL, 0777);
file_descriptor = open(file_name, O_RDWR | O_CREAT, 0777);
if (file_descriptor < 0)
{
obi_set_errno(OBI_TAXONOMY_ERROR);
@ -2463,6 +2463,32 @@ int read_merged_dmp(const char* taxdump, OBIDMS_taxonomy_p tax, int32_t* delnode
return -1;
}
// Write the rest of the taxa from the current taxa list
while (nT < (tax->taxa)->count)
{
// Add element from taxa list
// Enlarge structure if needed
if (n == buffer_size)
{
buffer_size = buffer_size * 2;
tax->merged_idx = (ecomergedidx_t*) realloc(tax->merged_idx, sizeof(ecomergedidx_t) + sizeof(ecomerged_t) * buffer_size);
if (tax->merged_idx == NULL)
{
obi_set_errno(OBI_MALLOC_ERROR);
obidebug(1, "\nError reallocating memory for a taxonomy structure");
closedir(tax_dir);
fclose(file);
return -1;
}
}
(tax->merged_idx)->merged[n].taxid = (tax->taxa)->taxon[nT].taxid;
(tax->merged_idx)->merged[n].idx = nT;
nT++;
n++;
}
// Store count
(tax->merged_idx)->count = n;
@ -3224,47 +3250,48 @@ OBIDMS_taxonomy_p obi_read_taxonomy(OBIDMS_p dms, const char* taxonomy_name, boo
}
int obi_write_taxonomy(OBIDMS_p dms, OBIDMS_taxonomy_p tax, const char* tax_name)
int obi_write_taxonomy(OBIDMS_p dms, OBIDMS_taxonomy_p tax, const char* tax_name, bool update)
{
char* taxonomy_path;
// Build the taxonomy directory path
taxonomy_path = get_taxonomy_path(dms, tax_name);
if (taxonomy_path == NULL)
return -1;
// Try to create the directory
if (mkdir(taxonomy_path, 00777) < 0)
{
if (errno == EEXIST)
obidebug(1, "\nA taxonomy already exists with this name.");
obidebug(1, "\nProblem creating a new taxonomy directory");
if (!update) {
// Build the taxonomy directory path
taxonomy_path = get_taxonomy_path(dms, tax_name);
if (taxonomy_path == NULL)
return -1;
// Try to create the directory
if (mkdir(taxonomy_path, 00777) < 0)
{
if (errno == EEXIST)
obidebug(1, "\nA taxonomy already exists with this name.");
obidebug(1, "\nProblem creating a new taxonomy directory");
free(taxonomy_path);
return -1;
}
free(taxonomy_path);
return -1;
}
free(taxonomy_path);
if (write_ranks_idx(dms, tax, tax_name) < 0)
return -1;
if (write_taxonomy_idx(dms, tax, tax_name) < 0)
return -1;
if (write_names_idx(dms, tax, tax_name) < 0)
return -1;
if (write_merged_idx(dms, tax, tax_name) < 0)
return -1;
// Check if there are local taxa (if so last taxon is local)
if (write_ranks_idx(dms, tax, tax_name) < 0)
return -1;
if (write_taxonomy_idx(dms, tax, tax_name) < 0)
return -1;
if (write_names_idx(dms, tax, tax_name) < 0)
return -1;
if (write_merged_idx(dms, tax, tax_name) < 0)
return -1;
// Write preferred names if there are some
if (tax->preferred_names != NULL)
{
if (write_preferred_names_idx(dms, tax, tax_name) < 0)
return -1;
}
// Write local taxa if there are some
if ((tax->taxa)->local_count > 0)
{
if (write_local_taxonomy_idx(dms, tax, tax_name) < 0)
return -1;
}
// Write preferred names if there are some
if (tax->preferred_names != NULL)
{
if (write_preferred_names_idx(dms, tax, tax_name) < 0)
return -1;
}
return 0;
}
@ -3276,16 +3303,17 @@ int obi_close_taxonomy(OBIDMS_taxonomy_p taxonomy)
if (taxonomy)
{
// Update local informations (local taxa and preferred names) if there are any
if ((taxonomy->taxa)->local_count > 0)
{
if (taxonomy->dms == NULL)
{
obi_set_errno(OBI_TAXONOMY_ERROR);
obidebug(1, "\nError closing a taxonomy with local files but no DMS associated (probably read directly from taxdump)"); // TODO discuss
}
if (write_local_taxonomy_idx(taxonomy->dms, taxonomy, taxonomy->tax_name) < 0)
return -1;
}
// Done with write_taxo, edits all needed files. Only ldx file was edited in OBI1 but it led to issues. Discussable
// if ((taxonomy->taxa)->local_count > 0)
// {
// if (taxonomy->dms == NULL)
// {
// obi_set_errno(OBI_TAXONOMY_ERROR);
// obidebug(1, "\nError closing a taxonomy with local files but no DMS associated (probably read directly from taxdump)"); // TODO discuss
// }
// if (write_local_taxonomy_idx(taxonomy->dms, taxonomy, taxonomy->tax_name) < 0)
// return -1;
// }
// Write preferred names if there are some
if (taxonomy->preferred_names)
@ -3351,9 +3379,10 @@ int obi_close_taxonomy(OBIDMS_taxonomy_p taxonomy)
int obi_taxo_add_local_taxon(OBIDMS_taxonomy_p tax, const char* name, const char* rank_name, int32_t parent_taxid, int32_t min_taxid)
{
int32_t taxid;
int32_t count;
ecotx_t* taxon;
int i;
// econame_t* name_struct;
econame_t* name_struct;
// Enlarge the structure memory for a new taxon
tax->taxa = (ecotxidx_t*) realloc(tax->taxa, sizeof(ecotxidx_t) + sizeof(ecotx_t) * (((tax->taxa)->count) + 1));
@ -3415,42 +3444,65 @@ int obi_taxo_add_local_taxon(OBIDMS_taxonomy_p tax, const char* name, const char
((tax->taxa)->local_count)++;
(tax->taxa)->buffer_size = (tax->taxa)->count;
// // Add new name in names structure // Commented because the new name was not added in the .ndx file in the OBITools1
// // Allocate memory for new name
// tax->names = (econameidx_t*) realloc(tax->names, sizeof(econameidx_t) + sizeof(econame_t) * ((tax->names)->count + 1));
// if (tax->names == NULL)
// {
// obi_set_errno(OBI_MALLOC_ERROR);
// obidebug(1, "\nError reallocating memory for a taxonomy structure to add a new taxon");
// return -1;
// }
//
// // Add new name
// name_struct = (tax->names)->names + ((tax->names)->count);
// name_struct->name = (char*) malloc((strlen(name) + 1) * sizeof(char));
// if (name_struct->name == NULL)
// {
// obi_set_errno(OBI_MALLOC_ERROR);
// obidebug(1, "\nError allocating memory for a taxon name to add a new taxon");
// return -1;
// }
// strcpy(name_struct->name, name);
// name_struct->class_name = (char*) malloc((strlen("scientific name") + 1) * sizeof(char));
// if (name_struct->class_name == NULL)
// {
// obi_set_errno(OBI_MALLOC_ERROR);
// obidebug(1, "\nError allocating memory for a taxon class name to add a new taxon");
// return -1;
// }
// strcpy(name_struct->class_name, "scientific name");
// name_struct->is_scientific_name = true;
// name_struct->taxon = ((tax->taxa)->taxon) + ((tax->taxa)->count) - 1;
//
// // Sort names in alphabetical order
// qsort((tax->names)->names, (tax->names)->count, sizeof(econame_t), cmp_names);
//
// // Update name count
// ((tax->names)->count)++;
// Add new name in names structure // On the OBI1, the new name was not added in the .ndx file but it could create issues
// Allocate memory for new name
tax->names = (econameidx_t*) realloc(tax->names, sizeof(econameidx_t) + sizeof(econame_t) * ((tax->names)->count + 1));
if (tax->names == NULL)
{
obi_set_errno(OBI_MALLOC_ERROR);
obidebug(1, "\nError reallocating memory for a taxonomy structure to add a new taxon");
return -1;
}
// Add new name
name_struct = (tax->names)->names + ((tax->names)->count);
name_struct->name = (char*) malloc((strlen(name) + 1) * sizeof(char));
if (name_struct->name == NULL)
{
obi_set_errno(OBI_MALLOC_ERROR);
obidebug(1, "\nError allocating memory for a taxon name to add a new taxon");
return -1;
}
strcpy(name_struct->name, name);
name_struct->class_name = (char*) malloc((strlen("scientific name") + 1) * sizeof(char));
if (name_struct->class_name == NULL)
{
obi_set_errno(OBI_MALLOC_ERROR);
obidebug(1, "\nError allocating memory for a taxon class name to add a new taxon");
return -1;
}
strcpy(name_struct->class_name, "scientific name");
name_struct->is_scientific_name = true;
name_struct->taxon = ((tax->taxa)->taxon) + ((tax->taxa)->count) - 1;
// Update name count
((tax->names)->count)++;
// Sort names in alphabetical order
qsort((tax->names)->names, (tax->names)->count, sizeof(econame_t), cmp_names);
// Add to merged index
tax->merged_idx = (ecomergedidx_t*) realloc(tax->merged_idx, sizeof(ecomergedidx_t) + sizeof(ecomerged_t) * ((tax->merged_idx)->count + 1));
if (tax->merged_idx == NULL)
{
obi_set_errno(OBI_MALLOC_ERROR);
obidebug(1, "\nError reallocating memory for a taxonomy structure");
return -1;
}
count = (tax->merged_idx)->count;
(tax->merged_idx)->count = count + 1;
(tax->merged_idx)->merged[count].taxid = taxid;
(tax->merged_idx)->merged[count].idx = taxon->idx;
//fprintf(stderr, "\nEntered in merged taxon.idx=%d", (tax->merged_idx)->merged[(tax->merged_idx)->count -1].idx);
//fprintf(stderr, "\nEntered in merged taxon.taxid=%d", (tax->merged_idx)->merged[(tax->merged_idx)->count -1].taxid);
//fprintf(stderr, "\nEntered in merged at %d", (tax->merged_idx)->count -1);
//taxon = obi_taxo_get_taxon_with_taxid(tax, taxid);
//fprintf(stderr, "\ntaxon=%x", taxon);
//fprintf(stderr, "\ntaxon.taxid=%d", taxon->taxid);
//fprintf(stderr, "\ntaxon.name=%s", taxon->name);
//fprintf(stderr, "\ntaxon.idx=%d\n\n", ((tax->merged_idx)->count));
return taxid;
}
@ -3521,11 +3573,12 @@ int obi_taxo_add_preferred_name_with_taxon(OBIDMS_taxonomy_p tax, ecotx_t* taxon
name_struct->is_scientific_name = false;
name_struct->taxon = taxon;
// Update preferred name count
((tax->preferred_names)->count)++;
// Sort preferred names in alphabetical order
qsort((tax->preferred_names)->names, (tax->preferred_names)->count, sizeof(econame_t), cmp_names);
// Update preferred name count
((tax->preferred_names)->count)++;
return 0;
}
@ -3643,8 +3696,10 @@ ecotx_t* obi_taxo_get_taxon_with_taxid(OBIDMS_taxonomy_p taxonomy, int32_t taxid
else if (indexed_taxon->idx == -1)
current_taxon = NULL; // TODO discuss what to do when old deleted taxon
else
{
current_taxon = (taxonomy->taxa->taxon)+(indexed_taxon->idx);
//fprintf(stderr, "\n>>>idx %d, taxid %d<<<\n", indexed_taxon->idx, indexed_taxon->taxid);
}
return current_taxon;
}

View File

@ -75,7 +75,7 @@ typedef struct {
*/
int32_t max_taxid; /**< Maximum taxid existing in the taxon index.
*/
int32_t buffer_size; /**< Number of taxa. // TODO kept this but not sure of its use
int32_t buffer_size; /**< . // TODO kept this but not sure of its use
*/
ecotx_t taxon[]; /**< Taxon array.
*/
@ -239,6 +239,7 @@ OBIDMS_taxonomy_p obi_read_taxonomy(OBIDMS_p dms, const char* taxonomy_name, boo
* @param dms A pointer on the DMS to which the taxonomy belongs.
* @param tax A pointer on the taxonomy structure.
* @param tax_name The name (prefix) of the taxonomy.
* @param update Whether files should be rewritten or if it's a new taxonomy (set to true e.g. after adding local taxa).
*
* @returns An integer value indicating the success of the operation.
* @retval 0 on success.
@ -247,7 +248,7 @@ OBIDMS_taxonomy_p obi_read_taxonomy(OBIDMS_p dms, const char* taxonomy_name, boo
* @since 2016
* @author Celine Mercier (celine.mercier@metabarcoding.org)
*/
int obi_write_taxonomy(OBIDMS_p dms, OBIDMS_taxonomy_p tax, const char* tax_name);
int obi_write_taxonomy(OBIDMS_p dms, OBIDMS_taxonomy_p tax, const char* tax_name, bool update);
/**

View File

@ -36,7 +36,7 @@
*/
#define COLUMN_GROWTH_FACTOR (2) /**< The growth factor when a column is enlarged.
*/
#define MAXIMUM_LINE_COUNT (1000000000) /**< The maximum line count for the data of a column (1E9). //TODO
#define MAXIMUM_LINE_COUNT (1000000000000) /**< The maximum line count for the data of a column (1E12). //TODO
*/
#define COMMENTS_MAX_LENGTH (4096) /**< The maximum length for comments.
*/

View File

@ -29,6 +29,8 @@
#define OBIQual_int_NA (NULL) /**< NA value for the type OBI_QUAL if the quality is in integer format */
#define OBITuple_NA (NULL) /**< NA value for tuples of any type */
#define OBI_INT_MAX (INT32_MAX) /**< Maximum value for the type OBI_INT */
/**
* @brief enum for the boolean OBIType.

View File

@ -2910,7 +2910,7 @@ int obi_clean_unfinished_views(OBIDMS_p dms)
if ((dp->d_name)[0] == '.')
continue;
i=0;
while ((dp->d_name)[i] != '.')
while (strncmp((dp->d_name)+i, ".obiview", 8))
i++;
relative_path = (char*) malloc(strlen(VIEW_DIR_NAME) + strlen(dp->d_name) + 2);
strcpy(relative_path, VIEW_DIR_NAME);