-
Notifications
You must be signed in to change notification settings - Fork 32
Dvorakouski Kiryl #37
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Dvorakouski Kiryl #37
Conversation
self.links = [] | ||
self.text = "" | ||
|
||
def handle_starttag(self, tag, attrs): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Описываю ситуацию. Я открываю пулл реквест, первым делом я вижу вот эту функцию. Я не смотрел остальной код, на данный момент еще не разбирался. Пытаюсь разобраться с этой функцией.
Так вот, я совсем не могу понять, что эта функция делает, для чего она предназначена и т.д., пока я не просмотрю весь код или даже не начну гонять этот код с дебаггером.
Хотя бы подробный док стринг написать, что оно делает, пояснить, какие аргументы приходят (это как минимум)
project/html_parser.py
Outdated
from html.parser import HTMLParser | ||
|
||
|
||
class _html_parser(HTMLParser): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Очень странное название класса, должен быть CamelCase
project/reader.py
Outdated
print(string, sep=sep, end=end, flush=flush) | ||
|
||
|
||
def progress(elems, done, length=20): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
название функций и методов должны показывать действие (в самом простом случае содержать глагол). названия output
и progress
очень плохо подходят как имена функций
output("Error: Can't connect to web-site, please check URL") | ||
else: | ||
output("Unknown error") | ||
sys.exit() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Лучше будет использовать уже встроенный функционал для обработки исключений и прописать несколько except блоков, где будет обрабатываться каждое из этих исключений
project/reader.py
Outdated
show_news() - output news to stdout | ||
""" | ||
|
||
def __init__(self, args): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
В данном случае интерфейс класса очень сильно завязан на объект args, который содержит аргументы командной строки.
Если завтра придется избавиться от argparse, то придется и этот класс переписывать.
я бы посоветовал просто принимать 4 этих значения как аргументы init вместо объекта args
project/reader.py
Outdated
output(f"Title: {news[0]}") | ||
output(f"Date: {news[1]}") | ||
output(f"Link: {news[2]}", end="\n\n") | ||
output(news[3], end="\n\n") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
очень много магических переменных, которые что-то значат и скорее всего что-то важное, но я не могу понять, какой смысл в них скрывается :)
Как минимум имеет смысл эти индексы вынестси в отдельные переменные, а лучше подумать, как можно красивее работать с этими объектами news
project/reader.py
Outdated
if separ: | ||
json += ',' | ||
separ = True | ||
json += '{\n "title": "' + news[0] + '",' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
обычно советуют избегать использовать в качестве имени переменных/функций и т.д. названия модулей (в пайтоне есть модуль json)
лучше переименовать эту переменную
project/reader.py
Outdated
|
||
def output(string, sep=' ', end='\n', flush=False, verbose=True): | ||
"""Output function for singe string but convert ' to '""" | ||
if verbose: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
для этого лучше использовать функциональность модуля logging
# rss_reader https://news.tut.by/rss/index.rss --json
Traceback (most recent call last):
File "/usr/local/bin/rss_reader", line 8, in <module>
sys.exit(main())
File "/usr/local/lib/python3.8/site-packages/project/rss_reader.py", line 26, in main
rss.show_json()
File "/usr/local/lib/python3.8/site-packages/project/reader.py", line 136, in show_json
json_text = Converter.to_json(feed, column, self.__verbose, color=self.__colorize)
TypeError: to_json() got an unexpected keyword argument 'color' |
Сгенерировать HTML не получается # rss_reader https://news.tut.by/rss/index.rss --to_html
Traceback (most recent call last):
File "/usr/local/bin/rss_reader", line 8, in <module>
sys.exit(main())
File "/usr/local/lib/python3.8/site-packages/project/rss_reader.py", line 32, in main
rss.save_html()
File "/usr/local/lib/python3.8/site-packages/project/reader.py", line 154, in save_html
Converter().to_html(feed, column, verbose=self.__verbose, color=self.__colorize)
File "/usr/local/lib/python3.8/site-packages/project/converter.py", line 203, in to_html
img_path = _download_image(link, verbose)
TypeError: _download_image() missing 1 required positional argument: 'color'
root@e646f5762ed4:/data/PythonHomework# rss_reader https://news.tut.by/rss/index.rss --to_html /data/my_news
usage: rss_reader [-h] [--version] [--json] [--verbose] [--to_fb2] [--to_html] [--colorize] [--path PATH] [--limit LIMIT] [--date DATE] source
rss_reader: error: unrecognized arguments: /data/my_news |
Такая же ситуация с fb2 |
есть небольшие стилистические ошибки root@e646f5762ed4:/data/PythonHomework# pycodestyle --max-line-length=120 .
./project/SQL_cache.py:19:66: W291 trailing whitespace
./project/SQL_cache.py:20:50: W291 trailing whitespace
./project/SQL_cache.py:39:37: W291 trailing whitespace
./project/SQL_cache.py:49:40: W291 trailing whitespace
./project/SQL_cache.py:51:41: W291 trailing whitespace
./project/converter.py:70:50: W291 trailing whitespace
./project/converter.py:81:82: W291 trailing whitespace
./project/converter.py:95:21: W291 trailing whitespace
./project/reader.py:57:9: E731 do not assign a lambda expression, use a def
./project/reader.py:66:83: W291 trailing whitespace
./project/reader.py:143:76: W291 trailing whitespace
./project/rss_reader.py:14:37: E231 missing whitespace after ',' |
# rss_reader https://news.tut.by/rss/world.rss --limit 1
Traceback (most recent call last):
File "/usr/local/bin/rss_reader", line 8, in <module>
sys.exit(main())
File "/usr/local/lib/python3.8/site-packages/project/rss_reader.py", line 23, in main
if ' ' in args.path:
TypeError: argument of type 'NoneType' is not iterable |
ошибка при попытке сгенерировать pdf # rss_reader https://news.tut.by/rss/world.rss --to_html --path /data/news
Traceback (most recent call last):
File "/usr/local/bin/rss_reader", line 8, in <module>
sys.exit(main())
File "/usr/local/lib/python3.8/site-packages/project/rss_reader.py", line 43, in main
rss.save_html()
File "/usr/local/lib/python3.8/site-packages/project/reader.py", line 152, in save_html
Converter().to_html(feed, column, self.__sv_path, verbose=self.__verbose, color=self.__colorize)
File "/usr/local/lib/python3.8/site-packages/project/converter.py", line 203, in to_html
img_path = _download_image(link, verbose, sv_path, color)
File "/usr/local/lib/python3.8/site-packages/project/converter.py", line 14, in _download_image
local_name, headers = urllib.request.urlretrieve(
File "/usr/local/lib/python3.8/urllib/request.py", line 257, in urlretrieve
tfp = open(filename, 'wb')
FileNotFoundError: [Errno 2] No such file or directory: '/data/news/vulkan_novaya_zelandiya_09122019_3.jpg' |
"""Class working with SQLite3 database""" | ||
|
||
def __init__(self): | ||
super(Database, self).__init__() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
В данном случае эта строка не нужна.
|
||
def __init__(self): | ||
super(Database, self).__init__() | ||
if not exists("cache.db"): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Советую название файла с кэшем вынести в какую-нибудь переменную, к которой можно обратиться из всех мест, где оно необходимо. Например сделать ее отрибутом класса (либо сделать как аргумент функции init, в таком случае эта функциональность будет более кастомизируема.
try: | ||
self._open() | ||
self.cursor.execute(f""" | ||
SELECT name from feed WHERE source = '{url}' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Тут есть опасность SQL инъекций (https://ru.wikipedia.org/wiki/%D0%92%D0%BD%D0%B5%D0%B4%D1%80%D0%B5%D0%BD%D0%B8%D0%B5_SQL-%D0%BA%D0%BE%D0%B4%D0%B0)
if self.__verbose: | ||
write_progressbar(len(data), counter) | ||
for news in data: | ||
column += [{"title": news[2], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Чтобы не было магических чисел в коде, можно использовать объектную модель хранения данных. В данном случае возможно подойдет использование namedtuple
def __cache_data(self, column, feed): | ||
"""Take parsed data and write it to database""" | ||
stdout_write("Writing data to database...", verbose=self.__verbose, color="blue", colorize=self.__colorize) | ||
date = lambda pubDate: dateutil.parser.parse(pubDate).strftime("%Y%m%d") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
выглядит достаточно сложным решением. Не думаю, что в данном случае необходимо использовать лямбду
from .SQL_cache import Database | ||
|
||
|
||
class RSSReader(): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Данный класс немного перегружен по функциональности.
Класс RSSReader должен заниматься чтением RSS. Однако в данном случае он также занимается сохранением в новостей в различные форматы и выводом новостей в консоль.
Данный класс стоит разделить на несколько классов
@@ -0,0 +1,51 @@ | |||
#!/usr/bin/env python3 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Отсутствуют юнит-тесты
if separ: | ||
json_text += ',' | ||
separ = True | ||
json_text += '{\n "title": "' + news['title'] + '",' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Есть модуль json, в котором есть функциональность по конвертированию объектов Python в JSON представление.
text_links = [] | ||
for link in news["links"]: | ||
if "(image)" in link: | ||
image_links += [link[:-8]] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Magic number
""" | ||
|
||
def __init__(self, source, limit, verbose, date, sv_path, colorize): | ||
super(RSSReader, self).__init__() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Класс RSSReader не наследуется от других классов (кроме неявного наследования от object)
Данный вызов super не нужен
I'm not sure should I write Dvarakouski Kiryl or Dvorakouski Kiryl