Robot Framework
handlers.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 from copy import copy
17 import inspect
18 
19 from robot.utils import (getdoc, getshortdoc, is_list_like, normpath, printable_name,
20  split_tags_from_doc, type_name)
21 from robot.errors import DataError
22 from robot.model import Tags
23 
24 from .arguments import ArgumentSpec, DynamicArgumentParser, PythonArgumentParser
25 from .dynamicmethods import GetKeywordSource, GetKeywordTypes
26 from .librarykeywordrunner import (EmbeddedArgumentsRunner,
27  LibraryKeywordRunner, RunKeywordRunner)
28 from .runkwregister import RUN_KW_REGISTER
29 
30 
31 def Handler(library, name, method):
32  if RUN_KW_REGISTER.is_run_keyword(library.orig_name, name):
33  return _RunKeywordHandler(library, name, method)
34  return _PythonHandler(library, name, method)
35 
36 
37 def DynamicHandler(library, name, method, doc, argspec, tags=None):
38  if RUN_KW_REGISTER.is_run_keyword(library.orig_name, name):
39  return _DynamicRunKeywordHandler(library, name, method, doc, argspec, tags)
40  return _DynamicHandler(library, name, method, doc, argspec, tags)
41 
42 
43 def InitHandler(library, method=None, docgetter=None):
44  return _PythonInitHandler(library, '__init__', method, docgetter)
45 
46 
48  supports_embedded_args = False
49 
50  def __init__(self, library, handler_name, handler_method, doc='', tags=None):
51  self.librarylibrary = library
52  self._handler_name_handler_name = handler_name
53  self.namename = self._get_name_get_name(handler_name, handler_method)
54  self.argumentsarguments = self._parse_arguments_parse_arguments(handler_method)
55  self._method_method = self._get_initial_handler_get_initial_handler(library, handler_name,
56  handler_method)
57  doc, tags_from_doc = split_tags_from_doc(doc or '')
58  tags_from_attr = self._get_tags_from_attribute_get_tags_from_attribute(handler_method)
59  self._doc_doc = doc
60  self.tagstags = Tags(tuple(tags_from_doc) +
61  tuple(tags_from_attr) +
62  tuple(tags or ()))
63 
64  def _get_name(self, handler_name, handler_method):
65  robot_name = getattr(handler_method, 'robot_name', None)
66  name = robot_name or printable_name(handler_name, code_style=True)
67  if not name:
68  raise DataError('Keyword name cannot be empty.')
69  return name
70 
71  def _parse_arguments(self, handler_method):
72  raise NotImplementedError
73 
74  def _get_tags_from_attribute(self, handler_method):
75  tags = getattr(handler_method, 'robot_tags', ())
76  if not is_list_like(tags):
77  raise DataError(f"Expected tags to be list-like, got {type_name(tags)}.")
78  return tags
79 
80  def _get_initial_handler(self, library, name, method):
81  if library.scope.is_global:
82  return self._get_global_handler_get_global_handler(method, name)
83  return None
84 
85  def resolve_arguments(self, args, variables=None, languages=None):
86  return self.argumentsarguments.resolve(args, variables, self.librarylibrary.converters,
87  languages=languages)
88 
89  @property
90  doc = property
91 
92  def doc(self):
93  return self._doc_doc
94 
95  @property
96  longname = property
97 
98  def longname(self):
99  return f'{self.library.name}.{self.name}'
100 
101  @property
102  shortdoc = property
103 
104  def shortdoc(self):
105  return getshortdoc(self.docdocdoc)
106 
107  @property
108  libname = property
109 
110  def libname(self):
111  return self.librarylibrary.name
112 
113  @property
114  source = property
115 
116  def source(self):
117  return self.librarylibrary.source
118 
119  @property
120  lineno = property
121 
122  def lineno(self):
123  return -1
124 
125  def create_runner(self, name, languages=None):
126  return LibraryKeywordRunner(self, languages=languages)
127 
128  def current_handler(self):
129  if self._method_method:
130  return self._method_method
131  return self._get_handler_get_handler(self.librarylibrary.get_instance(), self._handler_name_handler_name)
132 
133  def _get_global_handler(self, method, name):
134  return method
135 
136  def _get_handler(self, lib_instance, handler_name):
137  try:
138  return getattr(lib_instance, handler_name)
139  except AttributeError:
140  # Occurs with old-style classes.
141  if handler_name == '__init__':
142  return None
143  raise
144 
145 
147 
148  def __init__(self, library, handler_name, handler_method):
149  super().__init__(library, handler_name, handler_method, getdoc(handler_method))
150 
151  def _parse_arguments(self, handler_method):
152  return PythonArgumentParser().parse(handler_method, self.longnamelongnamelongname)
153 
154  @property
155  source = property
156 
157  def source(self):
158  handler = self.current_handlercurrent_handler()
159  # `getsourcefile` can return None and raise TypeError.
160  try:
161  source = inspect.getsourcefile(inspect.unwrap(handler))
162  except TypeError:
163  source = None
164  return normpath(source) if source else self.librarylibrary.source
165 
166  @property
167  lineno = property
168 
169  def lineno(self):
170  handler = self.current_handlercurrent_handler()
171  try:
172  lines, start_lineno = inspect.getsourcelines(inspect.unwrap(handler))
173  except (TypeError, OSError, IOError):
174  return -1
175  for increment, line in enumerate(lines):
176  if line.strip().startswith('def '):
177  return start_lineno + increment
178  return start_lineno
179 
180 
182 
183  def __init__(self, library, handler_name, dynamic_method, doc='', argspec=None,
184  tags=None):
185  self._argspec_argspec = argspec
186  self._run_keyword_method_name_run_keyword_method_name = dynamic_method.name
187  self._supports_kwargs_supports_kwargs = dynamic_method.supports_kwargs
188  # Cannot use super() here due to multi-inheritance in _DynamicRunKeywordHandler
189  _RunnableHandler.__init__(self, library, handler_name, dynamic_method.method,
190  doc, tags)
191  self._source_info_source_info = None
192 
193  def _parse_arguments(self, handler_method):
194  spec = DynamicArgumentParser().parse(self._argspec_argspec, self.longnamelongnamelongname)
195  if not self._supports_kwargs_supports_kwargs:
196  name = self._run_keyword_method_name_run_keyword_method_name
197  if spec.var_named:
198  raise DataError(f"Too few '{name}' method parameters for "
199  f"**kwargs support.")
200  if spec.named_only:
201  raise DataError(f"Too few '{name}' method parameters for "
202  f"keyword-only arguments support.")
203  get_keyword_types = GetKeywordTypes(self.librarylibrary.get_instance())
204  spec.types = get_keyword_types(self._handler_name_handler_name)
205  return spec
206 
207  @property
208  source = property
209 
210  def source(self):
211  if self._source_info_source_info is None:
212  self._source_info_source_info = self._get_source_info_get_source_info()
213  return self._source_info_source_info[0]
214 
215  def _get_source_info(self):
216  get_keyword_source = GetKeywordSource(self.librarylibrary.get_instance())
217  try:
218  source = get_keyword_source(self._handler_name_handler_name)
219  except DataError as err:
220  self.librarylibrary.report_error(
221  f"Getting source information for keyword '{self.name}' failed: {err}",
222  err.details
223  )
224  source = None
225  if source and ':' in source and source.rsplit(':', 1)[1].isdigit():
226  source, lineno = source.rsplit(':', 1)
227  lineno = int(lineno)
228  else:
229  lineno = -1
230  return normpath(source) if source else self.librarylibrary.source, lineno
231 
232  @property
233  lineno = property
234 
235  def lineno(self):
236  if self._source_info_source_info is None:
237  self._source_info_source_info = self._get_source_info_get_source_info()
238  return self._source_info_source_info[1]
239 
240  def resolve_arguments(self, arguments, variables=None, languages=None):
241  positional, named = super().resolve_arguments(arguments, variables, languages)
242  if not self._supports_kwargs_supports_kwargs:
243  positional, named = self.argumentsarguments.map(positional, named)
244  return positional, named
245 
246  def _get_handler(self, lib_instance, handler_name):
247  runner = getattr(lib_instance, self._run_keyword_method_name_run_keyword_method_name)
248  return self._get_dynamic_handler_get_dynamic_handler(runner, handler_name)
249 
250  def _get_global_handler(self, method, name):
251  return self._get_dynamic_handler_get_dynamic_handler(method, name)
252 
253  def _get_dynamic_handler(self, runner, name):
254  def handler(*positional, **kwargs):
255  if self._supports_kwargs_supports_kwargs:
256  return runner(name, positional, kwargs)
257  else:
258  return runner(name, positional)
259  return handler
260 
261 
263 
264  def create_runner(self, name, languages=None):
265  dry_run = RUN_KW_REGISTER.get_dry_run(self.librarylibrary.orig_name, self.namename)
266  return RunKeywordRunner(self, execute_in_dry_run=dry_run)
267 
268  @property
269  _args_to_process = property
270 
271  def _args_to_process(self):
272  return RUN_KW_REGISTER.get_args_to_process(self.librarylibrary.orig_name, self.namename)
273 
274  def resolve_arguments(self, args, variables=None, languages=None):
275  return self.argumentsarguments.resolve(args, variables, self.librarylibrary.converters,
276  resolve_named=False,
277  resolve_variables_until=self._args_to_process_args_to_process_args_to_process)
278 
279 
281 
284  _parse_arguments = _RunKeywordHandler._parse_arguments
285  resolve_arguments = _RunKeywordHandler.resolve_arguments
286 
287 
289 
290  def __init__(self, library, handler_name, handler_method, docgetter):
291  super().__init__(library, handler_name, handler_method)
292  self._docgetter_docgetter = docgetter
293 
294  def _get_name(self, handler_name, handler_method):
295  return '__init__'
296 
297  @property
298  doc = property
299 
300  def doc(self):
301  if self._docgetter_docgetter:
302  self._doc_doc_doc = self._docgetter_docgetter() or self._doc_doc_doc
303  self._docgetter_docgetter = None
304  return self._doc_doc_doc
305 
306  def _parse_arguments(self, init_method):
307  parser = PythonArgumentParser(type='Library')
308  return parser.parse(init_method or (lambda: None), self.librarylibrary.name)
309 
310 
312  supports_embedded_args = True
313 
314  def __init__(self, embedded, orig_handler):
315  self.argumentsarguments = ArgumentSpec() # Show empty argument spec for Libdoc
316  self.embeddedembedded = embedded
317  self._orig_handler_orig_handler = orig_handler
318 
319  def __getattr__(self, item):
320  return getattr(self._orig_handler_orig_handler, item)
321 
322  @property
323  library = property
324 
325  def library(self):
326  return self._orig_handler_orig_handler.library
327 
328  @library.setter
329 
330  def library(self, library):
331  self._orig_handler_orig_handler.library = library
332 
333  def matches(self, name):
334  return self.embeddedembedded.match(name) is not None
335 
336  def create_runner(self, name, languages=None):
337  return EmbeddedArgumentsRunner(self, name)
338 
339  def resolve_arguments(self, args, variables=None, languages=None):
340  argspec = self._orig_handler_orig_handler.arguments
341  if variables:
342  if argspec.var_positional:
343  args = variables.replace_list(args)
344  else:
345  args = [variables.replace_scalar(a) for a in args]
346  self.embeddedembedded.validate(args)
347  return argspec.convert(args, named={}, converters=self.librarylibrarylibrarylibrary.converters,
348  dry_run=not variables)
349 
350  def __copy__(self):
351  return EmbeddedArgumentsHandler(self.embeddedembedded, copy(self._orig_handler_orig_handler))
def __init__(self, embedded, orig_handler)
Definition: handlers.py:314
def resolve_arguments(self, args, variables=None, languages=None)
Definition: handlers.py:339
def create_runner(self, name, languages=None)
Definition: handlers.py:336
def resolve_arguments(self, arguments, variables=None, languages=None)
Definition: handlers.py:240
def _get_dynamic_handler(self, runner, name)
Definition: handlers.py:253
def _get_global_handler(self, method, name)
Definition: handlers.py:250
def __init__(self, library, handler_name, dynamic_method, doc='', argspec=None, tags=None)
Definition: handlers.py:184
def _parse_arguments(self, handler_method)
Definition: handlers.py:193
def _get_handler(self, lib_instance, handler_name)
Definition: handlers.py:246
def __init__(self, library, handler_name, handler_method)
Definition: handlers.py:148
def _parse_arguments(self, handler_method)
Definition: handlers.py:151
def _parse_arguments(self, init_method)
Definition: handlers.py:306
def __init__(self, library, handler_name, handler_method, docgetter)
Definition: handlers.py:290
def _get_name(self, handler_name, handler_method)
Definition: handlers.py:294
def resolve_arguments(self, args, variables=None, languages=None)
Definition: handlers.py:274
def create_runner(self, name, languages=None)
Definition: handlers.py:264
def resolve_arguments(self, args, variables=None, languages=None)
Definition: handlers.py:85
def _parse_arguments(self, handler_method)
Definition: handlers.py:71
def create_runner(self, name, languages=None)
Definition: handlers.py:125
def _get_initial_handler(self, library, name, method)
Definition: handlers.py:80
def _get_tags_from_attribute(self, handler_method)
Definition: handlers.py:74
def __init__(self, library, handler_name, handler_method, doc='', tags=None)
Definition: handlers.py:50
def _get_global_handler(self, method, name)
Definition: handlers.py:133
def _get_handler(self, lib_instance, handler_name)
Definition: handlers.py:136
def _get_name(self, handler_name, handler_method)
Definition: handlers.py:64
def InitHandler(library, method=None, docgetter=None)
Definition: handlers.py:43
def Handler(library, name, method)
Definition: handlers.py:31
def DynamicHandler(library, name, method, doc, argspec, tags=None)
Definition: handlers.py:37
def printable_name(string, code_style=False)
Generates and returns printable name from the given string.
Definition: misc.py:40
def normpath(path, case_normalize=False)
Replacement for os.path.normpath with some enhancements.
Definition: robotpath.py:46
def is_list_like(item)
Definition: robottypes.py:66
def getdoc(item)
Definition: text.py:180
def getshortdoc(doc_or_item, linesep='\n')
Definition: text.py:184
def split_tags_from_doc(doc)
Definition: text.py:167