Robot Framework
listeners.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 os.path
17 
18 from robot.errors import DataError
19 from robot.utils import Importer, is_string, split_args_from_name_or_path, type_name
20 
21 from .listenermethods import ListenerMethods, LibraryListenerMethods
22 from .loggerhelper import AbstractLoggerProxy, IsLogged
23 from .logger import LOGGER
24 
25 
26 class Listeners:
27 
30  _method_names = ('start_suite', 'end_suite', 'start_test', 'end_test',
31  'start_keyword', 'end_keyword', 'log_message', 'message',
32  'output_file', 'report_file', 'log_file', 'debug_file',
33  'xunit_file', 'library_import', 'resource_import',
34  'variables_import', 'close')
35 
36  def __init__(self, listeners, log_level='INFO'):
37  self._is_logged_is_logged = IsLogged(log_level)
38  listeners = ListenerProxy.import_listeners(listeners,
39  self._method_names_method_names)
40  for name in self._method_names_method_names:
41  method = ListenerMethods(name, listeners)
42  if name.endswith(('_keyword', '_file', '_import', 'log_message')):
43  name = '_' + name
44  setattr(self, name, method)
45 
46  def set_log_level(self, level):
47  self._is_logged_is_logged.set_level(level)
48 
49  def start_keyword(self, kw):
50  if kw.type not in (kw.IF_ELSE_ROOT, kw.TRY_EXCEPT_ROOT):
51  self._start_keyword(kw)
52 
53  def end_keyword(self, kw):
54  if kw.type not in (kw.IF_ELSE_ROOT, kw.TRY_EXCEPT_ROOT):
55  self._end_keyword(kw)
56 
57  def log_message(self, msg):
58  if self._is_logged_is_logged(msg.level):
59  self._log_message(msg)
60 
61  def imported(self, import_type, name, attrs):
62  method = getattr(self, '_%s_import' % import_type.lower())
63  method(name, attrs)
64 
65  def output_file(self, file_type, path):
66  method = getattr(self, '_%s_file' % file_type.lower())
67  method(path)
68 
69  def __bool__(self):
70  return any(isinstance(method, ListenerMethods) and method
71  for method in self.__dict__.values())
72 
73 
75 
78  _method_names = ('start_suite', 'end_suite', 'start_test', 'end_test',
79  'start_keyword', 'end_keyword', 'log_message', 'message',
80  'close')
81 
82  def __init__(self, log_level='INFO'):
83  self._is_logged_is_logged = IsLogged(log_level)
84  for name in self._method_names_method_names:
85  method = LibraryListenerMethods(name)
86  if name == 'log_message':
87  name = '_' + name
88  setattr(self, name, method)
89 
90  def register(self, listeners, library):
91  listeners = ListenerProxy.import_listeners(listeners,
92  self._method_names_method_names,
93  prefix='_',
94  raise_on_error=True)
95  for method in self._listener_methods_listener_methods():
96  method.register(listeners, library)
97 
98  def _listener_methods(self):
99  return [method for method in self.__dict__.values()
100  if isinstance(method, LibraryListenerMethods)]
101 
102  def unregister(self, library, close=False):
103  if close:
104  self.close(library=library)
105  for method in self._listener_methods_listener_methods():
106  method.unregister(library)
107 
108  def new_suite_scope(self):
109  for method in self._listener_methods_listener_methods():
110  method.new_suite_scope()
111 
113  for method in self._listener_methods_listener_methods():
114  method.discard_suite_scope()
115 
116  def set_log_level(self, level):
117  self._is_logged_is_logged.set_level(level)
118 
119  def log_message(self, msg):
120  if self._is_logged_is_logged(msg.level):
121  self._log_message(msg)
122 
123  def imported(self, import_type, name, attrs):
124  pass
125 
126  def output_file(self, file_type, path):
127  pass
128 
129 
130 class ListenerProxy(AbstractLoggerProxy):
131 
134  _no_method = None
135 
136  def __init__(self, listener, method_names, prefix=None):
137  listener, name = self._import_listener_import_listener(listener)
138  AbstractLoggerProxy.__init__(self, listener, method_names, prefix)
139  self.namename = name
140  self.versionversion = self._get_version_get_version(listener)
141  if self.versionversion == 3:
142  self.start_keywordstart_keyword = self.end_keywordend_keyword = None
143  self.library_importlibrary_import = self.resource_importresource_import = self.variables_importvariables_import = None
144 
145  def _import_listener(self, listener):
146  if not is_string(listener):
147  # Modules have `__name__`, with others better to use `type_name`.
148  name = getattr(listener, '__name__', None) or type_name(listener)
149  return listener, name
150  name, args = split_args_from_name_or_path(listener)
151  importer = Importer('listener', logger=LOGGER)
152  listener = importer.import_class_or_module(os.path.normpath(name),
153  instantiate_with_args=args)
154  return listener, name
155 
156  def _get_version(self, listener):
157  try:
158  version = int(listener.ROBOT_LISTENER_API_VERSION)
159  if version not in (2, 3):
160  raise ValueError
161  except AttributeError:
162  raise DataError("Listener '%s' does not have mandatory "
163  "'ROBOT_LISTENER_API_VERSION' attribute."
164  % self.namename)
165  except (ValueError, TypeError):
166  raise DataError("Listener '%s' uses unsupported API version '%s'."
167  % (self.namename, listener.ROBOT_LISTENER_API_VERSION))
168  return version
169 
170  @classmethod
171  def import_listeners(cls, listeners, method_names, prefix=None,
172  raise_on_error=False):
173  imported = []
174  for listener in listeners:
175  try:
176  imported.append(cls(listener, method_names, prefix))
177  except DataError as err:
178  name = listener if is_string(listener) else type_name(listener)
179  msg = "Taking listener '%s' into use failed: %s" % (name, err)
180  if raise_on_error:
181  raise DataError(msg)
182  LOGGER.error(msg)
183  return imported
def imported(self, import_type, name, attrs)
Definition: listeners.py:123
def output_file(self, file_type, path)
Definition: listeners.py:126
def unregister(self, library, close=False)
Definition: listeners.py:102
def register(self, listeners, library)
Definition: listeners.py:90
def __init__(self, log_level='INFO')
Definition: listeners.py:82
def _get_version(self, listener)
Definition: listeners.py:156
def __init__(self, listener, method_names, prefix=None)
Definition: listeners.py:136
def import_listeners(cls, listeners, method_names, prefix=None, raise_on_error=False)
Definition: listeners.py:172
def _import_listener(self, listener)
Definition: listeners.py:145
def output_file(self, file_type, path)
Definition: listeners.py:65
def set_log_level(self, level)
Definition: listeners.py:46
def __init__(self, listeners, log_level='INFO')
Definition: listeners.py:36
def imported(self, import_type, name, attrs)
Definition: listeners.py:61
def type_name(item, capitalize=False)
Return "non-technical" type name for objects and types.
Definition: robottypes.py:86
def split_args_from_name_or_path(name)
Split arguments embedded to name or path like Example:arg1:arg2.
Definition: text.py:141