aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitrii Agibov <dmitrii.agibov@arm.com>2022-12-13 09:39:21 +0000
committerDmitrii Agibov <dmitrii.agibov@arm.com>2022-12-16 09:25:21 +0000
commit8da6441c87532d20d3c8dad538e46dc99d073927 (patch)
tree6afb7f0c82c5c357f7497413f0e18473e84d472c
parentba9aeace4c3d3f4f31830d68b5cc7dd3f4bf1dde (diff)
downloadmlia-8da6441c87532d20d3c8dad538e46dc99d073927.tar.gz
MLIA-460 Revisit backend management
- Provide command for backend installation in case if backend is not available - Fix issue with connection timeout during downloading - Show installation tools output only in verbose mode Change-Id: Ic0e495ba19879cc2cda4fd0bce20b57ba896cfeb
-rw-r--r--src/mlia/backend/errors.py12
-rw-r--r--src/mlia/backend/tosa_checker/compat.py6
-rw-r--r--src/mlia/cli/main.py9
-rw-r--r--src/mlia/utils/download.py3
-rw-r--r--src/mlia/utils/py_manager.py41
-rw-r--r--tests/test_backend_tosa_compat.py5
-rw-r--r--tests/test_cli_main.py29
-rw-r--r--tests/test_utils_py_manager.py30
8 files changed, 108 insertions, 27 deletions
diff --git a/src/mlia/backend/errors.py b/src/mlia/backend/errors.py
new file mode 100644
index 0000000..bd5da95
--- /dev/null
+++ b/src/mlia/backend/errors.py
@@ -0,0 +1,12 @@
+# SPDX-FileCopyrightText: Copyright 2022, Arm Limited and/or its affiliates.
+# SPDX-License-Identifier: Apache-2.0
+"""Backend errors."""
+
+
+class BackendUnavailableError(Exception):
+ """Backend unavailable error."""
+
+ def __init__(self, msg: str, backend: str) -> None:
+ """Init error."""
+ super().__init__(msg)
+ self.backend = backend
diff --git a/src/mlia/backend/tosa_checker/compat.py b/src/mlia/backend/tosa_checker/compat.py
index e1bcb24..bd21774 100644
--- a/src/mlia/backend/tosa_checker/compat.py
+++ b/src/mlia/backend/tosa_checker/compat.py
@@ -8,6 +8,7 @@ from typing import Any
from typing import cast
from typing import Protocol
+from mlia.backend.errors import BackendUnavailableError
from mlia.core.typing import PathOrFileLike
@@ -45,9 +46,8 @@ def get_tosa_compatibility_info(
checker = get_tosa_checker(tflite_model_path)
if checker is None:
- raise Exception(
- "TOSA checker is not available. "
- "Please make sure that 'tosa-checker' backend is installed."
+ raise BackendUnavailableError(
+ "Backend tosa-checker is not available", "tosa-checker"
)
ops = [
diff --git a/src/mlia/cli/main.py b/src/mlia/cli/main.py
index 33a44e1..98fdb63 100644
--- a/src/mlia/cli/main.py
+++ b/src/mlia/cli/main.py
@@ -11,6 +11,7 @@ from inspect import signature
from pathlib import Path
from mlia import __version__
+from mlia.backend.errors import BackendUnavailableError
from mlia.cli.commands import all_tests
from mlia.cli.commands import backend_install
from mlia.cli.commands import backend_list
@@ -225,6 +226,14 @@ def run_command(args: argparse.Namespace) -> int:
logger.error("Internal error: %s", err)
except ConfigurationError as err:
logger.error(err)
+ except BackendUnavailableError as err:
+ logger.error("Error: Backend %s is not available.", err.backend)
+ # apart from tosa-checker all other backends are currently optional
+ if err.backend in ("tosa-checker",):
+ logger.error(
+ 'Please use next command to install it: mlia-backend install "%s"',
+ err.backend,
+ )
except Exception as err: # pylint: disable=broad-except
logger.error(
"\nExecution finished with error: %s",
diff --git a/src/mlia/utils/download.py b/src/mlia/utils/download.py
index c8d0b69..e00be28 100644
--- a/src/mlia/utils/download.py
+++ b/src/mlia/utils/download.py
@@ -46,9 +46,10 @@ def download(
show_progress: bool = False,
label: str | None = None,
chunk_size: int = 8192,
+ timeout: int = 30,
) -> None:
"""Download the file."""
- with requests.get(url, stream=True, timeout=10.0) as resp:
+ with requests.get(url, stream=True, timeout=timeout) as resp:
resp.raise_for_status()
content_chunks = resp.iter_content(chunk_size=chunk_size)
diff --git a/src/mlia/utils/py_manager.py b/src/mlia/utils/py_manager.py
index 5f98fcc..d7821d3 100644
--- a/src/mlia/utils/py_manager.py
+++ b/src/mlia/utils/py_manager.py
@@ -3,10 +3,16 @@
"""Util functions for managing python packages."""
from __future__ import annotations
+import logging
+import subprocess # nosec
import sys
from importlib.metadata import distribution
from importlib.metadata import PackageNotFoundError
-from subprocess import check_call # nosec
+
+from mlia.core.errors import InternalError
+
+
+logger = logging.getLogger(__name__)
class PyPackageManager:
@@ -45,16 +51,29 @@ class PyPackageManager:
"""Execute pip command."""
assert sys.executable, "Unable to launch pip command"
- check_call(
- [
- sys.executable,
- "-m",
- "pip",
- "--disable-pip-version-check",
- subcommand,
- *params,
- ]
- )
+ try:
+ output = subprocess.check_output( # nosec
+ [
+ sys.executable,
+ "-m",
+ "pip",
+ "--disable-pip-version-check",
+ subcommand,
+ *params,
+ ],
+ stderr=subprocess.STDOUT,
+ text=True,
+ )
+ returncode = 0
+ except subprocess.CalledProcessError as err:
+ output = err.output
+ returncode = err.returncode
+
+ for line in output.splitlines():
+ logger.debug(line.rstrip())
+
+ if returncode != 0:
+ raise InternalError("Unable to install python package")
def get_package_manager() -> PyPackageManager:
diff --git a/tests/test_backend_tosa_compat.py b/tests/test_backend_tosa_compat.py
index 4c4dc5a..52aaa44 100644
--- a/tests/test_backend_tosa_compat.py
+++ b/tests/test_backend_tosa_compat.py
@@ -10,6 +10,7 @@ from unittest.mock import MagicMock
import pytest
+from mlia.backend.errors import BackendUnavailableError
from mlia.backend.tosa_checker.compat import get_tosa_compatibility_info
from mlia.backend.tosa_checker.compat import Operator
from mlia.backend.tosa_checker.compat import TOSACompatibilityInfo
@@ -31,7 +32,9 @@ def test_compatibility_check_should_fail_if_checker_not_available(
"""Test that compatibility check should fail if TOSA checker is not available."""
replace_get_tosa_checker_with_mock(monkeypatch, None)
- with pytest.raises(Exception, match="TOSA checker is not available"):
+ with pytest.raises(
+ BackendUnavailableError, match="Backend tosa-checker is not available"
+ ):
get_tosa_compatibility_info(test_tflite_model)
diff --git a/tests/test_cli_main.py b/tests/test_cli_main.py
index 5f6beb6..925f1e4 100644
--- a/tests/test_cli_main.py
+++ b/tests/test_cli_main.py
@@ -15,10 +15,12 @@ from unittest.mock import MagicMock
import pytest
import mlia
+from mlia.backend.errors import BackendUnavailableError
from mlia.cli.main import backend_main
from mlia.cli.main import CommandInfo
from mlia.cli.main import main
from mlia.core.context import ExecutionContext
+from mlia.core.errors import InternalError
from tests.utils.logging import clear_loggers
@@ -358,6 +360,33 @@ def test_commands_execution_backend_main(
MagicMock(side_effect=KeyboardInterrupt()),
["Execution has been interrupted"],
],
+ [
+ False,
+ MagicMock(
+ side_effect=BackendUnavailableError(
+ "Backend sample is not available", "sample"
+ )
+ ),
+ ["Error: Backend sample is not available."],
+ ],
+ [
+ False,
+ MagicMock(
+ side_effect=BackendUnavailableError(
+ "Backend tosa-checker is not available", "tosa-checker"
+ )
+ ),
+ [
+ "Error: Backend tosa-checker is not available.",
+ "Please use next command to install it: "
+ 'mlia-backend install "tosa-checker"',
+ ],
+ ],
+ [
+ False,
+ MagicMock(side_effect=InternalError("Unknown error")),
+ ["Internal error: Unknown error"],
+ ],
],
)
def test_verbose_output(
diff --git a/tests/test_utils_py_manager.py b/tests/test_utils_py_manager.py
index e41680d..c9047f1 100644
--- a/tests/test_utils_py_manager.py
+++ b/tests/test_utils_py_manager.py
@@ -1,6 +1,7 @@
# SPDX-FileCopyrightText: Copyright 2022, Arm Limited and/or its affiliates.
# SPDX-License-Identifier: Apache-2.0
"""Tests for python package manager."""
+import subprocess # nosec
import sys
from unittest.mock import MagicMock
@@ -16,13 +17,16 @@ def test_get_package_manager() -> None:
assert isinstance(manager, PyPackageManager)
-@pytest.fixture(name="mock_check_call")
-def mock_check_call_fixture(monkeypatch: pytest.MonkeyPatch) -> MagicMock:
+@pytest.fixture(name="mock_check_output")
+def mock_check_output_fixture(monkeypatch: pytest.MonkeyPatch) -> MagicMock:
"""Mock check_call function."""
- mock_check_call = MagicMock()
- monkeypatch.setattr("mlia.utils.py_manager.check_call", mock_check_call)
+ mock_check_output = MagicMock()
- return mock_check_call
+ monkeypatch.setattr(
+ "mlia.utils.py_manager.subprocess.check_output", mock_check_output
+ )
+
+ return mock_check_output
def test_py_package_manager_metadata() -> None:
@@ -32,14 +36,14 @@ def test_py_package_manager_metadata() -> None:
assert manager.packages_installed(["pytest", "mlia"])
-def test_py_package_manager_install(mock_check_call: MagicMock) -> None:
+def test_py_package_manager_install(mock_check_output: MagicMock) -> None:
"""Test package installation."""
manager = PyPackageManager()
with pytest.raises(ValueError, match="No package names provided"):
manager.install([])
manager.install(["mlia", "pytest"])
- mock_check_call.assert_called_once_with(
+ mock_check_output.assert_called_once_with(
[
sys.executable,
"-m",
@@ -48,18 +52,20 @@ def test_py_package_manager_install(mock_check_call: MagicMock) -> None:
"install",
"mlia",
"pytest",
- ]
+ ],
+ stderr=subprocess.STDOUT,
+ text=True,
)
-def test_py_package_manager_uninstall(mock_check_call: MagicMock) -> None:
+def test_py_package_manager_uninstall(mock_check_output: MagicMock) -> None:
"""Test package removal."""
manager = PyPackageManager()
with pytest.raises(ValueError, match="No package names provided"):
manager.uninstall([])
manager.uninstall(["mlia", "pytest"])
- mock_check_call.assert_called_once_with(
+ mock_check_output.assert_called_once_with(
[
sys.executable,
"-m",
@@ -69,5 +75,7 @@ def test_py_package_manager_uninstall(mock_check_call: MagicMock) -> None:
"--yes",
"mlia",
"pytest",
- ]
+ ],
+ stderr=subprocess.STDOUT,
+ text=True,
)