Robot Framework Integrated Development Environment (RIDE)
signalhandler.py
Go to the documentation of this file.
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.
15 
16 import sys
17 from threading import currentThread
18 import signal
19 
20 from robotide.lib.robot.errors import ExecutionFailed
21 from robotide.lib.robot.output import LOGGER
22 from robotide.lib.robot.utils import JYTHON
23 
24 if JYTHON:
25  from java.lang import IllegalArgumentException
26 else:
27  IllegalArgumentException = ValueError
28 
29 
31 
32  def __init__(self):
33  self._signal_count_signal_count = 0
34  self._running_keyword_running_keyword = False
35  self._orig_sigint_orig_sigint = None
36  self._orig_sigterm_orig_sigterm = None
37 
38  def __call__(self, signum, frame):
39  self._signal_count_signal_count += 1
40  LOGGER.info('Received signal: %s.' % signum)
41  if self._signal_count_signal_count > 1:
42  sys.__stderr__.write('Execution forcefully stopped.\n')
43  raise SystemExit()
44  sys.__stderr__.write('Second signal will force exit.\n')
45  if self._running_keyword_running_keyword and not JYTHON:
46  self._stop_execution_gracefully_stop_execution_gracefully()
47 
49  raise ExecutionFailed('Execution terminated by signal', exit=True)
50 
51  def __enter__(self):
52  if self._can_register_signal_can_register_signal_can_register_signal:
53  self._orig_sigint_orig_sigint = signal.getsignal(signal.SIGINT)
54  self._orig_sigterm_orig_sigterm = signal.getsignal(signal.SIGTERM)
55  for signum in signal.SIGINT, signal.SIGTERM:
56  self._register_signal_handler_register_signal_handler(signum)
57  return self
58 
59  def __exit__(self, *exc_info):
60  if self._can_register_signal_can_register_signal_can_register_signal:
61  signal.signal(signal.SIGINT, self._orig_sigint_orig_sigint or signal.SIG_DFL)
62  signal.signal(signal.SIGTERM, self._orig_sigterm_orig_sigterm or signal.SIG_DFL)
63 
64  @property
65  _can_register_signal = property
66 
68  return signal and currentThread().getName() == 'MainThread'
69 
70  def _register_signal_handler(self, signum):
71  try:
72  signal.signal(signum, self)
73  except (ValueError, IllegalArgumentException) as err:
74  # IllegalArgumentException due to http://bugs.jython.org/issue1729
75  self._warn_about_registeration_error_warn_about_registeration_error(signum, err)
76 
77  def _warn_about_registeration_error(self, signum, err):
78  name, ctrlc = {signal.SIGINT: ('INT', 'or with Ctrl-C '),
79  signal.SIGTERM: ('TERM', '')}[signum]
80  LOGGER.warn('Registering signal %s failed. Stopping execution '
81  'gracefully with this signal %sis not possible. '
82  'Original error was: %s' % (name, ctrlc, err))
83 
84  def start_running_keyword(self, in_teardown):
85  self._running_keyword_running_keyword = True
86  if self._signal_count_signal_count and not in_teardown:
87  self._stop_execution_gracefully_stop_execution_gracefully()
88 
90  self._running_keyword_running_keyword = False
91 
92 
93 STOP_SIGNAL_MONITOR = _StopSignalMonitor()
Used for communicating failures in test execution.
Definition: errors.py:177