From 762b32113b776b98eda0108a09049108bb2486b7 Mon Sep 17 00:00:00 2001 From: ilyaborodin Date: Sun, 10 Nov 2019 22:21:27 +0300 Subject: [PATCH 01/23] =?UTF-8?q?=D0=94=D0=B5=D0=BB=D0=B0=D0=B5=D0=BC=20?= =?UTF-8?q?=D0=BA=D0=BE=D0=BC=D0=B8=D1=82=20=D1=81=20=D0=BF=D1=83=D1=81?= =?UTF-8?q?=D1=82=D1=8B=D0=BC=20=D1=84=D0=B0=D0=B9=D0=BB=D0=BE=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- RSSReader.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 RSSReader.py diff --git a/RSSReader.py b/RSSReader.py new file mode 100644 index 0000000..e69de29 From 0222fcee9b946d67c99ff617d7328a824064ad1e Mon Sep 17 00:00:00 2001 From: ilyaborodin Date: Sun, 17 Nov 2019 13:16:35 +0300 Subject: [PATCH 02/23] Add 1st iter --- App/Args_parser.py | 29 ++++++++++++++++++++ App/News.py | 63 ++++++++++++++++++++++++++++++++++++++++++ App/Portal.py | 68 ++++++++++++++++++++++++++++++++++++++++++++++ App/RSSListener.py | 30 ++++++++++++++++++++ App/__init__.py | 1 + RSSReader.py | 0 rss_reader.py | 11 ++++++++ 7 files changed, 202 insertions(+) create mode 100644 App/Args_parser.py create mode 100644 App/News.py create mode 100644 App/Portal.py create mode 100644 App/RSSListener.py create mode 100644 App/__init__.py delete mode 100644 RSSReader.py create mode 100755 rss_reader.py diff --git a/App/Args_parser.py b/App/Args_parser.py new file mode 100644 index 0000000..163e30c --- /dev/null +++ b/App/Args_parser.py @@ -0,0 +1,29 @@ +import argparse +import sys +import App +import logging + + +def parsing_args(): + """Парсим аргументы""" + parser = argparse.ArgumentParser(description='Pure Python command-line RSS reader.') + parser.add_argument('source', type=str, help='RSS URL') + parser.add_argument('--version', action="store_true", help='Print version info') + parser.add_argument('--json', action="store_true", help='Print result as JSON in stdout') + parser.add_argument('--verbose', action="store_true", help='Outputs verbose status messages') + parser.add_argument('--limit', type=int, help='Limit news topics if this parameter provided') + return parser.parse_args() + + +def start_settings(args): + """Проверяем аргументы и действуем согласно их сценарию""" + if args.version: + print("*" * 50 + "\n" + "Version: " + App.__version__ + "\n" + "*" * 50 + "\n" * 2) + if args.verbose: + logging.basicConfig(stream=sys.stdout, level=logging.DEBUG) + else: + logging.basicConfig(level=logging.CRITICAL) + if args.limit is not None and args.limit < 0: + print("Limit cannot be less than 0") + logging.error("Limit cannot be less than 0") + exit() diff --git a/App/News.py b/App/News.py new file mode 100644 index 0000000..5cc1814 --- /dev/null +++ b/App/News.py @@ -0,0 +1,63 @@ +import logging + + +class News: + """Класс служит для хранения и обработки информации свзянной с отдельной новостью.""" + + def __init__(self, entry): + logging.info("Creating object News") + try: + self.title = entry.title + self.date = entry.published + self.summary = entry.summary + self.link = entry.link + except Exception as e: + print("Problems with article processing") + logging.error(str(e)) + exit() + self.images = [] + self.links = [] + self.clear_text() + + def del_tags(self, ind1, ind2, ind3, delta=0, items=None): + """В зависимости от входных параметров, метод может удалять ишние теги или + сохранять ссылки на картинки""" + logging.info("Tag processing") + while self.summary.find(ind1) != -1: + index1 = self.summary.index(ind1) + index2 = self.summary[index1 + delta:].index(ind2) + index3 = self.summary[index1:].index(ind3) + if items is not None: + items.append(self.summary[index1 + delta:index1 + index2 + delta]) + self.summary = self.summary[0:index1] + self.summary[index1 + index3 + 2:] + + def clear_text(self): + """Метод запускающий del_tags() в различной конфигурации + Это требуется, потому что на некоторых порталах в summary чатсть информации является \"мусором\"""" + logging.info("Improvement summary and and search for pictures and links") + try: + self.del_tags("", 10, self.images) + self.del_tags("", 9, self.links) + self.del_tags("") + self.del_tags("

", "

", "p>") + self.del_tags("

", "

", "p>") + for link in self.links: + if link == self.link: + self.links.remove(link) + except Exception as e: + logging.warning("Problems with tag parsing:\n" + str(e)) + + def __str__(self): + string = "Title: {0}\n" \ + "Date: {1}\n" \ + "Link: {2}\n\n" \ + "Summary: {3}".format(self.title, self.date, self.link, self.summary) + if len(self.images) > 0: + string = string + "\n\nImages in the article:" + for img in self.images: + string = string + "\n" + img + if len(self.links) > 0: + string = string + "\n\nLinks in the article:" + for link in self.links: + string = string + "\n" + link + return string diff --git a/App/Portal.py b/App/Portal.py new file mode 100644 index 0000000..4a9fccb --- /dev/null +++ b/App/Portal.py @@ -0,0 +1,68 @@ +import logging +import feedparser +import json +from App.News import News + + +class Portal: + """Класс служит для хранения и обработки информации свзянной с одним новостным порталом.""" + + def __init__(self, url): + logging.info("Creating object Portal") + self.url = url + rss = self.get_rss() + try: + self.title = rss.feed.title + self.link = rss.feed.link + self.updated = None + self.news = [] + self.links = [] + self.update(rss.entries[::-1]) + except Exception as e: + print("Problems with rss processing") + logging.error(str(e)) + exit() + + def get_rss(self): + """Получает rss файл""" + logging.info("Getting rss file") + try: + return feedparser.parse(self.url) + except Exception as e: + print("Problems getting rss file") + logging.error(str(e)) + exit() + + def update(self, entries): + """Метод служит для получения(добавления новых в будущем) статей""" + logging.info("Start processing article") + try: + rss = self.get_rss() + if self.updated != rss.feed.updated: + self.updated = rss.feed.updated + for entry in entries: + self.news.insert(0, News(entry)) + except Exception as e: + print("Problems with article processing") + logging.error(str(e)) + exit() + + def print(self, limit, json_flag): + """Метод выводит информацию о портале и о статьях""" + if limit is None or limit > len(self.news): + limit = len(self.news) + if json_flag: + logging.info("Saving to json") + json_news = [] + for news in self.news[:limit]: + json_news.append({"Title": news.title, "Date": news.date, "Link": news.link, + "Summary": news.summary, "Images": news.images, "Links": news.links}) + main_dict = {"Title": self.title, "Url": self.url, "News": json_news} + + print(json.dumps(main_dict, ensure_ascii=False, indent=4)) + else: + logging.info("Saving to text") + print("\n\nRSS-chanel\n" + "Title: {0}\n".format(self.title)) + for news in self.news[:limit]: + print("*" * 20 + "New article" + "*" * 20 + "\n{0}\n".format(news)) diff --git a/App/RSSListener.py b/App/RSSListener.py new file mode 100644 index 0000000..d042237 --- /dev/null +++ b/App/RSSListener.py @@ -0,0 +1,30 @@ +import logging +from App.Portal import Portal + + +class RSSListener: + """Класс листенер. Обрабатывает новые rss ссылки. + Постороен так, что в будущем при добавлении минимального функционала, + будет обрабатывать и сохранять новости из разных источников""" + + def __init__(self, limit, json_flag): + logging.info("Creating object RSSListener") + self.portals = [] + self.limit = limit + self.json_flag = json_flag + + def start(self, url): + """Метод принимает url и пускает его в обработку""" + logging.info("We begin to process the url") + try: + self.portals.append(Portal(url)) + except Exception as e: + print("Something go wrong") + logging.error(str(e)) + exit() + try: + self.portals[0].print(self.limit, self.json_flag) + except Exception as e: + print("Problems with printing") + logging.error(str(e)) + exit() diff --git a/App/__init__.py b/App/__init__.py new file mode 100644 index 0000000..4802e90 --- /dev/null +++ b/App/__init__.py @@ -0,0 +1 @@ +__version__ = "1.0" diff --git a/RSSReader.py b/RSSReader.py deleted file mode 100644 index e69de29..0000000 diff --git a/rss_reader.py b/rss_reader.py new file mode 100755 index 0000000..464f1bf --- /dev/null +++ b/rss_reader.py @@ -0,0 +1,11 @@ +#!/usr/bin/python3.8 +import logging +from App.RSSListener import RSSListener +from App import Args_parser + +if __name__ == '__main__': + args = Args_parser.parsing_args() + Args_parser.start_settings(args) + logging.info("Program launch") + rss_listener = RSSListener(args.limit, args.json) + rss_listener.start(args.source) From a432523b1e468a66f1b798c280d86dc82668d04d Mon Sep 17 00:00:00 2001 From: ilyaborodin Date: Sun, 17 Nov 2019 13:55:57 +0300 Subject: [PATCH 03/23] =?UTF-8?q?=D0=98=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D0=BF=D1=83=D1=82=D0=B8=20=D0=BD=D0=B0=20?= =?UTF-8?q?=D0=B8=D0=BD=D1=82=D0=B5=D0=BF=D1=80=D0=B5=D1=82=D0=B0=D1=82?= =?UTF-8?q?=D0=BE=D1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- rss_reader.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rss_reader.py b/rss_reader.py index 464f1bf..796110e 100755 --- a/rss_reader.py +++ b/rss_reader.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3.8 +#!/usr/bin/env python3.8 import logging from App.RSSListener import RSSListener from App import Args_parser From 00b6bf7ba3af43dfe099e1e6b5a9ecf155cdc91b Mon Sep 17 00:00:00 2001 From: ilyaborodin Date: Sun, 17 Nov 2019 18:52:34 +0300 Subject: [PATCH 04/23] =?UTF-8?q?=D0=92=D1=8B=D0=BF=D0=BE=D0=BB=D0=BD?= =?UTF-8?q?=D0=B8=D0=BB=202-=D1=83=D1=8E=20=D0=B8=D1=82=D0=B5=D1=80=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Добавлен файл setup.py Добавлен метож main Изменена версия программы на "2.0" --- App/__init__.py | 2 +- rss_reader.py => App/rss_reader.py | 7 ++++++- setup.py | 18 ++++++++++++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) rename rss_reader.py => App/rss_reader.py (92%) create mode 100644 setup.py diff --git a/App/__init__.py b/App/__init__.py index 4802e90..f2dc0e4 100644 --- a/App/__init__.py +++ b/App/__init__.py @@ -1 +1 @@ -__version__ = "1.0" +__version__ = "2.0" diff --git a/rss_reader.py b/App/rss_reader.py similarity index 92% rename from rss_reader.py rename to App/rss_reader.py index 796110e..abda71d 100755 --- a/rss_reader.py +++ b/App/rss_reader.py @@ -3,9 +3,14 @@ from App.RSSListener import RSSListener from App import Args_parser -if __name__ == '__main__': + +def main(): args = Args_parser.parsing_args() Args_parser.start_settings(args) logging.info("Program launch") rss_listener = RSSListener(args.limit, args.json) rss_listener.start(args.source) + + +if __name__ == '__main__': + main() diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..5950c75 --- /dev/null +++ b/setup.py @@ -0,0 +1,18 @@ +from setuptools import setup, find_packages +import App + +setup( + name="RSS Reader", + version=App.__version__, + description="Utility to process RSS", + author="Borodin Ilya", + author_email="ilya.borodin8@gmail.com", + url="https://github.com/ilyaborodin/PythonHomework/tree/Final_Task", + packages=find_packages(), + install_requires=['feedparser==5.2.1'], + python_requires='>=3.8', + entry_points={ + "console_scripts": ["rss_reader=App.rss_reader:main"], + } + +) From 772c22be62a583bc7116257d3482e2ca6281112f Mon Sep 17 00:00:00 2001 From: ilyaborodin Date: Sun, 17 Nov 2019 19:57:59 +0300 Subject: [PATCH 05/23] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D0=BE=D0=B2=D0=B0=D0=BB=20=D0=BA=D0=BE=D0=BC=D0=B0=D0=BD?= =?UTF-8?q?=D0=B4=D1=83=20=D0=B2=20rss-reader?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 5950c75..7ae5d95 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ install_requires=['feedparser==5.2.1'], python_requires='>=3.8', entry_points={ - "console_scripts": ["rss_reader=App.rss_reader:main"], + "console_scripts": ["rss-reader=App.rss_reader:main"], } ) From 53c76d28579fccb3a63f72398b3daaaba7768a3a Mon Sep 17 00:00:00 2001 From: ilyaborodin Date: Fri, 29 Nov 2019 11:31:34 +0300 Subject: [PATCH 06/23] =?UTF-8?q?=D0=A3=D0=B1=D1=80=D0=B0=D0=BB=20=D0=BB?= =?UTF-8?q?=D0=B8=D1=88=D0=BD=D0=B8=D0=B5=20=D1=82=D0=BE=D1=87=D0=BA=D0=B8?= =?UTF-8?q?=20=D0=B2=D1=8B=D1=85=D0=BE=D0=B4=D0=B0=20=D0=B8=20=D0=BF=D0=BE?= =?UTF-8?q?=D0=BF=D1=80=D0=B0=D0=B2=D0=B8=D0=BB=20=D1=81=D0=B8=D1=81=D1=82?= =?UTF-8?q?=D0=B5=D0=BC=D1=83=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BE=D0=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Убрал все лишние exit Добавил прокидывание ошибок дальше по вертикали --- App/Args_parser.py | 7 +++---- App/Errors.py | 3 +++ App/News.py | 6 ++---- App/Portal.py | 15 ++++++--------- App/RSSListener.py | 12 +++++------- App/rss_reader.py | 19 ++++++++++++++----- 6 files changed, 33 insertions(+), 29 deletions(-) create mode 100644 App/Errors.py diff --git a/App/Args_parser.py b/App/Args_parser.py index 163e30c..954ed35 100644 --- a/App/Args_parser.py +++ b/App/Args_parser.py @@ -1,7 +1,8 @@ import argparse import sys -import App import logging +from App.Errors import FatalError + def parsing_args(): @@ -24,6 +25,4 @@ def start_settings(args): else: logging.basicConfig(level=logging.CRITICAL) if args.limit is not None and args.limit < 0: - print("Limit cannot be less than 0") - logging.error("Limit cannot be less than 0") - exit() + raise FatalError("Limit cannot be less than 0") diff --git a/App/Errors.py b/App/Errors.py new file mode 100644 index 0000000..0262fe4 --- /dev/null +++ b/App/Errors.py @@ -0,0 +1,3 @@ +class FatalError(Exception): + def __init__(self, text): + self.__str__ = text \ No newline at end of file diff --git a/App/News.py b/App/News.py index 5cc1814..bb7bd17 100644 --- a/App/News.py +++ b/App/News.py @@ -1,5 +1,5 @@ import logging - +from App.Errors import FatalError class News: """Класс служит для хранения и обработки информации свзянной с отдельной новостью.""" @@ -12,9 +12,7 @@ def __init__(self, entry): self.summary = entry.summary self.link = entry.link except Exception as e: - print("Problems with article processing") - logging.error(str(e)) - exit() + raise FatalError("Problems with article processing") self.images = [] self.links = [] self.clear_text() diff --git a/App/Portal.py b/App/Portal.py index 4a9fccb..d6e97fe 100644 --- a/App/Portal.py +++ b/App/Portal.py @@ -1,6 +1,7 @@ import logging import feedparser import json +from App.Errors import FatalError from App.News import News @@ -19,9 +20,7 @@ def __init__(self, url): self.links = [] self.update(rss.entries[::-1]) except Exception as e: - print("Problems with rss processing") - logging.error(str(e)) - exit() + raise FatalError("Problems with rss processing") def get_rss(self): """Получает rss файл""" @@ -29,9 +28,7 @@ def get_rss(self): try: return feedparser.parse(self.url) except Exception as e: - print("Problems getting rss file") - logging.error(str(e)) - exit() + raise FatalError("Problems getting rss file") def update(self, entries): """Метод служит для получения(добавления новых в будущем) статей""" @@ -42,10 +39,10 @@ def update(self, entries): self.updated = rss.feed.updated for entry in entries: self.news.insert(0, News(entry)) + except FatalError: + raise except Exception as e: - print("Problems with article processing") - logging.error(str(e)) - exit() + raise FatalError("Problems with article processing") def print(self, limit, json_flag): """Метод выводит информацию о портале и о статьях""" diff --git a/App/RSSListener.py b/App/RSSListener.py index d042237..e0c9be4 100644 --- a/App/RSSListener.py +++ b/App/RSSListener.py @@ -1,6 +1,6 @@ import logging from App.Portal import Portal - +from App.Errors import FatalError class RSSListener: """Класс листенер. Обрабатывает новые rss ссылки. @@ -18,13 +18,11 @@ def start(self, url): logging.info("We begin to process the url") try: self.portals.append(Portal(url)) + except FatalError: + raise except Exception as e: - print("Something go wrong") - logging.error(str(e)) - exit() + raise FatalError("Something go wrong") try: self.portals[0].print(self.limit, self.json_flag) except Exception as e: - print("Problems with printing") - logging.error(str(e)) - exit() + raise FatalError("Problems with printing") diff --git a/App/rss_reader.py b/App/rss_reader.py index abda71d..a1a6d04 100755 --- a/App/rss_reader.py +++ b/App/rss_reader.py @@ -5,11 +5,20 @@ def main(): - args = Args_parser.parsing_args() - Args_parser.start_settings(args) - logging.info("Program launch") - rss_listener = RSSListener(args.limit, args.json) - rss_listener.start(args.source) + try: + args = Args_parser.parsing_args() + Args_parser.start_settings(args) + logging.info("Program launch") + rss_listener = RSSListener(args.limit, args.json) + rss_listener.start(args.source) + except Exception as e: + print(str(e)) + close_program() + + +def close_program(): + print("The program suddenly completed its work") + exit() if __name__ == '__main__': From 7df5749117e2f426131ee0e93a61414fb5de43a2 Mon Sep 17 00:00:00 2001 From: ilyaborodin Date: Fri, 29 Nov 2019 11:45:30 +0300 Subject: [PATCH 07/23] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BD=D0=B0=D0=B7=D0=B2=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5?= =?UTF-8?q?=20=D0=BF=D0=BE=D1=80=D1=82=D0=B0=D0=BB=D0=B0=20=D0=BA=20=D0=BA?= =?UTF-8?q?=D0=B0=D0=B6=D0=B4=D0=BE=D0=B9=20=D0=BD=D0=BE=D0=B2=D0=BE=D1=81?= =?UTF-8?q?=D1=82=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/News.py | 12 +++++++----- App/Portal.py | 5 ++--- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/App/News.py b/App/News.py index bb7bd17..fe69ad0 100644 --- a/App/News.py +++ b/App/News.py @@ -4,13 +4,14 @@ class News: """Класс служит для хранения и обработки информации свзянной с отдельной новостью.""" - def __init__(self, entry): + def __init__(self, entry, channel_name): logging.info("Creating object News") try: self.title = entry.title self.date = entry.published self.summary = entry.summary self.link = entry.link + self.channel_name = channel_name except Exception as e: raise FatalError("Problems with article processing") self.images = [] @@ -46,10 +47,11 @@ def clear_text(self): logging.warning("Problems with tag parsing:\n" + str(e)) def __str__(self): - string = "Title: {0}\n" \ - "Date: {1}\n" \ - "Link: {2}\n\n" \ - "Summary: {3}".format(self.title, self.date, self.link, self.summary) + string = "Channel name: {0}\n" \ + "Title: {1}\n" \ + "Date: {2}\n" \ + "Link: {3}\n\n" \ + "Summary: {4}".format(self.channel_name, self.title, self.date, self.link, self.summary) if len(self.images) > 0: string = string + "\n\nImages in the article:" for img in self.images: diff --git a/App/Portal.py b/App/Portal.py index d6e97fe..0396a0c 100644 --- a/App/Portal.py +++ b/App/Portal.py @@ -38,7 +38,7 @@ def update(self, entries): if self.updated != rss.feed.updated: self.updated = rss.feed.updated for entry in entries: - self.news.insert(0, News(entry)) + self.news.insert(0, News(entry, self.title)) except FatalError: raise except Exception as e: @@ -59,7 +59,6 @@ def print(self, limit, json_flag): print(json.dumps(main_dict, ensure_ascii=False, indent=4)) else: logging.info("Saving to text") - print("\n\nRSS-chanel\n" - "Title: {0}\n".format(self.title)) + print("\n\nRSS-chanel") for news in self.news[:limit]: print("*" * 20 + "New article" + "*" * 20 + "\n{0}\n".format(news)) From 3971278084ade5fc6d58b4207f242b87a2a7b896 Mon Sep 17 00:00:00 2001 From: ilyaborodin Date: Fri, 29 Nov 2019 18:05:19 +0300 Subject: [PATCH 08/23] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=20saver?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/News.py | 13 +++++++++++++ App/RSSListener.py | 9 ++++++--- App/Saver.py | 30 ++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 App/Saver.py diff --git a/App/News.py b/App/News.py index fe69ad0..08c6bfe 100644 --- a/App/News.py +++ b/App/News.py @@ -7,6 +7,7 @@ class News: def __init__(self, entry, channel_name): logging.info("Creating object News") try: + self.parsed_date = self.pars_date(entry.published_parsed) self.title = entry.title self.date = entry.published self.summary = entry.summary @@ -18,6 +19,18 @@ def __init__(self, entry, channel_name): self.links = [] self.clear_text() + def pars_date(self, struct): + """Parsed date to string""" + year = str(struct.tm_year) + mon = str(struct.tm_mon) + if len(mon) < 2: + mon = "0" + mon + day = str(struct.tm_mday) + if len(day) < 2: + day = "0" + day + return year + mon + day + + def del_tags(self, ind1, ind2, ind3, delta=0, items=None): """В зависимости от входных параметров, метод может удалять ишние теги или сохранять ссылки на картинки""" diff --git a/App/RSSListener.py b/App/RSSListener.py index e0c9be4..68d0029 100644 --- a/App/RSSListener.py +++ b/App/RSSListener.py @@ -1,6 +1,7 @@ import logging from App.Portal import Portal from App.Errors import FatalError +from App.Saver import Saver class RSSListener: """Класс листенер. Обрабатывает новые rss ссылки. @@ -9,20 +10,22 @@ class RSSListener: def __init__(self, limit, json_flag): logging.info("Creating object RSSListener") - self.portals = [] self.limit = limit self.json_flag = json_flag + self.portal = None def start(self, url): """Метод принимает url и пускает его в обработку""" logging.info("We begin to process the url") try: - self.portals.append(Portal(url)) + self.portal = Portal(url) + saver = Saver(self.portal.news) + saver.start_saving() except FatalError: raise except Exception as e: raise FatalError("Something go wrong") try: - self.portals[0].print(self.limit, self.json_flag) + self.portal.print(self.limit, self.json_flag) except Exception as e: raise FatalError("Problems with printing") diff --git a/App/Saver.py b/App/Saver.py new file mode 100644 index 0000000..965b523 --- /dev/null +++ b/App/Saver.py @@ -0,0 +1,30 @@ +import pickle +import os + + +class Saver: + def __init__(self, news_list): + self.news_list = news_list + self.date_handler = {} + + def sort(self): + for news in self.news_list: + if news.parsed_date in self.date_handler: + self.date_handler[news.parsed_date].append(news) + else: + self.date_handler[news.parsed_date] = [news, ] + + def save(self): + for date in self.date_handler: + if os.path.exists("./Cache/" + date): + with open("./Cache/" + date, 'rb') as f: + old_date = pickle.load(f) + with open("./Cache/" + date, 'wb') as f: + pickle.dump(old_date + self.date_handler[date], f) + else: + with open("./Cache/" + date, 'wb') as f: + pickle.dump(self.date_handler[date], f) + + def start_saving(self): + self.sort() + self.save() From 39fddde45f4a2aa343b8ad14f798b9a9aa56d50b Mon Sep 17 00:00:00 2001 From: ilyaborodin Date: Fri, 29 Nov 2019 18:16:01 +0300 Subject: [PATCH 09/23] =?UTF-8?q?=D0=A3=D0=B1=D1=80=D0=B0=D0=BB=20limit=20?= =?UTF-8?q?=D1=81=20print=20=D0=B8=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B5=D0=B3=D0=BE=20=D0=B2=20=D0=BC=D0=B5=D1=82=D0=BE?= =?UTF-8?q?=D0=B4=20update?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/Portal.py | 18 +++++++++--------- App/RSSListener.py | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/App/Portal.py b/App/Portal.py index 0396a0c..d9505b9 100644 --- a/App/Portal.py +++ b/App/Portal.py @@ -8,7 +8,7 @@ class Portal: """Класс служит для хранения и обработки информации свзянной с одним новостным порталом.""" - def __init__(self, url): + def __init__(self, url, limit): logging.info("Creating object Portal") self.url = url rss = self.get_rss() @@ -18,7 +18,7 @@ def __init__(self, url): self.updated = None self.news = [] self.links = [] - self.update(rss.entries[::-1]) + self.update(rss.entries[::-1], limit) except Exception as e: raise FatalError("Problems with rss processing") @@ -30,28 +30,28 @@ def get_rss(self): except Exception as e: raise FatalError("Problems getting rss file") - def update(self, entries): + def update(self, entries, limit): """Метод служит для получения(добавления новых в будущем) статей""" logging.info("Start processing article") + if limit is None or limit > len(entries): + limit = len(entries) try: rss = self.get_rss() if self.updated != rss.feed.updated: self.updated = rss.feed.updated - for entry in entries: + for entry in entries[:limit]: self.news.insert(0, News(entry, self.title)) except FatalError: raise except Exception as e: raise FatalError("Problems with article processing") - def print(self, limit, json_flag): + def print(self, json_flag): """Метод выводит информацию о портале и о статьях""" - if limit is None or limit > len(self.news): - limit = len(self.news) if json_flag: logging.info("Saving to json") json_news = [] - for news in self.news[:limit]: + for news in self.news: json_news.append({"Title": news.title, "Date": news.date, "Link": news.link, "Summary": news.summary, "Images": news.images, "Links": news.links}) main_dict = {"Title": self.title, "Url": self.url, "News": json_news} @@ -60,5 +60,5 @@ def print(self, limit, json_flag): else: logging.info("Saving to text") print("\n\nRSS-chanel") - for news in self.news[:limit]: + for news in self.news: print("*" * 20 + "New article" + "*" * 20 + "\n{0}\n".format(news)) diff --git a/App/RSSListener.py b/App/RSSListener.py index 68d0029..ec7e714 100644 --- a/App/RSSListener.py +++ b/App/RSSListener.py @@ -18,7 +18,7 @@ def start(self, url): """Метод принимает url и пускает его в обработку""" logging.info("We begin to process the url") try: - self.portal = Portal(url) + self.portal = Portal(url, self.limit) saver = Saver(self.portal.news) saver.start_saving() except FatalError: @@ -26,6 +26,6 @@ def start(self, url): except Exception as e: raise FatalError("Something go wrong") try: - self.portal.print(self.limit, self.json_flag) + self.portal.print(self.json_flag) except Exception as e: raise FatalError("Problems with printing") From 2f3b6748bb3981a78f2ab0cd94bf387f4c187240 Mon Sep 17 00:00:00 2001 From: ilyaborodin Date: Fri, 29 Nov 2019 21:00:52 +0300 Subject: [PATCH 10/23] =?UTF-8?q?=D0=92=D1=8B=D0=BF=D0=BE=D0=BB=D0=BD?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=203-=D0=B0=D1=8F=20=D0=B8=D1=82=D0=B5=D1=80?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/Args_parser.py | 4 ++++ App/Errors.py | 2 +- App/News.py | 1 + App/Portal.py | 45 +++++++++++++++++++++++++++--------------- App/RSSListener.py | 21 +++++++++++++------- App/Saver.py | 49 +++++++++++++++++++++++++++++++--------------- App/rss_reader.py | 2 +- 7 files changed, 83 insertions(+), 41 deletions(-) diff --git a/App/Args_parser.py b/App/Args_parser.py index 954ed35..e3517f0 100644 --- a/App/Args_parser.py +++ b/App/Args_parser.py @@ -1,5 +1,6 @@ import argparse import sys +import App import logging from App.Errors import FatalError @@ -13,6 +14,7 @@ def parsing_args(): parser.add_argument('--json', action="store_true", help='Print result as JSON in stdout') parser.add_argument('--verbose', action="store_true", help='Outputs verbose status messages') parser.add_argument('--limit', type=int, help='Limit news topics if this parameter provided') + parser.add_argument('--date', type=str, help='Date for which you want to display news (format %y%m%d)') return parser.parse_args() @@ -26,3 +28,5 @@ def start_settings(args): logging.basicConfig(level=logging.CRITICAL) if args.limit is not None and args.limit < 0: raise FatalError("Limit cannot be less than 0") + if args.date is not None and (len(args.date) != 8 or args.date.isdigit() is False): + raise FatalError("Invalid date format") diff --git a/App/Errors.py b/App/Errors.py index 0262fe4..7b90c4c 100644 --- a/App/Errors.py +++ b/App/Errors.py @@ -1,3 +1,3 @@ class FatalError(Exception): def __init__(self, text): - self.__str__ = text \ No newline at end of file + self.__str__ = text diff --git a/App/News.py b/App/News.py index 08c6bfe..f1de0cf 100644 --- a/App/News.py +++ b/App/News.py @@ -1,4 +1,5 @@ import logging +import time from App.Errors import FatalError class News: diff --git a/App/Portal.py b/App/Portal.py index d9505b9..df00d1c 100644 --- a/App/Portal.py +++ b/App/Portal.py @@ -17,8 +17,9 @@ def __init__(self, url, limit): self.link = rss.feed.link self.updated = None self.news = [] + self.limit = limit self.links = [] - self.update(rss.entries[::-1], limit) + self.update(rss.entries[::-1]) except Exception as e: raise FatalError("Problems with rss processing") @@ -30,11 +31,13 @@ def get_rss(self): except Exception as e: raise FatalError("Problems getting rss file") - def update(self, entries, limit): + def update(self, entries): """Метод служит для получения(добавления новых в будущем) статей""" logging.info("Start processing article") - if limit is None or limit > len(entries): + if self.limit is None or self.limit > len(entries): limit = len(entries) + else: + limit = self.limit try: rss = self.get_rss() if self.updated != rss.feed.updated: @@ -46,19 +49,29 @@ def update(self, entries, limit): except Exception as e: raise FatalError("Problems with article processing") + def load_new_news(self, news): + if self.limit is None or self.limit > len(news): + self.news = news + else: + self.news = news[:self.limit] + def print(self, json_flag): """Метод выводит информацию о портале и о статьях""" - if json_flag: - logging.info("Saving to json") - json_news = [] - for news in self.news: - json_news.append({"Title": news.title, "Date": news.date, "Link": news.link, - "Summary": news.summary, "Images": news.images, "Links": news.links}) - main_dict = {"Title": self.title, "Url": self.url, "News": json_news} + try: + if json_flag: + logging.info("Saving to json") + json_news = [] + for news in self.news: + json_news.append({"Title": news.title, "Date": news.date, "Link": news.link, + "Summary": news.summary, "Images": news.images, "Links": news.links}) + main_dict = {"Title": self.title, "Url": self.url, "News": json_news} - print(json.dumps(main_dict, ensure_ascii=False, indent=4)) - else: - logging.info("Saving to text") - print("\n\nRSS-chanel") - for news in self.news: - print("*" * 20 + "New article" + "*" * 20 + "\n{0}\n".format(news)) + print(json.dumps(main_dict, ensure_ascii=False, indent=4)) + else: + logging.info("Saving to text") + print("\n\nRSS-chanel") + for news in self.news: + print("*" * 20 + "New article" + "*" * 20 + "\n{0}\n".format(news)) + except Exception as e: + logging.error(str(e)) + raise FatalError("Problems with printing") diff --git a/App/RSSListener.py b/App/RSSListener.py index ec7e714..b6d4e15 100644 --- a/App/RSSListener.py +++ b/App/RSSListener.py @@ -8,10 +8,11 @@ class RSSListener: Постороен так, что в будущем при добавлении минимального функционала, будет обрабатывать и сохранять новости из разных источников""" - def __init__(self, limit, json_flag): + def __init__(self, limit, json_flag, date): logging.info("Creating object RSSListener") self.limit = limit self.json_flag = json_flag + self.date = date self.portal = None def start(self, url): @@ -19,13 +20,19 @@ def start(self, url): logging.info("We begin to process the url") try: self.portal = Portal(url, self.limit) - saver = Saver(self.portal.news) - saver.start_saving() + saver = Saver() + saver.start_saving(self.portal.news) + if self.date is not None: + old_news = saver.load(self.date) + if old_news is not None: + self.portal.load_new_news(old_news) + self.portal.print(self.json_flag) + else: + print("Error: news haven't been founded") + + else: + self.portal.print(self.json_flag) except FatalError: raise except Exception as e: raise FatalError("Something go wrong") - try: - self.portal.print(self.json_flag) - except Exception as e: - raise FatalError("Problems with printing") diff --git a/App/Saver.py b/App/Saver.py index 965b523..b176e3f 100644 --- a/App/Saver.py +++ b/App/Saver.py @@ -1,30 +1,47 @@ import pickle import os +import logging class Saver: - def __init__(self, news_list): - self.news_list = news_list - self.date_handler = {} - - def sort(self): - for news in self.news_list: - if news.parsed_date in self.date_handler: - self.date_handler[news.parsed_date].append(news) + def sort(self, news_list): + date_handler = {} + for news in news_list: + if news.parsed_date in date_handler: + date_handler[news.parsed_date].append(news) else: - self.date_handler[news.parsed_date] = [news, ] + date_handler[news.parsed_date] = [news, ] + return date_handler - def save(self): - for date in self.date_handler: + def save(self, date_handler): + for date in date_handler: if os.path.exists("./Cache/" + date): with open("./Cache/" + date, 'rb') as f: old_date = pickle.load(f) + delete_list = [] + for new_d in date_handler[date]: + for old_d in old_date: + if str(new_d) == str(old_d): + delete_list.append(new_d) + for new_d in delete_list: + date_handler[date].remove(new_d) with open("./Cache/" + date, 'wb') as f: - pickle.dump(old_date + self.date_handler[date], f) + pickle.dump(old_date + date_handler[date], f) else: with open("./Cache/" + date, 'wb') as f: - pickle.dump(self.date_handler[date], f) + pickle.dump(date_handler[date], f) + + def start_saving(self, news_list): + try: + handler = self.sort(news_list) + self.save(handler) + except Exception as e: + logging.error("Saving error") + logging.error(str(e)) - def start_saving(self): - self.sort() - self.save() + def load(self, date): + if not os.path.exists("./Cache/" + date): + return None + with open("./Cache/" + date, 'rb') as f: + old_news = pickle.load(f) + return old_news diff --git a/App/rss_reader.py b/App/rss_reader.py index a1a6d04..ae1858a 100755 --- a/App/rss_reader.py +++ b/App/rss_reader.py @@ -9,7 +9,7 @@ def main(): args = Args_parser.parsing_args() Args_parser.start_settings(args) logging.info("Program launch") - rss_listener = RSSListener(args.limit, args.json) + rss_listener = RSSListener(args.limit, args.json, args.date) rss_listener.start(args.source) except Exception as e: print(str(e)) From 40fb83455dfba86625b883a4d28bc38b5a0610b6 Mon Sep 17 00:00:00 2001 From: Ilya Borodin <48887908+ilyaborodin@users.noreply.github.com> Date: Fri, 29 Nov 2019 21:14:07 +0300 Subject: [PATCH 11/23] =?UTF-8?q?=D1=81=D0=BE=D0=B7=D0=B4=D0=B0=D0=BB=20Re?= =?UTF-8?q?adme?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..6ba21b5 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +h1 FinalTask From 69fadd61f4dfbb35ab4614f4f01e43acf9092960 Mon Sep 17 00:00:00 2001 From: Ilya Borodin <48887908+ilyaborodin@users.noreply.github.com> Date: Fri, 29 Nov 2019 21:20:59 +0300 Subject: [PATCH 12/23] Update README.md --- README.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6ba21b5..2860200 100644 --- a/README.md +++ b/README.md @@ -1 +1,16 @@ -h1 FinalTask +# FinalTask + +## 1 iter + +Выполнена + +## 2 iter + +Выполнена + +## 3 iter + +Выполнена. +Для хранения данных использовал pickle. Данные храню +в папке Cache. Название файлов соответствуют дате статей, хранящихся там. +Отвечает за загрузку и выгрузку статей из файла класс Saver From b6867ecc59a263662ce3ddf3c625bcc1ddb4d5e9 Mon Sep 17 00:00:00 2001 From: Ilya Borodin <48887908+ilyaborodin@users.noreply.github.com> Date: Fri, 29 Nov 2019 21:24:39 +0300 Subject: [PATCH 13/23] =?UTF-8?q?=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0=D0=BB=20?= =?UTF-8?q?=D0=BF=D0=B0=D0=BF=D0=BA=D1=83=20=D0=B4=D0=BB=D1=8F=20=D1=85?= =?UTF-8?q?=D1=80=D0=B0=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B4=D0=B0=D0=BD?= =?UTF-8?q?=D0=BD=D1=8B=D1=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cache/.gitkeep | 1 + 1 file changed, 1 insertion(+) create mode 100644 Cache/.gitkeep diff --git a/Cache/.gitkeep b/Cache/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/Cache/.gitkeep @@ -0,0 +1 @@ + From 94d057d559386d7c769ce0880ac65ff43d1c3e7a Mon Sep 17 00:00:00 2001 From: ilyaborodin Date: Sat, 30 Nov 2019 04:54:26 +0300 Subject: [PATCH 14/23] =?UTF-8?q?=D0=92=D1=8B=D0=BF=D0=BE=D0=BB=D0=BD?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=204-=D0=B0=D1=8F=20=D0=B8=D1=82=D0=B5=D1=80?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Добавлены классы ToPDF и ToHtml Добавлены новые аругемнты для конвертации Изменена версия программы --- App/Args_parser.py | 3 ++- App/News.py | 7 +++---- App/Portal.py | 24 ++++++++++++++++++++++++ App/RSSListener.py | 18 ++++++++++++++---- App/Saver.py | 7 +++++++ App/ToHtml.py | 46 ++++++++++++++++++++++++++++++++++++++++++++++ App/ToPDF.py | 24 ++++++++++++++++++++++++ App/__init__.py | 2 +- App/rss_reader.py | 2 +- setup.py | 2 +- 10 files changed, 123 insertions(+), 12 deletions(-) create mode 100644 App/ToHtml.py create mode 100644 App/ToPDF.py diff --git a/App/Args_parser.py b/App/Args_parser.py index e3517f0..ff2fda1 100644 --- a/App/Args_parser.py +++ b/App/Args_parser.py @@ -5,7 +5,6 @@ from App.Errors import FatalError - def parsing_args(): """Парсим аргументы""" parser = argparse.ArgumentParser(description='Pure Python command-line RSS reader.') @@ -15,6 +14,8 @@ def parsing_args(): parser.add_argument('--verbose', action="store_true", help='Outputs verbose status messages') parser.add_argument('--limit', type=int, help='Limit news topics if this parameter provided') parser.add_argument('--date', type=str, help='Date for which you want to display news (format %y%m%d)') + parser.add_argument('--to_html', type=str, help='Convert data to html to your path') + parser.add_argument('--to_pdf', type=str, help='Convert data to pdf to your path') return parser.parse_args() diff --git a/App/News.py b/App/News.py index f1de0cf..98e3770 100644 --- a/App/News.py +++ b/App/News.py @@ -1,7 +1,7 @@ import logging -import time from App.Errors import FatalError + class News: """Класс служит для хранения и обработки информации свзянной с отдельной новостью.""" @@ -14,14 +14,14 @@ def __init__(self, entry, channel_name): self.summary = entry.summary self.link = entry.link self.channel_name = channel_name - except Exception as e: + except: raise FatalError("Problems with article processing") self.images = [] self.links = [] self.clear_text() def pars_date(self, struct): - """Parsed date to string""" + """Parse date to string""" year = str(struct.tm_year) mon = str(struct.tm_mon) if len(mon) < 2: @@ -31,7 +31,6 @@ def pars_date(self, struct): day = "0" + day return year + mon + day - def del_tags(self, ind1, ind2, ind3, delta=0, items=None): """В зависимости от входных параметров, метод может удалять ишние теги или сохранять ссылки на картинки""" diff --git a/App/Portal.py b/App/Portal.py index df00d1c..3a309a8 100644 --- a/App/Portal.py +++ b/App/Portal.py @@ -3,6 +3,9 @@ import json from App.Errors import FatalError from App.News import News +from App.ToHtml import ToHtml +from App.ToPDF import ToPDF +import traceback class Portal: @@ -75,3 +78,24 @@ def print(self, json_flag): except Exception as e: logging.error(str(e)) raise FatalError("Problems with printing") + + def convert_to_html(self, html_path): + """Convert news to html""" + logging.info("Start converting news to html") + try: + to_html = ToHtml(self.news, html_path) + to_html.make_file() + except Exception as e: + print("Error with converting to html") + logging.info(str(e)) + + def convert_to_pdf(self, pdf_path): + """Convert news to pdf""" + logging.info("Start converting news to pdf") + try: + to_html = ToHtml(self.news) + to_pdf = ToPDF(to_html.html, pdf_path) + to_pdf.make_file() + except Exception as e: + print("Error with converting to pdf") + logging.info(str(e)) diff --git a/App/RSSListener.py b/App/RSSListener.py index b6d4e15..ee5e812 100644 --- a/App/RSSListener.py +++ b/App/RSSListener.py @@ -3,17 +3,20 @@ from App.Errors import FatalError from App.Saver import Saver + class RSSListener: """Класс листенер. Обрабатывает новые rss ссылки. Постороен так, что в будущем при добавлении минимального функционала, будет обрабатывать и сохранять новости из разных источников""" - def __init__(self, limit, json_flag, date): + def __init__(self, limit, json_flag, date, html_path, pdf_path): logging.info("Creating object RSSListener") self.limit = limit - self.json_flag = json_flag self.date = date self.portal = None + self.json_flag = json_flag + self.html_path = html_path + self.pdf_path = pdf_path def start(self, url): """Метод принимает url и пускает его в обработку""" @@ -26,13 +29,20 @@ def start(self, url): old_news = saver.load(self.date) if old_news is not None: self.portal.load_new_news(old_news) - self.portal.print(self.json_flag) + self.printing() else: print("Error: news haven't been founded") else: - self.portal.print(self.json_flag) + self.printing() + if self.html_path is not None: + self.portal.convert_to_html(self.html_path) + if self.pdf_path is not None: + self.portal.convert_to_pdf(self.pdf_path) except FatalError: raise except Exception as e: raise FatalError("Something go wrong") + + def printing(self): + self.portal.print(self.json_flag) \ No newline at end of file diff --git a/App/Saver.py b/App/Saver.py index b176e3f..e2596e0 100644 --- a/App/Saver.py +++ b/App/Saver.py @@ -4,7 +4,10 @@ class Saver: + """The class is responsible for saving and unloading data.""" def sort(self, news_list): + """The method sorts news from the link by date""" + logging.info("Sorting news in saver") date_handler = {} for news in news_list: if news.parsed_date in date_handler: @@ -14,6 +17,8 @@ def sort(self, news_list): return date_handler def save(self, date_handler): + """Save data""" + logging.info("Saving data") for date in date_handler: if os.path.exists("./Cache/" + date): with open("./Cache/" + date, 'rb') as f: @@ -40,6 +45,8 @@ def start_saving(self, news_list): logging.error(str(e)) def load(self, date): + """Load data from files""" + logging.info("Loading data from files") if not os.path.exists("./Cache/" + date): return None with open("./Cache/" + date, 'rb') as f: diff --git a/App/ToHtml.py b/App/ToHtml.py new file mode 100644 index 0000000..57c4965 --- /dev/null +++ b/App/ToHtml.py @@ -0,0 +1,46 @@ +import logging + + +class ToHtml: + """Class responsible for converting data to html""" + def __init__(self, news, path="./news.html"): + self.news = news + self.path = path + self.html = self.make_html() + + def make_html(self): + """Create html""" + logging.info("Creating html") + html = """ + + + + News + + + """ + for entry in self.news: + html += f"

{entry.title}

" + html += f"

Channel name: {entry.channel_name}

" + html += f"

Date: {entry.date}

" + html += f"

Link

" + for img in entry.images: + html += f"

" + html += f"

{entry.summary}

" + if len(entry.links) > 0: + counter = 0 + html += "

Links in the article:

" + for link in entry.links: + counter += 1 + html += f"

Link №{counter}

" + html += "" + return html + + def make_file(self): + """Create html file""" + logging.info("Creating html file") + try: + with open(self.path, 'w') as f: + f.write(self.html) + except: + print("Saving file error. Problems with path") diff --git a/App/ToPDF.py b/App/ToPDF.py new file mode 100644 index 0000000..cce21f6 --- /dev/null +++ b/App/ToPDF.py @@ -0,0 +1,24 @@ +import weasyprint +import logging + + +class ToPDF: + """Class responsible for converting data to pdf""" + def __init__(self, html, path="./news.pdf"): + self.html = html + self.path = path + self.pdf = self.make_pdf() + + def make_pdf(self): + """Create pdf""" + logging.info("Creating pdf") + return weasyprint.HTML(string=self.html).write_pdf() + + def make_file(self): + """Create pdf file""" + logging.info("Creating pdf file") + try: + with open(self.path, "wb") as f: + f.write(self.pdf) + except: + print("Saving file error. Problems with path") diff --git a/App/__init__.py b/App/__init__.py index f2dc0e4..b777be9 100644 --- a/App/__init__.py +++ b/App/__init__.py @@ -1 +1 @@ -__version__ = "2.0" +__version__ = "4.0" diff --git a/App/rss_reader.py b/App/rss_reader.py index ae1858a..54e2df0 100755 --- a/App/rss_reader.py +++ b/App/rss_reader.py @@ -9,7 +9,7 @@ def main(): args = Args_parser.parsing_args() Args_parser.start_settings(args) logging.info("Program launch") - rss_listener = RSSListener(args.limit, args.json, args.date) + rss_listener = RSSListener(args.limit, args.json, args.date, args.to_html, args.to_pdf) rss_listener.start(args.source) except Exception as e: print(str(e)) diff --git a/setup.py b/setup.py index 7ae5d95..f1f601a 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ author_email="ilya.borodin8@gmail.com", url="https://github.com/ilyaborodin/PythonHomework/tree/Final_Task", packages=find_packages(), - install_requires=['feedparser==5.2.1'], + install_requires=['feedparser==5.2.1', 'weasyprint'], python_requires='>=3.8', entry_points={ "console_scripts": ["rss-reader=App.rss_reader:main"], From 5969654fc22b3e8183428b3294ca3d946ae19320 Mon Sep 17 00:00:00 2001 From: Ilya Borodin <48887908+ilyaborodin@users.noreply.github.com> Date: Sat, 30 Nov 2019 05:05:41 +0300 Subject: [PATCH 15/23] Update README.md --- README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README.md b/README.md index 2860200..3a3284e 100644 --- a/README.md +++ b/README.md @@ -14,3 +14,18 @@ Для хранения данных использовал pickle. Данные храню в папке Cache. Название файлов соответствуют дате статей, хранящихся там. Отвечает за загрузку и выгрузку статей из файла класс Saver + +## 4 iter + +Выполнена +Данные сохраняю в формат html и pdf +В условиях не было указано в каком формате поставляется, поэтому выбрал для этого свой. +Путь должен содержать название файла и формат. +Примеры: +/home/ilya/snap/test.pdf +./test.html + +## Help +usage: rss-reader [-h] [--version] [--json] [--verbose] [--limit LIMIT] + [--date DATE] [--to_html TO_HTML] [--to_pdf TO_PDF] + source From 33a66cc31980203e4d7b8b66711c00bd34e9452f Mon Sep 17 00:00:00 2001 From: ilyaborodin Date: Sat, 30 Nov 2019 05:14:49 +0300 Subject: [PATCH 16/23] =?UTF-8?q?=D0=A3=D0=B1=D1=80=D0=B0=D0=BB=20=D0=BB?= =?UTF-8?q?=D0=B8=D1=88=D0=BD=D0=B8=D0=B9=20=D0=B8=D0=BC=D0=BF=D0=BE=D1=80?= =?UTF-8?q?=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/Portal.py | 1 - 1 file changed, 1 deletion(-) diff --git a/App/Portal.py b/App/Portal.py index 3a309a8..ead0a9b 100644 --- a/App/Portal.py +++ b/App/Portal.py @@ -5,7 +5,6 @@ from App.News import News from App.ToHtml import ToHtml from App.ToPDF import ToPDF -import traceback class Portal: From 5f126bbd4cef20dd0b9e8c2fed9554b84eb64298 Mon Sep 17 00:00:00 2001 From: ilyaborodin Date: Sat, 30 Nov 2019 20:28:41 +0300 Subject: [PATCH 17/23] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=B2=D0=B5?= =?UTF-8?q?=D0=BB=20=D0=B4=D0=BE=D0=BA=D1=83=D0=BC=D0=B5=D0=BD=D1=82=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D1=8E=20=D0=BD=D0=B0=20=D0=B0=D0=BD=D0=B3=D0=BB?= =?UTF-8?q?=D0=B8=D0=B9=D1=81=D0=BA=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/Args_parser.py | 4 ++-- App/Errors.py | 1 + App/News.py | 9 ++++----- App/Portal.py | 8 ++++---- App/RSSListener.py | 6 ++---- 5 files changed, 13 insertions(+), 15 deletions(-) diff --git a/App/Args_parser.py b/App/Args_parser.py index ff2fda1..51dcad6 100644 --- a/App/Args_parser.py +++ b/App/Args_parser.py @@ -6,7 +6,7 @@ def parsing_args(): - """Парсим аргументы""" + """Parsing arguments""" parser = argparse.ArgumentParser(description='Pure Python command-line RSS reader.') parser.add_argument('source', type=str, help='RSS URL') parser.add_argument('--version', action="store_true", help='Print version info') @@ -20,7 +20,7 @@ def parsing_args(): def start_settings(args): - """Проверяем аргументы и действуем согласно их сценарию""" + """Check the arguments and act according to their scenario""" if args.version: print("*" * 50 + "\n" + "Version: " + App.__version__ + "\n" + "*" * 50 + "\n" * 2) if args.verbose: diff --git a/App/Errors.py b/App/Errors.py index 7b90c4c..d9d61d2 100644 --- a/App/Errors.py +++ b/App/Errors.py @@ -1,3 +1,4 @@ class FatalError(Exception): + """An error in which we forcefully terminate the program""" def __init__(self, text): self.__str__ = text diff --git a/App/News.py b/App/News.py index 98e3770..8bd0b30 100644 --- a/App/News.py +++ b/App/News.py @@ -3,7 +3,7 @@ class News: - """Класс служит для хранения и обработки информации свзянной с отдельной новостью.""" + """The class is used to store and process information related to a separate news item.""" def __init__(self, entry, channel_name): logging.info("Creating object News") @@ -32,8 +32,7 @@ def pars_date(self, struct): return year + mon + day def del_tags(self, ind1, ind2, ind3, delta=0, items=None): - """В зависимости от входных параметров, метод может удалять ишние теги или - сохранять ссылки на картинки""" + """Depending on the input parameters, the method may remove unnecessary tags or save links to images""" logging.info("Tag processing") while self.summary.find(ind1) != -1: index1 = self.summary.index(ind1) @@ -44,8 +43,8 @@ def del_tags(self, ind1, ind2, ind3, delta=0, items=None): self.summary = self.summary[0:index1] + self.summary[index1 + index3 + 2:] def clear_text(self): - """Метод запускающий del_tags() в различной конфигурации - Это требуется, потому что на некоторых порталах в summary чатсть информации является \"мусором\"""" + """Method running del_tags () in a different configuration. +This is required because on some portals in summary, some of the information is unnecessary.""" logging.info("Improvement summary and and search for pictures and links") try: self.del_tags("", 10, self.images) diff --git a/App/Portal.py b/App/Portal.py index ead0a9b..d001ad1 100644 --- a/App/Portal.py +++ b/App/Portal.py @@ -8,7 +8,7 @@ class Portal: - """Класс служит для хранения и обработки информации свзянной с одним новостным порталом.""" + """The class is used to store and process information associated with one news portal""" def __init__(self, url, limit): logging.info("Creating object Portal") @@ -26,7 +26,7 @@ def __init__(self, url, limit): raise FatalError("Problems with rss processing") def get_rss(self): - """Получает rss файл""" + """Get rss file""" logging.info("Getting rss file") try: return feedparser.parse(self.url) @@ -34,7 +34,7 @@ def get_rss(self): raise FatalError("Problems getting rss file") def update(self, entries): - """Метод служит для получения(добавления новых в будущем) статей""" + """The method is used to obtain articles""" logging.info("Start processing article") if self.limit is None or self.limit > len(entries): limit = len(entries) @@ -58,7 +58,7 @@ def load_new_news(self, news): self.news = news[:self.limit] def print(self, json_flag): - """Метод выводит информацию о портале и о статьях""" + """The method displays information about the portal and articles""" try: if json_flag: logging.info("Saving to json") diff --git a/App/RSSListener.py b/App/RSSListener.py index ee5e812..8456a61 100644 --- a/App/RSSListener.py +++ b/App/RSSListener.py @@ -5,9 +5,7 @@ class RSSListener: - """Класс листенер. Обрабатывает новые rss ссылки. - Постороен так, что в будущем при добавлении минимального функционала, - будет обрабатывать и сохранять новости из разных источников""" + """""" def __init__(self, limit, json_flag, date, html_path, pdf_path): logging.info("Creating object RSSListener") @@ -19,7 +17,7 @@ def __init__(self, limit, json_flag, date, html_path, pdf_path): self.pdf_path = pdf_path def start(self, url): - """Метод принимает url и пускает его в обработку""" + """Class listener. Handles new rss links and saved news""" logging.info("We begin to process the url") try: self.portal = Portal(url, self.limit) From ce0c8e1d06d7fff921682e26f619deed73f0da3d Mon Sep 17 00:00:00 2001 From: ilyaborodin Date: Sat, 30 Nov 2019 21:35:21 +0300 Subject: [PATCH 18/23] =?UTF-8?q?=D0=92=D1=8B=D0=BF=D0=BE=D0=BB=D0=BD?= =?UTF-8?q?=D0=B8=D0=BB=205-=D1=83=D1=8E=20=D0=B8=D1=82=D0=B5=D1=80=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/Args_parser.py | 5 +++++ App/Colors.py | 7 +++++++ App/Portal.py | 11 +++++++---- App/RSSListener.py | 6 ++++-- App/ToHtml.py | 4 +++- App/ToPDF.py | 4 +++- App/__init__.py | 2 +- App/rss_reader.py | 6 ++++-- setup.py | 2 +- 9 files changed, 35 insertions(+), 12 deletions(-) create mode 100644 App/Colors.py diff --git a/App/Args_parser.py b/App/Args_parser.py index 51dcad6..61fb4a1 100644 --- a/App/Args_parser.py +++ b/App/Args_parser.py @@ -3,6 +3,7 @@ import App import logging from App.Errors import FatalError +from App.Colors import Colors def parsing_args(): @@ -16,6 +17,7 @@ def parsing_args(): parser.add_argument('--date', type=str, help='Date for which you want to display news (format %y%m%d)') parser.add_argument('--to_html', type=str, help='Convert data to html to your path') parser.add_argument('--to_pdf', type=str, help='Convert data to pdf to your path') + parser.add_argument('--colorize', action="store_true", help='colorful output') return parser.parse_args() @@ -31,3 +33,6 @@ def start_settings(args): raise FatalError("Limit cannot be less than 0") if args.date is not None and (len(args.date) != 8 or args.date.isdigit() is False): raise FatalError("Invalid date format") + if not args.colorize: + for color in Colors: + Colors[color] = "white" diff --git a/App/Colors.py b/App/Colors.py new file mode 100644 index 0000000..462feb4 --- /dev/null +++ b/App/Colors.py @@ -0,0 +1,7 @@ +"""Dictionary stores output colors""" +Colors = { + "error": "red", + "article": "blue", + "text": "yellow", + "other": "green" +} \ No newline at end of file diff --git a/App/Portal.py b/App/Portal.py index d001ad1..2dece31 100644 --- a/App/Portal.py +++ b/App/Portal.py @@ -5,6 +5,8 @@ from App.News import News from App.ToHtml import ToHtml from App.ToPDF import ToPDF +from termcolor import colored +from App.Colors import Colors class Portal: @@ -71,9 +73,10 @@ def print(self, json_flag): print(json.dumps(main_dict, ensure_ascii=False, indent=4)) else: logging.info("Saving to text") - print("\n\nRSS-chanel") + print(colored("\n\nRSS-chanel", Colors["other"])) for news in self.news: - print("*" * 20 + "New article" + "*" * 20 + "\n{0}\n".format(news)) + print(colored("*" * 20 + "New article" + "*" * 20 + "\n", Colors["article"])) + print(colored(news, Colors["text"])) except Exception as e: logging.error(str(e)) raise FatalError("Problems with printing") @@ -85,7 +88,7 @@ def convert_to_html(self, html_path): to_html = ToHtml(self.news, html_path) to_html.make_file() except Exception as e: - print("Error with converting to html") + print(colored("Error with converting to html", Colors["error"])) logging.info(str(e)) def convert_to_pdf(self, pdf_path): @@ -96,5 +99,5 @@ def convert_to_pdf(self, pdf_path): to_pdf = ToPDF(to_html.html, pdf_path) to_pdf.make_file() except Exception as e: - print("Error with converting to pdf") + print(colored("Error with converting to pdf", Colors["error"])) logging.info(str(e)) diff --git a/App/RSSListener.py b/App/RSSListener.py index 8456a61..b55d034 100644 --- a/App/RSSListener.py +++ b/App/RSSListener.py @@ -2,6 +2,8 @@ from App.Portal import Portal from App.Errors import FatalError from App.Saver import Saver +from termcolor import colored +from App.Colors import Colors class RSSListener: @@ -29,7 +31,7 @@ def start(self, url): self.portal.load_new_news(old_news) self.printing() else: - print("Error: news haven't been founded") + print(colored("Error: news haven't been founded", Colors["error"])) else: self.printing() @@ -43,4 +45,4 @@ def start(self, url): raise FatalError("Something go wrong") def printing(self): - self.portal.print(self.json_flag) \ No newline at end of file + self.portal.print(self.json_flag) diff --git a/App/ToHtml.py b/App/ToHtml.py index 57c4965..a9cff74 100644 --- a/App/ToHtml.py +++ b/App/ToHtml.py @@ -1,4 +1,6 @@ import logging +from termcolor import colored +from App.Colors import Colors class ToHtml: @@ -43,4 +45,4 @@ def make_file(self): with open(self.path, 'w') as f: f.write(self.html) except: - print("Saving file error. Problems with path") + print(colored("Saving file error. Problems with path", Colors["error"])) diff --git a/App/ToPDF.py b/App/ToPDF.py index cce21f6..c13ced1 100644 --- a/App/ToPDF.py +++ b/App/ToPDF.py @@ -1,5 +1,7 @@ import weasyprint import logging +from termcolor import colored +from App.Colors import Colors class ToPDF: @@ -21,4 +23,4 @@ def make_file(self): with open(self.path, "wb") as f: f.write(self.pdf) except: - print("Saving file error. Problems with path") + print(colored("Saving file error. Problems with path", Colors["error"])) diff --git a/App/__init__.py b/App/__init__.py index b777be9..a7fd423 100644 --- a/App/__init__.py +++ b/App/__init__.py @@ -1 +1 @@ -__version__ = "4.0" +__version__ = "5.0" diff --git a/App/rss_reader.py b/App/rss_reader.py index 54e2df0..f23481d 100755 --- a/App/rss_reader.py +++ b/App/rss_reader.py @@ -2,6 +2,8 @@ import logging from App.RSSListener import RSSListener from App import Args_parser +from termcolor import colored +from App.Colors import Colors def main(): @@ -12,12 +14,12 @@ def main(): rss_listener = RSSListener(args.limit, args.json, args.date, args.to_html, args.to_pdf) rss_listener.start(args.source) except Exception as e: - print(str(e)) + print(colored(str(e), Colors["error"])) close_program() def close_program(): - print("The program suddenly completed its work") + print(colored("The program suddenly completed its work", Colors["error"])) exit() diff --git a/setup.py b/setup.py index f1f601a..0a4c126 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ author_email="ilya.borodin8@gmail.com", url="https://github.com/ilyaborodin/PythonHomework/tree/Final_Task", packages=find_packages(), - install_requires=['feedparser==5.2.1', 'weasyprint'], + install_requires=['feedparser==5.2.1', 'weasyprint', 'termcolor'], python_requires='>=3.8', entry_points={ "console_scripts": ["rss-reader=App.rss_reader:main"], From deb03ba799ab607eac2c545e10badc010ad996d3 Mon Sep 17 00:00:00 2001 From: Ilya Borodin <48887908+ilyaborodin@users.noreply.github.com> Date: Sat, 30 Nov 2019 21:37:21 +0300 Subject: [PATCH 19/23] Update README.md --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 3a3284e..ea5f653 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,14 @@ /home/ilya/snap/test.pdf ./test.html + +## 5 iter + +Выполнена + ## Help usage: rss-reader [-h] [--version] [--json] [--verbose] [--limit LIMIT] [--date DATE] [--to_html TO_HTML] [--to_pdf TO_PDF] + [--colorize] source + From 0cdc00d4126bafaac4797fa7ddc39d30c8b3263e Mon Sep 17 00:00:00 2001 From: Ilya Borodin <48887908+ilyaborodin@users.noreply.github.com> Date: Sat, 30 Nov 2019 21:39:00 +0300 Subject: [PATCH 20/23] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index ea5f653..48cb6a8 100644 --- a/README.md +++ b/README.md @@ -36,3 +36,5 @@ usage: rss-reader [-h] [--version] [--json] [--verbose] [--limit LIMIT] [--colorize] source +## Install +python setup.py install From ac95113db89f483ce10c6f281de445b17af077b0 Mon Sep 17 00:00:00 2001 From: Ilya Borodin Date: Sat, 30 Nov 2019 22:36:31 +0300 Subject: [PATCH 21/23] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20\n=20=D0=BA=20=D0=B2=D1=8B=D0=B2=D0=BE=D0=B4=D1=83=20?= =?UTF-8?q?=D0=BD=D0=BE=D0=B2=D0=BE=D1=81=D1=82=D0=B5=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/Portal.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/App/Portal.py b/App/Portal.py index 2dece31..6fc7cfd 100644 --- a/App/Portal.py +++ b/App/Portal.py @@ -75,7 +75,7 @@ def print(self, json_flag): logging.info("Saving to text") print(colored("\n\nRSS-chanel", Colors["other"])) for news in self.news: - print(colored("*" * 20 + "New article" + "*" * 20 + "\n", Colors["article"])) + print(colored("\n" + "*" * 20 + "New article" + "*" * 20 + "\n", Colors["article"])) print(colored(news, Colors["text"])) except Exception as e: logging.error(str(e)) From 0b13159873c9b4c34c3af7c0525fad57e3949ecb Mon Sep 17 00:00:00 2001 From: Ilya Borodin Date: Mon, 2 Dec 2019 01:42:47 +0300 Subject: [PATCH 22/23] =?UTF-8?q?=D0=92=D1=8B=D0=BF=D0=BE=D0=BB=D0=BD?= =?UTF-8?q?=D0=B8=D0=BB=20=D1=87=D0=B0=D1=81=D1=82=D0=B8=D1=87=D0=BD=D0=BE?= =?UTF-8?q?=206-=D1=83=D1=8E=20=D0=B8=D1=82=D0=B5=D1=80=D0=B0=D1=86=D0=B8?= =?UTF-8?q?=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/RSSListener.py | 2 +- Dockerfile | 4 ++ PythonHomework/__init__.py | 0 PythonHomework/settings.py | 125 +++++++++++++++++++++++++++++++++++++ PythonHomework/urls.py | 21 +++++++ PythonHomework/wsgi.py | 16 +++++ docker-compose.yml | 19 ++++++ landing/__init__.py | 0 landing/forms.py | 6 ++ landing/urls.py | 23 +++++++ landing/views.py | 25 ++++++++ manage.py | 21 +++++++ templates/landing.html | 44 +++++++++++++ 13 files changed, 305 insertions(+), 1 deletion(-) create mode 100644 Dockerfile create mode 100644 PythonHomework/__init__.py create mode 100644 PythonHomework/settings.py create mode 100644 PythonHomework/urls.py create mode 100644 PythonHomework/wsgi.py create mode 100644 docker-compose.yml create mode 100644 landing/__init__.py create mode 100644 landing/forms.py create mode 100644 landing/urls.py create mode 100644 landing/views.py create mode 100755 manage.py create mode 100644 templates/landing.html diff --git a/App/RSSListener.py b/App/RSSListener.py index b55d034..ad2f552 100644 --- a/App/RSSListener.py +++ b/App/RSSListener.py @@ -7,7 +7,7 @@ class RSSListener: - """""" + """Class listener""" def __init__(self, limit, json_flag, date, html_path, pdf_path): logging.info("Creating object RSSListener") diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..404c98d --- /dev/null +++ b/Dockerfile @@ -0,0 +1,4 @@ +FROM python:latest +COPY . /serverr/ +RUN pip3 install -r ./serverr/requirements.txt +WORKDIR /serverr \ No newline at end of file diff --git a/PythonHomework/__init__.py b/PythonHomework/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/PythonHomework/settings.py b/PythonHomework/settings.py new file mode 100644 index 0000000..0daa0ea --- /dev/null +++ b/PythonHomework/settings.py @@ -0,0 +1,125 @@ +""" +Django settings for PythonHomework project. + +Generated by 'django-admin startproject' using Django 2.2.7. + +For more information on this file, see +https://docs.djangoproject.com/en/2.2/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/2.2/ref/settings/ +""" + +import os + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = '-++fsq$(tcdmr-2n#%pybeg*4m=%rot8-_c02#!m*9g@h955(o' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'PythonHomework.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [os.path.join(BASE_DIR, 'templates')] + , + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'PythonHomework.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/2.2/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.postgresql_psycopg2', + 'NAME': 'django_db', + 'USER': 'django_user', + 'PASSWORD': 'Sekret', + 'HOST': 'db', + 'PORT': '5432', + } +} + + +# Password validation +# https://docs.djangoproject.com/en/2.2/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/2.2/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/2.2/howto/static-files/ + +STATIC_URL = '/static/' diff --git a/PythonHomework/urls.py b/PythonHomework/urls.py new file mode 100644 index 0000000..c8d5183 --- /dev/null +++ b/PythonHomework/urls.py @@ -0,0 +1,21 @@ +"""PythonHomework URL Configuration + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/2.2/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" + +from django.conf.urls import url, include + +urlpatterns = [ + url(r'^', include('landing.urls')), +] diff --git a/PythonHomework/wsgi.py b/PythonHomework/wsgi.py new file mode 100644 index 0000000..507d571 --- /dev/null +++ b/PythonHomework/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for PythonHomework project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/2.2/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'PythonHomework.settings') + +application = get_wsgi_application() diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..49033a9 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,19 @@ +version: "3" +services: + db: + image: "postgres:12.1" + container_name: "my_postgres" + environment: + - POSTGRES_USER=django_user + - POSTGRES_PASSWORD=Sekret + - POSTGRES_DB=django_db + expose: + - "5432" + server: + container_name: "server" + build: ./ + command: bash -c "python3 ./manage.py migrate && python3 ./manage.py runserver 0.0.0.0:2504" + ports: + - 2504:2504 + depends_on: + - db \ No newline at end of file diff --git a/landing/__init__.py b/landing/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/landing/forms.py b/landing/forms.py new file mode 100644 index 0000000..6601c67 --- /dev/null +++ b/landing/forms.py @@ -0,0 +1,6 @@ +from django import forms + + +class MainForm(forms.Form): + rss = forms.CharField(max_length=300) + limit = forms.IntegerField() \ No newline at end of file diff --git a/landing/urls.py b/landing/urls.py new file mode 100644 index 0000000..f8862d4 --- /dev/null +++ b/landing/urls.py @@ -0,0 +1,23 @@ +"""test_project URL Configuration + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/1.10/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.conf.urls import url, include + 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) +""" +from django.conf.urls import url, include +from django.contrib import admin +from landing import views + +urlpatterns = [ + url(r'^$', views.home, name='home'), + url(r'^news', views.news, name='news'), +] diff --git a/landing/views.py b/landing/views.py new file mode 100644 index 0000000..1aa8fc9 --- /dev/null +++ b/landing/views.py @@ -0,0 +1,25 @@ +from django.shortcuts import render +from .forms import MainForm +from App.RSSListener import RSSListener + + +def home(request): + submitbutton = request.POST.get("submit") + + rss = '' + limit = 20 + + form = MainForm(request.POST or None) + if form.is_valid(): + rss = form.cleaned_data.get("rss") + limit = form.cleaned_data.get("limit") + listener = RSSListener(limit, False, None, "./templates/news.html", None) + listener.start(rss) + + context = {'form': form, 'rss': rss, 'limit': limit, 'submitbutton': submitbutton} + + return render(request, 'landing.html', context) + + +def news(request): + return render(request, 'news.html', locals()) diff --git a/manage.py b/manage.py new file mode 100755 index 0000000..3f448eb --- /dev/null +++ b/manage.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'PythonHomework.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/templates/landing.html b/templates/landing.html new file mode 100644 index 0000000..7e01388 --- /dev/null +++ b/templates/landing.html @@ -0,0 +1,44 @@ + + + + + Title + + + + + + + + + + + + +
+
+
+
+

RSS Reader

+
+
+ {% csrf_token %} + {{ form.as_p }} + + +
+ {% if submitbutton == "Submit" %} +

Ваши данные загружены

+
+ +
+ + {% endif %} +
+
+
+
+
+ + + \ No newline at end of file From 31d600f569ee51ebfb58e1ca3d60f2ee95492cea Mon Sep 17 00:00:00 2001 From: Ilya Borodin <48887908+ilyaborodin@users.noreply.github.com> Date: Mon, 2 Dec 2019 01:47:17 +0300 Subject: [PATCH 23/23] Update README.md --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 48cb6a8..20129e6 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,15 @@ Выполнена +## 6 iter + +Частично выполнил +К сожалению не успел сдлеать из-за ряда причин. +Сразу извиняюсь за код в этом задании) +Установка: +Перейти в директорию с проектом и запустить команду: +sudo docker-compose up --build + ## Help usage: rss-reader [-h] [--version] [--json] [--verbose] [--limit LIMIT] [--date DATE] [--to_html TO_HTML] [--to_pdf TO_PDF]