scriptplan 0.9.0__py3-none-any.whl

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 (49) hide show
  1. scriptplan/__init__.py +22 -0
  2. scriptplan/cli/__init__.py +7 -0
  3. scriptplan/cli/main.py +546 -0
  4. scriptplan/core/__init__.py +0 -0
  5. scriptplan/core/account.py +125 -0
  6. scriptplan/core/allocation.py +69 -0
  7. scriptplan/core/booking.py +39 -0
  8. scriptplan/core/journal.py +377 -0
  9. scriptplan/core/leave.py +14 -0
  10. scriptplan/core/limits.py +354 -0
  11. scriptplan/core/project.py +924 -0
  12. scriptplan/core/property.py +1290 -0
  13. scriptplan/core/resource.py +198 -0
  14. scriptplan/core/resource_scenario.py +711 -0
  15. scriptplan/core/scenario.py +5 -0
  16. scriptplan/core/scenario_data.py +39 -0
  17. scriptplan/core/shift.py +71 -0
  18. scriptplan/core/task.py +77 -0
  19. scriptplan/core/task_scenario.py +1515 -0
  20. scriptplan/core/timesheet.py +457 -0
  21. scriptplan/core/working_hours.py +231 -0
  22. scriptplan/parser/__init__.py +0 -0
  23. scriptplan/parser/macro_processor.py +264 -0
  24. scriptplan/parser/tjp.lark +412 -0
  25. scriptplan/parser/tjp_parser.py +1904 -0
  26. scriptplan/py.typed +0 -0
  27. scriptplan/report/__init__.py +75 -0
  28. scriptplan/report/html_generator.py +477 -0
  29. scriptplan/report/report.py +466 -0
  30. scriptplan/report/report_base.py +397 -0
  31. scriptplan/report/report_context.py +248 -0
  32. scriptplan/report/resource_report.py +341 -0
  33. scriptplan/report/table_report.py +693 -0
  34. scriptplan/report/task_report.py +362 -0
  35. scriptplan/report/text_report.py +172 -0
  36. scriptplan/scheduler/__init__.py +0 -0
  37. scriptplan/scheduler/batch_processor.py +238 -0
  38. scriptplan/scheduler/scoreboard.py +120 -0
  39. scriptplan/utils/__init__.py +0 -0
  40. scriptplan/utils/data_cache.py +46 -0
  41. scriptplan/utils/logger.py +243 -0
  42. scriptplan/utils/message_handler.py +515 -0
  43. scriptplan/utils/time.py +195 -0
  44. scriptplan-0.9.0.dist-info/METADATA +161 -0
  45. scriptplan-0.9.0.dist-info/RECORD +49 -0
  46. scriptplan-0.9.0.dist-info/WHEEL +5 -0
  47. scriptplan-0.9.0.dist-info/entry_points.txt +2 -0
  48. scriptplan-0.9.0.dist-info/licenses/LICENSE +201 -0
  49. scriptplan-0.9.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,5 @@
