Source code for polyfemos.back.filewriter

# -*- coding: utf-8 -*-
# -----------------------------------------------------------------------------
# This file is part of Polyfemos.
#
# Polyfemos is free software: you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation, either version 3 of the License, or any later version.
#
# Polyfemos is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License and
# GNU General Public License along with Polyfemos. If not, see
# <https://www.gnu.org/licenses/>.'
#
# Author: Henrik Jänkävaara
# -----------------------------------------------------------------------------
"""
Contains classes for writing state of health files

:copyright:
    2019, University of Oulu, Sodankyla Geophysical Observatory
:license:
    GNU Lesser General Public License v3.0 or later
    (https://spdx.org/licenses/LGPL-3.0-or-later.html)
"""
import functools

from polyfemos.util import fileutils


[docs]def get_csv_header(unit, *args): """ :type unit: str :param unit: unit of the parameter values :rtype: list :return: soh csv file header as list of strings """ return ["utctimestamp", "value [{}]".format(unit), "z"]
[docs]def get_alert_header(*args): """ :rtype: list :return: soh alert file header as list of strings """ return ["station_id", "parameter", "alert", "priority", "last_dp_ts"]
[docs]def create_stfline(values, parname, *args): r""" :type values: list :param values: 2-3 value list, [timevalue, y, z] :type parname: str :param parname: parameter name :rtype: str :return: line for '\*.stf' file following the soh text file format """ stfline = values[:] stfline.insert(1, parname) str_ = "".join("{:30}".format(str(r)) for r in stfline).strip() str_ += "\n" return str_
[docs]def create_csvline(values, *args): r""" :type values: list :param values: 2-3 value list, [timevalue, y, z] :rtype: list :return: row for '\*.csv' file, the timevalue is replaced with the corresponding timestamp """ return [values[0].timestamp] + values[1:]
[docs]def _check_bool(method): """ A decorator to be used with :class:`~polyfemos.back.filewriter.FileWriter`. The call of the decorated method is omitted if ``self._bool`` attribute is ``False``. :type method: func :param method: A decorated method :rtype: func :return: """ @functools.wraps(method) def wrapper(self, *args, **kwargs): if self._bool: return method(self, *args, **kwargs) return None return wrapper
[docs]class FileWriter(object): """ Parent class for state of health file writer classes """
[docs] def __init__(self, bool_=False, fp_func=None, retroactive=False): """ The attribute values are suitable for writing state of health csv files by default. ``self._file_writing_func`` is set to :func:`~polyfemos.util.fileutils.write_csv`. ``self._create_line_func`` is set to :func:`~polyfemos.back.filewriter.create_csvline`. :type bool\_: bool :param bool\_: If ``False``, methods of this class do nothing, If ``fp_func`` is not callable, ``bool_`` is set to ``False`` :type fp_func: func :param fp_func: filepath function, e.g. FLAGs 'sohtextfilepath' 'sohalertpath' or 'sohcsvpath'. See :meth:`~polyfemos.back.interpreter.Interpreter._init_flags` for more information. :type retroactive: bool :param retroactive: defines if the retroactive mode is used. See :meth:`~polyfemos.back.interpreter.Interpreter._init_flags` for more info. """ bool_ &= callable(fp_func) self._bool = bool_ self._filepath_func = fp_func self._retroactive = retroactive self._dict = {} self._header = None self._suffix = "csv" self._file_writing_func = fileutils.write_csv self._create_line_func = create_csvline
[docs] @_check_bool def get_filename(self, pathkwargs): """ Applies ``pathkwargs`` to ``self._filepath_func`` and returns the resulting filepath. If retroactive mode is used, 'retro' identifier is added to the filepath. :type pathkwargs: dict :param pathkwargs: keyword arguments for ``self._filepath_func`` :rtype: str :return: """ retro = ".retro" if self._retroactive else "" fn = self._filepath_func(**pathkwargs) fn += "{}.{}".format(retro, self._suffix) return fn
[docs] @_check_bool def update_header(self, header): """ :type header: str or list :param header: a new header applied to ``self._header`` """ self._header = header
[docs] @_check_bool def append_line(self, filename, line): """ If there is no file with a name ``filename`` in ``self._dict``, header is added to the corersponding file entry in ``self._dict``. :type filename: str :param filename: :type line: list :param line: A line to be appended into the file (``filename``) entry in ``self._dict``. """ if filename not in self._dict: self._dict[filename] = [self._header] self._dict[filename].append(line)
[docs] @_check_bool def append_data(self, filename, *args): """ Additional arguments ``args`` are applied to the function ``self._create_line_func``. Creates and appends a new line to file entry (``filename``) in ``self._dict``. :type filename: str :param filename: """ line = self._create_line_func(*args) self.append_line(filename, line)
[docs] @_check_bool def append_and_write_data(self, filename, *args): """ Additional arguments ``args`` are applied to the function ``self._create_line_func``. Creates and immediately writes a new line to file ``filename``. :type filename: str :param filename: """ line = self._create_line_func(*args) fileutils.append_to_file(filename, line, self._header)
[docs] @_check_bool def write_files(self): """ Writes out every file in ``self._dict`` and deletes the data contained in it. """ for filename, rows in self._dict.items(): self._file_writing_func(filename, rows) self._dict = {}
[docs]class CSVWriter(FileWriter): r""" State of health csv file ('\*.csv') writer """
[docs] def __init__(self, *args, **kwargs): """ See :meth:`~polyfemos.back.filewriter.FileWriter.__init__` for more info. """ super().__init__(*args, **kwargs)
[docs]class AlertWriter(FileWriter): r""" State of health alert file ('\*.alert') writer """
[docs] def __init__(self, *args, **kwargs): """ ``self._header`` is set to a fixed value returned by :func:`~polyfemos.back.filewriter.get_alert_header`. See :meth:`~polyfemos.back.filewriter.FileWriter.__init__` for more info. """ super().__init__(*args, **kwargs) self._header = get_alert_header() self._suffix = "alert"
[docs]class STFWriter(FileWriter): r""" State of health text file ('\*.stf') writer """
[docs] def __init__(self, *args, **kwargs): """ ``self._file_writing_func`` is set to :func:`~polyfemos.util.fileutils.write_file`. ``self._create_line_func`` is set to :func:`~polyfemos.back.filewriter.create_stfline`. See :meth:`~polyfemos.back.filewriter.FileWriter.__init__` for more info. """ super().__init__(*args, **kwargs) self._file_writing_func = fileutils.write_file self._create_line_func = create_stfline self._suffix = "stf"
[docs] @_check_bool def append_line(self, filename, line): """ If there is no file with a name ``filename`` in ``self._dict``, header is added to the corersponding file entry in ``self._dict``. :type filename: str :param filename: :type line: str :param line: Line to be appended into the file (``filename``) entry in ``self._dict``. """ if filename not in self._dict: self._dict[filename] = self._header self._dict[filename] += line