Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PIP runner introduction #6072

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions avocado/plugins/runners/pip.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import sys
import traceback
from multiprocessing import set_start_method

from avocado.core.nrunner.app import BaseRunnerApp
from avocado.core.nrunner.runner import BaseRunner
from avocado.core.utils import messages
from avocado.utils import process


class PipRunner(BaseRunner):
"""Runner for dependencies of type pip
This runner handles, the installation, verification and removal of
packages using the pip.
Runnable attributes usage:
* kind: 'pip'
* uri: not used
* args: not used
* kwargs:
- name: the package name (required)
- action: one of 'install' or 'uninstall' (optional, defaults
to 'install')
"""

name = "pip"
description = "Runner for dependencies of type pip"

def run(self, runnable):
try:
yield messages.StartedMessage.get()
# check if there is a valid 'action' argument
cmd = runnable.kwargs.get("action", "install")
# avoid invalid arguments
if cmd not in ["install", "uninstall"]:
stderr = f"Invalid action {cmd}. Use one of 'install' or 'remove'"
yield messages.StderrMessage.get(stderr.encode())
yield messages.FinishedMessage.get("error")
return

Check warning on line 44 in avocado/plugins/runners/pip.py

View check run for this annotation

Codecov / codecov/patch

avocado/plugins/runners/pip.py#L41-L44

Added lines #L41 - L44 were not covered by tests

package = runnable.kwargs.get("name")
# if package was passed correctly, run python -m pip
if package is not None:
try:
cmd = f"python3 -m ensurepip && python3 -m pip {cmd} {package}"
result = process.run(cmd, shell=True)
except Exception as e:
yield messages.StderrMessage.get(str(e))
yield messages.FinishedMessage.get("error")
return

Check warning on line 55 in avocado/plugins/runners/pip.py

View check run for this annotation

Codecov / codecov/patch

avocado/plugins/runners/pip.py#L52-L55

Added lines #L52 - L55 were not covered by tests

yield messages.StdoutMessage.get(result.stdout)
yield messages.StderrMessage.get(result.stderr)
yield messages.FinishedMessage.get("pass")
except Exception as e:
yield messages.StderrMessage.get(traceback.format_exc())
yield messages.FinishedMessage.get(
"error",
fail_reason=str(e),
fail_class=e.__class__.__name__,
traceback=traceback.format_exc(),
)


class RunnerApp(BaseRunnerApp):
PROG_NAME = "avocado-runner-pip"
PROG_DESCRIPTION = "nrunner application for dependencies of type pip"
RUNNABLE_KINDS_CAPABLE = ["pip"]


def main():
if sys.platform == "darwin":
set_start_method("fork")

Check warning on line 78 in avocado/plugins/runners/pip.py

View check run for this annotation

Codecov / codecov/patch

avocado/plugins/runners/pip.py#L78

Added line #L78 was not covered by tests
app = RunnerApp(print)
app.run()


if __name__ == "__main__":
main()
11 changes: 11 additions & 0 deletions docs/source/guides/user/chapters/dependencies.rst
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,17 @@ Following is an example of a test using the Package dependency:

.. literalinclude:: ../../../../../examples/tests/passtest_with_dependency.py

Pip
+++

Support managing python packages via pip. The
parameters available to use the asset `type` of dependencies are:

* `type`: `pip`
* `name`: the package name (required)
* `action`: `install` or `uninstall`
(optional, defaults to `install`)

Asset
+++++

Expand Down
1 change: 1 addition & 0 deletions examples/nrunner/recipes/runnable/pip_coverage.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"kind": "pip", "kwargs": {"action": "install", "name": "coverage"}}
11 changes: 11 additions & 0 deletions examples/tests/dependency_pip.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from avocado import Test, fail_on


class Pip(Test):
"""
:avocado: dependency={"type": "pip", "name": "pip", "action": "install"}
"""

