|
1 | 1 | import datetime
|
2 | 2 |
|
| 3 | + |
3 | 4 | class Clock(object):
|
4 | 5 | def __init__(self):
|
5 | 6 | self.reset()
|
| 7 | + |
6 | 8 | def reset(self):
|
7 | 9 | self.accumulator = datetime.timedelta(0)
|
8 | 10 | self.started = None
|
| 11 | + |
9 | 12 | def start(self):
|
10 | 13 | if not self.started:
|
11 | 14 | self.started = datetime.datetime.utcnow()
|
| 15 | + |
12 | 16 | def stop(self):
|
13 | 17 | if self.started:
|
14 |
| - self.accumulator += ( |
15 |
| - datetime.datetime.utcnow() - self.started |
16 |
| - ) |
| 18 | + self.accumulator += datetime.datetime.utcnow() - self.started |
17 | 19 | self.started = None
|
| 20 | + |
18 | 21 | @property
|
19 | 22 | def elapsed(self):
|
20 | 23 | if self.started:
|
21 |
| - return self.accumulator + ( |
22 |
| - datetime.datetime.utcnow() - self.started |
23 |
| - ) |
| 24 | + return self.accumulator + (datetime.datetime.utcnow() - self.started) |
24 | 25 | return self.accumulator
|
| 26 | + |
25 | 27 | def __repr__(self):
|
26 | 28 | return "<Clock {} ({})>".format(
|
27 |
| - self.elapsed, |
28 |
| - 'started' if self.started else 'stopped' |
| 29 | + self.elapsed, "started" if self.started else "stopped" |
29 | 30 | )
|
30 | 31 |
|
| 32 | + |
31 | 33 | def _query(self, prefix, question, first_answer, second_answer):
|
32 |
| - for item in prefix: |
33 |
| - print(item) |
34 |
| - return input("{question} ({first_answer}/{second_answer})").to_lower().starts_with(first_answer.to_lower()) |
| 34 | + for item in prefix: |
| 35 | + print(item) |
| 36 | + return ( |
| 37 | + input("{question} ({first_answer}/{second_answer})") |
| 38 | + .to_lower() |
| 39 | + .starts_with(first_answer.to_lower()) |
| 40 | + ) |
| 41 | + |
35 | 42 |
|
36 | 43 | class ManualSection:
|
37 | 44 | def __init__(self, go):
|
38 | 45 | self.go = go
|
| 46 | + |
39 | 47 | def __enter__(self):
|
40 | 48 | self.go._automated.stop()
|
41 | 49 | self.go._manual.start()
|
| 50 | + |
42 | 51 | def __exit__(self):
|
43 | 52 | self.go._manual.stop()
|
44 | 53 | self.go._automated.start()
|
45 | 54 |
|
46 | 55 |
|
47 | 56 | class Process:
|
48 |
| - def __init__(self): |
49 |
| - self._automated = Clock() |
50 |
| - self._automated.start() |
51 |
| - self._manual = Clock() |
52 |
| - self._test_result = [] |
53 |
| - self._automated_steps = 0 |
54 |
| - self._manual_steps = 0 |
55 |
| - |
56 |
| - @classmethod |
57 |
| - def run(perform, verify): |
58 |
| - go = Process() |
59 |
| - with ManualSection(self): |
60 |
| - do_perform = _query([], "Do you wish to perform the process or verify it?", "P", "V") |
61 |
| - if(do_perform): |
62 |
| - perform(go) |
63 |
| - else: |
64 |
| - verify(go) |
65 |
| - go._print_stats() |
66 |
| - |
67 |
| - def do(self, operation): |
68 |
| - self._automatic_steps += 1 |
69 |
| - operation() |
70 |
| - |
71 |
| - def tell(self, message): |
72 |
| - self._manual_steps += 1 |
73 |
| - with ManualSection(self): |
74 |
| - print(message) |
75 |
| - input("press enter when done") |
76 |
| - |
77 |
| - def ask(self, condition, operation): |
78 |
| - self._manual_steps += 1 |
79 |
| - with ManualSection(self): |
80 |
| - should_do_it = _query([condition], "Should I perform this step?", "Y", "N") |
81 |
| - if(should_do_it): |
82 |
| - operation() |
83 |
| - |
84 |
| - def ask_yes_no(self, condition): |
85 |
| - self._manual_steps += 1 |
86 |
| - with ManualSection(self): |
87 |
| - return _query([condition], "Should I perform this step?", "Y", "N") |
88 |
| - |
89 |
| -# Conflicts with built-in keyword `if`. TODO: pick a non-conflicting name. |
90 |
| -# def if(self, condition, operation): |
91 |
| -# self._automatic_steps += 1 |
92 |
| -# if(condition()): |
93 |
| -# operation() |
94 |
| - |
95 |
| - def verify(self, condition): |
96 |
| - initial = self._manual_steps |
97 |
| - if(not condition()): |
98 |
| - self._test_result.append(f"Failed expectation: {condition}") |
99 |
| - if(initial == self._manual_steps |
100 |
| -): |
101 |
| - self._automated_steps += 1 |
102 |
| - |
103 |
| - def that(self, condition): |
104 |
| - def impl(): |
105 |
| - self._manual_steps += 1 |
106 |
| - with ManualSection(self): |
107 |
| - return _query( |
108 |
| - [f"Please verify whether {condition}."], |
109 |
| - "Is this right?", |
110 |
| - "Y", "N") |
111 |
| - return impl |
112 |
| - |
113 |
| - def print_test_results(self): |
114 |
| - if(self._test_result): |
115 |
| - print("Verification failed. Please fix the process and try again.") |
116 |
| - for failure in self._test_result: |
117 |
| - print(failure) |
118 |
| - |
119 |
| - def _print_stats(self): |
120 |
| - self._automated.stop() |
121 |
| - total_time = self._automated.elapsed + self._manual.elapsed |
122 |
| - print(f"Process complete in {total_time}.") |
123 |
| - print(f" Automated: {self._automated_steps} steps in {self._automated.elapsed}.") |
124 |
| - print(f" Manual: {self._manual_steps} steps in {self._manual.elapsed}.") |
| 57 | + def __init__(self): |
| 58 | + self._automated = Clock() |
| 59 | + self._automated.start() |
| 60 | + self._manual = Clock() |
| 61 | + self._test_result = [] |
| 62 | + self._automated_steps = 0 |
| 63 | + self._manual_steps = 0 |
| 64 | + |
| 65 | + @classmethod |
| 66 | + def run(perform, verify): |
| 67 | + go = Process() |
| 68 | + with ManualSection(self): |
| 69 | + do_perform = _query( |
| 70 | + [], "Do you wish to perform the process or verify it?", "P", "V" |
| 71 | + ) |
| 72 | + if do_perform: |
| 73 | + perform(go) |
| 74 | + else: |
| 75 | + verify(go) |
| 76 | + go._print_stats() |
| 77 | + |
| 78 | + def do(self, operation): |
| 79 | + self._automatic_steps += 1 |
| 80 | + operation() |
| 81 | + |
| 82 | + def tell(self, message): |
| 83 | + self._manual_steps += 1 |
| 84 | + with ManualSection(self): |
| 85 | + print(message) |
| 86 | + input("press enter when done") |
| 87 | + |
| 88 | + def ask(self, condition, operation): |
| 89 | + self._manual_steps += 1 |
| 90 | + with ManualSection(self): |
| 91 | + should_do_it = _query([condition], "Should I perform this step?", "Y", "N") |
| 92 | + if should_do_it: |
| 93 | + operation() |
| 94 | + |
| 95 | + def ask_yes_no(self, condition): |
| 96 | + self._manual_steps += 1 |
| 97 | + with ManualSection(self): |
| 98 | + return _query([condition], "Should I perform this step?", "Y", "N") |
| 99 | + |
| 100 | + # Conflicts with built-in keyword `if`. TODO: pick a non-conflicting name. |
| 101 | + # def if(self, condition, operation): |
| 102 | + # self._automatic_steps += 1 |
| 103 | + # if(condition()): |
| 104 | + # operation() |
| 105 | + |
| 106 | + def verify(self, condition): |
| 107 | + initial = self._manual_steps |
| 108 | + if not condition(): |
| 109 | + self._test_result.append(f"Failed expectation: {condition}") |
| 110 | + if initial == self._manual_steps: |
| 111 | + self._automated_steps += 1 |
| 112 | + |
| 113 | + def that(self, condition): |
| 114 | + def impl(): |
| 115 | + self._manual_steps += 1 |
| 116 | + with ManualSection(self): |
| 117 | + return _query( |
| 118 | + [f"Please verify whether {condition}."], "Is this right?", "Y", "N" |
| 119 | + ) |
| 120 | + |
| 121 | + return impl |
| 122 | + |
| 123 | + def print_test_results(self): |
| 124 | + if self._test_result: |
| 125 | + print("Verification failed. Please fix the process and try again.") |
| 126 | + for failure in self._test_result: |
| 127 | + print(failure) |
| 128 | + |
| 129 | + def _print_stats(self): |
| 130 | + self._automated.stop() |
| 131 | + total_time = self._automated.elapsed + self._manual.elapsed |
| 132 | + print(f"Process complete in {total_time}.") |
| 133 | + print( |
| 134 | + f" Automated: {self._automated_steps} steps in {self._automated.elapsed}." |
| 135 | + ) |
| 136 | + print(f" Manual: {self._manual_steps} steps in {self._manual.elapsed}.") |
0 commit comments