diff --git a/python/obitools3/dms/view/__init__.py b/python/obitools3/dms/view/__init__.py index 154f29e..24c4503 100644 --- a/python/obitools3/dms/view/__init__.py +++ b/python/obitools3/dms/view/__init__.py @@ -1,3 +1,3 @@ -from .view import View # @UnresolvedImport -from .view import Line_selection # @UnresolvedImport -from .view import Line # @UnresolvedImport \ No newline at end of file +#from .view import View # @UnresolvedImport +#from .view import Line_selection # @UnresolvedImport +#from .view import Line # @UnresolvedImport \ No newline at end of file diff --git a/python/obitools3/dms/view/view.pxd b/python/obitools3/dms/view/view.pxd index 347638b..d4c8560 100644 --- a/python/obitools3/dms/view/view.pxd +++ b/python/obitools3/dms/view/view.pxd @@ -1,13 +1,16 @@ #cython: language_level=3 + from ..capi.obiview cimport Obiview_p -from ..capi.obitypes cimport index_t, \ - obitype_t + +from ..capi.obitypes cimport index_t from ..object cimport OBIWrapper + from ..dms cimport DMS -from ..column.column cimport Column + +cdef dict __OBIDMS_VIEW_CLASS__ cdef class View(OBIWrapper): @@ -37,13 +40,15 @@ cdef class View(OBIWrapper): cdef class Line_selection(list): cdef View _view - + cdef bytes _view_name + cdef index_t* __build_binary_list__(self) cpdef View materialize(self, object view_name, object comments=*) - + + cdef class Line : cdef index_t _index diff --git a/python/obitools3/dms/view/view.pyx b/python/obitools3/dms/view/view.pyx index 43a7638..fcaf06e 100644 --- a/python/obitools3/dms/view/view.pyx +++ b/python/obitools3/dms/view/view.pyx @@ -1,10 +1,11 @@ #cython: language_level=3 -from libc.stdlib cimport malloc cdef dict __VIEW_CLASS__= {} +from libc.stdlib cimport malloc + from ..capi.obiview cimport Alias_column_pair_p, \ obi_new_view, \ obi_open_view, \ @@ -15,54 +16,57 @@ from ..capi.obiview cimport Alias_column_pair_p, \ from ..capi.obidmscolumn cimport OBIDMS_column_p from ..capi.obidms cimport OBIDMS_p +from ..capi.obitypes cimport obitype_t from obitools3.utils cimport tobytes, \ + str2bytes, \ bytes2str from ..object cimport OBIObjectClosedInstance - + +from ..column.column cimport Column + +from ..capi.obitypes cimport only_ATGC, \ + OBI_BOOL, \ + OBI_CHAR, \ + OBI_FLOAT, \ + OBI_INT, \ + OBI_QUAL, \ + OBI_SEQ, \ + OBI_STR + cdef class View(OBIWrapper) : - cdef inline Obiview_p pointer(self): - return (self.pointer) + cdef inline Obiview_p pointer(self) : + return (self._pointer) @staticmethod - cdef register_view_class(bytes viewtype, - type classe): - """ + cdef register_view_class(bytes view_type_name, + type view_class): + ''' Each sub class of `dms.View` needs to be registered after its declaration to declare its relationship with an `OBIType_t` - """ + ''' global __VIEW_CLASS__ - assert issubclass(classe,View) + assert issubclass(view_class, View) - __VIEW_CLASS__[viewtype]=classe + __VIEW_CLASS__[view_type_name] = view_class @staticmethod - cdef type get_view_class(bytes viewtype): + cdef type get_view_class(bytes view_type): global __VIEW_CLASS__ - return __VIEW_CLASS__.get(viewtype,View) + return __VIEW_CLASS__.get(view_type, View) - - def __init__(self,dms,int __internalCall__): - - OBIWrapper.__init__(self,__internalCall__) - - if __internalCall__!=987654: - raise RuntimeError('OBIView constructor cannot be called directly') - - self._pointer = NULL - - + @staticmethod def new(DMS dms, object view_name, object comments=None, - type viewclass=View): + type view_class=View): cdef bytes view_name_b = tobytes(view_name) cdef bytes comments_b @@ -86,8 +90,8 @@ cdef class View(OBIWrapper) : message = "Error : Cannot create view %s" % bytes2str(view_name_b) raise RuntimeError(message) - view = OBIWrapper.new_wrapper(viewclass, pointer) - view._dms = dms + view = OBIWrapper.new(view_class, pointer) + view._dms = dms dms.register(view) return view @@ -101,16 +105,19 @@ cdef class View(OBIWrapper) : cdef bytes view_name_b = tobytes(view_name) cdef bytes comments_b cdef void* pointer - cdef View + cdef View view + if not self.active() : + raise OBIObjectClosedInstance() + if comments is not None: comments_b = tobytes(comments) else: comments_b = b'' - pointer = obi_new_view((self._dms._pointer), + pointer = obi_new_view(self._dms.pointer(), view_name_b, - self._pointer, + self.pointer(), NULL, comments_b) @@ -120,9 +127,8 @@ cdef class View(OBIWrapper) : bytes2str(view_name_b)) ) - view = OBIWrapper.new_wrapper(type(self),pointer) + view = OBIWrapper.new(type(self), pointer) view._dms = self._dms - self._dms.register(view) return view @@ -134,52 +140,59 @@ cdef class View(OBIWrapper) : cdef bytes view_name_b = tobytes(view_name) cdef void* pointer - cdef View view + cdef View view + cdef type view_class - pointer = obi_open_view(dms._pointer, + pointer = obi_open_view(dms.pointer(), view_name_b) - + if pointer == NULL : raise RuntimeError("Error : Cannot open view %s" % bytes2str(view_name_b)) - view = OBIWrapper.new_wrapper(View.get_view_class((pointer).infos.view_type), - pointer) + view_class = View.get_view_class((pointer).infos.view_type) + view = OBIWrapper.new(view_class, pointer) + view._dms = dms - dms.register(view) - + return view cpdef close(self): - cdef Obiview_p pointer = self._pointer + cdef Obiview_p pointer = self.pointer() - if (pointer != NULL): + if self.active() : self._dms.unregister(self) - OBIWrapper.close(self) - + OBIWrapper.close(self) if obi_save_and_close_view(pointer) < 0 : raise Exception("Problem closing view %s" % bytes2str(self.name)) def __repr__(self) : + # TODO check everywhere + if not self.active() : + raise OBIObjectClosedInstance() + cdef str s = "{name:s}\n{comments:s}\n{line_count:d} lines\n".format(name = str(self.name), comments = str(self.comments), line_count = self.line_count) - - #for column_name in self._columns : - # s = s + repr(self._columns[column_name]) + '\n' - + + for column_name in self.keys() : + s = s + repr(self[column_name]) + '\n' + return s def keys(self): - cdef int i + cdef int i cdef Obiview_p pointer = self.pointer() cdef int nb_column = pointer.infos.column_count cdef Alias_column_pair_p column_p = pointer.infos.column_references + if not self.active() : + raise OBIObjectClosedInstance() + for i in range(nb_column) : col_alias = bytes2str(pointer.infos.column_references[i].alias) yield col_alias @@ -187,36 +200,21 @@ cdef class View(OBIWrapper) : def get_column(self, object column_name): - cdef bytes column_name_b = tobytes(column_name) - cdef OBIDMS_column_p* column_pp - cdef OBIDMS_column_p column_p - cdef Column column - cdef obitype_t column_type - cdef Obiview_p pointer = self.pointer() - - column_pp = obi_view_get_pointer_on_column_in_view(pointer, - column_name_b) - if column_pp == NULL: - raise KeyError("Cannot access to column %s in view %s" % ( - bytes2str(column_name_b), - bytes2str(self.name) - )) - - column_p = column_pp[0] - column_type = column_p.header.returned_data_type - - column = DMS.get_column_class(column_type)(self) - column._pointer = column_pp - - return column + if not self.active() : + raise OBIObjectClosedInstance() + + return Column.open(self, column_name) cpdef delete_column(self, object column_name) : - + + if not self.active() : + raise OBIObjectClosedInstance() + cdef bytes column_name_b = tobytes(column_name) - + if obi_view_delete_column(self.pointer(), column_name_b) < 0 : raise Exception("Problem deleting column %s from a view", bytes2str(column_name_b)) @@ -230,6 +228,9 @@ cdef class View(OBIWrapper) : cdef bytes current_name_b = tobytes(current_name) cdef bytes new_name_b = tobytes(new_name) + if not self.active() : + raise OBIObjectClosedInstance() + if (obi_view_create_column_alias(self.pointer(), tobytes(current_name_b), tobytes(new_name_b)) < 0) : @@ -239,15 +240,15 @@ cdef class View(OBIWrapper) : cpdef Line_selection new_selection(self,list lines=None): - return Line_selection(self,lines) + return Line_selection(self, lines) def __iter__(self): # Iteration on each line of all columns # Declarations - cdef index_t line_nb - cdef Line line + cdef index_t line_nb + cdef Line line # Yield each line for line_nb in range(self.line_count) : @@ -257,13 +258,13 @@ cdef class View(OBIWrapper) : def __getitem__(self, object item) : if type(item) == str : - return (self._columns)[item] + return self.get_column(item) # TODO hyper lent dans la pratique elif type(item) == int : return Line(self, item) - + def __contains__(self, str column_name): - return (column_name in self._columns) + return (column_name in self.keys()) def __len__(self): @@ -287,99 +288,28 @@ cdef class View(OBIWrapper) : # line_count property getter @property def line_count(self): - return (self._pointer).infos.line_count + return self.pointer().infos.line_count # name property getter @property def name(self): - return (self._pointer).infos.name + return self.pointer().infos.name # view type property getter @property def type(self): # @ReservedAssignment - return (self._pointer).infos.view_type + return self.pointer().infos.view_type # comments property getter @property def comments(self): - return (self._pointer).infos.comments + return self.pointer().infos.comments # TODO setter that concatenates new comments? -cdef class Line_selection(list): - - def __init__(self, View view, lines=None) : - if view._pointer == NULL: - raise Exception("Error: trying to create a line selection with an invalidated view") - self._view = view - self._view_name = view.name - - if lines is not None: - self.extend(lines) - - - def extend(self, iterable): - cdef index_t i - cdef index_t max_i = self._view.line_count - - for i in iterable: - if i > max_i: - raise RuntimeError("Error: trying to select line %d beyond the line count %d of view %s" % - (i, - max_i, - self._view_name) - ) - list.append(self,i) - - - def append(self, index_t idx) : - if idx >= self._view.line_count : - raise IndexError("Error: trying to select line %d beyond the line count %d of view %s" % - (idx, - self._view.line_count, - bytes2str(self.name)) - ) - list.append(self,idx) - - - cdef index_t* __build_binary_list__(self): - cdef index_t* line_selection_p = NULL - cdef int i - cdef size_t l_selection = len(self) - - line_selection_p = malloc((l_selection + 1) * sizeof(index_t)) # +1 for the -1 flagging the end of the array - for i in range(l_selection) : - line_selection_p[i] = self[i] - line_selection_p[l_selection] = -1 # flagging the end of the array - - return line_selection_p - - - cpdef View materialize(self, - object view_name, - object comments=""): - - cdef View view = View(987654) - cdef bytes view_name_b=tobytes(view_name) - - view._pointer = obi_new_view(self.view._dms.pointer, - view_name_b, - self._view._pointer, - self.__build_binary_list__(), - tobytes(comments)) - - if view._pointer == NULL : - raise RuntimeError("Error : Cannot clone view %s into view %s" - % (str(self.name), - view_name) - ) - - return view - - cdef class Line : def __init__(self, View view, index_t line_nb) : @@ -388,55 +318,60 @@ cdef class Line : def __getitem__(self, str column_name) : - return ((self._view)._columns)[column_name][self._index] - -# def __setitem__(self, str column_name, object value): -# # TODO detect multiple elements (dict type)? put somewhere else? but more risky (in get) -# # TODO OBI_QUAL ? -# cdef type value_type -# cdef str value_obitype -# cdef bytes value_b -# -# if column_name not in self._view : -# if value == None : -# raise Exception("Trying to create a column from a None value (can't guess type)") -# value_type = type(value) -# if value_type == int : -# value_obitype = 'OBI_INT' -# elif value_type == float : -# value_obitype = 'OBI_FLOAT' -# elif value_type == bool : -# value_obitype = 'OBI_BOOL' -# elif value_type == str or value_type == bytes : -# if value_type == str : -# value_b = str2bytes(value) -# else : -# value_b = value -# if only_ATGC(value_b) : # TODO detect IUPAC -# value_obitype = 'OBI_SEQ' -# elif len(value) == 1 : -# value_obitype = 'OBI_CHAR' -# elif (len(value) > 1) : -# value_obitype = 'OBI_STR' -# else : -# raise Exception("Could not guess the type of a value to create a new column") -# self._view.add_column(column_name, type=value_obitype) -# -# (((self._view)._columns)[column_name]).set_line(self._index, value) -# -# def __iter__(self): -# for column_name in ((self._view)._columns) : -# yield column_name -# -# def __contains__(self, str column_name): -# return (column_name in self._view._columns) - + return (self._view)[column_name][self._index] + + + def __setitem__(self, str column_name, object value): # TODO discuss + # TODO detect multiple elements (dict type)? put somewhere else? but more risky (in get) + # TODO OBI_QUAL ? + cdef type value_type + cdef obitype_t value_obitype + cdef bytes value_b + + if column_name not in self._view : + if value == None : + raise Exception("Trying to create a column from a None value (can't guess type)") + value_type = type(value) + if value_type == int : + value_obitype = OBI_INT + elif value_type == float : + value_obitype = OBI_FLOAT + elif value_type == bool : + value_obitype = OBI_BOOL + elif value_type == str or value_type == bytes : + if value_type == str : + value_b = str2bytes(value) + else : + value_b = value + if only_ATGC(value_b) : # TODO detect IUPAC + value_obitype = OBI_SEQ + elif len(value) == 1 : + value_obitype = OBI_CHAR + elif (len(value) > 1) : + value_obitype = OBI_STR + else : + raise Exception("Could not guess the type of a value to create a new column") + + Column.new_column(self._view, column_name, value_obitype) + + (self._view)[column_name][self._index] = value + + + def __iter__(self): + for column_name in (self._view).keys() : + yield self[column_name] + + + def __contains__(self, str column_name): + return (column_name in self._view.keys()) + + def __repr__(self): cdef dict line cdef str column_name line = {} -# for column_name in self._view._columns : -# line[column_name] = self[column_name] + for column_name in self._view.keys() : + line[column_name] = self[column_name] return str(line) @@ -477,3 +412,74 @@ cdef class Line : # return view_infos_d + +cdef class Line_selection(list): + + def __init__(self, View view, lines=None) : + if view._pointer == NULL: + raise Exception("Error: trying to create a line selection with an invalidated view") + self._view = view + self._view_name = view.name + + if lines is not None: + self.extend(lines) + + + def extend(self, iterable): + cdef index_t i + cdef index_t max_i = self._view.line_count + + for i in iterable: # TODO this is already checked in C + if i > max_i: + raise RuntimeError("Error: trying to select line %d beyond the line count %d of view %s" % + (i, + max_i, + self._view_name) + ) + list.append(self,i) + + + def append(self, index_t idx) : + if idx >= self._view.line_count : + raise IndexError("Error: trying to select line %d beyond the line count %d of view %s" % + (idx, + self._view.line_count, + bytes2str(self.name)) + ) + list.append(self,idx) + + + cdef index_t* __build_binary_list__(self): + cdef index_t* line_selection_p = NULL + cdef int i + cdef size_t l_selection = len(self) + + line_selection_p = malloc((l_selection + 1) * sizeof(index_t)) # +1 for the -1 flagging the end of the array + for i in range(l_selection) : + line_selection_p[i] = self[i] + line_selection_p[l_selection] = -1 # flagging the end of the array + + return line_selection_p + + + cpdef View materialize(self, + object view_name, + object comments=""): + + cdef View view = View(987654) + cdef bytes view_name_b=tobytes(view_name) + + view._pointer = obi_new_view(self._view._dms.pointer(), + view_name_b, + self._view.pointer(), + self.__build_binary_list__(), + tobytes(comments)) + + if view._pointer == NULL : + raise RuntimeError("Error : Cannot clone view %s into view %s" + % (str(self._view_name), + view_name) + ) + + return view +