Robot Framework
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 current_thread, main_thread
18 import signal
19 
20 from robot.errors import ExecutionFailed
21 from robot.output import LOGGER
22 
23 
25 
26  def __init__(self):
27  self._signal_count_signal_count = 0
28  self._running_keyword_running_keyword = False
29  self._orig_sigint_orig_sigint = None
30  self._orig_sigterm_orig_sigterm = None
31 
32  def __call__(self, signum, frame):
33  self._signal_count_signal_count += 1
34  LOGGER.info('Received signal: %s.' % signum)
35  if self._signal_count_signal_count > 1:
36  sys.__stderr__.write('Execution forcefully stopped.\n')
37  raise SystemExit()
38  sys.__stderr__.write('Second signal will force exit.\n')
39  if self._running_keyword_running_keyword:
40  self._stop_execution_gracefully_stop_execution_gracefully()
41 
43  raise ExecutionFailed('Execution terminated by signal', exit=True)
44 
45  def __enter__(self):
46  if self._can_register_signal_can_register_signal_can_register_signal:
47  self._orig_sigint_orig_sigint = signal.getsignal(signal.SIGINT)
48  self._orig_sigterm_orig_sigterm = signal.getsignal(signal.SIGTERM)
49  for signum in signal.SIGINT, signal.SIGTERM:
50  self._register_signal_handler_register_signal_handler(signum)
51  return self
52 
53  def __exit__(self, *exc_info):
54  if self._can_register_signal_can_register_signal_can_register_signal:
55  signal.signal(signal.SIGINT, self._orig_sigint_orig_sigint or signal.SIG_DFL)
56  signal.signal(signal.SIGTERM, self._orig_sigterm_orig_sigterm or signal.SIG_DFL)
57 
58  @property
59  _can_register_signal = property
60 
62  return signal and current_thread() is main_thread()
63 
64  def _register_signal_handler(self, signum):
65  try:
66  signal.signal(signum, self)
67  except ValueError as err:
68  self._warn_about_registeration_error_warn_about_registeration_error(signum, err)
69 
70  def _warn_about_registeration_error(self, signum, err):
71  name, ctrlc = {signal.SIGINT: ('INT', 'or with Ctrl-C '),
72  signal.SIGTERM: ('TERM', '')}[signum]
73  LOGGER.warn('Registering signal %s failed. Stopping execution '
74  'gracefully with this signal %sis not possible. '
75  'Original error was: %s' % (name, ctrlc, err))
76 
77  def start_running_keyword(self, in_teardown):
78  self._running_keyword_running_keyword = True
79  if self._signal_count_signal_count and not in_teardown:
80  self._stop_execution_gracefully_stop_execution_gracefully()
81 
83  self._running_keyword_running_keyword = False
84 
85 
86 STOP_SIGNAL_MONITOR = _StopSignalMonitor()
Used for communicating failures in test execution.
Definition: errors.py:178
def _warn_about_registeration_error(self, signum, err)