From a1a3a0e945475aa6011e0932f99dc772985b9130 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Mon, 30 Jan 2023 14:29:26 -0400 Subject: [PATCH 1/2] feat: Limit schedule generator by session purpose --- .../management/commands/generate_schedule.py | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/ietf/meeting/management/commands/generate_schedule.py b/ietf/meeting/management/commands/generate_schedule.py index c0645eed65..6cfb1ffb04 100644 --- a/ietf/meeting/management/commands/generate_schedule.py +++ b/ietf/meeting/management/commands/generate_schedule.py @@ -25,6 +25,8 @@ from ietf.person.models import Person from ietf.meeting import models from ietf.meeting.helpers import get_person_by_email +from ietf.name.models import SessionPurposeName + # 40 runs of the optimiser for IETF 106 with cycles=160 resulted in 16 # zero-violation invocations, with a mean number of runs of 91 and @@ -72,18 +74,31 @@ def add_arguments(self, parser): 'Base schedule for generated schedule, specified as "[owner/]name"' ' (default is no base schedule; owner not required if name is unique)' )) + parser.add_argument('-p', '--purpose', + dest='purposes', + action='append', + choices=[ + spn.slug for spn in SessionPurposeName.objects.all() + if 'regular' in spn.timeslot_types # scheduler only works with "regular" timeslots + ], + default=None, + help=( + 'Limit scheduling to specified purpose ' + '(use option multiple times to specify more than one purpose; default is all purposes)' + )) - def handle(self, meeting, name, max_cycles, verbosity, base_id, *args, **kwargs): - ScheduleHandler(self.stdout, meeting, name, max_cycles, verbosity, base_id).run() + def handle(self, meeting, name, max_cycles, verbosity, base_id, purposes, *args, **kwargs): + ScheduleHandler(self.stdout, meeting, name, max_cycles, verbosity, base_id, purposes).run() class ScheduleHandler(object): def __init__(self, stdout, meeting_number, name=None, max_cycles=OPTIMISER_MAX_CYCLES, - verbosity=1, base_id=None): + verbosity=1, base_id=None, session_purposes=None): self.stdout = stdout self.verbosity = verbosity self.name = name self.max_cycles = max_cycles + self.session_purposes = session_purposes if meeting_number: try: self.meeting = models.Meeting.objects.get(type="ietf", number=meeting_number) @@ -194,6 +209,8 @@ def _sessions_to_schedule(self, *args, **kwargs): Extra arguments are passed to the Session constructor. """ sessions_db = self.meeting.session_set.that_can_be_scheduled().filter(type_id='regular') + if self.session_purposes is not None: + sessions_db = sessions_db.filter(purpose__slug__in=self.session_purposes) if self.base_schedule is None: fixed_sessions = models.Session.objects.none() else: From 91e07863cbb5c67f5713e2ede7d00c3f2546e410 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Mon, 30 Jan 2023 14:35:15 -0400 Subject: [PATCH 2/2] feat: Raise exceptions if no sessions/timeslots are found --- ietf/meeting/management/commands/generate_schedule.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ietf/meeting/management/commands/generate_schedule.py b/ietf/meeting/management/commands/generate_schedule.py index 6cfb1ffb04..f4fc5e4a95 100644 --- a/ietf/meeting/management/commands/generate_schedule.py +++ b/ietf/meeting/management/commands/generate_schedule.py @@ -129,6 +129,10 @@ def __init__(self, stdout, meeting_number, name=None, max_cycles=OPTIMISER_MAX_C msgs.append('Applying schedule {} as base schedule'.format(ScheduleId.from_schedule(self.base_schedule))) self.stdout.write('\n{}\n\n'.format('\n'.join(msgs))) self._load_meeting() + if len(self.schedule.sessions) == 0: + raise CommandError('No sessions found to schedule') + if len(self.schedule.timeslots) == 0: + raise CommandError('No timeslots found for schedule') def run(self): """Schedule all sessions"""