From 2e6f50f210b28e80a50c9bca57b403078086903f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jiri=20Dan=C4=9Bk?= Date: Wed, 10 Apr 2024 18:12:11 +0200 Subject: [PATCH] Allow running the yacfg scripts directly; use absolute imports, add shebang, and fixup `sys.path` if needed (#308) * Allow running the yacfg scripts directly; use absolute imports, add shebang, and fixup `sys.path` if needed Shebang has been added at the beginning of yacfg_batch_cli.py and yacfg_cli.py to allow script execution. The import statements have been updated to avoid 'ImportError'. Unnecessary sys.path entries are removed to guard against import misdirection. Also, a script entry point check has been added at the end of yacfg_cli.py. --- src/yacfg/cli/cli_arguments.py | 6 ++++-- src/yacfg/cli/yacfg_cli.py | 18 ++++++++++++------ src/yacfg/files.py | 17 +++++++++-------- src/yacfg/yacfg.py | 2 +- src/yacfg_batch/yacfg_batch_cli.py | 17 ++++++++++++++--- 5 files changed, 40 insertions(+), 20 deletions(-) mode change 100644 => 100755 src/yacfg/cli/cli_arguments.py mode change 100644 => 100755 src/yacfg_batch/yacfg_batch_cli.py diff --git a/src/yacfg/cli/cli_arguments.py b/src/yacfg/cli/cli_arguments.py old mode 100644 new mode 100755 index efe8103f..ae442e98 --- a/src/yacfg/cli/cli_arguments.py +++ b/src/yacfg/cli/cli_arguments.py @@ -1,3 +1,5 @@ +#! /usr/bin/env -S python3 -sP + from __future__ import annotations import argparse @@ -5,7 +7,7 @@ import re from typing import Dict, List, Tuple, Union -from .. import DESCRIPTION, NAME, __version__ +from yacfg import DESCRIPTION, NAME, __version__ REX_BOOL_TRUE = re.compile(r"^(true|yes|1|on)$", re.IGNORECASE) REX_BOOL_FALSE = re.compile(r"^(false|no|0|off)$", re.IGNORECASE) @@ -210,5 +212,5 @@ def parse_key_value_list(items: list[str]) -> dict[str, str]: "--version", help="Display version information", action="store_true" ) -if __name__ == '__main__': +if __name__ == "__main__": args = parser.parse_args() diff --git a/src/yacfg/cli/yacfg_cli.py b/src/yacfg/cli/yacfg_cli.py index 0e57790e..03a22844 100755 --- a/src/yacfg/cli/yacfg_cli.py +++ b/src/yacfg/cli/yacfg_cli.py @@ -1,19 +1,21 @@ +#! /usr/bin/env -S python3 -sP + import logging import os import sys -from .. import NAME, __version__, logger_settings +from yacfg import NAME, __version__, logger_settings from yacfg.cli.cli_arguments import boolize, parse_key_value_list, parser -from ..config_data import RenderOptions -from ..exceptions import GenerationError, ProfileError, TemplateError -from ..output import ( +from yacfg.config_data import RenderOptions +from yacfg.exceptions import GenerationError, ProfileError, TemplateError +from yacfg.output import ( export_tuning_variables, new_profile, new_profile_rendered, new_template, ) -from ..query import list_profiles, list_templates -from ..yacfg import generate +from yacfg.query import list_profiles, list_templates +from yacfg.yacfg import generate logger_settings.config_console_logger() @@ -148,3 +150,7 @@ def error(msg: str, ecode: int = 2) -> None: def main(): app = CommandLineApp() app.run() + + +if __name__ == "__main__": + main() diff --git a/src/yacfg/files.py b/src/yacfg/files.py index c021cd5c..8590e883 100644 --- a/src/yacfg/files.py +++ b/src/yacfg/files.py @@ -108,13 +108,17 @@ def select_profile_file(profile_name: str) -> Tuple[str, str]: # User-defined profile in the ./profiles/ directory LOG.debug(f"User-defined profile in the ./profiles/ directory: {profile_name}") profile_tmp_name = os.path.abspath(user_extra_path) - selected_profile_name, selected_profile_path = os.path.basename(profile_tmp_name), os.path.dirname(profile_tmp_name) + selected_profile_name, selected_profile_path = os.path.basename( + profile_tmp_name + ), os.path.dirname(profile_tmp_name) if os.path.isfile(profile_name): # User directly specified the profile file LOG.debug(f"User directly specified the profile file: {profile_name}") profile_tmp_name = os.path.abspath(profile_name) - selected_profile_name, selected_profile_path = os.path.basename(profile_tmp_name), os.path.dirname(profile_tmp_name) + selected_profile_name, selected_profile_path = os.path.basename( + profile_tmp_name + ), os.path.dirname(profile_tmp_name) profiles_paths = get_profiles_paths() LOG.debug(f"Profiles paths: {profiles_paths}") @@ -150,17 +154,15 @@ def select_template_dir(template_name: str) -> str: if os.path.isdir(user_extra_path): selected_template_path = user_extra_path - LOG.debug(f'Using user defined template path {template_name}') + LOG.debug(f"Using user defined template path {template_name}") # user direct path if os.path.isdir(template_name): selected_template_path = template_name - LOG.debug(f'Using user defined template path {template_name}') + LOG.debug(f"Using user defined template path {template_name}") if not os.path.isdir(selected_template_path): - raise TemplateError( - f'Unable to load requested template set "{template_name}"' - ) + raise TemplateError(f'Unable to load requested template set "{template_name}"') if not os.path.isfile(os.path.join(selected_template_path, "_template")): raise TemplateError( @@ -172,7 +174,6 @@ def select_template_dir(template_name: str) -> str: return selected_template_path - def ensure_output_path(output_path: str) -> None: """ Ensure that the output path is an existing directory diff --git a/src/yacfg/yacfg.py b/src/yacfg/yacfg.py index 3af81fc9..9b1adc03 100644 --- a/src/yacfg/yacfg.py +++ b/src/yacfg/yacfg.py @@ -263,7 +263,7 @@ def generate_outputs( generate_exception: Optional[GenerationError] = None # TODO: volkswagen mode on - if 'PYTEST_CURRENT_TEST' not in os.environ: + if "PYTEST_CURRENT_TEST" not in os.environ: if output_path and not os.path.exists(output_path): raise GenerationError(f"Output path '{output_path}' does not exist.") diff --git a/src/yacfg_batch/yacfg_batch_cli.py b/src/yacfg_batch/yacfg_batch_cli.py old mode 100644 new mode 100755 index 41b8159c..c220769b --- a/src/yacfg_batch/yacfg_batch_cli.py +++ b/src/yacfg_batch/yacfg_batch_cli.py @@ -1,13 +1,24 @@ +#! /usr/bin/env -S python3 -sP + from __future__ import print_function import logging +import pathlib import sys +# `from yacfg_batch import ...` may target both src/yacfg/yacfg_batch/__init__.py +# and src/yacfg/yacfg_batch/yacfg_batch.py (which is on sys.path when running +# this file directly). Remove the undesirable sys.path entry to prevent `ImportError`s. +try: + sys.path.remove(str(pathlib.Path(__file__).resolve().parent)) +except ValueError: + pass + from yacfg import NAME, logger_settings -from . import __version__ -from .cli_arguments import parser -from .yacfg_batch import generate +from yacfg_batch import __version__ +from yacfg_batch.cli_arguments import parser +from yacfg_batch.yacfg_batch import generate logger_settings.config_console_logger()