scriptplan 0.9.2__tar.gz → 0.10.0__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.
Files changed (136) hide show
  1. scriptplan-0.10.0/CHANGELOG.md +118 -0
  2. {scriptplan-0.9.2 → scriptplan-0.10.0}/MANIFEST.in +1 -0
  3. {scriptplan-0.9.2/scriptplan.egg-info → scriptplan-0.10.0}/PKG-INFO +68 -39
  4. {scriptplan-0.9.2 → scriptplan-0.10.0}/README.md +66 -37
  5. {scriptplan-0.9.2 → scriptplan-0.10.0}/pyproject.toml +11 -5
  6. {scriptplan-0.9.2 → scriptplan-0.10.0}/scriptplan/__init__.py +4 -1
  7. {scriptplan-0.9.2 → scriptplan-0.10.0}/scriptplan/cli/plan.py +42 -321
  8. scriptplan-0.10.0/scriptplan/cli/plan_files.py +195 -0
  9. scriptplan-0.10.0/scriptplan/cli/plan_help.py +194 -0
  10. scriptplan-0.10.0/scriptplan/core/allocation_plan.py +171 -0
  11. scriptplan-0.10.0/scriptplan/core/attributes.py +464 -0
  12. {scriptplan-0.9.2 → scriptplan-0.10.0}/scriptplan/core/exceptions.py +319 -319
  13. scriptplan-0.10.0/scriptplan/core/limits.py +335 -0
  14. scriptplan-0.10.0/scriptplan/core/project.py +519 -0
  15. scriptplan-0.10.0/scriptplan/core/project_attributes.py +212 -0
  16. scriptplan-0.10.0/scriptplan/core/project_calendar.py +126 -0
  17. scriptplan-0.10.0/scriptplan/core/project_tree.py +256 -0
  18. scriptplan-0.10.0/scriptplan/core/property.py +100 -0
  19. scriptplan-0.10.0/scriptplan/core/property_list.py +358 -0
  20. scriptplan-0.10.0/scriptplan/core/property_set.py +338 -0
  21. scriptplan-0.10.0/scriptplan/core/property_tree_node.py +334 -0
  22. scriptplan-0.10.0/scriptplan/core/resolution.py +95 -0
  23. scriptplan-0.10.0/scriptplan/core/resource_availability.py +187 -0
  24. scriptplan-0.10.0/scriptplan/core/resource_reporting.py +311 -0
  25. scriptplan-0.10.0/scriptplan/core/resource_scenario.py +436 -0
  26. {scriptplan-0.9.2 → scriptplan-0.10.0}/scriptplan/core/scenario_data.py +1 -2
  27. scriptplan-0.10.0/scriptplan/core/task_booking.py +320 -0
  28. scriptplan-0.10.0/scriptplan/core/task_dependencies.py +267 -0
  29. scriptplan-0.10.0/scriptplan/core/task_placement.py +415 -0
  30. scriptplan-0.10.0/scriptplan/core/task_resources.py +335 -0
  31. scriptplan-0.10.0/scriptplan/core/task_scenario.py +424 -0
  32. scriptplan-0.10.0/scriptplan/core/timezones.py +59 -0
  33. scriptplan-0.10.0/scriptplan/core/units.py +190 -0
  34. {scriptplan-0.9.2 → scriptplan-0.10.0}/scriptplan/core/working_hours.py +78 -70
  35. scriptplan-0.10.0/scriptplan/parser/attribute_apply.py +302 -0
  36. scriptplan-0.10.0/scriptplan/parser/model_pieces.py +227 -0
  37. scriptplan-0.10.0/scriptplan/parser/report_builder.py +223 -0
  38. {scriptplan-0.9.2 → scriptplan-0.10.0}/scriptplan/parser/tjp.lark +29 -6
  39. scriptplan-0.10.0/scriptplan/parser/tjp_parser.py +416 -0
  40. scriptplan-0.10.0/scriptplan/parser/transformer_project.py +193 -0
  41. scriptplan-0.10.0/scriptplan/parser/transformer_report.py +285 -0
  42. scriptplan-0.10.0/scriptplan/parser/transformer_resource.py +224 -0
  43. scriptplan-0.10.0/scriptplan/parser/transformer_task.py +339 -0
  44. scriptplan-0.10.0/scriptplan/report/logical_expression.py +392 -0
  45. {scriptplan-0.9.2 → scriptplan-0.10.0}/scriptplan/report/report.py +51 -15
  46. {scriptplan-0.9.2 → scriptplan-0.10.0}/scriptplan/report/report_base.py +27 -6
  47. scriptplan-0.10.0/scriptplan/report/table_cells.py +165 -0
  48. scriptplan-0.10.0/scriptplan/report/table_headers.py +69 -0
  49. {scriptplan-0.9.2 → scriptplan-0.10.0}/scriptplan/report/table_report.py +32 -160
  50. {scriptplan-0.9.2 → scriptplan-0.10.0}/scriptplan/report/task_report.py +4 -7
  51. scriptplan-0.10.0/scriptplan/scheduler/postcheck.py +106 -0
  52. scriptplan-0.10.0/scriptplan/scheduler/preflight.py +121 -0
  53. {scriptplan-0.9.2 → scriptplan-0.10.0}/scriptplan/scheduler/scoreboard.py +1 -47
  54. scriptplan-0.10.0/scriptplan/utils/data_cache.py +9 -0
  55. scriptplan-0.10.0/scriptplan/utils/logger.py +39 -0
  56. {scriptplan-0.9.2 → scriptplan-0.10.0}/scriptplan/utils/message_handler.py +103 -231
  57. scriptplan-0.10.0/scriptplan/utils/messages.py +192 -0
  58. {scriptplan-0.9.2 → scriptplan-0.10.0/scriptplan.egg-info}/PKG-INFO +68 -39
  59. {scriptplan-0.9.2 → scriptplan-0.10.0}/scriptplan.egg-info/SOURCES.txt +38 -10
  60. {scriptplan-0.9.2 → scriptplan-0.10.0}/scriptplan.egg-info/requires.txt +0 -1
  61. scriptplan-0.10.0/setup.py +17 -0
  62. scriptplan-0.10.0/tests/test_ansi_color.py +24 -0
  63. scriptplan-0.10.0/tests/test_audit_probes.py +78 -0
  64. {scriptplan-0.9.2 → scriptplan-0.10.0}/tests/test_core_resource.py +1 -1
  65. scriptplan-0.10.0/tests/test_fixture_golden.py +63 -0
  66. scriptplan-0.10.0/tests/test_plan_cli.py +139 -0
  67. scriptplan-0.10.0/tests/test_project_isolation.py +89 -0
  68. {scriptplan-0.9.2 → scriptplan-0.10.0}/tests/test_property_set.py +4 -2
  69. {scriptplan-0.9.2 → scriptplan-0.10.0}/tests/test_report.py +2 -2
  70. {scriptplan-0.9.2 → scriptplan-0.10.0}/tests/test_scheduling.py +3 -3
  71. {scriptplan-0.9.2 → scriptplan-0.10.0}/tests/test_scheduling_validation.py +130 -210
  72. scriptplan-0.9.2/scriptplan/_cython/__init__.py +0 -45
  73. scriptplan-0.9.2/scriptplan/_cython/scoreboard_cy.c +0 -11547
  74. scriptplan-0.9.2/scriptplan/_cython/scoreboard_cy.pyx +0 -174
  75. scriptplan-0.9.2/scriptplan/_cython/time_utils_cy.c +0 -11618
  76. scriptplan-0.9.2/scriptplan/_cython/time_utils_cy.pyx +0 -149
  77. scriptplan-0.9.2/scriptplan/_cython/working_hours_cy.c +0 -11742
  78. scriptplan-0.9.2/scriptplan/_cython/working_hours_cy.pyx +0 -150
  79. scriptplan-0.9.2/scriptplan/core/limits.py +0 -369
  80. scriptplan-0.9.2/scriptplan/core/project.py +0 -948
  81. scriptplan-0.9.2/scriptplan/core/property.py +0 -1323
  82. scriptplan-0.9.2/scriptplan/core/resource_scenario.py +0 -719
  83. scriptplan-0.9.2/scriptplan/core/task_scenario.py +0 -1590
  84. scriptplan-0.9.2/scriptplan/parser/tjp_parser.py +0 -1845
  85. scriptplan-0.9.2/scriptplan/scheduler/batch_processor.py +0 -233
  86. scriptplan-0.9.2/scriptplan/utils/data_cache.py +0 -50
  87. scriptplan-0.9.2/scriptplan/utils/logger.py +0 -246
  88. scriptplan-0.9.2/setup.py +0 -66
  89. scriptplan-0.9.2/tests/test_batch_processor.py +0 -118
  90. scriptplan-0.9.2/tests/test_logger.py +0 -148
  91. {scriptplan-0.9.2 → scriptplan-0.10.0}/LICENSE +0 -0
  92. {scriptplan-0.9.2 → scriptplan-0.10.0}/scriptplan/cli/__init__.py +0 -0
  93. {scriptplan-0.9.2 → scriptplan-0.10.0}/scriptplan/cli/main.py +0 -0
  94. {scriptplan-0.9.2 → scriptplan-0.10.0}/scriptplan/core/__init__.py +0 -0
  95. {scriptplan-0.9.2 → scriptplan-0.10.0}/scriptplan/core/account.py +0 -0
  96. {scriptplan-0.9.2 → scriptplan-0.10.0}/scriptplan/core/allocation.py +0 -0
  97. {scriptplan-0.9.2 → scriptplan-0.10.0}/scriptplan/core/booking.py +0 -0
  98. {scriptplan-0.9.2 → scriptplan-0.10.0}/scriptplan/core/journal.py +0 -0
  99. {scriptplan-0.9.2 → scriptplan-0.10.0}/scriptplan/core/leave.py +0 -0
  100. {scriptplan-0.9.2 → scriptplan-0.10.0}/scriptplan/core/resource.py +0 -0
  101. {scriptplan-0.9.2 → scriptplan-0.10.0}/scriptplan/core/scenario.py +0 -0
  102. {scriptplan-0.9.2 → scriptplan-0.10.0}/scriptplan/core/shift.py +0 -0
  103. {scriptplan-0.9.2 → scriptplan-0.10.0}/scriptplan/core/task.py +0 -0
  104. {scriptplan-0.9.2 → scriptplan-0.10.0}/scriptplan/core/timesheet.py +0 -0
  105. {scriptplan-0.9.2 → scriptplan-0.10.0}/scriptplan/parser/__init__.py +0 -0
  106. {scriptplan-0.9.2 → scriptplan-0.10.0}/scriptplan/parser/macro_processor.py +0 -0
  107. {scriptplan-0.9.2 → scriptplan-0.10.0}/scriptplan/py.typed +0 -0
  108. {scriptplan-0.9.2 → scriptplan-0.10.0}/scriptplan/report/__init__.py +0 -0
  109. {scriptplan-0.9.2 → scriptplan-0.10.0}/scriptplan/report/report_context.py +0 -0
  110. {scriptplan-0.9.2 → scriptplan-0.10.0}/scriptplan/report/resource_report.py +0 -0
  111. {scriptplan-0.9.2 → scriptplan-0.10.0}/scriptplan/report/text_report.py +0 -0
  112. {scriptplan-0.9.2 → scriptplan-0.10.0}/scriptplan/scheduler/__init__.py +0 -0
  113. {scriptplan-0.9.2 → scriptplan-0.10.0}/scriptplan/utils/__init__.py +0 -0
  114. {scriptplan-0.9.2 → scriptplan-0.10.0}/scriptplan/utils/time.py +0 -0
  115. {scriptplan-0.9.2 → scriptplan-0.10.0}/scriptplan.egg-info/dependency_links.txt +0 -0
  116. {scriptplan-0.9.2 → scriptplan-0.10.0}/scriptplan.egg-info/entry_points.txt +0 -0
  117. {scriptplan-0.9.2 → scriptplan-0.10.0}/scriptplan.egg-info/top_level.txt +0 -0
  118. {scriptplan-0.9.2 → scriptplan-0.10.0}/setup.cfg +0 -0
  119. {scriptplan-0.9.2 → scriptplan-0.10.0}/tests/test_account.py +0 -0
  120. {scriptplan-0.9.2 → scriptplan-0.10.0}/tests/test_attribute_base.py +0 -0
  121. {scriptplan-0.9.2 → scriptplan-0.10.0}/tests/test_cli.py +0 -0
  122. {scriptplan-0.9.2 → scriptplan-0.10.0}/tests/test_core_allocation.py +0 -0
  123. {scriptplan-0.9.2 → scriptplan-0.10.0}/tests/test_core_booking.py +0 -0
  124. {scriptplan-0.9.2 → scriptplan-0.10.0}/tests/test_core_project.py +0 -0
  125. {scriptplan-0.9.2 → scriptplan-0.10.0}/tests/test_core_scenario.py +0 -0
  126. {scriptplan-0.9.2 → scriptplan-0.10.0}/tests/test_core_task.py +0 -0
  127. {scriptplan-0.9.2 → scriptplan-0.10.0}/tests/test_journal.py +0 -0
  128. {scriptplan-0.9.2 → scriptplan-0.10.0}/tests/test_macro_processor.py +0 -0
  129. {scriptplan-0.9.2 → scriptplan-0.10.0}/tests/test_message_handler.py +0 -0
  130. {scriptplan-0.9.2 → scriptplan-0.10.0}/tests/test_parser.py +0 -0
  131. {scriptplan-0.9.2 → scriptplan-0.10.0}/tests/test_property_list.py +0 -0
  132. {scriptplan-0.9.2 → scriptplan-0.10.0}/tests/test_property_tree_node.py +0 -0
  133. {scriptplan-0.9.2 → scriptplan-0.10.0}/tests/test_scoreboard.py +0 -0
  134. {scriptplan-0.9.2 → scriptplan-0.10.0}/tests/test_shift.py +0 -0
  135. {scriptplan-0.9.2 → scriptplan-0.10.0}/tests/test_timesheet.py +0 -0
  136. {scriptplan-0.9.2 → scriptplan-0.10.0}/tests/test_utils_time.py +0 -0
