scriptplan 0.10.1__tar.gz → 0.10.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {scriptplan-0.10.1 → scriptplan-0.10.2}/CHANGELOG.md +140 -1
- {scriptplan-0.10.1 → scriptplan-0.10.2}/MANIFEST.in +1 -0
- {scriptplan-0.10.1/scriptplan.egg-info → scriptplan-0.10.2}/PKG-INFO +33 -18
- {scriptplan-0.10.1 → scriptplan-0.10.2}/README.md +32 -17
- scriptplan-0.10.2/examples/README.md +42 -0
- scriptplan-0.10.2/examples/edge_cases/alap_before_declared_start.expected.csv +5 -0
- scriptplan-0.10.2/examples/edge_cases/alap_before_declared_start.expected.md +6 -0
- scriptplan-0.10.2/examples/edge_cases/alap_before_declared_start.tjp +8 -0
- scriptplan-0.10.2/examples/edge_cases/alap_bounded_by_declared_starts.expected.csv +5 -0
- scriptplan-0.10.2/examples/edge_cases/alap_bounded_by_declared_starts.expected.md +6 -0
- scriptplan-0.10.2/examples/edge_cases/alap_bounded_by_declared_starts.tjp +8 -0
- scriptplan-0.10.2/examples/edge_cases/alap_gapduration_before_successor.expected.csv +5 -0
- scriptplan-0.10.2/examples/edge_cases/alap_gapduration_before_successor.expected.md +6 -0
- scriptplan-0.10.2/examples/edge_cases/alap_gapduration_before_successor.tjp +15 -0
- scriptplan-0.10.2/examples/edge_cases/alap_keeps_successor_gaps.expected.csv +7 -0
- scriptplan-0.10.2/examples/edge_cases/alap_keeps_successor_gaps.expected.md +8 -0
- scriptplan-0.10.2/examples/edge_cases/alap_keeps_successor_gaps.tjp +10 -0
- scriptplan-0.10.2/examples/edge_cases/alap_milestones_exact.expected.csv +6 -0
- scriptplan-0.10.2/examples/edge_cases/alap_milestones_exact.expected.md +5 -0
- scriptplan-0.10.2/examples/edge_cases/alap_milestones_exact.tjp +9 -0
- scriptplan-0.10.2/examples/edge_cases/alap_onstart_reading.expected.csv +5 -0
- scriptplan-0.10.2/examples/edge_cases/alap_onstart_reading.expected.md +5 -0
- scriptplan-0.10.2/examples/edge_cases/alap_onstart_reading.tjp +15 -0
- scriptplan-0.10.2/examples/edge_cases/alap_own_end_before_successor.expected.csv +5 -0
- scriptplan-0.10.2/examples/edge_cases/alap_own_end_before_successor.expected.md +5 -0
- scriptplan-0.10.2/examples/edge_cases/alap_own_end_before_successor.tjp +15 -0
- scriptplan-0.10.2/examples/edge_cases/alap_project_end_and_declared_end.expected.csv +4 -0
- scriptplan-0.10.2/examples/edge_cases/alap_project_end_and_declared_end.expected.md +5 -0
- scriptplan-0.10.2/examples/edge_cases/alap_project_end_and_declared_end.tjp +7 -0
- scriptplan-0.10.2/examples/edge_cases/alap_spans_before_mid_slot_successor.expected.csv +5 -0
- scriptplan-0.10.2/examples/edge_cases/alap_spans_before_mid_slot_successor.expected.md +5 -0
- scriptplan-0.10.2/examples/edge_cases/alap_spans_before_mid_slot_successor.tjp +8 -0
- scriptplan-0.10.2/examples/edge_cases/alap_without_anchor_parent.expected.csv +5 -0
- scriptplan-0.10.2/examples/edge_cases/alap_without_anchor_parent.expected.md +6 -0
- scriptplan-0.10.2/examples/edge_cases/alap_without_anchor_parent.tjp +15 -0
- scriptplan-0.10.2/examples/edge_cases/alap_without_anchor_plan.expected.csv +5 -0
- scriptplan-0.10.2/examples/edge_cases/alap_without_anchor_plan.expected.md +6 -0
- scriptplan-0.10.2/examples/edge_cases/alap_without_anchor_plan.tjp +15 -0
- scriptplan-0.10.2/examples/edge_cases/asap_and_alap_share_a_slot.expected.csv +4 -0
- scriptplan-0.10.2/examples/edge_cases/asap_and_alap_share_a_slot.expected.md +5 -0
- scriptplan-0.10.2/examples/edge_cases/asap_and_alap_share_a_slot.tjp +7 -0
- scriptplan-0.10.2/examples/edge_cases/daily_cap_counts_worked_time.expected.csv +4 -0
- scriptplan-0.10.2/examples/edge_cases/daily_cap_counts_worked_time.expected.md +6 -0
- scriptplan-0.10.2/examples/edge_cases/daily_cap_counts_worked_time.tjp +7 -0
- scriptplan-0.10.2/examples/edge_cases/dependency_offset_one_slot.expected.csv +4 -0
- scriptplan-0.10.2/examples/edge_cases/dependency_offset_one_slot.expected.md +5 -0
- scriptplan-0.10.2/examples/edge_cases/dependency_offset_one_slot.tjp +8 -0
- scriptplan-0.10.2/examples/edge_cases/duration_length_after_mid_slot_end.expected.csv +4 -0
- scriptplan-0.10.2/examples/edge_cases/duration_length_after_mid_slot_end.expected.md +5 -0
- scriptplan-0.10.2/examples/edge_cases/duration_length_after_mid_slot_end.tjp +7 -0
- scriptplan-0.10.2/examples/edge_cases/eight_efforts_fill_whole_days.expected.csv +9 -0
- scriptplan-0.10.2/examples/edge_cases/eight_efforts_fill_whole_days.expected.md +5 -0
- scriptplan-0.10.2/examples/edge_cases/eight_efforts_fill_whole_days.tjp +12 -0
- scriptplan-0.10.2/examples/edge_cases/gaplength_on_project_calendar.expected.csv +5 -0
- scriptplan-0.10.2/examples/edge_cases/gaplength_on_project_calendar.expected.md +6 -0
- scriptplan-0.10.2/examples/edge_cases/gaplength_on_project_calendar.tjp +15 -0
- scriptplan-0.10.2/examples/edge_cases/inherited_start_waits_for_dependency.expected.csv +4 -0
- scriptplan-0.10.2/examples/edge_cases/inherited_start_waits_for_dependency.expected.md +6 -0
- scriptplan-0.10.2/examples/edge_cases/inherited_start_waits_for_dependency.tjp +19 -0
- scriptplan-0.10.2/examples/edge_cases/mid_slot_start_and_end.expected.csv +3 -0
- scriptplan-0.10.2/examples/edge_cases/mid_slot_start_and_end.expected.md +4 -0
- scriptplan-0.10.2/examples/edge_cases/mid_slot_start_and_end.tjp +7 -0
- scriptplan-0.10.2/examples/edge_cases/shared_slot_backward.expected.csv +4 -0
- scriptplan-0.10.2/examples/edge_cases/shared_slot_backward.expected.md +4 -0
- scriptplan-0.10.2/examples/edge_cases/shared_slot_backward.tjp +7 -0
- scriptplan-0.10.2/examples/edge_cases/shared_slot_forward_5min.expected.csv +4 -0
- scriptplan-0.10.2/examples/edge_cases/shared_slot_forward_5min.expected.md +6 -0
- scriptplan-0.10.2/examples/edge_cases/shared_slot_forward_5min.tjp +7 -0
- scriptplan-0.10.2/examples/edge_cases/shared_slot_forward_60min.expected.csv +4 -0
- scriptplan-0.10.2/examples/edge_cases/shared_slot_forward_60min.expected.md +6 -0
- scriptplan-0.10.2/examples/edge_cases/shared_slot_forward_60min.tjp +7 -0
- scriptplan-0.10.2/examples/edge_cases/skipped_time_stays_free.expected.csv +5 -0
- scriptplan-0.10.2/examples/edge_cases/skipped_time_stays_free.expected.md +6 -0
- scriptplan-0.10.2/examples/edge_cases/skipped_time_stays_free.tjp +8 -0
- scriptplan-0.10.2/examples/edge_cases/two_people_finish_together.expected.csv +2 -0
- scriptplan-0.10.2/examples/edge_cases/two_people_finish_together.expected.md +5 -0
- scriptplan-0.10.2/examples/edge_cases/two_people_finish_together.tjp +6 -0
- scriptplan-0.10.2/examples/showcase/airport_retrofit.expected.csv +5 -0
- scriptplan-0.10.2/examples/showcase/airport_retrofit.expected.md +84 -0
- scriptplan-0.10.2/examples/showcase/airport_retrofit.tjp +80 -0
- scriptplan-0.10.2/examples/showcase/airport_stress_test.expected.csv +9 -0
- scriptplan-0.10.2/examples/showcase/airport_stress_test.expected.md +106 -0
- scriptplan-0.10.2/examples/showcase/airport_stress_test.tjp +110 -0
- scriptplan-0.10.2/examples/showcase/airport_ultra_math.expected.csv +6 -0
- scriptplan-0.10.2/examples/showcase/airport_ultra_math.expected.md +111 -0
- scriptplan-0.10.2/examples/showcase/airport_ultra_math.tjp +160 -0
- scriptplan-0.10.2/examples/showcase/airport_ultra_math_report.expected.csv +6 -0
- scriptplan-0.10.2/examples/showcase/airport_ultra_math_report.expected.md +30 -0
- scriptplan-0.10.2/examples/showcase/airport_ultra_math_report.tjp +152 -0
- scriptplan-0.10.2/examples/showcase/alap_backward.expected.csv +4 -0
- scriptplan-0.10.2/examples/showcase/alap_backward.expected.md +61 -0
- scriptplan-0.10.2/examples/showcase/alap_backward.tjp +44 -0
- scriptplan-0.10.2/examples/showcase/atomic.expected.csv +2 -0
- scriptplan-0.10.2/examples/showcase/atomic.expected.md +49 -0
- scriptplan-0.10.2/examples/showcase/atomic.tjp +31 -0
- scriptplan-0.10.2/examples/showcase/blackbox.expected.csv +4 -0
- scriptplan-0.10.2/examples/showcase/blackbox.expected.md +86 -0
- scriptplan-0.10.2/examples/showcase/blackbox.tjp +51 -0
- scriptplan-0.10.2/examples/showcase/bottleneck.expected.csv +5 -0
- scriptplan-0.10.2/examples/showcase/bottleneck.expected.md +67 -0
- scriptplan-0.10.2/examples/showcase/bottleneck.tjp +55 -0
- scriptplan-0.10.2/examples/showcase/eclipse.expected.csv +3 -0
- scriptplan-0.10.2/examples/showcase/eclipse.expected.md +60 -0
- scriptplan-0.10.2/examples/showcase/eclipse.tjp +43 -0
- scriptplan-0.10.2/examples/showcase/failover.expected.csv +2 -0
- scriptplan-0.10.2/examples/showcase/failover.expected.md +48 -0
- scriptplan-0.10.2/examples/showcase/failover.tjp +37 -0
- scriptplan-0.10.2/examples/showcase/jit_supply.expected.csv +7 -0
- scriptplan-0.10.2/examples/showcase/jit_supply.expected.md +126 -0
- scriptplan-0.10.2/examples/showcase/jit_supply.tjp +58 -0
- scriptplan-0.10.2/examples/showcase/math_torture.expected.csv +502 -0
- scriptplan-0.10.2/examples/showcase/math_torture.expected.md +208 -0
- scriptplan-0.10.2/examples/showcase/math_torture.tjp +3028 -0
- scriptplan-0.10.2/examples/showcase/paradox.expected.csv +4 -0
- scriptplan-0.10.2/examples/showcase/paradox.expected.md +89 -0
- scriptplan-0.10.2/examples/showcase/paradox.tjp +48 -0
- scriptplan-0.10.2/examples/showcase/priority_clash.expected.csv +4 -0
- scriptplan-0.10.2/examples/showcase/priority_clash.expected.md +36 -0
- scriptplan-0.10.2/examples/showcase/priority_clash.tjp +36 -0
- scriptplan-0.10.2/examples/showcase/quota.expected.csv +5 -0
- scriptplan-0.10.2/examples/showcase/quota.expected.md +63 -0
- scriptplan-0.10.2/examples/showcase/quota.tjp +49 -0
- scriptplan-0.10.2/examples/showcase/simple.expected.csv +5 -0
- scriptplan-0.10.2/examples/showcase/simple.expected.md +52 -0
- scriptplan-0.10.2/examples/showcase/simple.tjp +50 -0
- scriptplan-0.10.2/examples/showcase/synchrony.expected.csv +5 -0
- scriptplan-0.10.2/examples/showcase/synchrony.expected.md +54 -0
- scriptplan-0.10.2/examples/showcase/synchrony.tjp +70 -0
- scriptplan-0.10.2/examples/showcase/thermal.expected.csv +4 -0
- scriptplan-0.10.2/examples/showcase/thermal.expected.md +82 -0
- scriptplan-0.10.2/examples/showcase/thermal.tjp +43 -0
- scriptplan-0.10.2/examples/showcase/throughput.expected.csv +2 -0
- scriptplan-0.10.2/examples/showcase/throughput.expected.md +42 -0
- scriptplan-0.10.2/examples/showcase/throughput.tjp +37 -0
- scriptplan-0.10.2/examples/showcase/time_traveler.expected.csv +4 -0
- scriptplan-0.10.2/examples/showcase/time_traveler.expected.md +75 -0
- scriptplan-0.10.2/examples/showcase/time_traveler.tjp +63 -0
- scriptplan-0.10.2/examples/showcase/timezone_stress.expected.csv +4 -0
- scriptplan-0.10.2/examples/showcase/timezone_stress.expected.md +56 -0
- scriptplan-0.10.2/examples/showcase/timezone_stress.tjp +65 -0
- scriptplan-0.10.2/examples/showcase/tutorial.expected.csv +16 -0
- scriptplan-0.10.2/examples/showcase/tutorial.expected.md +448 -0
- scriptplan-0.10.2/examples/showcase/tutorial.tjp +494 -0
- scriptplan-0.10.2/examples/showcase/union_contract.expected.csv +6 -0
- scriptplan-0.10.2/examples/showcase/union_contract.expected.md +44 -0
- scriptplan-0.10.2/examples/showcase/union_contract.tjp +53 -0
- scriptplan-0.10.2/examples/showcase/workflow_engine.expected.csv +4 -0
- scriptplan-0.10.2/examples/showcase/workflow_engine.expected.md +43 -0
- scriptplan-0.10.2/examples/showcase/workflow_engine.tjp +66 -0
- scriptplan-0.10.2/examples/simple.tjp +26 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/pyproject.toml +1 -1
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/__init__.py +4 -8
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/cli/main.py +3 -3
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/cli/plan.py +16 -7
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/cli/plan_help.py +5 -5
- scriptplan-0.10.2/scriptplan/core/declared_dates.py +47 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/core/project.py +20 -57
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/core/resource_reporting.py +32 -28
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/core/resource_scenario.py +12 -15
- scriptplan-0.10.2/scriptplan/core/slot_ledger.py +263 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/core/task_booking.py +24 -11
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/core/task_dependencies.py +51 -1
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/core/task_placement.py +107 -73
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/core/task_resources.py +36 -10
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/core/task_scenario.py +42 -15
- scriptplan-0.10.2/scriptplan/core/task_spans.py +65 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/core/units.py +4 -4
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/parser/model_pieces.py +51 -63
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/parser/tjp.lark +3 -3
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/parser/tjp_parser.py +28 -5
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/report/logical_expression.py +5 -4
- scriptplan-0.10.2/scriptplan/scheduler/postcheck.py +211 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/scheduler/preflight.py +32 -1
- scriptplan-0.10.2/scriptplan/scheduler/stalls.py +89 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/utils/message_handler.py +37 -21
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/utils/messages.py +2 -2
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/utils/time.py +1 -1
- {scriptplan-0.10.1 → scriptplan-0.10.2/scriptplan.egg-info}/PKG-INFO +33 -18
- scriptplan-0.10.2/scriptplan.egg-info/SOURCES.txt +271 -0
- scriptplan-0.10.2/tests/test_dependency_check.py +67 -0
- scriptplan-0.10.2/tests/test_examples.py +117 -0
- scriptplan-0.10.2/tests/test_failure_messages.py +49 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/tests/test_fixture_golden.py +2 -2
- {scriptplan-0.10.1 → scriptplan-0.10.2}/tests/test_parser.py +2 -2
- {scriptplan-0.10.1 → scriptplan-0.10.2}/tests/test_property_set.py +1 -1
- {scriptplan-0.10.1 → scriptplan-0.10.2}/tests/test_scheduling.py +1 -1
- {scriptplan-0.10.1 → scriptplan-0.10.2}/tests/test_scheduling_validation.py +21 -21
- {scriptplan-0.10.1 → scriptplan-0.10.2}/tests/test_slot_ledger.py +36 -16
- scriptplan-0.10.2/tests/test_stated_dates.py +107 -0
- scriptplan-0.10.2/tests/test_threads.py +108 -0
- scriptplan-0.10.1/scriptplan/core/slot_ledger.py +0 -234
- scriptplan-0.10.1/scriptplan/scheduler/postcheck.py +0 -106
- scriptplan-0.10.1/scriptplan.egg-info/SOURCES.txt +0 -117
- {scriptplan-0.10.1 → scriptplan-0.10.2}/LICENSE +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/cli/__init__.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/cli/plan_files.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/core/__init__.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/core/account.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/core/allocation.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/core/allocation_plan.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/core/attributes.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/core/booking.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/core/exceptions.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/core/journal.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/core/leave.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/core/limits.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/core/project_attributes.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/core/project_calendar.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/core/project_tree.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/core/property.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/core/property_list.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/core/property_set.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/core/property_tree_node.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/core/resolution.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/core/resource.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/core/resource_availability.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/core/scenario.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/core/scenario_data.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/core/shift.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/core/task.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/core/timesheet.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/core/timezones.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/core/working_hours.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/parser/__init__.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/parser/attribute_apply.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/parser/macro_processor.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/parser/report_builder.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/parser/transformer_project.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/parser/transformer_report.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/parser/transformer_resource.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/parser/transformer_task.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/py.typed +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/report/__init__.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/report/report.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/report/report_base.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/report/report_context.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/report/resource_report.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/report/table_cells.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/report/table_headers.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/report/table_report.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/report/task_report.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/report/text_report.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/scheduler/__init__.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/scheduler/scoreboard.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/utils/__init__.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/utils/data_cache.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan/utils/logger.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan.egg-info/dependency_links.txt +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan.egg-info/entry_points.txt +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan.egg-info/requires.txt +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/scriptplan.egg-info/top_level.txt +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/setup.cfg +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/setup.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/tests/test_account.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/tests/test_ansi_color.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/tests/test_attribute_base.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/tests/test_audit_probes.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/tests/test_cli.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/tests/test_core_allocation.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/tests/test_core_booking.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/tests/test_core_project.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/tests/test_core_resource.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/tests/test_core_scenario.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/tests/test_core_task.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/tests/test_journal.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/tests/test_macro_processor.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/tests/test_message_handler.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/tests/test_plan_cli.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/tests/test_project_isolation.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/tests/test_property_list.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/tests/test_property_tree_node.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/tests/test_report.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/tests/test_scoreboard.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/tests/test_shift.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/tests/test_timesheet.py +0 -0
- {scriptplan-0.10.1 → scriptplan-0.10.2}/tests/test_utils_time.py +0 -0
|
@@ -1,5 +1,144 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.10.2
|
|
4
|
+
|
|
5
|
+
0.10.1 shipped two regressions. This release fixes them and the gaps 0.10.1 listed as
|
|
6
|
+
not fixed. It also fixes the defects found while checking every example project
|
|
7
|
+
against answers worked out without the engine, and the thirteen that Trace reported.
|
|
8
|
+
Several plans that 0.10.1 scheduled silently and wrongly are now refused with an error
|
|
9
|
+
that names the task and the date it cannot keep.
|
|
10
|
+
|
|
11
|
+
### Regressions in 0.10.1
|
|
12
|
+
|
|
13
|
+
- An alap `duration` or `length` task before a successor that starts inside a slot
|
|
14
|
+
ended after that successor started. Before a task starting at 16:20, a 1-hour
|
|
15
|
+
duration ran 16:00-17:00. It now runs 15:20-16:20. 0.10.0 put it at 15:00-16:00.
|
|
16
|
+
- Time a task skipped to honour a mid-slot start or end was lost to every other task.
|
|
17
|
+
After an alap task that had to end at 14:30, a task free from 14:00 ran 15:00-16:00
|
|
18
|
+
instead of 14:30-15:30. Before a task declared to start at 09:30, a task free from
|
|
19
|
+
09:00 was pushed to 10:00 instead of using 09:00-09:30.
|
|
20
|
+
|
|
21
|
+
Each booking now holds its own interval of the slot, so time a task skips stays free
|
|
22
|
+
and a task that finishes early frees only what follows it.
|
|
23
|
+
|
|
24
|
+
### Fixed: wrong schedules
|
|
25
|
+
|
|
26
|
+
- A `duration` or `length` task after a task ending mid-slot started at the top of
|
|
27
|
+
that slot, before its predecessor finished. It now starts when the predecessor ends
|
|
28
|
+
and lasts its duration or length to the second.
|
|
29
|
+
- A `duration` waited for working time. After a task ending Friday 17:00 a 2-hour
|
|
30
|
+
duration ran Monday 09:00-11:00, and it now runs Friday 17:00-19:00. An alap 2-hour
|
|
31
|
+
duration that had to end on a Sunday spanned 48 hours, and it now spans 2.
|
|
32
|
+
- A task's finish depended on `timingresolution` when several people shared its last
|
|
33
|
+
slot, because only the first of them worked it. In `tutorial.tjp` the project ended
|
|
34
|
+
at 12:48, 12:00 or 11:44 depending on the slot size alone. All of them now work the
|
|
35
|
+
last slot, and the answer is the same at every resolution.
|
|
36
|
+
- An alap milestone sat a slot before the moment it had to be at. Before a task
|
|
37
|
+
starting at 16:00 it was placed at 15:00. It now sits at 16:00, and one with no
|
|
38
|
+
successor sits at the project end.
|
|
39
|
+
- An alap task did not keep the gap its successor asked for. With `gapduration 24h`
|
|
40
|
+
it ended where the successor began, and now it ends 24 hours earlier.
|
|
41
|
+
- An alap task with an `end` of its own ignored its successors and could end after
|
|
42
|
+
one had started. It now ends by the earlier of the two.
|
|
43
|
+
- An alap task whose successor states its start was moved to the project start, as
|
|
44
|
+
though nothing bounded it. It now ends as late as that start allows.
|
|
45
|
+
- A `start` inherited from a container overrode the task's dependencies. It is now an
|
|
46
|
+
earliest start, and the task waits for what it depends on.
|
|
47
|
+
|
|
48
|
+
### Fixed: silent wrong schedules are now errors
|
|
49
|
+
|
|
50
|
+
Each of these exits non-zero with a message naming the task and both dates:
|
|
51
|
+
|
|
52
|
+
- a task that would start before a task it depends on ends, including when its own
|
|
53
|
+
`start` says so, with or without a gap, and for milestones;
|
|
54
|
+
- a stated `end` that a task scheduled as soon as possible, or its container, cannot
|
|
55
|
+
meet, which 0.10.1 overran by hours;
|
|
56
|
+
- a stated `start` that an alap task cannot keep;
|
|
57
|
+
- a stated start or end outside the project window. A start after the window used to
|
|
58
|
+
crash with "Error parsing project file: list index out of range", and an end after
|
|
59
|
+
it was clamped while the milestone was dated outside the project.
|
|
60
|
+
|
|
61
|
+
An alap task that cannot fit before its deadline now names that deadline. A task
|
|
62
|
+
whose successor failed is reported as blocked by it. 0.10.1 blamed the project window
|
|
63
|
+
for the first, and moved the second to the start of the project, booked after the
|
|
64
|
+
deadline.
|
|
65
|
+
|
|
66
|
+
### Fixed: other
|
|
67
|
+
|
|
68
|
+
- A reference that could mean two tasks with the same id bound whichever came first.
|
|
69
|
+
It is now an error that lists both.
|
|
70
|
+
- `getAllocatedTime()` and timesheet figures credited a shared slot to the last task
|
|
71
|
+
booked in it. 40, 13 and 40 minutes in one hour read as 0, 0 and 2 hours, and now
|
|
72
|
+
read as 0.67, 0.22 and 0.67.
|
|
73
|
+
- Each `ProjectFileParser()` compiled the grammar again (about 0.7 s). The grammar is
|
|
74
|
+
now compiled once per process.
|
|
75
|
+
- The `plan` CLI scheduled every project twice and reported any exception raised
|
|
76
|
+
while scheduling as a parse error. It now schedules each project once and reports
|
|
77
|
+
a scheduling exception as a scheduling error.
|
|
78
|
+
- Projects scheduled in parallel threads shared one message list, one error count
|
|
79
|
+
and one switch that turns error collection on. When one thread finished scheduling,
|
|
80
|
+
another thread's error could raise `TjRuntimeError` out of `schedule()` instead of
|
|
81
|
+
making it return False, and an error in one project could fail another. Each thread
|
|
82
|
+
now has its own messages, error count and switch.
|
|
83
|
+
- An `effort` task with no resource allocated was reported as running outside the
|
|
84
|
+
project window because it "needs more time or more resource availability". It is now
|
|
85
|
+
reported as having effort but no resource to do it.
|
|
86
|
+
- `plan report` printed every engine error as "Error: Error: …". It now prints one
|
|
87
|
+
"Error:".
|
|
88
|
+
|
|
89
|
+
### Documentation
|
|
90
|
+
|
|
91
|
+
- README described `onstart` as one reading for both directions. For a task scheduled
|
|
92
|
+
as soon as possible it is start-to-start. For one scheduled as late as possible it
|
|
93
|
+
means the task must finish before the predecessor starts.
|
|
94
|
+
- README now says that `length` and `gaplength` count the project's working time, how
|
|
95
|
+
an alap task's end is bounded, and that unkept stated dates are errors.
|
|
96
|
+
- README listed `maxgaplength` among the checked constraints. The syntax has never
|
|
97
|
+
accepted it, and the claim is removed.
|
|
98
|
+
|
|
99
|
+
### Schedules that move
|
|
100
|
+
|
|
101
|
+
A plan whose dates all fall on its slot grid, with no alap milestones and no
|
|
102
|
+
`duration` across non-working time, schedules as it did in 0.10.1. Of the 24 example
|
|
103
|
+
projects, 22 schedule identically:
|
|
104
|
+
|
|
105
|
+
- `tutorial.tjp`: `spec` ends 14:20 instead of 15:00 on 24 January because three
|
|
106
|
+
developers finish it together, and every task after it moves with it. The project
|
|
107
|
+
ends on 18 April at 11:44 instead of 12:48.
|
|
108
|
+
- `jit_supply.tjp`: the alap milestone `connection_setup.set_deps` sits at 2025-07-18
|
|
109
|
+
08:00, when `pack` starts, instead of 2025-07-17 16:00.
|
|
110
|
+
|
|
111
|
+
### Internal API
|
|
112
|
+
|
|
113
|
+
`ResourceScenario.reserve()` returns a list of `SlotBooking`, one per free stretch it
|
|
114
|
+
books. The slot ledger is `slotIntervals`, and `slotFrontUsed` and `slotBackUsed` from
|
|
115
|
+
0.10.1 are gone. Failure handling moved to `scriptplan.scheduler.stalls`, and stated
|
|
116
|
+
dates are tracked in `scriptplan.core.declared_dates`. `slotSecondsUsed` is now
|
|
117
|
+
exactly the sum of `slotTaskUsage` for every slot.
|
|
118
|
+
|
|
119
|
+
### Verification
|
|
120
|
+
|
|
121
|
+
The golden snapshots record what the engine produced last time. They catch a change
|
|
122
|
+
but not an error, and 0.10.1 passed all of them. `examples/` now holds an answer for every
|
|
123
|
+
task in the 24 showcase projects and in 24 edge cases, each derived by hand from
|
|
124
|
+
the file and the documented semantics without running ScriptPlan, and compared with an
|
|
125
|
+
hour-level reference scheduler wherever it accepts the file. `tests/test_examples.py`
|
|
126
|
+
runs each project through the `plan` CLI and compares every task to the second. Every
|
|
127
|
+
project passes on 0.10.2, and 13 of the edge cases fail on 0.10.1.
|
|
128
|
+
|
|
129
|
+
`audit/evaluations/probe_placement.py` generates 300 plans that mix effort, duration,
|
|
130
|
+
length and milestones in both directions. It checks that every dependency, stated date
|
|
131
|
+
and span holds, that no slot is overfull, and that no task leaves free time it could
|
|
132
|
+
have used. All 300 pass on 0.10.2, against 28 on 0.10.1 and 14
|
|
133
|
+
on 0.10.0.
|
|
134
|
+
|
|
135
|
+
`tests/test_threads.py` schedules five projects three times each in parallel threads
|
|
136
|
+
and compares every date and message with the same project scheduled alone. It also
|
|
137
|
+
forces one thread to leave error collection while another is still inside it. Its
|
|
138
|
+
three tests fail on the 0.10.1 message handler.
|
|
139
|
+
|
|
140
|
+
The full gate runs on Python 3.9 and 3.13.
|
|
141
|
+
|
|
3
142
|
## 0.10.1
|
|
4
143
|
|
|
5
144
|
Tasks that shared a timing slot on one resource could be booked into time that
|
|
@@ -106,7 +245,7 @@ engine took the largest contribution in each slot rather than the sum, so the
|
|
|
106
245
|
labour of every resource but one was booked, billed and discarded.
|
|
107
246
|
|
|
108
247
|
Effort is now the amount of work to be done, and each allocated resource
|
|
109
|
-
contributes its own time towards it, as
|
|
248
|
+
contributes its own time towards it, as the .tjp format defines it. The same task
|
|
110
249
|
with two resources finishes in half the time and costs what one resource's worth
|
|
111
250
|
of work costs.
|
|
112
251
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: scriptplan
|
|
3
|
-
Version: 0.10.
|
|
3
|
+
Version: 0.10.2
|
|
4
4
|
Summary: A precise project scheduling engine with minute-level accuracy for resource allocation and dependency management.
|
|
5
5
|
Author-email: Farshid Ashouri <farsheed.ashouri@gmail.com>
|
|
6
6
|
Maintainer-email: Farshid Ashouri <farsheed.ashouri@gmail.com>
|
|
@@ -49,12 +49,12 @@ Dynamic: license-file
|
|
|
49
49
|
|
|
50
50
|
# ScriptPlan
|
|
51
51
|
|
|
52
|
-

