def __init__(self, title, dict_of_elems=None): # Store list of all elements in Item self._elems = Elem.get_elems() # Required elements are 'ROOT' and 'TITLE' # Set 'root' Item Element self.__setattr__('_' + Elem.ROOT, Elem.elem_init(Elem.ROOT, None)) # 'title' Element is required, set it first if not title: raise OrganizemIllegalDataFormatException("Cannot construct Item with null or empty title") title_obj = Elem.elem_init(Elem.TITLE, title) self.__setattr__('_' + Elem.TITLE, title_obj) self.__setattr__(Elem.TITLE, title_obj.val) # A little dirty, but not bad. Elem exposes method to get list of optional # elements, with the assumption being client can call get_optional_data_elems() to # get all elements and this to get only optional, so it can take care of # required ones (statically, as here) and process optional ones dynamically opt_elems = Elem.get_optional_data_elems() for elem in opt_elems: kwval = None elem_obj = None if dict_of_elems: if elem in dict_of_elems: kwval = dict_of_elems[elem] elem_obj = Elem.elem_init(elem, kwval) # Private object str(), repr() used by Item str() and repr() self.__setattr__('_' + elem, elem_obj) # Public getter just returns obj.val, value for the element self.__setattr__(elem, elem_obj.val) else: self.__setattr__('_' + elem, Elem.elem_init(elem, None)) self.__setattr__(elem, None)
def convert_to_item(py_item): """Converts Item serialized to Python object form, dicts and lists, to YAML""" # The list of names of elements an Item must have for this version elem_names = Elem.get_optional_data_elems() # List of names of elements in the py_item py_elem_names = YamlItemConverter._get_py_item_elems(py_item) # Item must have title element, so check for that first title = YamlItemConverter._get_py_item_title(py_item, py_elem_names) # Handling dynamic list of kwargs to __init__(), so build string # dynamically and make __init__() call an eval() init_call = [] init_call.append("Item('%s', {" % title) # eval(x) where x is a multiline string literal fails on # exception from scanning literal and finding an EOL in it # So, store the multiline string in this local List. Put the # note_vals[idx] into the string to be evaled. # And, yes, this is a pretty sweet hack note_vals = [] # Algo: # - Iterate the list of expected elements, item_elems # - Test for matching elem in py_item passed in (which was loaded from data) # - If found, add to kwargs list with py_item value for Item.__init__() # - If not found, add to kwargs list with None value for Item.__init__() for elem_name in elem_names: if elem_name in py_elem_names: idx = py_elem_names.index(elem_name) py_elems = py_item[Elem.ROOT] py_elem_val = py_elems[idx][elem_name] py_elem_val = Elem.elem_init(elem_name, py_elem_val).escaped_str() if py_elem_val: # Handle special case of multiline string value for Note elem # See comment above where note_vals[] is declared if Elem.get_elem_type(elem_name) == Elem.MULTILINE_TEXT_TYPE: note_vals.append(py_elem_val) val_idx = len(note_vals) - 1 init_call.append("'%s' : note_vals[%i], " % (elem_name, val_idx)) else: init_call.append("'%s' : %s, " % (elem_name, py_elem_val)) else: init_call.append("'%s' : None, " % elem_name) else: init_call.append("'%s' : None, " % elem_name) init_call.append("})") init_call = "".join(init_call) item = eval(init_call) return item