@@ -0,0 +1,118 @@
1
+ # Changelog
2
+
3
+ ## 0.10.0
4
+
5
+ A readiness audit of 0.9.2 turned every documented claim into a probe that
6
+ drives ScriptPlan through its own API or CLI. 32 of those probes failed. This
7
+ release is what it took to make them pass, and it changes scheduling results.
8
+
9
+ ### Breaking: `effort` is person-time
10
+
11
+ `effort 16h allocate a, b` used to occupy both resources for sixteen hours and
12
+ credit sixteen hours of work. Two resources booked thirty-two hours, four booked
13
+ sixty-four, and the completion date never moved however many were assigned. The
14
+ engine took the largest contribution in each slot rather than the sum, so the
15
+ labour of every resource but one was booked, billed and discarded.
16
+
17
+ Effort is now the amount of work to be done, and each allocated resource
18
+ contributes its own time towards it, as TaskJuggler defines it. The same task
19
+ with two resources finishes in half the time and costs what one resource's worth
20
+ of work costs.
21
+
22
+ **Upgrading.** A task whose allocations were meant to work side by side is
23
+ written with `mandatory` and its effort in person-hours:
24
+
25
+ ```
26
+ # before 0.10.0: four hours of a pair working together
27
+ task deploy "Deploy" { effort 4h allocate dev, qa }
28
+
29
+ # 0.10.0 and after
30
+ task deploy "Deploy" { effort 8h allocate dev { mandatory }, qa { mandatory } }
31
+ ```
32
+
33
+ Tasks with a single allocation are unaffected. Of the 24 example projects, 21
34
+ schedule identically to 0.9.2; the three that differ are those that allocate
35
+ more than one resource to a task.
36
+
37
+ ### Breaking: failures are reported as failures
38
+
39
+ `Project.schedule()` always returned `True`, and the CLI exited 0 with empty
40
+ start and end cells. A circular dependency, an effort task with no allocation,
41
+ or a task that did not fit the project window produced a warning nobody saw.
42
+
43
+ Scheduling now returns the real result and names each failing task and why; the
44
+ CLIs exit non-zero. A dependency cycle is rejected before scheduling, naming the
45
+ cycle. An attribute or reference the parser cannot place is an error rather than
46
+ a silent drop, which is how `duration`, `length`, `complete` and `note` reached
47
+ the model for the first time.
48
+
49
+ ### Breaking: the declared project period is honoured
50
+
51
+ The project end was grown by a heuristic before scheduling. It is now taken as
52
+ written, and a task that does not fit is reported. Projects that relied on the
53
+ extension need their period stated honestly.
54
+
55
+ ### Breaking: unimplemented report formats are rejected
56
+
57
+ `ical`, `tjp`, `niku`, `ctags` and MS Project XML were accepted, wrote no file,
58
+ and left the CLI blaming a scheduling problem that did not exist. They now raise
59
+ at parse time. Use `json` or `csv`.
60
+
61
+ ### Fixed
62
+
63
+ - Durations follow one table: `m` is months and `min` is minutes everywhere;
64
+ `duration` and `gapduration` are calendar time, `effort`, `length` and
65
+ `gaplength` working time derived from `dailyworkinghours` and
66
+ `yearlyworkingdays`. `gapduration 2d` was 16 hours; `gaplength 30min` was no
67
+ gap at all; `limits { dailymax 30min }` was a 4800-hour cap.
68
+ - Limits count seconds in the resource's own calendar and admit part of a slot,
69
+ so `dailymax 6.4h` is exact. A resource in Los Angeles capped at four hours a
70
+ day was working five in one of its own days. `dailymin`, `weeklymin`,
71
+ `monthlymax`, `monthlymin`, `maximum` and `minimum` reach the grammar, as do
72
+ `maxend`, `maxstart`, `minend` and `minstart`, and violations are reported.
73
+ - Dates are read in the project's timezone and scheduled in UTC; reports convert
74
+ back. The default working day was compared against the hour of a UTC slot,
75
+ putting a New York project five hours out.
76
+ - Slot size is derived from the times a project uses, so `start 09:30` and a
77
+ shift of `08:13 - 11:59` are exact without setting `timingresolution`. That
78
+ shift was credited with seven hours a day instead of eight and a half.
79
+ - A working-hours interval crossing midnight applies to the following day.
80
+ `fri 22:00 - 06:00` marked Friday morning instead of Saturday.
81
+ - Chains mixing ASAP and ALAP schedule instead of deadlocking.
82
+ - Scheduling twice gives the same dates and the same bookings. The second run
83
+ kept the dates and discarded every booking.
84
+ - Reports honour their own `sorttasks`, `hidetask`, column options and formats,
85
+ and `plan report` renders the reports a project declares rather than
86
+ substituting a three-column one. Descending sort was a no-op, and any filter
87
+ hid every row.
88
+ - `report_id` is a SHA-256 of the rendered result. It hashed the input file, so
89
+ a correct and a broken schedule of the same input shared an id.
90
+ - `mandatory`, `persistent` and per-resource allocation options work; they
91
+ parsed to nothing.
92
+
93
+ ### Removed
94
+
95
+ - The Cython extensions. Under `cdivision` the compiled path computed
96
+ `(0 - 1) % 7` as `-1`, so a resource with a Sunday night shift lost its Monday
97
+ morning in every published wheel and kept it in every source checkout: the
98
+ same file, two schedules, and no test covering the compiled one. The wheel is
99
+ now pure Python and cannot diverge from its source.
100
+ - `scheduler.batch_processor`, `utils.data_cache.DataCache` and `utils.Log`,
101
+ none of which were reachable.
102
+
103
+ ### Performance
104
+
105
+ 500 chained tasks at minute resolution schedule in 3.3s, from 14.4s. A year at
106
+ minute resolution with ten resources takes about 13s, from 58.7s.
107
+
108
+ ### Verification
109
+
110
+ `audit/evaluations/` holds 74 probes across 12 files, each named after the
111
+ behaviour it would falsify and each driving ScriptPlan through its own
112
+ interface. `scripts/ci.sh` runs lint, types, a file-size cap, 411 tests, a
113
+ showcase currency check and the probes. The probes also pass against the built
114
+ wheel installed in a clean virtualenv, so what is verified is what ships.
115
+
116
+ ## 0.9.2 and earlier
117
+
118
+ See the git history.
@@ -1,5 +1,6 @@
1
1
  include LICENSE
