Refactor shift constraints in tests to use new constraint classes

- Updated test cases in `test_workers.py` to replace dictionary-based constraints with instances of `PreShiftConstraint`, `PostShiftConstraint`, and `MaxShiftsPerWeekConstraint`.
- Added a new test `test_worker_assign_as_block_preference2` to verify worker preferences for block assignments.
- Marked tests as slow where appropriate to improve test suite performance.
This commit is contained in:
Ross
2025-08-11 13:03:08 +01:00
parent d7bcfce78c
commit 76f3b48c1d
12 changed files with 790 additions and 987 deletions
+4 -4
View File
@@ -1,6 +1,6 @@
import pytest
import datetime
from rota.shifts import RotaBuilder, SingleShift, days
from rota.shifts import BalanceAcrossGroupsConstraint, RotaBuilder, SingleShift, days
from rota.workers import Worker
@pytest.fixture
@@ -31,7 +31,7 @@ def test_balance_blocks_across_2_groups(demo_rota_balance_sites):
balance_offset=40,
workers_required=2,
force_as_block=True,
constraint=[{"name": "balance_across_groups"}],
constraints=[BalanceAcrossGroupsConstraint()],
),
)
Rota.constraint_options["balance_nights_across_sites"] = False
@@ -76,7 +76,7 @@ def test_balance_blocks_across_2_groups_unbalanced(demo_rota_balance_sites):
balance_offset=40,
workers_required=3,
force_as_block=True,
constraint=[{"name": "balance_across_groups"}],
constraints=[BalanceAcrossGroupsConstraint()],
),
)
Rota.constraint_options["balance_nights_across_sites"] = False
@@ -116,7 +116,7 @@ def test_balance_blocks_across_3_groups(demo_rota_balance_sites):
balance_offset=40,
workers_required=3,
force_as_block=True,
constraint=[{"name": "balance_across_groups"}],
constraints=[BalanceAcrossGroupsConstraint()],
),
)
Rota.constraint_options["balance_nights_across_sites"] = False
+2 -2
View File
@@ -1,7 +1,7 @@
import datetime
import pytest
from pytest import approx
from rota.shifts import RotaBuilder, SingleShift, days
from rota.shifts import PostShiftConstraint, PreShiftConstraint, RotaBuilder, SingleShift, days
from rota.workers import Worker
def generate_basic_rota(weeks_to_rota=10):
@@ -61,7 +61,7 @@ def test_weighted_shift_balancing():
balance_weighting=10,
workers_required=1,
force_as_block=False,
constraint=[{"name": "pre","options": "2"}, {"name": "post","options": "2"}],
constraints=[PreShiftConstraint(days=2), PostShiftConstraint(days=2)]
),
SingleShift(
sites=("group1", "group2"),
+15 -24
View File
@@ -1,6 +1,6 @@
import pytest
import datetime
from rota.shifts import RotaBuilder, SingleShift, days
from rota.shifts import MinimumGradeNumberConstraint, RequireRemoteSitePresenceConstraint, RotaBuilder, SingleShift, days, LimitGradeNumberConstraint
from rota.workers import Worker
@pytest.fixture
@@ -33,7 +33,7 @@ def test_constraint_limit_grades(limit_constraint_rota):
balance_offset=60,
workers_required=4,
force_as_block=True,
constraint=[{"name": "limit_grade_number", "options": {2: 1}}],
constraints=[LimitGradeNumberConstraint(grade=2, max_number=1)]
),
)
Rota.build_and_solve(options={"ratio": 0.01})
@@ -60,7 +60,7 @@ def test_constraint_limit_grades2(limit_constraint_rota):
balance_offset=40,
workers_required=4,
force_as_block=True,
constraint=[{"name": "limit_grade_number", "options": {3: 1}}],
constraints=[LimitGradeNumberConstraint(grade=3, max_number=1)],
),
)
Rota.constraint_options["balance_shifts_quadratic"] = True
@@ -96,7 +96,7 @@ def test_constraint_limit_grades3(limit_constraint_rota):
balance_offset=60,
workers_required=4,
force_as_block=True,
constraint=[{"name": "limit_grade_number", "options": {2: 3, 3: 1}}],
constraints=[LimitGradeNumberConstraint(grade=2, max_number=3), LimitGradeNumberConstraint(grade=3, max_number=1)],
),
)
Rota.constraint_options["balance_shifts_quadratic"] = True
@@ -124,7 +124,7 @@ def test_constraint_limit_grades4(limit_constraint_rota):
balance_offset=40,
workers_required=4,
force_as_block=True,
constraint=[{"name": "limit_grade_number", "options": {2: 4, 3: 0}}],
constraints=[LimitGradeNumberConstraint(grade=2, max_number=4), LimitGradeNumberConstraint(grade=3, max_number=0)],
),
)
Rota.constraint_options["balance_shifts_quadratic"] = True
@@ -143,7 +143,7 @@ def test_constraint_minimum_grades(limit_constraint_rota):
balance_offset=40,
workers_required=1,
force_as_block=True,
constraint=[{"name": "minimum_grade_number", "options": (3, 1)}],
constraints=[MinimumGradeNumberConstraint(grade=3, min_number=1)],
),
)
Rota.constraint_options["balance_shifts_quadratic"] = True
@@ -170,7 +170,7 @@ def test_constraint_minimum_grades2(limit_constraint_rota):
balance_offset=40,
workers_required=4,
force_as_block=True,
constraint=[{"name": "minimum_grade_number", "options": (3, 3)}],
constraints=[MinimumGradeNumberConstraint(grade=3, min_number=3)],
),
)
Rota.constraint_options["balance_shifts_quadratic"] = True
@@ -197,7 +197,7 @@ def test_constraint_minimum_grades3(limit_constraint_rota):
balance_offset=40,
workers_required=4,
force_as_block=True,
constraint=[{"name": "minimum_grade_number", "options": (3, 0)}],
constraints=[MinimumGradeNumberConstraint(grade=3, min_number=0)],
),
)
Rota.constraint_options["balance_shifts_quadratic"] = True
@@ -217,7 +217,7 @@ def test_constraint_minimum_grades_no_valid_worker(limit_constraint_rota):
balance_offset=40,
workers_required=4,
force_as_block=True,
constraint=[{"name": "minimum_grade_number", "options": (4, 1)}],
constraints=[MinimumGradeNumberConstraint(grade=4, min_number=1)],
),
)
Rota.constraint_options["balance_shifts_quadratic"] = True
@@ -236,11 +236,8 @@ def test_constraint_require_remote_site_presence_week(limit_constraint_rota):
balance_offset=40,
workers_required=2,
force_as_block=True,
constraint=[
{
"name": "require_remote_site_presence_week",
"options": ("group1", 2),
}
constraints=[
RequireRemoteSitePresenceConstraint(site="group1", required_number=2)
],
),
)
@@ -272,11 +269,8 @@ def test_constraint_require_remote_site_presence_week2(limit_constraint_rota):
balance_offset=20,
workers_required=3,
force_as_block=True,
constraint=[
{
"name": "require_remote_site_presence_week",
"options": ("group1", 2),
}
constraints=[
RequireRemoteSitePresenceConstraint(site="group1", required_number=2)
],
),
)
@@ -304,11 +298,8 @@ def test_constraint_require_remote_site_presence_week3(limit_constraint_rota):
balance_offset=20,
workers_required=3,
force_as_block=True,
constraint=[
{
"name": "require_remote_site_presence_week",
"options": ("group2", 1),
}
constraints=[
RequireRemoteSitePresenceConstraint(site="group2", required_number=1)
],
),
)
+5 -5
View File
@@ -1,6 +1,6 @@
import pytest
import datetime
from rota.shifts import RotaBuilder, SingleShift, days
from rota.shifts import NightConstraint, RotaBuilder, SingleShift, days
from rota.workers import Worker
@pytest.fixture
@@ -45,7 +45,7 @@ def test_basic_assignment(demo_rota_night_unavailable):
name="night_weekend",
length=12.5,
days=days[5:],
constraint=[{"name": "night"}],
constraints=[NightConstraint()],
),
)
Rota.build_and_solve(options={"ratio": 0.00})
@@ -66,7 +66,7 @@ def test_assign_night_prior_to_unavailablity(demo_rota_night_unavailable):
length=12.5,
days=days[5:],
workers_required=2,
constraint=[{"name": "night"}],
constraints=[NightConstraint()],
),
)
Rota.build_and_solve(options={"ratio": 0.00})
@@ -101,7 +101,7 @@ def test_assign_prior_to_unavailablity_non_night(demo_rota_night_unavailable):
length=12.5,
days=days[5:],
workers_required=2,
constraint=[],
constraints=[],
),
)
Rota.build_and_solve(options={"ratio": 0.00})
@@ -135,7 +135,7 @@ def test_assign_split(demo_rota_night_unavailable):
length=12.5,
days=days[5:],
workers_required=3,
constraint=[],
constraints=[],
),
)
Rota.build_and_solve(options={"ratio": 0.00})
+19 -19
View File
@@ -1,6 +1,6 @@
import datetime
import pytest
from rota.shifts import InvalidShift, NoWorkers, RotaBuilder, SingleShift, days
from rota.shifts import InvalidShift, NightConstraint, NoWorkers, PostShiftConstraint, PreShiftConstraint, RotaBuilder, SingleShift, days
from rota.workers import Worker
def generate_basic_rota(weeks_to_rota=10):
@@ -35,7 +35,7 @@ def test_nights():
length=12.5,
days=days[5:],
force_as_block=True,
constraint=[{"name": "night"}, {"name": "pre", "options": 2}],
constraints=[NightConstraint(), PreShiftConstraint(days=2)],
workers_required=2,
),
SingleShift(
@@ -60,7 +60,7 @@ def test_nights_pre3():
length=12.5,
days=days[5:],
force_as_block=True,
constraint=[{"name": "night"}, {"name": "pre", "options": 3}],
constraints=[NightConstraint(), PreShiftConstraint(days=3)],
workers_required=2,
),
SingleShift(
@@ -84,7 +84,7 @@ def test_nights_pre3_2():
length=12.5,
days=days[5:],
force_as_block=True,
constraint=[{"name": "night"}, {"name": "pre", "options": 3}],
constraints=[NightConstraint(), PreShiftConstraint(days=3)],
workers_required=1,
),
SingleShift(
@@ -108,7 +108,7 @@ def test_nights_fail():
length=12.5,
days=days[5:],
force_as_block=True,
constraint=[{"name": "night"}, {"name": "pre", "options": 3}],
constraints=[NightConstraint(), PreShiftConstraint(days=3)],
workers_required=2,
),
SingleShift(
@@ -132,7 +132,7 @@ def test_nights2():
length=12.5,
days=days[5:],
force_as_block=True,
constraint=[{"name": "night"}],
constraints=[NightConstraint()],
workers_required=2,
),
SingleShift(
@@ -158,10 +158,10 @@ def test_nights_pre_wrap_around():
length=12.5,
days=days[:2],
force_as_block=True,
constraint=[
{"name": "night"},
{"name": "pre", "options": 5},
{"name": "post", "options": 5},
constraints=[
NightConstraint(),
PreShiftConstraint(days=5),
PostShiftConstraint(days=5),
],
workers_required=3,
),
@@ -195,7 +195,7 @@ def test_nights_max_frequency():
length=12.5,
days=days[5:],
force_as_block=True,
constraint=[{"name": "night"}],
constraints=[NightConstraint()],
workers_required=2,
),
)
@@ -213,7 +213,7 @@ def test_nights_max_frequency_fail():
length=12.5,
days=days[5:],
force_as_block=True,
constraint=[{"name": "night"}],
constraints=[NightConstraint()],
workers_required=2,
),
)
@@ -230,7 +230,7 @@ def test_nights_max_frequency3():
length=12.5,
days=days[5:],
force_as_block=True,
constraint=[{"name": "night"}],
constraints=[NightConstraint()],
workers_required=1,
),
SingleShift(
@@ -239,7 +239,7 @@ def test_nights_max_frequency3():
length=12.5,
days=days[:5],
force_as_block=True,
constraint=[{"name": "night"}],
constraints=[NightConstraint()],
workers_required=1,
),
)
@@ -257,7 +257,7 @@ def test_nights_max_frequency4():
length=12.5,
days=days[5:],
force_as_block=True,
constraint=[{"name": "night"}],
constraints=[NightConstraint()],
workers_required=1,
),
SingleShift(
@@ -266,7 +266,7 @@ def test_nights_max_frequency4():
length=12.5,
days=days[:5],
force_as_block=True,
constraint=[{"name": "night"}],
constraints=[NightConstraint()],
workers_required=1,
),
)
@@ -291,7 +291,7 @@ def test_nights_max_frequency_exclusions():
length=12.5,
days=days[5:],
force_as_block=True,
constraint=[{"name": "night"}],
constraints=[NightConstraint()],
workers_required=2,
),
)
@@ -310,7 +310,7 @@ def test_nights_max_frequency_exclusions2():
length=12.5,
days=days[5:],
force_as_block=True,
constraint=[{"name": "night"}],
constraints=[NightConstraint()],
workers_required=2,
),
)
@@ -346,7 +346,7 @@ def test_nights_max_frequency_exclusions3():
days=days[5:],
force_as_block=True,
balance_offset=10,
constraint=[{"name": "night"}],
constraints=[NightConstraint()],
workers_required=2,
),
)
+4 -4
View File
@@ -1,6 +1,6 @@
import pytest
from rota.shifts import NoWorkers, RotaBuilder, SingleShift, days
from rota.shifts import NoWorkers, RequireRemoteSitePresenceConstraint, RotaBuilder, SingleShift, days
import datetime
from rota.workers import Worker
@@ -34,7 +34,7 @@ class TestRemoteRotas:
workers_required=1,
balance_offset=100,
force_as_block=False,
constraint=[{"name":"require_remote_site_presence_week", "options":("group2", 2)}],
constraints=[RequireRemoteSitePresenceConstraint(site="group2", required_number=2)],
),
)
@@ -70,7 +70,7 @@ class TestRemoteRotas:
workers_required=1,
balance_offset=10,
force_as_block=True,
constraint=[{"name":"require_remote_site_presence_week", "options":("group2", 1)}],
constraints=[RequireRemoteSitePresenceConstraint(site="group2", required_number=1)],
),
SingleShift(
sites=("group1", "group2"), name="b", length= 12.5, days=days[3:],
@@ -130,7 +130,7 @@ class TestRemoteRotas:
workers_required=1,
balance_offset=10,
force_as_block=False,
constraint=[{"name":"require_remote_site_presence_week", "options":("group2", 1)}],
constraints=[RequireRemoteSitePresenceConstraint(site="group2", required_number=1)],
),
SingleShift(
sites=("group1", "group2"), name="b", length= 12.5, days=days[3:],
+32 -69
View File
@@ -1,5 +1,5 @@
import pytest
from rota.shifts import RotaBuilder, SingleShift, days
from rota.shifts import PostShiftConstraint, PreShiftConstraint, RotaBuilder, SingleShift, days
from rota.workers import Worker
import datetime
@@ -59,7 +59,7 @@ def test_pre(demo_rota_clear):
length=12.5,
days=days[:5],
workers_required=2,
constraint=[{"name": "pre", "options": 1}],
constraints=[PreShiftConstraint(days=1)],
),
SingleShift(
sites=("group1", "group2"),
@@ -74,7 +74,7 @@ def test_pre(demo_rota_clear):
length=12.5,
days=days[3],
workers_required=1,
constraint=[{"name": "pre", "options": 1}, {"name": "post", "options": 1}],
constraints=[PreShiftConstraint(days=1), PostShiftConstraint(days=1)],
),
)
@@ -123,12 +123,9 @@ def test_pre_post_clear(demo_rota_clear):
days=days[:5],
workers_required=2,
assign_as_block=False, # global setting is off
constraint=[
{
"name": "pre",
"options": 1,
},
{"name": "post", "options": 1},
constraints=[
PreShiftConstraint(days=1),
PostShiftConstraint(days=1),
],
),
SingleShift(
@@ -138,12 +135,9 @@ def test_pre_post_clear(demo_rota_clear):
days=days[5:],
workers_required=2,
assign_as_block=False, # global setting is off
constraint=[
{
"name": "pre",
"options": 1,
},
{"name": "post", "options": 1},
constraints=[
PreShiftConstraint(days=1),
PostShiftConstraint(days=1),
],
),
)
@@ -178,12 +172,9 @@ def test_pre_post_clear2(demo_rota_clear):
days=days[:5],
workers_required=2,
assign_as_block=False, # global setting is off
constraint=[
{
"name": "pre",
"options": 2,
},
{"name": "post", "options": 2},
constraints=[
PreShiftConstraint(days=2),
PostShiftConstraint(days=2),
],
),
SingleShift(
@@ -193,12 +184,9 @@ def test_pre_post_clear2(demo_rota_clear):
days=days[5:],
workers_required=2,
assign_as_block=False, # global setting is off
constraint=[
{
"name": "pre",
"options": 2,
},
{"name": "post", "options": 2},
constraints=[
PreShiftConstraint(days=2),
PostShiftConstraint(days=2),
],
),
)
@@ -237,12 +225,9 @@ def test_pre_post_clear_multi_group(demo_rota_clear):
days=days[:5],
workers_required=2,
assign_as_block=False, # global setting is off
constraint=[
{
"name": "pre",
"options": 2,
},
{"name": "post", "options": 2},
constraints=[
PreShiftConstraint(days=2),
PostShiftConstraint(days=2),
],
),
SingleShift(
@@ -252,12 +237,9 @@ def test_pre_post_clear_multi_group(demo_rota_clear):
days=days[5:],
workers_required=1,
assign_as_block=False, # global setting is off
constraint=[
{
"name": "pre",
"options": 2,
},
{"name": "post", "options": 2},
constraints=[
PreShiftConstraint(days=2),
PostShiftConstraint(days=2),
],
),
SingleShift(
@@ -267,12 +249,9 @@ def test_pre_post_clear_multi_group(demo_rota_clear):
days=days[5:],
workers_required=1,
assign_as_block=False, # global setting is off
constraint=[
{
"name": "pre",
"options": 2,
},
{"name": "post", "options": 2},
constraints=[
PreShiftConstraint(days=2),
PostShiftConstraint(days=2),
],
),
)
@@ -318,12 +297,9 @@ def test_pre_post_clear_force_assign(demo_rota_clear):
days=days[:5],
workers_required=1,
assign_as_block=False, # global setting is off
constraint=[
{
"name": "pre",
"options": 1,
},
{"name": "post", "options": 1},
constraints=[
PreShiftConstraint(days=1),
PostShiftConstraint(days=1),
],
),
SingleShift(
@@ -394,12 +370,7 @@ def test_pre_post_clear_force_assign2(demo_rota_clear):
days=days[:5],
workers_required=1,
assign_as_block=False, # global setting is off
constraint=[
#{
# "name": "pre",
# "options": 1,
#},
#{"name": "post", "options": 1},
constraints=[
],
),
SingleShift(
@@ -417,12 +388,7 @@ def test_pre_post_clear_force_assign2(demo_rota_clear):
days=days[5:],
workers_required=1,
assign_as_block=False, # global setting is off
constraint=[
#{
# "name": "pre",
# "options": 2,
#},
#{"name": "post", "options": 2},
constraints=[
],
),
SingleShift(
@@ -432,12 +398,9 @@ def test_pre_post_clear_force_assign2(demo_rota_clear):
days=days[5:],
workers_required=1,
assign_as_block=False, # global setting is off
constraint=[
{
"name": "pre",
"options": 1,
},
{"name": "post", "options": 1},
constraints=[
PreShiftConstraint(days=1),
PostShiftConstraint(days=1),
],
),
)
+10 -3
View File
@@ -1,8 +1,9 @@
import datetime
import pytest
from pytest import approx
from rota.shifts import RotaBuilder, SingleShift, days
from rota.shifts import PostShiftConstraint, RotaBuilder, SingleShift, days
from rota.workers import Worker
from web.rota.shifts import PreShiftConstraint
@pytest.fixture
def demo_rota_nights():
@@ -48,7 +49,10 @@ def demo_rota_nights():
length=12.5,
days=days[:4],
workers_required=1,
constraint=[{"name": "pre", "options": 1}, {"name": "post", "options": 2}],
constraints=[
PreShiftConstraint(days=1),
PostShiftConstraint(days=2),
],
force_as_block=True
),
SingleShift(
@@ -56,7 +60,10 @@ def demo_rota_nights():
name="night_weekend",
length=12.5,
days=days[4:],
constraint=[{"name": "pre", "options": 1}, {"name": "post", "options": 2}],
constraints=[
PreShiftConstraint(days=1),
PostShiftConstraint(days=2),
],
force_as_block=True,
),
SingleShift(
+417 -694
View File
File diff suppressed because it is too large Load Diff
+60 -32
View File
@@ -1,9 +1,10 @@
import pytest
from rota.shifts import InvalidShift, NoWorkers, RotaBuilder, SingleShift, WarningTermination, WorkerRequirement, days
from rota.shifts import InvalidShift, MaxShiftsPerWeekConstraint, NoWorkers, PostShiftConstraint, RotaBuilder, SingleShift, WarningTermination, WorkerRequirement, days
import datetime
from rota.workers import NonWorkingDays, NotAvailableToWork, Worker, generate_not_available_to_works
from rota.workers import WorkRequests
from web.rota.shifts import PreShiftConstraint
def generate_basic_rota(
weeks_to_rota=10, workers=0, start_date=datetime.date(2022, 3, 7)
@@ -577,9 +578,9 @@ def test_worker_requirement_and_force_block():
days=days[:4],
workers_required=wr,
force_as_block=True,
constraint=[
{"name": "pre", "options": 2},
{"name": "post", "options": 3},
constraints=[
PreShiftConstraint(days=2),
PostShiftConstraint(days=3),
]
),
SingleShift(
@@ -589,9 +590,9 @@ def test_worker_requirement_and_force_block():
days=days[4:],
workers_required=wr,
force_as_block=True,
constraint=[
{"name": "pre", "options": 2},
{"name": "post", "options": 3},
constraints=[
PreShiftConstraint(days=2),
PostShiftConstraint(days=3),
]
),
)
@@ -606,6 +607,7 @@ def test_worker_requirement_and_force_block():
assert shift_string.count("cccc") == shift_string.count("c") / 4
assert shift_string.count("ddd") == shift_string.count("d") / 3
@pytest.mark.slow
def test_split_shift():
Rota = generate_basic_rota(workers=11, weeks_to_rota=22)
@@ -620,10 +622,10 @@ def test_split_shift():
length=12.5,
days=days[:4],
workers_required=1,
constraint=[
{"name": "pre", "options": 2},
{"name": "post", "options": 3},
{"name": "max_shifts_per_week", "options": 1},
constraints=[
PreShiftConstraint(days=2),
PostShiftConstraint(days=3),
MaxShiftsPerWeekConstraint(max_shifts=1),
]
),
SingleShift(
@@ -633,9 +635,9 @@ def test_split_shift():
days=(days[4], days[6]),
workers_required=1,
assign_as_block=True,
constraint=[
{"name": "pre", "options": 2},
{"name": "post", "options": 3},
constraints=[
PreShiftConstraint(days=2),
PostShiftConstraint(days=3),
]
),
SingleShift(
@@ -644,9 +646,9 @@ def test_split_shift():
length=12.5,
days=days[5],
workers_required=1,
constraint=[
{"name": "pre", "options": 2},
{"name": "post", "options": 3},
constraints=[
PreShiftConstraint(days=2),
PostShiftConstraint(days=3),
]
),
)
@@ -685,7 +687,7 @@ def test_locums_basic():
days=days[:4],
workers_required=1,
constraint=[
constraints=[
#{"name": "pre", "options": 1},
#{"name": "post", "options": 1},
#{"name": "max_shifts_per_week", "options": 1},
@@ -734,7 +736,7 @@ def test_locums_nwds():
days=days[:4],
workers_required=1,
constraint=[
constraints=[
#{"name": "pre", "options": 1},
#{"name": "post", "options": 1},
#{"name": "max_shifts_per_week", "options": 1},
@@ -751,7 +753,6 @@ def test_locums_nwds():
assert Rota.results.solver.status == "ok"
for worker in Rota.get_workers():
print( Rota.get_worker_shift_list(worker))
assert Rota.get_worker_shift_list(worker).count("a") == 4
if worker.name in ("worker03", "worker04"):
@@ -782,7 +783,7 @@ def test_locums_no_availablity():
days=days[:4],
workers_required=1,
constraint=[
constraints=[
#{"name": "pre", "options": 1},
#{"name": "post", "options": 1},
#{"name": "max_shifts_per_week", "options": 1},
@@ -794,6 +795,7 @@ def test_locums_no_availablity():
with pytest.raises(WarningTermination):
Rota.build_and_solve()
@pytest.mark.slow
def test_locums():
Rota = generate_basic_rota(workers=7, weeks_to_rota=10)
@@ -832,10 +834,10 @@ def test_locums():
days=days[:4],
workers_required=1,
constraint=[
{"name": "pre", "options": 2},
{"name": "post", "options": 3},
{"name": "max_shifts_per_week", "options": 1},
constraints=[
PreShiftConstraint(days=2),
PostShiftConstraint(days=3),
MaxShiftsPerWeekConstraint(max_shifts=1),
]
),
SingleShift(
@@ -845,9 +847,9 @@ def test_locums():
days=(days[4], days[6]),
workers_required=1,
assign_as_block=True,
constraint=[
{"name": "pre", "options": 2},
{"name": "post", "options": 3},
constraints=[
PreShiftConstraint(days=2),
PostShiftConstraint(days=3),
]
),
SingleShift(
@@ -856,9 +858,9 @@ def test_locums():
length=12.5,
days=days[5],
workers_required=1,
constraint=[
{"name": "pre", "options": 2},
{"name": "post", "options": 3},
constraints=[
PreShiftConstraint(days=2),
PostShiftConstraint(days=3),
]
),
)
@@ -912,11 +914,37 @@ def test_worker_assign_as_block_preference():
shift_list_4 = Rota.get_worker_shift_list_string(worker4)
assert shift_list_4.count("a") == 12, "Worker 4 should have at least 12 'a' shifts, but may not be grouped together"
def test_worker_assign_as_block_preference2():
"""Test that a worker's assign_as_block preference is respected over the global setting."""
Rota = generate_basic_rota(workers=4, weeks_to_rota=8)
# Worker 1 prefers to have shift 'a' assigned as a block, worker 2 does not
workers = Rota.get_workers()
worker1 = workers[0]
worker2 = workers[1]
worker3 = workers[2]
worker4 = workers[3]
# Add a shift 'a' that is NOT globally set as assign_as_block
Rota.add_shifts(
SingleShift(
sites=("group1",),
name="a",
length=8,
days=days[:4],
workers_required=1,
assign_as_block=False, # global setting is off
),
)
# Modify worker1's preference to prevent block 'a' shifts
worker1.assign_as_block_preferences = {"a":-1}
Rota.build_and_solve(options={"ratio": 0.0})
Rota.export_rota_to_html("test_worker_assign_as_block_preference", folder="tests")
shift_list_1 = Rota.get_worker_shift_list_string(worker1)
assert shift_list_1.count("aaaa") == 0, "Worker 1 should have all 'a' shifts grouped together (block)"
assert shift_list_1.count("aaaa") == 0, "Worker 1 should have less 'a' shifts grouped together (block)"
worker1.assign_as_block_preferences = {"a":0}