def test_15_display_ListWindow_fillEmpty_skipTable(preCreatedListWindow, capsys, height): createdListWindow = ListWindow(height, 100, {"Title": "List"}, 3, ("Column1", "Column2", "Column3")) createdListWindow.setHeader() createdListWindow.makeheader() headerLines = createdListWindow.header createdListWindow.draw(fillWindow=True, skipTable=True) captured = capsys.readouterr() lineIdentifiers = list(string.ascii_lowercase) + list( string.ascii_uppercase) blankLines = (height - len(headerLines)) * [100 * " "] expectedLines = [] for iline, line in enumerate(headerLines + blankLines): expectedLines.append(line.replace(" ", lineIdentifiers[iline])) modCapturedLines = [] for iline, line in enumerate(captured.out.split("\n")): if line != "": modCapturedLines.append(line.replace(" ", lineIdentifiers[iline])) ##################################################################################### print( "/////////////////////////////// EXPECTATION /////////////////////////////////////" ) for line in expectedLines: print(line) print( "///////////////////////////////// RETURN ////////////////////////////////////////" ) for line in modCapturedLines: print(line) ##################################################################################### assert len(expectedLines) == len(modCapturedLines) for iline in range(len(modCapturedLines)): assert modCapturedLines[iline] == expectedLines[iline]
def test_07_display_ListWindow_init(): createdListWindow = ListWindow(100, 100, {"Title": "List"}, 3, ("Column1", "Column2", "Column3")) createdListWindow.setHeader() #Check inherited values: assert createdListWindow.boxWidth == createdListWindow.width - 2 assert createdListWindow.headerTitle == "List" assert len(createdListWindow.headerText) == 0 assert createdListWindow.headerOptions is None #Check ListWidow init options: assert createdListWindow.nColumns == 3 assert createdListWindow.lines == [] assert createdListWindow.tableMaxLen == [ len("Column1"), len("Column2"), len("Column3"), ] with pytest.raises(ValueError): ListWindow(100, 100, {"Title": "List"}, 2, ("Column1", "Column2", "Column3"))
def preCreatedListWindow(): headerElements = { "Title": "This is the Title", "Text": ["First line text", "Second line text"], "Options": [("FirstName", "FirstComment"), ("SecondName", "SecondComment")] } fixWindow = ListWindow(100, 100, headerElements, 3, ("Column1", "Column2", "Column3")) fixWindow.setHeader() entry1 = ("Entry1,1", "Entry1,2", "Entry1,3") entry2 = ("Entry2,1", "Entry2,2", "Entry2,3") entry3 = ("Entry3,1", "Entry3,2", "Entry3,3") fixWindow.update([entry1, entry2, entry3]) return fixWindow
def __init__(self, dababase: DataBase, enableStartupSeatch=True): self.database = dababase if not os.path.exists(self.database.mimirdir + "/MTF_model.json"): raise RuntimeError( "No MTF configuration found in .mimir directory. Use make MTFconfig.py to create on from the database config" ) self.config = MTFConfig(self.database.mimirdir + "/MTF_model.json") self.lastIDList = self.database.getAllValuebyItemName("ID") self.windowHeight = self.config.height self.windowWidth = self.config.width self.tableColumns = len(self.config.items) self.tableColumnItems = self.config.items self.tableColumnNames = [] for item in self.config.items: self.tableColumnNames.append( self.config.itemInfo[item]["DisplayName"]) self.tableColumnNames = tuple(self.tableColumnNames) ################### Main Window ################### mainHeader = { "Title": self.config.windows["Main"]["Title"], "Text": ["Mimir base dir: {0}".format(self.database.databaseRoot)] + self.config.windows["Main"]["Text"], "Options": self.config.windows["Main"]["Options"], } self.mainWindow = Window(self.windowHeight, self.windowWidth, mainHeader) self.mainWindow.setHeader() ################### List Window ################### listHeader = { "Title": self.config.windows["List"]["Title"], "Options": self.config.windows["List"]["Options"], } self.listWindow = ListWindow(self.windowHeight, self.windowWidth, listHeader, self.tableColumns, self.tableColumnNames) self.listWindow.setHeader() self.listWindowDrawn = False self.firstInteraction = True self.inOverflow = False ################### DB Window ################### dbHeader = { "Title": self.config.windows["DB"]["Title"], "Text": self.config.windows["DB"]["Text"], "Options": self.config.windows["DB"]["Options"], } self.dbWindow = Window(self.windowHeight, self.windowWidth, dbHeader) self.dbWindow.setHeader() for key in self.config.windows: print(self.config.windows[key]) ################### Modification Window ################### modHeader = { "Title": self.config.windows["Modify"]["Title"], "Text": self.config.windows["Modify"]["Text"], "Options": self.config.windows["Modify"]["Options"], } self.modWindow = Window(self.windowHeight, self.windowWidth, modHeader) self.modWindow.setHeader() ################### Mulit Modification Window ################### self.mulitModExecVal = len( self.config.windows["MultiModify"]["Options"]) self.config.windows["MultiModify"]["Options"].append( ("Silent Execute", "Will not count to opened")) multiModHeader = { "Title": self.config.windows["MultiModify"]["Title"], "Text": self.config.windows["MultiModify"]["Text"], "Options": self.config.windows["MultiModify"]["Options"], } self.multiModWindow = Window(self.windowHeight, self.windowWidth, multiModHeader) self.multiModWindow.setHeader() self.allMultiModWindow = {} self.modSingleItems = [] self.modListItems = [] for item in self.config.modItems: if item in self.database.model.items: self.modSingleItems.append(item) else: self.modListItems.append(item)
class App: """ App class that manages the communication between the Window module and the database model Args: dababase (DataBase) : Initialized mimir DataBase enableStartupSeatch (bool) : If True, a search for new files will be enabled on startup """ def __init__(self, dababase: DataBase, enableStartupSeatch=True): self.database = dababase if not os.path.exists(self.database.mimirdir + "/MTF_model.json"): raise RuntimeError( "No MTF configuration found in .mimir directory. Use make MTFconfig.py to create on from the database config" ) self.config = MTFConfig(self.database.mimirdir + "/MTF_model.json") self.lastIDList = self.database.getAllValuebyItemName("ID") self.windowHeight = self.config.height self.windowWidth = self.config.width self.tableColumns = len(self.config.items) self.tableColumnItems = self.config.items self.tableColumnNames = [] for item in self.config.items: self.tableColumnNames.append( self.config.itemInfo[item]["DisplayName"]) self.tableColumnNames = tuple(self.tableColumnNames) ################### Main Window ################### mainHeader = { "Title": self.config.windows["Main"]["Title"], "Text": ["Mimir base dir: {0}".format(self.database.databaseRoot)] + self.config.windows["Main"]["Text"], "Options": self.config.windows["Main"]["Options"], } self.mainWindow = Window(self.windowHeight, self.windowWidth, mainHeader) self.mainWindow.setHeader() ################### List Window ################### listHeader = { "Title": self.config.windows["List"]["Title"], "Options": self.config.windows["List"]["Options"], } self.listWindow = ListWindow(self.windowHeight, self.windowWidth, listHeader, self.tableColumns, self.tableColumnNames) self.listWindow.setHeader() self.listWindowDrawn = False self.firstInteraction = True self.inOverflow = False ################### DB Window ################### dbHeader = { "Title": self.config.windows["DB"]["Title"], "Text": self.config.windows["DB"]["Text"], "Options": self.config.windows["DB"]["Options"], } self.dbWindow = Window(self.windowHeight, self.windowWidth, dbHeader) self.dbWindow.setHeader() for key in self.config.windows: print(self.config.windows[key]) ################### Modification Window ################### modHeader = { "Title": self.config.windows["Modify"]["Title"], "Text": self.config.windows["Modify"]["Text"], "Options": self.config.windows["Modify"]["Options"], } self.modWindow = Window(self.windowHeight, self.windowWidth, modHeader) self.modWindow.setHeader() ################### Mulit Modification Window ################### self.mulitModExecVal = len( self.config.windows["MultiModify"]["Options"]) self.config.windows["MultiModify"]["Options"].append( ("Silent Execute", "Will not count to opened")) multiModHeader = { "Title": self.config.windows["MultiModify"]["Title"], "Text": self.config.windows["MultiModify"]["Text"], "Options": self.config.windows["MultiModify"]["Options"], } self.multiModWindow = Window(self.windowHeight, self.windowWidth, multiModHeader) self.multiModWindow.setHeader() self.allMultiModWindow = {} self.modSingleItems = [] self.modListItems = [] for item in self.config.modItems: if item in self.database.model.items: self.modSingleItems.append(item) else: self.modListItems.append(item) def start(self): """ Start point for the app. Launches the mainWindow. """ logger.info("Starting App") self.runMainWindow(None) def runMainWindow(self, startVal): """ Function defining the interactions of the main window """ logger.info("Switching to main window") retVal = startVal while retVal != "0": retVal = self.mainWindow.draw("Enter Value") if retVal == "1": executeID = self.mainWindow.draw("Enter ID to execute") self.execute(executeID, self.mainWindow) elif retVal == "2": self.runModWindow(None, fromMain=True, fromList=False) elif retVal == "3": self.runListWindow(None) elif retVal == "4": self.executeRandom(self.mainWindow) elif retVal == "5": self.runDBWindow(None) elif retVal == "0": self.terminate() else: if retVal != "0": self.mainWindow.update("Please enter value present in %s" % self.mainWindow.validOptions) def runListWindow(self, startVal): """ Function defining the interactions of the List window """ logger.info("Switching to ListWindow") retVal = startVal if self.listWindow.nLinesPrinted > self.windowHeight: logger.info("Listwindow in overflow -> nPrinted %s", self.listWindow.nLinesPrinted) self.inOverflow = True logger.debug("self.inOverflow=%s self.listWindowDrawn=%s", self.inOverflow, self.listWindowDrawn) self.listWindow.draw(skipHeader=self.inOverflow, skipTable=(not self.listWindowDrawn), fillWindow=(not self.inOverflow)) self.listWindowDrawn = True #retVal = self.listWindow.interact("Enter Value:", None) while retVal != "0": retVal = self.listWindow.interact( "Enter Value", None, onlyInteraction=self.firstInteraction) if self.firstInteraction: self.firstInteraction = False if retVal == "1": #Print All allIDs = sorted(list( self.database.getAllValuebyItemName("ID")), key=lambda x: int(x)) tableElements = self.generateList(allIDs) #tableElements = self.generateList("All") self.listWindow.lines = [] self.listWindow.update(tableElements) #print("=========================================") #self.listWindow.draw(skipHeader = True, skipTable = False, fillWindow = False) #print("+++++++++++++++++++++++++++++++++++++++++") #retVal = self.listWindow.interact("Enter Value", None, onlyInteraction = False) elif retVal == "2": self.runModWindow(None, fromMain=False, fromList=True) elif retVal == "3": executeID = self.listWindow.interact("Enter ID to execute") self.execute(executeID, self.listWindow, fromList=True) elif retVal == "4": self.executeRandom(self.listWindow, fromList=True) elif retVal == "5": queryString = self.listWindow.interact("Enter Query", None, onlyInteraction=True) thisQuery = queryString.split(" ") queryIDs = self.database.query(self.config.queryItems, thisQuery, returnIDs=True) queryIDs = sorted(queryIDs, key=lambda x: int(x)) tableElements = self.generateList(queryIDs) self.listWindow.lines = [] self.listWindow.update(tableElements) elif retVal == "6": sortedIDs = self.database.getSortedIDs( "Added", reverseOrder=True)[0:self.config.restrictedListLen] tableElements = self.generateList(sortedIDs) self.listWindow.lines = [] self.listWindow.update(tableElements) elif retVal == "7": sortedIDs = self.database.getSortedIDs( "Opened", reverseOrder=True)[0:self.config.restrictedListLen] tableElements = self.generateList(sortedIDs) self.listWindow.lines = [] self.listWindow.update(tableElements) elif retVal == "8": sortedIDs = self.database.getSortedIDs( "Changed", reverseOrder=True)[0:self.config.restrictedListLen] tableElements = self.generateList(sortedIDs) self.listWindow.lines = [] self.listWindow.update(tableElements) elif retVal == "9": del_ID = self.listWindow.interact( "Enter ID to be marked/unmarked for deletion") self.toggle_for_deletion(del_ID, self.listWindow) elif retVal == "10": queryIDs = self.database.query(["DeletionMark"], "1", returnIDs=True) queryIDs = sorted(queryIDs, key=lambda x: int(x)) tableElements = self.generateList(queryIDs) self.listWindow.lines = [] self.listWindow.update(tableElements) else: if retVal != "0": self.listWindow.print("Please enter value present in %s" % self.listWindow.validOptions) #tableElements = self.generateList("All") self.runMainWindow(None) def runDBWindow(self, startVal): """ Function defining the interactions of the DB interaction window """ logger.info("Switching to main window") retVal = startVal while retVal != "0": retVal = self.dbWindow.draw("Enter Value: ") if retVal == "1": self.dbWindow.update("Saving database") self.database.saveMain() elif retVal == "2": newFiles, file_id_pair = self.database.findNewFiles() for newFile, ID in file_id_pair: self.dbWindow.update("Added file %s with ID %s" % (newFile, ID)) suggestedOptions = self.database.getItemsPyPath(newFile) foundOne = False for item in suggestedOptions: if suggestedOptions[item] != set(): foundOne = True if not foundOne: continue for item in suggestedOptions: for option in suggestedOptions[item]: answer = self.dbWindow.draw( "Do you want to add %s to %s [Yes/No]" % (option, item)) if answer.lower() == "yes": if item in self.database.model.items: self.database.modifySingleEntry(ID, item, option, byID=True) elif item in self.database.model.listitems: self.database.modifyListEntry(ID, item, option, "Append", byID=True) else: raise RuntimeError( "This should not happen!") elif retVal == "3": updatedFiles = self.database.checkChangedPaths() if updatedFiles: for id_, oldPath_, newPath_ in updatedFiles: self.dbWindow.update( "Moved entry with ID %s now has path %s" % (id_, newPath_)) else: self.dbWindow.update("No files with changed paths") elif retVal == "4": IDchanges = self.database.checkMissingFiles() if IDchanges: for oldID, newID in IDchanges: self.dbWindow.update("Moved entry from ID %s to %s" % (oldID, newID)) else: self.dbWindow.update("No Files removed") elif retVal == "5": queryIDs = self.database.query(["DeletionMark"], "1", returnIDs=True) queryIDs = sorted(queryIDs, key=lambda x: int(x)) if len(queryIDs) > 0: total_size = 0 for id_ in queryIDs: e = self.database.getEntryByItemName("ID", id_)[0] total_size += float(e.Size) self.dbWindow.update( f"{id_} is marked for delection(Name: {e.Name}; Size: {e.Size} GB)" ) self.dbWindow.update( f"{len(queryIDs)} entries marked for deletion with a total size of {total_size} GB" ) del_q = self.dbWindow.draw( "Are you sure you want to delete these entries? [Y/n]: " ) if del_q == "Y": self.del_ids(queryIDs, self.dbWindow) IDchanges = self.database.checkMissingFiles() if IDchanges: for oldID, newID in IDchanges: self.dbWindow.update( "Moved entry from ID %s to %s" % (oldID, newID)) else: self.dbWindow.update("No entries marked for deletion") else: if retVal != "0": self.dbWindow.update("Please enter value present in %s" % self.dbWindow.validOptions) self.runMainWindow(None) def runModWindow(self, startVal, fromMain, fromList): """ Function defining the interactions of the modification window """ logger.info("Switching to modification window") retVal = startVal while retVal != "0": retVal = self.modWindow.draw("Enter Value: ") if retVal == "0": pass elif retVal == "1": ID = self.modWindow.draw("Enter ID: ") if ID in self.database.getAllValuebyItemName("ID"): newWindow = False if ID not in self.allMultiModWindow.keys(): self.allMultiModWindow[ID] = deepcopy( self.multiModWindow) newWindow = True self.runMultiModWindow(None, ID, newWindow, fromMain, fromList) else: self.modWindow.update("ID %s not in database" % ID) elif retVal == "2": IDs = self.modWindow.draw("Enter IDs as XXX - YYY") IDs = IDs.replace(" ", "") res = re.search("[0-9]+-[0-9]+", IDs) validInput = False if res is not None: if res.span() == (0, len(IDs)): validInput = True if validInput: self.modWindow.update("%s is a valid intput" % IDs) fistID, lastID = IDs.split("-") IDList = [ str(x) for x in list(range(int(fistID), int(lastID) + 1)) ] self.processListOfModification(self.modWindow, IDList) else: self.modWindow.update("%s is a invalid intput" % IDs) elif retVal == "3": IDs = self.modWindow.draw("Enter IDs as XXX,YYY,..") IDs = IDs.replace(" ", "") res = re.search("([0-9],)+[0-9]", IDs) validInput = False if res is not None: if res.span() == (0, len(IDs)): validInput = True if validInput: IDList = IDs.split(",") self.processListOfModification(self.modWindow, IDList) else: self.modWindow.update("%s is a invalid intput" % IDs) else: if retVal != "0": self.modWindow.update("Please enter value present in %s" % self.modWindow.validOptions) if fromMain: self.runMainWindow(None) if fromList: self.runListWindow(None) def processListOfModification(self, window, IDList): """ Function prevalidating the IDs set in the ModWindows for bulk updating of Entries """ IDList = sorted(IDList, key=lambda x: int(x)) _validIDs = [] _rmIDs = [] for ID in IDList: if int(ID) > len(self.database.entries) - 1: _rmIDs.append(ID) else: _validIDs.append(ID) if len(_rmIDs) > 0: window.update("IDs %s are larger than max (%s)" % (_rmIDs, len(self.database.entries) - 1)) if len(_validIDs) > 0: window.update("IDList : %s" % _validIDs) self.modListOfItems(self.modWindow, _validIDs) def runMultiModWindow(self, startVal, ID, isNewWindow, fromMain, fromList): """ Function defining the interactions of the multi modification window. Will spawn a new one for each ID modified in the current scope of the app """ logger.info("Switching to multi modification window for ID %s", ID) thisWindow = self.allMultiModWindow[ID] entry = self.database.getEntrybyID(ID) if isNewWindow: thisWindow.headerText.append("Entry information:") thisWindow.headerText.append("ID: %s" % ID) thisWindow.headerText.append("Path: %s" % entry.getItem("Path").value) for elem in thisWindow.headerOptions: modID, name, comment = elem if name in self.database.model.allItems: thisWindow.headerTextSecondary[name] = self.getPrintItemValues( ID, name, joinFull=True) retVal = startVal while retVal != "0": retVal = thisWindow.draw("Enter Value: ") if retVal == "0": pass elif retVal in thisWindow.validOptions: if retVal == str(self.mulitModExecVal): thisWindow.update("Silent Execute triggered") ###TEMP self.execute(ID, thisWindow, silent=True) else: for elem in thisWindow.headerOptions: modID, name, comment = elem if modID == retVal: thisWindow.update("%s, %s" % (modID, name)) ###TEMP if name in self.database.model.items.keys(): thisWindow.update("%s is a Item" % name) ###TEMP self.modSingleItem(thisWindow, [ID], name, fromMultiMod=True) elif name in self.database.model.listitems.keys(): thisWindow.update("%s is a ListItem" % name) ###TEMP self.modListItem(thisWindow, [ID], name, fromMultiMod=True) else: thisWindow.update( "Something weird happend for %s" % (name)) else: thisWindow.update("Please enter value present in %s" % thisWindow.validOptions) self.runModWindow(None, fromMain, fromList) def modListItem(self, window, IDs, name, verbose=True, fromMultiMod=False): """ Wrapper for the different modification options and how they are called in the database Args: windows (Window or ListWindows) : Current window IDs (list) : List of IDs to be modified name (str) : Item name to be modified """ method = window.draw("Choose Method (Append | Replace | Remove)") if method in ["Append", "Replace", "Remove"]: if method == "Append": newValue = window.draw("New Value") for ID in IDs: self.makeListModifications(ID, name, "Append", None, newValue) if verbose: window.update("Appended %s" % newValue) elif method == "Remove": oldValue = window.draw("Remove Value") for ID in IDs: sucess = self.makeListModifications( ID, name, "Remove", oldValue, None) if sucess: if verbose: window.update("Removed %s from entry" % oldValue) else: window.update("Value %s no in entry" % oldValue) else: oldValue = window.draw("Value to replace") newValue = window.draw("New Value") for ID in IDs: sucess = self.makeListModifications( ID, name, "Replace", oldValue, newValue) if not sucess: window.update("Value %s no in entry" % oldValue) else: if verbose: window.update("Replaces %s with %s" % (oldValue, newValue)) else: window.update("!!! - %s is Invalid Method" % method) if fromMultiMod: window.headerTextSecondary[name] = self.getPrintItemValues( IDs[0], name, joinFull=True) def modListOfItems(self, window, IDs): """ Multiple modification of a single Item """ item = window.draw("Change item ({0})".format(" | ".join( self.config.modItems))) if item in self.modSingleItems: newValue = window.draw("New Value for %s" % item) for ID in IDs: self.database.modifySingleEntry(ID, item, newValue, byID=True) elif item in self.modListItems: self.modListItem(window, IDs, item, verbose=False) else: window.update("Input is no valid item") def modSingleItem(self, window, IDs, name=None, fromMultiMod=False): """ Wrapper for modifying a Single Item """ if name is None: name = window.draw("Change item ({0})".format(" | ".join( self.modSingleItems))) if name in self.modSingleItems: newValue = window.draw("New Value for %s" % name) for ID in IDs: self.database.modifySingleEntry(ID, name, newValue, byID=True) if fromMultiMod: window.headerTextSecondary[name] = self.getPrintItemValues( IDs[0], name, joinFull=True) def makeListModifications(self, ID, name, method, oldValue, newValue): """ Making a singel modification to a ListItem """ if method == "Append": self.database.modifyListEntry(ID, name, newValue, "Append", byID=True) return True elif method == "Remove": try: self.database.modifyListEntry(ID, name, None, "Remove", oldValue, byID=True) except ValueError: return False else: return True elif method == "Replace": try: self.database.modifyListEntry(ID, name, newValue, "Replace", oldValue, byID=True) except ValueError: return False else: return True else: pass def execute(self, ID, window, fromList=False, silent=False): """ Function called when a entry should be executed. The idea is, that for a desired execution program etc. a shell script with the called (as done in the terminal) is placed in the executable folder. After execution the **Opened** will be incrememented. """ if ID not in self.database.getAllValuebyItemName("ID"): window.print("ID %s not in database" % ID) else: entry2Exec = self.database.getEntryByItemName("ID", ID)[0] path2Exec = self.database.databaseRoot + "/" + entry2Exec.Path if not fromList: window.print("Path: %s" % path2Exec) os.system("{0} {1}".format(self.config.executable, path2Exec)) if not silent: self.database.modifyListEntry( ID, "Opened", mimir.backend.helper.getTimeFormatted("Full"), byID=True) def executeRandom(self, window, fromList=False): """ Function for getting a random entry from the last printed List of entries (if none printed from all) """ if not self.lastIDList: window.print("No entries to choose from. Maybe requery?") else: randID = self.database.getRandomEntry(chooseFrom=self.lastIDList) _listIDList = self.lastIDList if fromList: tableElements = self.generateList([randID]) self.lastIDList = _listIDList window.lines = [] window.update(tableElements) else: window.update("Executing entry with ID {0}".format(randID)) self.execute(randID, window, fromList) def toggle_for_deletion(self, ID, window): if ID not in self.database.getAllValuebyItemName("ID"): window.update("ID %s not in database" % ID) else: e = self.database.getEntryByItemName("ID", ID)[0] if e.DeletionMark == "0": logger.info("Marking ID %s for deletion", ID) self.database.modifySingleEntry(ID, "DeletionMark", "1", byID=True) else: logger.info("Unmarking ID %s for deletion", ID) self.database.modifySingleEntry(ID, "DeletionMark", "0", byID=True) def del_ids(self, ids, window): window.update("Will delete entries...") for id_ in ids: e = self.database.getEntryByItemName("ID", id_)[0] path2del = self.database.databaseRoot + "/" + e.Path window.update(f"Removing {path2del}") os.remove(path2del) window.update("...done deleting entries.") def terminate(self): """ Function called form the main window to terminate the app """ logger.info("Checking if database was saved") #TODO: CHeck if database is modified but nit saved logger.info("Terminating app") exit() def generateList(self, get="All"): """ Function generating the necessary table elements win using the ListWindow. Will used all items set in the DisplayItems configuration option """ #TODO Check get input tableElements = [] ids2Print = None if get == "All": ids2Print = self.database.getAllValuebyItemName("ID") ids2Print = sorted(list(ids2Print), key=lambda x: int(x)) elif isinstance(get, list): ids2Print = get self.lastIDList = ids2Print #logger.info(ids2Print) for id in ids2Print: entryElements = [] thisEntry = self.database.getEntryByItemName("ID", id)[0] for item in self.tableColumnItems: isCounter = False if self.config.itemInfo[item]["Type"] == "Counter": thisItem = None isCounter = True else: thisItem = thisEntry.getItem(item) if isCounter: value = str( self.database.getCount( id, self.config.itemInfo[item]["Base"], byID=True)) else: value = self.getPrintItemValues(id, item) entryElements.append(value) tableElements.append(tuple(entryElements)) return tableElements def getPrintItemValues(self, ID, item, joinWith=", ", joinFull=False): retValue = None thisEntry = self.database.getEntryByItemName("ID", ID)[0] if item in self.database.model.items: value = thisEntry.getItem(item).value self.modDisaply(item, value) if len(value ) > self.config.itemInfo[item]["maxLen"] and not joinFull: retValue = value[:self.config.itemInfo[item]["maxLen"]] + ".." else: retValue = value elif item in self.database.model.listitems: retValue = self.joinItemValues(thisEntry, item, joinWith, joinFull) else: raise KeyError("Item %s no listitem or singelitem") return retValue def joinItemValues(self, entry, item, joinWith=", ", joinFull=False): """ Will join all values in a ListItem. Will use the config settings Priority, DisplayDefault and nDisplay to format the return value. nDisplay can be overruled by the joinFull argument. Args: entry (DataBaseEntry) item (str) : ListItem to be joined (Function expects listitem no check implemented) joinWith (str) : String that will be used to join values joinFull (bool) : Will overrule the maximum lenghts Returns: value (str) : Joined values """ thisValue = [] for priority in self.config.itemInfo[item]["Priority"]: if priority in entry.getItem(item).value: thisValue.append(priority) loopVals = deepcopy(entry.getItem(item).value) if self.config.itemInfo[item]["Sorting"] == "reverse": loopVals.reverse() for val in loopVals: if val not in thisValue and len( thisValue) <= self.config.itemInfo[item]["nDisplay"]: if (val == self.database.model.getDefaultValue(item) and self.config.itemInfo[item]["DisplayDefault"] is not None): if self.config.itemInfo[item]["DisplayDefault"] != "": thisValue.append( self.config.itemInfo[item]["DisplayDefault"]) else: thisValue.append(self.modDisaply(item, val)) if len(thisValue) >= self.config.itemInfo[item]["nDisplay"]: if item not in ["Opened", "Changed"]: thisValue.append("..") break value = joinWith.join(thisValue) return value def modDisaply(self, item, value): """ Function processes the modDisplay setting from the config. """ if "modDisplay" in self.config.itemInfo[item].keys(): if self.config.itemInfo[item]["modDisplay"] == "Date": value = value.split("|")[0] elif self.config.itemInfo[item]["modDisplay"] == "Time": value = value.split("|")[1] elif self.config.itemInfo[item]["modDisplay"] == "Full": pass else: raise NotImplementedError( "modDisplay value %s not implemented" % self.config.itemInfo[item]["modDisplay"]) return value def modifyItemDisplay(self, item, value): """ Function for processing the modDisplay option in the MTF coniguration: Args: value (str) : Item Value item (str) : Item name Returns: value (str) : If modDispaly set will return modified value otherwise passed one """ if "modDisplay" in self.config.itemInfo[item].keys(): if self.config.itemInfo[item]["modDisplay"] == "Date": value = value.split("|")[0] elif self.config.itemInfo[item]["modDisplay"] == "Time": value = value.split("|")[1] elif self.config.itemInfo[item]["modDisplay"] == "Full": pass else: raise NotImplementedError( "modDisplay value %s not implemented" % self.config.itemInfo[item]["modDisplay"]) return value def about(self): """ Method that returns the information for the about screen. Like python-version, number entryies, number if values per ListItem, most used Value Returns: aboutInfo (dict) : All values of interest TODO: Implement """ pass
def test_16_display_ListWindow_fillEmpty_afterTableDraw(capsys, height): """ This test is used to varify """ def mock_input(s): return s + " (mocked)" createdListWindow = ListWindow(height, 100, {"Title": "List"}, 3, ("Column1", "Column2", "Column3")) createdListWindow.setHeader() createdListWindow.makeheader() headerLines = createdListWindow.header tableEntries = [] tableEntries2 = [] for i in range(5): tableEntries.append(("Entry" + str(i) + ",1", "Entry" + str(i) + ",2", "Entry" + str(i) + ",3")) tableEntries2.append( ("SecEntry" + str(i) + ",1", "SecEntry" + str(i) + ",2", "SecEntry" + str(i) + ",3")) createdListWindow.update(tableEntries) tableLines = createdListWindow.makeTable( createdListWindow.tableHeaderElements, createdListWindow.lines, createdListWindow.tableMaxLen) createdListWindow.draw(fillWindow=True) captured = capsys.readouterr() # -1 because there is one empty element after the split assert len(captured.out.split("\n")) - 1 == height # for iline, line in enumerate(captured.out.split("\n")): # print(iline, "a ",line) # captured = capsys.readouterr() display.input = mock_input createdListWindow.interact("Requesting input", None, onlyInteraction=True) createdListWindow.lines = [] createdListWindow.update(tableEntries2) tableLines2 = createdListWindow.makeTable( createdListWindow.tableHeaderElements, createdListWindow.lines, createdListWindow.tableMaxLen) createdListWindow.draw(fillWindow=True) captured = capsys.readouterr() assert len(captured.out.split("\n")) - 1 == height # for iline, line in enumerate(captured.out.split("\n")): # print("{0:2}".format(iline), "b",line) #Build expectation lineIdentifiers = 3 * (list(string.ascii_lowercase) + list(string.ascii_uppercase) + list(range(10))) leftAlignTableLines = [] for line in tableLines: lineLen = len(line) leftAlignTableLines.append(" " + line + " " + (createdListWindow.boxWidth - lineLen) * " ") leftAlignTableLines2 = [] for line in tableLines2: lineLen = len(line) leftAlignTableLines2.append(" " + line + " " + (createdListWindow.boxWidth - lineLen) * " ") interactionStr = "" + mock_input("Requesting input: Requesting input: ") interaction = [interactionStr + " " * (100 - len(interactionStr))] blankLines = (height - len(headerLines) - len(leftAlignTableLines) - len(leftAlignTableLines2) - 1) * [100 * " "] expectedLines = [] for iline, line in enumerate(headerLines + blankLines + leftAlignTableLines + interaction + leftAlignTableLines2): expectedLines.append(line.replace(" ", lineIdentifiers[iline])) modCapturedLines = [] for iline, line in enumerate(captured.out.split("\n")): if line != "": modCapturedLines.append( line.replace(" ", str(lineIdentifiers[iline]))) #################################################################################### print( "/////////////////////////////// EXPECTATION /////////////////////////////////////" ) for line in expectedLines: print(line) print( "///////////////////////////////// RETURN ////////////////////////////////////////" ) for line in modCapturedLines: print(line) #################################################################################### assert len(expectedLines) == len(modCapturedLines) for iline in range(len(modCapturedLines)): assert modCapturedLines[iline] == expectedLines[iline]
def test_08_display_ListWindow_update(): createdListWindow = ListWindow(100, 100, {"Title": "List"}, 3, ("Column1", "Column2", "Column3")) createdListWindow.setHeader() with pytest.raises(TypeError): createdListWindow.update("NotATuple") with pytest.raises(TypeError): createdListWindow.update(["NotATuple"]) with pytest.raises(ValueError): createdListWindow.update(("1", "2", "3", "4")) with pytest.raises(ValueError): createdListWindow.update(("1", "2")) createdListWindow.lines = [] entry1 = ("Entry1,1", "Entry1,2", "Entry1,3") createdListWindow.update(entry1) assert entry1 == createdListWindow.lines[0] entry2 = ("Entry2,1", "Entry2,2", "Entry2,3") entry3 = ("Entry3,1", "Entry3,2", "Entry3,3") createdListWindow.update([entry2, entry3]) assert entry2 == createdListWindow.lines[1] assert entry3 == createdListWindow.lines[2]