Skip to content
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
30f3c2e
Add env and readme.md
ZayJob Nov 9, 2019
816db01
Basic functionality added and application architecture
ZayJob Nov 16, 2019
2005715
Redone architecture and add documentation
ZayJob Nov 17, 2019
589c80b
Add dir tests and change logging
ZayJob Nov 17, 2019
1bfbade
Add setup.py file and requirement.txt
ZayJob Nov 17, 2019
08466f2
Change version
ZayJob Nov 17, 2019
061aaea
Change setup.py
ZayJob Nov 18, 2019
a839057
Add entry point in __main__
ZayJob Nov 19, 2019
cfbdb81
Change path
ZayJob Nov 19, 2019
bc80c7b
Add 3 iteration
ZayJob Nov 24, 2019
fad6d07
Add convert to html(base tamplate)
ZayJob Nov 25, 2019
54b83b4
Limit parameter processing fixed
ZayJob Nov 25, 2019
6bab677
Update README.md
ZayJob Nov 26, 2019
8cb8726
Change setup.py and docker-compose.yaml file
ZayJob Nov 27, 2019
020a7f7
Merge
ZayJob Nov 27, 2019
cb574a2
Change argument_parser.py
ZayJob Nov 27, 2019
80b0192
Change port in docker-compose.yaml
ZayJob Nov 27, 2019
cb3c78e
Add Guide in README.md
ZayJob Nov 27, 2019
1f7bb1a
Add app in docker-compose.yaml
ZayJob Nov 27, 2019
59a3f0d
Change host in mongo
ZayJob Nov 27, 2019
41faeb9
Change mongodb_config.py
ZayJob Nov 27, 2019
bdbde32
Optimized function get_news
ZayJob Nov 27, 2019
5142ca5
Cnahge docker-compose.yaml and Dockerfile
ZayJob Nov 27, 2019
3e7316c
Update README.md and add unit tests
ZayJob Nov 27, 2019
728adca
Add host
ZayJob Nov 28, 2019
3030202
Add Mongo-Express
ZayJob Nov 28, 2019
a781281
Add depends on mongo-express
ZayJob Nov 28, 2019
cfead5b
Add colored
ZayJob Nov 29, 2019
57f1901
Add --to-pdf and install script
ZayJob Nov 30, 2019
2441334
Change README.md
ZayJob Nov 30, 2019
3c681ca
Edit README.md
ZayJob Nov 30, 2019
108783d
Change lid for PDF
ZayJob Nov 30, 2019
2489650
Change README.md
ZayJob Nov 30, 2019
8f8d6c2
eh, not enough time (
ZayJob Dec 1, 2019
5318e0b
last commit
ZayJob Dec 1, 2019
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
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ celerybeat-schedule
# Environments
.env
.venv
.vscode
env/
venv/
ENV/
Expand All @@ -102,3 +103,10 @@ venv.bak/

# mypy
.mypy_cache/

#logging
.idea
apps.log

#file
News_feed.html
2 changes: 2 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
include requirements.txt
include json_schema.json
37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#RSS reader

RSS reader is a command-line utility which receives RSS URL and prints results in human-readable format.


## Specification
Utility provides the following interface:
+ positional arguments:
+ source - RSS URL
+ optional arguments:
+ -h, --help - Show help message and exit.
+ --version - Print version info.
+ --json - Print result as JSON in stdout.
+ --verbose - Outputs verbose status messages.
+ --limit - Limit news topics if this parameter is provided.
+ --date - Return cached news from the specified day. Format is %Y%M%D.

##Install RSS reader

1. Clone or Download [repository](https://github.com/ZayJob/PythonHomework)
2. Go to folder /PythonHomework
3. **git branch**
4. There is no branch besides **master**? Then follow this tutorial.
+ **git branch -a**.
+ **git branch --track finalTask remotes/origin/finalTask**.
+ **git checkout finalTask**.
+ **git branch**.
+ **git checkout cfbdb81**.
5. I recommend creating a virtual environment. **python3.8 -m venv env**, **. env/bin/activate**.
6. Let's collect our package **python3.8 setup.py sdist**.
7. Let's install our package **pip3.8 install dist/rss-reader-2.0.tar.gz**

## Distribution
Utility is wrapped into package named rss_reader_ft. Additionally this package exports CLI utility named rss-reader.

## Caching
The RSS news are stored in a local storage while reading.
28 changes: 28 additions & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
version: '3.1'

services:

app:
build:
context: ./rss_reader_ft
dockerfile: Dockerfile
depends_on:
- mongo

mongo:
image: mongo
restart: always
ports:
- 27017:27017
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: example

mongo-express:
image: mongo-express
restart: always
ports:
- 8081:8081
environment:
ME_CONFIG_MONGODB_ADMINUSERNAME: root
ME_CONFIG_MONGODB_ADMINPASSWORD: example
126 changes: 126 additions & 0 deletions json_schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
{
"type": "object",
"title": "The Root Schema",
"required": [
"Feed",
"Url",
"News"
],
"properties": {
"Feed": {
"$id": "#/properties/Feed",
"type": "string",
"title": "The Feed Schema",
"default": "",
"examples": [
"Yahoo News - Latest News & Headlines"
],
"pattern": "^(.*)$"
},
"Url": {
"$id": "#/properties/Url",
"type": "string",
"title": "The Url Schema",
"default": "",
"examples": [
"http://rss.news.yahoo.com/rss/"
],
"pattern": "^(.*)$"
},
"News": {
"$id": "#/properties/News",
"type": "array",
"title": "The News Schema",
"items": {
"$id": "#/properties/News/items",
"type": "object",
"title": "The Items Schema",
"required": [
"Title",
"Date",
"Link",
"Description",
"Links"
],
"properties": {
"Title": {
"$id": "#/properties/News/items/properties/Title",
"type": "string",
"title": "The Title Schema",
"default": "",
"examples": [
"House Democrat warns Trump could be reelected despite impeachment inquiry"
],
"pattern": "^(.*)$"
},
"Date": {
"$id": "#/properties/News/items/properties/Date",
"type": "string",
"title": "The Date Schema",
"default": "",
"examples": [
"Fri, 15 Nov 2019 18:07:20 -0500"
],
"pattern": "^(.*)$"
},
"Link": {
"$id": "#/properties/News/items/properties/Link",
"type": "string",
"title": "The Link Schema",
"default": "",
"examples": [
"https://news.yahoo.com/house-democrat-warns-trump-could-be-reelected-despite-impeachment-inquiry-230720070.html"
],
"pattern": "^(.*)$"
},
"Description": {
"$id": "#/properties/News/items/properties/Description",
"type": "string",
"title": "The Description Schema",
"default": "",
"examples": [
"Michigan Democrat Debbie Dingell thinks Trump could win reelection in 2020."
],
"pattern": "^(.*)$"
},
"Links": {
"$id": "#/properties/News/items/properties/Links",
"type": "object",
"title": "The Links Schema",
"required": [
"Source_link",
"Img_links"
],
"properties": {
"Source_link": {
"$id": "#/properties/News/items/properties/Links/properties/Source_link",
"type": "string",
"title": "The Source_link Schema",
"default": "",
"examples": [
"https://news.yahoo.com/house-democrat-warns-trump-could-be-reelected-despite-impeachment-inquiry-230720070.html"
],
"pattern": "^(.*)$"
},
"Img_links": {
"$id": "#/properties/News/items/properties/Links/properties/Img_links",
"type": "array",
"title": "The Img_links Schema",
"items": {
"$id": "#/properties/News/items/properties/Links/properties/Img_links/items",
"type": "string",
"title": "The Items Schema",
"default": "",
"examples": [
"http://l.yimg.com/uu/api/res/1.2/xLjRXbrMf4Uu4liSopZAig--/YXBwaWQ9eXRhY2h5b247aD04Njt3PTEzMDs-/https://media-mbst-pub-ue1.s3.amazonaws.com/creatr-uploaded-images/2019-11/68be2920-07fb-11ea-baff-2733831db38e"
],
"pattern": "^(.*)$"
}
}
}
}
}
}
}
}
}
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
feedparser==5.2.1
bs4==0.0.1
pymongo==3.9.0
4 changes: 4 additions & 0 deletions rss_reader_ft/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
FROM python:3-alpine
#RUN apt-get update -y && apt-get install python3-pip -y && pip3 install pip --upgrade && apt-get clean


2 changes: 2 additions & 0 deletions rss_reader_ft/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
"""Сonnected modules"""
__all__ = ['app', 'conversion', 'rss', 'db', ]
5 changes: 5 additions & 0 deletions rss_reader_ft/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"""Entry point for package"""
from rss_reader_ft.rss_reader import main

if __name__ == "__main__":
main()
Empty file added rss_reader_ft/app/__init__.py
Empty file.
45 changes: 45 additions & 0 deletions rss_reader_ft/app/application.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
"""Module contains objects related to logs"""
import sys
from typing import Dict, Any

from rss_reader_ft.app.application_log import ApplicationLog
from rss_reader_ft.app.argument_parser import ArgumentParser
from rss_reader_ft.rss.data_loader import DataLoader
from rss_reader_ft.rss.output import Output
from rss_reader_ft.rss.rss_feed import RSSFeed
from rss_reader_ft.db.mongodb import MongoDatabase
from rss_reader_ft.db.mongodb_config import URL_CONNECTION, DB_NAME, COLLECTION_NAME


class Application:
"""Application class"""
def __init__(self):
"""Init Application class"""
self.dict_args: Dict[str, Any] = ArgumentParser.parse_args()

def run_app(self) -> None:
"""Мethod sets application behavior"""

mongo_db = MongoDatabase(URL_CONNECTION, DB_NAME, COLLECTION_NAME)
mongo_db.database_connection()

data = DataLoader(self.dict_args['source']).upload()

feed = RSSFeed(self.dict_args, data)

process_data = feed.data_processing()

mongo_db.cache_news_feed(process_data)

news = mongo_db.get_news(self.dict_args["limit"], self.dict_args["date"], self.dict_args["source"])
if news is not None:
if self.dict_args["json"]:
Output.to_json_format(news)
elif self.dict_args["to_html"]:
Output.to_html_format(news)
else:
Output.to_rss_format(news)

if self.dict_args["verbose"]:
ApplicationLog.print_log()
sys.exit(1)
25 changes: 25 additions & 0 deletions rss_reader_ft/app/application_log.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"""Module contains objects related to logs"""
import logging


class ApplicationLog:
""""ApplicationLog class"""
@staticmethod
def setup_logs() -> None:
"""Method that sets logger configuration parameters"""
logging.basicConfig(
filename="apps.log",
filemode="w",
format="%(asctime)s - %(levelname)s - %(message)s",
datefmt='%Y-%m-%d %H:%M:%S',
level=logging.INFO
)
logging.info('Create base config')

@staticmethod
def print_log() -> None:
"""Method displays logs to the console"""
logging.info('Print the logs from the apps.log file to stdout')
with open("apps.log", "r") as file_handler:
for line in file_handler:
print(line)
61 changes: 61 additions & 0 deletions rss_reader_ft/app/argument_parser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
"""Module contains objects related to arguments parsing"""
import logging
from typing import Dict
import argparse

from rss_reader_ft.config import __version__


class ArgumentParser:
"""ArgumentParser class"""
@staticmethod
def parse_args() -> Dict:
"""
The method in which we set the parser,
indicate what objects we expect from it,
and return the dictionary
"""
parser = argparse.ArgumentParser(description='Python command-line RSS reader.')
parser.add_argument(
'source',
help='Enter the link to the information portal(RSS url)',
type=str
)
parser.add_argument(
'--version',
help='Print version info',
action='version', version=__version__
)
parser.add_argument(
'--json',
help='Print result as JSON in stdout',
action='store_true'
)
parser.add_argument(
'--verbose',
help='Outputs verbose status messages',
action='store_true'
)
parser.add_argument(
'--limit',
help='Limit news topics if this parameter is provided',
type=int
)
parser.add_argument(
'--date',
help='The cashed news can be read with it. The new from the specified day will be printed out.\
If the news are not found return an error.',
type=int
)
parser.add_argument(
'--to-html',
help='Print result as JSON in stdout',
action='store_true'
)
parser.add_argument(
'--to-pdf',
help='Print result as JSON in stdout',
action='store_true'
)
logging.info('Parsed arguments')
return vars(parser.parse_args())
3 changes: 3 additions & 0 deletions rss_reader_ft/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"""This modules contains internal application configuration"""
__version__ = "3.0"
__package__ = "rss_reader_ft"
Empty file.
9 changes: 9 additions & 0 deletions rss_reader_ft/conversion/format_converter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"""Module contains objects related to converted"""
from abc import ABC, abstractmethod


class FormatConverter(ABC):
"""FormatConverter abstract class"""
@abstractmethod
def convert_to_format(self):
pass
Loading