-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #12 from rodrigo-arenas/develop
Release 0.2.1
- Loading branch information
Showing
13 changed files
with
222 additions
and
66 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,9 @@ omit = | |
./tests/* | ||
./venv/* | ||
./docs/* | ||
./examples/* | ||
*/tests/* | ||
setup.py | ||
[report] | ||
precision = 2 | ||
show_missing = True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
language: python | ||
python: | ||
- 3.6 | ||
- 3.7 | ||
- 3.8 | ||
- 3.9 | ||
before_install: | ||
- python --version | ||
- pip install -U pip | ||
install: | ||
- pip install -r dev-requirements.txt | ||
script: | ||
- pytest pyworkforce/ --verbose --color=yes --assert=plain --cov-config=.coveragerc --cov=./ | ||
after_success: | ||
- codecov |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,6 @@ | ||
pytest==6.2.2 | ||
codecov==2.1.11 | ||
pytest-cov==2.11.1 | ||
twine==2.4.7 | ||
twine==3.3.0 | ||
numpy>=1.18.1 | ||
ortools>=7.8.7959 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
import pytest | ||
from pyworkforce.queuing import ErlangC | ||
|
||
|
||
def test_expected_erlangc_results(): | ||
erlang = ErlangC(transactions=100, asa=0.33, aht=3, interval=30, shrinkage=0.3) | ||
results = erlang.required_positions(service_level=0.8, max_occupancy=0.85) | ||
raw_positions = results['raw_positions'] | ||
positions = results['positions'] | ||
service_level = results['service_level'] | ||
occupancy = results['occupancy'] | ||
waiting_probability = results['waiting_probability'] | ||
|
||
assert raw_positions == 14 | ||
assert positions == 20 | ||
assert round(service_level, 3) == 0.888 | ||
assert round(occupancy, 3) == 0.714 | ||
assert round(waiting_probability, 3) == 0.174 | ||
|
||
|
||
def test_scale_positions_erlangc(): | ||
erlang = ErlangC(transactions=100, asa=0.33, aht=3, interval=30, shrinkage=0.3) | ||
results = erlang.required_positions(service_level=0.8, max_occupancy=0.85) | ||
positions = results['positions'] | ||
service_level = erlang.service_level(positions=positions, scale_positions=True) | ||
occupancy = erlang.achieved_occupancy(positions=positions, scale_positions=True) | ||
waiting_probability = erlang.waiting_probability(positions=positions, scale_positions=True) | ||
|
||
assert positions == 20 | ||
assert round(service_level, 3) == 0.888 | ||
assert round(occupancy, 3) == 0.714 | ||
assert round(waiting_probability, 3) == 0.174 | ||
|
||
|
||
def test_over_occupancy_erlangc(): | ||
erlang = ErlangC(transactions=100, asa=0.33, aht=3, interval=30, shrinkage=0.3) | ||
results = erlang.required_positions(service_level=0.8, max_occupancy=0.7) | ||
raw_positions = results['raw_positions'] | ||
positions = results['positions'] | ||
service_level = erlang.service_level(positions=positions, scale_positions=True) | ||
occupancy = erlang.achieved_occupancy(positions=positions, scale_positions=True) | ||
waiting_probability = erlang.waiting_probability(positions=positions, scale_positions=True) | ||
|
||
assert raw_positions == 15 | ||
assert positions == 22 | ||
assert round(service_level, 3) == 0.941 | ||
assert round(occupancy, 3) == 0.667 | ||
assert round(waiting_probability, 3) == 0.102 | ||
|
||
|
||
def test_wrong_transactions_erlangc(): | ||
with pytest.raises(Exception) as excinfo: | ||
erlang = ErlangC(transactions=-20, asa=0.33, aht=3, interval=30, shrinkage=0.3) | ||
assert str(excinfo.value) == "transactions can't be smaller or equals than 0" | ||
|
||
|
||
def test_wrong_aht_erlangc(): | ||
with pytest.raises(Exception) as excinfo: | ||
erlang = ErlangC(transactions=100, asa=0.33, aht=-5, interval=30, shrinkage=0.3) | ||
assert str(excinfo.value) == "aht can't be smaller or equals than 0" | ||
|
||
|
||
def test_wrong_asa_erlangc(): | ||
with pytest.raises(Exception) as excinfo: | ||
erlang = ErlangC(transactions=100, asa=0, aht=5, interval=30, shrinkage=0.3) | ||
assert str(excinfo.value) == "asa can't be smaller or equals than 0" | ||
|
||
|
||
def test_wrong_interval_erlangc(): | ||
with pytest.raises(Exception) as excinfo: | ||
erlang = ErlangC(transactions=100, asa=10, aht=5, interval=-30, shrinkage=0.3) | ||
assert str(excinfo.value) == "interval can't be smaller or equals than 0" | ||
|
||
|
||
def test_wrong_shrinkage_erlangc(): | ||
with pytest.raises(Exception) as excinfo: | ||
erlang = ErlangC(transactions=100, asa=10, aht=5, interval=30, shrinkage=1) | ||
assert str(excinfo.value) == "shrinkage must be between in the interval [0,1)" | ||
|
||
|
||
def test_wrong_service_level_erlangc(): | ||
erlang = ErlangC(transactions=100, asa=0.33, aht=3, interval=30, shrinkage=0.3) | ||
with pytest.raises(Exception) as excinfo: | ||
results = erlang.required_positions(service_level=1.8, max_occupancy=0.85) | ||
assert str(excinfo.value) == "service_level must be between 0 and 1" | ||
|
||
|
||
def test_wrong_max_occupancy_erlangc(): | ||
erlang = ErlangC(transactions=100, asa=0.33, aht=3, interval=30, shrinkage=0.3) | ||
with pytest.raises(Exception) as excinfo: | ||
results = erlang.required_positions(service_level=0.8, max_occupancy=1.2) | ||
assert str(excinfo.value) == "max_occupancy must be between 0 and 1" |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
from pyworkforce.shifts import MinAbsDifference | ||
|
||
|
||
def test_min_abs_difference_schedule(): | ||
required_resources = [ | ||
[9, 11, 17, 9, 7, 12, 5, 11, 8, 9, 18, 17, 8, 12, 16, 8, 7, 12, 11, 10, 13, 19, 16, 7], | ||
[13, 13, 12, 15, 18, 20, 13, 16, 17, 8, 13, 11, 6, 19, 11, 20, 19, 17, 10, 13, 14, 23, 16, 8] | ||
] | ||
shifts_coverage = {"Morning": [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], | ||
"Afternoon": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], | ||
"Night": [1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1], | ||
"Mixed": [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0]} | ||
|
||
num_days = 2 | ||
|
||
scheduler = MinAbsDifference(num_days=num_days, | ||
periods=24, | ||
shifts_coverage=shifts_coverage, | ||
required_resources=required_resources, | ||
max_period_concurrency=25, | ||
max_shift_concurrency=20) | ||
|
||
solution = scheduler.solve() | ||
|
||
assert solution['status'] == 'OPTIMAL' | ||
assert 'cost' in solution | ||
assert 'resources_shifts' in solution | ||
assert len(solution['resources_shifts']) == num_days * len(shifts_coverage) | ||
for i in range(num_days * len(shifts_coverage)): | ||
assert solution['resources_shifts'][i]['resources'] >= 0 | ||
|
||
|
||
def test_infeasible_min_abs_difference_schedule(): | ||
required_resources = [ | ||
[9, 11, 17, 9, 7, 12, 5, 11, 8, 9, 18, 17, 8, 12, 16, 8, 7, 12, 11, 10, 13, 19, 16, 7], | ||
[13, 13, 12, 15, 18, 20, 13, 16, 17, 8, 13, 11, 6, 19, 11, 20, 19, 17, 10, 13, 14, 23, 16, 8] | ||
] | ||
shifts_coverage = {"Morning": [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], | ||
"Afternoon": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], | ||
"Night": [1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1], | ||
"Mixed": [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0]} | ||
|
||
num_days = 2 | ||
|
||
scheduler = MinAbsDifference(num_days=num_days, | ||
periods=24, | ||
shifts_coverage=shifts_coverage, | ||
required_resources=required_resources, | ||
max_period_concurrency=10, | ||
max_shift_concurrency=20) | ||
|
||
solution = scheduler.solve() | ||
|
||
assert solution['status'] == 'INFEASIBLE' | ||
assert 'cost' in solution | ||
assert 'resources_shifts' in solution | ||
assert solution['cost'] == -1 | ||
assert len(solution['resources_shifts']) == 1 | ||
assert solution['resources_shifts'][0]['day'] == -1 | ||
assert solution['resources_shifts'][0]['shift'] == 'Unknown' | ||
assert solution['resources_shifts'][0]['resources'] == -1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import pytest | ||
from pyworkforce.shifts.utils import check_positive_integer, check_positive_float | ||
|
||
|
||
def test_check_positive_integer(): | ||
assert check_positive_integer('my_val', 5) | ||
|
||
|
||
def test_check_non_positive_integers(): | ||
with pytest.raises(Exception) as excinfo: | ||
result = check_positive_integer('my_val', -1) | ||
assert str(excinfo.value) == "my_val must be a positive integer" | ||
|
||
with pytest.raises(Exception) as excinfo: | ||
result = check_positive_integer('my_val2', 5.4) | ||
assert str(excinfo.value) == "my_val2 must be a positive integer" | ||
|
||
|
||
def test_check_positive_float(): | ||
assert check_positive_float('my_val', 2.43) | ||
|
||
|
||
def test_check_non_positive_floats(): | ||
with pytest.raises(Exception) as excinfo: | ||
result = check_positive_float('my_val', -45.3) | ||
assert str(excinfo.value) == "my_val must be a positive float" | ||
|
||
with pytest.raises(Exception) as excinfo: | ||
result = check_positive_float('my_val2', 80) | ||
assert str(excinfo.value) == "my_val2 must be a positive float" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,5 +33,6 @@ | |
'numpy>=1.18.1', | ||
'ortools>=7.8.7959' | ||
], | ||
python_requires=">=3.6", | ||
include_package_data=True, | ||
) |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.