-
Notifications
You must be signed in to change notification settings - Fork 0
/
homework.py
161 lines (127 loc) · 5.48 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
from dotenv import load_dotenv
import logging
import os
import requests
import sys
import time
import telegram
load_dotenv()
PRACTICUM_TOKEN = os.getenv('PRACTICUM_TOKEN')
TELEGRAM_TOKEN = os.getenv('TELEGRAM_TOKEN')
TELEGRAM_CHAT_ID = os.getenv('CHAT_ID')
headers = {'Authorization': f'OAuth {PRACTICUM_TOKEN}'}
ENV = {
'PRACTICUM_TOKEN': PRACTICUM_TOKEN,
'TELEGRAM_TOKEN': TELEGRAM_TOKEN
}
RETRY_TIME = 60 * 10
ENDPOINT = 'https://practicum.yandex.ru/api/user_api/homework_statuses/'
HOMEWORK_STATUSES = {
'approved': 'Работа проверена: ревьюеру всё понравилось. Ура!',
'reviewing': 'Работа взята на проверку ревьюером.',
'rejected': 'Работа проверена, в ней нашлись ошибки.'
}
logging.basicConfig(
format='%(asctime)s - %(lineno)d - %(levelname)s - %(message)s',
level=logging.INFO,
stream=sys.stdout
)
class StatusCodeNot200(Exception):
"""Исключение, вызываемое при коде ответа API, не равном 200."""
def __init__(self, response):
"""Инициализатор."""
self.response = response
def __str__(self):
"""Вывод сообщения об ошибке."""
return (f'Эндпойнт "{self.response.url} недоступен.'
f'Код ответа API: {self.response.status_code}')
class KeyNotFound(Exception):
"""Исключение, вызываемое при отсутствии ожидаемых ключей в ответе API."""
def __str__(self):
"""Вывод сообщения об ошибке."""
return "Ожидаемые данные отсутствуют в ответе API"
class StatusError(Exception):
"""Исключение, вызываемое при недокументированном статусе работы."""
def __init__(self, status):
"""Инициализатор."""
self.status = status
def __str__(self):
"""Вывод сообщения об ошибке."""
return f'Недокументированный статус домашней работы: {self.status}'
def send_message(bot, message):
"""Функция отправки сообщений об изменении статуса в мессенджер."""
try:
bot.send_message(TELEGRAM_CHAT_ID, message)
logging.info(f'Бот отправил сообщение "{message}"')
except Exception:
logging.error(
f'Не удалось отправить сообщение "{message}".'
'Сбой при отправке сообщения.'
)
def get_api_answer(url, current_timestamp):
"""Функция отправки запросов к API."""
payload = {'from_date': current_timestamp}
try:
homework_statuses = requests.get(url, headers=headers, params=payload)
if homework_statuses.status_code != 200:
raise StatusCodeNot200(homework_statuses)
except Exception:
raise StatusCodeNot200(homework_statuses)
return homework_statuses.json()
def parse_status(homework):
"""Функция для анализа статуса домашнего задания в ответе API."""
status = homework.get('status')
try:
verdict = HOMEWORK_STATUSES[status]
except KeyError:
raise StatusError(status)
homework_name = homework.get('homework_name')
return f'Изменился статус проверки работы "{homework_name}". {verdict}'
def check_response(response):
"""Функция проверки изменения статуса домашнего задания в ответе API."""
try:
homeworks = response['homeworks']
except KeyError:
raise KeyNotFound
if homeworks:
return parse_status(homeworks[0])
def update_timestamp(response):
"""Функция обновления временной метки, отправляемой в запросе к API."""
try:
current_date = int(response['current_date'])
except KeyError:
raise KeyNotFound
return current_date
def check_tokens():
"""Функция проверки наличия токенов."""
for token in ENV:
if ENV[token] is None:
logging.critical(
f'Отсутcтвует обязательная переменная окружения {token}'
'Программа принудительно завершена'
)
exit()
def main():
"""Функция запуска бот-ассистента."""
check_tokens()
bot = telegram.Bot(token=TELEGRAM_TOKEN)
previous_error = ""
current_timestamp = int(time.time())
while True:
try:
response = get_api_answer(ENDPOINT, current_timestamp)
message = check_response(response)
current_timestamp = update_timestamp(response)
if message:
send_message(bot, message)
time.sleep(RETRY_TIME)
except (StatusCodeNot200, KeyNotFound, StatusError) as error:
message = f'Сбой в работе программы: {error}'
logging.error(message)
if str(error) != previous_error:
send_message(bot, message)
previous_error = str(error)
time.sleep(RETRY_TIME)
continue
if __name__ == '__main__':
main()