-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhomework.py
161 lines (132 loc) · 5.9 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
"""Получает данные о статусе домашней работы и отправляет их в телеграм."""
import logging
import os
import time
from http import HTTPStatus
from json.decoder import JSONDecodeError
import requests
import telegram
from dotenv import load_dotenv
from exceptions import (
YandexApiResponseError, UnknownHomeworkStatus,
ResponseHasNoHomeworks)
load_dotenv()
PRACTICUM_TOKEN = os.getenv('PRACTICUM_TOKEN')
TELEGRAM_TOKEN = os.getenv('TELEGRAM_TOKEN')
TELEGRAM_CHAT_ID = os.getenv('TELEGRAM_CHAT_ID')
RETRY_TIME = 600
ENDPOINT = 'https://practicum.yandex.ru/api/user_api/homework_statuses/'
HEADERS = {'Authorization': f'OAuth {PRACTICUM_TOKEN}'}
HOMEWORK_STATUSES = {
'approved': 'Работа проверена: ревьюеру всё понравилось. Ура!',
'reviewing': 'Работа взята на проверку ревьюером.',
'rejected': 'Работа проверена: у ревьюера есть замечания.'
}
YEAR = 31556926
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
handler = logging.StreamHandler()
logger.addHandler(handler)
formatter = logging.Formatter(
'%(asctime)s - %(name)s - [%(levelname)s] - %(message)s')
handler.setFormatter(formatter)
def send_message(bot, message):
"""Step 5: Отправляет сообщение в Telegram чат."""
try:
bot.send_message(
chat_id=TELEGRAM_CHAT_ID,
text=message
)
logger.info(f'Сообщение: {message} - успешно отправлено')
except telegram.TelegramError as error:
logger.error(error)
raise error
def get_api_answer(current_timestamp):
"""Step 2: Получает данные о статусе домашних работ за месяц."""
timestamp = current_timestamp or int(time.time())
params = {'from_date': timestamp}
try:
response = requests.get(ENDPOINT, headers=HEADERS, params=params)
except requests.exceptions.RequestException as error:
logger.error(error)
raise error
logger.info(f'step 2 - status code: {response.status_code}')
status_code = response.status_code
if status_code != HTTPStatus.OK:
raise YandexApiResponseError(
f'Ошибка ответа от сервера Яндекс. Код ответа: {status_code}')
try:
response = response.json()
except JSONDecodeError as error:
logger.error(error)
raise error
logger.info('step 2 - выполнен')
return response
def check_response(response):
"""Step 3: Проверяет ответ API на корректность."""
if not isinstance(response, dict):
raise TypeError(
f'Функция получила на вход аргумент типа: {type(response)}.'
'Ожидаемыей тип: dict'
)
if 'homeworks' not in response:
raise ResponseHasNoHomeworks(
'Проверяемый ответ от сервера не содержит ключ "homeworks"')
homeworks = response['homeworks']
if not isinstance(homeworks, list):
raise TypeError('Функция возвращает не список')
logger.info('step 3 - выполнен')
return homeworks
def parse_status(homework):
"""Step 4: Извлекает статус последней домашней работы."""
if 'homework_name' not in homework and 'status' not in homework:
raise KeyError('Ключи homework_name и status не найдены')
homework_name = homework['homework_name']
homework_status = homework['status']
if homework_status not in HOMEWORK_STATUSES:
raise UnknownHomeworkStatus(
f'{homework_status} - неизвестный статус домашней работы')
verdict = HOMEWORK_STATUSES[homework_status]
logger.info('step 4 - выполнен')
return f'Изменился статус проверки работы "{homework_name}". {verdict}'
def check_tokens():
"""Step 1: Проверяет доступность переменных окружения.
Которые необходимы для работы программы.
"""
if PRACTICUM_TOKEN and TELEGRAM_TOKEN and TELEGRAM_CHAT_ID:
logger.info('step 1 - выполнен')
return True
else:
logger.critical('Отсутствуют переменные окружения')
return False
def main():
"""Основная логика работы бота.
Проверяет статус последней работы и в случае изменения статуса
отпрявляет уведомление в телеграм чат, а в случает ошибки отправляет
в телеграм чат однократное уведомление об ошибке.
"""
current_date = int(time.time())
from_date = current_date - YEAR
bot = telegram.Bot(token=TELEGRAM_TOKEN)
errors_list = []
last_homework_status = ['has no status yet']
while check_tokens():
try:
response = get_api_answer(from_date)
homework_list = check_response(response)
message = parse_status(homework_list[0])
if message not in last_homework_status:
send_message(bot, message)
last_homework_status[0] = message
else:
logger.debug('Статус работы не изменился.')
time.sleep(RETRY_TIME)
except Exception as error:
message = f'Сбой в работе программы: {error}'
logger.error(error)
if message not in errors_list:
send_message(bot, message)
errors_list.append(message)
time.sleep(RETRY_TIME)
if __name__ == '__main__':
main()