From 1ff1842c597c696a1de6338103256d4271ca15ab Mon Sep 17 00:00:00 2001
From: Valery Litskevich
Date: Tue, 12 Apr 2022 00:01:28 +0500
Subject: [PATCH 1/8] Add homework for session 2
---
Homework-2_Python-Data_Types.md | 74 +++++++++++++++++++++++++++++++++
1 file changed, 74 insertions(+)
create mode 100644 Homework-2_Python-Data_Types.md
diff --git a/Homework-2_Python-Data_Types.md b/Homework-2_Python-Data_Types.md
new file mode 100644
index 00000000..69c73afc
--- /dev/null
+++ b/Homework-2_Python-Data_Types.md
@@ -0,0 +1,74 @@
+# Python Practice - Session 2
+
+### Task 2.1
+Write a Python program to calculate the length of a string without using the `len` function.
+
+### Task 2.2
+Write a Python program to count the number of characters (character frequency) in a string (ignore case of letters).
+Examples:
+```
+Input: 'Oh, it is python'
+Output: {',': 1, ' ': 3, 'o': 2, 'h': 2, 'i': 2, 't': 2, 's': 1, 'p': 1, 'y': 1, 'n': 1}
+```
+
+### Task 2.3
+Write a Python program that accepts a comma separated sequence of words as input and prints the unique words in sorted form.
+Examples:
+```
+Input: ['red', 'white', 'black', 'red', 'green', 'black']
+Output: ['black', 'green', 'red', 'white', 'red']
+```
+
+### Task 2.3
+Create a program that asks the user for a number and then prints out a list of all the [divisors](https://en.wikipedia.org/wiki/Divisor) of that number.
+Examples:
+```
+Input: 60
+Output: {1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, 60}
+```
+
+### Task 2.4
+Write a Python program to sort a dictionary by key.
+
+### Task 2.5
+Write a Python program to print all unique values of all dictionaries in a list.
+Examples:
+```
+Input: [{"V":"S001"}, {"V": "S002"}, {"VI": "S001"}, {"VI": "S005"}, {"VII":"S005"}, {"V":"S009"},{"VIII":"S007"}]
+Output: {'S005', 'S002', 'S007', 'S001', 'S009'}
+```
+
+### Task 2.6
+Write a Python program to convert a given tuple of positive integers into an integer.
+Examples:
+```
+Input: (1, 2, 3, 4)
+Output: 1234
+```
+
+
+### Task 2.7
+Write a program which makes a pretty print of a part of the multiplication table.
+Examples:
+```
+Input:
+a = 2
+b = 4
+c = 3
+d = 7
+
+Output:
+ 3 4 5 6 7
+2 6 8 10 12 14
+3 9 12 15 18 21
+4 12 16 20 24 28
+```
+
+### Materials
+* [Python Data Types](https://realpython.com/python-data-types/)
+* [Python Data Structures](https://realpython.com/python-data-structures/)
+* [Conditional Statements](https://realpython.com/python-conditional-statements/)
+* [While loop](https://realpython.com/python-while-loop/)
+* [For loop](https://realpython.com/python-for-loop/)
+* [Operators](http://pythonicway.com/python-operators)
+
From 8e04a8be35bf04704d7cc89ca5e35140ccf176ef Mon Sep 17 00:00:00 2001
From: Nurmatov Farrukh <84759185+unrealmw@users.noreply.github.com>
Date: Mon, 18 Apr 2022 10:17:26 +0500
Subject: [PATCH 2/8] add folder with HW session_2
---
Farrukh Nurmatov/Task 2.1.py | 15 +++++++++++++++
Farrukh Nurmatov/Task 2.2.py | 19 +++++++++++++++++++
Farrukh Nurmatov/Task 2.3.1.py | 10 ++++++++++
Farrukh Nurmatov/Task 2.3.2.py | 18 ++++++++++++++++++
Farrukh Nurmatov/Task 2.4.py | 15 +++++++++++++++
Farrukh Nurmatov/Task 2.5.py | 5 +++++
Farrukh Nurmatov/Task 2.6.py | 13 +++++++++++++
Farrukh Nurmatov/Task 2.7.py | 29 +++++++++++++++++++++++++++++
8 files changed, 124 insertions(+)
create mode 100644 Farrukh Nurmatov/Task 2.1.py
create mode 100644 Farrukh Nurmatov/Task 2.2.py
create mode 100644 Farrukh Nurmatov/Task 2.3.1.py
create mode 100644 Farrukh Nurmatov/Task 2.3.2.py
create mode 100644 Farrukh Nurmatov/Task 2.4.py
create mode 100644 Farrukh Nurmatov/Task 2.5.py
create mode 100644 Farrukh Nurmatov/Task 2.6.py
create mode 100644 Farrukh Nurmatov/Task 2.7.py
diff --git a/Farrukh Nurmatov/Task 2.1.py b/Farrukh Nurmatov/Task 2.1.py
new file mode 100644
index 00000000..cb9913e9
--- /dev/null
+++ b/Farrukh Nurmatov/Task 2.1.py
@@ -0,0 +1,15 @@
+"""Write a Python program to calculate the length of a string without using the `len` function."""
+
+
+def my_count(countable_str: str):
+
+ """Function takes string and counts characters, moving through the string in 'for' loop and increasing counter."""
+
+ c = 0
+ for char in countable_str:
+ c += 1
+ return c
+
+if __name__ == '__main__':
+ input_string = input("Input:")
+ print(f"Output: {my_count(input_string)}")
diff --git a/Farrukh Nurmatov/Task 2.2.py b/Farrukh Nurmatov/Task 2.2.py
new file mode 100644
index 00000000..4af5d9fe
--- /dev/null
+++ b/Farrukh Nurmatov/Task 2.2.py
@@ -0,0 +1,19 @@
+"""Write a Python program to count the number of characters
+ (character frequency) in a string (ignore case of letters)."""
+
+
+
+def freq_counter(some_str: str):
+
+ """Function takes string in input and returns dictionary of letters and letters frequency in string,
+ ignoring case of the letters"""
+
+ some_str = some_str.lower() # set all letters in string to lowercase
+ counter_dict = dict()
+ for char in set(list(some_str)): # loop that moves across letters set
+ counter_dict[char] = input_str.count(char) # add letter: letter_frequency to dictionary
+ return counter_dict
+
+if __name__ == '__main__':
+ input_str = input("Input your string:")
+ print(freq_counter(input_str))
diff --git a/Farrukh Nurmatov/Task 2.3.1.py b/Farrukh Nurmatov/Task 2.3.1.py
new file mode 100644
index 00000000..42df0787
--- /dev/null
+++ b/Farrukh Nurmatov/Task 2.3.1.py
@@ -0,0 +1,10 @@
+"""Write a Python program that accepts a comma separated sequence of
+ words as input and prints the unique words in sorted form.
+
+ Input: ['red', 'white', 'black', 'red', 'green', 'black']
+ Output: ['black', 'green', 'red', 'white', 'red']"""
+
+input_seq = ['red', 'white', 'black', 'red', 'green', 'black']
+unique_words = list(set(input_seq))
+
+print("Output:", sorted(unique_words), sep=" ")
\ No newline at end of file
diff --git a/Farrukh Nurmatov/Task 2.3.2.py b/Farrukh Nurmatov/Task 2.3.2.py
new file mode 100644
index 00000000..c32bcb65
--- /dev/null
+++ b/Farrukh Nurmatov/Task 2.3.2.py
@@ -0,0 +1,18 @@
+"""Create a program that asks the user for a number and then prints out a list of all the
+ [divisors](https://en.wikipedia.org/wiki/Divisor) of that number.
+ Examples:
+ Input: 60
+ Output: [1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, 60]"""
+
+
+def divisors_lst(num: int):
+
+ """Function takes integer number to input and return list of divisors."""
+
+ divisors = [i for i in range(1, num + 1) if num % i == 0]
+ return divisors
+
+
+if __name__ == '__main__':
+ number = int(input("Input:"))
+ print("Output:", divisors_lst(number), sep=" ")
\ No newline at end of file
diff --git a/Farrukh Nurmatov/Task 2.4.py b/Farrukh Nurmatov/Task 2.4.py
new file mode 100644
index 00000000..9aed2d85
--- /dev/null
+++ b/Farrukh Nurmatov/Task 2.4.py
@@ -0,0 +1,15 @@
+"""Write a Python program to sort a dictionary by key."""
+
+example_dict = {1: "stas", 3: "misha", 4: "fara", 5: "dima", 2: "serega"} # initial dict
+dict_keys = list(example_dict.keys()) # create list of keys
+dict_keys.sort() # sorting list of keys
+
+sorted_dict = dict() # create new dict
+
+# add key: value pair to dict, taking key from sorted list and getting value from initial dict by key
+for key in dict_keys:
+ sorted_dict[key] = example_dict.get(key)
+
+
+print(example_dict) # initial dict
+print(sorted_dict) # sorted dict
\ No newline at end of file
diff --git a/Farrukh Nurmatov/Task 2.5.py b/Farrukh Nurmatov/Task 2.5.py
new file mode 100644
index 00000000..a8a994a2
--- /dev/null
+++ b/Farrukh Nurmatov/Task 2.5.py
@@ -0,0 +1,5 @@
+a = (1, 2, 3, 4)
+s = ""
+for i in a:
+ s += str(i)
+print(int(s))
diff --git a/Farrukh Nurmatov/Task 2.6.py b/Farrukh Nurmatov/Task 2.6.py
new file mode 100644
index 00000000..b5a965eb
--- /dev/null
+++ b/Farrukh Nurmatov/Task 2.6.py
@@ -0,0 +1,13 @@
+"""Write a Python program to print all unique values of all dictionaries in a list."""
+
+
+lst = [{"V": "S001"}, {"V": "S002"}, {"VI": "S001"}, {"VI": "S005"},
+ {"VII": "S005"}, {"V": "S009"}, {"VIII": "S007"}] # example list of dicts
+
+unique_values = set() # empty set for unique values
+
+# add all values from dicts to make them unique
+for i in lst:
+ unique_values.update(set(i.values()))
+
+print(unique_values)
diff --git a/Farrukh Nurmatov/Task 2.7.py b/Farrukh Nurmatov/Task 2.7.py
new file mode 100644
index 00000000..9245aef4
--- /dev/null
+++ b/Farrukh Nurmatov/Task 2.7.py
@@ -0,0 +1,29 @@
+"""Write a program which makes a pretty print of a part of the multiplication table."""
+
+# input parameters
+a = 2
+b = 4
+c = 3
+d = 7
+
+
+# calculating multiplication table
+matrix = []
+for i in range(a, b + 1):
+ lst = []
+ for j in range(c, d + 1):
+ lst.append(i * j)
+ matrix.append(lst)
+
+# calculating parameters for .ljust() function
+max_num_len = len(str(matrix[-1][-1])) # length of the one cell in the table
+max_str_len = len("0 " + " ".join(str(i).ljust(len(str(i))) for i in matrix[-1])) # length of the one row in the table
+
+"""pretty printing"""
+# top row of multipliers printing
+print(" ".join(str(i).ljust(max_num_len) for i in range(c, d + 1)).rjust(max_str_len))
+
+for i in range(a, b + 1):
+ print(i, end=" ") # colon multiplier printing
+ print(" ".join(str(i).ljust(max_num_len) for i in matrix[i - 2]).ljust(max_str_len)) # print row of the table
+
From d4735ecc92a3f626b15eeb6675c9f6e463b09461 Mon Sep 17 00:00:00 2001
From: Nurmatov Farrukh <84759185+unrealmw@users.noreply.github.com>
Date: Mon, 18 Apr 2022 10:53:51 +0500
Subject: [PATCH 3/8] Delete Farrukh Nurmatov directory
---
Farrukh Nurmatov/Task 2.1.py | 15 ---------------
Farrukh Nurmatov/Task 2.2.py | 19 -------------------
Farrukh Nurmatov/Task 2.3.1.py | 10 ----------
Farrukh Nurmatov/Task 2.3.2.py | 18 ------------------
Farrukh Nurmatov/Task 2.4.py | 15 ---------------
Farrukh Nurmatov/Task 2.5.py | 5 -----
Farrukh Nurmatov/Task 2.6.py | 13 -------------
Farrukh Nurmatov/Task 2.7.py | 29 -----------------------------
8 files changed, 124 deletions(-)
delete mode 100644 Farrukh Nurmatov/Task 2.1.py
delete mode 100644 Farrukh Nurmatov/Task 2.2.py
delete mode 100644 Farrukh Nurmatov/Task 2.3.1.py
delete mode 100644 Farrukh Nurmatov/Task 2.3.2.py
delete mode 100644 Farrukh Nurmatov/Task 2.4.py
delete mode 100644 Farrukh Nurmatov/Task 2.5.py
delete mode 100644 Farrukh Nurmatov/Task 2.6.py
delete mode 100644 Farrukh Nurmatov/Task 2.7.py
diff --git a/Farrukh Nurmatov/Task 2.1.py b/Farrukh Nurmatov/Task 2.1.py
deleted file mode 100644
index cb9913e9..00000000
--- a/Farrukh Nurmatov/Task 2.1.py
+++ /dev/null
@@ -1,15 +0,0 @@
-"""Write a Python program to calculate the length of a string without using the `len` function."""
-
-
-def my_count(countable_str: str):
-
- """Function takes string and counts characters, moving through the string in 'for' loop and increasing counter."""
-
- c = 0
- for char in countable_str:
- c += 1
- return c
-
-if __name__ == '__main__':
- input_string = input("Input:")
- print(f"Output: {my_count(input_string)}")
diff --git a/Farrukh Nurmatov/Task 2.2.py b/Farrukh Nurmatov/Task 2.2.py
deleted file mode 100644
index 4af5d9fe..00000000
--- a/Farrukh Nurmatov/Task 2.2.py
+++ /dev/null
@@ -1,19 +0,0 @@
-"""Write a Python program to count the number of characters
- (character frequency) in a string (ignore case of letters)."""
-
-
-
-def freq_counter(some_str: str):
-
- """Function takes string in input and returns dictionary of letters and letters frequency in string,
- ignoring case of the letters"""
-
- some_str = some_str.lower() # set all letters in string to lowercase
- counter_dict = dict()
- for char in set(list(some_str)): # loop that moves across letters set
- counter_dict[char] = input_str.count(char) # add letter: letter_frequency to dictionary
- return counter_dict
-
-if __name__ == '__main__':
- input_str = input("Input your string:")
- print(freq_counter(input_str))
diff --git a/Farrukh Nurmatov/Task 2.3.1.py b/Farrukh Nurmatov/Task 2.3.1.py
deleted file mode 100644
index 42df0787..00000000
--- a/Farrukh Nurmatov/Task 2.3.1.py
+++ /dev/null
@@ -1,10 +0,0 @@
-"""Write a Python program that accepts a comma separated sequence of
- words as input and prints the unique words in sorted form.
-
- Input: ['red', 'white', 'black', 'red', 'green', 'black']
- Output: ['black', 'green', 'red', 'white', 'red']"""
-
-input_seq = ['red', 'white', 'black', 'red', 'green', 'black']
-unique_words = list(set(input_seq))
-
-print("Output:", sorted(unique_words), sep=" ")
\ No newline at end of file
diff --git a/Farrukh Nurmatov/Task 2.3.2.py b/Farrukh Nurmatov/Task 2.3.2.py
deleted file mode 100644
index c32bcb65..00000000
--- a/Farrukh Nurmatov/Task 2.3.2.py
+++ /dev/null
@@ -1,18 +0,0 @@
-"""Create a program that asks the user for a number and then prints out a list of all the
- [divisors](https://en.wikipedia.org/wiki/Divisor) of that number.
- Examples:
- Input: 60
- Output: [1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, 60]"""
-
-
-def divisors_lst(num: int):
-
- """Function takes integer number to input and return list of divisors."""
-
- divisors = [i for i in range(1, num + 1) if num % i == 0]
- return divisors
-
-
-if __name__ == '__main__':
- number = int(input("Input:"))
- print("Output:", divisors_lst(number), sep=" ")
\ No newline at end of file
diff --git a/Farrukh Nurmatov/Task 2.4.py b/Farrukh Nurmatov/Task 2.4.py
deleted file mode 100644
index 9aed2d85..00000000
--- a/Farrukh Nurmatov/Task 2.4.py
+++ /dev/null
@@ -1,15 +0,0 @@
-"""Write a Python program to sort a dictionary by key."""
-
-example_dict = {1: "stas", 3: "misha", 4: "fara", 5: "dima", 2: "serega"} # initial dict
-dict_keys = list(example_dict.keys()) # create list of keys
-dict_keys.sort() # sorting list of keys
-
-sorted_dict = dict() # create new dict
-
-# add key: value pair to dict, taking key from sorted list and getting value from initial dict by key
-for key in dict_keys:
- sorted_dict[key] = example_dict.get(key)
-
-
-print(example_dict) # initial dict
-print(sorted_dict) # sorted dict
\ No newline at end of file
diff --git a/Farrukh Nurmatov/Task 2.5.py b/Farrukh Nurmatov/Task 2.5.py
deleted file mode 100644
index a8a994a2..00000000
--- a/Farrukh Nurmatov/Task 2.5.py
+++ /dev/null
@@ -1,5 +0,0 @@
-a = (1, 2, 3, 4)
-s = ""
-for i in a:
- s += str(i)
-print(int(s))
diff --git a/Farrukh Nurmatov/Task 2.6.py b/Farrukh Nurmatov/Task 2.6.py
deleted file mode 100644
index b5a965eb..00000000
--- a/Farrukh Nurmatov/Task 2.6.py
+++ /dev/null
@@ -1,13 +0,0 @@
-"""Write a Python program to print all unique values of all dictionaries in a list."""
-
-
-lst = [{"V": "S001"}, {"V": "S002"}, {"VI": "S001"}, {"VI": "S005"},
- {"VII": "S005"}, {"V": "S009"}, {"VIII": "S007"}] # example list of dicts
-
-unique_values = set() # empty set for unique values
-
-# add all values from dicts to make them unique
-for i in lst:
- unique_values.update(set(i.values()))
-
-print(unique_values)
diff --git a/Farrukh Nurmatov/Task 2.7.py b/Farrukh Nurmatov/Task 2.7.py
deleted file mode 100644
index 9245aef4..00000000
--- a/Farrukh Nurmatov/Task 2.7.py
+++ /dev/null
@@ -1,29 +0,0 @@
-"""Write a program which makes a pretty print of a part of the multiplication table."""
-
-# input parameters
-a = 2
-b = 4
-c = 3
-d = 7
-
-
-# calculating multiplication table
-matrix = []
-for i in range(a, b + 1):
- lst = []
- for j in range(c, d + 1):
- lst.append(i * j)
- matrix.append(lst)
-
-# calculating parameters for .ljust() function
-max_num_len = len(str(matrix[-1][-1])) # length of the one cell in the table
-max_str_len = len("0 " + " ".join(str(i).ljust(len(str(i))) for i in matrix[-1])) # length of the one row in the table
-
-"""pretty printing"""
-# top row of multipliers printing
-print(" ".join(str(i).ljust(max_num_len) for i in range(c, d + 1)).rjust(max_str_len))
-
-for i in range(a, b + 1):
- print(i, end=" ") # colon multiplier printing
- print(" ".join(str(i).ljust(max_num_len) for i in matrix[i - 2]).ljust(max_str_len)) # print row of the table
-
From c5520f32f8f0a4a3ed82fadff11d8f70bae4b7f3 Mon Sep 17 00:00:00 2001
From: Farrukh Nurmatov
Date: Thu, 23 Jun 2022 20:05:03 +0500
Subject: [PATCH 4/8] first iteration finished
---
Homework-2_Python-Data_Types.md | 74 -------------
README.md | 90 +++++++++++-----
requirements.txt | Bin 0 -> 336 bytes
rss_reader.py | 181 ++++++++++++++++++++++++++++++++
tests.py | 58 ++++++++++
5 files changed, 302 insertions(+), 101 deletions(-)
delete mode 100644 Homework-2_Python-Data_Types.md
create mode 100644 requirements.txt
create mode 100644 rss_reader.py
create mode 100644 tests.py
diff --git a/Homework-2_Python-Data_Types.md b/Homework-2_Python-Data_Types.md
deleted file mode 100644
index 69c73afc..00000000
--- a/Homework-2_Python-Data_Types.md
+++ /dev/null
@@ -1,74 +0,0 @@
-# Python Practice - Session 2
-
-### Task 2.1
-Write a Python program to calculate the length of a string without using the `len` function.
-
-### Task 2.2
-Write a Python program to count the number of characters (character frequency) in a string (ignore case of letters).
-Examples:
-```
-Input: 'Oh, it is python'
-Output: {',': 1, ' ': 3, 'o': 2, 'h': 2, 'i': 2, 't': 2, 's': 1, 'p': 1, 'y': 1, 'n': 1}
-```
-
-### Task 2.3
-Write a Python program that accepts a comma separated sequence of words as input and prints the unique words in sorted form.
-Examples:
-```
-Input: ['red', 'white', 'black', 'red', 'green', 'black']
-Output: ['black', 'green', 'red', 'white', 'red']
-```
-
-### Task 2.3
-Create a program that asks the user for a number and then prints out a list of all the [divisors](https://en.wikipedia.org/wiki/Divisor) of that number.
-Examples:
-```
-Input: 60
-Output: {1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, 60}
-```
-
-### Task 2.4
-Write a Python program to sort a dictionary by key.
-
-### Task 2.5
-Write a Python program to print all unique values of all dictionaries in a list.
-Examples:
-```
-Input: [{"V":"S001"}, {"V": "S002"}, {"VI": "S001"}, {"VI": "S005"}, {"VII":"S005"}, {"V":"S009"},{"VIII":"S007"}]
-Output: {'S005', 'S002', 'S007', 'S001', 'S009'}
-```
-
-### Task 2.6
-Write a Python program to convert a given tuple of positive integers into an integer.
-Examples:
-```
-Input: (1, 2, 3, 4)
-Output: 1234
-```
-
-
-### Task 2.7
-Write a program which makes a pretty print of a part of the multiplication table.
-Examples:
-```
-Input:
-a = 2
-b = 4
-c = 3
-d = 7
-
-Output:
- 3 4 5 6 7
-2 6 8 10 12 14
-3 9 12 15 18 21
-4 12 16 20 24 28
-```
-
-### Materials
-* [Python Data Types](https://realpython.com/python-data-types/)
-* [Python Data Structures](https://realpython.com/python-data-structures/)
-* [Conditional Statements](https://realpython.com/python-conditional-statements/)
-* [While loop](https://realpython.com/python-while-loop/)
-* [For loop](https://realpython.com/python-for-loop/)
-* [Operators](http://pythonicway.com/python-operators)
-
diff --git a/README.md b/README.md
index c86d1e65..b43edc85 100644
--- a/README.md
+++ b/README.md
@@ -1,28 +1,64 @@
-# 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!
+Installization:
+- copy your programm to your folder
+- open your folder in terminal
+- than install requerments:
+ py -m pip install -r requerments.txt
+- after that you you can adress to script typing command in terminal:
+....\you folder\py rss_reader.py [-h] [-v] [--verbose] [--json] [--limit LIMIT] source
+
+
+usage: rss_reader.py [-h] [-v] [--verbose] [--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
+ -v, --version Print program version and exit.
+ --verbose Outputs verbose status messages.
+ --json Print result as JSON in stdout.
+ --limit LIMIT Limit news topics if this parameter provided.
+
+
+source is a positional argument that you should always input to your program.
+
+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.
+
+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]
+
+
+Parameter --json 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]"
+ }
+ ]
+}
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000000000000000000000000000000000000..bb334892b90f51b25b2301ee9041c90900a0c4c9
GIT binary patch
literal 336
zcmX|7TMmLS5S(ulk0Q~6Mm{_Y#TrSfVgX}3ygEA-vss$#&TIL+Jpvj`7}4RxH)6nz
zZ;uKGR)qo^mVK94z;mBBYtF3myroY1sdQpGZXK(@PN=Q;Eza~yR0%|{aHU(qg|o;6
zFR7TX@v^!TufvhpM#?33rKS;2a-*h}v=+;9CMw-|N1)Tlo;4lzf6RR8K<9u5dq$aq
ZCFq&X`1!_(s!=&T{S9mX#p%9UdA@umF?#?2
literal 0
HcmV?d00001
diff --git a/rss_reader.py b/rss_reader.py
new file mode 100644
index 00000000..a663abdd
--- /dev/null
+++ b/rss_reader.py
@@ -0,0 +1,181 @@
+import requests
+from lxml import etree
+import xml.etree.ElementTree as elementTree
+from bs4 import BeautifulSoup
+import json
+import logging as log
+import argparse
+
+
+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 = bunch.find("pubDate").text
+ description = description_handler(bunch.find("description"))
+ inf_lst = [title, link, date, description]
+ log.info("Branch retrieved successful!")
+ yield inf_lst
+
+
+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
+ log.info("Description retrieved successful.")
+ if "<" in description:
+ soup = BeautifulSoup(description, "html.parser")
+ data = soup.text
+ return data
+ else:
+ 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":
+ printer(main_title, news_data)
+ elif form == "json":
+ news_json = news_to_json(main_title, news_data)
+ print(news_json)
+
+
+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, help="RSS link for your information")
+ parser.add_argument("-v", "--version", action="version", version="Version 1.0.0",
+ help="Print program version and exit.")
+ parser.add_argument("--verbose", action="store_true", help="Outputs verbose status messages.")
+ 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
+ verbose = args.verbose
+ print_json = args.json
+ limit = args.limit
+
+ if verbose:
+ log.basicConfig(format="%(levelname)s: %(message)s", level=log.DEBUG)
+ log.info("Verbose output.")
+ else:
+ log.basicConfig(format="%(levelname)s: %(message)s")
+
+ xml_content = get_content(rss_url)
+ feed = get_feed(xml_content)
+ news_db = get_news_db(xml_content, limit)
+ if print_json:
+ output_form(feed, news_db, "json")
+ else:
+ output_form(feed, news_db, "console")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/tests.py b/tests.py
new file mode 100644
index 00000000..873eac67
--- /dev/null
+++ b/tests.py
@@ -0,0 +1,58 @@
+import unittest
+from unittest.mock import patch
+from rss_reader.rss_reader import *
+
+
+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)
+
+
+if __name__ == '__main__':
+ unittest.main(argv=[''], exit=False)
\ No newline at end of file
From c20b1c9d0a078532b8df78a5c99c23e7da59d7e5 Mon Sep 17 00:00:00 2001
From: Farrukh Nurmatov
Date: Thu, 23 Jun 2022 20:13:33 +0500
Subject: [PATCH 5/8] iteration 2 complieted program released as a package
---
README.md | 19 ++++++++++++--
rss_reader/__init__.py | 2 ++
rss_reader/__main__.py | 5 ++++
.../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 206 bytes
.../__pycache__/rss_reader.cpython-310.pyc | Bin 0 -> 5882 bytes
rss_reader/__pycache__/tests.cpython-310.pyc | Bin 0 -> 3847 bytes
rss_reader.py => rss_reader/rss_reader.py | 2 +-
tests.py => rss_reader/tests.py | 0
setup.py | 24 ++++++++++++++++++
9 files changed, 49 insertions(+), 3 deletions(-)
create mode 100644 rss_reader/__init__.py
create mode 100644 rss_reader/__main__.py
create mode 100644 rss_reader/__pycache__/__init__.cpython-310.pyc
create mode 100644 rss_reader/__pycache__/rss_reader.cpython-310.pyc
create mode 100644 rss_reader/__pycache__/tests.cpython-310.pyc
rename rss_reader.py => rss_reader/rss_reader.py (99%)
rename tests.py => rss_reader/tests.py (100%)
create mode 100644 setup.py
diff --git a/README.md b/README.md
index b43edc85..71549526 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,27 @@
Welcome to rss_reader.py readme file!
-Installization:
+
+
+Installization.
+First option:
- copy your programm to your folder
- open your folder in terminal
- than install requerments:
py -m pip install -r requerments.txt
- after that you you can adress to script typing command in terminal:
-....\you folder\py rss_reader.py [-h] [-v] [--verbose] [--json] [--limit LIMIT] source
+....\you folder\rss_reader\py rss_reader.py [-h] [-v] [--verbose] [--json] [--limit LIMIT] source
+
+Second option:
+- copy your package to your folder
+- open your folder in terminal
+- than install package:
+ py pip install setup.py
+ or
+ py pip install .
+- after that you you can adress to script typing command in terminal:
+....\you folder\rss_reader\py rss_reader.py [-h] [-v] [--verbose] [--json] [--limit LIMIT] source
+....\you folder\py rss_reader [-h] [-v] [--verbose] [--json] [--limit LIMIT] source
+....\any folder\rss_reader [-h] [-v] [--verbose] [--json] [--limit LIMIT] source
usage: rss_reader.py [-h] [-v] [--verbose] [--json] [--limit LIMIT] source
diff --git a/rss_reader/__init__.py b/rss_reader/__init__.py
new file mode 100644
index 00000000..a8bf2082
--- /dev/null
+++ b/rss_reader/__init__.py
@@ -0,0 +1,2 @@
+from .rss_reader import *
+from .tests 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/__pycache__/__init__.cpython-310.pyc b/rss_reader/__pycache__/__init__.cpython-310.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..2b8adab8b0a58e686aea744d1c67b91d7278d8a5
GIT binary patch
literal 206
zcmd1j<>g`kf;O%-N%}zgF^Gc@H>j5*!RX
Fi~xfOG>iZM
literal 0
HcmV?d00001
diff --git a/rss_reader/__pycache__/rss_reader.cpython-310.pyc b/rss_reader/__pycache__/rss_reader.cpython-310.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..7a103a187ff4c18739560c135afaea9741e996ee
GIT binary patch
literal 5882
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
JE7)j9iN#UuQzKuA8u$CcVno@d8ja_@-JN(o
zw(q^Q6@yJNoz;pi4@0Tiv4dZV#$Uim)ucE015N>cYFzWQS0yDJgmP!3WP*^nH
zG`P(NZW(+)7}xEsLVZ9Kd2!j2-@tf~4>nC+;)i}g66V#cRmy*dPGg~BrUPwPdo6U#
zZ+kSCe+n49il$x%5k}qQM&05jw{98r0xxhIZ&>Cj7w10~X;ubdlUkd}Lsi?Smsh16CeXr!i0hp^`C3I5KIN8#z`-@SC<+7F>Y
zU2}QpN7vq3^IEP9-;(il;c0aZ<{c?qF66Zp5v}CMn%t?j*U};CIX&Bhl!FpT*({oe
z%~7*E+RIoq$MmJylLL@MHo8ap*$7=fsLD>IC`q#<&GHbDVIo6Bs0=FwIf7Ses?_wd
z$a>@$O^)PDJ5$6bUjXSIf8H}^>KWe%)gl@pt1f^XL{=BJfh&+MWT+PPAUC)0)5Y}y
zw_Zji-N`B)7#9{KsghJVmC}K5(gC5R5NWv~<4|eoN6kL8Z@kxWgVfe*ZIKQE`#ypd
zI}2Ij+cV@5kkpoOtPci%Gz&f_N1>}eLS>Vg-Iwxt$Z>XG+(*BfoA)fJ=s(maZCQ#g
zqr*}34i&knk(k@ZOhY3TTU7YwwtdGijUVCDxAEI5&?a!zm^9R>RjkwR$7tCnQCPT~
z<*PD~4ojgsGICbjpd;$Tz2g3X>nowsLvP&hL|glDBu~P4eYCggcy15~?!=KNDpr=L
z`cN2q%X?*dFiXd?EHz^3$EXg+{#MELT*qbyg+4woMBAc#CkT)@?bA?-<}KnXnDT>NgUW9nsIv^8%5|Vg)EFq
z(dZyC;~sVezp*wRiW|Nck55cYPfSkEo;zD@=`fh9Wg5HR`w!~up87t#WDQ>gobgzw
z=oQV{GG6hy;HOcoFChu?1QAMXI!rD&EjQwUkbA{kFJ+V1r{pQ(v1xb^t792fd1(gT
z3@95Q+2&F6xY<3C2P)6}3`(@AJVohk3^+FJFG6V_l^#m_sBwD(hsef2CS?QL;vSAg
z;5hK~^Di!R{)%s9jtk{UKdadJxzq1ldi}M<*WO`s?fE&E&CmH^lPT$49P0zKw_R7`
z2r&p*U0TZyh?;J7!lekCV{Q7J$ERoc?D^@L8GcT9vy*({{Ot6s@RrU@HMm#3-WJU<
z<_7xW*chwL&(&Ns*lW)xzhFId=O@peIaeEF+Lib|
zE{-`%fg3H4%_kowA18N6Bir3f?(V+7`+o8$xtn~7_UGgwOLmfb4E_69+e{uN55L2(
zzO#E1jreb~|4pNF!KQRZ?Y$wA7Bm|ACoh^;U~lo(TBS~fq1eFTOtw}GWk;9zFsPZ+?(D!bx#xyxpzW*B*u#qbC&
zZBdAr`8lRp@)=Y-g4_<}DC4@fy9LK~lF!%`Aw7X=VOQHY4m7aeL+v@p+>Va(1u``;
zHC3CKsZE}(h2+J!(s8gHbplt7tMSlZma)5{+Y7lUo}O}py<6%~ZY?|L>O)>2TMA}x_!Xf#!{2}=TvI~`RT5_Do
z4Ta;RWyc9)-U+Bb>^O8U?X5^sFJC0`RU&jJl#IyNiF}g?{oBY9x|qxU^;*$l$tann
zVyRdxmhm1Q%vQ-dl?5ysmn&9k;{aMoZQN;erBp9)!~HK*az6
literal 0
HcmV?d00001
diff --git a/rss_reader.py b/rss_reader/rss_reader.py
similarity index 99%
rename from rss_reader.py
rename to rss_reader/rss_reader.py
index a663abdd..9c74c01e 100644
--- a/rss_reader.py
+++ b/rss_reader/rss_reader.py
@@ -150,7 +150,7 @@ 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, help="RSS link for your information")
- parser.add_argument("-v", "--version", action="version", version="Version 1.0.0",
+ parser.add_argument("-v", "--version", action="version", version="Version 1.2.0",
help="Print program version and exit.")
parser.add_argument("--verbose", action="store_true", help="Outputs verbose status messages.")
parser.add_argument("--json", action="store_true", help="Print result as JSON in stdout.")
diff --git a/tests.py b/rss_reader/tests.py
similarity index 100%
rename from tests.py
rename to rss_reader/tests.py
diff --git a/setup.py b/setup.py
new file mode 100644
index 00000000..b9f777b4
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,24 @@
+from setuptools import setup, find_packages
+
+setup(
+ name="rss_reader",
+ version="1.2.0",
+ description="Simple RSS-reader for console use.",
+ author="Farrukh Nurmatov",
+ packages=find_packages(),
+ install_requires=["beautifulsoup4>=4.11.1",
+ "bs4>=0.0.1",
+ "certifi>=2022.6.15",
+ "charset-normalizer>=2.0.12",
+ "idna>=3.3",
+ "lxml>=4.9.0",
+ "requests>=2.28.0",
+ "soupsieve>=2.3.2.post1",
+ "urllib3>=1.26.9"
+ ],
+ python_requires=">=3.9",
+ entry_points={
+ 'console_scripts':
+ ['rss_reader = '
+ 'rss_reader.rss_reader:main', ]}
+ )
From afd3984e36cf99e4523e8d01de17379c887ceee5 Mon Sep 17 00:00:00 2001
From: Farrukh Nurmatov
Date: Tue, 28 Jun 2022 17:46:04 +0500
Subject: [PATCH 6/8] complieted iteration 3
---
README.md | 103 ++++++++-----
requirements.txt | Bin 336 -> 410 bytes
rss_reader/__init__.py | 3 +-
.../database_handler.cpython-310.pyc | Bin 0 -> 5425 bytes
.../__pycache__/rss_reader.cpython-310.pyc | Bin 5882 -> 6264 bytes
rss_reader/database_handler.py | 139 ++++++++++++++++++
rss_reader/dbh_tests.py | 7 +
rss_reader/requirements.txt | Bin 0 -> 538 bytes
rss_reader/rss_reader.py | 110 ++++++++++++--
rss_reader/tests.py | 57 ++++++-
setup.py | 5 +-
11 files changed, 369 insertions(+), 55 deletions(-)
create mode 100644 rss_reader/__pycache__/database_handler.cpython-310.pyc
create mode 100644 rss_reader/database_handler.py
create mode 100644 rss_reader/dbh_tests.py
create mode 100644 rss_reader/requirements.txt
diff --git a/README.md b/README.md
index 71549526..6a1a7d00 100644
--- a/README.md
+++ b/README.md
@@ -1,52 +1,79 @@
-Welcome to rss_reader.py readme file!
+ _ __ ___ ___ _ __ ___ __ _ __| | ___ _ __
+| '__|/ __|/ __| | '__| / _ \ / _` | / _` | / _ \| '__|
+| | \__ \\__ \ | | | __/| (_| || (_| || __/| |
+|_| |___/|___/ _____ |_| \___| \__,_| \__,_| \___||_|
+ |_____|
+Welcome to rss_reader.py readme file!
-Installization.
-First option:
-- copy your programm to your folder
-- open your folder in terminal
-- than install requerments:
- py -m pip install -r requerments.txt
-- after that you you can adress to script typing command in terminal:
-....\you folder\rss_reader\py rss_reader.py [-h] [-v] [--verbose] [--json] [--limit LIMIT] source
+usage: rss_reader.py [-h] [--date DATE] [-v] [--verbose] [--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.
+ --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.
-Second option:
-- copy your package to your folder
-- open your folder in terminal
-- than install package:
- py pip install setup.py
- or
- py pip install .
-- after that you you can adress to script typing command in terminal:
-....\you folder\rss_reader\py rss_reader.py [-h] [-v] [--verbose] [--json] [--limit LIMIT] source
-....\you folder\py rss_reader [-h] [-v] [--verbose] [--json] [--limit LIMIT] source
-....\any folder\rss_reader [-h] [-v] [--verbose] [--json] [--limit LIMIT] source
+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.
+If --json parameter not provided, program print to console news in format below.
-usage: rss_reader.py [-h] [-v] [--verbose] [--json] [--limit LIMIT] source
+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]
-This program gets information from RSS-channel and returns in user friendly format.
-positional arguments:
- source RSS link for your information
+Parameter --json print json string in format that described below. This parameter also takes effect from --limit parameter.
-options:
- -h, --help show this help message and exit
- -v, --version Print program version and exit.
- --verbose Outputs verbose status messages.
- --json Print result as JSON in stdout.
- --limit LIMIT Limit news topics if this parameter provided.
+"[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]"
+ }
+ ]
+}
+--date - parameter to get information from the database. This parameter should take a date in `%Y%m%d` format.
+For example: `--date 20191020`
-source is a positional argument that you should always input to your program.
+--date with source parameter returns data from database according to date and source link.
-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.
+Just --date parameter returns to console news in format described below:
-If --json parameter not provided, program print to console news in format below.
-Feed:[title of the rss site where you get news]
+News on date [date]!
Title: [fact [1] title]
Date: [date of that fact[1]]
@@ -59,9 +86,9 @@ Link: [link to the fact[limit]]
Description: [fact's [limit] short summary]
-Parameter --json print json string in format that described below. This parameter also takes effect from --limit parameter.
+With --json parameter this parameter returns JSON string:
-"[title of the rss site where you get news]": [
+"[date]": [
{
"Title": "[date of that fact[1]]",
"Link": "[link to the fact[1]]",
@@ -76,4 +103,4 @@ Parameter --json print json string in format that described below. This paramete
"Description": "[fact's [limit] short summary]"
}
]
-}
+}
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
index bb334892b90f51b25b2301ee9041c90900a0c4c9..1293898a715af24358b779058e079bfd2d691ebc 100644
GIT binary patch
delta 72
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
literal 0
HcmV?d00001
diff --git a/rss_reader/__pycache__/rss_reader.cpython-310.pyc b/rss_reader/__pycache__/rss_reader.cpython-310.pyc
index 7a103a187ff4c18739560c135afaea9741e996ee..20c647e90b3f15d98143be6f6a3fe7107587def0 100644
GIT binary patch
delta 938
zcmY*XO-vI(6rQ);Znr1(Xp{Y>_pn?e`rV62n*|hG`6w4N;i)hn^
z7&P%@LM9py9w5fMq-Q-#qVeF3M9&^MipJELEhe&?_suuo``I^d_E+lXh_}+w;X?G8
zPQNQ`ckg&(@Np+uhTff5lL;-V#h##CMDNz(_c&b8Bijg&23gCLzWt*WAzY@(kCBOX
zL4!R2R7W%DPLh-zG0C*oVVBeRJ=lf@Zwk$q4iA8Xyb%ZN9xZR`=T!ULehL1<4?NJnHi-1mi9P=$B
z!?lT)n8w#RE8bSOWlxl?|E1F*f>jETfR<4fDYk`LM9vQ-WGx{V67q6Fp3TVf89AGf
zYqfy9oRZg4vUcmAnp5mJLL1JB?5JjGO+OT?CSJFgYcXHm(63@#*}|5*!eoVS2dgDx
z1rM@Z=lTZLRaPM9#=5zI4Qqq_)Y*mrV`nJbpjM4h5P%1Xj#L7!#kD*<58NLQ$AhOO
zffadbz+~3mK?=@qu-Ke*T?bIeGxwlmIVu+eY?4vVm{RJ
8q~i*#6uM{&a67aeDlrs-preC<}mkjG1LwQRe`l{
zPoM85jDBbq-t@CgnC(9*7>-e$xhCQjM?VlisKO<0Smvw4t4g84Hr*Av!T_o;1Q7Ox
zqHsCWgMAo?RdEOnUr+2x-pV(G1L*lYE_o5DD~|?#4M3qU$pZaCZiF-lfd(oNkbYo_
z7G#rtR6oP^=yl*CK$=dplswOB?$F~w6Xxj$d1_P+PC!pF(ULI9CNvq0eKn_rY1#?T
zfJ5(xO;{Se2*)9i;TaZ(EPWTb1*}Lkrz~>dP^|NU1)Rv`ko
zOy5S|L!Lf}ZKPKC#yo?PrJ&5_vFsqW5d%E1#9^6!kCn`OjJh!fMCA4eGfJ3I4W!?=
zI;-Pt%>mx^ng}eVlj}IL9fkfGc!+x)@$#bnM@AaJTI`n5R#sPvusbW*sRj
zoeDB-ELE`Pmi_3u_DyW!1r{x<9jv#ycEfGAaD&SF33y0P>TB^$ejKsw>y>)Twk;@G
zNqR>wCV9oOzuB(U>aCjR49_zO*XbwSnB&il$2joc_~(-|eiPiJhLM8|-7=1b10+JG
L*wDzF3ew~c#(Rw>
diff --git a/rss_reader/database_handler.py b/rss_reader/database_handler.py
new file mode 100644
index 00000000..36969962
--- /dev/null
+++ b/rss_reader/database_handler.py
@@ -0,0 +1,139 @@
+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)
+ 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')
+
+
+
+
+
diff --git a/rss_reader/dbh_tests.py b/rss_reader/dbh_tests.py
new file mode 100644
index 00000000..565ce9fe
--- /dev/null
+++ b/rss_reader/dbh_tests.py
@@ -0,0 +1,7 @@
+import unittest
+from database_handler import *
+
+
+class MyTest(unittest.TestCase):
+
+
diff --git a/rss_reader/requirements.txt b/rss_reader/requirements.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ee51d552e3d1c95c9749bcbe0516d5f633bc7b3c
GIT binary patch
literal 538
zcmYL`QBK1^3`FM}i92us+OjQ(A|WAh0e<*KNt&ubn-F$WR5(2F>?J}gXE*kEJhp$n
zYqhF$)TB;(?x?Ic?ok`vb2eJ&ieuk%ov9{XA}f4m#oxe_{#ZKC3`7HGp&LhCdw!z>
z^%5*C=t~V$OX~4O6nr_0)wR6B9z3tp4s7MjYhr8nMxDrw?lq-b&oZ5(KH)#WK2T*x
z<^*@?v*4}5Emrsw(Rbo4$|h{q5FE4eYNk5FX4nc&>-a(s*dFbX|2r-HJo@Vyv|%zn
z!}p*D-cM+o=g{+)Q27e7@ybij$a>-auVX!B@=va;?8D|-l+8OcM5_;M)^D@2PDg53
WXJuPQxT8=4.9.0",
"requests>=2.28.0",
"soupsieve>=2.3.2.post1",
- "urllib3>=1.26.9"
+ "urllib3>=1.26.9",
+ "python-dateutil>=2.8.2"
],
python_requires=">=3.9",
entry_points={
From d87d327129902b6181493c7d92353f634ffb3d4d Mon Sep 17 00:00:00 2001
From: Farrukh Nurmatov
Date: Thu, 30 Jun 2022 17:14:49 +0500
Subject: [PATCH 7/8] finished iteration 4 added news conversion to html and
epub
---
README.md | 84 ++++++-----
requirements.txt | Bin 410 -> 544 bytes
.../__pycache__/__init__.cpython-310.pyc | Bin 206 -> 0 bytes
.../database_handler.cpython-310.pyc | Bin 5425 -> 0 bytes
.../__pycache__/rss_reader.cpython-310.pyc | Bin 6264 -> 0 bytes
rss_reader/__pycache__/tests.cpython-310.pyc | Bin 3847 -> 0 bytes
rss_reader/database_handler.py | 39 ++++-
rss_reader/dbh_tests.py | 16 ++
rss_reader/requirements.txt | Bin 538 -> 0 bytes
rss_reader/rss_reader.py | 139 +++++++++++++++++-
rss_reader/tests.py | 29 ++--
setup.py | 11 +-
12 files changed, 260 insertions(+), 58 deletions(-)
delete mode 100644 rss_reader/__pycache__/__init__.cpython-310.pyc
delete mode 100644 rss_reader/__pycache__/database_handler.cpython-310.pyc
delete mode 100644 rss_reader/__pycache__/rss_reader.cpython-310.pyc
delete mode 100644 rss_reader/__pycache__/tests.cpython-310.pyc
delete mode 100644 rss_reader/requirements.txt
diff --git a/README.md b/README.md
index 6a1a7d00..ed2490b3 100644
--- a/README.md
+++ b/README.md
@@ -7,23 +7,23 @@
Welcome to rss_reader.py readme file!
-usage: rss_reader.py [-h] [--date DATE] [-v] [--verbose] [--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.
- --json Print result as JSON in stdout.
- --limit LIMIT Limit news topics if this parameter provided.
+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.
@@ -31,22 +31,8 @@ source is a positional argument that you should input to your program, when you
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.
-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]
-
-
-Parameter --json print json string in format that described below. This parameter also takes effect from --limit parameter.
+--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]": [
{
@@ -65,13 +51,31 @@ Parameter --json print json string in format that described below. This paramete
]
}
---date - parameter to get information from the database. This parameter should take a date in `%Y%m%d` format.
-For example: `--date 20191020`
+If --json parameter not provided, program print to console news in format below.
---date with source parameter returns data from database according to date and source link.
+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]
-Just --date parameter returns to console news in format described below:
+--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]!
@@ -86,7 +90,7 @@ Link: [link to the fact[limit]]
Description: [fact's [limit] short summary]
-With --json parameter this parameter returns JSON string:
+With --json parameter returns JSON string:
"[date]": [
{
@@ -103,4 +107,8 @@ With --json parameter this parameter returns JSON string:
"Description": "[fact's [limit] short summary]"
}
]
-}
\ No newline at end of file
+}
+
+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
index 1293898a715af24358b779058e079bfd2d691ebc..e848f78c969ee03e19c88f00db1e6d07036fd005 100644
GIT binary patch
delta 160
zcmbQmyntoGs$f@!B!+w-%x3Um$ON)&fzW_KkHL_^98B^uZ~?_r81fhr!E(kxQDX*>
zs25N?k0A>vZUmPx1j-ss+%0eK3luH_8d}Owzz_^%r!l006&ZmI1sM-AA^>Pa4iM%u
Ol!Ik0VX_mi9t8k~jT;02
delta 17
ZcmZ3$GK+b_s)^^sCNnWgO-^7u002AE22}t6
diff --git a/rss_reader/__pycache__/__init__.cpython-310.pyc b/rss_reader/__pycache__/__init__.cpython-310.pyc
deleted file mode 100644
index 2b8adab8b0a58e686aea744d1c67b91d7278d8a5..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 206
zcmd1j<>g`kf;O%-N%}zgF^Gc@H>j5*!RX
Fi~xfOG>iZM
diff --git a/rss_reader/__pycache__/database_handler.cpython-310.pyc b/rss_reader/__pycache__/database_handler.cpython-310.pyc
deleted file mode 100644
index a9402ccd454748560040b1c75136d2a81af30380..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 5425
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
diff --git a/rss_reader/__pycache__/rss_reader.cpython-310.pyc b/rss_reader/__pycache__/rss_reader.cpython-310.pyc
deleted file mode 100644
index 20c647e90b3f15d98143be6f6a3fe7107587def0..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 6264
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
diff --git a/rss_reader/database_handler.py b/rss_reader/database_handler.py
index 36969962..bc0012e3 100644
--- a/rss_reader/database_handler.py
+++ b/rss_reader/database_handler.py
@@ -118,12 +118,13 @@ def data_to_json(self, date):
"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:
@@ -133,6 +134,42 @@ def data_to_print(self, date):
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"""