3
0
Fork 0

feat: add basic support for batch execution

no execution options yet, and no progress indicator

also basic delete support, invoking handler
This commit is contained in:
Lance Edgar 2024-12-14 20:42:57 -06:00
parent e3beb9953d
commit dd1fd8c0ce
9 changed files with 404 additions and 11 deletions

View file

@ -28,6 +28,7 @@ import logging
import threading
import time
import markdown
from sqlalchemy import orm
from wuttaweb.views import MasterView
@ -41,6 +42,13 @@ log = logging.getLogger(__name__)
class BatchMasterView(MasterView):
"""
Base class for all "batch master" views.
.. attribute:: batch_handler
Reference to the :term:`batch handler` for use with the view.
This is set when the view is first created, using return value
from :meth:`get_batch_handler()`.
"""
labels = {
@ -66,6 +74,46 @@ class BatchMasterView(MasterView):
"""
raise NotImplementedError
def get_fallback_templates(self, template):
"""
We override the default logic here, to prefer "batch"
templates over the "master" templates.
So for instance the "view batch" page will by default use the
``/batch/view.mako`` template - which does inherit from
``/master/view.mako`` but adds extra features specific to
batches.
"""
templates = super().get_fallback_templates(template)
templates.insert(0, f'/batch/{template}.mako')
return templates
def render_to_response(self, template, context):
"""
We override the default logic here, to inject batch-related
context for the
:meth:`~wuttaweb.views.master.MasterView.view()` template
specifically. These values are used in the template file,
``/batch/view.mako``.
* ``batch`` - reference to the current :term:`batch`
* ``batch_handler`` reference to :attr:`batch_handler`
* ``why_not_execute`` - text of reason (if any) not to execute batch
* ``execution_described`` - HTML (rendered from markdown) describing batch execution
"""
if template == 'view':
batch = context['instance']
context['batch'] = batch
context['batch_handler'] = self.batch_handler
context['why_not_execute'] = self.batch_handler.why_not_execute(batch)
description = (self.batch_handler.describe_execution(batch)
or "Handler does not say! Your guess is as good as mine.")
context['execution_described'] = markdown.markdown(
description, extensions=['fenced_code', 'codehilite'])
return super().render_to_response(template, context)
def configure_grid(self, g):
""" """
super().configure_grid(g)
@ -208,6 +256,20 @@ class BatchMasterView(MasterView):
thread.start()
return self.render_progress(progress)
def delete_instance(self, batch):
"""
Delete the given batch instance.
This calls
:meth:`~wuttjamaican:wuttjamaican.batch.BatchHandler.do_delete()`
on the :attr:`batch_handler`.
"""
self.batch_handler.do_delete(batch, self.request.user)
##############################
# populate methods
##############################
def populate_thread(self, batch_uuid, progress=None):
"""
Thread target for populating new object with progress indicator.
@ -258,6 +320,31 @@ class BatchMasterView(MasterView):
finally:
session.close()
##############################
# execute methods
##############################
def execute(self):
"""
View to execute the current :term:`batch`.
Eventually this should show a progress indicator etc., but for
now it simply calls
:meth:`~wuttjamaican:wuttjamaican.batch.BatchHandler.do_execute()`
on the :attr:`batch_handler` and waits for it to complete,
then redirects user back to the "view batch" page.
"""
self.executing = True
batch = self.get_instance()
try:
self.batch_handler.do_execute(batch, self.request.user)
except Exception as error:
log.warning("failed to execute batch: %s", batch, exc_info=True)
self.request.session.flash(f"Execution failed!: {error}", 'error')
return self.redirect(self.get_action_url('view', batch))
##############################
# row methods
##############################
@ -287,3 +374,31 @@ class BatchMasterView(MasterView):
super().configure_row_grid(g)
g.set_label('sequence', "Seq.", column_only=True)
##############################
# configuration
##############################
@classmethod
def defaults(cls, config):
""" """
cls._defaults(config)
cls._batch_defaults(config)
@classmethod
def _batch_defaults(cls, config):
route_prefix = cls.get_route_prefix()
permission_prefix = cls.get_permission_prefix()
model_title = cls.get_model_title()
instance_url_prefix = cls.get_instance_url_prefix()
# execute
config.add_route(f'{route_prefix}.execute',
f'{instance_url_prefix}/execute',
request_method='POST')
config.add_view(cls, attr='execute',
route_name=f'{route_prefix}.execute',
permission=f'{permission_prefix}.execute')
config.add_wutta_permission(permission_prefix,
f'{permission_prefix}.execute',
f"Execute {model_title}")