The Incredible Rota Machine

The 'people' csv has these headings:

name
The person's name. Two people cannot have the same name.
team
What team the person is on. Two people on the same team can't be on in-hours support at the same time.
can_do_inhours
Whether they can do in-hours support or not. Should be one of "true", "false", "yes", "no", "y", "n", "1", or "0". Case insensitive.
num_times_inhours
The number of times they have done in-hours support. Someone can only be primary in-hours if they have had at least 3 shifts (including earlier ones in the generated rota).
num_times_shadow
The number of times they have shadowed in-hours support. Someone can only be secondary in-hours if they have had at least 2 shadow shifts (including earlier ones in the generated rota).
can_do_oncall
Whether they can do out-of-hours support or not. Takes the same values as can_do_inhours.
num_times_oncall
The number of times they have done out-of-hours support. Someone can only be secondary on-call if they have had at least 3 shifts (including earlier ones in the generated rota).
forbidden_weeks
Weeks that this person cannot do, counting from 1.

There is an example file. If you're generating the actual GOV.UK rota, there is a spreadsheet in Google Drive.

A full list of constraints is available on GitHub.