Source code for pypenelopetools.penelope.keyword

"""
Definition of base keyword classes.
"""

# Standard library modules.
import abc
import os
import enum

# Third party modules.

# Local modules.
from pypenelopetools.penelope.base import InputLineBase

# Globals and constants variables.

#--- Abstract classes

[docs]class KeywordBase(InputLineBase): """ Base of all PENELOPE keywords. """ def __str__(self): return self.name
[docs] @abc.abstractmethod def get(self): """ Returns: tuple: Value(s) of this keyword. """ raise NotImplementedError
[docs] @abc.abstractmethod def copy(self): """ Returns: _KeyboardBase: Deep copy of this keyword. """ raise NotImplementedError
@abc.abstractproperty def name(self): """str: Name of keyword.""" raise NotImplementedError
#--- Core classes
[docs]class TypeKeyword(KeywordBase): """ Keyword where the :obj:`type` of the values are checked. Args: name (str): Name of keyword. types (tuple(type)): Type of each value of the keyword. comment (str, optional): Comment. """ def __init__(self, name, types, comment=""): self._name = name self._types = tuple(types) self._values = tuple([None] * len(types)) self._comment = comment
[docs] def set(self, *args): """ Sets the value(s) of the keyword. Each value is checked if it matches the defined type. Args: *args: Value(s). Raises: TypeError: If one value does not match its defined type. """ if len(args) < len(self._types): # Less than to account for additional, not parsed values raise ValueError("Keyword {0} requires {1} values, {2} given" .format(self.name, len(self._types), len(args))) values = [] for type_, value in zip(self._types, args): if value is not None: if issubclass(type_, enum.IntEnum): value = int(value) try: value = type_(value) except ValueError: raise TypeError("Value {0!r} must be of type {1}" .format(value, type_)) values.append(value) self.validate(*values) self._values = tuple(values)
[docs] def get(self): return self._values
[docs] def copy(self): return self.__class__(self.name, self._types, self.comment)
[docs] def validate(self, *args): pass
[docs] def read(self, fileobj): line = self._peek_next_line(fileobj) name, values, _comment = self._parse_line(line) # If it is not the expected line, do nothing if name != self.name: return # Set values self.set(*values) # Jump to next line self._read_next_line(fileobj)
[docs] def write(self, fileobj): values = list(self.get()) # Skip if no values are defined if None in values: return # Write to file line = self._create_line(self.name, values, self.comment) fileobj.write(line + os.linesep)
@property def name(self): return self._name @property def comment(self): """str: Comment.""" return self._comment
[docs]class KeywordGroupBase(KeywordBase): """ Group of keywords, keywords that should always be defined together. """
[docs] @abc.abstractmethod def get_keywords(self): """ Returns: tuple: Keywords apart of this group. """ raise NotImplementedError
[docs] def get(self): """ Returns: tuple: Value(s) of all keywords. """ values = [] for keyword in self.get_keywords(): values.extend(keyword.get()) return tuple(values)
[docs] def copy(self): return self.__class__()
[docs] def read(self, fileobj): for keyword in self.get_keywords(): keyword.read(fileobj)
[docs] def write(self, fileobj): for keyword in self.get_keywords(): keyword.write(fileobj)
def _set_keyword_sequence(self, keyword, values): keyword.clear() if values is None: return if not isinstance(values, (list, tuple)): values = [values] for args in values: keyword.add(*args) @property def name(self): return self.get_keywords()[0].name
[docs]class KeywordSequence(KeywordBase): """ Sequence of keywords, keywords that can be defined multiple times. Args: keyword (KeywordBase): Base keyword. maxlength (int): Maximum number of keywords that can be added. """ def __init__(self, keyword, maxlength): self._base_keyword = keyword self._keywords = [] self._maxlength = maxlength def _create_keyword(self): return self._base_keyword.copy() def _add_keyword(self, keyword): if len(self._keywords) >= self._maxlength: raise ValueError('Exceeded maximum number of keywords.') self._keywords.append(keyword)
[docs] def add(self, *args): """Adds a new keyword definition. This internally creates a new keyword based on the base keyword, sets the value(s) and add it to a list. Args: *args: Value(s). """ keyword = self._create_keyword() keyword.set(*args) self._add_keyword(keyword) return keyword
[docs] def pop(self, index): """Removes a keyword. Args: index (int): Index of the keyword to be removed. """ self._keywords.pop(index)
[docs] def clear(self): """Clears all added keywords.""" self._keywords.clear()
[docs] def get(self): """ Returns: tuple: Value(s) of all keywords. """ values = [] for keyword in self._keywords: values.append(keyword.get()) return (tuple(values),)
[docs] def copy(self): return self.__class__(self._base_keyword.copy())
[docs] def read(self, fileobj): line = self._peek_next_line(fileobj) name, _values, _comment = self._parse_line(line) while name == self._base_keyword.name: # Read keyword keyword = self._create_keyword() keyword.read(fileobj) self._add_keyword(keyword) # Try to read line line = self._peek_next_line(fileobj) name, _values, _comment = self._parse_line(line)
[docs] def write(self, fileobj): for keyword in self._keywords: keyword.write(fileobj)
@property def name(self): return self._base_keyword.name