Source code for hermespy.bin.hermes

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
=============================
Hermes Command Line Interface
=============================

Within this module the primary entry point to the HermesPy simulation routine is defined as
command line interface (CLI).
In order to conveniently launch HermesPy from any command line,
make sure that the virtual Python environment you installed HermesPy in is activated by executing

.. tabs::

   .. code-tab:: powershell Conda

      conda activate <envname>

   .. code-tab:: powershell VEnv Windows

      <envname>/Scripts/activate.bat

   .. code-tab:: batch VEnv Linux

      source <envname>\\bin\\activate

within a terminal.
Usually activated environments are indicated by a `(<envname>)` in front of your terminal command line.
Afterwards, HermesPy can be launched by executing the command

.. code-block:: console

   hermes <configuration> -o <output_dir>

The configuration should point to a configuration file describing the simulation scenario.
Refer to the `repository <https://github.com/Barkhausen-Institut/hermespy/tree/main/_examples/settings>`_ for examples.
The available argument options are

.. list-table:: CLI Argument Options
   :align: center

   * - <configuration>
     - Path to a `.yml` file containing a simulation scenario description

   * - -h, --help
     - Display the CLI help

   * - -o `<directory>`
     - Specify the result output directory

   * - -s `<style>`
     - Specify the style of the result plots.

   * - -t
     - Run the CLI in test mode. No artifacts will be saved to results folders.

If no output directory was specified, a new folder `results` is being created within the current working directory.
"""

from __future__ import annotations
import os
import shutil
import sys
import argparse
from typing import List
from collections.abc import Sequence

from ruamel.yaml.constructor import ConstructorError
from rich.console import Console

from hermespy.core.executable import Executable
from hermespy.core.factory import Serializable, Factory

__author__ = "André Noll Barreto"
__copyright__ = "Copyright 2024, Barkhausen Institut gGmbH"
__credits__ = ["André Barreto", "Jan Adler"]
__license__ = "AGPLv3"
__version__ = "1.4.0"
__maintainer__ = "Jan Adler"
__email__ = "jan.adler@barkhauseninstitut.org"
__status__ = "Prototype"


[docs] def hermes_simulation(args: List[str] | None = None) -> None: """HermesPy Command Line Interface. Default entry point to execute hermespy `.yml` files via terminals. Args: args ([List[str], optional): Command line arguments. By default, the system argument vector will be interpreted. """ # Recover command line arguments from system if none are provided args = sys.argv[1:] if args is None else args parser = argparse.ArgumentParser( description="HermesPy - The Heterogeneous Mobile Radio Simulator", prog="hermes" ) parser.add_argument("-o", help="output directory to which results will be dumped", type=str) parser.add_argument("-s", help="style of result plots", type=str) parser.add_argument( "-t", "--test", action="store_true", help="run in test-mode, does not dump results" ) parser.add_argument( "-l", "--log", action="store_true", help="log the console information to a txt file" ) parser.add_argument( "config", help="parameters source file from which to read the simulation configuration", type=str, ) arguments = parser.parse_args(args) # Create console console = Console(record=arguments.log) console.show_cursor(False) # Draw welcome header console.print("\n[bold green]Welcome to HermesPy - The Heterogeneous Radio Mobile Simulator\n") console.print(f"Version: {__version__}") console.print(f"Maintainer: {__maintainer__}") console.print(f"Contact: {__email__}") console.print("\nFor detailed instructions, refer to the documentation https://hermespy.org/") console.print( "Please report any bugs to https://github.com/Barkhausen-Institut/hermespy/issues\n" ) console.print(f"Configuration will be read from '{arguments.config}'") with console.status("Initializing Environment...", spinner="dots"): ################## # Import executable from YAML config dump factory = Factory() try: # Load serializable objects from configuration files serializables: Sequence[Serializable] = factory.from_path(arguments.config) # Filter out non-executables from the serialization list executables: Sequence[Executable] = [ s for s in serializables if isinstance(s, Executable) ] # Abort execution if no executable was found if len(executables) < 1: console.log("No executable routine was detected, aborting execution", style="red") sys.exit(-1) # For now, only single executables are supported executable = executables[0] executable.results_dir = ( Executable.default_results_dir() if arguments.o is None else arguments.o ) except ConstructorError as error: console.log( f"YAML import failed during parsing of line {error.problem_mark.line} in file '{error.problem_mark.name}':\n\t{error.problem}", style="red", ) sys.exit(-1) # Configure console executable.console = console # Configure style if arguments.s is not None: executable.style = arguments.s # Inform about the results directory console.print(f"Results will be saved in '{executable.results_dir}'") # Dump current configuration to results directory if not arguments.test: shutil.copy(arguments.config, executable.results_dir) ################## # run simulation executable.execute() ########### # Goodbye :) console.print("Configuration executed. Goodbye.") # Save log if arguments.log: console.save_text(os.path.join(executable.results_dir, "log.txt"))
if __name__ == "__main__": # pragma: no cover # Run hermespy default entry point hermes_simulation()