def _release_and_log(self): stdout, stderr = self._release() if stdout: LOGGER.log_output(stdout) if stderr: LOGGER.log_output(stderr) sys.__stderr__.write(console_encode(stderr, stream=sys.__stderr__))
def _release_and_log(self): stdout, stderr = self._release() if stdout: LOGGER.log_output(stdout) if stderr: LOGGER.log_output(stderr) sys.__stderr__.write(encode_output(stderr + '\n'))
def _release_and_log(self): stdout, stderr = self._release() if stdout: LOGGER.log_output(stdout) if stderr: LOGGER.log_output(stderr) sys.__stderr__.write(encode_output(stderr+'\n'))
def _deprecate_escaped_cells_before_continuation(self, data): index = data.index(self._row_continuation_marker) if any(cell == '\\' for cell in data[:index]): LOGGER.warn("Error in file '%s': Escaping empty cells with " "'\\' before line continuation marker '...' is " "deprecated. Remove escaping before Robot " "Framework 3.2." % self.source)
def import_resource(self, path): if path in self._resource_cache: LOGGER.info("Found resource file '%s' from cache" % path) else: resource = ResourceFileBuilder().build(path) self._resource_cache[path] = resource return self._resource_cache[path]
def _deprecate_quoting(self, cell, path, line_number): if len(cell) > 1 and cell[0] == cell[-1] == '"': LOGGER.warn("TSV file '%s' has quotes around cells which is " "deprecated and must be fixed. Remove quotes " "from '%s' on line %d." % (path, cell, line_number)) return cell[1:-1].replace('""', '"').strip() return cell
def main(self, datasources, **options): settings = RebotSettings(options) LOGGER.register_console_logger(**settings.console_output_config) LOGGER.disable_message_cache() rc = ResultWriter(*datasources).write_results(settings) if rc < 0: raise DataError('No outputs created.') return rc
def _report_adding_keyword_failed(self, name, message=None, details=None, level=None): if not message: message, details = get_error_details() LOGGER.write("Adding keyword '%s' to library '%s' failed: %s" % (name, self.name, message), level or self._failure_level) if details: LOGGER.debug('Details:\n%s' % details)
def _create_handlers(self, libcode): for name in self._get_handler_names(libcode): method = self._try_to_get_handler_method(libcode, name) if method: handler, embedded = self._try_to_create_handler(name, method) if handler: self.handlers.add(handler, embedded) LOGGER.debug("Created keyword '%s'" % handler.name)
def populate(self, path, datadir, include_suites=None, warn_on_skipped=False, recurse=True): LOGGER.info("Parsing test data directory '%s'" % path) include_suites = self._get_include_suites(path, include_suites or []) init_file, children = self._get_children(path, include_suites) if init_file: self._populate_init_file(datadir, init_file) if recurse: self._populate_children(datadir, children, include_suites, warn_on_skipped)
def _warn_about_registeration_error(self, signum, err): name, ctrlc = { signal.SIGINT: ('INT', 'or with Ctrl-C '), signal.SIGTERM: ('TERM', '') }[signum] LOGGER.warn('Registering signal %s failed. Stopping execution ' 'gracefully with this signal %sis not possible. ' 'Original error was: %s' % (name, ctrlc, err))
def __init__(self, variables, suite, resource): LOGGER.info("Initializing namespace for test suite '%s'" % suite.longname) self.variables = variables self._imports = resource.imports self._kw_store = KeywordStore(resource) self._imported_variable_files = ImportCache() self._suite_name = suite.longname self._running_test = False
def _populate_children(self, datadir, children, include_extensions, include_suites): for child in children: try: datadir.add_child(child, include_suites, include_extensions) except NoTestsFound: LOGGER.info("Data source '%s' has no tests or tasks." % child) except DataError as err: LOGGER.error("Parsing '%s' failed: %s" % (child, err.message))
def populate(self, path, resource=False): LOGGER.info("Parsing file '%s'." % path) source = self._open(path) try: self._get_reader(path, resource).read(source, self) except: raise DataError(get_error_message()) finally: source.close()
def __call__(self, signum, frame): self._signal_count += 1 LOGGER.info('Received signal: %s.' % signum) if self._signal_count > 1: sys.__stderr__.write('Execution forcefully stopped.\n') raise SystemExit() sys.__stderr__.write('Second signal will force exit.\n') if self._running_keyword and not sys.platform.startswith('java'): self._stop_execution_gracefully()
def __init__(self, variables, suite, user_keywords, imports): LOGGER.info("Initializing namespace for test suite '%s'" % suite.longname) self.suite = suite self.test = None self.uk_handlers = [] self.variables = variables self._imports = imports self._kw_store = KeywordStore(user_keywords) self._imported_variable_files = ImportCache()
def _process_cell(self, cell, path): if len(cell) > 1 and cell[0] == cell[-1] == '"': cell = cell[1:-1].replace('""', '"') if path not in self._warned_escaping: LOGGER.warn("Un-escaping quotes in TSV files is deprecated. " "Change cells in '%s' to not contain surrounding " "quotes." % path) self._warned_escaping.add(path) return cell
def import_library(self, name, args, alias, variables): lib = TestLibrary(name, args, variables, create_handlers=False) positional, named = lib.positional_args, lib.named_args lib = self._import_library(name, positional, named, lib) if alias: alias = variables.replace_scalar(alias) lib = self._copy_library(lib, alias) LOGGER.info("Imported library '%s' with name '%s'" % (name, alias)) return lib
def _log_imported_library(self, name, args, lib): type = lib.__class__.__name__.replace('Library', '').lower()[1:] listener = ', with listener' if lib.has_listener else '' LOGGER.info("Imported library '%s' with arguments %s " "(version %s, %s type, %s scope, %d keywords%s)" % (name, seq2str2(args), lib.version or '<unknown>', type, lib.scope.lower(), len(lib), listener)) if not lib and not lib.has_listener: LOGGER.warn("Imported library '%s' contains no keywords" % name)
def _log_imported_library(self, name, args, lib): type = lib.__class__.__name__.replace("Library", "").lower()[1:] listener = ", with listener" if lib.has_listener else "" LOGGER.info( "Imported library '%s' with arguments %s " "(version %s, %s type, %s scope, %d keywords%s)" % (name, seq2str2(args), lib.version or "<unknown>", type, lib.scope.lower(), len(lib), listener) ) if not lib and not lib.has_listener: LOGGER.warn("Imported library '%s' contains no keywords" % name)
def _import_library(self, name, positional, named, lib): args = positional + ["%s=%s" % arg for arg in sorted(named.items())] key = (name, positional, named) if key in self._library_cache: LOGGER.info("Found test library '%s' with arguments %s from cache" % (name, seq2str2(args))) return self._library_cache[key] lib.create_handlers() self._library_cache[key] = lib self._log_imported_library(name, args, lib) return lib
def populate(self, path, datadir, include_suites=None, include_extensions=None, recurse=True): LOGGER.info("Parsing directory '%s'." % path) include_suites = self._get_include_suites(path, include_suites) init_file, children = self._get_children(path, include_extensions, include_suites) if init_file: self._populate_init_file(datadir, init_file) if recurse: self._populate_children(datadir, children, include_extensions, include_suites)
def _import_library(self, name, positional, named, lib): args = positional + ['%s=%s' % arg for arg in sorted(named.items())] key = (name, positional, named) if key in self._library_cache: LOGGER.info("Found test library '%s' with arguments %s from cache" % (name, seq2str2(args))) return self._library_cache[key] lib.create_handlers() self._library_cache[key] = lib self._log_imported_library(name, args, lib) return lib
def register_listeners(self): if self.has_listener: try: listeners = EXECUTION_CONTEXTS.current.output.library_listeners listeners.register(self.get_listeners(), self) except DataError as err: self.has_listener = False # Error should have information about suite where the # problem occurred but we don't have such info here. LOGGER.error("Registering listeners for library '%s' failed: %s" % (self.name, err))
def _check_deprecations(self, cells, path, line_number): for original in cells: normalized = self._normalize_whitespace(original) if normalized != original: if len(normalized) != len(original): msg = 'Collapsing consecutive whitespace' else: msg = 'Converting whitespace characters to ASCII spaces' LOGGER.warn("%s during parsing is deprecated. Fix %s in file " "'%s' on line %d." % (msg, prepr(original), path, line_number)) yield normalized
def _close_listener(self, listener): method = (getattr(listener, 'close', None) or getattr(listener, '_close', None)) try: if method: method() except: message, details = get_error_details() name = getattr(listener, '__name__', None) or type_name(listener) LOGGER.error("Calling method '%s' of listener '%s' failed: %s" % (method.__name__, name, message)) LOGGER.info("Details:\n%s" % details)
def _check_deprecated_extensions(self, source): if os.path.isdir(source): return ext = os.path.splitext(source)[1][1:].lower() if self.extensions and ext in self.extensions: return # HTML files cause deprecation warning that cannot be avoided with # --extension at parsing time. No need for double warning. if ext not in ('robot', 'html', 'htm', 'xhtml'): LOGGER.warn("Automatically parsing other than '*.robot' files is " "deprecated. Convert '%s' to '*.robot' format or use " "'--extension' to explicitly configure which files to " "parse." % source)
def _get_children(self, dirpath, incl_extensions, incl_suites): init_file = None children = [] for path, is_init_file in self._list_dir(dirpath, incl_extensions, incl_suites): if is_init_file: if not init_file: init_file = path else: LOGGER.error("Ignoring second test suite init file '%s'." % path) else: children.append(path) return init_file, children
def __init__(self, user_keywords, path=None): basename = os.path.basename(path) if path else None self.name = os.path.splitext(basename)[0] if path else None self.handlers = HandlerStore(basename) for kw in user_keywords: try: handler, embedded = self._create_handler(kw) self._validate_not_duplicate(handler) except DataError as err: LOGGER.error("Creating user keyword '%s' failed: %s" % (kw.name, unicode(err))) handler = UserErrorHandler(kw.name, unicode(err)) embedded = False self.handlers.add(handler, embedded)
def _get_children(self, dirpath, incl_suites): init_file = None children = [] for name, path in self._list_dir(dirpath): if self._is_init_file(name, path): if not init_file: init_file = path else: LOGGER.error("Ignoring second test suite init file '%s'." % path) elif self._is_included(name, path, incl_suites): children.append(path) else: LOGGER.info("Ignoring file or directory '%s'." % name) return init_file, children
def _unescape_opts_and_args(self, opts, args): from robotide.lib.robot.output import LOGGER with LOGGER.cache_only: LOGGER.warn("Option '--escape' is deprecated. Use console escape " "mechanism instead.") try: escape_strings = opts['escape'] except KeyError: raise FrameworkError("No 'escape' in options") escapes = self._get_escapes(escape_strings) for name, value in opts.items(): if name != 'escape': opts[name] = self._unescape(value, escapes) return opts, [self._unescape(arg, escapes) for arg in args]
def read(self, htmlfile, populator, path=None): self.populator = populator self.state = self.IGNORE self.current_row = None self.current_cell = None for line in htmlfile.readlines(): self.feed(self._decode(line)) # Calling close is required by the HTMLParser but may cause problems # if the same instance of our HtmlParser is reused. Currently it's # used only once so there's no problem. self.close() if self.populator.eof(): LOGGER.warn("Using test data in HTML format is deprecated. " "Convert '%s' to plain text format." % (path or htmlfile.name))
def _import_resource(self, import_setting, overwrite=False): path = self._resolve_name(import_setting) self._validate_not_importing_init_file(path) if overwrite or path not in self._kw_store.resources: resource = IMPORTER.import_resource(path) self.variables.set_from_variable_table(resource.variables, overwrite) user_library = UserLibrary(resource) self._kw_store.resources[path] = user_library self._handle_imports(resource.imports) LOGGER.imported("Resource", user_library.name, importer=import_setting.source, source=path) else: LOGGER.info("Resource file '%s' already imported by suite '%s'" % (path, self._suite_name))
def _list_dir(self, dir_path, incl_extensions, incl_suites): # os.listdir returns Unicode entries when path is Unicode dir_path = unic(dir_path) names = os.listdir(dir_path) for name in sorted(names, key=lambda item: item.lower()): name = unic(name) # needed to handle nfc/nfd normalization on OSX path = os.path.join(dir_path, name) base, ext = os.path.splitext(name) ext = ext[1:].lower() if self._is_init_file(path, base, ext, incl_extensions): yield path, True elif self._is_included(path, base, ext, incl_extensions, incl_suites): yield path, False else: LOGGER.info("Ignoring file or directory '%s'." % path)
def _import_if_needed(self, path_or_variables, args=None): if not is_string(path_or_variables): return path_or_variables LOGGER.info("Importing variable file '%s' with args %s" % (path_or_variables, args)) if path_or_variables.lower().endswith('.yaml'): importer = YamlImporter() else: importer = PythonImporter() try: return importer.import_variables(path_or_variables, args) except: args = 'with arguments %s ' % seq2str2(args) if args else '' raise DataError("Processing variable file '%s' %sfailed: %s" % (path_or_variables, args, get_error_message()))
def _set_cli_variables(self, settings): for path, args in settings.variable_files: try: path = find_file(path, file_type='Variable file') self.set_from_file(path, args) except: msg, details = get_error_details() LOGGER.error(msg) LOGGER.info(details) for varstr in settings.variables: try: name, value = varstr.split(':', 1) except ValueError: name, value = varstr, '' self['${%s}' % name] = value
def _get_output_file(self, option): """Returns path of the requested output file and creates needed dirs. `option` can be 'Output', 'Log', 'Report', 'XUnit' or 'DebugFile'. """ name = self._opts[option] if not name: return None if option == 'Log' and self._output_disabled(): self['Log'] = None LOGGER.error('Log file is not created if output.xml is disabled.') return None name = self._process_output_name(option, name) path = abspath(os.path.join(self['OutputDir'], name)) self._create_output_dir(os.path.dirname(path), option) return path
def _import_variables(self, import_setting, overwrite=False): path = self._resolve_name(import_setting) args = self._resolve_args(import_setting) if overwrite or (path, args) not in self._imported_variable_files: self._imported_variable_files.add((path, args)) self.variables.set_from_file(path, args, overwrite) LOGGER.imported("Variables", os.path.basename(path), args=list(args), importer=import_setting.source, source=path) else: msg = "Variable file '%s'" % path if args: msg += " with arguments %s" % seq2str2(args) LOGGER.info("%s already imported by suite '%s'" % (msg, self._suite_name))
def _process_value(self, name, value): if name == 'ReRunFailed': return gather_failed_tests(value) if name == 'ReRunFailedSuites': return gather_failed_suites(value) if name == 'LogLevel': return self._process_log_level(value) if value == self._get_default_value(name): return value if name == 'Doc': return self._escape_as_data(value) if name in ['Metadata', 'TagDoc']: if name == 'Metadata': value = [self._escape_as_data(v) for v in value] return [self._process_metadata_or_tagdoc(v) for v in value] if name in ['Include', 'Exclude']: return [self._format_tag_patterns(v) for v in value] if name in self._output_opts and (not value or value.upper() == 'NONE'): return None if name == 'OutputDir': return abspath(value) if name in ['SuiteStatLevel', 'ConsoleWidth']: return self._convert_to_positive_integer_or_default(name, value) if name == 'VariableFiles': return [split_args_from_name_or_path(item) for item in value] if name == 'ReportBackground': return self._process_report_background(value) if name == 'TagStatCombine': return [self._process_tag_stat_combine(v) for v in value] if name == 'TagStatLink': return [v for v in [self._process_tag_stat_link(v) for v in value] if v] if name == 'Randomize': return self._process_randomize_value(value) if name == 'MaxErrorLines': return self._process_max_error_lines(value) if name == 'RemoveKeywords': self._validate_remove_keywords(value) if name == 'FlattenKeywords': self._validate_flatten_keywords(value) if name == 'WarnOnSkipped': with LOGGER.cache_only: LOGGER.warn("Option '--warnonskippedfiles' is deprecated and " "has no effect. Nowadays all skipped files are " "reported.") return value
def _import_library(self, import_setting, notify=True): name = self._resolve_name(import_setting) lib = IMPORTER.import_library(name, import_setting.args, import_setting.alias, self.variables) if lib.name in self._kw_store.libraries: LOGGER.info("Test library '%s' already imported by suite '%s'" % (lib.name, self._suite_name)) return if notify: LOGGER.imported("Library", lib.name, args=list(import_setting.args), originalname=lib.orig_name, importer=import_setting.source, source=lib.source) self._kw_store.libraries[lib.name] = lib lib.start_suite() if self._running_test: lib.start_test()