-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhomework.py
176 lines (145 loc) · 6.25 KB
/
homework.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
from json import JSONDecodeError
from logging import StreamHandler
import logging
import os
import sys
import time
from dotenv import load_dotenv
from telegram.error import TelegramError
import requests
import telegram
from exсeptions import (
ConnectionError,
HomeworkStatusError,
MessageError,
ResponseFormatError,
)
load_dotenv()
logger = logging.getLogger(__name__)
last_parse_status = None
api_errors = []
PRACTICUM_TOKEN = os.getenv('PRACTICUM_TOKEN')
TELEGRAM_TOKEN = os.getenv('TELEGRAM_TOKEN')
TELEGRAM_CHAT_ID = os.getenv('TELEGRAM_CHAT_ID')
RETRY_PERIOD = int(os.getenv('RETRY_PERIOD', 600))
ENDPOINT = os.getenv(
'ENDPOINT', 'https://practicum.yandex.ru/api/user_api/homework_statuses/'
)
HEADERS = {'Authorization': f'OAuth {PRACTICUM_TOKEN}'}
HOMEWORK_VERDICTS = {
'approved': 'Работа проверена: ревьюеру всё понравилось. Ура!',
'reviewing': 'Работа взята на проверку ревьюером.',
'rejected': 'Работа проверена: у ревьюера есть замечания.',
}
def check_tokens():
"""Проверяет наличие необходимых переменных окружения."""
return all([PRACTICUM_TOKEN, TELEGRAM_TOKEN, TELEGRAM_CHAT_ID])
def send_message(bot, message):
"""Отправка сообщения в телеграм."""
logger.debug('Начата отправка сообщения в Telegram')
try:
bot.send_message(text=message, chat_id=TELEGRAM_CHAT_ID)
logger.debug(f'Сообщение успешно отправлено: {message}')
except TelegramError as error:
message = f'Ошибка при отправке сообщения {error}'
logger.error(message)
# без логирования до raise не проходит тест не понятно почему)
raise MessageError(message)
def get_api_answer(timestamp):
"""Получение ответа от API домашки."""
date = {'from_date': timestamp}
logger.debug(
f'Начат запрос к серверу. Эндпоинт: {ENDPOINT}, headers: {HEADERS},'
f' params: {date}'
)
try:
response = requests.get(url=ENDPOINT, headers=HEADERS, params=date)
except Exception as error:
raise ConnectionError(f'Ошибка при запросе к API: {error}')
response = response.json()
check_response(response)
homeworks = response.get('homeworks')
return (
homeworks[0] if homeworks else {'status': None, 'homework_name': None}
)
def check_response(response):
"""Проверка формата ответа API."""
logger.debug(f'Начата проверка ответа сервера: {response}')
try:
actual = response['homeworks']
if not isinstance(actual, list):
raise TypeError('Тип значения ключа homeworks не лист!')
except KeyError:
raise ResponseFormatError(response)
def parse_status(homework):
"""
Извлекает статус последней домашки и в случае обновления статуса.
Возвращает новый статус в виде строки.
"""
global last_parse_status
try:
new_status = homework['status']
homework_name = homework['homework_name']
except KeyError:
raise HomeworkStatusError(homework) # детали хендлятся exceptions.py
if new_status not in HOMEWORK_VERDICTS and new_status is not None:
raise HomeworkStatusError(f'Неизвестный статус домашки: {new_status}')
if last_parse_status != new_status:
homework_name = homework.get('homework_name')
verdict = HOMEWORK_VERDICTS.get(new_status)
last_parse_status = new_status
logger.debug(f'Новый статус домашки: {new_status}')
return f'Изменился статус проверки работы "{homework_name}". {verdict}'
logger.debug('Статус домашки не изменился')
# flake8: noqa: C901
def main():
"""Основная логика работы бота."""
if check_tokens():
try:
bot = telegram.Bot(token=TELEGRAM_TOKEN)
except TelegramError as error:
raise TelegramError(f'Ошибка при инциализации бота: {error}')
timestamp = int(time.time())
while True:
try:
homework = get_api_answer(timestamp)
status = parse_status(homework)
if status:
send_message(bot, status)
time.sleep(RETRY_PERIOD)
except ConnectionError as error:
logger.error(error)
message = str(error)
if message not in api_errors:
send_message(bot, message)
api_errors.append(message)
except JSONDecodeError as error:
message = f'Формат ответа API не JSON: {error}'
logger.error(message)
if message not in api_errors:
send_message(bot, message)
api_errors.append(message)
except MessageError as error:
logger.error(error)
except Exception as error:
message = f'Сбой в работе программы: {error}'
logger.error(message)
if message not in api_errors:
send_message(bot, message)
api_errors.append(message)
finally:
time.sleep(RETRY_PERIOD)
logger.critical('Не найдены токены! Завершение программы')
sys.exit()
if __name__ == '__main__':
logger.setLevel(logging.DEBUG)
formatter = logging.Formatter(
'%(asctime)s, %(levelname)s, %(name)s, %(message)s, Строка: %(lineno)s,'
)
terminal_handler = StreamHandler(sys.stdout)
terminal_handler.setFormatter(formatter)
file_handler = logging.FileHandler('homework.log', encoding='UTF-8')
file_handler.setFormatter(formatter)
logger.addHandler(terminal_handler)
logger.addHandler(file_handler)
main()