From 78c6af9314db4f2908735b4840f1ea58c5c68b9f Mon Sep 17 00:00:00 2001 From: Philip Loche Date: Wed, 29 Nov 2023 23:55:39 +0100 Subject: [PATCH] Add basic cli interface to scripts --- .github/workflows/build.yml | 24 ++++++++ .github/workflows/lint.yml | 21 +++++++ .github/workflows/tests.yml | 68 ++++++++------------- bin/__init__.py | 0 bin/eval-metatensor-model.py | 1 - bin/export-metatensor-model.py | 1 - bin/train-metatensor-model.py | 1 - pyproject.toml | 4 +- src/metatensor_models/__init__.py | 2 +- src/metatensor_models/__main__.py | 72 +++++++++++++++++++++++ src/metatensor_models/scripts/__init__.py | 5 ++ src/metatensor_models/scripts/evaluate.py | 3 + src/metatensor_models/scripts/export.py | 3 + src/metatensor_models/scripts/train.py | 3 + tests/cli.py | 30 ++++++++++ tox.ini | 42 ++++--------- 16 files changed, 202 insertions(+), 78 deletions(-) create mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/lint.yml delete mode 100644 bin/__init__.py delete mode 100644 bin/eval-metatensor-model.py delete mode 100644 bin/export-metatensor-model.py delete mode 100644 bin/train-metatensor-model.py create mode 100644 src/metatensor_models/__main__.py create mode 100644 src/metatensor_models/scripts/__init__.py create mode 100644 src/metatensor_models/scripts/evaluate.py create mode 100644 src/metatensor_models/scripts/export.py create mode 100644 src/metatensor_models/scripts/train.py create mode 100644 tests/cli.py diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 000000000..cc87dd00f --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,24 @@ +# This workflow builds and checks the package for release +name: Build + +on: + pull_request: + branches: [main] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.10" + - run: pip install tox + + - name: Test build integrity + run: tox -e build + env: + # Use the CPU only version of torch when building/running the code + PIP_EXTRA_INDEX_URL: https://download.pytorch.org/whl/cpu diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 000000000..9db6584ee --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,21 @@ +name: Lint + +on: + pull_request: + branches: [main] + +jobs: + lint: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.10" + - run: pip install tox + + - name: Lint the code + run: tox -e lint diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 2df74b7af..0b0cc55ff 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -4,57 +4,39 @@ on: push: branches: [main] pull_request: - # Run for all PRs + # Check all PR jobs: tests: runs-on: ${{ matrix.os }} - name: Test on ${{ matrix.os }} strategy: matrix: include: - - os: ubuntu-20.04 + - os: ubuntu-22.04 + python-version: "3.8" + - os: ubuntu-22.04 + python-version: "3.11" - os: macos-11 + python-version: "3.11" - os: windows-2019 - steps: - - uses: actions/checkout@v3 - - - name: setup Python - uses: actions/setup-python@v4 - with: - python-version: "3.10" - - - name: install tests dependencies - run: | - python -m pip install --upgrade pip - python -m pip install tox + python-version: "3.11" - - name: run Python tests - run: python -m tox - env: - PIP_EXTRA_INDEX_URL: https://download.pytorch.org/whl/cpu - - # check that we can build Python wheels on any Python version - python-build: - runs-on: ubuntu-20.04 - name: check Python build - strategy: - matrix: - python-version: ['3.7', '3.11'] steps: - - uses: actions/checkout@v3 - - - name: set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - - - name: install python dependencies - run: | - python -m pip install --upgrade pip - python -m pip install tox wheel - - - name: python build tests - run: tox -e build-python - env: - PIP_EXTRA_INDEX_URL: https://download.pytorch.org/whl/cpu + - uses: actions/checkout@v3 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + - run: pip install tox + + - name: run Python tests + run: tox -e tests + env: + # Use the CPU only version of torch when building/running the code + PIP_EXTRA_INDEX_URL: https://download.pytorch.org/whl/cpu + + - name: Upload codecoverage + uses: codecov/codecov-action@v3 + with: + files: ./tests/coverage.xml diff --git a/bin/__init__.py b/bin/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/bin/eval-metatensor-model.py b/bin/eval-metatensor-model.py deleted file mode 100644 index eacb83ed3..000000000 --- a/bin/eval-metatensor-model.py +++ /dev/null @@ -1 +0,0 @@ -print("eval") diff --git a/bin/export-metatensor-model.py b/bin/export-metatensor-model.py deleted file mode 100644 index ed7570b13..000000000 --- a/bin/export-metatensor-model.py +++ /dev/null @@ -1 +0,0 @@ -print("export") diff --git a/bin/train-metatensor-model.py b/bin/train-metatensor-model.py deleted file mode 100644 index c859094af..000000000 --- a/bin/train-metatensor-model.py +++ /dev/null @@ -1 +0,0 @@ -print("train") diff --git a/pyproject.toml b/pyproject.toml index ca20272f1..8e7fcd940 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,7 +42,7 @@ repository = "https://github.com/lab-cosmo/metatensor-models" # changelog = "TODO" [project.scripts] -maicos = "maicos.__main__:main" +metatensor_models = "metatensor_models.__main__:main" ### ======================================================================== ### @@ -59,7 +59,7 @@ soap-bpnn = [ ] [tool.setuptools.packages.find] -where = ["src", "bin"] +where = ["src"] [tool.setuptools.dynamic] version = {attr = "metatensor_models.__version__"} diff --git a/src/metatensor_models/__init__.py b/src/metatensor_models/__init__.py index e728ace74..3c0a79516 100644 --- a/src/metatensor_models/__init__.py +++ b/src/metatensor_models/__init__.py @@ -1 +1 @@ -__version__ = "0.0.0-dev" +__version__ = "2023.11.29" diff --git a/src/metatensor_models/__main__.py b/src/metatensor_models/__main__.py new file mode 100644 index 000000000..7263902ae --- /dev/null +++ b/src/metatensor_models/__main__.py @@ -0,0 +1,72 @@ +"""The main entry point for the metatensor model interface.""" +import argparse +import sys + +from . import __version__ +from .scripts import evaluate, export, train + + +def main(): + ap = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter, + ) + + ap.add_argument( + "--version", + action="version", + version=f"metatensor_models {__version__}", + ) + + ap.add_argument( + "--debug", + action="store_true", + help="Run with debug options.", + ) + + ap.add_argument( + "--logfile", dest="logfile", action="store", help="Logfile (optional)" + ) + + subparser = ap.add_subparsers(help="sub-command help") + evaluate_parser = subparser.add_parser( + "evaluate", + help=evaluate.__doc__, + description="evaluate", + formatter_class=argparse.RawDescriptionHelpFormatter, + ) + evaluate_parser.set_defaults(callable="evaluate") + + export_parser = subparser.add_parser( + "export", + help=export.__doc__, + description="export", + formatter_class=argparse.RawDescriptionHelpFormatter, + ) + export_parser.set_defaults(callable="export") + train_parser = subparser.add_parser( + "train", + help=train.__doc__, + description="train", + formatter_class=argparse.RawDescriptionHelpFormatter, + ) + train_parser.set_defaults(callable="train") + + if len(sys.argv) < 2: + ap.error("A subcommand is required.") + + # Be case insensitive for the subcommand + sys.argv[1] = sys.argv[1].lower() + + args = ap.parse_args(sys.argv[1:]) + + if args.callable == "evaluate": + evaluate() + elif args.callable == "export": + export() + elif args.callable == "train": + train() + + +if __name__ == "__main__": + main() diff --git a/src/metatensor_models/scripts/__init__.py b/src/metatensor_models/scripts/__init__.py new file mode 100644 index 000000000..f4043c941 --- /dev/null +++ b/src/metatensor_models/scripts/__init__.py @@ -0,0 +1,5 @@ +from .evaluate import evaluate +from .export import export +from .train import train + +__all__ = ["evaluate", "export", "train"] diff --git a/src/metatensor_models/scripts/evaluate.py b/src/metatensor_models/scripts/evaluate.py new file mode 100644 index 000000000..65d30915b --- /dev/null +++ b/src/metatensor_models/scripts/evaluate.py @@ -0,0 +1,3 @@ +def evaluate(): + """evaluate a model""" + print("Run evaluate...") diff --git a/src/metatensor_models/scripts/export.py b/src/metatensor_models/scripts/export.py new file mode 100644 index 000000000..f34030701 --- /dev/null +++ b/src/metatensor_models/scripts/export.py @@ -0,0 +1,3 @@ +def export(): + """export a model""" + print("Run exort...") diff --git a/src/metatensor_models/scripts/train.py b/src/metatensor_models/scripts/train.py new file mode 100644 index 000000000..5908ef522 --- /dev/null +++ b/src/metatensor_models/scripts/train.py @@ -0,0 +1,3 @@ +def train(): + """train a model""" + print("Run train...") diff --git a/tests/cli.py b/tests/cli.py new file mode 100644 index 000000000..95dd4da8c --- /dev/null +++ b/tests/cli.py @@ -0,0 +1,30 @@ +import subprocess +import sys + +import pytest + +from metatensor_models.scripts import __all__ as available_scripts + + +class Test_parse_args(object): + """Tests for argument parsing.""" + + def test_required_args(self): + """Test required arguments.""" + with pytest.raises(subprocess.CalledProcessError): + subprocess.check_call(["metatensor_models"]) + + def test_wrong_module(self): + """Test wrong module.""" + with pytest.raises(subprocess.CalledProcessError): + subprocess.check_call(["metatensor_models", "foo"]) + + @pytest.mark.parametrize("module", tuple(available_scripts)) + def test_available_modules(self, module): + """Test available modules.""" + subprocess.check_call(["metatensor_models", module, "--help"]) + + @pytest.mark.parametrize("args", ("version", "help")) + def test_extra_options(self, args): + """Test extra options.""" + subprocess.check_call(["metatensor_models", "--" + args]) diff --git a/tox.ini b/tox.ini index 8bbd6cd36..a149d5770 100644 --- a/tox.ini +++ b/tox.ini @@ -12,8 +12,7 @@ passenv = * lint_folders = "{toxinidir}/src" [testenv:lint] -# this environement lints the Python code with flake8 (code linter), black (code -# formatter), and isort (sorting of imports) +description = Run linters and type checks package = skip deps = flake8 @@ -29,9 +28,7 @@ commands = isort --check-only --diff {[testenv]lint_folders} [testenv:format] -# this environement abuses tox to do actual formatting -# -# Users can run `tox -e format` to run formatting on all files +description = Abuse tox to do actual formatting on all files. package = skip deps = black @@ -51,34 +48,21 @@ deps = commands = pytest --import-mode=append {posargs} -[testenv:soap-bpnn] -passenv = * -deps = - pytest - -commands = - echo "success" - -[testenv:build-python] -# this environement makes sure one can build sdist and wheels for Python +[testenv:build] +description = builds the package and checks integrity +usedevelop = true deps = - setuptools - wheel - cmake - twine build - -allowlist_externals = - bash - + check-manifest + twine +allowlist_externals = bash +commands_pre = + bash -c "if [ -e {toxinidir}/dist/*tar.gz ]; then unlink {toxinidir}/dist/*.whl; fi" + bash -c "if [ -e {toxinidir}/dist/*tar.gz ]; then unlink {toxinidir}/dist/*.tar.gz; fi" commands = - # check building sdist and wheels from a checkout python -m build - twine check dist/*.tar.gz - twine check dist/*.whl - - # check building wheels from the sdist - bash -c "python -m pip wheel --verbose dist/metatensor_models-*.tar.gz -w dist/test" + twine check dist/*.tar.gz dist/*.whl + check-manifest {toxinidir} [flake8] # longer lines for compatibility with other linters