Skip to content

Commit

Permalink
Refactor SuiteStructure.
Browse files Browse the repository at this point in the history
Separate classes for SuiteFile and SuiteDirectory to ease typing.
  • Loading branch information
pekkaklarck committed May 2, 2023
1 parent 187bae5 commit 80cf0da
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 27 deletions.
3 changes: 2 additions & 1 deletion src/robot/parsing/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@
from .lexer import get_tokens, get_resource_tokens, get_init_tokens, Token
from .model import File, ModelTransformer, ModelVisitor
from .parser import get_model, get_resource_model, get_init_model
from .suitestructure import SuiteStructure, SuiteStructureBuilder, SuiteStructureVisitor
from .suitestructure import (SuiteFile, SuiteDirectory, SuiteStructure,
SuiteStructureBuilder, SuiteStructureVisitor)
67 changes: 47 additions & 20 deletions src/robot/parsing/suitestructure.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,61 +13,88 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from abc import ABC, abstractmethod
from pathlib import Path
from typing import Iterable
from typing import Iterable, Sequence

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


class SuiteStructure:
class SuiteStructure(ABC):
source: 'Path|None'
init_file: 'Path|None'
children: 'list[SuiteStructure]|None'

def __init__(self, source: 'Path|None' = None, init_file: 'Path|None' = None,
children: 'list[SuiteStructure]|None' = None):
def __init__(self, source: 'Path|None', init_file: 'Path|None' = None,
children: 'Sequence[SuiteStructure]|None' = None):
self.source = source
self.init_file = init_file
self.children = children
self.children = list(children) if children is not None else None

@property
@abstractmethod
def extension(self) -> 'str|None':
source = self.source if self.is_file else self.init_file
return source.suffix[1:].lower() if source else None
raise NotImplementedError

@abstractmethod
def visit(self, visitor: 'SuiteStructureVisitor'):
raise NotImplementedError


class SuiteFile(SuiteStructure):
source: Path

def __init__(self, source: Path):
super().__init__(source)

@property
def is_file(self) -> bool:
return self.children is None
def extension(self) -> str:
return self.source.suffix[1:].lower()

def visit(self, visitor: 'SuiteStructureVisitor'):
visitor.visit_file(self)


class SuiteDirectory(SuiteStructure):
children: 'list[SuiteStructure]'

def __init__(self, source: 'Path|None' = None, init_file: 'Path|None' = None,
children: Sequence[SuiteStructure] = ()):
super().__init__(source, init_file, children)

@property
def is_multi_source(self) -> bool:
return self.source is None

@property
def extension(self) -> 'str|None':
return self.init_file.suffix[1:].lower() if self.init_file else None

def add(self, child: 'SuiteStructure'):
self.children.append(child)

def visit(self, visitor: 'SuiteStructureVisitor'):
if self.children is None:
visitor.visit_file(self)
else:
visitor.visit_directory(self)
visitor.visit_directory(self)


class SuiteStructureVisitor:

def visit_file(self, structure: SuiteStructure):
def visit_file(self, structure: SuiteFile):
pass

def visit_directory(self, structure: SuiteStructure):
def visit_directory(self, structure: SuiteDirectory):
self.start_directory(structure)
for child in structure.children:
child.visit(self)
self.end_directory(structure)

def start_directory(self, structure: SuiteStructure):
def start_directory(self, structure: SuiteDirectory):
pass

def end_directory(self, structure: SuiteStructure):
def end_directory(self, structure: SuiteDirectory):
pass


Expand Down Expand Up @@ -96,12 +123,12 @@ def build(self, *paths: Path) -> SuiteStructure:

def _build(self, path: Path, included_suites: SuiteNamePatterns) -> SuiteStructure:
if path.is_file():
return SuiteStructure(path)
return SuiteFile(path)
return self._build_directory(path, included_suites)

def _build_directory(self, path: Path,
included_suites: SuiteNamePatterns) -> SuiteStructure:
structure = SuiteStructure(path, children=[])
structure = SuiteDirectory(path)
# If a directory is included, also its children are included.
if self._is_suite_included(path.name, included_suites):
included_suites = SuiteNamePatterns()
Expand Down Expand Up @@ -147,7 +174,7 @@ def _is_included(self, path: Path, included_suites: SuiteNamePatterns) -> bool:
return self._is_suite_included(path.stem, included_suites)

def _build_multi_source(self, paths: Iterable[Path]) -> SuiteStructure:
structure = SuiteStructure(children=[])
structure = SuiteDirectory()
for path in paths:
if self._is_init_file(path):
if structure.init_file:
Expand Down
13 changes: 7 additions & 6 deletions src/robot/running/builder/builders.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
from robot.conf import LanguagesLike
from robot.errors import DataError
from robot.output import LOGGER
from robot.parsing import SuiteStructure, SuiteStructureBuilder, SuiteStructureVisitor
from robot.parsing import (SuiteFile, SuiteDirectory, SuiteStructure,
SuiteStructureBuilder, SuiteStructureVisitor)
from robot.utils import Importer, seq2str, split_args_from_name_or_path, type_name

from ..model import ResourceFile, TestSuite
Expand Down Expand Up @@ -197,15 +198,15 @@ def parse(self, structure: SuiteStructure) -> TestSuite:
suite.rpa = self.rpa
return suite

def visit_file(self, structure: SuiteStructure):
def visit_file(self, structure: SuiteFile):
LOGGER.info(f"Parsing file '{structure.source}'.")
suite = self._build_suite_file(structure)
if self.suite is None:
self.suite = suite
else:
self._stack[-1][0].suites.append(suite)

def start_directory(self, structure: SuiteStructure):
def start_directory(self, structure: SuiteDirectory):
if structure.source:
LOGGER.info(f"Parsing directory '{structure.source}'.")
suite, defaults = self._build_suite_directory(structure)
Expand All @@ -215,12 +216,12 @@ def start_directory(self, structure: SuiteStructure):
self._stack[-1][0].suites.append(suite)
self._stack.append((suite, defaults))

def end_directory(self, structure: SuiteStructure):
def end_directory(self, structure: SuiteDirectory):
suite, _ = self._stack.pop()
if suite.rpa is None and suite.suites:
suite.rpa = suite.suites[0].rpa

def _build_suite_file(self, structure: SuiteStructure):
def _build_suite_file(self, structure: SuiteFile):
source = cast(Path, structure.source)
defaults = self.parent_defaults or TestDefaults()
parser = self.parsers[structure.extension]
Expand All @@ -233,7 +234,7 @@ def _build_suite_file(self, structure: SuiteStructure):
raise DataError(f"Parsing '{source}' failed: {err.message}")
return suite

def _build_suite_directory(self, structure: SuiteStructure):
def _build_suite_directory(self, structure: SuiteDirectory):
source = cast(Path, structure.init_file or structure.source)
defaults = TestDefaults(self.parent_defaults)
parser = self.parsers[structure.extension]
Expand Down

0 comments on commit 80cf0da

Please sign in to comment.