diff --git a/README.md b/README.md
index c86d1e65..67964c8b 100644
--- a/README.md
+++ b/README.md
@@ -1,28 +1,116 @@
-# How to create a PR with a homework task
-
-1. Create fork from the following repo: https://github.com/E-P-T/Homework. (Docs: https://docs.github.com/en/get-started/quickstart/fork-a-repo )
-2. Clone your forked repo in your local folder.
-3. Create separate branches for each session.Example(`session_2`, `session_3` and so on)
-4. Create folder with you First and Last name in you forked repo in the created session.
-5. Add your task into created folder
-6. Push finished session task in the appropriate branch in accordance with written above.
- You should get the structure that looks something like that
-
-```
- Branch: Session_2
- DzmitryKolb
- |___Task1.py
- |___Task2.py
- Branch: Session_3
- DzmitryKolb
- |___Task1.py
- |___Task2.py
-```
-
-7. When you finish your work on task you should create Pull request to the appropriate branch of the main repo https://github.com/E-P-T/Homework (Docs: https://docs.github.com/en/github/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork).
-Please use the following instructions to prepare good description of the pull request:
- - Pull request header should be: `Session - `.
- Example: `Session 2 - Dzmitry Kolb`
- - Pull request body: You should write here what tasks were implemented.
- Example: `Finished: Task 1.2, Task 1.3, Task 1.6`
+ _ __ ___ ___ _ __ ___ __ _ __| | ___ _ __
+| '__|/ __|/ __| | '__| / _ \ / _` | / _` | / _ \| '__|
+| | \__ \\__ \ | | | __/| (_| || (_| || __/| |
+|_| |___/|___/ _____ |_| \___| \__,_| \__,_| \___||_|
+ |_____|
+
+Welcome to rss_reader.py readme file!
+
+Tested on Windows 10!
+
+usage: rss_reader.py [-h] [--date DATE] [-v] [--verbose] [--to-html] [--to-epub] [--json] [--limit LIMIT] [source]
+
+This program gets information from RSS-channel and returns in user friendly format.
+
+positional arguments:
+ source RSS link for your information
+
+options:
+ -h, --help show this help message and exit
+ --date DATE Get news form the database by date.
+ -v, --version Print program version and exit.
+ --verbose Outputs verbose status messages.
+ --to-html Return HTML file to C:\rss_reader\html_files
+ --to-epub Return HTML file to C:\rss_reader\epub_files
+ --json Print result as JSON in stdout.
+ --limit LIMIT Limit news topics if this parameter provided.
+
+
+
+source is a positional argument that you should input to your program, when you have to get information from the RSS-channel.
+
+If --limit parameter takes only integer numbers which provide program to return that number of news.
+If that parameter not provided, program print all news from RSS-channel.
+
+
+--json is a parameter that print json string in format that described below. This parameter also takes effect from --limit parameter.
+
+"[title of the rss site where you get news]": [
+ {
+ "Title": "[date of that fact[1]]",
+ "Link": "[link to the fact[1]]",
+ "Date": "[date of that fact[1]]",
+ "Description": "[fact's [1] short summary]"
+ },
+ ...........,
+ {
+ "Title": "[date of that fact[limit]]",
+ "Link": "[link to the fact[limit]]",
+ "Date": "[date of that fact[limit]]",
+ "Description": "[fact's [limit] short summary]"
+ }
+ ]
+}
+
+If --json parameter not provided, program print to console news in format below.
+
+Feed:[title of the rss site where you get news]
+
+Title: [fact [1] title]
+Date: [date of that fact[1]]
+Link: [link to the fact[1]]
+Description: [fact's [1] short summary]
+......
+Title: [fact [limit] title]
+Date: [date of that fact[limit]]
+Link: [link to the fact[limit]]
+Description: [fact's [limit] short summary]
+
+--to-html is parameter that saves information to C:\rss_reader\html_files folder with given name in date time format `%d%m%y%H%M`.
+
+--to-epub is parameter that saves information to C:\rss_reader\epub_files folder with given name in date time format `%d%m%y%H%M`.
+
+--to-epub and --to-html also works with other parameters.
+
+--date is a parameter to get information from the database. This parameter should take a date in `%Y%m%d` format.
+For example: `--date 20191020`
+With --to-epub or --to-html parameter program saves html or epub files to corresponding folders with `%Y%m%d` nameformat.
+--date with source parameter returns data from database according to date and source link.
+Just --date parameter returns to console news in format described below:
+
+News on date [date]!
+
+Title: [fact [1] title]
+Date: [date of that fact[1]]
+Link: [link to the fact[1]]
+Description: [fact's [1] short summary]
+......
+Title: [fact [limit] title]
+Date: [date of that fact[limit]]
+Link: [link to the fact[limit]]
+Description: [fact's [limit] short summary]
+
+
+With --json parameter returns JSON string:
+
+"[date]": [
+ {
+ "Title": "[date of that fact[1]]",
+ "Link": "[link to the fact[1]]",
+ "Date": "[date of that fact[1]]",
+ "Description": "[fact's [1] short summary]"
+ },
+ ...........,
+ {
+ "Title": "[date of that fact[limit]]",
+ "Link": "[link to the fact[limit]]",
+ "Date": "[date of that fact[limit]]",
+ "Description": "[fact's [limit] short summary]"
+ }
+ ]
+}
+
+Running unittests for rss_reader:
+py -m unittest rss_reader/dbh_tests.py
+py -m unittest rss_reader/tests.py
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 00000000..e848f78c
Binary files /dev/null and b/requirements.txt differ
diff --git a/rss_reader/__init__.py b/rss_reader/__init__.py
new file mode 100644
index 00000000..ac65caad
--- /dev/null
+++ b/rss_reader/__init__.py
@@ -0,0 +1,3 @@
+from .rss_reader import *
+from .tests import *
+from .database_handler import *
\ No newline at end of file
diff --git a/rss_reader/__main__.py b/rss_reader/__main__.py
new file mode 100644
index 00000000..369e5c9b
--- /dev/null
+++ b/rss_reader/__main__.py
@@ -0,0 +1,5 @@
+from rss_reader import main
+
+
+if __name__ == '__main__':
+ main()
\ No newline at end of file
diff --git a/rss_reader/database_handler.py b/rss_reader/database_handler.py
new file mode 100644
index 00000000..bc0012e3
--- /dev/null
+++ b/rss_reader/database_handler.py
@@ -0,0 +1,176 @@
+import sqlite3
+import time
+import os
+import logging as log
+import json
+
+data_base = "news_data.db"
+
+class DataBaseHandler:
+
+ """Class that handles with sqlite3 database. With that class you can:
+ adress to your DB through context manager, create table, input data to table,
+ get data from table by date, souce, check emtyness of the table."""
+
+ def __init__(self, base_path):
+ log.info("Initialization of object complieted.")
+ self.path = base_path
+
+ def __enter__(self):
+ log.info("Connection to database esteblished.")
+ self.conn = sqlite3.connect(self.path)
+ return self.conn
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ log.info("Connection closed")
+ if exc_type is None:
+ self.conn.close()
+
+ def create_table(self):
+
+ """Metod that help us to create table in our database if it doesn't exist.
+ Table contains next fields: date TEXT,
+ source TEXT,
+ title TEXT,
+ url TEXT,
+ full_date TEXT,
+ description TEXT"""
+
+ with DataBaseHandler(self.path) as conn:
+ cursor = conn.cursor()
+ cursor.execute("""CREATE TABLE IF NOT EXISTS news_data (
+ date TEXT,
+ source TEXT,
+ title TEXT,
+ url TEXT,
+ full_date TEXT,
+ description TEXT)""")
+ conn.commit()
+ log.info("Now news_data table exists in out database.")
+
+
+ def emptiness_checker(self):
+
+ """This metod check our database and return boolean result.
+ If it is empty - return True, else return - False"""
+
+ log.info("Cheking table for emptiness...")
+ with DataBaseHandler(self.path) as conn:
+ cursor = conn.cursor()
+ cursor.execute("""SELECT COUNT(*) FROM news_data""")
+ result = cursor.fetchone()
+ if result[0] == 0:
+ log.info("Table is empty!")
+ return True
+ else:
+ log.info("There is data in the table!")
+ return False
+
+ def add_data(self, source, *args):
+
+ """This method add information to news_data table,
+ also this method creates information to date field."""
+
+ converted_date = time.strptime(args[2], "%a, %d %b %Y %H:%M:%S %z")
+ date = time.strftime("%Y%m%d", converted_date)
+ with DataBaseHandler(self.path) as conn:
+ cursor = conn.cursor()
+ cursor.execute("""INSERT INTO news_data (date, source, title, url, full_date, description)
+ VALUES (?, ?, ?, ?, ?, ?)""", (date, source, args[0], args[1], args[2], args[3]))
+ conn.commit()
+ log.info("Data added to the news_data table.")
+
+ def retrieve_data(self, date, source=None, num=None):
+
+ """If num parameter specified, takes numered quantity of data,
+ from database especially by date, and by source if it specified."""
+
+ with DataBaseHandler(self.path) as conn:
+ cursor = conn.cursor()
+ if source is None:
+ cursor.execute("""SELECT title, url, full_date, description FROM news_data WHERE date=?""", (date,))
+ else:
+ cursor.execute("""SELECT title, url, full_date, description
+ FROM news_data WHERE date=? AND source=?""", (date, source))
+ conn.commit()
+ data = cursor.fetchall()
+ if len(data) == 0:
+ log.info("There is no such data in the table.")
+ raise ValueError
+ if num is None:
+ self.data = data
+ log.info("Provided amount of data retrieved from the table.")
+ else:
+ self.data = data[:num]
+ log.info("Provided amount of data retrieved from the table.")
+ return self.data
+
+ def data_to_json(self, date):
+
+ """Returns retrieved data from database in json format"""
+
+ log.info("Collecting data in json!")
+ self.json_data = {date:[]}
+ for i in self.data:
+ fact_dict = {"Title": i[0],
+ "Link": i[1],
+ "Date": i[2],
+ "Description": i[3],
+ }
+ self.json_data[date].append(fact_dict)
+ log.info("Collecting data to json complieted!")
+ return json.dumps(self.json_data, ensure_ascii=False, indent=4)
+
+ def data_to_print(self, date):
+
+ """Prints retrieved data from database to console."""
+
+ log.info("Printing data from database.")
+ print(f"News on {date}!\n")
+ for i in self.data:
+ print(f"Title: {i[0]}")
+ print(f"Date: {i[2]}")
+ print(f"Link: {i[1]}")
+ print(f"Description: {i[3]}", end="\n")
+ print('\n')
+
+ def data_to_html(self, date):
+
+ """Metod that costract HTML text from data retrieved from database.
+ Takes input date as a title and header."""
+
+ header = f"""
+
+
+
+ {date}
+
+ """
+
+ end = """
+ """
+
+ log.info("Stating construction HTML file!")
+ self.html_text = header
+
+ h1 = f"""
News on: {date}
"""
+ self.html_text += h1
+ for inf in self.data:
+ p = f"""
"""
+ self.html_text += p
+ self.html_text += end
+ log.info("Construction HTML file complieted!")
+ return self.html_text
+
+
+
+
+
+
+
diff --git a/rss_reader/dbh_tests.py b/rss_reader/dbh_tests.py
new file mode 100644
index 00000000..39234bc3
--- /dev/null
+++ b/rss_reader/dbh_tests.py
@@ -0,0 +1,23 @@
+import unittest
+from database_handler import *
+from unittest.mock import patch, Mock
+
+
+class MyTest(unittest.TestCase):
+ @patch("database_handler.DataBaseHandler")
+ def test_create_table(self, mock_DataBase):
+ m = mock_DataBase
+ m.create_table()
+ m.create_table.assert_called()
+
+ @patch("database_handler.DataBaseHandler")
+ def test_emptiness_checker(self, mock_DataBase):
+ m = mock_DataBase
+ m.emptiness_checker()
+ m.emptiness_checker.assert_called()
+
+
+
+
+if __name__ == '__main__':
+ unittest.main(argv=[''], exit=False)
\ No newline at end of file
diff --git a/rss_reader/rss_reader.py b/rss_reader/rss_reader.py
new file mode 100644
index 00000000..4f26a8db
--- /dev/null
+++ b/rss_reader/rss_reader.py
@@ -0,0 +1,394 @@
+import requests
+from lxml import etree
+import xml.etree.ElementTree as elementTree
+from bs4 import BeautifulSoup
+import time
+from dateutil import parser
+import json
+import logging as log
+import argparse
+import os
+import rss_reader.database_handler as handler
+from datetime import datetime
+from ebooklib import epub
+
+
+
+def get_content(url: str):
+
+ """Get request from the url and depending on a flag returns corresponding xml etree or html soup"""
+
+ log.info(f"Try in to retrieve information from {url}")
+ try:
+ r = requests.get(url)
+ log.info(f"Connection to {url} established!")
+ if is_xml(r.content):
+ root = etree.fromstring(r.content)
+ log.info("XML content downloaded and parsed.")
+ return root[0]
+ else:
+ raise AttributeError()
+ except requests.exceptions.RequestException as exc:
+ print(f"Error Occurred: {exc}")
+ except AttributeError:
+ print("Site that you entered is not RSS, because it doesn't contain XML!")
+
+
+def is_xml(value):
+
+ """Check value containing XML content"""
+
+ try:
+ elementTree.fromstring(value)
+ except elementTree.ParseError:
+ log.info("Received data isn't XML.")
+ return False
+ else:
+ log.info("Received data is XML content.")
+ return True
+
+
+def get_feed(root):
+
+ """Return feed string"""
+
+ feed = root.find("title").text
+ return feed
+
+
+def get_news_db(root, num=None):
+
+ """Get all "item" elements and return list or slice of the list from root if num specified."""
+
+ news_db = root.findall("item")
+
+ if num is not None:
+ news_slice = news_db[:num]
+ log.info("Retrieved user defined number of news.")
+ return news_slice
+ else:
+ log.info("Retrieved all amount of news.")
+ return news_db
+
+
+def inf_generator(news_db):
+
+ """Get information from the "item" list and yield it as a list
+ next format [title, link, date, description]"""
+
+ log.info("Retrieving information from item branches.")
+ for bunch in news_db:
+ title = bunch.find("title").text
+ link = link_handler(bunch.find("link"))
+ date = date_handler(bunch.find("pubDate"))
+ description = description_handler(bunch.find("description"))
+ inf_lst = [title, link, date, description]
+ log.info("Branch retrieved successful!")
+ yield inf_lst
+
+
+def date_handler(date_inf):
+
+ """Return date in weekday, daynumber month year hours:minutes:seconds timezone"""
+
+ if date_inf is None:
+ log.info("RSS doesn't provide date field!")
+ return "Date field doesn't provided!"
+ else:
+ date = date_inf.text
+ pure_date = parser.parse(date)
+ return_date = pure_date.strftime("%a, %d %b %Y %H:%M:%S %z")
+ log.info("Date retrieved successfully!")
+ return return_date
+
+
+def link_handler(inf):
+
+ """Handles absence of link in RSS."""
+
+ if inf is None:
+ log.info("RSS doesn't provide news link!")
+ return "Link field doesn't provided!"
+ else:
+ log.info("Link retrieved successful.")
+ link = inf.text
+ return link
+
+
+def description_handler(inf):
+
+ """Handles absence of link in RSS and gets HTML from the string."""
+
+ if inf is None:
+ log.info("RSS doesn't provide description!")
+ return "There is no description!"
+ else:
+ description = inf.text
+ if description is None:
+ log.info("RSS doesn't provide description!")
+ return "There is no description"
+ elif "<" in description:
+ soup = BeautifulSoup(description, "html.parser")
+ data = soup.text
+ log.info("Description retrieved successful from HTML text.")
+ return data
+ else:
+ log.info("Description retrieved successful.")
+ return description
+
+
+def printer(feed, news_db):
+
+ """Printing in the console news in next format:
+ Feed:[title of the rss site where you get news]
+
+ Title: [fact's title]
+ Date: [date of that fact]
+ Link: [link to the fact]
+ Description: [fact's short summary]
+ """""
+
+ log.info("Printing information to console!")
+ print(f"Feed: {feed}", "\n")
+ gen = inf_generator(news_db)
+ for inf in gen:
+ print(f"Title: {inf[0]}")
+ print(f"Date: {inf[2]}")
+ print(f"Link: {inf[1]}")
+ print(f"Description: {inf[3]}", end="\n")
+ print('\n')
+
+
+def news_to_json(feed, news_db):
+
+ """Collect information form the site into dict "news feed" and return it as a json string"""
+
+ log.info("Collection information to json format.")
+ news_feed = {feed: []}
+ gen = inf_generator(news_db)
+ for inf in gen:
+ fact_dict = {"Title": inf[0],
+ "Link": inf[1],
+ "Date": inf[2],
+ "Description": inf[3],
+ }
+ news_feed[feed].append(fact_dict)
+ log.info("Collecting JSON completed successful!")
+ return json.dumps(news_feed, ensure_ascii=False, indent=4)
+
+
+def output_form(main_title, news_data, form):
+
+ """Printing return the output to console if form specified (console/json)"""
+
+ if form not in ["console", "json"]:
+ log.error("Entered unavailable format!")
+ raise AttributeError("Choose between console or json!")
+ elif form == "console":
+ log.info("Printing information to console....")
+ printer(main_title, news_data)
+ elif form == "json":
+ log.info("Printing json information to console....")
+ news_json = news_to_json(main_title, news_data)
+ print(news_json)
+
+
+def create_path(path):
+
+ """Creates path if it not exist"""
+
+ if not os.path.exists(path):
+ os.mkdir(path)
+ log.info(f"Path {path} created")
+
+
+def html_adder(nw_title, db, head=None):
+
+ """Creates HTML text from database and title."""
+
+ log.info("Start creating HTML text!")
+ if head is None:
+ head = datetime.now().strftime("%d%m%y %H:%M")
+ log.info("Created head for HTML text!")
+
+ header = f"""
+
+
+
+ {head}
+
+ """
+
+ end = """
+ """
+
+ html_text = header
+
+ h1 = f"""
Feed: {nw_title}
"""
+ html_text += h1
+ gen = inf_generator(db)
+ for inf in gen:
+ p = f"""
+ """
+ html_text += p
+ html_text += end
+ log.info("HTML text creation complieted!")
+ return html_text
+
+def write_html_file(path, html_text, html_name=None):
+
+ """Write HTML text to file, than saves file to the path,
+ also this programm automatically gives name to files."""
+
+ log.info("Starting writing HTML to the file!")
+ if html_name is None:
+ html_name = datetime.now().strftime("%d%m%y%H%M") + ".html"
+ log.info("Created name for HTML file!")
+ if not html_name.endswith(".html"):
+ html_name = html_name + ".html"
+ log.info("Added .html extention to file name!")
+ full_path = os.path.join(path, html_name)
+ with open(full_path, "w", encoding="utf-8") as file:
+ file.write(html_text)
+ log.info("HTML file created!")
+ print(f"HTML file saved to to path: {full_path}")
+
+
+def write_epub_file(path, html_text, epub_name=None):
+
+ """Write ePub file, than saves file to the path,
+ also this programm automatically gives name to files."""
+
+ log.info("Starting writing HTML to the ePub file!")
+ if epub_name is None:
+ epub_name = datetime.now().strftime("%d%m%y%H%M") + ".epub"
+ log.info("Created name for ePub file!")
+ if not epub_name.endswith(".epub"):
+ epub_name = epub_name + ".epub"
+ log.info("Added .epub extention to file name!")
+ file_path = os.path.join(path, epub_name)
+ book = epub.EpubBook()
+ book.add_author('Nurmatov Farrukh') # you found easter egg
+ c1 = epub.EpubHtml(title='News', file_name='chap_01.xhtml')
+ c1.content = html_text
+ book.add_item(c1)
+ book.add_item(epub.EpubNcx())
+ book.add_item(epub.EpubNav())
+ style = 'BODY {color: white;}'
+ nav_css = epub.EpubItem(uid="style_nav", file_name="style/nav.css", media_type="text/css", content=style)
+ book.add_item(nav_css)
+ book.spine = ['nav', c1]
+ epub.write_epub(file_path, book, {})
+ log.info("ePub file created!")
+ print(f"Epub file saved to: {file_path}")
+
+
+def main():
+ parser = argparse.ArgumentParser(description="This program gets information from RSS-channel "
+ "and returns in user friendly format.")
+ parser.add_argument("source", type=str, nargs="?", help="RSS link for your information", default=None)
+ parser.add_argument("--date", type=str, help="Get news form the database by date.")
+ parser.add_argument("-v", "--version", action="version", version="Version 1.4.0",
+ help="Print program version and exit.")
+ parser.add_argument("--verbose", action="store_true", help="Outputs verbose status messages.")
+ parser.add_argument("--to-html", action="store_true", help="Return HTML file to C:\\rss_reader\\html_files",
+ dest="to_html")
+ parser.add_argument("--to-epub", action="store_true", help="Return HTML file to C:\\rss_reader\\epub_files",
+ dest="to_epub")
+ parser.add_argument("--json", action="store_true", help="Print result as JSON in stdout.")
+ parser.add_argument("--limit", type=int, help="Limit news topics if this parameter provided.")
+
+ args = parser.parse_args()
+ rss_url = args.source
+ date = args.date
+ verbose = args.verbose
+ html = args.to_html
+ epub = args.to_epub
+ print_json = args.json
+ limit = args.limit
+
+ parent_dir = "C:/"
+ root_dir = "rss_reader"
+ db_dir = "data_base"
+ html_dir = "html_files"
+ epub_dir = "epub_files"
+
+ if verbose:
+ log.basicConfig(format="%(levelname)s: %(message)s", level=log.DEBUG)
+ log.info("Verbose output.")
+ else:
+ log.basicConfig(format="%(levelname)s: %(message)s")
+
+ sys_path = os.path.join(parent_dir, root_dir)
+ create_path(sys_path)
+ db_path = os.path.join(sys_path, db_dir)
+ create_path(db_path)
+ html_path = os.path.join(sys_path, html_dir)
+ create_path(html_path)
+ epub_path = os.path.join(sys_path, epub_dir)
+ create_path(epub_path)
+ db = os.path.join(db_path, handler.data_base)
+ base = handler.DataBaseHandler(db)
+ base.create_table()
+
+ try:
+ if date is not None:
+ if base.emptiness_checker():
+ raise AttributeError
+ base_inf = base.retrieve_data(date, rss_url, limit)
+ html_data = base.data_to_html(date)
+ if print_json and html:
+ print(base.data_to_json(date))
+ write_html_file(html_path, html_data, date)
+ elif print_json and epub:
+ print(base.data_to_json(date))
+ write_epub_file(epub_path, html_data, date)
+ elif print_json:
+ print(base.data_to_json(date))
+ elif html:
+ write_html_file(html_path, html_data, date)
+ base.data_to_print(date)
+ elif epub:
+ write_epub_file(epub_path, html_data, date)
+ base.data_to_print(date)
+ else:
+ base.data_to_print(date)
+ else:
+ xml_content = get_content(rss_url)
+ feed = get_feed(xml_content)
+ news_db = get_news_db(xml_content, limit)
+ sql_gen = inf_generator(news_db)
+ html_inf = html_adder(feed, news_db)
+
+ for inf in sql_gen:
+ base.add_data(rss_url, *inf)
+
+ if print_json and html:
+ output_form(feed, news_db, "json")
+ write_html_file(html_path, html_inf)
+ elif print_json and epub:
+ output_form(feed, news_db, "json")
+ write_epub_file(epub_path, html_inf)
+ elif print_json:
+ output_form(feed, news_db, "json")
+ elif html:
+ write_html_file(html_path, html_inf)
+ output_form(feed, news_db, "console")
+ elif epub:
+ write_epub_file(epub_path, html_inf)
+ output_form(feed, news_db, "console")
+ else:
+ output_form(feed, news_db, "console")
+ except ValueError:
+ print(f"There is no data in database on date {date}.")
+ except AttributeError:
+ print(f"There is not data in the database. You should fill the database first.")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/rss_reader/tests.py b/rss_reader/tests.py
new file mode 100644
index 00000000..b1e62e1b
--- /dev/null
+++ b/rss_reader/tests.py
@@ -0,0 +1,120 @@
+import unittest
+from unittest.mock import patch, Mock, MagicMock
+import rss_reader
+from rss_reader import *
+import lxml
+import os
+
+
+class MyTest(unittest.TestCase):
+ def test_is_xml(self):
+ r = requests.get("https://news.yahoo.com/rss/")
+ xml_content = r.content
+ self.assertFalse(is_xml(xml_content))
+ self.assertTrue(is_xml(xml_content))
+
+ def test_is_xml_2(self):
+ s = requests.get("https://mail.ru")
+ c = s.content
+ self.assertTrue(is_xml(c))
+ self.assertFalse(is_xml(c))
+
+ def test_get_content(self):
+ r = requests.get("https://news.yahoo.com/rss/")
+ xml_content = r.content
+ root = etree.fromstring(xml_content)
+ self.assertEqual(type(get_content("https://news.yahoo.com/rss/")), type(root[0]))
+
+ @patch('rss_reader.get_content')
+ def test_for_get_content(self, mock_is_xml):
+ mock_is_xml.return_value = False
+ with self.assertRaises(Exception):
+ get_content("https://news.yahoo.com/rss/")
+ mock_is_xml.assert_called_once()
+
+ def test_link_handler(self):
+ link_xml = "https://news.yahoo.com/gop-commission-refuses-certify-mexico-004011875.html"
+ root = etree.fromstring(link_xml)
+ link = "https://news.yahoo.com/gop-commission-refuses-certify-mexico-004011875.html"
+ self.assertEqual(link_handler(None), "Link field doesn't provided!")
+ self.assertEqual(link_handler(root), link)
+
+ def test_description_handler(self):
+ description = '' \
+ '
В МЧС рассказали об аварии, которая произошла 14 июня ' \
+ 'около 17:30 на трассе М1 (Брест — Минск — граница России), вблизи деревни Рябиновка Дзержинского района. Mazda 626 столкнулась с микроавтобусом Mercedes Sprinter.' \
+ '
]]>'
+ root = etree.fromstring(description)
+ clear_descr = " В МЧС рассказали об аварии, которая произошла 14 июня около 17:30 на трассе М1 (Брест — Минск — граница России), " \
+ "вблизи деревни Рябиновка Дзержинского района. Mazda 626 столкнулась с микроавтобусом Mercedes Sprinter.Читать далее… "
+ self.assertEqual(description_handler(root), clear_descr)
+ self.assertEqual(description_handler(None), "There is no description!")
+ description_2 = "Graphic footage of the attack in China set off a heated debate that showed both " \
+ "the growing awareness of women’s rights and how divisive feminism still remains."
+ clear_descr_2 = "Graphic footage of the attack in China set off a heated debate that showed both " \
+ "the growing awareness of women’s rights and how divisive feminism still remains."
+ root_2 = etree.fromstring(description_2)
+ self.assertEqual(description_handler(root_2), clear_descr_2)
+
+
+ def test_date_handler(self):
+ date_inf_1 = Mock()
+ date_inf_1.text = "Fri, 24 Jun 2022 07:18:35 +0000"
+ date_inf_2 = Mock()
+ date_inf_2.text = "Fri, 24 Jun 2022 05:36:37 GMT"
+ date_inf_3 = Mock()
+ date_inf_3.text = "2022-06-24T05:39:45Z"
+ self.assertEqual(date_handler(date_inf_1), "Fri, 24 Jun 2022 07:18:35 +0000")
+ self.assertEqual(date_handler(date_inf_2), "Fri, 24 Jun 2022 05:36:37 +0000")
+ self.assertEqual(date_handler(date_inf_3), "Fri, 24 Jun 2022 05:39:45 +0000")
+ self.assertEqual(date_handler(None), "Date field doesn't provided!")
+
+ def test_link_handler(self):
+ inf = Mock()
+ inf.text = "https://www.google.com"
+ self.assertEqual(link_handler(inf), "https://www.google.com")
+ self.assertEqual(link_handler(None), "Link field doesn't provided!")
+
+ def test_description_handler(self):
+ self.assertEqual(description_handler(None), "There is no description!")
+ inf_1 = Mock()
+ inf_1.text = None
+ self.assertEqual(description_handler(inf_1), "There is no description")
+ inf_2 = Mock()
+ inf_2.text = '