Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 115 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
@@ -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 <Number of the session> - <FirstName> <LastName>`.
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
Binary file added requirements.txt
Binary file not shown.
3 changes: 3 additions & 0 deletions rss_reader/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from .rss_reader import *
from .tests import *
from .database_handler import *
5 changes: 5 additions & 0 deletions rss_reader/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from rss_reader import main


if __name__ == '__main__':
main()
176 changes: 176 additions & 0 deletions rss_reader/database_handler.py
Original file line number Diff line number Diff line change
@@ -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"""<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{date}</title>
</head>
<body>"""

end = """</body>
</html>"""

log.info("Stating construction HTML file!")
self.html_text = header

h1 = f"""<h1>News on: {date}</h1>"""
self.html_text += h1
for inf in self.data:
p = f"""<p>
<a><b>Title:</b> {inf[0]}</a><br>
<a><b>Date:</b> {inf[2]}</a><br>
<a><b>Link:</b> <a href = "{inf[1]}">clickable link</a></a><br>
<a><b>Description:</b> {inf[3]}</a><br>
<hr>
</p>"""
self.html_text += p
self.html_text += end
log.info("Construction HTML file complieted!")
return self.html_text







23 changes: 23 additions & 0 deletions rss_reader/dbh_tests.py
Original file line number Diff line number Diff line change
@@ -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)
Loading