scriptplan 0.9.0__tar.gz → 0.9.1__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.9.0/scriptplan.egg-info → scriptplan-0.9.1}/PKG-INFO +93 -9
- {scriptplan-0.9.0 → scriptplan-0.9.1}/README.md +82 -4
- {scriptplan-0.9.0 → scriptplan-0.9.1}/pyproject.toml +28 -5
- scriptplan-0.9.1/scriptplan/cli/__init__.py +7 -0
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/cli/main.py +64 -17
- scriptplan-0.9.1/scriptplan/cli/plan.py +678 -0
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/core/account.py +44 -25
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/core/allocation.py +35 -23
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/core/booking.py +23 -13
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/core/journal.py +16 -16
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/core/leave.py +5 -2
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/core/limits.py +55 -33
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/core/project.py +155 -143
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/core/property.py +278 -276
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/core/resource.py +32 -22
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/core/resource_scenario.py +39 -41
- scriptplan-0.9.1/scriptplan/core/scenario.py +11 -0
- scriptplan-0.9.1/scriptplan/core/scenario_data.py +69 -0
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/core/shift.py +30 -15
- scriptplan-0.9.1/scriptplan/core/task.py +86 -0
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/core/task_scenario.py +153 -117
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/core/timesheet.py +59 -45
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/core/working_hours.py +24 -20
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/parser/macro_processor.py +5 -5
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/parser/tjp_parser.py +333 -334
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/report/__init__.py +20 -20
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/report/report.py +27 -122
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/report/report_base.py +45 -45
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/report/report_context.py +6 -7
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/report/resource_report.py +18 -19
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/report/table_report.py +97 -128
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/report/task_report.py +20 -21
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/report/text_report.py +25 -28
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/scheduler/batch_processor.py +51 -29
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/scheduler/scoreboard.py +64 -42
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/utils/data_cache.py +22 -18
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/utils/logger.py +32 -30
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/utils/message_handler.py +65 -45
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/utils/time.py +74 -63
- {scriptplan-0.9.0 → scriptplan-0.9.1/scriptplan.egg-info}/PKG-INFO +93 -9
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan.egg-info/SOURCES.txt +1 -3
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan.egg-info/entry_points.txt +1 -0
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan.egg-info/requires.txt +5 -0
- {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_account.py +2 -1
- {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_attribute_base.py +3 -3
- {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_batch_processor.py +2 -3
- {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_cli.py +3 -9
- {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_core_allocation.py +5 -3
- {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_core_booking.py +8 -6
- {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_core_project.py +4 -2
- {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_core_resource.py +5 -3
- {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_core_scenario.py +6 -4
- {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_core_task.py +7 -5
- {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_journal.py +2 -1
- {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_logger.py +3 -2
- {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_macro_processor.py +1 -0
- {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_message_handler.py +11 -6
- {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_parser.py +4 -2
- {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_property_list.py +2 -1
- {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_property_set.py +7 -6
- {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_property_tree_node.py +7 -6
- {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_report.py +77 -57
- {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_scheduling.py +4 -3
- {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_scheduling_validation.py +28 -20
- {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_scoreboard.py +11 -9
- {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_shift.py +1 -0
- {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_timesheet.py +2 -1
- {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_utils_time.py +7 -5
- scriptplan-0.9.0/scriptplan/cli/__init__.py +0 -7
- scriptplan-0.9.0/scriptplan/core/scenario.py +0 -5
- scriptplan-0.9.0/scriptplan/core/scenario_data.py +0 -39
- scriptplan-0.9.0/scriptplan/core/task.py +0 -77
- scriptplan-0.9.0/scriptplan/report/html_generator.py +0 -477
- scriptplan-0.9.0/tests/test_html_generator.py +0 -268
- scriptplan-0.9.0/tests/test_html_report_integration.py +0 -199
- {scriptplan-0.9.0 → scriptplan-0.9.1}/LICENSE +0 -0
- {scriptplan-0.9.0 → scriptplan-0.9.1}/MANIFEST.in +0 -0
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/__init__.py +3 -3
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/core/__init__.py +0 -0
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/parser/__init__.py +0 -0
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/parser/tjp.lark +0 -0
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/py.typed +0 -0
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/scheduler/__init__.py +0 -0
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/utils/__init__.py +0 -0
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan.egg-info/dependency_links.txt +0 -0
- {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan.egg-info/top_level.txt +0 -0
- {scriptplan-0.9.0 → scriptplan-0.9.1}/setup.cfg +0 -0
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: scriptplan
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.1
|
|
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>
|
|
7
7
|
License-Expression: Apache-2.0
|
|
8
|
-
Project-URL: Homepage, https://github.com/
|
|
9
|
-
Project-URL: Documentation, https://github.com/
|
|
10
|
-
Project-URL: Bug Tracker, https://github.com/
|
|
11
|
-
Project-URL: Source, https://github.com/
|
|
8
|
+
Project-URL: Homepage, https://github.com/rodmena-limited/scriptplan
|
|
9
|
+
Project-URL: Documentation, https://github.com/rodmena-limited/scriptplan#readme
|
|
10
|
+
Project-URL: Bug Tracker, https://github.com/rodmena-limited/scriptplan/issues
|
|
11
|
+
Project-URL: Source, https://github.com/rodmena-limited/scriptplan
|
|
12
12
|
Keywords: scheduling,project-management,resource-allocation,gantt,critical-path
|
|
13
13
|
Classifier: Development Status :: 4 - Beta
|
|
14
14
|
Classifier: Intended Audience :: Developers
|
|
@@ -19,6 +19,7 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.11
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.12
|
|
21
21
|
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
22
23
|
Classifier: Operating System :: OS Independent
|
|
23
24
|
Classifier: Topic :: Office/Business :: Scheduling
|
|
24
25
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
@@ -28,16 +29,31 @@ Description-Content-Type: text/markdown
|
|
|
28
29
|
License-File: LICENSE
|
|
29
30
|
Requires-Dist: lark>=1.0.0
|
|
30
31
|
Requires-Dist: python-dateutil>=2.8.0
|
|
32
|
+
Requires-Dist: click>=8.0.0
|
|
31
33
|
Provides-Extra: dev
|
|
32
34
|
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
33
35
|
Requires-Dist: pytest-xdist>=3.0.0; extra == "dev"
|
|
34
36
|
Requires-Dist: pandas>=1.5.0; extra == "dev"
|
|
37
|
+
Requires-Dist: types-python-dateutil>=2.8.0; extra == "dev"
|
|
38
|
+
Requires-Dist: types-pytz>=2022.1.0; extra == "dev"
|
|
35
39
|
Requires-Dist: build; extra == "dev"
|
|
36
40
|
Requires-Dist: twine; extra == "dev"
|
|
41
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
42
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
37
43
|
Dynamic: license-file
|
|
38
44
|
|
|
45
|
+
<p align="center">
|
|
46
|
+
<img src="https://raw.githubusercontent.com/rodmena-limited/scriptplan/main/icons/logo.svg" alt="ScriptPlan" width="400"/>
|
|
47
|
+
</p>
|
|
48
|
+
|
|
39
49
|
# ScriptPlan
|
|
40
50
|
|
|
51
|
+

|
|
52
|
+

|
|
53
|
+

|
|
54
|
+

|
|
55
|
+

|
|
56
|
+
|
|
41
57
|
A precise project scheduling engine with minute-level accuracy for resource allocation and dependency management. The syntax is compatible with TaskJuggler (.tjp files).
|
|
42
58
|
|
|
43
59
|
## Installation
|
|
@@ -46,15 +62,59 @@ A precise project scheduling engine with minute-level accuracy for resource allo
|
|
|
46
62
|
pip install scriptplan
|
|
47
63
|
```
|
|
48
64
|
|
|
49
|
-
##
|
|
65
|
+
## Quick Start
|
|
50
66
|
|
|
51
|
-
###
|
|
67
|
+
### Report Generation (Unix-style)
|
|
52
68
|
|
|
53
69
|
```bash
|
|
54
|
-
|
|
55
|
-
|
|
70
|
+
# Generate JSON report to stdout
|
|
71
|
+
plan report project.tjp
|
|
72
|
+
|
|
73
|
+
# Generate CSV report
|
|
74
|
+
plan report --csv project.tjp
|
|
75
|
+
|
|
76
|
+
# Save to file
|
|
77
|
+
plan report project.tjp > output.json
|
|
78
|
+
plan report --csv project.tjp > output.csv
|
|
79
|
+
|
|
80
|
+
# Read from stdin
|
|
81
|
+
cat project.tjp | plan report
|
|
82
|
+
plan report - < project.tjp
|
|
83
|
+
|
|
84
|
+
# Pipe to other tools
|
|
85
|
+
plan report project.tjp | jq '.data[0]'
|
|
86
|
+
plan report --csv project.tjp | csvkit
|
|
87
|
+
|
|
88
|
+
# Process multiple files
|
|
89
|
+
for f in projects/*.tjp; do
|
|
90
|
+
plan report "$f" | jq -r '.report_id'
|
|
91
|
+
done
|
|
56
92
|
```
|
|
57
93
|
|
|
94
|
+
**Output Format** (JSON):
|
|
95
|
+
```json
|
|
96
|
+
{
|
|
97
|
+
"data": [
|
|
98
|
+
{
|
|
99
|
+
"id": "project.task1",
|
|
100
|
+
"start": "2024-01-01-09:00",
|
|
101
|
+
"end": "2024-01-05-17:00"
|
|
102
|
+
}
|
|
103
|
+
],
|
|
104
|
+
"columns": ["id", "start", "end"],
|
|
105
|
+
"report_id": "ea3f901dd6426dfa58288d945819c75485fd9ff1875db59def350f219e2d62ca"
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
**Features**:
|
|
110
|
+
- Output to stdout (Unix philosophy)
|
|
111
|
+
- Messages to stderr
|
|
112
|
+
- SHA256 report_id (content-based hash)
|
|
113
|
+
- Lowercase column names
|
|
114
|
+
- No HTML metadata
|
|
115
|
+
- No file pollution (uses temp directories)
|
|
116
|
+
- Safe for concurrent execution (100+ instances)
|
|
117
|
+
|
|
58
118
|
### Python API
|
|
59
119
|
|
|
60
120
|
```python
|
|
@@ -71,6 +131,20 @@ for task in project.tasks:
|
|
|
71
131
|
print(f"{task.id}: {start} -> {end}")
|
|
72
132
|
```
|
|
73
133
|
|
|
134
|
+
## System Certified
|
|
135
|
+
|
|
136
|
+
**Certification Level**: Airport-Grade / Mission Critical
|
|
137
|
+
|
|
138
|
+
**Capabilities Verified**:
|
|
139
|
+
|
|
140
|
+
- **Temporal Physics**: Floating point precision, Timezones, DST awareness, Date Line crossing.
|
|
141
|
+
|
|
142
|
+
- **Resource Constraints**: Daily/Weekly limits, Hierarchical quotas, Shift intersections.
|
|
143
|
+
|
|
144
|
+
- **Advanced Scheduling**: ALAP (Backward pass), Priority preemption, Smart Resource Selection (Failover).
|
|
145
|
+
|
|
146
|
+
- **Workflow Logic**: Atomicity (Contiguous), Perishability (Max Gap), Zero-Buffer Synchronization.
|
|
147
|
+
|
|
74
148
|
## Features
|
|
75
149
|
|
|
76
150
|
- Minute-level scheduling precision
|
|
@@ -159,3 +233,13 @@ delivery.assemble_b: 2025-07-16-08:00 -> 2025-07-17-16:00
|
|
|
159
233
|
## License
|
|
160
234
|
|
|
161
235
|
Apache 2.0
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
## Why?
|
|
239
|
+
This scheduler is part of Highway Workflow Egnine's worker capacity management system.
|
|
240
|
+
I decided to open-source it for the community to benefit from its precise scheduling capabilities.
|
|
241
|
+
Thanks to TaskJuggler's established syntax, users can easily adopt ScriptPlan without learning a new format.
|
|
242
|
+
Credits to TaskJuggler for the original project definition language and concepts.
|
|
243
|
+
|
|
244
|
+
Yours,
|
|
245
|
+
Farshid.
|
|
@@ -1,5 +1,15 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/rodmena-limited/scriptplan/main/icons/logo.svg" alt="ScriptPlan" width="400"/>
|
|
3
|
+
</p>
|
|
4
|
+
|
|
1
5
|
# ScriptPlan
|
|
2
6
|
|
|
7
|
+

|
|
8
|
+

|
|
9
|
+

|
|
10
|
+

|
|
11
|
+

|
|
12
|
+
|
|
3
13
|
A precise project scheduling engine with minute-level accuracy for resource allocation and dependency management. The syntax is compatible with TaskJuggler (.tjp files).
|
|
4
14
|
|
|
5
15
|
## Installation
|
|
@@ -8,15 +18,59 @@ A precise project scheduling engine with minute-level accuracy for resource allo
|
|
|
8
18
|
pip install scriptplan
|
|
9
19
|
```
|
|
10
20
|
|
|
11
|
-
##
|
|
21
|
+
## Quick Start
|
|
12
22
|
|
|
13
|
-
###
|
|
23
|
+
### Report Generation (Unix-style)
|
|
14
24
|
|
|
15
25
|
```bash
|
|
16
|
-
|
|
17
|
-
|
|
26
|
+
# Generate JSON report to stdout
|
|
27
|
+
plan report project.tjp
|
|
28
|
+
|
|
29
|
+
# Generate CSV report
|
|
30
|
+
plan report --csv project.tjp
|
|
31
|
+
|
|
32
|
+
# Save to file
|
|
33
|
+
plan report project.tjp > output.json
|
|
34
|
+
plan report --csv project.tjp > output.csv
|
|
35
|
+
|
|
36
|
+
# Read from stdin
|
|
37
|
+
cat project.tjp | plan report
|
|
38
|
+
plan report - < project.tjp
|
|
39
|
+
|
|
40
|
+
# Pipe to other tools
|
|
41
|
+
plan report project.tjp | jq '.data[0]'
|
|
42
|
+
plan report --csv project.tjp | csvkit
|
|
43
|
+
|
|
44
|
+
# Process multiple files
|
|
45
|
+
for f in projects/*.tjp; do
|
|
46
|
+
plan report "$f" | jq -r '.report_id'
|
|
47
|
+
done
|
|
18
48
|
```
|
|
19
49
|
|
|
50
|
+
**Output Format** (JSON):
|
|
51
|
+
```json
|
|
52
|
+
{
|
|
53
|
+
"data": [
|
|
54
|
+
{
|
|
55
|
+
"id": "project.task1",
|
|
56
|
+
"start": "2024-01-01-09:00",
|
|
57
|
+
"end": "2024-01-05-17:00"
|
|
58
|
+
}
|
|
59
|
+
],
|
|
60
|
+
"columns": ["id", "start", "end"],
|
|
61
|
+
"report_id": "ea3f901dd6426dfa58288d945819c75485fd9ff1875db59def350f219e2d62ca"
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**Features**:
|
|
66
|
+
- Output to stdout (Unix philosophy)
|
|
67
|
+
- Messages to stderr
|
|
68
|
+
- SHA256 report_id (content-based hash)
|
|
69
|
+
- Lowercase column names
|
|
70
|
+
- No HTML metadata
|
|
71
|
+
- No file pollution (uses temp directories)
|
|
72
|
+
- Safe for concurrent execution (100+ instances)
|
|
73
|
+
|
|
20
74
|
### Python API
|
|
21
75
|
|
|
22
76
|
```python
|
|
@@ -33,6 +87,20 @@ for task in project.tasks:
|
|
|
33
87
|
print(f"{task.id}: {start} -> {end}")
|
|
34
88
|
```
|
|
35
89
|
|
|
90
|
+
## System Certified
|
|
91
|
+
|
|
92
|
+
**Certification Level**: Airport-Grade / Mission Critical
|
|
93
|
+
|
|
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
|
+
|
|
36
104
|
## Features
|
|
37
105
|
|
|
38
106
|
- Minute-level scheduling precision
|
|
@@ -121,3 +189,13 @@ delivery.assemble_b: 2025-07-16-08:00 -> 2025-07-17-16:00
|
|
|
121
189
|
## License
|
|
122
190
|
|
|
123
191
|
Apache 2.0
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
## Why?
|
|
195
|
+
This scheduler is part of Highway Workflow Egnine's worker capacity management system.
|
|
196
|
+
I decided to open-source it for the community to benefit from its precise scheduling capabilities.
|
|
197
|
+
Thanks to TaskJuggler's established syntax, users can easily adopt ScriptPlan without learning a new format.
|
|
198
|
+
Credits to TaskJuggler for the original project definition language and concepts.
|
|
199
|
+
|
|
200
|
+
Yours,
|
|
201
|
+
Farshid.
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "scriptplan"
|
|
7
|
-
version = "0.9.
|
|
7
|
+
version = "0.9.1"
|
|
8
8
|
description = "A precise project scheduling engine with minute-level accuracy for resource allocation and dependency management."
|
|
9
9
|
authors = [
|
|
10
10
|
{ name = "Farshid Ashouri", email = "farsheed.ashouri@gmail.com" },
|
|
@@ -26,6 +26,7 @@ classifiers = [
|
|
|
26
26
|
"Programming Language :: Python :: 3.11",
|
|
27
27
|
"Programming Language :: Python :: 3.12",
|
|
28
28
|
"Programming Language :: Python :: 3.13",
|
|
29
|
+
"Programming Language :: Python :: 3.14",
|
|
29
30
|
"Operating System :: OS Independent",
|
|
30
31
|
"Topic :: Office/Business :: Scheduling",
|
|
31
32
|
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
@@ -35,6 +36,7 @@ keywords = ["scheduling", "project-management", "resource-allocation", "gantt",
|
|
|
35
36
|
dependencies = [
|
|
36
37
|
"lark>=1.0.0",
|
|
37
38
|
"python-dateutil>=2.8.0",
|
|
39
|
+
"click>=8.0.0",
|
|
38
40
|
]
|
|
39
41
|
|
|
40
42
|
[project.optional-dependencies]
|
|
@@ -42,18 +44,23 @@ dev = [
|
|
|
42
44
|
"pytest>=7.0.0",
|
|
43
45
|
"pytest-xdist>=3.0.0",
|
|
44
46
|
"pandas>=1.5.0",
|
|
47
|
+
"types-python-dateutil>=2.8.0",
|
|
48
|
+
"types-pytz>=2022.1.0",
|
|
45
49
|
"build",
|
|
46
50
|
"twine",
|
|
51
|
+
"ruff>=0.1.0",
|
|
52
|
+
"mypy>=1.0.0",
|
|
47
53
|
]
|
|
48
54
|
|
|
49
55
|
[project.scripts]
|
|
50
56
|
scriptplan = "scriptplan.cli.main:main"
|
|
57
|
+
plan = "scriptplan.cli.plan:main"
|
|
51
58
|
|
|
52
59
|
[project.urls]
|
|
53
|
-
"Homepage" = "https://github.com/
|
|
54
|
-
"Documentation" = "https://github.com/
|
|
55
|
-
"Bug Tracker" = "https://github.com/
|
|
56
|
-
"Source" = "https://github.com/
|
|
60
|
+
"Homepage" = "https://github.com/rodmena-limited/scriptplan"
|
|
61
|
+
"Documentation" = "https://github.com/rodmena-limited/scriptplan#readme"
|
|
62
|
+
"Bug Tracker" = "https://github.com/rodmena-limited/scriptplan/issues"
|
|
63
|
+
"Source" = "https://github.com/rodmena-limited/scriptplan"
|
|
57
64
|
|
|
58
65
|
[tool.setuptools]
|
|
59
66
|
include-package-data = true
|
|
@@ -75,3 +82,19 @@ filterwarnings = [
|
|
|
75
82
|
"ignore::DeprecationWarning",
|
|
76
83
|
"ignore::PendingDeprecationWarning",
|
|
77
84
|
]
|
|
85
|
+
|
|
86
|
+
[tool.ruff]
|
|
87
|
+
line-length = 120
|
|
88
|
+
target-version = "py39"
|
|
89
|
+
|
|
90
|
+
[tool.ruff.lint]
|
|
91
|
+
select = ["E", "F", "W", "I", "UP", "B", "C4", "SIM", "RUF"]
|
|
92
|
+
# N rules ignored: codebase uses camelCase for TaskJuggler API compatibility
|
|
93
|
+
ignore = ["E501"] # Line length handled separately
|
|
94
|
+
|
|
95
|
+
[tool.mypy]
|
|
96
|
+
python_version = "3.9"
|
|
97
|
+
strict = true
|
|
98
|
+
warn_return_any = true
|
|
99
|
+
warn_unused_configs = true
|
|
100
|
+
ignore_missing_imports = true
|
|
@@ -17,17 +17,17 @@ Examples:
|
|
|
17
17
|
"""
|
|
18
18
|
|
|
19
19
|
import argparse
|
|
20
|
-
import sys
|
|
21
|
-
import os
|
|
22
20
|
import logging
|
|
23
|
-
|
|
24
|
-
from typing import List, Optional
|
|
21
|
+
import os
|
|
25
22
|
import re
|
|
23
|
+
import sys
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
from typing import Optional
|
|
26
26
|
|
|
27
27
|
from scriptplan import __version__
|
|
28
28
|
|
|
29
29
|
|
|
30
|
-
def setup_logging(debug_level: int = 0, debug_modules: Optional[
|
|
30
|
+
def setup_logging(debug_level: int = 0, debug_modules: Optional[list[str]] = None) -> None:
|
|
31
31
|
"""
|
|
32
32
|
Configure logging based on debug settings.
|
|
33
33
|
|
|
@@ -226,8 +226,10 @@ class ScriptPlan:
|
|
|
226
226
|
Args:
|
|
227
227
|
args: Parsed command-line arguments
|
|
228
228
|
"""
|
|
229
|
+
from scriptplan.core.project import Project
|
|
230
|
+
|
|
229
231
|
self.args = args
|
|
230
|
-
self.project = None
|
|
232
|
+
self.project: Optional[Project] = None
|
|
231
233
|
self.errors = 0
|
|
232
234
|
self.warnings = 0
|
|
233
235
|
self.logger = logging.getLogger('scriptplan.cli')
|
|
@@ -284,22 +286,20 @@ class ScriptPlan:
|
|
|
284
286
|
return 1
|
|
285
287
|
|
|
286
288
|
# Freeze (generate bookings) if requested
|
|
287
|
-
if self.args.freeze:
|
|
288
|
-
|
|
289
|
-
return 1
|
|
289
|
+
if self.args.freeze and not self.freeze_project():
|
|
290
|
+
return 1
|
|
290
291
|
|
|
291
292
|
# List reports if requested
|
|
292
293
|
if self.args.list_reports:
|
|
293
294
|
self.list_reports(self.args.list_reports)
|
|
294
295
|
|
|
295
296
|
# Generate reports
|
|
296
|
-
if not self.args.no_reports:
|
|
297
|
-
|
|
298
|
-
return 1
|
|
297
|
+
if not self.args.no_reports and not self.generate_reports():
|
|
298
|
+
return 1
|
|
299
299
|
|
|
300
300
|
return 0 if self.errors == 0 else 1
|
|
301
301
|
|
|
302
|
-
def parse_files(self, files:
|
|
302
|
+
def parse_files(self, files: list[str]) -> bool:
|
|
303
303
|
"""
|
|
304
304
|
Parse the project files.
|
|
305
305
|
|
|
@@ -322,11 +322,12 @@ class ScriptPlan:
|
|
|
322
322
|
print(f"Error: File '{main_file}' not found", file=sys.stderr)
|
|
323
323
|
return False
|
|
324
324
|
|
|
325
|
-
with open(main_file,
|
|
325
|
+
with open(main_file, encoding='utf-8') as f:
|
|
326
326
|
content = f.read()
|
|
327
327
|
|
|
328
328
|
self.project = parser.parse(content)
|
|
329
|
-
|
|
329
|
+
if self.project:
|
|
330
|
+
self.logger.info(f"Project '{self.project.name}' loaded successfully")
|
|
330
331
|
|
|
331
332
|
# Parse additional include files
|
|
332
333
|
for include_file in files[1:]:
|
|
@@ -505,7 +506,7 @@ class ScriptPlan:
|
|
|
505
506
|
context.push()
|
|
506
507
|
|
|
507
508
|
try:
|
|
508
|
-
result = report.generate()
|
|
509
|
+
result = report.generate() # type: ignore[attr-defined]
|
|
509
510
|
if result != 0:
|
|
510
511
|
self.warnings += 1
|
|
511
512
|
finally:
|
|
@@ -520,7 +521,53 @@ class ScriptPlan:
|
|
|
520
521
|
return False
|
|
521
522
|
|
|
522
523
|
|
|
523
|
-
def
|
|
524
|
+
def run_scriptplan(tjp_file: str, output_dir: Optional[str] = None) -> tuple[bool, Optional[str]]:
|
|
525
|
+
"""
|
|
526
|
+
Run ScriptPlan report generation on a .tjp file.
|
|
527
|
+
|
|
528
|
+
This is a simplified interface for programmatic use.
|
|
529
|
+
|
|
530
|
+
Args:
|
|
531
|
+
tjp_file: Path to the .tjp file
|
|
532
|
+
output_dir: Optional output directory for reports (default: current directory)
|
|
533
|
+
|
|
534
|
+
Returns:
|
|
535
|
+
Tuple of (success, error_message)
|
|
536
|
+
"""
|
|
537
|
+
import contextlib
|
|
538
|
+
import io
|
|
539
|
+
|
|
540
|
+
# Capture stderr to get error messages
|
|
541
|
+
stderr_capture = io.StringIO()
|
|
542
|
+
|
|
543
|
+
try:
|
|
544
|
+
with contextlib.redirect_stderr(stderr_capture):
|
|
545
|
+
# Create minimal args
|
|
546
|
+
parser = create_parser()
|
|
547
|
+
args_list = [tjp_file]
|
|
548
|
+
if output_dir:
|
|
549
|
+
args_list.extend(['--output-dir', output_dir])
|
|
550
|
+
args = parser.parse_args(args_list)
|
|
551
|
+
|
|
552
|
+
# Suppress logging for programmatic use
|
|
553
|
+
logging.getLogger().setLevel(logging.ERROR)
|
|
554
|
+
|
|
555
|
+
# Run the application
|
|
556
|
+
app = ScriptPlan(args)
|
|
557
|
+
exit_code = app.run()
|
|
558
|
+
|
|
559
|
+
if exit_code == 0:
|
|
560
|
+
return (True, None)
|
|
561
|
+
else:
|
|
562
|
+
error_output = stderr_capture.getvalue()
|
|
563
|
+
return (False, error_output or "Report generation failed")
|
|
564
|
+
|
|
565
|
+
except Exception as e:
|
|
566
|
+
error_output = stderr_capture.getvalue()
|
|
567
|
+
return (False, error_output or str(e))
|
|
568
|
+
|
|
569
|
+
|
|
570
|
+
def main(argv: Optional[list[str]] = None) -> int:
|
|
524
571
|
"""
|
|
525
572
|
Main entry point for the CLI.
|
|
526
573
|
|