add so delete request
[testsuite/python-testing-utils.git] / robotframework-onap / ONAPLibrary / robotlibcore.py
1 # Copyright 2017- Robot Framework Foundation
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 """Generic test library core for Robot Framework.
16
17 Main usage is easing creating larger test libraries. For more information and
18 examples see the project pages at
19 https://github.com/robotframework/PythonLibCore
20 """
21
22 import inspect
23 import sys
24
25 try:
26     from robot.api.deco import keyword
27 except ImportError:  # Support RF < 2.9
28     def keyword(name=None, tags=()):
29         if callable(name):
30             return keyword()(name)
31         def decorator(func):
32             func.robot_name = name
33             func.robot_tags = tags
34             return func
35         return decorator
36
37
38 PY2 = sys.version_info < (3,)
39
40 __version__ = '1.0.1.dev1'
41
42
43 class HybridCore(object):
44
45     def __init__(self, library_components):
46         self.keywords = {}
47         self.attributes = {}
48         self.add_library_components(library_components)
49         self.add_library_components([self])
50
51     def add_library_components(self, library_components):
52         for component in library_components:
53             for name, func in self._get_members(component):
54                 if callable(func) and hasattr(func, 'robot_name'):
55                     kw = getattr(component, name)
56                     kw_name = func.robot_name or name
57                     self.keywords[kw_name] = kw
58                     # Expose keywords as attributes both using original
59                     # method names as well as possible custom names.
60                     self.attributes[name] = self.attributes[kw_name] = kw
61
62     def _get_members(self, component):
63         if inspect.ismodule(component):
64             return inspect.getmembers(component)
65         if inspect.isclass(component):
66             raise TypeError('Libraries must be modules or instances, got '
67                             'class {!r} instead.'.format(component.__name__))
68         if type(component) != component.__class__:
69             raise TypeError('Libraries must be modules or new-style class '
70                             'instances, got old-style class {!r} instead.'
71                             .format(component.__class__.__name__))
72         return self._get_members_from_instance(component)
73
74     def _get_members_from_instance(self, instance):
75         # Avoid calling properties by getting members from class, not instance.
76         cls = type(instance)
77         for name in dir(instance):
78             owner = cls if hasattr(cls, name) else instance
79             yield name, getattr(owner, name)
80
81     def __getattr__(self, name):
82         if name in self.attributes:
83             return self.attributes[name]
84         raise AttributeError('{!r} object has no attribute {!r}'
85                              .format(type(self).__name__, name))
86
87     def __dir__(self):
88         if PY2:
89             my_attrs = dir(type(self)) + list(self.__dict__)
90         else:
91             my_attrs = super().__dir__()
92         return sorted(set(my_attrs) | set(self.attributes))
93
94     def get_keyword_names(self):
95         return sorted(self.keywords)
96
97
98 class DynamicCore(HybridCore):
99     _get_keyword_tags_supported = False  # get_keyword_tags is new in RF 3.0.2
100
101     def run_keyword(self, name, args, kwargs):
102         return self.keywords[name](*args, **kwargs)
103
104     def get_keyword_arguments(self, name):
105         kw = self.keywords[name] if name != '__init__' else self.__init__
106         args, defaults, varargs, kwargs = self._get_arg_spec(kw)
107         args += ['{}={}'.format(name, value) for name, value in defaults]
108         if varargs:
109             args.append('*{}'.format(varargs))
110         if kwargs:
111             args.append('**{}'.format(kwargs))
112         return args
113
114     def _get_arg_spec(self, kw):
115         if PY2:
116             spec = inspect.getargspec(kw)
117             keywords = spec.keywords
118         else:
119             spec = inspect.getfullargspec(kw)
120             keywords = spec.varkw
121         args = spec.args[1:] if inspect.ismethod(kw) else spec.args  # drop self
122         defaults = spec.defaults or ()
123         nargs = len(args) - len(defaults)
124         mandatory = args[:nargs]
125         defaults = zip(args[nargs:], defaults)
126         return mandatory, defaults, spec.varargs, keywords
127
128     def get_keyword_tags(self, name):
129         self._get_keyword_tags_supported = True
130         return self.keywords[name].robot_tags
131
132     def get_keyword_documentation(self, name):
133         if name == '__intro__':
134             return inspect.getdoc(self) or ''
135         if name == '__init__':
136             return inspect.getdoc(self.__init__) or ''
137         kw = self.keywords[name]
138         doc = inspect.getdoc(kw) or ''
139         if kw.robot_tags and not self._get_keyword_tags_supported:
140             tags = 'Tags: {}'.format(', '.join(kw.robot_tags))
141             doc = '{}\n\n{}'.format(doc, tags) if doc else tags
142         return doc
143
144
145 class StaticCore(HybridCore):
146
147     def __init__(self):
148         HybridCore.__init__(self, [])