From a7c131d594a6b66dfa047acbe98c4460d122de93 Mon Sep 17 00:00:00 2001 From: asdf Date: Fri, 20 Dec 2019 22:15:11 +1100 Subject: [PATCH] Finalised search control --- data.py | 2 +- linkulator.py | 63 ++++++++++++++++++++++++++++++++++++---------- tests/data_test.py | 2 ++ 3 files changed, 53 insertions(+), 14 deletions(-) diff --git a/data.py b/data.py index d67b284..1457b80 100644 --- a/data.py +++ b/data.py @@ -185,7 +185,7 @@ class LinkData: cat_record["last_updated"] = timestamp def search(self, keyword: str) -> list: - """returns a unique list of link_data record IDs for posts that contain + """returns a unique list of link_data records for posts that contain the specified keyword""" if keyword == "": raise ValueError("a search keyword must be specified") diff --git a/linkulator.py b/linkulator.py index c6aad70..85927b0 100755 --- a/linkulator.py +++ b/linkulator.py @@ -132,19 +132,46 @@ def print_search_results(keyword: str, search_results: list): date = datetime.fromtimestamp(float(record[2])).strftime("%Y-%m-%d") author = record[1] desc = record[6] - print( - "{:4d} {:<15s}{:<12s}{:<13s}\n".format(display_index, date, author, desc) - ) + print("{:4d} {:<15s}{:<12s}{:<13s}".format(display_index, date, author, desc)) ## CONTROLS -def do_search(): - keyword = input("\nEnter your search\n") - search_results = LinkData.search(keyword) - print_search_results(keyword, search_results) - +def search(): + """Control for the search function""" + while True: + keyword = input("\nEnter your search (or leave empty to cancel):\n") + if keyword == "": + print("Search cancelled\n") + return + search_results = LinkData.search(keyword) + if not search_results: + print("No results found\n") + return + while True: + print_search_results(keyword, search_results) + option = input( + "\nEnter a post ID to see its thread, {} to start a new search, {} to go back, or {} to quit: \n".format( + style_text("s", "underline"), + style_text("m", "underline"), + style_text("q", "underline"), + ) + ).lower() + if option == "q": + graceful_exit() + if option == "m": + return + if option == "s": + break + try: + if 1 <= int(option) <= len(search_results): + menu_view_thread_details(search_results[int(option) - 1][0]) + else: + raise IndexError("Invalid post ID") + except (KeyError, ValueError, IndexError): + # Catch a Post ID that is not in the thread list or is not a number + print("\n{}\n".format(style_text("Invalid entry", "bold"))) def view_link_in_browser(url): """Attempts to view the specified URL in the configured browser""" @@ -271,8 +298,10 @@ def menu_view_categories(): print_categories() option = input( - "\nEnter a category ID, {} to post a link, or {} to quit: ".format( - style_text("p", "underline"), style_text("q", "underline") + "\nEnter a category ID, {} to post a link, {} to search, or {} to quit: ".format( + style_text("p", "underline"), + style_text("s", "underline"), + style_text("q", "underline"), ) ).lower() @@ -284,7 +313,7 @@ def menu_view_categories(): menu_view_thread_details(post_id) continue if option == "s": - do_search() + search() continue try: cat_index = categories[int(option) - 1] @@ -302,8 +331,9 @@ def menu_view_category_details(cat_index): option = input( "Enter a post ID to see its thread, {} to go back, {} to " - "post a link, or {} to quit: ".format( + "search, {} to post a link, or {} to quit: ".format( style_text("m", "underline"), + style_text("s", "underline"), style_text("p", "underline"), style_text("q", "underline"), ) @@ -313,6 +343,9 @@ def menu_view_category_details(cat_index): graceful_exit() if option == "m": return + if option == "s": + search() + continue if option == "p": post_id = post_link() if post_id >= 0: @@ -328,10 +361,11 @@ def menu_view_category_details(cat_index): def menu_view_thread_details(post_id): """Displays thread details, handles related navigation menu""" - option_text = "\nType {} to reply, {} to view in {}, {} to post a new link, {} to go back, or {} to quit: ".format( + option_text = "\nType {} to reply, {} to view in {}, {} to search, {} to post a new link, {} to go back, or {} to quit: ".format( style_text("r", "underline"), style_text("b", "underline"), config.USER.browser, + style_text("s", "underline"), style_text("p", "underline"), style_text("m", "underline"), style_text("q", "underline"), @@ -348,6 +382,9 @@ def menu_view_thread_details(post_id): if option == "r": reply(parent_id) continue + if option == "s": + search() + continue if option == "p": post_id = post_link() if post_id >= 0: diff --git a/tests/data_test.py b/tests/data_test.py index 935f352..febec99 100644 --- a/tests/data_test.py +++ b/tests/data_test.py @@ -116,6 +116,7 @@ class TestDataHelperFunctions(unittest.TestCase): class TestLinkDataSearch(unittest.TestCase): @unittest.mock.patch.object(data.LinkData, "get") def test_search_exceptions(self, mock_get): + """ensures exceptions are raised""" link_data = data.LinkData() mock_get.assert_called() with self.assertRaises(ValueError): @@ -123,6 +124,7 @@ class TestLinkDataSearch(unittest.TestCase): @unittest.mock.patch.object(data.LinkData, "get") def test_search(self, mock_get): + """tests search function""" link_data = data.LinkData() mock_get.assert_called()