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:
@@ -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
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -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)
|
||||
],
|
||||
),
|
||||
)
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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),
|
||||
],
|
||||
),
|
||||
)
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
+60
-32
@@ -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}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user