From e819f9b10514e6dc34f5bfaf8a632d642bb8ba22 Mon Sep 17 00:00:00 2001 From: Bouwe Andela Date: Thu, 14 May 2026 17:35:04 +0100 Subject: [PATCH] Nicer command line --- esmvalcore/_main.py | 66 +++++++++++++++++++++++++++++---------------- 1 file changed, 43 insertions(+), 23 deletions(-) diff --git a/esmvalcore/_main.py b/esmvalcore/_main.py index 401c58847a..0d58d10b1f 100644 --- a/esmvalcore/_main.py +++ b/esmvalcore/_main.py @@ -190,6 +190,7 @@ def show( """ import yaml from nested_lookup import nested_delete + from rich.markdown import Markdown from rich.syntax import Syntax from esmvalcore.config import CFG @@ -203,7 +204,7 @@ def show( if filter else "" ) - self._console.print(f"# Current configuration{exclude_msg}:") + self._console.print(Markdown(f"# Current configuration{exclude_msg}:")) self._console.print( Syntax( yaml.safe_dump(cfg), @@ -450,28 +451,43 @@ class Recipes: https://docs.esmvaltool.org/en/latest/recipes/index.html. """ - @staticmethod - def list() -> None: + def __init__(self) -> None: + from rich.console import Console + + self._console = Console(soft_wrap=True) + + def list(self) -> None: """List all installed recipes. Show all installed recipes, grouped by folder. """ + import yaml + from rich.markdown import Markdown + from .config._diagnostics import DIAGNOSTICS - from .config._logging import configure_logging - configure_logging(console_log_level="info") recipes_folder = DIAGNOSTICS.recipes - logger.info("Showing recipes installed in %s", recipes_folder) - print("# Installed recipes") # noqa: T201 - for recipe_root, _, files in sorted(os.walk(recipes_folder)): - root = os.path.relpath(recipe_root, recipes_folder) - if root == ".": - root = "" - if root: - print(f"\n# {root.replace(os.sep, ' - ').title()}") # noqa: T201 + messages = [f"# ESMValTool recipes available in `{DIAGNOSTICS.path}`"] + for recipe_root, _, files in sorted(recipes_folder.walk()): + subdir = recipe_root.relative_to(recipes_folder).as_posix() + if subdir == ".": + subdir = "" + if subdir: + messages.append( + f"\n## {subdir.replace(os.sep, ' - ').title()}", + ) for filename in sorted(files): - if filename.endswith(".yml"): - print(os.path.join(root, filename)) # noqa: T201 + recipe = recipe_root / filename + if recipe.suffix == ".yml": + title = ( + yaml.safe_load(recipe.read_text(encoding="utf-8")) + .get("documentation", {}) + .get("title", "") + ) + messages.append( + f"- `{recipe.relative_to(recipe_root)}`: {title}", + ) + self._console.print(Markdown("\n".join(messages))) @staticmethod def get(recipe: str) -> None: @@ -502,8 +518,7 @@ def get(recipe: str) -> None: shutil.copy(installed_recipe, Path(recipe).name) logger.info("Recipe %s successfully copied", recipe) - @staticmethod - def show(recipe: str) -> None: + def show(self, recipe: str) -> None: """Show the given recipe in console. Use this command to see the contents of any installed recipe. @@ -513,11 +528,12 @@ def show(recipe: str) -> None: recipe: str Name of the recipe to get, including any subdirectories. """ + from rich.markdown import Markdown + from rich.syntax import Syntax + from .config._diagnostics import DIAGNOSTICS - from .config._logging import configure_logging from .exceptions import RecipeError - configure_logging(console_log_level="info") installed_recipe = DIAGNOSTICS.recipes / recipe if not installed_recipe.exists(): msg = ( @@ -525,10 +541,14 @@ def show(recipe: str) -> None: 'execute "esmvaltool list"' ) raise RecipeError(msg) - msg = f"Recipe {recipe}" - logger.info(msg) - logger.info("=" * len(msg)) - print(installed_recipe.read_text(encoding="utf-8")) # noqa: T201 + self._console.print(Markdown(f"# Recipe `{recipe}`")) + self._console.print( + Syntax( + installed_recipe.read_text(encoding="utf-8"), + "yaml", + background_color="default", + ), + ) class ESMValTool: