Source code for robot.parsing.suitestructure

#  Copyright 2008-2015 Nokia Networks
#  Copyright 2016-     Robot Framework Foundation
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  See the License for the specific language governing permissions and
#  limitations under the License.

import os.path

from robot.errors import DataError
from robot.model import SuiteNamePatterns
from robot.output import LOGGER
from robot.utils import abspath, get_error_message, unic

[docs]class SuiteStructure(object): def __init__(self, source=None, init_file=None, children=None): self.source = source self.init_file = init_file self.children = children self.extension = self._get_extension(source, init_file) def _get_extension(self, source, init_file): if self.is_directory and not init_file: return None source = init_file or source return os.path.splitext(source)[1][1:].lower() @property def is_directory(self): return self.children is not None
[docs] def visit(self, visitor): if self.children is None: visitor.visit_file(self) else: visitor.visit_directory(self)
[docs]class SuiteStructureBuilder(object): ignored_prefixes = ('_', '.') ignored_dirs = ('CVS',) def __init__(self, included_extensions=('robot',), included_suites=None): self.included_extensions = included_extensions self.included_suites = included_suites
[docs] def build(self, paths): paths = list(self._normalize_paths(paths)) if len(paths) == 1: return self._build(paths[0], self.included_suites) children = [self._build(p, self.included_suites) for p in paths] return SuiteStructure(children=children)
def _normalize_paths(self, paths): if not paths: raise DataError('One or more source paths required.') for path in paths: path = os.path.normpath(path) if not os.path.exists(path): raise DataError("Parsing '%s' failed: File or directory to " "execute does not exist." % path) yield abspath(path) def _build(self, path, include_suites): if os.path.isfile(path): return SuiteStructure(path) include_suites = self._get_include_suites(path, include_suites) init_file, paths = self._get_child_paths(path, include_suites) children = [self._build(p, include_suites) for p in paths] return SuiteStructure(path, init_file, children) def _get_include_suites(self, path, incl_suites): if not incl_suites: return None if not isinstance(incl_suites, SuiteNamePatterns): incl_suites = SuiteNamePatterns( self._create_included_suites(incl_suites)) # If a directory is included, also all its children should be included. if self._is_in_included_suites(os.path.basename(path), incl_suites): return None return incl_suites def _create_included_suites(self, incl_suites): for suite in incl_suites: yield suite while '.' in suite: suite = suite.split('.', 1)[1] yield suite def _get_child_paths(self, dirpath, incl_suites=None): init_file = None paths = [] for path, is_init_file in self._list_dir(dirpath, 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: paths.append(path) return init_file, paths def _list_dir(self, dir_path, incl_suites): # os.listdir returns Unicode entries when path is Unicode dir_path = unic(dir_path) try: names = os.listdir(dir_path) except: raise DataError("Reading directory '%s' failed: %s" % (dir_path, get_error_message())) 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): yield path, True elif self._is_included(path, base, ext, incl_suites): yield path, False else:"Ignoring file or directory '%s'." % path) def _is_init_file(self, path, base, ext): return (base.lower() == '__init__' and ext in self.included_extensions and os.path.isfile(path)) def _is_included(self, path, base, ext, incl_suites): if base.startswith(self.ignored_prefixes): return False if os.path.isdir(path): return base not in self.ignored_dirs or ext if ext not in self.included_extensions: return False return self._is_in_included_suites(base, incl_suites) def _is_in_included_suites(self, name, incl_suites): if not incl_suites: return True return incl_suites.match(self._split_prefix(name)) def _split_prefix(self, name): return name.split('__', 1)[-1]
[docs]class SuiteStructureVisitor(object):
[docs] def visit_file(self, structure): pass
[docs] def visit_directory(self, structure): self.start_directory(structure) for child in structure.children: child.visit(self) self.end_directory(structure)
[docs] def start_directory(self, structure): pass
[docs] def end_directory(self, structure): pass