@fail_on(ImportError)
def test(self):
import pip # pylint: disable=W0611
1 change: 1 addition & 0 deletions python-avocado.spec
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ PATH=%{buildroot}%{_bindir}:%{buildroot}%{_libexecdir}/avocado:$PATH \
%{_bindir}/avocado-runner-tap
%{_bindir}/avocado-runner-asset
%{_bindir}/avocado-runner-package
%{_bindir}/avocado-runner-pip
%{_bindir}/avocado-runner-podman-image
%{_bindir}/avocado-runner-sysinfo
%{_bindir}/avocado-software-manager
Expand Down
7 changes: 5 additions & 2 deletions selftests/check.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@
"job-api-check-file-exists": 11,
"job-api-check-output-file": 4,
"job-api-check-tmp-directory-exists": 1,
"nrunner-interface": 70,
"nrunner-interface": 80,
"nrunner-requirement": 28,
"unit": 682,
"jobs": 11,
"functional-parallel": 314,
"functional-parallel": 317,
"functional-serial": 7,
"optional-plugins": 0,
"optional-plugins-golang": 2,
Expand Down Expand Up @@ -627,6 +627,9 @@ def create_suites(args): # pylint: disable=W0621
{
"runner": "avocado-runner-podman-image",
},
{
"runner": "avocado-runner-pip",
},
],
}

Expand Down
1 change: 1 addition & 0 deletions selftests/functional/resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ def test_runnables_recipe(self):
exec-test: 3
noop: 3
package: 1
pip: 1
python-unittest: 1
sysinfo: 1"""
cmd_line = f"{AVOCADO} -V list {runnables_recipe_path}"
Expand Down
49 changes: 49 additions & 0 deletions selftests/functional/runner_pip.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import os
import sys
import unittest

from avocado.utils import process
from selftests.utils import AVOCADO, BASEDIR, TestCaseTmpDir

RUNNER = f"{sys.executable} -m avocado.plugins.runners.pip"


class RunnableRun(unittest.TestCase):
def test_no_kwargs(self):
res = process.run(f"{RUNNER} runnable-run -k pip", ignore_status=True)
self.assertIn(b"'status': 'started'", res.stdout)
self.assertIn(b"'status': 'finished'", res.stdout)
self.assertIn(b"'time': ", res.stdout)
self.assertEqual(res.exit_status, 0)


class TaskRun(unittest.TestCase):
def test_no_kwargs(self):
res = process.run(f"{RUNNER} task-run -i pip_1 -k pip", ignore_status=True)
self.assertIn(b"'status': 'finished'", res.stdout)
self.assertIn(b"'result': 'error'", res.stdout)
self.assertIn(b"'id': 'pip_1'", res.stdout)
self.assertEqual(res.exit_status, 0)


class PipTest(TestCaseTmpDir):
def test_pip_dependencies(self):
test_path = os.path.join(
BASEDIR,
"examples",
"tests",
"dependency_pip.py",
)
res = process.run(
f"{AVOCADO} run --job-results-dir {self.tmpdir.name} {test_path}",
ignore_status=True,
)
self.assertIn(
b"RESULTS : PASS 1 | ERROR 0 | FAIL 0 | SKIP 0 | WARN 0 | INTERRUPT 0 | CANCEL 0",
res.stdout,
)
self.assertEqual(res.exit_status, 0)


if __name__ == "__main__":
unittest.main()
2 changes: 2 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,7 @@ def run(self):
"avocado-runner-tap = avocado.plugins.runners.tap:main",
"avocado-runner-asset = avocado.plugins.runners.asset:main",
"avocado-runner-package = avocado.plugins.runners.package:main",
"avocado-runner-pip = avocado.plugins.runners.pip:main",
"avocado-runner-podman-image = avocado.plugins.runners.podman_image:main",
"avocado-runner-sysinfo = avocado.plugins.runners.sysinfo:main",
"avocado-software-manager = avocado.utils.software_manager.main:main",
Expand Down Expand Up @@ -479,6 +480,7 @@ def run(self):
"python-unittest = avocado.plugins.runners.python_unittest:PythonUnittestRunner",
"asset = avocado.plugins.runners.asset:AssetRunner",
"package = avocado.plugins.runners.package:PackageRunner",
"pip = avocado.plugins.runners.pip:PipRunner",
"podman-image = avocado.plugins.runners.podman_image:PodmanImageRunner",
"sysinfo = avocado.plugins.runners.sysinfo:SysinfoRunner",
],
Expand Down
Loading