|
|
53
|
+

|
|
54
54
|

|
|
55
55
|

|
|
56
56
|
|
|
57
|
-
A precise project scheduling engine with minute-level accuracy for resource allocation and dependency management.
|
|
57
|
+
A precise project scheduling engine with minute-level accuracy for resource allocation and dependency management. It reads projects written in the .tjp format.
|
|
58
58
|
|
|
59
59
|
## Installation
|
|
60
60
|
|
|
@@ -131,6 +131,10 @@ for task in project.tasks:
|
|
|
131
131
|
print(f"{task.id}: {start} -> {end}")
|
|
132
132
|
```
|
|
133
133
|
|
|
134
|
+
Projects can be parsed and scheduled in parallel threads. Messages and the error
|
|
135
|
+
count belong to the thread that produced them, so read
|
|
136
|
+
`get_message_handler_instance().messages` in the thread that called `schedule()`.
|
|
137
|
+
|
|
134
138
|
## What is verified
|
|
135
139
|
|
|
136
140
|
Each behaviour below has a probe in `audit/evaluations/` that drives ScriptPlan
|
|
@@ -168,12 +172,22 @@ audit/evaluations/run_all.sh
|
|
|
168
172
|
**Scheduling**
|
|
169
173
|
|
|
170
174
|
- ASAP and ALAP, including chains that mix the two.
|
|
175
|
+
- A task scheduled as late as possible ends by the earliest of its own `end`, the
|
|
176
|
+
start of each successor (less any gap that successor asks for) and the project
|
|
177
|
+
end. With none of these but a successor scheduled as soon as possible that
|
|
178
|
+
states no start, it is scheduled as soon as possible instead, with a warning.
|
|
171
179
|
- Contention is resolved by priority, then criticalness, then declaration order.
|
|
172
180
|
- The declared project period is never rewritten. A task that does not fit is
|
|
173
|
-
reported, with its name and the reason.
|
|
181
|
+
reported, with its name and the reason. A date stated outside the period is an
|
|
182
|
+
error.
|
|
174
183
|
- Scheduling the same project twice produces the same dates and the same bookings.
|
|
175
|
-
-
|
|
176
|
-
|
|
184
|
+
- A stated `start` or `end` that the schedule cannot keep, and a task that would
|
|
185
|
+
start before something it depends on finishes, are errors.
|
|
186
|
+
- `length` and `gaplength` count the project's working time, not a resource's:
|
|
187
|
+
a resource on longer hours does not shorten the gap.
|
|
188
|
+
- `maxgapduration`, `maxstart`, `minstart`, `maxend` and `minend` are checked
|
|
189
|
+
once the schedule is complete, and a violation is an error. (`maxgaplength` is
|
|
190
|
+
not part of the syntax and is refused when parsed.)
|
|
177
191
|
|
|
178
192
|
**Honesty**
|
|
179
193
|
|
|
@@ -191,9 +205,15 @@ audit/evaluations/run_all.sh
|
|
|
191
205
|
rejected at parse time rather than silently producing nothing.
|
|
192
206
|
- Accounts are parsed but not yet modelled, so `chargeset` and `charge` record an
|
|
193
207
|
amount without posting it anywhere.
|
|
194
|
-
-
|
|
195
|
-
|
|
196
|
-
|
|
208
|
+
- A task reference is first looked up from the referring task's scope, one level
|
|
209
|
+
up for each `!`. When that finds nothing but exactly one task in the project has
|
|
210
|
+
that id, the reference binds to it, so `depends !!pack` inside `delivery` finds
|
|
211
|
+
`delivery.pack`. When two tasks could be meant, the file is refused and both are
|
|
212
|
+
named.
|
|
213
|
+
- `onstart` on a dependency means start-to-start for a task scheduled as soon as
|
|
214
|
+
possible: it may start once the predecessor starts. For a task scheduled as
|
|
215
|
+
late as possible it means the task must finish before the predecessor starts,
|
|
216
|
+
which is ScriptPlan's own reading.
|
|
197
217
|
|
|
198
218
|
## Example Project
|
|
199
219
|
|
|
@@ -266,17 +286,12 @@ Apache-2.0
|
|
|
266
286
|
|
|
267
287
|
## Acknowledgments
|
|
268
288
|
|
|
269
|
-
ScriptPlan
|
|
270
|
-
|
|
271
|
-
- The `.tjp` file format is documented publicly and widely used in the project management community
|
|
272
|
-
- All scheduling algorithms, parser, and report generation in ScriptPlan are original implementations
|
|
273
|
-
- TaskJuggler is mentioned only to indicate that ScriptPlan can read the same project file format
|
|
274
|
-
|
|
275
|
-
If you're looking for the original TaskJuggler with its full feature set including interactive HTML reports and GUI tools, please visit [taskjuggler.org](https://taskjuggler.org/).
|
|
289
|
+
ScriptPlan reads the .tjp project file format. It contains no code from any other
|
|
290
|
+
scheduler: the parser, the scheduling algorithms and the reports are its own.
|
|
276
291
|
|
|
277
292
|
## Why ScriptPlan?
|
|
278
293
|
|
|
279
|
-
This scheduler is part of Highway Workflow Engine's worker capacity management system. I decided to open-source it for the community to benefit from its precise scheduling capabilities.
|
|
294
|
+
This scheduler is part of Highway Workflow Engine's worker capacity management system. I decided to open-source it for the community to benefit from its precise scheduling capabilities. Because it reads the established .tjp syntax, users can adopt ScriptPlan without learning a new format.
|
|
280
295
|
|
|
281
296
|
Yours,
|
|
282
297
|
Farshid.
|
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
# ScriptPlan
|
|
6
6
|
|
|
7
|
-

|
|
8
|
+

|
|
9
9
|

|
|
10
10
|

|
|
11
11
|
|
|
12
|
-
A precise project scheduling engine with minute-level accuracy for resource allocation and dependency management.
|
|
12
|
+
A precise project scheduling engine with minute-level accuracy for resource allocation and dependency management. It reads projects written in the .tjp format.
|
|
13
13
|
|
|
14
14
|
## Installation
|
|
15
15
|
|
|
@@ -86,6 +86,10 @@ for task in project.tasks:
|
|
|
86
86
|
print(f"{task.id}: {start} -> {end}")
|
|
87
87
|
```
|
|
88
88
|
|
|
89
|
+
Projects can be parsed and scheduled in parallel threads. Messages and the error
|
|
90
|
+
count belong to the thread that produced them, so read
|
|
91
|
+
`get_message_handler_instance().messages` in the thread that called `schedule()`.
|
|
92
|
+
|
|
89
93
|
## What is verified
|
|
90
94
|
|
|
91
95
|
Each behaviour below has a probe in `audit/evaluations/` that drives ScriptPlan
|
|
@@ -123,12 +127,22 @@ audit/evaluations/run_all.sh
|
|
|
123
127
|
**Scheduling**
|
|
124
128
|
|
|
125
129
|
- ASAP and ALAP, including chains that mix the two.
|
|
130
|
+
- A task scheduled as late as possible ends by the earliest of its own `end`, the
|
|
131
|
+
start of each successor (less any gap that successor asks for) and the project
|
|
132
|
+
end. With none of these but a successor scheduled as soon as possible that
|
|
133
|
+
states no start, it is scheduled as soon as possible instead, with a warning.
|
|
126
134
|
- Contention is resolved by priority, then criticalness, then declaration order.
|
|
127
135
|
- The declared project period is never rewritten. A task that does not fit is
|
|
128
|
-
reported, with its name and the reason.
|
|
136
|
+
reported, with its name and the reason. A date stated outside the period is an
|
|
137
|
+
error.
|
|
129
138
|
- Scheduling the same project twice produces the same dates and the same bookings.
|
|
130
|
-
-
|
|
131
|
-
|
|
139
|
+
- A stated `start` or `end` that the schedule cannot keep, and a task that would
|
|
140
|
+
start before something it depends on finishes, are errors.
|
|
141
|
+
- `length` and `gaplength` count the project's working time, not a resource's:
|
|
142
|
+
a resource on longer hours does not shorten the gap.
|
|
143
|
+
- `maxgapduration`, `maxstart`, `minstart`, `maxend` and `minend` are checked
|
|
144
|
+
once the schedule is complete, and a violation is an error. (`maxgaplength` is
|
|
145
|
+
not part of the syntax and is refused when parsed.)
|
|
132
146
|
|
|
133
147
|
**Honesty**
|
|
134
148
|
|
|
@@ -146,9 +160,15 @@ audit/evaluations/run_all.sh
|
|
|
146
160
|
rejected at parse time rather than silently producing nothing.
|
|
147
161
|
- Accounts are parsed but not yet modelled, so `chargeset` and `charge` record an
|
|
148
162
|
amount without posting it anywhere.
|
|
149
|
-
-
|
|
150
|
-
|
|
151
|
-
|
|
163
|
+
- A task reference is first looked up from the referring task's scope, one level
|
|
164
|
+
up for each `!`. When that finds nothing but exactly one task in the project has
|
|
165
|
+
that id, the reference binds to it, so `depends !!pack` inside `delivery` finds
|
|
166
|
+
`delivery.pack`. When two tasks could be meant, the file is refused and both are
|
|
167
|
+
named.
|
|
168
|
+
- `onstart` on a dependency means start-to-start for a task scheduled as soon as
|
|
169
|
+
possible: it may start once the predecessor starts. For a task scheduled as
|
|
170
|
+
late as possible it means the task must finish before the predecessor starts,
|
|
171
|
+
which is ScriptPlan's own reading.
|
|
152
172
|
|
|
153
173
|
## Example Project
|
|
154
174
|
|
|
@@ -221,17 +241,12 @@ Apache-2.0
|
|
|
221
241
|
|
|
222
242
|
## Acknowledgments
|
|
223
243
|
|
|
224
|
-
ScriptPlan
|
|
225
|
-
|
|
226
|
-
- The `.tjp` file format is documented publicly and widely used in the project management community
|
|
227
|
-
- All scheduling algorithms, parser, and report generation in ScriptPlan are original implementations
|
|
228
|
-
- TaskJuggler is mentioned only to indicate that ScriptPlan can read the same project file format
|
|
229
|
-
|
|
230
|
-
If you're looking for the original TaskJuggler with its full feature set including interactive HTML reports and GUI tools, please visit [taskjuggler.org](https://taskjuggler.org/).
|
|
244
|
+
ScriptPlan reads the .tjp project file format. It contains no code from any other
|
|
245
|
+
scheduler: the parser, the scheduling algorithms and the reports are its own.
|
|
231
246
|
|
|
232
247
|
## Why ScriptPlan?
|
|
233
248
|
|
|
234
|
-
This scheduler is part of Highway Workflow Engine's worker capacity management system. I decided to open-source it for the community to benefit from its precise scheduling capabilities.
|
|
249
|
+
This scheduler is part of Highway Workflow Engine's worker capacity management system. I decided to open-source it for the community to benefit from its precise scheduling capabilities. Because it reads the established .tjp syntax, users can adopt ScriptPlan without learning a new format.
|
|
235
250
|
|
|
236
251
|
Yours,
|
|
237
252
|
Farshid.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Examples
|
|
2
|
+
|
|
3
|
+
Each project here comes with the answer it should produce.
|
|
4
|
+
|
|
5
|
+
- `showcase/` holds the 24 demonstration projects that `SHOWCASE.md` is built from:
|
|
6
|
+
airport upgrades, a 500-task chain on an irregular shift, time zones, quotas,
|
|
7
|
+
limits, mixed forward and backward plans.
|
|
8
|
+
- `edge_cases/` holds one small project for each scheduling pattern that has gone
|
|
9
|
+
wrong in a release, such as several tasks sharing one hour of one person, a
|
|
10
|
+
backward task before a successor that starts mid-hour, or a declared start inside
|
|
11
|
+
a slot.
|
|
12
|
+
- `simple.tjp` is a minimal starting point.
|
|
13
|
+
|
|
14
|
+
## The answers
|
|
15
|
+
|
|
16
|
+
Next to every project is `<name>.expected.csv`, with the start and end of every task
|
|
17
|
+
in the project's own time zone, to the second, and `<name>.expected.md`, which shows
|
|
18
|
+
how each date was worked out.
|
|
19
|
+
|
|
20
|
+
The answers were derived by hand from the project file and the documented semantics,
|
|
21
|
+
without running ScriptPlan. Where an hour-level reference scheduler accepts the file,
|
|
22
|
+
its result was compared too. Where the two disagree, the reason is recorded: it books
|
|
23
|
+
whole slots, so it can end a task later than ScriptPlan, which places work to the
|
|
24
|
+
minute.
|
|
25
|
+
|
|
26
|
+
In three projects the hand derivation and the engine first disagreed, and the notes
|
|
27
|
+
record how each was settled. In `thermal` and `quota` the project's own header and its
|
|
28
|
+
long-standing test specify the engine's answer. In `jit_supply` the engine moved in
|
|
29
|
+
0.10.2 and two independent sources confirm the new date.
|
|
30
|
+
|
|
31
|
+
## Checking them
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pytest tests/test_examples.py # this checkout
|
|
35
|
+
SCRIPTPLAN_EXAMPLES_PYTHON=/path/to/venv/bin/python \
|
|
36
|
+
pytest tests/test_examples.py # an installed release
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Each project runs through the `plan` CLI in a fresh process, and every task is
|
|
40
|
+
compared with its answer. These answers are not the golden snapshots in
|
|
41
|
+
`tests/golden/`. A snapshot records what the engine produced last time and catches a
|
|
42
|
+
change; these files record what it should produce and catch an error.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# alap_before_declared_start
|
|
2
|
+
|
|
3
|
+
x is declared to start at 14:30 and depends on d, l and e, which are alap with no end of their own.
|
|
4
|
+
x's stated start is a fixed moment, so each ends as late as it can before it: d and l 12:30-14:30, and e on
|
|
5
|
+
the desk 14:00-14:30. x then starts at its declared 14:30 and runs to 15:30. 0.10.1 degraded d, l and e
|
|
6
|
+
to asap and put them at the project start (issuedb #14).
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
project p "alap_before_declared_start" 2026-10-19 +2w {
|
|
2
|
+
timingresolution 60min
|
|
3
|
+
}
|
|
4
|
+
resource r0 "Desk" { workinghours mon - fri 9:00 - 17:00 }
|
|
5
|
+
task d "D" { scheduling alap duration 2h }
|
|
6
|
+
task l "L" { scheduling alap length 2h }
|
|
7
|
+
task e "E" { scheduling alap effort 30min allocate r0 }
|
|
8
|
+
task x "X" { depends d, l, e start 2026-10-19-14:30 effort 60min allocate r0 }
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# alap_bounded_by_declared_starts
|
|
2
|
+
|
|
3
|
+
x and y are declared to start at 14:00 and 14:30; x holds the desk until 15:00, so y runs 15:00-16:00.
|
|
4
|
+
The alap milestones m and n precede them and are bounded by the starts the file states: m at 14:00, n at
|
|
5
|
+
14:30. Scheduling twice gives the same answer because the bound is the stated start, not a start a
|
|
6
|
+
previous run wrote back.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
project p "alap_bounded_by_declared_starts" 2026-10-19 +2w {
|
|
2
|
+
timingresolution 60min
|
|
3
|
+
}
|
|
4
|
+
resource r0 "Desk" { workinghours mon - fri 9:00 - 17:00 }
|
|
5
|
+
task x "X" { start 2026-10-19-14:00 effort 60min allocate r0 }
|
|
6
|
+
task y "Y" { start 2026-10-19-14:30 effort 60min allocate r0 }
|
|
7
|
+
task m "M" { scheduling alap precedes x }
|
|
8
|
+
task n "N" { scheduling alap precedes y }
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# alap_gapduration_before_successor
|
|
2
|
+
|
|
3
|
+
Everything is alap and g must end Fri 17:30, so m sits there. b's 480 minutes end at m: Friday allows
|
|
4
|
+
450 of them (10:00-17:30) under the daily cap and Thursday the last 30 (17:00-17:30). a must end 24 hours
|
|
5
|
+
before b starts, by Wed 17:00, and takes Wed 13:00-17:00. 0.10.1 ignored the gap and ended a where b
|
|
6
|
+
began (trace's defect 1).
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
project d "alap_gapduration_before_successor" 2026-11-02 +4w {
|
|
2
|
+
timingresolution 30min
|
|
3
|
+
scheduling alap
|
|
4
|
+
}
|
|
5
|
+
resource r1 "Analyst" {
|
|
6
|
+
workinghours mon - fri 8:30 - 17:30
|
|
7
|
+
timezone "Europe/London"
|
|
8
|
+
limits { dailymax 450min }
|
|
9
|
+
}
|
|
10
|
+
task g "Group" {
|
|
11
|
+
end 2026-11-06-17:30
|
|
12
|
+
task a "A" { effort 240min allocate r1 }
|
|
13
|
+
task b "B" { effort 480min allocate r1 depends !a { gapduration 1440min } }
|
|
14
|
+
task m "Milestone" { milestone depends !b }
|
|
15
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
id;start;end
|
|
2
|
+
b;2026-10-20-14:00:00;2026-10-20-15:00:00
|
|
3
|
+
a;2026-10-20-13:00:00;2026-10-20-14:00:00
|
|
4
|
+
c;2026-10-20-12:00:00;2026-10-20-13:00:00
|
|
5
|
+
d;2026-10-20-15:00:00;2026-10-20-16:00:00
|
|
6
|
+
e;2026-10-19-15:00:00;2026-10-19-16:00:00
|
|
7
|
+
f;2026-10-20-11:00:00;2026-10-20-12:00:00
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# alap_keeps_successor_gaps
|
|
2
|
+
|
|
3
|
+
Backward tasks end as late as their successors allow, less the gap each successor asks for.
|
|
4
|
+
b holds the desk Tue 14:00-15:00, so a (alap, precedes b) runs 13:00-14:00. d starts Tue 15:00 and wants
|
|
5
|
+
c finished 2 hours (calendar) before it: c ends 13:00 and runs 12:00-13:00. f starts Tue 11:00 and wants
|
|
6
|
+
3 working hours after e: Tue 09:00-11:00 is 2 of them and Mon 16:00-17:00 the third, so e ends Mon 16:00
|
|
7
|
+
and runs 15:00-16:00. Before 0.10.2 these alap tasks were moved to the project start, and once they were
|
|
8
|
+
not, the gap was ignored (issuedb #19).
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
project p "alap_keeps_successor_gaps" 2026-10-19 +2w {
|
|
2
|
+
timingresolution 60min
|
|
3
|
+
}
|
|
4
|
+
resource r0 "Desk" { workinghours mon - fri 9:00 - 17:00 }
|
|
5
|
+
task b "B" { start 2026-10-20-14:00 effort 1h allocate r0 }
|
|
6
|
+
task a "A" { scheduling alap effort 1h allocate r0 precedes b }
|
|
7
|
+
task c "C" { scheduling alap duration 1h }
|
|
8
|
+
task d "D" { start 2026-10-20-15:00 depends c { gapduration 2h } effort 1h allocate r0 }
|
|
9
|
+
task e "E" { scheduling alap duration 1h }
|
|
10
|
+
task f "F" { start 2026-10-20-11:00 depends e { gaplength 3h } duration 1h }
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# alap_milestones_exact
|
|
2
|
+
|
|
3
|
+
t holds the desk 16:00-17:00, so t2 (end 16:30) must run before it: 15:30-16:00. An alap milestone
|
|
4
|
+
sits at the latest moment its successor allows: m at t's start 16:00, m2 at t2's start 15:30. d ends at m,
|
|
5
|
+
16:00, and lasts 2 hours: 14:00. 0.10.1 put m at 15:00 and m2 at 15:00 (issuedb #14).
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
project p "alap_milestones_exact" 2026-10-19 +2w {
|
|
2
|
+
timingresolution 60min
|
|
3
|
+
}
|
|
4
|
+
resource r0 "Desk" { workinghours mon - fri 9:00 - 17:00 }
|
|
5
|
+
task t "T" { scheduling alap effort 60min allocate r0 end 2026-10-19-17:00 }
|
|
6
|
+
task m "M" { scheduling alap precedes t }
|
|
7
|
+
task d "D" { scheduling alap duration 2h precedes m }
|
|
8
|
+
task t2 "T2" { scheduling alap effort 30min allocate r0 end 2026-10-19-16:30 }
|
|
9
|
+
task m2 "M2" { scheduling alap precedes t2 }
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# alap_onstart_reading
|
|
2
|
+
|
|
3
|
+
For a task scheduled as late as possible, `onstart` reads as: it must finish before the predecessor
|
|
4
|
+
starts (README). a is bounded only by g's end: Fri 13:30-17:30. b must end by a's start, Fri 13:30:
|
|
5
|
+
Friday has 210 minutes left under the cap (10:00-13:30) and Thursday gives the other 270 (13:00-17:30).
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
project d "alap_onstart_reading" 2026-11-02 +4w {
|
|
2
|
+
timingresolution 30min
|
|
3
|
+
scheduling alap
|
|
4
|
+
}
|
|
5
|
+
resource r1 "Analyst" {
|
|
6
|
+
workinghours mon - fri 8:30 - 17:30
|
|
7
|
+
timezone "Europe/London"
|
|
8
|
+
limits { dailymax 450min }
|
|
9
|
+
}
|
|
10
|
+
task g "Group" {
|
|
11
|
+
end 2026-11-06-17:30
|
|
12
|
+
task a "A" { effort 240min allocate r1 }
|
|
13
|
+
task b "B" { effort 480min allocate r1 depends !a { onstart } }
|
|
14
|
+
task m "Milestone" { milestone depends !b }
|
|
15
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# alap_own_end_before_successor
|
|
2
|
+
|
|
3
|
+
b runs Thu 17:00-Fri 17:30 as above. a has its own end, Fri 12:00, and must also end before b starts,
|
|
4
|
+
Thu 17:00; the earlier wins. Thursday has 420 minutes left under the cap once b's 30 are booked, so a runs
|
|
5
|
+
13:00-17:00. 0.10.1 ended a at its own end, after b had started (trace's defect 9).
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
project d "alap_own_end_before_successor" 2026-11-02 +4w {
|
|
2
|
+
timingresolution 30min
|
|
3
|
+
scheduling alap
|
|
4
|
+
}
|
|
5
|
+
resource r1 "Analyst" {
|
|
6
|
+
workinghours mon - fri 8:30 - 17:30
|
|
7
|
+
timezone "Europe/London"
|
|
8
|
+
limits { dailymax 450min }
|
|
9
|
+
}
|
|
10
|
+
task g "Group" {
|
|
11
|
+
end 2026-11-06-17:30
|
|
12
|
+
task a "A" { effort 240min allocate r1 end 2026-11-06-12:00 }
|
|
13
|
+
task b "B" { effort 480min allocate r1 depends !a }
|
|
14
|
+
task m "Milestone" { milestone depends !b }
|
|
15
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# alap_project_end_and_declared_end
|
|
2
|
+
|
|
3
|
+
The project runs 2026-10-19 +2w, so it ends 2026-11-02 00:00. An alap milestone with no successor and
|
|
4
|
+
no end of its own sits at the project end. One declared to end at 11:30 sits at 11:30. An alap duration
|
|
5
|
+
of 2 hours declared to end at 11:30 runs 09:30-11:30 (0.10.0: 09:00-11:30; 0.10.1: 10:00-11:30).
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
project p "alap_project_end_and_declared_end" 2026-10-19 +2w {
|
|
2
|
+
timingresolution 60min
|
|
3
|
+
}
|
|
4
|
+
resource r0 "Desk" { workinghours mon - fri 9:00 - 17:00 }
|
|
5
|
+
task m "M" { scheduling alap }
|
|
6
|
+
task mm "MM" { scheduling alap end 2026-10-21-11:30 }
|
|
7
|
+
task d "D" { scheduling alap duration 2h end 2026-10-21-11:30 }
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# alap_spans_before_mid_slot_successor
|
|
2
|
+
|
|
3
|
+
t4 (alap, 40 min, end 17:00) runs 16:20-17:00. Everything that precedes it must end by 16:20:
|
|
4
|
+
the 1-hour duration and length tasks run 15:20-16:20, and the milestone sits at 16:20.
|
|
5
|
+
0.10.1 placed d4 and l4 at 16:00-17:00, ending after t4 began: a regression (issuedb #13).
|