py_stepik/mod_oop/3.2_10_request_handler.py
2024-04-11 14:02:10 +03:00

80 lines
5.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
https://stepik.org/lesson/701987/step/4?unit=702088
Необходимо объявить класс-декоратор с именем Handler, который можно было бы применять к функциям следующим образом:
@Handler(methods=('GET', 'POST')) # по умолчанию methods = ('GET',)
def contact(request):
return "Сергей Балакирев"
Здесь аргумент methods декоратора Handler содержит список разрешенных запросов для обработки. Сама декорированная функция вызывается по аналогии с предыдущим подвигом:
res = contact({"method": "POST", "url": "contact.html"})
В результате функция contact должна возвращать строку в формате:
"<метод>: <данные из функции>"
В нашем примере - это будет:
"POST: Сергей Балакирев"
>>> @Handler(methods=('GET', 'POST')) # по умолчанию methods = ('GET',)
... def contact(request):
... return "Сергей Балакирев"
>>> contact({"method": "POST", "url": "contact.html"})
'POST: Сергей Балакирев'
Если ключ method в словаре request отсутствует, то по умолчанию подразумевается GET-запрос. Если ключ method принимает значение отсутствующее в списке methods декоратора Handler, например, "PUT", то декорированная функция contact должна возвращать значение None.
Для имитации GET и POST-запросов в классе Handler необходимо объявить два вспомогательных метода с сигнатурами:
def get(self, func, request, *args, **kwargs) - для имитации обработки GET-запроса
def post(self, func, request, *args, **kwargs) - для имитации обработки POST-запроса
В зависимости от типа запроса должен вызываться соответствующий метод (его выбор в классе можно реализовать методом __getattribute__()). На выходе эти методы должны формировать строки в заданном формате.
P.S. В программе достаточно объявить только класс. Ничего на экран выводить не нужно.
Небольшая справка
Для реализации декоратора с параметрами на уровне класса в инициализаторе __init__(self, methods) прописываем параметр для декоратора, а магический метод __call__() объявляем как полноценный декоратор на уровне функции, например:
class Handler:
def __init__(self, methods):
# здесь нужные строчки
def __call__(self, func):
def wrapper(request, *args, **kwargs):
# здесь нужные строчки
return wrapper
"""
Handler=[(setattr(a,"get",0),setattr(a,"post",0),a)[2]for a in[lambda **b:lambda c:lambda d,*e,**f:[h in(g or["GET"])and f"{h}: {c(d,*e,**f)}"or None for g in[b["methods"]]for h in[d.get("method",g and g[0]or"GET")]][0]]][0]
def tests():
assert hasattr(Handler, 'get') and hasattr(Handler, 'post'), "класс Handler должен содержать методы get и post"
@Handler(methods=('GET', 'POST'))
def contact2(request):
return "контакты"
assert contact2({"method": "POST"}) == "POST: контакты", "декорированная функция вернула неверные данные"
assert contact2({"method": "GET"}) == "GET: контакты", "декорированная функция вернула неверные данные"
assert contact2({"method": "DELETE"}) is None, "декорированная функция вернула неверные данные"
assert contact2({}) == "GET: контакты", "декорированная функция вернула неверные данные при указании пустого словаря"
@Handler(methods=('POST'))
def index(request):
return "index"
assert index({"method": "POST"}) == "POST: index", "декорированная функция вернула неверные данные"
assert index({"method": "GET"}) is None, "декорированная функция вернула неверные данные"
assert index({"method": "DELETE"}) is None, "декорированная функция вернула неверные данные"
if __name__ == "__main__":
import doctest
doctest.testmod()
tests()