Repository: fast-aircraft-design/FAST-OAD (language: python)

Issue:
Enabling pathlib.Path inputs for DataFile objects
Fixes #520 by making the DataFile class able to use `pathlib.Path` instances as input.

Also added some refactoring that CodeClimate was demanding.



Discussion / hints:

Fix patch:
diff --git a/src/fastoad/_utils/resource_management/copy.py b/src/fastoad/_utils/resource_management/copy.py
index 52e5ea23b..ee050b15d 100644
--- a/src/fastoad/_utils/resource_management/copy.py
+++ b/src/fastoad/_utils/resource_management/copy.py
@@ -2,7 +2,7 @@
 Helper module for copying resources
 """
 #  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
-#  Copyright (C) 2022 ONERA & ISAE-SUPAERO
+#  Copyright (C) 2024 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
@@ -14,17 +14,16 @@
 #  You should have received a copy of the GNU General Public License
 #  along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-import os.path as pth
 import shutil
 from importlib.resources import Package, is_resource, path
-from types import ModuleType
-from typing import List
+from os import PathLike
+from typing import Union, Iterable
 
 from .contents import PackageReader
-from ..files import make_parent_dir
+from ..files import as_path, make_parent_dir
 
 
-def copy_resource(package: Package, resource: str, target_path):
+def copy_resource(package: Package, resource: str, target_path: Union[str, PathLike]):
     """
     Copies the indicated resource file to provided target path.
 
@@ -41,7 +40,9 @@ def copy_resource(package: Package, resource: str, target_path):
         shutil.copy(source_path, target_path)
 
 
-def copy_resource_folder(package: Package, destination_path: str, exclude: List[str] = None):
+def copy_resource_folder(
+    package: Package, destination_path: Union[str, PathLike], exclude: Iterable[str] = None
+):
     """
     Copies the full content of provided package in destination folder.
 
@@ -51,33 +52,30 @@ def copy_resource_folder(package: Package, destination_path: str, exclude: List[
 
         As the resources in the folder are discovered by browsing
         through the folder, they are not explicitly listed in the Python code.
-        Therefore, to have the install process run smoothly, these resources need
+        Therefore, to have the installation process run smoothly, these resources need
         to be listed in the MANIFEST.in file.
 
     :param package: name of resource package to copy
     :param destination_path: file system path of destination
     :param exclude: list of item names that should not be copied
     """
-    exclusion_list = ["__pycache__"]
+    destination_path = as_path(destination_path)
+
+    exclusion_list = {"__pycache__"}
     if exclude:
-        exclusion_list += exclude
-
-    package_contents = PackageReader(package).contents
-    if package_contents:
-        for resource_name in package_contents:
-            if resource_name in exclusion_list:
-                continue
-            if is_resource(package, resource_name):
-                destination_file_path = pth.join(destination_path, resource_name)
-                copy_resource(package, resource_name, destination_file_path)
-            else:
-                # In case of subfolders that are only declared in MANIFEST.in,
-                # getattr(package, "resource_name") will fail (is there another way?).
-                # So we fall back to using package name as as string.
-                if isinstance(package, ModuleType):
-                    package_name = package.__name__
-                else:  # str
-                    package_name = package
-                new_package_name = ".".join([package_name, resource_name])
-                new_destination_path = pth.join(destination_path, resource_name)
-                copy_resource_folder(new_package_name, new_destination_path, exclude=exclude)
+        exclusion_list |= set(exclude)
+
+    package_contents = set(PackageReader(package).contents) - exclusion_list
+    for resource_name in package_contents:
+        if is_resource(package, resource_name):
+            destination_file_path = destination_path / resource_name
+            copy_resource(package, resource_name, destination_file_path)
+        else:
+            # In case of subfolders that are only declared in MANIFEST.in,
+            # getattr(package, "resource_name") will fail (is there another way?).
+            # So we fall back to using package name as string.
+            package_name = package if isinstance(package, str) else package.__name__
+
+            new_package_name = ".".join([package_name, resource_name])
+            new_destination_path = destination_path / resource_name
+            copy_resource_folder(new_package_name, new_destination_path, exclude=exclude)
diff --git a/src/fastoad/cmd/api.py b/src/fastoad/cmd/api.py
index b44c4cc4d..ed6af55fc 100644
--- a/src/fastoad/cmd/api.py
+++ b/src/fastoad/cmd/api.py
@@ -16,7 +16,6 @@
 
 import logging
 import os
-import os.path as pth
 import shutil
 import sys
 import textwrap as tw
@@ -24,6 +23,7 @@
 from collections.abc import Iterable
 from enum import Enum
 from os import PathLike
+from pathlib import Path
 from time import time
 from typing import Dict, List, Union, TextIO
 
@@ -34,7 +34,7 @@
 from tabulate import tabulate
 
 import fastoad.openmdao.whatsopt
