aiohttp_utils/routing.py
def add_resource_context(
    app: web.Application, module=None,
    url_prefix: str=None, name_prefix: str=None, make_resource=lambda cls: cls()
):
    """Context manager which yields a function for adding multiple resources from a given module
    to an app using `ResourceRouter <aiohttp_utils.routing.ResourceRouter>`.

    Example:

    .. code-block:: python

        # myapp/articles/views.py
        class ArticleList:
            async def get(self, request):
                return web.Response(b'article list...')

        class ArticleDetail:
            async def get(self, request):
                return web.Response(b'article detail...')

    .. code-block:: python

        # myapp/app.py
        from myapp.articles import views

        with add_resource_context(app, url_prefix='/api/') as route:
            route('/articles/', views.ArticleList())
            route('/articles/{pk}', views.ArticleDetail())

        app.router['ArticleList:get'].url()  # /api/articles/
        app.router['ArticleDetail:get'].url(parts={'pk': 42})  # /api/articles/42

    If you prefer, you can also pass module and class names as strings. ::

        with add_resource_context(app, module='myapp.articles.views',
                                  url_prefix='/api/') as route:
            route('/articles/', 'ArticleList')
            route('/articles/{pk}', 'ArticleDetail')

    .. note::
        If passing class names, the resource classes will be instantiated with no
        arguments. You can change this behavior by overriding ``make_resource``.

        .. code-block:: python

            # myapp/authors/views.py
            class AuthorList:
                def __init__(self, db):
                    self.db = db

                async def get(self, request):
                    # Fetch authors from self.db...

        .. code-block:: python

            # myapp/app.py
            from myapp.database import db

            with add_resource_context(app, module='myapp.authors.views',
                                    url_prefix='/api/',
                                    make_resource=lambda cls: cls(db=db)) as route:
                route('/authors/', 'AuthorList')

    :param app: Application to add routes to.
    :param resource: Import path to module (str) or module object
        which contains the resource classes.
    :param url_prefix: Prefix to prepend to all route paths.
    :param name_prefix: Prefix to prepend to all route names.
    :param make_resource: Function which receives a resource class and returns
        a resource instance.
    """
    assert isinstance(app.router, ResourceRouter), 'app must be using ResourceRouter'

    if isinstance(module, (str, bytes)):
        module = importlib.import_module(module)

    def get_base_name(resource, method_name, names):
        return names.get(method_name,
                         app.router.get_default_handler_name(resource, method_name))

    default_make_resource = make_resource

    def add_route(
        path: str, resource, names: Mapping=None, make_resource=None
    ):
        make_resource = make_resource or default_make_resource
        names = names or {}
        if isinstance(resource, (str, bytes)):
            if not module:
                raise ValueError(
                    'Must pass module to add_route_context if passing resource name strings.'
                )
            resource_cls = getattr(module, resource)
            resource = make_resource(resource_cls)
        path = make_path(path, url_prefix)
        if name_prefix:
            supported_method_names = get_supported_method_names(resource)
            names = {
                method_name: '.'.join(
                    (name_prefix, get_base_name(resource, method_name, names=names))
                )
                for method_name in supported_method_names
            }
        return app.router.add_resource_object(path, resource, names=names)
    yield add_route
