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.
Files changed (87) hide show
  1. {scriptplan-0.9.0/scriptplan.egg-info → scriptplan-0.9.1}/PKG-INFO +93 -9
  2. {scriptplan-0.9.0 → scriptplan-0.9.1}/README.md +82 -4
  3. {scriptplan-0.9.0 → scriptplan-0.9.1}/pyproject.toml +28 -5
  4. scriptplan-0.9.1/scriptplan/cli/__init__.py +7 -0
  5. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/cli/main.py +64 -17
  6. scriptplan-0.9.1/scriptplan/cli/plan.py +678 -0
  7. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/core/account.py +44 -25
  8. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/core/allocation.py +35 -23
  9. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/core/booking.py +23 -13
  10. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/core/journal.py +16 -16
  11. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/core/leave.py +5 -2
  12. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/core/limits.py +55 -33
  13. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/core/project.py +155 -143
  14. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/core/property.py +278 -276
  15. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/core/resource.py +32 -22
  16. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/core/resource_scenario.py +39 -41
  17. scriptplan-0.9.1/scriptplan/core/scenario.py +11 -0
  18. scriptplan-0.9.1/scriptplan/core/scenario_data.py +69 -0
  19. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/core/shift.py +30 -15
  20. scriptplan-0.9.1/scriptplan/core/task.py +86 -0
  21. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/core/task_scenario.py +153 -117
  22. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/core/timesheet.py +59 -45
  23. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/core/working_hours.py +24 -20
  24. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/parser/macro_processor.py +5 -5
  25. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/parser/tjp_parser.py +333 -334
  26. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/report/__init__.py +20 -20
  27. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/report/report.py +27 -122
  28. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/report/report_base.py +45 -45
  29. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/report/report_context.py +6 -7
  30. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/report/resource_report.py +18 -19
  31. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/report/table_report.py +97 -128
  32. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/report/task_report.py +20 -21
  33. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/report/text_report.py +25 -28
  34. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/scheduler/batch_processor.py +51 -29
  35. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/scheduler/scoreboard.py +64 -42
  36. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/utils/data_cache.py +22 -18
  37. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/utils/logger.py +32 -30
  38. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/utils/message_handler.py +65 -45
  39. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/utils/time.py +74 -63
  40. {scriptplan-0.9.0 → scriptplan-0.9.1/scriptplan.egg-info}/PKG-INFO +93 -9
  41. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan.egg-info/SOURCES.txt +1 -3
  42. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan.egg-info/entry_points.txt +1 -0
  43. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan.egg-info/requires.txt +5 -0
  44. {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_account.py +2 -1
  45. {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_attribute_base.py +3 -3
  46. {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_batch_processor.py +2 -3
  47. {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_cli.py +3 -9
  48. {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_core_allocation.py +5 -3
  49. {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_core_booking.py +8 -6
  50. {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_core_project.py +4 -2
  51. {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_core_resource.py +5 -3
  52. {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_core_scenario.py +6 -4
  53. {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_core_task.py +7 -5
  54. {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_journal.py +2 -1
  55. {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_logger.py +3 -2
  56. {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_macro_processor.py +1 -0
  57. {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_message_handler.py +11 -6
  58. {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_parser.py +4 -2
  59. {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_property_list.py +2 -1
  60. {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_property_set.py +7 -6
  61. {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_property_tree_node.py +7 -6
  62. {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_report.py +77 -57
  63. {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_scheduling.py +4 -3
  64. {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_scheduling_validation.py +28 -20
  65. {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_scoreboard.py +11 -9
  66. {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_shift.py +1 -0
  67. {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_timesheet.py +2 -1
  68. {scriptplan-0.9.0 → scriptplan-0.9.1}/tests/test_utils_time.py +7 -5
  69. scriptplan-0.9.0/scriptplan/cli/__init__.py +0 -7
  70. scriptplan-0.9.0/scriptplan/core/scenario.py +0 -5
  71. scriptplan-0.9.0/scriptplan/core/scenario_data.py +0 -39
  72. scriptplan-0.9.0/scriptplan/core/task.py +0 -77
  73. scriptplan-0.9.0/scriptplan/report/html_generator.py +0 -477
  74. scriptplan-0.9.0/tests/test_html_generator.py +0 -268
  75. scriptplan-0.9.0/tests/test_html_report_integration.py +0 -199
  76. {scriptplan-0.9.0 → scriptplan-0.9.1}/LICENSE +0 -0
  77. {scriptplan-0.9.0 → scriptplan-0.9.1}/MANIFEST.in +0 -0
  78. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/__init__.py +3 -3
  79. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/core/__init__.py +0 -0
  80. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/parser/__init__.py +0 -0
  81. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/parser/tjp.lark +0 -0
  82. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/py.typed +0 -0
  83. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/scheduler/__init__.py +0 -0
  84. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan/utils/__init__.py +0 -0
  85. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan.egg-info/dependency_links.txt +0 -0
  86. {scriptplan-0.9.0 → scriptplan-0.9.1}/scriptplan.egg-info/top_level.txt +0 -0
  87. {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.0
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/farshidash/scriptplan
9
- Project-URL: Documentation, https://github.com/farshidash/scriptplan#readme
10
- Project-URL: Bug Tracker, https://github.com/farshidash/scriptplan/issues
11
- Project-URL: Source, https://github.com/farshidash/scriptplan
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
+ ![Logic Certified](https://img.shields.io/badge/Logic-Certified_Airport--Grade-success?style=for-the-badge&logo=github)
52
+ ![Tests Passed](https://img.shields.io/badge/Stress_Tests-24%2F24_Passed-success?style=for-the-badge)
53
+ ![Temporal Physics](https://img.shields.io/badge/Temporal_Physics-Verified-blue?style=for-the-badge)
54
+ ![Scheduling](https://img.shields.io/badge/Scheduling-ALAP_%7C_JIT_%7C_Priority-blueviolet?style=for-the-badge)
55
+ ![Constraints](https://img.shields.io/badge/Constraints-Hard_Limits_%7C_Quotas-orange?style=for-the-badge)
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
- ## Usage
65
+ ## Quick Start
50
66
 
51
- ### Command Line
67
+ ### Report Generation (Unix-style)
52
68
 
53
69
  ```bash
54
- scriptplan project.tjp
55
- scriptplan --output-dir ./reports project.tjp
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
+ ![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)
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
- ## Usage
21
+ ## Quick Start
12
22
 
13
- ### Command Line
23
+ ### Report Generation (Unix-style)
14
24
 
15
25
  ```bash
16
- scriptplan project.tjp
17
- scriptplan --output-dir ./reports project.tjp
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.0"
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/farshidash/scriptplan"
54
- "Documentation" = "https://github.com/farshidash/scriptplan#readme"
55
- "Bug Tracker" = "https://github.com/farshidash/scriptplan/issues"
56
- "Source" = "https://github.com/farshidash/scriptplan"
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
@@ -0,0 +1,7 @@
1
+ """
2
+ Command-line interface for ScriptPlan.
3
+ """
4
+
5
+ from scriptplan.cli.main import ScriptPlan, create_parser, main
6
+
7
+ __all__ = ['ScriptPlan', 'create_parser', 'main']
@@ -17,17 +17,17 @@ Examples:
17
17
  """
18
18
 
19
19
  import argparse
20
- import sys
21
- import os
22
20
  import logging
23
- from pathlib import Path
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[List[str]] = None) -> None:
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
- if not self.freeze_project():
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
- if not self.generate_reports():
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: List[str]) -> bool:
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, 'r', encoding='utf-8') as f:
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
- self.logger.info(f"Project '{self.project.name}' loaded successfully")
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 main(argv: Optional[List[str]] = None) -> int:
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