Source code for aiida_vasp.parsers.content_parsers.stream
"""
This module contains the parsing interfaces to ``parsevasp`` used to parse standard streams
for VASP related notification, warnings, and errors.
"""
# pylint: disable=abstract-method
import re
from typing import TextIO
from parsevasp.stream import Stream
from aiida_vasp.parsers.content_parsers.base import BaseFileParser
[docs]
class StreamParser(BaseFileParser):
"""
Parser used for parsing errors and warnings from VASP.
:ivar DEFAULT_SETTINGS: Default settings for quantities to parse.
:ivar PARSABLE_QUANTITIES: The quantities that can be parsed.
"""
DEFAULT_SETTINGS = {'quantities_to_parse': ['notifications']}
PARSABLE_QUANTITIES = {
'notifications': {
'inputs': [],
'name': 'notifications',
'prerequisites': [],
}
}
[docs]
def _init_from_handler(self, handler: TextIO) -> None:
"""
Initialize a ``parsevasp`` object of ``Stream`` using a file like handler.
:param handler: A file like object that provides the necessary standard stream content to be parsed.
:type handler: file-like object
"""
# First get any special config from the parser settings, else use the default
stream_config = None
history = False
if self._settings is not None:
stream_config = self._settings.get('stream_config', None)
history = self._settings.get('stream_history', False)
try:
self._content_parser = Stream(
file_handler=handler, logger=self._logger, history=history, config=stream_config
)
except SystemExit:
self._logger.warning('Parsevasp exited abnormally.')
@property
def notifications(self):
"""
Fetch the notifications that VASP generated.
:returns: A list of all notifications from VASP. Each entry is a dict with the keys ``name``,
``kind``, ``message``
and ``regex`` containing the name of the message, what kind it is (``ERROR`` or ``WARNING``),
a description
of the notification, and the regular expression detected as string values.
:rtype: list
"""
# ``parsevasp`` returns ``VaspStream`` objects, which we cannot serialize. We could serialize this, but
# eventually, we would like to move to a dedicated node for the notifications with its own data class.
# This should be fixed in AiiDA core and coordinated across many plugins. For now, we convert the relevant info
# into dict entries explicitly.
notifications = []
for item in self._content_parser.entries:
if isinstance(item.regex, type(re.compile(''))):
regex = item.regex.pattern
else:
regex = item.regex
notifications.append({'name': item.shortname, 'kind': item.kind, 'message': item.message, 'regex': regex})
return notifications
@property
def errors(self):
"""
Fetch the errors that VASP generated.
:returns: A list of all errors from VASP. Each entry is a dict with the keys ``name``, ``kind``, ``message``
and ``regex`` containing the name of the message, what kind it is (``ERROR``), a description
of the error, and the regular expression detected as string values.
:rtype: list
"""
return [item for item in self._content_parser.entries if item.kind == 'ERROR']
@property
def warnings(self):
"""
Fetch the warnings that VASP generated.
:returns: A list of all warnings from VASP. Each entry is a dict with the keys ``name``, ``kind``, ``message``
and ``regex`` containing the name of the message, what kind it is (``WARNING``), a description
of the warning, and the regular expression detected as string values.
:rtype: list
"""
return [item for item in self._content_parser.entries if item.kind == 'WARNING']
@property
def has_entries(self):
"""
Check if there are notifications from VASP present according to the config after parsing.
:returns: ``True`` if notifications were detected, ``False`` otherwise.
:rtype: bool
"""
entries = self._content_parser.has_entries
return entries
@property
def number_of_entries(self):
"""
Find the number of unique notifications from VASP.
:returns: The number of unique notification entries that VASP generated.
:rtype: int
"""
number_of_entries = len(self._content_parser)
return number_of_entries