def add_resource_context(
    app: web.Application, module=None,
    url_prefix: str=None, name_prefix: str=None, make_resource=lambda cls: cls()
):
    """Context manager which yields a function for adding multiple resources from a given module
    to an app using `ResourceRouter <aiohttp_utils.routing.ResourceRouter>`.

    Example:

    .. code-block:: python

        # myapp/articles/views.py
        class ArticleList:
            async def get(self, request):
                return web.Response(b'article list...')

        class ArticleDetail:
            async def get(self, request):
                return web.Response(b'article detail...')

    .. code-block:: python

        # myapp/app.py
        from myapp.articles import views

        with add_resource_context(app, url_prefix='/api/') as route:
            route('/articles/', views.ArticleList())
            route('/articles/{pk}', views.ArticleDetail())

        app.router['ArticleList:get'].url()  # /api/articles/
        app.router['ArticleDetail:get'].url(parts={'pk': 42})  # /api/articles/42

    If you prefer, you can also pass module and class names as strings. ::

        with add_resource_context(app, module='myapp.articles.views',
                                  url_prefix='/api/') as route:
            route('/articles/', 'ArticleList')
            route('/articles/{pk}', 'ArticleDetail')

    .. note::
        If passing class names, the resource classes will be instantiated with no
        arguments. You can change this behavior by overriding ``make_resource``.

        .. code-block:: python

            # myapp/authors/views.py
            class AuthorList:
                def __init__(self, db):
                    self.db = db

                async def get(self, request):
                    # Fetch authors from self.db...

        .. code-block:: python

            # myapp/app.py
            from myapp.database import db

            with add_resource_context(app, module='myapp.authors.views',
                                    url_prefix='/api/',
                                    make_resource=lambda cls: cls(db=db)) as route:
                route('/authors/', 'AuthorList')

    :param app: Application to add routes to.
    :param resource: Import path to module (str) or module object
        which contains the resource classes.
    :param url_prefix: Prefix to prepend to all route paths.
    :param name_prefix: Prefix to prepend to all route names.
    :param make_resource: Function which receives a resource class and returns
        a resource instance.
    """
    assert isinstance(app.router, ResourceRouter), 'app must be using ResourceRouter'

    if isinstance(module, (str, bytes)):
        module = importlib.import_module(module)

    def get_base_name(resource, method_name, names):
        return names.get(method_name,
                         app.router.get_default_handler_name(resource, method_name))

    default_make_resource = make_resource

    def add_route(
        path: str, resource, names: Mapping=None, make_resource=None
    ):
        make_resource = make_resource or default_make_resource
        names = names or {}
        if isinstance(resource, (str, bytes)):
            if not module:
                raise ValueError(
                    'Must pass module to add_route_context if passing resource name strings.'
                )
            resource_cls = getattr(module, resource)
            resource = make_resource(resource_cls)
        path = make_path(path, url_prefix)
        if name_prefix:
            supported_method_names = get_supported_method_names(resource)
            names = {
                method_name: '.'.join(
                    (name_prefix, get_base_name(resource, method_name, names=names))
                )
                for method_name in supported_method_names
            }
        return app.router.add_resource_object(path, resource, names=names)
    yield add_route
Context manager which yields a function for adding multiple resources from a given module
    to an app using `ResourceRouter <aiohttp_utils.routing.ResourceRouter>`.

    Example:

    .. code-block:: python

        # myapp/articles/views.py
        class ArticleList:
            async def get(self, request):
                return web.Response(b'article list...')

        class ArticleDetail:
            async def get(self, request):
                return web.Response(b'article detail...')

    .. code-block:: python

        # myapp/app.py
        from myapp.articles import views

        with add_resource_context(app, url_prefix='/api/') as route:
            route('/articles/', views.ArticleList())
            route('/articles/{pk}', views.ArticleDetail())

        app.router['ArticleList:get'].url()  # /api/articles/
        app.router['ArticleDetail:get'].url(parts={'pk': 42})  # /api/articles/42

    If you prefer, you can also pass module and class names as strings. ::

        with add_resource_context(app, module='myapp.articles.views',
                                  url_prefix='/api/') as route:
            route('/articles/', 'ArticleList')
            route('/articles/{pk}', 'ArticleDetail')

    .. note::
        If passing class names, the resource classes will be instantiated with no
        arguments. You can change this behavior by overriding ``make_resource``.

        .. code-block:: python

            # myapp/authors/views.py
            class AuthorList:
                def __init__(self, db):
                    self.db = db

                async def get(self, request):
                    # Fetch authors from self.db...

        .. code-block:: python

            # myapp/app.py
            from myapp.database import db

            with add_resource_context(app, module='myapp.authors.views',
                                    url_prefix='/api/',
                                    make_resource=lambda cls: cls(db=db)) as route:
                route('/authors/', 'AuthorList')

    :param app: Application to add routes to.
    :param resource: Import path to module (str) or module object
        which contains the resource classes.
    :param url_prefix: Prefix to prepend to all route paths.
    :param name_prefix: Prefix to prepend to all route names.
    :param make_resource: Function which receives a resource class and returns
        a resource instance.