# Path: lepo/excs.py
# class InvalidOperation(ValueError):
#     pass
# 
# Path: lepo/path_view.py
# class PathView(View):
#     router = None  # Filled in by subclasses
#     path = None  # Filled in by subclasses
# 
#     def dispatch(self, request, **kwargs):
#         try:
#             operation = self.path.get_operation(request.method)
#         except InvalidOperation:
#             return self.http_method_not_allowed(request, **kwargs)
#         request.api_info = APIInfo(
#             operation=operation,
#             router=self.router,
#         )
#         params = {
#             snake_case(name): value
#             for (name, value)
#             in read_parameters(request, kwargs, capture_errors=True).items()
#         }
#         handler = request.api_info.router.get_handler(operation.id)
#         try:
#             response = handler(request, **params)
#         except ExceptionalResponse as er:
#             response = er.response
# 
#         return self.transform_response(response)
# 
#     def transform_response(self, response):
#         if isinstance(response, HttpResponse):
#             # TODO: validate against responses
#             return response
#         return JsonResponse(response, safe=False)  # TODO: maybe less TIMTOWDI here?


import re
from lepo.excs import InvalidOperation
from lepo.path_view import PathView
        :type path: str
        :type mapping: dict
        """
        self.api = api
        self.path = path
        self.mapping = mapping
        self.regex = self._build_regex()
        self.name = self._build_view_name()

    def get_view_class(self, router):
        return type(f'{self.name.title()}View', (PathView,), {
            'path': self,
            'router': router,
        })

    def _build_view_name(self):
        path = re.sub(PATH_PLACEHOLDER_REGEX, r'\1', self.path)
        name = re.sub(r'[^a-z0-9]+', '-', path, flags=re.I).strip('-').lower()
        return name

    def _build_regex(self):
        return re.sub(
            PATH_PLACEHOLDER_REGEX,
            lambda m: f'(?P<{m.group(1)}>[^/]+?)',
            self.path,
        ).lstrip('/') + '$'

    def get_operation(self, method):
        operation_data = self.mapping.get(method.lower())
        if not operation_data:

# Path: lepo/excs.py
# class InvalidOperation(ValueError):
#     pass
# 
# Path: lepo/path_view.py
# class PathView(View):
#     router = None  # Filled in by subclasses
#     path = None  # Filled in by subclasses
# 
#     def dispatch(self, request, **kwargs):
#         try:
#             operation = self.path.get_operation(request.method)
#         except InvalidOperation:
#             return self.http_method_not_allowed(request, **kwargs)
#         request.api_info = APIInfo(
#             operation=operation,
#             router=self.router,
#         )
#         params = {
#             snake_case(name): value
#             for (name, value)
#             in read_parameters(request, kwargs, capture_errors=True).items()
#         }
#         handler = request.api_info.router.get_handler(operation.id)
#         try:
#             response = handler(request, **params)
#         except ExceptionalResponse as er:
#             response = er.response
# 
#         return self.transform_response(response)
# 
#     def transform_response(self, response):
#         if isinstance(response, HttpResponse):
#             # TODO: validate against responses
#             return response
#         return JsonResponse(response, safe=False)  # TODO: maybe less TIMTOWDI here?


# Path: lepo/apidef/path.py
import re
from lepo.excs import InvalidOperation
from lepo.path_view import PathView

        :type path: str
        :type mapping: dict
        """
        self.api = api
        self.path = path
        self.mapping = mapping
        self.regex = self._build_regex()
        self.name = self._build_view_name()

    def get_view_class(self, router):
        return type(f'{self.name.title()}View', (PathView,), {
            'path': self,
            'router': router,
        })

    def _build_view_name(self):
        path = re.sub(PATH_PLACEHOLDER_REGEX, r'\1', self.path)
        name = re.sub(r'[^a-z0-9]+', '-', path, flags=re.I).strip('-').lower()
        return name

    def _build_regex(self):
        return re.sub(
            PATH_PLACEHOLDER_REGEX,
            lambda m: f'(?P<{m.group(1)}>[^/]+?)',
            self.path,
        ).lstrip('/') + '$'

    def get_operation(self, method):
        operation_data = self.mapping.get(method.lower())
        if not operation_data:

            raise InvalidOperation(f'Path {self.path} does not support method {method.upper()}')