Dvorakouski Kiryl#37
Dvorakouski Kiryl#37KirylDv wants to merge 35 commits intointroduction-to-python-bsuir-2019:masterfrom KirylDv:FinalTask
Conversation
| self.links = [] | ||
| self.text = "" | ||
|
|
||
| def handle_starttag(self, tag, attrs): |
There was a problem hiding this comment.
Описываю ситуацию. Я открываю пулл реквест, первым делом я вижу вот эту функцию. Я не смотрел остальной код, на данный момент еще не разбирался. Пытаюсь разобраться с этой функцией.
Так вот, я совсем не могу понять, что эта функция делает, для чего она предназначена и т.д., пока я не просмотрю весь код или даже не начну гонять этот код с дебаггером.
Хотя бы подробный док стринг написать, что оно делает, пояснить, какие аргументы приходят (это как минимум)
project/html_parser.py
Outdated
| from html.parser import HTMLParser | ||
|
|
||
|
|
||
| class _html_parser(HTMLParser): |
There was a problem hiding this comment.
Очень странное название класса, должен быть 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.
название функций и методов должны показывать действие (в самом простом случае содержать глагол). названия 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.
Лучше будет использовать уже встроенный функционал для обработки исключений и прописать несколько except блоков, где будет обрабатываться каждое из этих исключений
project/reader.py
Outdated
| show_news() - output news to stdout | ||
| """ | ||
|
|
||
| def __init__(self, args): |
There was a problem hiding this comment.
В данном случае интерфейс класса очень сильно завязан на объект 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.
очень много магических переменных, которые что-то значат и скорее всего что-то важное, но я не могу понять, какой смысл в них скрывается :)
Как минимум имеет смысл эти индексы вынестси в отдельные переменные, а лучше подумать, как можно красивее работать с этими объектами news
project/reader.py
Outdated
| if separ: | ||
| json += ',' | ||
| separ = True | ||
| json += '{\n "title": "' + news[0] + '",' |
There was a problem hiding this comment.
обычно советуют избегать использовать в качестве имени переменных/функций и т.д. названия модулей (в пайтоне есть модуль 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.
для этого лучше использовать функциональность модуля 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.
В данном случае эта строка не нужна.
|
|
||
| def __init__(self): | ||
| super(Database, self).__init__() | ||
| if not exists("cache.db"): |
There was a problem hiding this comment.
Советую название файла с кэшем вынести в какую-нибудь переменную, к которой можно обратиться из всех мест, где оно необходимо. Например сделать ее отрибутом класса (либо сделать как аргумент функции init, в таком случае эта функциональность будет более кастомизируема.
| try: | ||
| self._open() | ||
| self.cursor.execute(f""" | ||
| SELECT name from feed WHERE source = '{url}' |
There was a problem hiding this comment.
Тут есть опасность 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.
Чтобы не было магических чисел в коде, можно использовать объектную модель хранения данных. В данном случае возможно подойдет использование 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.
выглядит достаточно сложным решением. Не думаю, что в данном случае необходимо использовать лямбду
| from .SQL_cache import Database | ||
|
|
||
|
|
||
| class RSSReader(): |
There was a problem hiding this comment.
Данный класс немного перегружен по функциональности.
Класс RSSReader должен заниматься чтением RSS. Однако в данном случае он также занимается сохранением в новостей в различные форматы и выводом новостей в консоль.
Данный класс стоит разделить на несколько классов
| @@ -0,0 +1,51 @@ | |||
| #!/usr/bin/env python3 | |||
There was a problem hiding this comment.
Отсутствуют юнит-тесты
| if separ: | ||
| json_text += ',' | ||
| separ = True | ||
| json_text += '{\n "title": "' + news['title'] + '",' |
There was a problem hiding this comment.
Есть модуль json, в котором есть функциональность по конвертированию объектов Python в JSON представление.
| text_links = [] | ||
| for link in news["links"]: | ||
| if "(image)" in link: | ||
| image_links += [link[:-8]] |
| """ | ||
|
|
||
| def __init__(self, source, limit, verbose, date, sv_path, colorize): | ||
| super(RSSReader, self).__init__() |
There was a problem hiding this comment.
Класс RSSReader не наследуется от других классов (кроме неявного наследования от object)
Данный вызов super не нужен
I'm not sure should I write Dvarakouski Kiryl or Dvorakouski Kiryl