Robot Framework
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 import os
19 
20 from robot.output import LOGGER
21 from robot.errors import FrameworkError, DataError
22 from robot.utils import normpath, seq2str, seq2str2, is_string
23 
24 from .builder import ResourceFileBuilder
25 from .handlerstore import HandlerStore
26 from .testlibraries import TestLibrary
27 
28 
29 RESOURCE_EXTENSIONS = ('.resource', '.robot', '.txt', '.tsv', '.rst', '.rest')
30 
31 
32 class Importer:
33 
34  def __init__(self):
35  self._library_cache_library_cache = ImportCache()
36  self._resource_cache_resource_cache = ImportCache()
37 
38  def reset(self):
39  self.__init____init__()
40 
42  for lib in self._library_cache_library_cache.values():
43  lib.close_global_listeners()
44 
45  def import_library(self, name, args, alias, variables):
46  lib = TestLibrary(name, args, variables, create_handlers=False)
47  positional, named = lib.positional_args, lib.named_args
48  lib = self._import_library_import_library(name, positional, named, lib)
49  if alias:
50  alias = variables.replace_scalar(alias)
51  lib = self._copy_library_copy_library(lib, alias)
52  LOGGER.info("Imported library '%s' with name '%s'" % (name, alias))
53  return lib
54 
55  def import_resource(self, path, lang=None):
56  self._validate_resource_extension_validate_resource_extension(path)
57  if path in self._resource_cache_resource_cache:
58  LOGGER.info("Found resource file '%s' from cache" % path)
59  else:
60  resource = ResourceFileBuilder(lang=lang).build(path)
61  self._resource_cache_resource_cache[path] = resource
62  return self._resource_cache_resource_cache[path]
63 
65  extension = os.path.splitext(path)[1]
66  if extension.lower() not in RESOURCE_EXTENSIONS:
67  raise DataError("Invalid resource file extension '%s'. "
68  "Supported extensions are %s."
69  % (extension, seq2str(RESOURCE_EXTENSIONS)))
70 
71  def _import_library(self, name, positional, named, lib):
72  args = positional + ['%s=%s' % arg for arg in named]
73  key = (name, positional, named)
74  if key in self._library_cache_library_cache:
75  LOGGER.info("Found library '%s' with arguments %s from cache."
76  % (name, seq2str2(args)))
77  return self._library_cache_library_cache[key]
78  lib.create_handlers()
79  self._library_cache_library_cache[key] = lib
80  self._log_imported_library_log_imported_library(name, args, lib)
81  return lib
82 
83  def _log_imported_library(self, name, args, lib):
84  type = lib.__class__.__name__.replace('Library', '').lower()[1:]
85  listener = ', with listener' if lib.has_listener else ''
86  LOGGER.info("Imported library '%s' with arguments %s "
87  "(version %s, %s type, %s scope, %d keywords%s)"
88  % (name, seq2str2(args), lib.version or '<unknown>',
89  type, lib.scope, len(lib), listener))
90  if not lib:
91  LOGGER.warn("Imported library '%s' contains no keywords." % name)
92 
93  def _copy_library(self, orig, name):
94  # This is pretty ugly. Hopefully we can remove cache and copying
95  # altogether in 3.0 and always just re-import libraries:
96  # https://github.com/robotframework/robotframework/issues/2106
97  lib = copy.copy(orig)
98  lib.name = name
99  lib.scope = type(lib.scope)(lib)
100  lib.reset_instance()
101  lib.handlers = HandlerStore()
102  for handler in orig.handlers._normal.values():
103  handler = copy.copy(handler)
104  handler.library = lib
105  lib.handlers.add(handler)
106  for handler in orig.handlers._embedded:
107  handler = copy.copy(handler)
108  handler.library = lib
109  lib.handlers.add(handler, embedded=True)
110  return lib
111 
112 
113 
119 
120  def __init__(self):
121  self._keys_keys = []
122  self._items_items = []
123 
124  def __setitem__(self, key, item):
125  if not is_string(key) and not isinstance(key, tuple):
126  raise FrameworkError('Invalid key for ImportCache')
127  key = self._norm_path_key_norm_path_key(key)
128  if key not in self._keys_keys:
129  self._keys_keys.append(key)
130  self._items_items.append(item)
131  else:
132  self._items_items[self._keys_keys.index(key)] = item
133 
134  def add(self, key, item=None):
135  self.__setitem____setitem__(key, item)
136 
137  def __getitem__(self, key):
138  key = self._norm_path_key_norm_path_key(key)
139  if key not in self._keys_keys:
140  raise KeyError
141  return self._items_items[self._keys_keys.index(key)]
142 
143  def __contains__(self, key):
144  return self._norm_path_key_norm_path_key(key) in self._keys_keys
145 
146  def values(self):
147  return self._items_items
148 
149  def _norm_path_key(self, key):
150  if self._is_path_is_path(key):
151  return normpath(key, case_normalize=True)
152  if isinstance(key, tuple):
153  return tuple(self._norm_path_key_norm_path_key(k) for k in key)
154  return key
155 
156  def _is_path(self, key):
157  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:53
Keeps track on and optionally caches imported items.
Definition: importer.py:118
def add(self, key, item=None)
Definition: importer.py:134
def __setitem__(self, key, item)
Definition: importer.py:124
def _copy_library(self, orig, name)
Definition: importer.py:93
def _import_library(self, name, positional, named, lib)
Definition: importer.py:71
def _log_imported_library(self, name, args, lib)
Definition: importer.py:83
def close_global_library_listeners(self)
Definition: importer.py:41
def _validate_resource_extension(self, path)
Definition: importer.py:64
def import_resource(self, path, lang=None)
Definition: importer.py:55
def import_library(self, name, args, alias, variables)
Definition: importer.py:45
def TestLibrary(name, args=None, variables=None, create_handlers=True, logger=LOGGER)
def seq2str(sequence, quote="'", sep=', ', lastsep=' and ')
Returns sequence in format ‘'item 1’, 'item 2' and 'item 3'`.
Definition: misc.py:79
def seq2str2(sequence)
Returns sequence in format [ item 1 | item 2 | ...
Definition: misc.py:90
def normpath(path, case_normalize=False)
Replacement for os.path.normpath with some enhancements.
Definition: robotpath.py:46