Robot Framework Integrated Development Environment (RIDE)
importer.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 copy
17 import os.path
18 
19 from robotide.lib.robot.output import LOGGER
20 from robotide.lib.robot.errors import FrameworkError
21 from robotide.lib.robot.utils import normpath, seq2str2, is_string
22 
23 from .builder import ResourceFileBuilder
24 from .handlerstore import HandlerStore
25 from .testlibraries import TestLibrary
26 
27 
28 class Importer():
29 
30  def __init__(self):
31  self._library_cache_library_cache = ImportCache()
32  self._resource_cache_resource_cache = ImportCache()
33 
34  def reset(self):
35  self.__init____init__()
36 
38  for lib in self._library_cache_library_cache.values():
39  lib.close_global_listeners()
40 
41  def import_library(self, name, args, alias, variables):
42  lib = TestLibrary(name, args, variables, create_handlers=False)
43  positional, named = lib.positional_args, lib.named_args
44  lib = self._import_library_import_library(name, positional, named, lib)
45  if alias:
46  alias = variables.replace_scalar(alias)
47  lib = self._copy_library_copy_library(lib, alias)
48  LOGGER.info("Imported library '%s' with name '%s'" % (name, alias))
49  return lib
50 
51  def import_resource(self, path):
52  if path in self._resource_cache_resource_cache:
53  LOGGER.info("Found resource file '%s' from cache" % path)
54  else:
55  resource = ResourceFileBuilder().build(path)
56  self._resource_cache_resource_cache[path] = resource
57  return self._resource_cache_resource_cache[path]
58 
59  def _import_library(self, name, positional, named, lib):
60  args = positional + ['%s=%s' % arg for arg in named]
61  key = (name, positional, named)
62  if key in self._library_cache_library_cache:
63  LOGGER.info("Found test library '%s' with arguments %s from cache"
64  % (name, seq2str2(args)))
65  return self._library_cache_library_cache[key]
66  lib.create_handlers()
67  self._library_cache_library_cache[key] = lib
68  self._log_imported_library_log_imported_library(name, args, lib)
69  return lib
70 
71  def _log_imported_library(self, name, args, lib):
72  type = lib.__class__.__name__.replace('Library', '').lower()[1:]
73  listener = ', with listener' if lib.has_listener else ''
74  LOGGER.info("Imported library '%s' with arguments %s "
75  "(version %s, %s type, %s scope, %d keywords%s)"
76  % (name, seq2str2(args), lib.version or '<unknown>',
77  type, lib.scope, len(lib), listener))
78  if not lib and not lib.has_listener:
79  LOGGER.warn("Imported library '%s' contains no keywords." % name)
80 
81  def _copy_library(self, orig, name):
82  # This is pretty ugly. Hopefully we can remove cache and copying
83  # altogether in 3.0 and always just re-import libraries:
84  # https://github.com/robotframework/robotframework/issues/2106
85  # Could then also remove __copy__ methods added to some handlers as
86  # a workaround for this IronPython bug:
87  # https://github.com/IronLanguages/main/issues/1192
88  lib = copy.copy(orig)
89  lib.name = name
90  lib.scope = type(lib.scope)(lib)
91  lib.reset_instance()
92  lib.handlers = HandlerStore(orig.handlers.source,
93  orig.handlers.source_type)
94  for handler in orig.handlers._normal.values():
95  handler = copy.copy(handler)
96  handler.library = lib
97  lib.handlers.add(handler)
98  for handler in orig.handlers._embedded:
99  handler = copy.copy(handler)
100  handler.library = lib
101  lib.handlers.add(handler, embedded=True)
102  return lib
103 
104 
105 
110 class ImportCache():
111 
112  def __init__(self):
113  self._keys_keys = []
114  self._items_items = []
115 
116  def __setitem__(self, key, item):
117  if not is_string(key) and not isinstance(key, tuple):
118  raise FrameworkError('Invalid key for ImportCache')
119  key = self._norm_path_key_norm_path_key(key)
120  if key not in self._keys_keys:
121  self._keys_keys.append(key)
122  self._items_items.append(item)
123  else:
124  self._items_items[self._keys_keys.index(key)] = item
125 
126  def add(self, key, item=None):
127  self.__setitem____setitem__(key, item)
128 
129  def __getitem__(self, key):
130  key = self._norm_path_key_norm_path_key(key)
131  if key not in self._keys_keys:
132  raise KeyError
133  return self._items_items[self._keys_keys.index(key)]
134 
135  def __contains__(self, key):
136  return self._norm_path_key_norm_path_key(key) in self._keys_keys
137 
138  def values(self):
139  return self._items_items
140 
141  def _norm_path_key(self, key):
142  if self._is_path_is_path(key):
143  return normpath(key, case_normalize=True)
144  if isinstance(key, tuple):
145  return tuple(self._norm_path_key_norm_path_key(k) for k in key)
146  return key
147 
148  def _is_path(self, key):
149  return is_string(key) and os.path.isabs(key) and os.path.exists(key)
Can be used when the core framework goes to unexpected state.
Definition: errors.py:59
Keeps track on and optionally caches imported items.
Definition: importer.py:110
def _import_library(self, name, positional, named, lib)
Definition: importer.py:59
def import_library(self, name, args, alias, variables)
Definition: importer.py:41
def _log_imported_library(self, name, args, lib)
Definition: importer.py:71
def TestLibrary(name, args=None, variables=None, create_handlers=True)
def seq2str2(sequence)
Returns sequence in format [ item 1 | item 2 | ...
Definition: misc.py:126
def normpath(path, case_normalize=False)
Replacement for os.path.normpath with some enhancements.
Definition: robotpath.py:68