Source code for alts.core.run_from_path
#Version 1.1.1 conform as of 14.12.2024
"""
| *alts.core.run_from_path*
"""
from __future__ import annotations
from types import ModuleType
from typing import TYPE_CHECKING, List
import sys
import os
import importlib.util
from alts.core.experiment_runner import ExperimentRunner
if TYPE_CHECKING:
from alts.core.blueprint import Blueprint
[docs]
def load_modules_from_folder(experiment_path):
"""
load_modules_from_folder(experiment_path) -> modules
| **Description**
| Loads and returns all modules from the ``experiment_path`` folder.
| It does so by loading all .py files in the folder. Subfolders are ignored.
:param experiment_path: Path to folder with modules
:type experiment_path: Dir path
:return: The modules inside the ``experiment_path`` folder
:rtype: List[ModuleType]
"""
for dirpath, dnames, fnames in os.walk(experiment_path):
file_name: str
for file_name in fnames:
if file_name.endswith(".py"):
module = load_module(dirpath, file_name)
yield module
[docs]
def load_module(dirpath: str, file_name: str):
"""
load_module(dirpath, file_name) -> module
| **Description**
| Loads and returns the contents of the specified file as a module using the importlib library.
:param dirpath: Path to folder containing module
:type dirpath: Dir path
:param file_name: The module in the folder to be loaded
:param file_name: File name
:return: Loaded, interactable module from the file
:rtype: ModuleType
:raises ImportError: If importlib fails to find a module spec or fails to create spec.loader
"""
file_path = os.path.join(dirpath, file_name)
module_name = file_name.split(sep=".")[0]
spec = importlib.util.spec_from_file_location(module_name, file_path)
if spec is None:
raise ImportError()
else:
module = importlib.util.module_from_spec(spec)
if spec.loader is None:
raise ImportError()
else:
spec.loader.exec_module(module)
return module
[docs]
def set_exp_path_and_name(module: ModuleType, exp_path: str):
"""
set_exp_path_and_name(module, exp_path) -> blueprints
| **Description**
| Returns all blueprints from a module and sets their experiment path to ``exp_name``.
| It first tries to load a blueprint from ``module.blueprint``. If that fails, it tries
to load a list of blueprints from ``module.blueprints``. If that fails, too, it returns
an empty list.
:param module: Module to be laoded from
:type module: ModuleType
:param exp_path: The desired experiment output path. A new output folder "eval" will be created in there.
:type exp_path: Dir path
:return: All prepared blueprints
:rtype: list[Blueprint]
"""
try:
blueprint: Blueprint = module.blueprint
blueprint.exp_path = os.path.join(exp_path, "eval", module.__name__)
blueprint.exp_name = module.__name__
return [blueprint]
except AttributeError:
try:
print("loaded file not a blueprint, test for multiple blueprints")
blueprints: List[Blueprint] = module.blueprints
for blueprint in blueprints:
blueprint.exp_path = os.path.join(exp_path, "eval", module.__name__)
return blueprints
except AttributeError:
print("loaded file contains no blueprints, skipping file!")
return []
[docs]
def run_experiments_from_folder(experiment_path, parallel = False):
"""
run_experiments_from_folder(experiment_path, parallel) -> None
| **Description**
| Loads all blueprint found in modules in ``experiment_path`` and runs an experiment with each configuration.
| The output folder ("eval") with its output files will be created in ``experiment_path``.
:param experiment_path: Folder with modules containing blueprints
:type experiment_path: Dir path
:param parallel: If True, runs experiments in parallel (default= False)
:type parallel: bool
"""
blueprints = []
for module in load_modules_from_folder(experiment_path):
blueprints.extend(set_exp_path_and_name(module, experiment_path))
er = ExperimentRunner(blueprints)
if parallel:
er.run_experiments_parallel()
else:
er.run_experiments()