Source code for gemseo.core.grammars.factory
# Copyright 2021 IRT Saint Exupéry, https://www.irt-saintexupery.com
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License version 3 as published by the Free Software Foundation.
#
# 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
# Contributors:
# INITIAL AUTHORS - initial API and implementation and/or initial
# documentation
# :author: Francois Gallard, Matthias De Lozzo
# OTHER AUTHORS - MACROSCOPIC CHANGES
"""A factory to instantiate a derived class of :class:`.BaseGrammar`."""
from __future__ import annotations
import sys
from pathlib import Path
from typing import TYPE_CHECKING
from typing import Any
from strenum import StrEnum
from gemseo.core.base_factory import BaseFactory
from gemseo.core.grammars.base_grammar import BaseGrammar
if TYPE_CHECKING:
from gemseo.core.discipline import Discipline
[docs]
class GrammarFactory(BaseFactory[BaseGrammar]):
"""A factory of :class:`.BaseGrammar`."""
_CLASS = BaseGrammar
_PACKAGE_NAMES = ("gemseo.core.grammars",)
[docs]
def create(
self,
class_name: str,
name: str,
search_file: bool = False,
discipline_class: type[Discipline] | None = None,
directory_path: Path | str = "",
file_name_suffix: str = "",
**options: Any,
) -> BaseGrammar:
"""Create a grammar.
Args:
class_name: The name of a class deriving from :class:`.BaseGrammar`.
name: The name to be given to the grammar.
search_file: Whether to search for a JSON grammar file.
This argument is considered to be ``False`` when the option
``file_path`` is given.
discipline_class: The class of the discipline used for searching the grammar
in the parent classes.
This argument is used when ``search_file`` is ``True``.
directory_path: The path to the directory where to search for JSON grammar
files.
This argument is used when ``search_file`` is ``True``.
file_name_suffix: The suffix of the JSON grammar file.
This argument is used when ``search_file`` is ``True``.
**options: The options to be passed to the initialization.
"""
if class_name == "JSONGrammar" and search_file and not options.get("file_path"):
if discipline_class is None:
msg = (
"The argument discipline_class is needed when the argument "
"when the argument search_file is True."
)
raise ValueError(msg)
options["file_path"] = self.__search_file(
discipline_class, file_name_suffix, directory_path
)
return super().create(class_name, name=name, **options)
@staticmethod
def __search_file(
discipline_class: type[Discipline],
file_name_suffix: str,
directory_path: str | Path,
) -> Path:
"""Use a naming convention to associate a grammar file to the discipline.
Search in the directory ``directory_path`` for
either an input grammar file named ``name + "_input.json"``
or an output grammar file named ``name + "_output.json"``.
Args:
file_name_suffix: The suffix of the file name (xxx_suffix.json)
directory_path: The directory in which to search the grammar file.
If ``None``,
use the :attr:`.GRAMMAR_DIRECTORY` if any,
or the directory of the discipline class module.
Returns:
The grammar file path.
"""
# To avoid circular dependencies.
from gemseo.core.discipline.base_discipline import BaseDiscipline
classes = [discipline_class] + [
base
for base in discipline_class.__bases__
if issubclass(base, BaseDiscipline)
]
for cls in classes:
name = cls.__name__
if not directory_path:
class_module = sys.modules[cls.__module__]
directory_path_ = Path(class_module.__file__).parent # type: ignore[arg-type] # __file__ could be None
else:
directory_path_ = Path(directory_path)
grammar_file_path = directory_path_ / f"{name}_{file_name_suffix}.json"
if grammar_file_path.is_file():
return grammar_file_path
file_name = f"{discipline_class.__name__}_{file_name_suffix}.json"
msg = f"The grammar file {file_name} is missing."
raise FileNotFoundError(msg)
[docs]
class GrammarType(StrEnum):
"""The name of the grammar class."""
JSON = "JSONGrammar"
SIMPLE = "SimpleGrammar"
SIMPLER = "SimplerGrammar"
PYDANTIC = "PydanticGrammar"