2
2
  include README.md
3
+ include CHANGELOG.md
3
4
  include pyproject.toml
4
5
  recursive-include scriptplan *.lark
5
6
  recursive-include scriptplan py.typed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: scriptplan
3
- Version: 0.9.2
3
+ Version: 0.10.0
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>
@@ -9,6 +9,7 @@ Project-URL: Homepage, https://github.com/rodmena-limited/scriptplan
9
9
  Project-URL: Documentation, https://github.com/rodmena-limited/scriptplan#readme
10
10
  Project-URL: Bug Tracker, https://github.com/rodmena-limited/scriptplan/issues
11
11
  Project-URL: Source, https://github.com/rodmena-limited/scriptplan
12
+ Project-URL: Changelog, https://github.com/rodmena-limited/scriptplan/blob/main/CHANGELOG.md
12
13
  Keywords: scheduling,project-management,resource-allocation,gantt,critical-path
13
14
  Classifier: Development Status :: 4 - Beta
14
15
  Classifier: Intended Audience :: Developers
@@ -40,7 +41,6 @@ Requires-Dist: build; extra == "dev"
40
41
  Requires-Dist: twine; extra == "dev"
41
42
  Requires-Dist: ruff>=0.1.0; extra == "dev"
42
43
  Requires-Dist: mypy>=1.0.0; extra == "dev"
