def _format_and_validate(self, args): # Unpack args, trim and clean, repack # Get action first for clarity of code here # TODO - expunge the magic string! action = OrgmCliController._trim_quotes(args['action']) # Process all the data elements, values for fields in Elem, dynamically for elem in Elem.get_data_elems(): elem_type = Elem.get_elem_type(elem) if elem_type == Elem.LIST_TYPE: # Must split() the two list element types, so the string becomes Py list # Trim single and double quotes from each element # NOTE: _trim_quotes() keeps args not passed as None and empty strings as empty, # which is *crucial* to logic of _run_cli_get_group_elem() below args[elem] = [OrgmCliController._trim_quotes(t).strip() for t in args[elem].split(',')] elif elem_type == Elem.TEXT_TYPE: args[elem] = OrgmCliController._trim_quotes(args[elem]) # Process filename args[ActionArg.FILENAME] = OrgmCliController._trim_quotes(args[ActionArg.FILENAME]) # Validation if action == Action.ADD and not args[Elem.TITLE]: raise OrganizemIllegalUsageException("'--add' action must include '--title' element and a value for title.") elif (action == Action.SETCONF_DATA_FILE or action == Action.SETCONF_BAK_FILE) \ and not args[ActionArg.FILENAME]: raise OrganizemIllegalUsageException("'--setconf_*' actions must include '--filename' element and a value for filename.") return (action, args)
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
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 _get_match(self, action, args): match_elem = None match_val = None if action == Action.FIND or action == Action.REMOVE: for elemkey in Elem.get_data_elems(): if elemkey in args: argval = args[elemkey] if len(argval): match_elem = elemkey match_val = argval break # Validate that we have match_elem and match_val if action requires them if match_elem is None or match_val is None: raise OrganizemIllegalUsageException("'--find and --remove must include an element (e.g. --title) and a value for that element.") return (match_elem, match_val)
def __init__(self): # This line is the whole reason for all this clumsy scaffolding -- build the group by # enums dynamically from Elem fields, so that if we add new Elements to Item # there is nothing to keep in synch here for elem in Elem.get_data_elems(): self.__setattr__(self.PFX + elem.upper(), self.PFX.lower() + elem.lower())