From 72f482d8bc1593176557b8a67c382c1e9611f113 Mon Sep 17 00:00:00 2001 From: PAND-or Date: Fri, 15 Mar 2019 02:48:43 +0300 Subject: [PATCH 1/6] hw04 --- lesson04/client/__main__.py | 81 +++++++++++++++++++ lesson04/server/__init__.py | 3 + lesson04/server/__main__.py | 79 ++++++++++++++++++ lesson04/server/routes.py | 20 +++++ lesson04/server/test_module/controllers.py | 5 ++ lesson04/server/test_module/routes.py | 6 ++ lesson04/server/text/controllers.py | 6 ++ lesson04/server/text/routes.py | 9 +++ lesson04/server/text/tests/__init__.py | 0 .../server/text/tests/test_controllers.py | 9 +++ 10 files changed, 218 insertions(+) create mode 100644 lesson04/client/__main__.py create mode 100644 lesson04/server/__init__.py create mode 100644 lesson04/server/__main__.py create mode 100644 lesson04/server/routes.py create mode 100644 lesson04/server/test_module/controllers.py create mode 100644 lesson04/server/test_module/routes.py create mode 100644 lesson04/server/text/controllers.py create mode 100644 lesson04/server/text/routes.py create mode 100644 lesson04/server/text/tests/__init__.py create mode 100644 lesson04/server/text/tests/test_controllers.py diff --git a/lesson04/client/__main__.py b/lesson04/client/__main__.py new file mode 100644 index 0000000..713d571 --- /dev/null +++ b/lesson04/client/__main__.py @@ -0,0 +1,81 @@ +#!/usr/bin/python3 +__author__ = "Андрей Петров" + +""" +клиент отправляет запрос серверу; +сервер отвечает соответствующим кодом результата. Клиент и сервер должны быть реализованы в виде отдельных скриптов, +содержащих соответствующие функции. + +Функции клиента: +сформировать presence-сообщение; +отправить сообщение серверу; +получить ответ сервера; +разобрать сообщение сервера; +параметры командной строки скрипта client.py []: addr — ip-адрес сервера; +port — tcp-порт на сервере, +по умолчанию 7777. + +""" +import re +import sys +import argparse +import socket +import json +from datetime import datetime + + +def createParser(): + parser = argparse.ArgumentParser() + parser.add_argument('host', nargs='?', default='localhost') + parser.add_argument('port', nargs='?', default='7777') + return parser + + +parser = createParser() +args = parser.parse_args(sys.argv[1:]) + +port = int(re.search('[0-9]{2,}', args.port).group(0)) + +sock = socket.socket() +sock.connect((args.host, port)) + +# сформировать presence-сообщение; +# В формате JIM +msg_presence = json.dumps( + { + "action": "presence", + "time": datetime.now().timestamp(), + "type": "status", + "user": { + "account_name": "User Name", + "status": "Yep, I am here!" + } + } +) + +msg_lower = json.dumps( + { + "action": "lower_text", + "data": 'GGGGG' + } +) + +# отправить сообщение серверу; +sock.send(msg_presence.encode()) +#sock.send(msg_lower.encode()) + +# получить ответ сервера; +data = sock.recv(1024) +response = json.loads( + data.decode('utf-8') +) +# разобрать сообщение сервера; +if response.get('response') == 200: + print( + f"Response Message: {response.get('msg')}" + ) +else: + print( + f"Error: {response.get('error')}" + ) +sock.close() diff --git a/lesson04/server/__init__.py b/lesson04/server/__init__.py new file mode 100644 index 0000000..da70eca --- /dev/null +++ b/lesson04/server/__init__.py @@ -0,0 +1,3 @@ +from .controllers import * +from .routes import * + diff --git a/lesson04/server/__main__.py b/lesson04/server/__main__.py new file mode 100644 index 0000000..f7a47e6 --- /dev/null +++ b/lesson04/server/__main__.py @@ -0,0 +1,79 @@ +#!/usr/bin/python3 +__author__ = "Андрей Петров" + +""" +клиент отправляет запрос серверу; +сервер отвечает соответствующим кодом результата. Клиент и сервер должны быть реализованы в виде отдельных скриптов, +содержащих соответствующие функции. + +Функции сервера: +принимает сообщение клиента; +формирует ответ клиенту; +отправляет ответ клиенту; +имеет параметры командной строки: -p — TCP-порт для работы (по умолчанию использует 7777); +-a — IP-адрес для прослушивания (по умолчанию слушает все доступные адреса). +""" + +import sys +import os +import json +import socket +import argparse +from routes import get_server_routes + + +def createParser(): + parser = argparse.ArgumentParser() + parser.add_argument('-a', '--addr', nargs='?', default='') + parser.add_argument('-p', '--port', nargs='?', default='7777') + return parser + + +parser = createParser() +args = parser.parse_args(sys.argv[1:]) + + +sock = socket.socket() +sock.bind((args.addr, int(args.port))) +sock.listen(5) + + +## Без этого не работал код из урока +os.chdir('server') +sys.path.append(os.getcwd()) +## + +while True: + # принимает сообщение клиента; + client, address = sock.accept() + + data = client.recv(1024) + request = json.loads( + data.decode('utf-8') + ) + + # формирует ответ клиенту; + + client_action = request.get('action') + + resolved_routes = list( + filter( + lambda itm: itm.get('action') == client_action, + get_server_routes() + ) + ) + + route = resolved_routes[0] if resolved_routes else None + if route: + controller = route.get('controller') + response = controller(request.get('data'), request) + + else: + response = { + "response": 400, + "error": "Wrong action, try again" + } + + # отправляет ответ клиенту; + client.send(json.dumps(response).encode('utf-8')) + client.close() diff --git a/lesson04/server/routes.py b/lesson04/server/routes.py new file mode 100644 index 0000000..9d5b03a --- /dev/null +++ b/lesson04/server/routes.py @@ -0,0 +1,20 @@ +import os +from importlib import import_module +from functools import reduce + + +def get_server_routes(): + return reduce( + lambda routes, module: routes + getattr(module, 'routes', []), + reduce( + lambda modules, dir: modules + [import_module(f'{dir}.routes')], + filter( + lambda itm: os.path.isdir(itm) and itm != '__pycache__', + os.listdir() + ), + [] + ), + [] + ) + + diff --git a/lesson04/server/test_module/controllers.py b/lesson04/server/test_module/controllers.py new file mode 100644 index 0000000..036ec40 --- /dev/null +++ b/lesson04/server/test_module/controllers.py @@ -0,0 +1,5 @@ +def send_presence(data, request): + return { + "response": 200, + "msg": f"Hi {request.get('user')['account_name']}" + } diff --git a/lesson04/server/test_module/routes.py b/lesson04/server/test_module/routes.py new file mode 100644 index 0000000..1eb5c4c --- /dev/null +++ b/lesson04/server/test_module/routes.py @@ -0,0 +1,6 @@ +from .controllers import send_presence + + +routes = [ + {'action': 'presence', 'controller': send_presence} +] \ No newline at end of file diff --git a/lesson04/server/text/controllers.py b/lesson04/server/text/controllers.py new file mode 100644 index 0000000..f320424 --- /dev/null +++ b/lesson04/server/text/controllers.py @@ -0,0 +1,6 @@ +def get_lower_text(data): + return data.lower() + + +def get_upper_text(data): + return data.upper() diff --git a/lesson04/server/text/routes.py b/lesson04/server/text/routes.py new file mode 100644 index 0000000..290e162 --- /dev/null +++ b/lesson04/server/text/routes.py @@ -0,0 +1,9 @@ +from .controllers import get_lower_text +from .controllers import get_upper_text + + + +routes = [ + {'action': 'lower_text', 'controller': get_lower_text}, + {'action': 'upper_text', 'controller': get_upper_text} +] \ No newline at end of file diff --git a/lesson04/server/text/tests/__init__.py b/lesson04/server/text/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lesson04/server/text/tests/test_controllers.py b/lesson04/server/text/tests/test_controllers.py new file mode 100644 index 0000000..ee83895 --- /dev/null +++ b/lesson04/server/text/tests/test_controllers.py @@ -0,0 +1,9 @@ +from text.controllers import ( + get_lower_text, get_upper_text +) + +TEXT_TEST = 'SOME TEXT' +ASSERT_TEXT = 'some text' + +def test_get_lower_text_is_lower(): + assert get_lower_text(TEXT_TEST) == ASSERT_TEXT From 0f2a73a19d4bc2f2dfce86504d6e95dddd135f5c Mon Sep 17 00:00:00 2001 From: PAND-or Date: Fri, 15 Mar 2019 03:39:00 +0300 Subject: [PATCH 2/6] test --- lesson04/server/__init__.py | 3 --- lesson04/server/__main__.py | 2 +- lesson04/server/routes.py | 2 +- lesson04/server/test_module/controllers.py | 2 +- lesson04/server/text/controllers.py | 6 ----- lesson04/server/text/routes.py | 9 -------- lesson04/server/text/tests/__init__.py | 0 .../server/text/tests/test_controllers.py | 9 -------- lesson04/tests/test_server.py | 22 +++++++++++++++++++ 9 files changed, 25 insertions(+), 30 deletions(-) delete mode 100644 lesson04/server/__init__.py delete mode 100644 lesson04/server/text/controllers.py delete mode 100644 lesson04/server/text/routes.py delete mode 100644 lesson04/server/text/tests/__init__.py delete mode 100644 lesson04/server/text/tests/test_controllers.py create mode 100644 lesson04/tests/test_server.py diff --git a/lesson04/server/__init__.py b/lesson04/server/__init__.py deleted file mode 100644 index da70eca..0000000 --- a/lesson04/server/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .controllers import * -from .routes import * - diff --git a/lesson04/server/__main__.py b/lesson04/server/__main__.py index f7a47e6..c72ea45 100644 --- a/lesson04/server/__main__.py +++ b/lesson04/server/__main__.py @@ -66,7 +66,7 @@ def createParser(): route = resolved_routes[0] if resolved_routes else None if route: controller = route.get('controller') - response = controller(request.get('data'), request) + response = controller(request) else: response = { diff --git a/lesson04/server/routes.py b/lesson04/server/routes.py index 9d5b03a..3451d82 100644 --- a/lesson04/server/routes.py +++ b/lesson04/server/routes.py @@ -9,7 +9,7 @@ def get_server_routes(): reduce( lambda modules, dir: modules + [import_module(f'{dir}.routes')], filter( - lambda itm: os.path.isdir(itm) and itm != '__pycache__', + lambda itm: os.path.isdir(itm) and itm != '__pycache__' and itm != '.pytest_cache', os.listdir() ), [] diff --git a/lesson04/server/test_module/controllers.py b/lesson04/server/test_module/controllers.py index 036ec40..4b1996d 100644 --- a/lesson04/server/test_module/controllers.py +++ b/lesson04/server/test_module/controllers.py @@ -1,4 +1,4 @@ -def send_presence(data, request): +def send_presence(request): return { "response": 200, "msg": f"Hi {request.get('user')['account_name']}" diff --git a/lesson04/server/text/controllers.py b/lesson04/server/text/controllers.py deleted file mode 100644 index f320424..0000000 --- a/lesson04/server/text/controllers.py +++ /dev/null @@ -1,6 +0,0 @@ -def get_lower_text(data): - return data.lower() - - -def get_upper_text(data): - return data.upper() diff --git a/lesson04/server/text/routes.py b/lesson04/server/text/routes.py deleted file mode 100644 index 290e162..0000000 --- a/lesson04/server/text/routes.py +++ /dev/null @@ -1,9 +0,0 @@ -from .controllers import get_lower_text -from .controllers import get_upper_text - - - -routes = [ - {'action': 'lower_text', 'controller': get_lower_text}, - {'action': 'upper_text', 'controller': get_upper_text} -] \ No newline at end of file diff --git a/lesson04/server/text/tests/__init__.py b/lesson04/server/text/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/lesson04/server/text/tests/test_controllers.py b/lesson04/server/text/tests/test_controllers.py deleted file mode 100644 index ee83895..0000000 --- a/lesson04/server/text/tests/test_controllers.py +++ /dev/null @@ -1,9 +0,0 @@ -from text.controllers import ( - get_lower_text, get_upper_text -) - -TEXT_TEST = 'SOME TEXT' -ASSERT_TEXT = 'some text' - -def test_get_lower_text_is_lower(): - assert get_lower_text(TEXT_TEST) == ASSERT_TEXT diff --git a/lesson04/tests/test_server.py b/lesson04/tests/test_server.py new file mode 100644 index 0000000..46ed84b --- /dev/null +++ b/lesson04/tests/test_server.py @@ -0,0 +1,22 @@ +import sys +sys.path.append('../') + +from server.test_module.controllers import send_presence + +REQUEST = { + "action": "presence", + "type": "status", + "user": { + "account_name": "User Name", + "status": "Yep, I am here!" + } + } + +RESPONSE = { + "response": 200, + "msg": "Hi User Name" + } + + +def presence_msg_request_to_response(): + assert send_presence(REQUEST) == RESPONSE From 8968df6952b4ede3e3bc44363507a5a08984ef8b Mon Sep 17 00:00:00 2001 From: PAND-or Date: Tue, 19 Mar 2019 00:53:10 +0300 Subject: [PATCH 3/6] lesson05 init --- lesson05/__init__.py | 0 lesson05/client/__main__.py | 86 +++++++++++++++++++ lesson05/default.log | 24 ++++++ lesson05/server/__main__.py | 81 +++++++++++++++++ lesson05/server/presence/controllers.py | 12 +++ lesson05/server/presence/routes.py | 6 ++ lesson05/server/protocol.py | 29 +++++++ lesson05/server/routes.py | 29 +++++++ lesson05/server/settings.py | 9 ++ .../tests/protocol/test_make_response.py | 43 ++++++++++ .../tests/protocol/test_validate_request.py | 28 ++++++ lesson05/server/tests/routes/test_resolve.py | 19 ++++ lesson05/server/text/controllers.py | 23 +++++ lesson05/server/text/routes.py | 9 ++ .../server/text/tests/controllers/__init__.py | 0 .../text/tests/controllers/test_lower.py | 38 ++++++++ .../text/tests/controllers/test_upper.py | 38 ++++++++ 17 files changed, 474 insertions(+) create mode 100644 lesson05/__init__.py create mode 100644 lesson05/client/__main__.py create mode 100644 lesson05/default.log create mode 100644 lesson05/server/__main__.py create mode 100644 lesson05/server/presence/controllers.py create mode 100644 lesson05/server/presence/routes.py create mode 100644 lesson05/server/protocol.py create mode 100644 lesson05/server/routes.py create mode 100644 lesson05/server/settings.py create mode 100644 lesson05/server/tests/protocol/test_make_response.py create mode 100644 lesson05/server/tests/protocol/test_validate_request.py create mode 100644 lesson05/server/tests/routes/test_resolve.py create mode 100644 lesson05/server/text/controllers.py create mode 100644 lesson05/server/text/routes.py create mode 100644 lesson05/server/text/tests/controllers/__init__.py create mode 100644 lesson05/server/text/tests/controllers/test_lower.py create mode 100644 lesson05/server/text/tests/controllers/test_upper.py diff --git a/lesson05/__init__.py b/lesson05/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lesson05/client/__main__.py b/lesson05/client/__main__.py new file mode 100644 index 0000000..27d384e --- /dev/null +++ b/lesson05/client/__main__.py @@ -0,0 +1,86 @@ +#!/usr/bin/python3 +__author__ = "Андрей Петров" + +""" +клиент отправляет запрос серверу; +сервер отвечает соответствующим кодом результата. Клиент и сервер должны быть реализованы в виде отдельных скриптов, +содержащих соответствующие функции. + +Функции клиента: +сформировать presence-сообщение; +отправить сообщение серверу; +получить ответ сервера; +разобрать сообщение сервера; +параметры командной строки скрипта client.py []: addr — ip-адрес сервера; +port — tcp-порт на сервере, +по умолчанию 7777. + +""" +import re +import sys +import argparse +import socket +import json +from datetime import datetime + + +def createParser(): + parser = argparse.ArgumentParser() + parser.add_argument('host', nargs='?', default='localhost') + parser.add_argument('port', nargs='?', default='7777') + return parser + + +parser = createParser() +args = parser.parse_args(sys.argv[1:]) + +port = int(re.search('[0-9]{2,}', args.port).group(0)) + +sock = socket.socket() +sock.connect((args.host, port)) + +# сформировать presence-сообщение; +# В формате JIM + +msg_presence = json.dumps( + { + "action": "presence", + "time": datetime.now().timestamp(), + "type": "status", + "user": { + "account_name": input("Enter user Name: "), + "status": input("Status message: ") + } + } +) +""" +msg_action = json.dumps( + { + "action": input("Enter action (lower_text): "), + "data": input("Enter data: ") + } +) +#sock.send(msg_action.encode()) +""" + +# отправить сообщение серверу; +sock.send(msg_presence.encode()) + + +# получить ответ сервера; +data = sock.recv(1024) +response = json.loads( + data.decode('utf-8') +) +# разобрать сообщение сервера; + +if response.get('response') == 200: + if response.get('alert'): + print( + f"Response Message: {response.get('alert')}" + ) +else: + print( + f"Error: {response.get('error')}" + ) +sock.close() diff --git a/lesson05/default.log b/lesson05/default.log new file mode 100644 index 0000000..40914a5 --- /dev/null +++ b/lesson05/default.log @@ -0,0 +1,24 @@ +2019-03-18 21:38:58,556 - DEBUG - Client detected ('127.0.0.1', 57458) +2019-03-18 21:40:01,858 - DEBUG - Client detected ('127.0.0.1', 57464) +2019-03-18 21:40:10,016 - DEBUG - Client detected ('127.0.0.1', 57465) +2019-03-18 23:41:19,099 - DEBUG - Client detected ('127.0.0.1', 60493) +2019-03-18 23:42:06,300 - DEBUG - Client detected ('127.0.0.1', 60496) +2019-03-18 23:42:54,092 - DEBUG - Client detected ('127.0.0.1', 60501) +2019-03-18 23:51:58,722 - DEBUG - Client detected ('127.0.0.1', 60631) +2019-03-18 23:52:27,013 - DEBUG - Client detected ('127.0.0.1', 60633) +2019-03-18 23:53:55,819 - DEBUG - Client detected ('127.0.0.1', 60638) +2019-03-19 00:06:15,021 - DEBUG - Client detected ('127.0.0.1', 61013) +2019-03-19 00:09:42,991 - DEBUG - Client detected ('127.0.0.1', 61045) +2019-03-19 00:17:01,016 - DEBUG - Client detected ('127.0.0.1', 61226) +2019-03-19 00:21:39,446 - DEBUG - Client detected ('127.0.0.1', 61272) +2019-03-19 00:21:50,358 - DEBUG - Client detected ('127.0.0.1', 61274) +2019-03-19 00:24:33,940 - DEBUG - Client detected ('127.0.0.1', 61300) +2019-03-19 00:29:55,684 - DEBUG - Client detected ('127.0.0.1', 61404) +2019-03-19 00:30:43,120 - DEBUG - Client detected ('127.0.0.1', 61410) +2019-03-19 00:32:23,369 - DEBUG - Client detected ('127.0.0.1', 61421) +2019-03-19 00:47:00,622 - DEBUG - Client detected ('127.0.0.1', 61804) +2019-03-19 00:47:47,436 - DEBUG - Client detected ('127.0.0.1', 61807) +2019-03-19 00:48:18,901 - DEBUG - Client detected ('127.0.0.1', 61817) +2019-03-19 00:48:30,243 - DEBUG - Client detected ('127.0.0.1', 61822) +2019-03-19 00:48:41,896 - DEBUG - Client detected ('127.0.0.1', 61825) +2019-03-19 00:48:47,608 - DEBUG - Client detected ('127.0.0.1', 61827) diff --git a/lesson05/server/__main__.py b/lesson05/server/__main__.py new file mode 100644 index 0000000..6d67885 --- /dev/null +++ b/lesson05/server/__main__.py @@ -0,0 +1,81 @@ +#!/usr/bin/python3 +__author__ = "Андрей Петров" + + +import sys +import os +import json +import socket +import argparse +import logging +from datetime import datetime + +from protocol import ( + validate_request, make_response, + make_400, make_404 +) +from routes import resolve + +logger = logging.getLogger('default') +formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') +handler = logging.FileHandler('default.log') + +handler.setFormatter(formatter) +handler.setLevel(logging.DEBUG) + +logger.addHandler(handler) +logger.setLevel(logging.DEBUG) + + +def createParser(): + parser = argparse.ArgumentParser() + parser.add_argument('-a', '--addr', nargs='?', default='') + parser.add_argument('-p', '--port', nargs='?', default='7777') + return parser + + +parser = createParser() +args = parser.parse_args(sys.argv[1:]) + + +sock = socket.socket() +sock.bind((args.addr, int(args.port))) +sock.listen(5) + + +## Без этого не работал код из урока +#os.chdir('server') +#sys.path.append(os.getcwd()) +## + +try: + while True: + # принимает сообщение клиента; + client, address = sock.accept() + logger.debug(f'Client detected {address}') + + data = client.recv(1024) + request = json.loads( + data.decode('utf-8') + ) + + if validate_request(request): + controller = resolve(request.get('action')) + if controller: + try: + response = controller(request) + except Exception: + response = make_response( + request, 500, + error='Internal server error.' + ) + else: + response = make_404(request) + else: + response = make_400(request) + + response_string = json.dumps(response) + client.send(response_string.encode('utf-8')) + client.close() +except KeyboardInterrupt: + sock.close() diff --git a/lesson05/server/presence/controllers.py b/lesson05/server/presence/controllers.py new file mode 100644 index 0000000..bf56412 --- /dev/null +++ b/lesson05/server/presence/controllers.py @@ -0,0 +1,12 @@ +from protocol import make_response, make_400 + + +def send_presence(request): + user = request.get('user') + if not user: + return make_400(request) + return make_response( + request, + 200, + alert=f"Hi {user['account_name']}" + ) diff --git a/lesson05/server/presence/routes.py b/lesson05/server/presence/routes.py new file mode 100644 index 0000000..6679a46 --- /dev/null +++ b/lesson05/server/presence/routes.py @@ -0,0 +1,6 @@ +from .controllers import send_presence + + +routes = [ + {'action': 'presence', 'controller': send_presence} +] diff --git a/lesson05/server/protocol.py b/lesson05/server/protocol.py new file mode 100644 index 0000000..0a269fe --- /dev/null +++ b/lesson05/server/protocol.py @@ -0,0 +1,29 @@ +from datetime import datetime + + +def validate_request(raw): + request_time = raw.get('time') + request_action = raw.get('action') + if request_time and request_action: + return True + return False + + +def make_response(request, code, data=None, error=None, alert=None): + return { + 'action': request.get('action'), + 'user': request.get('user'), + 'time': datetime.now().timestamp(), + 'data': data, + 'response': code, + 'error': error, + 'alert': alert, + } + + +def make_400(request): + return make_response(request, 400, error='Wrong request format') + + +def make_404(request): + return make_response(request, 404, error='Action is not supported.') diff --git a/lesson05/server/routes.py b/lesson05/server/routes.py new file mode 100644 index 0000000..6458acb --- /dev/null +++ b/lesson05/server/routes.py @@ -0,0 +1,29 @@ +import os +from functools import reduce +from importlib import __import__ + +from settings import INSTALLED_MODULES + + +def get_server_routes(): + return reduce( + lambda routes, module: routes + getattr(module, 'routes', []), + reduce( + lambda submodules, module: submodules + [getattr(module, 'routes', [])], + reduce ( + lambda modules, module: modules + [__import__(f'{module}.routes')], + INSTALLED_MODULES, + [] + ), + [] + ), + [] + ) + + +def resolve(action, routes=None): + routes_mapping = { + route['action']:route['controller'] + for route in routes or get_server_routes() + } + return routes_mapping.get(action, None) diff --git a/lesson05/server/settings.py b/lesson05/server/settings.py new file mode 100644 index 0000000..fe7eb4c --- /dev/null +++ b/lesson05/server/settings.py @@ -0,0 +1,9 @@ +import os + +BASE_DIR = os.path.dirname( + os.path.abspath(__file__) +) + +INSTALLED_MODULES = [ + 'text', 'presence' +] \ No newline at end of file diff --git a/lesson05/server/tests/protocol/test_make_response.py b/lesson05/server/tests/protocol/test_make_response.py new file mode 100644 index 0000000..d9d34eb --- /dev/null +++ b/lesson05/server/tests/protocol/test_make_response.py @@ -0,0 +1,43 @@ +import pytest +from datetime import datetime +from protocol import make_response + + +@pytest.fixture +def success_status(): + return 200 + + +@pytest.fixture +def valid_request(): + return { + 'action': 'upper_text', + 'time': datetime.now().timestamp() + } + + +@pytest.fixture +def assert_response(success_status): + return { + 'action': 'upper_text', + 'user': None, + 'time': datetime.now().timestamp(), + 'data': None, + 'response': success_status, + } + + +def test_make_response( + valid_request, + assert_response, + success_status +): + response = make_response( + valid_request, + success_status, + ) + + assert response.get('action') == assert_response.get('action') + assert response.get('user') == assert_response.get('user') + assert response.get('data') == assert_response.get('data') + assert response.get('code') == assert_response.get('code') diff --git a/lesson05/server/tests/protocol/test_validate_request.py b/lesson05/server/tests/protocol/test_validate_request.py new file mode 100644 index 0000000..33f13a4 --- /dev/null +++ b/lesson05/server/tests/protocol/test_validate_request.py @@ -0,0 +1,28 @@ +import pytest +from datetime import datetime +from protocol import validate_request + + +@pytest.fixture +def valid_request(): + return { + 'action': 'upper_text', + 'time': datetime.now().timestamp() + } + + +@pytest.fixture +def invalid_request(): + return {} + + +def test_validate_request_success( + valid_request +): + assert validate_request(valid_request) == True + + +def test_validate_request_fail( + invalid_request +): + assert validate_request(invalid_request) == False diff --git a/lesson05/server/tests/routes/test_resolve.py b/lesson05/server/tests/routes/test_resolve.py new file mode 100644 index 0000000..7efe1d5 --- /dev/null +++ b/lesson05/server/tests/routes/test_resolve.py @@ -0,0 +1,19 @@ +import pytest +from routes import resolve + + +@pytest.fixture +def controller(): + return lambda arg: arg + + +@pytest.fixture +def routes(controller): + return [ + {'action': 'upper_text', 'controller': controller}, + ] + + +def test_resolve(routes, controller): + resolved = resolve('upper_text', routes) + assert resolved == controller diff --git a/lesson05/server/text/controllers.py b/lesson05/server/text/controllers.py new file mode 100644 index 0000000..f2ae160 --- /dev/null +++ b/lesson05/server/text/controllers.py @@ -0,0 +1,23 @@ +from protocol import make_response, make_400 + + +def get_upper_text(request): + data = request.get('data') + if not data: + return make_400(request) + return make_response( + request, + 200, + data.upper() + ) + + +def get_lower_text(request): + data = request.get('data') + if not data: + return make_400(request) + return make_response( + request, + 200, + data.lower() + ) diff --git a/lesson05/server/text/routes.py b/lesson05/server/text/routes.py new file mode 100644 index 0000000..57b929d --- /dev/null +++ b/lesson05/server/text/routes.py @@ -0,0 +1,9 @@ +from .controllers import ( + get_upper_text, get_lower_text +) + + +routes = [ + {'action': 'upper_text', 'controller': get_upper_text}, + {'action': 'lower_text', 'controller': get_lower_text}, +] \ No newline at end of file diff --git a/lesson05/server/text/tests/controllers/__init__.py b/lesson05/server/text/tests/controllers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lesson05/server/text/tests/controllers/test_lower.py b/lesson05/server/text/tests/controllers/test_lower.py new file mode 100644 index 0000000..1650704 --- /dev/null +++ b/lesson05/server/text/tests/controllers/test_lower.py @@ -0,0 +1,38 @@ +import pytest +from datetime import datetime +from text.controllers import get_lower_text + + +@pytest.fixture +def lower_text_request(): + return { + 'action': 'lower_text', + 'time': datetime.now().timestamp(), + 'data': 'LOWER TEXT', + } + + +@pytest.fixture +def lower_text_response_data(): + return 'lower text' + + +@pytest.fixture +def empty_request(): + return { + 'action': 'upper_text', + 'time': datetime.now().timestamp() + } + + +def test_get_lower_text_is_lower( + lower_text_request, + lower_text_response_data +): + response = get_lower_text(lower_text_request) + assert response.get('data') == lower_text_response_data + + +def test_get_lower_text_empty(empty_request): + response = get_lower_text(empty_request) + assert response.get('response') == 400 diff --git a/lesson05/server/text/tests/controllers/test_upper.py b/lesson05/server/text/tests/controllers/test_upper.py new file mode 100644 index 0000000..1dd16cd --- /dev/null +++ b/lesson05/server/text/tests/controllers/test_upper.py @@ -0,0 +1,38 @@ +import pytest +from datetime import datetime +from text.controllers import get_upper_text + + +@pytest.fixture +def valid_request(): + return { + 'action': 'upper_text', + 'time': datetime.now().timestamp(), + 'data': 'upper text', + } + + +@pytest.fixture +def empty_request(): + return { + 'action': 'upper_text', + 'time': datetime.now().timestamp() + } + + +@pytest.fixture +def upper_text_response_data(): + return 'UPPER TEXT' + + +def test_get_upper_text_is_upper( + valid_request, + upper_text_response_data +): + response = get_upper_text(valid_request) + assert response.get('data') == upper_text_response_data + + +def test_get_upper_text_empty(empty_request): + response = get_upper_text(empty_request) + assert response.get('response') == 400 From 3259911c94d4cc5add92b8427176ec490fda8f5c Mon Sep 17 00:00:00 2001 From: PAND-or Date: Tue, 19 Mar 2019 03:13:05 +0300 Subject: [PATCH 4/6] hw05 --- lesson05/__init__.py | 0 lesson05/client/__main__.py | 94 +++++++++++++++------------- lesson05/client/client_log_config.py | 18 ++++++ lesson05/log/client.log | 7 +++ lesson05/log/server.log | 5 ++ lesson05/server/__main__.py | 32 ++++------ lesson05/server/server_log_config.py | 18 ++++++ 7 files changed, 110 insertions(+), 64 deletions(-) delete mode 100644 lesson05/__init__.py create mode 100644 lesson05/client/client_log_config.py create mode 100644 lesson05/log/client.log create mode 100644 lesson05/log/server.log create mode 100644 lesson05/server/server_log_config.py diff --git a/lesson05/__init__.py b/lesson05/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/lesson05/client/__main__.py b/lesson05/client/__main__.py index 27d384e..bc7c8bc 100644 --- a/lesson05/client/__main__.py +++ b/lesson05/client/__main__.py @@ -22,6 +22,7 @@ import socket import json from datetime import datetime +from client_log_config import logger def createParser(): @@ -31,56 +32,61 @@ def createParser(): return parser + parser = createParser() args = parser.parse_args(sys.argv[1:]) port = int(re.search('[0-9]{2,}', args.port).group(0)) + sock = socket.socket() -sock.connect((args.host, port)) - -# сформировать presence-сообщение; -# В формате JIM - -msg_presence = json.dumps( - { - "action": "presence", - "time": datetime.now().timestamp(), - "type": "status", - "user": { - "account_name": input("Enter user Name: "), - "status": input("Status message: ") +try: + sock.connect((args.host, port)) + + # сформировать presence-сообщение; + # В формате JIM + + msg_presence = json.dumps( + { + "action": "presence", + "time": datetime.now().timestamp(), + "type": "status", + "user": { + "account_name": input("Enter user Name: "), + "status": input("Status message: ") + } } - } -) -""" -msg_action = json.dumps( - { - "action": input("Enter action (lower_text): "), - "data": input("Enter data: ") - } -) -#sock.send(msg_action.encode()) -""" + ) + """ + msg_action = json.dumps( + { + "action": input("Enter action (lower_text): "), + "data": input("Enter data: ") + } + ) + #sock.send(msg_action.encode()) + """ + + # отправить сообщение серверу; + sock.send(msg_presence.encode()) -# отправить сообщение серверу; -sock.send(msg_presence.encode()) - - -# получить ответ сервера; -data = sock.recv(1024) -response = json.loads( - data.decode('utf-8') -) -# разобрать сообщение сервера; - -if response.get('response') == 200: - if response.get('alert'): - print( - f"Response Message: {response.get('alert')}" - ) -else: - print( - f"Error: {response.get('error')}" + + # получить ответ сервера; + data = sock.recv(1024) + response = json.loads( + data.decode('utf-8') ) -sock.close() + # разобрать сообщение сервера; + + if response.get('response') == 200: + if response.get('alert'): + logger.debug(f"Response Message: {response.get('alert')}") + print( + f"Response Message: {response.get('alert')}" + ) + else: + logger.critical(f"Error request: {response.get('error')}") + + sock.close() +except Exception: + logger.critical(f'client cant conntect to host:{args.host} port{port}') diff --git a/lesson05/client/client_log_config.py b/lesson05/client/client_log_config.py new file mode 100644 index 0000000..9c31693 --- /dev/null +++ b/lesson05/client/client_log_config.py @@ -0,0 +1,18 @@ +""" +Создание именованного логгера; +Сообщения лога должны иметь следующий формат: "<дата-время> <уровеньважности> <имямодуля> <сообщение>"; +Журналирование должно производиться в лог-файл; +На стороне сервера необходимо настроить ежедневную ротацию лог-файлов. +""" + +import logging.handlers + +logger = logging.getLogger('client') +formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(name)s - %(module)s - %(message)s') +handler = logging.handlers.TimedRotatingFileHandler('log/client.log', when='d', interval=1, backupCount=4) + +handler.setFormatter(formatter) +handler.setLevel(logging.DEBUG) + +logger.addHandler(handler) +logger.setLevel(logging.DEBUG) \ No newline at end of file diff --git a/lesson05/log/client.log b/lesson05/log/client.log new file mode 100644 index 0000000..4f3b8ea --- /dev/null +++ b/lesson05/log/client.log @@ -0,0 +1,7 @@ + +2019-03-19 03:05:05,291 - CRITICAL - client - __main__ - client cant conntect to host:localhost port7777 +2019-03-19 03:10:20,565 - DEBUG - client - __main__ - Response Message: Hi vASYA +2019-03-19 03:10:29,685 - CRITICAL - client - __main__ - client cant conntect to host:localhost port7777 +2019-03-19 03:11:09,124 - CRITICAL - client - __main__ - client cant conntect to host:localhost port7777 +2019-03-19 03:11:14,589 - CRITICAL - client - __main__ - client cant conntect to host:localhost port7777 +2019-03-19 03:11:57,166 - DEBUG - client - __main__ - Response Message: Hi gfd diff --git a/lesson05/log/server.log b/lesson05/log/server.log new file mode 100644 index 0000000..934ad27 --- /dev/null +++ b/lesson05/log/server.log @@ -0,0 +1,5 @@ +2019-03-19 03:10:13,134 - DEBUG - __main__ - Client detected ('127.0.0.1', 64775) +2019-03-19 03:10:20,565 - DEBUG - __main__ - client ('127.0.0.1', 64775) closed +2019-03-19 03:10:56,456 - DEBUG - __main__ - Client detected ('127.0.0.1', 64819) +2019-03-19 03:11:50,998 - DEBUG - __main__ - Client detected ('127.0.0.1', 64851) +2019-03-19 03:11:57,166 - DEBUG - __main__ - client ('127.0.0.1', 64851) closed diff --git a/lesson05/server/__main__.py b/lesson05/server/__main__.py index 6d67885..c63036f 100644 --- a/lesson05/server/__main__.py +++ b/lesson05/server/__main__.py @@ -1,31 +1,24 @@ #!/usr/bin/python3 __author__ = "Андрей Петров" - import sys -import os + + + import json import socket import argparse -import logging -from datetime import datetime + + + + from protocol import ( validate_request, make_response, make_400, make_404 ) from routes import resolve - -logger = logging.getLogger('default') -formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') -handler = logging.FileHandler('default.log') - -handler.setFormatter(formatter) -handler.setLevel(logging.DEBUG) - -logger.addHandler(handler) -logger.setLevel(logging.DEBUG) - +from server_log_config import logger def createParser(): parser = argparse.ArgumentParser() @@ -43,11 +36,6 @@ def createParser(): sock.listen(5) -## Без этого не работал код из урока -#os.chdir('server') -#sys.path.append(os.getcwd()) -## - try: while True: # принимает сообщение клиента; @@ -65,17 +53,21 @@ def createParser(): try: response = controller(request) except Exception: + logger.critical(f'error 500 controller: {controller}') response = make_response( request, 500, error='Internal server error.' ) else: + logger.critical(f"error 404 controller: {request.get('action')} not found") response = make_404(request) else: response = make_400(request) + logger.critical(f"error 400 bad request: {request}") response_string = json.dumps(response) client.send(response_string.encode('utf-8')) client.close() + logger.debug(f"client {address} closed") except KeyboardInterrupt: sock.close() diff --git a/lesson05/server/server_log_config.py b/lesson05/server/server_log_config.py new file mode 100644 index 0000000..7410b14 --- /dev/null +++ b/lesson05/server/server_log_config.py @@ -0,0 +1,18 @@ +""" +Создание именованного логгера; +Сообщения лога должны иметь следующий формат: "<дата-время> <уровеньважности> <имямодуля> <сообщение>"; +Журналирование должно производиться в лог-файл; +На стороне сервера необходимо настроить ежедневную ротацию лог-файлов. +""" + +import logging.handlers + +logger = logging.getLogger('server') +formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(module)s - %(message)s') +handler = logging.handlers.TimedRotatingFileHandler('log/server.log', when='d', interval=1, backupCount=4) + +handler.setFormatter(formatter) +handler.setLevel(logging.DEBUG) + +logger.addHandler(handler) +logger.setLevel(logging.DEBUG) \ No newline at end of file From 01f350f5910288f8c04c0c430bae8700dd306754 Mon Sep 17 00:00:00 2001 From: PAND-or Date: Tue, 19 Mar 2019 03:14:45 +0300 Subject: [PATCH 5/6] delete old log --- lesson05/default.log | 24 ------------------------ 1 file changed, 24 deletions(-) delete mode 100644 lesson05/default.log diff --git a/lesson05/default.log b/lesson05/default.log deleted file mode 100644 index 40914a5..0000000 --- a/lesson05/default.log +++ /dev/null @@ -1,24 +0,0 @@ -2019-03-18 21:38:58,556 - DEBUG - Client detected ('127.0.0.1', 57458) -2019-03-18 21:40:01,858 - DEBUG - Client detected ('127.0.0.1', 57464) -2019-03-18 21:40:10,016 - DEBUG - Client detected ('127.0.0.1', 57465) -2019-03-18 23:41:19,099 - DEBUG - Client detected ('127.0.0.1', 60493) -2019-03-18 23:42:06,300 - DEBUG - Client detected ('127.0.0.1', 60496) -2019-03-18 23:42:54,092 - DEBUG - Client detected ('127.0.0.1', 60501) -2019-03-18 23:51:58,722 - DEBUG - Client detected ('127.0.0.1', 60631) -2019-03-18 23:52:27,013 - DEBUG - Client detected ('127.0.0.1', 60633) -2019-03-18 23:53:55,819 - DEBUG - Client detected ('127.0.0.1', 60638) -2019-03-19 00:06:15,021 - DEBUG - Client detected ('127.0.0.1', 61013) -2019-03-19 00:09:42,991 - DEBUG - Client detected ('127.0.0.1', 61045) -2019-03-19 00:17:01,016 - DEBUG - Client detected ('127.0.0.1', 61226) -2019-03-19 00:21:39,446 - DEBUG - Client detected ('127.0.0.1', 61272) -2019-03-19 00:21:50,358 - DEBUG - Client detected ('127.0.0.1', 61274) -2019-03-19 00:24:33,940 - DEBUG - Client detected ('127.0.0.1', 61300) -2019-03-19 00:29:55,684 - DEBUG - Client detected ('127.0.0.1', 61404) -2019-03-19 00:30:43,120 - DEBUG - Client detected ('127.0.0.1', 61410) -2019-03-19 00:32:23,369 - DEBUG - Client detected ('127.0.0.1', 61421) -2019-03-19 00:47:00,622 - DEBUG - Client detected ('127.0.0.1', 61804) -2019-03-19 00:47:47,436 - DEBUG - Client detected ('127.0.0.1', 61807) -2019-03-19 00:48:18,901 - DEBUG - Client detected ('127.0.0.1', 61817) -2019-03-19 00:48:30,243 - DEBUG - Client detected ('127.0.0.1', 61822) -2019-03-19 00:48:41,896 - DEBUG - Client detected ('127.0.0.1', 61825) -2019-03-19 00:48:47,608 - DEBUG - Client detected ('127.0.0.1', 61827) From c6a250879bc1ba4541bfa8b136a9bde995c2cc6d Mon Sep 17 00:00:00 2001 From: PAND-or Date: Tue, 19 Mar 2019 03:17:36 +0300 Subject: [PATCH 6/6] to root directry --- .gitignore | 3 + {lesson05/client => client}/__main__.py | 0 .../client => client}/client_log_config.py | 0 lesson01/hw01.py | 187 ------------------ lesson01/test_file.txt | 3 - lesson02/file.yaml | 13 -- lesson02/info_1.txt | 42 ---- lesson02/info_2.txt | 42 ---- lesson02/info_3.txt | 42 ---- lesson02/new_file.csv | 4 - lesson02/orders.json | 32 --- lesson02/task01.py | 65 ------ lesson02/task02.py | 35 ---- lesson02/task03.py | 36 ---- lesson03/client/__main__.py | 73 ------- lesson03/server/__main__.py | 61 ------ lesson04/client/__main__.py | 81 -------- lesson04/server/__main__.py | 79 -------- lesson04/server/routes.py | 20 -- lesson04/server/test_module/controllers.py | 5 - lesson04/server/test_module/routes.py | 6 - lesson04/tests/test_server.py | 22 --- {lesson05/log => log}/client.log | 0 {lesson05/log => log}/server.log | 0 {lesson05/server => server}/__main__.py | 0 .../server => server}/presence/controllers.py | 0 .../server => server}/presence/routes.py | 0 {lesson05/server => server}/protocol.py | 0 {lesson05/server => server}/routes.py | 0 .../server => server}/server_log_config.py | 0 {lesson05/server => server}/settings.py | 0 .../tests/protocol/test_make_response.py | 0 .../tests/protocol/test_validate_request.py | 0 .../tests/routes/test_resolve.py | 0 .../server => server}/text/controllers.py | 0 {lesson05/server => server}/text/routes.py | 0 .../text/tests/controllers/__init__.py | 0 .../text/tests/controllers/test_lower.py | 0 .../text/tests/controllers/test_upper.py | 0 39 files changed, 3 insertions(+), 848 deletions(-) create mode 100644 .gitignore rename {lesson05/client => client}/__main__.py (100%) rename {lesson05/client => client}/client_log_config.py (100%) delete mode 100644 lesson01/hw01.py delete mode 100644 lesson01/test_file.txt delete mode 100644 lesson02/file.yaml delete mode 100644 lesson02/info_1.txt delete mode 100644 lesson02/info_2.txt delete mode 100644 lesson02/info_3.txt delete mode 100644 lesson02/new_file.csv delete mode 100644 lesson02/orders.json delete mode 100644 lesson02/task01.py delete mode 100644 lesson02/task02.py delete mode 100644 lesson02/task03.py delete mode 100644 lesson03/client/__main__.py delete mode 100644 lesson03/server/__main__.py delete mode 100644 lesson04/client/__main__.py delete mode 100644 lesson04/server/__main__.py delete mode 100644 lesson04/server/routes.py delete mode 100644 lesson04/server/test_module/controllers.py delete mode 100644 lesson04/server/test_module/routes.py delete mode 100644 lesson04/tests/test_server.py rename {lesson05/log => log}/client.log (100%) rename {lesson05/log => log}/server.log (100%) rename {lesson05/server => server}/__main__.py (100%) rename {lesson05/server => server}/presence/controllers.py (100%) rename {lesson05/server => server}/presence/routes.py (100%) rename {lesson05/server => server}/protocol.py (100%) rename {lesson05/server => server}/routes.py (100%) rename {lesson05/server => server}/server_log_config.py (100%) rename {lesson05/server => server}/settings.py (100%) rename {lesson05/server => server}/tests/protocol/test_make_response.py (100%) rename {lesson05/server => server}/tests/protocol/test_validate_request.py (100%) rename {lesson05/server => server}/tests/routes/test_resolve.py (100%) rename {lesson05/server => server}/text/controllers.py (100%) rename {lesson05/server => server}/text/routes.py (100%) rename {lesson05/server => server}/text/tests/controllers/__init__.py (100%) rename {lesson05/server => server}/text/tests/controllers/test_lower.py (100%) rename {lesson05/server => server}/text/tests/controllers/test_upper.py (100%) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..853aa9c --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.coverage +__pycache__ +.pytest_cache diff --git a/lesson05/client/__main__.py b/client/__main__.py similarity index 100% rename from lesson05/client/__main__.py rename to client/__main__.py diff --git a/lesson05/client/client_log_config.py b/client/client_log_config.py similarity index 100% rename from lesson05/client/client_log_config.py rename to client/client_log_config.py diff --git a/lesson01/hw01.py b/lesson01/hw01.py deleted file mode 100644 index ad092a1..0000000 --- a/lesson01/hw01.py +++ /dev/null @@ -1,187 +0,0 @@ -#!/usr/bin/python3 -__author__ = "Андрей Петров" - - -""" -1. Каждое из слов «разработка», «сокет», «декоратор» представить в строковом формате и проверить тип и содержание -соответствующих переменных. Затем с помощью онлайн-конвертера преобразовать строковые представление в формат Unicode -и также проверить тип и содержимое переменных. - ->>> a = 'разработка' ->>> print(f'development: {a}, type {type(a)}') -development: разработка, type - ->>> b = 'сокет' ->>> print(f'socket: {b}, type {type(b)}') -socket: сокет, type - ->>> c = 'декоратор' ->>> print(f'decorator: {c}, type {type(c)}') -decorator: декоратор, type - ->>> a = a.encode('utf-8') ->>> print(f'development: {a}, type {type(a)}') -development: b'\xd1\x80\xd0\xb0\xd0\xb7\xd1\x80\xd0\xb0\xd0\xb1\xd0\xbe\xd1\x82\xd0\xba\xd0\xb0', type - ->>> b = b.encode('utf-8') ->>> print(f'socket: {b}, type {type(b)}') -socket: b'\xd1\x81\xd0\xbe\xd0\xba\xd0\xb5\xd1\x82', type - ->>> c = c.encode('utf-8') ->>> print(f'decorator: {c}, type {type(c)}') -decorator: b'\xd0\xb4\xd0\xb5\xd0\xba\xd0\xbe\xd1\x80\xd0\xb0\xd1\x82\xd0\xbe\xd1\x80', type - -""" - - -""" -2. Каждое из слов «class», «function», «method» записать в байтовом типе без преобразования в последовательность кодов -(не используя методы encode и decode) и определить тип, содержимое и длину соответствующих переменных. - ->>> a = b'class' ->>> print(f'class: {a}, type: {type(a)}, len:{len(a)}') -class: b'class', type: , len:5 - ->>> b = b'function' ->>> print(f'function: {b}, type: {type(b)}, len:{len(b)}') -function: b'function', type: , len:8 - ->>> c = b'method' ->>> print(f'method: {c}, type: {type(c)}, len:{len(c)}') -method: b'method', type: , len:6 -""" - - -""" -3. Определить, какие из слов «attribute», «класс», «функция», «type» невозможно записать в байтовом типе. - ->>> b'attribute' -b'attribute' - ->>> b'класс' - File "", line 1 -SyntaxError: bytes can only contain ASCII literal characters. - ->>> b'функция' - File "", line 1 -SyntaxError: bytes can only contain ASCII literal characters. - ->>> b'type' -b'type' - -Нельзя записать в байтовый тип без преобразования кириллические символы, т.к. на хранение одного -кириллическоно символа требуется больше 1 байта - -""" - - -""" -4. Преобразовать слова «разработка», «администрирование», «protocol», «standard» из строкового представления в байтовое - и выполнить обратное преобразование (используя методы encode и decode). - ->>> a = 'разработка' ->>> a -'разработка' ->>> a = a.encode() ->>> a -b'\xd1\x80\xd0\xb0\xd0\xb7\xd1\x80\xd0\xb0\xd0\xb1\xd0\xbe\xd1\x82\xd0\xba\xd0\xb0' ->>> a = a.decode() ->>> a -'разработка' - ->>> b = 'администрирование' ->>> b -'администрирование' ->>> b = b.encode() ->>> b -b'\xd0\xb0\xd0\xb4\xd0\xbc\xd0\xb8\xd0\xbd\xd0\xb8\xd1\x81\xd1\x82\xd1\x80\xd0\xb8\xd1\x80\xd0\xbe\xd0\xb2\xd0\xb0\xd0\xbd\xd0\xb8\xd0\xb5' ->>> b = b.decode() ->>> b -'администрирование' - ->>> c = 'protocol' ->>> c -'protocol' ->>> c = c.encode() ->>> c -b'protocol' ->>> c = c.decode() ->>> c -'protocol' - ->>> d = 'standard' ->>> d -'standard' ->>> d = d.encode() ->>> d -b'standard' ->>> d = d.decode() ->>> d -'standard' - -""" - -""" -5. Выполнить пинг веб-ресурсов yandex.ru, youtube.com и преобразовать результаты из байтовового -в строковый тип на кириллице. - ->>> import subprocess ->>> args = ['ping', 'yandex.ru'] ->>> subproc_ping = subprocess.Popen(args, stdout=subprocess.PIPE) ->>> for line in subproc_ping.stdout: -... line = line.decode('cp866').encode('utf-8') -... print(line.decode('utf-8')) -... -Ответ от 5.255.255.70: число байт=32 время=24мс TTL=57 -Ответ от 5.255.255.70: число байт=32 время=26мс TTL=57 -Ответ от 5.255.255.70: число байт=32 время=27мс TTL=57 - -Статистика Ping для 5.255.255.70: - Пакетов: отправлено = 4, получено = 4, потеряно = 0 - (0% потерь) -Приблизительное время приема-передачи в мс: - Минимальное = 24мсек, Максимальное = 27 мсек, Среднее = 25 мсек - - ->>> args = ['ping', 'youtube.com'] ->>> subproc_ping = subprocess.Popen(args, stdout=subprocess.PIPE) ->>> for line in subproc_ping.stdout: -... line = line.decode('cp866').encode('utf-8') -... print(line.decode('utf-8')) -... -Обмен пакетами с youtube.com [173.194.44.39] с 32 байтами данных: -Ответ от 173.194.44.39: число байт=32 время=23мс TTL=120 -Ответ от 173.194.44.39: число байт=32 время=22мс TTL=120 -Ответ от 173.194.44.39: число байт=32 время=21мс TTL=120 -Ответ от 173.194.44.39: число байт=32 время=23мс TTL=120 - -Статистика Ping для 173.194.44.39: - Пакетов: отправлено = 4, получено = 4, потеряно = 0 - (0% потерь) -Приблизительное время приема-передачи в мс: - Минимальное = 21мсек, Максимальное = 23 мсек, Среднее = 22 мсек - -""" - -""" -6. Создать текстовый файл test_file.txt, заполнить его тремя строками: «сетевое программирование», «сокет», -«декоратор». Проверить кодировку файла по умолчанию. Принудительно открыть файл в формате Unicode и -вывести его содержимое. - ->>> with open('E:/PythonScripts/Repo/python_advanced/lesson01/test_file.txt') as file: -... for f_str in file: -... print(f_str) -... -сетевое программирование -сокет -декоратор - ->>> with open('E:/PythonScripts/Repo/python_advanced/lesson01/test_file.txt', encoding='utf-8') as file: -... for f_str in file: -... print(f_str) -... -сетевое программирование -сокет -декоратор - -""" diff --git a/lesson01/test_file.txt b/lesson01/test_file.txt deleted file mode 100644 index d9c8af1..0000000 --- a/lesson01/test_file.txt +++ /dev/null @@ -1,3 +0,0 @@ -сетевое программирование -сокет -декоратор \ No newline at end of file diff --git a/lesson02/file.yaml b/lesson02/file.yaml deleted file mode 100644 index 4f0efa3..0000000 --- a/lesson02/file.yaml +++ /dev/null @@ -1,13 +0,0 @@ -100: -- 1 -- 2 -- 3 -- 4 -200: 8000 -300: - first: - - 1 - - 2 - - 3 - - 4 - second: 800 diff --git a/lesson02/info_1.txt b/lesson02/info_1.txt deleted file mode 100644 index 845390d..0000000 --- a/lesson02/info_1.txt +++ /dev/null @@ -1,42 +0,0 @@ - : Comp1 - : Microsoft Windows 7 - : 6.1.7601 Service Pack 1 7601 - : Microsoft Corporation - : - : Multiprocessor Free - : User - : - : 00971-OEM-1982661-00231 - : 11.10.2013, 10:18:05 - : 0 ., 4 ., 41 , 0 . - : LENOVO - : 3538F2G - : x64-based PC -(): - 1. - [01]: Intel64 Family 6 Model 42 Stepping 7 GenuineIntel ~3400 - BIOS: LENOVO - 1390 - Windows: C:\Windows - : C:\Windows\system32 - : \Device\HarddiskVolume1 - : ru; - : en-us; () - : (UTC+04:00) , , - - : 3 914 - : 2 299 - : . : 7 826 - : : 6 139 - : : 1 687 - : / -: net - : / -(): - 74. - [01]: KB982861 - [02]: 982861 -. . . - [74]: KB982018 - : - 1. - [01]: Realtek PCIe GBE Family Controller - : - DHCP : - IP- - [01]: 192.168.0.4 \ No newline at end of file diff --git a/lesson02/info_2.txt b/lesson02/info_2.txt deleted file mode 100644 index 0f96fb2..0000000 --- a/lesson02/info_2.txt +++ /dev/null @@ -1,42 +0,0 @@ - : Comp1 - : Microsoft Windows 10 Professional - : 16299 - : Microsoft Corporation - : - : Multiprocessor Free - : User - : - : 00971-OEM-1982661-00231 - : 11.10.2013, 10:18:05 - : 0 ., 4 ., 41 , 0 . - : ACER - : 3538F2G - : x64-based PC -(): - 1. - [01]: Intel64 Family 6 Model 42 Stepping 7 GenuineIntel ~3400 - BIOS: LENOVO - 1390 - Windows: C:\Windows - : C:\Windows\system32 - : \Device\HarddiskVolume1 - : ru; - : en-us; () - : (UTC+04:00) , , - - : 3 914 - : 2 299 - : . : 7 826 - : : 6 139 - : : 1 687 - : / -: net - : / -(): - 74. - [01]: KB982861 - [02]: 982861 -. . . - [74]: KB982018 - : - 1. - [01]: Realtek PCIe GBE Family Controller - : - DHCP : - IP- - [01]: 192.168.0.4 \ No newline at end of file diff --git a/lesson02/info_3.txt b/lesson02/info_3.txt deleted file mode 100644 index c2a964a..0000000 --- a/lesson02/info_3.txt +++ /dev/null @@ -1,42 +0,0 @@ - : Comp1 - : Microsoft Windows 8.1 Professional - : 10001 - : Microsoft Corporation - : - : Multiprocessor Free - : User - : - : 00971-OEM-1982661-00231 - : 11.10.2013, 10:18:05 - : 0 ., 4 ., 41 , 0 . - : DELL - : 3538F2G - : x86-based PC -(): - 1. - [01]: Intel64 Family 6 Model 42 Stepping 7 GenuineIntel ~3400 - BIOS: LENOVO - 1390 - Windows: C:\Windows - : C:\Windows\system32 - : \Device\HarddiskVolume1 - : ru; - : en-us; () - : (UTC+04:00) , , - - : 3 914 - : 2 299 - : . : 7 826 - : : 6 139 - : : 1 687 - : / -: net - : / -(): - 74. - [01]: KB982861 - [02]: 982861 -. . . - [74]: KB982018 - : - 1. - [01]: Realtek PCIe GBE Family Controller - : - DHCP : - IP- - [01]: 192.168.0.4 \ No newline at end of file diff --git a/lesson02/new_file.csv b/lesson02/new_file.csv deleted file mode 100644 index 0f481d5..0000000 --- a/lesson02/new_file.csv +++ /dev/null @@ -1,4 +0,0 @@ - , , , -LENOVO,Microsoft Windows 7 ,00971-OEM-1982661-00231,x64-based PC -ACER,Microsoft Windows 10 Professional,00971-OEM-1982661-00231,x64-based PC -DELL,Microsoft Windows 8.1 Professional,00971-OEM-1982661-00231,x86-based PC diff --git a/lesson02/orders.json b/lesson02/orders.json deleted file mode 100644 index 4a60f00..0000000 --- a/lesson02/orders.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "orders": [ - { - "item": "\u0411\u0430\u043d\u0430\u043d", - "quantity": 3, - "price": 300, - "buyer": "Pupkin", - "date": "08.03.2019" - }, - { - "item": "\u042f\u0431\u043b\u043e\u043a\u043e", - "quantity": 2, - "price": 700, - "buyer": "Pupkin", - "date": "08.03.2019" - }, - { - "item": "\u0410\u043f\u0435\u043b\u044c\u0441\u0438\u043d", - "quantity": 3, - "price": 1200, - "buyer": "Pupkin", - "date": "08.03.2019" - }, - { - "item": "\u0413\u0440\u0443\u0448\u0430", - "quantity": 4, - "price": 500, - "buyer": "Pupkin", - "date": "08.03.2019" - } - ] -} \ No newline at end of file diff --git a/lesson02/task01.py b/lesson02/task01.py deleted file mode 100644 index fa4e888..0000000 --- a/lesson02/task01.py +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/python3 -__author__ = "Андрей Петров" - -import csv -import re - - -""" -1. Задание на закрепление знаний по модулю CSV. Написать скрипт, осуществляющий выборку определенных данных из файлов -info_1.txt, info_2.txt, info_3.txt и формирующий новый «отчетный» файл в формате CSV. Для этого: -Создать функцию get_data(), в которой в цикле осуществляется перебор файлов с данными, их открытие и считывание данных. -В этой функции из считанных данных необходимо с помощью регулярных выражений извлечь значения параметров «Изготовитель -системы», «Название ОС», «Код продукта», «Тип системы». Значения каждого параметра поместить в соответствующий список. -Должно получиться четыре списка — например, os_prod_list, os_name_list, os_code_list, os_type_list. В этой же функции -создать главный список для хранения данных отчета — например, main_data — и поместить в него названия столбцов отчета -в виде списка: «Изготовитель системы», «Название ОС», «Код продукта», «Тип системы». Значения для этих столбцов также -оформить в виде списка и поместить в файл main_data (также для каждого файла); -Создать функцию write_to_csv(), в которую передавать ссылку на CSV-файл. В этой функции реализовать получение данных -через вызов функции get_data(), а также сохранение подготовленных данных в соответствующий CSV-файл; -Проверить работу программы через вызов функции write_to_csv(). ### -""" - - -def write_to_csv(file, data): - with open(file, 'w') as f_n: - f_n_writer = csv.writer(f_n) - for nrow in data: - f_n_writer.writerow(nrow) - - -def get_data(lst): - os_prod_list = [] - os_name_list = [] - os_code_list = [] - os_type_list = [] - main_data = [['Изготовитель системы', 'Название ОС', 'Код продукта', 'Тип системы']] - for file in lst: - datafile = open(file) - for row in datafile: - row = row.rstrip() - if re.match('Изготовитель системы', row): - os_prod_list.append(re.search(r'(Изготовитель системы).\s*(.*)', row).group(2)) - elif re.match('Название ОС', row): - os_name_list.append(re.search(r'(Название ОС).\s*(.*)', row).group(2)) - elif re.match('Код продукта', row): - os_code_list.append(re.search(r'(Код продукта).\s*(.*)', row).group(2)) - elif re.match('Тип системы', row): - os_type_list.append(re.search(r'(Тип системы).\s*(.*)', row).group(2)) - - for k in range(len(lst)): - main_data.append([ - os_prod_list[k], - os_name_list[k], - os_code_list[k], - os_type_list[k] - ]) - return main_data - - -if __name__ == "__main__": - res = get_data(['info_1.txt', 'info_2.txt', 'info_3.txt']) - write_to_csv('new_file.csv', res) - - with open('new_file.csv') as f_n: - print(f_n.read()) diff --git a/lesson02/task02.py b/lesson02/task02.py deleted file mode 100644 index 65b1628..0000000 --- a/lesson02/task02.py +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/python3 -__author__ = "Андрей Петров" - -import json - -""" -2. Задание на закрепление знаний по модулю json. Есть файл orders в формате JSON с информацией о заказах. Написать -скрипт, автоматизирующий его заполнение данными. Для этого: -Создать функцию write_order_to_json(), в которую передается 5 параметров — товар (item), количество (quantity), -цена (price), покупатель (buyer), дата (date). Функция должна предусматривать запись данных в виде словаря -в файл orders.json. При записи данных указать величину отступа в 4 пробельных символа; -Проверить работу программы через вызов функции write_order_to_json() с передачей в нее значений каждого параметра. -""" - - -def write_order_to_json(item, quantity, price, buyer, date): - with open('orders.json') as f_n: - dict_to_json = json.load(f_n) - print(dict_to_json) - dict_to_json['orders'].append({ - 'item': item, - 'quantity': quantity, - 'price': price, - 'buyer': buyer, - 'date': date, - }) - with open('orders.json', 'w') as f_w: - json.dump(dict_to_json, f_w, indent=4) - - -if __name__ == "__main__": - write_order_to_json('Банан', 3, 300, 'Pupkin', '08.03.2019') - write_order_to_json('Яблоко', 2, 700, 'Pupkin', '08.03.2019') - write_order_to_json('Апельсин', 3, 1200, 'Pupkin', '08.03.2019') - write_order_to_json('Груша', 4, 500, 'Pupkin', '08.03.2019') diff --git a/lesson02/task03.py b/lesson02/task03.py deleted file mode 100644 index 59d2de8..0000000 --- a/lesson02/task03.py +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/python3 -__author__ = "Андрей Петров" - -import yaml - -""" -### 3. Задание на закрепление знаний по модулю yaml. Написать скрипт, автоматизирующий сохранение данных -в файле YAML-формата. Для этого: -Подготовить данные для записи в виде словаря, в котором первому ключу соответствует список, второму — целое число, -третьему — вложенный словарь, где значение каждого ключа — это целое число с юникод-символом, отсутствующим -в кодировке ASCII (например, €); -Реализовать сохранение данных в файл формата YAML — например, в файл file.yaml. При этом обеспечить стилизацию файла -с помощью параметра default_flow_style, а также установить возможность работы с юникодом: allow_unicode = True; -Реализовать считывание данных из созданного файла и проверить, совпадают ли они с исходными. -""" - -def write_dict_to_yaml(dict, file): - with open(file, 'w') as f_n: - yaml.dump(dict, f_n, default_flow_style=False, allow_unicode = True) - - with open(file) as f_n: - f_n_content = yaml.load(f_n) - - print(f_n_content == dict) - -if __name__ == "__main__": - my_dict = { - '100€': [1, 2, 3, 4], - '200€': 8000, - '300€': { - 'first': [1,2,3,4], - 'second': 800, - } - } - - write_dict_to_yaml(my_dict, 'file.yaml') diff --git a/lesson03/client/__main__.py b/lesson03/client/__main__.py deleted file mode 100644 index 0e9c034..0000000 --- a/lesson03/client/__main__.py +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/python3 -__author__ = "Андрей Петров" - -""" -клиент отправляет запрос серверу; -сервер отвечает соответствующим кодом результата. Клиент и сервер должны быть реализованы в виде отдельных скриптов, -содержащих соответствующие функции. - -Функции клиента: -сформировать presence-сообщение; -отправить сообщение серверу; -получить ответ сервера; -разобрать сообщение сервера; -параметры командной строки скрипта client.py []: addr — ip-адрес сервера; -port — tcp-порт на сервере, -по умолчанию 7777. - -""" -import re -import sys -import argparse -import socket -import json -from datetime import datetime - - -def createParser(): - parser = argparse.ArgumentParser() - parser.add_argument('host', nargs='?', default='localhost') - parser.add_argument('port', nargs='?', default='7777') - return parser - - -parser = createParser() -args = parser.parse_args(sys.argv[1:]) - -port = int(re.search('[0-9]{2,}', args.port).group(0)) - -sock = socket.socket() -sock.connect((args.host, port)) - -# сформировать presence-сообщение; -# В формате JIM -msg_presence = json.dumps( - { - "action": "presence", - "time": datetime.now().timestamp(), - "type": "status", - "user": { - "account_name": "User Name", - "status": "Yep, I am here!" - } - } -) - -# отправить сообщение серверу; -sock.send(msg_presence.encode()) - -# получить ответ сервера; -data = sock.recv(1024) -response = json.loads( - data.decode('utf-8') -) -# разобрать сообщение сервера; -if response.get('response') == 200: - print( - f"Response Message: {response.get('msg')}" - ) -else: - print( - f"Error: {response.get('error')}" - ) -sock.close() diff --git a/lesson03/server/__main__.py b/lesson03/server/__main__.py deleted file mode 100644 index 6a146c4..0000000 --- a/lesson03/server/__main__.py +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/python3 -__author__ = "Андрей Петров" - -""" -клиент отправляет запрос серверу; -сервер отвечает соответствующим кодом результата. Клиент и сервер должны быть реализованы в виде отдельных скриптов, -содержащих соответствующие функции. - -Функции сервера: -принимает сообщение клиента; -формирует ответ клиенту; -отправляет ответ клиенту; -имеет параметры командной строки: -p — TCP-порт для работы (по умолчанию использует 7777); --a — IP-адрес для прослушивания (по умолчанию слушает все доступные адреса). -""" - -import sys -import json -import socket -import argparse - - -def createParser(): - parser = argparse.ArgumentParser() - parser.add_argument('-a', '--addr', nargs='?', default='') - parser.add_argument('-p', '--port', nargs='?', default='7777') - return parser - - -parser = createParser() -args = parser.parse_args(sys.argv[1:]) - - -sock = socket.socket() -sock.bind((args.addr, int(args.port))) -sock.listen(5) - -while True: - # принимает сообщение клиента; - client, address = sock.accept() - - data = client.recv(1024) - request = json.loads( - data.decode('utf-8') - ) - - # формирует ответ клиенту; - if request.get('action') == 'presence': - response = { - "response": 200, - "msg": f"Hi {request.get('user')['account_name']}" - } - else: - response = { - "response": 400, - "error": "Wrong action, try again" - } - - # отправляет ответ клиенту; - client.send(json.dumps(response).encode('utf-8')) - client.close() \ No newline at end of file diff --git a/lesson04/client/__main__.py b/lesson04/client/__main__.py deleted file mode 100644 index 713d571..0000000 --- a/lesson04/client/__main__.py +++ /dev/null @@ -1,81 +0,0 @@ -#!/usr/bin/python3 -__author__ = "Андрей Петров" - -""" -клиент отправляет запрос серверу; -сервер отвечает соответствующим кодом результата. Клиент и сервер должны быть реализованы в виде отдельных скриптов, -содержащих соответствующие функции. - -Функции клиента: -сформировать presence-сообщение; -отправить сообщение серверу; -получить ответ сервера; -разобрать сообщение сервера; -параметры командной строки скрипта client.py []: addr — ip-адрес сервера; -port — tcp-порт на сервере, -по умолчанию 7777. - -""" -import re -import sys -import argparse -import socket -import json -from datetime import datetime - - -def createParser(): - parser = argparse.ArgumentParser() - parser.add_argument('host', nargs='?', default='localhost') - parser.add_argument('port', nargs='?', default='7777') - return parser - - -parser = createParser() -args = parser.parse_args(sys.argv[1:]) - -port = int(re.search('[0-9]{2,}', args.port).group(0)) - -sock = socket.socket() -sock.connect((args.host, port)) - -# сформировать presence-сообщение; -# В формате JIM -msg_presence = json.dumps( - { - "action": "presence", - "time": datetime.now().timestamp(), - "type": "status", - "user": { - "account_name": "User Name", - "status": "Yep, I am here!" - } - } -) - -msg_lower = json.dumps( - { - "action": "lower_text", - "data": 'GGGGG' - } -) - -# отправить сообщение серверу; -sock.send(msg_presence.encode()) -#sock.send(msg_lower.encode()) - -# получить ответ сервера; -data = sock.recv(1024) -response = json.loads( - data.decode('utf-8') -) -# разобрать сообщение сервера; -if response.get('response') == 200: - print( - f"Response Message: {response.get('msg')}" - ) -else: - print( - f"Error: {response.get('error')}" - ) -sock.close() diff --git a/lesson04/server/__main__.py b/lesson04/server/__main__.py deleted file mode 100644 index c72ea45..0000000 --- a/lesson04/server/__main__.py +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/python3 -__author__ = "Андрей Петров" - -""" -клиент отправляет запрос серверу; -сервер отвечает соответствующим кодом результата. Клиент и сервер должны быть реализованы в виде отдельных скриптов, -содержащих соответствующие функции. - -Функции сервера: -принимает сообщение клиента; -формирует ответ клиенту; -отправляет ответ клиенту; -имеет параметры командной строки: -p — TCP-порт для работы (по умолчанию использует 7777); --a — IP-адрес для прослушивания (по умолчанию слушает все доступные адреса). -""" - -import sys -import os -import json -import socket -import argparse -from routes import get_server_routes - - -def createParser(): - parser = argparse.ArgumentParser() - parser.add_argument('-a', '--addr', nargs='?', default='') - parser.add_argument('-p', '--port', nargs='?', default='7777') - return parser - - -parser = createParser() -args = parser.parse_args(sys.argv[1:]) - - -sock = socket.socket() -sock.bind((args.addr, int(args.port))) -sock.listen(5) - - -## Без этого не работал код из урока -os.chdir('server') -sys.path.append(os.getcwd()) -## - -while True: - # принимает сообщение клиента; - client, address = sock.accept() - - data = client.recv(1024) - request = json.loads( - data.decode('utf-8') - ) - - # формирует ответ клиенту; - - client_action = request.get('action') - - resolved_routes = list( - filter( - lambda itm: itm.get('action') == client_action, - get_server_routes() - ) - ) - - route = resolved_routes[0] if resolved_routes else None - if route: - controller = route.get('controller') - response = controller(request) - - else: - response = { - "response": 400, - "error": "Wrong action, try again" - } - - # отправляет ответ клиенту; - client.send(json.dumps(response).encode('utf-8')) - client.close() diff --git a/lesson04/server/routes.py b/lesson04/server/routes.py deleted file mode 100644 index 3451d82..0000000 --- a/lesson04/server/routes.py +++ /dev/null @@ -1,20 +0,0 @@ -import os -from importlib import import_module -from functools import reduce - - -def get_server_routes(): - return reduce( - lambda routes, module: routes + getattr(module, 'routes', []), - reduce( - lambda modules, dir: modules + [import_module(f'{dir}.routes')], - filter( - lambda itm: os.path.isdir(itm) and itm != '__pycache__' and itm != '.pytest_cache', - os.listdir() - ), - [] - ), - [] - ) - - diff --git a/lesson04/server/test_module/controllers.py b/lesson04/server/test_module/controllers.py deleted file mode 100644 index 4b1996d..0000000 --- a/lesson04/server/test_module/controllers.py +++ /dev/null @@ -1,5 +0,0 @@ -def send_presence(request): - return { - "response": 200, - "msg": f"Hi {request.get('user')['account_name']}" - } diff --git a/lesson04/server/test_module/routes.py b/lesson04/server/test_module/routes.py deleted file mode 100644 index 1eb5c4c..0000000 --- a/lesson04/server/test_module/routes.py +++ /dev/null @@ -1,6 +0,0 @@ -from .controllers import send_presence - - -routes = [ - {'action': 'presence', 'controller': send_presence} -] \ No newline at end of file diff --git a/lesson04/tests/test_server.py b/lesson04/tests/test_server.py deleted file mode 100644 index 46ed84b..0000000 --- a/lesson04/tests/test_server.py +++ /dev/null @@ -1,22 +0,0 @@ -import sys -sys.path.append('../') - -from server.test_module.controllers import send_presence - -REQUEST = { - "action": "presence", - "type": "status", - "user": { - "account_name": "User Name", - "status": "Yep, I am here!" - } - } - -RESPONSE = { - "response": 200, - "msg": "Hi User Name" - } - - -def presence_msg_request_to_response(): - assert send_presence(REQUEST) == RESPONSE diff --git a/lesson05/log/client.log b/log/client.log similarity index 100% rename from lesson05/log/client.log rename to log/client.log diff --git a/lesson05/log/server.log b/log/server.log similarity index 100% rename from lesson05/log/server.log rename to log/server.log diff --git a/lesson05/server/__main__.py b/server/__main__.py similarity index 100% rename from lesson05/server/__main__.py rename to server/__main__.py diff --git a/lesson05/server/presence/controllers.py b/server/presence/controllers.py similarity index 100% rename from lesson05/server/presence/controllers.py rename to server/presence/controllers.py diff --git a/lesson05/server/presence/routes.py b/server/presence/routes.py similarity index 100% rename from lesson05/server/presence/routes.py rename to server/presence/routes.py diff --git a/lesson05/server/protocol.py b/server/protocol.py similarity index 100% rename from lesson05/server/protocol.py rename to server/protocol.py diff --git a/lesson05/server/routes.py b/server/routes.py similarity index 100% rename from lesson05/server/routes.py rename to server/routes.py diff --git a/lesson05/server/server_log_config.py b/server/server_log_config.py similarity index 100% rename from lesson05/server/server_log_config.py rename to server/server_log_config.py diff --git a/lesson05/server/settings.py b/server/settings.py similarity index 100% rename from lesson05/server/settings.py rename to server/settings.py diff --git a/lesson05/server/tests/protocol/test_make_response.py b/server/tests/protocol/test_make_response.py similarity index 100% rename from lesson05/server/tests/protocol/test_make_response.py rename to server/tests/protocol/test_make_response.py diff --git a/lesson05/server/tests/protocol/test_validate_request.py b/server/tests/protocol/test_validate_request.py similarity index 100% rename from lesson05/server/tests/protocol/test_validate_request.py rename to server/tests/protocol/test_validate_request.py diff --git a/lesson05/server/tests/routes/test_resolve.py b/server/tests/routes/test_resolve.py similarity index 100% rename from lesson05/server/tests/routes/test_resolve.py rename to server/tests/routes/test_resolve.py diff --git a/lesson05/server/text/controllers.py b/server/text/controllers.py similarity index 100% rename from lesson05/server/text/controllers.py rename to server/text/controllers.py diff --git a/lesson05/server/text/routes.py b/server/text/routes.py similarity index 100% rename from lesson05/server/text/routes.py rename to server/text/routes.py diff --git a/lesson05/server/text/tests/controllers/__init__.py b/server/text/tests/controllers/__init__.py similarity index 100% rename from lesson05/server/text/tests/controllers/__init__.py rename to server/text/tests/controllers/__init__.py diff --git a/lesson05/server/text/tests/controllers/test_lower.py b/server/text/tests/controllers/test_lower.py similarity index 100% rename from lesson05/server/text/tests/controllers/test_lower.py rename to server/text/tests/controllers/test_lower.py diff --git a/lesson05/server/text/tests/controllers/test_upper.py b/server/text/tests/controllers/test_upper.py similarity index 100% rename from lesson05/server/text/tests/controllers/test_upper.py rename to server/text/tests/controllers/test_upper.py