2017-07-05 17:15:23 +02:00
|
|
|
#cython: language_level=3
|
2016-08-16 15:17:26 +02:00
|
|
|
|
2017-07-28 12:41:28 +02:00
|
|
|
import sys
|
2018-10-07 19:10:34 +02:00
|
|
|
import os
|
2017-07-28 12:41:28 +02:00
|
|
|
|
2017-07-05 17:15:23 +02:00
|
|
|
from obitools3.apps.progress cimport ProgressBar # @UnresolvedImport
|
|
|
|
from obitools3.dms.view.view cimport View
|
2019-03-15 16:06:06 +01:00
|
|
|
from obitools3.dms.view import RollbackException
|
2017-08-20 17:58:36 +02:00
|
|
|
from obitools3.dms.view.typed_view.view_NUC_SEQS cimport View_NUC_SEQS
|
2017-07-05 17:15:23 +02:00
|
|
|
from obitools3.dms.column.column cimport Column
|
2017-08-20 17:58:36 +02:00
|
|
|
from obitools3.dms.obiseq cimport Nuc_Seq
|
2017-10-16 11:09:55 +02:00
|
|
|
from obitools3.dms import DMS
|
2018-03-21 16:35:44 +01:00
|
|
|
from obitools3.dms.taxo.taxo cimport Taxonomy
|
|
|
|
|
2017-07-28 16:33:19 +02:00
|
|
|
|
2017-07-05 17:15:23 +02:00
|
|
|
from obitools3.utils cimport tobytes, \
|
|
|
|
get_obitype, \
|
|
|
|
update_obitype
|
|
|
|
|
2019-03-15 11:39:21 +01:00
|
|
|
from obitools3.dms.capi.obiview cimport VIEW_TYPE_NUC_SEQS, \
|
|
|
|
NUC_SEQUENCE_COLUMN, \
|
|
|
|
ID_COLUMN, \
|
|
|
|
DEFINITION_COLUMN, \
|
|
|
|
QUALITY_COLUMN, \
|
|
|
|
COUNT_COLUMN, \
|
|
|
|
TAXID_COLUMN
|
|
|
|
|
2017-07-05 17:15:23 +02:00
|
|
|
from obitools3.dms.capi.obitypes cimport obitype_t, \
|
2017-12-19 11:07:00 +01:00
|
|
|
OBI_VOID, \
|
|
|
|
OBI_QUAL
|
2017-07-05 17:15:23 +02:00
|
|
|
|
|
|
|
from obitools3.dms.capi.obierrno cimport obi_errno
|
|
|
|
|
2018-10-17 11:19:48 +02:00
|
|
|
from obitools3.apps.optiongroups import addImportInputOption, \
|
2018-03-21 16:35:44 +01:00
|
|
|
addTabularInputOption, \
|
2018-10-17 11:19:48 +02:00
|
|
|
addTaxdumpInputOption, \
|
|
|
|
addMinimalOutputOption
|
2017-08-20 17:58:36 +02:00
|
|
|
|
2017-07-28 12:41:28 +02:00
|
|
|
from obitools3.uri.decode import open_uri
|
2017-07-05 17:15:23 +02:00
|
|
|
|
2017-07-28 16:33:19 +02:00
|
|
|
from obitools3.apps.config import logger
|
|
|
|
|
2017-07-05 17:15:23 +02:00
|
|
|
__title__="Imports sequences from different formats into a DMS"
|
|
|
|
|
|
|
|
|
|
|
|
default_config = { 'destview' : None,
|
|
|
|
'skip' : 0,
|
|
|
|
'only' : None,
|
|
|
|
'skiperror' : False,
|
|
|
|
'seqinformat' : None,
|
|
|
|
'moltype' : 'nuc',
|
2017-07-28 12:41:28 +02:00
|
|
|
'source' : None
|
2017-07-05 17:15:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
def addOptions(parser):
|
2017-07-28 12:41:28 +02:00
|
|
|
|
2018-10-17 11:19:48 +02:00
|
|
|
addImportInputOption(parser)
|
2018-03-12 18:10:43 +01:00
|
|
|
addTabularInputOption(parser)
|
2018-03-21 16:35:44 +01:00
|
|
|
addTaxdumpInputOption(parser)
|
2018-10-17 11:19:48 +02:00
|
|
|
addMinimalOutputOption(parser)
|
2017-07-11 12:10:33 +02:00
|
|
|
|
2017-07-05 17:15:23 +02:00
|
|
|
|
2016-04-15 17:00:08 +02:00
|
|
|
def run(config):
|
2017-07-05 17:15:23 +02:00
|
|
|
|
2017-08-20 17:58:36 +02:00
|
|
|
cdef tuple input
|
|
|
|
cdef tuple output
|
2017-07-05 17:15:23 +02:00
|
|
|
cdef int i
|
|
|
|
cdef type value_type
|
|
|
|
cdef obitype_t value_obitype
|
|
|
|
cdef obitype_t old_type
|
|
|
|
cdef obitype_t new_type
|
|
|
|
cdef bint get_quality
|
|
|
|
cdef bint NUC_SEQS_view
|
|
|
|
cdef int nb_elts
|
|
|
|
cdef object d
|
|
|
|
cdef View view
|
2018-03-12 18:10:43 +01:00
|
|
|
cdef object entries
|
|
|
|
cdef object entry
|
2017-07-05 17:15:23 +02:00
|
|
|
cdef Column id_col
|
|
|
|
cdef Column def_col
|
|
|
|
cdef Column seq_col
|
|
|
|
cdef Column qual_col
|
|
|
|
cdef Column old_column
|
|
|
|
cdef bint rewrite
|
|
|
|
cdef dict dcols
|
|
|
|
cdef int skipping
|
2017-08-20 17:58:36 +02:00
|
|
|
cdef bytes tag
|
2017-07-05 17:15:23 +02:00
|
|
|
cdef object value
|
|
|
|
cdef list elt_names
|
|
|
|
cdef int old_nb_elements_per_line
|
|
|
|
cdef int new_nb_elements_per_line
|
|
|
|
cdef list old_elements_names
|
|
|
|
cdef list new_elements_names
|
|
|
|
cdef ProgressBar pb
|
|
|
|
global obi_errno
|
2017-07-28 16:33:19 +02:00
|
|
|
|
2017-10-16 11:09:55 +02:00
|
|
|
DMS.obi_atexit()
|
2017-07-05 17:15:23 +02:00
|
|
|
|
2019-03-13 18:35:32 +01:00
|
|
|
logger("info", "obi import: imports an object (file(s), obiview, taxonomy...) into a DMS")
|
|
|
|
|
|
|
|
entry_count = -1
|
2018-03-21 16:35:44 +01:00
|
|
|
|
2018-10-07 19:10:34 +02:00
|
|
|
if not config['obi']['taxdump']:
|
2018-07-28 17:03:00 +02:00
|
|
|
input = open_uri(config['obi']['inputURI'])
|
|
|
|
if input is None: # TODO check for bytes instead now?
|
|
|
|
raise Exception("Could not open input URI")
|
2019-03-13 18:35:32 +01:00
|
|
|
|
|
|
|
entry_count = input[4]
|
|
|
|
logger("info", "Importing %d entries", entry_count)
|
|
|
|
|
2019-03-15 11:39:21 +01:00
|
|
|
# TODO a bit dirty?
|
2018-07-28 17:03:00 +02:00
|
|
|
if input[2]==Nuc_Seq:
|
|
|
|
v = View_NUC_SEQS
|
|
|
|
else:
|
|
|
|
v = View
|
|
|
|
else:
|
|
|
|
v = None
|
|
|
|
|
2017-07-28 16:33:19 +02:00
|
|
|
output = open_uri(config['obi']['outputURI'],
|
|
|
|
input=False,
|
|
|
|
newviewtype=v)
|
2017-12-19 11:07:00 +01:00
|
|
|
if output is None:
|
|
|
|
raise Exception("Could not create output view")
|
2018-10-07 19:10:34 +02:00
|
|
|
|
2018-07-28 17:03:00 +02:00
|
|
|
# Read taxdump
|
|
|
|
if config['obi']['taxdump']: # The input is a taxdump to import in a DMS
|
|
|
|
taxo = Taxonomy.open_taxdump(output[0], config['obi']['inputURI'])
|
|
|
|
taxo.write(output[1])
|
|
|
|
taxo.close()
|
2018-10-07 19:10:34 +02:00
|
|
|
output[0].record_command_line(" ".join(sys.argv[1:]))
|
2018-07-28 17:03:00 +02:00
|
|
|
output[0].close()
|
|
|
|
return
|
2017-07-28 16:33:19 +02:00
|
|
|
|
2019-03-13 18:35:32 +01:00
|
|
|
pb = ProgressBar(entry_count, config, seconde=5)
|
2017-07-28 12:41:28 +02:00
|
|
|
|
2018-03-12 18:10:43 +01:00
|
|
|
entries = input[1]
|
2018-10-17 16:41:15 +02:00
|
|
|
|
2017-08-20 17:58:36 +02:00
|
|
|
NUC_SEQS_view = False
|
|
|
|
if isinstance(output[1], View) :
|
|
|
|
view = output[1]
|
|
|
|
if output[2] == View_NUC_SEQS :
|
|
|
|
NUC_SEQS_view = True
|
|
|
|
else:
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
# Save basic columns in variables for optimization
|
2018-10-07 19:10:34 +02:00
|
|
|
if NUC_SEQS_view :
|
2019-03-15 11:39:21 +01:00
|
|
|
id_col = view[ID_COLUMN]
|
|
|
|
def_col = view[DEFINITION_COLUMN]
|
|
|
|
seq_col = view[NUC_SEQUENCE_COLUMN]
|
2018-11-19 11:23:39 +01:00
|
|
|
|
2017-08-20 17:58:36 +02:00
|
|
|
dcols = {}
|
2018-11-19 11:23:39 +01:00
|
|
|
|
2017-08-20 17:58:36 +02:00
|
|
|
i = 0
|
2018-03-12 18:10:43 +01:00
|
|
|
for entry in entries :
|
2018-10-07 19:10:34 +02:00
|
|
|
|
2019-03-15 16:06:06 +01:00
|
|
|
if entry is None: # error or exception handled at lower level, not raised because Python generators can't resume after any exception is raised
|
|
|
|
if config['obi']['skiperror']:
|
|
|
|
i-=1
|
|
|
|
continue
|
|
|
|
else:
|
|
|
|
raise RollbackException("obi import error, rollbacking view", view)
|
|
|
|
|
2017-08-20 17:58:36 +02:00
|
|
|
pb(i)
|
2018-11-19 11:23:39 +01:00
|
|
|
|
|
|
|
if NUC_SEQS_view:
|
2018-03-12 18:10:43 +01:00
|
|
|
id_col[i] = entry.id
|
|
|
|
def_col[i] = entry.definition
|
|
|
|
seq_col[i] = entry.seq
|
2018-12-11 19:33:55 +01:00
|
|
|
# Check if there is a sequencing quality associated by checking the first entry # TODO haven't found a more robust solution yet
|
|
|
|
if i == 0:
|
2019-03-15 11:39:21 +01:00
|
|
|
get_quality = QUALITY_COLUMN in entry
|
2018-12-11 19:33:55 +01:00
|
|
|
if get_quality:
|
2019-03-15 11:39:21 +01:00
|
|
|
Column.new_column(view, QUALITY_COLUMN, OBI_QUAL)
|
|
|
|
qual_col = view[QUALITY_COLUMN]
|
2018-12-11 19:33:55 +01:00
|
|
|
if get_quality:
|
2018-03-12 18:10:43 +01:00
|
|
|
qual_col[i] = entry.quality
|
2017-08-20 17:58:36 +02:00
|
|
|
|
2018-03-12 18:10:43 +01:00
|
|
|
for tag in entry :
|
2017-08-20 17:58:36 +02:00
|
|
|
|
2019-03-15 11:39:21 +01:00
|
|
|
if tag != ID_COLUMN and tag != DEFINITION_COLUMN and tag != NUC_SEQUENCE_COLUMN and tag != QUALITY_COLUMN : # TODO dirty
|
2017-08-20 17:58:36 +02:00
|
|
|
|
2018-03-12 18:10:43 +01:00
|
|
|
value = entry[tag]
|
2018-07-28 17:03:00 +02:00
|
|
|
if tag == b"taxid":
|
2019-03-15 11:39:21 +01:00
|
|
|
tag = TAXID_COLUMN
|
|
|
|
if tag == b"count":
|
|
|
|
tag = COUNT_COLUMN
|
|
|
|
|
2017-08-20 17:58:36 +02:00
|
|
|
if tag not in dcols :
|
|
|
|
|
|
|
|
value_type = type(value)
|
|
|
|
nb_elts = 1
|
|
|
|
value_obitype = OBI_VOID
|
|
|
|
|
|
|
|
if value_type == dict or value_type == list :
|
|
|
|
nb_elts = len(value)
|
|
|
|
elt_names = list(value)
|
|
|
|
else :
|
|
|
|
nb_elts = 1
|
|
|
|
elt_names = None
|
|
|
|
|
|
|
|
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), value_obitype)
|
|
|
|
|
|
|
|
# Fill value
|
|
|
|
dcols[tag][0][i] = value
|
|
|
|
|
|
|
|
# TODO else log error?
|
|
|
|
|
|
|
|
else :
|
|
|
|
|
|
|
|
rewrite = False
|
|
|
|
|
|
|
|
# Check type adequation
|
|
|
|
old_type = dcols[tag][1]
|
|
|
|
new_type = OBI_VOID
|
|
|
|
new_type = update_obitype(old_type, value)
|
|
|
|
if old_type != new_type :
|
|
|
|
rewrite = True
|
|
|
|
|
|
|
|
try:
|
|
|
|
# Fill value
|
|
|
|
dcols[tag][0][i] = value
|
|
|
|
|
|
|
|
except IndexError :
|
|
|
|
|
|
|
|
value_type = type(value)
|
|
|
|
old_column = dcols[tag][0]
|
|
|
|
old_nb_elements_per_line = old_column.nb_elements_per_line
|
|
|
|
new_nb_elements_per_line = 0
|
|
|
|
old_elements_names = old_column.elements_names
|
|
|
|
new_elements_names = None
|
|
|
|
|
|
|
|
#####################################################################
|
|
|
|
|
|
|
|
# Check the length and keys of column lines if needed
|
|
|
|
if value_type == dict : # Check dictionary keys
|
|
|
|
for k in value :
|
|
|
|
if k not in old_elements_names :
|
|
|
|
new_elements_names = list(set(old_elements_names+[tobytes(k) for k in value]))
|
|
|
|
rewrite = True
|
|
|
|
break
|
|
|
|
|
|
|
|
elif value_type == list or value_type == tuple : # Check vector length
|
|
|
|
if old_nb_elements_per_line < len(value) :
|
|
|
|
new_nb_elements_per_line = len(value)
|
|
|
|
rewrite = True
|
|
|
|
|
|
|
|
#####################################################################
|
|
|
|
|
|
|
|
if rewrite :
|
|
|
|
if new_nb_elements_per_line == 0 and new_elements_names is not None :
|
|
|
|
new_nb_elements_per_line = len(new_elements_names)
|
|
|
|
|
|
|
|
# Reset obierrno
|
|
|
|
obi_errno = 0
|
|
|
|
|
|
|
|
dcols[tag] = (view.rewrite_column_with_diff_attributes(old_column.name,
|
|
|
|
new_data_type=new_type,
|
|
|
|
new_nb_elements_per_line=new_nb_elements_per_line,
|
2019-03-13 11:13:55 +01:00
|
|
|
new_elements_names=new_elements_names,
|
|
|
|
rewrite_last_line=False),
|
2017-08-20 17:58:36 +02:00
|
|
|
value_obitype)
|
|
|
|
|
|
|
|
# Update the dictionary:
|
|
|
|
for t in dcols :
|
|
|
|
dcols[t] = (view[t], dcols[t][1])
|
|
|
|
|
|
|
|
# Fill value
|
|
|
|
dcols[tag][0][i] = value
|
|
|
|
|
2019-03-15 11:39:21 +01:00
|
|
|
i+=1 # TODO Not if None sequence
|
2017-08-20 17:58:36 +02:00
|
|
|
|
2019-03-13 18:35:32 +01:00
|
|
|
pb(i, force=True)
|
|
|
|
print("", file=sys.stderr)
|
|
|
|
|
2018-10-07 19:10:34 +02:00
|
|
|
# Save command config in View and DMS comments
|
|
|
|
command_line = " ".join(sys.argv[1:])
|
|
|
|
view.write_config(config, "import", command_line, input_str=[os.path.abspath(config['obi']['inputURI'])])
|
|
|
|
output[0].record_command_line(command_line)
|
|
|
|
|
2019-03-13 18:35:32 +01:00
|
|
|
#print("\n\nOutput view:\n````````````", file=sys.stderr)
|
|
|
|
#print(repr(view), file=sys.stderr)
|
|
|
|
|
2018-07-28 17:03:00 +02:00
|
|
|
try:
|
|
|
|
input[0].close()
|
|
|
|
except AttributeError:
|
|
|
|
pass
|
|
|
|
try:
|
|
|
|
output[0].close()
|
|
|
|
except AttributeError:
|
|
|
|
pass
|
2017-07-05 17:15:23 +02:00
|
|
|
|
2019-03-13 18:35:32 +01:00
|
|
|
logger("info", "Done.")
|