docstrings everywhere

This commit is contained in:
2021-03-15 02:21:41 +03:00
parent 67b97a64ea
commit d3e79120cb
34 changed files with 980 additions and 127 deletions

View File

@ -28,6 +28,11 @@ HandlerType = Callable[[Request], Awaitable[StreamResponse]]
def exception_handler(logger: Logger) -> Callable[[Request, HandlerType], Awaitable[StreamResponse]]:
'''
exception handler middleware. Just log any exception (except for client ones)
:param logger: class logger
:return: built middleware
'''
@middleware
async def handle(request: Request, handler: HandlerType) -> StreamResponse:
try:

View File

@ -24,11 +24,26 @@ from ahriman.web.views.package import PackageView
from ahriman.web.views.packages import PackagesView
def setup_routes(app: Application) -> None:
app.router.add_get('/', IndexView)
app.router.add_get('/index.html', IndexView)
def setup_routes(application: Application) -> None:
'''
setup all defined routes
app.router.add_post('/api/v1/packages', PackagesView)
Available routes are:
app.router.add_delete('/api/v1/packages/{package}', PackageView)
app.router.add_post('/api/v1/packages/{package}', PackageView)
GET / get build status page
GET /index.html same as above
POST /api/v1/packages force update every package from repository
POST /api/v1/package/:base update package base status
DELETE /api/v1/package/:base delete package base from status page
:param application: web application instance
'''
application.router.add_get('/', IndexView)
application.router.add_get('/index.html', IndexView)
application.router.add_post('/api/v1/packages', PackagesView)
application.router.add_delete('/api/v1/packages/{package}', PackageView)
application.router.add_post('/api/v1/packages/{package}', PackageView)

View File

@ -22,10 +22,15 @@ from aiohttp.web import View
from ahriman.core.watcher.watcher import Watcher
# special class to make it typed
class BaseView(View):
'''
base web view to make things typed
'''
@property
def service(self) -> Watcher:
'''
:return: build status watcher instance
'''
watcher: Watcher = self.request.app['watcher']
return watcher

View File

@ -27,9 +27,24 @@ from ahriman.web.views.base import BaseView
class IndexView(BaseView):
'''
root view
It uses jinja2 templates for report generation, the following variables are allowed:
architecture - repository architecture, string, required
packages - sorted list of packages properties: base, packages (sorted list), status,
timestamp, version, web_url. Required
repository - repository name, string, required
version - ahriman version, string, required
'''
@aiohttp_jinja2.template("build-status.jinja2") # type: ignore
async def get(self) -> Dict[str, Any]:
'''
process get request. No parameters supported here
:return: parameters for jinja template
'''
# some magic to make it jinja-friendly
packages = [
{

View File

@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from aiohttp.web import HTTPOk, Response
from aiohttp.web import HTTPBadRequest, HTTPOk, Response
from ahriman.models.build_status import BuildStatusEnum
from ahriman.models.package import Package
@ -25,19 +25,45 @@ from ahriman.web.views.base import BaseView
class PackageView(BaseView):
'''
package base specific web view
'''
async def delete(self) -> Response:
'''
delete package base from status page
:return: 200 on success
'''
base = self.request.match_info['package']
self.service.remove(base)
return HTTPOk()
async def post(self) -> Response:
'''
update package build status
JSON body must be supplied, the following model is used:
{
"status": "unknown", # package build status string, must be valid `BuildStatusEnum`
"package": {} # package body (use `dataclasses.asdict` to generate one), optional.
# Must be supplied in case if package base is unknown
}
:return: 200 on success
'''
base = self.request.match_info['package']
data = await self.request.json()
package = Package(**data['package']) if 'package' in data else None
status = BuildStatusEnum(data['status'])
self.service.update(base, status, package)
try:
package = Package(**data['package']) if 'package' in data else None
status = BuildStatusEnum(data['status'])
except Exception as e:
raise HTTPBadRequest(text=str(e))
try:
self.service.update(base, status, package)
except KeyError:
raise HTTPBadRequest(text=f'Package {base} is unknown, but no package body set')
return HTTPOk()

View File

@ -23,8 +23,15 @@ from ahriman.web.views.base import BaseView
class PackagesView(BaseView):
'''
global watcher view
'''
async def post(self) -> Response:
'''
reload all packages from repository. No parameters supported here
:return: 200 on success
'''
self.service.load()
return HTTPOk()

View File

@ -30,30 +30,49 @@ from ahriman.web.middlewares.exception_handler import exception_handler
from ahriman.web.routes import setup_routes
async def on_shutdown(app: web.Application) -> None:
app.logger.warning('server terminated')
async def on_shutdown(application: web.Application) -> None:
'''
web application shutdown handler
:param application: web application instance
'''
application.logger.warning('server terminated')
async def on_startup(app: web.Application) -> None:
app.logger.info('server started')
async def on_startup(application: web.Application) -> None:
'''
web application start handler
:param application: web application instance
'''
application.logger.info('server started')
try:
app['watcher'].load()
application['watcher'].load()
except Exception:
app.logger.exception('could not load packages', exc_info=True)
application.logger.exception('could not load packages', exc_info=True)
raise InitializeException()
def run_server(app: web.Application, architecture: str) -> None:
app.logger.info('start server')
def run_server(application: web.Application, architecture: str) -> None:
'''
run web application
:param application: web application instance
:param architecture: repository architecture
'''
application.logger.info('start server')
section = app['config'].get_section_name('web', architecture)
host = app['config'].get(section, 'host')
port = app['config'].getint(section, 'port')
section = application['config'].get_section_name('web', architecture)
host = application['config'].get(section, 'host')
port = application['config'].getint(section, 'port')
web.run_app(app, host=host, port=port, handle_signals=False)
web.run_app(application, host=host, port=port, handle_signals=False)
def setup_service(architecture: str, config: Configuration) -> web.Application:
'''
create web application
:param architecture: repository architecture
:param config: configuration instance
:return: web application instance
'''
app = web.Application(logger=logging.getLogger('http'))
app.on_shutdown.append(on_shutdown)
app.on_startup.append(on_startup)