# Path: lepo/apidef/doc.py
# class APIDefinition:
#     version = None
#     path_class = Path
#     operation_class = None
# 
#     def __init__(self, doc):
#         """
#         Instantiate a new Lepo router.
# 
#         :param doc: The OpenAPI definition document.
#         :type doc: dict
#         """
#         self.doc = doc
#         self.resolver = RefResolver('', self.doc)
# 
#     def resolve_reference(self, ref):
#         """
#         Resolve a JSON Pointer object reference to the object itself.
# 
#         :param ref: Reference string (`#/foo/bar`, for instance)
#         :return: The object, if found
#         :raises jsonschema.exceptions.RefResolutionError: if there is trouble resolving the reference
#         """
#         url, resolved = self.resolver.resolve(ref)
#         return resolved
# 
#     def get_path_mapping(self, path):
#         return maybe_resolve(self.doc['paths'][path], self.resolve_reference)
# 
#     def get_path_names(self):
#         yield from self.doc['paths']
# 
#     def get_path(self, path):
#         """
#         Construct a Path object from a path string.
# 
#         The Path string must be declared in the API.
# 
#         :type path: str
#         :rtype: lepo.path.Path
#         """
#         mapping = self.get_path_mapping(path)
#         return self.path_class(api=self, path=path, mapping=mapping)
# 
#     def get_paths(self):
#         """
#         Iterate over all Path objects declared by the API.
# 
#         :rtype: Iterable[lepo.path.Path]
#         """
#         for path_name in self.get_path_names():
#             yield self.get_path(path_name)
# 
#     @classmethod
#     def from_file(cls, filename):
#         """
#         Construct an APIDefinition by parsing the given `filename`.
# 
#         If PyYAML is installed, YAML files are supported.
#         JSON files are always supported.
# 
#         :param filename: The filename to read.
#         :rtype: APIDefinition
#         """
#         with open(filename) as infp:
#             if filename.endswith('.yaml') or filename.endswith('.yml'):
#                 import yaml
#                 data = yaml.safe_load(infp)
#             else:
#                 import json
#                 data = json.load(infp)
#         return cls.from_data(data)
# 
#     @classmethod
#     def from_data(cls, data):
#         version = parse_version(data)
#         if version == SWAGGER_2:
#             return Swagger2APIDefinition(data)
#         if version == OPENAPI_3:
#             return OpenAPI3APIDefinition(data)
#         raise NotImplementedError('We can never get here.')  # pragma: no cover
# 
#     @classmethod
#     def from_yaml(cls, yaml_string):
#         from yaml import safe_load
#         return cls.from_data(safe_load(yaml_string))
# 
# Path: lepo/excs.py
# class MissingHandler(ValueError):
#     pass
# 
# Path: lepo/utils.py
# def snake_case(string):
#     return camel_case_to_spaces(string).replace('-', '_').replace(' ', '_').replace('__', '_')


    from collections.abc import Iterable
    from collections import Iterable
