From fb4a9321369b18785e733333d8015516dbfb5bff Mon Sep 17 00:00:00 2001 From: Dmitry Date: Thu, 11 Apr 2024 14:02:10 +0300 Subject: [PATCH] + 3.2_10 --- mod_oop/3.2_10_request_handler.py | 79 +++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 mod_oop/3.2_10_request_handler.py diff --git a/mod_oop/3.2_10_request_handler.py b/mod_oop/3.2_10_request_handler.py new file mode 100644 index 0000000..de89f3a --- /dev/null +++ b/mod_oop/3.2_10_request_handler.py @@ -0,0 +1,79 @@ +""" + 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()