Source code for fastoad.io.xml.translator

"""
Conversion from OpenMDAO variables to XPath
"""

#  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
#  Copyright (C) 2021 ONERA & ISAE-SUPAERO
#  FAST is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#  This program 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 General Public License for more details.
#  You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <https://www.gnu.org/licenses/>.
from typing import IO, Sequence, Set, Union

import numpy as np

from fastoad.io.xml.exceptions import (
    FastXpathTranslatorDuplicates,
    FastXpathTranslatorInconsistentLists,
    FastXpathTranslatorVariableError,
    FastXpathTranslatorXPathError,
)


[docs]class VarXpathTranslator: """ Allows to convert OpenMDAO variable names from and to XPath, using a provided conversion table. At instantiation, user can provide (as keyword arguments only): - variable_names and xpaths (see :meth:`set`) - translation file (see :meth:`read_translation_table`) """ def __init__( self, *, variable_names: Sequence[str] = None, xpaths: Sequence[str] = None, source: Union[str, IO] = None ): if variable_names is not None and xpaths is not None: self.set(variable_names, xpaths) if source is not None: self.read_translation_table(source)
[docs] def set(self, variable_names: Sequence[str], xpaths: Sequence[str]): """ Sets the "conversion table", i.e. two lists where each element matches the other with same index. Provided lists must have the same length. :param variable_names: List of OpenMDAO variable names :param xpaths: List of XML Paths """ if len(variable_names) != len(xpaths): raise FastXpathTranslatorInconsistentLists( "lists var_names and xpaths have not the same length (%i and %i)" % (len(variable_names), len(xpaths)) ) # check duplicate variable names dupe_vars = self._get_duplicates(variable_names) if dupe_vars: raise FastXpathTranslatorDuplicates( "Following variable names are provided more than once: %s" % dupe_vars, dupe_vars ) # check duplicate XPaths dupe_xpaths = self._get_duplicates(xpaths) if dupe_xpaths: raise FastXpathTranslatorDuplicates( "Following variable names are provided more than once: %s" % dupe_xpaths, dupe_xpaths, ) self._variable_names = list(variable_names) self._xpaths = list(xpaths)
[docs] def read_translation_table(self, source: Union[str, IO]): """ Reads a file that sets how OpenMDAO variable are matched to XML Path. Provided file should have 2 comma-separated columns: - first one with OpenMDAO names - second one with their matching XPath :param source: """ arr = np.genfromtxt(source, dtype=str, delimiter=",", autostrip=True) self.set(arr[:, 0], arr[:, 1])
@property def variable_names(self) -> Sequence[str]: """List of variable names as set in :meth:`set`""" return self._variable_names @property def xpaths(self) -> Sequence[str]: """List of XPaths as set in :meth:`set`""" return self._xpaths
[docs] def get_xpath(self, var_name: str) -> str: """ :param var_name: OpenMDAO variable name :return: XPath that matches var_name :raise FastXpathTranslatorVariableError: if var_name is unknown """ if var_name in self._variable_names: i = self._variable_names.index(var_name) return self._xpaths[i] raise FastXpathTranslatorVariableError(var_name)
[docs] def get_variable_name(self, xpath: str) -> str: """ :param xpath: XML Path :return: OpenMDAO variable name that matches xpath :raise FastXpathTranslatorXPathError: if xpath is unknown """ if xpath in self._xpaths: i = self._xpaths.index(xpath) return self._variable_names[i] raise FastXpathTranslatorXPathError(xpath)
@staticmethod def _get_duplicates(seq: Sequence) -> Set: dupes = set() seen = set() for elem in seq: if elem in seen: dupes.add(elem) else: seen.add(elem) return dupes