aiohttp_app.py 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. """
  2. This module defines an AioHttpApp, a Connexion application to wrap an AioHttp application.
  3. """
  4. import logging
  5. import pathlib
  6. import pkgutil
  7. import sys
  8. from aiohttp import web
  9. from ..apis.aiohttp_api import AioHttpApi
  10. from ..exceptions import ConnexionException
  11. from .abstract import AbstractApp
  12. logger = logging.getLogger('connexion.aiohttp_app')
  13. class AioHttpApp(AbstractApp):
  14. def __init__(self, import_name, only_one_api=False, **kwargs):
  15. super().__init__(import_name, AioHttpApi, server='aiohttp', **kwargs)
  16. self._only_one_api = only_one_api
  17. self._api_added = False
  18. def create_app(self):
  19. return web.Application(**self.server_args)
  20. def get_root_path(self):
  21. mod = sys.modules.get(self.import_name)
  22. if mod is not None and hasattr(mod, '__file__'):
  23. return pathlib.Path(mod.__file__).resolve().parent
  24. loader = pkgutil.get_loader(self.import_name)
  25. filepath = None
  26. if hasattr(loader, 'get_filename'):
  27. filepath = loader.get_filename(self.import_name)
  28. if filepath is None:
  29. raise RuntimeError(f"Invalid import name '{self.import_name}'")
  30. return pathlib.Path(filepath).resolve().parent
  31. def set_errors_handlers(self):
  32. pass
  33. def add_api(self, specification, **kwargs):
  34. if self._only_one_api:
  35. if self._api_added:
  36. raise ConnexionException(
  37. "an api was already added, "
  38. "create a new app with 'only_one_api=False' "
  39. "to add more than one api"
  40. )
  41. else:
  42. self.app = self._get_api(specification, kwargs).subapp
  43. self._api_added = True
  44. return self.app
  45. api = self._get_api(specification, kwargs)
  46. try:
  47. self.app.add_subapp(api.base_path, api.subapp)
  48. except ValueError:
  49. raise ConnexionException(
  50. "aiohttp doesn't allow to set empty base_path ('/'), "
  51. "use non-empty instead, e.g /api"
  52. )
  53. return api
  54. def _get_api(self, specification, kwargs):
  55. return super().add_api(specification, **kwargs)
  56. def run(self, port=None, server=None, debug=None, host=None, **options):
  57. if port is not None:
  58. self.port = port
  59. elif self.port is None:
  60. self.port = 5000
  61. self.server = server or self.server
  62. self.host = host or self.host or '0.0.0.0'
  63. if debug is not None:
  64. self.debug = debug
  65. logger.debug('Starting %s HTTP server..', self.server, extra=vars(self))
  66. if self.server == 'aiohttp':
  67. logger.info('Listening on %s:%s..', self.host, self.port)
  68. access_log = options.pop('access_log', None)
  69. if options.pop('use_default_access_log', None):
  70. access_log = logger
  71. web.run_app(self.app, port=self.port, host=self.host, access_log=access_log, **options)
  72. else:
  73. raise Exception(f'Server {self.server} not recognized')