import webbrowser import tkinter as tk from controller.utilities import logger mv_logger = logger('view.main_view') class MainView(tk.Frame): """ Class for view.main_view creates, displays, modifies and receives input from the user interface """ entry_title = "Welcome to Tiny Ticker news feed" entry_link = "https://github.com/int-thumbWar-1-2-3-4/Python-RSS-ticker" def __init__(self, master=None): """ Constructor for view.main_view.MainView. """ mv_logger.debug('MainView.__init__') super().__init__(master) self.master = master self.content_label = tk.Label(self, cursor="gumby") self.pack() self.build_window() self.display_entry(self.entry_title, self.entry_link) self.menu_bar() def menu_bar(self): """ View.main_view.MainView.menu_bar adds a drop down menu for our tk window. """ mv_logger.debug('MainView.menubar')
import feedparser from typing import List from model.article import Article from controller.utilities import logger f_logger = logger('model.feed') class Feed: # A collection of articles from a single feed. def __init__(self, name: str, list_of_articles: List[Article]): # Will not create with empty list f_logger.debug('Feed.__init__') if len(list_of_articles) == 0: # TODO: Make this create an exception if the list is empty pass self.name: str = name self.__list_of_articles: List[Article] = list_of_articles self.__sort() self.__current_article_index: int = 0 def __sort(self): # Sorts all of the articles on this feed from newest to oldest. Uses the insertion sort process. # Refactored from code at:
""" model.article An object which hold the relevant data for a single feed entry. """ from datetime import datetime from controller.utilities import logger a_logger = logger('model.article') class Article: """ model.article.Article A single feed entry, i.e. a single news article. """ def __init__(self, title: str, link: str, published_date: datetime): """ Article.__init__ Arguments: title -- the title of the entry. It describes what the article is about. link -- the url for the entry itself. published_date -- the date and time in which the article was published. """ a_logger.debug('Article.__init__')
def test_logger(self): """ Unit test for controller.utilities.logger. Should return a Logger object """ result = logger('name') self.assertTrue(isinstance(result, lg.Logger))
""" controller.tiny_ticker Contains methods for mediating communication between this application's modules. It also initializes and runs the Tiny Ticker application. """ import threading from model import parser from typing import List from model.article import Article from view.main_view import start_main_view, MainView from model.feed_manager import create_feed_manager, FeedManager from controller.utilities import logger, ticker_argument_parser tt_logger = logger('controller.tiny_ticker') arguments = ticker_argument_parser() def ten_second_loop(main_view: MainView, cycle, feed_manager: FeedManager): """ controller.tiny_ticker.ten_second_loop Switches the display every <cycle> seconds. This function spans a timed looping thread. Every 'cycle' seconds this function calls it's self to continue the loop. It is a daemon thread so it acts in the background and it calls controller.title_loop.call_switch_display. Arguments: main_view -- the MainView which displays articles. cycle -- the amount of time between view changes. User input from the command line.
#https://github.com/Jhawk1196/CS3250PythonProject/blob/dev/src/parser.py from controller.utilities import logger from bs4 import BeautifulSoup import requests import re p_logger = logger('model.parser') def parse_url_feed(url): p_logger.debug('parser_url_feed') feed = [] if not check_url(url): return "Invalid URL. Must Be a RSS Feed URL ending in .rss, .html, or .xml" response = requests.get(url) parse_value = find_parser(response) soup = BeautifulSoup(response.content, parse_value) # print(soup.prettify()) if soup.rss is not None: tag = soup.rss tag = tag.channel for title in tag.find_all(re.compile("title")): for entry in title.find_all(string=True): feed.append(entry) elif soup.find_all(re.compile("atom")) is not None: tag = soup.feed for entry in tag.find_all("entry"): for title in entry.find_all("title"): for string in title.find_all(string=True):
!!! At this moment the parser only has a dummy method for .atom feed parsing and cannot actually parse them !!! rss v2.0 specs can be found here: https://cyber.harvard.edu/rss/rss.html#hrelementsOfLtitemgt atom v1.0 specs can be found here: https://support.google.com/merchants/answer/160593?hl=en """ from email import utils import requests from re import search from bs4 import BeautifulSoup from typing import List from datetime import datetime from model.article import Article from controller.utilities import logger p_logger = logger('model.parser.py') class InvalidRssException(Exception): """ model.parser.InvalidRssException Exception raised if an Rss feed is not correctly formatted. """ pass class InvalidUrlException(Exception): """ model.parser.InvalidUrlException
import feedparser from typing import List from model.feed import Feed from model.article import Article from controller.utilities import logger fm_logger = logger('model.feed_manager') class FeedManagerEmptyError(Exception): pass class FeedNotFoundError(Exception): pass class FeedManager: # Holds all of the feeds this instance of Python-RSS-Ticker displays. Manages ordering of Articles so they rotate # between feeds and repeat Articles as little as possible. def __init__(self): fm_logger.debug('FeedManager.__init__') self.__list_of_feeds: List[Feed] = list() self.__current_feed_index: int = -1 def __get_feed(self, feed_name: str) -> Feed: # Gets the feed which matches the given name. May return None if match could not be found.