1
+ from scriptplan.core.property import PropertyTreeNode
2
+
3
+ class Scenario(PropertyTreeNode):
4
+ def __init__(self, project, id, name, parent):
5
+ super().__init__(project.scenarios, id, name, parent)
@@ -0,0 +1,39 @@
1
+ from scriptplan.utils.message_handler import MessageHandler
2
+
3
+ class ScenarioData:
4
+ def __init__(self, property_node, idx, attributes):
5
+ self.property = property_node
6
+ self.project = property_node.project
7
+ self.scenarioIdx = idx
8
+ self.attributes = attributes
9
+ self.messageHandler = MessageHandler() # Should be singleton in real app
10
+
11
+ # Register the scenario with the property.
12
+ if self.property.data is None:
13
+ # Initialize if not present, assuming it's a list
14
+ # In PropertyTreeNode we initialized it as list of None
15
+ self.property.data = [None] * (self.project.scenarioCount() if hasattr(self.project, 'scenarioCount') else 1)
16
+
17
+ # Ensure list is big enough
18
+ while len(self.property.data) <= idx:
19
+ self.property.data.append(None)
20
+
21
+ self.property.data[idx] = self
22
+
23
+ def deep_clone(self):
24
+ return self
25
+
26
+ def a(self, attributeName):
27
+ return self.attributes[attributeName].get()
28
+
29
+ def error(self, id, text, sourceFileInfo=None, property_node=None):
30
+ # Delegating to message handler
31
+ # Simplified context passing
32
+ self.messageHandler.error(id, text, sourceFileInfo or self.property.sourceFileInfo)
33
+
34
+ def warning(self, id, text, sourceFileInfo=None, property_node=None):
35
+ self.messageHandler.warning(id, text, sourceFileInfo or self.property.sourceFileInfo)
36
+
37
+ def info(self, id, text, sourceFileInfo=None, property_node=None):
38
+ # Assuming info exists
39
+ print(f"INFO: {text}")
@@ -0,0 +1,71 @@
1
+ """Shift module implementing work schedule definitions.
2
+
3
+ A shift is a definition of working hours for each day of the week.
4
+ It may also contain a list of intervals that define off-duty periods or leaves.
5
+ """
6
+
7
+ from scriptplan.core.property import PropertyTreeNode
8
+ from scriptplan.core.scenario_data import ScenarioData
9
+
10
+
11
+ class ShiftScenario(ScenarioData):
12
+ """Handles the scenario-specific features of a Shift object."""
13
+
14
+ def __init__(self, shift, scenarioIdx, attributes):
15
+ super().__init__(shift, scenarioIdx, attributes)
16
+
17
+ def _get(self, attrName):
18
+ """Get attribute value using property's attribute access."""
19
+ return self.property.get(attrName, self.scenarioIdx)
20
+
21
+ def onShift(self, date):
22
+ """Returns True if the shift has working time defined for the date."""
23
+ workinghours = self._get('workinghours')
24
+ if workinghours:
25
+ return workinghours.onShift(date)
26
+ return False
27
+
28
+ def replace(self):
29
+ """Returns the replace attribute value."""
30
+ return self._get('replace')
31
+
32
+ def onLeave(self, date):
33
+ """Returns True if the shift has a vacation/leave defined for the date."""
34
+ leaves = self._get('leaves')
35
+ if leaves:
36
+ for leave in leaves:
37
+ if hasattr(leave, 'interval') and leave.interval.contains(date):
38
+ return True
39
+ return False
40
+
41
+
42
+ class Shift(PropertyTreeNode):
43
+ """A shift is a definition of working hours for each day of the week.
44
+
45
+ It may also contain a list of intervals that define off-duty periods or leaves.
46
+ """
47
+
48
+ def __init__(self, project, id, name, parent):
49
+ super().__init__(project.shifts, id, name, parent)
50
+ project.addShift(self)
51
+
52
+ # Initialize scenario data array
53
+ self.data = [None] * project.scenarioCount()
54
+ for i in range(project.scenarioCount()):
55
+ ShiftScenario(self, i, self._scenarioAttributes[i])
56
+
57
+ def scenario(self, scenarioIdx):
58
+ """Return a reference to the scenarioIdx-th scenario."""
59
+ return self.data[scenarioIdx]
60
+
61
+ def onShift(self, scenarioIdx, date):
62
+ """Check if shift is active on given date for the scenario."""
63
+ return self.data[scenarioIdx].onShift(date)
64
+
65
+ def onLeave(self, scenarioIdx, date):
66
+ """Check if there is leave defined for the date in the scenario."""
67
+ return self.data[scenarioIdx].onLeave(date)
68
+
69
+ def replace(self, scenarioIdx):
70
+ """Get the replace attribute for the scenario."""
71
+ return self.data[scenarioIdx].replace()
@@ -0,0 +1,77 @@
1
+ from scriptplan.core.property import PropertyTreeNode
2
+ from scriptplan.core.task_scenario import TaskScenario
3
+ # from scriptplan.utils.rich_text import RichText, RTFHandlers # To be implemented
4
+
5
+ class Task(PropertyTreeNode):
6
+ def __init__(self, project, id, name, parent):
7
+ # super init calls project.tasks.addProperty(self)
8
+ super().__init__(project.tasks, id, name, parent)
9
+
10
+ # In Ruby: project.addTask(self)
11
+ # But PropertyTreeNode.__init__ already adds to propertySet.
12
+ # project.tasks IS the propertySet for tasks.
13
+ # So it might be redundant or project specific logic.
14
+ # We'll assume super() handles registration with project.tasks
15
+
16
+ # Initialize scenarios
17
+ scenario_count = self.project.scenarioCount() if hasattr(self.project, 'scenarioCount') else 1
18
+ self.data = [None] * scenario_count
19
+
20
+ for i in range(scenario_count):
21
+ # @scenarioAttributes is initialized in PropertyTreeNode
22
+ TaskScenario(self, i, self._scenarioAttributes[i])
23
+
24
+ def readyForScheduling(self, scenarioIdx):
25
+ if self.data[scenarioIdx]:
26
+ return self.data[scenarioIdx].readyForScheduling()
27
+ return False
28
+
29
+ def prepareScheduling(self, scenarioIdx):
30
+ if self.data[scenarioIdx]:
31
+ # self.data[scenarioIdx] is TaskScenario
32
+ # TaskScenario doesn't implement prepareScheduling?
33
+ # Wait, ScenarioData might? Or TaskScenario should.
34
+ if hasattr(self.data[scenarioIdx], 'prepareScheduling'):
35
+ self.data[scenarioIdx].prepareScheduling()
36
+
37
+ def finishScheduling(self, scenarioIdx):
38
+ if self.data[scenarioIdx]:
39
+ if hasattr(self.data[scenarioIdx], 'finishScheduling'):
40
+ self.data[scenarioIdx].finishScheduling()
41
+
42
+ def schedule(self, scenarioIdx):
43
+ if self.data[scenarioIdx]:
44
+ return self.data[scenarioIdx].schedule()
45
+ return False
46
+
47
+ def journalText(self, query, longVersion, recursive):
48
+ # Implementation of journalText logic
49
+ # Depends on project.journal, RichText, etc.
50
+
51
+ r_text = ""
52
+
53
+ # Mocking journal retrieval
54
+ journal = self.project.attributes.get('journal')
55
+ if not journal:
56
+ return None
57
+
58
+ if recursive:
59
+ # entries = journal.entriesByTaskR(...)
60
+ entries = []
61
+ else:
62
+ # entries = journal.entriesByTask(...)
63
+ entries = []
64
+
65
+ # Sorting logic would go here
66
+
67
+ for entry in entries:
68
+ # Build r_text similar to Ruby
69
+ pass
70
+
71
+ if not r_text:
72
+ return None
73
+
74
+ # Rich Text generation
75
+ # rti = RichText(r_text, ...).generateIntermediateFormat()
76
+ # query.rti = rti
77
+ pass