43
- Requires-Dist: cython>=3.0.0; extra == "dev"
44
44
  Dynamic: license-file
45
45
 
46
46
  <p align="center">
@@ -49,11 +49,10 @@ Dynamic: license-file
49
49
 
50
50
  # ScriptPlan
51
51
 
52
- ![Logic Certified](https://img.shields.io/badge/Logic-Certified_Airport--Grade-success?style=for-the-badge&logo=github)
53
- ![Tests Passed](https://img.shields.io/badge/Stress_Tests-24%2F24_Passed-success?style=for-the-badge)
54
- ![Temporal Physics](https://img.shields.io/badge/Temporal_Physics-Verified-blue?style=for-the-badge)
55
- ![Scheduling](https://img.shields.io/badge/Scheduling-ALAP_%7C_JIT_%7C_Priority-blueviolet?style=for-the-badge)
56
- ![Constraints](https://img.shields.io/badge/Constraints-Hard_Limits_%7C_Quotas-orange?style=for-the-badge)
52
+ ![Tests](https://img.shields.io/badge/tests-411_passing-success?style=for-the-badge)
53
+ ![Probes](https://img.shields.io/badge/audit_probes-67_passing-success?style=for-the-badge)
54
+ ![Python](https://img.shields.io/badge/python-3.9%2B-blue?style=for-the-badge)
55
+ ![Licence](https://img.shields.io/badge/licence-Apache--2.0-lightgrey?style=for-the-badge)
57
56
 
58
57
  A precise project scheduling engine with minute-level accuracy for resource allocation and dependency management. The syntax is compatible with TaskJuggler (.tjp files).
59
58
 
@@ -110,11 +109,11 @@ done
110
109
  **Features**:
111
110
  - Output to stdout (Unix philosophy)
112
111
  - Messages to stderr
113
- - SHA256 report_id (content-based hash)
112
+ - SHA256 `report_id` over the rendered result, so it changes when the schedule does
114
113
  - Lowercase column names
115
114
  - No HTML metadata
116
115
  - No file pollution (uses temp directories)
117
- - Safe for concurrent execution (100+ instances)
116
+ - Separate processes do not collide: temporary files and directories are unique per run
118
117
 
119
118
  ### Python API
120
119
 
@@ -132,39 +131,69 @@ for task in project.tasks:
132
131
  print(f"{task.id}: {start} -> {end}")
133
132
  ```
134
133
 
135
- ## System Certified
134
+ ## What is verified
136
135
 
137
- **Certification Level**: Airport-Grade / Mission Critical
136
+ Each behaviour below has a probe in `audit/evaluations/` that drives ScriptPlan
137
+ through its own API or CLI and asserts the result. They run as part of the test
138
+ suite, and can be run on their own against an installed release:
138
139
 
139
- **Capabilities Verified**:
140
-
141
- - **Temporal Physics**: Floating point precision, Timezones, DST awareness, Date Line crossing.
142
-
143
- - **Resource Constraints**: Daily/Weekly limits, Hierarchical quotas, Shift intersections.
144
-
145
- - **Advanced Scheduling**: ALAP (Backward pass), Priority preemption, Smart Resource Selection (Failover).
146
-
147
- - **Workflow Logic**: Atomicity (Contiguous), Perishability (Max Gap), Zero-Buffer Synchronization.
148
-
149
- ## Features
150
-
151
- - Minute-level scheduling precision
152
- - ASAP and ALAP scheduling modes
153
- - Resource allocation with contention handling
154
- - Working hours and shift definitions
155
- - Dependency chains with gap constraints
156
- - Leap year and timezone handling
157
-
158
- ## Accuracy
159
-
160
- ScriptPlan uses integer arithmetic for all time calculations, avoiding floating-point drift. The scheduler correctly handles:
161
-
162
- - Non-standard shift boundaries (e.g., 08:13 - 11:59, 13:07 - 17:47)
163
- - Prime-number effort durations with prime-number gaps
164
- - Resource contention across multi-day tasks
165
- - Calendar gaps (weekends, holidays) vs working time gaps
140
+ ```bash
141
+ audit/evaluations/run_all.sh
142
+ ```
166
143
 
167
- Example: A chain of 500 tasks, each with 73-minute effort and 29-minute gaps, scheduled across leap year boundaries with non-standard shifts, produces exact minute-aligned results.
144
+ **Time**
145
+
146
+ - Dates are read in the project's timezone and scheduled in UTC; reports convert back.
147
+ - Resource shifts follow their own timezone across daylight-saving changes in both directions.
148
+ - A working-hours interval that crosses midnight applies to the following day.
149
+ - Slot size is derived from the times a project uses, so `start 09:30` is honoured
150
+ exactly and a shift of `08:13 - 11:59, 13:07 - 17:47` yields its true 8h26m a day.
151
+ `timingresolution` overrides this.
152
+
153
+ **Units**
154
+
155
+ - Calendar time (`duration`, `gapduration`) and working time (`effort`, `length`,
156
+ `gaplength`) are distinguished, with working time derived from
157
+ `dailyworkinghours` and `yearlyworkingdays`. `m` means months; `min` means minutes.
158
+
159
+ **Resources**
160
+
161
+ - `effort` is person-time: two resources available in a slot contribute two
162
+ slots of it. `mandatory` requires a resource for the task to progress at all;
163
+ `persistent` keeps the one first chosen; `alternative` falls back.
164
+ - `dailymax`, `weeklymax`, `monthlymax`, `maximum` and their `min` counterparts
165
+ block at the cap **and** release in the next period. Periods are counted in the
166
+ resource's own calendar, and a cap smaller than one slot is honoured exactly.
167
+
168
+ **Scheduling**
169
+
170
+ - ASAP and ALAP, including chains that mix the two.
171
+ - Contention is resolved by priority, then criticalness, then declaration order.
172
+ - The declared project period is never rewritten. A task that does not fit is
173
+ reported, with its name and the reason.
174
+ - Scheduling the same project twice produces the same dates and the same bookings.
175
+ - `maxgapduration`, `maxgaplength`, `maxstart`, `minstart`, `maxend` and `minend`
176
+ are checked once the schedule is complete, and a violation is an error.
177
+
178
+ **Honesty**
179
+
180
+ - A project that cannot be scheduled exits non-zero and says why. A dependency
181
+ cycle is rejected before scheduling, naming the cycle.
182
+ - An attribute or reference the parser cannot place is an error, never a silent
183
+ drop.
184
+ - `report_id` is a SHA-256 of the rendered result, so it differs when the
185
+ schedule differs.
186
+
187
+ ## Known limits
188
+
189
+ - `include`, `supplement`, `leaveallowance` and `statussheet` are not implemented.
190
+ - Output formats are JSON and CSV. `ical`, `tjp`, `niku` and MS Project XML are
191
+ rejected at parse time rather than silently producing nothing.
192
+ - Accounts are parsed but not yet modelled, so `chargeset` and `charge` record an
193
+ amount without posting it anywhere.
194
+ - `onstart` dependencies are read as "the dependent task must finish before the
195
+ predecessor starts", which is ScriptPlan's own reading rather than
196
+ TaskJuggler's start-to-start one.
168
197
 
169
198
  ## Example Project
170
199
 
@@ -4,11 +4,10 @@
4
4
 
5
5
  # ScriptPlan
6
6
 
7
- ![Logic Certified](https://img.shields.io/badge/Logic-Certified_Airport--Grade-success?style=for-the-badge&logo=github)
8
- ![Tests Passed](https://img.shields.io/badge/Stress_Tests-24%2F24_Passed-success?style=for-the-badge)
9
- ![Temporal Physics](https://img.shields.io/badge/Temporal_Physics-Verified-blue?style=for-the-badge)
10
- ![Scheduling](https://img.shields.io/badge/Scheduling-ALAP_%7C_JIT_%7C_Priority-blueviolet?style=for-the-badge)
11
- ![Constraints](https://img.shields.io/badge/Constraints-Hard_Limits_%7C_Quotas-orange?style=for-the-badge)
7
+ ![Tests](https://img.shields.io/badge/tests-411_passing-success?style=for-the-badge)
8
+ ![Probes](https://img.shields.io/badge/audit_probes-67_passing-success?style=for-the-badge)
9
+ ![Python](https://img.shields.io/badge/python-3.9%2B-blue?style=for-the-badge)
10
+ ![Licence](https://img.shields.io/badge/licence-Apache--2.0-lightgrey?style=for-the-badge)
12
11
 
13
12
  A precise project scheduling engine with minute-level accuracy for resource allocation and dependency management. The syntax is compatible with TaskJuggler (.tjp files).
14
13
 
@@ -65,11 +64,11 @@ done
65
64
  **Features**:
66
65
  - Output to stdout (Unix philosophy)
67
66
  - Messages to stderr
68
- - SHA256 report_id (content-based hash)
67
+ - SHA256 `report_id` over the rendered result, so it changes when the schedule does
69
68
  - Lowercase column names
70
69
  - No HTML metadata
71
70
  - No file pollution (uses temp directories)
72
- - Safe for concurrent execution (100+ instances)
71
+ - Separate processes do not collide: temporary files and directories are unique per run
73
72
 
74
73
  ### Python API
75
74
 
@@ -87,39 +86,69 @@ for task in project.tasks:
87
86
  print(f"{task.id}: {start} -> {end}")
88
87
  ```
89
88
 
90
- ## System Certified
89
+ ## What is verified
91
90
 
92
- **Certification Level**: Airport-Grade / Mission Critical
91
+ Each behaviour below has a probe in `audit/evaluations/` that drives ScriptPlan
92
+ through its own API or CLI and asserts the result. They run as part of the test
93
+ suite, and can be run on their own against an installed release:
93
94
 
94
- **Capabilities Verified**:
95
-
96
- - **Temporal Physics**: Floating point precision, Timezones, DST awareness, Date Line crossing.
97
-
98
- - **Resource Constraints**: Daily/Weekly limits, Hierarchical quotas, Shift intersections.
99
-
100
- - **Advanced Scheduling**: ALAP (Backward pass), Priority preemption, Smart Resource Selection (Failover).
101
-
102
- - **Workflow Logic**: Atomicity (Contiguous), Perishability (Max Gap), Zero-Buffer Synchronization.
103
-
104
- ## Features
105
-
106
- - Minute-level scheduling precision
107
- - ASAP and ALAP scheduling modes
108
- - Resource allocation with contention handling
109
- - Working hours and shift definitions
110
- - Dependency chains with gap constraints
111
- - Leap year and timezone handling
112
-
113
- ## Accuracy
114
-
115
- ScriptPlan uses integer arithmetic for all time calculations, avoiding floating-point drift. The scheduler correctly handles:
116
-
117
- - Non-standard shift boundaries (e.g., 08:13 - 11:59, 13:07 - 17:47)
118
- - Prime-number effort durations with prime-number gaps
119
- - Resource contention across multi-day tasks
120
- - Calendar gaps (weekends, holidays) vs working time gaps
95
+ ```bash
96
+ audit/evaluations/run_all.sh
97
+ ```
121
98
 
122
- Example: A chain of 500 tasks, each with 73-minute effort and 29-minute gaps, scheduled across leap year boundaries with non-standard shifts, produces exact minute-aligned results.
99
+ **Time**
100
+
101
+ - Dates are read in the project's timezone and scheduled in UTC; reports convert back.
102
+ - Resource shifts follow their own timezone across daylight-saving changes in both directions.
103
+ - A working-hours interval that crosses midnight applies to the following day.
104
+ - Slot size is derived from the times a project uses, so `start 09:30` is honoured
105
+ exactly and a shift of `08:13 - 11:59, 13:07 - 17:47` yields its true 8h26m a day.
106
+ `timingresolution` overrides this.
107
+
108
+ **Units**
109
+
110
+ - Calendar time (`duration`, `gapduration`) and working time (`effort`, `length`,
111
+ `gaplength`) are distinguished, with working time derived from
112
+ `dailyworkinghours` and `yearlyworkingdays`. `m` means months; `min` means minutes.
113
+
114
+ **Resources**
115
+
116
+ - `effort` is person-time: two resources available in a slot contribute two
117
+ slots of it. `mandatory` requires a resource for the task to progress at all;
118
+ `persistent` keeps the one first chosen; `alternative` falls back.
119
+ - `dailymax`, `weeklymax`, `monthlymax`, `maximum` and their `min` counterparts
120
+ block at the cap **and** release in the next period. Periods are counted in the
121
+ resource's own calendar, and a cap smaller than one slot is honoured exactly.
122
+
123
+ **Scheduling**
124
+
125
+ - ASAP and ALAP, including chains that mix the two.
126
+ - Contention is resolved by priority, then criticalness, then declaration order.
127
+ - The declared project period is never rewritten. A task that does not fit is
128
+ reported, with its name and the reason.
129
+ - Scheduling the same project twice produces the same dates and the same bookings.
130
+ - `maxgapduration`, `maxgaplength`, `maxstart`, `minstart`, `maxend` and `minend`
131
+ are checked once the schedule is complete, and a violation is an error.
132
+
133
+ **Honesty**
134
+
135
+ - A project that cannot be scheduled exits non-zero and says why. A dependency
136
+ cycle is rejected before scheduling, naming the cycle.
137
+ - An attribute or reference the parser cannot place is an error, never a silent
138
+ drop.
139
+ - `report_id` is a SHA-256 of the rendered result, so it differs when the
140
+ schedule differs.
141
+
142
+ ## Known limits
143
+
144
+ - `include`, `supplement`, `leaveallowance` and `statussheet` are not implemented.
145
+ - Output formats are JSON and CSV. `ical`, `tjp`, `niku` and MS Project XML are
146
+ rejected at parse time rather than silently producing nothing.
147
+ - Accounts are parsed but not yet modelled, so `chargeset` and `charge` record an
148
+ amount without posting it anywhere.
149
+ - `onstart` dependencies are read as "the dependent task must finish before the
150
+ predecessor starts", which is ScriptPlan's own reading rather than
151
+ TaskJuggler's start-to-start one.
123
152
 
124
153
  ## Example Project
125
154
 
@@ -1,10 +1,11 @@
1
1
  [build-system]
2
- requires = ["setuptools>=61.0", "wheel", "cython>=3.0.0"]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
3
  build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "scriptplan"
7
- version = "0.9.2"
7
+ # Single source of truth: scriptplan/__init__.py
8
+ dynamic = ["version"]
8
9
  description = "A precise project scheduling engine with minute-level accuracy for resource allocation and dependency management."
9
10
  authors = [
10
11
  { name = "Farshid Ashouri", email = "farsheed.ashouri@gmail.com" },
@@ -50,7 +51,6 @@ dev = [
50
51
  "twine",
51
52
  "ruff>=0.1.0",
52
53
  "mypy>=1.0.0",
53
- "cython>=3.0.0",
54
54
  ]
55
55
 
56
56
  [project.scripts]
@@ -62,23 +62,29 @@ plan = "scriptplan.cli.plan:main"
62
62
  "Documentation" = "https://github.com/rodmena-limited/scriptplan#readme"
63
63
  "Bug Tracker" = "https://github.com/rodmena-limited/scriptplan/issues"
64
64
  "Source" = "https://github.com/rodmena-limited/scriptplan"
65
+ "Changelog" = "https://github.com/rodmena-limited/scriptplan/blob/main/CHANGELOG.md"
65
66
 
66
67
  [tool.setuptools]
67
68
  include-package-data = true
68
69
 
70
+ [tool.setuptools.dynamic]
71
+ version = { attr = "scriptplan.__version__" }
72
+
69
73
  [tool.setuptools.packages.find]
70
74
  where = ["."]
71
75
  include = ["scriptplan*"]
72
76
 
73
77
  [tool.setuptools.package-data]
74
- scriptplan = ["py.typed", "parser/*.lark", "_cython/*.pyx"]
78
+ scriptplan = ["py.typed", "parser/*.lark"]
75
79
 
76
80
  [tool.pytest.ini_options]
77
81
  testpaths = ["tests"]
78
82
  python_files = ["test_*.py"]
79
83
  python_classes = ["Test*"]
80
84
  python_functions = ["test_*"]
81
- addopts = "-v --tb=short -n auto"
85
+ # No -n here: pytest-xdist is an optional extra, and requiring it means
86
+ # the suite cannot start without it. Pass -n yourself to parallelise.
87
+ addopts = "--tb=short"
82
88
  filterwarnings = [
83
89
  "ignore::DeprecationWarning",
84
90
  "ignore::PendingDeprecationWarning",
@@ -9,7 +9,10 @@ the pioneering open-source project management tool created by Chris Schlaeger.
9
9
  The TJP file format and scheduling concepts originate from TaskJuggler.
10
10
  """
11
11
 
12
- __version__ = "0.9.2"
12
+ # The single source of truth for the version; pyproject reads it from here.
13
+ # A semantic change: effort is now person-time, failures are reported as
14
+ # failures, and the compiled extensions are gone.
15
+ __version__ = "0.10.0"
13
16
  __author__ = "ScriptPlan Team"
14
17
 
15
18
  from scriptplan.core.project import Project