from functools import reduce
from importlib import import_module
from inspect import isfunction, ismethod
from django.http import HttpResponse
from django.urls import re_path
from lepo.apidef.doc import APIDefinition
from lepo.excs import MissingHandler
from lepo.utils import snake_case
                if not regex.endswith('/'):
                    regex += '/'
                regex += '?$'
            view = decorate(path.get_view_class(router=self).as_view())
            urls.append(re_path(regex, view, name=name_template.format(name=path.name)))

        if root_view_name:
            urls.append(re_path(r'^$', root_view, name=name_template.format(name=root_view_name)))
        return urls

    def get_handler(self, operation_id):
        """
        Get the handler function for a given operation.

        To remain Pythonic, both the original and the snake_cased version of the operation ID are
        supported.

        This could be overridden in a subclass.

        :param operation_id: Operation ID.
        :return: Handler function
        :rtype: function
        """
        handler = (
            self.handlers.get(operation_id)
            or self.handlers.get(snake_case(operation_id))
        )
        if handler:
            return handler
        raise MissingHandler(

# Path: lepo/apidef/doc.py
# class APIDefinition:
#     version = None
#     path_class = Path
#     operation_class = None
# 
#     def __init__(self, doc):
#         """
#         Instantiate a new Lepo router.
# 
#         :param doc: The OpenAPI definition document.
#         :type doc: dict
#         """
#         self.doc = doc
#         self.resolver = RefResolver('', self.doc)
# 
#     def resolve_reference(self, ref):
#         """
#         Resolve a JSON Pointer object reference to the object itself.
# 
#         :param ref: Reference string (`#/foo/bar`, for instance)
#         :return: The object, if found
#         :raises jsonschema.exceptions.RefResolutionError: if there is trouble resolving the reference
#         """
#         url, resolved = self.resolver.resolve(ref)
#         return resolved
# 
#     def get_path_mapping(self, path):
#         return maybe_resolve(self.doc['paths'][path], self.resolve_reference)
# 
#     def get_path_names(self):
#         yield from self.doc['paths']
# 
#     def get_path(self, path):
#         """
#         Construct a Path object from a path string.
# 
#         The Path string must be declared in the API.
# 
#         :type path: str
#         :rtype: lepo.path.Path
#         """
#         mapping = self.get_path_mapping(path)
#         return self.path_class(api=self, path=path, mapping=mapping)
# 
#     def get_paths(self):
#         """
#         Iterate over all Path objects declared by the API.
# 
#         :rtype: Iterable[lepo.path.Path]
#         """
#         for path_name in self.get_path_names():
#             yield self.get_path(path_name)
# 
#     @classmethod
#     def from_file(cls, filename):
#         """
#         Construct an APIDefinition by parsing the given `filename`.
# 
#         If PyYAML is installed, YAML files are supported.
#         JSON files are always supported.
# 
#         :param filename: The filename to read.
#         :rtype: APIDefinition
#         """
#         with open(filename) as infp:
#             if filename.endswith('.yaml') or filename.endswith('.yml'):
#                 import yaml
#                 data = yaml.safe_load(infp)
#             else:
#                 import json
#                 data = json.load(infp)
#         return cls.from_data(data)
# 
#     @classmethod
#     def from_data(cls, data):
#         version = parse_version(data)
#         if version == SWAGGER_2:
#             return Swagger2APIDefinition(data)
#         if version == OPENAPI_3:
#             return OpenAPI3APIDefinition(data)
#         raise NotImplementedError('We can never get here.')  # pragma: no cover
# 
#     @classmethod
#     def from_yaml(cls, yaml_string):
#         from yaml import safe_load
#         return cls.from_data(safe_load(yaml_string))
# 
# Path: lepo/excs.py
# class MissingHandler(ValueError):
#     pass
# 
# Path: lepo/utils.py
# def snake_case(string):
#     return camel_case_to_spaces(string).replace('-', '_').replace(' ', '_').replace('__', '_')


# Path: lepo/router.py
    from collections.abc import Iterable
    from collections import Iterable
from functools import reduce
from importlib import import_module
from inspect import isfunction, ismethod
from django.http import HttpResponse
from django.urls import re_path
from lepo.apidef.doc import APIDefinition
from lepo.excs import MissingHandler
from lepo.utils import snake_case

                if not regex.endswith('/'):
                    regex += '/'
                regex += '?$'
            view = decorate(path.get_view_class(router=self).as_view())
            urls.append(re_path(regex, view, name=name_template.format(name=path.name)))

        if root_view_name:
            urls.append(re_path(r'^$', root_view, name=name_template.format(name=root_view_name)))
        return urls

    def get_handler(self, operation_id):
        """
        Get the handler function for a given operation.

        To remain Pythonic, both the original and the snake_cased version of the operation ID are
        supported.

        This could be overridden in a subclass.

        :param operation_id: Operation ID.
        :return: Handler function
        :rtype: function
        """
        handler = (
            self.handlers.get(operation_id)
            or self.handlers.get(snake_case(operation_id))
        )
        if handler:
            return handler
        raise MissingHandler(

            f'Missing handler for operation {operation_id} (tried {snake_case(operation_id)} too)'