35 from robotide
import pluginapi
42 from sys
import getfilesystemencoding
43 from wx.lib.filebrowsebutton
import FileBrowseButton
45 OUTPUT_ENCODING = getfilesystemencoding()
72 if self.
_panel_panel
is None:
73 self.
_panel_panel = wx.Panel(parent, wx.ID_ANY)
77 if self.
_panel_panel
is None:
82 if self.
_panel_panel
is None:
84 self.
_panel_panel.Enable(
False)
132 except AttributeError:
134 return getattr(self.
pluginplugin, name)
135 except AttributeError:
144 return "%s_%s" % (self.name.replace(
' ',
'_'), name)
147 RF_INSTALLATION_NOT_FOUND =
"""Robot Framework installation not found.<br>
148 To run tests, you need to install Robot Framework separately.<br>
149 See <a href="http://robotframework.org">http://robotframework.org</a> for
150 installation instructions.
162 _quotes_re = re.compile(
'(.*)(\".*\")(.*)?')
165 default_settings = {
"arguments":
"",
166 "output_directory":
"",
169 "are_log_names_with_suite_name":
False,
170 "are_log_names_with_timestamp":
False,
171 "are_saving_logs":
False,
172 "apply_include_tags":
False,
173 "apply_exclude_tags":
False}
176 BaseProfile.__init__(self, plugin)
182 self.
_toolbar_toolbar = wx.Panel(parent, wx.ID_ANY)
186 sizer = wx.BoxSizer(wx.VERTICAL)
188 sizer.Add(item, 0, wx.EXPAND)
189 self.
_toolbar_toolbar.SetSizer(sizer)
208 for panel
in self.
_toolbar_toolbar.GetChildren():
209 if isinstance(panel, wx.CollapsiblePane):
210 panel = panel.GetPane()
213 @overrides(BaseProfile)
215 focused = wx.Window.FindFocus()
216 if focused
not in [self._arguments, self._include_tags,
219 start, end = focused.GetSelection()
220 focused.Remove(start, max(end, start + 1))
223 from subprocess
import call
224 from tempfile
import TemporaryFile
226 with TemporaryFile(mode=
"at")
as out:
227 result = call([
"robot",
"--version"], stdout=out)
231 with TemporaryFile(mode=
"at")
as out:
232 result = call([
"robot.bat" if os.name ==
"nt" else "robot",
233 "--version"], stdout=out)
235 return "robot.bat" if os.name ==
"nt" else "robot"
238 with TemporaryFile(mode=
"at")
as out:
239 result = call([
"pybot.bat" if os.name ==
"nt" else "pybot",
240 "--version"], stdout=out)
242 return "pybot.bat" if os.name ==
"nt" else "pybot"
249 if self.output_directory
and \
250 '--outputdir' not in args
and \
252 args.extend([
'-d', os.path.abspath(self.output_directory)])
254 log_name_format =
'%s'
255 if self.are_log_names_with_suite_name:
256 log_name_format = f
'{self.plugin.model.suite.name}-%s'
257 if '--log' not in args
and '-l' not in args:
258 args.extend([
'-l', log_name_format %
'Log.html'])
259 if '--report' not in args
and '-r' not in args:
260 args.extend([
'-r', log_name_format %
'Report.html'])
261 if '--output' not in args
and '-o' not in args:
262 args.extend([
'-o', log_name_format %
'Output.xml'])
264 if self.are_saving_logs
and \
265 '--debugfile' not in args
and \
267 args.extend([
'-b', log_name_format %
'Message.log'])
269 if self.are_log_names_with_timestamp
and \
270 '--timestampoutputs' not in args
and \
274 if self.apply_include_tags
and self.include_tags:
276 args.append(
'--include=%s' % include)
278 if self.apply_exclude_tags
and self.exclude_tags:
280 args.append(
'--exclude=%s' % exclude)
296 return args.strip().strip().split()
302 for gr
in res.groups():
304 if gr
is not None and gr !=
'':
305 second_m = re.split(
'"', gr)
310 for idx
in range(0, m):
313 line.extend(second_m[idx].strip().strip().split())
315 line.append(f
"{second_m[idx]}")
317 for idx
in range(0, m):
319 line.extend(second_m[idx].strip().strip().split())
323 for idx, value
in enumerate(clean):
324 if value[-1] ==
':' and idx + 1 < len(clean):
325 clean[idx] =
''.join([value, clean[idx+1]])
333 from subprocess
import Popen, PIPE
335 p = Popen([
'echo', self.arguments], stdin=PIPE, stdout=PIPE,
336 stderr=PIPE, shell=
True)
337 output, _ = p.communicate()
338 from ctypes
import cdll
340 code_page = cdll.kernel32.GetConsoleCP()
342 os_encoding = os.getenv(
'RIDE_ENCODING', OUTPUT_ENCODING)
344 os_encoding =
'cp' + str(code_page)
347 output = output.decode(os_encoding)
348 except UnicodeDecodeError:
349 wx.MessageBox(f
"An UnicodeDecodeError occurred when processing the Arguments."
350 f
" The encoding used was '{os_encoding}'. You may try to define the environment variable"
351 f
" RIDE_ENCODING with a proper value. Other possibility, is to replace 'pythonw.exe' by 'python.exe'"
352 f
" in the Desktop Shortcut.",
"UnicodeDecodeError")
354 output = str(output).lstrip(
"b\'").lstrip(
'"').replace(
'\\r\\n',
'').replace(
'\'',
'').replace(
'\\""',
'\"').strip()
358 for idx
in range(0, len(output)):
359 if output[idx] ==
'"':
361 even = counter % 2 == 0
364 .replace(
'\\\\',
'\\').replace(
'\\r\\n',
'')
374 from subprocess
import Popen, PIPE
376 p = Popen([
'echo ' + self.arguments.replace(
'"',
'\\"')], stdin=PIPE, stdout=PIPE,
377 stderr=PIPE, shell=
True)
378 output, _ = p.communicate()
380 output = str(output).lstrip(
"b\'").replace(
'\\n',
'').rstrip(
"\'").strip()
384 for idx
in range(0, len(output)):
385 if output[idx] ==
'"':
387 even = counter % 2 == 0
390 .replace(
'\\\\',
'\\').replace(
'\\n',
'')
401 for tag
in tag_string.split(
","):
402 tag = tag.strip().replace(
' ',
'')
409 if self.are_saving_logs:
411 if self.are_log_names_with_timestamp:
412 start_timestamp =
format_time(time.time(),
'',
'-',
'')
413 base, ext = os.path.splitext(name)
414 base = f
'{base}-{start_timestamp}'
417 if self.are_log_names_with_suite_name:
418 name = f
'{self.plugin.model.suite.name}-{name}'
419 settings.extend([
'console_log_name', name])
425 if b
'not found' in error \
426 or returncode == 127
or \
427 b
'system cannot find the file specified' in error:
428 return pluginapi.RideLogMessage(
429 RF_INSTALLATION_NOT_FOUND, notify_user=
True)
433 collapsible_pane = wx.CollapsiblePane(
434 parent, wx.ID_ANY,
'Log options',
435 style=wx.CP_DEFAULT_STYLE | wx.CP_NO_TLW_RESIZE)
436 collapsible_pane.Bind(wx.EVT_COLLAPSIBLEPANE_CHANGED,
439 pane = collapsible_pane.GetPane()
440 pane.SetBackgroundColour(self.
_mysettings_mysettings.color_background)
441 pane.SetForegroundColour(self.
_mysettings_mysettings.color_foreground)
442 label = Label(pane, label=
"Output directory: ")
445 "removed due unicode_error (delete this)",
450 button.SetBackgroundColour(self.
_mysettings_mysettings.color_secondary_background)
451 button.SetForegroundColour(self.
_mysettings_mysettings.color_secondary_foreground)
452 horizontal_sizer = wx.BoxSizer(wx.HORIZONTAL)
453 horizontal_sizer.Add(label, 0,
454 wx.ALIGN_CENTER_VERTICAL | wx.LEFT, 10)
456 horizontal_sizer.Add(button, 0, wx.LEFT | wx.RIGHT, 10)
459 pane, self.are_log_names_with_suite_name,
462 pane, self.are_log_names_with_timestamp,
465 pane, self.are_saving_logs,
468 vertical_sizer = wx.BoxSizer(wx.VERTICAL)
469 vertical_sizer.Add(horizontal_sizer, 0, wx.EXPAND)
470 vertical_sizer.Add(suite_name_outputs_cb, 0, wx.LEFT | wx.TOP, 10)
471 vertical_sizer.Add(timestamp_outputs_cb, 0, wx.LEFT | wx.TOP, 10)
472 vertical_sizer.Add(save_logs_cb, 0, wx.LEFT | wx.TOP | wx.BOTTOM, 10)
473 pane.SetSizer(vertical_sizer)
474 return collapsible_pane
478 self.
set_settingset_setting(
"output_directory", value)
482 dlg = wx.DirDialog(
None,
"Select Logs Directory",
483 path, wx.DD_DEFAULT_STYLE)
484 dlg.SetBackgroundColour(self.
_mysettings_mysettings.color_background)
485 dlg.SetForegroundColour(self.
_mysettings_mysettings.color_foreground)
486 for item
in dlg.GetChildren():
487 item.SetBackgroundColour(self.
_mysettings_mysettings.color_secondary_background)
488 item.SetForegroundColour(self.
_mysettings_mysettings.color_secondary_foreground)
489 if dlg.ShowModal() == wx.ID_OK
and dlg.Path:
494 self.
set_settingset_setting(
"are_log_names_with_suite_name", evt.IsChecked())
497 self.
set_settingset_setting(
"are_log_names_with_timestamp", evt.IsChecked())
500 self.
set_settingset_setting(
"are_saving_logs", evt.IsChecked())
503 collapsible_pane = wx.CollapsiblePane(
504 parent, wx.ID_ANY,
'Arguments',
505 style=wx.CP_DEFAULT_STYLE | wx.CP_NO_TLW_RESIZE)
506 collapsible_pane.Bind(wx.EVT_COLLAPSIBLEPANE_CHANGED,
509 pane = collapsible_pane.GetPane()
510 pane.SetBackgroundColour(self.
_mysettings_mysettings.color_background)
511 pane.SetForegroundColour(self.
_mysettings_mysettings.color_foreground)
514 "removed due unicode_error (delete this)",
516 self.
_args_text_ctrl_args_text_ctrl.SetToolTip(
"Arguments for the test run. "
517 "Arguments are space separated list.")
520 horizontal_sizer = wx.BoxSizer(wx.HORIZONTAL)
522 wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, 10)
524 pane.SetSizer(horizontal_sizer)
526 return collapsible_pane
537 'red' if invalid_message
else self.
_mysettings_mysettings.color_secondary_background)
539 'white' if invalid_message
else self.
_mysettings_mysettings.color_secondary_foreground)
540 if not bool(invalid_message):
541 invalid_message =
"Arguments for the test run. " \
542 "Arguments are space separated list."
550 clean_args = args.split(
"`")
552 for idx, item
in enumerate(clean_args):
553 clean_args[idx] = item.strip()
554 if clean_args[idx]
and clean_args[idx][0] !=
'-':
555 clean_args[idx] =
'arg'
556 args =
" ".join(clean_args)
558 _, invalid = ArgumentParser(USAGE).parse_args(args)
560 return 'Does not execute - help or version option given'
561 except (DataError, Exception)
as e:
567 return f
'Unknown option(s): {invalid}'
574 collapsible_pane = wx.CollapsiblePane(
575 parent, wx.ID_ANY,
'Tests filters',
576 style=wx.CP_DEFAULT_STYLE | wx.CP_NO_TLW_RESIZE)
577 collapsible_pane.Bind(wx.EVT_COLLAPSIBLEPANE_CHANGED,
580 pane = collapsible_pane.GetPane()
581 pane.SetBackgroundColour(self.
_mysettings_mysettings.color_background)
582 pane.SetForegroundColour(self.
_mysettings_mysettings.color_foreground)
583 include_cb = self.
_create_checkbox_create_checkbox(pane, self.apply_include_tags,
584 "Only run tests with these tags:",
586 exclude_cb = self.
_create_checkbox_create_checkbox(pane, self.apply_exclude_tags,
587 "Skip tests with these tags:",
590 self.
_create_text_ctrl_create_text_ctrl(pane, self.include_tags,
"unicode_error",
592 self.apply_include_tags)
594 self.
_create_text_ctrl_create_text_ctrl(pane, self.exclude_tags,
"unicode error",
596 self.apply_exclude_tags)
601 horizontal_sizer = wx.BoxSizer(wx.HORIZONTAL)
602 horizontal_sizer.Add(include_cb, 0, wx.ALIGN_CENTER_VERTICAL)
604 horizontal_sizer.Add(exclude_cb, 0, wx.ALIGN_CENTER_VERTICAL | wx.LEFT, 10)
607 sizer = wx.BoxSizer(wx.HORIZONTAL)
608 sizer.Add(horizontal_sizer, 1, wx.LEFT | wx.RIGHT | wx.BOTTOM, 10)
611 return collapsible_pane
614 parent = self.
_toolbar_toolbar.GetParent().GetParent()
618 self.
set_settingset_setting(
"apply_include_tags", evt.IsChecked())
622 self.
set_settingset_setting(
"apply_exclude_tags", evt.IsChecked())
633 checkbox = wx.CheckBox(parent, wx.ID_ANY, title)
634 checkbox.SetValue(value)
635 parent.Bind(wx.EVT_CHECKBOX, handler, checkbox)
640 text_change_handler, enable=True):
642 text_ctrl = wx.TextCtrl(parent, wx.ID_ANY, value=value)
644 text_ctrl = wx.TextCtrl(parent, wx.ID_ANY, value=value_for_error)
645 text_ctrl.Bind(wx.EVT_TEXT, text_change_handler)
646 text_ctrl.Enable(enable)
653 name =
"custom script"
654 default_settings =
dict(PybotProfile.default_settings, runner_script=
"")
659 return self.runner_script.strip()
662 return os.path.dirname(self.runner_script)
664 @overrides(PybotProfile)
679 panel = wx.Panel(parent, wx.ID_ANY)
681 panel, labelText=
"Script to run tests:", size=(-1, -1),
683 self.
_script_ctrl_script_ctrl.SetValue(self.runner_script)
685 sizer = wx.BoxSizer(wx.VERTICAL)
686 sizer.Add(self.
_script_ctrl_script_ctrl, 0, wx.EXPAND | wx.LEFT | wx.RIGHT, 5)
688 panel.SetSizerAndFit(sizer)
Base class for all test runner profiles.
def get_toolbar(self, parent)
Returns a panel with toolbar controls for this profile.
def __init__(self, plugin)
plugin is required so that the profiles can save their settings
def __getattr__(self, name)
Provides attribute access to profile's settings.
def _create_error_log_message(self, error, returncode)
def delete_pressed(self)
Handle delete key pressing.
dictionary default_settings
def set_setting(self, name, value)
Sets a plugin setting.
def _get_setting_name(self, name)
Adds profile's name to the setting.
def get_settings(self)
Return a list of settings unique to this profile.
def disable_toolbar(self)
def get_command(self)
Returns a command for this profile.
def get_command_args(self)
Return a list of command arguments unique to this profile.
def format_error(self, error, returncode)
A runner profile which uses script given by the use.
def _get_run_script_panel(self, parent)
def get_command(self)
Returns a command for this profile.
def get_toolbar_items(self, parent)
def OnCustomScriptChanged(self, evt)
def _create_error_log_message(self, error, returncode)
def _validate_arguments(self, args)
A runner profile which uses robot.
_output_directory_text_ctrl
def _create_text_ctrl(parent, value, value_for_error, text_change_handler, enable=True)
def get_toolbar_items(self, parent)
def OnExcludeCheckbox(self, evt)
def OnExcludeTagsChanged(self, evt)
def _get_invalid_message(args)
def OnIncludeCheckbox(self, evt)
def get_toolbar(self, parent)
Returns a panel with toolbar controls for this profile.
def get_command_args(self)
Return a list of command arguments unique to this profile.
def OnOutputDirectoryChanged(self, evt)
def _create_checkbox(parent, value, title, handler)
def _parse_windows_command(self)
def OnIncludeTagsChanged(self, evt)
def _get_tags_from_string(tag_string)
def _save_filenames(self)
def get_command(self)
Returns a command for this profile.
def OnTimestampOutputsCheckbox(self, evt)
def _enable_toolbar(self, enable=True)
def OnCollapsiblePaneChanged(self, evt=None)
def OnSaveLogsCheckbox(self, evt)
def get_settings(self)
Return a list of settings unique to this profile.
def _validate_arguments(self, args)
def _get_arguments_panel(self, parent)
def delete_pressed(self)
Handle delete key pressing.
def disable_toolbar(self)
def _get_tags_panel(self, parent)
Create a panel to input include/exclude tags.
def _handle_select_directory(self, event)
def OnArgumentsChanged(self, evt)
def _create_error_log_message(self, error, returncode)
def OnSuiteNameOutputsCheckBox(self, evt)
def _parse_posix_command(self)
def _get_log_options_panel(self, parent)
def __init__(self, plugin)
plugin is required so that the profiles can save their settings
def format_time(timetuple_or_epochsecs, daysep='', daytimesep=' ', timesep=':', millissep=None)
Returns a timestamp formatted from given time using separators.