diff --git a/.pylintrc b/.pylintrc index 489eb55..53ebb39 100644 --- a/.pylintrc +++ b/.pylintrc @@ -11,7 +11,8 @@ disable= W1203, R1732, W0621, - W0613 + W0613, + C0206 [FORMAT] diff --git a/playground/main.py b/playground/main.py index 94f46c4..316256f 100644 --- a/playground/main.py +++ b/playground/main.py @@ -21,7 +21,7 @@ def after(self, _request, response): return response -router.use_middleware(ExampleMiddleware) +# router.use_middleware(ExampleMiddleware) @router.get('/main', middlewares=[ExampleMiddleware]) @@ -39,6 +39,12 @@ def get_example(request): return web.responses.RedirectResponse('/main') +@router.get('/hello/{name}/{age}') +def get_example_with_params(request, name: str, age: int): + logger.info(f'got {request=}') + return web.responses.JsonResponse({'message': 'hello, world!', 'name': name, 'age': age}) + + @router.post('/hello', middlewares=[ExampleMiddleware]) def post_example(request): logger.info(f'got {request=}') diff --git a/requirements.txt b/requirements.txt index 35b3a94..7bef043 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,6 +11,7 @@ mccabe==0.7.0 mypy==1.13.0 mypy-extensions==1.0.0 packaging==24.2 +parse==1.20.2 platformdirs==4.3.6 pluggy==1.5.0 pycodestyle==2.12.1 diff --git a/setup.py b/setup.py index b860a64..4d30d61 100644 --- a/setup.py +++ b/setup.py @@ -11,6 +11,7 @@ def main() -> None: 'webob', 'jinja2', 'python-dotenv', + 'parse', 'locust' ], ) diff --git a/web/router.py b/web/router.py index 1d91d1e..f8d5728 100644 --- a/web/router.py +++ b/web/router.py @@ -1,8 +1,10 @@ +import logging from http import HTTPMethod -from typing import Type, Callable +from typing import Callable, Type from webob import Request, Response -from webob.exc import HTTPNotFound, HTTPInternalServerError +from webob.exc import HTTPNotFound, HTTPInternalServerError, HTTPBadRequest +from parse import parse from .middleware import Middleware @@ -33,35 +35,35 @@ def _add_route( self.global_middlewares + middlewares, ) - def get(self, path: str, middlewares: list[Middleware] | None = None): + def get(self, path: str, middlewares: list[Type[Middleware]] | None = None): def decorator(func): self._add_route(HTTPMethod.GET, path, func, middlewares) return func return decorator - def post(self, path: str, middlewares: list[Middleware] | None = None): + def post(self, path: str, middlewares: list[Type[Middleware]] | None = None): def decorator(func): self._add_route(HTTPMethod.POST, path, func, middlewares) return func return decorator - def put(self, path: str, middlewares: list[Middleware] | None = None): + def put(self, path: str, middlewares: list[Type[Middleware]] | None = None): def decorator(func): self._add_route(HTTPMethod.PUT, path, func, middlewares) return func return decorator - def patch(self, path: str, middlewares: list[Middleware] | None = None): + def patch(self, path: str, middlewares: list[Type[Middleware]] | None = None): def decorator(func): self._add_route(HTTPMethod.PATCH, path, func, middlewares) return func return decorator - def delete(self, path: str, middlewares: list[Middleware] | None = None): + def delete(self, path: str, middlewares: list[Type[Middleware]] | None = None): def decorator(func): self._add_route(HTTPMethod.DELETE, path, func, middlewares) return func @@ -85,12 +87,25 @@ def __call__(self, environ, start_response): request = Request(environ) response = Response() - method_routes = self._routes.get(request.path_info, {}) - handler = method_routes.get(request.method) + handler, kwargs = self._find_handler(request) + + if kwargs and handler: + # получаем типы аргументов из сигнатуры функции + logging.info(f'{handler=}') + signature = handler.__annotations__ + # приводим аргументы к нужным типам + try: + kwargs = {name: signature[name](value) for name, value in + kwargs.items()} + except ValueError: + response = HTTPBadRequest( + json={"error": "invalid type arguments"}) + return response(environ, start_response) if handler is not None: try: - response = handler(request) + + response = handler(request, **kwargs) except Exception: response = HTTPInternalServerError() else: @@ -107,3 +122,13 @@ def _apply_middlewares(handler, middlewares): handler = middleware(handler) return handler + + def _find_handler(self, request): + for route in self._routes: + parse_result = parse(route, request.path) + if parse_result: + handler = self._routes[route].get(request.method) + if handler is not None: + return handler, parse_result.named + + return None, None