def testFindRoot(self): """ Test finding the tree root of a word """ # Search for biology, since it's in two trees db = self.getDB() # First get references to the words num_trees, matched_words = cf.searchDB(db, "biology") test_source = matched_words[0][1] test_root = matched_words[0][0] self.assertEqual(num_trees, 2) # Find the root tree_root = cf.findRoot(test_source) tree_root_details = cf.loadWordDetails(tree_root) # Confirm it's right self.assertEqual(tree_root_details["lang"], "PIE") self.assertEqual(tree_root_details["morpheme"], "gweie") self.assertEqual(test_root, tree_root) # Now try the other biology tree test_source = matched_words[1][1] test_root = matched_words[1][0] # Find the root tree_root = cf.findRoot(test_source) tree_root_details = cf.loadWordDetails(tree_root) # Confirm it's right self.assertEqual(tree_root_details["lang"], "PIE") self.assertEqual(tree_root_details["morpheme"], "leg") self.assertEqual(test_root, tree_root)
def choose_word_from_many(words): """ From a list of matched words, prompts the user to select which one words is a list of tuples, each tuple is (tree,word). Returns the one (tree,word) tuple. """ # Find the morphemes,language for each instance mor_lan = [] word_text = cf.loadWordDetails(words[0][1])['text'][0] for item in words: word = item[1] word_details = cf.loadWordDetails(word) mor_lan.append( (word_details['morpheme'], word_details['lang']) ) print('For the word {0}, {1} options are available:'.format( word_text, len(mor_lan))) for item in enumerate(mor_lan, 1): print(' {0}: In {1}, choose the {2} morpheme'.format( item[0], item[1][1], item[1][0])) item_select = get_num_choice(min_num=1, max_num=len(mor_lan)) print('{0} morpheme of {1} chosen'.format( mor_lan[item_select-1][0], word_text)) return words[item_select-1]
def UpdateWordDetails(self): """ Update various widgets when a tree item has been selected """ # Set the 'word details' widgets nodeDetails = cf.loadWordDetails(self.current_node) alt_text = ', '.join(nodeDetails['text']) self.langbox.ChangeValue(nodeDetails['lang']) self.defbox.ChangeValue(nodeDetails['def']) self.altbox.ChangeValue(alt_text) # # Update the search word if applicable # if self.search_on_select: # self.search_word = node.xpath('text')[0].text # self.searchbox.SetValue(self.search_word) # # TODO: bold, debold the tree control # Highlight matching alternates, if applicable if self.search_word in alt_text: # Set the style bold_style = self.altbox.GetDefaultStyle() bold_font = bold_style.GetFont() bold_font.SetWeight(wx.FONTWEIGHT_BOLD) bold_style.SetFont(bold_font) # Find the start/end indices str_start = alt_text.find(self.search_word) # Bold the word self.altbox.SetStyle(str_start, str_start+len(self.search_word),bold_style)
def testReadWordDetails(self): """ Test reading the details of a word """ chosen_word = self.getWord("horse") wordDets = cf.loadWordDetails(chosen_word) self.assertEqual(wordDets["lang"], "Middle English") self.assertEqual(wordDets["def"], "A horse that you feed oats") self.assertEqual(wordDets["text"], ["horse", "hors", "horce", "horsse", "horis", "hos", "ors"])
def MenuTreeItem(self, event): """ Right-click menu for a tree item """ self.current_node = self.treebox.GetPyData(event.GetItem()) # Create the menu menu = wx.Menu() www_item_id = wx.NewId() menu.Append(www_item_id, 'Lookup on etymonline') menu.AppendSeparator() child_item_id = wx.NewId() menu.Append(child_item_id, 'Add child word') sib_item_id = wx.NewId() menu.Append(sib_item_id, 'Add sibling word') del_item_id = wx.NewId() menu.Append(del_item_id, 'Delete word') # Disable items if not in edit mode if not self.edit_mode: menu.Enable(child_item_id, False) menu.Enable(sib_item_id, False) menu.Enable(del_item_id, False) # Disable add sibling if we're on the root word (no parent) if cf.loadWordDetails(self.current_node)['tag'] == 'tree': menu.Enable(sib_item_id, False) # Bind events menu.Bind(wx.EVT_MENU, self.TreeItemLookupWWW, id=www_item_id) menu.Bind(wx.EVT_MENU, self.TreeItemAddChild, id=child_item_id) menu.Bind(wx.EVT_MENU, self.TreeItemAddSib, id=sib_item_id) menu.Bind(wx.EVT_MENU, self.TreeItemDelete, id=del_item_id) # Show the menu self.treebox.PopupMenu(menu)
def DisplayTree(self, root, nodes, select=None): """ Displays the tree in the wx.TreeCtrl object root is the ElementTree root node. nodes is a list of ElementTree word nodes to emphasize. If root is None, then is displays an empty tree message. select is a word that is selected (focused), this overrides focusing on any emphasized nodes. """ self.treebox.DeleteAllItems() if root is None: self.treebox.AddRoot('No matches found') self.editchk.Disable() self.editchk.SetValue(False) self.editbtn_save.Disable() self.editbtn_revert.Disable() self.langbox.ChangeValue('') self.defbox.ChangeValue('') self.altbox.ChangeValue('') self.selected_node = None else: root_details = cf.loadWordDetails(root) root_elem = self.treebox.AddRoot(root_details['text'][0], data = wx.TreeItemData(root)) if type(nodes) is not list: nodes = [nodes] self._populate_tree(root, root_elem, nodes, select) self.treebox.ExpandAll() self.editchk.Enable()
def _populate_tree(self, node, node_elem, emph_nodes, select): """ Recursive private function to fill in the rest of the tree control node: the ElementTree element we're working on. node_elem: the corresponding object in the TreeCtrl class. emph_nodes: a list of ElementTree elements, these will be emphasized. select: an element that will be selected (focused). If not None then it overrides focusing on emphasized nodes. """ # len() of a node returns how many children it has if cf.countWordChildren(node) > 0: for child in cf.loadWordChildren(node): child_details = cf.loadWordDetails(child) # Just display the first alternate child_label = child_details['text'][0] child_elem = self.treebox.AppendItem(node_elem, child_label, data = wx.TreeItemData(child)) if child in emph_nodes and select is None: # Emphasize the node self.treebox.SetItemBold(child_elem) # Select the node self.treebox.SelectItem(child_elem) if select is not None and child == select: self.treebox.SelectItem(child_elem) # Recurse! self._populate_tree(child, child_elem, emph_nodes, select)
def testCreateWord(self): """ Test creating a new word """ # Try some bad inputs word_dets = None self.assertRaises(cf.EtymExceptWord, cf.createWord, word_dets) word_dets = {} self.assertRaises(cf.EtymExceptWord, cf.createWord, word_dets) word_dets = {"lang": "English"} self.assertRaises(cf.EtymExceptWord, cf.createWord, word_dets) word_dets = {"lang": "English", "text": "banana", "morpheme": "bannana", "def": "A fruity thing"} self.assertRaises(cf.EtymExceptWord, cf.createWord, word_dets) # Now a good input, test the output word_dets = { "lang": "English", "text": ["banana", "pineapple"], "morpheme": "bannana", "def": "A fruity thing", "tag": "word", } new_word = cf.createWord(word_dets) new_word_details = cf.loadWordDetails(new_word) self.assertEqual(word_dets, new_word_details) # Try creating a word with a specified parent/children child_dets = {"lang": "Spanglish", "text": ["strawberry"], "morpheme": "strawberry", "def": "A fruity thing"} parent_dets = {"lang": "Fromesian", "text": ["raspberry"], "morpheme": "raspberry", "def": "A fruity thing"} word_dets = {"lang": "English", "text": ["banana"], "morpheme": "banana", "def": "A fruity thing"} new_child = cf.createWord(child_dets) new_parent = cf.createWord(parent_dets) new_word = cf.createWord(word_dets, word_parent=new_parent, word_children=new_child) self.assertEqual(cf.loadWordChildren(new_word)[0], new_child) self.assertEqual(cf.loadWordParents(new_word), new_parent)
def testAddTree(self): """ Test adding a tree """ # Create a test word to attach to the new tree word_dets = { "lang": "English", "text": ["banana", "pineapple"], "morpheme": "banana", "def": "A fruity thing", "tag": "word", } new_word = cf.createWord(word_dets) new_word_details = cf.loadWordDetails(new_word) self.assertEqual(word_dets, new_word_details) # Create the new tree db = self.getDB() tree_dets = {"lang": "PIE", "text": ["bane"], "morpheme": "bane", "def": "Some fruit", "tag": "tree"} cf.addTree(db, tree_dets, [new_word]) # Test that it was created num_trees, matched_words = cf.searchDB(db, "banana") search_word = matched_words[0][1] search_root = matched_words[0][0] search_root_dets = cf.loadWordDetails(search_root) self.assertEqual(search_word, new_word) self.assertEqual(search_root_dets["lang"], "PIE") self.assertEqual(search_root_dets["def"], "Some fruit") self.assertEqual(search_root_dets["morpheme"], "bane") self.assertEqual(search_root_dets["text"], ["bane"]) # Okay, now test some bad input # second arg not a list self.assertRaises(cf.EtymExceptWord, cf.addTree, db, tree_dets, new_word) # No word given self.assertRaises(cf.EtymExceptWord, cf.addTree, db, tree_dets, [None]) self.assertRaises(cf.EtymExceptWord, cf.addTree, db, tree_dets, []) # Invalid db self.assertRaises(cf.EtymExceptDB, cf.addTree, None, tree_dets, [new_word]) # Bad tree details tree_dets = {"lang": "PIE", "text": "bane", "morpheme": "bane", "tag": "tree"} self.assertRaises(cf.EtymExceptWord, cf.addTree, db, tree_dets, [new_word])
def testReadWordChildren(self): """ Test reading the children of a word """ # This word shouldn't have any children chosen_word = self.getWord("hross") word_children = cf.loadWordChildren(chosen_word) self.assertEqual(word_children, []) self.assertRaises(cf.EtymExceptWord, cf.loadWordDetails, word_children) # This word should have one child chosen_word = self.getWord("far") word_children = cf.loadWordChildren(chosen_word) wordDets = cf.loadWordDetails(word_children[0]) self.assertEqual(wordDets["text"][0], "farrow") self.assertEqual(wordDets["lang"], "Modern English") self.assertEqual(wordDets["def"], "An obsolete word for a pig")
def display_tree(tree, word, search_word): """ For a given word and tree, display the rest of the tree The search_word is emphasized. """ # Encapsulate word in a list if it isn't already if type(word) is not list: word = [word] tree_details = cf.loadWordDetails(tree) print('Root: {0} ({1})'.format(tree_details['text'][0], tree_details['lang'])) display_children(tree, 1, word, search_word)
def testReadWordParents(self): """ Test reading the parents of a word """ # The root shouldn't have any parents # TODO: Re-enable this once I can search for roots # chosen_word = self.getWord('khursa') # word_parents = cf.loadWordParents(chosen_word) # self.assertEqual(word_parents, None) # self.assertRaises(cf.EtymExceptWord, cf.loadWordDetails, word_parents[0]) # This word should have one parent chosen_word = self.getWord("horse") word_parents = cf.loadWordParents(chosen_word) wordDets = cf.loadWordDetails(word_parents) self.assertEqual(wordDets["text"][0], "hors") self.assertEqual(wordDets["lang"], "Old English") self.assertEqual(wordDets["def"], "A man-eating beast")
def testEditWordDetails(self): """ Test editing a word details """ chosen_word = self.getWord("horse") orig_wordDets = cf.loadWordDetails(chosen_word) new_wordDets = orig_wordDets.copy() new_wordDets["lang"] = "Elvish" new_wordDets["def"] = "A helpful friend" new_wordDets["text"] = ["horsey", "neigh"] new_wordDets["morpheme"] = "horsey" # Try purposefully giving incorrect details test_wordDets = {} self.assertRaises(cf.EtymExceptWord, cf.editWordDetails, chosen_word, test_wordDets) # Try refreshing the word cf.editWordDetails(chosen_word, orig_wordDets) test_wordDets = cf.loadWordDetails(chosen_word) self.assertEqual(orig_wordDets, test_wordDets) # Try new details cf.editWordDetails(chosen_word, new_wordDets) test_wordDets = cf.loadWordDetails(chosen_word) self.assertEqual(new_wordDets, test_wordDets) self.assertNotEqual(orig_wordDets, test_wordDets)
def testChangeParent(self): """ Tests modifying the parent of a word """ # This word has a parent, 'equinus' chosen_word = self.getWord("equine") # Make sure it can read the parent test_parent = cf.loadWordParents(chosen_word) parent_details = cf.loadWordDetails(test_parent) self.assertEqual(parent_details["text"], ["equinus"]) self.assertEqual(parent_details["lang"], "Latin") # Add a new word and set its parent word_dets = {"lang": "English", "text": ["banana", "pineapple"], "morpheme": "bannana", "def": "A fruity thing"} new_word = cf.createWord(word_dets) cf.editWordParent(new_word, test_parent) self.assertEqual(cf.countWordChildren(test_parent), 2) self.assertEqual(cf.countWordChildren(chosen_word), 0) cf.editWordParent(new_word, chosen_word) self.assertEqual(cf.countWordChildren(chosen_word), 1) # Add a new word and it to be parent to a word new_word = cf.createWord(word_dets) cf.editWordParent(chosen_word, new_word) self.assertEqual(new_word, cf.loadWordParents(chosen_word))
def OnSearch(self, event): """ Searches for a word, displays results """ self.search_word = self.searchbox.GetValue() if self.search_word is not '': # Simple validation for now num_trees, matched_words = cf.searchDB(self.words_tree, self.search_word) self.treebox.DeleteAllItems() # Clear the tree control out self.searchchoice.Clear() # Clear out the choice box self.searchchoice.Disable() wx.xrc.XRCCTRL(self.frame, 'et_txtLang').SetEditable(self.edit_mode) wx.xrc.XRCCTRL(self.frame, 'et_txtDef').SetEditable(self.edit_mode) wx.xrc.XRCCTRL(self.frame, 'et_txtAlt').SetEditable(self.edit_mode) if num_trees == 0: chosen_root = chosen_word = None elif num_trees > 1: # Populate the tree with the first match chosen_root = matched_words[0][0] chosen_word = [match[1] for match in matched_words] # Populate the choice button for item in matched_words: word = item[1] word_details = cf.loadWordDetails(word) choice_text = '{0} ({1})'.format( word_details['morpheme'], word_details['lang']) self.searchchoice.Append(choice_text, item) self.searchchoice.Enable() self.searchchoice.SetSelection(0) else: # Extract the tree and all matched words separately # Just pick the first entry (m_w[...][0] are the # same in this case) chosen_root = matched_words[0][0] chosen_word = [match[1] for match in matched_words] self.search_root = chosen_root self.search_words = chosen_word self.DisplayTree(self.search_root, self.search_words)
def display_children(node, depth, word, search_word): """ Recursive function to display children of a node depth is what level we're on. word is the word element we're looking for (it will be emphasized in the tree). search_word is the word text we're looking for. """ # The len() of a node returns how many children it has if cf.countWordChildren(node) > 0: for child in cf.loadWordChildren(node): depth_marker = ' '*depth child_markup = '' child_details = cf.loadWordDetails(child) if child in word: # First we have the emphasized word # Then the other matches, if there child_markup = ', '.join(['*{0}*'.format(text_var) for text_var in child_details['text'] if text_var == search_word]) child_markup_rest = ', '.join(['{0}'.format(text_var) for text_var in child_details['text'] if text_var != search_word]) if child_markup_rest is not '': child_markup = ', '.join([child_markup, child_markup_rest]) else: child_markup = ', '.join(['{0}'.format(text_var) for text_var in child_details['text']]) print(u'{0}Child: {1} ({2}, "{3}")'.format( depth_marker, child_markup, child_details['lang'], child_details['def'])) display_children(child, depth+1, word, search_word) else: # The base of the recursion simply does nothing pass
def TreeItemLookupWWW(self, event): """ Lookup an entry on etymonline """ lookup_word = cf.loadWordDetails(self.current_node) wx.LaunchDefaultBrowser('http://www.etymonline.com/index.php?' 'term={0}'.format(lookup_word['morpheme']))