Changeset d7a66ad in flowtimer
- Timestamp:
- 08/25/24 18:20:14 (9 months ago)
- Branches:
- guix
- Children:
- d310de3
- Parents:
- 5f4ef8e
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
flowtimer/Phase.py
r5f4ef8e rd7a66ad 47 47 """ 48 48 49 return (" -->" + self.title + "\nTicks left=" +49 return ("Title:" + self.title + "\nTicks left=" + 50 50 str(self._ticks_left) + "\n" + str(self._state) + "\n") 51 51 … … 54 54 55 55 def abort(self): 56 self._state = "finished" 56 self._state = "aborted" 57 58 def aborted(self): 59 return self.state == "aborted" 57 60 58 61 def start(self): … … 70 73 # return self.time_left > 0 71 74 72 def finished(self):73 return self._state == " finished"75 def completed(self): 76 return self._state == "completed" 74 77 75 78 def paused(self): … … 81 84 if result <= 0: 82 85 self._ticks_left = 0 83 self._state = " finished"86 self._state = "completed" 84 87 else: 85 88 self._ticks_left = result -
flowtimer/RecurringPhaseSequence.py
r5f4ef8e rd7a66ad 20 20 def default_json_string(cls): 21 21 return json.dumps({"title": "default", 22 "phase_list": [{"title": "Huddle", "initial_ticks": 10}, 23 {"title": "Tasking", "initial_ticks": 5}, 22 "phase_list": [{"title": "Tasking", "initial_ticks": 5}, 24 23 {"title": "Work", "initial_ticks": 45}, 25 24 {"title": "Break", "initial_ticks": 15}], … … 46 45 def title(self): 47 46 return self._title 47 48 def __str__(self): 49 return ("Sequence title:" + self.title + "\n" + str(self.current_phase)) 48 50 49 51 def is_sequence(self): … … 72 74 sum([each.ticks_left for each in self.upcoming_phases_in_pass()])) 73 75 74 def finished(self):76 def completed(self): 75 77 return ((self.passes_left < 1) and 76 78 (not self.upcoming_phases_in_pass() and 77 self.current_phase. finished()))79 self.current_phase.completed())) 78 80 79 81 def abort(self): 80 82 self.current_phase.abort() 81 self.state = " finished"83 self.state = "aborted" 82 84 83 85 def start(self): … … 99 101 self.current_phase = self.phase_list[0] 100 102 103 def advance_to_next_phase(self): 104 current_index = self.current_phase_number() 105 if current_index < len(self.phase_list) - 1: 106 # Move to the next phase in the sequence 107 self.current_phase.reset() 108 self.current_phase = self.phase_list[current_index + 1] 109 else: 110 # Completed a full sequence; check if more repetitions are needed 111 self.passes_left -= 1 112 if self.passes_left < 1: 113 self.state = "completed" 114 else: 115 self.current_phase.reset() 116 self.current_phase = self.phase_list[0] # Reset to the first phase 117 101 118 def tick(self, ticks): 102 if not self.finished(): 119 print("Before tick") 120 print(self.current_phase) 121 print("Tick:", ticks) 122 if not self.completed(): 103 123 result = self.current_phase.tick(ticks) 104 if self.current_phase.finished(): 105 if self.upcoming_phases_in_pass(): 106 self.current_phase.reset() 107 self.current_phase = self.upcoming_phases_in_pass()[0] 108 self.current_phase.start() 109 self.tick(abs(result)) 110 return True 111 self.passes_left -= 1 112 if self.finished(): 113 self.state = "finished" 114 else: 115 self.current_phase.reset() 116 self.current_phase = self.phase_list[0] 117 return True 124 print("Result", result, "\n") 125 if self.current_phase.completed(): 126 print(self.current_phase.title, "Phase Completed") 127 self.advance_to_next_phase() 128 print("Advanced to", self.current_phase, "\n") 129 result = self.tick(abs(result)) 130 return 131 if self.completed(): 132 self.advance_to_next_phase() 133 print("Passes left:", self.passes_left) 118 134 119 135 def unrolled(self): -
flowtimer/Schedule.py
r5f4ef8e rd7a66ad 6 6 I represent a Schedule consisting of blocks. Blocks can be a single phase or 7 7 a sequence of phases. 8 There are 6 states a Schedule can be in: initial, running, completed, aborted, paused, terminated. 8 9 """ 9 10 … … 72 73 def to_json(self): 73 74 def serialize_block(block): 74 if not block.is_sequence :75 if not block.is_sequence(): 75 76 return {"type": "Phase", "title": block.title, "initial_ticks": block.initial_ticks} 76 if block.is_sequence :77 if block.is_sequence(): 77 78 return { 78 79 "type": "Sequence", 79 80 "title": block.title, 80 "sequence": [serialize_block(phase) for phase in block. sequence],81 "sequence": [serialize_block(phase) for phase in block.phase_list], 81 82 "initial_repetitions": block.initial_repetitions 82 83 } … … 98 99 return self.state == "running" 99 100 100 def is_paused(self):101 def paused(self): 101 102 return self.state == "paused" 102 103 103 104 def abort(self): 104 105 self.current_block.abort() 105 self.state = " finished"106 self.state = "aborted" 106 107 107 def finished(self): 108 if (self.current_block.finished()) and (self.current_block.is_final()): 109 self.state = "finished" 108 def current_block_is_final(self): 109 index = self.blocks.index(self.current_block) 110 return index == (len(self.blocks) - 1) 111 112 def completed(self): 113 if (self.current_block.completed()) and (self.current_block_is_final()): 114 self.state = "completed" 110 115 return True 111 116 else: 112 117 return False 113 118 119 def aborted(self): 120 return self.state == "aborted" 121 122 def terminated(self): 123 return (self.aborted() or self.completed()) 124 114 125 def advance_to_next_block(self): 115 126 """Helper method to move to the next block in the schedule.""" 116 if self.current_block_index < len(self.blocks) - 1:117 self.current_block_index += 1118 self.current_block = self.blocks[ self.current_block_index]127 current_block_index = self.blocks.index(self.current_block) 128 if current_block_index < len(self.blocks) - 1: 129 self.current_block = self.blocks[current_block_index+1] 119 130 120 131 def skip(self): … … 126 137 print("Skip the next phase in sequence") 127 138 self.current_block.skip() 128 if self.current_block. finished():139 if self.current_block.completed(): 129 140 self.current_block = self.upcoming_blocks()[0] 130 141 return … … 143 154 return [] 144 155 145 def current_block_is_final(self):146 index = self.blocks.index(self.current_block)147 return index == (len(self.blocks) - 1)148 149 156 def tick(self, ticks): 150 if not self. finished():157 if not self.completed(): 151 158 self.current_block.tick(ticks) 152 if self.current_block. finished():159 if self.current_block.completed(): 153 160 if self.current_block_is_final(): 154 self. abort()161 self.state = "completed" 155 162 else: 156 163 self.skip() -
flowtimer/main.py
r5f4ef8e rd7a66ad 117 117 def tick(self): 118 118 119 if self.schedule. is_paused():119 if self.schedule.paused(): 120 120 return 121 121 self.label_start.pack_forget() … … 161 161 def skip(self): 162 162 self.schedule.skip() 163 if self.schedule.finished():164 print("finished")165 163 166 164 def toggle_tick(self): 167 if self.schedule. is_paused():165 if self.schedule.paused(): 168 166 self.freeze_button.config(relief="raised", fg='black') 169 167 self.label_sequence.config(fg="white") -
tests/test_phase.py
r5f4ef8e rd7a66ad 32 32 phase = Phase("Warm-up", 300) 33 33 phase.abort() 34 assert phase.state == " finished"35 assert phase. finished() is True34 assert phase.state == "aborted" 35 assert phase.aborted() is True 36 36 37 37 def test_phase_tick(self): … … 47 47 phase.tick(300) 48 48 assert phase.ticks_left == 0 49 assert phase. finished() is True49 assert phase.completed() is True 50 50 51 51 def test_phase_tick_beyond_completion(self): -
tests/test_recurring_phase_sequence.py
r5f4ef8e rd7a66ad 10 10 @pytest.fixture 11 11 def recurring_phase_sequence(self): 12 phase_list = [Phase("Huddle", 10), Phase("Tasking", 5), 13 Phase("Work", 45), Phase("Break", 15)] 14 return RecurringPhaseSequence(phase_list, 3) 12 return RecurringPhaseSequence.default() 15 13 16 14 def test_from_json(self): … … 19 17 assert isinstance(sequence, RecurringPhaseSequence) 20 18 assert sequence.initial_repetitions == 3 21 assert len(sequence.phase_list) == 422 assert sequence.phase_list[0].title == " Huddle"19 assert len(sequence.phase_list) == 3 20 assert sequence.phase_list[0].title == "Tasking" 23 21 24 22 def test_to_json(self, recurring_phase_sequence): … … 28 26 assert data['initial_repetitions'] == 3 29 27 assert data['passes_left'] == 3 30 assert len(data['phase_list']) == 428 assert len(data['phase_list']) == 3 31 29 32 30 def test_initial_state(self, recurring_phase_sequence): 33 31 assert recurring_phase_sequence.state == "initial" 34 assert recurring_phase_sequence.current_phase.title == " Huddle"32 assert recurring_phase_sequence.current_phase.title == "Tasking" 35 33 assert recurring_phase_sequence.passes_left == 3 36 34 … … 41 39 42 40 def test_phases_left_in_pass(self, recurring_phase_sequence): 43 assert recurring_phase_sequence.phases_left_in_pass() == 341 assert recurring_phase_sequence.phases_left_in_pass() == 2 44 42 recurring_phase_sequence.tick(10) 45 assert recurring_phase_sequence.phases_left_in_pass() == 243 assert recurring_phase_sequence.phases_left_in_pass() == 1 46 44 47 45 def test_upcoming_phases_in_pass(self, recurring_phase_sequence): 48 46 upcoming = recurring_phase_sequence.upcoming_phases_in_pass() 49 assert len(upcoming) == 350 assert upcoming[0].title == " Tasking"47 assert len(upcoming) == 2 48 assert upcoming[0].title == "Work" 51 49 52 50 def test_ticks_left(self, recurring_phase_sequence): … … 58 56 assert recurring_phase_sequence.ticks_left == (total_ticks - 10) 59 57 60 def test_ finished(self, recurring_phase_sequence):61 assert not recurring_phase_sequence. finished()58 def test_completed(self, recurring_phase_sequence): 59 assert not recurring_phase_sequence.completed() 62 60 for _ in range(3): 63 61 for phase in recurring_phase_sequence.phase_list: 64 62 recurring_phase_sequence.tick(phase.initial_ticks) 65 assert recurring_phase_sequence. finished()63 assert recurring_phase_sequence.completed() 66 64 67 65 def test_abort(self, recurring_phase_sequence): 68 66 recurring_phase_sequence.abort() 69 assert recurring_phase_sequence.state == " finished"70 assert recurring_phase_sequence.current_phase. finished()67 assert recurring_phase_sequence.state == "aborted" 68 assert recurring_phase_sequence.current_phase.aborted() 71 69 72 70 def test_tick_progression(self, recurring_phase_sequence): 73 recurring_phase_sequence.tick(10) 74 assert recurring_phase_sequence.current_phase.title == "Tasking" 75 assert recurring_phase_sequence.passes_left == 3 76 77 recurring_phase_sequence.tick(5) 71 recurring_phase_sequence.tick(6) 78 72 assert recurring_phase_sequence.current_phase.title == "Work" 79 73 assert recurring_phase_sequence.passes_left == 3 … … 84 78 85 79 recurring_phase_sequence.tick(15) 86 assert recurring_phase_sequence.current_phase.title == " Huddle"80 assert recurring_phase_sequence.current_phase.title == "Tasking" 87 81 assert recurring_phase_sequence.passes_left == 2 88 82 89 83 def test_unrolled(self, recurring_phase_sequence): 90 84 unrolled_phases = recurring_phase_sequence.unrolled() 91 assert len(unrolled_phases) == 1292 assert unrolled_phases[0].title == " Huddle"85 assert len(unrolled_phases) == 9 86 assert unrolled_phases[0].title == "Tasking" 93 87 assert unrolled_phases[-1].title == "Break" -
tests/test_schedule.py
r5f4ef8e rd7a66ad 1 1 import pytest 2 import json 2 3 from flowtimer.Schedule import Schedule 3 4 from flowtimer.Phase import Phase 5 from flowtimer.RecurringPhaseSequence import RecurringPhaseSequence 6 4 7 5 8 class TestSchedule: 6 7 def test_schedule_initialization(self): 8 phase1 = Phase("Warm-up", 300) 9 phase2 = Phase("Workout", 600) 10 schedule = Schedule([phase1, phase2]) 11 12 assert schedule.phase_list == [phase1, phase2] 13 assert schedule.current_phase == phase1 9 10 @pytest.fixture 11 def setup_schedule(self): 12 # Set up some real Phase and RecurringPhaseSequence objects for testing 13 phase1 = Phase("Phase 1", 300) 14 phase2 = Phase("Phase 2", 600) 15 sequence = RecurringPhaseSequence("Sequence 1", [phase1, phase2], 2) 16 blocks = [phase1, sequence] 17 schedule = Schedule("Test Schedule", blocks) 18 return schedule, phase1, phase2, sequence 19 20 def test_initialization(self, setup_schedule): 21 schedule, phase1, _, _ = setup_schedule 22 assert schedule.title == "Test Schedule" 23 assert schedule.blocks == [phase1, schedule.blocks[1]] 24 assert schedule.current_block == phase1 14 25 assert schedule.state == "initial" 15 26 16 def test_schedule_start(self): 17 phase1 = Phase("Warm-up", 300) 18 schedule = Schedule([phase1]) 27 def test_default_json_string(self): 28 default_json = Schedule.default_json_string() 29 assert isinstance(default_json, str) 30 31 def test_from_json(self): 32 json_string = Schedule.default_json_string() 33 schedule = Schedule.from_json(json_string) 34 assert schedule.title == "Default" 35 assert len(schedule.blocks) == 2 36 assert isinstance(schedule.blocks[0], Phase) 37 assert isinstance(schedule.blocks[1], RecurringPhaseSequence) 38 39 def test_to_json(self, setup_schedule): 40 schedule, _, _, _ = setup_schedule 41 json_string = schedule.to_json() 42 assert isinstance(json_string, str) 43 data = json.loads(json_string) 44 assert data['title'] == "Test Schedule" 45 assert len(data['blocks']) == 2 46 47 def test_start(self, setup_schedule): 48 schedule, phase1, _, _ = setup_schedule 19 49 schedule.start() 20 21 50 assert schedule.state == "running" 22 assert schedule.current_phase.running() is True 23 24 def test_schedule_pause(self): 25 phase1 = Phase("Warm-up", 300) 26 schedule = Schedule([phase1]) 51 # assert phase1.ticks_left < phase1.initial_ticks # Assuming the phase reduces ticks when started 52 53 def test_running(self, setup_schedule): 54 schedule, _, _, _ = setup_schedule 27 55 schedule.start() 56 assert schedule.running() is True 28 57 schedule.pause() 29 30 assert schedule.state == "paused" 31 assert schedule.is_paused() is True 58 assert schedule.running() is False 32 59 33 def test_schedule_abort(self): 34 phase1 = Phase("Warm-up", 300) 35 schedule = Schedule([phase1]) 36 schedule.start() 60 def test_paused(self, setup_schedule): 61 schedule, _, _, _ = setup_schedule 62 schedule.pause() 63 assert schedule.paused() is True 64 65 def test_abort(self, setup_schedule): 66 schedule, _, _, _ = setup_schedule 37 67 schedule.abort() 38 39 assert schedule.state == "finished" 40 assert schedule.current_phase.finished() is True 68 assert schedule.state == "aborted" 41 69 42 def test_schedule_finished(self): 43 phase1 = Phase("Warm-up", 300) 44 phase2 = Phase("Workout", 600) 45 schedule = Schedule([phase1, phase2]) 46 47 assert schedule.finished() is False 48 49 phase1.start() 50 phase1.tick(300) 51 assert phase1.finished() is True 52 assert schedule.finished() is False 53 70 def test_completed(self, setup_schedule): 71 schedule, phase1, _, sequence = setup_schedule 72 schedule.tick(phase1.initial_ticks) # Complete phase1 73 schedule.tick(sequence.initial_ticks) # Complete sequence 74 schedule.tick(phase1.initial_ticks) # Complete phase1 75 schedule.tick(sequence.initial_ticks) # Complete sequence 76 print(schedule.current_block) 77 assert schedule.completed() is True 78 assert schedule.state == "completed" 79 80 def test_advance_to_next_block(self, setup_schedule): 81 schedule, _, _, sequence = setup_schedule 82 schedule.advance_to_next_block() 83 assert schedule.current_block == schedule.blocks[1] 84 85 def test_skip(self, setup_schedule): 86 schedule, _, _, sequence = setup_schedule 54 87 schedule.skip() 55 schedule.current_phase.tick(600) 56 assert schedule.finished() is True 88 assert schedule.current_block == schedule.blocks[1] # Should skip to Phase 2 within the sequence 57 89 58 def test_schedule_skip(self): 59 phase1 = Phase("Warm-up", 300) 60 phase2 = Phase("Workout", 600) 61 schedule = Schedule([phase1, phase2]) 62 63 schedule.start() 64 schedule.skip() 65 66 assert schedule.current_phase == phase2 90 def test_total_ticks_left(self, setup_schedule): 91 schedule, phase1, phase2, sequence = setup_schedule 92 expected_total_ticks = phase1.ticks_left + sequence.ticks_left 93 assert schedule.total_ticks_left() == expected_total_ticks 67 94 68 def test_schedule_skip_at_final_phase(self): 69 phase1 = Phase("Warm-up", 300) 70 schedule = Schedule([phase1]) 71 72 schedule.start() 73 schedule.skip() 74 75 assert schedule.state == "finished" 95 def test_upcoming_blocks(self, setup_schedule): 96 schedule, _, _, sequence = setup_schedule 97 assert schedule.upcoming_blocks() == [sequence] 76 98 77 def test_schedule_tick(self): 78 phase1 = Phase("Warm-up", 300) 79 phase2 = Phase("Workout", 600) 80 schedule = Schedule([phase1, phase2]) 81 82 schedule.start() 83 schedule.tick(300) 84 85 assert phase1.finished() is True 86 assert schedule.current_phase == phase2 87 assert schedule.state == "running" 99 def test_current_block_is_final(self, setup_schedule): 100 schedule, _, _, sequence = setup_schedule 101 assert schedule.current_block_is_final() is False 102 schedule.advance_to_next_block() 103 assert schedule.current_block_is_final() is True 88 104 89 def test_schedule_tick_to_completion(self): 90 phase1 = Phase("Warm-up", 300) 91 phase2 = Phase("Workout", 600) 92 schedule = Schedule([phase1, phase2]) 93 94 schedule.start() 95 schedule.tick(300) # Should finish phase1 and move to phase2 96 schedule.tick(600) # Should finish phase2 and complete the schedule 97 98 assert phase2.finished() is True 99 assert schedule.finished() is True 105 def test_tick(self, setup_schedule): 106 schedule, phase1, _, _ = setup_schedule 107 initial_ticks = phase1.ticks_left 108 schedule.tick(100) 109 assert phase1.ticks_left == initial_ticks - 100 100 110 101 def test_schedule_current_phase_is_final(self): 102 phase1 = Phase("Warm-up", 300) 103 phase2 = Phase("Workout", 600) 104 schedule = Schedule([phase1, phase2]) 105 106 assert schedule.current_phase_is_final() is False 107 108 schedule.skip() 109 assert schedule.current_phase_is_final() is True 110 111 schedule.tick(phase1.ticks_left) # Finish phase1 112 assert schedule.current_block == schedule.blocks[1] # Should advance to the next block
Note:
See TracChangeset
for help on using the changeset viewer.