From b5faa43e4bf98c49b756bfc1b2ebfacd6f64202f Mon Sep 17 00:00:00 2001 From: Baudouin Raoult Date: Sat, 18 May 2024 10:29:09 +0100 Subject: [PATCH] Add commands --- pyproject.toml | 2 + src/anemoi/inference/__main__.py | 72 +++++++++++++++++++++ src/anemoi/inference/commands/__init__.py | 78 +++++++++++++++++++++++ src/anemoi/inference/commands/hello.py | 32 ++++++++++ 4 files changed, 184 insertions(+) create mode 100644 src/anemoi/inference/__main__.py create mode 100644 src/anemoi/inference/commands/__init__.py create mode 100644 src/anemoi/inference/commands/hello.py diff --git a/pyproject.toml b/pyproject.toml index d9c5863..ae983a8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -67,6 +67,8 @@ Repository = "https://github.com/ecmwf/anemoi-inference/" Issues = "https://github.com/ecmwf/anemoi-inference/issues" # Changelog = "https://github.com/ecmwf/anemoi-inference/CHANGELOG.md" +[project.scripts] +anemoi-inference = "anemoi.inference.__main__:main" [tool.setuptools_scm] version_file = "src/anemoi/inference/_version.py" diff --git a/src/anemoi/inference/__main__.py b/src/anemoi/inference/__main__.py new file mode 100644 index 0000000..2ac1a15 --- /dev/null +++ b/src/anemoi/inference/__main__.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python +# (C) Copyright 2024 ECMWF. +# +# This software is licensed under the terms of the Apache Licence Version 2.0 +# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +# In applying this licence, ECMWF does not waive the privileges and immunities +# granted to it by virtue of its status as an intergovernmental organisation +# nor does it submit to any jurisdiction. +# + + +import argparse +import logging +import sys +import traceback + +from . import __version__ +from .commands import COMMANDS + +LOG = logging.getLogger(__name__) + + +def main(): + parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) + + parser.add_argument( + "--version", + "-V", + action="store_true", + help="show the version and exit", + ) + parser.add_argument( + "--debug", + "-d", + action="store_true", + help="Debug mode", + ) + + subparsers = parser.add_subparsers(help="commands:", dest="command") + for name, command in COMMANDS.items(): + command_parser = subparsers.add_parser(name, help=command.__doc__) + command.add_arguments(command_parser) + + args = parser.parse_args() + + if args.version: + print(__version__) + return + + if args.command is None: + parser.print_help() + return + + cmd = COMMANDS[args.command] + + logging.basicConfig( + format="%(asctime)s %(levelname)s %(message)s", + datefmt="%Y-%m-%d %H:%M:%S", + level=logging.DEBUG if args.debug else logging.INFO, + ) + + try: + cmd.run(args) + except ValueError as e: + traceback.print_exc() + LOG.error("\nšŸ’£ %s", str(e).lstrip()) + LOG.error("šŸ’£ Exiting") + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/src/anemoi/inference/commands/__init__.py b/src/anemoi/inference/commands/__init__.py new file mode 100644 index 0000000..0932e6e --- /dev/null +++ b/src/anemoi/inference/commands/__init__.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python +# (C) Copyright 2024 ECMWF. +# +# This software is licensed under the terms of the Apache Licence Version 2.0 +# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +# In applying this licence, ECMWF does not waive the privileges and immunities +# granted to it by virtue of its status as an intergovernmental organisation +# nor does it submit to any jurisdiction. +# + +import argparse +import importlib +import logging +import os +import sys + +LOG = logging.getLogger(__name__) + + +def register(here, package, select, fail=None): + result = {} + not_available = {} + + for p in os.listdir(here): + full = os.path.join(here, p) + if p.startswith("_"): + continue + if not (p.endswith(".py") or (os.path.isdir(full) and os.path.exists(os.path.join(full, "__init__.py")))): + continue + + name, _ = os.path.splitext(p) + + try: + imported = importlib.import_module( + f".{name}", + package=package, + ) + except ImportError as e: + not_available[name] = e + continue + + obj = select(imported) + if obj is not None: + result[name] = obj + + for name, e in not_available.items(): + if fail is None: + pass + if callable(fail): + result[name] = fail(name, e) + + return result + + +class Command: + def run(self, args): + raise NotImplementedError(f"Command not implemented: {args.command}") + + +class Failed(Command): + def __init__(self, name, error): + self.name = name + self.error = error + + def add_arguments(self, command_parser): + command_parser.add_argument("x", nargs=argparse.REMAINDER) + + def run(self, args): + print(f"Command '{self.name}' not available: {self.error}") + sys.exit(1) + + +COMMANDS = register( + os.path.dirname(__file__), + __name__, + lambda x: x.command(), + lambda name, error: Failed(name, error), +) diff --git a/src/anemoi/inference/commands/hello.py b/src/anemoi/inference/commands/hello.py new file mode 100644 index 0000000..12a0495 --- /dev/null +++ b/src/anemoi/inference/commands/hello.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python +# (C) Copyright 2024 ECMWF. +# +# This software is licensed under the terms of the Apache Licence Version 2.0 +# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +# In applying this licence, ECMWF does not waive the privileges and immunities +# granted to it by virtue of its status as an intergovernmental organisation +# nor does it submit to any jurisdiction. +# + +"""Command place holder. Delete when we have real commands. + +""" + +from . import Command + + +def say_hello(greetings, who): + print(greetings, who) + + +class Hello(Command): + + def add_arguments(self, command_parser): + command_parser.add_argument("--greetings", default="hello") + command_parser.add_argument("--who", default="world") + + def run(self, args): + say_hello(args.greetings, args.who) + + +command = Hello