diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3694d0a --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +.idea/ +final_task/dist +*.pyc +*.json +*.idea'.idea' +final_task/rss_reader/.coverage +*.html +*.pdf +*.pkl +*.idea'.idea' +final_task/FinalTaskRssParser.egg-inf +final_task/rss_reader/images/ +.idea/ diff --git a/final_task/README.md b/final_task/README.md index 7af281f..810a656 100644 --- a/final_task/README.md +++ b/final_task/README.md @@ -1,3 +1,49 @@ -# Your readme here -Some text. -Checkout how to write this file using *markdown*. + +# Python RSS-reader +Python RSS-reader is a command-line utility which receives RSS URL and prints results in human-readable format. + +To start Python RSS-reader run one of the following commands in command line: + + ``python rss_reader.py "https://news.yahoo.com/rss/" --limit 1`` +``python rss_reader.py "https://timesofindia.indiatimes.com/rssfeedstopstories.cms" --json --limit 1`` + 7 file in my project + - consoleArgumemt.py this file which handles console phrases + - ConsoleOut.py - in this file function which handles print to console + - Handler.py - handles request + - Log.py - + - rss-reader.py - main file in project + - RssException.py - contains exception + - WorkWithCache.py - in this file function which works with cache(read and write json) + +### JSON structure: + ``` +{ + "news": "news text", + "title": "Title of news", + "date": "Wed, 20 Nov 2019 02:47:47 -0500", + "links": [ + "http://l1.yimg.com/uu/api/res/1.2/1KHP4ztUcOL6a98.vsEHQA--/YXBwaWQ9eXRhY2h5b247aD04Njt3PTEzMDs-/http://media.zenfs.com/en_us/News/afp.com/0dca2dadd67f7128eb881f0333640fce05a84084.jpg" + ], + "strDate": "20191120" + +} +``` +### Functional +``` +positional arguments: +source RSS URL +optional arguments: +-h, --help show this help message and exit +--version Print version info +--json Print result as JSON in stdout +--verbose Outputs verbose status messages +--limit LIMIT Limit news topics if this parameter provided +--date - view news from cache with specified date +``` + +### Iteration 4 +``python rss_reader.py --date 20191122 --to_html "D:\EpamFINAL\FinalTaskRssParser\final_task\rss_reader"`` + +``python rss_reader.py "https://news.yahoo.com/rss/" --to_pdf "D:\EpamFINAL\FinalTaskRssParser\final_task\rss_reader" + + diff --git a/final_task/rss_reader/ConsoleArgument.py b/final_task/rss_reader/ConsoleArgument.py new file mode 100644 index 0000000..f24b968 --- /dev/null +++ b/final_task/rss_reader/ConsoleArgument.py @@ -0,0 +1,15 @@ +import argparse + + +def get_console_argument(): + arg = argparse.ArgumentParser(description="read command of comamnd-line") + arg.add_argument("link", nargs='?', type=str, default="", help="Rss URL") + arg.add_argument('--limit', help="limit news topics if this parameter privided", type=int) + arg.add_argument('--verbose', help="verbose", action='store_true') + arg.add_argument('--json', help="print result as json in stdout", action='store_true') + arg.add_argument('--version', help="print version info", action='store_true') + arg.add_argument('--date', help="print news from cache for your date", type=int) + arg.add_argument('--to-html', help="create html file with news") + arg.add_argument('--to-pdf', help="create pdf file with news") + + return arg.parse_args() diff --git a/final_task/rss_reader/ConsoleOut.py b/final_task/rss_reader/ConsoleOut.py new file mode 100644 index 0000000..5bd3b99 --- /dev/null +++ b/final_task/rss_reader/ConsoleOut.py @@ -0,0 +1,33 @@ +from pprint import pprint + +from Log import log_decore + + +@log_decore +def print_json(list_json): + for item_list in list_json: + pprint(item_list) + + +@log_decore +def print_array_of_news(news): + for item_news in news: + print("Title: " + item_news.title) + print("Date: " + item_news.date) + print("Link: " + item_news.link) + print("\n" + item_news.news + '\n') + print("Links: ") + for item_link in item_news.links: + print(item_link + "\n") + + +@log_decore +def print_array_of_dict(news): + for item_news in news: + print("Title: " + item_news["title"]) + print("Date: " + item_news["date"]) + print("Link: " + item_news["link"]) + print("\n" + item_news["news"] + '\n') + print("Links: ") + for item_link in item_news["links"]: + print(item_link + "\n") diff --git a/final_task/rss_reader/ConvertToHtmlAndPdf.py b/final_task/rss_reader/ConvertToHtmlAndPdf.py new file mode 100644 index 0000000..31f9e79 --- /dev/null +++ b/final_task/rss_reader/ConvertToHtmlAndPdf.py @@ -0,0 +1,112 @@ +import os +import sys +from fpdf import FPDF +from News import News +from dominate.tags import html, head, meta, body, div, img, p, b, br, h1, a + +from WorkWithCache import correct_title +from Log import log_decore +from RssException import RssException + +@log_decore +def convert_Dict_to_News(arr_news_dict): + all_news = [] + for item_news in arr_news_dict: + tmp_img_link = item_news["links"] + tmp_link = item_news["link"] + tmp_news = item_news["news"] + tmp_title = item_news["title"] + tmp_date = item_news["date"] + tmp_date_str_date = item_news["strDate"] + item_of_list_news = News(tmp_news, tmp_link, tmp_title, tmp_date, tmp_img_link, tmp_date_str_date) + all_news.append(item_of_list_news) + return all_news + + + +'''create an HTML file and fill it with news''' +@log_decore +def create_html_news(path, News): + if os.path.isdir(path) is False: + raise RssException("Error. It isn't a folder") + + path = os.path.join(path, "News.html") + + news_html = html() + news_html.add(head(meta(charset='utf-8'))) + news_body = news_html.add(body()) + with news_body: + for item_news in News: + news_body = news_body.add(div()) + news_body += h1(item_news.title) + news_body += p(b("Date: "), a(item_news.date)) + + text = item_news.news + + # remove links in the text and add pictures + if len(item_news.links) > 0: + start = text.find(']', 0, len(text)) + text = text[start + 1:] + + this_dir = os.path.abspath(os.path.dirname(__file__)) + sys.path.append(this_dir) + news_body += img(src=f"file:///{this_dir}/images/{correct_title(item_news.title)}.jpg") + else: + # if there are no pictures, just remove the links + start = text.find(']', 0, len(text)) + text = text[start + 1:] + + news_body += p(text.encode("utf-8").decode("utf-8"), br(), br()) + + try: + with open(path, 'w', encoding='utf-8') as rss_html: + rss_html.write(str(news_html)) + except FileNotFoundError: + raise RssException('Error. No such folder\n') + print("file News.html created") + + + +'''create an PDF file and fill it with news''' +@log_decore +def create_pdf_news(path, News): + if os.path.isdir(path) is False: + raise RssException("Error. It isn't a folder") + path = os.path.join(path, "News.pdf") + + pdf = FPDF() + try: + pdf.add_font('DejaVuSans', '', 'DejaVuSans.ttf', uni=True) + pdf.set_font("DejaVuSans") + except RuntimeError: + raise RssException("fonts file not found") + pdf.alias_nb_pages() + pdf.add_page() + + for item_news in News: + text = item_news.news + # remove links in the text and add pictures + + start = text.find(']', 0, len(text)) + text = text[start + 1:] + + pdf.set_font_size(26) + pdf.write(11, item_news.title + '\n\n') + pdf.set_font_size(14) + pdf.write(11, f"Date: {item_news.date}\n") + + this_dir = os.path.abspath(os.path.dirname(__file__)) + sys.path.append(this_dir) + if len(item_news.links) > 0: + try: + pdf.image(f'{this_dir}/images/{correct_title(item_news.title)}.jpg', w=75, h=75) + except RuntimeError: + pass + pdf.write(10, "\n") + pdf.write(10, text + "\n\n\n\n") + pdf.output(path, 'F') + try: + pdf.output(path, 'F') + except FileNotFoundError: + raise RssException("Error. No such folder") + print("file News.pdf created") diff --git a/final_task/rss_reader/DejaVuSans.ttf b/final_task/rss_reader/DejaVuSans.ttf new file mode 100644 index 0000000..e5f7eec Binary files /dev/null and b/final_task/rss_reader/DejaVuSans.ttf differ diff --git a/final_task/rss_reader/Handler.py b/final_task/rss_reader/Handler.py new file mode 100644 index 0000000..9ad7257 --- /dev/null +++ b/final_task/rss_reader/Handler.py @@ -0,0 +1,124 @@ +import feedparser +from dataclasses import asdict +import html + +from Log import log_decore +from WorkWithCache import write_json_to_cache +from News import News +''' convert from News class to json''' + + +@log_decore +def parse_to_json(news): + return asdict(news) + + + +''' In this class, we do all the news processing. +Here we translate the format required by the user''' + + +class Handler: + @log_decore + # limit - count elements which user want see + def __init__(self, url, limit): + + self.article = feedparser.parse(url) + self.numb_news = 0 + self.parsers = [] + # standart value if user did not indicate limit we get all news + if limit == -1: + limit = len(self.article.entries) + self.create_news(url, limit) + + @log_decore + def create_news(self, url, limit): + # for every news, which user will see we create object + while self.numb_news < limit: + tmp_img_link = self.get_img_links(self.get_news(self.numb_news)) + tmp_link = self.get_link(self.numb_news) + tmp_news = self.parse_html(self.get_news(self.numb_news)) + tmp_title = self.get_title(self.numb_news) + tmp_date = self.get_date(self.numb_news) + tmp_date_str_date = self.get_str_date(self.numb_news) + item_of_list_news = News(tmp_news, tmp_link, tmp_title, tmp_date, tmp_img_link, tmp_date_str_date) + self.parsers.append(item_of_list_news) + self.numb_news += 1 + + @log_decore + def get_news(self, index): + try: + return self.article.entries[index].summary + except IndexError: + pass + + @log_decore + def get_link(self, index): + return self.article.entries[index].link + + + @log_decore + def get_title(self, index): + return html.unescape(self.article.entries[index].title) + + @log_decore + def get_date(self, index): + return self.article.entries[index].published + + @log_decore + def get_str_date(self, index): + str_date = "" + str_date += str(self.article.entries[index]['published_parsed'].tm_year) + str_date += str(self.article.entries[index]['published_parsed'].tm_mon) + str_date += str(self.article.entries[index]['published_parsed'].tm_mday) + return str_date + + @log_decore + def get_img_links(self, text): + img_links = [] + index_start_find = 0 + while 1: + start = text.find('src="', index_start_find, len(text)) + index_start_find = start + len('src="') + end = text.find('"', index_start_find) + if start == -1 or end == -1: + break + img_links.append(text[start + len('src="'):end]) + return img_links + + @log_decore + def get_img_alt(self, text): + img_alt = [] + index_start_find = 0 + while 1: + start = text.find('alt="', index_start_find, len(text)) + index_start_find = start + len('alt="') + end = text.find('"', index_start_find) + if start == -1 or end == -1: + break + img_alt.append(text[start + len('alt="'):end]) + return img_alt + + @log_decore + def parse_html(self, text): + news = "" + img_alt = self.get_img_alt(text) + # add imgLinks to article + for id, item in enumerate(img_alt): + news += ("[img " + str(id) + " ") + news += (item + "]") + + # clean the news from + while text.count('<'): + text = text[:text.find('<')] + text[text.find('>') + 1:] + news += text + news = html.unescape(news) + return news + + @log_decore + def get_all(self): + # return all news which user want see + for item_news in self.parsers: + write_json_to_cache(parse_to_json(item_news)) + + return self.parsers diff --git a/final_task/rss_reader/Log.py b/final_task/rss_reader/Log.py new file mode 100644 index 0000000..277a9de --- /dev/null +++ b/final_task/rss_reader/Log.py @@ -0,0 +1,11 @@ +import logging + + +def log_decore(fn): + def wrapper(*args, **kwargs): + logging.info(f"function \"{fn.__name__}\"Run function") + res = fn(*args, **kwargs) + logging.info(f"function \"{fn.__name__}\"Stop function") + return res + + return wrapper diff --git a/final_task/rss_reader/News.py b/final_task/rss_reader/News.py new file mode 100644 index 0000000..01548f5 --- /dev/null +++ b/final_task/rss_reader/News.py @@ -0,0 +1,17 @@ +from dataclasses import dataclass +from typing import List + +''' + in this class, we store news in the required format and + implement all the logic for processing news in the class Handler +''' + + +@dataclass +class News: + news: str + link: str + title: str + date: str + links: List[str] + strDate: str \ No newline at end of file diff --git a/final_task/rss_reader/RssException.py b/final_task/rss_reader/RssException.py new file mode 100644 index 0000000..111d759 --- /dev/null +++ b/final_task/rss_reader/RssException.py @@ -0,0 +1,2 @@ +class RssException(Exception): + pass diff --git a/final_task/rss_reader/WorkWithCache.py b/final_task/rss_reader/WorkWithCache.py new file mode 100644 index 0000000..3e11390 --- /dev/null +++ b/final_task/rss_reader/WorkWithCache.py @@ -0,0 +1,72 @@ +import json +import os + +from RssException import RssException +# from Handler import News +from Log import log_decore +import urllib.request + +''' +pass the dictionary to a function and write to a file json +''' + + +@log_decore +def correct_title(title): + return title.replace('"', "_").replace("?", "_").replace(":", "_").replace("'", "_").replace(" ", "_")[:15] + + +@log_decore +def save_img(url, name): + if os.path.exists("images"): + if name.find(".jpg") == -1: + urllib.request.urlretrieve(url, f'images/{name}.jpg') + else: + urllib.request.urlretrieve(url, f'images/{name}') + else: + os.makedirs("images") + urllib.request.urlretrieve(url, f"images/{name}.jpg") + + +@log_decore +def write_json_to_cache(entry_dict): + try: + load_news = json.load(open("cache.json")) + except json.JSONDecodeError: + load_news = [] + except FileNotFoundError: + load_news = [] + + if not [item_news for item_news in load_news if item_news["title"] == entry_dict["title"]]: + load_news.append(entry_dict) + if(entry_dict["links"][0] != ''): + save_img(entry_dict["links"][0], correct_title(entry_dict["title"])) + + with open("cache.json", "w") as cache: + json.dump(load_news, cache, indent=3) + + + +''' +read from the file and, if the date converges, return a list of these news +''' + + +def read_from_file(date, lim): + # here we look, if = -1, then we make a flag to read all the news + flag = 0 + if lim == -1: + flag = 1 + try: + entries = json.load(open("cache.json")) + except json.JSONDecodeError: + raise RssException("emty File") + except FileNotFoundError: + raise RssException("File not found error") + daily_news = [] + date = str(date) + for item_entries in entries: + if item_entries["strDate"] == date and (lim or flag): + daily_news.append(item_entries) + lim -= 1 + return daily_news diff --git a/final_task/rss_reader/rss_reader.py b/final_task/rss_reader/rss_reader.py index e69de29..42b717e 100644 --- a/final_task/rss_reader/rss_reader.py +++ b/final_task/rss_reader/rss_reader.py @@ -0,0 +1,106 @@ +import logging + +from ConsoleArgument import get_console_argument +from Handler import Handler +from Handler import parse_to_json +from ConsoleOut import print_array_of_news +from ConsoleOut import print_array_of_dict +from ConsoleOut import print_json +from RssException import RssException +from WorkWithCache import read_from_file +from ConvertToHtmlAndPdf import create_html_news +from ConvertToHtmlAndPdf import create_pdf_news +from ConvertToHtmlAndPdf import convert_Dict_to_News + + +def main(): + arg = get_console_argument() + link = arg.link + lim = -1 + if arg.version: + print("version: 4.0") + if arg.verbose: + logging.getLogger().setLevel(logging.INFO) + # if user enter to_html + if arg.to_html: + # if user enter link + if arg.link: + if arg.limit: + if arg.limit <= 0: + raise RssException("Error count news <=0") + lim = arg.limit + + hand = Handler(link, lim) + news = hand.get_all() + # if user enter --date + elif arg.date: + if arg.limit: + lim = arg.limit + dict_news = read_from_file(arg.date, lim) + news = convert_Dict_to_News(dict_news) + else: + raise RssException("Error. Please enter url or --date") + create_html_news(arg.to_html, news) + + # if user enter to_pdf + elif arg.to_pdf: + # if user enter link + if arg.link: + if arg.limit: + if arg.limit <= 0: + raise RssException("Error count news <=0") + lim = arg.limit + + hand = Handler(link, lim) + news = hand.get_all() + # if user --date + elif arg.date: + if arg.limit: + lim = arg.limit + dict_news = read_from_file(arg.date, lim) + news = convert_Dict_to_News(dict_news) + else: + raise RssException("Error. Please enter url or --date") + create_pdf_news(arg.to_pdf, news) + + elif arg.date: + if arg.limit: + lim = arg.limit + news = read_from_file(arg.date, lim) + if arg.json: + print_json(news) + else: + print_array_of_dict(news) + + + else: + # standart value -1, in handler we will process and get all the value + + if arg.limit or arg.limit == 0: + if arg.limit <= 0: + raise RssException("Error count news <=0") + lim = arg.limit + hand = Handler(link, lim) + news = hand.get_all() + if len(news) < lim: + raise RssException("not have this count of news") + if arg.json: + arr_json = [] + for i in news: + arr_json.append(parse_to_json(i)) + print_json(arr_json) + else: + print_array_of_news(news) + + +if __name__ == "__main__": + try: + main() + except AttributeError: + print("Error no have attribute") + except PermissionError: + print("error the file in which the news is recorded is open") + except TimeoutError: + print("poor internet connection") + except RssException as exc: + print(exc) diff --git a/final_task/rss_reader/test.py b/final_task/rss_reader/test.py new file mode 100644 index 0000000..066a08d --- /dev/null +++ b/final_task/rss_reader/test.py @@ -0,0 +1,148 @@ +import os +import unittest +from Handler import parse_to_json +from Handler import Handler +from News import News + +from WorkWithCache import save_img +from WorkWithCache import read_from_file + + +class TestEntry(unittest.TestCase): + def test__init__(self): + news = News("news", "lll", "ttt", "55af5", ["jfajaf", "fakf"], "1223665") + self.assertIsInstance(news, News) + self.assertNotIsInstance("news", News) + self.assertIsInstance(news.title, str) + self.assertIsInstance(news.strDate, str) + self.assertIsInstance(news.date, str) + self.assertIsInstance(news.news, str) + self.assertIsInstance(news.link, str) + self.assertIsInstance(news.links, list) + + def test_parse_to_json(self): + self.assertIsInstance(parse_to_json(News("news", "lll", "ttt", "55af5", ["jfajaf", "fakf"], "1223665")), dict) + + def test_get_all(self): + url = "https://news.yahoo.com/rss/" + lim = 3 + hand = Handler(url, lim) + + self.assertIsInstance(hand.get_all(), list) + self.assertIsInstance(hand.get_all()[0], News) + self.assertEqual(len(hand.get_all()), lim) + + # def test_link(self): + # link = "https://news.yahoo.com/rss/" + # hand = Handler("https://news.yahoo.com/rss/", 3) + # self.assertEqual(hand.get_link(link), "https://news.yahoo.com") + + def test_img_link(self): + text = 'img src="http://l.yimg.com/uu/api/res/1.2/I4AtbbFWPM.66LesQWxLqQ--/YXBwaWQ9eXRhY2h5b247aD04Njt3PTEzM' \ + 'Ds-/https://media.zenfs.com/en/the_new_york_times_articles_158/101bec76cc1717d8bfd63460b9443fd1" width=' \ + '"130" height="86" alt="She Texted About Dinner While Driving. Then a Pedestrian Was Dead." align="left" ' \ + 'title="She Texted About Dinner While Driving. Then a Pedestrian Was Dead." border="0" >FREEHOLD, N.J.' \ + ' -- One woman was out for a walk and a taste of fresh air during a break from her job as a scientist at' \ + ' a New Jersey fragrance manufacturer. She and her husband had been trying to get pregnant, and brief' \ + ' bouts of exercise, away from the laboratory's smells and fumes, were part of that plan.A second ' \ + 'woman was behind the wheel of a black Mercedes-Benz, headed to work as chief executive of a nonprofit in ' + img_link = 'http://l.yimg.com/uu/api/res/1.2/I4AtbbFWPM.66LesQWxLqQ--/YXBwaWQ9eXRhY2h5b247aD04Njt3PTEzM' \ + 'Ds-/https://media.zenfs.com/en/the_new_york_times_articles_158/101bec76cc1717d8bfd63460b9443fd1' + hand = Handler("https://news.yahoo.com/rss/", 3) + + self.assertEqual(hand.get_img_links(text)[0], img_link) + + def test_img_link_2(self): + text = 'img src="http://l.yimg.com/uu/api/res/1.2/I4AtbbFWPM.66LesQWxLqQ--/YXBwaWQ9eXRhY2h5b247aD04Njt3PTEzM' \ + 'Ds-/https://media.zenfs.com/en/the_new_york_times_articles_158/101bec76cc1717d8bfd63460b9443fd1" width=' \ + '"130" height="86" alt="She Texted About Dinner While Driving. Then a Pedestrian Was Dead." align="left" ' \ + 'title="She Texted About Dinner While Driving. Then a Pedestrian Was Dead." border="0" >FREEHOLD, N.J.' \ + ' -- One woman was out for a walk and a taste of fresh air during a break from her job as a scientist at' \ + ' a New Jersey fragrance manufacturer. She and her husband had been trying to get pregnant, and brief' \ + ' bouts of exercise, away from the laboratory's smells and fumes, were part of that plan.A second ' \ + 'woman was behind the wheel of a black Mercedes-Benz, headed to work as chief executive of a nonprofit in ' + img_link = 'l.yimg.com/uu/api/res/1.2/I4AtbbFWPM.66LesQWxLqQ--/YXBwaWQ9eXRhY2h5b247aD04Njt3PTEzM' \ + 'Ds-/https://media.zenfs.com/en/the_new_york_times_articles_158/101bec76cc1717d8bfd63460b9443fd1' + hand = Handler("https://news.yahoo.com/rss/", 3) + + self.assertNotEqual(hand.get_img_links(text)[0], img_link) + + def test_img_alt(self): + text = 'img src="http://l.yimg.com/uu/api/res/1.2/I4AtbbFWPM.66LesQWxLqQ--/YXBwaWQ9eXRhY2h5b247aD04Njt3PTEzM' \ + 'Ds-/https://media.zenfs.com/en/the_new_york_times_articles_158/101bec76cc1717d8bfd63460b9443fd1" width=' \ + '"130" height="86" alt="She Texted About Dinner While Driving. Then a Pedestrian Was Dead." align="left" ' \ + 'title="She Texted About Dinner While Driving. Then a Pedestrian Was Dead." border="0" >FREEHOLD, N.J.' \ + ' -- One woman was out for a walk and a taste of fresh air during a break from her job as a scientist at' \ + ' a New Jersey fragrance manufacturer. She and her husband had been trying to get pregnant, and brief' \ + ' bouts of exercise, away from the laboratory's smells and fumes, were part of that plan.A second ' \ + 'woman was behind the wheel of a black Mercedes-Benz, headed to work as chief executive of a nonprofit in ' + img_alt = 'She Texted About Dinner While Driving. Then a Pedestrian Was Dead.' + hand = Handler("https://news.yahoo.com/rss/", 3) + + self.assertEqual(hand.get_img_alt(text)[0], img_alt) + + def test_img_alt_2(self): + text = 'img src="http://l.yimg.com/uu/api/res/1.2/I4AtbbFWPM.66LesQWxLqQ--/YXBwaWQ9eXRhY2h5b247aD04Njt3PTEzM' \ + 'Ds-/https://media.zenfs.com/en/the_new_york_times_articles_158/101bec76cc1717d8bfd63460b9443fd1" width=' \ + '"130" height="86" alt="She Texted About Dinner While Driving. Then a Pedestrian Was Dead." align="left" ' \ + 'title="She Texted About Dinner While Driving. Then a Pedestrian Was Dead." border="0" >FREEHOLD, N.J.' \ + ' -- One woman was out for a walk and a taste of fresh air during a break from her job as a scientist at' \ + ' a New Jersey fragrance manufacturer. She and her husband had been trying to get pregnant, and brief' \ + ' bouts of exercise, away from the laboratory's smells and fumes, were part of that plan.A second ' \ + 'woman was behind the wheel of a black Mercedes-Benz, headed to work as chief executive of a nonprofit in ' + img_alt = '="She Texted About Dinner While Driving. Then a Pedestrian Was Dead.' + hand = Handler("https://news.yahoo.com/rss/", 3) + + self.assertNotEqual(hand.get_img_alt(text)[0], img_alt) + + def test_html_parse(self): + text = '
' \
+ 'A day after sayi' \
+ 'ng he wouldn’t bother to read the testimony, Sen. Lindsey Graham now says he did read it, and hi' \
+ 's conclusion is that the Trump administration’s Ukraine policy was too "incoherent" fo' \
+ 'r it to have orchestrated the quid pro quo at the heart of the impeachment inquiry.
'
+
+ news = "[img 0 Graham now says Trump's Ukraine policy was too 'incoherent' for quid pro quo]A day after " \
+ "saying he wouldn’t bother to read the testimony, Sen. Lindsey Graham now says he did read it, and his " \
+ "conclusion is that the Trump administration’s Ukraine policy was too \"incoherent\" for it to have" \
+ " orchestrated the quid pro quo at the heart of the impeachment inquiry."
+
+ hand = Handler("https://news.yahoo.com/rss/", 3)
+ self.assertEqual(hand.parse_html(text), news)
+
+ def test_html_parse_2(self):
+ text = '
' \
+ 'A day after sayi' \
+ 'ng he wouldn’t bother to read the testimony, Sen. Lindsey Graham now says he did read it, and hi' \
+ 's conclusion is that the Trump administration’s Ukraine policy was too "incoherent" fo' \
+ 'r it to have orchestrated the quid pro quo at the heart of the impeachment inquiry.
'
+
+ news = "A day after " \
+ "saying he wouldn’t bother to read the testimony, Sen. Lindsey Graham now says he did read it, and his " \
+ "conclusion is that the Trump administration’s Ukraine policy was too \"incoherent\" for it to have" \
+ " orchestrated the quid pro quo at the heart of the impeachment inquiry."
+
+ hand = Handler("https://news.yahoo.com/rss/", 3)
+ self.assertNotEqual(hand.parse_html(text), news)
+
+ def test_save_img(self):
+ url = "http://l1.yimg.com/uu/api/res/1.2/e2khNA0h_dG4YdzIfYpnMA--/YXBwaWQ9eXRhY2h5b247aD04Njt3PTEzMDs-/https://" \
+ "media-mbst-pub-ue1.s3.amazonaws.com/creatr-uploaded-images/2019-11/fa203490-0d54-11ea-b6b2-f04309019748"
+ name = "nameimgnameimgnameimgnameimg"
+ save_img(url, name)
+ self.assertTrue(os.path.exists(f'images/{name}.jpg'))
+
+ def test_read_file_lenght(self):
+ lim=3
+ news = read_from_file(20191124, 3)
+ self.assertEqual(len(news), lim)
+if __name__ == '__main__':
+ unittest.main()
\ No newline at end of file
diff --git a/final_task/setup.py b/final_task/setup.py
index e69de29..2e5d2cc 100644
--- a/final_task/setup.py
+++ b/final_task/setup.py
@@ -0,0 +1,19 @@
+from setuptools import setup, find_packages
+
+setup(
+ name='rss-reader',
+ version='4.0',
+ packages=find_packages(),
+ description='RSS reader',
+ url='https://github.com/AnatoliAgeichik/FinalTaskRssParser',
+ author='AnatoliAgeichik',
+ author_email='3anatoliageichik@gmail.com',
+ python_requires='>=3.7.0',
+ install_requires=['feedparser==5.2.1', 'fpdf==1.7.2', 'dominate==2.4.0'],
+ entry_points={
+ 'console_scripts': [
+ 'rss-reader = rss_reader.rss_reader:main',
+ ],
+ },
+ test_suite='rss_reader.tests'
+)