-from fastoad._utils.files import make_parent_dir
+from fastoad._utils.files import as_path, make_parent_dir
 from fastoad._utils.resource_management.copy import copy_resource, copy_resource_folder
 from fastoad.cmd.exceptions import (
     FastNoAvailableNotebookError,
@@ -88,7 +88,7 @@ def get_plugin_information(print_data=False) -> Dict[str, DistributionPluginDefi
 
 
 def generate_notebooks(
-    destination_path: str,
+    destination_path: Union[str, PathLike],
     overwrite: bool = False,
     distribution_name=None,
 ):
@@ -101,6 +101,8 @@ def generate_notebooks(
     :param overwrite: if True and `destination_path` exists, it will be removed before writing.
     :param distribution_name: the name of an installed package that provides notebooks
     """
+    destination_path = as_path(destination_path)
+
     # Check available notebooks
     folder_info_list = FastoadLoader().get_notebook_folder_list(distribution_name)
 
@@ -108,8 +110,8 @@ def generate_notebooks(
         raise FastNoAvailableNotebookError(distribution_name)
 
     # Create and copy folder
-    destination_path = pth.abspath(destination_path)
-    if pth.exists(destination_path):
+    destination_path = destination_path.absolute()
+    if destination_path.exists():
         if overwrite:
             shutil.rmtree(destination_path)
         else:
@@ -137,7 +139,7 @@ def generate_notebooks(
             if not only_one_plugin:
                 target_path_elements.append(folder_info.plugin_name)
 
-            target_path = pth.join(*target_path_elements)
+            target_path = Path(*target_path_elements)
             os.makedirs(target_path)
             copy_resource_folder(folder_info.package_name, target_path)
 
@@ -146,7 +148,7 @@ def generate_notebooks(
 
 def _generate_user_file(
     user_file_type: UserFileType,
-    user_file_path: str,
+    user_file_path: Union[str, PathLike],
     overwrite: bool = False,
     distribution_name=None,
     sample_user_file_name=None,
@@ -168,6 +170,7 @@ def _generate_user_file(
     :return: path of generated file
     :raise FastPathExistsError: if overwrite==False and user_file_path already exists
     """
+    user_file_path = as_path(user_file_path)
 
     if distribution_name is None:
         # If no distribution is specified, but only one contains the type of user files
@@ -216,8 +219,8 @@ def _generate_user_file(
         file_info = dist_definition.get_source_data_file_info(sample_user_file_name)
 
     # Check on file overwrite
-    user_file_path = pth.abspath(user_file_path)
-    if not overwrite and pth.exists(user_file_path):
+    user_file_path = user_file_path.absolute()
+    if not overwrite and user_file_path.exists():
         raise FastPathExistsError(
             user_file_type.value.capitalize()
             + f" {user_file_path} not written because it already exists. "
@@ -236,7 +239,7 @@ def _generate_user_file(
 
 
 def generate_configuration_file(
-    configuration_file_path: str,
+    configuration_file_path: Union[str, PathLike],
     overwrite: bool = False,
     distribution_name=None,
     sample_file_name=None,
@@ -264,7 +267,7 @@ def generate_configuration_file(
 
 
 def generate_source_data_file(
-    source_data_file_path: str,
+    source_data_file_path: Union[str, PathLike],
     overwrite: bool = False,
     distribution_name=None,
     sample_file_name=None,
@@ -292,8 +295,8 @@ def generate_source_data_file(
 
 
 def generate_inputs(
-    configuration_file_path: str,
-    source_data_path: str = None,
+    configuration_file_path: Union[str, PathLike],
+    source_data_path: Union[str, PathLike] = None,
     source_data_path_schema="native",
     overwrite: bool = False,
 ) -> str:
@@ -310,8 +313,8 @@ def generate_inputs(
     conf = FASTOADProblemConfigurator(configuration_file_path)
     conf._set_configuration_modifier(_PROBLEM_CONFIGURATOR)
 
-    input_file_path = conf.input_file_path
-    if not overwrite and pth.exists(conf.input_file_path):
+    input_file_path = as_path(conf.input_file_path)
+    if not overwrite and input_file_path.exists():
         raise FastPathExistsError(
             f"Input file {input_file_path} not written because it already exists. "
             "Use overwrite=True to bypass.",
@@ -324,7 +327,7 @@ def generate_inputs(
         conf.write_needed_inputs(source_data_path)
 
     _LOGGER.info("Problem inputs written in %s", input_file_path)
-    return input_file_path
+    return conf.input_file_path
 
 
 def list_variables(
@@ -355,6 +358,8 @@ def list_variables(
     :return: path of generated file, or None if no file was generated.
     :raise FastPathExistsError: if `overwrite==False` and `out` is a file path and the file exists
     """
+    configuration_file_path = as_path(configuration_file_path)
+
     if out is None:
         out = sys.stdout
 
@@ -380,9 +385,9 @@ def list_variables(
         .rename(columns={"name": "NAME", "desc": "DESCRIPTION"})
     )
 
-    if isinstance(out, str):
-        out = pth.abspath(out)
-        if not overwrite and pth.exists(out):
+    if isinstance(out, (str, PathLike)):
+        out = as_path(out).absolute()
+        if not overwrite and out.exists():
             raise FastPathExistsError(
                 f"File {out} not written because it already exists. "
                 "Use overwrite=True to bypass.",
@@ -462,19 +467,21 @@ def list_modules(
     if out is None:
         out = sys.stdout
 
-    if isinstance(source_path, str):
-        if pth.isfile(source_path):
+    if isinstance(source_path, (str, PathLike)):
+        source_path = as_path(source_path)
+        if source_path.is_file():
             conf = FASTOADProblemConfigurator(source_path)
             conf._set_configuration_modifier(_PROBLEM_CONFIGURATOR)
             # As the problem has been configured,
             # BundleLoader now knows additional registered systems
-        elif pth.isdir(source_path):
+        elif source_path.is_dir():
             RegisterOpenMDAOSystem.explore_folder(source_path)
         else:
             raise FileNotFoundError(f"Could not find {source_path}")
     elif isinstance(source_path, Iterable):
         for folder_path in source_path:
-            if not pth.isdir(folder_path):
+            folder_path = as_path(folder_path)
+            if not folder_path.is_dir():
                 _LOGGER.warning("SKIPPED %s: folder does not exist.", folder_path)
             else:
                 RegisterOpenMDAOSystem.explore_folder(folder_path)
@@ -486,9 +493,9 @@ def list_modules(
     else:
         cell_list = _get_simple_system_list()
 
-    if isinstance(out, str):
-        out = pth.abspath(out)
-        if not overwrite and pth.exists(out):
+    if isinstance(out, (str, PathLike)):
+        out = as_path(out).absolute()
+        if not overwrite and out.exists():
             raise FastPathExistsError(
                 f"File {out} not written because it already exists. "
                 "Use overwrite=True to bypass.",
@@ -576,7 +583,11 @@ def _get_detailed_system_list():
     return cell_list
 
 
-def write_n2(configuration_file_path: str, n2_file_path: str = None, overwrite: bool = False):
+def write_n2(
+    configuration_file_path: Union[str, PathLike],
+    n2_file_path: Union[str, PathLike] = None,
+    overwrite: bool = False,
+):
     """
     Write the N2 diagram of the problem in file n2.html
 
@@ -586,12 +597,14 @@ def write_n2(configuration_file_path: str, n2_file_path: str = None, overwrite:
     :return: path of generated file.
     :raise FastPathExistsError: if overwrite==False and n2_file_path already exists
     """
+    configuration_file_path = as_path(configuration_file_path)
+    n2_file_path = as_path(n2_file_path)
 
     if not n2_file_path:
-        n2_file_path = "n2.html"
-    n2_file_path = pth.abspath(n2_file_path)
+        n2_file_path = Path("n2.html")
+    n2_file_path = n2_file_path.absolute()
 
-    if not overwrite and pth.exists(n2_file_path):
+    if not overwrite and n2_file_path.exists():
         raise FastPathExistsError(
             f"N2-diagram file {n2_file_path} not written because it already exists. "
             "Use overwrite=True to bypass.",
@@ -608,13 +621,13 @@ def write_n2(configuration_file_path: str, n2_file_path: str = None, overwrite:
     om.n2(problem, outfile=n2_file_path, show_browser=False)
     if InteractiveShell.initialized():
         clear_output()
-    _LOGGER.info("N2 diagram written in %s", pth.abspath(n2_file_path))
+    _LOGGER.info("N2 diagram written in %s", n2_file_path.resolve())
     return n2_file_path
 
 
 def write_xdsm(
-    configuration_file_path: str,
-    xdsm_file_path: str = None,
+    configuration_file_path: Union[str, PathLike],
+    xdsm_file_path: Union[str, PathLike] = None,
     overwrite: bool = False,
     depth: int = 2,
     wop_server_url: str = None,
@@ -632,11 +645,14 @@ def write_xdsm(
     :return: path of generated file.
     :raise FastPathExistsError: if overwrite==False and xdsm_file_path already exists
     """
+    configuration_file_path = as_path(configuration_file_path)
+    xdsm_file_path = as_path(xdsm_file_path)
+
     if not xdsm_file_path:
-        xdsm_file_path = pth.join(pth.dirname(configuration_file_path), "xdsm.html")
-    xdsm_file_path = pth.abspath(xdsm_file_path)
+        xdsm_file_path = configuration_file_path.parent / "xdsm.html"
+    xdsm_file_path = xdsm_file_path.absolute()
 
-    if not overwrite and pth.exists(xdsm_file_path):
+    if not overwrite and xdsm_file_path.exists():
         raise FastPathExistsError(
             "XDSM-diagram file %s not written because it already exists. "
             "Use overwrite=True to bypass." % xdsm_file_path,
@@ -656,7 +672,7 @@ def write_xdsm(
 
 
 def _run_problem(
-    configuration_file_path: str,
+    configuration_file_path: Union[str, PathLike],
     overwrite: bool = False,
     mode="run_model",
     auto_scaling: bool = False,
@@ -677,10 +693,10 @@ def _run_problem(
     conf._set_configuration_modifier(_PROBLEM_CONFIGURATOR)
     problem = conf.get_problem(read_inputs=True, auto_scaling=auto_scaling)
 
-    outputs_path = pth.normpath(problem.output_file_path)
-    if not overwrite and pth.exists(outputs_path):
+    outputs_path = as_path(problem.output_file_path)
+    if not overwrite and outputs_path.exists():
         raise FastPathExistsError(
-            f"Problem not run because output file {outputs_path} already exists. "
+            f"Problem not run because output file {outputs_path.resolve()} already exists. "
             "Use overwrite=True to bypass.",
             outputs_path,
         )
@@ -707,7 +723,9 @@ def _run_problem(
     return problem
 
 
-def evaluate_problem(configuration_file_path: str, overwrite: bool = False) -> FASTOADProblem:
+def evaluate_problem(
+    configuration_file_path: Union[str, PathLike], overwrite: bool = False
+) -> FASTOADProblem:
     """
     Runs model according to provided problem file
 
@@ -720,7 +738,9 @@ def evaluate_problem(configuration_file_path: str, overwrite: bool = False) -> F
 
 
 def optimize_problem(
-    configuration_file_path: str, overwrite: bool = False, auto_scaling: bool = False
+    configuration_file_path: Union[str, PathLike],
+    overwrite: bool = False,
+    auto_scaling: bool = False,
 ) -> FASTOADProblem:
     """
     Runs driver according to provided problem file
@@ -735,7 +755,7 @@ def optimize_problem(
     return _run_problem(configuration_file_path, overwrite, "run_driver", auto_scaling=auto_scaling)
 
 
-def optimization_viewer(configuration_file_path: str):
+def optimization_viewer(configuration_file_path: Union[str, PathLike]):
     """
     Displays optimization information and enables its editing
 
@@ -750,7 +770,9 @@ def optimization_viewer(configuration_file_path: str):
     return viewer.display()
 
 
-def variable_viewer(file_path: str, file_formatter: IVariableIOFormatter = None, editable=True):
+def variable_viewer(
+    file_path: Union[str, PathLike], file_formatter: IVariableIOFormatter = None, editable=True
+):
     """
     Displays a widget that enables to visualize variables information and edit their values.
 
diff --git a/src/fastoad/cmd/cli.py b/src/fastoad/cmd/cli.py
index 31373d67f..be80084e6 100644
--- a/src/fastoad/cmd/cli.py
+++ b/src/fastoad/cmd/cli.py
@@ -1,6 +1,6 @@
 """Command Line Interface."""
 #  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
-#  Copyright (C) 2022 ONERA & ISAE-SUPAERO
+#  Copyright (C) 2024 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
@@ -12,7 +12,7 @@
 #  You should have received a copy of the GNU General Public License
 #  along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-import os.path as pth
+from pathlib import Path
 
 import click
 import tabulate
@@ -304,7 +304,7 @@ def create_notebooks(path, from_package):
     IMPORTANT: Please note that all content of an existing FAST-OAD_notebooks/ will be overwritten.
     """
 
-    root_target_path = pth.abspath(pth.join(path, NOTEBOOK_FOLDER_NAME))
+    root_target_path = Path(path, NOTEBOOK_FOLDER_NAME).absolute()
     try:
         if manage_overwrite(
             api.generate_notebooks,
diff --git a/src/fastoad/gui/analysis_and_plots.py b/src/fastoad/gui/analysis_and_plots.py
index b516e62d3..e205e17ae 100644
--- a/src/fastoad/gui/analysis_and_plots.py
+++ b/src/fastoad/gui/analysis_and_plots.py
@@ -2,7 +2,7 @@
 Defines the analysis and plotting functions for postprocessing
 """
 #  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
-#  Copyright (C) 2022 ONERA & ISAE-SUPAERO
+#  Copyright (C) 2024 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
@@ -14,7 +14,8 @@
 #  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 Dict
+from os import PathLike
+from typing import Dict, Union
 
 import numpy as np
 import plotly.express as px
@@ -30,7 +31,7 @@
 
 # pylint: disable-msg=too-many-locals
 def wing_geometry_plot(
-    aircraft_file_path: str, name=None, fig=None, *, file_formatter=None
+    aircraft_file_path: Union[str, PathLike], name=None, fig=None, *, file_formatter=None
 ) -> go.FigureWidget:
     """
     Returns a figure plot of the top view of the wing.
@@ -102,7 +103,7 @@ def wing_geometry_plot(
 
 # pylint: disable-msg=too-many-locals
 def aircraft_geometry_plot(
-    aircraft_file_path: str, name=None, fig=None, *, file_formatter=None
+    aircraft_file_path: Union[str, PathLike], name=None, fig=None, *, file_formatter=None
 ) -> go.FigureWidget:
     """
     Returns a figure plot of the top view of the wing.
@@ -227,7 +228,7 @@ def aircraft_geometry_plot(
 
 
 def drag_polar_plot(
-    aircraft_file_path: str, name=None, fig=None, *, file_formatter=None
+    aircraft_file_path: Union[str, PathLike], name=None, fig=None, *, file_formatter=None
 ) -> go.FigureWidget:
     """
     Returns a figure plot of the aircraft drag polar.
@@ -267,7 +268,7 @@ def drag_polar_plot(
 
 
 def mass_breakdown_bar_plot(
-    aircraft_file_path: str,
+    aircraft_file_path: Union[str, PathLike],
     name=None,
     fig=None,
     *,
@@ -334,7 +335,7 @@ def mass_breakdown_bar_plot(
 
 
 def mass_breakdown_sun_plot(
-    aircraft_file_path: str,
+    aircraft_file_path: Union[str, PathLike],
     *,
     file_formatter=None,
     input_mass_name="data:weight:aircraft:MTOW",
@@ -450,7 +451,7 @@ def mass_breakdown_sun_plot(
 
 
 def payload_range_plot(
-    aircraft_file_path: str,
+    aircraft_file_path: Union[str, PathLike],
     name="Payload-Range",
     mission_name="operational",
     variable_of_interest: str = None,
@@ -598,8 +599,9 @@ def _data_weight_decomposition(variables: VariableList, owe=None):
     for variable in variables.names():
         name_split = variable.split(":")
         if isinstance(name_split, list) and len(name_split) == 4:
-            if name_split[0] + name_split[1] + name_split[3] == "dataweightmass" and not (
-                "aircraft" in name_split[2]
+            if (
+                name_split[0] + name_split[1] + name_split[3] == "dataweightmass"
+                and "aircraft" not in name_split[2]
             ):
                 category_values.append(
                     convert_units(variables[variable].value[0], variables[variable].units, "kg")
diff --git a/src/fastoad/gui/mission_viewer.py b/src/fastoad/gui/mission_viewer.py
index 8c00ed852..8aaed48fe 100644
--- a/src/fastoad/gui/mission_viewer.py
+++ b/src/fastoad/gui/mission_viewer.py
@@ -2,7 +2,7 @@
 Defines the analysis and plotting functions for postprocessing regarding the mission
 """
 #  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
-#  Copyright (C) 2021 ONERA & ISAE-SUPAERO
+#  Copyright (C) 2024 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
@@ -14,7 +14,7 @@
 #  You should have received a copy of the GNU General Public License
 #  along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-import os.path as pth
+from os import PathLike
 from typing import Union
 
 import ipywidgets as widgets
@@ -22,6 +22,8 @@
 import plotly.graph_objects as go
 from IPython.display import clear_output, display
 
+from fastoad._utils.files import as_path
+
 
 class MissionViewer:
     """
@@ -41,22 +43,24 @@ def __init__(self):
         # The y selector
         self._y_widget = None
 
-    def add_mission(self, mission_data: Union[str, pd.DataFrame], name=None):
+    def add_mission(self, mission_data: Union[str, PathLike, pd.DataFrame], name=None):
         """
         Adds the mission to the mission database (self.missions)
         :param mission_data: path of the mission file or Dataframe containing the mission data
         :param name: name to give to the mission
         """
-        if (
-            isinstance(mission_data, str)
-            and mission_data.endswith(".csv")
-            and pth.exists(mission_data)
-        ):
-            self.missions[name] = pd.read_csv(mission_data, index_col=0)
-        elif isinstance(mission_data, pd.DataFrame):
+        if isinstance(mission_data, pd.DataFrame):
             self.missions[name] = mission_data
         else:
-            raise TypeError("Unknown type for mission data, please use .csv of DataFrame")
+            mission_data = as_path(mission_data)
+            if (
+                mission_data is not None
+                and mission_data.suffix == ".csv"
+                and mission_data.is_file()
+            ):
+                self.missions[name] = pd.read_csv(mission_data, index_col=0)
+            else:
+                raise TypeError("Unknown type for mission data, please use .csv of DataFrame")
 
     def display(self):
         """
diff --git a/src/fastoad/gui/optimization_viewer.py b/src/fastoad/gui/optimization_viewer.py
index 095cd44f8..132a1e5ee 100644
--- a/src/fastoad/gui/optimization_viewer.py
+++ b/src/fastoad/gui/optimization_viewer.py
@@ -2,7 +2,7 @@
 Defines the variable viewer for postprocessing
 """
 #  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
-#  Copyright (C) 2021 ONERA & ISAE-SUPAERO
+#  Copyright (C) 2024 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
@@ -14,8 +14,8 @@
 #  You should have received a copy of the GNU General Public License
 #  along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-import os.path as pth
 from math import isnan
+from pathlib import Path
 from typing import Dict
 
 import ipysheet as sh
@@ -87,13 +87,13 @@ def load(self, problem_configuration: FASTOADProblemConfigurator):
 
         self.problem_configuration = problem_configuration
 
-        if pth.isfile(self.problem_configuration.input_file_path):
+        if Path(self.problem_configuration.input_file_path).is_file():
             input_variables = DataFile(self.problem_configuration.input_file_path)
         else:
             # TODO: generate the input file by default ?
             raise FastMissingFile("Please generate input file before using the optimization viewer")
 
-        if pth.isfile(self.problem_configuration.output_file_path):
+        if Path(self.problem_configuration.output_file_path).is_file():
             self._MISSING_OUTPUT_FILE = False
             output_variables = DataFile(self.problem_configuration.output_file_path)
         else:
diff --git a/src/fastoad/gui/variable_viewer.py b/src/fastoad/gui/variable_viewer.py
index 70ac3df34..f3e7a5b64 100644
--- a/src/fastoad/gui/variable_viewer.py
+++ b/src/fastoad/gui/variable_viewer.py
@@ -2,7 +2,7 @@
 Defines the variable viewer for postprocessing
 """
 #  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
-#  Copyright (C) 2021 ONERA & ISAE-SUPAERO
+#  Copyright (C) 2024 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
@@ -14,7 +14,8 @@
 #  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 Dict, List, Set
+from os import PathLike
+from typing import Dict, List, Set, Union
 
 import ipysheet as sh
 import ipywidgets as widgets
@@ -83,7 +84,7 @@ def __init__(self):
         # The complete user interface
         self._ui = None
 
-    def load(self, file_path: str, file_formatter: IVariableIOFormatter = None):
+    def load(self, file_path: Union[str, PathLike], file_formatter: IVariableIOFormatter = None):
         """
         Loads the file and stores its data.
 
@@ -95,7 +96,9 @@ def load(self, file_path: str, file_formatter: IVariableIOFormatter = None):
         self.file = file_path
         self.load_variables(VariableIO(file_path, file_formatter).read())
 
-    def save(self, file_path: str = None, file_formatter: IVariableIOFormatter = None):
+    def save(
+        self, file_path: Union[str, PathLike] = None, file_formatter: IVariableIOFormatter = None
+    ):
         """
         Save the dataframe to the file.
 
diff --git a/src/fastoad/io/configuration/configuration.py b/src/fastoad/io/configuration/configuration.py
index ff372442a..8ab4d279c 100644
--- a/src/fastoad/io/configuration/configuration.py
+++ b/src/fastoad/io/configuration/configuration.py
@@ -16,17 +16,18 @@
 
 import json
 import logging
-import os.path as pth
 from abc import ABC, abstractmethod
 from importlib.resources import open_text
-from typing import Dict
+from os import PathLike
+from pathlib import Path
+from typing import Dict, List, Optional, Union
 
 import openmdao.api as om
 import tomlkit
 from jsonschema import validate
 from ruamel.yaml import YAML
 
-from fastoad._utils.files import make_parent_dir
+from fastoad._utils.files import as_path, make_parent_dir
 from fastoad.io import IVariableIOFormatter
 from fastoad.module_management.service_registry import RegisterOpenMDAOSystem, RegisterSubmodel
 from fastoad.openmdao.problem import FASTOADProblem
@@ -63,41 +64,38 @@ class for configuring an OpenMDAO problem from a configuration file
     :param conf_file_path: if provided, configuration will be read directly from it
     """
 
-    def __init__(self, conf_file_path=None):
-        self._conf_file = None
-
-        self._serializer = _YAMLSerializer()
+    def __init__(self, conf_file_path: Union[str, PathLike] = None):
+        self._serializer: _IDictSerializer = _YAMLSerializer()
 
         # self._configuration_modifier offers a way to modify problems after
         # they have been generated from configuration (private usage for now)
-        self._configuration_modifier: "_IConfigurationModifier" = None
+        self._configuration_modifier: Optional["_IConfigurationModifier"] = None
 
+        self._conf_file_path: Optional[Path] = None
         if conf_file_path:
             self.load(conf_file_path)
 
     @property
-    def input_file_path(self):
+    def input_file_path(self) -> str:
         """path of file with input variables of the problem"""
-        path = str(self._serializer.data[KEY_INPUT_FILE])
-        if not pth.isabs(path):
-            path = pth.normpath(pth.join(pth.dirname(self._conf_file), path))
-        return path
+        return self._make_absolute(self._data[KEY_INPUT_FILE]).as_posix()
 
     @input_file_path.setter
-    def input_file_path(self, file_path: str):
-        self._serializer.data[KEY_INPUT_FILE] = file_path
+    def input_file_path(self, file_path: Union[str, PathLike]):
+        self._data[KEY_INPUT_FILE] = str(file_path)
 
     @property
-    def output_file_path(self):
+    def output_file_path(self) -> str:
         """path of file where output variables will be written"""
-        path = str(self._serializer.data[KEY_OUTPUT_FILE])
-        if not pth.isabs(path):
-            path = pth.normpath(pth.join(pth.dirname(self._conf_file), path))
-        return path
+        return self._make_absolute(self._data[KEY_OUTPUT_FILE]).as_posix()
 
     @output_file_path.setter
-    def output_file_path(self, file_path: str):
-        self._serializer.data[KEY_OUTPUT_FILE] = file_path
+    def output_file_path(self, file_path: Union[str, PathLike]):
+        self._data[KEY_OUTPUT_FILE] = str(file_path)
+
+    @property
+    def _data(self) -> dict:
+        return self._serializer.data
 
     def get_problem(self, read_inputs: bool = False, auto_scaling: bool = False) -> FASTOADProblem:
         """
@@ -109,7 +107,7 @@ def get_problem(self, read_inputs: bool = False, auto_scaling: bool = False) ->
                              variables and constraints
         :return: the problem instance
         """
-        if self._serializer.data is None:
+        if self._data is None:
             raise RuntimeError("read configuration file first")
 
         problem = FASTOADProblem()
@@ -124,13 +122,14 @@ def get_problem(self, read_inputs: bool = False, auto_scaling: bool = False) ->
         if read_inputs:
             problem.read_inputs()
 
-        driver = self._serializer.data.get(KEY_DRIVER, "")
+        driver = self._data.get(KEY_DRIVER, "")
         if driver:
             problem.driver = _om_eval(driver)
 
-        model_options = self._serializer.data.get(KEY_MODEL_OPTIONS)
-        if model_options:
-            problem.model_options = model_options
+        model_options = self._data.get(KEY_MODEL_OPTIONS, {})
+        for options in model_options.values():
+            self._make_option_path_values_absolute(options)
+        problem.model_options = model_options
 
         if self.get_optimization_definition():
             self._add_constraints(problem.model, auto_scaling)
@@ -141,53 +140,48 @@ def get_problem(self, read_inputs: bool = False, auto_scaling: bool = False) ->
 
         return problem
 
-    def load(self, conf_file):
+    def load(self, conf_file: Union[str, PathLike]):
         """
         Reads the problem definition
 
-        :param conf_file: Path to the file to open or a file descriptor
+        :param conf_file: Path to the file to open
         """
 
-        self._conf_file = pth.abspath(conf_file)  # for resolving relative paths
-        conf_dirname = pth.dirname(self._conf_file)
+        self._conf_file_path = as_path(conf_file).resolve()  # for resolving relative paths
 
-        if pth.splitext(self._conf_file)[-1] == ".toml":
+        if self._conf_file_path.suffix == ".toml":
             self._serializer = _TOMLSerializer()
             _LOGGER.warning(
                 "TOML-formatted configuration files are deprecated. Please use YAML format."
             )
         else:
             self._serializer = _YAMLSerializer()
-        self._serializer.read(self._conf_file)
+        self._serializer.read(self._conf_file_path)
 
         # Syntax validation
         with open_text(resources, JSON_SCHEMA_NAME) as json_file:
             json_schema = json.loads(json_file.read())
-        validate(self._serializer.data, json_schema)
+        validate(self._data, json_schema)
+
         # Issue a simple warning for unknown keys at root level
-        for key in self._serializer.data:
+        for key in self._data:
             if key not in json_schema["properties"].keys():
                 _LOGGER.warning('Configuration file: "%s" is not a FAST-OAD key.', key)
 
         # Looking for modules to register
-        module_folder_paths = self._serializer.data.get(KEY_FOLDERS)
-        if isinstance(module_folder_paths, str):
-            module_folder_paths = [module_folder_paths]
-        if module_folder_paths:
-            for folder_path in module_folder_paths:
-                folder_path = pth.join(conf_dirname, str(folder_path))
-                if not pth.exists(folder_path):
-                    _LOGGER.warning("SKIPPED %s: it does not exist.", folder_path)
-                else:
-                    RegisterOpenMDAOSystem.explore_folder(folder_path)
+        for module_folder_path in self._get_module_folder_paths():
+            if not module_folder_path.is_dir():
+                _LOGGER.warning("SKIPPED %s: it does not exist.", module_folder_path)
+            else:
+                RegisterOpenMDAOSystem.explore_folder(module_folder_path.as_posix())
 
         # Settings submodels
         RegisterSubmodel.cancel_submodel_deactivations()
-        submodel_specs = self._serializer.data.get(KEY_SUBMODELS, {})
+        submodel_specs = self._data.get(KEY_SUBMODELS, {})
         for submodel_requirement, submodel_id in submodel_specs.items():
             RegisterSubmodel.active_models[submodel_requirement] = submodel_id
 
-    def save(self, filename: str = None):
+    def save(self, filename: Union[str, PathLike] = None):
         """
         Saves the current configuration
         If no filename is provided, the initially read file is used.
@@ -195,13 +189,15 @@ def save(self, filename: str = None):
         :param filename: file where to save configuration
         """
         if not filename:
-            filename = self._conf_file
+            filename = self._conf_file_path
 
         make_parent_dir(filename)
         self._serializer.write(filename)
 
     def write_needed_inputs(
-        self, source_file_path: str = None, source_formatter: IVariableIOFormatter = None
+        self,
+        source_file_path: Union[str, PathLike] = None,
+        source_formatter: IVariableIOFormatter = None,
     ):
         """
         Writes the input file of the problem with unconnected inputs of the
@@ -230,7 +226,7 @@ def get_optimization_definition(self) -> Dict:
         """
 
         optimization_definition = {}
-        conf_dict = self._serializer.data.get(KEY_OPTIMIZATION)
+        conf_dict = self._data.get(KEY_OPTIMIZATION)
         if conf_dict:
             for sec, elements in conf_dict.items():
                 optimization_definition[sec] = {elem["name"]: elem for elem in elements}
@@ -251,7 +247,27 @@ def set_optimization_definition(self, optimization_definition: Dict):
         for key, value in optimization_definition.items():
             subpart[key] = [value for _, value in optimization_definition[key].items()]
         subpart = {"optimization": subpart}
-        self._serializer.data.update(subpart)
+        self._data.update(subpart)
+
+    def _make_absolute(self, path: Union[str, PathLike]) -> Path:
+        """
+        Make the provided path absolute using configuration file folder as base.
+
+        Does nothing if the path is already absolute.
+        """
+        path = as_path(path)
+        if not path.is_absolute():
+            path = (self._conf_file_path.parent / path).resolve()
+        return path
+
+    def _get_module_folder_paths(self) -> List[Path]:
+        module_folder_paths = self._data.get(KEY_FOLDERS)
+        # Key may be present, but with None value
+        if not module_folder_paths:
+            return []
+        if isinstance(module_folder_paths, str):
+            module_folder_paths = [module_folder_paths]
+        return [self._make_absolute(folder_path) for folder_path in module_folder_paths]
 
     def _build_model(self, problem: FASTOADProblem):
         """
@@ -261,9 +277,9 @@ def _build_model(self, problem: FASTOADProblem):
         """
 
         model = problem.model
-        model.active_submodels = self._serializer.data.get(KEY_SUBMODELS, {})
+        model.active_submodels = self._data.get(KEY_SUBMODELS, {})
 
-        model_definition = self._serializer.data.get(KEY_MODEL)
+        model_definition = self._data.get(KEY_MODEL)
 
         try:
             if KEY_COMPONENT_ID in model_definition:
@@ -296,22 +312,7 @@ def _parse_problem_table(self, group: om.Group, table: dict):
                     options = value.copy()
                     identifier = options.pop(KEY_COMPONENT_ID)
 
-                    # Process option values that are relative paths
-                    conf_dirname = pth.dirname(self._conf_file)
-                    for name, option_value in options.items():
-                        option_is_path = (
-                            name.endswith("file")
-                            or name.endswith("path")
-                            or name.endswith("dir")
-                            or name.endswith("directory")
-                            or name.endswith("folder")
-                        )
-                        if (
-                            isinstance(option_value, str)
-                            and option_is_path
-                            and not pth.isabs(option_value)
-                        ):
-                            options[name] = pth.join(conf_dirname, option_value)
+                    self._make_option_path_values_absolute(options)
 
                     sub_component = RegisterOpenMDAOSystem.get_system(identifier, options=options)
                     group.add_subsystem(key, sub_component, promotes=["*"])
@@ -345,6 +346,17 @@ def _parse_problem_table(self, group: om.Group, table: dict):
                 except Exception as err:
                     raise FASTConfigurationBadOpenMDAOInstructionError(err, key, value)
 
+    def _make_option_path_values_absolute(self, options):
+        # Process option values that are relative paths
+        conf_folder_path = self._conf_file_path.parent
+        for name, option_value in options.items():
+            if (
+                isinstance(option_value, str)
+                and name.endswith(("file", "path", "dir", "directory", "folder"))
+                and not Path(option_value).is_absolute()
+            ):
+                options[name] = (conf_folder_path / option_value).as_posix()
+
     def _add_constraints(self, model, auto_scaling):
         """
         Adds constraints to provided model as instructed in current configuration
@@ -433,14 +445,14 @@ def data(self) -> dict:
         """
 
     @abstractmethod
-    def read(self, file_path: str):
+    def read(self, file_path: Union[str, PathLike]):
         """
         Reads data from provided file.
         :param file_path:
         """
 
     @abstractmethod
-    def write(self, file_path: str):
+    def write(self, file_path: Union[str, PathLike]):
         """
         Writes data to provided file.
         :param file_path:
@@ -457,11 +469,11 @@ def __init__(self):
     def data(self):
         return self._data
 
-    def read(self, file_path: str):
+    def read(self, file_path: Union[str, PathLike]):
         with open(file_path, "r") as toml_file:
-            self._data = tomlkit.loads(toml_file.read())
+            self._data = tomlkit.loads(toml_file.read()).value
 
-    def write(self, file_path: str):
+    def write(self, file_path: Union[str, PathLike]):
         with open(file_path, "w") as file:
             file.write(tomlkit.dumps(self._data))
 
@@ -476,12 +488,12 @@ def __init__(self):
     def data(self):
         return self._data
 
-    def read(self, file_path: str):
+    def read(self, file_path: Union[str, PathLike]):
         yaml = YAML(typ="safe")
         with open(file_path) as yaml_file:
             self._data = yaml.load(yaml_file)
 
-    def write(self, file_path: str):
+    def write(self, file_path: Union[str, PathLike]):
         yaml = YAML()
         yaml.default_flow_style = False
         with open(file_path, "w") as file:
diff --git a/src/fastoad/models/performances/mission/mission.py b/src/fastoad/models/performances/mission/mission.py
index 0d914271c..6527d8b9c 100644
--- a/src/fastoad/models/performances/mission/mission.py
+++ b/src/fastoad/models/performances/mission/mission.py
@@ -1,7 +1,7 @@
 """Definition of aircraft mission."""
 
 #  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
-#  Copyright (C) 2023 ONERA & ISAE-SUPAERO
+#  Copyright (C) 2024 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
@@ -13,7 +13,6 @@
 #  You should have received a copy of the GNU General Public License
 #  along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-import logging
 from copy import deepcopy
 from dataclasses import dataclass, field
 from typing import Optional
@@ -26,8 +25,6 @@
 from .routes import RangedRoute
 from .segments.registered.cruise import CruiseSegment
 
-_LOGGER = logging.getLogger(__name__)  # Logger for this module
-
 
 @dataclass
 class Mission(FlightSequence):
diff --git a/src/fastoad/models/performances/mission/mission_definition/mission_builder/mission_builder.py b/src/fastoad/models/performances/mission/mission_definition/mission_builder/mission_builder.py
index 2e1349a9e..1986a3900 100644
--- a/src/fastoad/models/performances/mission/mission_definition/mission_builder/mission_builder.py
+++ b/src/fastoad/models/performances/mission/mission_definition/mission_builder/mission_builder.py
@@ -1,6 +1,6 @@
 """Mission generator."""
 #  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
-#  Copyright (C) 2023 ONERA & ISAE-SUPAERO
+#  Copyright (C) 2024 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
@@ -15,6 +15,7 @@
 from collections import ChainMap
 from copy import deepcopy
 from dataclasses import fields
+from os import PathLike
 from typing import Dict, List, Mapping, Optional, Union
 
 import pandas as pd
@@ -77,7 +78,7 @@ class MissionBuilder:
 
     def __init__(
         self,
-        mission_definition: Union[str, MissionDefinition],
+        mission_definition: Union[str, PathLike, MissionDefinition],
         *,
         propulsion: IPropulsion = None,
         reference_area: float = None,
@@ -114,11 +115,11 @@ def definition(self) -> MissionDefinition:
         return self._definition
 
     @definition.setter
-    def definition(self, mission_definition: Union[str, MissionDefinition]):
-        if isinstance(mission_definition, str):
-            self._definition = MissionDefinition(mission_definition)
-        else:
+    def definition(self, mission_definition: Union[str, PathLike, MissionDefinition]):
+        if isinstance(mission_definition, MissionDefinition):
             self._definition = mission_definition
+        else:
+            self._definition = MissionDefinition(mission_definition)
 
         self._update_structure_builders()
 
diff --git a/src/fastoad/models/performances/mission/openmdao/base.py b/src/fastoad/models/performances/mission/openmdao/base.py
index 31ca3d979..efdef5134 100644
--- a/src/fastoad/models/performances/mission/openmdao/base.py
+++ b/src/fastoad/models/performances/mission/openmdao/base.py
@@ -17,6 +17,7 @@
 from abc import ABCMeta
 from enum import Enum
 from importlib.resources import path
+from os import PathLike
 from typing import Optional, Union
 
 from openmdao.core.system import System
@@ -93,7 +94,7 @@ def initialize(self):
         self.options.declare(
             "mission_file_path",
             default="::sizing_mission",
-            types=(str, MissionDefinition, MissionWrapper),
+            types=(str, PathLike, MissionDefinition, MissionWrapper),
             allow_none=True,
             check_valid=self._update_mission_wrapper,
             desc="The path to file that defines the mission.\n"
@@ -149,7 +150,7 @@ def first_route_name(self) -> Optional[str]:
 
     @staticmethod
     def get_mission_definition(
-        mission_file_path: Optional[Union[str, MissionDefinition]]
+        mission_file_path: Optional[Union[str, PathLike, MissionDefinition]]
     ) -> MissionDefinition:
         """
 
@@ -159,10 +160,11 @@ def get_mission_definition(
         """
         if isinstance(mission_file_path, MissionDefinition):
             mission_definition = mission_file_path
-        elif "::" in mission_file_path:
+        elif "::" in str(mission_file_path):
             # The configuration file parser will have added the working directory before
             # the file name. But as the user-provided string begins with "::", we just
             # have to ignore all before "::".
+            mission_file_path = str(mission_file_path)
             i = mission_file_path.index("::")
             file_name = mission_file_path[i + 2 :] + ".yml"
             with path(resources, file_name) as mission_input_file:
diff --git a/src/fastoad/models/performances/mission/openmdao/link_mtow.py b/src/fastoad/models/performances/mission/openmdao/link_mtow.py
index 32db0aa60..33c9c363a 100644
--- a/src/fastoad/models/performances/mission/openmdao/link_mtow.py
+++ b/src/fastoad/models/performances/mission/openmdao/link_mtow.py
@@ -2,7 +2,7 @@
 OpenMDAO component for computation of sizing mission.
 """
 #  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
-#  Copyright (C) 2022 ONERA & ISAE-SUPAERO
+#  Copyright (C) 2024 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
@@ -14,15 +14,11 @@
 #  You should have received a copy of the GNU General Public License
 #  along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-import logging
-
 import openmdao.api as om
 
 from fastoad.module_management.constants import ModelDomain
 from fastoad.module_management.service_registry import RegisterOpenMDAOSystem
 
-_LOGGER = logging.getLogger(__name__)  # Logger for this module
-
 
 @RegisterOpenMDAOSystem("fastoad.mass_performances.compute_MTOW", domain=ModelDomain.OTHER)
 class ComputeMTOW(om.AddSubtractComp):
diff --git a/src/fastoad/models/performances/mission/openmdao/mission.py b/src/fastoad/models/performances/mission/openmdao/mission.py
index 0d2793387..c466d28a8 100644
--- a/src/fastoad/models/performances/mission/openmdao/mission.py
+++ b/src/fastoad/models/performances/mission/openmdao/mission.py
@@ -14,8 +14,8 @@
 #  You should have received a copy of the GNU General Public License
 #  along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-import logging
 from enum import EnumMeta
+from os import PathLike
 
 import numpy as np
 import openmdao.api as om
@@ -26,8 +26,6 @@
 from .base import BaseMissionComp, NeedsOWE
 from .mission_run import AdvancedMissionComp
 
-_LOGGER = logging.getLogger(__name__)  # Logger for this module
-
 
 @RegisterOpenMDAOSystem("fastoad.performances.mission", domain=ModelDomain.PERFORMANCE)
 class OMMission(om.Group, BaseMissionComp, NeedsOWE):
@@ -40,7 +38,7 @@ def initialize(self):
         self.options.declare(
             "out_file",
             default="",
-            types=str,
+            types=(str, PathLike),
             desc="If provided, a csv file will be written at provided path with all computed "
             "flight points.",
         )
diff --git a/src/fastoad/models/performances/mission/openmdao/mission_run.py b/src/fastoad/models/performances/mission/openmdao/mission_run.py
index 483ff91d9..b11582673 100644
--- a/src/fastoad/models/performances/mission/openmdao/mission_run.py
+++ b/src/fastoad/models/performances/mission/openmdao/mission_run.py
@@ -1,5 +1,5 @@
 #  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
-#  Copyright (C) 2023 ONERA & ISAE-SUPAERO
+#  Copyright (C) 2024 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
@@ -12,12 +12,13 @@
 #  along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
 import logging
-from os import makedirs, path as pth
+from os import PathLike
 from typing import Optional
 
 import numpy as np
 from openmdao import api as om
 
+from fastoad._utils.files import make_parent_dir
 from fastoad.model_base import FlightPoint
 from fastoad.model_base.propulsion import IOMPropulsionWrapper
 from fastoad.module_management.service_registry import RegisterPropulsion
@@ -44,7 +45,7 @@ def initialize(self):
         self.options.declare(
             "out_file",
             default="",
-            types=str,
+            types=(str, PathLike),
             desc="if provided, a csv file will be written at provided path with "
             "all computed flight points.",
         )
@@ -114,7 +115,7 @@ def as_scalar(value):
         }
         flight_points.rename(columns=rename_dict, inplace=True)
         if self.options["out_file"]:
-            makedirs(pth.dirname(self.options["out_file"]), exist_ok=True)
+            make_parent_dir(self.options["out_file"])
             flight_points.to_csv(self.options["out_file"])
 
         return flight_points
diff --git a/src/fastoad/models/performances/mission/openmdao/mission_wrapper.py b/src/fastoad/models/performances/mission/openmdao/mission_wrapper.py
index 6b1c48d96..01e1b1451 100644
--- a/src/fastoad/models/performances/mission/openmdao/mission_wrapper.py
+++ b/src/fastoad/models/performances/mission/openmdao/mission_wrapper.py
@@ -2,7 +2,7 @@
 Mission wrapper.
 """
 #  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
-#  Copyright (C) 2023 ONERA & ISAE-SUPAERO
+#  Copyright (C) 2024 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
@@ -14,6 +14,7 @@
 #  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 os import PathLike
 from typing import Dict, Optional, Tuple, Union
 
 import numpy as np
@@ -36,6 +37,20 @@
 )
 
 
+#  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
+#  Copyright (C) 2023 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/>.
+
+
 class MissionWrapper(MissionBuilder):
     """
     Wrapper around
@@ -48,7 +63,7 @@ class MissionWrapper(MissionBuilder):
 
     def __init__(
         self,
-        mission_definition: Union[str, MissionDefinition],
+        mission_definition: Union[str, PathLike, MissionDefinition],
         *,
         propulsion: IPropulsion = None,
         reference_area: float = None,
diff --git a/src/fastoad/models/performances/mission/segments/base.py b/src/fastoad/models/performances/mission/segments/base.py
index 6dbc89503..a4948eea7 100644
--- a/src/fastoad/models/performances/mission/segments/base.py
+++ b/src/fastoad/models/performances/mission/segments/base.py
@@ -12,7 +12,6 @@
 #  You should have received a copy of the GNU General Public License
 #  along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-import logging
 from abc import ABC, abstractmethod
 from copy import deepcopy
 from dataclasses import dataclass, field
@@ -28,8 +27,6 @@
 from ..base import IFlightPart, RegisterElement
 from ..exceptions import FastFlightSegmentIncompleteFlightPoint
 
-_LOGGER = logging.getLogger(__name__)  # Logger for this module
-
 
 class RegisterSegment(RegisterElement, base_class=IFlightPart):
     """
diff --git a/src/fastoad/models/performances/mission/segments/registered/altitude_change.py b/src/fastoad/models/performances/mission/segments/registered/altitude_change.py
index 1e068d81d..412767deb 100644
--- a/src/fastoad/models/performances/mission/segments/registered/altitude_change.py
+++ b/src/fastoad/models/performances/mission/segments/registered/altitude_change.py
@@ -1,6 +1,6 @@
 """Classes for climb/descent segments."""
 #  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
-#  Copyright (C) 2023 ONERA & ISAE-SUPAERO
+#  Copyright (C) 2024 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
@@ -12,7 +12,6 @@
 #  You should have received a copy of the GNU General Public License
 #  along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-import logging
 from copy import copy
 from dataclasses import dataclass
 from typing import List, Tuple
@@ -28,8 +27,6 @@
 from fastoad.models.performances.mission.segments.time_step_base import AbstractManualThrustSegment
 from fastoad.models.performances.mission.util import get_closest_flight_level
 
-_LOGGER = logging.getLogger(__name__)  # Logger for this module
-
 
 @RegisterSegment("altitude_change")
 @dataclass
diff --git a/src/fastoad/models/performances/mission/segments/registered/ground_speed_change.py b/src/fastoad/models/performances/mission/segments/registered/ground_speed_change.py
index 452fbef7c..feaf454c2 100644
--- a/src/fastoad/models/performances/mission/segments/registered/ground_speed_change.py
+++ b/src/fastoad/models/performances/mission/segments/registered/ground_speed_change.py
@@ -1,6 +1,6 @@
 """Classes for acceleration/deceleration segments."""
 #  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
-#  Copyright (C) 2023 ONERA & ISAE-SUPAERO
+#  Copyright (C) 2024 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
@@ -12,7 +12,6 @@
 #  You should have received a copy of the GNU General Public License
 #  along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-import logging
 from dataclasses import dataclass
 from typing import List
 
@@ -21,8 +20,6 @@
 from fastoad.models.performances.mission.segments.base import RegisterSegment
 from fastoad.models.performances.mission.segments.time_step_base import AbstractGroundSegment
 
-_LOGGER = logging.getLogger(__name__)  # Logger for this module
-
 
 @RegisterSegment("ground_speed_change")
 @dataclass
diff --git a/src/fastoad/models/performances/mission/segments/registered/speed_change.py b/src/fastoad/models/performances/mission/segments/registered/speed_change.py
index b3a7b5f45..a02b2c201 100644
--- a/src/fastoad/models/performances/mission/segments/registered/speed_change.py
+++ b/src/fastoad/models/performances/mission/segments/registered/speed_change.py
@@ -1,6 +1,6 @@
 """Classes for acceleration/deceleration segments."""
 #  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
-#  Copyright (C) 2023 ONERA & ISAE-SUPAERO
+#  Copyright (C) 2024 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
@@ -12,7 +12,6 @@
 #  You should have received a copy of the GNU General Public License
 #  along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-import logging
 from dataclasses import dataclass
 from typing import List, Tuple
 
@@ -23,8 +22,6 @@
 )
 from fastoad.models.performances.mission.segments.time_step_base import AbstractManualThrustSegment
 
-_LOGGER = logging.getLogger(__name__)  # Logger for this module
-
 
 @RegisterSegment("speed_change")
 @dataclass
diff --git a/src/fastoad/models/performances/mission/segments/registered/takeoff/end_of_takeoff.py b/src/fastoad/models/performances/mission/segments/registered/takeoff/end_of_takeoff.py
index f99d75043..e088b5269 100644
--- a/src/fastoad/models/performances/mission/segments/registered/takeoff/end_of_takeoff.py
+++ b/src/fastoad/models/performances/mission/segments/registered/takeoff/end_of_takeoff.py
@@ -1,6 +1,6 @@
 """Classes for climb/descent segments."""
 #  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
-#  Copyright (C) 2023 ONERA & ISAE-SUPAERO
+#  Copyright (C) 2024 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
@@ -12,7 +12,6 @@
 #  You should have received a copy of the GNU General Public License
 #  along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-import logging
 from dataclasses import dataclass
 from typing import List
 
@@ -24,7 +23,6 @@
 from fastoad.models.performances.mission.segments.base import RegisterSegment
 from fastoad.models.performances.mission.segments.time_step_base import AbstractTakeOffSegment
 
-_LOGGER = logging.getLogger(__name__)  # Logger for this module
 
 # FIXME: This class is a bit awkward, because get_gamma_and_acceleration() knows
 #       only the current flight point, which prevents from using the slope derivative.
diff --git a/src/fastoad/module_management/_bundle_loader.py b/src/fastoad/module_management/_bundle_loader.py
index 385eb622a..3b67a813d 100644
--- a/src/fastoad/module_management/_bundle_loader.py
+++ b/src/fastoad/module_management/_bundle_loader.py
@@ -2,7 +2,7 @@
 Basis for registering and retrieving services
 """
 #  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
-#  Copyright (C) 2022 ONERA & ISAE-SUPAERO
+#  Copyright (C) 2024 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
@@ -17,6 +17,7 @@
 import gc
 import logging
 import re
+from os import PathLike
 from typing import Any, Dict, List, Optional, Set, Tuple, Type, TypeVar, Union
 
 import pelix
@@ -30,6 +31,7 @@
     FastBundleLoaderDuplicateFactoryError,
     FastBundleLoaderUnknownFactoryNameError,
 )
+from .._utils.files import as_path
 from .._utils.resource_management.contents import PackageReader
 
 _LOGGER = logging.getLogger(__name__)
@@ -75,7 +77,7 @@ def context(self) -> BundleContext:
         return self.framework.get_bundle_context()
 
     def explore_folder(
-        self, folder_path: str, is_package: bool = False
+        self, folder_path: Union[str, PathLike], is_package: bool = False
     ) -> Tuple[Set[Bundle], Set[str]]:
         """
         Installs bundles found in *folder_path*.
@@ -93,7 +95,7 @@ def explore_folder(
         if is_package:
             bundles, failed = self._install_python_package(folder_path)
         else:
-            bundles, failed = self.framework.install_package(folder_path, True)
+            bundles, failed = self.framework.install_package(as_path(folder_path).as_posix(), True)
 
         for bundle in bundles:
             _LOGGER.info(
diff --git a/src/fastoad/module_management/_plugins.py b/src/fastoad/module_management/_plugins.py
index 920569d3f..3e42251bc 100644
--- a/src/fastoad/module_management/_plugins.py
+++ b/src/fastoad/module_management/_plugins.py
@@ -2,7 +2,7 @@
 Plugin system for declaration of FAST-OAD models.
 """
 #  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
-#  Copyright (C) 2023 ONERA & ISAE-SUPAERO
+#  Copyright (C) 2024 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
@@ -20,11 +20,11 @@
 from __future__ import annotations
 
 import logging
-import os.path as pth
 import sys
 import warnings
 from dataclasses import InitVar, dataclass, field
 from enum import Enum
+from pathlib import Path
 from typing import Callable, Dict, List, Optional
 
 import numpy as np
@@ -135,7 +135,7 @@ def get_configuration_file_list(self) -> List[ResourceInfo]:
                     package_name=self.subpackages[SubPackageNames.CONFIGURATIONS],
                 )
                 for file in PackageReader(self.subpackages[SubPackageNames.CONFIGURATIONS]).contents
-                if pth.splitext(file)[1] in [".yml", ".yaml"]
+                if Path(file).suffix in [".yml", ".yaml"]
             ]
 
         return []
@@ -155,7 +155,7 @@ def get_source_data_file_list(self) -> List[ResourceInfo]:
                 for file in PackageReader(
                     self.subpackages[SubPackageNames.SOURCE_DATA_FILES]
                 ).contents
-                if pth.splitext(file)[1] in [".xml"]
+                if Path(file).suffix in [".xml"]
             ]
 
         return []
diff --git a/src/fastoad/module_management/service_registry.py b/src/fastoad/module_management/service_registry.py
index 53005420b..76305e248 100644
--- a/src/fastoad/module_management/service_registry.py
+++ b/src/fastoad/module_management/service_registry.py
@@ -1,6 +1,6 @@
 """Module for registering services."""
 #  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
-#  Copyright (C) 2022 ONERA & ISAE-SUPAERO
+#  Copyright (C) 2024 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
@@ -13,7 +13,7 @@
 #  along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
 
-import logging
+from os import PathLike
 from types import MethodType
 from typing import Any, Dict, List, Optional, Type, TypeVar, Union
 
@@ -39,7 +39,6 @@
 from ..model_base.propulsion import IOMPropulsionWrapper
 from ..openmdao.variables import Variable
 
-_LOGGER = logging.getLogger(__name__)  # Logger for this module
 T = TypeVar("T")
 
 
@@ -215,7 +214,7 @@ def __call__(self, service_class: Type[T]) -> Type[T]:
         return super().__call__(service_class)
 
     @classmethod
-    def explore_folder(cls, folder_path: str):
+    def explore_folder(cls, folder_path: Union[str, PathLike]):
         """
         Explores provided folder and looks for service providers to register.
 
diff --git a/src/fastoad/openmdao/variables/variable.py b/src/fastoad/openmdao/variables/variable.py
index 9264891c3..469729967 100644
--- a/src/fastoad/openmdao/variables/variable.py
+++ b/src/fastoad/openmdao/variables/variable.py
@@ -2,7 +2,7 @@
 Class for managing an OpenMDAO variable.
 """
 #  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
-#  Copyright (C) 2022 ONERA & ISAE-SUPAERO
+#  Copyright (C) 2024 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
@@ -15,13 +15,14 @@
 #  along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
 import logging
-import os.path as pth
 from importlib.resources import open_text
+from os import PathLike
 from typing import Dict, Hashable, Iterable, Mapping, Tuple, Union
 
 import numpy as np
 import openmdao.api as om
 
+from fastoad._utils.files import as_path
 from fastoad._utils.resource_management.contents import PackageReader
 
 _LOGGER = logging.getLogger(__name__)  # Logger for this module
@@ -136,7 +137,9 @@ def __init__(self, name, **kwargs):
             self.description = self._variable_descriptions[self.name]
 
     @classmethod
-    def read_variable_descriptions(cls, file_parent: str, update_existing: bool = True):
+    def read_variable_descriptions(
+        cls, file_parent: Union[str, PathLike], update_existing: bool = True
+    ):
         """
         Reads variable descriptions in indicated folder or package, if it contains some.
 
@@ -151,6 +154,8 @@ def read_variable_descriptions(cls, file_parent: str, update_existing: bool = Tr
         :param update_existing: if True, previous descriptions will be updated.
                                 if False, previous descriptions will be erased.
         """
+        file_parent = as_path(file_parent)
+
         if not update_existing:
             cls._variable_descriptions = {}
             cls._loaded_descriptions = set()
@@ -159,14 +164,14 @@ def read_variable_descriptions(cls, file_parent: str, update_existing: bool = Tr
         description_file = None
 
         if file_parent:
-            if pth.isdir(file_parent):
-                file_path = pth.join(file_parent, DESCRIPTION_FILENAME)
-                if pth.isfile(file_path):
+            if file_parent.is_dir():
+                file_path = file_parent / DESCRIPTION_FILENAME
+                if file_path.is_file():
                     description_file = open(file_path)
             else:
                 # Then it is a module name
-                if DESCRIPTION_FILENAME in PackageReader(file_parent).contents:
-                    description_file = open_text(file_parent, DESCRIPTION_FILENAME)
+                if DESCRIPTION_FILENAME in PackageReader(str(file_parent)).contents:
+                    description_file = open_text(str(file_parent), DESCRIPTION_FILENAME)
 
         if description_file is not None:
             try:
diff --git a/src/fastoad/openmdao/whatsopt.py b/src/fastoad/openmdao/whatsopt.py
index c38618352..1d988150c 100644
--- a/src/fastoad/openmdao/whatsopt.py
+++ b/src/fastoad/openmdao/whatsopt.py
@@ -1,6 +1,6 @@
 """WhatsOpt-related operations."""
 #  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
-#  Copyright (C) 2021 ONERA & ISAE-SUPAERO
+#  Copyright (C) 2024 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
@@ -12,20 +12,19 @@
 #  You should have received a copy of the GNU General Public License
 #  along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-import logging
+from os import PathLike
+from typing import Union
 
 import openmdao.api as om
 import whatsopt.whatsopt_client as wop
 
-from fastoad._utils.files import make_parent_dir
 from fastoad import __version__ as fastoad_version
-
-_LOGGER = logging.getLogger(__name__)  # Logger for this module
+from fastoad._utils.files import make_parent_dir
 
 
 def write_xdsm(
     problem: om.Problem,
-    xdsm_file_path: str = None,
+    xdsm_file_path: Union[str, PathLike] = None,
     depth: int = 2,
     wop_server_url: str = None,
     dry_run: bool = False,


Test patch:
diff --git a/.PyCharmRunConfs/pytest units no-cov.run.xml b/.PyCharmRunConfs/pytest units no-cov.run.xml
index 660e8619a..ac8fb518e 100644
--- a/.PyCharmRunConfs/pytest units no-cov.run.xml
+++ b/.PyCharmRunConfs/pytest units no-cov.run.xml
@@ -1,6 +1,6 @@
 <!--
   ~ This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
-  ~ Copyright (C) 2020  ONERA & ISAE-SUPAERO
+  ~ Copyright (C) 2024 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
@@ -16,8 +16,12 @@
 <component name="ProjectRunConfigurationManager">
   <configuration default="false" name="pytest units no-cov" type="tests" factoryName="py.test">
     <module name="FAST-OAD" />
+    <option name="ENV_FILES" value="" />
     <option name="INTERPRETER_OPTIONS" value="" />
     <option name="PARENT_ENVS" value="true" />
+    <envs>
+      <env name="RUN_WEB_REQUESTS" value="0" />
+    </envs>
     <option name="SDK_HOME" value="" />
     <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
     <option name="IS_MODULE_SDK" value="true" />
diff --git a/src/fastoad/_utils/testing.py b/src/fastoad/_utils/testing.py
index 2c5ab1e8c..8fa39eca3 100644
--- a/src/fastoad/_utils/testing.py
+++ b/src/fastoad/_utils/testing.py
@@ -2,7 +2,7 @@
 Convenience functions for helping tests
 """
 #  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
-#  Copyright (C) 2022 ONERA & ISAE-SUPAERO
+#  Copyright (C) 2024 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
@@ -14,16 +14,12 @@
 #  You should have received a copy of the GNU General Public License
 #  along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-import logging
-
 import numpy as np
 import openmdao.api as om
 from openmdao.core.system import System
 
 from fastoad.openmdao.variables import VariableList
 
-_LOGGER = logging.getLogger(__name__)  # Logger for this module
-
 
 def run_system(
     component: System, input_vars: om.IndepVarComp, setup_mode="auto", add_solvers=False
diff --git a/src/fastoad/cmd/tests/test_api.py b/src/fastoad/cmd/tests/test_api.py
index 5451e60c8..2bbb8390d 100644
--- a/src/fastoad/cmd/tests/test_api.py
+++ b/src/fastoad/cmd/tests/test_api.py
@@ -62,7 +62,7 @@ def test_generate_notebooks_with_one_dist_plugin(
 ):
     target_path = RESULTS_FOLDER_PATH / "notebooks_1dist"
 
-    api.generate_notebooks(target_path.as_posix())
+    api.generate_notebooks(target_path)
     assert (target_path / "test_plugin_1" / "notebook_1.ipynb").is_file()
     assert (target_path / "test_plugin_4" / "notebook_1.ipynb").is_file()
     assert (target_path / "test_plugin_4" / "data").is_dir()
@@ -292,7 +292,7 @@ def test_generate_inputs(cleanup):
     input_file_path = Path(api.generate_inputs(CONFIGURATION_FILE_PATH, overwrite=False))
     assert input_file_path == RESULTS_FOLDER_PATH / "inputs.xml"
     assert input_file_path.exists()
-    data = DataFile(input_file_path.as_posix())
+    data = DataFile(input_file_path)
     assert len(data) == 2
     assert "x" in data.names() and "z" in data.names()
 
@@ -312,7 +312,7 @@ def test_generate_inputs(cleanup):
 
     assert input_file_path == RESULTS_FOLDER_PATH / "inputs.xml"
     assert input_file_path.exists()
-    data = DataFile(input_file_path.as_posix())
+    data = DataFile(input_file_path)
     assert len(data) == 2
     assert "x" in data.names() and "z" in data.names()
 
@@ -321,13 +321,13 @@ def test_generate_inputs(cleanup):
     input_file_path = Path(api.generate_inputs(CONFIGURATION_FILE_PATH, overwrite=True))
     assert input_file_path == RESULTS_FOLDER_PATH / "inputs.xml"
     assert input_file_path.exists()
-    data = DataFile(input_file_path.as_posix())
+    data = DataFile(input_file_path)
     assert len(data) == 2
     assert "x" in data.names() and "z" in data.names()
 
 
 def test_list_modules(cleanup):
-    conf_file_path = CONFIGURATION_FILE_PATH.as_posix()
+    conf_file_path = CONFIGURATION_FILE_PATH
 
     # Run with stdout output (no test)
     api.list_modules()
@@ -337,38 +337,38 @@ def test_list_modules(cleanup):
     # Run with file output (test file existence)
     out_file = RESULTS_FOLDER_PATH / "list_modules.txt"
     assert not out_file.exists()
-    api.list_modules(conf_file_path, out_file.as_posix())
+    api.list_modules(conf_file_path, out_file)
     with pytest.raises(FastPathExistsError):
-        api.list_modules(conf_file_path, out_file.as_posix())
-    api.list_modules(conf_file_path, out_file.as_posix(), overwrite=True)
+        api.list_modules(conf_file_path, out_file)
+    api.list_modules(conf_file_path, out_file, overwrite=True)
 
     assert out_file.exists()
 
     #
     # Run with file output (test file existence)
-    source_folder = (DATA_FOLDER_PATH / "cmd_sellar_example").as_posix()
+    source_folder = DATA_FOLDER_PATH / "cmd_sellar_example"
 
     # Run with file output with folders (test file existence)
     out_file = RESULTS_FOLDER_PATH / "list_modules_with_folder.txt"
     assert not out_file.exists()
-    api.list_modules(source_folder, out_file.as_posix())
+    api.list_modules(source_folder, out_file)
     with pytest.raises(FastPathExistsError):
-        api.list_modules(source_folder, out_file.as_posix())
+        api.list_modules(source_folder, out_file)
 
     # Testing with single folder
-    api.list_modules(source_folder, out_file.as_posix(), overwrite=True)
+    api.list_modules(source_folder, out_file, overwrite=True)
 
     assert out_file.exists()
 
     # Testing with list of folders
     source_folder = [source_folder]
-    api.list_modules(source_folder, out_file.as_posix(), overwrite=True)
+    api.list_modules(source_folder, out_file, overwrite=True)
 
     assert out_file.exists()
 
 
 def test_list_variables(cleanup):
-    conf_file_path = CONFIGURATION_FILE_PATH.as_posix()
+    conf_file_path = CONFIGURATION_FILE_PATH
 
     # Run with stdout output (no test)
     api.list_variables(conf_file_path)
@@ -376,10 +376,10 @@ def test_list_variables(cleanup):
     # Run with file output (test file existence)
     out_file_path = RESULTS_FOLDER_PATH / "list_variables.txt"
     assert not out_file_path.exists()
-    api.list_variables(conf_file_path, out=out_file_path.as_posix())
+    api.list_variables(conf_file_path, out=out_file_path)
     with pytest.raises(FastPathExistsError):
-        api.list_variables(conf_file_path, out=out_file_path.as_posix())
-    api.list_variables(conf_file_path, out=out_file_path.as_posix(), overwrite=True)
+        api.list_variables(conf_file_path, out=out_file_path)
+    api.list_variables(conf_file_path, out=out_file_path, overwrite=True)
     assert out_file_path.exists()
 
     ref_file_path = DATA_FOLDER_PATH / "ref_list_variables.txt"
@@ -388,7 +388,7 @@ def test_list_variables(cleanup):
     # Test with variable_description.txt format
     api.list_variables(
         conf_file_path,
-        out=out_file_path.as_posix(),
+        out=out_file_path,
         overwrite=True,
         tablefmt="var_desc",
     )
@@ -431,9 +431,7 @@ def test_write_xdsm(cleanup):
 
 
 def test_evaluate_problem(cleanup):
-    api.generate_inputs(
-        CONFIGURATION_FILE_PATH, (DATA_FOLDER_PATH / "inputs.xml").as_posix(), overwrite=True
-    )
+    api.generate_inputs(CONFIGURATION_FILE_PATH, DATA_FOLDER_PATH / "inputs.xml", overwrite=True)
     api.evaluate_problem(CONFIGURATION_FILE_PATH, False)
     # Running again without forcing overwrite of outputs will make it fail
     with pytest.raises(FastPathExistsError):
@@ -446,9 +444,7 @@ def test_evaluate_problem(cleanup):
 
 
 def test_optimize_problem(cleanup):
-    api.generate_inputs(
-        CONFIGURATION_FILE_PATH, (DATA_FOLDER_PATH / "inputs.xml").as_posix(), overwrite=True
-    )
+    api.generate_inputs(CONFIGURATION_FILE_PATH, DATA_FOLDER_PATH / "inputs.xml", overwrite=True)
     api.optimize_problem(CONFIGURATION_FILE_PATH, False)
     # Running again without forcing overwrite of outputs will make it fail
     with pytest.raises(FastPathExistsError):
@@ -459,9 +455,7 @@ def test_optimize_problem(cleanup):
 
 
 def test_optimization_viewer(cleanup):
-    api.generate_inputs(
-        CONFIGURATION_FILE_PATH, (DATA_FOLDER_PATH / "inputs.xml").as_posix(), overwrite=True
-    )
+    api.generate_inputs(CONFIGURATION_FILE_PATH, DATA_FOLDER_PATH / "inputs.xml", overwrite=True)
 
     # Before a run
     api.optimization_viewer(CONFIGURATION_FILE_PATH)
@@ -474,7 +468,7 @@ def test_optimization_viewer(cleanup):
 
 def test_variable_viewer(cleanup):
 
-    file_path = (DATA_FOLDER_PATH / "short_inputs.xml").as_posix()
+    file_path = DATA_FOLDER_PATH / "short_inputs.xml"
 
     # Using default file formatter
     api.variable_viewer(file_path)
diff --git a/src/fastoad/gui/tests/test_analysis_and_plots.py b/src/fastoad/gui/tests/test_analysis_and_plots.py
index bb5ad6618..e33d74a12 100644
--- a/src/fastoad/gui/tests/test_analysis_and_plots.py
+++ b/src/fastoad/gui/tests/test_analysis_and_plots.py
@@ -33,7 +33,7 @@ def test_wing_geometry_plot():
     Basic tests for testing the plotting.
     """
 
-    filename = (DATA_FOLDER_PATH / "problem_outputs.xml").as_posix()
+    filename = DATA_FOLDER_PATH / "problem_outputs.xml"
 
     # First plot
     # This is a rudimentary test as plot are difficult to verify
@@ -57,7 +57,7 @@ def test_aircraft_geometry_plot():
     Basic tests for testing the plotting.
     """
 
-    filename = (DATA_FOLDER_PATH / "problem_outputs.xml").as_posix()
+    filename = DATA_FOLDER_PATH / "problem_outputs.xml"
 
     # First plot
     # This is a rudimentary test as plot are difficult to verify
@@ -81,7 +81,7 @@ def test_mass_breakdown_bar_plot():
     Basic tests for testing the plotting.
     """
 
-    filename = (DATA_FOLDER_PATH / "problem_outputs.xml").as_posix()
+    filename = DATA_FOLDER_PATH / "problem_outputs.xml"
 
     # First plot
     # This is a rudimentary test as plot are difficult to verify
@@ -105,7 +105,7 @@ def test_drag_polar_plot():
     Basic tests for testing the plotting.
     """
 
-    filename = (DATA_FOLDER_PATH / "problem_outputs.xml").as_posix()
+    filename = DATA_FOLDER_PATH / "problem_outputs.xml"
 
     # First plot
     # This is a rudimentary test as plot are difficult to verify
@@ -118,7 +118,7 @@ def test_mass_breakdown_sun_plot():
     Basic tests for testing the plotting.
     """
 
-    filename = (DATA_FOLDER_PATH / "problem_outputs.xml").as_posix()
+    filename = DATA_FOLDER_PATH / "problem_outputs.xml"
 
     # First plot
     # This is a rudimentary test as plot are difficult to verify
@@ -131,7 +131,7 @@ def test_payload_range_plot():
     Basic tests for testing the plotting.
     """
 
-    filename = (DATA_FOLDER_PATH / "problem_outputs.xml").as_posix()
+    filename = DATA_FOLDER_PATH / "problem_outputs.xml"
 
     # First plot
     # This is a rudimentary test as plot are difficult to verify
diff --git a/src/fastoad/gui/tests/test_mission_viewer.py b/src/fastoad/gui/tests/test_mission_viewer.py
index 0261cd4f9..3f7a37d12 100644
--- a/src/fastoad/gui/tests/test_mission_viewer.py
+++ b/src/fastoad/gui/tests/test_mission_viewer.py
@@ -28,7 +28,7 @@ def test_mission_viewer():
     """
     Basic tests for testing the mission viewer.
     """
-    filename = (DATA_FOLDER_PATH / "flight_points.csv").as_posix()
+    filename = DATA_FOLDER_PATH / "flight_points.csv"
 
     mission_viewer = MissionViewer()
 
@@ -41,5 +41,5 @@ def test_mission_viewer():
 
     # Testing with existing .yml
     with pytest.raises(TypeError):
-        filename = (DATA_FOLDER_PATH / "valid_sellar.yml").as_posix()
+        filename = DATA_FOLDER_PATH / "valid_sellar.yml"
         mission_viewer.add_mission(filename, name="Mission 2")
diff --git a/src/fastoad/gui/tests/test_optimization_viewer.py b/src/fastoad/gui/tests/test_optimization_viewer.py
index cdf6a968b..8da3e05d2 100644
--- a/src/fastoad/gui/tests/test_optimization_viewer.py
+++ b/src/fastoad/gui/tests/test_optimization_viewer.py
@@ -37,7 +37,7 @@ def test_optimization_viewer_load(cleanup):
     """
     Basic tests for testing the OptimizationViewer load method.
     """
-    filename = (DATA_FOLDER_PATH / "valid_sellar.yml").as_posix()
+    filename = DATA_FOLDER_PATH / "valid_sellar.yml"
 
     # The problem has not yet been run
     problem_configuration = FASTOADProblemConfigurator(filename)
diff --git a/src/fastoad/gui/tests/test_variable_viewer.py b/src/fastoad/gui/tests/test_variable_viewer.py
index 92fdabd92..7fcd47b10 100644
--- a/src/fastoad/gui/tests/test_variable_viewer.py
+++ b/src/fastoad/gui/tests/test_variable_viewer.py
@@ -23,19 +23,6 @@
 
 from .. import VariableViewer
 
-#  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
-#  Copyright (C) 2024 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/>.
-
 DATA_FOLDER_PATH = Path(__file__).parent / "data"
 RESULTS_FOLDER_PATH = Path(__file__).parent / "results"
 
@@ -49,7 +36,7 @@ def test_variable_reader_display():
     """
     Basic tests for testing the VariableReader display method.
     """
-    filename = (DATA_FOLDER_PATH / "problem_outputs.xml").as_posix()
+    filename = DATA_FOLDER_PATH / "problem_outputs.xml"
 
     # pylint: disable=invalid-name # that's a common naming
     df = VariableViewer()
@@ -117,7 +104,7 @@ def test_variable_reader_load():
 
     ref_df = ref_df.reset_index(drop=True)
 
-    filename = (DATA_FOLDER_PATH / "light_data.xml").as_posix()
+    filename = DATA_FOLDER_PATH / "light_data.xml"
 
     # Testing file to df
     variable_viewer = VariableViewer()
@@ -186,7 +173,7 @@ def test_variable_reader_save():
 
     ref_df = ref_df.reset_index(drop=True)
 
-    filename = (RESULTS_FOLDER_PATH / "light_data.xml").as_posix()
+    filename = RESULTS_FOLDER_PATH / "light_data.xml"
 
     # Testing file to df
     variable_viewer = VariableViewer()
diff --git a/src/fastoad/io/configuration/tests/data/conf_sellar_example/disc1.py b/src/fastoad/io/configuration/tests/data/conf_sellar_example/disc1.py
index e75db457d..659549432 100644
--- a/src/fastoad/io/configuration/tests/data/conf_sellar_example/disc1.py
+++ b/src/fastoad/io/configuration/tests/data/conf_sellar_example/disc1.py
@@ -26,6 +26,7 @@ def initialize(self):
         # These options have no effect and are used for checks
         self.options.declare("dummy_disc1_option", types=dict, default={})
         self.options.declare("dummy_generic_option", types=str, default="")
+        self.options.declare("input_file", types=str, default="")
 
     def setup(self):
         self.add_input("x", val=np.nan, desc="")  # NaN as default for testing connexion check
diff --git a/src/fastoad/io/configuration/tests/data/conf_sellar_example/functions.py b/src/fastoad/io/configuration/tests/data/conf_sellar_example/functions.py
index 71b034e09..7b4b6cbd7 100644
--- a/src/fastoad/io/configuration/tests/data/conf_sellar_example/functions.py
+++ b/src/fastoad/io/configuration/tests/data/conf_sellar_example/functions.py
@@ -30,6 +30,7 @@ def initialize(self):
         # Defined the default "f" function. This choice can be overridden in
         # configuration file
         RegisterSubmodel.active_models[SERVICE_FUNCTION_F] = "function.f.default"
+        self.options.declare("input_path", types=str, default="")
 
     def setup(self):
         self.add_subsystem("f", RegisterSubmodel.get_submodel(SERVICE_FUNCTION_F), promotes=["*"])
diff --git a/src/fastoad/io/configuration/tests/data/valid_sellar.toml b/src/fastoad/io/configuration/tests/data/valid_sellar.toml
index 645aa876c..39d315b1a 100644
--- a/src/fastoad/io/configuration/tests/data/valid_sellar.toml
+++ b/src/fastoad/io/configuration/tests/data/valid_sellar.toml
@@ -28,6 +28,7 @@ driver = "om.ScipyOptimizeDriver(optimizer='SLSQP')"
             id = "configuration_test.sellar.disc2"
     [model.functions]
         id = "configuration_test.sellar.functions"
+        input_path = "translator.txt"
 
 [model_options."*"]
   dummy_f_option = 10
@@ -37,6 +38,7 @@ driver = "om.ScipyOptimizeDriver(optimizer='SLSQP')"
     b = 2
 [model_options."cycle.*"]
   dummy_generic_option = "it works here also"
+  input_file = "__init__.py"
 
 [submodels]
     "service.function.f" = "function.f.default"
diff --git a/src/fastoad/io/configuration/tests/data/valid_sellar.yml b/src/fastoad/io/configuration/tests/data/valid_sellar.yml
index c593baf0b..2edf3f3d3 100644
--- a/src/fastoad/io/configuration/tests/data/valid_sellar.yml
+++ b/src/fastoad/io/configuration/tests/data/valid_sellar.yml
@@ -25,6 +25,7 @@ model:
       id: configuration_test.sellar.disc2
   functions:
     id: configuration_test.sellar.functions
+    input_path: "translator.txt"
 
 model_options:
   "*":
@@ -35,6 +36,7 @@ model_options:
     dummy_generic_option: "it works"
   "cycle.*":
     dummy_generic_option: "it works here also"
+    input_file: "__init__.py"
 
 submodels:
   service.function.f: function.f.default
diff --git a/src/fastoad/io/configuration/tests/test_configuration.py b/src/fastoad/io/configuration/tests/test_configuration.py
index 71cec5b27..a29b78ecb 100644
--- a/src/fastoad/io/configuration/tests/test_configuration.py
+++ b/src/fastoad/io/configuration/tests/test_configuration.py
@@ -119,10 +119,10 @@ def test_problem_definition_with_xml_ref(cleanup, caplog):
         conf = FASTOADProblemConfigurator(DATA_FOLDER_PATH / f"valid_sellar.{extension}")
 
         result_folder_path = RESULTS_FOLDER_PATH / "problem_definition_with_xml_ref"
-        conf.input_file_path = (result_folder_path / "inputs.xml").as_posix()
-        conf.output_file_path = (result_folder_path / "outputs.xml").as_posix()
-        ref_input_data_path_with_nan = (DATA_FOLDER_PATH / "ref_inputs_with_nan.xml").as_posix()
-        ref_input_data_path = (DATA_FOLDER_PATH / "ref_inputs.xml").as_posix()
+        conf.input_file_path = result_folder_path / "inputs.xml"
+        conf.output_file_path = result_folder_path / "outputs.xml"
+        ref_input_data_path_with_nan = DATA_FOLDER_PATH / "ref_inputs_with_nan.xml"
+        ref_input_data_path = DATA_FOLDER_PATH / "ref_inputs.xml"
 
         # Test that the presence of NaN values in inputs logs a warning
         caplog.clear()
@@ -141,12 +141,24 @@ def test_problem_definition_with_xml_ref(cleanup, caplog):
 
         problem = conf.get_problem(read_inputs=True, auto_scaling=True)
         problem.setup()
+
         # check the global way to set options
         assert problem.model.functions.f.options["dummy_f_option"] == 10
         assert problem.model.functions.f.options["dummy_generic_option"] == "it works"
         assert problem.model.cycle.disc1.options["dummy_disc1_option"] == {"a": 1, "b": 2}
         assert problem.model.cycle.disc1.options["dummy_generic_option"] == "it works here also"
 
+        # check that path options are made absolute
+        assert (
+            problem.model.functions.options["input_path"]
+            == (DATA_FOLDER_PATH / "translator.txt").as_posix()
+        )
+
+        assert (
+            problem.model_options["cycle.*"]["input_file"]
+            == (DATA_FOLDER_PATH / "__init__.py").as_posix()
+        )
+
         # runs evaluation without optimization loop to check that inputs are taken into account
         problem.run_model()
         assert problem.model.options["assembled_jac_type"] == "csc"
@@ -157,8 +169,8 @@ def test_problem_definition_with_xml_ref(cleanup, caplog):
         alt_conf = FASTOADProblemConfigurator(
             DATA_FOLDER_PATH / f"valid_sellar_alternate.{extension}"
         )
-        alt_conf.input_file_path = (result_folder_path / "inputs.xml").as_posix()
-        alt_conf.output_file_path = (result_folder_path / "outputs_alt.xml").as_posix()
+        alt_conf.input_file_path = result_folder_path / "inputs.xml"
+        alt_conf.output_file_path = result_folder_path / "outputs_alt.xml"
         alt_problem = alt_conf.get_problem(read_inputs=True, auto_scaling=True)
         # runs evaluation without optimization loop to check that inputs are taken into account
         alt_problem.setup()
@@ -188,9 +200,9 @@ def test_problem_definition_with_xml_ref_with_indep(cleanup):
         result_folder_path = RESULTS_FOLDER_PATH.joinpath(
             "problem_definition_with_xml_ref_with_indep"
         )
-        conf.input_file_path = (result_folder_path / "inputs.xml").as_posix()
-        conf.output_file_path = (result_folder_path / "outputs.xml").as_posix()
-        ref_input_data_path = (DATA_FOLDER_PATH / "ref_inputs.xml").as_posix()
+        conf.input_file_path = result_folder_path / "inputs.xml"
+        conf.output_file_path = result_folder_path / "outputs.xml"
+        ref_input_data_path = DATA_FOLDER_PATH / "ref_inputs.xml"
         conf.write_needed_inputs(ref_input_data_path)
         input_data = DataFile(conf.input_file_path)
         assert len(input_data) == 2
@@ -213,8 +225,8 @@ def test_problem_definition_with_custom_xml(cleanup):
     conf = FASTOADProblemConfigurator(DATA_FOLDER_PATH / "valid_sellar.toml")
 
     result_folder_path = RESULTS_FOLDER_PATH / "problem_definition_with_custom_xml"
-    conf.input_file_path = (result_folder_path / "inputs.xml").as_posix()
-    conf.output_file_path = (result_folder_path / "outputs.xml").as_posix()
+    conf.input_file_path = result_folder_path / "inputs.xml"
+    conf.output_file_path = result_folder_path / "outputs.xml"
 
     input_data = DATA_FOLDER_PATH / "ref_inputs.xml"
     os.makedirs(result_folder_path, exist_ok=True)
@@ -240,8 +252,8 @@ def test_problem_definition_with_xml_ref_run_optim(cleanup):
         result_folder_path = RESULTS_FOLDER_PATH.joinpath(
             "problem_definition_with_xml_ref_run_optim"
         )
-        conf.input_file_path = (result_folder_path / "inputs.xml").as_posix()
-        input_data = (DATA_FOLDER_PATH / "ref_inputs.xml").as_posix()
+        conf.input_file_path = result_folder_path / "inputs.xml"
+        input_data = DATA_FOLDER_PATH / "ref_inputs.xml"
         conf.write_needed_inputs(input_data)
 
         # Runs optimization problem with semi-analytic FD
@@ -251,7 +263,7 @@ def test_problem_definition_with_xml_ref_run_optim(cleanup):
         assert problem1["f"] == pytest.approx(28.58830817, abs=1e-6)
         problem1.run_driver()
         assert problem1["f"] == pytest.approx(3.18339395, abs=1e-6)
-        problem1.output_file_path = (result_folder_path / "outputs_1.xml").as_posix()
+        problem1.output_file_path = result_folder_path / "outputs_1.xml"
         problem1.write_outputs()
 
         # Runs optimization problem with monolithic FD
@@ -262,7 +274,7 @@ def test_problem_definition_with_xml_ref_run_optim(cleanup):
         assert problem2["f"] == pytest.approx(28.58830817, abs=1e-6)
         problem2.run_driver()
         assert problem2["f"] == pytest.approx(3.18339395, abs=1e-6)
-        problem2.output_file_path = (result_folder_path / "outputs_2.xml").as_posix()
+        problem2.output_file_path = result_folder_path / "outputs_2.xml"
         problem2.write_outputs()
 
 
diff --git a/src/fastoad/io/xml/tests/test_variable_io_legacy.py b/src/fastoad/io/xml/tests/test_variable_io_legacy.py
index e0520d5b0..ca36e2325 100644
--- a/src/fastoad/io/xml/tests/test_variable_io_legacy.py
+++ b/src/fastoad/io/xml/tests/test_variable_io_legacy.py
@@ -72,6 +72,6 @@ def test_legacy1(cleanup):
 
     # check by reading without conversion table
     # -> this will give the actual number of entries in the file
-    xml_check = VariableIO(new_filename.as_posix())
+    xml_check = VariableIO(new_filename)
     check_vars = xml_check.read()
     assert len(check_vars) == entry_count
diff --git a/src/fastoad/models/performances/mission/mission_definition/mission_builder/tests/test_mission_builder.py b/src/fastoad/models/performances/mission/mission_definition/mission_builder/tests/test_mission_builder.py
index 4da968dde..ae7f36377 100644
--- a/src/fastoad/models/performances/mission/mission_definition/mission_builder/tests/test_mission_builder.py
+++ b/src/fastoad/models/performances/mission/mission_definition/mission_builder/tests/test_mission_builder.py
@@ -75,7 +75,7 @@ def test_input_definition_units():
 
 def test_initialization():
     mission_builder = MissionBuilder(
-        (DATA_FOLDER_PATH / "mission.yml").as_posix(),
+        DATA_FOLDER_PATH / "mission.yml",
         propulsion=Mock(IPropulsion),
         reference_area=100.0,
     )
@@ -99,7 +99,7 @@ def test_initialization():
 
 def test_get_input_weight_variable_name():
     mission_builder = MissionBuilder(
-        (DATA_FOLDER_PATH / "mission.yml").as_posix(),
+        DATA_FOLDER_PATH / "mission.yml",
         propulsion=Mock(IPropulsion),
         reference_area=100.0,
     )
@@ -114,7 +114,7 @@ def test_get_input_weight_variable_name():
 
 def test_inputs():
     mission_builder = MissionBuilder(
-        (DATA_FOLDER_PATH / "mission.yml").as_posix(),
+        DATA_FOLDER_PATH / "mission.yml",
         propulsion=Mock(IPropulsion),
         reference_area=100.0,
     )
@@ -351,7 +351,7 @@ def test_get_route_ranges():
 
 def test_get_reserve():
     mission_builder = MissionBuilder(
-        (DATA_FOLDER_PATH / "mission.yml").as_posix(),
+        DATA_FOLDER_PATH / "mission.yml",
         propulsion=Mock(IPropulsion),
         reference_area=100.0,
     )
diff --git a/src/fastoad/models/performances/mission/openmdao/tests/test_mission.py b/src/fastoad/models/performances/mission/openmdao/tests/test_mission.py
index fda752b19..19b0c2dbb 100644
--- a/src/fastoad/models/performances/mission/openmdao/tests/test_mission.py
+++ b/src/fastoad/models/performances/mission/openmdao/tests/test_mission.py
@@ -91,15 +91,15 @@ def test_mission_component(cleanup, with_dummy_plugin_2):
     # Also checking behavior when is_sizing is True
 
     input_file_path = DATA_FOLDER_PATH / "test_mission.xml"
-    ivc = DataFile(input_file_path.as_posix()).to_ivc()
+    ivc = DataFile(input_file_path).to_ivc()
 
     problem = run_system(
         AdvancedMissionComp(
             propulsion_id="test.wrapper.propulsion.dummy_engine",
-            out_file=(RESULTS_FOLDER_PATH / "mission.csv").as_posix(),
+            out_file=RESULTS_FOLDER_PATH / "mission.csv",
             use_initializer_iteration=False,
             mission_file_path=MissionWrapper(
-                (DATA_FOLDER_PATH / "test_mission.yml").as_posix(),
+                DATA_FOLDER_PATH / "test_mission.yml",
                 mission_name="operational",
             ),
             reference_area_variable="data:geometry:aircraft:reference_area",
@@ -160,17 +160,17 @@ def test_mission_component(cleanup, with_dummy_plugin_2):
 def test_mission_component_breguet(cleanup, with_dummy_plugin_2):
 
     input_file_path = DATA_FOLDER_PATH / "test_mission.xml"
-    vars = DataFile(input_file_path.as_posix())
+    vars = DataFile(input_file_path)
     ivc = vars.to_ivc()
     ivc.add_output("data:mission:operational:ramp_weight", 70100.0, units="kg")
 
     problem = run_system(
         AdvancedMissionComp(
             propulsion_id="test.wrapper.propulsion.dummy_engine",
-            out_file=(RESULTS_FOLDER_PATH / "breguet.csv").as_posix(),
+            out_file=RESULTS_FOLDER_PATH / "breguet.csv",
             use_initializer_iteration=False,
             mission_file_path=MissionWrapper(
-                (DATA_FOLDER_PATH / "test_breguet_from_block_fuel.yml").as_posix(),
+                DATA_FOLDER_PATH / "test_breguet_from_block_fuel.yml",
                 mission_name="operational",
             ),
             reference_area_variable="data:geometry:aircraft:reference_area",
@@ -205,15 +205,15 @@ def test_mission_component_breguet(cleanup, with_dummy_plugin_2):
 
 def test_mission_group_without_fuel_adjustment(cleanup, with_dummy_plugin_2):
     input_file_path = DATA_FOLDER_PATH / "test_mission.xml"
-    ivc = DataFile(input_file_path.as_posix()).to_ivc()
+    ivc = DataFile(input_file_path).to_ivc()
 
     with pytest.raises(FastMissionFileMissingMissionNameError):
         run_system(
             OMMission(
                 propulsion_id="test.wrapper.propulsion.dummy_engine",
-                out_file=(RESULTS_FOLDER_PATH / "unlooped_mission_group.csv").as_posix(),
+                out_file=RESULTS_FOLDER_PATH / "unlooped_mission_group.csv",
                 use_initializer_iteration=False,
-                mission_file_path=(DATA_FOLDER_PATH / "test_mission.yml").as_posix(),
+                mission_file_path=DATA_FOLDER_PATH / "test_mission.yml",
                 adjust_fuel=False,
                 reference_area_variable="data:geometry:aircraft:reference_area",
                 add_solver=True,
@@ -224,9 +224,9 @@ def test_mission_group_without_fuel_adjustment(cleanup, with_dummy_plugin_2):
     problem = run_system(
         OMMission(
             propulsion_id="test.wrapper.propulsion.dummy_engine",
-            out_file=(RESULTS_FOLDER_PATH / "unlooped_mission_group.csv").as_posix(),
+            out_file=RESULTS_FOLDER_PATH / "unlooped_mission_group.csv",
             use_initializer_iteration=False,
-            mission_file_path=(DATA_FOLDER_PATH / "test_mission.yml").as_posix(),
+            mission_file_path=DATA_FOLDER_PATH / "test_mission.yml",
             mission_name="operational",
             adjust_fuel=False,
             reference_area_variable="data:geometry:aircraft:reference_area",
@@ -244,14 +244,14 @@ def test_mission_group_without_fuel_adjustment(cleanup, with_dummy_plugin_2):
 
 def test_mission_group_breguet_without_fuel_adjustment(cleanup, with_dummy_plugin_2):
     input_file_path = DATA_FOLDER_PATH / "test_breguet.xml"
-    ivc = DataFile(input_file_path.as_posix()).to_ivc()
+    ivc = DataFile(input_file_path).to_ivc()
 
     problem = run_system(
         OMMission(
             propulsion_id="test.wrapper.propulsion.dummy_engine",
-            out_file=(RESULTS_FOLDER_PATH / "unlooped_breguet_mission_group.csv").as_posix(),
+            out_file=RESULTS_FOLDER_PATH / "unlooped_breguet_mission_group.csv",
             use_initializer_iteration=False,
-            mission_file_path=(DATA_FOLDER_PATH / "test_breguet.yml").as_posix(),
+            mission_file_path=DATA_FOLDER_PATH / "test_breguet.yml",
             adjust_fuel=False,
             reference_area_variable="data:geometry:aircraft:reference_area",
         ),
@@ -266,16 +266,16 @@ def test_mission_group_breguet_without_fuel_adjustment(cleanup, with_dummy_plugi
 def test_mission_group_with_fuel_adjustment(cleanup, with_dummy_plugin_2):
 
     input_file_path = DATA_FOLDER_PATH / "test_mission.xml"
-    vars = DataFile(input_file_path.as_posix())
+    vars = DataFile(input_file_path)
     del vars["data:mission:operational:TOW"]
     ivc = vars.to_ivc()
 
     problem = run_system(
         OMMission(
             propulsion_id="test.wrapper.propulsion.dummy_engine",
-            out_file=(RESULTS_FOLDER_PATH / "looped_mission_group.csv").as_posix(),
+            out_file=RESULTS_FOLDER_PATH / "looped_mission_group.csv",
             use_initializer_iteration=True,
-            mission_file_path=(DATA_FOLDER_PATH / "test_mission.yml").as_posix(),
+            mission_file_path=DATA_FOLDER_PATH / "test_mission.yml",
             mission_name="operational",
             add_solver=True,
             reference_area_variable="data:geometry:aircraft:reference_area",
@@ -313,16 +313,16 @@ def test_mission_group_breguet_with_fuel_adjustment(cleanup, with_dummy_plugin_2
     # Also checking behavior when is_sizing is True
 
     input_file_path = DATA_FOLDER_PATH / "test_breguet.xml"
-    vars = DataFile(input_file_path.as_posix())
+    vars = DataFile(input_file_path)
     del vars["data:mission:operational:ramp_weight"]
     ivc = vars.to_ivc()
 
     problem = run_system(
         OMMission(
             propulsion_id="test.wrapper.propulsion.dummy_engine",
-            out_file=(RESULTS_FOLDER_PATH / "looped_breguet_mission_group.csv").as_posix(),
+            out_file=RESULTS_FOLDER_PATH / "looped_breguet_mission_group.csv",
             use_initializer_iteration=True,
-            mission_file_path=(DATA_FOLDER_PATH / "test_breguet.yml").as_posix(),
+            mission_file_path=DATA_FOLDER_PATH / "test_breguet.yml",
             add_solver=True,
             reference_area_variable="data:geometry:aircraft:reference_area",
             is_sizing=True,
@@ -359,15 +359,15 @@ def test_mission_group_breguet_with_fuel_adjustment(cleanup, with_dummy_plugin_2
 def test_mission_group_with_fuel_objective(cleanup, with_dummy_plugin_2):
 
     input_file_path = DATA_FOLDER_PATH / "test_mission.xml"
-    vars = DataFile(input_file_path.as_posix())
+    vars = DataFile(input_file_path)
     ivc = vars.to_ivc()
 
     problem = run_system(
         OMMission(
             propulsion_id="test.wrapper.propulsion.dummy_engine",
-            out_file=(RESULTS_FOLDER_PATH / "fuel_as_objective.csv").as_posix(),
+            out_file=RESULTS_FOLDER_PATH / "fuel_as_objective.csv",
             use_initializer_iteration=False,
-            mission_file_path=(DATA_FOLDER_PATH / "test_mission.yml").as_posix(),
+            mission_file_path=DATA_FOLDER_PATH / "test_mission.yml",
             mission_name="fuel_as_objective",
             add_solver=True,
             adjust_fuel=False,
@@ -398,7 +398,7 @@ def test_mission_group_with_fuel_objective(cleanup, with_dummy_plugin_2):
 def test_mission_group_with_CL_limitation(cleanup, with_dummy_plugin_2):
 
     input_file_path = DATA_FOLDER_PATH / "test_mission.xml"
-    vars = VariableIO(input_file_path.as_posix()).read(ignore=["data:mission:operational:max_CL"])
+    vars = VariableIO(input_file_path).read(ignore=["data:mission:operational:max_CL"])
     ivc = vars.to_ivc()
 
     # Activate CL limitation during cruise and climb
@@ -407,10 +407,10 @@ def test_mission_group_with_CL_limitation(cleanup, with_dummy_plugin_2):
     problem = run_system(
         AdvancedMissionComp(
             propulsion_id="test.wrapper.propulsion.dummy_engine",
-            out_file=(RESULTS_FOLDER_PATH / "CL_limitation_1.csv").as_posix(),
+            out_file=RESULTS_FOLDER_PATH / "CL_limitation_1.csv",
             use_initializer_iteration=False,
             mission_file_path=MissionWrapper(
-                (DATA_FOLDER_PATH / "test_mission.yml").as_posix(),
+                DATA_FOLDER_PATH / "test_mission.yml",
                 mission_name="operational",
             ),
             reference_area_variable="data:geometry:aircraft:reference_area",
@@ -438,10 +438,10 @@ def test_mission_group_with_CL_limitation(cleanup, with_dummy_plugin_2):
     problem = run_system(
         AdvancedMissionComp(
             propulsion_id="test.wrapper.propulsion.dummy_engine",
-            out_file=(RESULTS_FOLDER_PATH / "CL_limitation_2.csv").as_posix(),
+            out_file=RESULTS_FOLDER_PATH / "CL_limitation_2.csv",
             use_initializer_iteration=False,
             mission_file_path=MissionWrapper(
-                (DATA_FOLDER_PATH / "test_mission.yml").as_posix(),
+                DATA_FOLDER_PATH / "test_mission.yml",
                 mission_name="operational_optimal",
             ),
             reference_area_variable="data:geometry:aircraft:reference_area",
@@ -470,14 +470,14 @@ def test_mission_group_with_CL_limitation(cleanup, with_dummy_plugin_2):
 
 def test_mission_group_without_route(cleanup, with_dummy_plugin_2):
     input_file_path = DATA_FOLDER_PATH / "test_mission.xml"
-    ivc = DataFile(input_file_path.as_posix()).to_ivc()
+    ivc = DataFile(input_file_path).to_ivc()
 
     problem = run_system(
         OMMission(
             propulsion_id="test.wrapper.propulsion.dummy_engine",
-            out_file=(RESULTS_FOLDER_PATH / "without_route_mission_group.csv").as_posix(),
+            out_file=RESULTS_FOLDER_PATH / "without_route_mission_group.csv",
             use_initializer_iteration=False,
-            mission_file_path=(DATA_FOLDER_PATH / "test_mission.yml").as_posix(),
+            mission_file_path=DATA_FOLDER_PATH / "test_mission.yml",
             mission_name="without_route",
             adjust_fuel=True,
             reference_area_variable="data:geometry:aircraft:reference_area",
diff --git a/src/fastoad/models/performances/mission/openmdao/tests/test_mission_run.py b/src/fastoad/models/performances/mission/openmdao/tests/test_mission_run.py
index 26b76121d..025576a29 100644
--- a/src/fastoad/models/performances/mission/openmdao/tests/test_mission_run.py
+++ b/src/fastoad/models/performances/mission/openmdao/tests/test_mission_run.py
@@ -34,13 +34,13 @@ def cleanup():
 def test_mission_run(cleanup, with_dummy_plugin_2):
 
     input_file_path = DATA_FOLDER_PATH / "test_mission_run.xml"
-    ivc = DataFile(input_file_path.as_posix()).to_ivc()
+    ivc = DataFile(input_file_path).to_ivc()
 
     problem = run_system(
         MissionComp(
             propulsion_id="test.wrapper.propulsion.dummy_engine",
-            out_file=(RESULTS_FOLDER_PATH / "mission.csv").as_posix(),
-            mission_file_path=(DATA_FOLDER_PATH / "test_mission.yml").as_posix(),
+            out_file=RESULTS_FOLDER_PATH / "mission.csv",
+            mission_file_path=DATA_FOLDER_PATH / "test_mission.yml",
             mission_name="operational",
             reference_area_variable="data:geometry:aircraft:reference_area",
             variable_prefix="data:payload_range",
diff --git a/src/fastoad/models/performances/mission/openmdao/tests/test_mission_takeoff.py b/src/fastoad/models/performances/mission/openmdao/tests/test_mission_takeoff.py
index c3c6f9264..c8d3c116b 100644
--- a/src/fastoad/models/performances/mission/openmdao/tests/test_mission_takeoff.py
+++ b/src/fastoad/models/performances/mission/openmdao/tests/test_mission_takeoff.py
@@ -88,7 +88,7 @@ def plot_flight(flight_points, fig_filename):
 def test_mission_component(cleanup, with_dummy_plugin_2):
 
     input_file_path = DATA_FOLDER_PATH / "test_mission.xml"
-    ivc = DataFile(input_file_path.as_posix()).to_ivc()
+    ivc = DataFile(input_file_path).to_ivc()
 
     ivc.add_output("data:mission:operational_wo_gnd_effect:TOW", 70000, units="kg")
     ivc.add_output("data:mission:operational_wo_gnd_effect:OWE", 40000, units="kg")
@@ -102,10 +102,10 @@ def test_mission_component(cleanup, with_dummy_plugin_2):
     problem = run_system(
         AdvancedMissionComp(
             propulsion_id="test.wrapper.propulsion.dummy_engine",
-            out_file=(RESULTS_FOLDER_PATH / "test_mission.csv").as_posix(),
+            out_file=RESULTS_FOLDER_PATH / "test_mission.csv",
             use_initializer_iteration=False,
             mission_file_path=MissionWrapper(
-                (DATA_FOLDER_PATH / "test_mission_takeoff.yml").as_posix(),
+                DATA_FOLDER_PATH / "test_mission_takeoff.yml",
                 mission_name="operational_wo_gnd_effect",
             ),
         ),
@@ -134,7 +134,7 @@ def test_mission_component(cleanup, with_dummy_plugin_2):
 def test_ground_effect(cleanup, with_dummy_plugin_2):
 
     input_file_path = DATA_FOLDER_PATH / "test_mission.xml"
-    datafile = DataFile(input_file_path.as_posix())
+    datafile = DataFile(input_file_path)
     del datafile["data:mission:operational:takeoff:fuel"]
 
     ivc = datafile.to_ivc()
@@ -148,10 +148,10 @@ def test_ground_effect(cleanup, with_dummy_plugin_2):
     problem = run_system(
         AdvancedMissionComp(
             propulsion_id="test.wrapper.propulsion.dummy_engine",
-            out_file=(RESULTS_FOLDER_PATH / "test_mission_to.csv").as_posix(),
+            out_file=RESULTS_FOLDER_PATH / "test_mission_to.csv",
             use_initializer_iteration=False,
             mission_file_path=MissionWrapper(
-                (DATA_FOLDER_PATH / "test_mission_takeoff.yml").as_posix(),
+                DATA_FOLDER_PATH / "test_mission_takeoff.yml",
                 mission_name="operational",
             ),
         ),
@@ -166,7 +166,7 @@ def test_ground_effect(cleanup, with_dummy_plugin_2):
 
 def test_start_stop(cleanup, with_dummy_plugin_2):
     input_file_path = DATA_FOLDER_PATH / "test_mission.xml"
-    ivc = DataFile(input_file_path.as_posix()).to_ivc()
+    ivc = DataFile(input_file_path).to_ivc()
 
     ivc.add_output("data:mission:start_stop_mission:TOW", 79000, units="kg")
     ivc.add_output("data:mission:start_stop_mission:OWE", 40000, units="kg")
@@ -180,10 +180,10 @@ def test_start_stop(cleanup, with_dummy_plugin_2):
     problem = run_system(
         AdvancedMissionComp(
             propulsion_id="test.wrapper.propulsion.dummy_engine",
-            out_file=(RESULTS_FOLDER_PATH / "test_mission_start_stop.csv").as_posix(),
+            out_file=RESULTS_FOLDER_PATH / "test_mission_start_stop.csv",
             use_initializer_iteration=False,
             mission_file_path=MissionWrapper(
-                (DATA_FOLDER_PATH / "test_mission_takeoff.yml").as_posix(),
+                DATA_FOLDER_PATH / "test_mission_takeoff.yml",
                 mission_name="start_stop_mission",
             ),
         ),
@@ -197,7 +197,7 @@ def test_start_stop(cleanup, with_dummy_plugin_2):
 
 def test_mission_group_without_loop(cleanup, with_dummy_plugin_2):
     input_file_path = DATA_FOLDER_PATH / "test_mission.xml"
-    datafile = DataFile(input_file_path.as_posix())
+    datafile = DataFile(input_file_path)
     del datafile["data:mission:operational:takeoff:fuel"]
     ivc = datafile.to_ivc()
     ivc.add_output(
@@ -209,9 +209,9 @@ def test_mission_group_without_loop(cleanup, with_dummy_plugin_2):
     problem = run_system(
         OMMission(
             propulsion_id="test.wrapper.propulsion.dummy_engine",
-            out_file=(RESULTS_FOLDER_PATH / "test_unlooped_mission_group.csv").as_posix(),
+            out_file=RESULTS_FOLDER_PATH / "test_unlooped_mission_group.csv",
             use_initializer_iteration=False,
-            mission_file_path=(DATA_FOLDER_PATH / "test_mission_takeoff.yml").as_posix(),
+            mission_file_path=DATA_FOLDER_PATH / "test_mission_takeoff.yml",
             mission_name="operational",
             adjust_fuel=False,
         ),
diff --git a/src/fastoad/models/performances/mission/openmdao/tests/test_payload_range.py b/src/fastoad/models/performances/mission/openmdao/tests/test_payload_range.py
index 7860ce7a5..0913994cf 100644
--- a/src/fastoad/models/performances/mission/openmdao/tests/test_payload_range.py
+++ b/src/fastoad/models/performances/mission/openmdao/tests/test_payload_range.py
@@ -33,12 +33,12 @@ def cleanup():
 def test_payload_range_custom_breguet_mission(cleanup, with_dummy_plugin_2):
 
     input_file_path = DATA_FOLDER_PATH / "test_payload_range.xml"
-    ivc = DataFile(input_file_path.as_posix()).to_ivc()
+    ivc = DataFile(input_file_path).to_ivc()
 
     problem = run_system(
         PayloadRange(
             propulsion_id="test.wrapper.propulsion.dummy_engine",
-            mission_file_path=(DATA_FOLDER_PATH / "test_payload_range.yml").as_posix(),
+            mission_file_path=DATA_FOLDER_PATH / "test_payload_range.yml",
             mission_name="operational",
             reference_area_variable="data:geometry:aircraft:reference_area",
             nb_contour_points=6,
@@ -104,7 +104,7 @@ def test_payload_range_custom_breguet_mission(cleanup, with_dummy_plugin_2):
 def test_payload_range_sizing_breguet(cleanup, with_dummy_plugin_2):
 
     input_file_path = DATA_FOLDER_PATH / "test_payload_range.xml"
-    ivc = DataFile(input_file_path.as_posix()).to_ivc()
+    ivc = DataFile(input_file_path).to_ivc()
 
     problem = run_system(
         PayloadRange(
@@ -139,7 +139,7 @@ def test_payload_range_sizing_breguet(cleanup, with_dummy_plugin_2):
 def test_payload_range_sizing_mission(cleanup, with_dummy_plugin_2):
 
     input_file_path = DATA_FOLDER_PATH / "test_payload_range.xml"
-    ivc = DataFile(input_file_path.as_posix()).to_ivc()
+    ivc = DataFile(input_file_path).to_ivc()
 
     problem = run_system(
         PayloadRange(
diff --git a/src/fastoad/models/performances/mission/openmdao/tests/test_sizing_breguet.py b/src/fastoad/models/performances/mission/openmdao/tests/test_sizing_breguet.py
index 4d3762594..b40a9acb4 100644
--- a/src/fastoad/models/performances/mission/openmdao/tests/test_sizing_breguet.py
+++ b/src/fastoad/models/performances/mission/openmdao/tests/test_sizing_breguet.py
@@ -55,7 +55,7 @@ def test_sizing_breguet(cleanup, with_dummy_plugin_2):
     problem = run_system(
         OMMission(
             propulsion_id="test.wrapper.propulsion.dummy_engine",
-            out_file=(RESULTS_FOLDER_PATH / "sizing_breguet.csv").as_posix(),
+            out_file=RESULTS_FOLDER_PATH / "sizing_breguet.csv",
             use_initializer_iteration=False,
             mission_file_path="::sizing_breguet",
             adjust_fuel=False,
diff --git a/src/fastoad/models/performances/mission/openmdao/tests/test_sizing_mission.py b/src/fastoad/models/performances/mission/openmdao/tests/test_sizing_mission.py
index a47925f75..10098ceca 100644
--- a/src/fastoad/models/performances/mission/openmdao/tests/test_sizing_mission.py
+++ b/src/fastoad/models/performances/mission/openmdao/tests/test_sizing_mission.py
@@ -63,7 +63,7 @@ def test_sizing_mission(cleanup, with_dummy_plugin_2):
     problem = run_system(
         OMMission(
             propulsion_id="test.wrapper.propulsion.dummy_engine",
-            out_file=(RESULTS_FOLDER_PATH / "sizing_mission.csv").as_posix(),
+            out_file=RESULTS_FOLDER_PATH / "sizing_mission.csv",
             use_initializer_iteration=False,
             mission_file_path="::sizing_mission",
             adjust_fuel=False,
diff --git a/src/fastoad/models/performances/mission/openmdao/tests/test_with_custom_segment.py b/src/fastoad/models/performances/mission/openmdao/tests/test_with_custom_segment.py
index f8650a7bd..46d65c2e4 100644
--- a/src/fastoad/models/performances/mission/openmdao/tests/test_with_custom_segment.py
+++ b/src/fastoad/models/performances/mission/openmdao/tests/test_with_custom_segment.py
@@ -51,15 +51,13 @@ def compute_from_start_to_target(self, start, target) -> pd.DataFrame:
 
 def test_with_custom_segment(cleanup, with_dummy_plugin_2):
     input_file_path = DATA_FOLDER_PATH / "test_with_custom_segment.xml"
-    ivc = DataFile(input_file_path.as_posix()).to_ivc()
+    ivc = DataFile(input_file_path).to_ivc()
 
     problem = run_system(
         AdvancedMissionComp(
             propulsion_id="test.wrapper.propulsion.dummy_engine",
             use_initializer_iteration=False,
-            mission_file_path=MissionWrapper(
-                (DATA_FOLDER_PATH / "test_with_custom_segment.yml").as_posix()
-            ),
+            mission_file_path=MissionWrapper(DATA_FOLDER_PATH / "test_with_custom_segment.yml"),
             mission_name="test",
         ),
         ivc,
diff --git a/src/fastoad/models/performances/mission/tests/conftest.py b/src/fastoad/models/performances/mission/tests/conftest.py
index 584ba2a0c..9b883a4a7 100644
--- a/src/fastoad/models/performances/mission/tests/conftest.py
+++ b/src/fastoad/models/performances/mission/tests/conftest.py
@@ -12,7 +12,7 @@
 #  along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
 from dataclasses import InitVar, dataclass, field
-from os import path as pth
+from pathlib import Path
 from typing import Union
 
 import numpy as np
@@ -106,7 +106,7 @@ def plot_flight(flight_points, fig_filename, results_folder_path):
     labels = [l.get_label() for l in lines]
     plt.legend(lines, labels, loc=0)
 
-    plt.savefig(pth.join(results_folder_path, fig_filename))
+    plt.savefig(Path(results_folder_path, fig_filename))
     plt.close()
 
 
diff --git a/src/fastoad/module_management/tests/test_bundle_loader.py b/src/fastoad/module_management/tests/test_bundle_loader.py
index a2f9d3489..4dc925a6a 100644
--- a/src/fastoad/module_management/tests/test_bundle_loader.py
+++ b/src/fastoad/module_management/tests/test_bundle_loader.py
@@ -27,8 +27,6 @@
     FastBundleLoaderUnknownFactoryNameError,
 )
 
-_LOGGER = logging.getLogger(__name__)  # Logger for this module
-
 logging.basicConfig(level=logging.DEBUG)
 
 
@@ -105,7 +103,7 @@ def test_install_packages(delete_framework):
     """
     loader = BundleLoader()
 
-    loader.explore_folder((DATA_FOLDER_PATH / "dummy_pelix_bundles").as_posix())
+    loader.explore_folder(DATA_FOLDER_PATH / "dummy_pelix_bundles")
     assert (
         loader.framework.get_bundle_by_name("dummy_pelix_bundles.hello_world_with_decorators")
         is not None
@@ -128,7 +126,7 @@ def test_install_packages_on_faulty_install(delete_framework):
     sys.modules["numpy.random.mtrand"].__path__ = None
 
     # Install packages
-    loader.explore_folder((DATA_FOLDER_PATH / "dummy_pelix_bundles").as_posix())
+    loader.explore_folder(DATA_FOLDER_PATH / "dummy_pelix_bundles")
     assert (
         loader.framework.get_bundle_by_name("dummy_pelix_bundles.hello_world_with_decorators")
         is not None
@@ -144,7 +142,7 @@ def test_register_factory(delete_framework):
     """
 
     loader = BundleLoader()
-    loader.explore_folder((DATA_FOLDER_PATH / "dummy_pelix_bundles").as_posix())
+    loader.explore_folder(DATA_FOLDER_PATH / "dummy_pelix_bundles")
 
     class Greetings1:
         def hello(self, name="World"):
@@ -160,7 +158,7 @@ def test_get_services(delete_framework):
     Tests the method for retrieving services according to properties
     """
     loader = BundleLoader()
-    loader.explore_folder((DATA_FOLDER_PATH / "dummy_pelix_bundles").as_posix())
+    loader.explore_folder(DATA_FOLDER_PATH / "dummy_pelix_bundles")
 
     # Missing service
     services = loader.get_services("does.not.exists")
@@ -206,7 +204,7 @@ def test_instantiate_component(delete_framework):
     Tests the method for instantiating a component from factory name
     """
     loader = BundleLoader()
-    loader.explore_folder((DATA_FOLDER_PATH / "dummy_pelix_bundles").as_posix())
+    loader.explore_folder(DATA_FOLDER_PATH / "dummy_pelix_bundles")
 
     with pytest.raises(FastBundleLoaderUnknownFactoryNameError):
         unknown = loader.instantiate_component("the-unknown-hello-world-factory")
@@ -230,7 +228,7 @@ def test_get_factory_names(delete_framework):
     Tests the method for retrieving factories according to properties
     """
     loader = BundleLoader()
-    loader.explore_folder((DATA_FOLDER_PATH / "dummy_pelix_bundles").as_posix())
+    loader.explore_folder(DATA_FOLDER_PATH / "dummy_pelix_bundles")
 
     # Missing service
     factory_names = loader.get_factory_names("does.not.exists")
diff --git a/src/fastoad/module_management/tests/test_register_openmdao_system.py b/src/fastoad/module_management/tests/test_register_openmdao_system.py
index edfa929bb..ce1dff99a 100644
--- a/src/fastoad/module_management/tests/test_register_openmdao_system.py
+++ b/src/fastoad/module_management/tests/test_register_openmdao_system.py
@@ -14,7 +14,6 @@
 #  You should have received a copy of the GNU General Public License
 #  along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-import logging
 from pathlib import Path
 
 import openmdao.api as om
@@ -28,16 +27,13 @@
 from ..._utils.sellar.sellar_base import BasicSellarModel, BasicSellarProblem, ISellarFactory
 from ...openmdao.variables import Variable
 
-_LOGGER = logging.getLogger(__name__)  # Logger for this module
-
-
 DATA_FOLDER_PATH = Path(__file__).parent / "data"
 
 
 @pytest.fixture(scope="module")
 def load():
     """Loads components"""
-    RegisterOpenMDAOSystem.explore_folder((DATA_FOLDER_PATH / "module_sellar_example").as_posix())
+    RegisterOpenMDAOSystem.explore_folder(DATA_FOLDER_PATH / "module_sellar_example")
 
 
 def test_variable_description(load):
diff --git a/src/fastoad/module_management/tests/test_register_specialized_service.py b/src/fastoad/module_management/tests/test_register_specialized_service.py
index 9e3c6cf63..dc59d22dc 100644
--- a/src/fastoad/module_management/tests/test_register_specialized_service.py
+++ b/src/fastoad/module_management/tests/test_register_specialized_service.py
@@ -41,7 +41,7 @@ class RegisterDummyServiceB(
 @pytest.fixture(scope="module")
 def load():
     """Loads components"""
-    RegisterSpecializedService.explore_folder((DATA_FOLDER_PATH / "dummy_services").as_posix())
+    RegisterSpecializedService.explore_folder(DATA_FOLDER_PATH / "dummy_services")
 
 
 def test_get_provider_ids_without_explore_folders():
diff --git a/src/fastoad/module_management/tests/test_register_submodel.py b/src/fastoad/module_management/tests/test_register_submodel.py
index 66d558f43..24022fe5a 100644
--- a/src/fastoad/module_management/tests/test_register_submodel.py
+++ b/src/fastoad/module_management/tests/test_register_submodel.py
@@ -32,7 +32,7 @@ def load():
     """Loads components"""
     previous_active_submodels = RegisterSubmodel.active_models
     RegisterSubmodel.active_models = {}
-    BundleLoader().explore_folder((DATA_FOLDER_PATH / "dummy_submodels").as_posix())
+    BundleLoader().explore_folder(DATA_FOLDER_PATH / "dummy_submodels")
     yield
     RegisterSubmodel.active_models = previous_active_submodels
 
diff --git a/src/fastoad/openmdao/tests/test_problem.py b/src/fastoad/openmdao/tests/test_problem.py
index 7c62ec7a0..979d83085 100644
--- a/src/fastoad/openmdao/tests/test_problem.py
+++ b/src/fastoad/openmdao/tests/test_problem.py
@@ -40,7 +40,7 @@ def cleanup():
 def test_write_outputs():
     problem = FASTOADProblem()
     problem.model.add_subsystem("sellar", SellarModel(), promotes=["*"])
-    problem.output_file_path = (RESULTS_FOLDER_PATH / "output.xml").as_posix()
+    problem.output_file_path = RESULTS_FOLDER_PATH / "output.xml"
     problem.setup()
 
     problem.write_outputs()
@@ -79,7 +79,7 @@ def test_problem_read_inputs_after_setup(cleanup):
     problem = FASTOADProblem()
     problem.model.add_subsystem("sellar", SellarModel(), promotes=["*"])
 
-    problem.input_file_path = (DATA_FOLDER_PATH / "ref_inputs.xml").as_posix()
+    problem.input_file_path = DATA_FOLDER_PATH / "ref_inputs.xml"
 
     problem.setup()
 
@@ -103,7 +103,7 @@ def test_problem_read_inputs_before_setup(cleanup):
     problem = FASTOADProblem()
     problem.model.add_subsystem("sellar", SellarModel(), promotes=["*"])
 
-    problem.input_file_path = (DATA_FOLDER_PATH / "ref_inputs.xml").as_posix()
+    problem.input_file_path = DATA_FOLDER_PATH / "ref_inputs.xml"
 
     problem.read_inputs()
     problem.setup()
@@ -121,11 +121,11 @@ def test_problem_with_case_recorder(cleanup):
     problem = FASTOADProblem()
     sellar = SellarModel()
     sellar.nonlinear_solver = om.NonlinearBlockGS()  # Solver that is compatible with deepcopy
-    sellar.add_recorder(om.SqliteRecorder((RESULTS_FOLDER_PATH / "cases.sql").as_posix()))
+    sellar.add_recorder(om.SqliteRecorder(RESULTS_FOLDER_PATH / "cases.sql"))
 
     problem.model.add_subsystem("sellar", sellar, promotes=["*"])
 
-    problem.input_file_path = (DATA_FOLDER_PATH / "ref_inputs.xml").as_posix()
+    problem.input_file_path = DATA_FOLDER_PATH / "ref_inputs.xml"
 
     problem.setup()
     problem.read_inputs()
@@ -142,7 +142,7 @@ def test_problem_read_inputs_with_nan_inputs(cleanup):
     problem = FASTOADProblem()
     problem.model.add_subsystem("sellar", SellarModel(), promotes=["*"])
 
-    input_data_path = (DATA_FOLDER_PATH / "nan_inputs.xml").as_posix()
+    input_data_path = DATA_FOLDER_PATH / "nan_inputs.xml"
 
     problem.input_file_path = input_data_path
 
@@ -201,7 +201,7 @@ def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None):
 
     # In such case, reading inputs after the setup will make run_model fail, because dummy shapes
     # have already been provided, and will probably not match the ones in input file.
-    fastoad_problem.input_file_path = (DATA_FOLDER_PATH / "dynamic_shape_inputs_1.xml").as_posix()
+    fastoad_problem.input_file_path = DATA_FOLDER_PATH / "dynamic_shape_inputs_1.xml"
     fastoad_problem.read_inputs()
     with pytest.raises(ValueError):
         fastoad_problem.run_model()
@@ -211,7 +211,7 @@ def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None):
     fastoad_problem = FASTOADProblem()
     fastoad_problem.model.add_subsystem("comp1", MyComp1(), promotes=["*"])
     fastoad_problem.model.add_subsystem("comp2", MyComp2(), promotes=["*"])
-    fastoad_problem.input_file_path = (DATA_FOLDER_PATH / "dynamic_shape_inputs_1.xml").as_posix()
+    fastoad_problem.input_file_path = DATA_FOLDER_PATH / "dynamic_shape_inputs_1.xml"
     fastoad_problem.read_inputs()
     fastoad_problem.setup()
 
diff --git a/src/fastoad/openmdao/tests/test_validity_checker.py b/src/fastoad/openmdao/tests/test_validity_checker.py
index a6553a212..f4c8b6891 100644
--- a/src/fastoad/openmdao/tests/test_validity_checker.py
+++ b/src/fastoad/openmdao/tests/test_validity_checker.py
@@ -25,8 +25,6 @@
 from ..validity_checker import ValidityDomainChecker, ValidityStatus
 from ..variables import Variable, VariableList
 
-_LOGGER = logging.getLogger(__name__)  # Logger for this module
-
 RESULTS_FOLDER_PATH = Path(__file__).parent / "results" / Path(__file__).stem
 
 
diff --git a/src/fastoad/openmdao/tests/test_whatsopt.py b/src/fastoad/openmdao/tests/test_whatsopt.py
index f82cc9220..7302d0ee2 100644
--- a/src/fastoad/openmdao/tests/test_whatsopt.py
+++ b/src/fastoad/openmdao/tests/test_whatsopt.py
@@ -10,6 +10,7 @@
 #  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/>.
+
 import shutil
 from pathlib import Path
 
@@ -20,18 +21,18 @@
 from ..whatsopt import write_xdsm
 
 DATA_FOLDER_PATH = Path(__file__).parent / "data"
-RESULTS_FOLDER_PATH = Path(__file__).parent / "results", Path(__file__).stem
+RESULTS_FOLDER_PATH = Path(__file__).parent / "results" / Path(__file__).stem
 
 
 @pytest.fixture(scope="module")
 def cleanup():
     shutil.rmtree(RESULTS_FOLDER_PATH, ignore_errors=True)
-    RESULTS_FOLDER_PATH.mkdir()
+    RESULTS_FOLDER_PATH.mkdir(parents=True)
 
 
 @pytest.mark.skip(
     reason="Using web access during tests should not be the default behavior. "
-    "Moreover, fastoad/cmd/tests/test_apy.py:test_write_xdsm dose a similar test."
+    "Moreover, fastoad/cmd/tests/test_apy.py:test_write_xdsm does a similar test."
 )
 def test_write_xdsm(cleanup):
 
@@ -42,5 +43,5 @@ def test_write_xdsm(cleanup):
     problem.final_setup()
 
     xdsm_file_path = RESULTS_FOLDER_PATH / "xdsm.html"
-    write_xdsm(problem, xdsm_file_path.as_posix(), dry_run=True)
+    write_xdsm(problem, xdsm_file_path, dry_run=True)
     assert xdsm_file_path.joinpath()