ooze/ooze/application.py

102 lines
2.6 KiB
Python

import logging
from http import HTTPStatus
from . import exceptions
from . import configuration
from . import hooks
from . import web
class Application(web.SiteCompositionPiece):
"""
Class for the main app object.
Holds configuration, routing and rendering utilities.
This classes `__call__` function is the WSGI entrypoint.
"""
root = ''
absolute_root = '/'
def __init__(self):
super().__init__()
self.debug = True
self._booted = False
configuration.config.load(self)
# add handlers only to top-level logger, see:
# https://docs.python.org/3.8/library/logging.html#logging.Logger.propagate
self.logger.addHandler(logging.FileHandler(f'{self.project_path}/ooze.log'))
self.logger.addHandler(logging.StreamHandler())
# register new app in Appoxy singleton so submodules can access the
# app object without having a depenceny on the module instantiating
# it (which would be code in the project using Ooze).
from . import appoxy
appoxy.app.set_app(self)
def __call__(self, environ, start_response):
"""
WSGI entrypoint
"""
if not self._booted:
self.boot()
request = self.request_class(self, environ)
try:
response = self.handle_request(request)
except exceptions.HTTPException as e:
response = self.response_class(request)
response.status = e.status
response.body = e.safe_message
self.logger.warn(f"Encountered HTTPException: {e}")
except exceptions.SafeException as e:
response = self.response_class(request)
response.status = HTTPStatus(500)
response.body = e.safe_message
self.logger.warn(f"Encountered SafeException: {e}")
except Exception as e:
if self.debug:
raise e
response = self.response_class(request)
response.status = HTTPStatus(500)
response.body = 'Oops!'
self.logger.error(f"Encountered unplanned exception: {e}")
start_response(
f"{response.status.numerator} {response.status.name}",
response.headers_wsgi()
)
return response.body_wsgi()
def install(self):
self.logger.debug("Running install functions…")
hooks.call('install', self)
def boot(self):
self.logger.debug("Running boot functions…")
hooks.call('boot', self)
self._booted = True
self.logger.debug("All booted up.")