Coverage for src/robotide/run/ui.py: 42%
140 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-06 10:40 +0100
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-06 10:40 +0100
1# Copyright 2008-2015 Nokia Networks
2# Copyright 2016- Robot Framework Foundation
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
16import builtins
17import wx
19from .process import Process
20from ..widgets import Font, VerticalSizer, HorizontalSizer, RIDEDialog
21from ..log import LogOutput
22from ..publish import RideRunnerStopped
24_ = wx.GetTranslation # To keep linter/code analyser happy
25builtins.__dict__['_'] = wx.GetTranslation
27FINISHED = _('finished')
28RUN_AGAIN = _('Run Again')
29RUNNING = _('running')
30STOP = _('Stop')
33def get_label(label: str) -> str:
34 if label == RUN_AGAIN:
35 return 'on_run_again'
36 if label == STOP:
37 return 'on_stop'
38 raise ValueError
41class Runner(wx.EvtHandler):
43 def __init__(self, config, notebook):
44 wx.EvtHandler.__init__(self) 1cdeb
45 self.Bind(wx.EVT_TIMER, self.on_timer) 1cdeb
46 self.name = config.name 1cdeb
47 self._process = None 1cdeb
48 self._timer = wx.Timer(self) 1cdeb
49 self._config = config 1cdeb
50 self._window = self._get_output_window(notebook) 1cdeb
51 self.output_panel = self._window.output_panel 1cdeb
52 self._pid = None 1cdeb
54 @property
55 def pid(self):
56 return self._pid
58 def _get_output_window(self, notebook):
59 return _OutputWindow(notebook, self)
61 def run(self):
62 self._process = Process(self._config.command) 1cdeb
63 # print(f"DEBUG: runanything.py Runner run process object={self._process}"
64 # f"\nCommand: {self._config.command}")
65 if self._process is None: 65 ↛ 66line 65 didn't jump to line 66 because the condition on line 65 was never true1cdeb
66 message_box = RIDEDialog(message=f"FAILED TO RUN {self._config.command}", style=wx.ICON_ERROR)
67 message_box.ShowModal()
68 return
69 try: 1cdeb
70 self._process.start() 1cdeb
71 self._timer.Start(500) 1cdeb
72 self._pid = self._process.pid 1cdeb
73 return self._pid 1cdeb
74 except Exception as err:
75 message_box = RIDEDialog(message=str(err), style=wx.ICON_ERROR)
76 message_box.ShowModal()
77 return -1
79 def on_timer(self, event=None):
80 __ = event 1cdeb
81 finished = self._process.is_finished() 1cdeb
82 self._window.update_output(self._process.get_output(), finished) 1cdeb
83 if finished: 83 ↛ exitline 83 didn't return from function 'on_timer' because the condition on line 83 was always true1cdeb
84 self._timer.Stop() 1cdeb
86 def stop(self):
87 try: 1b
88 self._process.stop() 1b
89 except Exception as err:
90 message_box = RIDEDialog(message=str(err), style=wx.ICON_ERROR)
91 message_box.ShowModal()
94class _OutputWindow(wx.Panel): # wx.ScrolledWindow):
96 def __init__(self, notebook, runner):
97 wx.Panel.__init__(self, notebook)
98 self.notebook = notebook
99 self.output_panel = self._create_ui()
100 self._add_to_notebook(notebook, runner.name)
101 self._runner = runner
102 self._font_size = Font().fixed.GetPointSize() # DEBUG: This should be the font from General
104 def _create_ui(self):
105 self.SetSizer(VerticalSizer())
106 self.toolbar = HorizontalSizer()
107 self.toolbar.Add(self._create_state_button())
108 self.Sizer.Add(self.toolbar)
109 wsize = self.GetParent().GetSize()[0]
110 self.Sizer.Add(wx.StaticLine(self, size=(wsize, 5)))
111 output_panel = _OutputDisplay(self)
112 self.Sizer.add_expanding(output_panel)
113 self.Sizer.Layout()
114 return output_panel
116 def _create_state_button(self):
117 self._state_button = _StopAndRunAgainButton(self)
118 return self._state_button
120 def _add_to_notebook(self, notebook, name):
121 notebook.add_tab(self, f"{name} ({RUNNING})", allow_closing=False)
122 notebook.show_tab(self)
124 def update_output(self, output, finished=False):
125 if output:
126 self.output_panel.update(output)
127 self.SetVirtualSize(self.output_panel.Size)
128 if finished:
129 RideRunnerStopped(process=self._runner.pid).publish()
130 self._rename_tab(f"{self._runner.name} ({FINISHED})")
131 self.Parent.allow_closing(self)
132 self._state_button.enable_run_again()
133 size = (max(85, self._font_size * len(' ' + RUN_AGAIN + ' ')), max(28, self._font_size * 3))
134 self._state_button.SetSize(size)
136 def on_stop(self):
137 self.Parent.allow_closing(self)
138 self._runner.stop()
140 def on_run_again(self):
141 self.output_panel.clear()
142 self._rename_tab(f"{self._runner.name} ({RUNNING})")
143 self.Parent.disallow_closing(self)
144 self._state_button.reset()
145 size = (max(85, self._font_size * len(' ' + STOP + ' ')), max(28, self._font_size * 3))
146 self._state_button.SetSize(size)
147 self._runner.run()
149 def _rename_tab(self, name):
150 self.Parent.rename_tab(self, name)
153class _OutputDisplay(LogOutput):
155 def __init__(self, parent):
156 self._log = []
157 LogOutput.__init__(self, parent)
159 def update(self, addition):
160 try:
161 self._log.append(addition.decode('UTF-8', 'ignore'))
162 self.update_log(self._log)
163 except AttributeError:
164 self._log.append("ERROR")
165 self.update_log(self._log)
166 getattr(self.Parent, 'on_stop')()
168 def clear(self):
169 self._log = ['']
170 self.update_log(self._log)
173class _StopAndRunAgainButton(wx.Button):
175 def __init__(self, parent):
176 wx.Button.__init__(self, parent, label=' '+STOP+' ')
177 self.Bind(wx.EVT_BUTTON, self.on_click, self)
179 def on_click(self, event):
180 __ = event
181 self.Enable(False)
182 name = get_label(self.LabelText)
183 getattr(self.Parent, name)()
185 def enable_run_again(self):
186 self.Enable()
187 self.SetLabel(RUN_AGAIN)
189 def reset(self):
190 self.Enable()
191 self.SetLabel(STOP)