Robot Framework
filesetter.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 inspect
17 import io
18 try:
19  import yaml
20 except ImportError:
21  yaml = None
22 
23 from robot.errors import DataError
24 from robot.output import LOGGER
25 from robot.utils import (get_error_message, is_dict_like, is_list_like,
26  is_string, seq2str2, type_name, DotDict, Importer)
27 
28 
30 
31  def __init__(self, store):
32  self._store_store = store
33 
34  def set(self, path_or_variables, args=None, overwrite=False):
35  variables = self._import_if_needed_import_if_needed(path_or_variables, args)
36  self._set_set(variables, overwrite)
37  return variables
38 
39  def _import_if_needed(self, path_or_variables, args=None):
40  if not is_string(path_or_variables):
41  return path_or_variables
42  LOGGER.info("Importing variable file '%s' with args %s"
43  % (path_or_variables, args))
44  if path_or_variables.lower().endswith(('.yaml', '.yml')):
45  importer = YamlImporter()
46  else:
47  importer = PythonImporter()
48  try:
49  return importer.import_variables(path_or_variables, args)
50  except:
51  args = 'with arguments %s ' % seq2str2(args) if args else ''
52  raise DataError("Processing variable file '%s' %sfailed: %s"
53  % (path_or_variables, args, get_error_message()))
54 
55  def _set(self, variables, overwrite=False):
56  for name, value in variables:
57  self._store_store.add(name, value, overwrite)
58 
59 
61 
62  def import_variables(self, path, args=None):
63  if args:
64  raise DataError('YAML variable files do not accept arguments.')
65  variables = self._import_import(path)
66  return [('${%s}' % name, self._dot_dict_dot_dict(value))
67  for name, value in variables]
68 
69  def _import(self, path):
70  with io.open(path, encoding='UTF-8') as stream:
71  variables = self._load_yaml_load_yaml(stream)
72  if not is_dict_like(variables):
73  raise DataError('YAML variable file must be a mapping, got %s.'
74  % type_name(variables))
75  return variables.items()
76 
77  def _load_yaml(self, stream):
78  if not yaml:
79  raise DataError('Using YAML variable files requires PyYAML module '
80  'to be installed. Typically you can install it '
81  'by running `pip install pyyaml`.')
82  if yaml.__version__.split('.')[0] == '3':
83  return yaml.load(stream)
84  return yaml.full_load(stream)
85 
86  def _dot_dict(self, value):
87  if is_dict_like(value):
88  return DotDict((k, self._dot_dict_dot_dict(v)) for k, v in value.items())
89  if is_list_like(value):
90  return [self._dot_dict_dot_dict(v) for v in value]
91  return value
92 
93 
95 
96  def import_variables(self, path, args=None):
97  importer = Importer('variable file', LOGGER).import_class_or_module
98  var_file = importer(path, instantiate_with_args=())
99  return self._get_variables_get_variables(var_file, args)
100 
101  def _get_variables(self, var_file, args):
102  if self._is_dynamic_is_dynamic(var_file):
103  variables = self._get_dynamic_get_dynamic(var_file, args)
104  else:
105  variables = self._get_static_get_static(var_file)
106  return list(self._decorate_and_validate_decorate_and_validate(variables))
107 
108  def _is_dynamic(self, var_file):
109  return (hasattr(var_file, 'get_variables') or
110  hasattr(var_file, 'getVariables'))
111 
112  def _get_dynamic(self, var_file, args):
113  get_variables = (getattr(var_file, 'get_variables', None) or
114  getattr(var_file, 'getVariables'))
115  variables = get_variables(*args)
116  if is_dict_like(variables):
117  return variables.items()
118  raise DataError("Expected '%s' to return dict-like value, got %s."
119  % (get_variables.__name__, type_name(variables)))
120 
121  def _get_static(self, var_file):
122  names = [attr for attr in dir(var_file) if not attr.startswith('_')]
123  if hasattr(var_file, '__all__'):
124  names = [name for name in names if name in var_file.__all__]
125  variables = [(name, getattr(var_file, name)) for name in names]
126  if not inspect.ismodule(var_file):
127  variables = [(n, v) for n, v in variables if not callable(v)]
128  return variables
129 
130  def _decorate_and_validate(self, variables):
131  for name, value in variables:
132  name = self._decorate_decorate(name)
133  self._validate_validate(name, value)
134  yield name, value
135 
136  def _decorate(self, name):
137  if name.startswith('LIST__'):
138  return '@{%s}' % name[6:]
139  if name.startswith('DICT__'):
140  return '&{%s}' % name[6:]
141  return '${%s}' % name
142 
143  def _validate(self, name, value):
144  if name[0] == '@' and not is_list_like(value):
145  raise DataError("Invalid variable '%s': Expected list-like value, "
146  "got %s." % (name, type_name(value)))
147  if name[0] == '&' and not is_dict_like(value):
148  raise DataError("Invalid variable '%s': Expected dict-like value, "
149  "got %s." % (name, type_name(value)))
Utility that can import modules and classes based on names and paths.
Definition: importer.py:33
def import_variables(self, path, args=None)
Definition: filesetter.py:96
def _decorate_and_validate(self, variables)
Definition: filesetter.py:130
def _get_dynamic(self, var_file, args)
Definition: filesetter.py:112
def _get_variables(self, var_file, args)
Definition: filesetter.py:101
def set(self, path_or_variables, args=None, overwrite=False)
Definition: filesetter.py:34
def _set(self, variables, overwrite=False)
Definition: filesetter.py:55
def _import_if_needed(self, path_or_variables, args=None)
Definition: filesetter.py:39
def import_variables(self, path, args=None)
Definition: filesetter.py:62
def get_error_message()
Returns error message of the last occurred exception.
Definition: error.py:34
def seq2str2(sequence)
Returns sequence in format [ item 1 | item 2 | ...
Definition: misc.py:90
def is_dict_like(item)
Definition: robottypes.py:72
def type_name(item, capitalize=False)
Return "non-technical" type name for objects and types.
Definition: robottypes.py:86
def is_list_like(item)
Definition: robottypes.py:66