# -*- coding: utf-8 -*-
from setuptools import setup

packages = \
['or_shifty']

package_data = \
{'': ['*']}

install_requires = \
['ortools>=7.2,<8.0']

entry_points = \
{'console_scripts': ['shifty = or_shifty.app:main']}

setup_kwargs = {
    'name': 'or-shifty',
    'version': '1.1.0',
    'description': '',
    'long_description': '# OR-Shifty\n`OR-Shifty` is a CLI app to automate assignment of on-call shifts via constraint solving by use of the\n[OR-tools](https://github.com/google/or-tools) library.\n\nIt is designed to accept two JSON files as input:\n\n- a config file which describes the desired on-call rota, the people to assign, and any constraints\n- a history file which describes past shifts per person, to be used by certain constraints described below\n\nIt will then attempt to create a rota allocation given these inputs and print it either on terminal or as JSON to an\noutput file if provided.\n\nThe given constraints can be prioritised so if a solution cannot be found that satisfies all of them the tool will\ndrop the least important constraint and try again, repeatedly, until a solution is found or no more constraints can\nbe dropped. If any constraints had to be dropped the tool will also print to the terminal which of the original\nconstraints were violated, for which person, and on which day.\n\n## Installation\nYou will need Python 3.7 or greater.\n\n```bash\npip install or-shifty\n```\n\n## Use\nHelp:\n\n```bash\nshifty --help\n```\n\n### Solver mode\nFor using shifty in its default solver mode.\n\nAn output file path can optionally be provided in which case shifty will write the solution to the file in JSON\nformat. If a file already exists at that path then it will overwritten.\n\n```bash\nshifty \\\n    --config <path_to_config.json> \\\n    --history <path_to_history.json> \\\n    [--output <path_to_optional_output.json>]\n```\n\n### Evaluation mode\nShifty can also be run in evaluation mode.\n\nIn this mode an output with an existing solution must be provided. Shifty will then evaluate this solution against\nthe constraints, objective function, and history provided and it will print which (if any) constraints are violated\nby the solution and the score of the objective function. This is intended as a diagnostic tool to inspect shifty\'s\ndecisions.\n\nWhen in this mode the output file must contain exactly an assigned shift for every shift specified in config otherwise\nshifty will exit with an error.\n\n```bash\nshifty \\\n    --config <path_to_config.json> \\\n    --history <path_to_history.json> \\\n    --output <path_to_optional_output.json> \\\n    --evaluate\n```\n\n### Shift types\nAny shift can be assigned one of three types. These types have no intrinsic meaning and only exist so different \nconstraints can be applied to different shifts, e.g. it might be desired to have more unassigned days after having a\nSaturday shift or similar.\n\nThe currently supported shift types are:\n\n- STANDARD\n- SPECIAL_A\n- SPECIAL_B\n\n### Constraints\nSolver constraints fall into one of two categories:\n\n- Mandatory, that are always included\n- User selected, that can be included and configured using the config input file\n\nFor each user selected constraint there will be an example of the JSON configuration needed to include it.\n\nUser selected constraints can also be given a priority. If a solution can not be found the constraints with the highest\npriority number will be dropped and the solver will retry, then the constraints with the second highest priority\nnumber will be dropped and so on. Priority must be a positive integer. A priority of 0 means the constraint cannot ever\nbe dropped. If multiple constraints have the same priority and that priority is due to be dropped then all these\nconstraints will be dropped together.\n\nConstraints can also be named to make them easier to manager by providing `"name": "constraint name"` in the JSON\nconfig.\n\nIt is valid to include the same type of constraint multiple times in the config, e.g. by having a stricter constraint\nwith a higher priority number, followed by a more permissive one with a lower priority number. This way the solver\nwill try to meet the strict one first, but if it cannot it will then at least try to meet the more permissive one.\n\nThe mandatory constraints are mostly common sense and can be seen in the code, e.g. you can\'t assign Eve\'s first shift\ntwice, etc.\n\nThe user selected constraints are as follows:\n\n#### Each person works at most X shifts per assignment period\n```json\n"constraints": [\n    {\n      "type": "EachPersonWorksAtMostXShiftsPerAssignmentPeriod",\n      "priority": 0,\n      "params": {"x":  1}\n    }\n]\n```\n\nAn assignment period is one run of the program with given input files. This constraints that a person can only be\nassigned X of these shifts.\n\n#### There should be at least X days between ops\n```json\n"constraints": [\n    {\n      "type": "ThereShouldBeAtLeastXDaysBetweenOps",\n      "priority": 0,\n      "params": {"x":  4}\n    }\n]\n```\n\nSubtract the last date on ops from the date assigned on a shift. The resulting number of days must be greater that X.\n\n#### There should be at least X days between ops of shift types\n```json\n"constraints": [\n    {\n      "type": "ThereShouldBeAtLeastXDaysBetweenOpsOfShiftTypes",\n      "priority": 0,\n      "params": {"x":  8, "shift_types": ["SPECIAL_A", "SPECIAL_B"]}\n    }\n]\n```\nSubtract the last date on ops of any the given types from the date assigned on a shift of one of the given types. The\nresulting number of days must be grater than X. In the example configuration someone cannot be assigned to a\nSPECIAL_A or SPECIAL_B type shift if they have had a SPECIAL_A or SPECIAL_B shift in the last 8 days.\n\n#### Respect person restrictions per shift type\n```json\n"constraints": [\n    {\n      "type": "RespectPersonRestrictionsPerShiftType",\n      "priority": 0,\n      "params": {"forbidden_by_shift_type": {"special_a": ["Alice"]}}\n    }\n]\n```\n\nDisallow particular people from being assigned any shifts of a given type.\n\n#### Respect person restrictions per day\n```json\n"constraints": [\n    {\n      "type": "RespectPersonRestrictionsPerDay",\n      "name": "Holidays",\n      "priority": 0,\n      "params": {"restrictions": {"Alice": ["2019-11-01"]}}\n    }\n]\n```\n\nDisallow particular people from being assigned any shifts on a given date.\n\n### Objective function\nWhen scheduling the solver will choose between possible solutions that satisfy the constraints by using an objective \nfunction. Each possible solution will be assigned a score using this function and the solution with the highest score\nwill be chosen.\n\nThere is currently support for only one type of objective function called `RankingWeight`.\n\n#### RankingWeight\nThis objective function will rank people for each shift type based on the following criteria:\n\n1. How many shifts of the given type have they done before\n1. How recently have they been on shift\n1. Their name (just to ensure there is a total ordering)\n\nIn addition it will also rank someone being assigned a second shift below everyone else being assigned their first shift\nand so on for possible additional shifts on the same person.\n\ne.g. we have Bob, Alice, and Eve. Bob has done 10 shifts, Alice and Eve have done 8 each. Alice was last on call 2 days\nago and Even was 4 days ago. Everyone can be assigned a maximum of two shifts. The ranking would be:\n\n1. Eve, 1st shift\n1. Alice, 1st shift\n1. Bob, 1st shift\n1. Eve, 2nd shift\n1. Alice, 2nd shift\n1. Bob, 2nd shift\n\nEve is given the highest priority because she is tied for least number of shifts done, but has not been on call as\nrecently. Second shifts are ranked the same way, but after all first shifts.\n\nEach level of this rank is then assigned a weight that is higher the further up in the ranking. \n\nThere is a large gap in the weights when switching from the first shift to the second and so on in order to discourage\nassigning multiple shifts before exhausting other possibilities.\n\nThis process is repeated for each shift type. The resulting weights are then added together to produce the final score.\nThis final score is then given as a reward to the solver for assigning the corresponding person/shift.\n\n### Config\nExamples can be found under `examples`.\n\nThe config file describes the desired on-call rota, the people to assign, and any constraints. The meaning of its\nsections are as follows:\n\n- `shifts`: contains one entry for each shift to assign, along with its name, and type\n- `people`: the people to assign\n- `max_shifts_per_person`: a hard limit on how many shifts a single person can be assigned\n- `objective`: the chosen objective function\n- `constraints`: the chosen constraints\n\n### History\nExamples can be found under `examples`.\n\nThe history file describes past shifts per person, to be used by certain constraints. The meaning of its sections\nare as follows:\n\n- `shifts`: one entry per past shift a person has done, including its type\n- `offset`: offsets to be added to number of shifts done per type for each person\n\n## Development\nOR-Shifty is Python3 application developed using [Poetry](https://github.com/python-poetry/poetry). The minimum required\nPython version, project dependencies, and other project information can be found in the `pyproject.toml` file.\n\nFor ease of development there is a `Makefile`.\n\n```bash\nmake help     # Get a list of all supported make targets\nmake freeze   # Update and freeze python requirements\nmake test     # Run tests\nmake format   # Run formatters and linters\nmake verify   # Run formatters and linters in check only mode\nmake install  # Install project dependencies from poetry.lock, project module, and `shifty` script\nmake build    # Build source and wheels\n```\n\nBefore submitting any pull requests `make test` and `make verify` must both be run an be passing.\n\n## License\nSee the LICENSE file that is included with this repository.\n',
    'author': 'Thomas Maroulis',
    'author_email': 'thomasmaroulis@gmail.com',
    'maintainer': None,
    'maintainer_email': None,
    'url': 'https://github.com/Dalamar42/or-shifty',
    'packages': packages,
    'package_data': package_data,
    'install_requires': install_requires,
    'entry_points': entry_points,
    'python_requires': '>=3.7,<4.0',
}


setup(**setup_kwargs)
